Fresh dep ensure

This commit is contained in:
Mike Cronce
2018-11-26 13:23:56 -05:00
parent 93cb8a04d7
commit 407478ab9a
9016 changed files with 551394 additions and 279685 deletions

View File

@ -122,6 +122,7 @@
"k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/util",
"k8s.io/kubernetes/pkg/scheduler/api",
"k8s.io/kubernetes/pkg/scheduler/cache",
"k8s.io/kubernetes/pkg/scheduler/internal/cache",
"k8s.io/kubernetes/pkg/scheduler/util",
"k8s.io/kubernetes/pkg/scheduler/volumebinder",
"k8s.io/kubernetes/pkg/security/apparmor",
@ -138,13 +139,13 @@
"k8s.io/kubernetes/pkg/util/node",
"k8s.io/kubernetes/pkg/util/nsenter",
"k8s.io/kubernetes/pkg/util/parsers",
"k8s.io/kubernetes/pkg/util/pointer",
"k8s.io/kubernetes/pkg/util/slice",
"k8s.io/kubernetes/pkg/util/taints",
"k8s.io/kubernetes/pkg/version",
"k8s.io/kubernetes/pkg/version/prometheus",
"k8s.io/kubernetes/pkg/volume",
"k8s.io/kubernetes/pkg/volume/util"
"k8s.io/kubernetes/pkg/volume/util",
"k8s.io/utils/pointer"
],
"ForbiddenPrefixes": []
}]

View File

@ -9,71 +9,37 @@ load(
go_test(
name = "go_default_test",
srcs = [
"autoscale_test.go",
"clusterrolebinding_test.go",
"configmap_test.go",
"deployment_test.go",
"env_file_test.go",
"generate_test.go",
"history_test.go",
"namespace_test.go",
"pdb_test.go",
"priorityclass_test.go",
"quota_test.go",
"rolebinding_test.go",
"rollback_test.go",
"rolling_updater_test.go",
"rollout_status_test.go",
"run_test.go",
"scale_test.go",
"secret_for_docker_registry_test.go",
"secret_for_tls_test.go",
"secret_test.go",
"service_basic_test.go",
"service_test.go",
"serviceaccount_test.go",
"sorter_test.go",
],
embed = [":go_default_library"],
deps = [
"//pkg/api/legacyscheme:go_default_library",
"//pkg/api/testapi:go_default_library",
"//pkg/api/testing:go_default_library",
"//pkg/apis/core:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
"//pkg/kubectl/scheme:go_default_library",
"//pkg/kubectl/util:go_default_library",
"//pkg/util/pointer:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/k8s.io/api/apps/v1:go_default_library",
"//vendor/k8s.io/api/apps/v1beta1:go_default_library",
"//vendor/k8s.io/api/autoscaling/v1:go_default_library",
"//vendor/k8s.io/api/batch/v1:go_default_library",
"//vendor/k8s.io/api/batch/v1beta1:go_default_library",
"//vendor/k8s.io/api/batch/v2alpha1:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/api/policy/v1beta1:go_default_library",
"//vendor/k8s.io/api/rbac/v1:go_default_library",
"//vendor/k8s.io/api/rbac/v1beta1:go_default_library",
"//vendor/k8s.io/api/scheduling/v1alpha1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured: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/util/intstr:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library",
"//vendor/k8s.io/client-go/rest/fake:go_default_library",
"//vendor/k8s.io/client-go/scale:go_default_library",
"//vendor/k8s.io/client-go/scale/fake:go_default_library",
"//vendor/k8s.io/client-go/testing:go_default_library",
"//vendor/k8s.io/client-go/util/testing:go_default_library",
"//staging/src/k8s.io/api/apps/v1:go_default_library",
"//staging/src/k8s.io/api/autoscaling/v1:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/testapigroup/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
"//staging/src/k8s.io/client-go/rest:go_default_library",
"//staging/src/k8s.io/client-go/rest/fake:go_default_library",
"//staging/src/k8s.io/client-go/scale:go_default_library",
"//staging/src/k8s.io/client-go/scale/fake:go_default_library",
"//staging/src/k8s.io/client-go/testing:go_default_library",
],
)
@ -81,94 +47,48 @@ go_library(
name = "go_default_library",
srcs = [
"apply.go",
"autoscale.go",
"clusterrolebinding.go",
"conditions.go",
"configmap.go",
"deployment.go",
"doc.go",
"env_file.go",
"generate.go",
"history.go",
"interfaces.go",
"namespace.go",
"pdb.go",
"priorityclass.go",
"quota.go",
"rolebinding.go",
"rollback.go",
"rolling_updater.go",
"rollout_status.go",
"run.go",
"scale.go",
"secret.go",
"secret_for_docker_registry.go",
"secret_for_tls.go",
"service.go",
"service_basic.go",
"serviceaccount.go",
"sorter.go",
],
importpath = "k8s.io/kubernetes/pkg/kubectl",
deps = [
"//pkg/api/legacyscheme:go_default_library",
"//pkg/api/pod:go_default_library",
"//pkg/api/v1/pod:go_default_library",
"//pkg/apis/apps:go_default_library",
"//pkg/apis/core:go_default_library",
"//pkg/apis/core/v1:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/client/clientset_generated/internalclientset/typed/apps/internalversion:go_default_library",
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
"//pkg/client/clientset_generated/internalclientset/typed/extensions/internalversion:go_default_library",
"//pkg/controller/deployment/util:go_default_library",
"//pkg/credentialprovider:go_default_library",
"//pkg/kubectl/apps:go_default_library",
"//pkg/kubectl/describe/versioned:go_default_library",
"//pkg/kubectl/scheme:go_default_library",
"//pkg/kubectl/util:go_default_library",
"//pkg/kubectl/util/hash:go_default_library",
"//pkg/kubectl/util/deployment:go_default_library",
"//pkg/kubectl/util/podutils:go_default_library",
"//pkg/kubectl/util/slice:go_default_library",
"//pkg/printers:go_default_library",
"//pkg/printers/internalversion:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
"//vendor/k8s.io/api/apps/v1:go_default_library",
"//vendor/k8s.io/api/apps/v1beta1:go_default_library",
"//vendor/k8s.io/api/autoscaling/v1:go_default_library",
"//vendor/k8s.io/api/batch/v1:go_default_library",
"//vendor/k8s.io/api/batch/v1beta1:go_default_library",
"//vendor/k8s.io/api/batch/v2alpha1:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/api/policy/v1beta1:go_default_library",
"//vendor/k8s.io/api/rbac/v1:go_default_library",
"//vendor/k8s.io/api/rbac/v1beta1:go_default_library",
"//vendor/k8s.io/api/scheduling/v1alpha1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured: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/intstr:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/json:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/typed/apps/v1:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library",
"//vendor/k8s.io/client-go/scale:go_default_library",
"//vendor/k8s.io/client-go/util/integer:go_default_library",
"//vendor/k8s.io/client-go/util/jsonpath:go_default_library",
"//vendor/k8s.io/client-go/util/retry:go_default_library",
"//vendor/vbom.ml/util/sortorder:go_default_library",
"//staging/src/k8s.io/api/apps/v1:go_default_library",
"//staging/src/k8s.io/api/autoscaling/v1:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/api/extensions/v1beta1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/json:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/typed/apps/v1:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
"//staging/src/k8s.io/client-go/rest:go_default_library",
"//staging/src/k8s.io/client-go/scale:go_default_library",
"//staging/src/k8s.io/client-go/util/integer:go_default_library",
"//staging/src/k8s.io/client-go/util/retry:go_default_library",
],
)
@ -186,10 +106,11 @@ filegroup(
"//pkg/kubectl/apply:all-srcs",
"//pkg/kubectl/apps:all-srcs",
"//pkg/kubectl/cmd:all-srcs",
"//pkg/kubectl/describe:all-srcs",
"//pkg/kubectl/explain:all-srcs",
"//pkg/kubectl/genericclioptions:all-srcs",
"//pkg/kubectl/generate:all-srcs",
"//pkg/kubectl/generated:all-srcs",
"//pkg/kubectl/metricsutil:all-srcs",
"//pkg/kubectl/plugins:all-srcs",
"//pkg/kubectl/polymorphichelpers:all-srcs",
"//pkg/kubectl/proxy:all-srcs",
"//pkg/kubectl/scheme:all-srcs",

View File

@ -2,3 +2,6 @@ approvers:
- sig-cli-maintainers
reviewers:
- sig-cli
labels:
- area/kubectl
- sig/cli

View File

@ -135,7 +135,8 @@ func CreateApplyAnnotation(obj runtime.Object, codec runtime.Encoder) error {
return setOriginalConfiguration(obj, modified)
}
// Create the annotation used by kubectl apply only when createAnnotation is true
// CreateOrUpdateAnnotation creates the annotation used by
// kubectl apply only when createAnnotation is true
// Otherwise, only update the annotation when it already exists
func CreateOrUpdateAnnotation(createAnnotation bool, obj runtime.Object, codec runtime.Encoder) error {
if createAnnotation {

View File

@ -18,17 +18,18 @@ go_library(
deps = [
"//pkg/kubectl/apply:go_default_library",
"//pkg/kubectl/cmd/util/openapi:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/kube-openapi/pkg/util/proto:go_default_library",
],
)
go_test(
name = "go_default_xtest",
name = "go_default_test",
srcs = ["suite_test.go"],
data = [
"//api/openapi-spec:swagger-spec",
],
embed = [":go_default_library"],
deps = [
"//vendor/github.com/onsi/ginkgo:go_default_library",
"//vendor/github.com/onsi/ginkgo/config:go_default_library",

View File

@ -116,5 +116,5 @@ func (v *ElementBuildingVisitor) getItem(s proto.Schema, name string, data apply
},
}, nil
}
return nil, fmt.Errorf("unsupported type type %v", kind)
return nil, fmt.Errorf("unsupported type %v", kind)
}

View File

@ -16,7 +16,7 @@ go_library(
)
go_test(
name = "go_default_xtest",
name = "go_default_test",
srcs = [
"merge_conflict_test.go",
"merge_map_list_test.go",
@ -34,18 +34,18 @@ go_test(
":swagger-spec",
"//api/openapi-spec:swagger-spec",
],
embed = [":go_default_library"],
deps = [
":go_default_library",
"//pkg/kubectl/apply:go_default_library",
"//pkg/kubectl/apply/parse:go_default_library",
"//pkg/kubectl/cmd/util/openapi:go_default_library",
"//pkg/kubectl/cmd/util/openapi/testing:go_default_library",
"//vendor/github.com/ghodss/yaml:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//vendor/github.com/onsi/ginkgo:go_default_library",
"//vendor/github.com/onsi/ginkgo/config:go_default_library",
"//vendor/github.com/onsi/ginkgo/types:go_default_library",
"//vendor/github.com/onsi/gomega:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//vendor/sigs.k8s.io/yaml:go_default_library",
],
)

View File

@ -23,7 +23,7 @@ import (
"path/filepath"
"strings"
"github.com/ghodss/yaml"
"sigs.k8s.io/yaml"
"k8s.io/apimachinery/pkg/util/diff"
"k8s.io/kubernetes/pkg/kubectl/apply"

View File

@ -10,7 +10,7 @@ go_library(
name = "go_default_library",
srcs = ["kind_visitor.go"],
importpath = "k8s.io/kubernetes/pkg/kubectl/apps",
deps = ["//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library"],
deps = ["//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library"],
)
filegroup(
@ -27,13 +27,13 @@ filegroup(
)
go_test(
name = "go_default_xtest",
name = "go_default_test",
srcs = [
"apps_suite_test.go",
"kind_visitor_test.go",
],
embed = [":go_default_library"],
deps = [
":go_default_library",
"//vendor/github.com/onsi/ginkgo:go_default_library",
"//vendor/github.com/onsi/ginkgo/config:go_default_library",
"//vendor/github.com/onsi/ginkgo/types:go_default_library",

View File

@ -173,7 +173,7 @@ type TestKindVisitor struct {
var _ apps.KindVisitor = &TestKindVisitor{}
func (t *TestKindVisitor) Visit(kind apps.GroupKindElement) { t.visits[kind.Kind] += 1 }
func (t *TestKindVisitor) Visit(kind apps.GroupKindElement) { t.visits[kind.Kind]++ }
func (t *TestKindVisitor) VisitDaemonSet(kind apps.GroupKindElement) { t.Visit(kind) }
func (t *TestKindVisitor) VisitDeployment(kind apps.GroupKindElement) { t.Visit(kind) }

View File

@ -8,239 +8,78 @@ go_library(
name = "go_default_library",
srcs = [
"alpha.go",
"annotate.go",
"apiresources.go",
"apiversions.go",
"apply.go",
"apply_edit_last_applied.go",
"apply_set_last_applied.go",
"apply_view_last_applied.go",
"attach.go",
"autoscale.go",
"certificates.go",
"clusterinfo.go",
"clusterinfo_dump.go",
"cmd.go",
"completion.go",
"convert.go",
"cp.go",
"delete.go",
"delete_flags.go",
"describe.go",
"diff.go",
"drain.go",
"edit.go",
"exec.go",
"explain.go",
"expose.go",
"help.go",
"label.go",
"logs.go",
"options.go",
"patch.go",
"plugin.go",
"portforward.go",
"proxy.go",
"replace.go",
"rollingupdate.go",
"run.go",
"scale.go",
"taint.go",
"top.go",
"top_node.go",
"top_pod.go",
"version.go",
"profiling.go",
],
importpath = "k8s.io/kubernetes/pkg/kubectl/cmd",
visibility = [
"//build/visible_to:pkg_kubectl_cmd_CONSUMERS",
],
deps = [
"//pkg/api/legacyscheme:go_default_library",
"//pkg/apis/certificates:go_default_library",
"//pkg/apis/core:go_default_library",
"//pkg/apis/core/validation:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/clientset_generated/internalclientset/typed/batch/internalversion:go_default_library",
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
"//pkg/kubectl:go_default_library",
"//pkg/kubectl/apply/parse:go_default_library",
"//pkg/kubectl/apply/strategy:go_default_library",
"//pkg/kubectl/cmd/annotate:go_default_library",
"//pkg/kubectl/cmd/apiresources:go_default_library",
"//pkg/kubectl/cmd/apply:go_default_library",
"//pkg/kubectl/cmd/attach:go_default_library",
"//pkg/kubectl/cmd/auth:go_default_library",
"//pkg/kubectl/cmd/autoscale:go_default_library",
"//pkg/kubectl/cmd/certificates:go_default_library",
"//pkg/kubectl/cmd/clusterinfo:go_default_library",
"//pkg/kubectl/cmd/completion:go_default_library",
"//pkg/kubectl/cmd/config:go_default_library",
"//pkg/kubectl/cmd/convert:go_default_library",
"//pkg/kubectl/cmd/cp:go_default_library",
"//pkg/kubectl/cmd/create:go_default_library",
"//pkg/kubectl/cmd/delete:go_default_library",
"//pkg/kubectl/cmd/describe:go_default_library",
"//pkg/kubectl/cmd/diff:go_default_library",
"//pkg/kubectl/cmd/drain:go_default_library",
"//pkg/kubectl/cmd/edit:go_default_library",
"//pkg/kubectl/cmd/exec:go_default_library",
"//pkg/kubectl/cmd/explain:go_default_library",
"//pkg/kubectl/cmd/expose:go_default_library",
"//pkg/kubectl/cmd/get:go_default_library",
"//pkg/kubectl/cmd/label:go_default_library",
"//pkg/kubectl/cmd/logs:go_default_library",
"//pkg/kubectl/cmd/options:go_default_library",
"//pkg/kubectl/cmd/patch:go_default_library",
"//pkg/kubectl/cmd/plugin:go_default_library",
"//pkg/kubectl/cmd/portforward:go_default_library",
"//pkg/kubectl/cmd/proxy:go_default_library",
"//pkg/kubectl/cmd/replace:go_default_library",
"//pkg/kubectl/cmd/rollingupdate:go_default_library",
"//pkg/kubectl/cmd/rollout:go_default_library",
"//pkg/kubectl/cmd/scalejob:go_default_library",
"//pkg/kubectl/cmd/run:go_default_library",
"//pkg/kubectl/cmd/scale:go_default_library",
"//pkg/kubectl/cmd/set:go_default_library",
"//pkg/kubectl/cmd/templates:go_default_library",
"//pkg/kubectl/cmd/taint:go_default_library",
"//pkg/kubectl/cmd/top:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/cmd/util/editor:go_default_library",
"//pkg/kubectl/cmd/util/openapi:go_default_library",
"//pkg/kubectl/cmd/version:go_default_library",
"//pkg/kubectl/cmd/wait:go_default_library",
"//pkg/kubectl/explain: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/metricsutil:go_default_library",
"//pkg/kubectl/plugins:go_default_library",
"//pkg/kubectl/polymorphichelpers:go_default_library",
"//pkg/kubectl/proxy:go_default_library",
"//pkg/kubectl/scheme:go_default_library",
"//pkg/kubectl/util:go_default_library",
"//pkg/kubectl/util/i18n:go_default_library",
"//pkg/kubectl/util/term:go_default_library",
"//pkg/kubectl/validation:go_default_library",
"//pkg/printers:go_default_library",
"//pkg/util/interrupt:go_default_library",
"//pkg/util/taints:go_default_library",
"//pkg/version:go_default_library",
"//vendor/github.com/daviddengcn/go-colortext:go_default_library",
"//vendor/github.com/docker/distribution/reference:go_default_library",
"//vendor/github.com/docker/docker/pkg/term:go_default_library",
"//vendor/github.com/evanphx/json-patch:go_default_library",
"//vendor/github.com/ghodss/yaml:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/github.com/jonboulle/clockwork:go_default_library",
"//vendor/github.com/renstrom/dedent:go_default_library",
"//pkg/kubectl/util/templates:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/flag:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library",
"//staging/src/k8s.io/client-go/tools/clientcmd:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
"//vendor/k8s.io/api/apps/v1:go_default_library",
"//vendor/k8s.io/api/autoscaling/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/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructuredscheme: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/intstr:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/json:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/jsonmergepatch:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/mergepatch:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/yaml:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/version:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/flag:go_default_library",
"//vendor/k8s.io/client-go/discovery:go_default_library",
"//vendor/k8s.io/client-go/dynamic:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v1:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library",
"//vendor/k8s.io/client-go/scale:go_default_library",
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
"//vendor/k8s.io/client-go/tools/portforward:go_default_library",
"//vendor/k8s.io/client-go/tools/remotecommand:go_default_library",
"//vendor/k8s.io/client-go/transport/spdy:go_default_library",
"//vendor/k8s.io/kube-openapi/pkg/util/proto:go_default_library",
"//vendor/k8s.io/metrics/pkg/apis/metrics:go_default_library",
"//vendor/k8s.io/metrics/pkg/apis/metrics/v1beta1:go_default_library",
"//vendor/k8s.io/metrics/pkg/client/clientset_generated/clientset:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = [
"annotate_test.go",
"apply_test.go",
"attach_test.go",
"clusterinfo_dump_test.go",
"cmd_printing_test.go",
"cmd_test.go",
"convert_test.go",
"cp_test.go",
"delete_test.go",
"describe_test.go",
"diff_test.go",
"drain_test.go",
"edit_test.go",
"exec_test.go",
"expose_test.go",
"label_test.go",
"logs_test.go",
"patch_test.go",
"plugin_test.go",
"portforward_test.go",
"replace_test.go",
"rollingupdate_test.go",
"run_test.go",
"taint_test.go",
"top_node_test.go",
"top_pod_test.go",
"top_test.go",
],
srcs = ["cmd_test.go"],
data = [
"testdata",
"//api/openapi-spec:swagger-spec",
"//pkg/kubectl/cmd/plugin:testdata",
"//test/e2e/testing-manifests:all-srcs",
"//test/fixtures",
],
embed = [":go_default_library"],
deps = [
"//pkg/api/legacyscheme:go_default_library",
"//pkg/api/testapi:go_default_library",
"//pkg/api/testing:go_default_library",
"//pkg/apis/batch:go_default_library",
"//pkg/apis/core:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/kubectl/cmd/create:go_default_library",
"//pkg/kubectl/cmd/testing:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/cmd/util/openapi: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/plugins:go_default_library",
"//pkg/kubectl/polymorphichelpers:go_default_library",
"//pkg/kubectl/scheme:go_default_library",
"//pkg/kubectl/util/i18n:go_default_library",
"//pkg/kubectl/util/term:go_default_library",
"//pkg/printers:go_default_library",
"//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/gopkg.in/yaml.v2: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/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured: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/diff:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/strategicpatch/testing:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/version:go_default_library",
"//vendor/k8s.io/client-go/dynamic/fake:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library",
"//vendor/k8s.io/client-go/rest/fake:go_default_library",
"//vendor/k8s.io/client-go/testing:go_default_library",
"//vendor/k8s.io/client-go/tools/remotecommand:go_default_library",
"//vendor/k8s.io/metrics/pkg/apis/metrics/v1alpha1:go_default_library",
"//vendor/k8s.io/metrics/pkg/apis/metrics/v1beta1:go_default_library",
"//vendor/k8s.io/metrics/pkg/client/clientset_generated/clientset/fake:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
],
)
@ -254,17 +93,47 @@ filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//pkg/kubectl/cmd/annotate:all-srcs",
"//pkg/kubectl/cmd/apiresources:all-srcs",
"//pkg/kubectl/cmd/apply:all-srcs",
"//pkg/kubectl/cmd/attach:all-srcs",
"//pkg/kubectl/cmd/auth:all-srcs",
"//pkg/kubectl/cmd/autoscale:all-srcs",
"//pkg/kubectl/cmd/certificates:all-srcs",
"//pkg/kubectl/cmd/clusterinfo:all-srcs",
"//pkg/kubectl/cmd/completion:all-srcs",
"//pkg/kubectl/cmd/config:all-srcs",
"//pkg/kubectl/cmd/convert:all-srcs",
"//pkg/kubectl/cmd/cp:all-srcs",
"//pkg/kubectl/cmd/create:all-srcs",
"//pkg/kubectl/cmd/delete:all-srcs",
"//pkg/kubectl/cmd/describe:all-srcs",
"//pkg/kubectl/cmd/diff:all-srcs",
"//pkg/kubectl/cmd/drain:all-srcs",
"//pkg/kubectl/cmd/edit:all-srcs",
"//pkg/kubectl/cmd/exec:all-srcs",
"//pkg/kubectl/cmd/explain:all-srcs",
"//pkg/kubectl/cmd/expose:all-srcs",
"//pkg/kubectl/cmd/get:all-srcs",
"//pkg/kubectl/cmd/help:all-srcs",
"//pkg/kubectl/cmd/label:all-srcs",
"//pkg/kubectl/cmd/logs:all-srcs",
"//pkg/kubectl/cmd/options:all-srcs",
"//pkg/kubectl/cmd/patch:all-srcs",
"//pkg/kubectl/cmd/plugin:all-srcs",
"//pkg/kubectl/cmd/portforward:all-srcs",
"//pkg/kubectl/cmd/proxy:all-srcs",
"//pkg/kubectl/cmd/replace:all-srcs",
"//pkg/kubectl/cmd/rollingupdate:all-srcs",
"//pkg/kubectl/cmd/rollout:all-srcs",
"//pkg/kubectl/cmd/scalejob:all-srcs",
"//pkg/kubectl/cmd/run:all-srcs",
"//pkg/kubectl/cmd/scale:all-srcs",
"//pkg/kubectl/cmd/set:all-srcs",
"//pkg/kubectl/cmd/templates:all-srcs",
"//pkg/kubectl/cmd/testdata/edit:all-srcs",
"//pkg/kubectl/cmd/taint:all-srcs",
"//pkg/kubectl/cmd/testing:all-srcs",
"//pkg/kubectl/cmd/top:all-srcs",
"//pkg/kubectl/cmd/util:all-srcs",
"//pkg/kubectl/cmd/version:all-srcs",
"//pkg/kubectl/cmd/wait:all-srcs",
],
tags = ["automanaged"],

View File

@ -19,10 +19,10 @@ package cmd
import (
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
"k8s.io/cli-runtime/pkg/genericclioptions"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
// NewCmdAlpha creates a command that acts as an alternate root command for features in alpha
@ -36,7 +36,6 @@ func NewCmdAlpha(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.
// Alpha commands should be added here. As features graduate from alpha they should move
// from here to the CommandGroups defined by NewKubeletCommand() in cmd.go.
//cmd.AddCommand(NewCmdDebug(f, in, out, err))
cmd.AddCommand(NewCmdDiff(f, streams))
// NewKubeletCommand() will hide the alpha command if it has no subcommands. Overriding
// the help function ensures a reasonable message if someone types the hidden command anyway.

View File

@ -0,0 +1,60 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = ["annotate.go"],
importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/annotate",
visibility = ["//visibility:public"],
deps = [
"//pkg/kubectl:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/scheme:go_default_library",
"//pkg/kubectl/util/i18n:go_default_library",
"//pkg/kubectl/util/templates:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/json:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/printers:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/resource:go_default_library",
"//vendor/github.com/evanphx/json-patch:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["annotate_test.go"],
data = [
"//test/e2e/testing-manifests:all-srcs",
],
embed = [":go_default_library"],
deps = [
"//pkg/kubectl/cmd/testing:go_default_library",
"//pkg/kubectl/scheme:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/resource:go_default_library",
"//staging/src/k8s.io/client-go/rest/fake:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
package annotate
import (
"bytes"
@ -22,8 +22,8 @@ import (
"io"
jsonpatch "github.com/evanphx/json-patch"
"github.com/golang/glog"
"github.com/spf13/cobra"
"k8s.io/klog"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -31,14 +31,14 @@ import (
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/json"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/genericclioptions/printers"
"k8s.io/cli-runtime/pkg/genericclioptions/resource"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"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/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
// AnnotateOptions have the data required to perform the annotate operation
@ -123,11 +123,11 @@ func NewCmdAnnotate(parent string, f cmdutil.Factory, ioStreams genericclioption
o := NewAnnotateOptions(ioStreams)
cmd := &cobra.Command{
Use: "annotate [--overwrite] (-f FILENAME | TYPE NAME) KEY_1=VAL_1 ... KEY_N=VAL_N [--resource-version=version]",
Use: "annotate [--overwrite] (-f FILENAME | TYPE NAME) KEY_1=VAL_1 ... KEY_N=VAL_N [--resource-version=version]",
DisableFlagsInUseLine: true,
Short: i18n.T("Update the annotations on a resource"),
Long: annotateLong + "\n\n" + cmdutil.SuggestApiResources(parent),
Example: annotateExample,
Short: i18n.T("Update the annotations on a resource"),
Long: annotateLong + "\n\n" + cmdutil.SuggestApiResources(parent),
Example: annotateExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())
@ -245,7 +245,7 @@ func (o AnnotateOptions) RunAnnotate() error {
// only apply resource version locking on a single resource.
// we must perform this check after o.builder.Do() as
// []o.resources can not not accurately return the proper number
// []o.resources can not accurately return the proper number
// of resources when they are not passed in "resource/name" format.
if !singleItemImpliedResource && len(o.resourceVersion) > 0 {
return fmt.Errorf("--resource-version may only be used with a single resource")
@ -271,7 +271,7 @@ func (o AnnotateOptions) RunAnnotate() error {
return err
}
if err := o.Recorder.Record(info.Object); err != nil {
glog.V(4).Infof("error recording current command: %v", err)
klog.V(4).Infof("error recording current command: %v", err)
}
if err := o.updateAnnotations(obj); err != nil {
return err
@ -283,7 +283,7 @@ func (o AnnotateOptions) RunAnnotate() error {
patchBytes, err := jsonpatch.CreateMergePatch(oldData, newData)
createdPatch := err == nil
if err != nil {
glog.V(2).Infof("couldn't compute patch: %v", err)
klog.V(2).Infof("couldn't compute patch: %v", err)
}
mapping := info.ResourceMapping()
@ -294,7 +294,7 @@ func (o AnnotateOptions) RunAnnotate() error {
helper := resource.NewHelper(client, mapping)
if createdPatch {
outputObj, err = helper.Patch(namespace, name, types.MergePatchType, patchBytes)
outputObj, err = helper.Patch(namespace, name, types.MergePatchType, patchBytes, nil)
} else {
outputObj, err = helper.Replace(namespace, name, false, obj)
}

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
package annotate
import (
"net/http"
@ -26,10 +26,10 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/genericclioptions/resource"
"k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api/legacyscheme"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/scheme"
)
@ -421,7 +421,7 @@ func TestAnnotateErrors(t *testing.T) {
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
tf.ClientConfigVal = defaultClientConfig()
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
iostreams, _, bufOut, bufErr := genericclioptions.NewTestIOStreams()
cmd := NewCmdAnnotate("kubectl", tf, iostreams)
@ -450,22 +450,22 @@ func TestAnnotateErrors(t *testing.T) {
}
func TestAnnotateObject(t *testing.T) {
pods, _, _ := testData()
pods, _, _ := cmdtesting.TestData()
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
tf.UnstructuredClient = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Group: "testgroup", Version: "v1"},
NegotiatedSerializer: unstructuredSerializer,
NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch req.Method {
case "GET":
switch req.URL.Path {
case "/namespaces/test/pods/foo":
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods.Items[0])}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
@ -473,7 +473,7 @@ func TestAnnotateObject(t *testing.T) {
case "PATCH":
switch req.URL.Path {
case "/namespaces/test/pods/foo":
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods.Items[0])}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
@ -484,7 +484,7 @@ func TestAnnotateObject(t *testing.T) {
}
}),
}
tf.ClientConfigVal = defaultClientConfig()
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
iostreams, _, bufOut, _ := genericclioptions.NewTestIOStreams()
cmd := NewCmdAnnotate("kubectl", tf, iostreams)
@ -503,22 +503,22 @@ func TestAnnotateObject(t *testing.T) {
}
func TestAnnotateObjectFromFile(t *testing.T) {
pods, _, _ := testData()
pods, _, _ := cmdtesting.TestData()
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
tf.UnstructuredClient = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Group: "testgroup", Version: "v1"},
NegotiatedSerializer: unstructuredSerializer,
NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch req.Method {
case "GET":
switch req.URL.Path {
case "/namespaces/test/replicationcontrollers/cassandra":
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods.Items[0])}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
@ -526,7 +526,7 @@ func TestAnnotateObjectFromFile(t *testing.T) {
case "PATCH":
switch req.URL.Path {
case "/namespaces/test/replicationcontrollers/cassandra":
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods.Items[0])}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
@ -537,13 +537,13 @@ func TestAnnotateObjectFromFile(t *testing.T) {
}
}),
}
tf.ClientConfigVal = defaultClientConfig()
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
iostreams, _, bufOut, _ := genericclioptions.NewTestIOStreams()
cmd := NewCmdAnnotate("kubectl", tf, iostreams)
cmd.SetOutput(bufOut)
options := NewAnnotateOptions(iostreams)
options.Filenames = []string{"../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}
options.Filenames = []string{"../../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}
args := []string{"a=b", "c-"}
if err := options.Complete(tf, cmd, args); err != nil {
t.Fatalf("unexpected error: %v", err)
@ -562,19 +562,19 @@ func TestAnnotateLocal(t *testing.T) {
tf.UnstructuredClient = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Group: "testgroup", Version: "v1"},
NegotiatedSerializer: unstructuredSerializer,
NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req)
return nil, nil
}),
}
tf.ClientConfigVal = defaultClientConfig()
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
iostreams, _, _, _ := genericclioptions.NewTestIOStreams()
cmd := NewCmdAnnotate("kubectl", tf, iostreams)
options := NewAnnotateOptions(iostreams)
options.local = true
options.Filenames = []string{"../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}
options.Filenames = []string{"../../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}
args := []string{"a=b"}
if err := options.Complete(tf, cmd, args); err != nil {
t.Fatalf("unexpected error: %v", err)
@ -588,21 +588,21 @@ func TestAnnotateLocal(t *testing.T) {
}
func TestAnnotateMultipleObjects(t *testing.T) {
pods, _, _ := testData()
pods, _, _ := cmdtesting.TestData()
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
tf.UnstructuredClient = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Group: "testgroup", Version: "v1"},
NegotiatedSerializer: unstructuredSerializer,
NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch req.Method {
case "GET":
switch req.URL.Path {
case "/namespaces/test/pods":
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, pods)}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
@ -610,9 +610,9 @@ func TestAnnotateMultipleObjects(t *testing.T) {
case "PATCH":
switch req.URL.Path {
case "/namespaces/test/pods/foo":
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods.Items[0])}, nil
case "/namespaces/test/pods/bar":
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[1])}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods.Items[1])}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
@ -623,7 +623,7 @@ func TestAnnotateMultipleObjects(t *testing.T) {
}
}),
}
tf.ClientConfigVal = defaultClientConfig()
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
iostreams, _, _, _ := genericclioptions.NewTestIOStreams()
cmd := NewCmdAnnotate("kubectl", tf, iostreams)

View File

@ -0,0 +1,37 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"apiresources.go",
"apiversions.go",
],
importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/apiresources",
visibility = ["//visibility:public"],
deps = [
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/util/i18n:go_default_library",
"//pkg/kubectl/util/printers:go_default_library",
"//pkg/kubectl/util/templates:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library",
"//staging/src/k8s.io/client-go/discovery:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
package apiresources
import (
"fmt"
@ -27,10 +27,10 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
"k8s.io/cli-runtime/pkg/genericclioptions"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/printers"
"k8s.io/kubernetes/pkg/kubectl/util/printers"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
var (
@ -77,7 +77,8 @@ func NewAPIResourceOptions(ioStreams genericclioptions.IOStreams) *ApiResourcesO
}
}
func NewCmdApiResources(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
// NewCmdAPIResources creates the `api-resources` command
func NewCmdAPIResources(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
o := NewAPIResourceOptions(ioStreams)
cmd := &cobra.Command{
@ -86,7 +87,8 @@ func NewCmdApiResources(f cmdutil.Factory, ioStreams genericclioptions.IOStreams
Long: "Print the supported API resources on the server",
Example: apiresourcesExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Validate(cmd))
cmdutil.CheckErr(o.Complete(cmd, args))
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.RunApiResources(cmd, f))
},
}
@ -101,7 +103,7 @@ func NewCmdApiResources(f cmdutil.Factory, ioStreams genericclioptions.IOStreams
return cmd
}
func (o *ApiResourcesOptions) Validate(cmd *cobra.Command) error {
func (o *ApiResourcesOptions) Validate() error {
supportedOutputTypes := sets.NewString("", "wide", "name")
if !supportedOutputTypes.Has(o.Output) {
return fmt.Errorf("--output %v is not available", o.Output)
@ -109,6 +111,13 @@ func (o *ApiResourcesOptions) Validate(cmd *cobra.Command) error {
return nil
}
func (o *ApiResourcesOptions) Complete(cmd *cobra.Command, args []string) error {
if len(args) != 0 {
return cmdutil.UsageErrorf(cmd, "unexpected arguments: %v", args)
}
return nil
}
func (o *ApiResourcesOptions) RunApiResources(cmd *cobra.Command, f cmdutil.Factory) error {
w := printers.GetNewTabWriter(o.Out)
defer w.Flush()

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
package apiresources
import (
"fmt"
@ -23,11 +23,11 @@ import (
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/discovery"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
var (
@ -48,7 +48,8 @@ func NewApiVersionsOptions(ioStreams genericclioptions.IOStreams) *ApiVersionsOp
}
}
func NewCmdApiVersions(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
// NewCmdAPIVersions creates the `api-versions` command
func NewCmdAPIVersions(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
o := NewApiVersionsOptions(ioStreams)
cmd := &cobra.Command{
Use: "api-versions",
@ -56,14 +57,17 @@ func NewCmdApiVersions(f cmdutil.Factory, ioStreams genericclioptions.IOStreams)
Long: "Print the supported API versions on the server, in the form of \"group/version\"",
Example: apiversionsExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f))
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.RunApiVersions())
},
}
return cmd
}
func (o *ApiVersionsOptions) Complete(f cmdutil.Factory) error {
func (o *ApiVersionsOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
if len(args) != 0 {
return cmdutil.UsageErrorf(cmd, "unexpected arguments: %v", args)
}
var err error
o.discoveryClient, err = f.ToDiscoveryClient()
if err != nil {

93
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply/BUILD generated vendored Normal file
View File

@ -0,0 +1,93 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"apply.go",
"apply_edit_last_applied.go",
"apply_set_last_applied.go",
"apply_view_last_applied.go",
],
importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/apply",
visibility = ["//visibility:public"],
deps = [
"//pkg/kubectl:go_default_library",
"//pkg/kubectl/cmd/delete:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/cmd/util/editor:go_default_library",
"//pkg/kubectl/cmd/util/openapi:go_default_library",
"//pkg/kubectl/scheme:go_default_library",
"//pkg/kubectl/util/i18n:go_default_library",
"//pkg/kubectl/util/templates:go_default_library",
"//pkg/kubectl/validation:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/jsonmergepatch:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/mergepatch:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/printers:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/resource:go_default_library",
"//staging/src/k8s.io/client-go/discovery:go_default_library",
"//staging/src/k8s.io/client-go/dynamic:go_default_library",
"//vendor/github.com/jonboulle/clockwork:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/kube-openapi/pkg/util/proto:go_default_library",
"//vendor/sigs.k8s.io/yaml:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["apply_test.go"],
data = [
"//api/openapi-spec:swagger-spec",
"//test/fixtures",
],
embed = [":go_default_library"],
deps = [
"//pkg/kubectl/cmd/testing:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/cmd/util/openapi:go_default_library",
"//pkg/kubectl/scheme:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/api/extensions/v1beta1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/strategicpatch/testing:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/resource:go_default_library",
"//staging/src/k8s.io/client-go/dynamic/fake:go_default_library",
"//staging/src/k8s.io/client-go/rest:go_default_library",
"//staging/src/k8s.io/client-go/rest/fake:go_default_library",
"//staging/src/k8s.io/client-go/testing:go_default_library",
"//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -14,19 +14,18 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
package apply
import (
"encoding/json"
"fmt"
"io"
"strings"
"time"
"github.com/golang/glog"
"github.com/jonboulle/clockwork"
"github.com/spf13/cobra"
"k8s.io/api/core/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -39,18 +38,20 @@ import (
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/strategicpatch"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/genericclioptions/printers"
"k8s.io/cli-runtime/pkg/genericclioptions/resource"
"k8s.io/client-go/discovery"
"k8s.io/client-go/dynamic"
"k8s.io/klog"
oapi "k8s.io/kube-openapi/pkg/util/proto"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
"k8s.io/kubernetes/pkg/kubectl/cmd/delete"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi"
"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/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
"k8s.io/kubernetes/pkg/kubectl/validation"
)
@ -61,11 +62,12 @@ type ApplyOptions struct {
PrintFlags *genericclioptions.PrintFlags
ToPrinter func(string) (printers.ResourcePrinter, error)
DeleteFlags *DeleteFlags
DeleteOptions *DeleteOptions
DeleteFlags *delete.DeleteFlags
DeleteOptions *delete.DeleteOptions
Selector string
DryRun bool
ServerDryRun bool
Prune bool
PruneResources []pruneResource
cmdBaseName string
@ -75,11 +77,12 @@ type ApplyOptions struct {
PruneWhitelist []string
ShouldIncludeUninitialized bool
Validator validation.Schema
Builder *resource.Builder
Mapper meta.RESTMapper
DynamicClient dynamic.Interface
OpenAPISchema openapi.Resources
Validator validation.Schema
Builder *resource.Builder
Mapper meta.RESTMapper
DynamicClient dynamic.Interface
DiscoveryClient discovery.DiscoveryInterface
OpenAPISchema openapi.Resources
Namespace string
EnforceNamespace bool
@ -126,7 +129,7 @@ var (
func NewApplyOptions(ioStreams genericclioptions.IOStreams) *ApplyOptions {
return &ApplyOptions{
RecordFlags: genericclioptions.NewRecordFlags(),
DeleteFlags: NewDeleteFlags("that contains the configuration to apply"),
DeleteFlags: delete.NewDeleteFlags("that contains the configuration to apply"),
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
Overwrite: true,
@ -146,11 +149,11 @@ func NewCmdApply(baseName string, f cmdutil.Factory, ioStreams genericclioptions
o.cmdBaseName = baseName
cmd := &cobra.Command{
Use: "apply -f FILENAME",
Use: "apply -f FILENAME",
DisableFlagsInUseLine: true,
Short: i18n.T("Apply a configuration to a resource by filename or stdin"),
Long: applyLong,
Example: applyExample,
Short: i18n.T("Apply a configuration to a resource by filename or stdin"),
Long: applyLong,
Example: applyExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd))
cmdutil.CheckErr(validateArgs(cmd, args))
@ -172,6 +175,7 @@ func NewCmdApply(baseName string, f cmdutil.Factory, ioStreams genericclioptions
cmd.Flags().BoolVar(&o.All, "all", o.All, "Select all resources in the namespace of the specified resource types.")
cmd.Flags().StringArrayVar(&o.PruneWhitelist, "prune-whitelist", o.PruneWhitelist, "Overwrite the default whitelist with <group/version/kind> for --prune")
cmd.Flags().BoolVar(&o.OpenApiPatch, "openapi-patch", o.OpenApiPatch, "If true, use openapi to calculate diff when the openapi presents and the resource can be found in the openapi spec. Otherwise, fall back to use baked-in types.")
cmd.Flags().BoolVar(&o.ServerDryRun, "server-dry-run", o.ServerDryRun, "If true, request will be sent to server with dry-run flag, which means the modifications won't be persisted. This is an alpha feature and flag.")
cmdutil.AddDryRunFlag(cmd)
cmdutil.AddIncludeUninitializedFlag(cmd)
@ -186,13 +190,19 @@ func NewCmdApply(baseName string, f cmdutil.Factory, ioStreams genericclioptions
func (o *ApplyOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
o.DryRun = cmdutil.GetDryRunFlag(cmd)
if o.DryRun && o.ServerDryRun {
return fmt.Errorf("--dry-run and --server-dry-run can't be used together")
}
// allow for a success message operation to be specified at print time
o.ToPrinter = func(operation string) (printers.ResourcePrinter, error) {
o.PrintFlags.NamePrintFlags.Operation = operation
if o.DryRun {
o.PrintFlags.Complete("%s (dry run)")
}
if o.ServerDryRun {
o.PrintFlags.Complete("%s (server dry run)")
}
return o.PrintFlags.ToPrinter()
}
@ -203,6 +213,11 @@ func (o *ApplyOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
return err
}
o.DiscoveryClient, err = f.ToDiscoveryClient()
if err != nil {
return err
}
dynamicClient, err := f.DynamicClient()
if err != nil {
return err
@ -285,6 +300,11 @@ func (o *ApplyOptions) Run() error {
openapiSchema = o.OpenAPISchema
}
dryRunVerifier := &DryRunVerifier{
Finder: cmdutil.NewCRDFinder(cmdutil.CRDFromDynamic(o.DynamicClient)),
OpenAPIGetter: o.DiscoveryClient,
}
// include the uninitialized objects by default if --prune is true
// unless explicitly set --include-uninitialized=false
r := o.Builder.
@ -328,7 +348,7 @@ func (o *ApplyOptions) Run() error {
}
if err := o.Recorder.Record(info.Object); err != nil {
glog.V(4).Infof("error recording current command: %v", err)
klog.V(4).Infof("error recording current command: %v", err)
}
// Get the modified configuration of the object. Embed the result
@ -346,6 +366,13 @@ func (o *ApplyOptions) Run() error {
if !errors.IsNotFound(err) {
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%s\nfrom server for:", info.String()), info.Source, err)
}
// If server-dry-run is requested but the type doesn't support it, fail right away.
if o.ServerDryRun {
if err := dryRunVerifier.HasSupport(info.Mapping.GroupVersionKind); err != nil {
return err
}
}
// Create the resource if it doesn't exist
// First, update the annotation used by kubectl apply
if err := kubectl.CreateApplyAnnotation(info.Object, unstructured.UnstructuredJSONScheme); err != nil {
@ -354,18 +381,23 @@ func (o *ApplyOptions) Run() error {
if !o.DryRun {
// Then create the resource and skip the three-way merge
obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
options := metav1.CreateOptions{}
if o.ServerDryRun {
options.DryRun = []string{metav1.DryRunAll}
}
obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object, &options)
if err != nil {
return cmdutil.AddSourceToErr("creating", info.Source, err)
}
info.Refresh(obj, true)
metadata, err := meta.Accessor(info.Object)
if err != nil {
return err
}
visitedUids.Insert(string(metadata.GetUID()))
}
metadata, err := meta.Accessor(info.Object)
if err != nil {
return err
}
visitedUids.Insert(string(metadata.GetUID()))
count++
if printObject {
@ -380,40 +412,41 @@ func (o *ApplyOptions) Run() error {
return printer.PrintObj(info.Object, o.Out)
}
if !o.DryRun {
metadata, err := meta.Accessor(info.Object)
if err != nil {
return err
}
metadata, err := meta.Accessor(info.Object)
if err != nil {
return err
}
visitedUids.Insert(string(metadata.GetUID()))
if !o.DryRun {
annotationMap := metadata.GetAnnotations()
if _, ok := annotationMap[api.LastAppliedConfigAnnotation]; !ok {
if _, ok := annotationMap[corev1.LastAppliedConfigAnnotation]; !ok {
fmt.Fprintf(o.ErrOut, warningNoLastAppliedConfigAnnotation, o.cmdBaseName)
}
helper := resource.NewHelper(info.Client, info.Mapping)
patcher := &patcher{
mapping: info.Mapping,
helper: helper,
dynamicClient: o.DynamicClient,
overwrite: o.Overwrite,
backOff: clockwork.NewRealClock(),
force: o.DeleteOptions.ForceDeletion,
cascade: o.DeleteOptions.Cascade,
timeout: o.DeleteOptions.Timeout,
gracePeriod: o.DeleteOptions.GracePeriod,
openapiSchema: openapiSchema,
patcher := &Patcher{
Mapping: info.Mapping,
Helper: helper,
DynamicClient: o.DynamicClient,
Overwrite: o.Overwrite,
BackOff: clockwork.NewRealClock(),
Force: o.DeleteOptions.ForceDeletion,
Cascade: o.DeleteOptions.Cascade,
Timeout: o.DeleteOptions.Timeout,
GracePeriod: o.DeleteOptions.GracePeriod,
ServerDryRun: o.ServerDryRun,
OpenapiSchema: openapiSchema,
Retries: maxPatchRetry,
}
patchBytes, patchedObject, err := patcher.patch(info.Object, modified, info.Source, info.Namespace, info.Name, o.ErrOut)
patchBytes, patchedObject, err := patcher.Patch(info.Object, modified, info.Source, info.Namespace, info.Name, o.ErrOut)
if err != nil {
return cmdutil.AddSourceToErr(fmt.Sprintf("applying patch:\n%s\nto:\n%v\nfor:", patchBytes, info), info.Source, err)
}
info.Refresh(patchedObject, true)
visitedUids.Insert(string(metadata.GetUID()))
if string(patchBytes) == "{}" && !printObject {
count++
@ -454,7 +487,7 @@ func (o *ApplyOptions) Run() error {
objToPrint := objs[0]
if len(objs) > 1 {
list := &v1.List{
list := &corev1.List{
TypeMeta: metav1.TypeMeta{
Kind: "List",
APIVersion: "v1",
@ -483,9 +516,10 @@ func (o *ApplyOptions) Run() error {
labelSelector: o.Selector,
visitedUids: visitedUids,
cascade: o.DeleteOptions.Cascade,
dryRun: o.DryRun,
gracePeriod: o.DeleteOptions.GracePeriod,
cascade: o.DeleteOptions.Cascade,
dryRun: o.DryRun,
serverDryRun: o.ServerDryRun,
gracePeriod: o.DeleteOptions.GracePeriod,
toPrinter: o.ToPrinter,
@ -572,9 +606,10 @@ type pruner struct {
labelSelector string
fieldSelector string
cascade bool
dryRun bool
gracePeriod int
cascade bool
serverDryRun bool
dryRun bool
gracePeriod int
toPrinter func(string) (printers.ResourcePrinter, error)
@ -604,7 +639,7 @@ func (p *pruner) prune(namespace string, mapping *meta.RESTMapping, includeUnini
return err
}
annots := metadata.GetAnnotations()
if _, ok := annots[api.LastAppliedConfigAnnotation]; !ok {
if _, ok := annots[corev1.LastAppliedConfigAnnotation]; !ok {
// don't prune resources not created with apply
continue
}
@ -629,14 +664,17 @@ func (p *pruner) prune(namespace string, mapping *meta.RESTMapping, includeUnini
}
func (p *pruner) delete(namespace, name string, mapping *meta.RESTMapping) error {
return runDelete(namespace, name, mapping, p.dynamicClient, p.cascade, p.gracePeriod)
return runDelete(namespace, name, mapping, p.dynamicClient, p.cascade, p.gracePeriod, p.serverDryRun)
}
func runDelete(namespace, name string, mapping *meta.RESTMapping, c dynamic.Interface, cascade bool, gracePeriod int) error {
func runDelete(namespace, name string, mapping *meta.RESTMapping, c dynamic.Interface, cascade bool, gracePeriod int, serverDryRun bool) error {
options := &metav1.DeleteOptions{}
if gracePeriod >= 0 {
options = metav1.NewDeleteOptions(int64(gracePeriod))
}
if serverDryRun {
options.DryRun = []string{metav1.DryRunAll}
}
policy := metav1.DeletePropagationForeground
if !cascade {
policy = metav1.DeletePropagationOrphan
@ -645,27 +683,89 @@ func runDelete(namespace, name string, mapping *meta.RESTMapping, c dynamic.Inte
return c.Resource(mapping.Resource).Namespace(namespace).Delete(name, options)
}
func (p *patcher) delete(namespace, name string) error {
return runDelete(namespace, name, p.mapping, p.dynamicClient, p.cascade, p.gracePeriod)
func (p *Patcher) delete(namespace, name string) error {
return runDelete(namespace, name, p.Mapping, p.DynamicClient, p.Cascade, p.GracePeriod, p.ServerDryRun)
}
type patcher struct {
mapping *meta.RESTMapping
helper *resource.Helper
dynamicClient dynamic.Interface
type Patcher struct {
Mapping *meta.RESTMapping
Helper *resource.Helper
DynamicClient dynamic.Interface
overwrite bool
backOff clockwork.Clock
Overwrite bool
BackOff clockwork.Clock
force bool
cascade bool
timeout time.Duration
gracePeriod int
Force bool
Cascade bool
Timeout time.Duration
GracePeriod int
ServerDryRun bool
openapiSchema openapi.Resources
// If set, forces the patch against a specific resourceVersion
ResourceVersion *string
// Number of retries to make if the patch fails with conflict
Retries int
OpenapiSchema openapi.Resources
}
func (p *patcher) patchSimple(obj runtime.Object, modified []byte, source, namespace, name string, errOut io.Writer) ([]byte, runtime.Object, error) {
// DryRunVerifier verifies if a given group-version-kind supports DryRun
// against the current server. Sending dryRun requests to apiserver that
// don't support it will result in objects being unwillingly persisted.
//
// It reads the OpenAPI to see if the given GVK supports dryRun. If the
// GVK can not be found, we assume that CRDs will have the same level of
// support as "namespaces", and non-CRDs will not be supported. We
// delay the check for CRDs as much as possible though, since it
// requires an extra round-trip to the server.
type DryRunVerifier struct {
Finder cmdutil.CRDFinder
OpenAPIGetter discovery.OpenAPISchemaInterface
}
// HasSupport verifies if the given gvk supports DryRun. An error is
// returned if it doesn't.
func (v *DryRunVerifier) HasSupport(gvk schema.GroupVersionKind) error {
oapi, err := v.OpenAPIGetter.OpenAPISchema()
if err != nil {
return fmt.Errorf("failed to download openapi: %v", err)
}
supports, err := openapi.SupportsDryRun(oapi, gvk)
if err != nil {
// We assume that we couldn't find the type, then check for namespace:
supports, _ = openapi.SupportsDryRun(oapi, schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Namespace"})
// If namespace supports dryRun, then we will support dryRun for CRDs only.
if supports {
supports, err = v.Finder.HasCRD(gvk.GroupKind())
if err != nil {
return fmt.Errorf("failed to check CRD: %v", err)
}
}
}
if !supports {
return fmt.Errorf("%v doesn't support dry-run", gvk)
}
return nil
}
func addResourceVersion(patch []byte, rv string) ([]byte, error) {
var patchMap map[string]interface{}
err := json.Unmarshal(patch, &patchMap)
if err != nil {
return nil, err
}
u := unstructured.Unstructured{Object: patchMap}
a, err := meta.Accessor(&u)
if err != nil {
return nil, err
}
a.SetResourceVersion(rv)
return json.Marshal(patchMap)
}
func (p *Patcher) patchSimple(obj runtime.Object, modified []byte, source, namespace, name string, errOut io.Writer) ([]byte, runtime.Object, error) {
// Serialize the current configuration of the object from the server.
current, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
if err != nil {
@ -686,7 +786,7 @@ func (p *patcher) patchSimple(obj runtime.Object, modified []byte, source, names
// Create the versioned struct from the type defined in the restmapping
// (which is the API version we'll be submitting the patch to)
versionedObject, err := scheme.Scheme.New(p.mapping.GroupVersionKind)
versionedObject, err := scheme.Scheme.New(p.Mapping.GroupVersionKind)
switch {
case runtime.IsNotRegisteredError(err):
// fall back to generic JSON merge patch
@ -701,17 +801,17 @@ func (p *patcher) patchSimple(obj runtime.Object, modified []byte, source, names
return nil, nil, cmdutil.AddSourceToErr(fmt.Sprintf(createPatchErrFormat, original, modified, current), source, err)
}
case err != nil:
return nil, nil, cmdutil.AddSourceToErr(fmt.Sprintf("getting instance of versioned object for %v:", p.mapping.GroupVersionKind), source, err)
return nil, nil, cmdutil.AddSourceToErr(fmt.Sprintf("getting instance of versioned object for %v:", p.Mapping.GroupVersionKind), source, err)
case err == nil:
// Compute a three way strategic merge patch to send to server.
patchType = types.StrategicMergePatchType
// Try to use openapi first if the openapi spec is available and can successfully calculate the patch.
// Otherwise, fall back to baked-in types.
if p.openapiSchema != nil {
if schema = p.openapiSchema.LookupResource(p.mapping.GroupVersionKind); schema != nil {
if p.OpenapiSchema != nil {
if schema = p.OpenapiSchema.LookupResource(p.Mapping.GroupVersionKind); schema != nil {
lookupPatchMeta = strategicpatch.PatchMetaFromOpenAPI{Schema: schema}
if openapiPatch, err := strategicpatch.CreateThreeWayMergePatch(original, modified, current, lookupPatchMeta, p.overwrite); err != nil {
if openapiPatch, err := strategicpatch.CreateThreeWayMergePatch(original, modified, current, lookupPatchMeta, p.Overwrite); err != nil {
fmt.Fprintf(errOut, "warning: error calculating patch from openapi spec: %v\n", err)
} else {
patchType = types.StrategicMergePatchType
@ -725,7 +825,7 @@ func (p *patcher) patchSimple(obj runtime.Object, modified []byte, source, names
if err != nil {
return nil, nil, cmdutil.AddSourceToErr(fmt.Sprintf(createPatchErrFormat, original, modified, current), source, err)
}
patch, err = strategicpatch.CreateThreeWayMergePatch(original, modified, current, lookupPatchMeta, p.overwrite)
patch, err = strategicpatch.CreateThreeWayMergePatch(original, modified, current, lookupPatchMeta, p.Overwrite)
if err != nil {
return nil, nil, cmdutil.AddSourceToErr(fmt.Sprintf(createPatchErrFormat, original, modified, current), source, err)
}
@ -736,36 +836,51 @@ func (p *patcher) patchSimple(obj runtime.Object, modified []byte, source, names
return patch, obj, nil
}
patchedObj, err := p.helper.Patch(namespace, name, patchType, patch)
if p.ResourceVersion != nil {
patch, err = addResourceVersion(patch, *p.ResourceVersion)
if err != nil {
return nil, nil, cmdutil.AddSourceToErr("Failed to insert resourceVersion in patch", source, err)
}
}
options := metav1.UpdateOptions{}
if p.ServerDryRun {
options.DryRun = []string{metav1.DryRunAll}
}
patchedObj, err := p.Helper.Patch(namespace, name, patchType, patch, &options)
return patch, patchedObj, err
}
func (p *patcher) patch(current runtime.Object, modified []byte, source, namespace, name string, errOut io.Writer) ([]byte, runtime.Object, error) {
func (p *Patcher) Patch(current runtime.Object, modified []byte, source, namespace, name string, errOut io.Writer) ([]byte, runtime.Object, error) {
var getErr error
patchBytes, patchObject, err := p.patchSimple(current, modified, source, namespace, name, errOut)
for i := 1; i <= maxPatchRetry && errors.IsConflict(err); i++ {
if p.Retries == 0 {
p.Retries = maxPatchRetry
}
for i := 1; i <= p.Retries && errors.IsConflict(err); i++ {
if i > triesBeforeBackOff {
p.backOff.Sleep(backOffPeriod)
p.BackOff.Sleep(backOffPeriod)
}
current, getErr = p.helper.Get(namespace, name, false)
current, getErr = p.Helper.Get(namespace, name, false)
if getErr != nil {
return nil, nil, getErr
}
patchBytes, patchObject, err = p.patchSimple(current, modified, source, namespace, name, errOut)
}
if err != nil && errors.IsConflict(err) && p.force {
if err != nil && (errors.IsConflict(err) || errors.IsInvalid(err)) && p.Force {
patchBytes, patchObject, err = p.deleteAndCreate(current, modified, namespace, name)
}
return patchBytes, patchObject, err
}
func (p *patcher) deleteAndCreate(original runtime.Object, modified []byte, namespace, name string) ([]byte, runtime.Object, error) {
func (p *Patcher) deleteAndCreate(original runtime.Object, modified []byte, namespace, name string) ([]byte, runtime.Object, error) {
if err := p.delete(namespace, name); err != nil {
return modified, nil, err
}
// TODO: use wait
if err := wait.PollImmediate(1*time.Second, p.timeout, func() (bool, error) {
if _, err := p.helper.Get(namespace, name, false); !errors.IsNotFound(err) {
if err := wait.PollImmediate(1*time.Second, p.Timeout, func() (bool, error) {
if _, err := p.Helper.Get(namespace, name, false); !errors.IsNotFound(err) {
return false, err
}
return true, nil
@ -776,11 +891,15 @@ func (p *patcher) deleteAndCreate(original runtime.Object, modified []byte, name
if err != nil {
return modified, nil, err
}
createdObject, err := p.helper.Create(namespace, true, versionedObject)
options := metav1.CreateOptions{}
if p.ServerDryRun {
options.DryRun = []string{metav1.DryRunAll}
}
createdObject, err := p.Helper.Create(namespace, true, versionedObject, &options)
if err != nil {
// restore the original object if we fail to create the new one
// but still propagate and advertise error to user
recreated, recreateErr := p.helper.Create(namespace, true, original)
recreated, recreateErr := p.Helper.Create(namespace, true, original, &options)
if recreateErr != nil {
err = fmt.Errorf("An error occurred force-replacing the existing object with the newly provided one:\n\n%v.\n\nAdditionally, an error occurred attempting to restore the original object:\n\n%v\n", err, recreateErr)
} else {

View File

@ -14,15 +14,15 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
package apply
import (
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
"k8s.io/cli-runtime/pkg/genericclioptions"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/cmd/util/editor"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
var (
@ -59,11 +59,11 @@ func NewCmdApplyEditLastApplied(f cmdutil.Factory, ioStreams genericclioptions.I
o := editor.NewEditOptions(editor.ApplyEditMode, ioStreams)
cmd := &cobra.Command{
Use: "edit-last-applied (RESOURCE/NAME | -f FILENAME)",
Use: "edit-last-applied (RESOURCE/NAME | -f FILENAME)",
DisableFlagsInUseLine: true,
Short: "Edit latest last-applied-configuration annotations of a resource/object",
Long: applyEditLastAppliedLong,
Example: applyEditLastAppliedExample,
Short: "Edit latest last-applied-configuration annotations of a resource/object",
Long: applyEditLastAppliedLong,
Example: applyEditLastAppliedExample,
Run: func(cmd *cobra.Command, args []string) {
if err := o.Complete(f, args, cmd); err != nil {
cmdutil.CheckErr(err)
@ -76,10 +76,10 @@ func NewCmdApplyEditLastApplied(f cmdutil.Factory, ioStreams genericclioptions.I
// bind flag structs
o.RecordFlags.AddFlags(cmd)
o.PrintFlags.AddFlags(cmd)
usage := "to use to edit the resource"
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
cmd.Flags().StringVarP(&o.Output, "output", "o", o.Output, "Output format. One of: yaml|json.")
cmd.Flags().BoolVar(&o.WindowsLineEndings, "windows-line-endings", o.WindowsLineEndings,
"Defaults to the line ending native to your platform.")
cmdutil.AddIncludeUninitializedFlag(cmd)

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
package apply
import (
"bytes"
@ -26,15 +26,15 @@ import (
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/genericclioptions/printers"
"k8s.io/cli-runtime/pkg/genericclioptions/resource"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/cmd/util/editor"
"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/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
type SetLastAppliedOptions struct {
@ -91,11 +91,11 @@ func NewSetLastAppliedOptions(ioStreams genericclioptions.IOStreams) *SetLastApp
func NewCmdApplySetLastApplied(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
o := NewSetLastAppliedOptions(ioStreams)
cmd := &cobra.Command{
Use: "set-last-applied -f FILENAME",
Use: "set-last-applied -f FILENAME",
DisableFlagsInUseLine: true,
Short: i18n.T("Set the last-applied-configuration annotation on a live object to match the contents of a file."),
Long: applySetLastAppliedLong,
Example: applySetLastAppliedExample,
Short: i18n.T("Set the last-applied-configuration annotation on a live object to match the contents of a file."),
Long: applySetLastAppliedLong,
Example: applySetLastAppliedExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd))
cmdutil.CheckErr(o.Validate())
@ -200,7 +200,7 @@ func (o *SetLastAppliedOptions) RunSetLastApplied() error {
return err
}
helper := resource.NewHelper(client, mapping)
finalObj, err = helper.Patch(o.namespace, info.Name, patch.PatchType, patch.Patch)
finalObj, err = helper.Patch(o.namespace, info.Name, patch.PatchType, patch.Patch, nil)
if err != nil {
return err
}

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
package apply
import (
"bytes"
@ -29,32 +29,31 @@ import (
"strings"
"testing"
"github.com/googleapis/gnostic/OpenAPIv2"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
kubeerr "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
sptest "k8s.io/apimachinery/pkg/util/strategicpatch/testing"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/genericclioptions/resource"
dynamicfakeclient "k8s.io/client-go/dynamic/fake"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/rest/fake"
clienttesting "k8s.io/client-go/testing"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/api/testapi"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/extensions"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/scheme"
)
var (
fakeSchema = sptest.Fake{Path: filepath.Join("..", "..", "..", "api", "openapi-spec", "swagger.json")}
fakeSchema = sptest.Fake{Path: filepath.Join("..", "..", "..", "..", "api", "openapi-spec", "swagger.json")}
testingOpenAPISchemaFns = []func() (openapi.Resources, error){nil, AlwaysErrorOpenAPISchemaFn, openAPISchemaFn}
AlwaysErrorOpenAPISchemaFn = func() (openapi.Resources, error) {
return nil, errors.New("cannot get openapi spec")
@ -66,6 +65,7 @@ var (
}
return openapi.NewOpenAPIData(s)
}
codec = scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
)
func TestApplyExtraArgsFail(t *testing.T) {
@ -86,36 +86,41 @@ func validateApplyArgs(cmd *cobra.Command, args []string) error {
}
const (
filenameCM = "../../../test/fixtures/pkg/kubectl/cmd/apply/cm.yaml"
filenameRC = "../../../test/fixtures/pkg/kubectl/cmd/apply/rc.yaml"
filenameRCArgs = "../../../test/fixtures/pkg/kubectl/cmd/apply/rc-args.yaml"
filenameRCLastAppliedArgs = "../../../test/fixtures/pkg/kubectl/cmd/apply/rc-lastapplied-args.yaml"
filenameRCNoAnnotation = "../../../test/fixtures/pkg/kubectl/cmd/apply/rc-no-annotation.yaml"
filenameRCLASTAPPLIED = "../../../test/fixtures/pkg/kubectl/cmd/apply/rc-lastapplied.yaml"
filenameSVC = "../../../test/fixtures/pkg/kubectl/cmd/apply/service.yaml"
filenameRCSVC = "../../../test/fixtures/pkg/kubectl/cmd/apply/rc-service.yaml"
filenameNoExistRC = "../../../test/fixtures/pkg/kubectl/cmd/apply/rc-noexist.yaml"
filenameRCPatchTest = "../../../test/fixtures/pkg/kubectl/cmd/apply/patch.json"
dirName = "../../../test/fixtures/pkg/kubectl/cmd/apply/testdir"
filenameRCJSON = "../../../test/fixtures/pkg/kubectl/cmd/apply/rc.json"
filenameCM = "../../../../test/fixtures/pkg/kubectl/cmd/apply/cm.yaml"
filenameRC = "../../../../test/fixtures/pkg/kubectl/cmd/apply/rc.yaml"
filenameRCArgs = "../../../../test/fixtures/pkg/kubectl/cmd/apply/rc-args.yaml"
filenameRCLastAppliedArgs = "../../../../test/fixtures/pkg/kubectl/cmd/apply/rc-lastapplied-args.yaml"
filenameRCNoAnnotation = "../../../../test/fixtures/pkg/kubectl/cmd/apply/rc-no-annotation.yaml"
filenameRCLASTAPPLIED = "../../../../test/fixtures/pkg/kubectl/cmd/apply/rc-lastapplied.yaml"
filenameSVC = "../../../../test/fixtures/pkg/kubectl/cmd/apply/service.yaml"
filenameRCSVC = "../../../../test/fixtures/pkg/kubectl/cmd/apply/rc-service.yaml"
filenameNoExistRC = "../../../../test/fixtures/pkg/kubectl/cmd/apply/rc-noexist.yaml"
filenameRCPatchTest = "../../../../test/fixtures/pkg/kubectl/cmd/apply/patch.json"
dirName = "../../../../test/fixtures/pkg/kubectl/cmd/apply/testdir"
filenameRCJSON = "../../../../test/fixtures/pkg/kubectl/cmd/apply/rc.json"
filenameWidgetClientside = "../../../test/fixtures/pkg/kubectl/cmd/apply/widget-clientside.yaml"
filenameWidgetServerside = "../../../test/fixtures/pkg/kubectl/cmd/apply/widget-serverside.yaml"
filenameWidgetClientside = "../../../../test/fixtures/pkg/kubectl/cmd/apply/widget-clientside.yaml"
filenameWidgetServerside = "../../../../test/fixtures/pkg/kubectl/cmd/apply/widget-serverside.yaml"
)
func readConfigMapList(t *testing.T, filename string) []byte {
func readConfigMapList(t *testing.T, filename string) [][]byte {
data := readBytesFromFile(t, filename)
cmList := corev1.ConfigMapList{}
if err := runtime.DecodeInto(testapi.Default.Codec(), data, &cmList); err != nil {
if err := runtime.DecodeInto(codec, data, &cmList); err != nil {
t.Fatal(err)
}
cmListBytes, err := runtime.Encode(testapi.Default.Codec(), &cmList)
if err != nil {
t.Fatal(err)
var listCmBytes [][]byte
for _, cm := range cmList.Items {
cmBytes, err := runtime.Encode(codec, &cm)
if err != nil {
t.Fatal(err)
}
listCmBytes = append(listCmBytes, cmBytes)
}
return cmListBytes
return listCmBytes
}
func readBytesFromFile(t *testing.T, filename string) []byte {
@ -139,7 +144,7 @@ func readReplicationController(t *testing.T, filenameRC string) (string, []byte)
if err != nil {
t.Fatal(err)
}
rcBytes, err := runtime.Encode(testapi.Default.Codec(), rcObj)
rcBytes, err := runtime.Encode(codec, rcObj)
if err != nil {
t.Fatal(err)
}
@ -147,10 +152,10 @@ func readReplicationController(t *testing.T, filenameRC string) (string, []byte)
return metaAccessor.GetName(), rcBytes
}
func readReplicationControllerFromFile(t *testing.T, filename string) *api.ReplicationController {
func readReplicationControllerFromFile(t *testing.T, filename string) *corev1.ReplicationController {
data := readBytesFromFile(t, filename)
rc := api.ReplicationController{}
if err := runtime.DecodeInto(testapi.Default.Codec(), data, &rc); err != nil {
rc := corev1.ReplicationController{}
if err := runtime.DecodeInto(codec, data, &rc); err != nil {
t.Fatal(err)
}
@ -160,16 +165,16 @@ func readReplicationControllerFromFile(t *testing.T, filename string) *api.Repli
func readUnstructuredFromFile(t *testing.T, filename string) *unstructured.Unstructured {
data := readBytesFromFile(t, filename)
unst := unstructured.Unstructured{}
if err := runtime.DecodeInto(testapi.Default.Codec(), data, &unst); err != nil {
if err := runtime.DecodeInto(codec, data, &unst); err != nil {
t.Fatal(err)
}
return &unst
}
func readServiceFromFile(t *testing.T, filename string) *api.Service {
func readServiceFromFile(t *testing.T, filename string) *corev1.Service {
data := readBytesFromFile(t, filename)
svc := api.Service{}
if err := runtime.DecodeInto(testapi.Default.Codec(), data, &svc); err != nil {
svc := corev1.Service{}
if err := runtime.DecodeInto(codec, data, &svc); err != nil {
t.Fatal(err)
}
@ -191,7 +196,7 @@ func annotateRuntimeObject(t *testing.T, originalObj, currentObj runtime.Object,
originalLabels := originalAccessor.GetLabels()
originalLabels["DELETE_ME"] = "DELETE_ME"
originalAccessor.SetLabels(originalLabels)
original, err := runtime.Encode(unstructured.JSONFallbackEncoder{Encoder: testapi.Default.Codec()}, originalObj)
original, err := runtime.Encode(unstructured.JSONFallbackEncoder{Encoder: codec}, originalObj)
if err != nil {
t.Fatal(err)
}
@ -205,9 +210,9 @@ func annotateRuntimeObject(t *testing.T, originalObj, currentObj runtime.Object,
if currentAnnotations == nil {
currentAnnotations = make(map[string]string)
}
currentAnnotations[api.LastAppliedConfigAnnotation] = string(original)
currentAnnotations[corev1.LastAppliedConfigAnnotation] = string(original)
currentAccessor.SetAnnotations(currentAnnotations)
current, err := runtime.Encode(unstructured.JSONFallbackEncoder{Encoder: testapi.Default.Codec()}, currentObj)
current, err := runtime.Encode(unstructured.JSONFallbackEncoder{Encoder: codec}, currentObj)
if err != nil {
t.Fatal(err)
}
@ -245,7 +250,7 @@ func validatePatchApplication(t *testing.T, req *http.Request) {
}
annotationsMap := walkMapPath(t, patchMap, []string{"metadata", "annotations"})
if _, ok := annotationsMap[api.LastAppliedConfigAnnotation]; !ok {
if _, ok := annotationsMap[corev1.LastAppliedConfigAnnotation]; !ok {
t.Fatalf("patch does not contain annotation:\n%s\n", patch)
}
@ -269,30 +274,39 @@ func walkMapPath(t *testing.T, start map[string]interface{}, path []string) map[
}
func TestRunApplyPrintsValidObjectList(t *testing.T) {
initTestErrorHandler(t)
cmBytes := readConfigMapList(t, filenameCM)
cmdtesting.InitTestErrorHandler(t)
configMapList := readConfigMapList(t, filenameCM)
pathCM := "/namespaces/test/configmaps"
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
tf.UnstructuredClient = &fake.RESTClient{
NegotiatedSerializer: unstructuredSerializer,
NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case strings.HasPrefix(p, pathCM) && m != "GET":
pod := ioutil.NopCloser(bytes.NewReader(cmBytes))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: pod}, nil
case strings.HasPrefix(p, pathCM) && m != "PATCH":
pod := ioutil.NopCloser(bytes.NewReader(cmBytes))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: pod}, nil
case strings.HasPrefix(p, pathCM) && m == "GET":
fallthrough
case strings.HasPrefix(p, pathCM) && m == "PATCH":
var body io.ReadCloser
switch p {
case pathCM + "/test0":
body = ioutil.NopCloser(bytes.NewReader(configMapList[0]))
case pathCM + "/test1":
body = ioutil.NopCloser(bytes.NewReader(configMapList[1]))
default:
t.Errorf("unexpected request to %s", p)
}
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: body}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
}
}),
}
tf.ClientConfigVal = defaultClientConfig()
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
cmd := NewCmdApply("kubectl", tf, ioStreams)
@ -303,9 +317,19 @@ func TestRunApplyPrintsValidObjectList(t *testing.T) {
// ensure that returned list can be unmarshaled back into a configmap list
cmList := corev1.List{}
if err := runtime.DecodeInto(testapi.Default.Codec(), buf.Bytes(), &cmList); err != nil {
if err := runtime.DecodeInto(codec, buf.Bytes(), &cmList); err != nil {
t.Fatal(err)
}
if len(cmList.Items) != 2 {
t.Fatalf("Expected 2 items in the result; got %d", len(cmList.Items))
}
if !strings.Contains(string(cmList.Items[0].Raw), "key1") {
t.Fatalf("Did not get first ConfigMap at the first position")
}
if !strings.Contains(string(cmList.Items[1].Raw), "key2") {
t.Fatalf("Did not get second ConfigMap at the second position")
}
}
func TestRunApplyViewLastApplied(t *testing.T) {
@ -395,30 +419,28 @@ func TestRunApplyViewLastApplied(t *testing.T) {
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
tf.UnstructuredClient = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Version: "v1"},
NegotiatedSerializer: unstructuredSerializer,
NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == pathRC && m == "GET":
bodyRC := ioutil.NopCloser(bytes.NewReader(test.respBytes))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: bodyRC}, nil
case p == "/namespaces/test/replicationcontrollers" && m == "GET":
bodyRC := ioutil.NopCloser(bytes.NewReader(test.respBytes))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: bodyRC}, nil
case p == "/namespaces/test/replicationcontrollers/no-match" && m == "GET":
return &http.Response{StatusCode: 404, Header: defaultHeader(), Body: objBody(codec, &api.Pod{})}, nil
return &http.Response{StatusCode: 404, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &corev1.Pod{})}, nil
case p == "/api/v1/namespaces/test" && m == "GET":
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &api.Namespace{})}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &corev1.Namespace{})}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
}
}),
}
tf.ClientConfigVal = defaultClientConfig()
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
cmdutil.BehaviorOnFatal(func(str string, code int) {
if str != test.expectedErr {
@ -447,7 +469,7 @@ func TestRunApplyViewLastApplied(t *testing.T) {
}
func TestApplyObjectWithoutAnnotation(t *testing.T) {
initTestErrorHandler(t)
cmdtesting.InitTestErrorHandler(t)
nameRC, rcBytes := readReplicationController(t, filenameRC)
pathRC := "/namespaces/test/replicationcontrollers/" + nameRC
@ -455,22 +477,22 @@ func TestApplyObjectWithoutAnnotation(t *testing.T) {
defer tf.Cleanup()
tf.UnstructuredClient = &fake.RESTClient{
NegotiatedSerializer: unstructuredSerializer,
NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == pathRC && m == "GET":
bodyRC := ioutil.NopCloser(bytes.NewReader(rcBytes))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: bodyRC}, nil
case p == pathRC && m == "PATCH":
bodyRC := ioutil.NopCloser(bytes.NewReader(rcBytes))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: bodyRC}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
}
}),
}
tf.ClientConfigVal = defaultClientConfig()
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
ioStreams, _, buf, errBuf := genericclioptions.NewTestIOStreams()
cmd := NewCmdApply("kubectl", tf, ioStreams)
@ -490,7 +512,7 @@ func TestApplyObjectWithoutAnnotation(t *testing.T) {
}
func TestApplyObject(t *testing.T) {
initTestErrorHandler(t)
cmdtesting.InitTestErrorHandler(t)
nameRC, currentRC := readAndAnnotateReplicationController(t, filenameRC)
pathRC := "/namespaces/test/replicationcontrollers/" + nameRC
@ -500,16 +522,16 @@ func TestApplyObject(t *testing.T) {
defer tf.Cleanup()
tf.UnstructuredClient = &fake.RESTClient{
NegotiatedSerializer: unstructuredSerializer,
NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == pathRC && m == "GET":
bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: bodyRC}, nil
case p == pathRC && m == "PATCH":
validatePatchApplication(t, req)
bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: bodyRC}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
@ -517,7 +539,7 @@ func TestApplyObject(t *testing.T) {
}),
}
tf.OpenAPISchemaFunc = fn
tf.ClientConfigVal = defaultClientConfig()
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
ioStreams, _, buf, errBuf := genericclioptions.NewTestIOStreams()
cmd := NewCmdApply("kubectl", tf, ioStreams)
@ -538,7 +560,7 @@ func TestApplyObject(t *testing.T) {
}
func TestApplyObjectOutput(t *testing.T) {
initTestErrorHandler(t)
cmdtesting.InitTestErrorHandler(t)
nameRC, currentRC := readAndAnnotateReplicationController(t, filenameRC)
pathRC := "/namespaces/test/replicationcontrollers/" + nameRC
@ -564,16 +586,16 @@ func TestApplyObjectOutput(t *testing.T) {
defer tf.Cleanup()
tf.UnstructuredClient = &fake.RESTClient{
NegotiatedSerializer: unstructuredSerializer,
NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == pathRC && m == "GET":
bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: bodyRC}, nil
case p == pathRC && m == "PATCH":
validatePatchApplication(t, req)
bodyRC := ioutil.NopCloser(bytes.NewReader(postPatchData))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: bodyRC}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
@ -581,7 +603,7 @@ func TestApplyObjectOutput(t *testing.T) {
}),
}
tf.OpenAPISchemaFunc = fn
tf.ClientConfigVal = defaultClientConfig()
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
ioStreams, _, buf, errBuf := genericclioptions.NewTestIOStreams()
cmd := NewCmdApply("kubectl", tf, ioStreams)
@ -603,7 +625,7 @@ func TestApplyObjectOutput(t *testing.T) {
}
func TestApplyRetry(t *testing.T) {
initTestErrorHandler(t)
cmdtesting.InitTestErrorHandler(t)
nameRC, currentRC := readAndAnnotateReplicationController(t, filenameRC)
pathRC := "/namespaces/test/replicationcontrollers/" + nameRC
@ -616,25 +638,25 @@ func TestApplyRetry(t *testing.T) {
defer tf.Cleanup()
tf.UnstructuredClient = &fake.RESTClient{
NegotiatedSerializer: unstructuredSerializer,
NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == pathRC && m == "GET":
getCount++
bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: bodyRC}, nil
case p == pathRC && m == "PATCH":
if firstPatch {
firstPatch = false
statusErr := kubeerr.NewConflict(schema.GroupResource{Group: "", Resource: "rc"}, "test-rc", fmt.Errorf("the object has been modified. Please apply at first."))
bodyBytes, _ := json.Marshal(statusErr)
bodyErr := ioutil.NopCloser(bytes.NewReader(bodyBytes))
return &http.Response{StatusCode: http.StatusConflict, Header: defaultHeader(), Body: bodyErr}, nil
return &http.Response{StatusCode: http.StatusConflict, Header: cmdtesting.DefaultHeader(), Body: bodyErr}, nil
}
retry = true
validatePatchApplication(t, req)
bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: bodyRC}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
@ -642,7 +664,7 @@ func TestApplyRetry(t *testing.T) {
}),
}
tf.OpenAPISchemaFunc = fn
tf.ClientConfigVal = defaultClientConfig()
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
ioStreams, _, buf, errBuf := genericclioptions.NewTestIOStreams()
cmd := NewCmdApply("kubectl", tf, ioStreams)
@ -675,23 +697,23 @@ func TestApplyNonExistObject(t *testing.T) {
defer tf.Cleanup()
tf.UnstructuredClient = &fake.RESTClient{
NegotiatedSerializer: unstructuredSerializer,
NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == "/api/v1/namespaces/test" && m == "GET":
return &http.Response{StatusCode: 404, Header: defaultHeader(), Body: ioutil.NopCloser(bytes.NewReader(nil))}, nil
return &http.Response{StatusCode: 404, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader(nil))}, nil
case p == pathNameRC && m == "GET":
return &http.Response{StatusCode: 404, Header: defaultHeader(), Body: ioutil.NopCloser(bytes.NewReader(nil))}, nil
return &http.Response{StatusCode: 404, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader(nil))}, nil
case p == pathRC && m == "POST":
bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
return &http.Response{StatusCode: 201, Header: defaultHeader(), Body: bodyRC}, nil
return &http.Response{StatusCode: 201, Header: cmdtesting.DefaultHeader(), Body: bodyRC}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
}
}),
}
tf.ClientConfigVal = defaultClientConfig()
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
cmd := NewCmdApply("kubectl", tf, ioStreams)
@ -707,7 +729,7 @@ func TestApplyNonExistObject(t *testing.T) {
}
func TestApplyEmptyPatch(t *testing.T) {
initTestErrorHandler(t)
cmdtesting.InitTestErrorHandler(t)
nameRC, _ := readAndAnnotateReplicationController(t, filenameRC)
pathRC := "/namespaces/test/replicationcontrollers"
pathNameRC := pathRC + "/" + nameRC
@ -721,29 +743,29 @@ func TestApplyEmptyPatch(t *testing.T) {
tf.UnstructuredClient = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Version: "v1"},
NegotiatedSerializer: unstructuredSerializer,
NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == "/api/v1/namespaces/test" && m == "GET":
return &http.Response{StatusCode: 404, Header: defaultHeader(), Body: ioutil.NopCloser(bytes.NewReader(nil))}, nil
return &http.Response{StatusCode: 404, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader(nil))}, nil
case p == pathNameRC && m == "GET":
if body == nil {
return &http.Response{StatusCode: 404, Header: defaultHeader(), Body: ioutil.NopCloser(bytes.NewReader(nil))}, nil
return &http.Response{StatusCode: 404, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader(nil))}, nil
}
bodyRC := ioutil.NopCloser(bytes.NewReader(body))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: bodyRC}, nil
case p == pathRC && m == "POST":
body, _ = ioutil.ReadAll(req.Body)
verifyPost = true
bodyRC := ioutil.NopCloser(bytes.NewReader(body))
return &http.Response{StatusCode: 201, Header: defaultHeader(), Body: bodyRC}, nil
return &http.Response{StatusCode: 201, Header: cmdtesting.DefaultHeader(), Body: bodyRC}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
}
}),
}
tf.ClientConfigVal = defaultClientConfig()
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
// 1. apply non exist object
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
@ -793,23 +815,23 @@ func testApplyMultipleObjects(t *testing.T, asList bool) {
defer tf.Cleanup()
tf.UnstructuredClient = &fake.RESTClient{
NegotiatedSerializer: unstructuredSerializer,
NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == pathRC && m == "GET":
bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: bodyRC}, nil
case p == pathRC && m == "PATCH":
validatePatchApplication(t, req)
bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: bodyRC}, nil
case p == pathSVC && m == "GET":
bodySVC := ioutil.NopCloser(bytes.NewReader(currentSVC))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodySVC}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: bodySVC}, nil
case p == pathSVC && m == "PATCH":
validatePatchApplication(t, req)
bodySVC := ioutil.NopCloser(bytes.NewReader(currentSVC))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodySVC}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: bodySVC}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
@ -817,7 +839,7 @@ func testApplyMultipleObjects(t *testing.T, asList bool) {
}),
}
tf.OpenAPISchemaFunc = fn
tf.ClientConfigVal = defaultClientConfig()
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
ioStreams, _, buf, errBuf := genericclioptions.NewTestIOStreams()
cmd := NewCmdApply("kubectl", tf, ioStreams)
@ -848,17 +870,17 @@ func testApplyMultipleObjects(t *testing.T, asList bool) {
}
const (
filenameDeployObjServerside = "../../../test/fixtures/pkg/kubectl/cmd/apply/deploy-serverside.yaml"
filenameDeployObjClientside = "../../../test/fixtures/pkg/kubectl/cmd/apply/deploy-clientside.yaml"
filenameDeployObjServerside = "../../../../test/fixtures/pkg/kubectl/cmd/apply/deploy-serverside.yaml"
filenameDeployObjClientside = "../../../../test/fixtures/pkg/kubectl/cmd/apply/deploy-clientside.yaml"
)
func readDeploymentFromFile(t *testing.T, file string) []byte {
raw := readBytesFromFile(t, file)
obj := &extensions.Deployment{}
if err := runtime.DecodeInto(testapi.Extensions.Codec(), raw, obj); err != nil {
obj := &extensionsv1beta1.Deployment{}
if err := runtime.DecodeInto(codec, raw, obj); err != nil {
t.Fatal(err)
}
objJSON, err := runtime.Encode(testapi.Extensions.Codec(), obj)
objJSON, err := runtime.Encode(codec, obj)
if err != nil {
t.Fatal(err)
}
@ -866,7 +888,7 @@ func readDeploymentFromFile(t *testing.T, file string) []byte {
}
func TestApplyNULLPreservation(t *testing.T) {
initTestErrorHandler(t)
cmdtesting.InitTestErrorHandler(t)
deploymentName := "nginx-deployment"
deploymentPath := "/namespaces/test/deployments/" + deploymentName
@ -879,12 +901,12 @@ func TestApplyNULLPreservation(t *testing.T) {
defer tf.Cleanup()
tf.UnstructuredClient = &fake.RESTClient{
NegotiatedSerializer: unstructuredSerializer,
NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == deploymentPath && m == "GET":
body := ioutil.NopCloser(bytes.NewReader(deploymentBytes))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: body}, nil
case p == deploymentPath && m == "PATCH":
patch, err := ioutil.ReadAll(req.Body)
if err != nil {
@ -896,7 +918,7 @@ func TestApplyNULLPreservation(t *testing.T) {
t.Fatal(err)
}
annotationMap := walkMapPath(t, patchMap, []string{"metadata", "annotations"})
if _, ok := annotationMap[api.LastAppliedConfigAnnotation]; !ok {
if _, ok := annotationMap[corev1.LastAppliedConfigAnnotation]; !ok {
t.Fatalf("patch does not contain annotation:\n%s\n", patch)
}
strategy := walkMapPath(t, patchMap, []string{"spec", "strategy"})
@ -909,7 +931,7 @@ func TestApplyNULLPreservation(t *testing.T) {
// is ignoring the actual return object.
// TODO: Make this match actual server behavior by returning the patched object.
body := ioutil.NopCloser(bytes.NewReader(deploymentBytes))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: body}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
@ -917,7 +939,7 @@ func TestApplyNULLPreservation(t *testing.T) {
}),
}
tf.OpenAPISchemaFunc = fn
tf.ClientConfigVal = defaultClientConfig()
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
ioStreams, _, buf, errBuf := genericclioptions.NewTestIOStreams()
cmd := NewCmdApply("kubectl", tf, ioStreams)
@ -942,7 +964,7 @@ func TestApplyNULLPreservation(t *testing.T) {
// TestUnstructuredApply checks apply operations on an unstructured object
func TestUnstructuredApply(t *testing.T) {
initTestErrorHandler(t)
cmdtesting.InitTestErrorHandler(t)
name, curr := readAndAnnotateUnstructured(t, filenameWidgetClientside)
path := "/namespaces/test/widgets/" + name
@ -954,14 +976,14 @@ func TestUnstructuredApply(t *testing.T) {
defer tf.Cleanup()
tf.UnstructuredClient = &fake.RESTClient{
NegotiatedSerializer: unstructuredSerializer,
NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == path && m == "GET":
body := ioutil.NopCloser(bytes.NewReader(curr))
return &http.Response{
StatusCode: 200,
Header: defaultHeader(),
Header: cmdtesting.DefaultHeader(),
Body: body}, nil
case p == path && m == "PATCH":
contentType := req.Header.Get("Content-Type")
@ -974,7 +996,7 @@ func TestUnstructuredApply(t *testing.T) {
body := ioutil.NopCloser(bytes.NewReader(curr))
return &http.Response{
StatusCode: 200,
Header: defaultHeader(),
Header: cmdtesting.DefaultHeader(),
Body: body}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
@ -983,7 +1005,7 @@ func TestUnstructuredApply(t *testing.T) {
}),
}
tf.OpenAPISchemaFunc = fn
tf.ClientConfigVal = defaultClientConfig()
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
ioStreams, _, buf, errBuf := genericclioptions.NewTestIOStreams()
cmd := NewCmdApply("kubectl", tf, ioStreams)
@ -1007,10 +1029,10 @@ func TestUnstructuredApply(t *testing.T) {
// TestUnstructuredIdempotentApply checks repeated apply operation on an unstructured object
func TestUnstructuredIdempotentApply(t *testing.T) {
initTestErrorHandler(t)
cmdtesting.InitTestErrorHandler(t)
serversideObject := readUnstructuredFromFile(t, filenameWidgetServerside)
serversideData, err := runtime.Encode(unstructured.JSONFallbackEncoder{Encoder: testapi.Default.Codec()}, serversideObject)
serversideData, err := runtime.Encode(unstructured.JSONFallbackEncoder{Encoder: codec}, serversideObject)
if err != nil {
t.Fatal(err)
}
@ -1022,14 +1044,14 @@ func TestUnstructuredIdempotentApply(t *testing.T) {
defer tf.Cleanup()
tf.UnstructuredClient = &fake.RESTClient{
NegotiatedSerializer: unstructuredSerializer,
NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == path && m == "GET":
body := ioutil.NopCloser(bytes.NewReader(serversideData))
return &http.Response{
StatusCode: 200,
Header: defaultHeader(),
Header: cmdtesting.DefaultHeader(),
Body: body}, nil
case p == path && m == "PATCH":
// In idempotent updates, kubectl will resolve to an empty patch and not send anything to the server
@ -1048,7 +1070,7 @@ func TestUnstructuredIdempotentApply(t *testing.T) {
}),
}
tf.OpenAPISchemaFunc = fn
tf.ClientConfigVal = defaultClientConfig()
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
ioStreams, _, buf, errBuf := genericclioptions.NewTestIOStreams()
cmd := NewCmdApply("kubectl", tf, ioStreams)
@ -1068,7 +1090,7 @@ func TestUnstructuredIdempotentApply(t *testing.T) {
}
func TestRunApplySetLastApplied(t *testing.T) {
initTestErrorHandler(t)
cmdtesting.InitTestErrorHandler(t)
nameRC, currentRC := readAndAnnotateReplicationController(t, filenameRC)
pathRC := "/namespaces/test/replicationcontrollers/" + nameRC
@ -1122,34 +1144,32 @@ func TestRunApplySetLastApplied(t *testing.T) {
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
tf.UnstructuredClient = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Version: "v1"},
NegotiatedSerializer: unstructuredSerializer,
NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == pathRC && m == "GET":
bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: bodyRC}, nil
case p == noAnnotationPath && m == "GET":
bodyRC := ioutil.NopCloser(bytes.NewReader(noAnnotationRC))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: bodyRC}, nil
case p == noExistPath && m == "GET":
return &http.Response{StatusCode: 404, Header: defaultHeader(), Body: objBody(codec, &api.Pod{})}, nil
return &http.Response{StatusCode: 404, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &corev1.Pod{})}, nil
case p == pathRC && m == "PATCH":
checkPatchString(t, req)
bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: bodyRC}, nil
case p == "/api/v1/namespaces/test" && m == "GET":
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &api.Namespace{})}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &corev1.Namespace{})}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
}
}),
}
tf.ClientConfigVal = defaultClientConfig()
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
cmdutil.BehaviorOnFatal(func(str string, code int) {
if str != test.expectedErr {
@ -1184,7 +1204,7 @@ func checkPatchString(t *testing.T, req *http.Request) {
}
annotationsMap := walkMapPath(t, patchMap, []string{"metadata", "annotations"})
if _, ok := annotationsMap[api.LastAppliedConfigAnnotation]; !ok {
if _, ok := annotationsMap[corev1.LastAppliedConfigAnnotation]; !ok {
t.Fatalf("patch does not contain annotation:\n%s\n", patch)
}
@ -1195,7 +1215,7 @@ func checkPatchString(t *testing.T, req *http.Request) {
}
func TestForceApply(t *testing.T) {
initTestErrorHandler(t)
cmdtesting.InitTestErrorHandler(t)
scheme := runtime.NewScheme()
nameRC, currentRC := readAndAnnotateReplicationController(t, filenameRC)
pathRC := "/namespaces/test/replicationcontrollers/" + nameRC
@ -1217,22 +1237,22 @@ func TestForceApply(t *testing.T) {
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
tf.ClientConfigVal = defaultClientConfig()
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
tf.UnstructuredClient = &fake.RESTClient{
NegotiatedSerializer: unstructuredSerializer,
NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case strings.HasSuffix(p, pathRC) && m == "GET":
if deleted {
counts["getNotFound"]++
return &http.Response{StatusCode: 404, Header: defaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte{}))}, nil
return &http.Response{StatusCode: 404, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte{}))}, nil
}
counts["getOk"]++
var bodyRC io.ReadCloser
if isScaledDownToZero {
rcObj := readReplicationControllerFromFile(t, filenameRC)
rcObj.Spec.Replicas = 0
rcBytes, err := runtime.Encode(testapi.Default.Codec(), rcObj)
rcObj.Spec.Replicas = cmdtesting.Int32ptr(0)
rcBytes, err := runtime.Encode(codec, rcObj)
if err != nil {
t.Fatal(err)
}
@ -1240,7 +1260,7 @@ func TestForceApply(t *testing.T) {
} else {
bodyRC = ioutil.NopCloser(bytes.NewReader(currentRC))
}
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: bodyRC}, nil
case strings.HasSuffix(p, pathRCList) && m == "GET":
counts["getList"]++
rcObj := readUnstructuredFromFile(t, filenameRC)
@ -1251,19 +1271,19 @@ func TestForceApply(t *testing.T) {
},
Items: []unstructured.Unstructured{*rcObj},
}
listBytes, err := runtime.Encode(testapi.Default.Codec(), list)
listBytes, err := runtime.Encode(codec, list)
if err != nil {
t.Fatal(err)
}
bodyRCList := ioutil.NopCloser(bytes.NewReader(listBytes))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRCList}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: bodyRCList}, nil
case strings.HasSuffix(p, pathRC) && m == "PATCH":
counts["patch"]++
if counts["patch"] <= 6 {
statusErr := kubeerr.NewConflict(schema.GroupResource{Group: "", Resource: "rc"}, "test-rc", fmt.Errorf("the object has been modified. Please apply at first."))
bodyBytes, _ := json.Marshal(statusErr)
bodyErr := ioutil.NopCloser(bytes.NewReader(bodyBytes))
return &http.Response{StatusCode: http.StatusConflict, Header: defaultHeader(), Body: bodyErr}, nil
return &http.Response{StatusCode: http.StatusConflict, Header: cmdtesting.DefaultHeader(), Body: bodyErr}, nil
}
t.Fatalf("unexpected request: %#v after %v tries\n%#v", req.URL, counts["patch"], req)
return nil, nil
@ -1271,13 +1291,13 @@ func TestForceApply(t *testing.T) {
counts["put"]++
bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
isScaledDownToZero = true
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: bodyRC}, nil
case strings.HasSuffix(p, pathRCList) && m == "POST":
counts["post"]++
deleted = false
isScaledDownToZero = false
bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: bodyRC}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
@ -1322,3 +1342,75 @@ func TestForceApply(t *testing.T) {
})
}
}
func TestDryRunVerifier(t *testing.T) {
dryRunVerifier := DryRunVerifier{
Finder: cmdutil.NewCRDFinder(func() ([]schema.GroupKind, error) {
return []schema.GroupKind{
{
Group: "crd.com",
Kind: "MyCRD",
},
{
Group: "crd.com",
Kind: "MyNewCRD",
},
}, nil
}),
OpenAPIGetter: &fakeSchema,
}
err := dryRunVerifier.HasSupport(schema.GroupVersionKind{Group: "", Version: "v1", Kind: "NodeProxyOptions"})
if err == nil {
t.Fatalf("NodeProxyOptions doesn't support dry-run, yet no error found")
}
err = dryRunVerifier.HasSupport(schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"})
if err != nil {
t.Fatalf("Pod should support dry-run: %v", err)
}
err = dryRunVerifier.HasSupport(schema.GroupVersionKind{Group: "crd.com", Version: "v1", Kind: "MyCRD"})
if err != nil {
t.Fatalf("MyCRD should support dry-run: %v", err)
}
err = dryRunVerifier.HasSupport(schema.GroupVersionKind{Group: "crd.com", Version: "v1", Kind: "Random"})
if err == nil {
t.Fatalf("Random doesn't support dry-run, yet no error found")
}
}
type EmptyOpenAPI struct{}
func (EmptyOpenAPI) OpenAPISchema() (*openapi_v2.Document, error) {
return &openapi_v2.Document{}, nil
}
func TestDryRunVerifierNoOpenAPI(t *testing.T) {
dryRunVerifier := DryRunVerifier{
Finder: cmdutil.NewCRDFinder(func() ([]schema.GroupKind, error) {
return []schema.GroupKind{
{
Group: "crd.com",
Kind: "MyCRD",
},
{
Group: "crd.com",
Kind: "MyNewCRD",
},
}, nil
}),
OpenAPIGetter: EmptyOpenAPI{},
}
err := dryRunVerifier.HasSupport(schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"})
if err == nil {
t.Fatalf("Pod doesn't support dry-run, yet no error found")
}
err = dryRunVerifier.HasSupport(schema.GroupVersionKind{Group: "crd.com", Version: "v1", Kind: "MyCRD"})
if err == nil {
t.Fatalf("MyCRD doesn't support dry-run, yet no error found")
}
}

View File

@ -14,21 +14,21 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
package apply
import (
"bytes"
"encoding/json"
"fmt"
"github.com/ghodss/yaml"
"github.com/spf13/cobra"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/genericclioptions/resource"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
"sigs.k8s.io/yaml"
)
type ViewLastAppliedOptions struct {
@ -69,11 +69,11 @@ func NewCmdApplyViewLastApplied(f cmdutil.Factory, ioStreams genericclioptions.I
options := NewViewLastAppliedOptions(ioStreams)
cmd := &cobra.Command{
Use: "view-last-applied (TYPE [NAME | -l label] | TYPE/NAME | -f FILENAME)",
Use: "view-last-applied (TYPE [NAME | -l label] | TYPE/NAME | -f FILENAME)",
DisableFlagsInUseLine: true,
Short: i18n.T("View latest last-applied-configuration annotations of a resource/object"),
Long: applyViewLastAppliedLong,
Example: applyViewLastAppliedExample,
Short: i18n.T("View latest last-applied-configuration annotations of a resource/object"),
Long: applyViewLastAppliedLong,
Example: applyViewLastAppliedExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.Complete(cmd, f, args))
cmdutil.CheckErr(options.Validate(cmd))

58
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/attach/BUILD generated vendored Normal file
View File

@ -0,0 +1,58 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = ["attach.go"],
importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/attach",
visibility = ["//visibility:public"],
deps = [
"//pkg/kubectl/cmd/exec:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/polymorphichelpers:go_default_library",
"//pkg/kubectl/scheme:go_default_library",
"//pkg/kubectl/util/i18n:go_default_library",
"//pkg/kubectl/util/templates:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/resource:go_default_library",
"//staging/src/k8s.io/client-go/rest:go_default_library",
"//staging/src/k8s.io/client-go/tools/remotecommand:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["attach_test.go"],
embed = [":go_default_library"],
deps = [
"//pkg/kubectl/cmd/exec:go_default_library",
"//pkg/kubectl/cmd/testing:go_default_library",
"//pkg/kubectl/polymorphichelpers:go_default_library",
"//pkg/kubectl/scheme:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library",
"//staging/src/k8s.io/client-go/rest:go_default_library",
"//staging/src/k8s.io/client-go/rest/fake:go_default_library",
"//staging/src/k8s.io/client-go/tools/remotecommand:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -14,30 +14,29 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
package attach
import (
"errors"
"fmt"
"io"
"net/url"
"time"
"github.com/golang/glog"
"github.com/spf13/cobra"
"k8s.io/klog"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/genericclioptions/resource"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/remotecommand"
"k8s.io/kubernetes/pkg/api/legacyscheme"
api "k8s.io/kubernetes/pkg/apis/core"
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
"k8s.io/kubernetes/pkg/kubectl/cmd/exec"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/polymorphichelpers"
"k8s.io/kubernetes/pkg/kubectl/scheme"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
var (
@ -62,20 +61,47 @@ const (
defaultPodLogsTimeout = 20 * time.Second
)
func NewCmdAttach(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
o := &AttachOptions{
StreamOptions: StreamOptions{
// AttachOptions declare the arguments accepted by the Exec command
type AttachOptions struct {
exec.StreamOptions
// whether to disable use of standard error when streaming output from tty
DisableStderr bool
CommandName string
SuggestedCmdUsage string
Pod *corev1.Pod
AttachFunc func(*AttachOptions, *corev1.Container, bool, remotecommand.TerminalSizeQueue) func() error
Resources []string
Builder func() *resource.Builder
AttachablePodFn polymorphichelpers.AttachableLogsForObjectFunc
restClientGetter genericclioptions.RESTClientGetter
Attach RemoteAttach
GetPodTimeout time.Duration
Config *restclient.Config
}
func NewAttachOptions(streams genericclioptions.IOStreams) *AttachOptions {
return &AttachOptions{
StreamOptions: exec.StreamOptions{
IOStreams: streams,
},
Attach: &DefaultRemoteAttach{},
Attach: &DefaultRemoteAttach{},
AttachFunc: DefaultAttachFunc,
}
}
func NewCmdAttach(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
o := NewAttachOptions(streams)
cmd := &cobra.Command{
Use: "attach (POD | TYPE/NAME) -c CONTAINER",
Use: "attach (POD | TYPE/NAME) -c CONTAINER",
DisableFlagsInUseLine: true,
Short: i18n.T("Attach to a running container"),
Long: "Attach to a process that is already running inside an existing container.",
Example: attachExample,
Short: i18n.T("Attach to a running container"),
Long: "Attach to a process that is already running inside an existing container.",
Example: attachExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())
@ -94,6 +120,29 @@ type RemoteAttach interface {
Attach(method string, url *url.URL, config *restclient.Config, stdin io.Reader, stdout, stderr io.Writer, tty bool, terminalSizeQueue remotecommand.TerminalSizeQueue) error
}
func DefaultAttachFunc(o *AttachOptions, containerToAttach *corev1.Container, raw bool, sizeQueue remotecommand.TerminalSizeQueue) func() error {
return func() error {
restClient, err := restclient.RESTClientFor(o.Config)
if err != nil {
return err
}
req := restClient.Post().
Resource("pods").
Name(o.Pod.Name).
Namespace(o.Pod.Namespace).
SubResource("attach")
req.VersionedParams(&corev1.PodAttachOptions{
Container: containerToAttach.Name,
Stdin: o.Stdin,
Stdout: o.Out != nil,
Stderr: !o.DisableStderr,
TTY: raw,
}, scheme.ParameterCodec)
return o.Attach.Attach("POST", req.URL(), o.Config, o.In, o.Out, o.ErrOut, raw, sizeQueue)
}
}
// DefaultRemoteAttach is the standard implementation of attaching
type DefaultRemoteAttach struct{}
@ -111,63 +160,24 @@ func (*DefaultRemoteAttach) Attach(method string, url *url.URL, config *restclie
})
}
// AttachOptions declare the arguments accepted by the Exec command
type AttachOptions struct {
StreamOptions
CommandName string
SuggestedCmdUsage string
Pod *api.Pod
Attach RemoteAttach
PodClient coreclient.PodsGetter
GetPodTimeout time.Duration
Config *restclient.Config
}
// Complete verifies command line arguments and loads data from the command environment
func (p *AttachOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn []string) error {
if len(argsIn) == 0 {
return cmdutil.UsageErrorf(cmd, "at least 1 argument is required for attach")
}
if len(argsIn) > 2 {
return cmdutil.UsageErrorf(cmd, "expected POD, TYPE/NAME, or TYPE NAME, (at most 2 arguments) saw %d: %v", len(argsIn), argsIn)
}
namespace, _, err := f.ToRawKubeConfigLoader().Namespace()
func (o *AttachOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
var err error
o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()
if err != nil {
return err
}
p.GetPodTimeout, err = cmdutil.GetPodRunningTimeoutFlag(cmd)
o.AttachablePodFn = polymorphichelpers.AttachablePodForObjectFn
o.GetPodTimeout, err = cmdutil.GetPodRunningTimeoutFlag(cmd)
if err != nil {
return cmdutil.UsageErrorf(cmd, err.Error())
}
builder := f.NewBuilder().
WithScheme(legacyscheme.Scheme).
NamespaceParam(namespace).DefaultNamespace()
switch len(argsIn) {
case 1:
builder.ResourceNames("pods", argsIn[0])
case 2:
builder.ResourceNames(argsIn[0], argsIn[1])
}
obj, err := builder.Do().Object()
if err != nil {
return err
}
attachablePod, err := polymorphichelpers.AttachablePodForObjectFn(f, obj, p.GetPodTimeout)
if err != nil {
return err
}
p.PodName = attachablePod.Name
p.Namespace = namespace
o.Builder = f.NewBuilder
o.Resources = args
o.restClientGetter = f
fullCmdName := ""
cmdParent := cmd.Parent()
@ -175,82 +185,85 @@ func (p *AttachOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn [
fullCmdName = cmdParent.CommandPath()
}
if len(fullCmdName) > 0 && cmdutil.IsSiblingCommandExists(cmd, "describe") {
p.SuggestedCmdUsage = fmt.Sprintf("Use '%s describe pod/%s -n %s' to see all of the containers in this pod.", fullCmdName, p.PodName, p.Namespace)
o.SuggestedCmdUsage = fmt.Sprintf("Use '%s describe pod/%s -n %s' to see all of the containers in this pod.", fullCmdName, o.PodName, o.Namespace)
}
config, err := f.ToRESTConfig()
if err != nil {
return err
}
p.Config = config
o.Config = config
clientset, err := f.ClientSet()
if err != nil {
return err
}
p.PodClient = clientset.Core()
if p.CommandName == "" {
p.CommandName = cmd.CommandPath()
if o.CommandName == "" {
o.CommandName = cmd.CommandPath()
}
return nil
}
// Validate checks that the provided attach options are specified.
func (p *AttachOptions) Validate() error {
allErrs := []error{}
if len(p.PodName) == 0 {
allErrs = append(allErrs, errors.New("pod name must be specified"))
func (o *AttachOptions) Validate() error {
if len(o.Resources) == 0 {
return fmt.Errorf("at least 1 argument is required for attach")
}
if p.Out == nil || p.ErrOut == nil {
allErrs = append(allErrs, errors.New("both output and error output must be provided"))
if len(o.Resources) > 2 {
return fmt.Errorf("expected POD, TYPE/NAME, or TYPE NAME, (at most 2 arguments) saw %d: %v", len(o.Resources), o.Resources)
}
if p.Attach == nil || p.PodClient == nil || p.Config == nil {
allErrs = append(allErrs, errors.New("client, client config, and attach must be provided"))
if o.GetPodTimeout <= 0 {
return fmt.Errorf("--pod-running-timeout must be higher than zero")
}
return utilerrors.NewAggregate(allErrs)
return nil
}
// Run executes a validated remote execution against a pod.
func (p *AttachOptions) Run() error {
if p.Pod == nil {
pod, err := p.PodClient.Pods(p.Namespace).Get(p.PodName, metav1.GetOptions{})
func (o *AttachOptions) Run() error {
if o.Pod == nil {
b := o.Builder().
WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
NamespaceParam(o.Namespace).DefaultNamespace()
switch len(o.Resources) {
case 1:
b.ResourceNames("pods", o.Resources[0])
case 2:
b.ResourceNames(o.Resources[0], o.Resources[1])
}
obj, err := b.Do().Object()
if err != nil {
return err
}
if pod.Status.Phase == api.PodSucceeded || pod.Status.Phase == api.PodFailed {
return fmt.Errorf("cannot attach a container in a completed pod; current phase is %s", pod.Status.Phase)
o.Pod, err = o.findAttachablePod(obj)
if err != nil {
return err
}
p.Pod = pod
if o.Pod.Status.Phase == corev1.PodSucceeded || o.Pod.Status.Phase == corev1.PodFailed {
return fmt.Errorf("cannot attach a container in a completed pod; current phase is %s", o.Pod.Status.Phase)
}
// TODO: convert this to a clean "wait" behavior
}
pod := p.Pod
// check for TTY
containerToAttach, err := p.containerToAttachTo(pod)
containerToAttach, err := o.containerToAttachTo(o.Pod)
if err != nil {
return fmt.Errorf("cannot attach to the container: %v", err)
}
if p.TTY && !containerToAttach.TTY {
p.TTY = false
if p.ErrOut != nil {
fmt.Fprintf(p.ErrOut, "Unable to use a TTY - container %s did not allocate one\n", containerToAttach.Name)
if o.TTY && !containerToAttach.TTY {
o.TTY = false
if o.ErrOut != nil {
fmt.Fprintf(o.ErrOut, "Unable to use a TTY - container %s did not allocate one\n", containerToAttach.Name)
}
} else if !p.TTY && containerToAttach.TTY {
} else if !o.TTY && containerToAttach.TTY {
// the container was launched with a TTY, so we have to force a TTY here, otherwise you'll get
// an error "Unrecognized input header"
p.TTY = true
o.TTY = true
}
// ensure we can recover the terminal while attached
t := p.setupTTY()
// save p.Err so we can print the command prompt message below
stderr := p.ErrOut
t := o.SetupTTY()
var sizeQueue remotecommand.TerminalSizeQueue
if t.Raw {
@ -265,75 +278,61 @@ func (p *AttachOptions) Run() error {
sizeQueue = t.MonitorSize(&sizePlusOne, size)
}
// unset p.Err if it was previously set because both stdout and stderr go over p.Out when tty is
// true
p.ErrOut = nil
o.DisableStderr = true
}
fn := func() error {
restClient, err := restclient.RESTClientFor(p.Config)
if err != nil {
return err
}
// TODO: consider abstracting into a client invocation or client helper
req := restClient.Post().
Resource("pods").
Name(pod.Name).
Namespace(pod.Namespace).
SubResource("attach")
req.VersionedParams(&api.PodAttachOptions{
Container: containerToAttach.Name,
Stdin: p.Stdin,
Stdout: p.Out != nil,
Stderr: p.ErrOut != nil,
TTY: t.Raw,
}, legacyscheme.ParameterCodec)
return p.Attach.Attach("POST", req.URL(), p.Config, p.In, p.Out, p.ErrOut, t.Raw, sizeQueue)
if !o.Quiet {
fmt.Fprintln(o.ErrOut, "If you don't see a command prompt, try pressing enter.")
}
if !p.Quiet && stderr != nil {
fmt.Fprintln(stderr, "If you don't see a command prompt, try pressing enter.")
}
if err := t.Safe(fn); err != nil {
if err := t.Safe(o.AttachFunc(o, containerToAttach, t.Raw, sizeQueue)); err != nil {
return err
}
if p.Stdin && t.Raw && pod.Spec.RestartPolicy == api.RestartPolicyAlways {
fmt.Fprintf(p.Out, "Session ended, resume using '%s %s -c %s -i -t' command when the pod is running\n", p.CommandName, pod.Name, containerToAttach.Name)
if o.Stdin && t.Raw && o.Pod.Spec.RestartPolicy == corev1.RestartPolicyAlways {
fmt.Fprintf(o.Out, "Session ended, resume using '%s %s -c %s -i -t' command when the pod is running\n", o.CommandName, o.Pod.Name, containerToAttach.Name)
}
return nil
}
func (o *AttachOptions) findAttachablePod(obj runtime.Object) (*corev1.Pod, error) {
attachablePod, err := o.AttachablePodFn(o.restClientGetter, obj, o.GetPodTimeout)
if err != nil {
return nil, err
}
o.StreamOptions.PodName = attachablePod.Name
return attachablePod, nil
}
// containerToAttach returns a reference to the container to attach to, given
// by name or the first container if name is empty.
func (p *AttachOptions) containerToAttachTo(pod *api.Pod) (*api.Container, error) {
if len(p.ContainerName) > 0 {
func (o *AttachOptions) containerToAttachTo(pod *corev1.Pod) (*corev1.Container, error) {
if len(o.ContainerName) > 0 {
for i := range pod.Spec.Containers {
if pod.Spec.Containers[i].Name == p.ContainerName {
if pod.Spec.Containers[i].Name == o.ContainerName {
return &pod.Spec.Containers[i], nil
}
}
for i := range pod.Spec.InitContainers {
if pod.Spec.InitContainers[i].Name == p.ContainerName {
if pod.Spec.InitContainers[i].Name == o.ContainerName {
return &pod.Spec.InitContainers[i], nil
}
}
return nil, fmt.Errorf("container not found (%s)", p.ContainerName)
return nil, fmt.Errorf("container not found (%s)", o.ContainerName)
}
if len(p.SuggestedCmdUsage) > 0 {
fmt.Fprintf(p.ErrOut, "Defaulting container name to %s.\n", pod.Spec.Containers[0].Name)
fmt.Fprintf(p.ErrOut, "%s\n", p.SuggestedCmdUsage)
if len(o.SuggestedCmdUsage) > 0 {
fmt.Fprintf(o.ErrOut, "Defaulting container name to %s.\n", pod.Spec.Containers[0].Name)
fmt.Fprintf(o.ErrOut, "%s\n", o.SuggestedCmdUsage)
}
glog.V(4).Infof("defaulting container name to %s", pod.Spec.Containers[0].Name)
klog.V(4).Infof("defaulting container name to %s", pod.Spec.Containers[0].Name)
return &pod.Spec.Containers[0], nil
}
// GetContainerName returns the name of the container to attach to, with a fallback.
func (p *AttachOptions) GetContainerName(pod *api.Pod) (string, error) {
c, err := p.containerToAttachTo(pod)
func (o *AttachOptions) GetContainerName(pod *corev1.Pod) (string, error) {
c, err := o.containerToAttachTo(pod)
if err != nil {
return "", err
}

View File

@ -0,0 +1,422 @@
/*
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 attach
import (
"fmt"
"io"
"net/http"
"net/url"
"strings"
"testing"
"time"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/cli-runtime/pkg/genericclioptions"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/rest/fake"
"k8s.io/client-go/tools/remotecommand"
"k8s.io/kubernetes/pkg/kubectl/cmd/exec"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
"k8s.io/kubernetes/pkg/kubectl/polymorphichelpers"
"k8s.io/kubernetes/pkg/kubectl/scheme"
)
type fakeRemoteAttach struct {
method string
url *url.URL
err error
}
func (f *fakeRemoteAttach) Attach(method string, url *url.URL, config *restclient.Config, stdin io.Reader, stdout, stderr io.Writer, tty bool, terminalSizeQueue remotecommand.TerminalSizeQueue) error {
f.method = method
f.url = url
return f.err
}
func fakeAttachablePodFn(pod *corev1.Pod) polymorphichelpers.AttachableLogsForObjectFunc {
return func(getter genericclioptions.RESTClientGetter, obj runtime.Object, timeout time.Duration) (*corev1.Pod, error) {
return pod, nil
}
}
func TestPodAndContainerAttach(t *testing.T) {
tests := []struct {
name string
args []string
options *AttachOptions
expectError string
expectedPodName string
expectedContainerName string
obj *corev1.Pod
}{
{
name: "empty",
options: &AttachOptions{GetPodTimeout: 1},
expectError: "at least 1 argument is required",
},
{
name: "too many args",
options: &AttachOptions{GetPodTimeout: 2},
args: []string{"one", "two", "three"},
expectError: "at most 2 arguments",
},
{
name: "no container, no flags",
options: &AttachOptions{GetPodTimeout: defaultPodLogsTimeout},
args: []string{"foo"},
expectedPodName: "foo",
expectedContainerName: "bar",
obj: attachPod(),
},
{
name: "container in flag",
options: &AttachOptions{StreamOptions: exec.StreamOptions{ContainerName: "bar"}, GetPodTimeout: 10000000},
args: []string{"foo"},
expectedPodName: "foo",
expectedContainerName: "bar",
obj: attachPod(),
},
{
name: "init container in flag",
options: &AttachOptions{StreamOptions: exec.StreamOptions{ContainerName: "initfoo"}, GetPodTimeout: 30},
args: []string{"foo"},
expectedPodName: "foo",
expectedContainerName: "initfoo",
obj: attachPod(),
},
{
name: "non-existing container",
options: &AttachOptions{StreamOptions: exec.StreamOptions{ContainerName: "wrong"}, GetPodTimeout: 10},
args: []string{"foo"},
expectedPodName: "foo",
expectError: "container not found",
obj: attachPod(),
},
{
name: "no container, no flags, pods and name",
options: &AttachOptions{GetPodTimeout: 10000},
args: []string{"pods", "foo"},
expectedPodName: "foo",
expectedContainerName: "bar",
obj: attachPod(),
},
{
name: "invalid get pod timeout value",
options: &AttachOptions{GetPodTimeout: 0},
args: []string{"pod/foo"},
expectedPodName: "foo",
expectedContainerName: "bar",
obj: attachPod(),
expectError: "must be higher than zero",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
// setup opts to fetch our test pod
test.options.AttachablePodFn = fakeAttachablePodFn(test.obj)
test.options.Resources = test.args
if err := test.options.Validate(); err != nil {
if !strings.Contains(err.Error(), test.expectError) {
t.Errorf("unexpected error: expected %q, got %q", test.expectError, err)
}
return
}
pod, err := test.options.findAttachablePod(&corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "test-pod", Namespace: "test"},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "foobar",
},
},
},
})
if err != nil {
if !strings.Contains(err.Error(), test.expectError) {
t.Errorf("unexpected error: expected %q, got %q", err, test.expectError)
}
return
}
if pod.Name != test.expectedPodName {
t.Errorf("unexpected pod name: expected %q, got %q", test.expectedContainerName, pod.Name)
}
container, err := test.options.containerToAttachTo(attachPod())
if err != nil {
if !strings.Contains(err.Error(), test.expectError) {
t.Errorf("unexpected error: expected %q, got %q", err, test.expectError)
}
return
}
if container.Name != test.expectedContainerName {
t.Errorf("unexpected container name: expected %q, got %q", test.expectedContainerName, container.Name)
}
if test.options.PodName != test.expectedPodName {
t.Errorf("%s: expected: %s, got: %s", test.name, test.expectedPodName, test.options.PodName)
}
if len(test.expectError) > 0 {
t.Fatalf("expected error %q, but saw none", test.expectError)
}
})
}
}
func TestAttach(t *testing.T) {
version := "v1"
tests := []struct {
name, version, podPath, fetchPodPath, attachPath, container string
pod *corev1.Pod
remoteAttachErr bool
exepctedErr string
}{
{
name: "pod attach",
version: version,
podPath: "/api/" + version + "/namespaces/test/pods/foo",
fetchPodPath: "/namespaces/test/pods/foo",
attachPath: "/api/" + version + "/namespaces/test/pods/foo/attach",
pod: attachPod(),
container: "bar",
},
{
name: "pod attach error",
version: version,
podPath: "/api/" + version + "/namespaces/test/pods/foo",
fetchPodPath: "/namespaces/test/pods/foo",
attachPath: "/api/" + version + "/namespaces/test/pods/foo/attach",
pod: attachPod(),
remoteAttachErr: true,
container: "bar",
exepctedErr: "attach error",
},
{
name: "container not found error",
version: version,
podPath: "/api/" + version + "/namespaces/test/pods/foo",
fetchPodPath: "/namespaces/test/pods/foo",
attachPath: "/api/" + version + "/namespaces/test/pods/foo/attach",
pod: attachPod(),
container: "foo",
exepctedErr: "cannot attach to the container: container not found (foo)",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
ns := scheme.Codecs
tf.Client = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},
NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == test.podPath && m == "GET":
body := cmdtesting.ObjBody(codec, test.pod)
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: body}, nil
case p == test.fetchPodPath && m == "GET":
body := cmdtesting.ObjBody(codec, test.pod)
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: body}, nil
default:
t.Errorf("%s: unexpected request: %s %#v\n%#v", p, req.Method, req.URL, req)
return nil, fmt.Errorf("unexpected request")
}
}),
}
tf.ClientConfigVal = &restclient.Config{APIPath: "/api", ContentConfig: restclient.ContentConfig{NegotiatedSerializer: scheme.Codecs, GroupVersion: &schema.GroupVersion{Version: test.version}}}
remoteAttach := &fakeRemoteAttach{}
if test.remoteAttachErr {
remoteAttach.err = fmt.Errorf("attach error")
}
options := &AttachOptions{
StreamOptions: exec.StreamOptions{
ContainerName: test.container,
IOStreams: genericclioptions.NewTestIOStreamsDiscard(),
},
Attach: remoteAttach,
GetPodTimeout: 1000,
}
options.restClientGetter = tf
options.Namespace = "test"
options.Resources = []string{"foo"}
options.Builder = tf.NewBuilder
options.AttachablePodFn = fakeAttachablePodFn(test.pod)
options.AttachFunc = func(opts *AttachOptions, containerToAttach *corev1.Container, raw bool, sizeQueue remotecommand.TerminalSizeQueue) func() error {
return func() error {
u, err := url.Parse(fmt.Sprintf("%s?container=%s", test.attachPath, containerToAttach.Name))
if err != nil {
return err
}
return options.Attach.Attach("POST", u, nil, nil, nil, nil, raw, sizeQueue)
}
}
err := options.Run()
if test.exepctedErr != "" && err.Error() != test.exepctedErr {
t.Errorf("%s: Unexpected exec error: %v", test.name, err)
return
}
if test.exepctedErr == "" && err != nil {
t.Errorf("%s: Unexpected error: %v", test.name, err)
return
}
if test.exepctedErr != "" {
return
}
if remoteAttach.url.Path != test.attachPath {
t.Errorf("%s: Did not get expected path for exec request: %q %q", test.name, test.attachPath, remoteAttach.url.Path)
return
}
if remoteAttach.method != "POST" {
t.Errorf("%s: Did not get method for attach request: %s", test.name, remoteAttach.method)
}
if remoteAttach.url.Query().Get("container") != "bar" {
t.Errorf("%s: Did not have query parameters: %s", test.name, remoteAttach.url.Query())
}
})
}
}
func TestAttachWarnings(t *testing.T) {
version := "v1"
tests := []struct {
name, container, version, podPath, fetchPodPath, expectedErr string
pod *corev1.Pod
stdin, tty bool
}{
{
name: "fallback tty if not supported",
version: version,
podPath: "/api/" + version + "/namespaces/test/pods/foo",
fetchPodPath: "/namespaces/test/pods/foo",
pod: attachPod(),
stdin: true,
tty: true,
expectedErr: "Unable to use a TTY - container bar did not allocate one",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
streams, _, _, bufErr := genericclioptions.NewTestIOStreams()
codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
ns := scheme.Codecs
tf.Client = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},
NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == test.podPath && m == "GET":
body := cmdtesting.ObjBody(codec, test.pod)
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: body}, nil
case p == test.fetchPodPath && m == "GET":
body := cmdtesting.ObjBody(codec, test.pod)
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: body}, nil
default:
t.Errorf("%s: unexpected request: %s %#v\n%#v", p, req.Method, req.URL, req)
return nil, fmt.Errorf("unexpected request")
}
}),
}
tf.ClientConfigVal = &restclient.Config{APIPath: "/api", ContentConfig: restclient.ContentConfig{NegotiatedSerializer: scheme.Codecs, GroupVersion: &schema.GroupVersion{Version: test.version}}}
options := &AttachOptions{
StreamOptions: exec.StreamOptions{
Stdin: test.stdin,
TTY: test.tty,
ContainerName: test.container,
IOStreams: streams,
},
Attach: &fakeRemoteAttach{},
GetPodTimeout: 1000,
}
options.restClientGetter = tf
options.Namespace = "test"
options.Resources = []string{"foo"}
options.Builder = tf.NewBuilder
options.AttachablePodFn = fakeAttachablePodFn(test.pod)
options.AttachFunc = func(opts *AttachOptions, containerToAttach *corev1.Container, raw bool, sizeQueue remotecommand.TerminalSizeQueue) func() error {
return func() error {
u, err := url.Parse("http://foo.bar")
if err != nil {
return err
}
return options.Attach.Attach("POST", u, nil, nil, nil, nil, raw, sizeQueue)
}
}
if err := options.Run(); err != nil {
t.Fatal(err)
}
if test.stdin && test.tty {
if !test.pod.Spec.Containers[0].TTY {
if !strings.Contains(bufErr.String(), test.expectedErr) {
t.Errorf("%s: Expected TTY fallback warning for attach request: %s", test.name, bufErr.String())
return
}
}
}
})
}
}
func attachPod() *corev1.Pod {
return &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "10"},
Spec: corev1.PodSpec{
RestartPolicy: corev1.RestartPolicyAlways,
DNSPolicy: corev1.DNSClusterFirst,
Containers: []corev1.Container{
{
Name: "bar",
},
},
InitContainers: []corev1.Container{
{
Name: "initfoo",
},
},
},
Status: corev1.PodStatus{
Phase: corev1.PodRunning,
},
}
}

View File

@ -1,391 +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 cmd
import (
"fmt"
"io"
"net/http"
"net/url"
"strings"
"testing"
"time"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/rest/fake"
"k8s.io/client-go/tools/remotecommand"
"k8s.io/kubernetes/pkg/api/legacyscheme"
api "k8s.io/kubernetes/pkg/apis/core"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/scheme"
)
type fakeRemoteAttach struct {
method string
url *url.URL
err error
}
func (f *fakeRemoteAttach) Attach(method string, url *url.URL, config *restclient.Config, stdin io.Reader, stdout, stderr io.Writer, tty bool, terminalSizeQueue remotecommand.TerminalSizeQueue) error {
f.method = method
f.url = url
return f.err
}
func TestPodAndContainerAttach(t *testing.T) {
tests := []struct {
args []string
p *AttachOptions
name string
expectError bool
expectedPod string
expectedContainer string
timeout time.Duration
obj runtime.Object
}{
{
p: &AttachOptions{},
expectError: true,
name: "empty",
timeout: 1,
},
{
p: &AttachOptions{},
args: []string{"one", "two", "three"},
expectError: true,
name: "too many args",
timeout: 2,
},
{
p: &AttachOptions{},
args: []string{"foo"},
expectedPod: "foo",
name: "no container, no flags",
obj: attachPod(),
timeout: defaultPodLogsTimeout,
},
{
p: &AttachOptions{StreamOptions: StreamOptions{ContainerName: "bar"}},
args: []string{"foo"},
expectedPod: "foo",
expectedContainer: "bar",
name: "container in flag",
obj: attachPod(),
timeout: 10000000,
},
{
p: &AttachOptions{StreamOptions: StreamOptions{ContainerName: "initfoo"}},
args: []string{"foo"},
expectedPod: "foo",
expectedContainer: "initfoo",
name: "init container in flag",
obj: attachPod(),
timeout: 30,
},
{
p: &AttachOptions{StreamOptions: StreamOptions{ContainerName: "bar"}},
args: []string{"foo", "-c", "wrong"},
expectError: true,
name: "non-existing container in flag",
obj: attachPod(),
timeout: 10,
},
{
p: &AttachOptions{},
args: []string{"pods", "foo"},
expectedPod: "foo",
name: "no container, no flags, pods and name",
obj: attachPod(),
timeout: 10000,
},
{
p: &AttachOptions{},
args: []string{"pod/foo"},
expectedPod: "foo",
name: "no container, no flags, pod/name",
obj: attachPod(),
timeout: 1,
},
{
p: &AttachOptions{},
args: []string{"pod/foo"},
expectedPod: "foo",
name: "invalid get pod timeout value",
obj: attachPod(),
expectError: true,
timeout: 0,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
ns := legacyscheme.Codecs
tf.Client = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},
NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
if test.obj != nil {
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, test.obj)}, nil
}
return nil, nil
}),
}
tf.ClientConfigVal = defaultClientConfig()
cmd := &cobra.Command{}
options := test.p
cmdutil.AddPodRunningTimeoutFlag(cmd, test.timeout)
err := options.Complete(tf, cmd, test.args)
if test.expectError && err == nil {
t.Errorf("%s: unexpected non-error", test.name)
}
if !test.expectError && err != nil {
t.Errorf("%s: unexpected error: %v", test.name, err)
}
if err != nil {
return
}
if options.PodName != test.expectedPod {
t.Errorf("%s: expected: %s, got: %s", test.name, test.expectedPod, options.PodName)
}
if options.ContainerName != test.expectedContainer {
t.Errorf("%s: expected: %s, got: %s", test.name, test.expectedContainer, options.ContainerName)
}
})
}
}
func TestAttach(t *testing.T) {
version := "v1"
tests := []struct {
name, version, podPath, fetchPodPath, attachPath, container string
pod *api.Pod
remoteAttachErr bool
exepctedErr string
}{
{
name: "pod attach",
version: version,
podPath: "/api/" + version + "/namespaces/test/pods/foo",
fetchPodPath: "/namespaces/test/pods/foo",
attachPath: "/api/" + version + "/namespaces/test/pods/foo/attach",
pod: attachPod(),
container: "bar",
},
{
name: "pod attach error",
version: version,
podPath: "/api/" + version + "/namespaces/test/pods/foo",
fetchPodPath: "/namespaces/test/pods/foo",
attachPath: "/api/" + version + "/namespaces/test/pods/foo/attach",
pod: attachPod(),
remoteAttachErr: true,
container: "bar",
exepctedErr: "attach error",
},
{
name: "container not found error",
version: version,
podPath: "/api/" + version + "/namespaces/test/pods/foo",
fetchPodPath: "/namespaces/test/pods/foo",
attachPath: "/api/" + version + "/namespaces/test/pods/foo/attach",
pod: attachPod(),
container: "foo",
exepctedErr: "cannot attach to the container: container not found (foo)",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
ns := legacyscheme.Codecs
tf.Client = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},
NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == test.podPath && m == "GET":
body := objBody(codec, test.pod)
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil
case p == test.fetchPodPath && m == "GET":
body := objBody(codec, test.pod)
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil
default:
t.Errorf("%s: unexpected request: %s %#v\n%#v", p, req.Method, req.URL, req)
return nil, fmt.Errorf("unexpected request")
}
}),
}
tf.ClientConfigVal = &restclient.Config{APIPath: "/api", ContentConfig: restclient.ContentConfig{NegotiatedSerializer: legacyscheme.Codecs, GroupVersion: &schema.GroupVersion{Version: test.version}}}
remoteAttach := &fakeRemoteAttach{}
if test.remoteAttachErr {
remoteAttach.err = fmt.Errorf("attach error")
}
params := &AttachOptions{
StreamOptions: StreamOptions{
ContainerName: test.container,
IOStreams: genericclioptions.NewTestIOStreamsDiscard(),
},
Attach: remoteAttach,
GetPodTimeout: 1000,
}
cmd := &cobra.Command{}
cmdutil.AddPodRunningTimeoutFlag(cmd, 1000)
if err := params.Complete(tf, cmd, []string{"foo"}); err != nil {
t.Fatal(err)
}
err := params.Run()
if test.exepctedErr != "" && err.Error() != test.exepctedErr {
t.Errorf("%s: Unexpected exec error: %v", test.name, err)
return
}
if test.exepctedErr == "" && err != nil {
t.Errorf("%s: Unexpected error: %v", test.name, err)
return
}
if test.exepctedErr != "" {
return
}
if remoteAttach.url.Path != test.attachPath {
t.Errorf("%s: Did not get expected path for exec request: %q %q", test.name, test.attachPath, remoteAttach.url.Path)
return
}
if remoteAttach.method != "POST" {
t.Errorf("%s: Did not get method for attach request: %s", test.name, remoteAttach.method)
}
if remoteAttach.url.Query().Get("container") != "bar" {
t.Errorf("%s: Did not have query parameters: %s", test.name, remoteAttach.url.Query())
}
})
}
}
func TestAttachWarnings(t *testing.T) {
version := "v1"
tests := []struct {
name, container, version, podPath, fetchPodPath, expectedErr string
pod *api.Pod
stdin, tty bool
}{
{
name: "fallback tty if not supported",
version: version,
podPath: "/api/" + version + "/namespaces/test/pods/foo",
fetchPodPath: "/namespaces/test/pods/foo",
pod: attachPod(),
stdin: true,
tty: true,
expectedErr: "Unable to use a TTY - container bar did not allocate one",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
ns := legacyscheme.Codecs
tf.Client = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},
NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == test.podPath && m == "GET":
body := objBody(codec, test.pod)
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil
case p == test.fetchPodPath && m == "GET":
body := objBody(codec, test.pod)
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil
default:
t.Errorf("%s: unexpected request: %s %#v\n%#v", test.name, req.Method, req.URL, req)
return nil, fmt.Errorf("unexpected request")
}
}),
}
tf.ClientConfigVal = &restclient.Config{APIPath: "/api", ContentConfig: restclient.ContentConfig{NegotiatedSerializer: legacyscheme.Codecs, GroupVersion: &schema.GroupVersion{Version: test.version}}}
streams, _, _, bufErr := genericclioptions.NewTestIOStreams()
ex := &fakeRemoteAttach{}
params := &AttachOptions{
StreamOptions: StreamOptions{
ContainerName: test.container,
IOStreams: streams,
Stdin: test.stdin,
TTY: test.tty,
},
Attach: ex,
GetPodTimeout: 1000,
}
cmd := &cobra.Command{}
cmdutil.AddPodRunningTimeoutFlag(cmd, 1000)
if err := params.Complete(tf, cmd, []string{"foo"}); err != nil {
t.Fatal(err)
}
if err := params.Run(); err != nil {
t.Fatal(err)
}
if test.stdin && test.tty {
if !test.pod.Spec.Containers[0].TTY {
if !strings.Contains(bufErr.String(), test.expectedErr) {
t.Errorf("%s: Expected TTY fallback warning for attach request: %s", test.name, bufErr.String())
return
}
}
}
})
}
}
func attachPod() *api.Pod {
return &api.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "10"},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
Containers: []api.Container{
{
Name: "bar",
},
},
InitContainers: []api.Container{
{
Name: "initfoo",
},
},
},
Status: api.PodStatus{
Phase: api.PodRunning,
},
}
}

View File

@ -16,22 +16,24 @@ go_library(
"//build/visible_to:pkg_kubectl_cmd_auth_CONSUMERS",
],
deps = [
"//pkg/apis/authorization:go_default_library",
"//pkg/client/clientset_generated/internalclientset/typed/authorization/internalversion:go_default_library",
"//pkg/kubectl/cmd/templates:go_default_library",
"//pkg/kubectl/cmd/util: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/templates:go_default_library",
"//pkg/registry/rbac/reconciliation:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//staging/src/k8s.io/api/authorization/v1:go_default_library",
"//staging/src/k8s.io/api/rbac/v1:go_default_library",
"//staging/src/k8s.io/api/rbac/v1alpha1:go_default_library",
"//staging/src/k8s.io/api/rbac/v1beta1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/printers:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/resource:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/typed/authorization/v1:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/typed/rbac/v1:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/k8s.io/api/rbac/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/typed/rbac/v1:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
],
)
@ -55,10 +57,10 @@ go_test(
srcs = ["cani_test.go"],
embed = [":go_default_library"],
deps = [
"//pkg/api/legacyscheme:go_default_library",
"//pkg/kubectl/cmd/testing:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library",
"//vendor/k8s.io/client-go/rest/fake:go_default_library",
"//pkg/kubectl/scheme:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/client-go/rest:go_default_library",
"//staging/src/k8s.io/client-go/rest/fake:go_default_library",
],
)

7
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/auth/OWNERS generated vendored Normal file
View File

@ -0,0 +1,7 @@
approvers:
- sig-auth-authorizers-approvers
reviewers:
- sig-auth-authorizers-reviewers
labels:
- sig/auth

View File

@ -18,7 +18,7 @@ package auth
import (
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/cli-runtime/pkg/genericclioptions"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
)

View File

@ -24,14 +24,14 @@ import (
"strings"
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
authorizationv1 "k8s.io/api/authorization/v1"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime/schema"
authorizationapi "k8s.io/kubernetes/pkg/apis/authorization"
internalauthorizationclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/authorization/internalversion"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
"k8s.io/cli-runtime/pkg/genericclioptions"
authorizationv1client "k8s.io/client-go/kubernetes/typed/authorization/v1"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
// CanIOptions is the start of the data required to perform the operation. As new fields are added, add them here instead of
@ -40,7 +40,7 @@ type CanIOptions struct {
AllNamespaces bool
Quiet bool
Namespace string
SelfSARClient internalauthorizationclient.SelfSubjectAccessReviewsGetter
SelfSARClient authorizationv1client.SelfSubjectAccessReviewsGetter
Verb string
Resource schema.GroupVersionResource
@ -86,11 +86,11 @@ func NewCmdCanI(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.C
}
cmd := &cobra.Command{
Use: "can-i VERB [TYPE | TYPE/NAME | NONRESOURCEURL]",
Use: "can-i VERB [TYPE | TYPE/NAME | NONRESOURCEURL]",
DisableFlagsInUseLine: true,
Short: "Check whether an action is allowed",
Long: canILong,
Example: canIExample,
Short: "Check whether an action is allowed",
Long: canILong,
Example: canIExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, args))
cmdutil.CheckErr(o.Validate())
@ -138,11 +138,11 @@ func (o *CanIOptions) Complete(f cmdutil.Factory, args []string) error {
}
var err error
client, err := f.ClientSet()
client, err := f.KubernetesClientSet()
if err != nil {
return err
}
o.SelfSARClient = client.Authorization()
o.SelfSARClient = client.AuthorizationV1()
o.Namespace = ""
if !o.AllNamespaces {
@ -168,11 +168,11 @@ func (o *CanIOptions) Validate() error {
}
func (o *CanIOptions) RunAccessCheck() (bool, error) {
var sar *authorizationapi.SelfSubjectAccessReview
var sar *authorizationv1.SelfSubjectAccessReview
if o.NonResourceURL == "" {
sar = &authorizationapi.SelfSubjectAccessReview{
Spec: authorizationapi.SelfSubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{
sar = &authorizationv1.SelfSubjectAccessReview{
Spec: authorizationv1.SelfSubjectAccessReviewSpec{
ResourceAttributes: &authorizationv1.ResourceAttributes{
Namespace: o.Namespace,
Verb: o.Verb,
Group: o.Resource.Group,
@ -183,9 +183,9 @@ func (o *CanIOptions) RunAccessCheck() (bool, error) {
},
}
} else {
sar = &authorizationapi.SelfSubjectAccessReview{
Spec: authorizationapi.SelfSubjectAccessReviewSpec{
NonResourceAttributes: &authorizationapi.NonResourceAttributes{
sar = &authorizationv1.SelfSubjectAccessReview{
Spec: authorizationv1.SelfSubjectAccessReviewSpec{
NonResourceAttributes: &authorizationv1.NonResourceAttributes{
Verb: o.Verb,
Path: o.NonResourceURL,
},

View File

@ -27,8 +27,8 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api/legacyscheme"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
"k8s.io/kubernetes/pkg/kubectl/scheme"
)
func TestRunAccessCheck(t *testing.T) {
@ -124,7 +124,7 @@ func TestRunAccessCheck(t *testing.T) {
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
ns := legacyscheme.Codecs
ns := scheme.Codecs
tf.Client = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},

View File

@ -18,28 +18,33 @@ package auth
import (
"errors"
"fmt"
"github.com/golang/glog"
"github.com/spf13/cobra"
"k8s.io/klog"
rbacv1 "k8s.io/api/rbac/v1"
rbacv1alpha1 "k8s.io/api/rbac/v1alpha1"
rbacv1beta1 "k8s.io/api/rbac/v1beta1"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/genericclioptions/printers"
"k8s.io/cli-runtime/pkg/genericclioptions/resource"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
rbacv1client "k8s.io/client-go/kubernetes/typed/rbac/v1"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"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/templates"
"k8s.io/kubernetes/pkg/registry/rbac/reconciliation"
)
// ReconcileOptions is the start of the data required to perform the operation. As new fields are added, add them here instead of
// referencing the cmd.Flags()
type ReconcileOptions struct {
PrintFlags *genericclioptions.PrintFlags
FilenameOptions *resource.FilenameOptions
DryRun bool
PrintFlags *genericclioptions.PrintFlags
FilenameOptions *resource.FilenameOptions
DryRun bool
RemoveExtraPermissions bool
RemoveExtraSubjects bool
Visitor resource.Visitor
RBACClient rbacv1client.RbacV1Interface
@ -73,11 +78,11 @@ func NewCmdReconcile(f cmdutil.Factory, streams genericclioptions.IOStreams) *co
o := NewReconcileOptions(streams)
cmd := &cobra.Command{
Use: "reconcile -f FILENAME",
Use: "reconcile -f FILENAME",
DisableFlagsInUseLine: true,
Short: "Reconciles rules for RBAC Role, RoleBinding, ClusterRole, and ClusterRole binding objects",
Long: reconcileLong,
Example: reconcileExample,
Short: "Reconciles rules for RBAC Role, RoleBinding, ClusterRole, and ClusterRole binding objects",
Long: reconcileLong,
Example: reconcileExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(cmd, f, args))
cmdutil.CheckErr(o.Validate())
@ -89,6 +94,8 @@ func NewCmdReconcile(f cmdutil.Factory, streams genericclioptions.IOStreams) *co
cmdutil.AddFilenameOptionFlags(cmd, o.FilenameOptions, "identifying the resource to reconcile.")
cmd.Flags().BoolVar(&o.DryRun, "dry-run", o.DryRun, "If true, display results but do not submit changes")
cmd.Flags().BoolVar(&o.RemoveExtraPermissions, "remove-extra-permissions", o.RemoveExtraPermissions, "If true, removes extra permissions added to roles")
cmd.Flags().BoolVar(&o.RemoveExtraSubjects, "remove-extra-subjects", o.RemoveExtraSubjects, "If true, removes extra subjects added to rolebindings")
cmd.MarkFlagRequired("filename")
return cmd
@ -174,8 +181,8 @@ func (o *ReconcileOptions) RunReconcile() error {
case *rbacv1.Role:
reconcileOptions := reconciliation.ReconcileRoleOptions{
Confirm: !o.DryRun,
RemoveExtraPermissions: false,
Role: reconciliation.RoleRuleOwner{Role: t},
RemoveExtraPermissions: o.RemoveExtraPermissions,
Role: reconciliation.RoleRuleOwner{Role: t},
Client: reconciliation.RoleModifier{
NamespaceClient: o.NamespaceClient.Namespaces(),
Client: o.RBACClient,
@ -190,8 +197,8 @@ func (o *ReconcileOptions) RunReconcile() error {
case *rbacv1.ClusterRole:
reconcileOptions := reconciliation.ReconcileRoleOptions{
Confirm: !o.DryRun,
RemoveExtraPermissions: false,
Role: reconciliation.ClusterRoleRuleOwner{ClusterRole: t},
RemoveExtraPermissions: o.RemoveExtraPermissions,
Role: reconciliation.ClusterRoleRuleOwner{ClusterRole: t},
Client: reconciliation.ClusterRoleModifier{
Client: o.RBACClient.ClusterRoles(),
},
@ -205,7 +212,7 @@ func (o *ReconcileOptions) RunReconcile() error {
case *rbacv1.RoleBinding:
reconcileOptions := reconciliation.ReconcileRoleBindingOptions{
Confirm: !o.DryRun,
RemoveExtraSubjects: false,
RemoveExtraSubjects: o.RemoveExtraSubjects,
RoleBinding: reconciliation.RoleBindingAdapter{RoleBinding: t},
Client: reconciliation.RoleBindingClientAdapter{
Client: o.RBACClient,
@ -221,7 +228,7 @@ func (o *ReconcileOptions) RunReconcile() error {
case *rbacv1.ClusterRoleBinding:
reconcileOptions := reconciliation.ReconcileRoleBindingOptions{
Confirm: !o.DryRun,
RemoveExtraSubjects: false,
RemoveExtraSubjects: o.RemoveExtraSubjects,
RoleBinding: reconciliation.ClusterRoleBindingAdapter{ClusterRoleBinding: t},
Client: reconciliation.ClusterRoleBindingClientAdapter{
Client: o.RBACClient.ClusterRoleBindings(),
@ -233,8 +240,18 @@ func (o *ReconcileOptions) RunReconcile() error {
}
o.PrintObject(result.RoleBinding.GetObject(), o.Out)
case *rbacv1beta1.Role,
*rbacv1beta1.RoleBinding,
*rbacv1beta1.ClusterRole,
*rbacv1beta1.ClusterRoleBinding,
*rbacv1alpha1.Role,
*rbacv1alpha1.RoleBinding,
*rbacv1alpha1.ClusterRole,
*rbacv1alpha1.ClusterRoleBinding:
return fmt.Errorf("only rbac.authorization.k8s.io/v1 is supported: not %T", t)
default:
glog.V(1).Infof("skipping %#v", info.Object.GetObjectKind())
klog.V(1).Infof("skipping %#v", info.Object.GetObjectKind())
// skip ignored resources
}

View File

@ -0,0 +1,40 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["autoscale.go"],
importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/autoscale",
visibility = ["//visibility:public"],
deps = [
"//pkg/kubectl:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/generate:go_default_library",
"//pkg/kubectl/generate/versioned:go_default_library",
"//pkg/kubectl/polymorphichelpers:go_default_library",
"//pkg/kubectl/scheme:go_default_library",
"//pkg/kubectl/util/i18n:go_default_library",
"//pkg/kubectl/util/templates:go_default_library",
"//staging/src/k8s.io/api/autoscaling/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/printers:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/resource:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/typed/autoscaling/v1:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -14,34 +14,35 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
package autoscale
import (
"fmt"
"github.com/golang/glog"
"github.com/spf13/cobra"
"k8s.io/klog"
autoscalingv1 "k8s.io/api/autoscaling/v1"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/genericclioptions/printers"
"k8s.io/cli-runtime/pkg/genericclioptions/resource"
autoscalingv1client "k8s.io/client-go/kubernetes/typed/autoscaling/v1"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"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/generate"
generateversioned "k8s.io/kubernetes/pkg/kubectl/generate/versioned"
"k8s.io/kubernetes/pkg/kubectl/polymorphichelpers"
"k8s.io/kubernetes/pkg/kubectl/scheme"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
var (
autoscaleLong = templates.LongDesc(i18n.T(`
Creates an autoscaler that automatically chooses and sets the number of pods that run in a kubernetes cluster.
Looks up a Deployment, ReplicaSet, or ReplicationController by name and creates an autoscaler that uses the given resource as a reference.
Looks up a Deployment, ReplicaSet, StatefulSet, or ReplicationController by name and creates an autoscaler that uses the given resource as a reference.
An autoscaler can automatically increase or decrease number of pods deployed within the system as needed.`))
autoscaleExample = templates.Examples(i18n.T(`
@ -74,7 +75,7 @@ type AutoscaleOptions struct {
dryRun bool
builder *resource.Builder
canBeAutoscaled polymorphichelpers.CanBeAutoscaledFunc
generatorFunc func(string, *meta.RESTMapping) (kubectl.StructuredGenerator, error)
generatorFunc func(string, *meta.RESTMapping) (generate.StructuredGenerator, error)
HPAClient autoscalingv1client.HorizontalPodAutoscalersGetter
@ -98,11 +99,11 @@ func NewCmdAutoscale(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *
validArgs := []string{"deployment", "replicaset", "replicationcontroller"}
cmd := &cobra.Command{
Use: "autoscale (-f FILENAME | TYPE NAME | TYPE/NAME) [--min=MINPODS] --max=MAXPODS [--cpu-percent=CPU]",
Use: "autoscale (-f FILENAME | TYPE NAME | TYPE/NAME) [--min=MINPODS] --max=MAXPODS [--cpu-percent=CPU]",
DisableFlagsInUseLine: true,
Short: i18n.T("Auto-scale a Deployment, ReplicaSet, or ReplicationController"),
Long: autoscaleLong,
Example: autoscaleExample,
Short: i18n.T("Auto-scale a Deployment, ReplicaSet, or ReplicationController"),
Long: autoscaleLong,
Example: autoscaleExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())
@ -115,7 +116,7 @@ func NewCmdAutoscale(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *
o.RecordFlags.AddFlags(cmd)
o.PrintFlags.AddFlags(cmd)
cmd.Flags().StringVar(&o.Generator, "generator", cmdutil.HorizontalPodAutoscalerV1GeneratorName, i18n.T("The name of the API generator to use. Currently there is only 1 generator."))
cmd.Flags().StringVar(&o.Generator, "generator", generateversioned.HorizontalPodAutoscalerV1GeneratorName, i18n.T("The name of the API generator to use. Currently there is only 1 generator."))
cmd.Flags().Int32Var(&o.Min, "min", -1, "The lower limit for the number of pods that can be set by the autoscaler. If it's not specified or negative, the server will apply a default value.")
cmd.Flags().Int32Var(&o.Max, "max", -1, "The upper limit for the number of pods that can be set by the autoscaler. Required.")
cmd.MarkFlagRequired("max")
@ -148,17 +149,17 @@ func (o *AutoscaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
o.HPAClient = kubeClient.AutoscalingV1()
// get the generator
o.generatorFunc = func(name string, mapping *meta.RESTMapping) (kubectl.StructuredGenerator, error) {
o.generatorFunc = func(name string, mapping *meta.RESTMapping) (generate.StructuredGenerator, error) {
switch o.Generator {
case cmdutil.HorizontalPodAutoscalerV1GeneratorName:
return &kubectl.HorizontalPodAutoscalerGeneratorV1{
case generateversioned.HorizontalPodAutoscalerV1GeneratorName:
return &generateversioned.HorizontalPodAutoscalerGeneratorV1{
Name: name,
MinReplicas: o.Min,
MaxReplicas: o.Max,
CPUPercent: o.CpuPercent,
ScaleRefName: name,
ScaleRefKind: mapping.GroupVersionKind.Kind,
ScaleRefApiVersion: mapping.GroupVersionKind.GroupVersion().String(),
ScaleRefAPIVersion: mapping.GroupVersionKind.GroupVersion().String(),
}, nil
default:
return nil, cmdutil.UsageErrorf(cmd, "Generator %s not supported. ", o.Generator)
@ -195,7 +196,7 @@ func (o *AutoscaleOptions) Validate() error {
func (o *AutoscaleOptions) Run() error {
r := o.builder.
WithScheme(legacyscheme.Scheme).
WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
ContinueOnError().
NamespaceParam(o.namespace).DefaultNamespace().
FilenameParam(o.enforceNamespace, o.FilenameOptions).
@ -233,7 +234,7 @@ func (o *AutoscaleOptions) Run() error {
}
if err := o.Recorder.Record(hpa); err != nil {
glog.V(4).Infof("error recording current command: %v", err)
klog.V(4).Infof("error recording current command: %v", err)
}
if o.dryRun {
@ -246,7 +247,7 @@ func (o *AutoscaleOptions) Run() error {
return printer.PrintObj(hpa, o.Out)
}
if err := kubectl.CreateOrUpdateAnnotation(o.createAnnotation, hpa, cmdutil.InternalVersionJSONEncoder()); err != nil {
if err := kubectl.CreateOrUpdateAnnotation(o.createAnnotation, hpa, scheme.DefaultJSONEncoder()); err != nil {
return err
}

View File

@ -0,0 +1,37 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["certificates.go"],
importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/certificates",
visibility = ["//visibility:public"],
deps = [
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/scheme:go_default_library",
"//pkg/kubectl/util/i18n:go_default_library",
"//pkg/kubectl/util/templates:go_default_library",
"//staging/src/k8s.io/api/certificates/v1beta1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/printers:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/resource:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/typed/certificates/v1beta1:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -14,35 +14,34 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
package certificates
import (
"fmt"
"io"
"github.com/spf13/cobra"
certificatesv1beta1 "k8s.io/api/certificates/v1beta1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/apis/certificates"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/genericclioptions/printers"
"k8s.io/cli-runtime/pkg/genericclioptions/resource"
certificatesv1beta1client "k8s.io/client-go/kubernetes/typed/certificates/v1beta1"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"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/i18n"
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
func NewCmdCertificate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
cmd := &cobra.Command{
Use: "certificate SUBCOMMAND",
Use: "certificate SUBCOMMAND",
DisableFlagsInUseLine: true,
Short: i18n.T("Modify certificate resources."),
Long: "Modify certificate resources.",
Short: i18n.T("Modify certificate resources."),
Long: "Modify certificate resources.",
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
@ -63,7 +62,7 @@ type CertificateOptions struct {
csrNames []string
outputStyle string
clientSet internalclientset.Interface
clientSet certificatesv1beta1client.CertificatesV1beta1Interface
builder *resource.Builder
genericclioptions.IOStreams
@ -83,7 +82,12 @@ func (o *CertificateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, arg
}
o.builder = f.NewBuilder()
o.clientSet, err = f.ClientSet()
clientConfig, err := f.ToRESTConfig()
if err != nil {
return err
}
o.clientSet, err = certificatesv1beta1client.NewForConfig(clientConfig)
if err != nil {
return err
}
@ -104,9 +108,9 @@ func NewCmdCertificateApprove(f cmdutil.Factory, ioStreams genericclioptions.IOS
IOStreams: ioStreams,
}
cmd := &cobra.Command{
Use: "approve (-f FILENAME | NAME)",
Use: "approve (-f FILENAME | NAME)",
DisableFlagsInUseLine: true,
Short: i18n.T("Approve a certificate signing request"),
Short: i18n.T("Approve a certificate signing request"),
Long: templates.LongDesc(`
Approve a certificate signing request.
@ -135,18 +139,18 @@ func NewCmdCertificateApprove(f cmdutil.Factory, ioStreams genericclioptions.IOS
}
func (o *CertificateOptions) RunCertificateApprove(force bool) error {
return o.modifyCertificateCondition(o.builder, o.clientSet, force, func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, bool) {
return o.modifyCertificateCondition(o.builder, o.clientSet, force, func(csr *certificatesv1beta1.CertificateSigningRequest) (*certificatesv1beta1.CertificateSigningRequest, bool) {
var alreadyApproved bool
for _, c := range csr.Status.Conditions {
if c.Type == certificates.CertificateApproved {
if c.Type == certificatesv1beta1.CertificateApproved {
alreadyApproved = true
}
}
if alreadyApproved {
return csr, true
}
csr.Status.Conditions = append(csr.Status.Conditions, certificates.CertificateSigningRequestCondition{
Type: certificates.CertificateApproved,
csr.Status.Conditions = append(csr.Status.Conditions, certificatesv1beta1.CertificateSigningRequestCondition{
Type: certificatesv1beta1.CertificateApproved,
Reason: "KubectlApprove",
Message: "This CSR was approved by kubectl certificate approve.",
LastUpdateTime: metav1.Now(),
@ -161,9 +165,9 @@ func NewCmdCertificateDeny(f cmdutil.Factory, ioStreams genericclioptions.IOStre
IOStreams: ioStreams,
}
cmd := &cobra.Command{
Use: "deny (-f FILENAME | NAME)",
Use: "deny (-f FILENAME | NAME)",
DisableFlagsInUseLine: true,
Short: i18n.T("Deny a certificate signing request"),
Short: i18n.T("Deny a certificate signing request"),
Long: templates.LongDesc(`
Deny a certificate signing request.
@ -187,30 +191,30 @@ func NewCmdCertificateDeny(f cmdutil.Factory, ioStreams genericclioptions.IOStre
}
func (o *CertificateOptions) RunCertificateDeny(force bool) error {
return o.modifyCertificateCondition(o.builder, o.clientSet, force, func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, bool) {
return o.modifyCertificateCondition(o.builder, o.clientSet, force, func(csr *certificatesv1beta1.CertificateSigningRequest) (*certificatesv1beta1.CertificateSigningRequest, bool) {
var alreadyDenied bool
for _, c := range csr.Status.Conditions {
if c.Type == certificates.CertificateDenied {
if c.Type == certificatesv1beta1.CertificateDenied {
alreadyDenied = true
}
}
if alreadyDenied {
return csr, true
}
csr.Status.Conditions = append(csr.Status.Conditions, certificates.CertificateSigningRequestCondition{
Type: certificates.CertificateDenied,
csr.Status.Conditions = append(csr.Status.Conditions, certificatesv1beta1.CertificateSigningRequestCondition{
Type: certificatesv1beta1.CertificateDenied,
Reason: "KubectlDeny",
Message: "This CSR was approved by kubectl certificate deny.",
Message: "This CSR was denied by kubectl certificate deny.",
LastUpdateTime: metav1.Now(),
})
return csr, false
})
}
func (options *CertificateOptions) modifyCertificateCondition(builder *resource.Builder, clientSet internalclientset.Interface, force bool, modify func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, bool)) error {
func (options *CertificateOptions) modifyCertificateCondition(builder *resource.Builder, clientSet certificatesv1beta1client.CertificatesV1beta1Interface, force bool, modify func(csr *certificatesv1beta1.CertificateSigningRequest) (*certificatesv1beta1.CertificateSigningRequest, bool)) error {
var found int
r := builder.
WithScheme(legacyscheme.Scheme).
WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
ContinueOnError().
FilenameParam(false, &options.FilenameOptions).
ResourceNames("certificatesigningrequest", options.csrNames...).
@ -223,12 +227,10 @@ func (options *CertificateOptions) modifyCertificateCondition(builder *resource.
return err
}
for i := 0; ; i++ {
csr := info.Object.(*certificates.CertificateSigningRequest)
csr := info.Object.(*certificatesv1beta1.CertificateSigningRequest)
csr, hasCondition := modify(csr)
if !hasCondition || force {
csr, err = clientSet.Certificates().
CertificateSigningRequests().
UpdateApproval(csr)
csr, err = clientSet.CertificateSigningRequests().UpdateApproval(csr)
if errors.IsConflict(err) && i < 10 {
if err := info.Get(); err != nil {
return err
@ -243,7 +245,7 @@ func (options *CertificateOptions) modifyCertificateCondition(builder *resource.
}
found++
return options.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping), options.Out)
return options.PrintObj(info.Object, options.Out)
})
if found == 0 {
fmt.Fprintf(options.Out, "No resources found\n")

View File

@ -0,0 +1,53 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"clusterinfo.go",
"clusterinfo_dump.go",
],
importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/clusterinfo",
visibility = ["//visibility:public"],
deps = [
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/polymorphichelpers:go_default_library",
"//pkg/kubectl/scheme:go_default_library",
"//pkg/kubectl/util/i18n:go_default_library",
"//pkg/kubectl/util/templates:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/printers:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/resource:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/typed/apps/v1:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
"//staging/src/k8s.io/client-go/rest:go_default_library",
"//vendor/github.com/daviddengcn/go-colortext:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["clusterinfo_dump_test.go"],
embed = [":go_default_library"],
deps = [
"//pkg/kubectl/cmd/testing:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -14,23 +14,23 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
package clusterinfo
import (
"fmt"
"io"
"strconv"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilnet "k8s.io/apimachinery/pkg/util/net"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/genericclioptions/resource"
restclient "k8s.io/client-go/rest"
"k8s.io/kubernetes/pkg/api/legacyscheme"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
"k8s.io/kubernetes/pkg/kubectl/scheme"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
ct "github.com/daviddengcn/go-colortext"
"github.com/spf13/cobra"
@ -92,11 +92,9 @@ func (o *ClusterInfoOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) err
}
func (o *ClusterInfoOptions) Run() error {
printService(o.Out, "Kubernetes master", o.Client.Host)
// TODO use generalized labels once they are implemented (#341)
b := o.Builder.
WithScheme(legacyscheme.Scheme).
WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
NamespaceParam(o.Namespace).DefaultNamespace().
LabelSelectorParam("kubernetes.io/cluster-service=true").
ResourceTypeOrNameArgs(false, []string{"services"}...).
@ -105,7 +103,9 @@ func (o *ClusterInfoOptions) Run() error {
if err != nil {
return err
}
services := r.Object.(*api.ServiceList).Items
printService(o.Out, "Kubernetes master", o.Client.Host)
services := r.Object.(*corev1.ServiceList).Items
for _, service := range services {
var link string
if len(service.Status.LoadBalancer.Ingress) > 0 {

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
package clusterinfo
import (
"fmt"
@ -25,16 +25,22 @@ import (
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/genericclioptions/printers"
appsv1client "k8s.io/client-go/kubernetes/typed/apps/v1"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/printers"
"k8s.io/kubernetes/pkg/kubectl/polymorphichelpers"
"k8s.io/kubernetes/pkg/kubectl/scheme"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
const (
defaultPodLogsTimeout = 20 * time.Second
timeout = 5 * time.Minute
)
type ClusterInfoDumpOptions struct {
@ -46,7 +52,8 @@ type ClusterInfoDumpOptions struct {
Namespaces []string
Timeout time.Duration
Clientset internalclientset.Interface
AppsClient appsv1client.AppsV1Interface
CoreClient corev1client.CoreV1Interface
Namespace string
RESTClientGetter genericclioptions.RESTClientGetter
LogsForObject polymorphichelpers.LogsForObjectFunc
@ -57,7 +64,7 @@ type ClusterInfoDumpOptions struct {
// NewCmdCreateSecret groups subcommands to create various types of secrets
func NewCmdClusterInfoDump(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
o := &ClusterInfoDumpOptions{
PrintFlags: genericclioptions.NewPrintFlags("").WithTypeSetter(scheme.Scheme),
PrintFlags: genericclioptions.NewPrintFlags("").WithTypeSetter(scheme.Scheme).WithDefaultOutput("json"),
IOStreams: ioStreams,
}
@ -72,6 +79,9 @@ func NewCmdClusterInfoDump(f cmdutil.Factory, ioStreams genericclioptions.IOStre
cmdutil.CheckErr(o.Run())
},
}
o.PrintFlags.AddFlags(cmd)
cmd.Flags().StringVar(&o.OutputDir, "output-directory", o.OutputDir, i18n.T("Where to output the files. If empty or '-' uses stdout, otherwise creates a directory hierarchy in that directory"))
cmd.Flags().StringSliceVar(&o.Namespaces, "namespaces", o.Namespaces, "A comma separated list of namespaces to dump.")
cmd.Flags().BoolVar(&o.AllNamespaces, "all-namespaces", o.AllNamespaces, "If true, dump all namespaces. If true, --namespaces is ignored.")
@ -122,18 +132,28 @@ func (o *ClusterInfoDumpOptions) Complete(f cmdutil.Factory, cmd *cobra.Command)
return err
}
jsonOutputFmt := "json"
o.PrintFlags.OutputFormat = &jsonOutputFmt
o.PrintObj = printer.PrintObj
config, err := f.ToRESTConfig()
if err != nil {
return err
}
o.CoreClient, err = corev1client.NewForConfig(config)
if err != nil {
return err
}
o.AppsClient, err = appsv1client.NewForConfig(config)
if err != nil {
return err
}
o.Timeout, err = cmdutil.GetPodRunningTimeoutFlag(cmd)
if err != nil {
return err
}
o.Clientset, err = f.ClientSet()
if err != nil {
return err
}
o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()
if err != nil {
return err
@ -146,7 +166,7 @@ func (o *ClusterInfoDumpOptions) Complete(f cmdutil.Factory, cmd *cobra.Command)
}
func (o *ClusterInfoDumpOptions) Run() error {
nodes, err := o.Clientset.Core().Nodes().List(metav1.ListOptions{})
nodes, err := o.CoreClient.Nodes().List(metav1.ListOptions{})
if err != nil {
return err
}
@ -157,7 +177,7 @@ func (o *ClusterInfoDumpOptions) Run() error {
var namespaces []string
if o.AllNamespaces {
namespaceList, err := o.Clientset.Core().Namespaces().List(metav1.ListOptions{})
namespaceList, err := o.CoreClient.Namespaces().List(metav1.ListOptions{})
if err != nil {
return err
}
@ -175,7 +195,7 @@ func (o *ClusterInfoDumpOptions) Run() error {
for _, namespace := range namespaces {
// TODO: this is repetitive in the extreme. Use reflection or
// something to make this a for loop.
events, err := o.Clientset.Core().Events(namespace).List(metav1.ListOptions{})
events, err := o.CoreClient.Events(namespace).List(metav1.ListOptions{})
if err != nil {
return err
}
@ -183,7 +203,7 @@ func (o *ClusterInfoDumpOptions) Run() error {
return err
}
rcs, err := o.Clientset.Core().ReplicationControllers(namespace).List(metav1.ListOptions{})
rcs, err := o.CoreClient.ReplicationControllers(namespace).List(metav1.ListOptions{})
if err != nil {
return err
}
@ -191,7 +211,7 @@ func (o *ClusterInfoDumpOptions) Run() error {
return err
}
svcs, err := o.Clientset.Core().Services(namespace).List(metav1.ListOptions{})
svcs, err := o.CoreClient.Services(namespace).List(metav1.ListOptions{})
if err != nil {
return err
}
@ -199,7 +219,7 @@ func (o *ClusterInfoDumpOptions) Run() error {
return err
}
sets, err := o.Clientset.Extensions().DaemonSets(namespace).List(metav1.ListOptions{})
sets, err := o.AppsClient.DaemonSets(namespace).List(metav1.ListOptions{})
if err != nil {
return err
}
@ -207,7 +227,7 @@ func (o *ClusterInfoDumpOptions) Run() error {
return err
}
deps, err := o.Clientset.Extensions().Deployments(namespace).List(metav1.ListOptions{})
deps, err := o.AppsClient.Deployments(namespace).List(metav1.ListOptions{})
if err != nil {
return err
}
@ -215,7 +235,7 @@ func (o *ClusterInfoDumpOptions) Run() error {
return err
}
rps, err := o.Clientset.Extensions().ReplicaSets(namespace).List(metav1.ListOptions{})
rps, err := o.AppsClient.ReplicaSets(namespace).List(metav1.ListOptions{})
if err != nil {
return err
}
@ -223,7 +243,7 @@ func (o *ClusterInfoDumpOptions) Run() error {
return err
}
pods, err := o.Clientset.Core().Pods(namespace).List(metav1.ListOptions{})
pods, err := o.CoreClient.Pods(namespace).List(metav1.ListOptions{})
if err != nil {
return err
}
@ -232,24 +252,26 @@ func (o *ClusterInfoDumpOptions) Run() error {
return err
}
printContainer := func(writer io.Writer, container api.Container, pod *api.Pod) {
printContainer := func(writer io.Writer, container corev1.Container, pod *corev1.Pod) {
writer.Write([]byte(fmt.Sprintf("==== START logs for container %s of pod %s/%s ====\n", container.Name, pod.Namespace, pod.Name)))
defer writer.Write([]byte(fmt.Sprintf("==== END logs for container %s of pod %s/%s ====\n", container.Name, pod.Namespace, pod.Name)))
request, err := o.LogsForObject(o.RESTClientGetter, pod, &api.PodLogOptions{Container: container.Name}, timeout)
requests, err := o.LogsForObject(o.RESTClientGetter, pod, &corev1.PodLogOptions{Container: container.Name}, timeout, false)
if err != nil {
// Print error and return.
writer.Write([]byte(fmt.Sprintf("Create log request error: %s\n", err.Error())))
return
}
data, err := request.DoRaw()
if err != nil {
// Print error and return.
writer.Write([]byte(fmt.Sprintf("Request log error: %s\n", err.Error())))
return
for _, request := range requests {
data, err := request.DoRaw()
if err != nil {
// Print error and return.
writer.Write([]byte(fmt.Sprintf("Request log error: %s\n", err.Error())))
return
}
writer.Write(data)
}
writer.Write(data)
}
for ix := range pods.Items {
@ -262,8 +284,13 @@ func (o *ClusterInfoDumpOptions) Run() error {
}
}
}
if o.OutputDir != "-" {
fmt.Fprintf(o.Out, "Cluster info dumped to %s\n", o.OutputDir)
dest := o.OutputDir
if len(dest) == 0 {
dest = "standard output"
}
if dest != "-" {
fmt.Fprintf(o.Out, "Cluster info dumped to %s\n", dest)
}
return nil
}

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
package clusterinfo
import (
"io/ioutil"
@ -22,8 +22,8 @@ import (
"path"
"testing"
"k8s.io/cli-runtime/pkg/genericclioptions"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
)
func TestSetupOutputWriterNoOp(t *testing.T) {

View File

@ -21,23 +21,59 @@ import (
"fmt"
"io"
"os"
"k8s.io/apimachinery/pkg/api/meta"
utilflag "k8s.io/apiserver/pkg/util/flag"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/kubernetes/pkg/kubectl/cmd/auth"
cmdconfig "k8s.io/kubernetes/pkg/kubectl/cmd/config"
"k8s.io/kubernetes/pkg/kubectl/cmd/create"
"k8s.io/kubernetes/pkg/kubectl/cmd/get"
"k8s.io/kubernetes/pkg/kubectl/cmd/rollout"
"k8s.io/kubernetes/pkg/kubectl/cmd/set"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/cmd/wait"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"os/exec"
"runtime"
"strings"
"syscall"
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
utilflag "k8s.io/apiserver/pkg/util/flag"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/kubernetes/pkg/kubectl/cmd/annotate"
"k8s.io/kubernetes/pkg/kubectl/cmd/apiresources"
"k8s.io/kubernetes/pkg/kubectl/cmd/apply"
"k8s.io/kubernetes/pkg/kubectl/cmd/attach"
"k8s.io/kubernetes/pkg/kubectl/cmd/auth"
"k8s.io/kubernetes/pkg/kubectl/cmd/autoscale"
"k8s.io/kubernetes/pkg/kubectl/cmd/certificates"
"k8s.io/kubernetes/pkg/kubectl/cmd/clusterinfo"
"k8s.io/kubernetes/pkg/kubectl/cmd/completion"
cmdconfig "k8s.io/kubernetes/pkg/kubectl/cmd/config"
"k8s.io/kubernetes/pkg/kubectl/cmd/convert"
"k8s.io/kubernetes/pkg/kubectl/cmd/cp"
"k8s.io/kubernetes/pkg/kubectl/cmd/create"
"k8s.io/kubernetes/pkg/kubectl/cmd/delete"
"k8s.io/kubernetes/pkg/kubectl/cmd/describe"
"k8s.io/kubernetes/pkg/kubectl/cmd/diff"
"k8s.io/kubernetes/pkg/kubectl/cmd/drain"
"k8s.io/kubernetes/pkg/kubectl/cmd/edit"
cmdexec "k8s.io/kubernetes/pkg/kubectl/cmd/exec"
"k8s.io/kubernetes/pkg/kubectl/cmd/explain"
"k8s.io/kubernetes/pkg/kubectl/cmd/expose"
"k8s.io/kubernetes/pkg/kubectl/cmd/get"
"k8s.io/kubernetes/pkg/kubectl/cmd/label"
"k8s.io/kubernetes/pkg/kubectl/cmd/logs"
"k8s.io/kubernetes/pkg/kubectl/cmd/options"
"k8s.io/kubernetes/pkg/kubectl/cmd/patch"
"k8s.io/kubernetes/pkg/kubectl/cmd/plugin"
"k8s.io/kubernetes/pkg/kubectl/cmd/portforward"
"k8s.io/kubernetes/pkg/kubectl/cmd/proxy"
"k8s.io/kubernetes/pkg/kubectl/cmd/replace"
"k8s.io/kubernetes/pkg/kubectl/cmd/rollingupdate"
"k8s.io/kubernetes/pkg/kubectl/cmd/rollout"
"k8s.io/kubernetes/pkg/kubectl/cmd/run"
"k8s.io/kubernetes/pkg/kubectl/cmd/scale"
"k8s.io/kubernetes/pkg/kubectl/cmd/set"
"k8s.io/kubernetes/pkg/kubectl/cmd/taint"
"k8s.io/kubernetes/pkg/kubectl/cmd/top"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/cmd/version"
"k8s.io/kubernetes/pkg/kubectl/cmd/wait"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
"k8s.io/cli-runtime/pkg/genericclioptions"
)
const (
@ -248,7 +284,7 @@ __custom_func() {
)
var (
bash_completion_flags = map[string]string{
bashCompletionFlags = map[string]string{
"namespace": "__kubectl_get_resource_namespace",
"context": "__kubectl_config_get_contexts",
"cluster": "__kubectl_config_get_clusters",
@ -256,8 +292,103 @@ var (
}
)
// NewDefaultKubectlCommand creates the `kubectl` command with default arguments
func NewDefaultKubectlCommand() *cobra.Command {
return NewKubectlCommand(os.Stdin, os.Stdout, os.Stderr)
return NewDefaultKubectlCommandWithArgs(&defaultPluginHandler{}, os.Args, os.Stdin, os.Stdout, os.Stderr)
}
// NewDefaultKubectlCommandWithArgs creates the `kubectl` command with arguments
func NewDefaultKubectlCommandWithArgs(pluginHandler PluginHandler, args []string, in io.Reader, out, errout io.Writer) *cobra.Command {
cmd := NewKubectlCommand(in, out, errout)
if pluginHandler == nil {
return cmd
}
if len(args) > 1 {
cmdPathPieces := args[1:]
// only look for suitable extension executables if
// the specified command does not already exist
if _, _, err := cmd.Find(cmdPathPieces); err != nil {
if err := handleEndpointExtensions(pluginHandler, cmdPathPieces); err != nil {
fmt.Fprintf(errout, "%v\n", err)
os.Exit(1)
}
}
}
return cmd
}
// PluginHandler is capable of parsing command line arguments
// and performing executable filename lookups to search
// for valid plugin files, and execute found plugins.
type PluginHandler interface {
// Lookup receives a potential filename and returns
// a full or relative path to an executable, if one
// exists at the given filename, or an error.
Lookup(filename string) (string, error)
// Execute receives an executable's filepath, a slice
// of arguments, and a slice of environment variables
// to relay to the executable.
Execute(executablePath string, cmdArgs, environment []string) error
}
type defaultPluginHandler struct{}
// Lookup implements PluginHandler
func (h *defaultPluginHandler) Lookup(filename string) (string, error) {
// if on Windows, append the "exe" extension
// to the filename that we are looking up.
if runtime.GOOS == "windows" {
filename = filename + ".exe"
}
return exec.LookPath(filename)
}
// Execute implements PluginHandler
func (h *defaultPluginHandler) Execute(executablePath string, cmdArgs, environment []string) error {
return syscall.Exec(executablePath, cmdArgs, environment)
}
func handleEndpointExtensions(pluginHandler PluginHandler, cmdArgs []string) error {
remainingArgs := []string{} // all "non-flag" arguments
for idx := range cmdArgs {
if strings.HasPrefix(cmdArgs[idx], "-") {
break
}
remainingArgs = append(remainingArgs, strings.Replace(cmdArgs[idx], "-", "_", -1))
}
foundBinaryPath := ""
// attempt to find binary, starting at longest possible name with given cmdArgs
for len(remainingArgs) > 0 {
path, err := pluginHandler.Lookup(fmt.Sprintf("kubectl-%s", strings.Join(remainingArgs, "-")))
if err != nil || len(path) == 0 {
remainingArgs = remainingArgs[:len(remainingArgs)-1]
continue
}
foundBinaryPath = path
break
}
if len(foundBinaryPath) == 0 {
return nil
}
// invoke cmd binary relaying the current environment and args given
// remainingArgs will always have at least one element.
// execve will make remainingArgs[0] the "binary name".
if err := pluginHandler.Execute(foundBinaryPath, append([]string{foundBinaryPath}, cmdArgs[len(remainingArgs):]...), os.Environ()); err != nil {
return err
}
return nil
}
// NewKubectlCommand creates the `kubectl` command and its nested children.
@ -272,6 +403,14 @@ func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.Command {
Find more information at:
https://kubernetes.io/docs/reference/kubectl/overview/`),
Run: runHelp,
// Hook before and after Run initialize and write profiles to disk,
// respectively.
PersistentPreRunE: func(*cobra.Command, []string) error {
return initProfiling()
},
PersistentPostRunE: func(*cobra.Command, []string) error {
return flushProfiling()
},
BashCompletionFunction: bashCompletionFunc,
}
@ -282,6 +421,8 @@ func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.Command {
// a.k.a. change all "_" to "-". e.g. glog package
flags.SetNormalizeFunc(utilflag.WordSepNormalizeFunc)
addProfilingFlags(flags)
kubeConfigFlags := genericclioptions.NewConfigFlags()
kubeConfigFlags.AddFlags(flags)
matchVersionKubeConfigFlags := cmdutil.NewMatchVersionFlags(kubeConfigFlags)
@ -308,71 +449,71 @@ func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.Command {
Message: "Basic Commands (Beginner):",
Commands: []*cobra.Command{
create.NewCmdCreate(f, ioStreams),
NewCmdExposeService(f, ioStreams),
NewCmdRun(f, ioStreams),
expose.NewCmdExposeService(f, ioStreams),
run.NewCmdRun(f, ioStreams),
set.NewCmdSet(f, ioStreams),
deprecatedAlias("run-container", NewCmdRun(f, ioStreams)),
},
},
{
Message: "Basic Commands (Intermediate):",
Commands: []*cobra.Command{
NewCmdExplain("kubectl", f, ioStreams),
explain.NewCmdExplain("kubectl", f, ioStreams),
get.NewCmdGet("kubectl", f, ioStreams),
NewCmdEdit(f, ioStreams),
NewCmdDelete(f, ioStreams),
edit.NewCmdEdit(f, ioStreams),
delete.NewCmdDelete(f, ioStreams),
},
},
{
Message: "Deploy Commands:",
Commands: []*cobra.Command{
rollout.NewCmdRollout(f, ioStreams),
NewCmdRollingUpdate(f, ioStreams),
NewCmdScale(f, ioStreams),
NewCmdAutoscale(f, ioStreams),
rollingupdate.NewCmdRollingUpdate(f, ioStreams),
scale.NewCmdScale(f, ioStreams),
autoscale.NewCmdAutoscale(f, ioStreams),
},
},
{
Message: "Cluster Management Commands:",
Commands: []*cobra.Command{
NewCmdCertificate(f, ioStreams),
NewCmdClusterInfo(f, ioStreams),
NewCmdTop(f, ioStreams),
NewCmdCordon(f, ioStreams),
NewCmdUncordon(f, ioStreams),
NewCmdDrain(f, ioStreams),
NewCmdTaint(f, ioStreams),
certificates.NewCmdCertificate(f, ioStreams),
clusterinfo.NewCmdClusterInfo(f, ioStreams),
top.NewCmdTop(f, ioStreams),
drain.NewCmdCordon(f, ioStreams),
drain.NewCmdUncordon(f, ioStreams),
drain.NewCmdDrain(f, ioStreams),
taint.NewCmdTaint(f, ioStreams),
},
},
{
Message: "Troubleshooting and Debugging Commands:",
Commands: []*cobra.Command{
NewCmdDescribe("kubectl", f, ioStreams),
NewCmdLogs(f, ioStreams),
NewCmdAttach(f, ioStreams),
NewCmdExec(f, ioStreams),
NewCmdPortForward(f, ioStreams),
NewCmdProxy(f, ioStreams),
NewCmdCp(f, ioStreams),
describe.NewCmdDescribe("kubectl", f, ioStreams),
logs.NewCmdLogs(f, ioStreams),
attach.NewCmdAttach(f, ioStreams),
cmdexec.NewCmdExec(f, ioStreams),
portforward.NewCmdPortForward(f, ioStreams),
proxy.NewCmdProxy(f, ioStreams),
cp.NewCmdCp(f, ioStreams),
auth.NewCmdAuth(f, ioStreams),
},
},
{
Message: "Advanced Commands:",
Commands: []*cobra.Command{
NewCmdApply("kubectl", f, ioStreams),
NewCmdPatch(f, ioStreams),
NewCmdReplace(f, ioStreams),
diff.NewCmdDiff(f, ioStreams),
apply.NewCmdApply("kubectl", f, ioStreams),
patch.NewCmdPatch(f, ioStreams),
replace.NewCmdReplace(f, ioStreams),
wait.NewCmdWait(f, ioStreams),
NewCmdConvert(f, ioStreams),
convert.NewCmdConvert(f, ioStreams),
},
},
{
Message: "Settings Commands:",
Commands: []*cobra.Command{
NewCmdLabel(f, ioStreams),
NewCmdAnnotate("kubectl", f, ioStreams),
NewCmdCompletion(ioStreams.Out, ""),
label.NewCmdLabel(f, ioStreams),
annotate.NewCmdAnnotate("kubectl", f, ioStreams),
completion.NewCmdCompletion(ioStreams.Out, ""),
},
},
}
@ -388,7 +529,7 @@ func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.Command {
templates.ActsAsRootCommand(cmds, filters, groups...)
for name, completion := range bash_completion_flags {
for name, completion := range bashCompletionFlags {
if cmds.Flag(name) != nil {
if cmds.Flag(name).Annotations == nil {
cmds.Flag(name).Annotations = map[string][]string{}
@ -402,11 +543,11 @@ func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.Command {
cmds.AddCommand(alpha)
cmds.AddCommand(cmdconfig.NewCmdConfig(f, clientcmd.NewDefaultPathOptions(), ioStreams))
cmds.AddCommand(NewCmdPlugin(f, ioStreams))
cmds.AddCommand(NewCmdVersion(f, ioStreams))
cmds.AddCommand(NewCmdApiVersions(f, ioStreams))
cmds.AddCommand(NewCmdApiResources(f, ioStreams))
cmds.AddCommand(NewCmdOptions(ioStreams.Out))
cmds.AddCommand(plugin.NewCmdPlugin(f, ioStreams))
cmds.AddCommand(version.NewCmdVersion(f, ioStreams))
cmds.AddCommand(apiresources.NewCmdAPIVersions(f, ioStreams))
cmds.AddCommand(apiresources.NewCmdAPIResources(f, ioStreams))
cmds.AddCommand(options.NewCmdOptions(ioStreams.Out))
return cmds
}
@ -415,10 +556,6 @@ func runHelp(cmd *cobra.Command, args []string) {
cmd.Help()
}
func printDeprecationWarning(errOut io.Writer, command, alias string) {
fmt.Fprintf(errOut, "%s is DEPRECATED and will be removed in a future version. Use %s instead.\n", alias, command)
}
// deprecatedAlias is intended to be used to create a "wrapper" command around
// an existing command. The wrapper works the same but prints a deprecation
// message before running. This command is identical functionality.
@ -433,5 +570,3 @@ func deprecatedAlias(deprecatedVersion string, cmd *cobra.Command) *cobra.Comman
cmd.Hidden = true
return cmd
}
var metadataAccessor = meta.NewAccessor()

View File

@ -1,234 +0,0 @@
/*
Copyright 2018 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 cmd
import (
"bytes"
"testing"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
genericprinters "k8s.io/kubernetes/pkg/kubectl/genericclioptions/printers"
"k8s.io/kubernetes/pkg/kubectl/scheme"
"k8s.io/kubernetes/pkg/printers"
)
func TestIllegalPackageSourceCheckerThroughPrintFlags(t *testing.T) {
testCases := []struct {
name string
expectInternalObjErr bool
output string
obj runtime.Object
expectedOutput string
}{
{
name: "success printer: object containing package path beginning with forbidden prefix is rejected",
expectInternalObjErr: true,
obj: internalPod(),
},
{
name: "success printer: object containing package path with no forbidden prefix returns no error",
expectInternalObjErr: false,
obj: externalPod(),
output: "",
expectedOutput: "pod/foo succeeded\n",
},
{
name: "name printer: object containing package path beginning with forbidden prefix is rejected",
expectInternalObjErr: true,
output: "name",
obj: internalPod(),
},
{
name: "json printer: object containing package path beginning with forbidden prefix is rejected",
expectInternalObjErr: true,
output: "json",
obj: internalPod(),
},
{
name: "json printer: object containing package path with no forbidden prefix returns no error",
expectInternalObjErr: false,
obj: externalPod(),
output: "json",
},
{
name: "yaml printer: object containing package path beginning with forbidden prefix is rejected",
expectInternalObjErr: true,
output: "yaml",
obj: internalPod(),
},
{
name: "yaml printer: object containing package path with no forbidden prefix returns no error",
expectInternalObjErr: false,
obj: externalPod(),
output: "yaml",
},
}
for _, tc := range testCases {
printFlags := genericclioptions.NewPrintFlags("succeeded").WithTypeSetter(scheme.Scheme)
printFlags.OutputFormat = &tc.output
printer, err := printFlags.ToPrinter()
if err != nil {
t.Fatalf("unexpected error %v", err)
}
output := bytes.NewBuffer([]byte{})
err = printer.PrintObj(tc.obj, output)
if err != nil {
if !tc.expectInternalObjErr {
t.Fatalf("unexpected error %v", err)
}
if !genericprinters.IsInternalObjectError(err) {
t.Fatalf("unexpected error - expecting internal object printer error, got %q", err)
}
continue
}
if tc.expectInternalObjErr {
t.Fatalf("expected internal object printer error, but got no error")
}
if len(tc.expectedOutput) == 0 {
continue
}
if tc.expectedOutput != output.String() {
t.Fatalf("unexpected output: expecting %q, got %q", tc.expectedOutput, output.String())
}
}
}
func TestIllegalPackageSourceCheckerDirectlyThroughPrinters(t *testing.T) {
jsonPathPrinter, err := genericprinters.NewJSONPathPrinter("{ .metadata.name }")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
goTemplatePrinter, err := genericprinters.NewGoTemplatePrinter([]byte("{{ .metadata.name }}"))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
customColumns, err := printers.NewCustomColumnsPrinterFromSpec("NAME:.metadata.name", scheme.Codecs.UniversalDecoder(), true)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
testCases := []struct {
name string
expectInternalObjErr bool
printer genericprinters.ResourcePrinter
obj runtime.Object
expectedOutput string
}{
{
name: "json printer: object containing package path beginning with forbidden prefix is rejected",
expectInternalObjErr: true,
printer: &genericprinters.JSONPrinter{},
obj: internalPod(),
},
{
name: "yaml printer: object containing package path beginning with forbidden prefix is rejected",
expectInternalObjErr: true,
printer: &genericprinters.YAMLPrinter{},
obj: internalPod(),
},
{
name: "jsonpath printer: object containing package path beginning with forbidden prefix is rejected",
expectInternalObjErr: true,
printer: jsonPathPrinter,
obj: internalPod(),
},
{
name: "go-template printer: object containing package path beginning with forbidden prefix is rejected",
expectInternalObjErr: true,
printer: goTemplatePrinter,
obj: internalPod(),
},
{
name: "go-template printer: object containing package path beginning with forbidden prefix is rejected",
expectInternalObjErr: true,
printer: goTemplatePrinter,
obj: internalPod(),
},
{
name: "custom-columns printer: object containing package path beginning with forbidden prefix is rejected",
expectInternalObjErr: true,
printer: customColumns,
obj: internalPod(),
},
}
for _, tc := range testCases {
output := bytes.NewBuffer([]byte{})
err := tc.printer.PrintObj(tc.obj, output)
if err != nil {
if !tc.expectInternalObjErr {
t.Fatalf("unexpected error %v", err)
}
if !genericprinters.IsInternalObjectError(err) {
t.Fatalf("unexpected error - expecting internal object printer error, got %q", err)
}
continue
}
if tc.expectInternalObjErr {
t.Fatalf("expected internal object printer error, but got no error")
}
if len(tc.expectedOutput) == 0 {
continue
}
if tc.expectedOutput != output.String() {
t.Fatalf("unexpected output: expecting %q, got %q", tc.expectedOutput, output.String())
}
}
}
func internalPod() *api.Pod {
return &api.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "10"},
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "bar",
},
},
},
Status: api.PodStatus{
Phase: api.PodRunning,
},
}
}
func externalPod() *v1.Pod {
return &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
}
}

View File

@ -18,211 +18,19 @@ package cmd
import (
"bytes"
"encoding/json"
"io"
"fmt"
"io/ioutil"
"net/http"
"os"
"reflect"
stdstrings "strings"
"strings"
"testing"
"time"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
restclient "k8s.io/client-go/rest"
"k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/cli-runtime/pkg/genericclioptions"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/scheme"
)
// This init should be removed after switching this command and its tests to user external types.
func init() {
api.AddToScheme(scheme.Scheme)
}
func initTestErrorHandler(t *testing.T) {
cmdutil.BehaviorOnFatal(func(str string, code int) {
t.Errorf("Error running command (exit code %d): %s", code, str)
})
}
func defaultHeader() http.Header {
header := http.Header{}
header.Set("Content-Type", runtime.ContentTypeJSON)
return header
}
func defaultClientConfig() *restclient.Config {
return &restclient.Config{
APIPath: "/api",
ContentConfig: restclient.ContentConfig{
NegotiatedSerializer: scheme.Codecs,
ContentType: runtime.ContentTypeJSON,
GroupVersion: &schema.GroupVersion{Version: "v1"},
},
}
}
func testData() (*api.PodList, *api.ServiceList, *api.ReplicationControllerList) {
pods := &api.PodList{
ListMeta: metav1.ListMeta{
ResourceVersion: "15",
},
Items: []api.Pod{
{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "10"},
Spec: apitesting.DeepEqualSafePodSpec(),
},
{
ObjectMeta: metav1.ObjectMeta{Name: "bar", Namespace: "test", ResourceVersion: "11"},
Spec: apitesting.DeepEqualSafePodSpec(),
},
},
}
svc := &api.ServiceList{
ListMeta: metav1.ListMeta{
ResourceVersion: "16",
},
Items: []api.Service{
{
ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"},
Spec: api.ServiceSpec{
SessionAffinity: "None",
Type: api.ServiceTypeClusterIP,
},
},
},
}
rc := &api.ReplicationControllerList{
ListMeta: metav1.ListMeta{
ResourceVersion: "17",
},
Items: []api.ReplicationController{
{
ObjectMeta: metav1.ObjectMeta{Name: "rc1", Namespace: "test", ResourceVersion: "18"},
Spec: api.ReplicationControllerSpec{
Replicas: 1,
},
},
},
}
return pods, svc, rc
}
func objBody(codec runtime.Codec, obj runtime.Object) io.ReadCloser {
return ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(codec, obj))))
}
func policyObjBody(obj runtime.Object) io.ReadCloser {
return ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(testapi.Policy.Codec(), obj))))
}
func bytesBody(bodyBytes []byte) io.ReadCloser {
return ioutil.NopCloser(bytes.NewReader(bodyBytes))
}
func stringBody(body string) io.ReadCloser {
return ioutil.NopCloser(bytes.NewReader([]byte(body)))
}
func newAllPhasePodList() *api.PodList {
nodeName := "kubernetes-node-abcd"
return &api.PodList{
Items: []api.Pod{
{
ObjectMeta: metav1.ObjectMeta{
Name: "test1",
CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
},
Spec: api.PodSpec{
Containers: make([]api.Container, 2),
NodeName: nodeName,
},
Status: api.PodStatus{
Phase: api.PodPending,
ContainerStatuses: []api.ContainerStatus{
{Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
{RestartCount: 3},
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "test2",
CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
},
Spec: api.PodSpec{
Containers: make([]api.Container, 2),
NodeName: nodeName,
},
Status: api.PodStatus{
Phase: api.PodRunning,
ContainerStatuses: []api.ContainerStatus{
{Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
{RestartCount: 3},
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "test3",
CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
},
Spec: api.PodSpec{
Containers: make([]api.Container, 2),
NodeName: nodeName,
},
Status: api.PodStatus{
Phase: api.PodSucceeded,
ContainerStatuses: []api.ContainerStatus{
{Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
{RestartCount: 3},
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "test4",
CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
},
Spec: api.PodSpec{
Containers: make([]api.Container, 2),
NodeName: nodeName,
},
Status: api.PodStatus{
Phase: api.PodFailed,
ContainerStatuses: []api.ContainerStatus{
{Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
{RestartCount: 3},
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "test5",
CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
},
Spec: api.PodSpec{
Containers: make([]api.Container, 2),
NodeName: nodeName,
},
Status: api.PodStatus{
Phase: api.PodUnknown,
ContainerStatuses: []api.ContainerStatus{
{Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
{RestartCount: 3},
},
},
}},
}
}
func TestNormalizationFuncGlobalExistence(t *testing.T) {
// This test can be safely deleted when we will not support multiple flag formats
root := NewKubectlCommand(os.Stdin, os.Stdout, os.Stderr)
@ -249,14 +57,6 @@ func TestNormalizationFuncGlobalExistence(t *testing.T) {
}
}
func genResponseWithJsonEncodedBody(bodyStruct interface{}) (*http.Response, error) {
jsonBytes, err := json.Marshal(bodyStruct)
if err != nil {
return nil, err
}
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bytesBody(jsonBytes)}, nil
}
func Test_deprecatedAlias(t *testing.T) {
var correctCommandCalled bool
makeCobraCommand := func() *cobra.Command {
@ -274,7 +74,7 @@ func Test_deprecatedAlias(t *testing.T) {
if len(alias.Deprecated) == 0 {
t.Error("deprecatedAlias should always have a non-empty .Deprecated")
}
if !stdstrings.Contains(alias.Deprecated, "print") {
if !strings.Contains(alias.Deprecated, "print") {
t.Error("deprecatedAlias should give the name of the new function in its .Deprecated field")
}
if !alias.Hidden {
@ -294,7 +94,7 @@ func Test_deprecatedAlias(t *testing.T) {
alias.SetOutput(buffer)
alias.Execute()
str := buffer.String()
if !stdstrings.Contains(str, "deprecated") || !stdstrings.Contains(str, "print") {
if !strings.Contains(str, "deprecated") || !strings.Contains(str, "print") {
t.Errorf("deprecation warning %q does not include enough information", str)
}
@ -306,3 +106,106 @@ func Test_deprecatedAlias(t *testing.T) {
t.Errorf("original function doesn't appear to have been called by alias")
}
}
func TestKubectlCommandHandlesPlugins(t *testing.T) {
tests := []struct {
name string
args []string
expectPlugin string
expectPluginArgs []string
expectError string
}{
{
name: "test that normal commands are able to be executed, when no plugin overshadows them",
args: []string{"kubectl", "get", "foo"},
expectPlugin: "",
expectPluginArgs: []string{},
},
{
name: "test that a plugin executable is found based on command args",
args: []string{"kubectl", "foo", "--bar"},
expectPlugin: "plugin/testdata/kubectl-foo",
expectPluginArgs: []string{"foo", "--bar"},
},
{
name: "test that a plugin does not execute over an existing command by the same name",
args: []string{"kubectl", "version"},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
pluginsHandler := &testPluginHandler{
pluginsDirectory: "plugin/testdata",
}
_, in, out, errOut := genericclioptions.NewTestIOStreams()
cmdutil.BehaviorOnFatal(func(str string, code int) {
errOut.Write([]byte(str))
})
root := NewDefaultKubectlCommandWithArgs(pluginsHandler, test.args, in, out, errOut)
if err := root.Execute(); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if pluginsHandler.err != nil && pluginsHandler.err.Error() != test.expectError {
t.Fatalf("unexpected error: expected %q to occur, but got %q", test.expectError, pluginsHandler.err)
}
if pluginsHandler.executedPlugin != test.expectPlugin {
t.Fatalf("unexpected plugin execution: expedcted %q, got %q", test.expectPlugin, pluginsHandler.executedPlugin)
}
if len(pluginsHandler.withArgs) != len(test.expectPluginArgs) {
t.Fatalf("unexpected plugin execution args: expedcted %q, got %q", test.expectPluginArgs, pluginsHandler.withArgs)
}
})
}
}
type testPluginHandler struct {
pluginsDirectory string
// execution results
executedPlugin string
withArgs []string
withEnv []string
err error
}
func (h *testPluginHandler) Lookup(filename string) (string, error) {
dir, err := os.Stat(h.pluginsDirectory)
if err != nil {
h.err = err
return "", err
}
if !dir.IsDir() {
h.err = fmt.Errorf("expected %q to be a directory", h.pluginsDirectory)
return "", h.err
}
plugins, err := ioutil.ReadDir(h.pluginsDirectory)
if err != nil {
h.err = err
return "", err
}
for _, p := range plugins {
if p.Name() == filename {
return fmt.Sprintf("%s/%s", h.pluginsDirectory, p.Name()), nil
}
}
h.err = fmt.Errorf("unable to find a plugin executable %q", filename)
return "", h.err
}
func (h *testPluginHandler) Execute(executablePath string, cmdArgs, env []string) error {
h.executedPlugin = executablePath
h.withArgs = cmdArgs
h.withEnv = env
return nil
}

View File

@ -0,0 +1,28 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["completion.go"],
importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/completion",
visibility = ["//visibility:public"],
deps = [
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/util/i18n:go_default_library",
"//pkg/kubectl/util/templates:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
package completion
import (
"bytes"
@ -22,9 +22,9 @@ import (
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
const defaultBoilerPlate = `
@ -67,6 +67,8 @@ var (
# Installing bash completion on Linux
## If bash-completion is not installed on Linux, please install the 'bash-completion' package
## via your distribution's package manager.
## Load the kubectl completion code for bash into the current shell
source <(kubectl completion bash)
## Write bash completion code to a file and source if from .bash_profile
@ -97,11 +99,11 @@ func NewCmdCompletion(out io.Writer, boilerPlate string) *cobra.Command {
}
cmd := &cobra.Command{
Use: "completion SHELL",
Use: "completion SHELL",
DisableFlagsInUseLine: true,
Short: i18n.T("Output shell completion code for the specified shell (bash or zsh)"),
Long: completion_long,
Example: completion_example,
Short: i18n.T("Output shell completion code for the specified shell (bash or zsh)"),
Long: completion_long,
Example: completion_example,
Run: func(cmd *cobra.Command, args []string) {
err := RunCompletion(out, boilerPlate, cmd, args)
cmdutil.CheckErr(err)
@ -262,7 +264,7 @@ __kubectl_quote() {
# Leave out first character
printf %q "${1:1}"
else
printf %q "$1"
printf %q "$1"
fi
}

View File

@ -28,19 +28,20 @@ go_library(
"//build/visible_to:pkg_kubectl_cmd_config_CONSUMERS",
],
deps = [
"//pkg/api/legacyscheme:go_default_library",
"//pkg/kubectl/cmd/templates:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/genericclioptions:go_default_library",
"//pkg/kubectl/scheme:go_default_library",
"//pkg/kubectl/util/i18n:go_default_library",
"//pkg/printers:go_default_library",
"//pkg/kubectl/util/printers:go_default_library",
"//pkg/kubectl/util/templates:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/flag:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/printers:go_default_library",
"//staging/src/k8s.io/client-go/tools/clientcmd:go_default_library",
"//staging/src/k8s.io/client-go/tools/clientcmd/api:go_default_library",
"//staging/src/k8s.io/client-go/tools/clientcmd/api/latest:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/flag:go_default_library",
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
"//vendor/k8s.io/client-go/tools/clientcmd/api:go_default_library",
"//vendor/k8s.io/client-go/tools/clientcmd/api/latest:go_default_library",
],
)
@ -66,12 +67,12 @@ go_test(
embed = [":go_default_library"],
deps = [
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/genericclioptions:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/flag:go_default_library",
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
"//vendor/k8s.io/client-go/tools/clientcmd/api:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/flag:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library",
"//staging/src/k8s.io/client-go/tools/clientcmd:go_default_library",
"//staging/src/k8s.io/client-go/tools/clientcmd/api:go_default_library",
],
)

View File

@ -23,11 +23,11 @@ import (
"github.com/spf13/cobra"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
// NewCmdConfig creates a command object for the "config" action, and adds all child commands to it.
@ -37,16 +37,16 @@ func NewCmdConfig(f cmdutil.Factory, pathOptions *clientcmd.PathOptions, streams
}
cmd := &cobra.Command{
Use: "config SUBCOMMAND",
Use: "config SUBCOMMAND",
DisableFlagsInUseLine: true,
Short: i18n.T("Modify kubeconfig files"),
Short: i18n.T("Modify kubeconfig files"),
Long: templates.LongDesc(`
Modify kubeconfig files using subcommands like "kubectl config set current-context my-context"
The loading order follows these rules:
1. If the --` + pathOptions.ExplicitFileFlag + ` flag is set, then only that file is loaded. The flag may only be set once and no merging takes place.
2. If $` + pathOptions.EnvVar + ` environment variable is set, then it is used a list of paths (normal path delimitting rules for your system). These paths are merged. When a value is modified, it is modified in the file that defines the stanza. When a value is created, it is created in the first file that exists. If no files in the chain exist, then it creates the last file in the list.
1. If the --` + pathOptions.ExplicitFileFlag + ` flag is set, then only that file is loaded. The flag may only be set once and no merging takes place.
2. If $` + pathOptions.EnvVar + ` environment variable is set, then it is used as a list of paths (normal path delimitting rules for your system). These paths are merged. When a value is modified, it is modified in the file that defines the stanza. When a value is created, it is created in the first file that exists. If no files in the chain exist, then it creates the last file in the list.
3. Otherwise, ` + path.Join("${HOME}", pathOptions.GlobalFileSubpath) + ` is used and no merging takes place.`),
Run: cmdutil.DefaultSubCommandRun(streams.ErrOut),
}

View File

@ -27,10 +27,10 @@ import (
apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/util/diff"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
)
func newRedFederalCowHammerConfig() clientcmdapi.Config {

View File

@ -29,9 +29,9 @@ import (
"k8s.io/apiserver/pkg/util/flag"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
type createAuthInfoOptions struct {
@ -100,11 +100,11 @@ func NewCmdConfigSetAuthInfo(out io.Writer, configAccess clientcmd.ConfigAccess)
func newCmdConfigSetAuthInfo(out io.Writer, options *createAuthInfoOptions) *cobra.Command {
cmd := &cobra.Command{
Use: fmt.Sprintf("set-credentials NAME [--%v=path/to/certfile] [--%v=path/to/keyfile] [--%v=bearer_token] [--%v=basic_user] [--%v=basic_password] [--%v=provider_name] [--%v=key=value]", clientcmd.FlagCertFile, clientcmd.FlagKeyFile, clientcmd.FlagBearerToken, clientcmd.FlagUsername, clientcmd.FlagPassword, flagAuthProvider, flagAuthProviderArg),
Use: fmt.Sprintf("set-credentials NAME [--%v=path/to/certfile] [--%v=path/to/keyfile] [--%v=bearer_token] [--%v=basic_user] [--%v=basic_password] [--%v=provider_name] [--%v=key=value]", clientcmd.FlagCertFile, clientcmd.FlagKeyFile, clientcmd.FlagBearerToken, clientcmd.FlagUsername, clientcmd.FlagPassword, flagAuthProvider, flagAuthProviderArg),
DisableFlagsInUseLine: true,
Short: i18n.T("Sets a user entry in kubeconfig"),
Long: create_authinfo_long,
Example: create_authinfo_example,
Short: i18n.T("Sets a user entry in kubeconfig"),
Long: create_authinfo_long,
Example: create_authinfo_example,
Run: func(cmd *cobra.Command, args []string) {
err := options.complete(cmd, out)
if err != nil {

View File

@ -36,6 +36,7 @@ func stringFlagFor(s string) flag.StringFlag {
func TestCreateAuthInfoOptions(t *testing.T) {
tests := []struct {
name string
flags []string
wantParseErr bool
wantCompleteErr bool
@ -44,6 +45,7 @@ func TestCreateAuthInfoOptions(t *testing.T) {
wantOptions *createAuthInfoOptions
}{
{
name: "test1",
flags: []string{
"me",
},
@ -52,6 +54,7 @@ func TestCreateAuthInfoOptions(t *testing.T) {
},
},
{
name: "test2",
flags: []string{
"me",
"--token=foo",
@ -62,6 +65,7 @@ func TestCreateAuthInfoOptions(t *testing.T) {
},
},
{
name: "test3",
flags: []string{
"me",
"--username=jane",
@ -74,6 +78,7 @@ func TestCreateAuthInfoOptions(t *testing.T) {
},
},
{
name: "test4",
// Cannot provide both token and basic auth.
flags: []string{
"me",
@ -84,6 +89,7 @@ func TestCreateAuthInfoOptions(t *testing.T) {
wantValidateErr: true,
},
{
name: "test5",
flags: []string{
"--auth-provider=oidc",
"--auth-provider-arg=client-id=foo",
@ -101,6 +107,7 @@ func TestCreateAuthInfoOptions(t *testing.T) {
},
},
{
name: "test6",
flags: []string{
"--auth-provider=oidc",
"--auth-provider-arg=client-id-",
@ -118,6 +125,7 @@ func TestCreateAuthInfoOptions(t *testing.T) {
},
},
{
name: "test7",
flags: []string{
"--auth-provider-arg=client-id-", // auth provider name not required
"--auth-provider-arg=client-secret-",
@ -133,6 +141,7 @@ func TestCreateAuthInfoOptions(t *testing.T) {
},
},
{
name: "test8",
flags: []string{
"--auth-provider=oidc",
"--auth-provider-arg=client-id", // values must be of form 'key=value' or 'key-'
@ -141,6 +150,7 @@ func TestCreateAuthInfoOptions(t *testing.T) {
wantCompleteErr: true,
},
{
name: "test9",
flags: []string{
// No name for authinfo provided.
},
@ -148,48 +158,50 @@ func TestCreateAuthInfoOptions(t *testing.T) {
},
}
for i, test := range tests {
buff := new(bytes.Buffer)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
buff := new(bytes.Buffer)
opts := new(createAuthInfoOptions)
cmd := newCmdConfigSetAuthInfo(buff, opts)
if err := cmd.ParseFlags(test.flags); err != nil {
if !test.wantParseErr {
t.Errorf("case %d: parsing error for flags %q: %v: %s", i, test.flags, err, buff)
opts := new(createAuthInfoOptions)
cmd := newCmdConfigSetAuthInfo(buff, opts)
if err := cmd.ParseFlags(tt.flags); err != nil {
if !tt.wantParseErr {
t.Errorf("case %s: parsing error for flags %q: %v: %s", tt.name, tt.flags, err, buff)
}
return
}
continue
}
if test.wantParseErr {
t.Errorf("case %d: expected parsing error for flags %q: %s", i, test.flags, buff)
continue
}
if err := opts.complete(cmd, buff); err != nil {
if !test.wantCompleteErr {
t.Errorf("case %d: complete() error for flags %q: %s", i, test.flags, buff)
if tt.wantParseErr {
t.Errorf("case %s: expected parsing error for flags %q: %s", tt.name, tt.flags, buff)
return
}
continue
}
if test.wantCompleteErr {
t.Errorf("case %d: complete() expected errors for flags %q: %s", i, test.flags, buff)
continue
}
if err := opts.validate(); err != nil {
if !test.wantValidateErr {
t.Errorf("case %d: flags %q: validate failed: %v", i, test.flags, err)
if err := opts.complete(cmd, buff); err != nil {
if !tt.wantCompleteErr {
t.Errorf("case %s: complete() error for flags %q: %s", tt.name, tt.flags, buff)
}
return
}
if tt.wantCompleteErr {
t.Errorf("case %s: complete() expected errors for flags %q: %s", tt.name, tt.flags, buff)
return
}
continue
}
if test.wantValidateErr {
t.Errorf("case %d: flags %q: expected validate to fail", i, test.flags)
continue
}
if err := opts.validate(); err != nil {
if !tt.wantValidateErr {
t.Errorf("case %s: flags %q: validate failed: %v", tt.name, tt.flags, err)
}
return
}
if !reflect.DeepEqual(opts, test.wantOptions) {
t.Errorf("case %d: flags %q: mis-matched options,\nwanted=%#v\ngot= %#v", i, test.flags, test.wantOptions, opts)
}
if tt.wantValidateErr {
t.Errorf("case %s: flags %q: expected validate to fail", tt.name, tt.flags)
return
}
if !reflect.DeepEqual(opts, tt.wantOptions) {
t.Errorf("case %s: flags %q: mis-matched options,\nwanted=%#v\ngot= %#v", tt.name, tt.flags, tt.wantOptions, opts)
}
})
}
}

View File

@ -28,9 +28,9 @@ import (
"k8s.io/apiserver/pkg/util/flag"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
type createClusterOptions struct {
@ -63,11 +63,11 @@ func NewCmdConfigSetCluster(out io.Writer, configAccess clientcmd.ConfigAccess)
options := &createClusterOptions{configAccess: configAccess}
cmd := &cobra.Command{
Use: fmt.Sprintf("set-cluster NAME [--%v=server] [--%v=path/to/certificate/authority] [--%v=true]", clientcmd.FlagAPIServer, clientcmd.FlagCAFile, clientcmd.FlagInsecure),
Use: fmt.Sprintf("set-cluster NAME [--%v=server] [--%v=path/to/certificate/authority] [--%v=true]", clientcmd.FlagAPIServer, clientcmd.FlagCAFile, clientcmd.FlagInsecure),
DisableFlagsInUseLine: true,
Short: i18n.T("Sets a cluster entry in kubeconfig"),
Long: create_cluster_long,
Example: create_cluster_example,
Short: i18n.T("Sets a cluster entry in kubeconfig"),
Long: create_cluster_long,
Example: create_cluster_example,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.complete(cmd))
cmdutil.CheckErr(options.run())

View File

@ -26,14 +26,15 @@ import (
"k8s.io/apiserver/pkg/util/flag"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
type createContextOptions struct {
configAccess clientcmd.ConfigAccess
name string
currContext bool
cluster flag.StringFlag
authInfo flag.StringFlag
namespace flag.StringFlag
@ -54,23 +55,24 @@ func NewCmdConfigSetContext(out io.Writer, configAccess clientcmd.ConfigAccess)
options := &createContextOptions{configAccess: configAccess}
cmd := &cobra.Command{
Use: fmt.Sprintf("set-context NAME [--%v=cluster_nickname] [--%v=user_nickname] [--%v=namespace]", clientcmd.FlagClusterName, clientcmd.FlagAuthInfoName, clientcmd.FlagNamespace),
Use: fmt.Sprintf("set-context [NAME | --current] [--%v=cluster_nickname] [--%v=user_nickname] [--%v=namespace]", clientcmd.FlagClusterName, clientcmd.FlagAuthInfoName, clientcmd.FlagNamespace),
DisableFlagsInUseLine: true,
Short: i18n.T("Sets a context entry in kubeconfig"),
Long: create_context_long,
Example: create_context_example,
Short: i18n.T("Sets a context entry in kubeconfig"),
Long: create_context_long,
Example: create_context_example,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.complete(cmd))
exists, err := options.run()
name, exists, err := options.run()
cmdutil.CheckErr(err)
if exists {
fmt.Fprintf(out, "Context %q modified.\n", options.name)
fmt.Fprintf(out, "Context %q modified.\n", name)
} else {
fmt.Fprintf(out, "Context %q created.\n", options.name)
fmt.Fprintf(out, "Context %q created.\n", name)
}
},
}
cmd.Flags().BoolVar(&options.currContext, "current", options.currContext, "Modify the current context")
cmd.Flags().Var(&options.cluster, clientcmd.FlagClusterName, clientcmd.FlagClusterName+" for the context entry in kubeconfig")
cmd.Flags().Var(&options.authInfo, clientcmd.FlagAuthInfoName, clientcmd.FlagAuthInfoName+" for the context entry in kubeconfig")
cmd.Flags().Var(&options.namespace, clientcmd.FlagNamespace, clientcmd.FlagNamespace+" for the context entry in kubeconfig")
@ -78,29 +80,37 @@ func NewCmdConfigSetContext(out io.Writer, configAccess clientcmd.ConfigAccess)
return cmd
}
func (o createContextOptions) run() (bool, error) {
func (o createContextOptions) run() (string, bool, error) {
err := o.validate()
if err != nil {
return false, err
return "", false, err
}
config, err := o.configAccess.GetStartingConfig()
if err != nil {
return false, err
return "", false, err
}
startingStanza, exists := config.Contexts[o.name]
name := o.name
if o.currContext {
if len(config.CurrentContext) == 0 {
return "", false, errors.New("no current context is set")
}
name = config.CurrentContext
}
startingStanza, exists := config.Contexts[name]
if !exists {
startingStanza = clientcmdapi.NewContext()
}
context := o.modifyContext(*startingStanza)
config.Contexts[o.name] = &context
config.Contexts[name] = &context
if err := clientcmd.ModifyConfig(o.configAccess, *config, true); err != nil {
return exists, err
return name, exists, err
}
return exists, nil
return name, exists, nil
}
func (o *createContextOptions) modifyContext(existingContext clientcmdapi.Context) clientcmdapi.Context {
@ -121,17 +131,21 @@ func (o *createContextOptions) modifyContext(existingContext clientcmdapi.Contex
func (o *createContextOptions) complete(cmd *cobra.Command) error {
args := cmd.Flags().Args()
if len(args) != 1 {
if len(args) > 1 {
return helpErrorf(cmd, "Unexpected args: %v", args)
}
o.name = args[0]
if len(args) == 1 {
o.name = args[0]
}
return nil
}
func (o createContextOptions) validate() error {
if len(o.name) == 0 {
return errors.New("you must specify a non-empty context name")
if len(o.name) == 0 && !o.currContext {
return errors.New("you must specify a non-empty context name or --current")
}
if len(o.name) > 0 && o.currContext {
return errors.New("you cannot specify both a context name and --current")
}
return nil

View File

@ -28,6 +28,7 @@ import (
type createContextTest struct {
description string
testContext string // name of the context being modified
config clientcmdapi.Config //initiate kubectl config
args []string //kubectl set-context args
flags []string //kubectl set-context flags
@ -38,6 +39,7 @@ type createContextTest struct {
func TestCreateContext(t *testing.T) {
conf := clientcmdapi.Config{}
test := createContextTest{
testContext: "shaker-context",
description: "Testing for create a new context",
config: conf,
args: []string{"shaker-context"},
@ -60,6 +62,7 @@ func TestModifyContext(t *testing.T) {
"shaker-context": {AuthInfo: "blue-user", Cluster: "big-cluster", Namespace: "saw-ns"},
"not-this": {AuthInfo: "blue-user", Cluster: "big-cluster", Namespace: "saw-ns"}}}
test := createContextTest{
testContext: "shaker-context",
description: "Testing for modify a already exist context",
config: conf,
args: []string{"shaker-context"},
@ -77,6 +80,32 @@ func TestModifyContext(t *testing.T) {
test.run(t)
}
func TestModifyCurrentContext(t *testing.T) {
conf := clientcmdapi.Config{
CurrentContext: "shaker-context",
Contexts: map[string]*clientcmdapi.Context{
"shaker-context": {AuthInfo: "blue-user", Cluster: "big-cluster", Namespace: "saw-ns"},
"not-this": {AuthInfo: "blue-user", Cluster: "big-cluster", Namespace: "saw-ns"}}}
test := createContextTest{
testContext: "shaker-context",
description: "Testing for modify a current context",
config: conf,
args: []string{},
flags: []string{
"--current",
"--cluster=cluster_nickname",
"--user=user_nickname",
"--namespace=namespace",
},
expected: `Context "shaker-context" modified.` + "\n",
expectedConfig: clientcmdapi.Config{
Contexts: map[string]*clientcmdapi.Context{
"shaker-context": {AuthInfo: "user_nickname", Cluster: "cluster_nickname", Namespace: "namespace"},
"not-this": {AuthInfo: "blue-user", Cluster: "big-cluster", Namespace: "saw-ns"}}},
}
test.run(t)
}
func (test createContextTest) run(t *testing.T) {
fakeKubeFile, err := ioutil.TempFile(os.TempDir(), "")
if err != nil {
@ -108,8 +137,8 @@ func (test createContextTest) run(t *testing.T) {
}
}
if test.expectedConfig.Contexts != nil {
expectContext := test.expectedConfig.Contexts[test.args[0]]
actualContext := config.Contexts[test.args[0]]
expectContext := test.expectedConfig.Contexts[test.testContext]
actualContext := config.Contexts[test.testContext]
if expectContext.AuthInfo != actualContext.AuthInfo || expectContext.Cluster != actualContext.Cluster ||
expectContext.Namespace != actualContext.Namespace {
t.Errorf("Fail in %q:\n expected Context %v\n but found %v in kubeconfig\n", test.description, expectContext, actualContext)

View File

@ -23,9 +23,9 @@ import (
"github.com/spf13/cobra"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
type CurrentContextOptions struct {

View File

@ -22,9 +22,9 @@ import (
"github.com/spf13/cobra"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
var (
@ -35,11 +35,11 @@ var (
func NewCmdConfigDeleteCluster(out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
cmd := &cobra.Command{
Use: "delete-cluster NAME",
Use: "delete-cluster NAME",
DisableFlagsInUseLine: true,
Short: i18n.T("Delete the specified cluster from the kubeconfig"),
Long: "Delete the specified cluster from the kubeconfig",
Example: delete_cluster_example,
Short: i18n.T("Delete the specified cluster from the kubeconfig"),
Long: "Delete the specified cluster from the kubeconfig",
Example: delete_cluster_example,
Run: func(cmd *cobra.Command, args []string) {
err := runDeleteCluster(out, configAccess, cmd)
cmdutil.CheckErr(err)

View File

@ -22,9 +22,9 @@ import (
"github.com/spf13/cobra"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
var (
@ -35,11 +35,11 @@ var (
func NewCmdConfigDeleteContext(out, errOut io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
cmd := &cobra.Command{
Use: "delete-context NAME",
Use: "delete-context NAME",
DisableFlagsInUseLine: true,
Short: i18n.T("Delete the specified context from the kubeconfig"),
Long: "Delete the specified context from the kubeconfig",
Example: delete_context_example,
Short: i18n.T("Delete the specified context from the kubeconfig"),
Long: "Delete the specified context from the kubeconfig",
Example: delete_context_example,
Run: func(cmd *cobra.Command, args []string) {
err := runDeleteContext(out, errOut, configAccess, cmd)
cmdutil.CheckErr(err)

View File

@ -22,9 +22,9 @@ import (
"github.com/spf13/cobra"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
var (

View File

@ -27,13 +27,13 @@ import (
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/printers"
"k8s.io/kubernetes/pkg/kubectl/util/printers"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
// GetContextsOptions contains the assignable options from the args.
@ -67,11 +67,11 @@ func NewCmdConfigGetContexts(streams genericclioptions.IOStreams, configAccess c
}
cmd := &cobra.Command{
Use: "get-contexts [(-o|--output=)name)]",
Use: "get-contexts [(-o|--output=)name)]",
DisableFlagsInUseLine: true,
Short: i18n.T("Describe one or many contexts"),
Long: getContextsLong,
Example: getContextsExample,
Short: i18n.T("Describe one or many contexts"),
Long: getContextsLong,
Example: getContextsExample,
Run: func(cmd *cobra.Command, args []string) {
validOutputTypes := sets.NewString("", "json", "yaml", "wide", "name", "custom-columns", "custom-columns-file", "go-template", "go-template-file", "jsonpath", "jsonpath-file")
supportedOutputTypes := sets.NewString("", "name")

View File

@ -21,9 +21,9 @@ import (
"os"
"testing"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
)
type getContextsTest struct {
@ -61,7 +61,7 @@ func TestGetContextsAllNoHeader(t *testing.T) {
names: []string{},
noHeader: true,
nameOnly: false,
expectedOut: "* shaker-context big-cluster blue-user saw-ns\n",
expectedOut: "* shaker-context big-cluster blue-user saw-ns\n",
}
test.run(t)
}
@ -171,7 +171,7 @@ func (test getContextsTest) run(t *testing.T) {
cmd.Run(cmd, test.names)
if len(test.expectedOut) != 0 {
if buf.String() != test.expectedOut {
t.Errorf("Expected %v, but got %v", test.expectedOut, buf.String())
t.Errorf("Expected\n%s\ngot\n%s", test.expectedOut, buf.String())
}
return
}

View File

@ -24,8 +24,8 @@ import (
"github.com/spf13/cobra"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
// RenameContextOptions contains the options for running the rename-context cli command.
@ -61,11 +61,11 @@ func NewCmdConfigRenameContext(out io.Writer, configAccess clientcmd.ConfigAcces
options := &RenameContextOptions{configAccess: configAccess}
cmd := &cobra.Command{
Use: renameContextUse,
Use: renameContextUse,
DisableFlagsInUseLine: true,
Short: renameContextShort,
Long: renameContextLong,
Example: renameContextExample,
Short: renameContextShort,
Long: renameContextLong,
Example: renameContextExample,
Run: func(cmd *cobra.Command, args []string) {
if err := options.Complete(cmd, args, out); err != nil {
cmdutil.CheckErr(err)

View File

@ -28,9 +28,9 @@ import (
"k8s.io/apiserver/pkg/util/flag"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
type setOptions struct {
@ -51,10 +51,10 @@ func NewCmdConfigSet(out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.
options := &setOptions{configAccess: configAccess}
cmd := &cobra.Command{
Use: "set PROPERTY_NAME PROPERTY_VALUE",
Use: "set PROPERTY_NAME PROPERTY_VALUE",
DisableFlagsInUseLine: true,
Short: i18n.T("Sets an individual value in a kubeconfig file"),
Long: set_long,
Short: i18n.T("Sets an individual value in a kubeconfig file"),
Long: set_long,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.complete(cmd))
cmdutil.CheckErr(options.run())

View File

@ -23,7 +23,7 @@ import (
"reflect"
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
"k8s.io/client-go/tools/clientcmd"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
@ -53,11 +53,11 @@ func NewCmdConfigUnset(out io.Writer, configAccess clientcmd.ConfigAccess) *cobr
options := &unsetOptions{configAccess: configAccess}
cmd := &cobra.Command{
Use: "unset PROPERTY_NAME",
Use: "unset PROPERTY_NAME",
DisableFlagsInUseLine: true,
Short: i18n.T("Unsets an individual value in a kubeconfig file"),
Long: unsetLong,
Example: unsetExample,
Short: i18n.T("Unsets an individual value in a kubeconfig file"),
Long: unsetLong,
Example: unsetExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.complete(cmd, args))
cmdutil.CheckErr(options.run(out))

View File

@ -25,9 +25,9 @@ import (
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
var (
@ -45,12 +45,12 @@ func NewCmdConfigUseContext(out io.Writer, configAccess clientcmd.ConfigAccess)
options := &useContextOptions{configAccess: configAccess}
cmd := &cobra.Command{
Use: "use-context CONTEXT_NAME",
Use: "use-context CONTEXT_NAME",
DisableFlagsInUseLine: true,
Short: i18n.T("Sets the current-context in a kubeconfig file"),
Aliases: []string{"use"},
Long: `Sets the current-context in a kubeconfig file`,
Example: use_context_example,
Short: i18n.T("Sets the current-context in a kubeconfig file"),
Aliases: []string{"use"},
Long: `Sets the current-context in a kubeconfig file`,
Example: use_context_example,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.complete(cmd))
cmdutil.CheckErr(options.run())

View File

@ -22,15 +22,15 @@ import (
"github.com/spf13/cobra"
"k8s.io/apiserver/pkg/util/flag"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/genericclioptions/printers"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/client-go/tools/clientcmd/api/latest"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/scheme"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/printers"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
type ViewOptions struct {
@ -70,7 +70,7 @@ var (
func NewCmdConfigView(f cmdutil.Factory, streams genericclioptions.IOStreams, ConfigAccess clientcmd.ConfigAccess) *cobra.Command {
o := &ViewOptions{
PrintFlags: genericclioptions.NewPrintFlags("").WithTypeSetter(legacyscheme.Scheme).WithDefaultOutput("yaml"),
PrintFlags: genericclioptions.NewPrintFlags("").WithTypeSetter(scheme.Scheme).WithDefaultOutput("yaml"),
ConfigAccess: ConfigAccess,
IOStreams: streams,
@ -82,7 +82,7 @@ func NewCmdConfigView(f cmdutil.Factory, streams genericclioptions.IOStreams, Co
Long: view_long,
Example: view_example,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(cmd))
cmdutil.CheckErr(o.Complete(cmd, args))
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.Run())
},
@ -99,7 +99,10 @@ func NewCmdConfigView(f cmdutil.Factory, streams genericclioptions.IOStreams, Co
return cmd
}
func (o *ViewOptions) Complete(cmd *cobra.Command) error {
func (o *ViewOptions) Complete(cmd *cobra.Command, args []string) error {
if len(args) != 0 {
return cmdutil.UsageErrorf(cmd, "unexpected arguments: %v", args)
}
if o.ConfigAccess.IsExplicitFile() {
if !o.Merge.Provided() {
o.Merge.Set("false")

View File

@ -21,10 +21,10 @@ import (
"os"
"testing"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
)
type viewClusterTest struct {

70
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/convert/BUILD generated vendored Normal file
View File

@ -0,0 +1,70 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"convert.go",
"import_known_versions.go",
],
importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/convert",
visibility = ["//visibility:public"],
deps = [
"//pkg/api/legacyscheme:go_default_library",
"//pkg/apis/apps/install:go_default_library",
"//pkg/apis/authentication/install:go_default_library",
"//pkg/apis/authorization/install:go_default_library",
"//pkg/apis/autoscaling/install:go_default_library",
"//pkg/apis/batch/install:go_default_library",
"//pkg/apis/certificates/install:go_default_library",
"//pkg/apis/coordination/install:go_default_library",
"//pkg/apis/core:go_default_library",
"//pkg/apis/core/install:go_default_library",
"//pkg/apis/events/install:go_default_library",
"//pkg/apis/extensions/install:go_default_library",
"//pkg/apis/policy/install:go_default_library",
"//pkg/apis/rbac/install:go_default_library",
"//pkg/apis/scheduling/install:go_default_library",
"//pkg/apis/settings/install:go_default_library",
"//pkg/apis/storage/install:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/util/i18n:go_default_library",
"//pkg/kubectl/util/templates:go_default_library",
"//pkg/kubectl/validation:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/printers:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/resource:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["convert_test.go"],
data = [
"//test/fixtures",
],
embed = [":go_default_library"],
deps = [
"//pkg/kubectl/cmd/testing:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library",
"//staging/src/k8s.io/client-go/rest/fake:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -14,25 +14,26 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
package convert
import (
"fmt"
"k8s.io/apimachinery/pkg/api/meta"
"github.com/spf13/cobra"
"k8s.io/klog"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/genericclioptions/printers"
"k8s.io/cli-runtime/pkg/genericclioptions/resource"
scheme "k8s.io/kubernetes/pkg/api/legacyscheme"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"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/util/i18n"
"github.com/golang/glog"
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
"k8s.io/kubernetes/pkg/kubectl/validation"
)
var (
@ -59,46 +60,20 @@ var (
kubectl convert -f . | kubectl create -f -`))
)
// NewCmdConvert creates a command object for the generic "convert" action, which
// translates the config file into a given version.
func NewCmdConvert(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
options := NewConvertOptions(ioStreams)
cmd := &cobra.Command{
Use: "convert -f FILENAME",
DisableFlagsInUseLine: true,
Short: i18n.T("Convert config files between different API versions"),
Long: convert_long,
Example: convert_example,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.Complete(f, cmd))
cmdutil.CheckErr(options.RunConvert())
},
}
options.PrintFlags.AddFlags(cmd)
usage := "to need to get converted."
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
cmd.MarkFlagRequired("filename")
cmdutil.AddValidateFlags(cmd)
cmd.Flags().BoolVar(&options.local, "local", options.local, "If true, convert will NOT try to contact api-server but run locally.")
cmd.Flags().String("output-version", "", i18n.T("Output the formatted object with the given group version (for ex: 'extensions/v1beta1').)"))
return cmd
}
// ConvertOptions have the data required to perform the convert operation
type ConvertOptions struct {
PrintFlags *genericclioptions.PrintFlags
PrintObj printers.ResourcePrinterFunc
Printer printers.ResourcePrinter
OutputVersion string
Namespace string
builder func() *resource.Builder
local bool
validator func() (validation.Schema, error)
resource.FilenameOptions
builder *resource.Builder
local bool
genericclioptions.IOStreams
specifiedOutputVersion schema.GroupVersion
}
func NewConvertOptions(ioStreams genericclioptions.IOStreams) *ConvertOptions {
@ -109,57 +84,81 @@ func NewConvertOptions(ioStreams genericclioptions.IOStreams) *ConvertOptions {
}
}
// outputVersion returns the preferred output version for generic content (JSON, YAML, or templates)
// defaultVersion is never mutated. Nil simply allows clean passing in common usage from client.Config
func outputVersion(cmd *cobra.Command) (schema.GroupVersion, error) {
outputVersionString := cmdutil.GetFlagString(cmd, "output-version")
if len(outputVersionString) == 0 {
return schema.GroupVersion{}, nil
// NewCmdConvert creates a command object for the generic "convert" action, which
// translates the config file into a given version.
func NewCmdConvert(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
o := NewConvertOptions(ioStreams)
cmd := &cobra.Command{
Use: "convert -f FILENAME",
DisableFlagsInUseLine: true,
Short: i18n.T("Convert config files between different API versions"),
Long: convert_long,
Example: convert_example,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd))
cmdutil.CheckErr(o.RunConvert())
},
}
return schema.ParseGroupVersion(outputVersionString)
cmd.Flags().BoolVar(&o.local, "local", o.local, "If true, convert will NOT try to contact api-server but run locally.")
cmd.Flags().StringVar(&o.OutputVersion, "output-version", o.OutputVersion, i18n.T("Output the formatted object with the given group version (for ex: 'extensions/v1beta1')."))
o.PrintFlags.AddFlags(cmd)
cmdutil.AddValidateFlags(cmd)
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, "to need to get converted.")
cmd.MarkFlagRequired("filename")
return cmd
}
// Complete collects information required to run Convert command from command line.
func (o *ConvertOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) (err error) {
o.specifiedOutputVersion, err = outputVersion(cmd)
o.builder = f.NewBuilder
o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()
if err != nil {
return err
}
// build the builder
o.builder = f.NewBuilder().
WithScheme(scheme.Scheme).
LocalParam(o.local)
if !o.local {
schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"))
if err != nil {
return err
}
o.builder.Schema(schema)
o.validator = func() (validation.Schema, error) {
return f.Validator(cmdutil.GetFlagBool(cmd, "validate"))
}
cmdNamespace, _, err := f.ToRawKubeConfigLoader().Namespace()
if err != nil {
return err
}
o.builder.NamespaceParam(cmdNamespace).
ContinueOnError().
FilenameParam(false, &o.FilenameOptions).
Flatten()
// build the printer
printer, err := o.PrintFlags.ToPrinter()
o.Printer, err = o.PrintFlags.ToPrinter()
if err != nil {
return err
}
o.PrintObj = printer.PrintObj
return nil
}
// RunConvert implements the generic Convert command
func (o *ConvertOptions) RunConvert() error {
r := o.builder.Do()
// Convert must be removed from kubectl, since kubectl can not depend on
// Kubernetes "internal" dependencies. These "internal" dependencies can
// not be removed from convert. Another way to convert a resource is to
// "kubectl apply" it to the cluster, then "kubectl get" at the desired version.
// Another possible solution is to make convert a plugin.
fmt.Fprintf(o.ErrOut, "kubectl convert is DEPRECATED and will be removed in a future version.\nIn order to convert, kubectl apply the object to the cluster, then kubectl get at the desired version.\n")
b := o.builder().
WithScheme(scheme.Scheme).
LocalParam(o.local)
if !o.local {
schema, err := o.validator()
if err != nil {
return err
}
b.Schema(schema)
}
r := b.NamespaceParam(o.Namespace).
ContinueOnError().
FilenameParam(false, &o.FilenameOptions).
Flatten().
Do()
err := r.Err()
if err != nil {
return err
@ -175,36 +174,22 @@ func (o *ConvertOptions) RunConvert() error {
return fmt.Errorf("no objects passed to convert")
}
objects, err := asVersionedObject(infos, !singleItemImplied, o.specifiedOutputVersion, cmdutil.InternalVersionJSONEncoder())
var specifiedOutputVersion schema.GroupVersion
if len(o.OutputVersion) > 0 {
specifiedOutputVersion, err = schema.ParseGroupVersion(o.OutputVersion)
if err != nil {
return err
}
}
internalEncoder := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
internalVersionJSONEncoder := unstructured.JSONFallbackEncoder{Encoder: internalEncoder}
objects, err := asVersionedObject(infos, !singleItemImplied, specifiedOutputVersion, internalVersionJSONEncoder)
if err != nil {
return err
}
if meta.IsListType(objects) {
obj, err := objectListToVersionedObject([]runtime.Object{objects}, o.specifiedOutputVersion)
if err != nil {
return err
}
return o.PrintObj(obj, o.Out)
}
return o.PrintObj(objects, o.Out)
}
// objectListToVersionedObject receives a list of api objects and a group version
// and squashes the list's items into a single versioned runtime.Object.
func objectListToVersionedObject(objects []runtime.Object, specifiedOutputVersion schema.GroupVersion) (runtime.Object, error) {
objectList := &api.List{Items: objects}
targetVersions := []schema.GroupVersion{}
if !specifiedOutputVersion.Empty() {
targetVersions = append(targetVersions, specifiedOutputVersion)
}
targetVersions = append(targetVersions, schema.GroupVersion{Group: "", Version: "v1"})
converted, err := tryConvert(scheme.Scheme, objectList, targetVersions...)
if err != nil {
return nil, err
}
return converted, nil
return o.Printer.PrintObj(objects, o.Out)
}
// asVersionedObject converts a list of infos into a single object - either a List containing
@ -241,7 +226,7 @@ func asVersionedObject(infos []*resource.Info, forceList bool, specifiedOutputVe
if len(actualVersion.Version) > 0 {
defaultVersionInfo = fmt.Sprintf("Defaulting to %q", actualVersion.Version)
}
glog.V(1).Infof("info: the output version specified is invalid. %s\n", defaultVersionInfo)
klog.V(1).Infof("info: the output version specified is invalid. %s\n", defaultVersionInfo)
}
return object, nil
}

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
package convert
import (
"bytes"
@ -23,9 +23,9 @@ import (
"strings"
"testing"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/rest/fake"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
)
type testcase struct {
@ -43,7 +43,7 @@ func TestConvertObject(t *testing.T) {
testcases := []testcase{
{
name: "apps deployment to extensions deployment",
file: "../../../test/fixtures/pkg/kubectl/cmd/convert/appsdeployment.yaml",
file: "../../../../test/fixtures/pkg/kubectl/cmd/convert/appsdeployment.yaml",
outputVersion: "extensions/v1beta1",
fields: []checkField{
{
@ -53,7 +53,7 @@ func TestConvertObject(t *testing.T) {
},
{
name: "extensions deployment to apps deployment",
file: "../../../test/fixtures/pkg/kubectl/cmd/convert/extensionsdeployment.yaml",
file: "../../../../test/fixtures/pkg/kubectl/cmd/convert/extensionsdeployment.yaml",
outputVersion: "apps/v1beta2",
fields: []checkField{
{
@ -63,7 +63,7 @@ func TestConvertObject(t *testing.T) {
},
{
name: "v1 HPA to v2beta1 HPA",
file: "../../../test/fixtures/pkg/kubectl/cmd/convert/v1HPA.yaml",
file: "../../../../test/fixtures/pkg/kubectl/cmd/convert/v1HPA.yaml",
outputVersion: "autoscaling/v2beta1",
fields: []checkField{
{
@ -79,7 +79,7 @@ func TestConvertObject(t *testing.T) {
},
{
name: "v2beta1 HPA to v1 HPA",
file: "../../../test/fixtures/pkg/kubectl/cmd/convert/v2beta1HPA.yaml",
file: "../../../../test/fixtures/pkg/kubectl/cmd/convert/v2beta1HPA.yaml",
outputVersion: "autoscaling/v1",
fields: []checkField{
{

View File

@ -0,0 +1,37 @@
/*
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 convert
// These imports are the API groups the client will support.
// TODO: Remove these manual install once we don't need legacy scheme in convert
import (
_ "k8s.io/kubernetes/pkg/apis/apps/install"
_ "k8s.io/kubernetes/pkg/apis/authentication/install"
_ "k8s.io/kubernetes/pkg/apis/authorization/install"
_ "k8s.io/kubernetes/pkg/apis/autoscaling/install"
_ "k8s.io/kubernetes/pkg/apis/batch/install"
_ "k8s.io/kubernetes/pkg/apis/certificates/install"
_ "k8s.io/kubernetes/pkg/apis/coordination/install"
_ "k8s.io/kubernetes/pkg/apis/core/install"
_ "k8s.io/kubernetes/pkg/apis/events/install"
_ "k8s.io/kubernetes/pkg/apis/extensions/install"
_ "k8s.io/kubernetes/pkg/apis/policy/install"
_ "k8s.io/kubernetes/pkg/apis/rbac/install"
_ "k8s.io/kubernetes/pkg/apis/scheduling/install"
_ "k8s.io/kubernetes/pkg/apis/settings/install"
_ "k8s.io/kubernetes/pkg/apis/storage/install"
)

50
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/cp/BUILD generated vendored Normal file
View File

@ -0,0 +1,50 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = ["cp.go"],
importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/cp",
visibility = ["//visibility:public"],
deps = [
"//pkg/kubectl/cmd/exec:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/util/i18n:go_default_library",
"//pkg/kubectl/util/templates:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
"//staging/src/k8s.io/client-go/rest:go_default_library",
"//vendor/github.com/renstrom/dedent:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["cp_test.go"],
embed = [":go_default_library"],
deps = [
"//pkg/kubectl/cmd/exec:go_default_library",
"//pkg/kubectl/cmd/testing:go_default_library",
"//pkg/kubectl/scheme:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library",
"//staging/src/k8s.io/client-go/rest/fake:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
package cp
import (
"archive/tar"
@ -27,12 +27,13 @@ import (
"path/filepath"
"strings"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
"k8s.io/kubernetes/pkg/kubectl/cmd/exec"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
"bytes"
@ -66,11 +67,12 @@ var (
)
type CopyOptions struct {
Container string
Namespace string
Container string
Namespace string
NoPreserve bool
ClientConfig *restclient.Config
Clientset internalclientset.Interface
Clientset kubernetes.Interface
genericclioptions.IOStreams
}
@ -86,17 +88,18 @@ func NewCmdCp(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.C
o := NewCopyOptions(ioStreams)
cmd := &cobra.Command{
Use: "cp <file-spec-src> <file-spec-dest>",
Use: "cp <file-spec-src> <file-spec-dest>",
DisableFlagsInUseLine: true,
Short: i18n.T("Copy files and directories to and from containers."),
Long: "Copy files and directories to and from containers.",
Example: cpExample,
Short: i18n.T("Copy files and directories to and from containers."),
Long: "Copy files and directories to and from containers.",
Example: cpExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd))
cmdutil.CheckErr(o.Run(args))
},
}
cmd.Flags().StringVarP(&o.Container, "container", "c", o.Container, "Container name. If omitted, the first container in the pod will be chosen")
cmd.Flags().BoolVarP(&o.NoPreserve, "no-preserve", "", false, "The copied file/directory's ownership and permissions will not be preserved in the container")
return cmd
}
@ -144,7 +147,7 @@ func (o *CopyOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
return err
}
o.Clientset, err = f.ClientSet()
o.Clientset, err = f.KubernetesClientSet()
if err != nil {
return err
}
@ -178,7 +181,7 @@ func (o *CopyOptions) Run(args []string) error {
if len(srcSpec.PodName) != 0 && len(destSpec.PodName) != 0 {
if _, err := os.Stat(args[0]); err == nil {
return o.copyToPod(fileSpec{File: args[0]}, destSpec)
return o.copyToPod(fileSpec{File: args[0]}, destSpec, &exec.ExecOptions{})
}
return fmt.Errorf("src doesn't exist in local filesystem")
}
@ -187,7 +190,7 @@ func (o *CopyOptions) Run(args []string) error {
return o.copyFromPod(srcSpec, destSpec)
}
if len(destSpec.PodName) != 0 {
return o.copyToPod(srcSpec, destSpec)
return o.copyToPod(srcSpec, destSpec, &exec.ExecOptions{})
}
return fmt.Errorf("one of src or dest must be a remote file specification")
}
@ -197,8 +200,8 @@ func (o *CopyOptions) Run(args []string) error {
// pod. If the destination path does not exist or is _not_ a
// directory, an error is returned with the exit code received.
func (o *CopyOptions) checkDestinationIsDir(dest fileSpec) error {
options := &ExecOptions{
StreamOptions: StreamOptions{
options := &exec.ExecOptions{
StreamOptions: exec.StreamOptions{
IOStreams: genericclioptions.IOStreams{
Out: bytes.NewBuffer([]byte{}),
ErrOut: bytes.NewBuffer([]byte{}),
@ -209,13 +212,13 @@ func (o *CopyOptions) checkDestinationIsDir(dest fileSpec) error {
},
Command: []string{"test", "-d", dest.File},
Executor: &DefaultRemoteExecutor{},
Executor: &exec.DefaultRemoteExecutor{},
}
return o.execute(options)
}
func (o *CopyOptions) copyToPod(src, dest fileSpec) error {
func (o *CopyOptions) copyToPod(src, dest fileSpec, options *exec.ExecOptions) error {
if len(src.File) == 0 || len(dest.File) == 0 {
return errFileCannotBeEmpty
}
@ -237,30 +240,33 @@ func (o *CopyOptions) copyToPod(src, dest fileSpec) error {
err := makeTar(src.File, dest.File, writer)
cmdutil.CheckErr(err)
}()
var cmdArr []string
// TODO: Improve error messages by first testing if 'tar' is present in the container?
cmdArr := []string{"tar", "xf", "-"}
if o.NoPreserve {
cmdArr = []string{"tar", "--no-same-permissions", "--no-same-owner", "-xf", "-"}
} else {
cmdArr = []string{"tar", "-xf", "-"}
}
destDir := path.Dir(dest.File)
if len(destDir) > 0 {
cmdArr = append(cmdArr, "-C", destDir)
}
options := &ExecOptions{
StreamOptions: StreamOptions{
IOStreams: genericclioptions.IOStreams{
In: reader,
Out: o.Out,
ErrOut: o.ErrOut,
},
Stdin: true,
Namespace: dest.PodNamespace,
PodName: dest.PodName,
options.StreamOptions = exec.StreamOptions{
IOStreams: genericclioptions.IOStreams{
In: reader,
Out: o.Out,
ErrOut: o.ErrOut,
},
Stdin: true,
Command: cmdArr,
Executor: &DefaultRemoteExecutor{},
Namespace: dest.PodNamespace,
PodName: dest.PodName,
}
options.Command = cmdArr
options.Executor = &exec.DefaultRemoteExecutor{}
return o.execute(options)
}
@ -270,8 +276,8 @@ func (o *CopyOptions) copyFromPod(src, dest fileSpec) error {
}
reader, outStream := io.Pipe()
options := &ExecOptions{
StreamOptions: StreamOptions{
options := &exec.ExecOptions{
StreamOptions: exec.StreamOptions{
IOStreams: genericclioptions.IOStreams{
In: nil,
Out: outStream,
@ -284,7 +290,7 @@ func (o *CopyOptions) copyFromPod(src, dest fileSpec) error {
// TODO: Improve error messages by first testing if 'tar' is present in the container?
Command: []string{"tar", "cf", "-", src.File},
Executor: &DefaultRemoteExecutor{},
Executor: &exec.DefaultRemoteExecutor{},
}
go func() {
@ -302,6 +308,18 @@ func (o *CopyOptions) copyFromPod(src, dest fileSpec) error {
// stripPathShortcuts removes any leading or trailing "../" from a given path
func stripPathShortcuts(p string) string {
newPath := path.Clean(p)
trimmed := strings.TrimPrefix(newPath, "../")
for trimmed != newPath {
newPath = trimmed
trimmed = strings.TrimPrefix(newPath, "../")
}
// trim leftover ".."
if newPath == ".." {
newPath = ""
}
if len(newPath) > 0 && string(newPath[0]) == "/" {
return newPath[1:]
}
@ -460,7 +478,7 @@ func getPrefix(file string) string {
return strings.TrimLeft(file, "/")
}
func (o *CopyOptions) execute(options *ExecOptions) error {
func (o *CopyOptions) execute(options *exec.ExecOptions) error {
if len(options.Namespace) == 0 {
options.Namespace = o.Namespace
}

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
package cp
import (
"archive/tar"
@ -26,6 +26,7 @@ import (
"os/exec"
"path"
"path/filepath"
"reflect"
"strings"
"testing"
@ -33,10 +34,10 @@ import (
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api/legacyscheme"
kexec "k8s.io/kubernetes/pkg/kubectl/cmd/exec"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/scheme"
)
@ -128,6 +129,62 @@ func TestGetPrefix(t *testing.T) {
}
}
func TestStripPathShortcuts(t *testing.T) {
tests := []struct {
name string
input string
expected string
}{
{
name: "test single path shortcut prefix",
input: "../foo/bar",
expected: "foo/bar",
},
{
name: "test multiple path shortcuts",
input: "../../foo/bar",
expected: "foo/bar",
},
{
name: "test multiple path shortcuts with absolute path",
input: "/tmp/one/two/../../foo/bar",
expected: "tmp/foo/bar",
},
{
name: "test multiple path shortcuts with no named directory",
input: "../../",
expected: "",
},
{
name: "test multiple path shortcuts with no named directory and no trailing slash",
input: "../..",
expected: "",
},
{
name: "test multiple path shortcuts with absolute path and filename containing leading dots",
input: "/tmp/one/two/../../foo/..bar",
expected: "tmp/foo/..bar",
},
{
name: "test multiple path shortcuts with no named directory and filename containing leading dots",
input: "../...foo",
expected: "...foo",
},
{
name: "test filename containing leading dots",
input: "...foo",
expected: "...foo",
},
}
for _, test := range tests {
out := stripPathShortcuts(test.input)
if out != test.expected {
t.Errorf("expected: %s, saw: %s", test.expected, out)
}
}
}
func TestTarUntar(t *testing.T) {
dir, err := ioutil.TempDir("", "input")
dir2, err2 := ioutil.TempDir("", "output")
@ -520,19 +577,19 @@ func TestClean(t *testing.T) {
func TestCopyToPod(t *testing.T) {
tf := cmdtesting.NewTestFactory().WithNamespace("test")
ns := legacyscheme.Codecs
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
ns := scheme.Codecs
codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
tf.Client = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},
NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
responsePod := &v1.Pod{}
return &http.Response{StatusCode: http.StatusNotFound, Header: defaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(codec, responsePod))))}, nil
return &http.Response{StatusCode: http.StatusNotFound, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(codec, responsePod))))}, nil
}),
}
tf.ClientConfigVal = defaultClientConfig()
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
ioStreams, _, _, _ := genericclioptions.NewTestIOStreams()
cmd := NewCmdCp(tf, ioStreams)
@ -574,7 +631,7 @@ func TestCopyToPod(t *testing.T) {
}
opts.Complete(tf, cmd)
t.Run(name, func(t *testing.T) {
err = opts.copyToPod(src, dest)
err = opts.copyToPod(src, dest, &kexec.ExecOptions{})
//If error is NotFound error , it indicates that the
//request has been sent correctly.
//Treat this as no error.
@ -588,6 +645,68 @@ func TestCopyToPod(t *testing.T) {
}
}
func TestCopyToPodNoPreserve(t *testing.T) {
tf := cmdtesting.NewTestFactory().WithNamespace("test")
ns := scheme.Codecs
codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
tf.Client = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},
NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
responsePod := &v1.Pod{}
return &http.Response{StatusCode: http.StatusNotFound, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(codec, responsePod))))}, nil
}),
}
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
ioStreams, _, _, _ := genericclioptions.NewTestIOStreams()
cmd := NewCmdCp(tf, ioStreams)
srcFile, err := ioutil.TempDir("", "test")
if err != nil {
t.Errorf("unexpected error: %v", err)
t.FailNow()
}
defer os.RemoveAll(srcFile)
tests := map[string]struct {
expectedCmd []string
nopreserve bool
}{
"copy to pod no preserve user and permissions": {
expectedCmd: []string{"tar", "--no-same-permissions", "--no-same-owner", "-xf", "-", "-C", "."},
nopreserve: true,
},
"copy to pod preserve user and permissions": {
expectedCmd: []string{"tar", "-xf", "-", "-C", "."},
nopreserve: false,
},
}
opts := NewCopyOptions(ioStreams)
src := fileSpec{
File: srcFile,
}
dest := fileSpec{
PodNamespace: "pod-ns",
PodName: "pod-name",
File: "foo",
}
opts.Complete(tf, cmd)
for name, test := range tests {
t.Run(name, func(t *testing.T) {
options := &kexec.ExecOptions{}
opts.NoPreserve = test.nopreserve
err = opts.copyToPod(src, dest, options)
if !(reflect.DeepEqual(test.expectedCmd, options.Command)) {
t.Errorf("expected cmd: %v, got: %v", test.expectedCmd, options.Command)
}
})
}
}
func TestValidate(t *testing.T) {
tests := []struct {
name string

View File

@ -22,32 +22,33 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/create",
visibility = ["//build/visible_to:pkg_kubectl_cmd_create_CONSUMERS"],
deps = [
"//pkg/api/legacyscheme:go_default_library",
"//pkg/kubectl:go_default_library",
"//pkg/kubectl/cmd/templates:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/cmd/util/editor:go_default_library",
"//pkg/kubectl/genericclioptions:go_default_library",
"//pkg/kubectl/genericclioptions/resource:go_default_library",
"//pkg/kubectl/generate:go_default_library",
"//pkg/kubectl/generate/versioned:go_default_library",
"//pkg/kubectl/scheme:go_default_library",
"//pkg/kubectl/util/i18n:go_default_library",
"//pkg/printers:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//pkg/kubectl/util/templates:go_default_library",
"//staging/src/k8s.io/api/batch/v1:go_default_library",
"//staging/src/k8s.io/api/batch/v1beta1:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/api/rbac/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/flag:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/printers:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/resource:go_default_library",
"//staging/src/k8s.io/client-go/dynamic:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/typed/batch/v1:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/typed/rbac/v1:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/k8s.io/api/batch/v1:go_default_library",
"//vendor/k8s.io/api/batch/v1beta1:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/rbac/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured: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/util/sets:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/flag:go_default_library",
"//vendor/k8s.io/client-go/dynamic:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/typed/batch/v1:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/typed/rbac/v1:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
],
)
@ -75,30 +76,24 @@ go_test(
],
embed = [":go_default_library"],
deps = [
"//pkg/api/legacyscheme:go_default_library",
"//pkg/api/testing:go_default_library",
"//pkg/apis/core:go_default_library",
"//pkg/kubectl:go_default_library",
"//pkg/kubectl/cmd/testing:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/genericclioptions:go_default_library",
"//pkg/kubectl/genericclioptions/resource:go_default_library",
"//pkg/kubectl/generate/versioned:go_default_library",
"//pkg/kubectl/scheme:go_default_library",
"//staging/src/k8s.io/api/batch/v1:go_default_library",
"//staging/src/k8s.io/api/batch/v1beta1:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/api/rbac/v1:go_default_library",
"//staging/src/k8s.io/api/rbac/v1beta1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/resource:go_default_library",
"//staging/src/k8s.io/client-go/rest:go_default_library",
"//staging/src/k8s.io/client-go/rest/fake:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library",
"//vendor/k8s.io/api/batch/v1:go_default_library",
"//vendor/k8s.io/api/batch/v1beta1:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/rbac/v1:go_default_library",
"//vendor/k8s.io/api/rbac/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1: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/util/diff:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library",
"//vendor/k8s.io/client-go/rest/fake:go_default_library",
"//vendor/k8s.io/client-go/testing:go_default_library",
],
)

View File

@ -24,23 +24,25 @@ import (
"runtime"
"strings"
"github.com/golang/glog"
"github.com/spf13/cobra"
"k8s.io/klog"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
kruntime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/genericclioptions/printers"
"k8s.io/cli-runtime/pkg/genericclioptions/resource"
"k8s.io/client-go/dynamic"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/cmd/util/editor"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
"k8s.io/kubernetes/pkg/kubectl/generate"
"k8s.io/kubernetes/pkg/kubectl/scheme"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/printers"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
type CreateOptions struct {
@ -79,7 +81,7 @@ var (
func NewCreateOptions(ioStreams genericclioptions.IOStreams) *CreateOptions {
return &CreateOptions{
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
RecordFlags: genericclioptions.NewRecordFlags(),
Recorder: genericclioptions.NoopRecorder{},
@ -92,11 +94,11 @@ func NewCmdCreate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cob
o := NewCreateOptions(ioStreams)
cmd := &cobra.Command{
Use: "create -f FILENAME",
Use: "create -f FILENAME",
DisableFlagsInUseLine: true,
Short: i18n.T("Create a resource from a file or from stdin."),
Long: createLong,
Example: createExample,
Short: i18n.T("Create a resource from a file or from stdin."),
Long: createLong,
Example: createExample,
Run: func(cmd *cobra.Command, args []string) {
if cmdutil.IsFilenameSliceEmpty(o.FilenameOptions.Filenames) {
defaultRunFunc := cmdutil.DefaultSubCommandRun(ioStreams.ErrOut)
@ -209,7 +211,7 @@ func (o *CreateOptions) RunCreate(f cmdutil.Factory, cmd *cobra.Command) error {
}
if o.EditBeforeCreate {
return RunEditOnCreate(f, o.RecordFlags, o.IOStreams, cmd, &o.FilenameOptions)
return RunEditOnCreate(f, o.PrintFlags, o.RecordFlags, o.IOStreams, cmd, &o.FilenameOptions)
}
schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"))
if err != nil {
@ -240,12 +242,12 @@ func (o *CreateOptions) RunCreate(f cmdutil.Factory, cmd *cobra.Command) error {
if err != nil {
return err
}
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info.Object, cmdutil.InternalVersionJSONEncoder()); err != nil {
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info.Object, scheme.DefaultJSONEncoder()); err != nil {
return cmdutil.AddSourceToErr("creating", info.Source, err)
}
if err := o.Recorder.Record(info.Object); err != nil {
glog.V(4).Infof("error recording current command: %v", err)
klog.V(4).Infof("error recording current command: %v", err)
}
if !o.DryRun {
@ -298,13 +300,13 @@ func (o *CreateOptions) raw(f cmdutil.Factory) error {
return nil
}
func RunEditOnCreate(f cmdutil.Factory, recordFlags *genericclioptions.RecordFlags, ioStreams genericclioptions.IOStreams, cmd *cobra.Command, options *resource.FilenameOptions) error {
func RunEditOnCreate(f cmdutil.Factory, printFlags *genericclioptions.PrintFlags, recordFlags *genericclioptions.RecordFlags, ioStreams genericclioptions.IOStreams, cmd *cobra.Command, options *resource.FilenameOptions) error {
editOptions := editor.NewEditOptions(editor.EditBeforeCreateMode, ioStreams)
editOptions.FilenameOptions = *options
editOptions.ValidateOptions = cmdutil.ValidateOptions{
EnableValidation: cmdutil.GetFlagBool(cmd, "validate"),
}
editOptions.Output = cmdutil.GetFlagString(cmd, "output")
editOptions.PrintFlags = printFlags
editOptions.ApplyAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag)
editOptions.RecordFlags = recordFlags
@ -317,7 +319,7 @@ func RunEditOnCreate(f cmdutil.Factory, recordFlags *genericclioptions.RecordFla
// createAndRefresh creates an object from input info and refreshes info with that object
func createAndRefresh(info *resource.Info) error {
obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object, nil)
if err != nil {
return err
}
@ -327,8 +329,13 @@ func createAndRefresh(info *resource.Info) error {
// NameFromCommandArgs is a utility function for commands that assume the first argument is a resource name
func NameFromCommandArgs(cmd *cobra.Command, args []string) (string, error) {
if len(args) != 1 {
return "", cmdutil.UsageErrorf(cmd, "exactly one NAME is required, got %d", len(args))
argsLen := cmd.ArgsLenAtDash()
// ArgsLenAtDash returns -1 when -- was not specified
if argsLen == -1 {
argsLen = len(args)
}
if argsLen != 1 {
return "", cmdutil.UsageErrorf(cmd, "exactly one NAME is required, got %d", argsLen)
}
return args[0], nil
}
@ -340,7 +347,7 @@ type CreateSubcommandOptions struct {
// Name of resource being created
Name string
// StructuredGenerator is the resource generator for the object being created
StructuredGenerator kubectl.StructuredGenerator
StructuredGenerator generate.StructuredGenerator
// DryRun is true if the command should be simulated but not run against the server
DryRun bool
CreateAnnotation bool
@ -358,12 +365,12 @@ type CreateSubcommandOptions struct {
func NewCreateSubcommandOptions(ioStreams genericclioptions.IOStreams) *CreateSubcommandOptions {
return &CreateSubcommandOptions{
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
IOStreams: ioStreams,
}
}
func (o *CreateSubcommandOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string, generator kubectl.StructuredGenerator) error {
func (o *CreateSubcommandOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string, generator generate.StructuredGenerator) error {
name, err := NameFromCommandArgs(cmd, args)
if err != nil {
return err
@ -412,7 +419,7 @@ func (o *CreateSubcommandOptions) Run() error {
}
if !o.DryRun {
// create subcommands have compiled knowledge of things they create, so type them directly
gvks, _, err := legacyscheme.Scheme.ObjectKinds(obj)
gvks, _, err := scheme.Scheme.ObjectKinds(obj)
if err != nil {
return err
}
@ -422,19 +429,19 @@ func (o *CreateSubcommandOptions) Run() error {
return err
}
if err := kubectl.CreateOrUpdateAnnotation(o.CreateAnnotation, obj, cmdutil.InternalVersionJSONEncoder()); err != nil {
if err := kubectl.CreateOrUpdateAnnotation(o.CreateAnnotation, obj, scheme.DefaultJSONEncoder()); err != nil {
return err
}
asUnstructured := &unstructured.Unstructured{}
if err := legacyscheme.Scheme.Convert(obj, asUnstructured, nil); err != nil {
if err := scheme.Scheme.Convert(obj, asUnstructured, nil); err != nil {
return err
}
if mapping.Scope.Name() == meta.RESTScopeNameRoot {
o.Namespace = ""
}
actualObject, err := o.DynamicClient.Resource(mapping.Resource).Namespace(o.Namespace).Create(asUnstructured)
actualObject, err := o.DynamicClient.Resource(mapping.Resource).Namespace(o.Namespace).Create(asUnstructured, metav1.CreateOptions{})
if err != nil {
return err
}

View File

@ -25,10 +25,10 @@ import (
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilflag "k8s.io/apiserver/pkg/util/flag"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
"k8s.io/cli-runtime/pkg/genericclioptions"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
var (
@ -71,11 +71,11 @@ func NewCmdCreateClusterRole(f cmdutil.Factory, ioStreams genericclioptions.IOSt
AggregationRule: map[string]string{},
}
cmd := &cobra.Command{
Use: "clusterrole NAME --verb=verb --resource=resource.group [--resource-name=resourcename] [--dry-run]",
Use: "clusterrole NAME --verb=verb --resource=resource.group [--resource-name=resourcename] [--dry-run]",
DisableFlagsInUseLine: true,
Short: clusterRoleLong,
Long: clusterRoleLong,
Example: clusterRoleExample,
Short: clusterRoleLong,
Long: clusterRoleLong,
Example: clusterRoleExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(c.Complete(f, cmd, args))
cmdutil.CheckErr(c.Validate())

View File

@ -24,12 +24,9 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
restclient "k8s.io/client-go/rest"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api/legacyscheme"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/scheme"
)
@ -40,7 +37,7 @@ func TestCreateClusterRole(t *testing.T) {
defer tf.Cleanup()
tf.Client = &fake.RESTClient{}
tf.ClientConfigVal = defaultClientConfig()
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
tests := map[string]struct {
verbs string
@ -166,7 +163,7 @@ func TestCreateClusterRole(t *testing.T) {
}
cmd.Run(cmd, []string{clusterRoleName})
actual := &rbac.ClusterRole{}
if err := runtime.DecodeInto(legacyscheme.Codecs.UniversalDecoder(), buf.Bytes(), actual); err != nil {
if err := runtime.DecodeInto(scheme.Codecs.UniversalDecoder(), buf.Bytes(), actual); err != nil {
t.Log(string(buf.Bytes()))
t.Fatal(err)
}
@ -515,14 +512,3 @@ func TestClusterRoleValidate(t *testing.T) {
})
}
}
func defaultClientConfig() *restclient.Config {
return &restclient.Config{
APIPath: "/api",
ContentConfig: restclient.ContentConfig{
NegotiatedSerializer: scheme.Codecs,
ContentType: runtime.ContentTypeJSON,
GroupVersion: &schema.GroupVersion{Version: "v1"},
},
}
}

View File

@ -19,11 +19,12 @@ package create
import (
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
"k8s.io/cli-runtime/pkg/genericclioptions"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/generate"
generateversioned "k8s.io/kubernetes/pkg/kubectl/generate/versioned"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
var (
@ -46,11 +47,11 @@ func NewCmdCreateClusterRoleBinding(f cmdutil.Factory, ioStreams genericclioptio
}
cmd := &cobra.Command{
Use: "clusterrolebinding NAME --clusterrole=NAME [--user=username] [--group=groupname] [--serviceaccount=namespace:serviceaccountname] [--dry-run]",
Use: "clusterrolebinding NAME --clusterrole=NAME [--user=username] [--group=groupname] [--serviceaccount=namespace:serviceaccountname] [--dry-run]",
DisableFlagsInUseLine: true,
Short: i18n.T("Create a ClusterRoleBinding for a particular ClusterRole"),
Long: clusterRoleBindingLong,
Example: clusterRoleBindingExample,
Short: i18n.T("Create a ClusterRoleBinding for a particular ClusterRole"),
Long: clusterRoleBindingLong,
Example: clusterRoleBindingExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.Complete(f, cmd, args))
cmdutil.CheckErr(options.Run())
@ -61,12 +62,12 @@ func NewCmdCreateClusterRoleBinding(f cmdutil.Factory, ioStreams genericclioptio
cmdutil.AddApplyAnnotationFlags(cmd)
cmdutil.AddValidateFlags(cmd)
cmdutil.AddGeneratorFlags(cmd, cmdutil.ClusterRoleBindingV1GeneratorName)
cmdutil.AddGeneratorFlags(cmd, generateversioned.ClusterRoleBindingV1GeneratorName)
cmd.Flags().String("clusterrole", "", i18n.T("ClusterRole this ClusterRoleBinding should reference"))
cmd.MarkFlagCustom("clusterrole", "__kubectl_get_resource_clusterrole")
cmd.Flags().StringArray("user", []string{}, "Usernames to bind to the role")
cmd.Flags().StringArray("group", []string{}, "Groups to bind to the role")
cmd.Flags().StringArray("serviceaccount", []string{}, "Service accounts to bind to the role, in the format <namespace>:<name>")
cmd.Flags().StringArray("user", []string{}, "Usernames to bind to the clusterrole")
cmd.Flags().StringArray("group", []string{}, "Groups to bind to the clusterrole")
cmd.Flags().StringArray("serviceaccount", []string{}, "Service accounts to bind to the clusterrole, in the format <namespace>:<name>")
return cmd
}
@ -76,10 +77,10 @@ func (o *ClusterRoleBindingOpts) Complete(f cmdutil.Factory, cmd *cobra.Command,
return err
}
var generator kubectl.StructuredGenerator
var generator generate.StructuredGenerator
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
case cmdutil.ClusterRoleBindingV1GeneratorName:
generator = &kubectl.ClusterRoleBindingGeneratorV1{
case generateversioned.ClusterRoleBindingV1GeneratorName:
generator = &generateversioned.ClusterRoleBindingGeneratorV1{
Name: name,
ClusterRole: cmdutil.GetFlagString(cmd, "clusterrole"),
Users: cmdutil.GetFlagStringArray(cmd, "user"),

View File

@ -28,11 +28,11 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/cli-runtime/pkg/genericclioptions"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api/legacyscheme"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/scheme"
)
func TestCreateClusterRoleBinding(t *testing.T) {
@ -71,7 +71,7 @@ func TestCreateClusterRoleBinding(t *testing.T) {
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
ns := legacyscheme.Codecs
ns := scheme.Codecs
info, _ := runtime.SerializerInfoForMediaType(ns.SupportedMediaTypes(), runtime.ContentTypeJSON)
encoder := ns.EncoderForVersion(info.Serializer, groupVersion)
@ -101,7 +101,7 @@ func TestCreateClusterRoleBinding(t *testing.T) {
responseBinding := &rbac.ClusterRoleBinding{}
responseBinding.Name = "fake-binding"
return &http.Response{StatusCode: 201, Header: defaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(encoder, responseBinding))))}, nil
return &http.Response{StatusCode: 201, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(encoder, responseBinding))))}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
@ -145,9 +145,3 @@ func (c *ClusterRoleBindingRESTClient) Post() *restclient.Request {
}
return restclient.NewRequest(c, "POST", &url.URL{Host: "localhost"}, c.VersionedAPIPath, config, serializers, nil, nil, 0)
}
func defaultHeader() http.Header {
header := http.Header{}
header.Set("Content-Type", runtime.ContentTypeJSON)
return header
}

View File

@ -19,11 +19,12 @@ package create
import (
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
"k8s.io/cli-runtime/pkg/genericclioptions"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/generate"
generateversioned "k8s.io/kubernetes/pkg/kubectl/generate/versioned"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
var (
@ -67,7 +68,7 @@ func NewCmdCreateConfigMap(f cmdutil.Factory, ioStreams genericclioptions.IOStre
}
cmd := &cobra.Command{
Use: "configmap NAME [--from-file=[key=]source] [--from-literal=key1=value1] [--dry-run]",
Use: "configmap NAME [--from-file=[key=]source] [--from-literal=key1=value1] [--dry-run]",
DisableFlagsInUseLine: true,
Aliases: []string{"cm"},
Short: i18n.T("Create a configmap from a local file, directory or literal value"),
@ -83,7 +84,7 @@ func NewCmdCreateConfigMap(f cmdutil.Factory, ioStreams genericclioptions.IOStre
cmdutil.AddApplyAnnotationFlags(cmd)
cmdutil.AddValidateFlags(cmd)
cmdutil.AddGeneratorFlags(cmd, cmdutil.ConfigMapV1GeneratorName)
cmdutil.AddGeneratorFlags(cmd, generateversioned.ConfigMapV1GeneratorName)
cmd.Flags().StringSlice("from-file", []string{}, "Key file can be specified using its file path, in which case file basename will be used as configmap key, or optionally with a key and file path, in which case the given key will be used. Specifying a directory will iterate each named file in the directory whose basename is a valid configmap key.")
cmd.Flags().StringArray("from-literal", []string{}, "Specify a key and literal value to insert in configmap (i.e. mykey=somevalue)")
cmd.Flags().String("from-env-file", "", "Specify the path to a file to read lines of key=val pairs to create a configmap (i.e. a Docker .env file).")
@ -97,10 +98,10 @@ func (o *ConfigMapOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []s
return err
}
var generator kubectl.StructuredGenerator
var generator generate.StructuredGenerator
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
case cmdutil.ConfigMapV1GeneratorName:
generator = &kubectl.ConfigMapGeneratorV1{
case generateversioned.ConfigMapV1GeneratorName:
generator = &generateversioned.ConfigMapGeneratorV1{
Name: name,
FileSources: cmdutil.GetFlagStringSlice(cmd, "from-file"),
LiteralSources: cmdutil.GetFlagStringArray(cmd, "from-literal"),

View File

@ -17,19 +17,14 @@ limitations under the License.
package create
import (
"bytes"
"io"
"io/ioutil"
"net/http"
"testing"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api/legacyscheme"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/scheme"
)
@ -39,8 +34,8 @@ func TestCreateConfigMap(t *testing.T) {
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
ns := legacyscheme.Codecs
codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
ns := scheme.Codecs
tf.Client = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},
@ -48,7 +43,7 @@ func TestCreateConfigMap(t *testing.T) {
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == "/namespaces/test/configmaps" && m == "POST":
return &http.Response{StatusCode: 201, Header: defaultHeader(), Body: objBody(codec, configMap)}, nil
return &http.Response{StatusCode: 201, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, configMap)}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
@ -64,7 +59,3 @@ func TestCreateConfigMap(t *testing.T) {
t.Errorf("expected output: %s, but got: %s", expectedOutput, buf.String())
}
}
func objBody(codec runtime.Codec, obj runtime.Object) io.ReadCloser {
return ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(codec, obj))))
}

View File

@ -19,11 +19,12 @@ package create
import (
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
"k8s.io/cli-runtime/pkg/genericclioptions"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/generate"
generateversioned "k8s.io/kubernetes/pkg/kubectl/generate/versioned"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
var (
@ -48,7 +49,7 @@ func NewCmdCreateDeployment(f cmdutil.Factory, ioStreams genericclioptions.IOStr
}
cmd := &cobra.Command{
Use: "deployment NAME --image=image [--dry-run]",
Use: "deployment NAME --image=image [--dry-run]",
DisableFlagsInUseLine: true,
Aliases: []string{"deploy"},
Short: i18n.T("Create a deployment with the specified name."),
@ -77,30 +78,30 @@ func generatorFromName(
generatorName string,
imageNames []string,
deploymentName string,
) (kubectl.StructuredGenerator, bool) {
) (generate.StructuredGenerator, bool) {
switch generatorName {
case cmdutil.DeploymentBasicAppsV1GeneratorName:
generator := &kubectl.DeploymentBasicAppsGeneratorV1{
BaseDeploymentGenerator: kubectl.BaseDeploymentGenerator{
case generateversioned.DeploymentBasicAppsV1GeneratorName:
generator := &generateversioned.DeploymentBasicAppsGeneratorV1{
BaseDeploymentGenerator: generateversioned.BaseDeploymentGenerator{
Name: deploymentName,
Images: imageNames,
},
}
return generator, true
case cmdutil.DeploymentBasicAppsV1Beta1GeneratorName:
generator := &kubectl.DeploymentBasicAppsGeneratorV1Beta1{
BaseDeploymentGenerator: kubectl.BaseDeploymentGenerator{
case generateversioned.DeploymentBasicAppsV1Beta1GeneratorName:
generator := &generateversioned.DeploymentBasicAppsGeneratorV1Beta1{
BaseDeploymentGenerator: generateversioned.BaseDeploymentGenerator{
Name: deploymentName,
Images: imageNames,
},
}
return generator, true
case cmdutil.DeploymentBasicV1Beta1GeneratorName:
generator := &kubectl.DeploymentBasicGeneratorV1{
BaseDeploymentGenerator: kubectl.BaseDeploymentGenerator{
case generateversioned.DeploymentBasicV1Beta1GeneratorName:
generator := &generateversioned.DeploymentBasicGeneratorV1{
BaseDeploymentGenerator: generateversioned.BaseDeploymentGenerator{
Name: deploymentName,
Images: imageNames,
},
@ -117,7 +118,7 @@ func (o *DeploymentOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []
return err
}
clientset, err := f.ClientSet()
clientset, err := f.KubernetesClientSet()
if err != nil {
return err
}
@ -125,8 +126,8 @@ func (o *DeploymentOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []
generatorName := cmdutil.GetFlagString(cmd, "generator")
if len(generatorName) == 0 {
generatorName = cmdutil.DeploymentBasicAppsV1GeneratorName
generatorNameTemp, err := cmdutil.FallbackGeneratorNameIfNecessary(generatorName, clientset.Discovery(), o.CreateSubcommandOptions.ErrOut)
generatorName = generateversioned.DeploymentBasicAppsV1GeneratorName
generatorNameTemp, err := generateversioned.FallbackGeneratorNameIfNecessary(generatorName, clientset.Discovery(), o.CreateSubcommandOptions.ErrOut)
if err != nil {
return err
}

View File

@ -24,21 +24,20 @@ import (
"github.com/stretchr/testify/assert"
"k8s.io/cli-runtime/pkg/genericclioptions"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/kubectl"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
generateversioned "k8s.io/kubernetes/pkg/kubectl/generate/versioned"
"k8s.io/kubernetes/pkg/kubectl/scheme"
)
func Test_generatorFromName(t *testing.T) {
const (
nonsenseName = "not-a-real-generator-name"
basicName = cmdutil.DeploymentBasicV1Beta1GeneratorName
basicAppsV1Beta1Name = cmdutil.DeploymentBasicAppsV1Beta1GeneratorName
basicAppsV1Name = cmdutil.DeploymentBasicAppsV1GeneratorName
basicName = generateversioned.DeploymentBasicV1Beta1GeneratorName
basicAppsV1Beta1Name = generateversioned.DeploymentBasicAppsV1Beta1GeneratorName
basicAppsV1Name = generateversioned.DeploymentBasicAppsV1GeneratorName
deploymentName = "deployment-name"
)
imageNames := []string{"image-1", "image-2"}
@ -51,8 +50,8 @@ func Test_generatorFromName(t *testing.T) {
assert.True(t, ok)
{
expectedGenerator := &kubectl.DeploymentBasicGeneratorV1{
BaseDeploymentGenerator: kubectl.BaseDeploymentGenerator{
expectedGenerator := &generateversioned.DeploymentBasicGeneratorV1{
BaseDeploymentGenerator: generateversioned.BaseDeploymentGenerator{
Name: deploymentName,
Images: imageNames,
},
@ -64,8 +63,8 @@ func Test_generatorFromName(t *testing.T) {
assert.True(t, ok)
{
expectedGenerator := &kubectl.DeploymentBasicAppsGeneratorV1Beta1{
BaseDeploymentGenerator: kubectl.BaseDeploymentGenerator{
expectedGenerator := &generateversioned.DeploymentBasicAppsGeneratorV1Beta1{
BaseDeploymentGenerator: generateversioned.BaseDeploymentGenerator{
Name: deploymentName,
Images: imageNames,
},
@ -77,8 +76,8 @@ func Test_generatorFromName(t *testing.T) {
assert.True(t, ok)
{
expectedGenerator := &kubectl.DeploymentBasicAppsGeneratorV1{
BaseDeploymentGenerator: kubectl.BaseDeploymentGenerator{
expectedGenerator := &generateversioned.DeploymentBasicAppsGeneratorV1{
BaseDeploymentGenerator: generateversioned.BaseDeploymentGenerator{
Name: deploymentName,
Images: imageNames,
},
@ -92,7 +91,7 @@ func TestCreateDeployment(t *testing.T) {
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
ns := legacyscheme.Codecs
ns := scheme.Codecs
fakeDiscovery := "{\"kind\":\"APIResourceList\",\"apiVersion\":\"v1\",\"groupVersion\":\"apps/v1\",\"resources\":[{\"name\":\"deployments\",\"singularName\":\"\",\"namespaced\":true,\"kind\":\"Deployment\",\"verbs\":[\"create\",\"delete\",\"deletecollection\",\"get\",\"list\",\"patch\",\"update\",\"watch\"],\"shortNames\":[\"deploy\"],\"categories\":[\"all\"]}]}"
tf.Client = &fake.RESTClient{
NegotiatedSerializer: ns,
@ -122,7 +121,7 @@ func TestCreateDeploymentNoImage(t *testing.T) {
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
ns := legacyscheme.Codecs
ns := scheme.Codecs
fakeDiscovery := "{\"kind\":\"APIResourceList\",\"apiVersion\":\"v1\",\"groupVersion\":\"apps/v1\",\"resources\":[{\"name\":\"deployments\",\"singularName\":\"\",\"namespaced\":true,\"kind\":\"Deployment\",\"verbs\":[\"create\",\"delete\",\"deletecollection\",\"get\",\"list\",\"patch\",\"update\",\"watch\"],\"shortNames\":[\"deploy\"],\"categories\":[\"all\"]}]}"
tf.Client = &fake.RESTClient{
NegotiatedSerializer: ns,
@ -140,7 +139,7 @@ func TestCreateDeploymentNoImage(t *testing.T) {
cmd.Flags().Set("output", "name")
options := &DeploymentOpts{
CreateSubcommandOptions: &CreateSubcommandOptions{
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
DryRun: true,
IOStreams: ioStreams,
},

View File

@ -23,16 +23,16 @@ import (
batchv1 "k8s.io/api/batch/v1"
batchv1beta1 "k8s.io/api/batch/v1beta1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
clientbatchv1 "k8s.io/client-go/kubernetes/typed/batch/v1"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/genericclioptions/resource"
batchv1client "k8s.io/client-go/kubernetes/typed/batch/v1"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
"k8s.io/kubernetes/pkg/kubectl/scheme"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
var (
@ -40,6 +40,12 @@ var (
Create a job with the specified name.`))
jobExample = templates.Examples(i18n.T(`
# Create a job
kubectl create job my-job --image=busybox
# Create a job with command
kubectl create job my-job --image=busybox -- date
# Create a job from a CronJob named "a-cronjob"
kubectl create job test-job --from=cronjob/a-cronjob`))
)
@ -49,22 +55,23 @@ type CreateJobOptions struct {
PrintObj func(obj runtime.Object) error
Name string
From string
Name string
Image string
From string
Command []string
Namespace string
OutputFormat string
Client clientbatchv1.BatchV1Interface
DryRun bool
Builder *resource.Builder
Cmd *cobra.Command
Namespace string
Client batchv1client.BatchV1Interface
DryRun bool
Builder *resource.Builder
Cmd *cobra.Command
genericclioptions.IOStreams
}
func NewCreateJobOptions(ioStreams genericclioptions.IOStreams) *CreateJobOptions {
return &CreateJobOptions{
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
IOStreams: ioStreams,
}
}
@ -72,15 +79,15 @@ func NewCreateJobOptions(ioStreams genericclioptions.IOStreams) *CreateJobOption
// NewCmdCreateJob is a command to ease creating Jobs from CronJobs.
func NewCmdCreateJob(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
o := NewCreateJobOptions(ioStreams)
cmd := &cobra.Command{
Use: "job NAME [--from=CRONJOB]",
Use: "job NAME [--image=image --from=cronjob/name] -- [COMMAND] [args...]",
Short: jobLong,
Long: jobLong,
Example: jobExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.RunCreateJob())
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.Run())
},
}
@ -89,32 +96,39 @@ func NewCmdCreateJob(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *
cmdutil.AddApplyAnnotationFlags(cmd)
cmdutil.AddValidateFlags(cmd)
cmdutil.AddDryRunFlag(cmd)
cmd.Flags().StringVar(&o.Image, "image", o.Image, "Image name to run.")
cmd.Flags().StringVar(&o.From, "from", o.From, "The name of the resource to create a Job from (only cronjob is supported).")
return cmd
}
func (o *CreateJobOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) (err error) {
if len(args) == 0 {
return cmdutil.UsageErrorf(cmd, "NAME is required")
func (o *CreateJobOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
name, err := NameFromCommandArgs(cmd, args)
if err != nil {
return err
}
o.Name = name
if len(args) > 1 {
o.Command = args[1:]
}
clientConfig, err := f.ToRESTConfig()
if err != nil {
return err
}
o.Client, err = batchv1client.NewForConfig(clientConfig)
if err != nil {
return err
}
o.Name = args[0]
o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()
if err != nil {
return err
}
clientset, err := f.KubernetesClientSet()
if err != nil {
return err
}
o.Client = clientset.BatchV1()
o.Builder = f.NewBuilder()
o.DryRun = cmdutil.GetDryRunFlag(cmd)
o.Cmd = cmd
o.OutputFormat = cmdutil.GetFlagString(cmd, "output")
o.DryRun = cmdutil.GetDryRunFlag(cmd)
if o.DryRun {
o.PrintFlags.Complete("%s (dry run)")
}
@ -122,7 +136,6 @@ func (o *CreateJobOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
if err != nil {
return err
}
o.PrintObj = func(obj runtime.Object) error {
return printer.PrintObj(obj, o.Out)
}
@ -130,50 +143,47 @@ func (o *CreateJobOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
return nil
}
func (o *CreateJobOptions) RunCreateJob() error {
infos, err := o.Builder.
Unstructured().
NamespaceParam(o.Namespace).DefaultNamespace().
ResourceTypeOrNameArgs(false, o.From).
Flatten().
Latest().
Do().
Infos()
if err != nil {
return err
func (o *CreateJobOptions) Validate() error {
if (len(o.Image) == 0 && len(o.From) == 0) || (len(o.Image) != 0 && len(o.From) != 0) {
return fmt.Errorf("either --image or --from must be specified")
}
if len(infos) != 1 {
return fmt.Errorf("from must be an existing cronjob")
if o.Command != nil && len(o.Command) != 0 && len(o.From) != 0 {
return fmt.Errorf("cannot specify --from and command")
}
uncastVersionedObj, err := scheme.Scheme.ConvertToVersion(infos[0].Object, batchv1beta1.SchemeGroupVersion)
if err != nil {
return fmt.Errorf("from must be an existing cronjob: %v", err)
}
cronJob, ok := uncastVersionedObj.(*batchv1beta1.CronJob)
if !ok {
return fmt.Errorf("from must be an existing cronjob")
}
return o.createJob(cronJob)
return nil
}
func (o *CreateJobOptions) createJob(cronJob *batchv1beta1.CronJob) error {
annotations := make(map[string]string)
annotations["cronjob.kubernetes.io/instantiate"] = "manual"
for k, v := range cronJob.Spec.JobTemplate.Annotations {
annotations[k] = v
}
job := &batchv1.Job{
ObjectMeta: metav1.ObjectMeta{
Name: o.Name,
Namespace: o.Namespace,
Annotations: annotations,
Labels: cronJob.Spec.JobTemplate.Labels,
},
Spec: cronJob.Spec.JobTemplate.Spec,
}
func (o *CreateJobOptions) Run() error {
var job *batchv1.Job
if len(o.Image) > 0 {
job = o.createJob()
} else {
infos, err := o.Builder.
Unstructured().
NamespaceParam(o.Namespace).DefaultNamespace().
ResourceTypeOrNameArgs(false, o.From).
Flatten().
Latest().
Do().
Infos()
if err != nil {
return err
}
if len(infos) != 1 {
return fmt.Errorf("from must be an existing cronjob")
}
uncastVersionedObj, err := scheme.Scheme.ConvertToVersion(infos[0].Object, batchv1beta1.SchemeGroupVersion)
if err != nil {
return fmt.Errorf("from must be an existing cronjob: %v", err)
}
cronJob, ok := uncastVersionedObj.(*batchv1beta1.CronJob)
if !ok {
return fmt.Errorf("from must be an existing cronjob")
}
job = o.createJobFromCronJob(cronJob)
}
if !o.DryRun {
var err error
job, err = o.Client.Jobs(o.Namespace).Create(job)
@ -184,3 +194,45 @@ func (o *CreateJobOptions) createJob(cronJob *batchv1beta1.CronJob) error {
return o.PrintObj(job)
}
func (o *CreateJobOptions) createJob() *batchv1.Job {
return &batchv1.Job{
// this is ok because we know exactly how we want to be serialized
TypeMeta: metav1.TypeMeta{APIVersion: batchv1.SchemeGroupVersion.String(), Kind: "Job"},
ObjectMeta: metav1.ObjectMeta{
Name: o.Name,
},
Spec: batchv1.JobSpec{
Template: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: o.Name,
Image: o.Image,
Command: o.Command,
},
},
RestartPolicy: corev1.RestartPolicyNever,
},
},
},
}
}
func (o *CreateJobOptions) createJobFromCronJob(cronJob *batchv1beta1.CronJob) *batchv1.Job {
annotations := make(map[string]string)
annotations["cronjob.kubernetes.io/instantiate"] = "manual"
for k, v := range cronJob.Spec.JobTemplate.Annotations {
annotations[k] = v
}
return &batchv1.Job{
// this is ok because we know exactly how we want to be serialized
TypeMeta: metav1.TypeMeta{APIVersion: batchv1.SchemeGroupVersion.String(), Kind: "Job"},
ObjectMeta: metav1.ObjectMeta{
Name: o.Name,
Annotations: annotations,
Labels: cronJob.Spec.JobTemplate.Labels,
},
Spec: cronJob.Spec.JobTemplate.Spec,
}
}

View File

@ -17,121 +17,176 @@ limitations under the License.
package create
import (
"strings"
"testing"
batchv1 "k8s.io/api/batch/v1"
batchv1beta1 "k8s.io/api/batch/v1beta1"
corev1 "k8s.io/api/core/v1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
fake "k8s.io/client-go/kubernetes/fake"
clienttesting "k8s.io/client-go/testing"
"k8s.io/kubernetes/pkg/api/legacyscheme"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
)
func TestCreateJobFromCronJob(t *testing.T) {
var submittedJob *batchv1.Job
testNamespaceName := "test"
testCronJobName := "test-cronjob"
testJobName := "test-job"
testImageName := "fake"
expectedLabels := make(map[string]string)
expectedAnnotations := make(map[string]string)
expectedLabels["test-label"] = "test-value"
expectJob := &batchv1.Job{
ObjectMeta: metav1.ObjectMeta{
Namespace: testNamespaceName,
Labels: expectedLabels,
Annotations: expectedAnnotations,
func TestCreateJobValidation(t *testing.T) {
tests := map[string]struct {
image string
command []string
from string
expected string
}{
"empty flags": {
expected: "--image or --from must be specified",
},
Spec: batchv1.JobSpec{
Template: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{Image: testImageName},
"both image and from specified": {
image: "my-image",
from: "cronjob/xyz",
expected: "--image or --from must be specified",
},
"from and command specified": {
from: "cronjob/xyz",
command: []string{"test", "command"},
expected: "cannot specify --from and command",
},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
o := &CreateJobOptions{
Image: tc.image,
From: tc.from,
Command: tc.command,
}
err := o.Validate()
if err != nil && !strings.Contains(err.Error(), tc.expected) {
t.Errorf("unexpected error: %v", err)
}
})
}
}
func TestCreateJob(t *testing.T) {
jobName := "test-job"
tests := map[string]struct {
image string
command []string
expected *batchv1.Job
}{
"just image": {
image: "busybox",
expected: &batchv1.Job{
TypeMeta: metav1.TypeMeta{APIVersion: batchv1.SchemeGroupVersion.String(), Kind: "Job"},
ObjectMeta: metav1.ObjectMeta{
Name: jobName,
},
Spec: batchv1.JobSpec{
Template: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: jobName,
Image: "busybox",
},
},
RestartPolicy: corev1.RestartPolicyNever,
},
},
},
},
},
"image and command": {
image: "busybox",
command: []string{"date"},
expected: &batchv1.Job{
TypeMeta: metav1.TypeMeta{APIVersion: batchv1.SchemeGroupVersion.String(), Kind: "Job"},
ObjectMeta: metav1.ObjectMeta{
Name: jobName,
},
Spec: batchv1.JobSpec{
Template: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: jobName,
Image: "busybox",
Command: []string{"date"},
},
},
RestartPolicy: corev1.RestartPolicyNever,
},
},
},
},
},
}
cronJob := &batchv1beta1.CronJob{
ObjectMeta: metav1.ObjectMeta{
Name: testCronJobName,
Namespace: testNamespaceName,
},
Spec: batchv1beta1.CronJobSpec{
Schedule: "* * * * *",
JobTemplate: batchv1beta1.JobTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Namespace: testNamespaceName,
Labels: expectedLabels,
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
o := &CreateJobOptions{
Name: jobName,
Image: tc.image,
Command: tc.command,
}
job := o.createJob()
if !apiequality.Semantic.DeepEqual(job, tc.expected) {
t.Errorf("expected:\n%#v\ngot:\n%#v", tc.expected, job)
}
})
}
}
func TestCreateJobFromCronJob(t *testing.T) {
jobName := "test-job"
tests := map[string]struct {
from *batchv1beta1.CronJob
expected *batchv1.Job
}{
"from CronJob": {
from: &batchv1beta1.CronJob{
Spec: batchv1beta1.CronJobSpec{
JobTemplate: batchv1beta1.JobTemplateSpec{
Spec: batchv1.JobSpec{
Template: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{Image: "test-image"},
},
RestartPolicy: corev1.RestartPolicyNever,
},
},
},
},
},
},
expected: &batchv1.Job{
TypeMeta: metav1.TypeMeta{APIVersion: batchv1.SchemeGroupVersion.String(), Kind: "Job"},
ObjectMeta: metav1.ObjectMeta{
Name: jobName,
Annotations: map[string]string{"cronjob.kubernetes.io/instantiate": "manual"},
},
Spec: batchv1.JobSpec{
Template: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{Image: "test-image"},
},
RestartPolicy: corev1.RestartPolicyNever,
},
},
},
Spec: expectJob.Spec,
},
},
}
clientset := fake.Clientset{}
clientset.PrependReactor("create", "jobs", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
ca := action.(clienttesting.CreateAction)
submittedJob = ca.GetObject().(*batchv1.Job)
return true, expectJob, nil
})
f := cmdtesting.NewTestFactory()
defer f.Cleanup()
printFlags := genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme)
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
cmdOptions := &CreateJobOptions{
PrintFlags: printFlags,
Name: testJobName,
Namespace: testNamespaceName,
Client: clientset.BatchV1(),
Cmd: NewCmdCreateJob(f, ioStreams),
PrintObj: func(obj runtime.Object) error {
p, err := printFlags.ToPrinter()
if err != nil {
return err
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
o := &CreateJobOptions{
Name: jobName,
}
return p.PrintObj(obj, buf)
},
IOStreams: ioStreams,
}
err := cmdOptions.createJob(cronJob)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if submittedJob.ObjectMeta.Name != testJobName {
t.Errorf("expected '%s', got '%s'", testJobName, submittedJob.ObjectMeta.Name)
}
if l := len(submittedJob.Annotations); l != 1 {
t.Errorf("expected length of annotations array to be 1, got %d", l)
}
if v, ok := submittedJob.Annotations["cronjob.kubernetes.io/instantiate"]; !ok || v != "manual" {
t.Errorf("expected annotation cronjob.kubernetes.io/instantiate=manual to exist, got '%s'", v)
}
if l := len(submittedJob.Labels); l != 1 {
t.Errorf("expected length of labels array to be 1, got %d", l)
}
if v, ok := submittedJob.Labels["test-label"]; !ok || v != "test-value" {
t.Errorf("expected label test-label=test-value to to exist, got '%s'", v)
}
if l := len(submittedJob.Spec.Template.Spec.Containers); l != 1 {
t.Errorf("expected length of container array to be 1, got %d", l)
}
if submittedJob.Spec.Template.Spec.Containers[0].Image != testImageName {
t.Errorf("expected '%s', got '%s'", testImageName, submittedJob.Spec.Template.Spec.Containers[0].Image)
job := o.createJobFromCronJob(tc.from)
if !apiequality.Semantic.DeepEqual(job, tc.expected) {
t.Errorf("expected:\n%#v\ngot:\n%#v", tc.expected, job)
}
})
}
}

View File

@ -19,11 +19,12 @@ package create
import (
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
"k8s.io/cli-runtime/pkg/genericclioptions"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/generate"
generateversioned "k8s.io/kubernetes/pkg/kubectl/generate/versioned"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
var (
@ -46,7 +47,7 @@ func NewCmdCreateNamespace(f cmdutil.Factory, ioStreams genericclioptions.IOStre
}
cmd := &cobra.Command{
Use: "namespace NAME [--dry-run]",
Use: "namespace NAME [--dry-run]",
DisableFlagsInUseLine: true,
Aliases: []string{"ns"},
Short: i18n.T("Create a namespace with the specified name"),
@ -62,7 +63,7 @@ func NewCmdCreateNamespace(f cmdutil.Factory, ioStreams genericclioptions.IOStre
cmdutil.AddApplyAnnotationFlags(cmd)
cmdutil.AddValidateFlags(cmd)
cmdutil.AddGeneratorFlags(cmd, cmdutil.NamespaceV1GeneratorName)
cmdutil.AddGeneratorFlags(cmd, generateversioned.NamespaceV1GeneratorName)
return cmd
}
@ -73,10 +74,10 @@ func (o *NamespaceOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []s
return err
}
var generator kubectl.StructuredGenerator
var generator generate.StructuredGenerator
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
case cmdutil.NamespaceV1GeneratorName:
generator = &kubectl.NamespaceGeneratorV1{Name: name}
case generateversioned.NamespaceV1GeneratorName:
generator = &generateversioned.NamespaceGeneratorV1{Name: name}
default:
return errUnsupportedGenerator(cmd, generatorName)
}

View File

@ -22,10 +22,9 @@ import (
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api/legacyscheme"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/scheme"
)
@ -35,8 +34,8 @@ func TestCreateNamespace(t *testing.T) {
tf := cmdtesting.NewTestFactory()
defer tf.Cleanup()
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
ns := legacyscheme.Codecs
codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
ns := scheme.Codecs
tf.Client = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Version: "v1"},
@ -44,7 +43,7 @@ func TestCreateNamespace(t *testing.T) {
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == "/namespaces" && m == "POST":
return &http.Response{StatusCode: 201, Header: defaultHeader(), Body: objBody(codec, namespaceObject)}, nil
return &http.Response{StatusCode: 201, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, namespaceObject)}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil

View File

@ -19,11 +19,12 @@ package create
import (
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
"k8s.io/cli-runtime/pkg/genericclioptions"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/generate"
generateversioned "k8s.io/kubernetes/pkg/kubectl/generate/versioned"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
var (
@ -51,7 +52,7 @@ func NewCmdCreatePodDisruptionBudget(f cmdutil.Factory, ioStreams genericcliopti
}
cmd := &cobra.Command{
Use: "poddisruptionbudget NAME --selector=SELECTOR --min-available=N [--dry-run]",
Use: "poddisruptionbudget NAME --selector=SELECTOR --min-available=N [--dry-run]",
DisableFlagsInUseLine: true,
Aliases: []string{"pdb"},
Short: i18n.T("Create a pod disruption budget with the specified name."),
@ -67,7 +68,7 @@ func NewCmdCreatePodDisruptionBudget(f cmdutil.Factory, ioStreams genericcliopti
cmdutil.AddApplyAnnotationFlags(cmd)
cmdutil.AddValidateFlags(cmd)
cmdutil.AddGeneratorFlags(cmd, cmdutil.PodDisruptionBudgetV2GeneratorName)
cmdutil.AddGeneratorFlags(cmd, generateversioned.PodDisruptionBudgetV2GeneratorName)
cmd.Flags().String("min-available", "", i18n.T("The minimum number or percentage of available pods this budget requires."))
cmd.Flags().String("max-unavailable", "", i18n.T("The maximum number or percentage of unavailable pods this budget requires."))
@ -81,16 +82,16 @@ func (o *PodDisruptionBudgetOpts) Complete(f cmdutil.Factory, cmd *cobra.Command
return err
}
var generator kubectl.StructuredGenerator
var generator generate.StructuredGenerator
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
case cmdutil.PodDisruptionBudgetV1GeneratorName:
generator = &kubectl.PodDisruptionBudgetV1Generator{
case generateversioned.PodDisruptionBudgetV1GeneratorName:
generator = &generateversioned.PodDisruptionBudgetV1Generator{
Name: name,
MinAvailable: cmdutil.GetFlagString(cmd, "min-available"),
Selector: cmdutil.GetFlagString(cmd, "selector"),
}
case cmdutil.PodDisruptionBudgetV2GeneratorName:
generator = &kubectl.PodDisruptionBudgetV2Generator{
case generateversioned.PodDisruptionBudgetV2GeneratorName:
generator = &generateversioned.PodDisruptionBudgetV2Generator{
Name: name,
MinAvailable: cmdutil.GetFlagString(cmd, "min-available"),
MaxUnavailable: cmdutil.GetFlagString(cmd, "max-unavailable"),

View File

@ -23,11 +23,11 @@ import (
"testing"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/cli-runtime/pkg/genericclioptions"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api/legacyscheme"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/scheme"
)
func TestCreatePdb(t *testing.T) {
@ -35,7 +35,7 @@ func TestCreatePdb(t *testing.T) {
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
ns := legacyscheme.Codecs
ns := scheme.Codecs
tf.Client = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Group: "policy", Version: "v1beta1"},
@ -58,7 +58,7 @@ func TestCreatePdb(t *testing.T) {
cmd.Flags().Set("dry-run", "true")
cmd.Flags().Set("output", outputFormat)
printFlags := genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme)
printFlags := genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme)
printFlags.OutputFormat = &outputFormat
options := &PodDisruptionBudgetOpts{

View File

@ -19,11 +19,12 @@ package create
import (
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
"k8s.io/cli-runtime/pkg/genericclioptions"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/generate"
generateversioned "k8s.io/kubernetes/pkg/kubectl/generate/versioned"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
var (
@ -32,7 +33,7 @@ var (
pcExample = templates.Examples(i18n.T(`
# Create a priorityclass named high-priority
kubectl create priorityclass default-priority --value=1000 --description="high priority"
kubectl create priorityclass high-priority --value=1000 --description="high priority"
# Create a priorityclass named default-priority that considered as the global default priority
kubectl create priorityclass default-priority --value=1000 --global-default=true --description="default priority"`))
@ -49,7 +50,7 @@ func NewCmdCreatePriorityClass(f cmdutil.Factory, ioStreams genericclioptions.IO
}
cmd := &cobra.Command{
Use: "priorityclass NAME --value=VALUE --global-default=BOOL [--dry-run]",
Use: "priorityclass NAME --value=VALUE --global-default=BOOL [--dry-run]",
DisableFlagsInUseLine: true,
Aliases: []string{"pc"},
Short: i18n.T("Create a priorityclass with the specified name."),
@ -65,7 +66,7 @@ func NewCmdCreatePriorityClass(f cmdutil.Factory, ioStreams genericclioptions.IO
cmdutil.AddApplyAnnotationFlags(cmd)
cmdutil.AddValidateFlags(cmd)
cmdutil.AddGeneratorFlags(cmd, cmdutil.PriorityClassV1Alpha1GeneratorName)
cmdutil.AddGeneratorFlags(cmd, generateversioned.PriorityClassV1Alpha1GeneratorName)
cmd.Flags().Int32("value", 0, i18n.T("the value of this priority class."))
cmd.Flags().Bool("global-default", false, i18n.T("global-default specifies whether this PriorityClass should be considered as the default priority."))
@ -79,10 +80,10 @@ func (o *PriorityClassOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args
return err
}
var generator kubectl.StructuredGenerator
var generator generate.StructuredGenerator
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
case cmdutil.PriorityClassV1Alpha1GeneratorName:
generator = &kubectl.PriorityClassV1Generator{
case generateversioned.PriorityClassV1Alpha1GeneratorName:
generator = &generateversioned.PriorityClassV1Generator{
Name: name,
Value: cmdutil.GetFlagInt32(cmd, "value"),
GlobalDefault: cmdutil.GetFlagBool(cmd, "global-default"),

View File

@ -23,11 +23,11 @@ import (
"testing"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/cli-runtime/pkg/genericclioptions"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api/legacyscheme"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/scheme"
)
func TestCreatePriorityClass(t *testing.T) {
@ -35,7 +35,7 @@ func TestCreatePriorityClass(t *testing.T) {
tf := cmdtesting.NewTestFactory()
defer tf.Cleanup()
ns := legacyscheme.Codecs
ns := scheme.Codecs
tf.Client = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Group: "scheduling.k8s.io", Version: "v1beta1"},
@ -59,7 +59,7 @@ func TestCreatePriorityClass(t *testing.T) {
cmd.Flags().Set("dry-run", "true")
cmd.Flags().Set("output", outputFormat)
printFlags := genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme)
printFlags := genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme)
printFlags.OutputFormat = &outputFormat
options := &PriorityClassOpts{

View File

@ -19,11 +19,12 @@ package create
import (
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
"k8s.io/cli-runtime/pkg/genericclioptions"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/generate"
generateversioned "k8s.io/kubernetes/pkg/kubectl/generate/versioned"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
var (
@ -49,7 +50,7 @@ func NewCmdCreateQuota(f cmdutil.Factory, ioStreams genericclioptions.IOStreams)
}
cmd := &cobra.Command{
Use: "quota NAME [--hard=key1=value1,key2=value2] [--scopes=Scope1,Scope2] [--dry-run=bool]",
Use: "quota NAME [--hard=key1=value1,key2=value2] [--scopes=Scope1,Scope2] [--dry-run=bool]",
DisableFlagsInUseLine: true,
Aliases: []string{"resourcequota"},
Short: i18n.T("Create a quota with the specified name."),
@ -65,7 +66,7 @@ func NewCmdCreateQuota(f cmdutil.Factory, ioStreams genericclioptions.IOStreams)
cmdutil.AddApplyAnnotationFlags(cmd)
cmdutil.AddValidateFlags(cmd)
cmdutil.AddGeneratorFlags(cmd, cmdutil.ResourceQuotaV1GeneratorName)
cmdutil.AddGeneratorFlags(cmd, generateversioned.ResourceQuotaV1GeneratorName)
cmd.Flags().String("hard", "", i18n.T("A comma-delimited set of resource=quantity pairs that define a hard limit."))
cmd.Flags().String("scopes", "", i18n.T("A comma-delimited set of quota scopes that must all match each object tracked by the quota."))
return cmd
@ -77,10 +78,10 @@ func (o *QuotaOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []strin
return err
}
var generator kubectl.StructuredGenerator
var generator generate.StructuredGenerator
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
case cmdutil.ResourceQuotaV1GeneratorName:
generator = &kubectl.ResourceQuotaGeneratorV1{
case generateversioned.ResourceQuotaV1GeneratorName:
generator = &generateversioned.ResourceQuotaGeneratorV1{
Name: name,
Hard: cmdutil.GetFlagString(cmd, "hard"),
Scopes: cmdutil.GetFlagString(cmd, "scopes"),

View File

@ -20,8 +20,8 @@ import (
"testing"
"k8s.io/api/core/v1"
"k8s.io/cli-runtime/pkg/genericclioptions"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
)
func TestCreateQuota(t *testing.T) {

View File

@ -28,12 +28,12 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/cli-runtime/pkg/genericclioptions"
clientgorbacv1 "k8s.io/client-go/kubernetes/typed/rbac/v1"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/scheme"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
var (
@ -54,7 +54,7 @@ var (
kubectl create role foo --verb=get,list,watch --resource=pods,pods/status`))
// Valid resource verb list for validation.
validResourceVerbs = []string{"*", "get", "delete", "list", "create", "update", "patch", "watch", "proxy", "deletecollection", "use", "bind", "impersonate"}
validResourceVerbs = []string{"*", "get", "delete", "list", "create", "update", "patch", "watch", "proxy", "deletecollection", "use", "bind", "escalate", "impersonate"}
// Specialized verbs and GroupResources
specialVerbs = map[string][]schema.GroupResource{
@ -74,6 +74,16 @@ var (
Resource: "clusterroles",
},
},
"escalate": {
{
Group: "rbac.authorization.k8s.io",
Resource: "roles",
},
{
Group: "rbac.authorization.k8s.io",
Resource: "clusterroles",
},
},
"impersonate": {
{
Group: "",
@ -121,7 +131,7 @@ type CreateRoleOptions struct {
func NewCreateRoleOptions(ioStreams genericclioptions.IOStreams) *CreateRoleOptions {
return &CreateRoleOptions{
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
IOStreams: ioStreams,
}
@ -132,11 +142,11 @@ func NewCmdCreateRole(f cmdutil.Factory, ioStreams genericclioptions.IOStreams)
o := NewCreateRoleOptions(ioStreams)
cmd := &cobra.Command{
Use: "role NAME --verb=verb --resource=resource.group/subresource [--resource-name=resourcename] [--dry-run]",
Use: "role NAME --verb=verb --resource=resource.group/subresource [--resource-name=resourcename] [--dry-run]",
DisableFlagsInUseLine: true,
Short: roleLong,
Long: roleLong,
Example: roleExample,
Short: roleLong,
Long: roleLong,
Example: roleExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())
@ -194,6 +204,11 @@ func (o *CreateRoleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
}
resource.Resource = parts[0]
if resource.Resource == "*" && len(parts) == 1 && len(sections) == 1 {
o.Resources = []ResourceOptions{*resource}
break
}
o.Resources = append(o.Resources, *resource)
}
@ -269,6 +284,9 @@ func (o *CreateRoleOptions) validateResource() error {
if len(r.Resource) == 0 {
return fmt.Errorf("resource must be specified if apiGroup/subresource specified")
}
if r.Resource == "*" {
return nil
}
resource := schema.GroupVersionResource{Resource: r.Resource, Group: r.Group}
groupVersionResource, err := o.Mapper.ResourceFor(schema.GroupVersionResource{Resource: r.Resource, Group: r.Group})

View File

@ -25,10 +25,10 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/diff"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api/legacyscheme"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/scheme"
)
func TestCreateRole(t *testing.T) {
@ -38,7 +38,7 @@ func TestCreateRole(t *testing.T) {
defer tf.Cleanup()
tf.Client = &fake.RESTClient{}
tf.ClientConfigVal = defaultClientConfig()
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
tests := map[string]struct {
verbs string
@ -139,7 +139,7 @@ func TestCreateRole(t *testing.T) {
}
cmd.Run(cmd, []string{roleName})
actual := &rbac.Role{}
if err := runtime.DecodeInto(legacyscheme.Codecs.UniversalDecoder(), buf.Bytes(), actual); err != nil {
if err := runtime.DecodeInto(scheme.Codecs.UniversalDecoder(), buf.Bytes(), actual); err != nil {
t.Log(string(buf.Bytes()))
t.Fatal(err)
}
@ -358,28 +358,30 @@ func TestComplete(t *testing.T) {
defer tf.Cleanup()
tf.Client = &fake.RESTClient{}
tf.ClientConfigVal = defaultClientConfig()
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
cmd := NewCmdCreateRole(tf, genericclioptions.NewTestIOStreamsDiscard())
cmd.Flags().Set("resource", "pods,deployments.extensions")
defaultTestResources := "pods,deployments.extensions"
tests := map[string]struct {
params []string
resources string
roleOptions *CreateRoleOptions
expected *CreateRoleOptions
expectErr bool
}{
"test-missing-name": {
params: []string{},
params: []string{},
resources: defaultTestResources,
roleOptions: &CreateRoleOptions{
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
},
expectErr: true,
},
"test-duplicate-verbs": {
params: []string{roleName},
params: []string{roleName},
resources: defaultTestResources,
roleOptions: &CreateRoleOptions{
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
Name: roleName,
Verbs: []string{
"get",
@ -410,9 +412,10 @@ func TestComplete(t *testing.T) {
expectErr: false,
},
"test-verball": {
params: []string{roleName},
params: []string{roleName},
resources: defaultTestResources,
roleOptions: &CreateRoleOptions{
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
Name: roleName,
Verbs: []string{
"get",
@ -438,10 +441,153 @@ func TestComplete(t *testing.T) {
},
expectErr: false,
},
"test-duplicate-resourcenames": {
params: []string{roleName},
"test-allresource": {
params: []string{roleName},
resources: "*,pods",
roleOptions: &CreateRoleOptions{
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
PrintFlags: genericclioptions.NewPrintFlags("created"),
Name: roleName,
Verbs: []string{"*"},
},
expected: &CreateRoleOptions{
Name: roleName,
Verbs: []string{"*"},
Resources: []ResourceOptions{
{
Resource: "*",
},
},
ResourceNames: []string{},
},
expectErr: false,
},
"test-allresource-subresource": {
params: []string{roleName},
resources: "*/scale,pods",
roleOptions: &CreateRoleOptions{
PrintFlags: genericclioptions.NewPrintFlags("created"),
Name: roleName,
Verbs: []string{"*"},
},
expected: &CreateRoleOptions{
Name: roleName,
Verbs: []string{"*"},
Resources: []ResourceOptions{
{
Resource: "*",
SubResource: "scale",
},
{
Resource: "pods",
},
},
ResourceNames: []string{},
},
expectErr: false,
},
"test-allresrouce-allgroup": {
params: []string{roleName},
resources: "*.*,pods",
roleOptions: &CreateRoleOptions{
PrintFlags: genericclioptions.NewPrintFlags("created"),
Name: roleName,
Verbs: []string{"*"},
},
expected: &CreateRoleOptions{
Name: roleName,
Verbs: []string{"*"},
Resources: []ResourceOptions{
{
Resource: "*",
Group: "*",
},
{
Resource: "pods",
},
},
ResourceNames: []string{},
},
expectErr: false,
},
"test-allresource-allgroup-subresource": {
params: []string{roleName},
resources: "*.*/scale,pods",
roleOptions: &CreateRoleOptions{
PrintFlags: genericclioptions.NewPrintFlags("created"),
Name: roleName,
Verbs: []string{"*"},
},
expected: &CreateRoleOptions{
Name: roleName,
Verbs: []string{"*"},
Resources: []ResourceOptions{
{
Resource: "*",
Group: "*",
SubResource: "scale",
},
{
Resource: "pods",
},
},
ResourceNames: []string{},
},
expectErr: false,
},
"test-allresource-specificgroup": {
params: []string{roleName},
resources: "*.extensions,pods",
roleOptions: &CreateRoleOptions{
PrintFlags: genericclioptions.NewPrintFlags("created"),
Name: roleName,
Verbs: []string{"*"},
},
expected: &CreateRoleOptions{
Name: roleName,
Verbs: []string{"*"},
Resources: []ResourceOptions{
{
Resource: "*",
Group: "extensions",
},
{
Resource: "pods",
},
},
ResourceNames: []string{},
},
expectErr: false,
},
"test-allresource-specificgroup-subresource": {
params: []string{roleName},
resources: "*.extensions/scale,pods",
roleOptions: &CreateRoleOptions{
PrintFlags: genericclioptions.NewPrintFlags("created"),
Name: roleName,
Verbs: []string{"*"},
},
expected: &CreateRoleOptions{
Name: roleName,
Verbs: []string{"*"},
Resources: []ResourceOptions{
{
Resource: "*",
Group: "extensions",
SubResource: "scale",
},
{
Resource: "pods",
},
},
ResourceNames: []string{},
},
expectErr: false,
},
"test-duplicate-resourcenames": {
params: []string{roleName},
resources: defaultTestResources,
roleOptions: &CreateRoleOptions{
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
Name: roleName,
Verbs: []string{"*"},
ResourceNames: []string{"foo", "foo"},
@ -464,9 +610,10 @@ func TestComplete(t *testing.T) {
expectErr: false,
},
"test-valid-complete-case": {
params: []string{roleName},
params: []string{roleName},
resources: defaultTestResources,
roleOptions: &CreateRoleOptions{
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
Name: roleName,
Verbs: []string{"*"},
ResourceNames: []string{"foo"},
@ -491,6 +638,9 @@ func TestComplete(t *testing.T) {
}
for name, test := range tests {
cmd := NewCmdCreateRole(tf, genericclioptions.NewTestIOStreamsDiscard())
cmd.Flags().Set("resource", test.resources)
err := test.roleOptions.Complete(tf, cmd, test.params)
if !test.expectErr && err != nil {
t.Errorf("%s: unexpected error: %v", name, err)

View File

@ -19,11 +19,12 @@ package create
import (
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
"k8s.io/cli-runtime/pkg/genericclioptions"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/generate"
generateversioned "k8s.io/kubernetes/pkg/kubectl/generate/versioned"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
var (
@ -46,11 +47,11 @@ func NewCmdCreateRoleBinding(f cmdutil.Factory, ioStreams genericclioptions.IOSt
}
cmd := &cobra.Command{
Use: "rolebinding NAME --clusterrole=NAME|--role=NAME [--user=username] [--group=groupname] [--serviceaccount=namespace:serviceaccountname] [--dry-run]",
Use: "rolebinding NAME --clusterrole=NAME|--role=NAME [--user=username] [--group=groupname] [--serviceaccount=namespace:serviceaccountname] [--dry-run]",
DisableFlagsInUseLine: true,
Short: i18n.T("Create a RoleBinding for a particular Role or ClusterRole"),
Long: roleBindingLong,
Example: roleBindingExample,
Short: i18n.T("Create a RoleBinding for a particular Role or ClusterRole"),
Long: roleBindingLong,
Example: roleBindingExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.Complete(f, cmd, args))
cmdutil.CheckErr(options.Run())
@ -61,7 +62,7 @@ func NewCmdCreateRoleBinding(f cmdutil.Factory, ioStreams genericclioptions.IOSt
cmdutil.AddApplyAnnotationFlags(cmd)
cmdutil.AddValidateFlags(cmd)
cmdutil.AddGeneratorFlags(cmd, cmdutil.RoleBindingV1GeneratorName)
cmdutil.AddGeneratorFlags(cmd, generateversioned.RoleBindingV1GeneratorName)
cmd.Flags().String("clusterrole", "", i18n.T("ClusterRole this RoleBinding should reference"))
cmd.Flags().String("role", "", i18n.T("Role this RoleBinding should reference"))
cmd.Flags().StringArray("user", []string{}, "Usernames to bind to the role")
@ -76,10 +77,10 @@ func (o *RoleBindingOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args [
return err
}
var generator kubectl.StructuredGenerator
var generator generate.StructuredGenerator
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
case cmdutil.RoleBindingV1GeneratorName:
generator = &kubectl.RoleBindingGeneratorV1{
case generateversioned.RoleBindingV1GeneratorName:
generator = &generateversioned.RoleBindingGeneratorV1{
Name: name,
ClusterRole: cmdutil.GetFlagString(cmd, "clusterrole"),
Role: cmdutil.GetFlagString(cmd, "role"),

View File

@ -28,11 +28,11 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/cli-runtime/pkg/genericclioptions"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api/legacyscheme"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/scheme"
)
var groupVersion = schema.GroupVersion{Group: "rbac.authorization.k8s.io", Version: "v1"}
@ -73,7 +73,7 @@ func TestCreateRoleBinding(t *testing.T) {
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
ns := legacyscheme.Codecs
ns := scheme.Codecs
info, _ := runtime.SerializerInfoForMediaType(ns.SupportedMediaTypes(), runtime.ContentTypeJSON)
encoder := ns.EncoderForVersion(info.Serializer, groupVersion)
@ -103,7 +103,7 @@ func TestCreateRoleBinding(t *testing.T) {
responseBinding := &rbac.RoleBinding{}
responseBinding.Name = "fake-binding"
return &http.Response{StatusCode: 201, Header: defaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(encoder, responseBinding))))}, nil
return &http.Response{StatusCode: 201, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(encoder, responseBinding))))}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil

View File

@ -19,11 +19,12 @@ package create
import (
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
"k8s.io/cli-runtime/pkg/genericclioptions"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/generate"
generateversioned "k8s.io/kubernetes/pkg/kubectl/generate/versioned"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
)
// NewCmdCreateSecret groups subcommands to create various types of secrets
@ -83,11 +84,11 @@ func NewCmdCreateSecretGeneric(f cmdutil.Factory, ioStreams genericclioptions.IO
}
cmd := &cobra.Command{
Use: "generic NAME [--type=string] [--from-file=[key=]source] [--from-literal=key1=value1] [--dry-run]",
Use: "generic NAME [--type=string] [--from-file=[key=]source] [--from-literal=key1=value1] [--dry-run]",
DisableFlagsInUseLine: true,
Short: i18n.T("Create a secret from a local file, directory or literal value"),
Long: secretLong,
Example: secretExample,
Short: i18n.T("Create a secret from a local file, directory or literal value"),
Long: secretLong,
Example: secretExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.Complete(f, cmd, args))
cmdutil.CheckErr(options.Run())
@ -98,7 +99,7 @@ func NewCmdCreateSecretGeneric(f cmdutil.Factory, ioStreams genericclioptions.IO
cmdutil.AddApplyAnnotationFlags(cmd)
cmdutil.AddValidateFlags(cmd)
cmdutil.AddGeneratorFlags(cmd, cmdutil.SecretV1GeneratorName)
cmdutil.AddGeneratorFlags(cmd, generateversioned.SecretV1GeneratorName)
cmd.Flags().StringSlice("from-file", []string{}, "Key files can be specified using their file path, in which case a default name will be given to them, or optionally with a name and file path, in which case the given name will be used. Specifying a directory will iterate each named file in the directory that is a valid secret key.")
cmd.Flags().StringArray("from-literal", []string{}, "Specify a key and literal value to insert in secret (i.e. mykey=somevalue)")
cmd.Flags().String("from-env-file", "", "Specify the path to a file to read lines of key=val pairs to create a secret (i.e. a Docker .env file).")
@ -113,10 +114,10 @@ func (o *SecretGenericOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args
return err
}
var generator kubectl.StructuredGenerator
var generator generate.StructuredGenerator
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
case cmdutil.SecretV1GeneratorName:
generator = &kubectl.SecretGeneratorV1{
case generateversioned.SecretV1GeneratorName:
generator = &generateversioned.SecretGeneratorV1{
Name: name,
Type: cmdutil.GetFlagString(cmd, "type"),
FileSources: cmdutil.GetFlagStringSlice(cmd, "from-file"),
@ -168,11 +169,11 @@ func NewCmdCreateSecretDockerRegistry(f cmdutil.Factory, ioStreams genericcliopt
}
cmd := &cobra.Command{
Use: "docker-registry NAME --docker-username=user --docker-password=password --docker-email=email [--docker-server=string] [--from-literal=key1=value1] [--dry-run]",
Use: "docker-registry NAME --docker-username=user --docker-password=password --docker-email=email [--docker-server=string] [--from-literal=key1=value1] [--dry-run]",
DisableFlagsInUseLine: true,
Short: i18n.T("Create a secret for use with a Docker registry"),
Long: secretForDockerRegistryLong,
Example: secretForDockerRegistryExample,
Short: i18n.T("Create a secret for use with a Docker registry"),
Long: secretForDockerRegistryLong,
Example: secretForDockerRegistryExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.Complete(f, cmd, args))
cmdutil.CheckErr(options.Run())
@ -183,7 +184,7 @@ func NewCmdCreateSecretDockerRegistry(f cmdutil.Factory, ioStreams genericcliopt
cmdutil.AddApplyAnnotationFlags(cmd)
cmdutil.AddValidateFlags(cmd)
cmdutil.AddGeneratorFlags(cmd, cmdutil.SecretForDockerRegistryV1GeneratorName)
cmdutil.AddGeneratorFlags(cmd, generateversioned.SecretForDockerRegistryV1GeneratorName)
cmd.Flags().String("docker-username", "", i18n.T("Username for Docker registry authentication"))
cmd.MarkFlagRequired("docker-username")
cmd.Flags().String("docker-password", "", i18n.T("Password for Docker registry authentication"))
@ -212,10 +213,10 @@ func (o *SecretDockerRegistryOpts) Complete(f cmdutil.Factory, cmd *cobra.Comman
}
}
var generator kubectl.StructuredGenerator
var generator generate.StructuredGenerator
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
case cmdutil.SecretForDockerRegistryV1GeneratorName:
generator = &kubectl.SecretForDockerRegistryGeneratorV1{
case generateversioned.SecretForDockerRegistryV1GeneratorName:
generator = &generateversioned.SecretForDockerRegistryGeneratorV1{
Name: name,
Username: cmdutil.GetFlagString(cmd, "docker-username"),
Email: cmdutil.GetFlagString(cmd, "docker-email"),
@ -259,11 +260,11 @@ func NewCmdCreateSecretTLS(f cmdutil.Factory, ioStreams genericclioptions.IOStre
}
cmd := &cobra.Command{
Use: "tls NAME --cert=path/to/cert/file --key=path/to/key/file [--dry-run]",
Use: "tls NAME --cert=path/to/cert/file --key=path/to/key/file [--dry-run]",
DisableFlagsInUseLine: true,
Short: i18n.T("Create a TLS secret"),
Long: secretForTLSLong,
Example: secretForTLSExample,
Short: i18n.T("Create a TLS secret"),
Long: secretForTLSLong,
Example: secretForTLSExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.Complete(f, cmd, args))
cmdutil.CheckErr(options.Run())
@ -274,7 +275,7 @@ func NewCmdCreateSecretTLS(f cmdutil.Factory, ioStreams genericclioptions.IOStre
cmdutil.AddApplyAnnotationFlags(cmd)
cmdutil.AddValidateFlags(cmd)
cmdutil.AddGeneratorFlags(cmd, cmdutil.SecretForTLSV1GeneratorName)
cmdutil.AddGeneratorFlags(cmd, generateversioned.SecretForTLSV1GeneratorName)
cmd.Flags().String("cert", "", i18n.T("Path to PEM encoded public key certificate."))
cmd.Flags().String("key", "", i18n.T("Path to private key associated with given certificate."))
cmd.Flags().Bool("append-hash", false, "Append a hash of the secret to its name.")
@ -293,10 +294,10 @@ func (o *SecretTLSOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []s
return cmdutil.UsageErrorf(cmd, "flag %s is required", requiredFlag)
}
}
var generator kubectl.StructuredGenerator
var generator generate.StructuredGenerator
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
case cmdutil.SecretForTLSV1GeneratorName:
generator = &kubectl.SecretForTLSGeneratorV1{
case generateversioned.SecretForTLSV1GeneratorName:
generator = &generateversioned.SecretForTLSGeneratorV1{
Name: name,
Key: cmdutil.GetFlagString(cmd, "key"),
Cert: cmdutil.GetFlagString(cmd, "cert"),

View File

@ -22,10 +22,9 @@ import (
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api/legacyscheme"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/scheme"
)
@ -40,8 +39,8 @@ func TestCreateSecretGeneric(t *testing.T) {
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
ns := legacyscheme.Codecs
codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
ns := scheme.Codecs
tf.Client = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Version: "v1"},
@ -49,7 +48,7 @@ func TestCreateSecretGeneric(t *testing.T) {
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == "/namespaces/test/secrets" && m == "POST":
return &http.Response{StatusCode: 201, Header: defaultHeader(), Body: objBody(codec, secretObject)}, nil
return &http.Response{StatusCode: 201, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, secretObject)}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
@ -72,8 +71,8 @@ func TestCreateSecretDockerRegistry(t *testing.T) {
secretObject := &v1.Secret{}
secretObject.Name = "my-secret"
tf := cmdtesting.NewTestFactory().WithNamespace("test")
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
ns := legacyscheme.Codecs
codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
ns := scheme.Codecs
tf.Client = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Version: "v1"},
@ -81,7 +80,7 @@ func TestCreateSecretDockerRegistry(t *testing.T) {
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == "/namespaces/test/secrets" && m == "POST":
return &http.Response{StatusCode: 201, Header: defaultHeader(), Body: objBody(codec, secretObject)}, nil
return &http.Response{StatusCode: 201, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, secretObject)}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil

Some files were not shown because too many files have changed in this diff Show More