mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 10:33:35 +00:00
vendor update for CSI 0.3.0
This commit is contained in:
2
vendor/k8s.io/kubernetes/pkg/kubectl/.import-restrictions
generated
vendored
2
vendor/k8s.io/kubernetes/pkg/kubectl/.import-restrictions
generated
vendored
@ -121,7 +121,7 @@
|
||||
"k8s.io/kubernetes/pkg/scheduler/algorithm/predicates",
|
||||
"k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/util",
|
||||
"k8s.io/kubernetes/pkg/scheduler/api",
|
||||
"k8s.io/kubernetes/pkg/scheduler/schedulercache",
|
||||
"k8s.io/kubernetes/pkg/scheduler/cache",
|
||||
"k8s.io/kubernetes/pkg/scheduler/util",
|
||||
"k8s.io/kubernetes/pkg/scheduler/volumebinder",
|
||||
"k8s.io/kubernetes/pkg/security/apparmor",
|
||||
|
41
vendor/k8s.io/kubernetes/pkg/kubectl/BUILD
generated
vendored
41
vendor/k8s.io/kubernetes/pkg/kubectl/BUILD
generated
vendored
@ -12,7 +12,6 @@ go_test(
|
||||
"autoscale_test.go",
|
||||
"clusterrolebinding_test.go",
|
||||
"configmap_test.go",
|
||||
"delete_test.go",
|
||||
"deployment_test.go",
|
||||
"env_file_test.go",
|
||||
"generate_test.go",
|
||||
@ -21,7 +20,6 @@ go_test(
|
||||
"pdb_test.go",
|
||||
"priorityclass_test.go",
|
||||
"quota_test.go",
|
||||
"resource_filter_test.go",
|
||||
"rolebinding_test.go",
|
||||
"rollback_test.go",
|
||||
"rolling_updater_test.go",
|
||||
@ -34,28 +32,21 @@ go_test(
|
||||
"service_basic_test.go",
|
||||
"service_test.go",
|
||||
"serviceaccount_test.go",
|
||||
"sorting_printer_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/apps: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/client/clientset_generated/internalclientset/fake:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/typed/apps/internalversion: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/client/clientset_generated/internalclientset/typed/extensions/internalversion:go_default_library",
|
||||
"//pkg/kubectl/util:go_default_library",
|
||||
"//pkg/printers: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/apps/v1beta2: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",
|
||||
@ -74,18 +65,13 @@ go_test(
|
||||
"//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/runtime/serializer: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/uuid:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
"//vendor/k8s.io/client-go/discovery:go_default_library",
|
||||
"//vendor/k8s.io/client-go/discovery/fake:go_default_library",
|
||||
"//vendor/k8s.io/client-go/dynamic: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",
|
||||
],
|
||||
@ -96,23 +82,19 @@ go_library(
|
||||
srcs = [
|
||||
"apply.go",
|
||||
"autoscale.go",
|
||||
"bash_comp_utils.go",
|
||||
"clusterrolebinding.go",
|
||||
"conditions.go",
|
||||
"configmap.go",
|
||||
"delete.go",
|
||||
"deployment.go",
|
||||
"doc.go",
|
||||
"env_file.go",
|
||||
"generate.go",
|
||||
"history.go",
|
||||
"interfaces.go",
|
||||
"kubectl.go",
|
||||
"namespace.go",
|
||||
"pdb.go",
|
||||
"priorityclass.go",
|
||||
"quota.go",
|
||||
"resource_filter.go",
|
||||
"rolebinding.go",
|
||||
"rollback.go",
|
||||
"rolling_updater.go",
|
||||
@ -125,7 +107,7 @@ go_library(
|
||||
"service.go",
|
||||
"service_basic.go",
|
||||
"serviceaccount.go",
|
||||
"sorting_printer.go",
|
||||
"sorter.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/kubectl",
|
||||
deps = [
|
||||
@ -133,21 +115,15 @@ go_library(
|
||||
"//pkg/api/pod:go_default_library",
|
||||
"//pkg/api/v1/pod:go_default_library",
|
||||
"//pkg/apis/apps:go_default_library",
|
||||
"//pkg/apis/batch: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:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/typed/apps/internalversion: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/client/clientset_generated/internalclientset/typed/extensions/internalversion:go_default_library",
|
||||
"//pkg/controller/daemon:go_default_library",
|
||||
"//pkg/controller/deployment/util:go_default_library",
|
||||
"//pkg/controller/statefulset:go_default_library",
|
||||
"//pkg/credentialprovider:go_default_library",
|
||||
"//pkg/kubectl/apps:go_default_library",
|
||||
"//pkg/kubectl/resource:go_default_library",
|
||||
"//pkg/kubectl/util:go_default_library",
|
||||
"//pkg/kubectl/util/hash:go_default_library",
|
||||
"//pkg/kubectl/util/slice:go_default_library",
|
||||
@ -182,14 +158,11 @@ go_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/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/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/kubernetes/typed/apps/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1: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",
|
||||
@ -212,13 +185,13 @@ filegroup(
|
||||
":package-srcs",
|
||||
"//pkg/kubectl/apply:all-srcs",
|
||||
"//pkg/kubectl/apps:all-srcs",
|
||||
"//pkg/kubectl/categories:all-srcs",
|
||||
"//pkg/kubectl/cmd:all-srcs",
|
||||
"//pkg/kubectl/explain:all-srcs",
|
||||
"//pkg/kubectl/genericclioptions:all-srcs",
|
||||
"//pkg/kubectl/metricsutil:all-srcs",
|
||||
"//pkg/kubectl/plugins:all-srcs",
|
||||
"//pkg/kubectl/polymorphichelpers:all-srcs",
|
||||
"//pkg/kubectl/proxy:all-srcs",
|
||||
"//pkg/kubectl/resource:all-srcs",
|
||||
"//pkg/kubectl/scheme:all-srcs",
|
||||
"//pkg/kubectl/util:all-srcs",
|
||||
"//pkg/kubectl/validation:all-srcs",
|
||||
|
47
vendor/k8s.io/kubernetes/pkg/kubectl/apply.go
generated
vendored
47
vendor/k8s.io/kubernetes/pkg/kubectl/apply.go
generated
vendored
@ -20,13 +20,14 @@ import (
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
)
|
||||
|
||||
var metadataAccessor = meta.NewAccessor()
|
||||
|
||||
// GetOriginalConfiguration retrieves the original configuration of the object
|
||||
// from the annotation, or nil if no annotation was found.
|
||||
func GetOriginalConfiguration(mapping *meta.RESTMapping, obj runtime.Object) ([]byte, error) {
|
||||
annots, err := mapping.MetadataAccessor.Annotations(obj)
|
||||
func GetOriginalConfiguration(obj runtime.Object) ([]byte, error) {
|
||||
annots, err := metadataAccessor.Annotations(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -45,13 +46,12 @@ func GetOriginalConfiguration(mapping *meta.RESTMapping, obj runtime.Object) ([]
|
||||
|
||||
// SetOriginalConfiguration sets the original configuration of the object
|
||||
// as the annotation on the object for later use in computing a three way patch.
|
||||
func SetOriginalConfiguration(info *resource.Info, original []byte) error {
|
||||
func setOriginalConfiguration(obj runtime.Object, original []byte) error {
|
||||
if len(original) < 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
accessor := info.Mapping.MetadataAccessor
|
||||
annots, err := accessor.Annotations(info.Object)
|
||||
annots, err := metadataAccessor.Annotations(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -61,22 +61,21 @@ func SetOriginalConfiguration(info *resource.Info, original []byte) error {
|
||||
}
|
||||
|
||||
annots[v1.LastAppliedConfigAnnotation] = string(original)
|
||||
return info.Mapping.MetadataAccessor.SetAnnotations(info.Object, annots)
|
||||
return metadataAccessor.SetAnnotations(obj, annots)
|
||||
}
|
||||
|
||||
// GetModifiedConfiguration retrieves the modified configuration of the object.
|
||||
// If annotate is true, it embeds the result as an annotation in the modified
|
||||
// configuration. If an object was read from the command input, it will use that
|
||||
// version of the object. Otherwise, it will use the version from the server.
|
||||
func GetModifiedConfiguration(info *resource.Info, annotate bool, codec runtime.Encoder) ([]byte, error) {
|
||||
func GetModifiedConfiguration(obj runtime.Object, annotate bool, codec runtime.Encoder) ([]byte, error) {
|
||||
// First serialize the object without the annotation to prevent recursion,
|
||||
// then add that serialization to it as the annotation and serialize it again.
|
||||
var modified []byte
|
||||
|
||||
// Otherwise, use the server side version of the object.
|
||||
accessor := info.Mapping.MetadataAccessor
|
||||
// Get the current annotations from the object.
|
||||
annots, err := accessor.Annotations(info.Object)
|
||||
annots, err := metadataAccessor.Annotations(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -87,22 +86,22 @@ func GetModifiedConfiguration(info *resource.Info, annotate bool, codec runtime.
|
||||
|
||||
original := annots[v1.LastAppliedConfigAnnotation]
|
||||
delete(annots, v1.LastAppliedConfigAnnotation)
|
||||
if err := accessor.SetAnnotations(info.Object, annots); err != nil {
|
||||
if err := metadataAccessor.SetAnnotations(obj, annots); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
modified, err = runtime.Encode(codec, info.Object)
|
||||
modified, err = runtime.Encode(codec, obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if annotate {
|
||||
annots[v1.LastAppliedConfigAnnotation] = string(modified)
|
||||
if err := info.Mapping.MetadataAccessor.SetAnnotations(info.Object, annots); err != nil {
|
||||
if err := metadataAccessor.SetAnnotations(obj, annots); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
modified, err = runtime.Encode(codec, info.Object)
|
||||
modified, err = runtime.Encode(codec, obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -110,7 +109,7 @@ func GetModifiedConfiguration(info *resource.Info, annotate bool, codec runtime.
|
||||
|
||||
// Restore the object to its original condition.
|
||||
annots[v1.LastAppliedConfigAnnotation] = original
|
||||
if err := info.Mapping.MetadataAccessor.SetAnnotations(info.Object, annots); err != nil {
|
||||
if err := metadataAccessor.SetAnnotations(obj, annots); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -119,28 +118,28 @@ func GetModifiedConfiguration(info *resource.Info, annotate bool, codec runtime.
|
||||
|
||||
// UpdateApplyAnnotation calls CreateApplyAnnotation if the last applied
|
||||
// configuration annotation is already present. Otherwise, it does nothing.
|
||||
func UpdateApplyAnnotation(info *resource.Info, codec runtime.Encoder) error {
|
||||
if original, err := GetOriginalConfiguration(info.Mapping, info.Object); err != nil || len(original) <= 0 {
|
||||
func UpdateApplyAnnotation(obj runtime.Object, codec runtime.Encoder) error {
|
||||
if original, err := GetOriginalConfiguration(obj); err != nil || len(original) <= 0 {
|
||||
return err
|
||||
}
|
||||
return CreateApplyAnnotation(info, codec)
|
||||
return CreateApplyAnnotation(obj, codec)
|
||||
}
|
||||
|
||||
// CreateApplyAnnotation gets the modified configuration of the object,
|
||||
// without embedding it again, and then sets it on the object as the annotation.
|
||||
func CreateApplyAnnotation(info *resource.Info, codec runtime.Encoder) error {
|
||||
modified, err := GetModifiedConfiguration(info, false, codec)
|
||||
func CreateApplyAnnotation(obj runtime.Object, codec runtime.Encoder) error {
|
||||
modified, err := GetModifiedConfiguration(obj, false, codec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return SetOriginalConfiguration(info, modified)
|
||||
return setOriginalConfiguration(obj, modified)
|
||||
}
|
||||
|
||||
// Create the annotation used by kubectl apply only when createAnnotation is true
|
||||
// Otherwise, only update the annotation when it already exists
|
||||
func CreateOrUpdateAnnotation(createAnnotation bool, info *resource.Info, codec runtime.Encoder) error {
|
||||
func CreateOrUpdateAnnotation(createAnnotation bool, obj runtime.Object, codec runtime.Encoder) error {
|
||||
if createAnnotation {
|
||||
return CreateApplyAnnotation(info, codec)
|
||||
return CreateApplyAnnotation(obj, codec)
|
||||
}
|
||||
return UpdateApplyAnnotation(info, codec)
|
||||
return UpdateApplyAnnotation(obj, codec)
|
||||
}
|
||||
|
1
vendor/k8s.io/kubernetes/pkg/kubectl/apply/BUILD
generated
vendored
1
vendor/k8s.io/kubernetes/pkg/kubectl/apply/BUILD
generated
vendored
@ -6,6 +6,7 @@ go_library(
|
||||
"doc.go",
|
||||
"element.go",
|
||||
"empty_element.go",
|
||||
"error.go",
|
||||
"list_element.go",
|
||||
"map_element.go",
|
||||
"primitive_element.go",
|
||||
|
22
vendor/k8s.io/kubernetes/pkg/kubectl/apply/element.go
generated
vendored
22
vendor/k8s.io/kubernetes/pkg/kubectl/apply/element.go
generated
vendored
@ -45,7 +45,7 @@ type Element interface {
|
||||
GetRecorded() interface{}
|
||||
|
||||
// HasLocal returns true if the field was explicitly
|
||||
// present in the recorded source. This is to differentiate between
|
||||
// present in the local source. This is to differentiate between
|
||||
// undefined and set to null
|
||||
HasLocal() bool
|
||||
|
||||
@ -88,7 +88,7 @@ type FieldMetaImpl struct {
|
||||
// Type is the openapi type of the field - "list", "primitive", "map"
|
||||
Type string
|
||||
|
||||
// Name contains of the field
|
||||
// Name contains name of the field
|
||||
Name string
|
||||
}
|
||||
|
||||
@ -276,8 +276,7 @@ func (s *CombinedMapSlice) UpsertRecorded(key MergeKeys, l interface{}) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
item.recorded = l
|
||||
item.recordedSet = true
|
||||
item.SetRecorded(l)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -289,8 +288,7 @@ func (s *CombinedMapSlice) UpsertLocal(key MergeKeys, l interface{}) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
item.local = l
|
||||
item.localSet = true
|
||||
item.SetLocal(l)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -302,8 +300,7 @@ func (s *CombinedMapSlice) UpsertRemote(key MergeKeys, l interface{}) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
item.remote = l
|
||||
item.remoteSet = true
|
||||
item.SetRemote(l)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -359,13 +356,13 @@ func (b *RawElementData) SetRecorded(value interface{}) {
|
||||
b.recordedSet = true
|
||||
}
|
||||
|
||||
// SetLocal sets the recorded value
|
||||
// SetLocal sets the local value
|
||||
func (b *RawElementData) SetLocal(value interface{}) {
|
||||
b.local = value
|
||||
b.localSet = true
|
||||
}
|
||||
|
||||
// SetRemote sets the recorded value
|
||||
// SetRemote sets the remote value
|
||||
func (b *RawElementData) SetRemote(value interface{}) {
|
||||
b.remote = value
|
||||
b.remoteSet = true
|
||||
@ -419,3 +416,8 @@ func (e HasElementData) HasLocal() bool {
|
||||
func (e HasElementData) HasRemote() bool {
|
||||
return e.remoteSet
|
||||
}
|
||||
|
||||
// ConflictDetector defines the capability to detect conflict. An element can examine remote/recorded value to detect conflict.
|
||||
type ConflictDetector interface {
|
||||
HasConflict() error
|
||||
}
|
||||
|
37
vendor/k8s.io/kubernetes/pkg/kubectl/apply/error.go
generated
vendored
Normal file
37
vendor/k8s.io/kubernetes/pkg/kubectl/apply/error.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
Copyright 2017 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 apply
|
||||
|
||||
import "fmt"
|
||||
|
||||
// ConflictError represents a conflict error occurred during the merge operation.
|
||||
type ConflictError struct {
|
||||
element Element
|
||||
}
|
||||
|
||||
// NewConflictError returns a ConflictError with detailed conflict information in element
|
||||
func NewConflictError(e PrimitiveElement) *ConflictError {
|
||||
return &ConflictError{
|
||||
element: e,
|
||||
}
|
||||
}
|
||||
|
||||
// Error implements error
|
||||
func (c *ConflictError) Error() string {
|
||||
return fmt.Sprintf("conflict detected, recorded value (%+v) and remote value (%+v)",
|
||||
c.element.GetRecorded(), c.element.GetRemote())
|
||||
}
|
14
vendor/k8s.io/kubernetes/pkg/kubectl/apply/list_element.go
generated
vendored
14
vendor/k8s.io/kubernetes/pkg/kubectl/apply/list_element.go
generated
vendored
@ -65,3 +65,17 @@ func sliceCast(i interface{}) []interface{} {
|
||||
}
|
||||
return i.([]interface{})
|
||||
}
|
||||
|
||||
// HasConflict returns ConflictError if fields in recorded and remote of ListElement conflict
|
||||
func (e ListElement) HasConflict() error {
|
||||
for _, item := range e.Values {
|
||||
if item, ok := item.(ConflictDetector); ok {
|
||||
if err := item.HasConflict(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ ConflictDetector = &ListElement{}
|
||||
|
14
vendor/k8s.io/kubernetes/pkg/kubectl/apply/map_element.go
generated
vendored
14
vendor/k8s.io/kubernetes/pkg/kubectl/apply/map_element.go
generated
vendored
@ -70,3 +70,17 @@ func mapCast(i interface{}) map[string]interface{} {
|
||||
}
|
||||
return i.(map[string]interface{})
|
||||
}
|
||||
|
||||
// HasConflict returns ConflictError if some elements in map conflict.
|
||||
func (e MapElement) HasConflict() error {
|
||||
for _, item := range e.GetValues() {
|
||||
if item, ok := item.(ConflictDetector); ok {
|
||||
if err := item.HasConflict(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ ConflictDetector = &MapElement{}
|
||||
|
2
vendor/k8s.io/kubernetes/pkg/kubectl/apply/parse/util.go
generated
vendored
2
vendor/k8s.io/kubernetes/pkg/kubectl/apply/parse/util.go
generated
vendored
@ -104,7 +104,7 @@ func getFieldMeta(s proto.Schema, name string) (apply.FieldMetaImpl, error) {
|
||||
if e, found := ext["x-kubernetes-patch-strategy"]; found {
|
||||
strategy, ok := e.(string)
|
||||
if !ok {
|
||||
return apply.FieldMetaImpl{}, fmt.Errorf("Expected string for x-kubernetes-patch-strategy by got %T", s)
|
||||
return apply.FieldMetaImpl{}, fmt.Errorf("Expected string for x-kubernetes-patch-strategy by got %T", e)
|
||||
}
|
||||
|
||||
// Take the first strategy if there are substrategies.
|
||||
|
20
vendor/k8s.io/kubernetes/pkg/kubectl/apply/primitive_element.go
generated
vendored
20
vendor/k8s.io/kubernetes/pkg/kubectl/apply/primitive_element.go
generated
vendored
@ -16,6 +16,8 @@ limitations under the License.
|
||||
|
||||
package apply
|
||||
|
||||
import "reflect"
|
||||
|
||||
// PrimitiveElement contains the recorded, local and remote values for a field
|
||||
// of type primitive
|
||||
type PrimitiveElement struct {
|
||||
@ -32,3 +34,21 @@ func (e PrimitiveElement) Merge(v Strategy) (Result, error) {
|
||||
}
|
||||
|
||||
var _ Element = &PrimitiveElement{}
|
||||
|
||||
// HasConflict returns ConflictError if primitive element has conflict field.
|
||||
// Conflicts happen when either of the following conditions:
|
||||
// 1. A field is specified in both recorded and remote values, but does not match.
|
||||
// 2. A field is specified in recorded values, but missing in remote values.
|
||||
func (e PrimitiveElement) HasConflict() error {
|
||||
if e.HasRecorded() && e.HasRemote() {
|
||||
if !reflect.DeepEqual(e.GetRecorded(), e.GetRemote()) {
|
||||
return NewConflictError(e)
|
||||
}
|
||||
}
|
||||
if e.HasRecorded() && !e.HasRemote() {
|
||||
return NewConflictError(e)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ ConflictDetector = &PrimitiveElement{}
|
||||
|
1
vendor/k8s.io/kubernetes/pkg/kubectl/apply/strategy/BUILD
generated
vendored
1
vendor/k8s.io/kubernetes/pkg/kubectl/apply/strategy/BUILD
generated
vendored
@ -18,6 +18,7 @@ go_library(
|
||||
go_test(
|
||||
name = "go_default_xtest",
|
||||
srcs = [
|
||||
"merge_conflict_test.go",
|
||||
"merge_map_list_test.go",
|
||||
"merge_map_test.go",
|
||||
"merge_primitive_list_test.go",
|
||||
|
206
vendor/k8s.io/kubernetes/pkg/kubectl/apply/strategy/merge_conflict_test.go
generated
vendored
Normal file
206
vendor/k8s.io/kubernetes/pkg/kubectl/apply/strategy/merge_conflict_test.go
generated
vendored
Normal file
@ -0,0 +1,206 @@
|
||||
/*
|
||||
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 strategy_test
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
|
||||
"k8s.io/kubernetes/pkg/kubectl/apply/strategy"
|
||||
)
|
||||
|
||||
var _ = Describe("Comparing fields of remote and recorded ", func() {
|
||||
Context("Test conflict in map fields of remote and recorded", func() {
|
||||
It("If conflicts found, expected return error", func() {
|
||||
recorded := create(`
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
spec:
|
||||
foo1: "key1"
|
||||
`)
|
||||
local := create(`
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
spec:
|
||||
foo2: "baz2-1"
|
||||
`)
|
||||
remote := create(`
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
spec:
|
||||
foo1: "baz1-0"
|
||||
`)
|
||||
|
||||
expect := hasConflict
|
||||
// map fields have conflict : recorded {foo1 : "key1"}, remote {foo1 : "baz1-0"}
|
||||
runConflictTest(strategy.Create(strategy.Options{FailOnConflict: true}), recorded, local, remote, expect)
|
||||
})
|
||||
})
|
||||
|
||||
Context("Test conflict in list fields of remote and recorded ", func() {
|
||||
It("If conflicts found, expected return false", func() {
|
||||
recorded := create(`
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
finalizers:
|
||||
- "a"
|
||||
- "b"
|
||||
- "d"
|
||||
`)
|
||||
local := create(`
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
finalizers:
|
||||
- "a"
|
||||
- "b"
|
||||
`)
|
||||
remote := create(`
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
finalizers:
|
||||
- "a"
|
||||
- "b"
|
||||
- "c"
|
||||
`)
|
||||
expect := hasConflict
|
||||
// primatie lists have conflicts: recorded [a, b, d], remote [a, b, c]
|
||||
runConflictTest(strategy.Create(strategy.Options{FailOnConflict: true}), recorded, local, remote, expect)
|
||||
})
|
||||
})
|
||||
|
||||
Context("Test conflict in Map-List fields of remote and recorded ", func() {
|
||||
It("should leave the item", func() {
|
||||
recorded := create(`
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: item1
|
||||
image: image1
|
||||
`)
|
||||
local := create(`
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: item2
|
||||
image: image2
|
||||
`)
|
||||
remote := create(`
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: item1
|
||||
image: image3
|
||||
`)
|
||||
expect := hasConflict
|
||||
// map list has conflict : recorded {containers: [ {name: item1, image: image1} ]} , remote {containers: [ {name: item1, image: image3} ]}
|
||||
runConflictTest(strategy.Create(strategy.Options{FailOnConflict: true}), recorded, local, remote, expect)
|
||||
})
|
||||
})
|
||||
|
||||
Context("Test conflicts in nested map field", func() {
|
||||
It("If conflicts found, expected return error", func() {
|
||||
recorded := create(`
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
spec:
|
||||
foo1:
|
||||
name: "key1"
|
||||
`)
|
||||
local := create(`
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
spec:
|
||||
foo1:
|
||||
name: "baz1-0"
|
||||
`)
|
||||
remote := create(`
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
spec:
|
||||
foo1:
|
||||
name: "baz1-1"
|
||||
`)
|
||||
expect := hasConflict
|
||||
// nested map has conflict : recorded {foo1: {name: "key1"}}, remote {foo1: {name : "baz1-1"}}
|
||||
runConflictTest(strategy.Create(strategy.Options{FailOnConflict: true}), recorded, local, remote, expect)
|
||||
})
|
||||
})
|
||||
|
||||
Context("Test conflicts in complicated map, list", func() {
|
||||
It("Should catch conflict in key-value in map element", func() {
|
||||
recorded := create(`
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: container
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
protocol: TCP
|
||||
hostPort: 2020
|
||||
- containerPort: 8080
|
||||
protocol: UDP
|
||||
hostPort: 2022
|
||||
`)
|
||||
local := create(`
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: container
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
protocol: TCP
|
||||
hostPort: 2020
|
||||
`)
|
||||
remote := create(`
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: container
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
protocol: TCP
|
||||
hostPort: 2020
|
||||
- containerPort: 8080
|
||||
protocol: UDP
|
||||
hostPort: 2022
|
||||
hostIP: "127.0.0.1"
|
||||
`)
|
||||
expect := noConflict
|
||||
runConflictTest(strategy.Create(strategy.Options{FailOnConflict: true}), recorded, local, remote, expect)
|
||||
})
|
||||
})
|
||||
})
|
20
vendor/k8s.io/kubernetes/pkg/kubectl/apply/strategy/merge_visitor.go
generated
vendored
20
vendor/k8s.io/kubernetes/pkg/kubectl/apply/strategy/merge_visitor.go
generated
vendored
@ -41,7 +41,10 @@ func (v mergeStrategy) MergeList(e apply.ListElement) (apply.Result, error) {
|
||||
if result, done := v.doAddOrDelete(e); done {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Detect conflict in ListElement
|
||||
if err := v.doConflictDetect(e); err != nil {
|
||||
return apply.Result{}, err
|
||||
}
|
||||
// Merge each item in the list and append it to the list
|
||||
merged := []interface{}{}
|
||||
for _, value := range e.Values {
|
||||
@ -76,7 +79,10 @@ func (v mergeStrategy) MergeMap(e apply.MapElement) (apply.Result, error) {
|
||||
if result, done := v.doAddOrDelete(e); done {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Detect conflict in MapElement
|
||||
if err := v.doConflictDetect(e); err != nil {
|
||||
return apply.Result{}, err
|
||||
}
|
||||
return v.doMergeMap(e.GetValues())
|
||||
}
|
||||
|
||||
@ -86,7 +92,10 @@ func (v mergeStrategy) MergeType(e apply.TypeElement) (apply.Result, error) {
|
||||
if result, done := v.doAddOrDelete(e); done {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Detect conflict in TypeElement
|
||||
if err := v.doConflictDetect(e); err != nil {
|
||||
return apply.Result{}, err
|
||||
}
|
||||
return v.doMergeMap(e.GetValues())
|
||||
}
|
||||
|
||||
@ -145,4 +154,9 @@ func (v mergeStrategy) MergeEmpty(diff apply.EmptyElement) (apply.Result, error)
|
||||
return apply.Result{Operation: apply.SET}, nil
|
||||
}
|
||||
|
||||
// doConflictDetect returns error if element has conflict
|
||||
func (v mergeStrategy) doConflictDetect(e apply.Element) error {
|
||||
return v.strategic.doConflictDetect(e)
|
||||
}
|
||||
|
||||
var _ apply.Strategy = &mergeStrategy{}
|
||||
|
11
vendor/k8s.io/kubernetes/pkg/kubectl/apply/strategy/replace_visitor.go
generated
vendored
11
vendor/k8s.io/kubernetes/pkg/kubectl/apply/strategy/replace_visitor.go
generated
vendored
@ -65,11 +65,13 @@ func (v replaceStrategy) MergeEmpty(e apply.EmptyElement) (apply.Result, error)
|
||||
// replace returns the local value if specified, otherwise it returns the remote value
|
||||
// this works regardless of the approach
|
||||
func (v replaceStrategy) doReplace(e apply.Element) (apply.Result, error) {
|
||||
// TODO: Check for conflicts
|
||||
|
||||
if result, done := v.doAddOrDelete(e); done {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
if err := v.doConflictDetect(e); err != nil {
|
||||
return apply.Result{}, err
|
||||
}
|
||||
if e.HasLocal() {
|
||||
// Specified locally, set the local value
|
||||
return apply.Result{Operation: apply.SET, MergedResult: e.GetLocal()}, nil
|
||||
@ -97,4 +99,9 @@ func (v replaceStrategy) doAddOrDelete(e apply.Element) (apply.Result, bool) {
|
||||
return apply.Result{}, false
|
||||
}
|
||||
|
||||
// doConflictDetect returns error if element has conflict
|
||||
func (v replaceStrategy) doConflictDetect(e apply.Element) error {
|
||||
return v.strategic.doConflictDetect(e)
|
||||
}
|
||||
|
||||
var _ apply.Strategy = &replaceStrategy{}
|
||||
|
10
vendor/k8s.io/kubernetes/pkg/kubectl/apply/strategy/strategic_visitor.go
generated
vendored
10
vendor/k8s.io/kubernetes/pkg/kubectl/apply/strategy/strategic_visitor.go
generated
vendored
@ -96,4 +96,14 @@ func (v delegatingStrategy) MergeEmpty(diff apply.EmptyElement) (apply.Result, e
|
||||
return v.merge.MergeEmpty(diff)
|
||||
}
|
||||
|
||||
// doConflictDetect detects conflicts in element when option enabled, return error if conflict happened.
|
||||
func (v delegatingStrategy) doConflictDetect(e apply.Element) error {
|
||||
if v.options.FailOnConflict {
|
||||
if e, ok := e.(apply.ConflictDetector); ok {
|
||||
return e.HasConflict()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ apply.Strategy = &delegatingStrategy{}
|
||||
|
2
vendor/k8s.io/kubernetes/pkg/kubectl/apply/strategy/test_swagger.json
generated
vendored
2
vendor/k8s.io/kubernetes/pkg/kubectl/apply/strategy/test_swagger.json
generated
vendored
@ -81,7 +81,7 @@
|
||||
"spec": {
|
||||
"description": "Specification of the desired behavior of the Deployment.",
|
||||
"$ref": "#/definitions/io.k8s.api.apps.v1beta1.DeploymentSpec"
|
||||
},
|
||||
}
|
||||
},
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
|
19
vendor/k8s.io/kubernetes/pkg/kubectl/apply/strategy/utils_test.go
generated
vendored
19
vendor/k8s.io/kubernetes/pkg/kubectl/apply/strategy/utils_test.go
generated
vendored
@ -32,6 +32,11 @@ import (
|
||||
tst "k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi/testing"
|
||||
)
|
||||
|
||||
const (
|
||||
hasConflict = true
|
||||
noConflict = false
|
||||
)
|
||||
|
||||
var fakeResources = tst.NewFakeResources(filepath.Join("..", "..", "..", "..", "api", "openapi-spec", "swagger.json"))
|
||||
|
||||
// run parses the openapi and runs the tests
|
||||
@ -64,3 +69,17 @@ func create(config string) map[string]interface{} {
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func runConflictTest(instance apply.Strategy, recorded, local, remote map[string]interface{}, isConflict bool) {
|
||||
parseFactory := parse.Factory{Resources: fakeResources}
|
||||
parsed, err := parseFactory.CreateElement(recorded, local, remote)
|
||||
Expect(err).Should(Not(HaveOccurred()))
|
||||
|
||||
merged, err := parsed.Merge(instance)
|
||||
if isConflict {
|
||||
Expect(err).Should(HaveOccurred())
|
||||
} else {
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(merged.Operation).Should(Equal(apply.SET))
|
||||
}
|
||||
}
|
||||
|
13
vendor/k8s.io/kubernetes/pkg/kubectl/apply/type_element.go
generated
vendored
13
vendor/k8s.io/kubernetes/pkg/kubectl/apply/type_element.go
generated
vendored
@ -40,4 +40,17 @@ func (e TypeElement) GetValues() map[string]Element {
|
||||
return e.Values
|
||||
}
|
||||
|
||||
// HasConflict returns ConflictError if some elements in type conflict.
|
||||
func (e TypeElement) HasConflict() error {
|
||||
for _, item := range e.GetValues() {
|
||||
if item, ok := item.(ConflictDetector); ok {
|
||||
if err := item.HasConflict(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ Element = &TypeElement{}
|
||||
var _ ConflictDetector = &TypeElement{}
|
||||
|
10
vendor/k8s.io/kubernetes/pkg/kubectl/autoscale_test.go
generated
vendored
10
vendor/k8s.io/kubernetes/pkg/kubectl/autoscale_test.go
generated
vendored
@ -22,6 +22,7 @@ import (
|
||||
|
||||
autoscalingv1 "k8s.io/api/autoscaling/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
utilpointer "k8s.io/kubernetes/pkg/util/pointer"
|
||||
)
|
||||
|
||||
func TestHPAGenerate(t *testing.T) {
|
||||
@ -51,14 +52,14 @@ func TestHPAGenerate(t *testing.T) {
|
||||
Name: "foo",
|
||||
},
|
||||
Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
|
||||
TargetCPUUtilizationPercentage: newInt32(80),
|
||||
TargetCPUUtilizationPercentage: utilpointer.Int32Ptr(80),
|
||||
ScaleTargetRef: autoscalingv1.CrossVersionObjectReference{
|
||||
Kind: "kind",
|
||||
Name: "name",
|
||||
APIVersion: "apiVersion",
|
||||
},
|
||||
MaxReplicas: int32(10),
|
||||
MinReplicas: newInt32(1),
|
||||
MinReplicas: utilpointer.Int32Ptr(1),
|
||||
},
|
||||
},
|
||||
expectErr: false,
|
||||
@ -125,8 +126,3 @@ func TestHPAGenerate(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newInt32(value int) *int32 {
|
||||
v := int32(value)
|
||||
return &v
|
||||
}
|
||||
|
36
vendor/k8s.io/kubernetes/pkg/kubectl/bash_comp_utils.go
generated
vendored
36
vendor/k8s.io/kubernetes/pkg/kubectl/bash_comp_utils.go
generated
vendored
@ -1,36 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// A set of common functions needed by cmd/kubectl and pkg/kubectl packages.
|
||||
|
||||
package kubectl
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
)
|
||||
|
||||
func AddJsonFilenameFlag(cmd *cobra.Command, value *[]string, usage string) {
|
||||
cmd.Flags().StringSliceVarP(value, "filename", "f", *value, usage)
|
||||
annotations := make([]string, 0, len(resource.FileExtensions))
|
||||
for _, ext := range resource.FileExtensions {
|
||||
annotations = append(annotations, strings.TrimLeft(ext, "."))
|
||||
}
|
||||
cmd.Flags().SetAnnotation("filename", cobra.BashCompFilenameExt, annotations)
|
||||
}
|
41
vendor/k8s.io/kubernetes/pkg/kubectl/categories/BUILD
generated
vendored
41
vendor/k8s.io/kubernetes/pkg/kubectl/categories/BUILD
generated
vendored
@ -1,41 +0,0 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["categories.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/kubectl/categories",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/client-go/discovery:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["categories_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/version:go_default_library",
|
||||
"//vendor/k8s.io/client-go/discovery:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/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"],
|
||||
)
|
192
vendor/k8s.io/kubernetes/pkg/kubectl/categories/categories.go
generated
vendored
192
vendor/k8s.io/kubernetes/pkg/kubectl/categories/categories.go
generated
vendored
@ -1,192 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 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 categories
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/discovery"
|
||||
)
|
||||
|
||||
// CategoryExpander maps category strings to GroupResouces.
|
||||
// Categories are classification or 'tag' of a group of resources.
|
||||
type CategoryExpander interface {
|
||||
Expand(category string) ([]schema.GroupResource, bool)
|
||||
}
|
||||
|
||||
// SimpleCategoryExpander implements CategoryExpander interface
|
||||
// using a static mapping of categories to GroupResource mapping.
|
||||
type SimpleCategoryExpander struct {
|
||||
Expansions map[string][]schema.GroupResource
|
||||
}
|
||||
|
||||
func (e SimpleCategoryExpander) Expand(category string) ([]schema.GroupResource, bool) {
|
||||
ret, ok := e.Expansions[category]
|
||||
return ret, ok
|
||||
}
|
||||
|
||||
// discoveryCategoryExpander struct lets a REST Client wrapper (discoveryClient) to retrieve list of APIResourceList,
|
||||
// and then convert to fallbackExpander
|
||||
type discoveryCategoryExpander struct {
|
||||
fallbackExpander CategoryExpander
|
||||
discoveryClient discovery.DiscoveryInterface
|
||||
}
|
||||
|
||||
// NewDiscoveryCategoryExpander returns a category expander that makes use of the "categories" fields from
|
||||
// the API, found through the discovery client. In case of any error or no category found (which likely
|
||||
// means we're at a cluster prior to categories support, fallback to the expander provided.
|
||||
func NewDiscoveryCategoryExpander(fallbackExpander CategoryExpander, client discovery.DiscoveryInterface) (discoveryCategoryExpander, error) {
|
||||
if client == nil {
|
||||
panic("Please provide discovery client to shortcut expander")
|
||||
}
|
||||
return discoveryCategoryExpander{fallbackExpander: fallbackExpander, discoveryClient: client}, nil
|
||||
}
|
||||
|
||||
func (e discoveryCategoryExpander) Expand(category string) ([]schema.GroupResource, bool) {
|
||||
// Get all supported resources for groups and versions from server, if no resource found, fallback anyway.
|
||||
apiResourceLists, _ := e.discoveryClient.ServerResources()
|
||||
if len(apiResourceLists) == 0 {
|
||||
return e.fallbackExpander.Expand(category)
|
||||
}
|
||||
|
||||
discoveredExpansions := map[string][]schema.GroupResource{}
|
||||
|
||||
for _, apiResourceList := range apiResourceLists {
|
||||
gv, err := schema.ParseGroupVersion(apiResourceList.GroupVersion)
|
||||
if err != nil {
|
||||
return e.fallbackExpander.Expand(category)
|
||||
}
|
||||
// Collect GroupVersions by categories
|
||||
for _, apiResource := range apiResourceList.APIResources {
|
||||
if categories := apiResource.Categories; len(categories) > 0 {
|
||||
for _, category := range categories {
|
||||
groupResource := schema.GroupResource{
|
||||
Group: gv.Group,
|
||||
Resource: apiResource.Name,
|
||||
}
|
||||
discoveredExpansions[category] = append(discoveredExpansions[category], groupResource)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(discoveredExpansions) == 0 {
|
||||
// We don't know if the server really don't have any resource with categories,
|
||||
// or we're on a cluster version prior to categories support. Anyways, fallback.
|
||||
return e.fallbackExpander.Expand(category)
|
||||
}
|
||||
|
||||
ret, ok := discoveredExpansions[category]
|
||||
return ret, ok
|
||||
}
|
||||
|
||||
// discoveryFilteredExpander expands the given CategoryExpander (delegate) to filter group and resource returned from server
|
||||
type discoveryFilteredExpander struct {
|
||||
delegate CategoryExpander
|
||||
|
||||
discoveryClient discovery.DiscoveryInterface
|
||||
}
|
||||
|
||||
// NewDiscoveryFilteredExpander returns a category expander that filters the returned groupresources
|
||||
// by what the server has available
|
||||
func NewDiscoveryFilteredExpander(delegate CategoryExpander, client discovery.DiscoveryInterface) (discoveryFilteredExpander, error) {
|
||||
if client == nil {
|
||||
panic("Please provide discovery client to shortcut expander")
|
||||
}
|
||||
return discoveryFilteredExpander{delegate: delegate, discoveryClient: client}, nil
|
||||
}
|
||||
|
||||
func (e discoveryFilteredExpander) Expand(category string) ([]schema.GroupResource, bool) {
|
||||
delegateExpansion, ok := e.delegate.Expand(category)
|
||||
|
||||
// Check if we have access to server resources
|
||||
apiResources, err := e.discoveryClient.ServerResources()
|
||||
if err != nil {
|
||||
return delegateExpansion, ok
|
||||
}
|
||||
|
||||
availableResources, err := discovery.GroupVersionResources(apiResources)
|
||||
if err != nil {
|
||||
return delegateExpansion, ok
|
||||
}
|
||||
|
||||
available := []schema.GroupResource{}
|
||||
for _, requestedResource := range delegateExpansion {
|
||||
for availableResource := range availableResources {
|
||||
if requestedResource.Group == availableResource.Group &&
|
||||
requestedResource.Resource == availableResource.Resource {
|
||||
available = append(available, requestedResource)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return available, ok
|
||||
}
|
||||
|
||||
// UnionCategoryExpander implements CategoryExpander interface.
|
||||
// It maps given category string to union of expansions returned by all the CategoryExpanders in the list.
|
||||
type UnionCategoryExpander []CategoryExpander
|
||||
|
||||
func (u UnionCategoryExpander) Expand(category string) ([]schema.GroupResource, bool) {
|
||||
ret := []schema.GroupResource{}
|
||||
ok := false
|
||||
|
||||
// Expand the category for each CategoryExpander in the list and merge/combine the results.
|
||||
for _, expansion := range u {
|
||||
curr, currOk := expansion.Expand(category)
|
||||
|
||||
for _, currGR := range curr {
|
||||
found := false
|
||||
for _, existing := range ret {
|
||||
if existing == currGR {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
ret = append(ret, currGR)
|
||||
}
|
||||
}
|
||||
ok = ok || currOk
|
||||
}
|
||||
|
||||
return ret, ok
|
||||
}
|
||||
|
||||
// legacyUserResources are the resource names that apply to the primary, user facing resources used by
|
||||
// client tools. They are in deletion-first order - dependent resources should be last.
|
||||
// Should remain exported in order to expose a current list of resources to downstream
|
||||
// composition that wants to build on the concept of 'all' for their CLIs.
|
||||
var legacyUserResources = []schema.GroupResource{
|
||||
{Group: "", Resource: "pods"},
|
||||
{Group: "", Resource: "replicationcontrollers"},
|
||||
{Group: "", Resource: "services"},
|
||||
{Group: "apps", Resource: "statefulsets"},
|
||||
{Group: "autoscaling", Resource: "horizontalpodautoscalers"},
|
||||
{Group: "batch", Resource: "jobs"},
|
||||
{Group: "batch", Resource: "cronjobs"},
|
||||
{Group: "extensions", Resource: "daemonsets"},
|
||||
{Group: "extensions", Resource: "deployments"},
|
||||
{Group: "extensions", Resource: "replicasets"},
|
||||
}
|
||||
|
||||
// LegacyCategoryExpander is the old hardcoded expansion
|
||||
var LegacyCategoryExpander CategoryExpander = SimpleCategoryExpander{
|
||||
Expansions: map[string][]schema.GroupResource{
|
||||
"all": legacyUserResources,
|
||||
},
|
||||
}
|
186
vendor/k8s.io/kubernetes/pkg/kubectl/categories/categories_test.go
generated
vendored
186
vendor/k8s.io/kubernetes/pkg/kubectl/categories/categories_test.go
generated
vendored
@ -1,186 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 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 categories
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/googleapis/gnostic/OpenAPIv2"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/version"
|
||||
"k8s.io/client-go/discovery"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
)
|
||||
|
||||
func TestCategoryExpansion(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
arg string
|
||||
|
||||
expected []schema.GroupResource
|
||||
expectedOk bool
|
||||
}{
|
||||
{
|
||||
name: "no-replacement",
|
||||
arg: "service",
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "all-replacement",
|
||||
arg: "all",
|
||||
expected: []schema.GroupResource{
|
||||
{Resource: "pods"},
|
||||
{Resource: "replicationcontrollers"},
|
||||
{Resource: "services"},
|
||||
{Resource: "statefulsets", Group: "apps"},
|
||||
{Resource: "horizontalpodautoscalers", Group: "autoscaling"},
|
||||
{Resource: "jobs", Group: "batch"},
|
||||
{Resource: "cronjobs", Group: "batch"},
|
||||
{Resource: "daemonsets", Group: "extensions"},
|
||||
{Resource: "deployments", Group: "extensions"},
|
||||
{Resource: "replicasets", Group: "extensions"},
|
||||
},
|
||||
expectedOk: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
actual, actualOk := LegacyCategoryExpander.Expand(test.arg)
|
||||
if e, a := test.expected, actual; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("%s: expected %s, got %s", test.name, e, a)
|
||||
}
|
||||
if e, a := test.expectedOk, actualOk; e != a {
|
||||
t.Errorf("%s: expected %v, got %v", test.name, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiscoveryCategoryExpander(t *testing.T) {
|
||||
tests := []struct {
|
||||
category string
|
||||
serverResponse []*metav1.APIResourceList
|
||||
expected []schema.GroupResource
|
||||
}{
|
||||
{
|
||||
category: "all",
|
||||
serverResponse: []*metav1.APIResourceList{
|
||||
{
|
||||
GroupVersion: "batch/v1",
|
||||
APIResources: []metav1.APIResource{
|
||||
{
|
||||
Name: "jobs",
|
||||
ShortNames: []string{"jz"},
|
||||
Categories: []string{"all"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []schema.GroupResource{
|
||||
{
|
||||
Group: "batch",
|
||||
Resource: "jobs",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
category: "all",
|
||||
serverResponse: []*metav1.APIResourceList{
|
||||
{
|
||||
GroupVersion: "batch/v1",
|
||||
APIResources: []metav1.APIResource{
|
||||
{
|
||||
Name: "jobs",
|
||||
ShortNames: []string{"jz"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
category: "targaryens",
|
||||
serverResponse: []*metav1.APIResourceList{
|
||||
{
|
||||
GroupVersion: "batch/v1",
|
||||
APIResources: []metav1.APIResource{
|
||||
{
|
||||
Name: "jobs",
|
||||
ShortNames: []string{"jz"},
|
||||
Categories: []string{"all"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
dc := &fakeDiscoveryClient{}
|
||||
for _, test := range tests {
|
||||
dc.serverResourcesHandler = func() ([]*metav1.APIResourceList, error) {
|
||||
return test.serverResponse, nil
|
||||
}
|
||||
expander, err := NewDiscoveryCategoryExpander(SimpleCategoryExpander{}, dc)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
expanded, _ := expander.Expand(test.category)
|
||||
if !reflect.DeepEqual(expanded, test.expected) {
|
||||
t.Errorf("expected %v, got %v", test.expected, expanded)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type fakeDiscoveryClient struct {
|
||||
serverResourcesHandler func() ([]*metav1.APIResourceList, error)
|
||||
}
|
||||
|
||||
var _ discovery.DiscoveryInterface = &fakeDiscoveryClient{}
|
||||
|
||||
func (c *fakeDiscoveryClient) RESTClient() restclient.Interface {
|
||||
return &fake.RESTClient{}
|
||||
}
|
||||
|
||||
func (c *fakeDiscoveryClient) ServerGroups() (*metav1.APIGroupList, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeDiscoveryClient) ServerResourcesForGroupVersion(groupVersion string) (*metav1.APIResourceList, error) {
|
||||
return &metav1.APIResourceList{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeDiscoveryClient) ServerResources() ([]*metav1.APIResourceList, error) {
|
||||
return c.serverResourcesHandler()
|
||||
}
|
||||
|
||||
func (c *fakeDiscoveryClient) ServerPreferredResources() ([]*metav1.APIResourceList, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeDiscoveryClient) ServerPreferredNamespacedResources() ([]*metav1.APIResourceList, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeDiscoveryClient) ServerVersion() (*version.Info, error) {
|
||||
return &version.Info{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeDiscoveryClient) OpenAPISchema() (*openapi_v2.Document, error) {
|
||||
return &openapi_v2.Document{}, nil
|
||||
}
|
84
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/BUILD
generated
vendored
84
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/BUILD
generated
vendored
@ -9,6 +9,7 @@ go_library(
|
||||
srcs = [
|
||||
"alpha.go",
|
||||
"annotate.go",
|
||||
"apiresources.go",
|
||||
"apiversions.go",
|
||||
"apply.go",
|
||||
"apply_edit_last_applied.go",
|
||||
@ -23,22 +24,8 @@ go_library(
|
||||
"completion.go",
|
||||
"convert.go",
|
||||
"cp.go",
|
||||
"create.go",
|
||||
"create_clusterrole.go",
|
||||
"create_clusterrolebinding.go",
|
||||
"create_configmap.go",
|
||||
"create_deployment.go",
|
||||
"create_job.go",
|
||||
"create_namespace.go",
|
||||
"create_pdb.go",
|
||||
"create_priorityclass.go",
|
||||
"create_quota.go",
|
||||
"create_role.go",
|
||||
"create_rolebinding.go",
|
||||
"create_secret.go",
|
||||
"create_service.go",
|
||||
"create_serviceaccount.go",
|
||||
"delete.go",
|
||||
"delete_flags.go",
|
||||
"describe.go",
|
||||
"diff.go",
|
||||
"drain.go",
|
||||
@ -74,30 +61,37 @@ go_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/auth:go_default_library",
|
||||
"//pkg/kubectl/cmd/config:go_default_library",
|
||||
"//pkg/kubectl/cmd/resource:go_default_library",
|
||||
"//pkg/kubectl/cmd/create:go_default_library",
|
||||
"//pkg/kubectl/cmd/get:go_default_library",
|
||||
"//pkg/kubectl/cmd/rollout:go_default_library",
|
||||
"//pkg/kubectl/cmd/scalejob:go_default_library",
|
||||
"//pkg/kubectl/cmd/set: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/cmd/util/openapi: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/resource: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/printers/internalversion:go_default_library",
|
||||
"//pkg/util/interrupt:go_default_library",
|
||||
"//pkg/util/taints:go_default_library",
|
||||
"//pkg/version:go_default_library",
|
||||
@ -111,16 +105,15 @@ go_library(
|
||||
"//vendor/github.com/renstrom/dedent:go_default_library",
|
||||
"//vendor/github.com/spf13/cobra:go_default_library",
|
||||
"//vendor/github.com/spf13/pflag: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/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/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/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",
|
||||
@ -134,6 +127,7 @@ go_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",
|
||||
@ -141,11 +135,12 @@ go_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/batch/v1: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/kubernetes/typed/rbac/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",
|
||||
@ -165,24 +160,10 @@ go_test(
|
||||
"apply_test.go",
|
||||
"attach_test.go",
|
||||
"clusterinfo_dump_test.go",
|
||||
"cmd_printing_test.go",
|
||||
"cmd_test.go",
|
||||
"convert_test.go",
|
||||
"cp_test.go",
|
||||
"create_clusterrole_test.go",
|
||||
"create_clusterrolebinding_test.go",
|
||||
"create_configmap_test.go",
|
||||
"create_deployment_test.go",
|
||||
"create_job_test.go",
|
||||
"create_namespace_test.go",
|
||||
"create_pdb_test.go",
|
||||
"create_priorityclass_test.go",
|
||||
"create_quota_test.go",
|
||||
"create_role_test.go",
|
||||
"create_rolebinding_test.go",
|
||||
"create_secret_test.go",
|
||||
"create_service_test.go",
|
||||
"create_serviceaccount_test.go",
|
||||
"create_test.go",
|
||||
"delete_test.go",
|
||||
"describe_test.go",
|
||||
"diff_test.go",
|
||||
@ -206,7 +187,6 @@ go_test(
|
||||
data = [
|
||||
"testdata",
|
||||
"//api/openapi-spec:swagger-spec",
|
||||
"//examples:config",
|
||||
"//test/e2e/testing-manifests:all-srcs",
|
||||
"//test/fixtures",
|
||||
],
|
||||
@ -218,29 +198,25 @@ go_test(
|
||||
"//pkg/apis/batch:go_default_library",
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/apis/extensions:go_default_library",
|
||||
"//pkg/kubectl:go_default_library",
|
||||
"//pkg/kubectl/cmd/resource: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/resource: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",
|
||||
"//pkg/util/strings:go_default_library",
|
||||
"//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
|
||||
"//vendor/github.com/spf13/cobra:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||
"//vendor/gopkg.in/yaml.v2: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/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/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",
|
||||
@ -256,8 +232,7 @@ go_test(
|
||||
"//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:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/fake: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",
|
||||
@ -281,13 +256,16 @@ filegroup(
|
||||
":package-srcs",
|
||||
"//pkg/kubectl/cmd/auth:all-srcs",
|
||||
"//pkg/kubectl/cmd/config:all-srcs",
|
||||
"//pkg/kubectl/cmd/resource:all-srcs",
|
||||
"//pkg/kubectl/cmd/create:all-srcs",
|
||||
"//pkg/kubectl/cmd/get:all-srcs",
|
||||
"//pkg/kubectl/cmd/rollout:all-srcs",
|
||||
"//pkg/kubectl/cmd/scalejob:all-srcs",
|
||||
"//pkg/kubectl/cmd/set:all-srcs",
|
||||
"//pkg/kubectl/cmd/templates:all-srcs",
|
||||
"//pkg/kubectl/cmd/testdata/edit:all-srcs",
|
||||
"//pkg/kubectl/cmd/testing:all-srcs",
|
||||
"//pkg/kubectl/cmd/util:all-srcs",
|
||||
"//pkg/kubectl/cmd/wait:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = [
|
||||
|
7
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/alpha.go
generated
vendored
7
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/alpha.go
generated
vendored
@ -17,17 +17,16 @@ limitations under the License.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
// NewCmdAlpha creates a command that acts as an alternate root command for features in alpha
|
||||
func NewCmdAlpha(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cobra.Command {
|
||||
func NewCmdAlpha(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "alpha",
|
||||
Short: i18n.T("Commands for features in alpha"),
|
||||
@ -37,7 +36,7 @@ func NewCmdAlpha(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cobra.Com
|
||||
// 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, 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.
|
||||
|
171
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/annotate.go
generated
vendored
171
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/annotate.go
generated
vendored
@ -34,32 +34,44 @@ import (
|
||||
"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/resource"
|
||||
"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"
|
||||
)
|
||||
|
||||
// AnnotateOptions have the data required to perform the annotate operation
|
||||
type AnnotateOptions struct {
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
PrintObj printers.ResourcePrinterFunc
|
||||
|
||||
// Filename options
|
||||
resource.FilenameOptions
|
||||
RecordFlags *genericclioptions.RecordFlags
|
||||
|
||||
// Common user flags
|
||||
overwrite bool
|
||||
local bool
|
||||
dryrun bool
|
||||
all bool
|
||||
resourceVersion string
|
||||
selector string
|
||||
outputFormat string
|
||||
recordChangeCause bool
|
||||
overwrite bool
|
||||
local bool
|
||||
dryrun bool
|
||||
all bool
|
||||
resourceVersion string
|
||||
selector string
|
||||
fieldSelector string
|
||||
outputFormat string
|
||||
|
||||
// results of arg parsing
|
||||
resources []string
|
||||
newAnnotations map[string]string
|
||||
removeAnnotations []string
|
||||
resources []string
|
||||
newAnnotations map[string]string
|
||||
removeAnnotations []string
|
||||
Recorder genericclioptions.Recorder
|
||||
namespace string
|
||||
enforceNamespace bool
|
||||
builder *resource.Builder
|
||||
unstructuredClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error)
|
||||
includeUninitialized bool
|
||||
|
||||
// Common share fields
|
||||
out io.Writer
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
var (
|
||||
@ -69,7 +81,7 @@ var (
|
||||
All Kubernetes objects support the ability to store additional data with the object as
|
||||
annotations. Annotations are key/value pairs that can be larger than labels and include
|
||||
arbitrary string values such as structured JSON. Tools and system extensions may use
|
||||
annotations to store their own data.
|
||||
annotations to store their own data.
|
||||
|
||||
Attempting to set an annotation that already exists will fail unless --overwrite is set.
|
||||
If --resource-version is specified and does not match the current resource version on
|
||||
@ -97,50 +109,81 @@ var (
|
||||
kubectl annotate pods foo description-`))
|
||||
)
|
||||
|
||||
func NewCmdAnnotate(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
options := &AnnotateOptions{}
|
||||
validArgs := cmdutil.ValidArgList(f)
|
||||
func NewAnnotateOptions(ioStreams genericclioptions.IOStreams) *AnnotateOptions {
|
||||
return &AnnotateOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("annotated").WithTypeSetter(scheme.Scheme),
|
||||
|
||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||
Recorder: genericclioptions.NoopRecorder{},
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdAnnotate(parent string, f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewAnnotateOptions(ioStreams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
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.ValidResourceTypeList(f),
|
||||
Long: annotateLong + "\n\n" + cmdutil.SuggestApiResources(parent),
|
||||
Example: annotateExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if err := options.Complete(out, cmd, args); err != nil {
|
||||
cmdutil.CheckErr(cmdutil.UsageErrorf(cmd, "%v", err))
|
||||
}
|
||||
if err := options.Validate(); err != nil {
|
||||
cmdutil.CheckErr(cmdutil.UsageErrorf(cmd, "%v", err))
|
||||
}
|
||||
cmdutil.CheckErr(options.RunAnnotate(f, cmd))
|
||||
cmdutil.CheckErr(o.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(o.Validate())
|
||||
cmdutil.CheckErr(o.RunAnnotate())
|
||||
},
|
||||
ValidArgs: validArgs,
|
||||
ArgAliases: kubectl.ResourceAliases(validArgs),
|
||||
}
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
|
||||
// bind flag structs
|
||||
o.RecordFlags.AddFlags(cmd)
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddIncludeUninitializedFlag(cmd)
|
||||
cmd.Flags().BoolVar(&options.overwrite, "overwrite", options.overwrite, "If true, allow annotations to be overwritten, otherwise reject annotation updates that overwrite existing annotations.")
|
||||
cmd.Flags().BoolVar(&options.local, "local", options.local, "If true, annotation will NOT contact api-server but run locally.")
|
||||
cmd.Flags().StringVarP(&options.selector, "selector", "l", options.selector, "Selector (label query) to filter on, not including uninitialized ones, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2).")
|
||||
cmd.Flags().BoolVar(&options.all, "all", options.all, "Select all resources, including uninitialized ones, in the namespace of the specified resource types.")
|
||||
cmd.Flags().StringVar(&options.resourceVersion, "resource-version", options.resourceVersion, i18n.T("If non-empty, the annotation update will only succeed if this is the current resource-version for the object. Only valid when specifying a single resource."))
|
||||
cmd.Flags().BoolVar(&o.overwrite, "overwrite", o.overwrite, "If true, allow annotations to be overwritten, otherwise reject annotation updates that overwrite existing annotations.")
|
||||
cmd.Flags().BoolVar(&o.local, "local", o.local, "If true, annotation will NOT contact api-server but run locally.")
|
||||
cmd.Flags().StringVarP(&o.selector, "selector", "l", o.selector, "Selector (label query) to filter on, not including uninitialized ones, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2).")
|
||||
cmd.Flags().StringVar(&o.fieldSelector, "field-selector", o.fieldSelector, "Selector (field query) to filter on, supports '=', '==', and '!='.(e.g. --field-selector key1=value1,key2=value2). The server only supports a limited number of field queries per type.")
|
||||
cmd.Flags().BoolVar(&o.all, "all", o.all, "Select all resources, including uninitialized ones, in the namespace of the specified resource types.")
|
||||
cmd.Flags().StringVar(&o.resourceVersion, "resource-version", o.resourceVersion, i18n.T("If non-empty, the annotation update will only succeed if this is the current resource-version for the object. Only valid when specifying a single resource."))
|
||||
usage := "identifying the resource to update the annotation"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
cmdutil.AddRecordFlag(cmd)
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// Complete adapts from the command line args and factory to the data required.
|
||||
func (o *AnnotateOptions) Complete(out io.Writer, cmd *cobra.Command, args []string) (err error) {
|
||||
o.out = out
|
||||
func (o *AnnotateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
var err error
|
||||
|
||||
o.RecordFlags.Complete(cmd)
|
||||
o.Recorder, err = o.RecordFlags.ToRecorder()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.outputFormat = cmdutil.GetFlagString(cmd, "output")
|
||||
o.dryrun = cmdutil.GetDryRunFlag(cmd)
|
||||
o.recordChangeCause = cmdutil.GetRecordFlag(cmd)
|
||||
|
||||
if o.dryrun {
|
||||
o.PrintFlags.Complete("%s (dry run)")
|
||||
}
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.PrintObj = func(obj runtime.Object, out io.Writer) error {
|
||||
return printer.PrintObj(obj, out)
|
||||
}
|
||||
|
||||
o.namespace, o.enforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.includeUninitialized = cmdutil.ShouldIncludeUninitialized(cmd, false)
|
||||
o.builder = f.NewBuilder()
|
||||
o.unstructuredClientForMapping = f.UnstructuredClientForMapping
|
||||
|
||||
// retrieves resource and annotation args from args
|
||||
// also checks args to verify that all resources are specified before annotations
|
||||
@ -150,7 +193,11 @@ func (o *AnnotateOptions) Complete(out io.Writer, cmd *cobra.Command, args []str
|
||||
}
|
||||
o.resources = resources
|
||||
o.newAnnotations, o.removeAnnotations, err = parseAnnotations(annotationArgs)
|
||||
return err
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate checks to the AnnotateOptions to see if there is sufficient information run the command.
|
||||
@ -158,6 +205,9 @@ func (o AnnotateOptions) Validate() error {
|
||||
if o.all && len(o.selector) > 0 {
|
||||
return fmt.Errorf("cannot set --all and --selector at the same time")
|
||||
}
|
||||
if o.all && len(o.fieldSelector) > 0 {
|
||||
return fmt.Errorf("cannot set --all and --field-selector at the same time")
|
||||
}
|
||||
if len(o.resources) < 1 && cmdutil.IsFilenameSliceEmpty(o.Filenames) {
|
||||
return fmt.Errorf("one or more resources must be specified as <resource> <name> or <resource>/<name>")
|
||||
}
|
||||
@ -168,26 +218,19 @@ func (o AnnotateOptions) Validate() error {
|
||||
}
|
||||
|
||||
// RunAnnotate does the work
|
||||
func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
namespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
changeCause := f.Command(cmd, false)
|
||||
|
||||
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
|
||||
b := f.NewBuilder().
|
||||
func (o AnnotateOptions) RunAnnotate() error {
|
||||
b := o.builder.
|
||||
Unstructured().
|
||||
LocalParam(o.local).
|
||||
ContinueOnError().
|
||||
NamespaceParam(namespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||
IncludeUninitialized(includeUninitialized).
|
||||
NamespaceParam(o.namespace).DefaultNamespace().
|
||||
FilenameParam(o.enforceNamespace, &o.FilenameOptions).
|
||||
IncludeUninitialized(o.includeUninitialized).
|
||||
Flatten()
|
||||
|
||||
if !o.local {
|
||||
b = b.LabelSelectorParam(o.selector).
|
||||
FieldSelectorParam(o.fieldSelector).
|
||||
ResourceTypeOrNameArgs(o.all, o.resources...).
|
||||
Latest()
|
||||
}
|
||||
@ -214,12 +257,7 @@ func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) erro
|
||||
}
|
||||
|
||||
var outputObj runtime.Object
|
||||
var obj runtime.Object
|
||||
|
||||
obj, err = info.Mapping.ConvertToVersion(info.Object, info.Mapping.GroupVersionKind.GroupVersion())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
obj := info.Object
|
||||
|
||||
if o.dryrun || o.local {
|
||||
if err := o.updateAnnotations(obj); err != nil {
|
||||
@ -232,9 +270,8 @@ func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) erro
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// If we should record change-cause, add it to new annotations
|
||||
if cmdutil.ContainsChangeCause(info) || o.recordChangeCause {
|
||||
o.newAnnotations[kubectl.ChangeCauseAnnotation] = changeCause
|
||||
if err := o.Recorder.Record(info.Object); err != nil {
|
||||
glog.V(4).Infof("error recording current command: %v", err)
|
||||
}
|
||||
if err := o.updateAnnotations(obj); err != nil {
|
||||
return err
|
||||
@ -250,7 +287,7 @@ func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) erro
|
||||
}
|
||||
|
||||
mapping := info.ResourceMapping()
|
||||
client, err := f.UnstructuredClientForMapping(mapping)
|
||||
client, err := o.unstructuredClientForMapping(mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -266,11 +303,7 @@ func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) erro
|
||||
}
|
||||
}
|
||||
|
||||
if len(o.outputFormat) > 0 {
|
||||
return cmdutil.PrintObject(cmd, outputObj, o.out)
|
||||
}
|
||||
cmdutil.PrintSuccess(false, o.out, info.Object, o.dryrun, "annotated")
|
||||
return nil
|
||||
return o.PrintObj(outputObj, o.Out)
|
||||
})
|
||||
}
|
||||
|
||||
|
124
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/annotate_test.go
generated
vendored
124
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/annotate_test.go
generated
vendored
@ -17,7 +17,6 @@ limitations under the License.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strings"
|
||||
@ -30,6 +29,7 @@ import (
|
||||
"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"
|
||||
)
|
||||
|
||||
@ -417,37 +417,45 @@ func TestAnnotateErrors(t *testing.T) {
|
||||
}
|
||||
|
||||
for k, testCase := range testCases {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
t.Run(k, func(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdAnnotate(tf, buf)
|
||||
cmd.SetOutput(buf)
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
for k, v := range testCase.flags {
|
||||
cmd.Flags().Set(k, v)
|
||||
}
|
||||
options := &AnnotateOptions{}
|
||||
err := options.Complete(buf, cmd, testCase.args)
|
||||
if err == nil {
|
||||
err = options.Validate()
|
||||
}
|
||||
if !testCase.errFn(err) {
|
||||
t.Errorf("%s: unexpected error: %v", k, err)
|
||||
continue
|
||||
}
|
||||
if buf.Len() > 0 {
|
||||
t.Errorf("buffer should be empty: %s", string(buf.Bytes()))
|
||||
}
|
||||
iostreams, _, bufOut, bufErr := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdAnnotate("kubectl", tf, iostreams)
|
||||
cmd.SetOutput(bufOut)
|
||||
|
||||
for k, v := range testCase.flags {
|
||||
cmd.Flags().Set(k, v)
|
||||
}
|
||||
options := NewAnnotateOptions(iostreams)
|
||||
err := options.Complete(tf, cmd, testCase.args)
|
||||
if err == nil {
|
||||
err = options.Validate()
|
||||
}
|
||||
if !testCase.errFn(err) {
|
||||
t.Errorf("%s: unexpected error: %v", k, err)
|
||||
return
|
||||
}
|
||||
if bufOut.Len() > 0 {
|
||||
t.Errorf("buffer should be empty: %s", string(bufOut.Bytes()))
|
||||
}
|
||||
if bufErr.Len() > 0 {
|
||||
t.Errorf("buffer should be empty: %s", string(bufErr.Bytes()))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnnotateObject(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Group: "testgroup", Version: "v1"},
|
||||
@ -476,21 +484,20 @@ func TestAnnotateObject(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdAnnotate(tf, buf)
|
||||
cmd.SetOutput(buf)
|
||||
options := &AnnotateOptions{}
|
||||
iostreams, _, bufOut, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdAnnotate("kubectl", tf, iostreams)
|
||||
cmd.SetOutput(bufOut)
|
||||
options := NewAnnotateOptions(iostreams)
|
||||
args := []string{"pods/foo", "a=b", "c-"}
|
||||
if err := options.Complete(buf, cmd, args); err != nil {
|
||||
if err := options.Complete(tf, cmd, args); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := options.Validate(); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := options.RunAnnotate(tf, cmd); err != nil {
|
||||
if err := options.RunAnnotate(); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
@ -498,8 +505,10 @@ func TestAnnotateObject(t *testing.T) {
|
||||
func TestAnnotateObjectFromFile(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Group: "testgroup", Version: "v1"},
|
||||
@ -528,28 +537,29 @@ func TestAnnotateObjectFromFile(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdAnnotate(tf, buf)
|
||||
cmd.SetOutput(buf)
|
||||
options := &AnnotateOptions{}
|
||||
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"}
|
||||
args := []string{"a=b", "c-"}
|
||||
if err := options.Complete(buf, cmd, args); err != nil {
|
||||
if err := options.Complete(tf, cmd, args); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := options.Validate(); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := options.RunAnnotate(tf, cmd); err != nil {
|
||||
if err := options.RunAnnotate(); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnnotateLocal(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Group: "testgroup", Version: "v1"},
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -558,21 +568,21 @@ func TestAnnotateLocal(t *testing.T) {
|
||||
return nil, nil
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdAnnotate(tf, buf)
|
||||
options := &AnnotateOptions{local: true}
|
||||
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"}
|
||||
args := []string{"a=b"}
|
||||
if err := options.Complete(buf, cmd, args); err != nil {
|
||||
if err := options.Complete(tf, cmd, args); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := options.Validate(); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := options.RunAnnotate(tf, cmd); err != nil {
|
||||
if err := options.RunAnnotate(); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
@ -580,8 +590,10 @@ func TestAnnotateLocal(t *testing.T) {
|
||||
func TestAnnotateMultipleObjects(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Group: "testgroup", Version: "v1"},
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -611,21 +623,21 @@ func TestAnnotateMultipleObjects(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdAnnotate(tf, buf)
|
||||
cmd.SetOutput(buf)
|
||||
options := &AnnotateOptions{all: true}
|
||||
iostreams, _, _, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdAnnotate("kubectl", tf, iostreams)
|
||||
cmd.SetOutput(iostreams.Out)
|
||||
options := NewAnnotateOptions(iostreams)
|
||||
options.all = true
|
||||
args := []string{"pods", "a=b", "c-"}
|
||||
if err := options.Complete(buf, cmd, args); err != nil {
|
||||
if err := options.Complete(tf, cmd, args); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := options.Validate(); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := options.RunAnnotate(tf, cmd); err != nil {
|
||||
if err := options.RunAnnotate(); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
229
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apiresources.go
generated
vendored
Normal file
229
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apiresources.go
generated
vendored
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
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 (
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
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"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
var (
|
||||
apiresourcesExample = templates.Examples(`
|
||||
# Print the supported API Resources
|
||||
kubectl api-resources
|
||||
|
||||
# Print the supported API Resources with more information
|
||||
kubectl api-resources -o wide
|
||||
|
||||
# Print the supported namespaced resources
|
||||
kubectl api-resources --namespaced=true
|
||||
|
||||
# Print the supported non-namespaced resources
|
||||
kubectl api-resources --namespaced=false
|
||||
|
||||
# Print the supported API Resources with specific APIGroup
|
||||
kubectl api-resources --api-group=extensions`)
|
||||
)
|
||||
|
||||
// ApiResourcesOptions 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 ApiResourcesOptions struct {
|
||||
Output string
|
||||
APIGroup string
|
||||
Namespaced bool
|
||||
Verbs []string
|
||||
NoHeaders bool
|
||||
Cached bool
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
// groupResource contains the APIGroup and APIResource
|
||||
type groupResource struct {
|
||||
APIGroup string
|
||||
APIResource metav1.APIResource
|
||||
}
|
||||
|
||||
func NewAPIResourceOptions(ioStreams genericclioptions.IOStreams) *ApiResourcesOptions {
|
||||
return &ApiResourcesOptions{
|
||||
IOStreams: ioStreams,
|
||||
Namespaced: true,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdApiResources(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewAPIResourceOptions(ioStreams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "api-resources",
|
||||
Short: "Print the supported API resources on the server",
|
||||
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.RunApiResources(cmd, f))
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().BoolVar(&o.NoHeaders, "no-headers", o.NoHeaders, "When using the default or custom-column output format, don't print headers (default print headers).")
|
||||
cmd.Flags().StringVarP(&o.Output, "output", "o", o.Output, "Output format. One of: wide|name.")
|
||||
|
||||
cmd.Flags().StringVar(&o.APIGroup, "api-group", o.APIGroup, "Limit to resources in the specified API group.")
|
||||
cmd.Flags().BoolVar(&o.Namespaced, "namespaced", o.Namespaced, "If false, non-namespaced resources will be returned, otherwise returning namespaced resources by default.")
|
||||
cmd.Flags().StringSliceVar(&o.Verbs, "verbs", o.Verbs, "Limit to resources that support the specified verbs.")
|
||||
cmd.Flags().BoolVar(&o.Cached, "cached", o.Cached, "Use the cached list of resources if available.")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o *ApiResourcesOptions) Validate(cmd *cobra.Command) error {
|
||||
supportedOutputTypes := sets.NewString("", "wide", "name")
|
||||
if !supportedOutputTypes.Has(o.Output) {
|
||||
return fmt.Errorf("--output %v is not available", o.Output)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *ApiResourcesOptions) RunApiResources(cmd *cobra.Command, f cmdutil.Factory) error {
|
||||
w := printers.GetNewTabWriter(o.Out)
|
||||
defer w.Flush()
|
||||
|
||||
discoveryclient, err := f.ToDiscoveryClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !o.Cached {
|
||||
// Always request fresh data from the server
|
||||
discoveryclient.Invalidate()
|
||||
}
|
||||
|
||||
lists, err := discoveryclient.ServerPreferredResources()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resources := []groupResource{}
|
||||
|
||||
groupChanged := cmd.Flags().Changed("api-group")
|
||||
nsChanged := cmd.Flags().Changed("namespaced")
|
||||
|
||||
for _, list := range lists {
|
||||
if len(list.APIResources) == 0 {
|
||||
continue
|
||||
}
|
||||
gv, err := schema.ParseGroupVersion(list.GroupVersion)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for _, resource := range list.APIResources {
|
||||
if len(resource.Verbs) == 0 {
|
||||
continue
|
||||
}
|
||||
// filter apiGroup
|
||||
if groupChanged && o.APIGroup != gv.Group {
|
||||
continue
|
||||
}
|
||||
// filter namespaced
|
||||
if nsChanged && o.Namespaced != resource.Namespaced {
|
||||
continue
|
||||
}
|
||||
// filter to resources that support the specified verbs
|
||||
if len(o.Verbs) > 0 && !sets.NewString(resource.Verbs...).HasAll(o.Verbs...) {
|
||||
continue
|
||||
}
|
||||
resources = append(resources, groupResource{
|
||||
APIGroup: gv.Group,
|
||||
APIResource: resource,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if o.NoHeaders == false && o.Output != "name" {
|
||||
if err = printContextHeaders(w, o.Output); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
sort.Stable(sortableGroupResource(resources))
|
||||
for _, r := range resources {
|
||||
switch o.Output {
|
||||
case "name":
|
||||
name := r.APIResource.Name
|
||||
if len(r.APIGroup) > 0 {
|
||||
name += "." + r.APIGroup
|
||||
}
|
||||
if _, err := fmt.Fprintf(w, "%s\n", name); err != nil {
|
||||
return err
|
||||
}
|
||||
case "wide":
|
||||
if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%v\t%s\t%v\n",
|
||||
r.APIResource.Name,
|
||||
strings.Join(r.APIResource.ShortNames, ","),
|
||||
r.APIGroup,
|
||||
r.APIResource.Namespaced,
|
||||
r.APIResource.Kind,
|
||||
r.APIResource.Verbs); err != nil {
|
||||
return err
|
||||
}
|
||||
case "":
|
||||
if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%v\t%s\n",
|
||||
r.APIResource.Name,
|
||||
strings.Join(r.APIResource.ShortNames, ","),
|
||||
r.APIGroup,
|
||||
r.APIResource.Namespaced,
|
||||
r.APIResource.Kind); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func printContextHeaders(out io.Writer, output string) error {
|
||||
columnNames := []string{"NAME", "SHORTNAMES", "APIGROUP", "NAMESPACED", "KIND"}
|
||||
if output == "wide" {
|
||||
columnNames = append(columnNames, "VERBS")
|
||||
}
|
||||
_, err := fmt.Fprintf(out, "%s\n", strings.Join(columnNames, "\t"))
|
||||
return err
|
||||
}
|
||||
|
||||
type sortableGroupResource []groupResource
|
||||
|
||||
func (s sortableGroupResource) Len() int { return len(s) }
|
||||
func (s sortableGroupResource) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
func (s sortableGroupResource) Less(i, j int) bool {
|
||||
ret := strings.Compare(s[i].APIGroup, s[j].APIGroup)
|
||||
if ret > 0 {
|
||||
return false
|
||||
} else if ret == 0 {
|
||||
return strings.Compare(s[i].APIResource.Name, s[j].APIResource.Name) < 0
|
||||
}
|
||||
return true
|
||||
}
|
36
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apiversions.go
generated
vendored
36
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apiversions.go
generated
vendored
@ -18,14 +18,15 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"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"
|
||||
)
|
||||
|
||||
@ -35,37 +36,54 @@ var (
|
||||
kubectl api-versions`))
|
||||
)
|
||||
|
||||
func NewCmdApiVersions(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
type ApiVersionsOptions struct {
|
||||
discoveryClient discovery.CachedDiscoveryInterface
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
func NewApiVersionsOptions(ioStreams genericclioptions.IOStreams) *ApiVersionsOptions {
|
||||
return &ApiVersionsOptions{
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdApiVersions(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewApiVersionsOptions(ioStreams)
|
||||
cmd := &cobra.Command{
|
||||
Use: "api-versions",
|
||||
Short: "Print the supported API versions on the server, in the form of \"group/version\"",
|
||||
Long: "Print the supported API versions on the server, in the form of \"group/version\"",
|
||||
Example: apiversionsExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := RunApiVersions(f, out)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(o.Complete(f))
|
||||
cmdutil.CheckErr(o.RunApiVersions())
|
||||
},
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func RunApiVersions(f cmdutil.Factory, w io.Writer) error {
|
||||
discoveryclient, err := f.DiscoveryClient()
|
||||
func (o *ApiVersionsOptions) Complete(f cmdutil.Factory) error {
|
||||
var err error
|
||||
o.discoveryClient, err = f.ToDiscoveryClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *ApiVersionsOptions) RunApiVersions() error {
|
||||
// Always request fresh data from the server
|
||||
discoveryclient.Invalidate()
|
||||
o.discoveryClient.Invalidate()
|
||||
|
||||
groupList, err := discoveryclient.ServerGroups()
|
||||
groupList, err := o.discoveryClient.ServerGroups()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Couldn't get available api versions from server: %v\n", err)
|
||||
}
|
||||
apiVersions := metav1.ExtractGroupVersions(groupList)
|
||||
sort.Strings(apiVersions)
|
||||
for _, v := range apiVersions {
|
||||
fmt.Fprintln(w, v)
|
||||
fmt.Fprintln(o.Out, v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
478
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply.go
generated
vendored
478
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply.go
generated
vendored
@ -26,9 +26,11 @@ import (
|
||||
"github.com/jonboulle/clockwork"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"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"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
@ -37,29 +39,52 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/dynamic"
|
||||
oapi "k8s.io/kube-openapi/pkg/util/proto"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
"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/openapi"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"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/validation"
|
||||
)
|
||||
|
||||
type ApplyOptions struct {
|
||||
FilenameOptions resource.FilenameOptions
|
||||
Selector string
|
||||
Force bool
|
||||
Prune bool
|
||||
Cascade bool
|
||||
GracePeriod int
|
||||
PruneResources []pruneResource
|
||||
Timeout time.Duration
|
||||
cmdBaseName string
|
||||
all bool
|
||||
RecordFlags *genericclioptions.RecordFlags
|
||||
Recorder genericclioptions.Recorder
|
||||
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
ToPrinter func(string) (printers.ResourcePrinter, error)
|
||||
|
||||
DeleteFlags *DeleteFlags
|
||||
DeleteOptions *DeleteOptions
|
||||
|
||||
Selector string
|
||||
DryRun bool
|
||||
Prune bool
|
||||
PruneResources []pruneResource
|
||||
cmdBaseName string
|
||||
All bool
|
||||
Overwrite bool
|
||||
OpenApiPatch bool
|
||||
PruneWhitelist []string
|
||||
ShouldIncludeUninitialized bool
|
||||
|
||||
Validator validation.Schema
|
||||
Builder *resource.Builder
|
||||
Mapper meta.RESTMapper
|
||||
DynamicClient dynamic.Interface
|
||||
OpenAPISchema openapi.Resources
|
||||
|
||||
Namespace string
|
||||
EnforceNamespace bool
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
const (
|
||||
@ -98,12 +123,27 @@ var (
|
||||
warningNoLastAppliedConfigAnnotation = "Warning: %[1]s apply should be used on resource created by either %[1]s create --save-config or %[1]s apply\n"
|
||||
)
|
||||
|
||||
func NewCmdApply(baseName string, f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
var options ApplyOptions
|
||||
func NewApplyOptions(ioStreams genericclioptions.IOStreams) *ApplyOptions {
|
||||
return &ApplyOptions{
|
||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||
DeleteFlags: NewDeleteFlags("that contains the configuration to apply"),
|
||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
|
||||
|
||||
Overwrite: true,
|
||||
OpenApiPatch: true,
|
||||
|
||||
Recorder: genericclioptions.NoopRecorder{},
|
||||
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdApply(baseName string, f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewApplyOptions(ioStreams)
|
||||
|
||||
// Store baseName for use in printing warnings / messages involving the base command name.
|
||||
// This is useful for downstream command that wrap this one.
|
||||
options.cmdBaseName = baseName
|
||||
o.cmdBaseName = baseName
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "apply -f FILENAME",
|
||||
@ -112,40 +152,85 @@ func NewCmdApply(baseName string, f cmdutil.Factory, out, errOut io.Writer) *cob
|
||||
Long: applyLong,
|
||||
Example: applyExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||
cmdutil.CheckErr(validateArgs(cmd, args))
|
||||
cmdutil.CheckErr(validatePruneAll(options.Prune, options.all, options.Selector))
|
||||
cmdutil.CheckErr(RunApply(f, cmd, out, errOut, &options))
|
||||
cmdutil.CheckErr(validatePruneAll(o.Prune, o.All, o.Selector))
|
||||
cmdutil.CheckErr(o.Run())
|
||||
},
|
||||
}
|
||||
|
||||
usage := "that contains the configuration to apply"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||
// bind flag structs
|
||||
o.DeleteFlags.AddFlags(cmd)
|
||||
o.RecordFlags.AddFlags(cmd)
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmd.MarkFlagRequired("filename")
|
||||
cmd.Flags().Bool("overwrite", true, "Automatically resolve conflicts between the modified and live configuration by using values from the modified configuration")
|
||||
cmd.Flags().BoolVar(&options.Prune, "prune", false, "Automatically delete resource objects, including the uninitialized ones, that do not appear in the configs and are created by either apply or create --save-config. Should be used with either -l or --all.")
|
||||
cmd.Flags().BoolVar(&options.Cascade, "cascade", true, "Only relevant during a prune or a force apply. If true, cascade the deletion of the resources managed by pruned or deleted resources (e.g. Pods created by a ReplicationController).")
|
||||
cmd.Flags().IntVar(&options.GracePeriod, "grace-period", -1, "Only relevant during a prune or a force apply. Period of time in seconds given to pruned or deleted resources to terminate gracefully. Ignored if negative.")
|
||||
cmd.Flags().BoolVar(&options.Force, "force", false, fmt.Sprintf("Delete and re-create the specified resource, when PATCH encounters conflict and has retried for %d times.", maxPatchRetry))
|
||||
cmd.Flags().DurationVar(&options.Timeout, "timeout", 0, "Only relevant during a force apply. The length of time to wait before giving up on a delete of the old resource, zero means determine a timeout from the size of the object. Any other values should contain a corresponding time unit (e.g. 1s, 2m, 3h).")
|
||||
cmd.Flags().BoolVar(&o.Overwrite, "overwrite", o.Overwrite, "Automatically resolve conflicts between the modified and live configuration by using values from the modified configuration")
|
||||
cmd.Flags().BoolVar(&o.Prune, "prune", o.Prune, "Automatically delete resource objects, including the uninitialized ones, that do not appear in the configs and are created by either apply or create --save-config. Should be used with either -l or --all.")
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmd.Flags().StringVarP(&options.Selector, "selector", "l", options.Selector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
|
||||
cmd.Flags().BoolVar(&options.all, "all", options.all, "Select all resources in the namespace of the specified resource types.")
|
||||
cmd.Flags().StringArray("prune-whitelist", []string{}, "Overwrite the default whitelist with <group/version/kind> for --prune")
|
||||
cmd.Flags().Bool("openapi-patch", true, "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().StringVarP(&o.Selector, "selector", "l", o.Selector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
|
||||
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.")
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddRecordFlag(cmd)
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
cmdutil.AddIncludeUninitializedFlag(cmd)
|
||||
|
||||
// apply subcommands
|
||||
cmd.AddCommand(NewCmdApplyViewLastApplied(f, out, errOut))
|
||||
cmd.AddCommand(NewCmdApplySetLastApplied(f, out, errOut))
|
||||
cmd.AddCommand(NewCmdApplyEditLastApplied(f, out, errOut))
|
||||
cmd.AddCommand(NewCmdApplyViewLastApplied(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdApplySetLastApplied(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdApplyEditLastApplied(f, ioStreams))
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o *ApplyOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
o.DryRun = cmdutil.GetDryRunFlag(cmd)
|
||||
|
||||
// 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)")
|
||||
}
|
||||
|
||||
return o.PrintFlags.ToPrinter()
|
||||
}
|
||||
|
||||
var err error
|
||||
o.RecordFlags.Complete(cmd)
|
||||
o.Recorder, err = o.RecordFlags.ToRecorder()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dynamicClient, err := f.DynamicClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.DeleteOptions = o.DeleteFlags.ToOptions(dynamicClient, o.IOStreams)
|
||||
o.ShouldIncludeUninitialized = cmdutil.ShouldIncludeUninitialized(cmd, o.Prune)
|
||||
|
||||
o.OpenAPISchema, _ = f.OpenAPISchema()
|
||||
o.Validator, err = f.Validator(cmdutil.GetFlagBool(cmd, "validate"))
|
||||
o.Builder = f.NewBuilder()
|
||||
o.Mapper, err = f.ToRESTMapper()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.DynamicClient, err = f.DynamicClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateArgs(cmd *cobra.Command, args []string) error {
|
||||
if len(args) != 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "Unexpected args: %v", args)
|
||||
@ -194,60 +279,44 @@ func parsePruneResources(mapper meta.RESTMapper, gvks []string) ([]pruneResource
|
||||
return pruneResources, nil
|
||||
}
|
||||
|
||||
func RunApply(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, options *ApplyOptions) error {
|
||||
schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
func (o *ApplyOptions) Run() error {
|
||||
var openapiSchema openapi.Resources
|
||||
if cmdutil.GetFlagBool(cmd, "openapi-patch") {
|
||||
openapiSchema, err = f.OpenAPISchema()
|
||||
if err != nil {
|
||||
openapiSchema = nil
|
||||
}
|
||||
}
|
||||
|
||||
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
if o.OpenApiPatch {
|
||||
openapiSchema = o.OpenAPISchema
|
||||
}
|
||||
|
||||
// include the uninitialized objects by default if --prune is true
|
||||
// unless explicitly set --include-uninitialized=false
|
||||
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, options.Prune)
|
||||
r := f.NewBuilder().
|
||||
r := o.Builder.
|
||||
Unstructured().
|
||||
Schema(schema).
|
||||
Schema(o.Validator).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &options.FilenameOptions).
|
||||
LabelSelectorParam(options.Selector).
|
||||
IncludeUninitialized(includeUninitialized).
|
||||
NamespaceParam(o.Namespace).DefaultNamespace().
|
||||
FilenameParam(o.EnforceNamespace, &o.DeleteOptions.FilenameOptions).
|
||||
LabelSelectorParam(o.Selector).
|
||||
IncludeUninitialized(o.ShouldIncludeUninitialized).
|
||||
Flatten().
|
||||
Do()
|
||||
if err := r.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if options.Prune {
|
||||
options.PruneResources, err = parsePruneResources(r.Mapper().RESTMapper, cmdutil.GetFlagStringArray(cmd, "prune-whitelist"))
|
||||
var err error
|
||||
if o.Prune {
|
||||
o.PruneResources, err = parsePruneResources(o.Mapper, o.PruneWhitelist)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
dryRun := cmdutil.GetDryRunFlag(cmd)
|
||||
output := cmdutil.GetFlagString(cmd, "output")
|
||||
output := *o.PrintFlags.OutputFormat
|
||||
shortOutput := output == "name"
|
||||
|
||||
encoder := scheme.DefaultJSONEncoder()
|
||||
deserializer := scheme.Codecs.UniversalDeserializer()
|
||||
mapper := r.Mapper().RESTMapper
|
||||
|
||||
visitedUids := sets.NewString()
|
||||
visitedNamespaces := sets.NewString()
|
||||
|
||||
var objs []runtime.Object
|
||||
|
||||
count := 0
|
||||
err = r.Visit(func(info *resource.Info, err error) error {
|
||||
if err != nil {
|
||||
@ -258,145 +327,185 @@ func RunApply(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, opti
|
||||
visitedNamespaces.Insert(info.Namespace)
|
||||
}
|
||||
|
||||
// Add change-cause annotation to resource info if it should be recorded
|
||||
if cmdutil.ShouldRecord(cmd, info) {
|
||||
recordInObj := info.Object
|
||||
if err := cmdutil.RecordChangeCause(recordInObj, f.Command(cmd, false)); err != nil {
|
||||
glog.V(4).Infof("error recording current command: %v", err)
|
||||
}
|
||||
if err := o.Recorder.Record(info.Object); err != nil {
|
||||
glog.V(4).Infof("error recording current command: %v", err)
|
||||
}
|
||||
|
||||
// Get the modified configuration of the object. Embed the result
|
||||
// as an annotation in the modified configuration, so that it will appear
|
||||
// in the patch sent to the server.
|
||||
modified, err := kubectl.GetModifiedConfiguration(info, true, encoder)
|
||||
modified, err := kubectl.GetModifiedConfiguration(info.Object, true, unstructured.UnstructuredJSONScheme)
|
||||
if err != nil {
|
||||
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving modified configuration from:\n%v\nfor:", info), info.Source, err)
|
||||
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving modified configuration from:\n%s\nfor:", info.String()), info.Source, err)
|
||||
}
|
||||
|
||||
// Print object only if output format other than "name" is specified
|
||||
printObject := len(output) > 0 && !shortOutput
|
||||
|
||||
if err := info.Get(); err != nil {
|
||||
if !errors.IsNotFound(err) {
|
||||
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%v\nfrom server for:", info), info.Source, err)
|
||||
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%s\nfrom server for:", info.String()), info.Source, err)
|
||||
}
|
||||
// Create the resource if it doesn't exist
|
||||
// First, update the annotation used by kubectl apply
|
||||
if err := kubectl.CreateApplyAnnotation(info, encoder); err != nil {
|
||||
if err := kubectl.CreateApplyAnnotation(info.Object, unstructured.UnstructuredJSONScheme); err != nil {
|
||||
return cmdutil.AddSourceToErr("creating", info.Source, err)
|
||||
}
|
||||
|
||||
if !dryRun {
|
||||
if !o.DryRun {
|
||||
// Then create the resource and skip the three-way merge
|
||||
if err := createAndRefresh(info); err != nil {
|
||||
obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
|
||||
if err != nil {
|
||||
return cmdutil.AddSourceToErr("creating", info.Source, err)
|
||||
}
|
||||
if uid, err := info.Mapping.UID(info.Object); err != nil {
|
||||
info.Refresh(obj, true)
|
||||
metadata, err := meta.Accessor(info.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
visitedUids.Insert(string(uid))
|
||||
}
|
||||
visitedUids.Insert(string(metadata.GetUID()))
|
||||
}
|
||||
|
||||
count++
|
||||
if len(output) > 0 && !shortOutput {
|
||||
return cmdutil.PrintObject(cmd, info.Object, out)
|
||||
}
|
||||
cmdutil.PrintSuccess(shortOutput, out, info.Object, dryRun, "created")
|
||||
return nil
|
||||
}
|
||||
|
||||
if !dryRun {
|
||||
annotationMap, err := info.Mapping.MetadataAccessor.Annotations(info.Object)
|
||||
if printObject {
|
||||
objs = append(objs, info.Object)
|
||||
return nil
|
||||
}
|
||||
|
||||
printer, err := o.ToPrinter("created")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, ok := annotationMap[api.LastAppliedConfigAnnotation]; !ok {
|
||||
fmt.Fprintf(errOut, warningNoLastAppliedConfigAnnotation, options.cmdBaseName)
|
||||
return printer.PrintObj(info.Object, o.Out)
|
||||
}
|
||||
|
||||
if !o.DryRun {
|
||||
metadata, err := meta.Accessor(info.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
overwrite := cmdutil.GetFlagBool(cmd, "overwrite")
|
||||
|
||||
annotationMap := metadata.GetAnnotations()
|
||||
if _, ok := annotationMap[api.LastAppliedConfigAnnotation]; !ok {
|
||||
fmt.Fprintf(o.ErrOut, warningNoLastAppliedConfigAnnotation, o.cmdBaseName)
|
||||
}
|
||||
|
||||
helper := resource.NewHelper(info.Client, info.Mapping)
|
||||
patcher := &patcher{
|
||||
encoder: encoder,
|
||||
decoder: deserializer,
|
||||
mapping: info.Mapping,
|
||||
helper: helper,
|
||||
clientFunc: f.UnstructuredClientForMapping,
|
||||
clientsetFunc: f.ClientSet,
|
||||
overwrite: overwrite,
|
||||
dynamicClient: o.DynamicClient,
|
||||
overwrite: o.Overwrite,
|
||||
backOff: clockwork.NewRealClock(),
|
||||
force: options.Force,
|
||||
cascade: options.Cascade,
|
||||
timeout: options.Timeout,
|
||||
gracePeriod: options.GracePeriod,
|
||||
force: o.DeleteOptions.ForceDeletion,
|
||||
cascade: o.DeleteOptions.Cascade,
|
||||
timeout: o.DeleteOptions.Timeout,
|
||||
gracePeriod: o.DeleteOptions.GracePeriod,
|
||||
openapiSchema: openapiSchema,
|
||||
}
|
||||
|
||||
patchBytes, patchedObject, err := patcher.patch(info.Object, modified, info.Source, info.Namespace, info.Name, 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)
|
||||
|
||||
if uid, err := info.Mapping.UID(info.Object); err != nil {
|
||||
return err
|
||||
} else {
|
||||
visitedUids.Insert(string(uid))
|
||||
}
|
||||
visitedUids.Insert(string(metadata.GetUID()))
|
||||
|
||||
if string(patchBytes) == "{}" {
|
||||
if string(patchBytes) == "{}" && !printObject {
|
||||
count++
|
||||
cmdutil.PrintSuccess(shortOutput, out, info.Object, false, "unchanged")
|
||||
return nil
|
||||
|
||||
printer, err := o.ToPrinter("unchanged")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return printer.PrintObj(info.Object, o.Out)
|
||||
}
|
||||
}
|
||||
count++
|
||||
if len(output) > 0 && !shortOutput {
|
||||
return cmdutil.PrintObject(cmd, info.Object, out)
|
||||
}
|
||||
cmdutil.PrintSuccess(shortOutput, out, info.Object, dryRun, "configured")
|
||||
return nil
|
||||
})
|
||||
|
||||
if printObject {
|
||||
objs = append(objs, info.Object)
|
||||
return nil
|
||||
}
|
||||
|
||||
printer, err := o.ToPrinter("configured")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return printer.PrintObj(info.Object, o.Out)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
return fmt.Errorf("no objects passed to apply")
|
||||
}
|
||||
|
||||
if !options.Prune {
|
||||
// print objects
|
||||
if len(objs) > 0 {
|
||||
printer, err := o.ToPrinter("")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
objToPrint := objs[0]
|
||||
if len(objs) > 1 {
|
||||
list := &v1.List{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "List",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ListMeta: metav1.ListMeta{},
|
||||
}
|
||||
if err := meta.SetList(list, objs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
objToPrint = list
|
||||
}
|
||||
if err := printer.PrintObj(objToPrint, o.Out); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if !o.Prune {
|
||||
return nil
|
||||
}
|
||||
|
||||
p := pruner{
|
||||
mapper: mapper,
|
||||
clientFunc: f.UnstructuredClientForMapping,
|
||||
clientsetFunc: f.ClientSet,
|
||||
mapper: o.Mapper,
|
||||
dynamicClient: o.DynamicClient,
|
||||
|
||||
labelSelector: options.Selector,
|
||||
labelSelector: o.Selector,
|
||||
visitedUids: visitedUids,
|
||||
|
||||
cascade: options.Cascade,
|
||||
dryRun: dryRun,
|
||||
gracePeriod: options.GracePeriod,
|
||||
cascade: o.DeleteOptions.Cascade,
|
||||
dryRun: o.DryRun,
|
||||
gracePeriod: o.DeleteOptions.GracePeriod,
|
||||
|
||||
out: out,
|
||||
toPrinter: o.ToPrinter,
|
||||
|
||||
out: o.Out,
|
||||
}
|
||||
|
||||
namespacedRESTMappings, nonNamespacedRESTMappings, err := getRESTMappings(mapper, &(options.PruneResources))
|
||||
namespacedRESTMappings, nonNamespacedRESTMappings, err := getRESTMappings(o.Mapper, &(o.PruneResources))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error retrieving RESTMappings to prune: %v", err)
|
||||
}
|
||||
|
||||
for n := range visitedNamespaces {
|
||||
for _, m := range namespacedRESTMappings {
|
||||
if err := p.prune(f, n, m, shortOutput, includeUninitialized); err != nil {
|
||||
if err := p.prune(n, m, o.ShouldIncludeUninitialized); err != nil {
|
||||
return fmt.Errorf("error pruning namespaced object %v: %v", m.GroupVersionKind, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, m := range nonNamespacedRESTMappings {
|
||||
if err := p.prune(f, metav1.NamespaceNone, m, shortOutput, includeUninitialized); err != nil {
|
||||
if err := p.prune(metav1.NamespaceNone, m, o.ShouldIncludeUninitialized); err != nil {
|
||||
return fmt.Errorf("error pruning nonNamespaced object %v: %v", m.GroupVersionKind, err)
|
||||
}
|
||||
}
|
||||
@ -430,6 +539,7 @@ func getRESTMappings(mapper meta.RESTMapper, pruneResources *[]pruneResource) (n
|
||||
{"", "v1", "Secret", true},
|
||||
{"", "v1", "Service", true},
|
||||
{"batch", "v1", "Job", true},
|
||||
{"batch", "v1beta1", "CronJob", true},
|
||||
{"extensions", "v1beta1", "DaemonSet", true},
|
||||
{"extensions", "v1beta1", "Deployment", true},
|
||||
{"extensions", "v1beta1", "Ingress", true},
|
||||
@ -456,8 +566,7 @@ func getRESTMappings(mapper meta.RESTMapper, pruneResources *[]pruneResource) (n
|
||||
|
||||
type pruner struct {
|
||||
mapper meta.RESTMapper
|
||||
clientFunc resource.ClientMapperFunc
|
||||
clientsetFunc func() (internalclientset.Interface, error)
|
||||
dynamicClient dynamic.Interface
|
||||
|
||||
visitedUids sets.String
|
||||
labelSelector string
|
||||
@ -467,117 +576,83 @@ type pruner struct {
|
||||
dryRun bool
|
||||
gracePeriod int
|
||||
|
||||
toPrinter func(string) (printers.ResourcePrinter, error)
|
||||
|
||||
out io.Writer
|
||||
}
|
||||
|
||||
func (p *pruner) prune(f cmdutil.Factory, namespace string, mapping *meta.RESTMapping, shortOutput, includeUninitialized bool) error {
|
||||
c, err := p.clientFunc(mapping)
|
||||
func (p *pruner) prune(namespace string, mapping *meta.RESTMapping, includeUninitialized bool) error {
|
||||
objList, err := p.dynamicClient.Resource(mapping.Resource).
|
||||
Namespace(namespace).
|
||||
List(metav1.ListOptions{
|
||||
LabelSelector: p.labelSelector,
|
||||
FieldSelector: p.fieldSelector,
|
||||
IncludeUninitialized: includeUninitialized,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
objList, err := resource.NewHelper(c, mapping).List(
|
||||
namespace,
|
||||
mapping.GroupVersionKind.Version,
|
||||
false,
|
||||
&metav1.ListOptions{
|
||||
LabelSelector: p.labelSelector,
|
||||
FieldSelector: p.fieldSelector,
|
||||
IncludeUninitialized: includeUninitialized,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
objs, err := meta.ExtractList(objList)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, obj := range objs {
|
||||
annots, err := mapping.MetadataAccessor.Annotations(obj)
|
||||
metadata, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
annots := metadata.GetAnnotations()
|
||||
if _, ok := annots[api.LastAppliedConfigAnnotation]; !ok {
|
||||
// don't prune resources not created with apply
|
||||
continue
|
||||
}
|
||||
uid, err := mapping.UID(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
uid := metadata.GetUID()
|
||||
if p.visitedUids.Has(string(uid)) {
|
||||
continue
|
||||
}
|
||||
|
||||
name, err := mapping.Name(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
name := metadata.GetName()
|
||||
if !p.dryRun {
|
||||
if err := p.delete(namespace, name, mapping); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
cmdutil.PrintSuccess(shortOutput, p.out, obj, p.dryRun, "pruned")
|
||||
|
||||
printer, err := p.toPrinter("pruned")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printer.PrintObj(obj, p.out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *pruner) delete(namespace, name string, mapping *meta.RESTMapping) error {
|
||||
c, err := p.clientFunc(mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return runDelete(namespace, name, mapping, c, nil, p.cascade, p.gracePeriod, p.clientsetFunc)
|
||||
return runDelete(namespace, name, mapping, p.dynamicClient, p.cascade, p.gracePeriod)
|
||||
}
|
||||
|
||||
func runDelete(namespace, name string, mapping *meta.RESTMapping, c resource.RESTClient, helper *resource.Helper, cascade bool, gracePeriod int, clientsetFunc func() (internalclientset.Interface, error)) error {
|
||||
if !cascade {
|
||||
if helper == nil {
|
||||
helper = resource.NewHelper(c, mapping)
|
||||
}
|
||||
return helper.Delete(namespace, name)
|
||||
}
|
||||
cs, err := clientsetFunc()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r, err := kubectl.ReaperFor(mapping.GroupVersionKind.GroupKind(), cs)
|
||||
if err != nil {
|
||||
if _, ok := err.(*kubectl.NoSuchReaperError); !ok {
|
||||
return err
|
||||
}
|
||||
return resource.NewHelper(c, mapping).Delete(namespace, name)
|
||||
}
|
||||
var options *metav1.DeleteOptions
|
||||
func runDelete(namespace, name string, mapping *meta.RESTMapping, c dynamic.Interface, cascade bool, gracePeriod int) error {
|
||||
options := &metav1.DeleteOptions{}
|
||||
if gracePeriod >= 0 {
|
||||
options = metav1.NewDeleteOptions(int64(gracePeriod))
|
||||
}
|
||||
if err := r.Stop(namespace, name, 2*time.Minute, options); err != nil {
|
||||
return err
|
||||
policy := metav1.DeletePropagationForeground
|
||||
if !cascade {
|
||||
policy = metav1.DeletePropagationOrphan
|
||||
}
|
||||
return nil
|
||||
options.PropagationPolicy = &policy
|
||||
return c.Resource(mapping.Resource).Namespace(namespace).Delete(name, options)
|
||||
}
|
||||
|
||||
func (p *patcher) delete(namespace, name string) error {
|
||||
c, err := p.clientFunc(p.mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return runDelete(namespace, name, p.mapping, c, p.helper, p.cascade, p.gracePeriod, p.clientsetFunc)
|
||||
return runDelete(namespace, name, p.mapping, p.dynamicClient, p.cascade, p.gracePeriod)
|
||||
}
|
||||
|
||||
type patcher struct {
|
||||
encoder runtime.Encoder
|
||||
decoder runtime.Decoder
|
||||
|
||||
mapping *meta.RESTMapping
|
||||
helper *resource.Helper
|
||||
clientFunc resource.ClientMapperFunc
|
||||
clientsetFunc func() (internalclientset.Interface, error)
|
||||
dynamicClient dynamic.Interface
|
||||
|
||||
overwrite bool
|
||||
backOff clockwork.Clock
|
||||
@ -592,13 +667,13 @@ type patcher struct {
|
||||
|
||||
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(p.encoder, obj)
|
||||
current, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
|
||||
if err != nil {
|
||||
return nil, nil, cmdutil.AddSourceToErr(fmt.Sprintf("serializing current configuration from:\n%v\nfor:", obj), source, err)
|
||||
}
|
||||
|
||||
// Retrieve the original configuration of the object from the annotation.
|
||||
original, err := kubectl.GetOriginalConfiguration(p.mapping, obj)
|
||||
original, err := kubectl.GetOriginalConfiguration(obj)
|
||||
if err != nil {
|
||||
return nil, nil, cmdutil.AddSourceToErr(fmt.Sprintf("retrieving original configuration from:\n%v\nfor:", obj), source, err)
|
||||
}
|
||||
@ -685,20 +760,19 @@ func (p *patcher) patch(current runtime.Object, modified []byte, source, namespa
|
||||
}
|
||||
|
||||
func (p *patcher) deleteAndCreate(original runtime.Object, modified []byte, namespace, name string) ([]byte, runtime.Object, error) {
|
||||
err := p.delete(namespace, name)
|
||||
if err != nil {
|
||||
if err := p.delete(namespace, name); err != nil {
|
||||
return modified, nil, err
|
||||
}
|
||||
err = wait.PollImmediate(kubectl.Interval, p.timeout, func() (bool, error) {
|
||||
// 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) {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
if err != nil {
|
||||
}); err != nil {
|
||||
return modified, nil, err
|
||||
}
|
||||
versionedObject, _, err := p.decoder.Decode(modified, nil, nil)
|
||||
versionedObject, _, err := unstructured.UnstructuredJSONScheme.Decode(modified, nil, nil)
|
||||
if err != nil {
|
||||
return modified, nil, err
|
||||
}
|
||||
|
29
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply_edit_last_applied.go
generated
vendored
29
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply_edit_last_applied.go
generated
vendored
@ -17,15 +17,12 @@ limitations under the License.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"io"
|
||||
"runtime"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -58,11 +55,8 @@ var (
|
||||
kubectl apply edit-last-applied -f deploy.yaml -o json`)
|
||||
)
|
||||
|
||||
func NewCmdApplyEditLastApplied(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
options := &editor.EditOptions{
|
||||
EditMode: editor.ApplyEditMode,
|
||||
}
|
||||
validArgs := cmdutil.ValidArgList(f)
|
||||
func NewCmdApplyEditLastApplied(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := editor.NewEditOptions(editor.ApplyEditMode, ioStreams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "edit-last-applied (RESOURCE/NAME | -f FILENAME)",
|
||||
@ -71,24 +65,23 @@ func NewCmdApplyEditLastApplied(f cmdutil.Factory, out, errOut io.Writer) *cobra
|
||||
Long: applyEditLastAppliedLong,
|
||||
Example: applyEditLastAppliedExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
options.ChangeCause = f.Command(cmd, false)
|
||||
if err := options.Complete(f, out, errOut, args, cmd); err != nil {
|
||||
if err := o.Complete(f, args, cmd); err != nil {
|
||||
cmdutil.CheckErr(err)
|
||||
}
|
||||
if err := options.Run(); err != nil {
|
||||
if err := o.Run(); err != nil {
|
||||
cmdutil.CheckErr(err)
|
||||
}
|
||||
},
|
||||
ValidArgs: validArgs,
|
||||
ArgAliases: kubectl.ResourceAliases(validArgs),
|
||||
}
|
||||
|
||||
// bind flag structs
|
||||
o.RecordFlags.AddFlags(cmd)
|
||||
|
||||
usage := "to use to edit the resource"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||
cmd.Flags().StringVarP(&options.Output, "output", "o", "yaml", "Output format. One of: yaml|json.")
|
||||
cmd.Flags().BoolVar(&options.WindowsLineEndings, "windows-line-endings", runtime.GOOS == "windows",
|
||||
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.AddRecordVarFlag(cmd, &options.Record)
|
||||
cmdutil.AddIncludeUninitializedFlag(cmd)
|
||||
|
||||
return cmd
|
||||
|
174
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply_set_last_applied.go
generated
vendored
174
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply_set_last_applied.go
generated
vendored
@ -18,44 +18,44 @@ package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
apijson "k8s.io/apimachinery/pkg/util/json"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"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/resource"
|
||||
"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"
|
||||
)
|
||||
|
||||
type SetLastAppliedOptions struct {
|
||||
FilenameOptions resource.FilenameOptions
|
||||
Selector string
|
||||
InfoList []*resource.Info
|
||||
Mapper meta.RESTMapper
|
||||
Typer runtime.ObjectTyper
|
||||
Namespace string
|
||||
EnforceNamespace bool
|
||||
DryRun bool
|
||||
ShortOutput bool
|
||||
CreateAnnotation bool
|
||||
Output string
|
||||
PatchBufferList []PatchBuffer
|
||||
Factory cmdutil.Factory
|
||||
Out io.Writer
|
||||
ErrOut io.Writer
|
||||
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
PrintObj printers.ResourcePrinterFunc
|
||||
|
||||
FilenameOptions resource.FilenameOptions
|
||||
|
||||
infoList []*resource.Info
|
||||
namespace string
|
||||
enforceNamespace bool
|
||||
dryRun bool
|
||||
shortOutput bool
|
||||
output string
|
||||
patchBufferList []PatchBuffer
|
||||
builder *resource.Builder
|
||||
unstructuredClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error)
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
type PatchBuffer struct {
|
||||
@ -81,8 +81,15 @@ var (
|
||||
`))
|
||||
)
|
||||
|
||||
func NewCmdApplySetLastApplied(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
|
||||
options := &SetLastAppliedOptions{Out: out, ErrOut: err}
|
||||
func NewSetLastAppliedOptions(ioStreams genericclioptions.IOStreams) *SetLastAppliedOptions {
|
||||
return &SetLastAppliedOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("configured").WithTypeSetter(scheme.Scheme),
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdApplySetLastApplied(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewSetLastAppliedOptions(ioStreams)
|
||||
cmd := &cobra.Command{
|
||||
Use: "set-last-applied -f FILENAME",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -90,42 +97,55 @@ func NewCmdApplySetLastApplied(f cmdutil.Factory, out, err io.Writer) *cobra.Com
|
||||
Long: applySetLastAppliedLong,
|
||||
Example: applySetLastAppliedExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(options.Complete(f, cmd))
|
||||
cmdutil.CheckErr(options.Validate(f, cmd))
|
||||
cmdutil.CheckErr(options.RunSetLastApplied(f, cmd))
|
||||
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||
cmdutil.CheckErr(o.Validate())
|
||||
cmdutil.CheckErr(o.RunSetLastApplied())
|
||||
},
|
||||
}
|
||||
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
cmdutil.AddRecordFlag(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmd.Flags().BoolVar(&options.CreateAnnotation, "create-annotation", false, "Will create 'last-applied-configuration' annotations if current objects doesn't have one")
|
||||
usage := "that contains the last-applied-configuration annotations"
|
||||
kubectl.AddJsonFilenameFlag(cmd, &options.FilenameOptions.Filenames, "Filename, directory, or URL to files "+usage)
|
||||
cmd.Flags().BoolVar(&o.CreateAnnotation, "create-annotation", o.CreateAnnotation, "Will create 'last-applied-configuration' annotations if current objects doesn't have one")
|
||||
cmdutil.AddJsonFilenameFlag(cmd.Flags(), &o.FilenameOptions.Filenames, "Filename, directory, or URL to files that contains the last-applied-configuration annotations")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o *SetLastAppliedOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
o.DryRun = cmdutil.GetDryRunFlag(cmd)
|
||||
o.Output = cmdutil.GetFlagString(cmd, "output")
|
||||
o.ShortOutput = o.Output == "name"
|
||||
o.dryRun = cmdutil.GetDryRunFlag(cmd)
|
||||
o.output = cmdutil.GetFlagString(cmd, "output")
|
||||
o.shortOutput = o.output == "name"
|
||||
|
||||
var err error
|
||||
o.Mapper, o.Typer = f.Object()
|
||||
o.namespace, o.enforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.builder = f.NewBuilder()
|
||||
o.unstructuredClientForMapping = f.UnstructuredClientForMapping
|
||||
|
||||
o.Namespace, o.EnforceNamespace, err = f.DefaultNamespace()
|
||||
return err
|
||||
if o.dryRun {
|
||||
// TODO(juanvallejo): This can be cleaned up even further by creating
|
||||
// a PrintFlags struct that binds the --dry-run flag, and whose
|
||||
// ToPrinter method returns a printer that understands how to print
|
||||
// this success message.
|
||||
o.PrintFlags.Complete("%s (dry run)")
|
||||
}
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.PrintObj = printer.PrintObj
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *SetLastAppliedOptions) Validate(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
r := f.NewBuilder().
|
||||
func (o *SetLastAppliedOptions) Validate() error {
|
||||
r := o.builder.
|
||||
Unstructured().
|
||||
NamespaceParam(o.Namespace).DefaultNamespace().
|
||||
FilenameParam(o.EnforceNamespace, &o.FilenameOptions).
|
||||
NamespaceParam(o.namespace).DefaultNamespace().
|
||||
FilenameParam(o.enforceNamespace, &o.FilenameOptions).
|
||||
Flatten().
|
||||
Do()
|
||||
|
||||
@ -133,7 +153,7 @@ func (o *SetLastAppliedOptions) Validate(f cmdutil.Factory, cmd *cobra.Command)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
patchBuf, diffBuf, patchType, err := editor.GetApplyPatch(info.Object, scheme.DefaultJSONEncoder())
|
||||
patchBuf, diffBuf, patchType, err := editor.GetApplyPatch(info.Object.(runtime.Unstructured))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -143,22 +163,22 @@ func (o *SetLastAppliedOptions) Validate(f cmdutil.Factory, cmd *cobra.Command)
|
||||
if errors.IsNotFound(err) {
|
||||
return err
|
||||
} else {
|
||||
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%v\nfrom server for:", info), info.Source, err)
|
||||
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%s\nfrom server for:", info.String()), info.Source, err)
|
||||
}
|
||||
}
|
||||
originalBuf, err := kubectl.GetOriginalConfiguration(info.Mapping, info.Object)
|
||||
originalBuf, err := kubectl.GetOriginalConfiguration(info.Object)
|
||||
if err != nil {
|
||||
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%v\nfrom server for:", info), info.Source, err)
|
||||
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%s\nfrom server for:", info.String()), info.Source, err)
|
||||
}
|
||||
if originalBuf == nil && !o.CreateAnnotation {
|
||||
return cmdutil.UsageErrorf(cmd, "no last-applied-configuration annotation found on resource: %s, to create the annotation, run the command with --create-annotation", info.Name)
|
||||
return fmt.Errorf("no last-applied-configuration annotation found on resource: %s, to create the annotation, run the command with --create-annotation", info.Name)
|
||||
}
|
||||
|
||||
//only add to PatchBufferList when changed
|
||||
if !bytes.Equal(cmdutil.StripComments(originalBuf), cmdutil.StripComments(diffBuf)) {
|
||||
p := PatchBuffer{Patch: patchBuf, PatchType: patchType}
|
||||
o.PatchBufferList = append(o.PatchBufferList, p)
|
||||
o.InfoList = append(o.InfoList, info)
|
||||
o.patchBufferList = append(o.patchBufferList, p)
|
||||
o.infoList = append(o.infoList, info)
|
||||
} else {
|
||||
fmt.Fprintf(o.Out, "set-last-applied %s: no changes required.\n", info.Name)
|
||||
}
|
||||
@ -168,68 +188,26 @@ func (o *SetLastAppliedOptions) Validate(f cmdutil.Factory, cmd *cobra.Command)
|
||||
return err
|
||||
}
|
||||
|
||||
func (o *SetLastAppliedOptions) RunSetLastApplied(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
for i, patch := range o.PatchBufferList {
|
||||
info := o.InfoList[i]
|
||||
if !o.DryRun {
|
||||
func (o *SetLastAppliedOptions) RunSetLastApplied() error {
|
||||
for i, patch := range o.patchBufferList {
|
||||
info := o.infoList[i]
|
||||
finalObj := info.Object
|
||||
|
||||
if !o.dryRun {
|
||||
mapping := info.ResourceMapping()
|
||||
client, err := f.UnstructuredClientForMapping(mapping)
|
||||
client, err := o.unstructuredClientForMapping(mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
helper := resource.NewHelper(client, mapping)
|
||||
patchedObj, err := helper.Patch(o.Namespace, info.Name, patch.PatchType, patch.Patch)
|
||||
finalObj, err = helper.Patch(o.namespace, info.Name, patch.PatchType, patch.Patch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(o.Output) > 0 && !o.ShortOutput {
|
||||
info.Refresh(patchedObj, false)
|
||||
return cmdutil.PrintObject(cmd, info.Object, o.Out)
|
||||
}
|
||||
cmdutil.PrintSuccess(o.ShortOutput, o.Out, info.Object, o.DryRun, "configured")
|
||||
|
||||
} else {
|
||||
err := o.formatPrinter(o.Output, patch.Patch, o.Out)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmdutil.PrintSuccess(o.ShortOutput, o.Out, info.Object, o.DryRun, "configured")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *SetLastAppliedOptions) formatPrinter(output string, buf []byte, w io.Writer) error {
|
||||
yamlOutput, err := yaml.JSONToYAML(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch output {
|
||||
case "json":
|
||||
jsonBuffer := &bytes.Buffer{}
|
||||
err = json.Indent(jsonBuffer, buf, "", " ")
|
||||
if err != nil {
|
||||
if err := o.PrintObj(finalObj, o.Out); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(w, "%s\n", jsonBuffer.String())
|
||||
case "yaml":
|
||||
fmt.Fprintf(w, "%s\n", string(yamlOutput))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *SetLastAppliedOptions) getPatch(info *resource.Info) ([]byte, []byte, error) {
|
||||
objMap := map[string]map[string]map[string]string{}
|
||||
metadataMap := map[string]map[string]string{}
|
||||
annotationsMap := map[string]string{}
|
||||
localFile, err := runtime.Encode(scheme.DefaultJSONEncoder(), info.Object)
|
||||
if err != nil {
|
||||
return nil, localFile, err
|
||||
}
|
||||
annotationsMap[api.LastAppliedConfigAnnotation] = string(localFile)
|
||||
metadataMap["annotations"] = annotationsMap
|
||||
objMap["metadata"] = metadataMap
|
||||
jsonString, err := apijson.Marshal(objMap)
|
||||
return jsonString, localFile, err
|
||||
}
|
||||
|
1099
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply_test.go
generated
vendored
1099
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply_test.go
generated
vendored
File diff suppressed because it is too large
Load Diff
60
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply_view_last_applied.go
generated
vendored
60
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply_view_last_applied.go
generated
vendored
@ -20,14 +20,14 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/spf13/cobra"
|
||||
"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/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
@ -38,8 +38,8 @@ type ViewLastAppliedOptions struct {
|
||||
OutputFormat string
|
||||
All bool
|
||||
Factory cmdutil.Factory
|
||||
Out io.Writer
|
||||
ErrOut io.Writer
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
var (
|
||||
@ -57,8 +57,17 @@ var (
|
||||
kubectl apply view-last-applied -f deploy.yaml -o json`))
|
||||
)
|
||||
|
||||
func NewCmdApplyViewLastApplied(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
|
||||
options := &ViewLastAppliedOptions{Out: out, ErrOut: err}
|
||||
func NewViewLastAppliedOptions(ioStreams genericclioptions.IOStreams) *ViewLastAppliedOptions {
|
||||
return &ViewLastAppliedOptions{
|
||||
OutputFormat: "yaml",
|
||||
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdApplyViewLastApplied(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := NewViewLastAppliedOptions(ioStreams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "view-last-applied (TYPE [NAME | -l label] | TYPE/NAME | -f FILENAME)",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -66,24 +75,23 @@ func NewCmdApplyViewLastApplied(f cmdutil.Factory, out, err io.Writer) *cobra.Co
|
||||
Long: applyViewLastAppliedLong,
|
||||
Example: applyViewLastAppliedExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(options.ValidateOutputArgs(cmd))
|
||||
cmdutil.CheckErr(options.Complete(f, args))
|
||||
cmdutil.CheckErr(options.Complete(cmd, f, args))
|
||||
cmdutil.CheckErr(options.Validate(cmd))
|
||||
cmdutil.CheckErr(options.RunApplyViewLastApplied())
|
||||
cmdutil.CheckErr(options.RunApplyViewLastApplied(cmd))
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringP("output", "o", "", "Output format. Must be one of yaml|json")
|
||||
cmd.Flags().StringVarP(&options.Selector, "selector", "l", "", "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
|
||||
cmd.Flags().BoolVar(&options.All, "all", false, "Select all resources in the namespace of the specified resource types")
|
||||
cmd.Flags().StringVarP(&options.OutputFormat, "output", "o", options.OutputFormat, "Output format. Must be one of yaml|json")
|
||||
cmd.Flags().StringVarP(&options.Selector, "selector", "l", options.Selector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
|
||||
cmd.Flags().BoolVar(&options.All, "all", options.All, "Select all resources in the namespace of the specified resource types")
|
||||
usage := "that contains the last-applied-configuration annotations"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o *ViewLastAppliedOptions) Complete(f cmdutil.Factory, args []string) error {
|
||||
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
func (o *ViewLastAppliedOptions) Complete(cmd *cobra.Command, f cmdutil.Factory, args []string) error {
|
||||
cmdNamespace, enforceNamespace, err := f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -108,7 +116,7 @@ func (o *ViewLastAppliedOptions) Complete(f cmdutil.Factory, args []string) erro
|
||||
return err
|
||||
}
|
||||
|
||||
configString, err := kubectl.GetOriginalConfiguration(info.Mapping, info.Object)
|
||||
configString, err := kubectl.GetOriginalConfiguration(info.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -130,7 +138,7 @@ func (o *ViewLastAppliedOptions) Validate(cmd *cobra.Command) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *ViewLastAppliedOptions) RunApplyViewLastApplied() error {
|
||||
func (o *ViewLastAppliedOptions) RunApplyViewLastApplied(cmd *cobra.Command) error {
|
||||
for _, str := range o.LastAppliedConfigurationList {
|
||||
switch o.OutputFormat {
|
||||
case "json":
|
||||
@ -146,23 +154,13 @@ func (o *ViewLastAppliedOptions) RunApplyViewLastApplied() error {
|
||||
return err
|
||||
}
|
||||
fmt.Fprint(o.Out, string(yamlOutput))
|
||||
default:
|
||||
return cmdutil.UsageErrorf(
|
||||
cmd,
|
||||
"Unexpected -o output mode: %s, the flag 'output' must be one of yaml|json",
|
||||
o.OutputFormat)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *ViewLastAppliedOptions) ValidateOutputArgs(cmd *cobra.Command) error {
|
||||
format := cmdutil.GetFlagString(cmd, "output")
|
||||
switch format {
|
||||
case "json":
|
||||
o.OutputFormat = "json"
|
||||
return nil
|
||||
// If flag -o is not specified, use yaml as default
|
||||
case "yaml", "":
|
||||
o.OutputFormat = "yaml"
|
||||
return nil
|
||||
default:
|
||||
return cmdutil.UsageErrorf(cmd, "Unexpected -o output mode: %s, the flag 'output' must be one of yaml|json", format)
|
||||
}
|
||||
}
|
||||
|
49
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/attach.go
generated
vendored
49
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/attach.go
generated
vendored
@ -35,6 +35,8 @@ import (
|
||||
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
|
||||
"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/polymorphichelpers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
@ -60,12 +62,10 @@ const (
|
||||
defaultPodLogsTimeout = 20 * time.Second
|
||||
)
|
||||
|
||||
func NewCmdAttach(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *cobra.Command {
|
||||
options := &AttachOptions{
|
||||
func NewCmdAttach(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := &AttachOptions{
|
||||
StreamOptions: StreamOptions{
|
||||
In: cmdIn,
|
||||
Out: cmdOut,
|
||||
Err: cmdErr,
|
||||
IOStreams: streams,
|
||||
},
|
||||
|
||||
Attach: &DefaultRemoteAttach{},
|
||||
@ -77,15 +77,15 @@ func NewCmdAttach(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer)
|
||||
Long: "Attach to a process that is already running inside an existing container.",
|
||||
Example: attachExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Validate())
|
||||
cmdutil.CheckErr(options.Run())
|
||||
cmdutil.CheckErr(o.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(o.Validate())
|
||||
cmdutil.CheckErr(o.Run())
|
||||
},
|
||||
}
|
||||
cmdutil.AddPodRunningTimeoutFlag(cmd, defaultPodAttachTimeout)
|
||||
cmd.Flags().StringVarP(&options.ContainerName, "container", "c", "", "Container name. If omitted, the first container in the pod will be chosen")
|
||||
cmd.Flags().BoolVarP(&options.Stdin, "stdin", "i", false, "Pass stdin to the container")
|
||||
cmd.Flags().BoolVarP(&options.TTY, "tty", "t", false, "Stdin is a TTY")
|
||||
cmd.Flags().StringVarP(&o.ContainerName, "container", "c", o.ContainerName, "Container name. If omitted, the first container in the pod will be chosen")
|
||||
cmd.Flags().BoolVarP(&o.Stdin, "stdin", "i", o.Stdin, "Pass stdin to the container")
|
||||
cmd.Flags().BoolVarP(&o.TTY, "tty", "t", o.TTY, "Stdin is a TTY")
|
||||
return cmd
|
||||
}
|
||||
|
||||
@ -135,7 +135,7 @@ func (p *AttachOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn [
|
||||
return cmdutil.UsageErrorf(cmd, "expected POD, TYPE/NAME, or TYPE NAME, (at most 2 arguments) saw %d: %v", len(argsIn), argsIn)
|
||||
}
|
||||
|
||||
namespace, _, err := f.DefaultNamespace()
|
||||
namespace, _, err := f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -146,7 +146,7 @@ func (p *AttachOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn [
|
||||
}
|
||||
|
||||
builder := f.NewBuilder().
|
||||
Internal().
|
||||
WithScheme(legacyscheme.Scheme).
|
||||
NamespaceParam(namespace).DefaultNamespace()
|
||||
|
||||
switch len(argsIn) {
|
||||
@ -161,7 +161,7 @@ func (p *AttachOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn [
|
||||
return err
|
||||
}
|
||||
|
||||
attachablePod, err := f.AttachablePodForObject(obj, p.GetPodTimeout)
|
||||
attachablePod, err := polymorphichelpers.AttachablePodForObjectFn(f, obj, p.GetPodTimeout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -178,7 +178,7 @@ func (p *AttachOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn [
|
||||
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)
|
||||
}
|
||||
|
||||
config, err := f.ClientConfig()
|
||||
config, err := f.ToRESTConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -188,6 +188,7 @@ func (p *AttachOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn [
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.PodClient = clientset.Core()
|
||||
|
||||
if p.CommandName == "" {
|
||||
@ -203,7 +204,7 @@ func (p *AttachOptions) Validate() error {
|
||||
if len(p.PodName) == 0 {
|
||||
allErrs = append(allErrs, errors.New("pod name must be specified"))
|
||||
}
|
||||
if p.Out == nil || p.Err == nil {
|
||||
if p.Out == nil || p.ErrOut == nil {
|
||||
allErrs = append(allErrs, errors.New("both output and error output must be provided"))
|
||||
}
|
||||
if p.Attach == nil || p.PodClient == nil || p.Config == nil {
|
||||
@ -236,8 +237,8 @@ func (p *AttachOptions) Run() error {
|
||||
}
|
||||
if p.TTY && !containerToAttach.TTY {
|
||||
p.TTY = false
|
||||
if p.Err != nil {
|
||||
fmt.Fprintf(p.Err, "Unable to use a TTY - container %s did not allocate one\n", containerToAttach.Name)
|
||||
if p.ErrOut != nil {
|
||||
fmt.Fprintf(p.ErrOut, "Unable to use a TTY - container %s did not allocate one\n", containerToAttach.Name)
|
||||
}
|
||||
} else if !p.TTY && containerToAttach.TTY {
|
||||
// the container was launched with a TTY, so we have to force a TTY here, otherwise you'll get
|
||||
@ -249,7 +250,7 @@ func (p *AttachOptions) Run() error {
|
||||
t := p.setupTTY()
|
||||
|
||||
// save p.Err so we can print the command prompt message below
|
||||
stderr := p.Err
|
||||
stderr := p.ErrOut
|
||||
|
||||
var sizeQueue remotecommand.TerminalSizeQueue
|
||||
if t.Raw {
|
||||
@ -266,7 +267,7 @@ func (p *AttachOptions) Run() error {
|
||||
|
||||
// unset p.Err if it was previously set because both stdout and stderr go over p.Out when tty is
|
||||
// true
|
||||
p.Err = nil
|
||||
p.ErrOut = nil
|
||||
}
|
||||
|
||||
fn := func() error {
|
||||
@ -284,11 +285,11 @@ func (p *AttachOptions) Run() error {
|
||||
Container: containerToAttach.Name,
|
||||
Stdin: p.Stdin,
|
||||
Stdout: p.Out != nil,
|
||||
Stderr: p.Err != nil,
|
||||
Stderr: p.ErrOut != nil,
|
||||
TTY: t.Raw,
|
||||
}, legacyscheme.ParameterCodec)
|
||||
|
||||
return p.Attach.Attach("POST", req.URL(), p.Config, p.In, p.Out, p.Err, t.Raw, sizeQueue)
|
||||
return p.Attach.Attach("POST", req.URL(), p.Config, p.In, p.Out, p.ErrOut, t.Raw, sizeQueue)
|
||||
}
|
||||
|
||||
if !p.Quiet && stderr != nil {
|
||||
@ -322,8 +323,8 @@ func (p *AttachOptions) containerToAttachTo(pod *api.Pod) (*api.Container, error
|
||||
}
|
||||
|
||||
if len(p.SuggestedCmdUsage) > 0 {
|
||||
fmt.Fprintf(p.Err, "Defaulting container name to %s.\n", pod.Spec.Containers[0].Name)
|
||||
fmt.Fprintf(p.Err, "%s\n", p.SuggestedCmdUsage)
|
||||
fmt.Fprintf(p.ErrOut, "Defaulting container name to %s.\n", pod.Spec.Containers[0].Name)
|
||||
fmt.Fprintf(p.ErrOut, "%s\n", p.SuggestedCmdUsage)
|
||||
}
|
||||
|
||||
glog.V(4).Infof("defaulting container name to %s", pod.Spec.Containers[0].Name)
|
||||
|
311
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/attach_test.go
generated
vendored
311
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/attach_test.go
generated
vendored
@ -17,7 +17,6 @@ limitations under the License.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@ -38,6 +37,7 @@ import (
|
||||
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"
|
||||
)
|
||||
|
||||
@ -139,48 +139,51 @@ func TestPodAndContainerAttach(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
ns := legacyscheme.Codecs
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
|
||||
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.Namespace = "test"
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
cmd := &cobra.Command{}
|
||||
options := test.p
|
||||
cmdutil.AddPodRunningTimeoutFlag(cmd, test.timeout)
|
||||
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()
|
||||
|
||||
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 {
|
||||
continue
|
||||
}
|
||||
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)
|
||||
}
|
||||
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 := legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion.Version
|
||||
version := "v1"
|
||||
tests := []struct {
|
||||
name, version, podPath, fetchPodPath, attachPath, container string
|
||||
pod *api.Pod
|
||||
@ -219,79 +222,76 @@ func TestAttach(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
ns := legacyscheme.Codecs
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
|
||||
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:
|
||||
// Ensures no GET is performed when deleting by name
|
||||
t.Errorf("%s: unexpected request: %s %#v\n%#v", p, req.Method, req.URL, req)
|
||||
return nil, fmt.Errorf("unexpected request")
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = &restclient.Config{APIPath: "/api", ContentConfig: restclient.ContentConfig{NegotiatedSerializer: legacyscheme.Codecs, GroupVersion: &schema.GroupVersion{Version: test.version}}}
|
||||
bufOut := bytes.NewBuffer([]byte{})
|
||||
bufErr := bytes.NewBuffer([]byte{})
|
||||
bufIn := bytes.NewBuffer([]byte{})
|
||||
remoteAttach := &fakeRemoteAttach{}
|
||||
if test.remoteAttachErr {
|
||||
remoteAttach.err = fmt.Errorf("attach error")
|
||||
}
|
||||
params := &AttachOptions{
|
||||
StreamOptions: StreamOptions{
|
||||
ContainerName: test.container,
|
||||
In: bufIn,
|
||||
Out: bufOut,
|
||||
Err: bufErr,
|
||||
},
|
||||
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)
|
||||
continue
|
||||
}
|
||||
if test.exepctedErr == "" && err != nil {
|
||||
t.Errorf("%s: Unexpected error: %v", test.name, err)
|
||||
continue
|
||||
}
|
||||
if test.exepctedErr != "" {
|
||||
continue
|
||||
}
|
||||
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)
|
||||
continue
|
||||
}
|
||||
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())
|
||||
}
|
||||
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 := legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion.Version
|
||||
version := "v1"
|
||||
tests := []struct {
|
||||
name, container, version, podPath, fetchPodPath, expectedErr string
|
||||
pod *api.Pod
|
||||
@ -309,62 +309,61 @@ func TestAttachWarnings(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
ns := legacyscheme.Codecs
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
|
||||
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.Namespace = "test"
|
||||
tf.ClientConfigVal = &restclient.Config{APIPath: "/api", ContentConfig: restclient.ContentConfig{NegotiatedSerializer: legacyscheme.Codecs, GroupVersion: &schema.GroupVersion{Version: test.version}}}
|
||||
bufOut := bytes.NewBuffer([]byte{})
|
||||
bufErr := bytes.NewBuffer([]byte{})
|
||||
bufIn := bytes.NewBuffer([]byte{})
|
||||
ex := &fakeRemoteAttach{}
|
||||
params := &AttachOptions{
|
||||
StreamOptions: StreamOptions{
|
||||
ContainerName: test.container,
|
||||
In: bufIn,
|
||||
Out: bufOut,
|
||||
Err: bufErr,
|
||||
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)
|
||||
}
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
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())
|
||||
continue
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
11
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/auth/BUILD
generated
vendored
11
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/auth/BUILD
generated
vendored
@ -17,18 +17,21 @@ go_library(
|
||||
],
|
||||
deps = [
|
||||
"//pkg/apis/authorization:go_default_library",
|
||||
"//pkg/apis/rbac:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/typed/authorization/internalversion:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion:go_default_library",
|
||||
"//pkg/kubectl/cmd/templates:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/kubectl/resource: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/registry/rbac/reconciliation:go_default_library",
|
||||
"//vendor/github.com/golang/glog: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",
|
||||
],
|
||||
)
|
||||
|
||||
|
11
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/auth/auth.go
generated
vendored
11
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/auth/auth.go
generated
vendored
@ -17,24 +17,23 @@ limitations under the License.
|
||||
package auth
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
)
|
||||
|
||||
func NewCmdAuth(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
func NewCmdAuth(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
// Parent command to which all subcommands are added.
|
||||
cmds := &cobra.Command{
|
||||
Use: "auth",
|
||||
Short: "Inspect authorization",
|
||||
Long: `Inspect authorization`,
|
||||
Run: cmdutil.DefaultSubCommandRun(errOut),
|
||||
Run: cmdutil.DefaultSubCommandRun(streams.ErrOut),
|
||||
}
|
||||
|
||||
cmds.AddCommand(NewCmdCanI(f, out, errOut))
|
||||
cmds.AddCommand(NewCmdReconcile(f, out, errOut))
|
||||
cmds.AddCommand(NewCmdCanI(f, streams))
|
||||
cmds.AddCommand(NewCmdReconcile(f, streams))
|
||||
|
||||
return cmds
|
||||
}
|
||||
|
25
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/auth/cani.go
generated
vendored
25
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/auth/cani.go
generated
vendored
@ -19,12 +19,12 @@ package auth
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
@ -48,8 +48,7 @@ type CanIOptions struct {
|
||||
Subresource string
|
||||
ResourceName string
|
||||
|
||||
Out io.Writer
|
||||
Err io.Writer
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
var (
|
||||
@ -81,10 +80,9 @@ var (
|
||||
kubectl auth can-i get /logs/`)
|
||||
)
|
||||
|
||||
func NewCmdCanI(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
|
||||
func NewCmdCanI(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := &CanIOptions{
|
||||
Out: out,
|
||||
Err: err,
|
||||
IOStreams: streams,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
@ -99,7 +97,7 @@ func NewCmdCanI(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
|
||||
|
||||
allowed, err := o.RunAccessCheck()
|
||||
if err == nil {
|
||||
if o.Quiet && !allowed {
|
||||
if !allowed {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
@ -110,7 +108,7 @@ func NewCmdCanI(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
|
||||
|
||||
cmd.Flags().BoolVar(&o.AllNamespaces, "all-namespaces", o.AllNamespaces, "If true, check the specified action in all namespaces.")
|
||||
cmd.Flags().BoolVarP(&o.Quiet, "quiet", "q", o.Quiet, "If true, suppress output and just return the exit code.")
|
||||
cmd.Flags().StringVar(&o.Subresource, "subresource", "", "SubResource such as pod/log or deployment/scale")
|
||||
cmd.Flags().StringVar(&o.Subresource, "subresource", o.Subresource, "SubResource such as pod/log or deployment/scale")
|
||||
return cmd
|
||||
}
|
||||
|
||||
@ -127,7 +125,10 @@ func (o *CanIOptions) Complete(f cmdutil.Factory, args []string) error {
|
||||
break
|
||||
}
|
||||
resourceTokens := strings.SplitN(args[1], "/", 2)
|
||||
restMapper, _ := f.Object()
|
||||
restMapper, err := f.ToRESTMapper()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.Resource = o.resourceFor(restMapper, resourceTokens[0])
|
||||
if len(resourceTokens) > 1 {
|
||||
o.ResourceName = resourceTokens[1]
|
||||
@ -145,7 +146,7 @@ func (o *CanIOptions) Complete(f cmdutil.Factory, args []string) error {
|
||||
|
||||
o.Namespace = ""
|
||||
if !o.AllNamespaces {
|
||||
o.Namespace, _, err = f.DefaultNamespace()
|
||||
o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -229,9 +230,9 @@ func (o *CanIOptions) resourceFor(mapper meta.RESTMapper, resourceArg string) sc
|
||||
gvr, err = mapper.ResourceFor(groupResource.WithVersion(""))
|
||||
if err != nil {
|
||||
if len(groupResource.Group) == 0 {
|
||||
fmt.Fprintf(o.Err, "Warning: the server doesn't have a resource type '%s'\n", groupResource.Resource)
|
||||
fmt.Fprintf(o.ErrOut, "Warning: the server doesn't have a resource type '%s'\n", groupResource.Resource)
|
||||
} else {
|
||||
fmt.Fprintf(o.Err, "Warning: the server doesn't have a resource type '%s' in group '%s'\n", groupResource.Resource, groupResource.Group)
|
||||
fmt.Fprintf(o.ErrOut, "Warning: the server doesn't have a resource type '%s' in group '%s'\n", groupResource.Resource, groupResource.Group)
|
||||
}
|
||||
return schema.GroupVersionResource{Resource: resourceArg}
|
||||
}
|
||||
|
107
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/auth/cani_test.go
generated
vendored
107
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/auth/cani_test.go
generated
vendored
@ -117,64 +117,67 @@ func TestRunAccessCheck(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test.o.Out = ioutil.Discard
|
||||
test.o.Err = ioutil.Discard
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
test.o.Out = ioutil.Discard
|
||||
test.o.ErrOut = ioutil.Discard
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
ns := legacyscheme.Codecs
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
expectPath := "/apis/authorization.k8s.io/v1/selfsubjectaccessreviews"
|
||||
if req.URL.Path != expectPath {
|
||||
t.Errorf("%s: expected %v, got %v", test.name, expectPath, req.URL.Path)
|
||||
return nil, nil
|
||||
}
|
||||
bodyBits, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
t.Errorf("%s: %v", test.name, err)
|
||||
return nil, nil
|
||||
}
|
||||
body := string(bodyBits)
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
for _, expectedBody := range test.expectedBodyStrings {
|
||||
if !strings.Contains(body, expectedBody) {
|
||||
t.Errorf("%s expecting %s in %s", test.name, expectedBody, body)
|
||||
tf.Client = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
expectPath := "/apis/authorization.k8s.io/v1/selfsubjectaccessreviews"
|
||||
if req.URL.Path != expectPath {
|
||||
t.Errorf("%s: expected %v, got %v", test.name, expectPath, req.URL.Path)
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
bodyBits, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
t.Errorf("%s: %v", test.name, err)
|
||||
return nil, nil
|
||||
}
|
||||
body := string(bodyBits)
|
||||
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: ioutil.NopCloser(bytes.NewBufferString(
|
||||
fmt.Sprintf(`{"kind":"SelfSubjectAccessReview","apiVersion":"authorization.k8s.io/v1","status":{"allowed":%v}}`, test.allowed),
|
||||
)),
|
||||
},
|
||||
test.serverErr
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Group: "", Version: "v1"}}}
|
||||
for _, expectedBody := range test.expectedBodyStrings {
|
||||
if !strings.Contains(body, expectedBody) {
|
||||
t.Errorf("%s expecting %s in %s", test.name, expectedBody, body)
|
||||
}
|
||||
}
|
||||
|
||||
if err := test.o.Complete(tf, test.args); err != nil {
|
||||
t.Errorf("%s: %v", test.name, err)
|
||||
continue
|
||||
}
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: ioutil.NopCloser(bytes.NewBufferString(
|
||||
fmt.Sprintf(`{"kind":"SelfSubjectAccessReview","apiVersion":"authorization.k8s.io/v1","status":{"allowed":%v}}`, test.allowed),
|
||||
)),
|
||||
},
|
||||
test.serverErr
|
||||
}),
|
||||
}
|
||||
tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Group: "", Version: "v1"}}}
|
||||
|
||||
actualAllowed, err := test.o.RunAccessCheck()
|
||||
switch {
|
||||
case test.serverErr == nil && err == nil:
|
||||
// pass
|
||||
case err != nil && test.serverErr != nil && strings.Contains(err.Error(), test.serverErr.Error()):
|
||||
// pass
|
||||
default:
|
||||
t.Errorf("%s: expected %v, got %v", test.name, test.serverErr, err)
|
||||
continue
|
||||
}
|
||||
if actualAllowed != test.allowed {
|
||||
t.Errorf("%s: expected %v, got %v", test.name, test.allowed, actualAllowed)
|
||||
continue
|
||||
}
|
||||
if err := test.o.Complete(tf, test.args); err != nil {
|
||||
t.Errorf("%s: %v", test.name, err)
|
||||
return
|
||||
}
|
||||
|
||||
actualAllowed, err := test.o.RunAccessCheck()
|
||||
switch {
|
||||
case test.serverErr == nil && err == nil:
|
||||
// pass
|
||||
case err != nil && test.serverErr != nil && strings.Contains(err.Error(), test.serverErr.Error()):
|
||||
// pass
|
||||
default:
|
||||
t.Errorf("%s: expected %v, got %v", test.name, test.serverErr, err)
|
||||
return
|
||||
}
|
||||
if actualAllowed != test.allowed {
|
||||
t.Errorf("%s: expected %v, got %v", test.name, test.allowed, actualAllowed)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
126
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/auth/reconcile.go
generated
vendored
126
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/auth/reconcile.go
generated
vendored
@ -18,31 +18,36 @@ package auth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||
internalcoreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
|
||||
internalrbacclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
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/resource"
|
||||
"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/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
|
||||
|
||||
Visitor resource.Visitor
|
||||
RBACClient internalrbacclient.RbacInterface
|
||||
NamespaceClient internalcoreclient.NamespaceInterface
|
||||
RBACClient rbacv1client.RbacV1Interface
|
||||
NamespaceClient corev1client.CoreV1Interface
|
||||
|
||||
Print func(*resource.Info) error
|
||||
PrintObject printers.ResourcePrinterFunc
|
||||
|
||||
Out io.Writer
|
||||
Err io.Writer
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
var (
|
||||
@ -56,12 +61,16 @@ var (
|
||||
kubectl auth reconcile -f my-rbac-rules.yaml`)
|
||||
)
|
||||
|
||||
func NewCmdReconcile(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
|
||||
fileOptions := &resource.FilenameOptions{}
|
||||
o := &ReconcileOptions{
|
||||
Out: out,
|
||||
Err: err,
|
||||
func NewReconcileOptions(ioStreams genericclioptions.IOStreams) *ReconcileOptions {
|
||||
return &ReconcileOptions{
|
||||
FilenameOptions: &resource.FilenameOptions{},
|
||||
PrintFlags: genericclioptions.NewPrintFlags("reconciled").WithTypeSetter(scheme.Scheme),
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdReconcile(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewReconcileOptions(streams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "reconcile -f FILENAME",
|
||||
@ -70,35 +79,36 @@ func NewCmdReconcile(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
|
||||
Long: reconcileLong,
|
||||
Example: reconcileExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(o.Complete(cmd, f, args, fileOptions))
|
||||
cmdutil.CheckErr(o.Complete(cmd, f, args))
|
||||
cmdutil.CheckErr(o.Validate())
|
||||
cmdutil.CheckErr(o.RunReconcile())
|
||||
},
|
||||
}
|
||||
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
usage := "identifying the resource to reconcile."
|
||||
cmdutil.AddFilenameOptionFlags(cmd, fileOptions, usage)
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
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.MarkFlagRequired("filename")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o *ReconcileOptions) Complete(cmd *cobra.Command, f cmdutil.Factory, args []string, options *resource.FilenameOptions) error {
|
||||
func (o *ReconcileOptions) Complete(cmd *cobra.Command, f cmdutil.Factory, args []string) error {
|
||||
if len(args) > 0 {
|
||||
return errors.New("no arguments are allowed")
|
||||
}
|
||||
|
||||
namespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
namespace, enforceNamespace, err := f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r := f.NewBuilder().
|
||||
Internal().
|
||||
WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
|
||||
ContinueOnError().
|
||||
NamespaceParam(namespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, options).
|
||||
FilenameParam(enforceNamespace, o.FilenameOptions).
|
||||
Flatten().
|
||||
Do()
|
||||
|
||||
@ -107,24 +117,28 @@ func (o *ReconcileOptions) Complete(cmd *cobra.Command, f cmdutil.Factory, args
|
||||
}
|
||||
o.Visitor = r
|
||||
|
||||
client, err := f.ClientSet()
|
||||
clientConfig, err := f.ToRESTConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.RBACClient = client.Rbac()
|
||||
o.NamespaceClient = client.Core().Namespaces()
|
||||
|
||||
dryRun := false
|
||||
output := cmdutil.GetFlagString(cmd, "output")
|
||||
shortOutput := output == "name"
|
||||
o.Print = func(info *resource.Info) error {
|
||||
if len(output) > 0 && !shortOutput {
|
||||
return cmdutil.PrintObject(cmd, info.Object, o.Out)
|
||||
}
|
||||
cmdutil.PrintSuccess(shortOutput, o.Out, info.Object, dryRun, "reconciled")
|
||||
return nil
|
||||
o.RBACClient, err = rbacv1client.NewForConfig(clientConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.NamespaceClient, err = corev1client.NewForConfig(clientConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if o.DryRun {
|
||||
o.PrintFlags.Complete("%s (dry run)")
|
||||
}
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.PrintObject = printer.PrintObj
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -138,13 +152,13 @@ func (o *ReconcileOptions) Validate() error {
|
||||
if o.NamespaceClient == nil {
|
||||
return errors.New("ReconcileOptions.NamespaceClient must be set")
|
||||
}
|
||||
if o.Print == nil {
|
||||
if o.PrintObject == nil {
|
||||
return errors.New("ReconcileOptions.Print must be set")
|
||||
}
|
||||
if o.Out == nil {
|
||||
return errors.New("ReconcileOptions.Out must be set")
|
||||
}
|
||||
if o.Err == nil {
|
||||
if o.ErrOut == nil {
|
||||
return errors.New("ReconcileOptions.Err must be set")
|
||||
}
|
||||
return nil
|
||||
@ -156,18 +170,14 @@ func (o *ReconcileOptions) RunReconcile() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// shallowInfoCopy this is used to later twiddle the Object for printing
|
||||
// we really need more straightforward printing options
|
||||
shallowInfoCopy := *info
|
||||
|
||||
switch t := info.Object.(type) {
|
||||
case *rbac.Role:
|
||||
case *rbacv1.Role:
|
||||
reconcileOptions := reconciliation.ReconcileRoleOptions{
|
||||
Confirm: true,
|
||||
Confirm: !o.DryRun,
|
||||
RemoveExtraPermissions: false,
|
||||
Role: reconciliation.RoleRuleOwner{Role: t},
|
||||
Client: reconciliation.RoleModifier{
|
||||
NamespaceClient: o.NamespaceClient,
|
||||
NamespaceClient: o.NamespaceClient.Namespaces(),
|
||||
Client: o.RBACClient,
|
||||
},
|
||||
}
|
||||
@ -175,12 +185,11 @@ func (o *ReconcileOptions) RunReconcile() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
shallowInfoCopy.Object = result.Role.GetObject()
|
||||
o.Print(&shallowInfoCopy)
|
||||
o.PrintObject(result.Role.GetObject(), o.Out)
|
||||
|
||||
case *rbac.ClusterRole:
|
||||
case *rbacv1.ClusterRole:
|
||||
reconcileOptions := reconciliation.ReconcileRoleOptions{
|
||||
Confirm: true,
|
||||
Confirm: !o.DryRun,
|
||||
RemoveExtraPermissions: false,
|
||||
Role: reconciliation.ClusterRoleRuleOwner{ClusterRole: t},
|
||||
Client: reconciliation.ClusterRoleModifier{
|
||||
@ -191,29 +200,27 @@ func (o *ReconcileOptions) RunReconcile() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
shallowInfoCopy.Object = result.Role.GetObject()
|
||||
o.Print(&shallowInfoCopy)
|
||||
o.PrintObject(result.Role.GetObject(), o.Out)
|
||||
|
||||
case *rbac.RoleBinding:
|
||||
case *rbacv1.RoleBinding:
|
||||
reconcileOptions := reconciliation.ReconcileRoleBindingOptions{
|
||||
Confirm: true,
|
||||
Confirm: !o.DryRun,
|
||||
RemoveExtraSubjects: false,
|
||||
RoleBinding: reconciliation.RoleBindingAdapter{RoleBinding: t},
|
||||
Client: reconciliation.RoleBindingClientAdapter{
|
||||
Client: o.RBACClient,
|
||||
NamespaceClient: o.NamespaceClient,
|
||||
NamespaceClient: o.NamespaceClient.Namespaces(),
|
||||
},
|
||||
}
|
||||
result, err := reconcileOptions.Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
shallowInfoCopy.Object = result.RoleBinding.GetObject()
|
||||
o.Print(&shallowInfoCopy)
|
||||
o.PrintObject(result.RoleBinding.GetObject(), o.Out)
|
||||
|
||||
case *rbac.ClusterRoleBinding:
|
||||
case *rbacv1.ClusterRoleBinding:
|
||||
reconcileOptions := reconciliation.ReconcileRoleBindingOptions{
|
||||
Confirm: true,
|
||||
Confirm: !o.DryRun,
|
||||
RemoveExtraSubjects: false,
|
||||
RoleBinding: reconciliation.ClusterRoleBindingAdapter{ClusterRoleBinding: t},
|
||||
Client: reconciliation.ClusterRoleBindingClientAdapter{
|
||||
@ -224,8 +231,7 @@ func (o *ReconcileOptions) RunReconcile() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
shallowInfoCopy.Object = result.RoleBinding.GetObject()
|
||||
o.Print(&shallowInfoCopy)
|
||||
o.PrintObject(result.RoleBinding.GetObject(), o.Out)
|
||||
|
||||
default:
|
||||
glog.V(1).Infof("skipping %#v", info.Object.GetObjectKind())
|
||||
|
244
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/autoscale.go
generated
vendored
244
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/autoscale.go
generated
vendored
@ -18,16 +18,23 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
autoscalingv1 "k8s.io/api/autoscaling/v1"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
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/resource"
|
||||
"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/polymorphichelpers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -45,11 +52,50 @@ var (
|
||||
kubectl autoscale rc foo --max=5 --cpu-percent=80`))
|
||||
)
|
||||
|
||||
func NewCmdAutoscale(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
options := &resource.FilenameOptions{}
|
||||
type AutoscaleOptions struct {
|
||||
FilenameOptions *resource.FilenameOptions
|
||||
|
||||
RecordFlags *genericclioptions.RecordFlags
|
||||
Recorder genericclioptions.Recorder
|
||||
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
ToPrinter func(string) (printers.ResourcePrinter, error)
|
||||
|
||||
Name string
|
||||
Generator string
|
||||
Min int32
|
||||
Max int32
|
||||
CpuPercent int32
|
||||
|
||||
createAnnotation bool
|
||||
args []string
|
||||
enforceNamespace bool
|
||||
namespace string
|
||||
dryRun bool
|
||||
builder *resource.Builder
|
||||
canBeAutoscaled polymorphichelpers.CanBeAutoscaledFunc
|
||||
generatorFunc func(string, *meta.RESTMapping) (kubectl.StructuredGenerator, error)
|
||||
|
||||
HPAClient autoscalingv1client.HorizontalPodAutoscalersGetter
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
func NewAutoscaleOptions(ioStreams genericclioptions.IOStreams) *AutoscaleOptions {
|
||||
return &AutoscaleOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("autoscaled").WithTypeSetter(scheme.Scheme),
|
||||
FilenameOptions: &resource.FilenameOptions{},
|
||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||
Recorder: genericclioptions.NoopRecorder{},
|
||||
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdAutoscale(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewAutoscaleOptions(ioStreams)
|
||||
|
||||
validArgs := []string{"deployment", "replicaset", "replicationcontroller"}
|
||||
argAliases := kubectl.ResourceAliases(validArgs)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "autoscale (-f FILENAME | TYPE NAME | TYPE/NAME) [--min=MINPODS] --max=MAXPODS [--cpu-percent=CPU]",
|
||||
@ -58,78 +104,122 @@ func NewCmdAutoscale(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
Long: autoscaleLong,
|
||||
Example: autoscaleExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := RunAutoscale(f, out, cmd, args, options)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(o.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(o.Validate())
|
||||
cmdutil.CheckErr(o.Run())
|
||||
},
|
||||
ValidArgs: validArgs,
|
||||
ArgAliases: argAliases,
|
||||
ValidArgs: validArgs,
|
||||
}
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmd.Flags().String("generator", cmdutil.HorizontalPodAutoscalerV1GeneratorName, i18n.T("The name of the API generator to use. Currently there is only 1 generator."))
|
||||
cmd.Flags().Int32("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().Int32("max", -1, "The upper limit for the number of pods that can be set by the autoscaler. Required.")
|
||||
|
||||
// bind flag structs
|
||||
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().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")
|
||||
cmd.Flags().Int32("cpu-percent", -1, fmt.Sprintf("The target average CPU utilization (represented as a percent of requested CPU) over all the pods. If it's not specified or negative, a default autoscaling policy will be used."))
|
||||
cmd.Flags().String("name", "", i18n.T("The name for the newly created object. If not specified, the name of the input resource will be used."))
|
||||
cmd.Flags().Int32Var(&o.CpuPercent, "cpu-percent", -1, fmt.Sprintf("The target average CPU utilization (represented as a percent of requested CPU) over all the pods. If it's not specified or negative, a default autoscaling policy will be used."))
|
||||
cmd.Flags().StringVar(&o.Name, "name", "", i18n.T("The name for the newly created object. If not specified, the name of the input resource will be used."))
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
usage := "identifying the resource to autoscale."
|
||||
cmdutil.AddFilenameOptionFlags(cmd, options, usage)
|
||||
cmdutil.AddFilenameOptionFlags(cmd, o.FilenameOptions, "identifying the resource to autoscale.")
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddRecordFlag(cmd)
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func RunAutoscale(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, options *resource.FilenameOptions) error {
|
||||
namespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
func (o *AutoscaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
var err error
|
||||
o.dryRun = cmdutil.GetFlagBool(cmd, "dry-run")
|
||||
o.createAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag)
|
||||
o.builder = f.NewBuilder()
|
||||
o.canBeAutoscaled = polymorphichelpers.CanBeAutoscaledFn
|
||||
o.args = args
|
||||
o.RecordFlags.Complete(cmd)
|
||||
|
||||
o.Recorder, err = o.RecordFlags.ToRecorder()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// validate flags
|
||||
if err := validateFlags(cmd); err != nil {
|
||||
kubeClient, err := f.KubernetesClientSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.HPAClient = kubeClient.AutoscalingV1()
|
||||
|
||||
// get the generator
|
||||
o.generatorFunc = func(name string, mapping *meta.RESTMapping) (kubectl.StructuredGenerator, error) {
|
||||
switch o.Generator {
|
||||
case cmdutil.HorizontalPodAutoscalerV1GeneratorName:
|
||||
return &kubectl.HorizontalPodAutoscalerGeneratorV1{
|
||||
Name: name,
|
||||
MinReplicas: o.Min,
|
||||
MaxReplicas: o.Max,
|
||||
CPUPercent: o.CpuPercent,
|
||||
ScaleRefName: name,
|
||||
ScaleRefKind: mapping.GroupVersionKind.Kind,
|
||||
ScaleRefApiVersion: mapping.GroupVersionKind.GroupVersion().String(),
|
||||
}, nil
|
||||
default:
|
||||
return nil, cmdutil.UsageErrorf(cmd, "Generator %s not supported. ", o.Generator)
|
||||
}
|
||||
}
|
||||
|
||||
o.namespace, o.enforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r := f.NewBuilder().
|
||||
Internal().
|
||||
o.ToPrinter = func(operation string) (printers.ResourcePrinter, error) {
|
||||
o.PrintFlags.NamePrintFlags.Operation = operation
|
||||
if o.dryRun {
|
||||
o.PrintFlags.Complete("%s (dry run)")
|
||||
}
|
||||
|
||||
return o.PrintFlags.ToPrinter()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *AutoscaleOptions) Validate() error {
|
||||
if o.Max < 1 {
|
||||
return fmt.Errorf("--max=MAXPODS is required and must be at least 1, max: %d", o.Max)
|
||||
}
|
||||
if o.Max < o.Min {
|
||||
return fmt.Errorf("--max=MAXPODS must be larger or equal to --min=MINPODS, max: %d, min: %d", o.Max, o.Min)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *AutoscaleOptions) Run() error {
|
||||
r := o.builder.
|
||||
WithScheme(legacyscheme.Scheme).
|
||||
ContinueOnError().
|
||||
NamespaceParam(namespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, options).
|
||||
ResourceTypeOrNameArgs(false, args...).
|
||||
NamespaceParam(o.namespace).DefaultNamespace().
|
||||
FilenameParam(o.enforceNamespace, o.FilenameOptions).
|
||||
ResourceTypeOrNameArgs(false, o.args...).
|
||||
Flatten().
|
||||
Do()
|
||||
err = r.Err()
|
||||
if err != nil {
|
||||
if err := r.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
count := 0
|
||||
err = r.Visit(func(info *resource.Info, err error) error {
|
||||
err := r.Visit(func(info *resource.Info, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mapping := info.ResourceMapping()
|
||||
if err := f.CanBeAutoscaled(mapping.GroupVersionKind.GroupKind()); err != nil {
|
||||
if err := o.canBeAutoscaled(mapping.GroupVersionKind.GroupKind()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// get the generator
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.HorizontalPodAutoscalerV1GeneratorName:
|
||||
generator = &kubectl.HorizontalPodAutoscalerGeneratorV1{
|
||||
Name: info.Name,
|
||||
MinReplicas: cmdutil.GetFlagInt32(cmd, "min"),
|
||||
MaxReplicas: cmdutil.GetFlagInt32(cmd, "max"),
|
||||
CPUPercent: cmdutil.GetFlagInt32(cmd, "cpu-percent"),
|
||||
ScaleRefName: info.Name,
|
||||
ScaleRefKind: mapping.GroupVersionKind.Kind,
|
||||
ScaleRefApiVersion: mapping.GroupVersionKind.GroupVersion().String(),
|
||||
}
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
generator, err := o.generatorFunc(info.Name, mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Generate new object
|
||||
@ -137,44 +227,40 @@ func RunAutoscale(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []s
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hpa, ok := object.(*autoscalingv1.HorizontalPodAutoscaler)
|
||||
if !ok {
|
||||
return fmt.Errorf("generator made %T, not autoscalingv1.HorizontalPodAutoscaler", object)
|
||||
}
|
||||
|
||||
mapper, typer := f.Object()
|
||||
resourceMapper := &resource.Mapper{
|
||||
ObjectTyper: typer,
|
||||
RESTMapper: mapper,
|
||||
ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
|
||||
Decoder: cmdutil.InternalVersionDecoder(),
|
||||
if err := o.Recorder.Record(hpa); err != nil {
|
||||
glog.V(4).Infof("error recording current command: %v", err)
|
||||
}
|
||||
hpa, err := resourceMapper.InfoForObject(object, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cmdutil.ShouldRecord(cmd, hpa) {
|
||||
if err := cmdutil.RecordChangeCause(hpa.Object, f.Command(cmd, false)); err != nil {
|
||||
|
||||
if o.dryRun {
|
||||
count++
|
||||
|
||||
printer, err := o.ToPrinter("created")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
object = hpa.Object
|
||||
}
|
||||
if cmdutil.GetDryRunFlag(cmd) {
|
||||
return cmdutil.PrintObject(cmd, object, out)
|
||||
return printer.PrintObj(hpa, o.Out)
|
||||
}
|
||||
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), hpa, cmdutil.InternalVersionJSONEncoder()); err != nil {
|
||||
if err := kubectl.CreateOrUpdateAnnotation(o.createAnnotation, hpa, cmdutil.InternalVersionJSONEncoder()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
object, err = resource.NewHelper(hpa.Client, hpa.Mapping).Create(namespace, false, object)
|
||||
actualHPA, err := o.HPAClient.HorizontalPodAutoscalers(o.namespace).Create(hpa)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
count++
|
||||
if len(cmdutil.GetFlagString(cmd, "output")) > 0 {
|
||||
return cmdutil.PrintObject(cmd, object, out)
|
||||
printer, err := o.ToPrinter("autoscaled")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmdutil.PrintSuccess(false, out, info.Object, cmdutil.GetDryRunFlag(cmd), "autoscaled")
|
||||
return nil
|
||||
return printer.PrintObj(actualHPA, o.Out)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@ -184,15 +270,3 @@ func RunAutoscale(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []s
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateFlags(cmd *cobra.Command) error {
|
||||
errs := []error{}
|
||||
max, min := cmdutil.GetFlagInt32(cmd, "max"), cmdutil.GetFlagInt32(cmd, "min")
|
||||
if max < 1 {
|
||||
errs = append(errs, fmt.Errorf("--max=MAXPODS is required and must be at least 1, max: %d", max))
|
||||
}
|
||||
if max < min {
|
||||
errs = append(errs, fmt.Errorf("--max=MAXPODS must be larger or equal to --min=MINPODS, max: %d, min: %d", max, min))
|
||||
}
|
||||
return utilerrors.NewAggregate(errs)
|
||||
}
|
||||
|
141
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/certificates.go
generated
vendored
141
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/certificates.go
generated
vendored
@ -20,17 +20,24 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"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"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"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"
|
||||
)
|
||||
|
||||
func NewCmdCertificate(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
func NewCmdCertificate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "certificate SUBCOMMAND",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -41,33 +48,61 @@ func NewCmdCertificate(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
},
|
||||
}
|
||||
|
||||
cmd.AddCommand(NewCmdCertificateApprove(f, out))
|
||||
cmd.AddCommand(NewCmdCertificateDeny(f, out))
|
||||
cmd.AddCommand(NewCmdCertificateApprove(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCertificateDeny(f, ioStreams))
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
type CertificateOptions struct {
|
||||
resource.FilenameOptions
|
||||
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
PrintObj printers.ResourcePrinterFunc
|
||||
|
||||
csrNames []string
|
||||
outputStyle string
|
||||
|
||||
clientSet internalclientset.Interface
|
||||
builder *resource.Builder
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
func (options *CertificateOptions) Complete(cmd *cobra.Command, args []string) error {
|
||||
options.csrNames = args
|
||||
options.outputStyle = cmdutil.GetFlagString(cmd, "output")
|
||||
func (o *CertificateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
o.csrNames = args
|
||||
o.outputStyle = cmdutil.GetFlagString(cmd, "output")
|
||||
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.PrintObj = func(obj runtime.Object, out io.Writer) error {
|
||||
return printer.PrintObj(obj, out)
|
||||
}
|
||||
|
||||
o.builder = f.NewBuilder()
|
||||
o.clientSet, err = f.ClientSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (options *CertificateOptions) Validate() error {
|
||||
if len(options.csrNames) < 1 && cmdutil.IsFilenameSliceEmpty(options.Filenames) {
|
||||
func (o *CertificateOptions) Validate() error {
|
||||
if len(o.csrNames) < 1 && cmdutil.IsFilenameSliceEmpty(o.Filenames) {
|
||||
return fmt.Errorf("one or more CSRs must be specified as <name> or -f <filename>")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewCmdCertificateApprove(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
options := CertificateOptions{}
|
||||
func NewCmdCertificateApprove(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := CertificateOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("approved").WithTypeSetter(scheme.Scheme),
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "approve (-f FILENAME | NAME)",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -85,19 +120,22 @@ func NewCmdCertificateApprove(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
signed certificate can do.
|
||||
`),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(options.Complete(cmd, args))
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Validate())
|
||||
cmdutil.CheckErr(options.RunCertificateApprove(f, out))
|
||||
cmdutil.CheckErr(options.RunCertificateApprove(cmdutil.GetFlagBool(cmd, "force")))
|
||||
},
|
||||
}
|
||||
cmdutil.AddOutputFlagsForMutation(cmd)
|
||||
|
||||
options.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmd.Flags().Bool("force", false, "Update the CSR even if it is already approved.")
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, "identifying the resource to update")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (options *CertificateOptions) RunCertificateApprove(f cmdutil.Factory, out io.Writer) error {
|
||||
return options.modifyCertificateCondition(f, out, func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, string) {
|
||||
func (o *CertificateOptions) RunCertificateApprove(force bool) error {
|
||||
return o.modifyCertificateCondition(o.builder, o.clientSet, force, func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, bool) {
|
||||
var alreadyApproved bool
|
||||
for _, c := range csr.Status.Conditions {
|
||||
if c.Type == certificates.CertificateApproved {
|
||||
@ -105,7 +143,7 @@ func (options *CertificateOptions) RunCertificateApprove(f cmdutil.Factory, out
|
||||
}
|
||||
}
|
||||
if alreadyApproved {
|
||||
return csr, "approved"
|
||||
return csr, true
|
||||
}
|
||||
csr.Status.Conditions = append(csr.Status.Conditions, certificates.CertificateSigningRequestCondition{
|
||||
Type: certificates.CertificateApproved,
|
||||
@ -113,12 +151,15 @@ func (options *CertificateOptions) RunCertificateApprove(f cmdutil.Factory, out
|
||||
Message: "This CSR was approved by kubectl certificate approve.",
|
||||
LastUpdateTime: metav1.Now(),
|
||||
})
|
||||
return csr, "approved"
|
||||
return csr, false
|
||||
})
|
||||
}
|
||||
|
||||
func NewCmdCertificateDeny(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
options := CertificateOptions{}
|
||||
func NewCmdCertificateDeny(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := CertificateOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("denied").WithTypeSetter(scheme.Scheme),
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "deny (-f FILENAME | NAME)",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -131,19 +172,22 @@ func NewCmdCertificateDeny(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
not to issue a certificate to the requestor.
|
||||
`),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(options.Complete(cmd, args))
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Validate())
|
||||
cmdutil.CheckErr(options.RunCertificateDeny(f, out))
|
||||
cmdutil.CheckErr(options.RunCertificateDeny(cmdutil.GetFlagBool(cmd, "force")))
|
||||
},
|
||||
}
|
||||
cmdutil.AddOutputFlagsForMutation(cmd)
|
||||
|
||||
options.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmd.Flags().Bool("force", false, "Update the CSR even if it is already denied.")
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, "identifying the resource to update")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (options *CertificateOptions) RunCertificateDeny(f cmdutil.Factory, out io.Writer) error {
|
||||
return options.modifyCertificateCondition(f, out, func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, string) {
|
||||
func (o *CertificateOptions) RunCertificateDeny(force bool) error {
|
||||
return o.modifyCertificateCondition(o.builder, o.clientSet, force, func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, bool) {
|
||||
var alreadyDenied bool
|
||||
for _, c := range csr.Status.Conditions {
|
||||
if c.Type == certificates.CertificateDenied {
|
||||
@ -151,7 +195,7 @@ func (options *CertificateOptions) RunCertificateDeny(f cmdutil.Factory, out io.
|
||||
}
|
||||
}
|
||||
if alreadyDenied {
|
||||
return csr, "denied"
|
||||
return csr, true
|
||||
}
|
||||
csr.Status.Conditions = append(csr.Status.Conditions, certificates.CertificateSigningRequestCondition{
|
||||
Type: certificates.CertificateDenied,
|
||||
@ -159,18 +203,14 @@ func (options *CertificateOptions) RunCertificateDeny(f cmdutil.Factory, out io.
|
||||
Message: "This CSR was approved by kubectl certificate deny.",
|
||||
LastUpdateTime: metav1.Now(),
|
||||
})
|
||||
return csr, "denied"
|
||||
return csr, false
|
||||
})
|
||||
}
|
||||
|
||||
func (options *CertificateOptions) modifyCertificateCondition(f cmdutil.Factory, out io.Writer, modify func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, string)) error {
|
||||
func (options *CertificateOptions) modifyCertificateCondition(builder *resource.Builder, clientSet internalclientset.Interface, force bool, modify func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, bool)) error {
|
||||
var found int
|
||||
c, err := f.ClientSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r := f.NewBuilder().
|
||||
Internal().
|
||||
r := builder.
|
||||
WithScheme(legacyscheme.Scheme).
|
||||
ContinueOnError().
|
||||
FilenameParam(false, &options.FilenameOptions).
|
||||
ResourceNames("certificatesigningrequest", options.csrNames...).
|
||||
@ -178,24 +218,35 @@ func (options *CertificateOptions) modifyCertificateCondition(f cmdutil.Factory,
|
||||
Flatten().
|
||||
Latest().
|
||||
Do()
|
||||
err = r.Visit(func(info *resource.Info, err error) error {
|
||||
err := r.Visit(func(info *resource.Info, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
csr := info.Object.(*certificates.CertificateSigningRequest)
|
||||
csr, verb := modify(csr)
|
||||
csr, err = c.Certificates().
|
||||
CertificateSigningRequests().
|
||||
UpdateApproval(csr)
|
||||
if err != nil {
|
||||
return err
|
||||
for i := 0; ; i++ {
|
||||
csr := info.Object.(*certificates.CertificateSigningRequest)
|
||||
csr, hasCondition := modify(csr)
|
||||
if !hasCondition || force {
|
||||
csr, err = clientSet.Certificates().
|
||||
CertificateSigningRequests().
|
||||
UpdateApproval(csr)
|
||||
if errors.IsConflict(err) && i < 10 {
|
||||
if err := info.Get(); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
found++
|
||||
cmdutil.PrintSuccess(options.outputStyle == "name", out, info.Object, false, verb)
|
||||
return nil
|
||||
|
||||
return options.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping), options.Out)
|
||||
})
|
||||
if found == 0 {
|
||||
fmt.Fprintf(out, "No resources found\n")
|
||||
fmt.Fprintf(options.Out, "No resources found\n")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
59
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/clusterinfo.go
generated
vendored
59
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/clusterinfo.go
generated
vendored
@ -23,10 +23,13 @@ import (
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
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/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
|
||||
ct "github.com/daviddengcn/go-colortext"
|
||||
@ -43,42 +46,62 @@ var (
|
||||
kubectl cluster-info`))
|
||||
)
|
||||
|
||||
func NewCmdClusterInfo(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
type ClusterInfoOptions struct {
|
||||
genericclioptions.IOStreams
|
||||
|
||||
Namespace string
|
||||
|
||||
Builder *resource.Builder
|
||||
Client *restclient.Config
|
||||
}
|
||||
|
||||
func NewCmdClusterInfo(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := &ClusterInfoOptions{
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "cluster-info",
|
||||
Short: i18n.T("Display cluster info"),
|
||||
Long: longDescr,
|
||||
Example: clusterinfoExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := RunClusterInfo(f, out, cmd)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||
cmdutil.CheckErr(o.Run())
|
||||
},
|
||||
}
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
cmd.AddCommand(NewCmdClusterInfoDump(f, out))
|
||||
cmd.AddCommand(NewCmdClusterInfoDump(f, ioStreams))
|
||||
return cmd
|
||||
}
|
||||
|
||||
func RunClusterInfo(f cmdutil.Factory, out io.Writer, cmd *cobra.Command) error {
|
||||
client, err := f.ClientConfig()
|
||||
func (o *ClusterInfoOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
var err error
|
||||
o.Client, err = f.ToRESTConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printService(out, "Kubernetes master", client.Host)
|
||||
|
||||
cmdNamespace := cmdutil.GetFlagString(cmd, "namespace")
|
||||
if cmdNamespace == "" {
|
||||
cmdNamespace = metav1.NamespaceSystem
|
||||
}
|
||||
o.Namespace = cmdNamespace
|
||||
|
||||
o.Builder = f.NewBuilder()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *ClusterInfoOptions) Run() error {
|
||||
printService(o.Out, "Kubernetes master", o.Client.Host)
|
||||
|
||||
// TODO use generalized labels once they are implemented (#341)
|
||||
b := f.NewBuilder().
|
||||
Internal().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
b := o.Builder.
|
||||
WithScheme(legacyscheme.Scheme).
|
||||
NamespaceParam(o.Namespace).DefaultNamespace().
|
||||
LabelSelectorParam("kubernetes.io/cluster-service=true").
|
||||
ResourceTypeOrNameArgs(false, []string{"services"}...).
|
||||
Latest()
|
||||
err = b.Do().Visit(func(r *resource.Info, err error) error {
|
||||
err := b.Do().Visit(func(r *resource.Info, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -110,10 +133,10 @@ func RunClusterInfo(f cmdutil.Factory, out io.Writer, cmd *cobra.Command) error
|
||||
name = utilnet.JoinSchemeNamePort(scheme, service.ObjectMeta.Name, port.Name)
|
||||
}
|
||||
|
||||
if len(client.GroupVersion.Group) == 0 {
|
||||
link = client.Host + "/api/" + client.GroupVersion.Version + "/namespaces/" + service.ObjectMeta.Namespace + "/services/" + name + "/proxy"
|
||||
if len(o.Client.GroupVersion.Group) == 0 {
|
||||
link = o.Client.Host + "/api/" + o.Client.GroupVersion.Version + "/namespaces/" + service.ObjectMeta.Namespace + "/services/" + name + "/proxy"
|
||||
} else {
|
||||
link = client.Host + "/api/" + client.GroupVersion.Group + "/" + client.GroupVersion.Version + "/namespaces/" + service.ObjectMeta.Namespace + "/services/" + name + "/proxy"
|
||||
link = o.Client.Host + "/api/" + o.Client.GroupVersion.Group + "/" + o.Client.GroupVersion.Version + "/namespaces/" + service.ObjectMeta.Namespace + "/services/" + name + "/proxy"
|
||||
|
||||
}
|
||||
}
|
||||
@ -121,11 +144,11 @@ func RunClusterInfo(f cmdutil.Factory, out io.Writer, cmd *cobra.Command) error
|
||||
if len(name) == 0 {
|
||||
name = service.ObjectMeta.Name
|
||||
}
|
||||
printService(out, name, link)
|
||||
printService(o.Out, name, link)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
out.Write([]byte("\nTo further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.\n"))
|
||||
o.Out.Write([]byte("\nTo further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.\n"))
|
||||
return err
|
||||
|
||||
// TODO consider printing more information about cluster
|
||||
|
134
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/clusterinfo_dump.go
generated
vendored
134
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/clusterinfo_dump.go
generated
vendored
@ -21,31 +21,60 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
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"
|
||||
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/printers"
|
||||
)
|
||||
|
||||
type ClusterInfoDumpOptions struct {
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
PrintObj printers.ResourcePrinterFunc
|
||||
|
||||
OutputDir string
|
||||
AllNamespaces bool
|
||||
Namespaces []string
|
||||
|
||||
Timeout time.Duration
|
||||
Clientset internalclientset.Interface
|
||||
Namespace string
|
||||
RESTClientGetter genericclioptions.RESTClientGetter
|
||||
LogsForObject polymorphichelpers.LogsForObjectFunc
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
// NewCmdCreateSecret groups subcommands to create various types of secrets
|
||||
func NewCmdClusterInfoDump(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdClusterInfoDump(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := &ClusterInfoDumpOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("").WithTypeSetter(scheme.Scheme),
|
||||
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "dump",
|
||||
Short: i18n.T("Dump lots of relevant info for debugging and diagnosis"),
|
||||
Long: dumpLong,
|
||||
Example: dumpExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(dumpClusterInfo(f, cmd, cmdOut))
|
||||
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||
cmdutil.CheckErr(o.Run())
|
||||
},
|
||||
}
|
||||
cmd.Flags().String("output-directory", "", i18n.T("Where to output the files. If empty or '-' uses stdout, otherwise creates a directory hierarchy in that directory"))
|
||||
cmd.Flags().StringSlice("namespaces", []string{}, "A comma separated list of namespaces to dump.")
|
||||
cmd.Flags().Bool("all-namespaces", false, "If true, dump all namespaces. If true, --namespaces is ignored.")
|
||||
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.")
|
||||
cmdutil.AddPodRunningTimeoutFlag(cmd, defaultPodLogsTimeout)
|
||||
return cmd
|
||||
}
|
||||
@ -74,8 +103,7 @@ var (
|
||||
kubectl cluster-info dump --namespaces default,kube-system --output-directory=/path/to/cluster-state`))
|
||||
)
|
||||
|
||||
func setupOutputWriter(cmd *cobra.Command, defaultWriter io.Writer, filename string) io.Writer {
|
||||
dir := cmdutil.GetFlagString(cmd, "output-directory")
|
||||
func setupOutputWriter(dir string, defaultWriter io.Writer, filename string) io.Writer {
|
||||
if len(dir) == 0 || dir == "-" {
|
||||
return defaultWriter
|
||||
}
|
||||
@ -88,31 +116,48 @@ func setupOutputWriter(cmd *cobra.Command, defaultWriter io.Writer, filename str
|
||||
return file
|
||||
}
|
||||
|
||||
func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error {
|
||||
timeout, err := cmdutil.GetPodRunningTimeoutFlag(cmd)
|
||||
if err != nil {
|
||||
return cmdutil.UsageErrorf(cmd, err.Error())
|
||||
}
|
||||
|
||||
clientset, err := f.ClientSet()
|
||||
func (o *ClusterInfoDumpOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printer := &printers.JSONPrinter{}
|
||||
jsonOutputFmt := "json"
|
||||
o.PrintFlags.OutputFormat = &jsonOutputFmt
|
||||
o.PrintObj = printer.PrintObj
|
||||
|
||||
nodes, err := clientset.Core().Nodes().List(metav1.ListOptions{})
|
||||
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
|
||||
}
|
||||
// TODO this should eventually just be the completed kubeconfigflag struct
|
||||
o.RESTClientGetter = f
|
||||
o.LogsForObject = polymorphichelpers.LogsForObjectFn
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *ClusterInfoDumpOptions) Run() error {
|
||||
nodes, err := o.Clientset.Core().Nodes().List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := printer.PrintObj(nodes, setupOutputWriter(cmd, out, "nodes.json")); err != nil {
|
||||
if err := o.PrintObj(nodes, setupOutputWriter(o.OutputDir, o.Out, "nodes.json")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var namespaces []string
|
||||
if cmdutil.GetFlagBool(cmd, "all-namespaces") {
|
||||
namespaceList, err := clientset.Core().Namespaces().List(metav1.ListOptions{})
|
||||
if o.AllNamespaces {
|
||||
namespaceList, err := o.Clientset.Core().Namespaces().List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -120,75 +165,70 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error
|
||||
namespaces = append(namespaces, namespaceList.Items[ix].Name)
|
||||
}
|
||||
} else {
|
||||
namespaces = cmdutil.GetFlagStringSlice(cmd, "namespaces")
|
||||
if len(namespaces) == 0 {
|
||||
cmdNamespace, _, err := f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(o.Namespaces) == 0 {
|
||||
namespaces = []string{
|
||||
metav1.NamespaceSystem,
|
||||
cmdNamespace,
|
||||
o.Namespace,
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, namespace := range namespaces {
|
||||
// TODO: this is repetitive in the extreme. Use reflection or
|
||||
// something to make this a for loop.
|
||||
events, err := clientset.Core().Events(namespace).List(metav1.ListOptions{})
|
||||
events, err := o.Clientset.Core().Events(namespace).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := printer.PrintObj(events, setupOutputWriter(cmd, out, path.Join(namespace, "events.json"))); err != nil {
|
||||
if err := o.PrintObj(events, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "events.json"))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rcs, err := clientset.Core().ReplicationControllers(namespace).List(metav1.ListOptions{})
|
||||
rcs, err := o.Clientset.Core().ReplicationControllers(namespace).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := printer.PrintObj(rcs, setupOutputWriter(cmd, out, path.Join(namespace, "replication-controllers.json"))); err != nil {
|
||||
if err := o.PrintObj(rcs, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "replication-controllers.json"))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
svcs, err := clientset.Core().Services(namespace).List(metav1.ListOptions{})
|
||||
svcs, err := o.Clientset.Core().Services(namespace).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := printer.PrintObj(svcs, setupOutputWriter(cmd, out, path.Join(namespace, "services.json"))); err != nil {
|
||||
if err := o.PrintObj(svcs, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "services.json"))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sets, err := clientset.Extensions().DaemonSets(namespace).List(metav1.ListOptions{})
|
||||
sets, err := o.Clientset.Extensions().DaemonSets(namespace).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := printer.PrintObj(sets, setupOutputWriter(cmd, out, path.Join(namespace, "daemonsets.json"))); err != nil {
|
||||
if err := o.PrintObj(sets, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "daemonsets.json"))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
deps, err := clientset.Extensions().Deployments(namespace).List(metav1.ListOptions{})
|
||||
deps, err := o.Clientset.Extensions().Deployments(namespace).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := printer.PrintObj(deps, setupOutputWriter(cmd, out, path.Join(namespace, "deployments.json"))); err != nil {
|
||||
if err := o.PrintObj(deps, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "deployments.json"))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rps, err := clientset.Extensions().ReplicaSets(namespace).List(metav1.ListOptions{})
|
||||
rps, err := o.Clientset.Extensions().ReplicaSets(namespace).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := printer.PrintObj(rps, setupOutputWriter(cmd, out, path.Join(namespace, "replicasets.json"))); err != nil {
|
||||
if err := o.PrintObj(rps, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "replicasets.json"))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pods, err := clientset.Core().Pods(namespace).List(metav1.ListOptions{})
|
||||
pods, err := o.Clientset.Core().Pods(namespace).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := printer.PrintObj(pods, setupOutputWriter(cmd, out, path.Join(namespace, "pods.json"))); err != nil {
|
||||
if err := o.PrintObj(pods, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "pods.json"))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -196,7 +236,7 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error
|
||||
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 := f.LogsForObject(pod, &api.PodLogOptions{Container: container.Name}, timeout)
|
||||
request, err := o.LogsForObject(o.RESTClientGetter, pod, &api.PodLogOptions{Container: container.Name}, timeout)
|
||||
if err != nil {
|
||||
// Print error and return.
|
||||
writer.Write([]byte(fmt.Sprintf("Create log request error: %s\n", err.Error())))
|
||||
@ -215,19 +255,15 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error
|
||||
for ix := range pods.Items {
|
||||
pod := &pods.Items[ix]
|
||||
containers := pod.Spec.Containers
|
||||
writer := setupOutputWriter(cmd, out, path.Join(namespace, pod.Name, "logs.txt"))
|
||||
writer := setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, pod.Name, "logs.txt"))
|
||||
|
||||
for i := range containers {
|
||||
printContainer(writer, containers[i], pod)
|
||||
}
|
||||
}
|
||||
}
|
||||
dir := cmdutil.GetFlagString(cmd, "output-directory")
|
||||
if len(dir) == 0 {
|
||||
dir = "standard output"
|
||||
}
|
||||
if dir != "-" {
|
||||
fmt.Fprintf(out, "Cluster info dumped to %s\n", dir)
|
||||
if o.OutputDir != "-" {
|
||||
fmt.Fprintf(o.Out, "Cluster info dumped to %s\n", o.OutputDir)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
26
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/clusterinfo_dump_test.go
generated
vendored
26
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/clusterinfo_dump_test.go
generated
vendored
@ -17,25 +17,25 @@ limitations under the License.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
)
|
||||
|
||||
func TestSetupOutputWriterNoOp(t *testing.T) {
|
||||
tests := []string{"", "-"}
|
||||
for _, test := range tests {
|
||||
out := &bytes.Buffer{}
|
||||
_, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
f := cmdtesting.NewTestFactory()
|
||||
cmd := NewCmdClusterInfoDump(f, os.Stdout)
|
||||
cmd.Flag("output-directory").Value.Set(test)
|
||||
writer := setupOutputWriter(cmd, out, "/some/file/that/should/be/ignored")
|
||||
if writer != out {
|
||||
t.Errorf("expected: %v, saw: %v", out, writer)
|
||||
defer f.Cleanup()
|
||||
|
||||
writer := setupOutputWriter(test, buf, "/some/file/that/should/be/ignored")
|
||||
if writer != buf {
|
||||
t.Errorf("expected: %v, saw: %v", buf, writer)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -49,13 +49,13 @@ func TestSetupOutputWriterFile(t *testing.T) {
|
||||
fullPath := path.Join(dir, file)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
out := &bytes.Buffer{}
|
||||
_, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
f := cmdtesting.NewTestFactory()
|
||||
cmd := NewCmdClusterInfoDump(f, os.Stdout)
|
||||
cmd.Flag("output-directory").Value.Set(dir)
|
||||
writer := setupOutputWriter(cmd, out, file)
|
||||
if writer == out {
|
||||
t.Errorf("expected: %v, saw: %v", out, writer)
|
||||
defer f.Cleanup()
|
||||
|
||||
writer := setupOutputWriter(dir, buf, file)
|
||||
if writer == buf {
|
||||
t.Errorf("expected: %v, saw: %v", buf, writer)
|
||||
}
|
||||
output := "some data here"
|
||||
writer.Write([]byte(output))
|
||||
|
179
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/cmd.go
generated
vendored
179
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/cmd.go
generated
vendored
@ -17,22 +17,27 @@ limitations under the License.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"k8s.io/apiserver/pkg/util/flag"
|
||||
"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/resource"
|
||||
"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"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -57,9 +62,6 @@ __kubectl_override_flags()
|
||||
;;
|
||||
esac
|
||||
done
|
||||
if [ "${w}" == "--all-namespaces" ]; then
|
||||
namespace="--all-namespaces"
|
||||
fi
|
||||
done
|
||||
for var in "${__kubectl_override_flag_list[@]##*-}"; do
|
||||
if eval "test -n \"\$${var}\""; then
|
||||
@ -93,20 +95,27 @@ __kubectl_parse_config()
|
||||
fi
|
||||
}
|
||||
|
||||
# $1 is the name of resource (required)
|
||||
# $2 is template string for kubectl get (optional)
|
||||
__kubectl_parse_get()
|
||||
{
|
||||
local template
|
||||
template="{{ range .items }}{{ .metadata.name }} {{ end }}"
|
||||
template="${2:-"{{ range .items }}{{ .metadata.name }} {{ end }}"}"
|
||||
local kubectl_out
|
||||
if kubectl_out=$(kubectl get $(__kubectl_override_flags) -o template --template="${template}" "$1" 2>/dev/null); then
|
||||
COMPREPLY=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
|
||||
COMPREPLY+=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
|
||||
fi
|
||||
}
|
||||
|
||||
__kubectl_get_resource()
|
||||
{
|
||||
if [[ ${#nouns[@]} -eq 0 ]]; then
|
||||
return 1
|
||||
local kubectl_out
|
||||
if kubectl_out=$(kubectl api-resources $(__kubectl_override_flags) -o name --cached --request-timeout=5s --verbs=get 2>/dev/null); then
|
||||
COMPREPLY=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
__kubectl_parse_get "${nouns[${#nouns[@]} -1]}"
|
||||
}
|
||||
@ -140,8 +149,8 @@ __kubectl_get_resource_clusterrole()
|
||||
__kubectl_get_containers()
|
||||
{
|
||||
local template
|
||||
template="{{ range .spec.containers }}{{ .name }} {{ end }}"
|
||||
__debug "${FUNCNAME} nouns are ${nouns[*]}"
|
||||
template="{{ range .spec.initContainers }}{{ .name }} {{end}}{{ range .spec.containers }}{{ .name }} {{ end }}"
|
||||
__kubectl_debug "${FUNCNAME} nouns are ${nouns[*]}"
|
||||
|
||||
local len="${#nouns[@]}"
|
||||
if [[ ${len} -ne 1 ]]; then
|
||||
@ -165,10 +174,41 @@ __kubectl_require_pod_and_container()
|
||||
return 0
|
||||
}
|
||||
|
||||
__kubectl_cp()
|
||||
{
|
||||
if [[ $(type -t compopt) = "builtin" ]]; then
|
||||
compopt -o nospace
|
||||
fi
|
||||
|
||||
case "$cur" in
|
||||
/*|[.~]*) # looks like a path
|
||||
return
|
||||
;;
|
||||
*:*) # TODO: complete remote files in the pod
|
||||
return
|
||||
;;
|
||||
*/*) # complete <namespace>/<pod>
|
||||
local template namespace kubectl_out
|
||||
template="{{ range .items }}{{ .metadata.namespace }}/{{ .metadata.name }}: {{ end }}"
|
||||
namespace="${cur%%/*}"
|
||||
if kubectl_out=( $(kubectl get $(__kubectl_override_flags) --namespace "${namespace}" -o template --template="${template}" pods 2>/dev/null) ); then
|
||||
COMPREPLY=( $(compgen -W "${kubectl_out[*]}" -- "${cur}") )
|
||||
fi
|
||||
return
|
||||
;;
|
||||
*) # complete namespaces, pods, and filedirs
|
||||
__kubectl_parse_get "namespace" "{{ range .items }}{{ .metadata.name }}/ {{ end }}"
|
||||
__kubectl_parse_get "pod" "{{ range .items }}{{ .metadata.name }}: {{ end }}"
|
||||
_filedir
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
__custom_func() {
|
||||
case ${last_command} in
|
||||
kubectl_get | kubectl_describe | kubectl_delete | kubectl_label | kubectl_edit | kubectl_patch |\
|
||||
kubectl_annotate | kubectl_expose | kubectl_scale | kubectl_autoscale | kubectl_taint | kubectl_rollout_*)
|
||||
kubectl_annotate | kubectl_expose | kubectl_scale | kubectl_autoscale | kubectl_taint | kubectl_rollout_* |\
|
||||
kubectl_apply_edit-last-applied | kubectl_apply_view-last-applied)
|
||||
__kubectl_get_resource
|
||||
return
|
||||
;;
|
||||
@ -196,6 +236,10 @@ __custom_func() {
|
||||
__kubectl_config_get_clusters
|
||||
return
|
||||
;;
|
||||
kubectl_cp)
|
||||
__kubectl_cp
|
||||
return
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
@ -213,11 +257,11 @@ var (
|
||||
)
|
||||
|
||||
func NewDefaultKubectlCommand() *cobra.Command {
|
||||
return NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, os.Stdout, os.Stderr)
|
||||
return NewKubectlCommand(os.Stdin, os.Stdout, os.Stderr)
|
||||
}
|
||||
|
||||
// NewKubectlCommand creates the `kubectl` command and its nested children.
|
||||
func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cobra.Command {
|
||||
func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.Command {
|
||||
// Parent command to which all subcommands are added.
|
||||
cmds := &cobra.Command{
|
||||
Use: "kubectl",
|
||||
@ -231,8 +275,21 @@ func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob
|
||||
BashCompletionFunction: bashCompletionFunc,
|
||||
}
|
||||
|
||||
f.BindFlags(cmds.PersistentFlags())
|
||||
f.BindExternalFlags(cmds.PersistentFlags())
|
||||
flags := cmds.PersistentFlags()
|
||||
flags.SetNormalizeFunc(utilflag.WarnWordSepNormalizeFunc) // Warn for "_" flags
|
||||
|
||||
// Normalize all flags that are coming from other packages or pre-configurations
|
||||
// a.k.a. change all "_" to "-". e.g. glog package
|
||||
flags.SetNormalizeFunc(utilflag.WordSepNormalizeFunc)
|
||||
|
||||
kubeConfigFlags := genericclioptions.NewConfigFlags()
|
||||
kubeConfigFlags.AddFlags(flags)
|
||||
matchVersionKubeConfigFlags := cmdutil.NewMatchVersionFlags(kubeConfigFlags)
|
||||
matchVersionKubeConfigFlags.AddFlags(cmds.PersistentFlags())
|
||||
|
||||
cmds.PersistentFlags().AddGoFlagSet(flag.CommandLine)
|
||||
|
||||
f := cmdutil.NewFactory(matchVersionKubeConfigFlags)
|
||||
|
||||
// Sending in 'nil' for the getLanguageFn() results in using
|
||||
// the LANG environment variable.
|
||||
@ -242,77 +299,80 @@ func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob
|
||||
i18n.LoadTranslations("kubectl", nil)
|
||||
|
||||
// From this point and forward we get warnings on flags that contain "_" separators
|
||||
cmds.SetGlobalNormalizationFunc(flag.WarnWordSepNormalizeFunc)
|
||||
cmds.SetGlobalNormalizationFunc(utilflag.WarnWordSepNormalizeFunc)
|
||||
|
||||
ioStreams := genericclioptions.IOStreams{In: in, Out: out, ErrOut: err}
|
||||
|
||||
groups := templates.CommandGroups{
|
||||
{
|
||||
Message: "Basic Commands (Beginner):",
|
||||
Commands: []*cobra.Command{
|
||||
NewCmdCreate(f, out, err),
|
||||
NewCmdExposeService(f, out),
|
||||
NewCmdRun(f, in, out, err),
|
||||
set.NewCmdSet(f, in, out, err),
|
||||
deprecatedAlias("run-container", NewCmdRun(f, in, out, err)),
|
||||
create.NewCmdCreate(f, ioStreams),
|
||||
NewCmdExposeService(f, ioStreams),
|
||||
NewCmdRun(f, ioStreams),
|
||||
set.NewCmdSet(f, ioStreams),
|
||||
deprecatedAlias("run-container", NewCmdRun(f, ioStreams)),
|
||||
},
|
||||
},
|
||||
{
|
||||
Message: "Basic Commands (Intermediate):",
|
||||
Commands: []*cobra.Command{
|
||||
resource.NewCmdGet(f, out, err),
|
||||
NewCmdExplain(f, out, err),
|
||||
NewCmdEdit(f, out, err),
|
||||
NewCmdDelete(f, out, err),
|
||||
NewCmdExplain("kubectl", f, ioStreams),
|
||||
get.NewCmdGet("kubectl", f, ioStreams),
|
||||
NewCmdEdit(f, ioStreams),
|
||||
NewCmdDelete(f, ioStreams),
|
||||
},
|
||||
},
|
||||
{
|
||||
Message: "Deploy Commands:",
|
||||
Commands: []*cobra.Command{
|
||||
rollout.NewCmdRollout(f, out, err),
|
||||
NewCmdRollingUpdate(f, out),
|
||||
NewCmdScale(f, out, err),
|
||||
NewCmdAutoscale(f, out),
|
||||
rollout.NewCmdRollout(f, ioStreams),
|
||||
NewCmdRollingUpdate(f, ioStreams),
|
||||
NewCmdScale(f, ioStreams),
|
||||
NewCmdAutoscale(f, ioStreams),
|
||||
},
|
||||
},
|
||||
{
|
||||
Message: "Cluster Management Commands:",
|
||||
Commands: []*cobra.Command{
|
||||
NewCmdCertificate(f, out),
|
||||
NewCmdClusterInfo(f, out),
|
||||
NewCmdTop(f, out, err),
|
||||
NewCmdCordon(f, out),
|
||||
NewCmdUncordon(f, out),
|
||||
NewCmdDrain(f, out, err),
|
||||
NewCmdTaint(f, out),
|
||||
NewCmdCertificate(f, ioStreams),
|
||||
NewCmdClusterInfo(f, ioStreams),
|
||||
NewCmdTop(f, ioStreams),
|
||||
NewCmdCordon(f, ioStreams),
|
||||
NewCmdUncordon(f, ioStreams),
|
||||
NewCmdDrain(f, ioStreams),
|
||||
NewCmdTaint(f, ioStreams),
|
||||
},
|
||||
},
|
||||
{
|
||||
Message: "Troubleshooting and Debugging Commands:",
|
||||
Commands: []*cobra.Command{
|
||||
NewCmdDescribe(f, out, err),
|
||||
NewCmdLogs(f, out, err),
|
||||
NewCmdAttach(f, in, out, err),
|
||||
NewCmdExec(f, in, out, err),
|
||||
NewCmdPortForward(f, out, err),
|
||||
NewCmdProxy(f, out),
|
||||
NewCmdCp(f, out, err),
|
||||
auth.NewCmdAuth(f, out, err),
|
||||
NewCmdDescribe("kubectl", f, ioStreams),
|
||||
NewCmdLogs(f, ioStreams),
|
||||
NewCmdAttach(f, ioStreams),
|
||||
NewCmdExec(f, ioStreams),
|
||||
NewCmdPortForward(f, ioStreams),
|
||||
NewCmdProxy(f, ioStreams),
|
||||
NewCmdCp(f, ioStreams),
|
||||
auth.NewCmdAuth(f, ioStreams),
|
||||
},
|
||||
},
|
||||
{
|
||||
Message: "Advanced Commands:",
|
||||
Commands: []*cobra.Command{
|
||||
NewCmdApply("kubectl", f, out, err),
|
||||
NewCmdPatch(f, out),
|
||||
NewCmdReplace(f, out),
|
||||
NewCmdConvert(f, out),
|
||||
NewCmdApply("kubectl", f, ioStreams),
|
||||
NewCmdPatch(f, ioStreams),
|
||||
NewCmdReplace(f, ioStreams),
|
||||
wait.NewCmdWait(f, ioStreams),
|
||||
NewCmdConvert(f, ioStreams),
|
||||
},
|
||||
},
|
||||
{
|
||||
Message: "Settings Commands:",
|
||||
Commands: []*cobra.Command{
|
||||
NewCmdLabel(f, out),
|
||||
NewCmdAnnotate(f, out),
|
||||
NewCmdCompletion(out, ""),
|
||||
NewCmdLabel(f, ioStreams),
|
||||
NewCmdAnnotate("kubectl", f, ioStreams),
|
||||
NewCmdCompletion(ioStreams.Out, ""),
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -321,7 +381,7 @@ func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob
|
||||
filters := []string{"options"}
|
||||
|
||||
// Hide the "alpha" subcommand if there are no alpha commands in this build.
|
||||
alpha := NewCmdAlpha(f, in, out, err)
|
||||
alpha := NewCmdAlpha(f, ioStreams)
|
||||
if !alpha.HasSubCommands() {
|
||||
filters = append(filters, alpha.Name())
|
||||
}
|
||||
@ -341,11 +401,12 @@ func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob
|
||||
}
|
||||
|
||||
cmds.AddCommand(alpha)
|
||||
cmds.AddCommand(cmdconfig.NewCmdConfig(f, clientcmd.NewDefaultPathOptions(), out, err))
|
||||
cmds.AddCommand(NewCmdPlugin(f, in, out, err))
|
||||
cmds.AddCommand(NewCmdVersion(f, out))
|
||||
cmds.AddCommand(NewCmdApiVersions(f, out))
|
||||
cmds.AddCommand(NewCmdOptions(out))
|
||||
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))
|
||||
|
||||
return cmds
|
||||
}
|
||||
@ -355,7 +416,7 @@ func runHelp(cmd *cobra.Command, args []string) {
|
||||
}
|
||||
|
||||
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.", alias, command)
|
||||
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
|
||||
@ -372,3 +433,5 @@ func deprecatedAlias(deprecatedVersion string, cmd *cobra.Command) *cobra.Comman
|
||||
cmd.Hidden = true
|
||||
return cmd
|
||||
}
|
||||
|
||||
var metadataAccessor = meta.NewAccessor()
|
||||
|
234
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/cmd_printing_test.go
generated
vendored
Normal file
234
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/cmd_printing_test.go
generated
vendored
Normal file
@ -0,0 +1,234 @@
|
||||
/*
|
||||
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",
|
||||
},
|
||||
}
|
||||
}
|
354
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/cmd_test.go
generated
vendored
354
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/cmd_test.go
generated
vendored
@ -19,7 +19,6 @@ package cmd
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
@ -35,17 +34,11 @@ import (
|
||||
"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/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/resource"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
"k8s.io/kubernetes/pkg/util/strings"
|
||||
)
|
||||
|
||||
// This init should be removed after switching this command and its tests to user external types.
|
||||
@ -122,44 +115,6 @@ func testData() (*api.PodList, *api.ServiceList, *api.ReplicationControllerList)
|
||||
return pods, svc, rc
|
||||
}
|
||||
|
||||
type testPrinter struct {
|
||||
Objects []runtime.Object
|
||||
Err error
|
||||
GenericPrinter bool
|
||||
}
|
||||
|
||||
func (t *testPrinter) PrintObj(obj runtime.Object, out io.Writer) error {
|
||||
t.Objects = append(t.Objects, obj)
|
||||
fmt.Fprintf(out, "%#v", obj)
|
||||
return t.Err
|
||||
}
|
||||
|
||||
// TODO: implement HandledResources()
|
||||
func (t *testPrinter) HandledResources() []string {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
func (t *testPrinter) AfterPrint(output io.Writer, res string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *testPrinter) IsGeneric() bool {
|
||||
return t.GenericPrinter
|
||||
}
|
||||
|
||||
type testDescriber struct {
|
||||
Name, Namespace string
|
||||
Settings printers.DescriberSettings
|
||||
Output string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (t *testDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (output string, err error) {
|
||||
t.Namespace, t.Name = namespace, name
|
||||
t.Settings = describerSettings
|
||||
return t.Output, t.Err
|
||||
}
|
||||
|
||||
func objBody(codec runtime.Codec, obj runtime.Object) io.ReadCloser {
|
||||
return ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(codec, obj))))
|
||||
}
|
||||
@ -176,184 +131,6 @@ func stringBody(body string) io.ReadCloser {
|
||||
return ioutil.NopCloser(bytes.NewReader([]byte(body)))
|
||||
}
|
||||
|
||||
func Example_printMultiContainersReplicationControllerWithWide() {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: nil,
|
||||
}
|
||||
cmd := NewCmdRun(tf, os.Stdin, os.Stdout, os.Stderr)
|
||||
ctrl := &api.ReplicationController{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Labels: map[string]string{"foo": "bar"},
|
||||
CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
|
||||
},
|
||||
Spec: api.ReplicationControllerSpec{
|
||||
Replicas: 1,
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
Template: &api.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{"foo": "bar"},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "foo",
|
||||
Image: "someimage",
|
||||
},
|
||||
{
|
||||
Name: "foo2",
|
||||
Image: "someimage2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: api.ReplicationControllerStatus{
|
||||
Replicas: 1,
|
||||
},
|
||||
}
|
||||
cmd.Flags().Set("output", "wide")
|
||||
err := cmdutil.PrintObject(cmd, ctrl, os.Stdout)
|
||||
if err != nil {
|
||||
fmt.Printf("Unexpected error: %v", err)
|
||||
}
|
||||
// Output:
|
||||
// NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
|
||||
// foo 1 1 0 10y foo,foo2 someimage,someimage2 foo=bar
|
||||
}
|
||||
|
||||
func Example_printReplicationController() {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: nil,
|
||||
}
|
||||
cmd := NewCmdRun(tf, os.Stdin, os.Stdout, os.Stderr)
|
||||
ctrl := &api.ReplicationController{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Labels: map[string]string{"foo": "bar"},
|
||||
CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
|
||||
},
|
||||
Spec: api.ReplicationControllerSpec{
|
||||
Replicas: 1,
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
Template: &api.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{"foo": "bar"},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "foo",
|
||||
Image: "someimage",
|
||||
},
|
||||
{
|
||||
Name: "foo2",
|
||||
Image: "someimage",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: api.ReplicationControllerStatus{
|
||||
Replicas: 1,
|
||||
},
|
||||
}
|
||||
err := cmdutil.PrintObject(cmd, ctrl, os.Stdout)
|
||||
if err != nil {
|
||||
fmt.Printf("Unexpected error: %v", err)
|
||||
}
|
||||
// Output:
|
||||
// NAME DESIRED CURRENT READY AGE
|
||||
// foo 1 1 0 10y
|
||||
}
|
||||
|
||||
func Example_printPodWithWideFormat() {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: nil,
|
||||
}
|
||||
nodeName := "kubernetes-node-abcd"
|
||||
cmd := NewCmdRun(tf, os.Stdin, os.Stdout, os.Stderr)
|
||||
pod := &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: "podPhase",
|
||||
ContainerStatuses: []api.ContainerStatus{
|
||||
{Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
|
||||
{RestartCount: 3},
|
||||
},
|
||||
PodIP: "10.1.1.3",
|
||||
},
|
||||
}
|
||||
cmd.Flags().Set("output", "wide")
|
||||
err := cmdutil.PrintObject(cmd, pod, os.Stdout)
|
||||
if err != nil {
|
||||
fmt.Printf("Unexpected error: %v", err)
|
||||
}
|
||||
// Output:
|
||||
// NAME READY STATUS RESTARTS AGE IP NODE
|
||||
// test1 1/2 podPhase 6 10y 10.1.1.3 kubernetes-node-abcd
|
||||
}
|
||||
|
||||
func Example_printPodWithShowLabels() {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: nil,
|
||||
}
|
||||
nodeName := "kubernetes-node-abcd"
|
||||
cmd := NewCmdRun(tf, os.Stdin, os.Stdout, os.Stderr)
|
||||
pod := &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test1",
|
||||
CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
|
||||
Labels: map[string]string{
|
||||
"l1": "key",
|
||||
"l2": "value",
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: make([]api.Container, 2),
|
||||
NodeName: nodeName,
|
||||
},
|
||||
Status: api.PodStatus{
|
||||
Phase: "podPhase",
|
||||
ContainerStatuses: []api.ContainerStatus{
|
||||
{Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
|
||||
{RestartCount: 3},
|
||||
},
|
||||
},
|
||||
}
|
||||
cmd.Flags().Set("show-labels", "true")
|
||||
err := cmdutil.PrintObject(cmd, pod, os.Stdout)
|
||||
if err != nil {
|
||||
fmt.Printf("Unexpected error: %v", err)
|
||||
}
|
||||
// Output:
|
||||
// NAME READY STATUS RESTARTS AGE LABELS
|
||||
// test1 1/2 podPhase 6 10y l1=key,l2=value
|
||||
}
|
||||
|
||||
func newAllPhasePodList() *api.PodList {
|
||||
nodeName := "kubernetes-node-abcd"
|
||||
return &api.PodList{
|
||||
@ -446,138 +223,9 @@ func newAllPhasePodList() *api.PodList {
|
||||
}
|
||||
}
|
||||
|
||||
func Example_printPodShowTerminated() {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: nil,
|
||||
}
|
||||
cmd := NewCmdRun(tf, os.Stdin, os.Stdout, os.Stderr)
|
||||
podList := newAllPhasePodList()
|
||||
// filter pods
|
||||
filterFuncs := tf.DefaultResourceFilterFunc()
|
||||
filterOpts := cmdutil.ExtractCmdPrintOptions(cmd, false)
|
||||
_, filteredPodList, errs := cmdutil.FilterResourceList(podList, filterFuncs, filterOpts)
|
||||
if errs != nil {
|
||||
fmt.Printf("Unexpected filter error: %v\n", errs)
|
||||
}
|
||||
printer, err := cmdutil.PrinterForOptions(cmdutil.ExtractCmdPrintOptions(cmd, false))
|
||||
if err != nil {
|
||||
fmt.Printf("Unexpected printer get error: %v\n", errs)
|
||||
}
|
||||
for _, pod := range filteredPodList {
|
||||
err := printer.PrintObj(pod, os.Stdout)
|
||||
if err != nil {
|
||||
fmt.Printf("Unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
// Output:
|
||||
// NAME READY STATUS RESTARTS AGE
|
||||
// test1 1/2 Pending 6 10y
|
||||
// test2 1/2 Running 6 10y
|
||||
// test3 1/2 Succeeded 6 10y
|
||||
// test4 1/2 Failed 6 10y
|
||||
// test5 1/2 Unknown 6 10y
|
||||
}
|
||||
|
||||
func Example_printPodShowAll() {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: nil,
|
||||
}
|
||||
cmd := NewCmdRun(tf, os.Stdin, os.Stdout, os.Stderr)
|
||||
podList := newAllPhasePodList()
|
||||
err := cmdutil.PrintObject(cmd, podList, os.Stdout)
|
||||
if err != nil {
|
||||
fmt.Printf("Unexpected error: %v", err)
|
||||
}
|
||||
// Output:
|
||||
// NAME READY STATUS RESTARTS AGE
|
||||
// test1 1/2 Pending 6 10y
|
||||
// test2 1/2 Running 6 10y
|
||||
// test3 1/2 Succeeded 6 10y
|
||||
// test4 1/2 Failed 6 10y
|
||||
// test5 1/2 Unknown 6 10y
|
||||
}
|
||||
|
||||
func Example_printServiceWithLabels() {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: nil,
|
||||
}
|
||||
cmd := resource.NewCmdGet(tf, os.Stdout, os.Stderr)
|
||||
svc := &api.ServiceList{
|
||||
Items: []api.Service{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "svc1",
|
||||
Namespace: "ns1",
|
||||
CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
|
||||
Labels: map[string]string{
|
||||
"l1": "value",
|
||||
},
|
||||
},
|
||||
Spec: api.ServiceSpec{
|
||||
Ports: []api.ServicePort{
|
||||
{Protocol: "UDP", Port: 53},
|
||||
{Protocol: "TCP", Port: 53},
|
||||
},
|
||||
Selector: map[string]string{
|
||||
"s": "magic",
|
||||
},
|
||||
ClusterIP: "10.1.1.1",
|
||||
Type: api.ServiceTypeClusterIP,
|
||||
},
|
||||
Status: api.ServiceStatus{},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "svc2",
|
||||
Namespace: "ns2",
|
||||
CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
|
||||
Labels: map[string]string{
|
||||
"l1": "dolla-bill-yall",
|
||||
},
|
||||
},
|
||||
Spec: api.ServiceSpec{
|
||||
Ports: []api.ServicePort{
|
||||
{Protocol: "TCP", Port: 80},
|
||||
{Protocol: "TCP", Port: 8080},
|
||||
},
|
||||
Selector: map[string]string{
|
||||
"s": "kazam",
|
||||
},
|
||||
ClusterIP: "10.1.1.2",
|
||||
Type: api.ServiceTypeClusterIP,
|
||||
},
|
||||
Status: api.ServiceStatus{},
|
||||
}},
|
||||
}
|
||||
ld := strings.NewLineDelimiter(os.Stdout, "|")
|
||||
defer ld.Flush()
|
||||
cmd.Flags().Set("label-columns", "l1")
|
||||
err := cmdutil.PrintObject(cmd, svc, ld)
|
||||
if err != nil {
|
||||
fmt.Printf("Unexpected error: %v", err)
|
||||
}
|
||||
// Output:
|
||||
// |NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE L1|
|
||||
// |svc1 ClusterIP 10.1.1.1 <none> 53/UDP,53/TCP 10y value|
|
||||
// |svc2 ClusterIP 10.1.1.2 <none> 80/TCP,8080/TCP 10y dolla-bill-yall|
|
||||
// ||
|
||||
}
|
||||
|
||||
func TestNormalizationFuncGlobalExistence(t *testing.T) {
|
||||
// This test can be safely deleted when we will not support multiple flag formats
|
||||
root := NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, os.Stdout, os.Stderr)
|
||||
root := NewKubectlCommand(os.Stdin, os.Stdout, os.Stderr)
|
||||
|
||||
if root.Parent() != nil {
|
||||
t.Fatal("We expect the root command to be returned")
|
||||
|
4
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/completion.go
generated
vendored
4
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/completion.go
generated
vendored
@ -223,7 +223,7 @@ __kubectl_get_comp_words_by_ref() {
|
||||
__kubectl_filedir() {
|
||||
local RET OLD_IFS w qw
|
||||
|
||||
__debug "_filedir $@ cur=$cur"
|
||||
__kubectl_debug "_filedir $@ cur=$cur"
|
||||
if [[ "$1" = \~* ]]; then
|
||||
# somehow does not work. Maybe, zsh does not call this at all
|
||||
eval echo "$1"
|
||||
@ -240,7 +240,7 @@ __kubectl_filedir() {
|
||||
fi
|
||||
IFS="$OLD_IFS"
|
||||
|
||||
IFS="," __debug "RET=${RET[@]} len=${#RET[@]}"
|
||||
IFS="," __kubectl_debug "RET=${RET[@]} len=${#RET[@]}"
|
||||
|
||||
for w in ${RET[@]}; do
|
||||
if [[ ! "${w}" = "${cur}"* ]]; then
|
||||
|
3
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/BUILD
generated
vendored
3
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/BUILD
generated
vendored
@ -28,8 +28,10 @@ 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/util/i18n:go_default_library",
|
||||
"//pkg/printers:go_default_library",
|
||||
"//vendor/github.com/spf13/cobra:go_default_library",
|
||||
@ -64,6 +66,7 @@ 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",
|
||||
|
33
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/config.go
generated
vendored
33
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/config.go
generated
vendored
@ -18,7 +18,6 @@ package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
@ -27,11 +26,12 @@ import (
|
||||
"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"
|
||||
)
|
||||
|
||||
// NewCmdConfig creates a command object for the "config" action, and adds all child commands to it.
|
||||
func NewCmdConfig(f cmdutil.Factory, pathOptions *clientcmd.PathOptions, out, errOut io.Writer) *cobra.Command {
|
||||
func NewCmdConfig(f cmdutil.Factory, pathOptions *clientcmd.PathOptions, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
if len(pathOptions.ExplicitFileFlag) == 0 {
|
||||
pathOptions.ExplicitFileFlag = clientcmd.RecommendedConfigPathFlag
|
||||
}
|
||||
@ -48,25 +48,26 @@ func NewCmdConfig(f cmdutil.Factory, pathOptions *clientcmd.PathOptions, out, er
|
||||
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.
|
||||
3. Otherwise, ` + path.Join("${HOME}", pathOptions.GlobalFileSubpath) + ` is used and no merging takes place.`),
|
||||
Run: cmdutil.DefaultSubCommandRun(errOut),
|
||||
Run: cmdutil.DefaultSubCommandRun(streams.ErrOut),
|
||||
}
|
||||
|
||||
// file paths are common to all sub commands
|
||||
cmd.PersistentFlags().StringVar(&pathOptions.LoadingRules.ExplicitPath, pathOptions.ExplicitFileFlag, pathOptions.LoadingRules.ExplicitPath, "use a particular kubeconfig file")
|
||||
|
||||
cmd.AddCommand(NewCmdConfigView(f, out, errOut, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigSetCluster(out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigSetAuthInfo(out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigSetContext(out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigSet(out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigUnset(out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigCurrentContext(out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigUseContext(out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigGetContexts(out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigGetClusters(out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigDeleteCluster(out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigDeleteContext(out, errOut, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigRenameContext(out, pathOptions))
|
||||
// TODO(juanvallejo): update all subcommands to work with genericclioptions.IOStreams
|
||||
cmd.AddCommand(NewCmdConfigView(f, streams, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigSetCluster(streams.Out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigSetAuthInfo(streams.Out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigSetContext(streams.Out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigSet(streams.Out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigUnset(streams.Out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigCurrentContext(streams.Out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigUseContext(streams.Out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigGetContexts(streams, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigGetClusters(streams.Out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigDeleteCluster(streams.Out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigDeleteContext(streams.Out, streams.ErrOut, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigRenameContext(streams.Out, pathOptions))
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
11
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/config_test.go
generated
vendored
11
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/config_test.go
generated
vendored
@ -17,7 +17,6 @@ limitations under the License.
|
||||
package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@ -31,6 +30,7 @@ import (
|
||||
"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 {
|
||||
@ -863,15 +863,14 @@ func testConfigCommand(args []string, startingConfig clientcmdapi.Config, t *tes
|
||||
argsToUse = append(argsToUse, "--kubeconfig="+fakeKubeFile.Name())
|
||||
argsToUse = append(argsToUse, args...)
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdConfig(cmdutil.NewFactory(nil), clientcmd.NewDefaultPathOptions(), buf, buf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdConfig(cmdutil.NewFactory(genericclioptions.NewTestConfigFlags()), clientcmd.NewDefaultPathOptions(), streams)
|
||||
// "context" is a global flag, inherited from base kubectl command in the real world
|
||||
cmd.PersistentFlags().String("context", "", "The name of the kubeconfig context to use")
|
||||
cmd.SetArgs(argsToUse)
|
||||
cmd.Execute()
|
||||
|
||||
// outBytes, _ := ioutil.ReadFile(fakeKubeFile.Name())
|
||||
config := clientcmd.GetConfigFromFileOrDie(fakeKubeFile.Name())
|
||||
|
||||
return buf.String(), *config
|
||||
}
|
||||
|
||||
|
2
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/create_authinfo_test.go
generated
vendored
2
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/create_authinfo_test.go
generated
vendored
@ -142,7 +142,7 @@ func TestCreateAuthInfoOptions(t *testing.T) {
|
||||
},
|
||||
{
|
||||
flags: []string{
|
||||
// No name for authinfo provided.
|
||||
// No name for authinfo provided.
|
||||
},
|
||||
wantCompleteErr: true,
|
||||
},
|
||||
|
28
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/get_contexts.go
generated
vendored
28
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/get_contexts.go
generated
vendored
@ -31,6 +31,7 @@ import (
|
||||
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"
|
||||
)
|
||||
@ -41,7 +42,8 @@ type GetContextsOptions struct {
|
||||
nameOnly bool
|
||||
showHeaders bool
|
||||
contextNames []string
|
||||
out io.Writer
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
var (
|
||||
@ -57,8 +59,12 @@ var (
|
||||
|
||||
// NewCmdConfigGetContexts creates a command object for the "get-contexts" action, which
|
||||
// retrieves one or more contexts from a kubeconfig.
|
||||
func NewCmdConfigGetContexts(out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
|
||||
options := &GetContextsOptions{configAccess: configAccess}
|
||||
func NewCmdConfigGetContexts(streams genericclioptions.IOStreams, configAccess clientcmd.ConfigAccess) *cobra.Command {
|
||||
options := &GetContextsOptions{
|
||||
configAccess: configAccess,
|
||||
|
||||
IOStreams: streams,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "get-contexts [(-o|--output=)name)]",
|
||||
@ -74,22 +80,22 @@ func NewCmdConfigGetContexts(out io.Writer, configAccess clientcmd.ConfigAccess)
|
||||
cmdutil.CheckErr(fmt.Errorf("output must be one of '' or 'name': %v", outputFormat))
|
||||
}
|
||||
if !supportedOutputTypes.Has(outputFormat) {
|
||||
fmt.Fprintf(out, "--output %v is not available in kubectl config get-contexts; resetting to default output format\n", outputFormat)
|
||||
fmt.Fprintf(options.Out, "--output %v is not available in kubectl config get-contexts; resetting to default output format\n", outputFormat)
|
||||
cmd.Flags().Set("output", "")
|
||||
}
|
||||
cmdutil.CheckErr(options.Complete(cmd, args, out))
|
||||
cmdutil.CheckErr(options.Complete(cmd, args))
|
||||
cmdutil.CheckErr(options.RunGetContexts())
|
||||
},
|
||||
}
|
||||
cmdutil.AddOutputFlags(cmd)
|
||||
cmdutil.AddNoHeadersFlags(cmd)
|
||||
|
||||
cmd.Flags().Bool("no-headers", false, "When using the default or custom-column output format, don't print headers (default print headers).")
|
||||
cmd.Flags().StringP("output", "o", "", "Output format. One of: name")
|
||||
return cmd
|
||||
}
|
||||
|
||||
// Complete assigns GetContextsOptions from the args.
|
||||
func (o *GetContextsOptions) Complete(cmd *cobra.Command, args []string, out io.Writer) error {
|
||||
func (o *GetContextsOptions) Complete(cmd *cobra.Command, args []string) error {
|
||||
o.contextNames = args
|
||||
o.out = out
|
||||
o.nameOnly = false
|
||||
if cmdutil.GetFlagString(cmd, "output") == "name" {
|
||||
o.nameOnly = true
|
||||
@ -109,9 +115,9 @@ func (o GetContextsOptions) RunGetContexts() error {
|
||||
return err
|
||||
}
|
||||
|
||||
out, found := o.out.(*tabwriter.Writer)
|
||||
out, found := o.Out.(*tabwriter.Writer)
|
||||
if !found {
|
||||
out = printers.GetNewTabWriter(o.out)
|
||||
out = printers.GetNewTabWriter(o.Out)
|
||||
defer out.Flush()
|
||||
}
|
||||
|
||||
|
6
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/get_contexts_test.go
generated
vendored
6
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/get_contexts_test.go
generated
vendored
@ -17,13 +17,13 @@ limitations under the License.
|
||||
package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
)
|
||||
|
||||
type getContextsTest struct {
|
||||
@ -157,11 +157,11 @@ func (test getContextsTest) run(t *testing.T) {
|
||||
pathOptions := clientcmd.NewDefaultPathOptions()
|
||||
pathOptions.GlobalFile = fakeKubeFile.Name()
|
||||
pathOptions.EnvVar = ""
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
options := GetContextsOptions{
|
||||
configAccess: pathOptions,
|
||||
}
|
||||
cmd := NewCmdConfigGetContexts(buf, options.configAccess)
|
||||
cmd := NewCmdConfigGetContexts(streams, options.configAccess)
|
||||
if test.nameOnly {
|
||||
cmd.Flags().Set("output", "name")
|
||||
}
|
||||
|
5
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/set.go
generated
vendored
5
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/set.go
generated
vendored
@ -33,11 +33,6 @@ import (
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
const (
|
||||
cannotHaveStepsAfterError = "Cannot have steps after %v. %v are remaining"
|
||||
additionStepRequiredUnlessUnsettingError = "Must have additional steps after %v unless you are unsetting it"
|
||||
)
|
||||
|
||||
type setOptions struct {
|
||||
configAccess clientcmd.ConfigAccess
|
||||
propertyName string
|
||||
|
119
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/view.go
generated
vendored
119
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/view.go
generated
vendored
@ -18,8 +18,6 @@ package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
@ -27,18 +25,28 @@ import (
|
||||
"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/util/i18n"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
type ViewOptions struct {
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
PrintObject printers.ResourcePrinterFunc
|
||||
|
||||
ConfigAccess clientcmd.ConfigAccess
|
||||
Merge flag.Tristate
|
||||
Flatten bool
|
||||
Minify bool
|
||||
RawByteData bool
|
||||
|
||||
Context string
|
||||
OutputFormat string
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
var (
|
||||
@ -48,17 +56,25 @@ var (
|
||||
You can use --output jsonpath={...} to extract specific values using a jsonpath expression.`)
|
||||
|
||||
view_example = templates.Examples(`
|
||||
# Show Merged kubeconfig settings.
|
||||
# Show merged kubeconfig settings.
|
||||
kubectl config view
|
||||
|
||||
# Show merged kubeconfig settings and raw certificate data.
|
||||
kubectl config view --raw
|
||||
|
||||
# Get the password for the e2e user
|
||||
kubectl config view -o jsonpath='{.users[?(@.name == "e2e")].user.password}'`)
|
||||
|
||||
defaultOutputFormat = "yaml"
|
||||
)
|
||||
|
||||
func NewCmdConfigView(f cmdutil.Factory, out, errOut io.Writer, ConfigAccess clientcmd.ConfigAccess) *cobra.Command {
|
||||
options := &ViewOptions{ConfigAccess: ConfigAccess}
|
||||
// Default to yaml
|
||||
defaultOutputFormat := "yaml"
|
||||
func NewCmdConfigView(f cmdutil.Factory, streams genericclioptions.IOStreams, ConfigAccess clientcmd.ConfigAccess) *cobra.Command {
|
||||
o := &ViewOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("").WithTypeSetter(legacyscheme.Scheme).WithDefaultOutput("yaml"),
|
||||
ConfigAccess: ConfigAccess,
|
||||
|
||||
IOStreams: streams,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "view",
|
||||
@ -66,46 +82,58 @@ func NewCmdConfigView(f cmdutil.Factory, out, errOut io.Writer, ConfigAccess cli
|
||||
Long: view_long,
|
||||
Example: view_example,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
options.Complete()
|
||||
outputFormat := cmdutil.GetFlagString(cmd, "output")
|
||||
if outputFormat == "wide" {
|
||||
fmt.Fprintf(errOut, "--output wide is not available in kubectl config view; reset to default output format (%s)\n\n", defaultOutputFormat)
|
||||
// TODO: once printing is abstracted, this should be handled at flag declaration time
|
||||
cmd.Flags().Set("output", defaultOutputFormat)
|
||||
}
|
||||
if outputFormat == "" {
|
||||
fmt.Fprintf(errOut, "Reset to default output format (%s) as --output is empty\n", defaultOutputFormat)
|
||||
// TODO: once printing is abstracted, this should be handled at flag declaration time
|
||||
cmd.Flags().Set("output", defaultOutputFormat)
|
||||
}
|
||||
|
||||
printOpts := cmdutil.ExtractCmdPrintOptions(cmd, false)
|
||||
printer, err := cmdutil.PrinterForOptions(printOpts)
|
||||
cmdutil.CheckErr(err)
|
||||
|
||||
cmdutil.CheckErr(options.Run(out, printer))
|
||||
cmdutil.CheckErr(o.Complete(cmd))
|
||||
cmdutil.CheckErr(o.Validate())
|
||||
cmdutil.CheckErr(o.Run())
|
||||
},
|
||||
}
|
||||
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmd.Flags().Set("output", defaultOutputFormat)
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
options.Merge.Default(true)
|
||||
mergeFlag := cmd.Flags().VarPF(&options.Merge, "merge", "", "Merge the full hierarchy of kubeconfig files")
|
||||
o.Merge.Default(true)
|
||||
mergeFlag := cmd.Flags().VarPF(&o.Merge, "merge", "", "Merge the full hierarchy of kubeconfig files")
|
||||
mergeFlag.NoOptDefVal = "true"
|
||||
cmd.Flags().BoolVar(&options.RawByteData, "raw", false, "Display raw byte data")
|
||||
cmd.Flags().BoolVar(&options.Flatten, "flatten", false, "Flatten the resulting kubeconfig file into self-contained output (useful for creating portable kubeconfig files)")
|
||||
cmd.Flags().BoolVar(&options.Minify, "minify", false, "Remove all information not used by current-context from the output")
|
||||
cmd.Flags().BoolVar(&o.RawByteData, "raw", o.RawByteData, "Display raw byte data")
|
||||
cmd.Flags().BoolVar(&o.Flatten, "flatten", o.Flatten, "Flatten the resulting kubeconfig file into self-contained output (useful for creating portable kubeconfig files)")
|
||||
cmd.Flags().BoolVar(&o.Minify, "minify", o.Minify, "Remove all information not used by current-context from the output")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o ViewOptions) Run(out io.Writer, printer printers.ResourcePrinter) error {
|
||||
func (o *ViewOptions) Complete(cmd *cobra.Command) error {
|
||||
if o.ConfigAccess.IsExplicitFile() {
|
||||
if !o.Merge.Provided() {
|
||||
o.Merge.Set("false")
|
||||
}
|
||||
}
|
||||
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.PrintObject = printer.PrintObj
|
||||
o.Context = cmdutil.GetFlagString(cmd, "context")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o ViewOptions) Validate() error {
|
||||
if !o.Merge.Value() && !o.ConfigAccess.IsExplicitFile() {
|
||||
return errors.New("if merge==false a precise file must to specified")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o ViewOptions) Run() error {
|
||||
config, err := o.loadConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if o.Minify {
|
||||
if len(o.Context) > 0 {
|
||||
config.CurrentContext = o.Context
|
||||
}
|
||||
if err := clientcmdapi.MinifyConfig(config); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -124,22 +152,7 @@ func (o ViewOptions) Run(out io.Writer, printer printers.ResourcePrinter) error
|
||||
return err
|
||||
}
|
||||
|
||||
err = printer.PrintObj(convertedObj, out)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *ViewOptions) Complete() bool {
|
||||
if o.ConfigAccess.IsExplicitFile() {
|
||||
if !o.Merge.Provided() {
|
||||
o.Merge.Set("false")
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
return o.PrintObject(convertedObj, o.Out)
|
||||
}
|
||||
|
||||
func (o ViewOptions) loadConfig() (*clientcmdapi.Config, error) {
|
||||
@ -152,14 +165,6 @@ func (o ViewOptions) loadConfig() (*clientcmdapi.Config, error) {
|
||||
return config, err
|
||||
}
|
||||
|
||||
func (o ViewOptions) Validate() error {
|
||||
if !o.Merge.Value() && !o.ConfigAccess.IsExplicitFile() {
|
||||
return errors.New("if merge==false a precise file must to specified")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getStartingConfig returns the Config object built from the sources specified by the options, the filename read (only if it was a single file), and an error if something goes wrong
|
||||
func (o *ViewOptions) getStartingConfig() (*clientcmdapi.Config, error) {
|
||||
switch {
|
||||
|
91
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/view_test.go
generated
vendored
91
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/view_test.go
generated
vendored
@ -17,7 +17,6 @@ limitations under the License.
|
||||
package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
@ -25,6 +24,7 @@ import (
|
||||
"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 {
|
||||
@ -43,19 +43,19 @@ func TestViewCluster(t *testing.T) {
|
||||
"my-cluster": {Server: "https://192.168.0.1:3434"},
|
||||
},
|
||||
Contexts: map[string]*clientcmdapi.Context{
|
||||
"minikube": {AuthInfo: "minikube", Cluster: "minikube"},
|
||||
"my-cluser": {AuthInfo: "mu-cluster", Cluster: "my-cluster"},
|
||||
"minikube": {AuthInfo: "minikube", Cluster: "minikube"},
|
||||
"my-cluster": {AuthInfo: "mu-cluster", Cluster: "my-cluster"},
|
||||
},
|
||||
CurrentContext: "minikube",
|
||||
AuthInfos: map[string]*clientcmdapi.AuthInfo{
|
||||
"minikube": {Token: "minikube-token"},
|
||||
"my-cluser": {Token: "minikube-token"},
|
||||
"minikube": {Token: "minikube-token"},
|
||||
"mu-cluster": {Token: "minikube-token"},
|
||||
},
|
||||
}
|
||||
|
||||
test := viewClusterTest{
|
||||
description: "Testing for kubectl config view",
|
||||
config: conf,
|
||||
flags: []string{},
|
||||
expected: `apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
@ -72,7 +72,7 @@ contexts:
|
||||
- context:
|
||||
cluster: my-cluster
|
||||
user: mu-cluster
|
||||
name: my-cluser
|
||||
name: my-cluster
|
||||
current-context: minikube
|
||||
kind: Config
|
||||
preferences: {}
|
||||
@ -80,10 +80,13 @@ users:
|
||||
- name: minikube
|
||||
user:
|
||||
token: minikube-token
|
||||
- name: my-cluser
|
||||
- name: mu-cluster
|
||||
user:
|
||||
token: minikube-token` + "\n"}
|
||||
token: minikube-token` + "\n",
|
||||
}
|
||||
|
||||
test.run(t)
|
||||
|
||||
}
|
||||
|
||||
func TestViewClusterMinify(t *testing.T) {
|
||||
@ -95,20 +98,27 @@ func TestViewClusterMinify(t *testing.T) {
|
||||
"my-cluster": {Server: "https://192.168.0.1:3434"},
|
||||
},
|
||||
Contexts: map[string]*clientcmdapi.Context{
|
||||
"minikube": {AuthInfo: "minikube", Cluster: "minikube"},
|
||||
"my-cluser": {AuthInfo: "mu-cluster", Cluster: "my-cluster"},
|
||||
"minikube": {AuthInfo: "minikube", Cluster: "minikube"},
|
||||
"my-cluster": {AuthInfo: "mu-cluster", Cluster: "my-cluster"},
|
||||
},
|
||||
CurrentContext: "minikube",
|
||||
AuthInfos: map[string]*clientcmdapi.AuthInfo{
|
||||
"minikube": {Token: "minikube-token"},
|
||||
"my-cluser": {Token: "minikube-token"},
|
||||
"minikube": {Token: "minikube-token"},
|
||||
"mu-cluster": {Token: "minikube-token"},
|
||||
},
|
||||
}
|
||||
test := viewClusterTest{
|
||||
description: "Testing for kubectl config view --minify=true",
|
||||
config: conf,
|
||||
flags: []string{"--minify=true"},
|
||||
expected: `apiVersion: v1
|
||||
|
||||
testCases := []struct {
|
||||
description string
|
||||
config clientcmdapi.Config
|
||||
flags []string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
description: "Testing for kubectl config view --minify=true",
|
||||
config: conf,
|
||||
flags: []string{"--minify=true"},
|
||||
expected: `apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
server: https://192.168.99.100:8443
|
||||
@ -124,8 +134,41 @@ preferences: {}
|
||||
users:
|
||||
- name: minikube
|
||||
user:
|
||||
token: minikube-token` + "\n"}
|
||||
test.run(t)
|
||||
token: minikube-token` + "\n",
|
||||
},
|
||||
{
|
||||
description: "Testing for kubectl config view --minify=true --context=my-cluster",
|
||||
config: conf,
|
||||
flags: []string{"--minify=true", "--context=my-cluster"},
|
||||
expected: `apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
server: https://192.168.0.1:3434
|
||||
name: my-cluster
|
||||
contexts:
|
||||
- context:
|
||||
cluster: my-cluster
|
||||
user: mu-cluster
|
||||
name: my-cluster
|
||||
current-context: my-cluster
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: mu-cluster
|
||||
user:
|
||||
token: minikube-token` + "\n",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
cmdTest := viewClusterTest{
|
||||
description: test.description,
|
||||
config: test.config,
|
||||
flags: test.flags,
|
||||
expected: test.expected,
|
||||
}
|
||||
cmdTest.run(t)
|
||||
}
|
||||
}
|
||||
|
||||
func (test viewClusterTest) run(t *testing.T) {
|
||||
@ -141,10 +184,12 @@ func (test viewClusterTest) run(t *testing.T) {
|
||||
pathOptions := clientcmd.NewDefaultPathOptions()
|
||||
pathOptions.GlobalFile = fakeKubeFile.Name()
|
||||
pathOptions.EnvVar = ""
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdConfigView(cmdutil.NewFactory(nil), buf, errBuf, pathOptions)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdConfigView(cmdutil.NewFactory(genericclioptions.NewTestConfigFlags()), streams, pathOptions)
|
||||
// "context" is a global flag, inherited from base kubectl command in the real world
|
||||
cmd.Flags().String("context", "", "The name of the kubeconfig context to use")
|
||||
cmd.Flags().Parse(test.flags)
|
||||
|
||||
if err := cmd.Execute(); err != nil {
|
||||
t.Fatalf("unexpected error executing command: %v,kubectl config view flags: %v", err, test.flags)
|
||||
}
|
||||
|
79
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/convert.go
generated
vendored
79
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/convert.go
generated
vendored
@ -18,7 +18,6 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@ -27,9 +26,10 @@ import (
|
||||
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/resource"
|
||||
"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"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
@ -61,8 +61,8 @@ var (
|
||||
|
||||
// NewCmdConvert creates a command object for the generic "convert" action, which
|
||||
// translates the config file into a given version.
|
||||
func NewCmdConvert(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
options := &ConvertOptions{}
|
||||
func NewCmdConvert(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := NewConvertOptions(ioStreams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "convert -f FILENAME",
|
||||
@ -71,37 +71,44 @@ func NewCmdConvert(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
Long: convert_long,
|
||||
Example: convert_example,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := options.Complete(f, out, cmd)
|
||||
cmdutil.CheckErr(err)
|
||||
err = options.RunConvert()
|
||||
cmdutil.CheckErr(err)
|
||||
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)
|
||||
cmdutil.AddNonDeprecatedPrinterFlags(cmd)
|
||||
cmd.Flags().BoolVar(&options.local, "local", true, "If true, convert will NOT try to contact api-server but run locally.")
|
||||
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').)"))
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// ConvertOptions have the data required to perform the convert operation
|
||||
type ConvertOptions struct {
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
PrintObj printers.ResourcePrinterFunc
|
||||
|
||||
resource.FilenameOptions
|
||||
|
||||
builder *resource.Builder
|
||||
local bool
|
||||
|
||||
out io.Writer
|
||||
printer printers.ResourcePrinter
|
||||
|
||||
genericclioptions.IOStreams
|
||||
specifiedOutputVersion schema.GroupVersion
|
||||
}
|
||||
|
||||
func NewConvertOptions(ioStreams genericclioptions.IOStreams) *ConvertOptions {
|
||||
return &ConvertOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("converted").WithTypeSetter(scheme.Scheme).WithDefaultOutput("yaml"),
|
||||
local: true,
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
@ -114,7 +121,7 @@ func outputVersion(cmd *cobra.Command) (schema.GroupVersion, error) {
|
||||
}
|
||||
|
||||
// Complete collects information required to run Convert command from command line.
|
||||
func (o *ConvertOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.Command) (err error) {
|
||||
func (o *ConvertOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) (err error) {
|
||||
o.specifiedOutputVersion, err = outputVersion(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -122,7 +129,7 @@ func (o *ConvertOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.C
|
||||
|
||||
// build the builder
|
||||
o.builder = f.NewBuilder().
|
||||
Internal().
|
||||
WithScheme(scheme.Scheme).
|
||||
LocalParam(o.local)
|
||||
if !o.local {
|
||||
schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"))
|
||||
@ -132,7 +139,7 @@ func (o *ConvertOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.C
|
||||
o.builder.Schema(schema)
|
||||
}
|
||||
|
||||
cmdNamespace, _, err := f.DefaultNamespace()
|
||||
cmdNamespace, _, err := f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -142,20 +149,12 @@ func (o *ConvertOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.C
|
||||
Flatten()
|
||||
|
||||
// build the printer
|
||||
o.out = out
|
||||
outputFormat := cmdutil.GetFlagString(cmd, "output")
|
||||
templateFile := cmdutil.GetFlagString(cmd, "template")
|
||||
if len(outputFormat) == 0 {
|
||||
if len(templateFile) == 0 {
|
||||
outputFormat = "yaml"
|
||||
} else {
|
||||
outputFormat = "template"
|
||||
}
|
||||
// TODO: once printing is abstracted, this should be handled at flag declaration time
|
||||
cmd.Flags().Set("output", outputFormat)
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.printer, err = cmdutil.PrinterForOptions(cmdutil.ExtractCmdPrintOptions(cmd, false))
|
||||
return err
|
||||
o.PrintObj = printer.PrintObj
|
||||
return nil
|
||||
}
|
||||
|
||||
// RunConvert implements the generic Convert command
|
||||
@ -182,18 +181,14 @@ func (o *ConvertOptions) RunConvert() error {
|
||||
}
|
||||
|
||||
if meta.IsListType(objects) {
|
||||
_, items, err := cmdutil.FilterResourceList(objects, nil, nil)
|
||||
obj, err := objectListToVersionedObject([]runtime.Object{objects}, o.specifiedOutputVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
filteredObj, err := objectListToVersionedObject(items, o.specifiedOutputVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return o.printer.PrintObj(filteredObj, o.out)
|
||||
return o.PrintObj(obj, o.Out)
|
||||
}
|
||||
|
||||
return o.printer.PrintObj(objects, o.out)
|
||||
return o.PrintObj(objects, o.Out)
|
||||
}
|
||||
|
||||
// objectListToVersionedObject receives a list of api objects and a group version
|
||||
@ -204,7 +199,7 @@ func objectListToVersionedObject(objects []runtime.Object, specifiedOutputVersio
|
||||
if !specifiedOutputVersion.Empty() {
|
||||
targetVersions = append(targetVersions, specifiedOutputVersion)
|
||||
}
|
||||
targetVersions = append(targetVersions, scheme.Registry.GroupOrDie(api.GroupName).GroupVersion)
|
||||
targetVersions = append(targetVersions, schema.GroupVersion{Group: "", Version: "v1"})
|
||||
converted, err := tryConvert(scheme.Scheme, objectList, targetVersions...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -231,7 +226,7 @@ func asVersionedObject(infos []*resource.Info, forceList bool, specifiedOutputVe
|
||||
if !specifiedOutputVersion.Empty() {
|
||||
targetVersions = append(targetVersions, specifiedOutputVersion)
|
||||
}
|
||||
targetVersions = append(targetVersions, scheme.Registry.GroupOrDie(api.GroupName).GroupVersion)
|
||||
targetVersions = append(targetVersions, schema.GroupVersion{Group: "", Version: "v1"})
|
||||
|
||||
converted, err := tryConvert(scheme.Scheme, object, targetVersions...)
|
||||
if err != nil {
|
||||
@ -280,14 +275,14 @@ func asVersionedObjects(infos []*resource.Info, specifiedOutputVersion schema.Gr
|
||||
gvks, _, err := scheme.Scheme.ObjectKinds(info.Object)
|
||||
if err == nil {
|
||||
for _, gvk := range gvks {
|
||||
for _, version := range scheme.Registry.EnabledVersionsForGroup(gvk.Group) {
|
||||
for _, version := range scheme.Scheme.PrioritizedVersionsForGroup(gvk.Group) {
|
||||
targetVersions = append(targetVersions, version)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
converted, err := tryConvert(info.Mapping.ObjectConvertor, info.Object, targetVersions...)
|
||||
converted, err := tryConvert(scheme.Scheme, info.Object, targetVersions...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
35
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/convert_test.go
generated
vendored
35
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/convert_test.go
generated
vendored
@ -20,10 +20,12 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/client-go/rest/fake"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
)
|
||||
|
||||
type testcase struct {
|
||||
@ -34,7 +36,6 @@ type testcase struct {
|
||||
}
|
||||
|
||||
type checkField struct {
|
||||
template string
|
||||
expected string
|
||||
}
|
||||
|
||||
@ -46,8 +47,7 @@ func TestConvertObject(t *testing.T) {
|
||||
outputVersion: "extensions/v1beta1",
|
||||
fields: []checkField{
|
||||
{
|
||||
template: "{{.apiVersion}}",
|
||||
expected: "extensions/v1beta1",
|
||||
expected: "apiVersion: extensions/v1beta1",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -57,8 +57,7 @@ func TestConvertObject(t *testing.T) {
|
||||
outputVersion: "apps/v1beta2",
|
||||
fields: []checkField{
|
||||
{
|
||||
template: "{{.apiVersion}}",
|
||||
expected: "apps/v1beta2",
|
||||
expected: "apiVersion: apps/v1beta2",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -68,16 +67,13 @@ func TestConvertObject(t *testing.T) {
|
||||
outputVersion: "autoscaling/v2beta1",
|
||||
fields: []checkField{
|
||||
{
|
||||
template: "{{.apiVersion}}",
|
||||
expected: "autoscaling/v2beta1",
|
||||
expected: "apiVersion: autoscaling/v2beta1",
|
||||
},
|
||||
{
|
||||
template: "{{(index .spec.metrics 0).resource.name}}",
|
||||
expected: "cpu",
|
||||
expected: "name: cpu",
|
||||
},
|
||||
{
|
||||
template: "{{(index .spec.metrics 0).resource.targetAverageUtilization}}",
|
||||
expected: "50",
|
||||
expected: "targetAverageUtilization: 50",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -87,12 +83,10 @@ func TestConvertObject(t *testing.T) {
|
||||
outputVersion: "autoscaling/v1",
|
||||
fields: []checkField{
|
||||
{
|
||||
template: "{{.apiVersion}}",
|
||||
expected: "autoscaling/v1",
|
||||
expected: "apiVersion: autoscaling/v1",
|
||||
},
|
||||
{
|
||||
template: "{{.spec.targetCPUUtilizationPercentage}}",
|
||||
expected: "50",
|
||||
expected: "targetCPUUtilizationPercentage: 50",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -101,23 +95,24 @@ func TestConvertObject(t *testing.T) {
|
||||
for _, tc := range testcases {
|
||||
for _, field := range tc.fields {
|
||||
t.Run(fmt.Sprintf("%s %s", tc.name, field), func(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
|
||||
return nil, nil
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdConvert(tf, buf)
|
||||
cmd := NewCmdConvert(tf, genericclioptions.IOStreams{Out: buf, ErrOut: buf})
|
||||
cmd.Flags().Set("filename", tc.file)
|
||||
cmd.Flags().Set("output-version", tc.outputVersion)
|
||||
cmd.Flags().Set("local", "true")
|
||||
cmd.Flags().Set("output", "go-template="+field.template)
|
||||
cmd.Flags().Set("output", "yaml")
|
||||
cmd.Run(cmd, []string{})
|
||||
if buf.String() != field.expected {
|
||||
if !strings.Contains(buf.String(), field.expected) {
|
||||
t.Errorf("unexpected output when converting %s to %q, expected: %q, but got %q", tc.file, tc.outputVersion, field.expected, buf.String())
|
||||
}
|
||||
})
|
||||
|
205
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/cp.go
generated
vendored
205
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/cp.go
generated
vendored
@ -18,7 +18,6 @@ package cmd
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@ -28,10 +27,15 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
"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"
|
||||
|
||||
"bytes"
|
||||
|
||||
"github.com/renstrom/dedent"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -61,8 +65,26 @@ var (
|
||||
/file/path for a local file`)
|
||||
)
|
||||
|
||||
type CopyOptions struct {
|
||||
Container string
|
||||
Namespace string
|
||||
|
||||
ClientConfig *restclient.Config
|
||||
Clientset internalclientset.Interface
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
func NewCopyOptions(ioStreams genericclioptions.IOStreams) *CopyOptions {
|
||||
return &CopyOptions{
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
// NewCmdCp creates a new Copy command.
|
||||
func NewCmdCp(f cmdutil.Factory, cmdOut, cmdErr io.Writer) *cobra.Command {
|
||||
func NewCmdCp(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewCopyOptions(ioStreams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "cp <file-spec-src> <file-spec-dest>",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -70,10 +92,11 @@ func NewCmdCp(f cmdutil.Factory, cmdOut, cmdErr io.Writer) *cobra.Command {
|
||||
Long: "Copy files and directories to and from containers.",
|
||||
Example: cpExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(runCopy(f, cmd, cmdOut, cmdErr, args))
|
||||
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||
cmdutil.CheckErr(o.Run(args))
|
||||
},
|
||||
}
|
||||
cmd.Flags().StringP("container", "c", "", "Container name. If omitted, the first container in the pod will be chosen")
|
||||
cmd.Flags().StringVarP(&o.Container, "container", "c", o.Container, "Container name. If omitted, the first container in the pod will be chosen")
|
||||
|
||||
return cmd
|
||||
}
|
||||
@ -90,39 +113,60 @@ var (
|
||||
)
|
||||
|
||||
func extractFileSpec(arg string) (fileSpec, error) {
|
||||
pieces := strings.Split(arg, ":")
|
||||
if len(pieces) == 1 {
|
||||
if i := strings.Index(arg, ":"); i == -1 {
|
||||
return fileSpec{File: arg}, nil
|
||||
}
|
||||
if len(pieces) != 2 {
|
||||
// FIXME Kubernetes can't copy files that contain a ':'
|
||||
// character.
|
||||
return fileSpec{}, errFileSpecDoesntMatchFormat
|
||||
}
|
||||
file := pieces[1]
|
||||
|
||||
pieces = strings.Split(pieces[0], "/")
|
||||
if len(pieces) == 1 {
|
||||
return fileSpec{
|
||||
PodName: pieces[0],
|
||||
File: file,
|
||||
}, nil
|
||||
}
|
||||
if len(pieces) == 2 {
|
||||
return fileSpec{
|
||||
PodNamespace: pieces[0],
|
||||
PodName: pieces[1],
|
||||
File: file,
|
||||
}, nil
|
||||
} else if i > 0 {
|
||||
file := arg[i+1:]
|
||||
pod := arg[:i]
|
||||
pieces := strings.Split(pod, "/")
|
||||
if len(pieces) == 1 {
|
||||
return fileSpec{
|
||||
PodName: pieces[0],
|
||||
File: file,
|
||||
}, nil
|
||||
}
|
||||
if len(pieces) == 2 {
|
||||
return fileSpec{
|
||||
PodNamespace: pieces[0],
|
||||
PodName: pieces[1],
|
||||
File: file,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
return fileSpec{}, errFileSpecDoesntMatchFormat
|
||||
}
|
||||
|
||||
func runCopy(f cmdutil.Factory, cmd *cobra.Command, out, cmderr io.Writer, args []string) error {
|
||||
func (o *CopyOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
var err error
|
||||
o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.Clientset, err = f.ClientSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.ClientConfig, err = f.ToRESTConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *CopyOptions) Validate(cmd *cobra.Command, args []string) error {
|
||||
if len(args) != 2 {
|
||||
return cmdutil.UsageErrorf(cmd, cpUsageStr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *CopyOptions) Run(args []string) error {
|
||||
if len(args) < 2 {
|
||||
return fmt.Errorf("source and destination are required")
|
||||
}
|
||||
srcSpec, err := extractFileSpec(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
@ -131,24 +175,34 @@ func runCopy(f cmdutil.Factory, cmd *cobra.Command, out, cmderr io.Writer, args
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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 fmt.Errorf("src doesn't exist in local filesystem")
|
||||
}
|
||||
|
||||
if len(srcSpec.PodName) != 0 {
|
||||
return copyFromPod(f, cmd, cmderr, srcSpec, destSpec)
|
||||
return o.copyFromPod(srcSpec, destSpec)
|
||||
}
|
||||
if len(destSpec.PodName) != 0 {
|
||||
return copyToPod(f, cmd, out, cmderr, srcSpec, destSpec)
|
||||
return o.copyToPod(srcSpec, destSpec)
|
||||
}
|
||||
return cmdutil.UsageErrorf(cmd, "One of src or dest must be a remote file specification")
|
||||
return fmt.Errorf("one of src or dest must be a remote file specification")
|
||||
}
|
||||
|
||||
// checkDestinationIsDir receives a destination fileSpec and
|
||||
// determines if the provided destination path exists on the
|
||||
// pod. If the destination path does not exist or is _not_ a
|
||||
// directory, an error is returned with the exit code received.
|
||||
func checkDestinationIsDir(dest fileSpec, f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
func (o *CopyOptions) checkDestinationIsDir(dest fileSpec) error {
|
||||
options := &ExecOptions{
|
||||
StreamOptions: StreamOptions{
|
||||
Out: bytes.NewBuffer([]byte{}),
|
||||
Err: bytes.NewBuffer([]byte{}),
|
||||
IOStreams: genericclioptions.IOStreams{
|
||||
Out: bytes.NewBuffer([]byte{}),
|
||||
ErrOut: bytes.NewBuffer([]byte{}),
|
||||
},
|
||||
|
||||
Namespace: dest.PodNamespace,
|
||||
PodName: dest.PodName,
|
||||
@ -158,21 +212,21 @@ func checkDestinationIsDir(dest fileSpec, f cmdutil.Factory, cmd *cobra.Command)
|
||||
Executor: &DefaultRemoteExecutor{},
|
||||
}
|
||||
|
||||
return execute(f, cmd, options)
|
||||
return o.execute(options)
|
||||
}
|
||||
|
||||
func copyToPod(f cmdutil.Factory, cmd *cobra.Command, stdout, stderr io.Writer, src, dest fileSpec) error {
|
||||
if len(src.File) == 0 {
|
||||
func (o *CopyOptions) copyToPod(src, dest fileSpec) error {
|
||||
if len(src.File) == 0 || len(dest.File) == 0 {
|
||||
return errFileCannotBeEmpty
|
||||
}
|
||||
reader, writer := io.Pipe()
|
||||
|
||||
// strip trailing slash (if any)
|
||||
if strings.HasSuffix(string(dest.File[len(dest.File)-1]), "/") {
|
||||
if dest.File != "/" && strings.HasSuffix(string(dest.File[len(dest.File)-1]), "/") {
|
||||
dest.File = dest.File[:len(dest.File)-1]
|
||||
}
|
||||
|
||||
if err := checkDestinationIsDir(dest, f, cmd); err == nil {
|
||||
if err := o.checkDestinationIsDir(dest); err == nil {
|
||||
// If no error, dest.File was found to be a directory.
|
||||
// Copy specified src into it
|
||||
dest.File = dest.File + "/" + path.Base(src.File)
|
||||
@ -193,9 +247,11 @@ func copyToPod(f cmdutil.Factory, cmd *cobra.Command, stdout, stderr io.Writer,
|
||||
|
||||
options := &ExecOptions{
|
||||
StreamOptions: StreamOptions{
|
||||
In: reader,
|
||||
Out: stdout,
|
||||
Err: stderr,
|
||||
IOStreams: genericclioptions.IOStreams{
|
||||
In: reader,
|
||||
Out: o.Out,
|
||||
ErrOut: o.ErrOut,
|
||||
},
|
||||
Stdin: true,
|
||||
|
||||
Namespace: dest.PodNamespace,
|
||||
@ -205,20 +261,22 @@ func copyToPod(f cmdutil.Factory, cmd *cobra.Command, stdout, stderr io.Writer,
|
||||
Command: cmdArr,
|
||||
Executor: &DefaultRemoteExecutor{},
|
||||
}
|
||||
return execute(f, cmd, options)
|
||||
return o.execute(options)
|
||||
}
|
||||
|
||||
func copyFromPod(f cmdutil.Factory, cmd *cobra.Command, cmderr io.Writer, src, dest fileSpec) error {
|
||||
if len(src.File) == 0 {
|
||||
func (o *CopyOptions) copyFromPod(src, dest fileSpec) error {
|
||||
if len(src.File) == 0 || len(dest.File) == 0 {
|
||||
return errFileCannotBeEmpty
|
||||
}
|
||||
|
||||
reader, outStream := io.Pipe()
|
||||
options := &ExecOptions{
|
||||
StreamOptions: StreamOptions{
|
||||
In: nil,
|
||||
Out: outStream,
|
||||
Err: cmderr,
|
||||
IOStreams: genericclioptions.IOStreams{
|
||||
In: nil,
|
||||
Out: outStream,
|
||||
ErrOut: o.Out,
|
||||
},
|
||||
|
||||
Namespace: src.PodNamespace,
|
||||
PodName: src.PodName,
|
||||
@ -231,13 +289,26 @@ func copyFromPod(f cmdutil.Factory, cmd *cobra.Command, cmderr io.Writer, src, d
|
||||
|
||||
go func() {
|
||||
defer outStream.Close()
|
||||
execute(f, cmd, options)
|
||||
o.execute(options)
|
||||
}()
|
||||
prefix := getPrefix(src.File)
|
||||
prefix = path.Clean(prefix)
|
||||
// remove extraneous path shortcuts - these could occur if a path contained extra "../"
|
||||
// and attempted to navigate beyond "/" in a remote filesystem
|
||||
prefix = stripPathShortcuts(prefix)
|
||||
return untarAll(reader, dest.File, prefix)
|
||||
}
|
||||
|
||||
// stripPathShortcuts removes any leading or trailing "../" from a given path
|
||||
func stripPathShortcuts(p string) string {
|
||||
newPath := path.Clean(p)
|
||||
if len(newPath) > 0 && string(newPath[0]) == "/" {
|
||||
return newPath[1:]
|
||||
}
|
||||
|
||||
return newPath
|
||||
}
|
||||
|
||||
func makeTar(srcPath, destPath string, writer io.Writer) error {
|
||||
// TODO: use compression here?
|
||||
tarWriter := tar.NewWriter(writer)
|
||||
@ -312,6 +383,12 @@ func recursiveTar(srcBase, srcFile, destBase, destFile string, tw *tar.Writer) e
|
||||
return nil
|
||||
}
|
||||
|
||||
// clean prevents path traversals by stripping them out.
|
||||
// This is adapted from https://golang.org/src/net/http/fs.go#L74
|
||||
func clean(fileName string) string {
|
||||
return path.Clean(string(os.PathSeparator) + fileName)
|
||||
}
|
||||
|
||||
func untarAll(reader io.Reader, destFile, prefix string) error {
|
||||
entrySeq := -1
|
||||
|
||||
@ -327,7 +404,7 @@ func untarAll(reader io.Reader, destFile, prefix string) error {
|
||||
}
|
||||
entrySeq++
|
||||
mode := header.FileInfo().Mode()
|
||||
outFileName := path.Join(destFile, header.Name[len(prefix):])
|
||||
outFileName := path.Join(destFile, clean(header.Name[len(prefix):]))
|
||||
baseName := path.Dir(outFileName)
|
||||
if err := os.MkdirAll(baseName, 0755); err != nil {
|
||||
return err
|
||||
@ -346,7 +423,7 @@ func untarAll(reader io.Reader, destFile, prefix string) error {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
outFileName = filepath.Join(outFileName, path.Base(header.Name))
|
||||
outFileName = filepath.Join(outFileName, path.Base(clean(header.Name)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -383,31 +460,17 @@ func getPrefix(file string) string {
|
||||
return strings.TrimLeft(file, "/")
|
||||
}
|
||||
|
||||
func execute(f cmdutil.Factory, cmd *cobra.Command, options *ExecOptions) error {
|
||||
func (o *CopyOptions) execute(options *ExecOptions) error {
|
||||
if len(options.Namespace) == 0 {
|
||||
namespace, _, err := f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
options.Namespace = namespace
|
||||
options.Namespace = o.Namespace
|
||||
}
|
||||
|
||||
container := cmdutil.GetFlagString(cmd, "container")
|
||||
if len(container) > 0 {
|
||||
options.ContainerName = container
|
||||
if len(o.Container) > 0 {
|
||||
options.ContainerName = o.Container
|
||||
}
|
||||
|
||||
config, err := f.ClientConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
options.Config = config
|
||||
|
||||
clientset, err := f.ClientSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
options.PodClient = clientset.Core()
|
||||
options.Config = o.ClientConfig
|
||||
options.PodClient = o.Clientset.Core()
|
||||
|
||||
if err := options.Validate(); err != nil {
|
||||
return err
|
||||
|
199
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/cp_test.go
generated
vendored
199
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/cp_test.go
generated
vendored
@ -21,12 +21,23 @@ import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"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"
|
||||
)
|
||||
|
||||
type FileType int
|
||||
@ -60,9 +71,18 @@ func TestExtractFileSpec(t *testing.T) {
|
||||
expectedFile: "/some/file",
|
||||
},
|
||||
{
|
||||
spec: "some:bad:spec",
|
||||
spec: ":file:not:exist:in:local:filesystem",
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
spec: "namespace/pod/invalid:/some/file",
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
spec: "pod:/some/filenamewith:in",
|
||||
expectedPod: "pod",
|
||||
expectedFile: "/some/filenamewith:in",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
spec, err := extractFileSpec(test.spec)
|
||||
@ -422,3 +442,180 @@ func TestTarDestinationName(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadTar(t *testing.T) {
|
||||
dir, err := ioutil.TempDir(os.TempDir(), "dest")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v ", err)
|
||||
t.FailNow()
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
// More or less cribbed from https://golang.org/pkg/archive/tar/#example__minimal
|
||||
var buf bytes.Buffer
|
||||
tw := tar.NewWriter(&buf)
|
||||
var files = []struct {
|
||||
name string
|
||||
body string
|
||||
}{
|
||||
{"/prefix/../../../tmp/foo", "Up to temp"},
|
||||
{"/prefix/foo/bar/../../home/bburns/names.txt", "Down and back"},
|
||||
}
|
||||
for _, file := range files {
|
||||
hdr := &tar.Header{
|
||||
Name: file.name,
|
||||
Mode: 0600,
|
||||
Size: int64(len(file.body)),
|
||||
}
|
||||
if err := tw.WriteHeader(hdr); err != nil {
|
||||
t.Errorf("unexpected error: %v ", err)
|
||||
t.FailNow()
|
||||
}
|
||||
if _, err := tw.Write([]byte(file.body)); err != nil {
|
||||
t.Errorf("unexpected error: %v ", err)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
if err := tw.Close(); err != nil {
|
||||
t.Errorf("unexpected error: %v ", err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if err := untarAll(&buf, dir, "/prefix"); err != nil {
|
||||
t.Errorf("unexpected error: %v ", err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
_, err := os.Stat(path.Join(dir, path.Clean(file.name[len("/prefix"):])))
|
||||
if err != nil {
|
||||
t.Errorf("Error finding file: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestClean(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
cleaned string
|
||||
}{
|
||||
{
|
||||
"../../../tmp/foo",
|
||||
"/tmp/foo",
|
||||
},
|
||||
{
|
||||
"/../../../tmp/foo",
|
||||
"/tmp/foo",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
out := clean(test.input)
|
||||
if out != test.cleaned {
|
||||
t.Errorf("Expected: %s, saw %s", test.cleaned, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyToPod(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
ns := legacyscheme.Codecs
|
||||
codec := legacyscheme.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
|
||||
}),
|
||||
}
|
||||
|
||||
tf.ClientConfigVal = 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 {
|
||||
dest string
|
||||
expectedErr bool
|
||||
}{
|
||||
"copy to directory": {
|
||||
dest: "/tmp/",
|
||||
expectedErr: false,
|
||||
},
|
||||
"copy to root": {
|
||||
dest: "/",
|
||||
expectedErr: false,
|
||||
},
|
||||
"copy to empty file name": {
|
||||
dest: "",
|
||||
expectedErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
opts := NewCopyOptions(ioStreams)
|
||||
src := fileSpec{
|
||||
File: srcFile,
|
||||
}
|
||||
dest := fileSpec{
|
||||
PodNamespace: "pod-ns",
|
||||
PodName: "pod-name",
|
||||
File: test.dest,
|
||||
}
|
||||
opts.Complete(tf, cmd)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
err = opts.copyToPod(src, dest)
|
||||
//If error is NotFound error , it indicates that the
|
||||
//request has been sent correctly.
|
||||
//Treat this as no error.
|
||||
if test.expectedErr && errors.IsNotFound(err) {
|
||||
t.Errorf("expected error but didn't get one")
|
||||
}
|
||||
if !test.expectedErr && !errors.IsNotFound(err) {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
expectedErr bool
|
||||
}{
|
||||
{
|
||||
name: "Validate Succeed",
|
||||
args: []string{"1", "2"},
|
||||
expectedErr: false,
|
||||
},
|
||||
{
|
||||
name: "Validate Fail",
|
||||
args: []string{"1", "2", "3"},
|
||||
expectedErr: true,
|
||||
},
|
||||
}
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
ioStreams, _, _, _ := genericclioptions.NewTestIOStreams()
|
||||
opts := NewCopyOptions(ioStreams)
|
||||
cmd := NewCmdCp(tf, ioStreams)
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
err := opts.Validate(cmd, test.args)
|
||||
if (err != nil) != test.expectedErr {
|
||||
t.Errorf("expected error: %v, saw: %v, error: %v", test.expectedErr, err != nil, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
362
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/create.go
generated
vendored
362
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/create.go
generated
vendored
@ -1,362 +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"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"net/url"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"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/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
type CreateOptions struct {
|
||||
FilenameOptions resource.FilenameOptions
|
||||
Selector string
|
||||
EditBeforeCreate bool
|
||||
Raw string
|
||||
Out io.Writer
|
||||
ErrOut io.Writer
|
||||
}
|
||||
|
||||
var (
|
||||
createLong = templates.LongDesc(i18n.T(`
|
||||
Create a resource from a file or from stdin.
|
||||
|
||||
JSON and YAML formats are accepted.`))
|
||||
|
||||
createExample = templates.Examples(i18n.T(`
|
||||
# Create a pod using the data in pod.json.
|
||||
kubectl create -f ./pod.json
|
||||
|
||||
# Create a pod based on the JSON passed into stdin.
|
||||
cat pod.json | kubectl create -f -
|
||||
|
||||
# Edit the data in docker-registry.yaml in JSON using the v1 API format then create the resource using the edited data.
|
||||
kubectl create -f docker-registry.yaml --edit --output-version=v1 -o json`))
|
||||
)
|
||||
|
||||
func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
options := &CreateOptions{
|
||||
Out: out,
|
||||
ErrOut: errOut,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "create -f FILENAME",
|
||||
DisableFlagsInUseLine: true,
|
||||
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(options.FilenameOptions.Filenames) {
|
||||
defaultRunFunc := cmdutil.DefaultSubCommandRun(errOut)
|
||||
defaultRunFunc(cmd, args)
|
||||
return
|
||||
}
|
||||
cmdutil.CheckErr(options.ValidateArgs(cmd, args))
|
||||
cmdutil.CheckErr(options.RunCreate(f, cmd))
|
||||
},
|
||||
}
|
||||
|
||||
usage := "to use to create the resource"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||
cmd.MarkFlagRequired("filename")
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmd.Flags().BoolVar(&options.EditBeforeCreate, "edit", false, "Edit the API resource before creating")
|
||||
cmd.Flags().Bool("windows-line-endings", runtime.GOOS == "windows",
|
||||
"Only relevant if --edit=true. Defaults to the line ending native to your platform.")
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddRecordFlag(cmd)
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
cmd.Flags().StringVarP(&options.Selector, "selector", "l", "", "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
|
||||
cmd.Flags().StringVar(&options.Raw, "raw", options.Raw, "Raw URI to POST to the server. Uses the transport specified by the kubeconfig file.")
|
||||
|
||||
// create subcommands
|
||||
cmd.AddCommand(NewCmdCreateNamespace(f, out))
|
||||
cmd.AddCommand(NewCmdCreateQuota(f, out))
|
||||
cmd.AddCommand(NewCmdCreateSecret(f, out, errOut))
|
||||
cmd.AddCommand(NewCmdCreateConfigMap(f, out))
|
||||
cmd.AddCommand(NewCmdCreateServiceAccount(f, out))
|
||||
cmd.AddCommand(NewCmdCreateService(f, out, errOut))
|
||||
cmd.AddCommand(NewCmdCreateDeployment(f, out, errOut))
|
||||
cmd.AddCommand(NewCmdCreateClusterRole(f, out))
|
||||
cmd.AddCommand(NewCmdCreateClusterRoleBinding(f, out))
|
||||
cmd.AddCommand(NewCmdCreateRole(f, out))
|
||||
cmd.AddCommand(NewCmdCreateRoleBinding(f, out))
|
||||
cmd.AddCommand(NewCmdCreatePodDisruptionBudget(f, out))
|
||||
cmd.AddCommand(NewCmdCreatePriorityClass(f, out))
|
||||
cmd.AddCommand(NewCmdCreateJob(f, out))
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o *CreateOptions) ValidateArgs(cmd *cobra.Command, args []string) error {
|
||||
if len(args) != 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "Unexpected args: %v", args)
|
||||
}
|
||||
if len(o.Raw) > 0 {
|
||||
if o.EditBeforeCreate {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw and --edit are mutually exclusive")
|
||||
}
|
||||
if len(o.FilenameOptions.Filenames) != 1 {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw can only use a single local file or stdin")
|
||||
}
|
||||
if strings.Index(o.FilenameOptions.Filenames[0], "http://") == 0 || strings.Index(o.FilenameOptions.Filenames[0], "https://") == 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw cannot read from a url")
|
||||
}
|
||||
if o.FilenameOptions.Recursive {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw and --recursive are mutually exclusive")
|
||||
}
|
||||
if len(o.Selector) > 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw and --selector (-l) are mutually exclusive")
|
||||
}
|
||||
if len(cmdutil.GetFlagString(cmd, "output")) > 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw and --output are mutually exclusive")
|
||||
}
|
||||
if _, err := url.ParseRequestURI(o.Raw); err != nil {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw must be a valid URL path: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *CreateOptions) RunCreate(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
// raw only makes sense for a single file resource multiple objects aren't likely to do what you want.
|
||||
// the validator enforces this, so
|
||||
if len(o.Raw) > 0 {
|
||||
return o.raw(f)
|
||||
}
|
||||
|
||||
if o.EditBeforeCreate {
|
||||
return RunEditOnCreate(f, o.Out, o.ErrOut, cmd, &o.FilenameOptions)
|
||||
}
|
||||
schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r := f.NewBuilder().
|
||||
Unstructured().
|
||||
Schema(schema).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||
LabelSelectorParam(o.Selector).
|
||||
Flatten().
|
||||
Do()
|
||||
err = r.Err()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dryRun := cmdutil.GetDryRunFlag(cmd)
|
||||
output := cmdutil.GetFlagString(cmd, "output")
|
||||
|
||||
count := 0
|
||||
err = r.Visit(func(info *resource.Info, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, cmdutil.InternalVersionJSONEncoder()); err != nil {
|
||||
return cmdutil.AddSourceToErr("creating", info.Source, err)
|
||||
}
|
||||
|
||||
if cmdutil.ShouldRecord(cmd, info) {
|
||||
if err := cmdutil.RecordChangeCause(info.Object, f.Command(cmd, false)); err != nil {
|
||||
return cmdutil.AddSourceToErr("creating", info.Source, err)
|
||||
}
|
||||
}
|
||||
|
||||
if !dryRun {
|
||||
if err := createAndRefresh(info); err != nil {
|
||||
return cmdutil.AddSourceToErr("creating", info.Source, err)
|
||||
}
|
||||
}
|
||||
|
||||
count++
|
||||
|
||||
shortOutput := output == "name"
|
||||
if len(output) > 0 && !shortOutput {
|
||||
return cmdutil.PrintObject(cmd, info.Object, o.Out)
|
||||
}
|
||||
|
||||
cmdutil.PrintSuccess(shortOutput, o.Out, info.Object, dryRun, "created")
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count == 0 {
|
||||
return fmt.Errorf("no objects passed to create")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// raw makes a simple HTTP request to the provided path on the server using the default
|
||||
// credentials.
|
||||
func (o *CreateOptions) raw(f cmdutil.Factory) error {
|
||||
restClient, err := f.RESTClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var data io.ReadCloser
|
||||
if o.FilenameOptions.Filenames[0] == "-" {
|
||||
data = os.Stdin
|
||||
} else {
|
||||
data, err = os.Open(o.FilenameOptions.Filenames[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// TODO post content with stream. Right now it ignores body content
|
||||
bytes, err := restClient.Post().RequestURI(o.Raw).Body(data).DoRaw()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintf(o.Out, "%v", string(bytes))
|
||||
return nil
|
||||
}
|
||||
|
||||
func RunEditOnCreate(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, options *resource.FilenameOptions) error {
|
||||
editOptions := &editor.EditOptions{
|
||||
EditMode: editor.EditBeforeCreateMode,
|
||||
FilenameOptions: *options,
|
||||
ValidateOptions: cmdutil.ValidateOptions{
|
||||
EnableValidation: cmdutil.GetFlagBool(cmd, "validate"),
|
||||
},
|
||||
Output: cmdutil.GetFlagString(cmd, "output"),
|
||||
WindowsLineEndings: cmdutil.GetFlagBool(cmd, "windows-line-endings"),
|
||||
ApplyAnnotation: cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag),
|
||||
Record: cmdutil.GetFlagBool(cmd, "record"),
|
||||
ChangeCause: f.Command(cmd, false),
|
||||
Include3rdParty: cmdutil.GetFlagBool(cmd, "include-extended-apis"),
|
||||
}
|
||||
err := editOptions.Complete(f, out, errOut, []string{}, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return editOptions.Run()
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info.Refresh(obj, true)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
return args[0], nil
|
||||
}
|
||||
|
||||
// CreateSubcommandOptions is an options struct to support create subcommands
|
||||
type CreateSubcommandOptions struct {
|
||||
// Name of resource being created
|
||||
Name string
|
||||
// StructuredGenerator is the resource generator for the object being created
|
||||
StructuredGenerator kubectl.StructuredGenerator
|
||||
// DryRun is true if the command should be simulated but not run against the server
|
||||
DryRun bool
|
||||
OutputFormat string
|
||||
}
|
||||
|
||||
// RunCreateSubcommand executes a create subcommand using the specified options
|
||||
func RunCreateSubcommand(f cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *CreateSubcommandOptions) error {
|
||||
namespace, nsOverriden, err := f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
obj, err := options.StructuredGenerator.StructuredGenerate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mapper, typer := f.Object()
|
||||
gvks, _, err := typer.ObjectKinds(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gvk := gvks[0]
|
||||
mapping, err := mapper.RESTMapping(schema.GroupKind{Group: gvk.Group, Kind: gvk.Kind}, gvk.Version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client, err := f.ClientForMapping(mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resourceMapper := &resource.Mapper{
|
||||
ObjectTyper: typer,
|
||||
RESTMapper: mapper,
|
||||
ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
|
||||
}
|
||||
info, err := resourceMapper.InfoForObject(obj, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, cmdutil.InternalVersionJSONEncoder()); err != nil {
|
||||
return err
|
||||
}
|
||||
obj = info.Object
|
||||
|
||||
if !options.DryRun {
|
||||
obj, err = resource.NewHelper(client, mapping).Create(namespace, false, info.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if meta, err := meta.Accessor(obj); err == nil && nsOverriden {
|
||||
meta.SetNamespace(namespace)
|
||||
}
|
||||
}
|
||||
|
||||
if useShortOutput := options.OutputFormat == "name"; useShortOutput || len(options.OutputFormat) == 0 {
|
||||
cmdutil.PrintSuccess(useShortOutput, out, info.Object, options.DryRun, "created")
|
||||
return nil
|
||||
}
|
||||
|
||||
return cmdutil.PrintObject(cmd, obj, out)
|
||||
}
|
117
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/create/BUILD
generated
vendored
Normal file
117
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/create/BUILD
generated
vendored
Normal file
@ -0,0 +1,117 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"create.go",
|
||||
"create_clusterrole.go",
|
||||
"create_clusterrolebinding.go",
|
||||
"create_configmap.go",
|
||||
"create_deployment.go",
|
||||
"create_job.go",
|
||||
"create_namespace.go",
|
||||
"create_pdb.go",
|
||||
"create_priorityclass.go",
|
||||
"create_quota.go",
|
||||
"create_role.go",
|
||||
"create_rolebinding.go",
|
||||
"create_secret.go",
|
||||
"create_service.go",
|
||||
"create_serviceaccount.go",
|
||||
],
|
||||
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/scheme:go_default_library",
|
||||
"//pkg/kubectl/util/i18n:go_default_library",
|
||||
"//pkg/printers:go_default_library",
|
||||
"//vendor/github.com/golang/glog: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",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"create_clusterrole_test.go",
|
||||
"create_clusterrolebinding_test.go",
|
||||
"create_configmap_test.go",
|
||||
"create_deployment_test.go",
|
||||
"create_job_test.go",
|
||||
"create_namespace_test.go",
|
||||
"create_pdb_test.go",
|
||||
"create_priorityclass_test.go",
|
||||
"create_quota_test.go",
|
||||
"create_role_test.go",
|
||||
"create_rolebinding_test.go",
|
||||
"create_secret_test.go",
|
||||
"create_service_test.go",
|
||||
"create_serviceaccount_test.go",
|
||||
"create_test.go",
|
||||
],
|
||||
data = [
|
||||
"//test/e2e/testing-manifests:all-srcs",
|
||||
],
|
||||
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/scheme: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",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
451
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/create/create.go
generated
vendored
Normal file
451
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/create/create.go
generated
vendored
Normal file
@ -0,0 +1,451 @@
|
||||
/*
|
||||
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 create
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
kruntime "k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"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/util/i18n"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
type CreateOptions struct {
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
RecordFlags *genericclioptions.RecordFlags
|
||||
|
||||
DryRun bool
|
||||
|
||||
FilenameOptions resource.FilenameOptions
|
||||
Selector string
|
||||
EditBeforeCreate bool
|
||||
Raw string
|
||||
|
||||
Recorder genericclioptions.Recorder
|
||||
PrintObj func(obj kruntime.Object) error
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
var (
|
||||
createLong = templates.LongDesc(i18n.T(`
|
||||
Create a resource from a file or from stdin.
|
||||
|
||||
JSON and YAML formats are accepted.`))
|
||||
|
||||
createExample = templates.Examples(i18n.T(`
|
||||
# Create a pod using the data in pod.json.
|
||||
kubectl create -f ./pod.json
|
||||
|
||||
# Create a pod based on the JSON passed into stdin.
|
||||
cat pod.json | kubectl create -f -
|
||||
|
||||
# Edit the data in docker-registry.yaml in JSON then create the resource using the edited data.
|
||||
kubectl create -f docker-registry.yaml --edit -o json`))
|
||||
)
|
||||
|
||||
func NewCreateOptions(ioStreams genericclioptions.IOStreams) *CreateOptions {
|
||||
return &CreateOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
|
||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||
|
||||
Recorder: genericclioptions.NoopRecorder{},
|
||||
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdCreate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewCreateOptions(ioStreams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "create -f FILENAME",
|
||||
DisableFlagsInUseLine: true,
|
||||
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)
|
||||
defaultRunFunc(cmd, args)
|
||||
return
|
||||
}
|
||||
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||
cmdutil.CheckErr(o.ValidateArgs(cmd, args))
|
||||
cmdutil.CheckErr(o.RunCreate(f, cmd))
|
||||
},
|
||||
}
|
||||
|
||||
// bind flag structs
|
||||
o.RecordFlags.AddFlags(cmd)
|
||||
|
||||
usage := "to use to create the resource"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
|
||||
cmd.MarkFlagRequired("filename")
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmd.Flags().BoolVar(&o.EditBeforeCreate, "edit", o.EditBeforeCreate, "Edit the API resource before creating")
|
||||
cmd.Flags().Bool("windows-line-endings", runtime.GOOS == "windows",
|
||||
"Only relevant if --edit=true. Defaults to the line ending native to your platform.")
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
cmd.Flags().StringVarP(&o.Selector, "selector", "l", o.Selector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
|
||||
cmd.Flags().StringVar(&o.Raw, "raw", o.Raw, "Raw URI to POST to the server. Uses the transport specified by the kubeconfig file.")
|
||||
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
// create subcommands
|
||||
cmd.AddCommand(NewCmdCreateNamespace(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateQuota(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateSecret(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateConfigMap(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateServiceAccount(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateService(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateDeployment(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateClusterRole(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateClusterRoleBinding(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateRole(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateRoleBinding(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreatePodDisruptionBudget(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreatePriorityClass(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateJob(f, ioStreams))
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o *CreateOptions) ValidateArgs(cmd *cobra.Command, args []string) error {
|
||||
if len(args) != 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "Unexpected args: %v", args)
|
||||
}
|
||||
if len(o.Raw) > 0 {
|
||||
if o.EditBeforeCreate {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw and --edit are mutually exclusive")
|
||||
}
|
||||
if len(o.FilenameOptions.Filenames) != 1 {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw can only use a single local file or stdin")
|
||||
}
|
||||
if strings.Index(o.FilenameOptions.Filenames[0], "http://") == 0 || strings.Index(o.FilenameOptions.Filenames[0], "https://") == 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw cannot read from a url")
|
||||
}
|
||||
if o.FilenameOptions.Recursive {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw and --recursive are mutually exclusive")
|
||||
}
|
||||
if len(o.Selector) > 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw and --selector (-l) are mutually exclusive")
|
||||
}
|
||||
if len(cmdutil.GetFlagString(cmd, "output")) > 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw and --output are mutually exclusive")
|
||||
}
|
||||
if _, err := url.ParseRequestURI(o.Raw); err != nil {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw must be a valid URL path: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *CreateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
var err error
|
||||
|
||||
o.RecordFlags.Complete(cmd)
|
||||
o.Recorder, err = o.RecordFlags.ToRecorder()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.DryRun = cmdutil.GetDryRunFlag(cmd)
|
||||
|
||||
if o.DryRun {
|
||||
o.PrintFlags.Complete("%s (dry run)")
|
||||
}
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.PrintObj = func(obj kruntime.Object) error {
|
||||
return printer.PrintObj(obj, o.Out)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *CreateOptions) RunCreate(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
// raw only makes sense for a single file resource multiple objects aren't likely to do what you want.
|
||||
// the validator enforces this, so
|
||||
if len(o.Raw) > 0 {
|
||||
return o.raw(f)
|
||||
}
|
||||
|
||||
if o.EditBeforeCreate {
|
||||
return RunEditOnCreate(f, o.RecordFlags, o.IOStreams, cmd, &o.FilenameOptions)
|
||||
}
|
||||
schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmdNamespace, enforceNamespace, err := f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r := f.NewBuilder().
|
||||
Unstructured().
|
||||
Schema(schema).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||
LabelSelectorParam(o.Selector).
|
||||
Flatten().
|
||||
Do()
|
||||
err = r.Err()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
count := 0
|
||||
err = r.Visit(func(info *resource.Info, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info.Object, cmdutil.InternalVersionJSONEncoder()); 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)
|
||||
}
|
||||
|
||||
if !o.DryRun {
|
||||
if err := createAndRefresh(info); err != nil {
|
||||
return cmdutil.AddSourceToErr("creating", info.Source, err)
|
||||
}
|
||||
}
|
||||
|
||||
count++
|
||||
|
||||
return o.PrintObj(info.Object)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count == 0 {
|
||||
return fmt.Errorf("no objects passed to create")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// raw makes a simple HTTP request to the provided path on the server using the default
|
||||
// credentials.
|
||||
func (o *CreateOptions) raw(f cmdutil.Factory) error {
|
||||
restClient, err := f.RESTClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var data io.ReadCloser
|
||||
if o.FilenameOptions.Filenames[0] == "-" {
|
||||
data = os.Stdin
|
||||
} else {
|
||||
data, err = os.Open(o.FilenameOptions.Filenames[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// TODO post content with stream. Right now it ignores body content
|
||||
result := restClient.Post().RequestURI(o.Raw).Body(data).Do()
|
||||
if err := result.Error(); err != nil {
|
||||
return err
|
||||
}
|
||||
body, err := result.Raw()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintf(o.Out, "%v", string(body))
|
||||
return nil
|
||||
}
|
||||
|
||||
func RunEditOnCreate(f cmdutil.Factory, 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.ApplyAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag)
|
||||
editOptions.RecordFlags = recordFlags
|
||||
|
||||
err := editOptions.Complete(f, []string{}, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return editOptions.Run()
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info.Refresh(obj, true)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
return args[0], nil
|
||||
}
|
||||
|
||||
// CreateSubcommandOptions is an options struct to support create subcommands
|
||||
type CreateSubcommandOptions struct {
|
||||
// PrintFlags holds options necessary for obtaining a printer
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
// Name of resource being created
|
||||
Name string
|
||||
// StructuredGenerator is the resource generator for the object being created
|
||||
StructuredGenerator kubectl.StructuredGenerator
|
||||
// DryRun is true if the command should be simulated but not run against the server
|
||||
DryRun bool
|
||||
CreateAnnotation bool
|
||||
|
||||
Namespace string
|
||||
EnforceNamespace bool
|
||||
|
||||
Mapper meta.RESTMapper
|
||||
DynamicClient dynamic.Interface
|
||||
|
||||
PrintObj printers.ResourcePrinterFunc
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
func NewCreateSubcommandOptions(ioStreams genericclioptions.IOStreams) *CreateSubcommandOptions {
|
||||
return &CreateSubcommandOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *CreateSubcommandOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string, generator kubectl.StructuredGenerator) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.Name = name
|
||||
o.StructuredGenerator = generator
|
||||
o.DryRun = cmdutil.GetDryRunFlag(cmd)
|
||||
o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag)
|
||||
|
||||
if o.DryRun {
|
||||
o.PrintFlags.Complete("%s (dry run)")
|
||||
}
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.PrintObj = func(obj kruntime.Object, out io.Writer) error {
|
||||
return printer.PrintObj(obj, out)
|
||||
}
|
||||
|
||||
o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.DynamicClient, err = f.DynamicClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.Mapper, err = f.ToRESTMapper()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RunCreateSubcommand executes a create subcommand using the specified options
|
||||
func (o *CreateSubcommandOptions) Run() error {
|
||||
obj, err := o.StructuredGenerator.StructuredGenerate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !o.DryRun {
|
||||
// create subcommands have compiled knowledge of things they create, so type them directly
|
||||
gvks, _, err := legacyscheme.Scheme.ObjectKinds(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gvk := gvks[0]
|
||||
mapping, err := o.Mapper.RESTMapping(schema.GroupKind{Group: gvk.Group, Kind: gvk.Kind}, gvk.Version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := kubectl.CreateOrUpdateAnnotation(o.CreateAnnotation, obj, cmdutil.InternalVersionJSONEncoder()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
asUnstructured := &unstructured.Unstructured{}
|
||||
|
||||
if err := legacyscheme.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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// ensure we pass a versioned object to the printer
|
||||
obj = actualObject
|
||||
} else {
|
||||
if meta, err := meta.Accessor(obj); err == nil && o.EnforceNamespace {
|
||||
meta.SetNamespace(o.Namespace)
|
||||
}
|
||||
}
|
||||
|
||||
return o.PrintObj(obj, o.Out)
|
||||
}
|
@ -14,18 +14,20 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
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"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
@ -38,7 +40,7 @@ var (
|
||||
kubectl create clusterrole pod-reader --verb=get,list,watch --resource=pods
|
||||
|
||||
# Create a ClusterRole named "pod-reader" with ResourceName specified
|
||||
kubectl create clusterrole pod-reader --verb=get,list,watch --resource=pods --resource-name=readablepod --resource-name=anotherpod
|
||||
kubectl create clusterrole pod-reader --verb=get --resource=pods --resource-name=readablepod --resource-name=anotherpod
|
||||
|
||||
# Create a ClusterRole named "foo" with API Group specified
|
||||
kubectl create clusterrole foo --verb=get,list,watch --resource=rs.extensions
|
||||
@ -47,7 +49,10 @@ var (
|
||||
kubectl create clusterrole foo --verb=get,list,watch --resource=pods,pods/status
|
||||
|
||||
# Create a ClusterRole name "foo" with NonResourceURL specified
|
||||
kubectl create clusterrole "foo" --verb=get --non-resource-url=/logs/*`))
|
||||
kubectl create clusterrole "foo" --verb=get --non-resource-url=/logs/*
|
||||
|
||||
# Create a ClusterRole name "monitoring" with AggregationRule specified
|
||||
kubectl create clusterrole monitoring --aggregation-rule="rbac.example.com/aggregate-to-monitoring=true"`))
|
||||
|
||||
// Valid nonResource verb list for validation.
|
||||
validNonResourceVerbs = []string{"*", "get", "post", "put", "delete", "patch", "head", "options"}
|
||||
@ -56,14 +61,14 @@ var (
|
||||
type CreateClusterRoleOptions struct {
|
||||
*CreateRoleOptions
|
||||
NonResourceURLs []string
|
||||
AggregationRule map[string]string
|
||||
}
|
||||
|
||||
// ClusterRole is a command to ease creating ClusterRoles.
|
||||
func NewCmdCreateClusterRole(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateClusterRole(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
c := &CreateClusterRoleOptions{
|
||||
CreateRoleOptions: &CreateRoleOptions{
|
||||
Out: cmdOut,
|
||||
},
|
||||
CreateRoleOptions: NewCreateRoleOptions(ioStreams),
|
||||
AggregationRule: map[string]string{},
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "clusterrole NAME --verb=verb --resource=resource.group [--resource-name=resourcename] [--dry-run]",
|
||||
@ -77,14 +82,17 @@ func NewCmdCreateClusterRole(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command
|
||||
cmdutil.CheckErr(c.RunCreateRole())
|
||||
},
|
||||
}
|
||||
|
||||
c.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
cmd.Flags().StringSliceVar(&c.Verbs, "verb", []string{}, "Verb that applies to the resources contained in the rule")
|
||||
cmd.Flags().StringSliceVar(&c.NonResourceURLs, "non-resource-url", []string{}, "A partial url that user should have access to.")
|
||||
cmd.Flags().StringSliceVar(&c.Verbs, "verb", c.Verbs, "Verb that applies to the resources contained in the rule")
|
||||
cmd.Flags().StringSliceVar(&c.NonResourceURLs, "non-resource-url", c.NonResourceURLs, "A partial url that user should have access to.")
|
||||
cmd.Flags().StringSlice("resource", []string{}, "Resource that the rule applies to")
|
||||
cmd.Flags().StringArrayVar(&c.ResourceNames, "resource-name", []string{}, "Resource in the white list that the rule applies to, repeat this flag for multiple items")
|
||||
cmd.Flags().StringArrayVar(&c.ResourceNames, "resource-name", c.ResourceNames, "Resource in the white list that the rule applies to, repeat this flag for multiple items")
|
||||
cmd.Flags().Var(utilflag.NewMapStringString(&c.AggregationRule), "aggregation-rule", "An aggregation label selector for combining ClusterRoles.")
|
||||
|
||||
return cmd
|
||||
}
|
||||
@ -107,6 +115,13 @@ func (c *CreateClusterRoleOptions) Validate() error {
|
||||
return fmt.Errorf("name must be specified")
|
||||
}
|
||||
|
||||
if len(c.AggregationRule) > 0 {
|
||||
if len(c.NonResourceURLs) > 0 || len(c.Verbs) > 0 || len(c.Resources) > 0 || len(c.ResourceNames) > 0 {
|
||||
return fmt.Errorf("aggregation rule must be specified without nonResourceURLs, verbs, resources or resourceNames")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validate verbs.
|
||||
if len(c.Verbs) == 0 {
|
||||
return fmt.Errorf("at least one verb must be specified")
|
||||
@ -156,26 +171,36 @@ func (c *CreateClusterRoleOptions) Validate() error {
|
||||
}
|
||||
|
||||
func (c *CreateClusterRoleOptions) RunCreateRole() error {
|
||||
clusterRole := &rbacv1.ClusterRole{}
|
||||
clusterRole.Name = c.Name
|
||||
rules, err := generateResourcePolicyRules(c.Mapper, c.Verbs, c.Resources, c.ResourceNames, c.NonResourceURLs)
|
||||
if err != nil {
|
||||
return err
|
||||
clusterRole := &rbacv1.ClusterRole{
|
||||
// this is ok because we know exactly how we want to be serialized
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: rbacv1.SchemeGroupVersion.String(), Kind: "ClusterRole"},
|
||||
}
|
||||
clusterRole.Name = c.Name
|
||||
|
||||
var err error
|
||||
if len(c.AggregationRule) == 0 {
|
||||
rules, err := generateResourcePolicyRules(c.Mapper, c.Verbs, c.Resources, c.ResourceNames, c.NonResourceURLs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
clusterRole.Rules = rules
|
||||
} else {
|
||||
clusterRole.AggregationRule = &rbacv1.AggregationRule{
|
||||
ClusterRoleSelectors: []metav1.LabelSelector{
|
||||
{
|
||||
MatchLabels: c.AggregationRule,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
clusterRole.Rules = rules
|
||||
|
||||
// Create ClusterRole.
|
||||
if !c.DryRun {
|
||||
_, err = c.Client.ClusterRoles().Create(clusterRole)
|
||||
clusterRole, err = c.Client.ClusterRoles().Create(clusterRole)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if useShortOutput := c.OutputFormat == "name"; useShortOutput || len(c.OutputFormat) == 0 {
|
||||
cmdutil.PrintSuccess(useShortOutput, c.Out, clusterRole, c.DryRun, "created")
|
||||
return nil
|
||||
}
|
||||
|
||||
return c.PrintObject(clusterRole)
|
||||
return c.PrintObj(clusterRole)
|
||||
}
|
@ -14,26 +14,31 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/api/equality"
|
||||
"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/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 TestCreateClusterRole(t *testing.T) {
|
||||
clusterRoleName := "my-cluster-role"
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf.Namespace = "test"
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.Client = &fake.RESTClient{}
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
@ -42,12 +47,14 @@ func TestCreateClusterRole(t *testing.T) {
|
||||
resources string
|
||||
nonResourceURL string
|
||||
resourceNames string
|
||||
aggregationRule string
|
||||
expectedClusterRole *rbac.ClusterRole
|
||||
}{
|
||||
"test-duplicate-resources": {
|
||||
verbs: "get,watch,list",
|
||||
resources: "pods,pods",
|
||||
expectedClusterRole: &rbac.ClusterRole{
|
||||
TypeMeta: v1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "ClusterRole"},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: clusterRoleName,
|
||||
},
|
||||
@ -65,6 +72,7 @@ func TestCreateClusterRole(t *testing.T) {
|
||||
verbs: "get,watch,list",
|
||||
resources: "pods,deployments.extensions",
|
||||
expectedClusterRole: &rbac.ClusterRole{
|
||||
TypeMeta: v1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "ClusterRole"},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: clusterRoleName,
|
||||
},
|
||||
@ -88,6 +96,7 @@ func TestCreateClusterRole(t *testing.T) {
|
||||
verbs: "get",
|
||||
nonResourceURL: "/logs/,/healthz",
|
||||
expectedClusterRole: &rbac.ClusterRole{
|
||||
TypeMeta: v1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "ClusterRole"},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: clusterRoleName,
|
||||
},
|
||||
@ -104,6 +113,7 @@ func TestCreateClusterRole(t *testing.T) {
|
||||
nonResourceURL: "/logs/,/healthz",
|
||||
resources: "pods",
|
||||
expectedClusterRole: &rbac.ClusterRole{
|
||||
TypeMeta: v1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "ClusterRole"},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: clusterRoleName,
|
||||
},
|
||||
@ -121,16 +131,36 @@ func TestCreateClusterRole(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
"test-aggregation-rules": {
|
||||
aggregationRule: "foo1=foo2,foo3=foo4",
|
||||
expectedClusterRole: &rbac.ClusterRole{
|
||||
TypeMeta: v1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "ClusterRole"},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: clusterRoleName,
|
||||
},
|
||||
AggregationRule: &rbac.AggregationRule{
|
||||
ClusterRoleSelectors: []metav1.LabelSelector{
|
||||
{
|
||||
MatchLabels: map[string]string{
|
||||
"foo1": "foo2",
|
||||
"foo3": "foo4",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateClusterRole(tf, buf)
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateClusterRole(tf, ioStreams)
|
||||
cmd.Flags().Set("dry-run", "true")
|
||||
cmd.Flags().Set("output", "yaml")
|
||||
cmd.Flags().Set("verb", test.verbs)
|
||||
cmd.Flags().Set("resource", test.resources)
|
||||
cmd.Flags().Set("non-resource-url", test.nonResourceURL)
|
||||
cmd.Flags().Set("aggregation-rule", test.aggregationRule)
|
||||
if test.resourceNames != "" {
|
||||
cmd.Flags().Set("resource-name", test.resourceNames)
|
||||
}
|
||||
@ -147,8 +177,8 @@ func TestCreateClusterRole(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestClusterRoleValidate(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf.Namespace = "test"
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tests := map[string]struct {
|
||||
clusterRoleOptions *CreateClusterRoleOptions
|
||||
@ -422,12 +452,60 @@ func TestClusterRoleValidate(t *testing.T) {
|
||||
},
|
||||
expectErr: false,
|
||||
},
|
||||
"test-aggregation-rule-with-verb": {
|
||||
clusterRoleOptions: &CreateClusterRoleOptions{
|
||||
CreateRoleOptions: &CreateRoleOptions{
|
||||
Name: "my-clusterrole",
|
||||
Verbs: []string{"get"},
|
||||
},
|
||||
AggregationRule: map[string]string{"foo-key": "foo-vlue"},
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
"test-aggregation-rule-with-resource": {
|
||||
clusterRoleOptions: &CreateClusterRoleOptions{
|
||||
CreateRoleOptions: &CreateRoleOptions{
|
||||
Name: "my-clusterrole",
|
||||
Resources: []ResourceOptions{
|
||||
{
|
||||
Resource: "replicasets",
|
||||
SubResource: "scale",
|
||||
},
|
||||
},
|
||||
},
|
||||
AggregationRule: map[string]string{"foo-key": "foo-vlue"},
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
"test-aggregation-rule-with-no-resource-url": {
|
||||
clusterRoleOptions: &CreateClusterRoleOptions{
|
||||
CreateRoleOptions: &CreateRoleOptions{
|
||||
Name: "my-clusterrole",
|
||||
},
|
||||
NonResourceURLs: []string{"/logs/"},
|
||||
AggregationRule: map[string]string{"foo-key": "foo-vlue"},
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
"test-aggregation-rule": {
|
||||
clusterRoleOptions: &CreateClusterRoleOptions{
|
||||
CreateRoleOptions: &CreateRoleOptions{
|
||||
Name: "my-clusterrole",
|
||||
},
|
||||
AggregationRule: map[string]string{"foo-key": "foo-vlue"},
|
||||
},
|
||||
expectErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
test.clusterRoleOptions.Mapper, _ = tf.Object()
|
||||
err := test.clusterRoleOptions.Validate()
|
||||
var err error
|
||||
test.clusterRoleOptions.Mapper, err = tf.ToRESTMapper()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = test.clusterRoleOptions.Validate()
|
||||
if test.expectErr && err == nil {
|
||||
t.Errorf("%s: expect error happens, but validate passes.", name)
|
||||
}
|
||||
@ -437,3 +515,14 @@ 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"},
|
||||
},
|
||||
}
|
||||
}
|
@ -14,16 +14,15 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"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/util/i18n"
|
||||
)
|
||||
|
||||
@ -36,8 +35,16 @@ var (
|
||||
kubectl create clusterrolebinding cluster-admin --clusterrole=cluster-admin --user=user1 --user=user2 --group=group1`))
|
||||
)
|
||||
|
||||
type ClusterRoleBindingOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// ClusterRoleBinding is a command to ease creating ClusterRoleBindings.
|
||||
func NewCmdCreateClusterRoleBinding(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateClusterRoleBinding(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &ClusterRoleBindingOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "clusterrolebinding NAME --clusterrole=NAME [--user=username] [--group=groupname] [--serviceaccount=namespace:serviceaccountname] [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -45,13 +52,15 @@ func NewCmdCreateClusterRoleBinding(f cmdutil.Factory, cmdOut io.Writer) *cobra.
|
||||
Long: clusterRoleBindingLong,
|
||||
Example: clusterRoleBindingExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateClusterRoleBinding(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.ClusterRoleBindingV1GeneratorName)
|
||||
cmd.Flags().String("clusterrole", "", i18n.T("ClusterRole this ClusterRoleBinding should reference"))
|
||||
cmd.MarkFlagCustom("clusterrole", "__kubectl_get_resource_clusterrole")
|
||||
@ -61,12 +70,12 @@ func NewCmdCreateClusterRoleBinding(f cmdutil.Factory, cmdOut io.Writer) *cobra.
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CreateClusterRoleBinding is the implementation of the create clusterrolebinding command.
|
||||
func CreateClusterRoleBinding(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *ClusterRoleBindingOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.ClusterRoleBindingV1GeneratorName:
|
||||
@ -80,10 +89,11 @@ func CreateClusterRoleBinding(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Co
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreateClusterRoleBinding is the implementation of the create clusterrolebinding command.
|
||||
func (o *ClusterRoleBindingOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -32,6 +32,7 @@ import (
|
||||
"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"
|
||||
)
|
||||
|
||||
func TestCreateClusterRoleBinding(t *testing.T) {
|
||||
@ -67,14 +68,15 @@ func TestCreateClusterRoleBinding(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
info, _ := runtime.SerializerInfoForMediaType(ns.SupportedMediaTypes(), runtime.ContentTypeJSON)
|
||||
encoder := ns.EncoderForVersion(info.Serializer, groupVersion)
|
||||
decoder := ns.DecoderToVersion(info.Serializer, groupVersion)
|
||||
|
||||
tf.Namespace = "test"
|
||||
tf.Client = &ClusterRoleBindingRESTClient{
|
||||
RESTClient: &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
@ -109,8 +111,8 @@ func TestCreateClusterRoleBinding(t *testing.T) {
|
||||
}
|
||||
|
||||
expectedOutput := "clusterrolebinding.rbac.authorization.k8s.io/" + expectBinding.Name + "\n"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateClusterRoleBinding(tf, buf)
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateClusterRoleBinding(tf, ioStreams)
|
||||
cmd.Flags().Set("clusterrole", "fake-clusterrole")
|
||||
cmd.Flags().Set("user", "fake-user")
|
||||
cmd.Flags().Set("group", "fake-group")
|
||||
@ -143,3 +145,9 @@ 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
|
||||
}
|
@ -14,16 +14,15 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"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/util/i18n"
|
||||
)
|
||||
|
||||
@ -57,8 +56,16 @@ var (
|
||||
kubectl create configmap my-config --from-env-file=path/to/bar.env`))
|
||||
)
|
||||
|
||||
type ConfigMapOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// ConfigMap is a command to ease creating ConfigMaps.
|
||||
func NewCmdCreateConfigMap(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateConfigMap(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &ConfigMapOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "configmap NAME [--from-file=[key=]source] [--from-literal=key1=value1] [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -67,13 +74,15 @@ func NewCmdCreateConfigMap(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
Long: configMapLong,
|
||||
Example: configMapExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateConfigMap(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.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)")
|
||||
@ -82,12 +91,12 @@ func NewCmdCreateConfigMap(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CreateConfigMap is the implementation of the create configmap command.
|
||||
func CreateConfigMap(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *ConfigMapOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.ConfigMapV1GeneratorName:
|
||||
@ -101,10 +110,11 @@ func CreateConfigMap(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, ar
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreateConfigMap is the implementation of the create configmap command.
|
||||
func (o *ConfigMapOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
@ -14,26 +14,32 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
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/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 TestCreateConfigMap(t *testing.T) {
|
||||
configMap := &v1.ConfigMap{}
|
||||
configMap.Name = "my-configmap"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
@ -49,9 +55,8 @@ func TestCreateConfigMap(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateConfigMap(tf, buf)
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateConfigMap(tf, ioStreams)
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{configMap.Name})
|
||||
expectedOutput := "configmap/" + configMap.Name + "\n"
|
||||
@ -59,3 +64,7 @@ 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))))
|
||||
}
|
@ -14,16 +14,15 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"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/util/i18n"
|
||||
)
|
||||
|
||||
@ -36,10 +35,18 @@ var (
|
||||
kubectl create deployment my-dep --image=busybox`))
|
||||
)
|
||||
|
||||
type DeploymentOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreateDeployment is a macro command to create a new deployment.
|
||||
// This command is better known to users as `kubectl create deployment`.
|
||||
// Note that this command overlaps significantly with the `kubectl run` command.
|
||||
func NewCmdCreateDeployment(f cmdutil.Factory, cmdOut, cmdErr io.Writer) *cobra.Command {
|
||||
func NewCmdCreateDeployment(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &DeploymentOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "deployment NAME --image=image [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -48,14 +55,16 @@ func NewCmdCreateDeployment(f cmdutil.Factory, cmdOut, cmdErr io.Writer) *cobra.
|
||||
Long: deploymentLong,
|
||||
Example: deploymentExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := createDeployment(f, cmdOut, cmdErr, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.DeploymentBasicV1Beta1GeneratorName)
|
||||
cmdutil.AddGeneratorFlags(cmd, "")
|
||||
cmd.Flags().StringSlice("image", []string{}, "Image name to run.")
|
||||
cmd.MarkFlagRequired("image")
|
||||
return cmd
|
||||
@ -71,7 +80,7 @@ func generatorFromName(
|
||||
) (kubectl.StructuredGenerator, bool) {
|
||||
|
||||
switch generatorName {
|
||||
case cmdutil.DeploymentBasicAppsV1Beta1GeneratorName:
|
||||
case cmdutil.DeploymentBasicAppsV1GeneratorName:
|
||||
generator := &kubectl.DeploymentBasicAppsGeneratorV1{
|
||||
BaseDeploymentGenerator: kubectl.BaseDeploymentGenerator{
|
||||
Name: deploymentName,
|
||||
@ -80,6 +89,15 @@ func generatorFromName(
|
||||
}
|
||||
return generator, true
|
||||
|
||||
case cmdutil.DeploymentBasicAppsV1Beta1GeneratorName:
|
||||
generator := &kubectl.DeploymentBasicAppsGeneratorV1Beta1{
|
||||
BaseDeploymentGenerator: kubectl.BaseDeploymentGenerator{
|
||||
Name: deploymentName,
|
||||
Images: imageNames,
|
||||
},
|
||||
}
|
||||
return generator, true
|
||||
|
||||
case cmdutil.DeploymentBasicV1Beta1GeneratorName:
|
||||
generator := &kubectl.DeploymentBasicGeneratorV1{
|
||||
BaseDeploymentGenerator: kubectl.BaseDeploymentGenerator{
|
||||
@ -93,14 +111,8 @@ func generatorFromName(
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// createDeployment
|
||||
// 1. Reads user config values from Cobra.
|
||||
// 2. Sets up the correct Generator object.
|
||||
// 3. Calls RunCreateSubcommand.
|
||||
func createDeployment(f cmdutil.Factory, cmdOut, cmdErr io.Writer,
|
||||
cmd *cobra.Command, args []string) error {
|
||||
|
||||
deploymentName, err := NameFromCommandArgs(cmd, args)
|
||||
func (o *DeploymentOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -112,23 +124,32 @@ func createDeployment(f cmdutil.Factory, cmdOut, cmdErr io.Writer,
|
||||
|
||||
generatorName := cmdutil.GetFlagString(cmd, "generator")
|
||||
|
||||
// It is possible we have to modify the user-provided generator name if
|
||||
// the server does not have support for the requested generator.
|
||||
generatorName, err = cmdutil.FallbackGeneratorNameIfNecessary(generatorName, clientset.Discovery(), cmdErr)
|
||||
if err != nil {
|
||||
return err
|
||||
if len(generatorName) == 0 {
|
||||
generatorName = cmdutil.DeploymentBasicAppsV1GeneratorName
|
||||
generatorNameTemp, err := cmdutil.FallbackGeneratorNameIfNecessary(generatorName, clientset.Discovery(), o.CreateSubcommandOptions.ErrOut)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if generatorNameTemp != generatorName {
|
||||
cmdutil.Warning(o.CreateSubcommandOptions.ErrOut, generatorName, generatorNameTemp)
|
||||
} else {
|
||||
generatorName = generatorNameTemp
|
||||
}
|
||||
}
|
||||
|
||||
imageNames := cmdutil.GetFlagStringSlice(cmd, "image")
|
||||
generator, ok := generatorFromName(generatorName, imageNames, deploymentName)
|
||||
generator, ok := generatorFromName(generatorName, imageNames, name)
|
||||
if !ok {
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: deploymentName,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// createDeployment
|
||||
// 1. Reads user config values from Cobra.
|
||||
// 2. Sets up the correct Generator object.
|
||||
// 3. Calls RunCreateSubcommand.
|
||||
func (o *DeploymentOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -30,14 +30,16 @@ import (
|
||||
"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"
|
||||
)
|
||||
|
||||
func Test_generatorFromName(t *testing.T) {
|
||||
const (
|
||||
nonsenseName = "not-a-real-generator-name"
|
||||
basicName = cmdutil.DeploymentBasicV1Beta1GeneratorName
|
||||
basicAppsName = cmdutil.DeploymentBasicAppsV1Beta1GeneratorName
|
||||
deploymentName = "deployment-name"
|
||||
nonsenseName = "not-a-real-generator-name"
|
||||
basicName = cmdutil.DeploymentBasicV1Beta1GeneratorName
|
||||
basicAppsV1Beta1Name = cmdutil.DeploymentBasicAppsV1Beta1GeneratorName
|
||||
basicAppsV1Name = cmdutil.DeploymentBasicAppsV1GeneratorName
|
||||
deploymentName = "deployment-name"
|
||||
)
|
||||
imageNames := []string{"image-1", "image-2"}
|
||||
|
||||
@ -58,7 +60,20 @@ func Test_generatorFromName(t *testing.T) {
|
||||
assert.Equal(t, expectedGenerator, generator)
|
||||
}
|
||||
|
||||
generator, ok = generatorFromName(basicAppsName, imageNames, deploymentName)
|
||||
generator, ok = generatorFromName(basicAppsV1Beta1Name, imageNames, deploymentName)
|
||||
assert.True(t, ok)
|
||||
|
||||
{
|
||||
expectedGenerator := &kubectl.DeploymentBasicAppsGeneratorV1Beta1{
|
||||
BaseDeploymentGenerator: kubectl.BaseDeploymentGenerator{
|
||||
Name: deploymentName,
|
||||
Images: imageNames,
|
||||
},
|
||||
}
|
||||
assert.Equal(t, expectedGenerator, generator)
|
||||
}
|
||||
|
||||
generator, ok = generatorFromName(basicAppsV1Name, imageNames, deploymentName)
|
||||
assert.True(t, ok)
|
||||
|
||||
{
|
||||
@ -74,28 +89,29 @@ func Test_generatorFromName(t *testing.T) {
|
||||
|
||||
func TestCreateDeployment(t *testing.T) {
|
||||
depName := "jonny-dep"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
ns := legacyscheme.Codecs
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
ns := legacyscheme.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,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: ioutil.NopCloser(bytes.NewBuffer([]byte("{}"))),
|
||||
Body: ioutil.NopCloser(bytes.NewBuffer([]byte(fakeDiscovery))),
|
||||
}, nil
|
||||
}),
|
||||
}
|
||||
tf.ClientConfigVal = &restclient.Config{}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdCreateDeployment(tf, buf, buf)
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateDeployment(tf, ioStreams)
|
||||
cmd.Flags().Set("dry-run", "true")
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Flags().Set("image", "hollywood/jonny.depp:v2")
|
||||
cmd.Run(cmd, []string{depName})
|
||||
expectedOutput := "deployment.extensions/" + depName + "\n"
|
||||
expectedOutput := "deployment.apps/" + depName + "\n"
|
||||
if buf.String() != expectedOutput {
|
||||
t.Errorf("expected output: %s, but got: %s", expectedOutput, buf.String())
|
||||
}
|
||||
@ -103,25 +119,38 @@ func TestCreateDeployment(t *testing.T) {
|
||||
|
||||
func TestCreateDeploymentNoImage(t *testing.T) {
|
||||
depName := "jonny-dep"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
ns := legacyscheme.Codecs
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
ns := legacyscheme.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,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: ioutil.NopCloser(&bytes.Buffer{}),
|
||||
Body: ioutil.NopCloser(bytes.NewBuffer([]byte(fakeDiscovery))),
|
||||
}, nil
|
||||
}),
|
||||
}
|
||||
tf.ClientConfigVal = &restclient.Config{}
|
||||
tf.Namespace = "test"
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateDeployment(tf, buf, buf)
|
||||
cmd.Flags().Set("dry-run", "true")
|
||||
ioStreams := genericclioptions.NewTestIOStreamsDiscard()
|
||||
cmd := NewCmdCreateDeployment(tf, ioStreams)
|
||||
cmd.Flags().Set("output", "name")
|
||||
err := createDeployment(tf, buf, buf, cmd, []string{depName})
|
||||
options := &DeploymentOpts{
|
||||
CreateSubcommandOptions: &CreateSubcommandOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
|
||||
DryRun: true,
|
||||
IOStreams: ioStreams,
|
||||
},
|
||||
}
|
||||
|
||||
err := options.Complete(tf, cmd, []string{depName})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
err = options.Run()
|
||||
assert.Error(t, err, "at least one image must be specified")
|
||||
}
|
186
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/create/create_job.go
generated
vendored
Normal file
186
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/create/create_job.go
generated
vendored
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
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 create
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
batchv1beta1 "k8s.io/api/batch/v1beta1"
|
||||
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"
|
||||
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"
|
||||
)
|
||||
|
||||
var (
|
||||
jobLong = templates.LongDesc(i18n.T(`
|
||||
Create a job with the specified name.`))
|
||||
|
||||
jobExample = templates.Examples(i18n.T(`
|
||||
# Create a job from a CronJob named "a-cronjob"
|
||||
kubectl create job test-job --from=cronjob/a-cronjob`))
|
||||
)
|
||||
|
||||
type CreateJobOptions struct {
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
|
||||
PrintObj func(obj runtime.Object) error
|
||||
|
||||
Name string
|
||||
From string
|
||||
|
||||
Namespace string
|
||||
OutputFormat string
|
||||
Client clientbatchv1.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),
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
// 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]",
|
||||
Short: jobLong,
|
||||
Long: jobLong,
|
||||
Example: jobExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(o.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(o.RunCreateJob())
|
||||
},
|
||||
}
|
||||
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
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")
|
||||
}
|
||||
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")
|
||||
|
||||
if o.DryRun {
|
||||
o.PrintFlags.Complete("%s (dry run)")
|
||||
}
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.PrintObj = func(obj runtime.Object) error {
|
||||
return printer.PrintObj(obj, o.Out)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
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")
|
||||
}
|
||||
|
||||
return o.createJob(cronJob)
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
if !o.DryRun {
|
||||
var err error
|
||||
job, err = o.Client.Jobs(o.Namespace).Create(job)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create job: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return o.PrintObj(job)
|
||||
}
|
@ -14,10 +14,9 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
@ -27,7 +26,9 @@ import (
|
||||
"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) {
|
||||
@ -82,13 +83,26 @@ func TestCreateJobFromCronJob(t *testing.T) {
|
||||
return true, expectJob, nil
|
||||
})
|
||||
f := cmdtesting.NewTestFactory()
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
defer f.Cleanup()
|
||||
|
||||
printFlags := genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme)
|
||||
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmdOptions := &CreateJobOptions{
|
||||
Name: testJobName,
|
||||
Namespace: testNamespaceName,
|
||||
Client: clientset.BatchV1(),
|
||||
Out: buf,
|
||||
Cmd: NewCmdCreateJob(f, buf),
|
||||
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
|
||||
}
|
||||
|
||||
return p.PrintObj(obj, buf)
|
||||
},
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
|
||||
err := cmdOptions.createJob(cronJob)
|
@ -14,16 +14,15 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"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/util/i18n"
|
||||
)
|
||||
|
||||
@ -36,8 +35,16 @@ var (
|
||||
kubectl create namespace my-namespace`))
|
||||
)
|
||||
|
||||
type NamespaceOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreateNamespace is a macro command to create a new namespace
|
||||
func NewCmdCreateNamespace(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateNamespace(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &NamespaceOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "namespace NAME [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -46,24 +53,26 @@ func NewCmdCreateNamespace(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
Long: namespaceLong,
|
||||
Example: namespaceExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateNamespace(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.NamespaceV1GeneratorName)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CreateNamespace implements the behavior to run the create namespace command
|
||||
func CreateNamespace(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *NamespaceOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.NamespaceV1GeneratorName:
|
||||
@ -71,10 +80,11 @@ func CreateNamespace(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, ar
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreateNamespace implements the behavior to run the create namespace command
|
||||
func (o *NamespaceOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
@ -14,10 +14,9 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@ -26,6 +25,7 @@ import (
|
||||
"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"
|
||||
)
|
||||
|
||||
@ -33,7 +33,9 @@ func TestCreateNamespace(t *testing.T) {
|
||||
namespaceObject := &v1.Namespace{}
|
||||
namespaceObject.Name = "my-namespace"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
@ -49,8 +51,8 @@ func TestCreateNamespace(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateNamespace(tf, buf)
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateNamespace(tf, ioStreams)
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{namespaceObject.Name})
|
||||
expectedOutput := "namespace/" + namespaceObject.Name + "\n"
|
@ -14,16 +14,15 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"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/util/i18n"
|
||||
)
|
||||
|
||||
@ -41,8 +40,16 @@ var (
|
||||
kubectl create pdb my-pdb --selector=app=nginx --min-available=50%`))
|
||||
)
|
||||
|
||||
type PodDisruptionBudgetOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreatePodDisruptionBudget is a macro command to create a new pod disruption budget.
|
||||
func NewCmdCreatePodDisruptionBudget(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreatePodDisruptionBudget(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &PodDisruptionBudgetOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "poddisruptionbudget NAME --selector=SELECTOR --min-available=N [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -51,14 +58,15 @@ func NewCmdCreatePodDisruptionBudget(f cmdutil.Factory, cmdOut io.Writer) *cobra
|
||||
Long: pdbLong,
|
||||
Example: pdbExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreatePodDisruptionBudget(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.PodDisruptionBudgetV2GeneratorName)
|
||||
|
||||
cmd.Flags().String("min-available", "", i18n.T("The minimum number or percentage of available pods this budget requires."))
|
||||
@ -67,12 +75,12 @@ func NewCmdCreatePodDisruptionBudget(f cmdutil.Factory, cmdOut io.Writer) *cobra
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CreatePodDisruptionBudget implements the behavior to run the create pdb command.
|
||||
func CreatePodDisruptionBudget(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *PodDisruptionBudgetOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.PodDisruptionBudgetV1GeneratorName:
|
||||
@ -91,10 +99,11 @@ func CreatePodDisruptionBudget(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.C
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreatePodDisruptionBudget implements the behavior to run the create pdb command.
|
||||
func (o *PodDisruptionBudgetOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -27,11 +27,14 @@ import (
|
||||
"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"
|
||||
)
|
||||
|
||||
func TestCreatePdb(t *testing.T) {
|
||||
pdbName := "my-pdb"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
@ -45,15 +48,36 @@ func TestCreatePdb(t *testing.T) {
|
||||
}),
|
||||
}
|
||||
tf.ClientConfigVal = &restclient.Config{}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdCreatePodDisruptionBudget(tf, buf)
|
||||
outputFormat := "name"
|
||||
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreatePodDisruptionBudget(tf, ioStreams)
|
||||
cmd.Flags().Set("min-available", "1")
|
||||
cmd.Flags().Set("selector", "app=rails")
|
||||
cmd.Flags().Set("dry-run", "true")
|
||||
cmd.Flags().Set("output", "name")
|
||||
CreatePodDisruptionBudget(tf, buf, cmd, []string{pdbName})
|
||||
cmd.Flags().Set("output", outputFormat)
|
||||
|
||||
printFlags := genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme)
|
||||
printFlags.OutputFormat = &outputFormat
|
||||
|
||||
options := &PodDisruptionBudgetOpts{
|
||||
CreateSubcommandOptions: &CreateSubcommandOptions{
|
||||
PrintFlags: printFlags,
|
||||
Name: pdbName,
|
||||
IOStreams: ioStreams,
|
||||
},
|
||||
}
|
||||
err := options.Complete(tf, cmd, []string{pdbName})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
err = options.Run()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
expectedOutput := "poddisruptionbudget.policy/" + pdbName + "\n"
|
||||
if buf.String() != expectedOutput {
|
||||
t.Errorf("expected output: %s, but got: %s", expectedOutput, buf.String())
|
@ -14,16 +14,15 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"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/util/i18n"
|
||||
)
|
||||
|
||||
@ -39,8 +38,16 @@ var (
|
||||
kubectl create priorityclass default-priority --value=1000 --global-default=true --description="default priority"`))
|
||||
)
|
||||
|
||||
type PriorityClassOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreatePriorityClass is a macro command to create a new priorityClass.
|
||||
func NewCmdCreatePriorityClass(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreatePriorityClass(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &PriorityClassOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "priorityclass NAME --value=VALUE --global-default=BOOL [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -49,13 +56,15 @@ func NewCmdCreatePriorityClass(f cmdutil.Factory, cmdOut io.Writer) *cobra.Comma
|
||||
Long: pcLong,
|
||||
Example: pcExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(CreatePriorityClass(f, cmdOut, cmd, args))
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.PriorityClassV1Alpha1GeneratorName)
|
||||
|
||||
cmd.Flags().Int32("value", 0, i18n.T("the value of this priority class."))
|
||||
@ -64,12 +73,12 @@ func NewCmdCreatePriorityClass(f cmdutil.Factory, cmdOut io.Writer) *cobra.Comma
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CreatePriorityClass implements the behavior to run the create priorityClass command.
|
||||
func CreatePriorityClass(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *PriorityClassOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.PriorityClassV1Alpha1GeneratorName:
|
||||
@ -82,10 +91,11 @@ func CreatePriorityClass(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreatePriorityClass implements the behavior to run the create priorityClass command.
|
||||
func (o *PriorityClassOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -27,15 +27,18 @@ import (
|
||||
"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"
|
||||
)
|
||||
|
||||
func TestCreatePriorityClass(t *testing.T) {
|
||||
pcName := "my-pc"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
defer tf.Cleanup()
|
||||
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Group: "scheduling.k8s.io", Version: "v1alpha1"},
|
||||
GroupVersion: schema.GroupVersion{Group: "scheduling.k8s.io", Version: "v1beta1"},
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
return &http.Response{
|
||||
@ -45,15 +48,37 @@ func TestCreatePriorityClass(t *testing.T) {
|
||||
}),
|
||||
}
|
||||
tf.ClientConfigVal = &restclient.Config{}
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdCreatePriorityClass(tf, buf)
|
||||
outputFormat := "name"
|
||||
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreatePriorityClass(tf, ioStreams)
|
||||
cmd.Flags().Set("value", "1000")
|
||||
cmd.Flags().Set("global-default", "true")
|
||||
cmd.Flags().Set("description", "my priority")
|
||||
cmd.Flags().Set("dry-run", "true")
|
||||
cmd.Flags().Set("output", "name")
|
||||
CreatePriorityClass(tf, buf, cmd, []string{pcName})
|
||||
cmd.Flags().Set("output", outputFormat)
|
||||
|
||||
printFlags := genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme)
|
||||
printFlags.OutputFormat = &outputFormat
|
||||
|
||||
options := &PriorityClassOpts{
|
||||
CreateSubcommandOptions: &CreateSubcommandOptions{
|
||||
PrintFlags: printFlags,
|
||||
Name: pcName,
|
||||
IOStreams: ioStreams,
|
||||
},
|
||||
}
|
||||
err := options.Complete(tf, cmd, []string{pcName})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
err = options.Run()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
expectedOutput := "priorityclass.scheduling.k8s.io/" + pcName + "\n"
|
||||
if buf.String() != expectedOutput {
|
||||
t.Errorf("expected output: %s, but got: %s", expectedOutput, buf.String())
|
@ -14,16 +14,15 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"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/util/i18n"
|
||||
)
|
||||
|
||||
@ -39,8 +38,16 @@ var (
|
||||
kubectl create quota best-effort --hard=pods=100 --scopes=BestEffort`))
|
||||
)
|
||||
|
||||
type QuotaOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreateQuota is a macro command to create a new quota
|
||||
func NewCmdCreateQuota(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateQuota(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &QuotaOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "quota NAME [--hard=key1=value1,key2=value2] [--scopes=Scope1,Scope2] [--dry-run=bool]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -49,26 +56,27 @@ func NewCmdCreateQuota(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
Long: quotaLong,
|
||||
Example: quotaExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateQuota(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.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
|
||||
}
|
||||
|
||||
// CreateQuota implements the behavior to run the create quota command
|
||||
func CreateQuota(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *QuotaOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.ResourceQuotaV1GeneratorName:
|
||||
@ -80,10 +88,11 @@ func CreateQuota(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args [
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreateQuota implements the behavior to run the create quota command
|
||||
func (o *QuotaOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
@ -14,42 +14,19 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"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"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
)
|
||||
|
||||
func TestCreateQuota(t *testing.T) {
|
||||
resourceQuotaObject := &v1.ResourceQuota{}
|
||||
resourceQuotaObject.Name = "my-quota"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Version: "v1"},
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch p, m := req.URL.Path, req.Method; {
|
||||
case p == "/namespaces/test/resourcequotas" && m == "POST":
|
||||
return &http.Response{StatusCode: 201, Header: defaultHeader(), Body: objBody(codec, resourceQuotaObject)}, nil
|
||||
default:
|
||||
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
|
||||
return nil, nil
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
|
||||
tests := map[string]struct {
|
||||
flags []string
|
||||
@ -73,14 +50,19 @@ func TestCreateQuota(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for name, test := range tests {
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateQuota(tf, buf)
|
||||
cmd.Flags().Parse(test.flags)
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{resourceQuotaObject.Name})
|
||||
t.Run(name, func(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
if buf.String() != test.expectedOutput {
|
||||
t.Errorf("%s: expected output: %s, but got: %s", name, test.expectedOutput, buf.String())
|
||||
}
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateQuota(tf, ioStreams)
|
||||
cmd.Flags().Parse(test.flags)
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{resourceQuotaObject.Name})
|
||||
|
||||
if buf.String() != test.expectedOutput {
|
||||
t.Errorf("%s: expected output: %s, but got: %s", name, test.expectedOutput, buf.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -14,23 +14,25 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
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/util/i18n"
|
||||
)
|
||||
|
||||
@ -43,7 +45,7 @@ var (
|
||||
kubectl create role pod-reader --verb=get --verb=list --verb=watch --resource=pods
|
||||
|
||||
# Create a Role named "pod-reader" with ResourceName specified
|
||||
kubectl create role pod-reader --verb=get,list,watch --resource=pods --resource-name=readablepod --resource-name=anotherpod
|
||||
kubectl create role pod-reader --verb=get --resource=pods --resource-name=readablepod --resource-name=anotherpod
|
||||
|
||||
# Create a Role named "foo" with API Group specified
|
||||
kubectl create role foo --verb=get,list,watch --resource=rs.extensions
|
||||
@ -100,6 +102,8 @@ type ResourceOptions struct {
|
||||
}
|
||||
|
||||
type CreateRoleOptions struct {
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
|
||||
Name string
|
||||
Verbs []string
|
||||
Resources []ResourceOptions
|
||||
@ -110,15 +114,23 @@ type CreateRoleOptions struct {
|
||||
Namespace string
|
||||
Client clientgorbacv1.RbacV1Interface
|
||||
Mapper meta.RESTMapper
|
||||
Out io.Writer
|
||||
PrintObject func(obj runtime.Object) error
|
||||
PrintObj func(obj runtime.Object) error
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
func NewCreateRoleOptions(ioStreams genericclioptions.IOStreams) *CreateRoleOptions {
|
||||
return &CreateRoleOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
|
||||
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
// Role is a command to ease creating Roles.
|
||||
func NewCmdCreateRole(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
c := &CreateRoleOptions{
|
||||
Out: cmdOut,
|
||||
}
|
||||
func NewCmdCreateRole(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewCreateRoleOptions(ioStreams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "role NAME --verb=verb --resource=resource.group/subresource [--resource-name=resourcename] [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -126,32 +138,34 @@ func NewCmdCreateRole(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
Long: roleLong,
|
||||
Example: roleExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(c.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(c.Validate())
|
||||
cmdutil.CheckErr(c.RunCreateRole())
|
||||
cmdutil.CheckErr(o.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(o.Validate())
|
||||
cmdutil.CheckErr(o.RunCreateRole())
|
||||
},
|
||||
}
|
||||
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
cmd.Flags().StringSliceVar(&c.Verbs, "verb", []string{}, "Verb that applies to the resources contained in the rule")
|
||||
cmd.Flags().StringSliceVar(&o.Verbs, "verb", o.Verbs, "Verb that applies to the resources contained in the rule")
|
||||
cmd.Flags().StringSlice("resource", []string{}, "Resource that the rule applies to")
|
||||
cmd.Flags().StringArrayVar(&c.ResourceNames, "resource-name", []string{}, "Resource in the white list that the rule applies to, repeat this flag for multiple items")
|
||||
cmd.Flags().StringArrayVar(&o.ResourceNames, "resource-name", o.ResourceNames, "Resource in the white list that the rule applies to, repeat this flag for multiple items")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c *CreateRoleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
func (o *CreateRoleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Name = name
|
||||
o.Name = name
|
||||
|
||||
// Remove duplicate verbs.
|
||||
verbs := []string{}
|
||||
for _, v := range c.Verbs {
|
||||
for _, v := range o.Verbs {
|
||||
// VerbAll respresents all kinds of verbs.
|
||||
if v == "*" {
|
||||
verbs = []string{"*"}
|
||||
@ -161,7 +175,7 @@ func (c *CreateRoleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
|
||||
verbs = append(verbs, v)
|
||||
}
|
||||
}
|
||||
c.Verbs = verbs
|
||||
o.Verbs = verbs
|
||||
|
||||
// Support resource.group pattern. If no API Group specified, use "" as core API Group.
|
||||
// e.g. --resource=pods,deployments.extensions
|
||||
@ -180,79 +194,89 @@ func (c *CreateRoleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
|
||||
}
|
||||
resource.Resource = parts[0]
|
||||
|
||||
c.Resources = append(c.Resources, *resource)
|
||||
o.Resources = append(o.Resources, *resource)
|
||||
}
|
||||
|
||||
// Remove duplicate resource names.
|
||||
resourceNames := []string{}
|
||||
for _, n := range c.ResourceNames {
|
||||
for _, n := range o.ResourceNames {
|
||||
if !arrayContains(resourceNames, n) {
|
||||
resourceNames = append(resourceNames, n)
|
||||
}
|
||||
}
|
||||
c.ResourceNames = resourceNames
|
||||
o.ResourceNames = resourceNames
|
||||
|
||||
// Complete other options for Run.
|
||||
c.Mapper, _ = f.Object()
|
||||
|
||||
c.DryRun = cmdutil.GetDryRunFlag(cmd)
|
||||
c.OutputFormat = cmdutil.GetFlagString(cmd, "output")
|
||||
|
||||
c.Namespace, _, err = f.DefaultNamespace()
|
||||
o.Mapper, err = f.ToRESTMapper()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.PrintObject = func(obj runtime.Object) error {
|
||||
return cmdutil.PrintObject(cmd, obj, c.Out)
|
||||
o.DryRun = cmdutil.GetDryRunFlag(cmd)
|
||||
o.OutputFormat = cmdutil.GetFlagString(cmd, "output")
|
||||
|
||||
if o.DryRun {
|
||||
o.PrintFlags.Complete("%s (dry run)")
|
||||
}
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.PrintObj = func(obj runtime.Object) error {
|
||||
return printer.PrintObj(obj, o.Out)
|
||||
}
|
||||
|
||||
o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clientset, err := f.KubernetesClientSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Client = clientset.RbacV1()
|
||||
o.Client = clientset.RbacV1()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *CreateRoleOptions) Validate() error {
|
||||
if c.Name == "" {
|
||||
func (o *CreateRoleOptions) Validate() error {
|
||||
if o.Name == "" {
|
||||
return fmt.Errorf("name must be specified")
|
||||
}
|
||||
|
||||
// validate verbs.
|
||||
if len(c.Verbs) == 0 {
|
||||
if len(o.Verbs) == 0 {
|
||||
return fmt.Errorf("at least one verb must be specified")
|
||||
}
|
||||
|
||||
for _, v := range c.Verbs {
|
||||
for _, v := range o.Verbs {
|
||||
if !arrayContains(validResourceVerbs, v) {
|
||||
return fmt.Errorf("invalid verb: '%s'", v)
|
||||
}
|
||||
}
|
||||
|
||||
// validate resources.
|
||||
if len(c.Resources) == 0 {
|
||||
if len(o.Resources) == 0 {
|
||||
return fmt.Errorf("at least one resource must be specified")
|
||||
}
|
||||
|
||||
return c.validateResource()
|
||||
return o.validateResource()
|
||||
}
|
||||
|
||||
func (c *CreateRoleOptions) validateResource() error {
|
||||
for _, r := range c.Resources {
|
||||
func (o *CreateRoleOptions) validateResource() error {
|
||||
for _, r := range o.Resources {
|
||||
if len(r.Resource) == 0 {
|
||||
return fmt.Errorf("resource must be specified if apiGroup/subresource specified")
|
||||
}
|
||||
|
||||
resource := schema.GroupVersionResource{Resource: r.Resource, Group: r.Group}
|
||||
groupVersionResource, err := c.Mapper.ResourceFor(schema.GroupVersionResource{Resource: r.Resource, Group: r.Group})
|
||||
groupVersionResource, err := o.Mapper.ResourceFor(schema.GroupVersionResource{Resource: r.Resource, Group: r.Group})
|
||||
if err == nil {
|
||||
resource = groupVersionResource
|
||||
}
|
||||
|
||||
for _, v := range c.Verbs {
|
||||
for _, v := range o.Verbs {
|
||||
if groupResources, ok := specialVerbs[v]; ok {
|
||||
match := false
|
||||
for _, extra := range groupResources {
|
||||
@ -275,29 +299,27 @@ func (c *CreateRoleOptions) validateResource() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *CreateRoleOptions) RunCreateRole() error {
|
||||
role := &rbacv1.Role{}
|
||||
role.Name = c.Name
|
||||
rules, err := generateResourcePolicyRules(c.Mapper, c.Verbs, c.Resources, c.ResourceNames, []string{})
|
||||
func (o *CreateRoleOptions) RunCreateRole() error {
|
||||
role := &rbacv1.Role{
|
||||
// this is ok because we know exactly how we want to be serialized
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: rbacv1.SchemeGroupVersion.String(), Kind: "Role"},
|
||||
}
|
||||
role.Name = o.Name
|
||||
rules, err := generateResourcePolicyRules(o.Mapper, o.Verbs, o.Resources, o.ResourceNames, []string{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
role.Rules = rules
|
||||
|
||||
// Create role.
|
||||
if !c.DryRun {
|
||||
_, err = c.Client.Roles(c.Namespace).Create(role)
|
||||
if !o.DryRun {
|
||||
role, err = o.Client.Roles(o.Namespace).Create(role)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if useShortOutput := c.OutputFormat == "name"; useShortOutput || len(c.OutputFormat) == 0 {
|
||||
cmdutil.PrintSuccess(useShortOutput, c.Out, role, c.DryRun, "created")
|
||||
return nil
|
||||
}
|
||||
|
||||
return c.PrintObject(role)
|
||||
return o.PrintObj(role)
|
||||
}
|
||||
|
||||
func arrayContains(s []string, e string) bool {
|
@ -14,10 +14,9 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
@ -29,13 +28,15 @@ import (
|
||||
"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"
|
||||
)
|
||||
|
||||
func TestCreateRole(t *testing.T) {
|
||||
roleName := "my-role"
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf.Namespace = "test"
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.Client = &fake.RESTClient{}
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
@ -49,6 +50,7 @@ func TestCreateRole(t *testing.T) {
|
||||
verbs: "get,watch,list",
|
||||
resources: "pods,pods",
|
||||
expectedRole: &rbac.Role{
|
||||
TypeMeta: v1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "Role"},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: roleName,
|
||||
},
|
||||
@ -66,6 +68,7 @@ func TestCreateRole(t *testing.T) {
|
||||
verbs: "get,watch,list",
|
||||
resources: "replicasets/scale",
|
||||
expectedRole: &rbac.Role{
|
||||
TypeMeta: v1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "Role"},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: roleName,
|
||||
},
|
||||
@ -83,6 +86,7 @@ func TestCreateRole(t *testing.T) {
|
||||
verbs: "get,watch,list",
|
||||
resources: "replicasets.extensions/scale",
|
||||
expectedRole: &rbac.Role{
|
||||
TypeMeta: v1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "Role"},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: roleName,
|
||||
},
|
||||
@ -100,6 +104,7 @@ func TestCreateRole(t *testing.T) {
|
||||
verbs: "get,watch,list",
|
||||
resources: "pods,deployments.extensions",
|
||||
expectedRole: &rbac.Role{
|
||||
TypeMeta: v1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "Role"},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: roleName,
|
||||
},
|
||||
@ -123,8 +128,8 @@ func TestCreateRole(t *testing.T) {
|
||||
|
||||
for name, test := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateRole(tf, buf)
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateRole(tf, ioStreams)
|
||||
cmd.Flags().Set("dry-run", "true")
|
||||
cmd.Flags().Set("output", "yaml")
|
||||
cmd.Flags().Set("verb", test.verbs)
|
||||
@ -146,8 +151,8 @@ func TestCreateRole(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestValidate(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf.Namespace = "test"
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tests := map[string]struct {
|
||||
roleOptions *CreateRoleOptions
|
||||
@ -331,8 +336,12 @@ func TestValidate(t *testing.T) {
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
test.roleOptions.Mapper, _ = tf.Object()
|
||||
err := test.roleOptions.Validate()
|
||||
var err error
|
||||
test.roleOptions.Mapper, err = tf.ToRESTMapper()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = test.roleOptions.Validate()
|
||||
if test.expectErr && err == nil {
|
||||
t.Errorf("%s: expect error happens but validate passes.", name)
|
||||
}
|
||||
@ -345,13 +354,13 @@ func TestValidate(t *testing.T) {
|
||||
func TestComplete(t *testing.T) {
|
||||
roleName := "my-role"
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf.Namespace = "test"
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.Client = &fake.RESTClient{}
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateRole(tf, buf)
|
||||
cmd := NewCmdCreateRole(tf, genericclioptions.NewTestIOStreamsDiscard())
|
||||
cmd.Flags().Set("resource", "pods,deployments.extensions")
|
||||
|
||||
tests := map[string]struct {
|
||||
@ -361,14 +370,17 @@ func TestComplete(t *testing.T) {
|
||||
expectErr bool
|
||||
}{
|
||||
"test-missing-name": {
|
||||
params: []string{},
|
||||
roleOptions: &CreateRoleOptions{},
|
||||
expectErr: true,
|
||||
params: []string{},
|
||||
roleOptions: &CreateRoleOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
"test-duplicate-verbs": {
|
||||
params: []string{roleName},
|
||||
roleOptions: &CreateRoleOptions{
|
||||
Name: roleName,
|
||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
|
||||
Name: roleName,
|
||||
Verbs: []string{
|
||||
"get",
|
||||
"watch",
|
||||
@ -400,7 +412,8 @@ func TestComplete(t *testing.T) {
|
||||
"test-verball": {
|
||||
params: []string{roleName},
|
||||
roleOptions: &CreateRoleOptions{
|
||||
Name: roleName,
|
||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
|
||||
Name: roleName,
|
||||
Verbs: []string{
|
||||
"get",
|
||||
"watch",
|
||||
@ -428,6 +441,7 @@ func TestComplete(t *testing.T) {
|
||||
"test-duplicate-resourcenames": {
|
||||
params: []string{roleName},
|
||||
roleOptions: &CreateRoleOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
|
||||
Name: roleName,
|
||||
Verbs: []string{"*"},
|
||||
ResourceNames: []string{"foo", "foo"},
|
||||
@ -452,6 +466,7 @@ func TestComplete(t *testing.T) {
|
||||
"test-valid-complete-case": {
|
||||
params: []string{roleName},
|
||||
roleOptions: &CreateRoleOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
|
||||
Name: roleName,
|
||||
Verbs: []string{"*"},
|
||||
ResourceNames: []string{"foo"},
|
@ -14,16 +14,15 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"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/util/i18n"
|
||||
)
|
||||
|
||||
@ -36,8 +35,16 @@ var (
|
||||
kubectl create rolebinding admin --clusterrole=admin --user=user1 --user=user2 --group=group1`))
|
||||
)
|
||||
|
||||
type RoleBindingOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// RoleBinding is a command to ease creating RoleBindings.
|
||||
func NewCmdCreateRoleBinding(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateRoleBinding(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &RoleBindingOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "rolebinding NAME --clusterrole=NAME|--role=NAME [--user=username] [--group=groupname] [--serviceaccount=namespace:serviceaccountname] [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -45,13 +52,15 @@ func NewCmdCreateRoleBinding(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command
|
||||
Long: roleBindingLong,
|
||||
Example: roleBindingExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateRoleBinding(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.RoleBindingV1GeneratorName)
|
||||
cmd.Flags().String("clusterrole", "", i18n.T("ClusterRole this RoleBinding should reference"))
|
||||
cmd.Flags().String("role", "", i18n.T("Role this RoleBinding should reference"))
|
||||
@ -61,11 +70,12 @@ func NewCmdCreateRoleBinding(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command
|
||||
return cmd
|
||||
}
|
||||
|
||||
func CreateRoleBinding(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *RoleBindingOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.RoleBindingV1GeneratorName:
|
||||
@ -80,10 +90,10 @@ func CreateRoleBinding(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command,
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
func (o *RoleBindingOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -32,6 +32,7 @@ import (
|
||||
"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"
|
||||
)
|
||||
|
||||
var groupVersion = schema.GroupVersion{Group: "rbac.authorization.k8s.io", Version: "v1"}
|
||||
@ -69,14 +70,15 @@ func TestCreateRoleBinding(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
info, _ := runtime.SerializerInfoForMediaType(ns.SupportedMediaTypes(), runtime.ContentTypeJSON)
|
||||
encoder := ns.EncoderForVersion(info.Serializer, groupVersion)
|
||||
decoder := ns.DecoderToVersion(info.Serializer, groupVersion)
|
||||
|
||||
tf.Namespace = "test"
|
||||
tf.Client = &RoleBindingRESTClient{
|
||||
RESTClient: &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
@ -110,8 +112,7 @@ func TestCreateRoleBinding(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateRoleBinding(tf, buf)
|
||||
cmd := NewCmdCreateRoleBinding(tf, genericclioptions.NewTestIOStreamsDiscard())
|
||||
cmd.Flags().Set("role", "fake-role")
|
||||
cmd.Flags().Set("user", "fake-user")
|
||||
cmd.Flags().Set("group", "fake-group")
|
@ -14,30 +14,29 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"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/util/i18n"
|
||||
)
|
||||
|
||||
// NewCmdCreateSecret groups subcommands to create various types of secrets
|
||||
func NewCmdCreateSecret(f cmdutil.Factory, cmdOut, errOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateSecret(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "secret",
|
||||
Short: i18n.T("Create a secret using specified subcommand"),
|
||||
Long: "Create a secret using specified subcommand.",
|
||||
Run: cmdutil.DefaultSubCommandRun(errOut),
|
||||
Run: cmdutil.DefaultSubCommandRun(ioStreams.ErrOut),
|
||||
}
|
||||
cmd.AddCommand(NewCmdCreateSecretDockerRegistry(f, cmdOut))
|
||||
cmd.AddCommand(NewCmdCreateSecretTLS(f, cmdOut))
|
||||
cmd.AddCommand(NewCmdCreateSecretGeneric(f, cmdOut))
|
||||
cmd.AddCommand(NewCmdCreateSecretDockerRegistry(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateSecretTLS(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateSecretGeneric(f, ioStreams))
|
||||
|
||||
return cmd
|
||||
}
|
||||
@ -73,8 +72,16 @@ var (
|
||||
kubectl create secret generic my-secret --from-env-file=path/to/bar.env`))
|
||||
)
|
||||
|
||||
type SecretGenericOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreateSecretGeneric is a command to create generic secrets from files, directories, or literal values
|
||||
func NewCmdCreateSecretGeneric(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateSecretGeneric(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &SecretGenericOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "generic NAME [--type=string] [--from-file=[key=]source] [--from-literal=key1=value1] [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -82,13 +89,15 @@ func NewCmdCreateSecretGeneric(f cmdutil.Factory, cmdOut io.Writer) *cobra.Comma
|
||||
Long: secretLong,
|
||||
Example: secretExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateSecretGeneric(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.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)")
|
||||
@ -98,12 +107,12 @@ func NewCmdCreateSecretGeneric(f cmdutil.Factory, cmdOut io.Writer) *cobra.Comma
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CreateSecretGeneric is the implementation of the create secret generic command
|
||||
func CreateSecretGeneric(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *SecretGenericOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.SecretV1GeneratorName:
|
||||
@ -118,12 +127,13 @@ func CreateSecretGeneric(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreateSecretGeneric is the implementation of the create secret generic command
|
||||
func (o *SecretGenericOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
||||
|
||||
var (
|
||||
@ -135,7 +145,7 @@ var (
|
||||
When using the Docker command line to push images, you can authenticate to a given registry by running:
|
||||
'$ docker login DOCKER_REGISTRY_SERVER --username=DOCKER_USER --password=DOCKER_PASSWORD --email=DOCKER_EMAIL'.
|
||||
|
||||
That produces a ~/.dockercfg file that is used by subsequent 'docker push' and 'docker pull' commands to
|
||||
That produces a ~/.dockercfg file that is used by subsequent 'docker push' and 'docker pull' commands to
|
||||
authenticate to the registry. The email address is optional.
|
||||
|
||||
When creating applications, you may have a Docker registry that requires authentication. In order for the
|
||||
@ -147,8 +157,16 @@ var (
|
||||
kubectl create secret docker-registry my-secret --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL`))
|
||||
)
|
||||
|
||||
type SecretDockerRegistryOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreateSecretDockerRegistry is a macro command for creating secrets to work with Docker registries
|
||||
func NewCmdCreateSecretDockerRegistry(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateSecretDockerRegistry(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &SecretDockerRegistryOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
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]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -156,13 +174,15 @@ func NewCmdCreateSecretDockerRegistry(f cmdutil.Factory, cmdOut io.Writer) *cobr
|
||||
Long: secretForDockerRegistryLong,
|
||||
Example: secretForDockerRegistryExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateSecretDockerRegistry(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.SecretForDockerRegistryV1GeneratorName)
|
||||
cmd.Flags().String("docker-username", "", i18n.T("Username for Docker registry authentication"))
|
||||
cmd.MarkFlagRequired("docker-username")
|
||||
@ -171,43 +191,49 @@ func NewCmdCreateSecretDockerRegistry(f cmdutil.Factory, cmdOut io.Writer) *cobr
|
||||
cmd.Flags().String("docker-email", "", i18n.T("Email for Docker registry"))
|
||||
cmd.Flags().String("docker-server", "https://index.docker.io/v1/", i18n.T("Server location for Docker registry"))
|
||||
cmd.Flags().Bool("append-hash", false, "Append a hash of the secret to its name.")
|
||||
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.")
|
||||
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CreateSecretDockerRegistry is the implementation of the create secret docker-registry command
|
||||
func CreateSecretDockerRegistry(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *SecretDockerRegistryOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
requiredFlags := []string{"docker-username", "docker-password", "docker-email", "docker-server"}
|
||||
for _, requiredFlag := range requiredFlags {
|
||||
if value := cmdutil.GetFlagString(cmd, requiredFlag); len(value) == 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "flag %s is required", requiredFlag)
|
||||
|
||||
fromFileFlag := cmdutil.GetFlagStringSlice(cmd, "from-file")
|
||||
if len(fromFileFlag) == 0 {
|
||||
requiredFlags := []string{"docker-username", "docker-password", "docker-server"}
|
||||
for _, requiredFlag := range requiredFlags {
|
||||
if value := cmdutil.GetFlagString(cmd, requiredFlag); len(value) == 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "flag %s is required", requiredFlag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.SecretForDockerRegistryV1GeneratorName:
|
||||
generator = &kubectl.SecretForDockerRegistryGeneratorV1{
|
||||
Name: name,
|
||||
Username: cmdutil.GetFlagString(cmd, "docker-username"),
|
||||
Email: cmdutil.GetFlagString(cmd, "docker-email"),
|
||||
Password: cmdutil.GetFlagString(cmd, "docker-password"),
|
||||
Server: cmdutil.GetFlagString(cmd, "docker-server"),
|
||||
AppendHash: cmdutil.GetFlagBool(cmd, "append-hash"),
|
||||
Name: name,
|
||||
Username: cmdutil.GetFlagString(cmd, "docker-username"),
|
||||
Email: cmdutil.GetFlagString(cmd, "docker-email"),
|
||||
Password: cmdutil.GetFlagString(cmd, "docker-password"),
|
||||
Server: cmdutil.GetFlagString(cmd, "docker-server"),
|
||||
AppendHash: cmdutil.GetFlagBool(cmd, "append-hash"),
|
||||
FileSources: cmdutil.GetFlagStringSlice(cmd, "from-file"),
|
||||
}
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreateSecretDockerRegistry is the implementation of the create secret docker-registry command
|
||||
func (o *SecretDockerRegistryOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
||||
|
||||
var (
|
||||
@ -222,8 +248,16 @@ var (
|
||||
kubectl create secret tls tls-secret --cert=path/to/tls.cert --key=path/to/tls.key`))
|
||||
)
|
||||
|
||||
type SecretTLSOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreateSecretTLS is a macro command for creating secrets to work with Docker registries
|
||||
func NewCmdCreateSecretTLS(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateSecretTLS(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &SecretTLSOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "tls NAME --cert=path/to/cert/file --key=path/to/key/file [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -231,13 +265,15 @@ func NewCmdCreateSecretTLS(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
Long: secretForTLSLong,
|
||||
Example: secretForTLSExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateSecretTLS(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.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."))
|
||||
@ -245,12 +281,12 @@ func NewCmdCreateSecretTLS(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CreateSecretTLS is the implementation of the create secret tls command
|
||||
func CreateSecretTLS(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *SecretTLSOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
requiredFlags := []string{"cert", "key"}
|
||||
for _, requiredFlag := range requiredFlags {
|
||||
if value := cmdutil.GetFlagString(cmd, requiredFlag); len(value) == 0 {
|
||||
@ -269,10 +305,11 @@ func CreateSecretTLS(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, ar
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreateSecretTLS is the implementation of the create secret tls command
|
||||
func (o *SecretTLSOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
@ -14,10 +14,9 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@ -26,6 +25,7 @@ import (
|
||||
"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"
|
||||
)
|
||||
|
||||
@ -37,8 +37,10 @@ func TestCreateSecretGeneric(t *testing.T) {
|
||||
},
|
||||
}
|
||||
secretObject.Name = "my-secret"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
@ -54,9 +56,8 @@ func TestCreateSecretGeneric(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateSecretGeneric(tf, buf)
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateSecretGeneric(tf, ioStreams)
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Flags().Set("from-literal", "password=includes,comma")
|
||||
cmd.Flags().Set("from-literal", "username=test_user")
|
||||
@ -70,8 +71,8 @@ func TestCreateSecretGeneric(t *testing.T) {
|
||||
func TestCreateSecretDockerRegistry(t *testing.T) {
|
||||
secretObject := &v1.Secret{}
|
||||
secretObject.Name = "my-secret"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
@ -87,9 +88,8 @@ func TestCreateSecretDockerRegistry(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateSecretDockerRegistry(tf, buf)
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateSecretDockerRegistry(tf, ioStreams)
|
||||
cmd.Flags().Set("docker-username", "test-user")
|
||||
cmd.Flags().Set("docker-password", "test-pass")
|
||||
cmd.Flags().Set("docker-email", "test-email")
|
@ -14,33 +14,32 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"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/util/i18n"
|
||||
)
|
||||
|
||||
// NewCmdCreateService is a macro command to create a new service
|
||||
func NewCmdCreateService(f cmdutil.Factory, cmdOut, errOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateService(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "service",
|
||||
Aliases: []string{"svc"},
|
||||
Short: i18n.T("Create a service using specified subcommand."),
|
||||
Long: "Create a service using specified subcommand.",
|
||||
Run: cmdutil.DefaultSubCommandRun(errOut),
|
||||
Run: cmdutil.DefaultSubCommandRun(ioStreams.ErrOut),
|
||||
}
|
||||
cmd.AddCommand(NewCmdCreateServiceClusterIP(f, cmdOut))
|
||||
cmd.AddCommand(NewCmdCreateServiceNodePort(f, cmdOut))
|
||||
cmd.AddCommand(NewCmdCreateServiceLoadBalancer(f, cmdOut))
|
||||
cmd.AddCommand(NewCmdCreateServiceExternalName(f, cmdOut))
|
||||
cmd.AddCommand(NewCmdCreateServiceClusterIP(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateServiceNodePort(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateServiceLoadBalancer(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateServiceExternalName(f, ioStreams))
|
||||
|
||||
return cmd
|
||||
}
|
||||
@ -61,8 +60,16 @@ func addPortFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().StringSlice("tcp", []string{}, "Port pairs can be specified as '<port>:<targetPort>'.")
|
||||
}
|
||||
|
||||
type ServiceClusterIPOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreateServiceClusterIP is a command to create a ClusterIP service
|
||||
func NewCmdCreateServiceClusterIP(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateServiceClusterIP(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &ServiceClusterIPOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "clusterip NAME [--tcp=<port>:<targetPort>] [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -70,13 +77,15 @@ func NewCmdCreateServiceClusterIP(f cmdutil.Factory, cmdOut io.Writer) *cobra.Co
|
||||
Long: serviceClusterIPLong,
|
||||
Example: serviceClusterIPExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateServiceClusterIP(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.ServiceClusterIPGeneratorV1Name)
|
||||
addPortFlags(cmd)
|
||||
cmd.Flags().String("clusterip", "", i18n.T("Assign your own ClusterIP or set to 'None' for a 'headless' service (no loadbalancing)."))
|
||||
@ -87,12 +96,12 @@ func errUnsupportedGenerator(cmd *cobra.Command, generatorName string) error {
|
||||
return cmdutil.UsageErrorf(cmd, "Generator %s not supported. ", generatorName)
|
||||
}
|
||||
|
||||
// CreateServiceClusterIP is the implementation of the create service clusterip command
|
||||
func CreateServiceClusterIP(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *ServiceClusterIPOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.ServiceClusterIPGeneratorV1Name:
|
||||
@ -105,12 +114,13 @@ func CreateServiceClusterIP(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Comm
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreateServiceClusterIP is the implementation of the create service clusterip command
|
||||
func (o *ServiceClusterIPOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
||||
|
||||
var (
|
||||
@ -122,8 +132,16 @@ var (
|
||||
kubectl create service nodeport my-ns --tcp=5678:8080`))
|
||||
)
|
||||
|
||||
type ServiceNodePortOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreateServiceNodePort is a macro command for creating a NodePort service
|
||||
func NewCmdCreateServiceNodePort(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateServiceNodePort(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &ServiceNodePortOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "nodeport NAME [--tcp=port:targetPort] [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -131,25 +149,27 @@ func NewCmdCreateServiceNodePort(f cmdutil.Factory, cmdOut io.Writer) *cobra.Com
|
||||
Long: serviceNodePortLong,
|
||||
Example: serviceNodePortExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateServiceNodePort(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.ServiceNodePortGeneratorV1Name)
|
||||
cmd.Flags().Int("node-port", 0, "Port used to expose the service on each node in a cluster.")
|
||||
addPortFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CreateServiceNodePort is the implementation of the create service nodeport command
|
||||
func CreateServiceNodePort(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *ServiceNodePortOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.ServiceNodePortGeneratorV1Name:
|
||||
@ -163,12 +183,13 @@ func CreateServiceNodePort(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Comma
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreateServiceNodePort is the implementation of the create service nodeport command
|
||||
func (o *ServiceNodePortOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
||||
|
||||
var (
|
||||
@ -180,8 +201,16 @@ var (
|
||||
kubectl create service loadbalancer my-lbs --tcp=5678:8080`))
|
||||
)
|
||||
|
||||
type ServiceLoadBalancerOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreateServiceLoadBalancer is a macro command for creating a LoadBalancer service
|
||||
func NewCmdCreateServiceLoadBalancer(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateServiceLoadBalancer(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &ServiceLoadBalancerOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "loadbalancer NAME [--tcp=port:targetPort] [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -189,24 +218,26 @@ func NewCmdCreateServiceLoadBalancer(f cmdutil.Factory, cmdOut io.Writer) *cobra
|
||||
Long: serviceLoadBalancerLong,
|
||||
Example: serviceLoadBalancerExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateServiceLoadBalancer(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.ServiceLoadBalancerGeneratorV1Name)
|
||||
addPortFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CreateServiceLoadBalancer is the implementation of the create service loadbalancer command
|
||||
func CreateServiceLoadBalancer(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *ServiceLoadBalancerOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.ServiceLoadBalancerGeneratorV1Name:
|
||||
@ -219,12 +250,13 @@ func CreateServiceLoadBalancer(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.C
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreateServiceLoadBalancer is the implementation of the create service loadbalancer command
|
||||
func (o *ServiceLoadBalancerOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
||||
|
||||
var (
|
||||
@ -236,12 +268,20 @@ var (
|
||||
that exist off platform, on other clusters, or locally.`))
|
||||
|
||||
serviceExternalNameExample = templates.Examples(i18n.T(`
|
||||
# Create a new ExternalName service named my-ns
|
||||
# Create a new ExternalName service named my-ns
|
||||
kubectl create service externalname my-ns --external-name bar.com`))
|
||||
)
|
||||
|
||||
type ServiceExternalNameOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreateServiceExternalName is a macro command for creating an ExternalName service
|
||||
func NewCmdCreateServiceExternalName(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateServiceExternalName(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &ServiceExternalNameOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "externalname NAME --external-name external.name [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -249,13 +289,15 @@ func NewCmdCreateServiceExternalName(f cmdutil.Factory, cmdOut io.Writer) *cobra
|
||||
Long: serviceExternalNameLong,
|
||||
Example: serviceExternalNameExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateExternalNameService(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.ServiceExternalNameGeneratorV1Name)
|
||||
addPortFlags(cmd)
|
||||
cmd.Flags().String("external-name", "", i18n.T("External name of service"))
|
||||
@ -263,12 +305,12 @@ func NewCmdCreateServiceExternalName(f cmdutil.Factory, cmdOut io.Writer) *cobra
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CreateExternalNameService is the implementation of the create service externalname command
|
||||
func CreateExternalNameService(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *ServiceExternalNameOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.ServiceExternalNameGeneratorV1Name:
|
||||
@ -281,10 +323,11 @@ func CreateExternalNameService(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.C
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreateExternalNameService is the implementation of the create service externalname command
|
||||
func (o *ServiceExternalNameOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
@ -14,10 +14,9 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@ -26,14 +25,17 @@ import (
|
||||
"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 TestCreateService(t *testing.T) {
|
||||
service := &v1.Service{}
|
||||
service.Name = "my-service"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
negSer := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
@ -49,9 +51,8 @@ func TestCreateService(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateServiceClusterIP(tf, buf)
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateServiceClusterIP(tf, ioStreams)
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Flags().Set("tcp", "8080:8000")
|
||||
cmd.Run(cmd, []string{service.Name})
|
||||
@ -64,8 +65,10 @@ func TestCreateService(t *testing.T) {
|
||||
func TestCreateServiceNodePort(t *testing.T) {
|
||||
service := &v1.Service{}
|
||||
service.Name = "my-node-port-service"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
negSer := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
@ -81,9 +84,8 @@ func TestCreateServiceNodePort(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateServiceNodePort(tf, buf)
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateServiceNodePort(tf, ioStreams)
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Flags().Set("tcp", "30000:8000")
|
||||
cmd.Run(cmd, []string{service.Name})
|
||||
@ -96,8 +98,10 @@ func TestCreateServiceNodePort(t *testing.T) {
|
||||
func TestCreateServiceExternalName(t *testing.T) {
|
||||
service := &v1.Service{}
|
||||
service.Name = "my-external-name-service"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
negSer := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
@ -113,9 +117,8 @@ func TestCreateServiceExternalName(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateServiceExternalName(tf, buf)
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateServiceExternalName(tf, ioStreams)
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Flags().Set("external-name", "name")
|
||||
cmd.Run(cmd, []string{service.Name})
|
@ -14,16 +14,15 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"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/util/i18n"
|
||||
)
|
||||
|
||||
@ -36,8 +35,16 @@ var (
|
||||
kubectl create serviceaccount my-service-account`))
|
||||
)
|
||||
|
||||
type ServiceAccountOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreateServiceAccount is a macro command to create a new service account
|
||||
func NewCmdCreateServiceAccount(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateServiceAccount(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &ServiceAccountOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "serviceaccount NAME [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -46,24 +53,25 @@ func NewCmdCreateServiceAccount(f cmdutil.Factory, cmdOut io.Writer) *cobra.Comm
|
||||
Long: serviceAccountLong,
|
||||
Example: serviceAccountExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateServiceAccount(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.ServiceAccountV1GeneratorName)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CreateServiceAccount implements the behavior to run the create service account command
|
||||
func CreateServiceAccount(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *ServiceAccountOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.ServiceAccountV1GeneratorName:
|
||||
@ -71,10 +79,11 @@ func CreateServiceAccount(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Comman
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreateServiceAccount implements the behavior to run the create service account command
|
||||
func (o *ServiceAccountOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
@ -14,10 +14,9 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@ -26,14 +25,17 @@ import (
|
||||
"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 TestCreateServiceAccount(t *testing.T) {
|
||||
serviceAccountObject := &v1.ServiceAccount{}
|
||||
serviceAccountObject.Name = "my-service-account"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
@ -49,9 +51,8 @@ func TestCreateServiceAccount(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateServiceAccount(tf, buf)
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateServiceAccount(tf, ioStreams)
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{serviceAccountObject.Name})
|
||||
expectedOutput := "serviceaccount/" + serviceAccountObject.Name + "\n"
|
@ -14,27 +14,32 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
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/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
)
|
||||
|
||||
func TestExtraArgsFail(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
f := cmdtesting.NewTestFactory()
|
||||
c := NewCmdCreate(f, buf, errBuf)
|
||||
defer f.Cleanup()
|
||||
|
||||
c := NewCmdCreate(f, genericclioptions.NewTestIOStreamsDiscard())
|
||||
options := CreateOptions{}
|
||||
if options.ValidateArgs(c, []string{"rc"}) == nil {
|
||||
t.Errorf("unexpected non-error")
|
||||
@ -46,8 +51,10 @@ func TestCreateObject(t *testing.T) {
|
||||
_, _, rc := testData()
|
||||
rc.Items[0].Name = "redis-master-controller"
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Version: "v1"},
|
||||
@ -62,12 +69,10 @@ func TestCreateObject(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdCreate(tf, buf, errBuf)
|
||||
cmd.Flags().Set("filename", "../../../examples/guestbook/legacy/redis-master-controller.yaml")
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreate(tf, ioStreams)
|
||||
cmd.Flags().Set("filename", "../../../../test/e2e/testing-manifests/guestbook/legacy/redis-master-controller.yaml")
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{})
|
||||
|
||||
@ -81,8 +86,10 @@ func TestCreateMultipleObject(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
_, svc, rc := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Version: "v1"},
|
||||
@ -99,13 +106,11 @@ func TestCreateMultipleObject(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdCreate(tf, buf, errBuf)
|
||||
cmd.Flags().Set("filename", "../../../examples/guestbook/legacy/redis-master-controller.yaml")
|
||||
cmd.Flags().Set("filename", "../../../examples/guestbook/frontend-service.yaml")
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreate(tf, ioStreams)
|
||||
cmd.Flags().Set("filename", "../../../../test/e2e/testing-manifests/guestbook/legacy/redis-master-controller.yaml")
|
||||
cmd.Flags().Set("filename", "../../../../test/e2e/testing-manifests/guestbook/frontend-service.yaml")
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{})
|
||||
|
||||
@ -120,8 +125,10 @@ func TestCreateDirectory(t *testing.T) {
|
||||
_, _, rc := testData()
|
||||
rc.Items[0].Name = "name"
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Version: "v1"},
|
||||
@ -136,12 +143,10 @@ func TestCreateDirectory(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdCreate(tf, buf, errBuf)
|
||||
cmd.Flags().Set("filename", "../../../examples/guestbook/legacy")
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreate(tf, ioStreams)
|
||||
cmd.Flags().Set("filename", "../../../../test/e2e/testing-manifests/guestbook/legacy")
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{})
|
||||
|
||||
@ -149,3 +154,57 @@ func TestCreateDirectory(t *testing.T) {
|
||||
t.Errorf("unexpected output: %s", buf.String())
|
||||
}
|
||||
}
|
||||
|
||||
var unstructuredSerializer = resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer
|
||||
|
||||
func initTestErrorHandler(t *testing.T) {
|
||||
cmdutil.BehaviorOnFatal(func(str string, code int) {
|
||||
t.Errorf("Error running command (exit code %d): %s", code, str)
|
||||
})
|
||||
}
|
||||
|
||||
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
|
||||
}
|
146
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/create_job.go
generated
vendored
146
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/create_job.go
generated
vendored
@ -1,146 +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 (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
batchv1beta1 "k8s.io/api/batch/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
clientbatchv1 "k8s.io/client-go/kubernetes/typed/batch/v1"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
var (
|
||||
jobLong = templates.LongDesc(i18n.T(`
|
||||
Create a job with the specified name.`))
|
||||
|
||||
jobExample = templates.Examples(i18n.T(`
|
||||
# Create a job from a CronJob named "a-cronjob"
|
||||
kubectl create job --from=cronjob/a-cronjob`))
|
||||
)
|
||||
|
||||
type CreateJobOptions struct {
|
||||
Name string
|
||||
From string
|
||||
|
||||
Namespace string
|
||||
Client clientbatchv1.BatchV1Interface
|
||||
Out io.Writer
|
||||
DryRun bool
|
||||
Builder *resource.Builder
|
||||
Cmd *cobra.Command
|
||||
}
|
||||
|
||||
// NewCmdCreateJob is a command to ease creating Jobs from CronJobs.
|
||||
func NewCmdCreateJob(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
c := &CreateJobOptions{
|
||||
Out: cmdOut,
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "job NAME [--from-cronjob=CRONJOB]",
|
||||
Short: jobLong,
|
||||
Long: jobLong,
|
||||
Example: jobExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(c.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(c.RunCreateJob())
|
||||
},
|
||||
}
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmd.Flags().String("from", "", "The name of the resource to create a Job from (only cronjob is supported).")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c *CreateJobOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) (err error) {
|
||||
if len(args) == 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "NAME is required")
|
||||
}
|
||||
c.Name = args[0]
|
||||
|
||||
c.From = cmdutil.GetFlagString(cmd, "from")
|
||||
c.Namespace, _, err = f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clientset, err := f.KubernetesClientSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Client = clientset.BatchV1()
|
||||
c.Builder = f.NewBuilder()
|
||||
c.Cmd = cmd
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *CreateJobOptions) RunCreateJob() error {
|
||||
infos, err := c.Builder.
|
||||
Unstructured().
|
||||
NamespaceParam(c.Namespace).DefaultNamespace().
|
||||
ResourceTypeOrNameArgs(false, c.From).
|
||||
Flatten().
|
||||
Latest().
|
||||
Do().
|
||||
Infos()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(infos) != 1 {
|
||||
return fmt.Errorf("from must be an existing cronjob")
|
||||
}
|
||||
cronJob, ok := infos[0].AsVersioned().(*batchv1beta1.CronJob)
|
||||
if !ok {
|
||||
return fmt.Errorf("from must be an existing cronjob")
|
||||
}
|
||||
|
||||
return c.createJob(cronJob)
|
||||
}
|
||||
|
||||
func (c *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
|
||||
}
|
||||
jobToCreate := &batchv1.Job{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: c.Name,
|
||||
Namespace: c.Namespace,
|
||||
Annotations: annotations,
|
||||
Labels: cronJob.Spec.JobTemplate.Labels,
|
||||
},
|
||||
Spec: cronJob.Spec.JobTemplate.Spec,
|
||||
}
|
||||
|
||||
job, err := c.Client.Jobs(c.Namespace).Create(jobToCreate)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create job: %v", err)
|
||||
}
|
||||
return cmdutil.PrintObject(c.Cmd, job, c.Out)
|
||||
}
|
357
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/delete.go
generated
vendored
357
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/delete.go
generated
vendored
@ -18,20 +18,28 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
kubectlwait "k8s.io/kubernetes/pkg/kubectl/cmd/wait"
|
||||
"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"
|
||||
)
|
||||
|
||||
@ -90,7 +98,8 @@ var (
|
||||
type DeleteOptions struct {
|
||||
resource.FilenameOptions
|
||||
|
||||
Selector string
|
||||
LabelSelector string
|
||||
FieldSelector string
|
||||
DeleteAll bool
|
||||
IgnoreNotFound bool
|
||||
Cascade bool
|
||||
@ -101,20 +110,17 @@ type DeleteOptions struct {
|
||||
GracePeriod int
|
||||
Timeout time.Duration
|
||||
|
||||
Include3rdParty bool
|
||||
Output string
|
||||
Output string
|
||||
|
||||
Mapper meta.RESTMapper
|
||||
Result *resource.Result
|
||||
DynamicClient dynamic.Interface
|
||||
Mapper meta.RESTMapper
|
||||
Result *resource.Result
|
||||
|
||||
f cmdutil.Factory
|
||||
Out io.Writer
|
||||
ErrOut io.Writer
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
func NewCmdDelete(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
options := &DeleteOptions{Include3rdParty: true}
|
||||
validArgs := cmdutil.ValidArgList(f)
|
||||
func NewCmdDelete(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
deleteFlags := NewDeleteCommandFlags("containing the resource to delete.")
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "delete ([-f FILENAME] | TYPE [(NAME | -l label | --all)])",
|
||||
@ -123,50 +129,52 @@ func NewCmdDelete(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
Long: delete_long,
|
||||
Example: delete_example,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
|
||||
if err := options.Complete(f, out, errOut, args, cmd); err != nil {
|
||||
cmdutil.CheckErr(err)
|
||||
}
|
||||
if err := options.Validate(cmd); err != nil {
|
||||
cmdutil.CheckErr(cmdutil.UsageErrorf(cmd, err.Error()))
|
||||
}
|
||||
if err := options.RunDelete(); err != nil {
|
||||
cmdutil.CheckErr(err)
|
||||
}
|
||||
o := deleteFlags.ToOptions(nil, streams)
|
||||
cmdutil.CheckErr(o.Complete(f, args, cmd))
|
||||
cmdutil.CheckErr(o.Validate(cmd))
|
||||
cmdutil.CheckErr(o.RunDelete())
|
||||
},
|
||||
SuggestFor: []string{"rm"},
|
||||
ValidArgs: validArgs,
|
||||
ArgAliases: kubectl.ResourceAliases(validArgs),
|
||||
}
|
||||
usage := "containing the resource to delete."
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||
cmd.Flags().StringVarP(&options.Selector, "selector", "l", "", "Selector (label query) to filter on, not including uninitialized ones.")
|
||||
cmd.Flags().BoolVar(&options.DeleteAll, "all", options.DeleteAll, "Delete all resources, including uninitialized ones, in the namespace of the specified resource types.")
|
||||
cmd.Flags().BoolVar(&options.IgnoreNotFound, "ignore-not-found", false, "Treat \"resource not found\" as a successful delete. Defaults to \"true\" when --all is specified.")
|
||||
cmd.Flags().BoolVar(&options.Cascade, "cascade", true, "If true, cascade the deletion of the resources managed by this resource (e.g. Pods created by a ReplicationController). Default true.")
|
||||
cmd.Flags().IntVar(&options.GracePeriod, "grace-period", -1, "Period of time in seconds given to the resource to terminate gracefully. Ignored if negative.")
|
||||
cmd.Flags().BoolVar(&options.DeleteNow, "now", false, "If true, resources are signaled for immediate shutdown (same as --grace-period=1).")
|
||||
cmd.Flags().BoolVar(&options.ForceDeletion, "force", false, "Immediate deletion of some resources may result in inconsistency or data loss and requires confirmation.")
|
||||
cmd.Flags().DurationVar(&options.Timeout, "timeout", 0, "The length of time to wait before giving up on a delete, zero means determine a timeout from the size of the object")
|
||||
cmdutil.AddOutputVarFlagsForMutation(cmd, &options.Output)
|
||||
cmdutil.AddInclude3rdPartyVarFlags(cmd, &options.Include3rdParty)
|
||||
|
||||
deleteFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddIncludeUninitializedFlag(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o *DeleteOptions) Complete(f cmdutil.Factory, out, errOut io.Writer, args []string, cmd *cobra.Command) error {
|
||||
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
func (o *DeleteOptions) Complete(f cmdutil.Factory, args []string, cmd *cobra.Command) error {
|
||||
cmdNamespace, enforceNamespace, err := f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if o.DeleteAll || len(o.LabelSelector) > 0 || len(o.FieldSelector) > 0 {
|
||||
if f := cmd.Flags().Lookup("ignore-not-found"); f != nil && !f.Changed {
|
||||
// If the user didn't explicitly set the option, default to ignoring NotFound errors when used with --all, -l, or --field-selector
|
||||
o.IgnoreNotFound = true
|
||||
}
|
||||
}
|
||||
if o.DeleteNow {
|
||||
if o.GracePeriod != -1 {
|
||||
return fmt.Errorf("--now and --grace-period cannot be specified together")
|
||||
}
|
||||
o.GracePeriod = 1
|
||||
}
|
||||
if o.GracePeriod == 0 && !o.ForceDeletion {
|
||||
// To preserve backwards compatibility, but prevent accidental data loss, we convert --grace-period=0
|
||||
// into --grace-period=1. Users may provide --force to bypass this conversion.
|
||||
o.GracePeriod = 1
|
||||
}
|
||||
|
||||
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
|
||||
r := f.NewBuilder().
|
||||
Unstructured().
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||
LabelSelectorParam(o.Selector).
|
||||
LabelSelectorParam(o.LabelSelector).
|
||||
FieldSelectorParam(o.FieldSelector).
|
||||
IncludeUninitialized(includeUninitialized).
|
||||
SelectAllParam(o.DeleteAll).
|
||||
ResourceTypeOrNameArgs(false, args...).RequireObject(false).
|
||||
@ -177,151 +185,185 @@ func (o *DeleteOptions) Complete(f cmdutil.Factory, out, errOut io.Writer, args
|
||||
return err
|
||||
}
|
||||
o.Result = r
|
||||
o.Mapper = r.Mapper().RESTMapper
|
||||
|
||||
o.f = f
|
||||
// Set up writer
|
||||
o.Out = out
|
||||
o.ErrOut = errOut
|
||||
o.Mapper, err = f.ToRESTMapper()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.DynamicClient, err = f.DynamicClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *DeleteOptions) Validate(cmd *cobra.Command) error {
|
||||
if o.DeleteAll && len(o.Selector) > 0 {
|
||||
if o.Output != "" && o.Output != "name" {
|
||||
return cmdutil.UsageErrorf(cmd, "Unexpected -o output mode: %v. We only support '-o name'.", o.Output)
|
||||
}
|
||||
|
||||
if o.DeleteAll && len(o.LabelSelector) > 0 {
|
||||
return fmt.Errorf("cannot set --all and --selector at the same time")
|
||||
}
|
||||
if o.DeleteAll {
|
||||
f := cmd.Flags().Lookup("ignore-not-found")
|
||||
// The flag should never be missing
|
||||
if f == nil {
|
||||
return fmt.Errorf("missing --ignore-not-found flag")
|
||||
}
|
||||
// If the user didn't explicitly set the option, default to ignoring NotFound errors when used with --all
|
||||
if !f.Changed {
|
||||
o.IgnoreNotFound = true
|
||||
}
|
||||
if o.DeleteAll && len(o.FieldSelector) > 0 {
|
||||
return fmt.Errorf("cannot set --all and --field-selector at the same time")
|
||||
}
|
||||
if o.DeleteNow {
|
||||
if o.GracePeriod != -1 {
|
||||
return fmt.Errorf("--now and --grace-period cannot be specified together")
|
||||
}
|
||||
o.GracePeriod = 1
|
||||
|
||||
if o.GracePeriod == 0 && !o.ForceDeletion && !o.WaitForDeletion {
|
||||
// With the explicit --wait flag we need extra validation for backward compatibility
|
||||
return fmt.Errorf("--grace-period=0 must have either --force specified, or --wait to be set to true")
|
||||
}
|
||||
if o.GracePeriod == 0 {
|
||||
if o.ForceDeletion {
|
||||
fmt.Fprintf(o.ErrOut, "warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.\n")
|
||||
} else {
|
||||
// To preserve backwards compatibility, but prevent accidental data loss, we convert --grace-period=0
|
||||
// into --grace-period=1 and wait until the object is successfully deleted. Users may provide --force
|
||||
// to bypass this wait.
|
||||
o.WaitForDeletion = true
|
||||
o.GracePeriod = 1
|
||||
}
|
||||
|
||||
switch {
|
||||
case o.GracePeriod == 0 && o.ForceDeletion:
|
||||
fmt.Fprintf(o.ErrOut, "warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.\n")
|
||||
case o.ForceDeletion:
|
||||
fmt.Fprintf(o.ErrOut, "warning: --force is ignored because --grace-period is not 0.\n")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *DeleteOptions) RunDelete() error {
|
||||
shortOutput := o.Output == "name"
|
||||
// By default use a reaper to delete all related resources.
|
||||
if o.Cascade {
|
||||
return ReapResult(o.Result, o.f, o.Out, true, o.IgnoreNotFound, o.Timeout, o.GracePeriod, o.WaitForDeletion, shortOutput, false)
|
||||
}
|
||||
return DeleteResult(o.Result, o.Out, o.IgnoreNotFound, o.GracePeriod, shortOutput)
|
||||
return o.DeleteResult(o.Result)
|
||||
}
|
||||
|
||||
func ReapResult(r *resource.Result, f cmdutil.Factory, out io.Writer, isDefaultDelete, ignoreNotFound bool, timeout time.Duration, gracePeriod int, waitForDeletion, shortOutput bool, quiet bool) error {
|
||||
func (o *DeleteOptions) DeleteResult(r *resource.Result) error {
|
||||
found := 0
|
||||
if ignoreNotFound {
|
||||
r = r.IgnoreErrors(errors.IsNotFound)
|
||||
}
|
||||
err := r.Visit(func(info *resource.Info, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
found++
|
||||
reaper, err := f.Reaper(info.Mapping)
|
||||
if err != nil {
|
||||
// If there is no reaper for this resources and the user didn't explicitly ask for stop.
|
||||
if kubectl.IsNoSuchReaperError(err) && isDefaultDelete {
|
||||
// No client side reaper found. Let the server do cascading deletion.
|
||||
return cascadingDeleteResource(info, out, shortOutput)
|
||||
}
|
||||
return cmdutil.AddSourceToErr("reaping", info.Source, err)
|
||||
}
|
||||
var options *metav1.DeleteOptions
|
||||
if gracePeriod >= 0 {
|
||||
options = metav1.NewDeleteOptions(int64(gracePeriod))
|
||||
}
|
||||
if err := reaper.Stop(info.Namespace, info.Name, timeout, options); err != nil {
|
||||
return cmdutil.AddSourceToErr("stopping", info.Source, err)
|
||||
}
|
||||
if waitForDeletion {
|
||||
if err := waitForObjectDeletion(info, timeout); err != nil {
|
||||
return cmdutil.AddSourceToErr("stopping", info.Source, err)
|
||||
}
|
||||
}
|
||||
if !quiet {
|
||||
printDeletion(info, out, shortOutput)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if found == 0 {
|
||||
fmt.Fprintf(out, "No resources found\n")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeleteResult(r *resource.Result, out io.Writer, ignoreNotFound bool, gracePeriod int, shortOutput bool) error {
|
||||
found := 0
|
||||
if ignoreNotFound {
|
||||
if o.IgnoreNotFound {
|
||||
r = r.IgnoreErrors(errors.IsNotFound)
|
||||
}
|
||||
deletedInfos := []*resource.Info{}
|
||||
err := r.Visit(func(info *resource.Info, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
deletedInfos = append(deletedInfos, info)
|
||||
found++
|
||||
|
||||
// if we're here, it means that cascade=false (not the default), so we should orphan as requested
|
||||
orphan := true
|
||||
options := &metav1.DeleteOptions{}
|
||||
if gracePeriod >= 0 {
|
||||
options = metav1.NewDeleteOptions(int64(gracePeriod))
|
||||
if o.GracePeriod >= 0 {
|
||||
options = metav1.NewDeleteOptions(int64(o.GracePeriod))
|
||||
}
|
||||
options.OrphanDependents = &orphan
|
||||
return deleteResource(info, out, shortOutput, options)
|
||||
policy := metav1.DeletePropagationBackground
|
||||
if !o.Cascade {
|
||||
policy = metav1.DeletePropagationOrphan
|
||||
}
|
||||
options.PropagationPolicy = &policy
|
||||
|
||||
return o.deleteResource(info, options)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if found == 0 {
|
||||
fmt.Fprintf(out, "No resources found\n")
|
||||
fmt.Fprintf(o.Out, "No resources found\n")
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
if !o.WaitForDeletion {
|
||||
return nil
|
||||
}
|
||||
// if we don't have a dynamic client, we don't want to wait. Eventually when delete is cleaned up, this will likely
|
||||
// drop out.
|
||||
if o.DynamicClient == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
effectiveTimeout := o.Timeout
|
||||
if effectiveTimeout == 0 {
|
||||
// if we requested to wait forever, set it to a week.
|
||||
effectiveTimeout = 168 * time.Hour
|
||||
}
|
||||
waitOptions := kubectlwait.WaitOptions{
|
||||
ResourceFinder: genericclioptions.ResourceFinderForResult(resource.InfoListVisitor(deletedInfos)),
|
||||
DynamicClient: o.DynamicClient,
|
||||
Timeout: effectiveTimeout,
|
||||
|
||||
Printer: printers.NewDiscardingPrinter(),
|
||||
ConditionFn: kubectlwait.IsDeleted,
|
||||
IOStreams: o.IOStreams,
|
||||
}
|
||||
err = waitOptions.RunWait()
|
||||
if errors.IsForbidden(err) {
|
||||
// if we're forbidden from waiting, we shouldn't fail.
|
||||
glog.V(1).Info(err)
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func cascadingDeleteResource(info *resource.Info, out io.Writer, shortOutput bool) error {
|
||||
falseVar := false
|
||||
deleteOptions := &metav1.DeleteOptions{OrphanDependents: &falseVar}
|
||||
return deleteResource(info, out, shortOutput, deleteOptions)
|
||||
}
|
||||
func (o *DeleteOptions) deleteResource(info *resource.Info, deleteOptions *metav1.DeleteOptions) error {
|
||||
// TODO: Remove this in or after 1.12 release.
|
||||
// Server version >= 1.11 no longer needs this hack.
|
||||
mapping := info.ResourceMapping()
|
||||
if mapping.Resource.GroupResource() == (schema.GroupResource{Group: "extensions", Resource: "daemonsets"}) ||
|
||||
mapping.Resource.GroupResource() == (schema.GroupResource{Group: "apps", Resource: "daemonsets"}) {
|
||||
if err := updateDaemonSet(info.Namespace, info.Name, o.DynamicClient); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func deleteResource(info *resource.Info, out io.Writer, shortOutput bool, deleteOptions *metav1.DeleteOptions) error {
|
||||
if err := resource.NewHelper(info.Client, info.Mapping).DeleteWithOptions(info.Namespace, info.Name, deleteOptions); err != nil {
|
||||
return cmdutil.AddSourceToErr("deleting", info.Source, err)
|
||||
}
|
||||
|
||||
printDeletion(info, out, shortOutput)
|
||||
o.PrintObj(info)
|
||||
return nil
|
||||
}
|
||||
|
||||
// deletion printing is special because they don't have an object to print. This logic mirrors PrintSuccess
|
||||
func printDeletion(info *resource.Info, out io.Writer, shortOutput bool) {
|
||||
// TODO: Remove this in or after 1.12 release.
|
||||
// Server version >= 1.11 no longer needs this hack.
|
||||
func updateDaemonSet(namespace, name string, dynamicClient dynamic.Interface) error {
|
||||
dsClient := dynamicClient.Resource(schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "daemonsets"}).Namespace(namespace)
|
||||
obj, err := dsClient.Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ds := &appsv1.DaemonSet{}
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, ds); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// We set the nodeSelector to a random label. This label is nearly guaranteed
|
||||
// to not be set on any node so the DameonSetController will start deleting
|
||||
// daemon pods. Once it's done deleting the daemon pods, it's safe to delete
|
||||
// the DaemonSet.
|
||||
ds.Spec.Template.Spec.NodeSelector = map[string]string{
|
||||
string(uuid.NewUUID()): string(uuid.NewUUID()),
|
||||
}
|
||||
// force update to avoid version conflict
|
||||
ds.ResourceVersion = ""
|
||||
|
||||
out, err := runtime.DefaultUnstructuredConverter.ToUnstructured(ds)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = dsClient.Update(&unstructured.Unstructured{Object: out}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Wait for the daemon set controller to kill all the daemon pods.
|
||||
if err := wait.Poll(1*time.Second, 5*time.Minute, func() (bool, error) {
|
||||
updatedObj, err := dsClient.Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
updatedDS := &appsv1.DaemonSet{}
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(updatedObj.Object, ds); err != nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return updatedDS.Status.CurrentNumberScheduled+updatedDS.Status.NumberMisscheduled == 0, nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// deletion printing is special because we do not have an object to print.
|
||||
// This mirrors name printer behavior
|
||||
func (o *DeleteOptions) PrintObj(info *resource.Info) {
|
||||
operation := "deleted"
|
||||
groupKind := info.Mapping.GroupVersionKind
|
||||
kindString := fmt.Sprintf("%s.%s", strings.ToLower(groupKind.Kind), groupKind.Group)
|
||||
@ -329,33 +371,16 @@ func printDeletion(info *resource.Info, out io.Writer, shortOutput bool) {
|
||||
kindString = strings.ToLower(groupKind.Kind)
|
||||
}
|
||||
|
||||
if shortOutput {
|
||||
if o.GracePeriod == 0 {
|
||||
operation = "force deleted"
|
||||
}
|
||||
|
||||
if o.Output == "name" {
|
||||
// -o name: prints resource/name
|
||||
fmt.Fprintf(out, "%s/%s\n", kindString, info.Name)
|
||||
fmt.Fprintf(o.Out, "%s/%s\n", kindString, info.Name)
|
||||
return
|
||||
}
|
||||
|
||||
// understandable output by default
|
||||
fmt.Fprintf(out, "%s \"%s\" %s\n", kindString, info.Name, operation)
|
||||
}
|
||||
|
||||
// objectDeletionWaitInterval is the interval to wait between checks for deletion.
|
||||
var objectDeletionWaitInterval = time.Second
|
||||
|
||||
// waitForObjectDeletion refreshes the object, waiting until it is deleted, a timeout is reached, or
|
||||
// an error is encountered. It checks once a second.
|
||||
func waitForObjectDeletion(info *resource.Info, timeout time.Duration) error {
|
||||
copied := *info
|
||||
info = &copied
|
||||
// TODO: refactor Reaper so that we can pass the "wait" option into it, and then check for UID change.
|
||||
return wait.PollImmediate(objectDeletionWaitInterval, timeout, func() (bool, error) {
|
||||
switch err := info.Get(); {
|
||||
case err == nil:
|
||||
return false, nil
|
||||
case errors.IsNotFound(err):
|
||||
return true, nil
|
||||
default:
|
||||
return false, err
|
||||
}
|
||||
})
|
||||
fmt.Fprintf(o.Out, "%s \"%s\" %s\n", kindString, info.Name, operation)
|
||||
}
|
||||
|
193
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/delete_flags.go
generated
vendored
Normal file
193
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/delete_flags.go
generated
vendored
Normal file
@ -0,0 +1,193 @@
|
||||
/*
|
||||
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 (
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
)
|
||||
|
||||
// PrintFlags composes common printer flag structs
|
||||
// used for commands requiring deletion logic.
|
||||
type DeleteFlags struct {
|
||||
FileNameFlags *genericclioptions.FileNameFlags
|
||||
LabelSelector *string
|
||||
FieldSelector *string
|
||||
|
||||
All *bool
|
||||
Cascade *bool
|
||||
Force *bool
|
||||
GracePeriod *int
|
||||
IgnoreNotFound *bool
|
||||
Now *bool
|
||||
Timeout *time.Duration
|
||||
Wait *bool
|
||||
Output *string
|
||||
}
|
||||
|
||||
func (f *DeleteFlags) ToOptions(dynamicClient dynamic.Interface, streams genericclioptions.IOStreams) *DeleteOptions {
|
||||
options := &DeleteOptions{
|
||||
DynamicClient: dynamicClient,
|
||||
IOStreams: streams,
|
||||
}
|
||||
|
||||
// add filename options
|
||||
if f.FileNameFlags != nil {
|
||||
options.FilenameOptions = f.FileNameFlags.ToOptions()
|
||||
}
|
||||
if f.LabelSelector != nil {
|
||||
options.LabelSelector = *f.LabelSelector
|
||||
}
|
||||
if f.FieldSelector != nil {
|
||||
options.FieldSelector = *f.FieldSelector
|
||||
}
|
||||
|
||||
// add output format
|
||||
if f.Output != nil {
|
||||
options.Output = *f.Output
|
||||
}
|
||||
|
||||
if f.All != nil {
|
||||
options.DeleteAll = *f.All
|
||||
}
|
||||
if f.Cascade != nil {
|
||||
options.Cascade = *f.Cascade
|
||||
}
|
||||
if f.Force != nil {
|
||||
options.ForceDeletion = *f.Force
|
||||
}
|
||||
if f.GracePeriod != nil {
|
||||
options.GracePeriod = *f.GracePeriod
|
||||
}
|
||||
if f.IgnoreNotFound != nil {
|
||||
options.IgnoreNotFound = *f.IgnoreNotFound
|
||||
}
|
||||
if f.Now != nil {
|
||||
options.DeleteNow = *f.Now
|
||||
}
|
||||
if f.Timeout != nil {
|
||||
options.Timeout = *f.Timeout
|
||||
}
|
||||
if f.Wait != nil {
|
||||
options.WaitForDeletion = *f.Wait
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
func (f *DeleteFlags) AddFlags(cmd *cobra.Command) {
|
||||
f.FileNameFlags.AddFlags(cmd.Flags())
|
||||
if f.LabelSelector != nil {
|
||||
cmd.Flags().StringVarP(f.LabelSelector, "selector", "l", *f.LabelSelector, "Selector (label query) to filter on, not including uninitialized ones.")
|
||||
}
|
||||
if f.FieldSelector != nil {
|
||||
cmd.Flags().StringVarP(f.FieldSelector, "field-selector", "", *f.FieldSelector, "Selector (field query) to filter on, supports '=', '==', and '!='.(e.g. --field-selector key1=value1,key2=value2). The server only supports a limited number of field queries per type.")
|
||||
}
|
||||
if f.All != nil {
|
||||
cmd.Flags().BoolVar(f.All, "all", *f.All, "Delete all resources, including uninitialized ones, in the namespace of the specified resource types.")
|
||||
}
|
||||
if f.Force != nil {
|
||||
cmd.Flags().BoolVar(f.Force, "force", *f.Force, "Only used when grace-period=0. If true, immediately remove resources from API and bypass graceful deletion. Note that immediate deletion of some resources may result in inconsistency or data loss and requires confirmation.")
|
||||
}
|
||||
if f.Cascade != nil {
|
||||
cmd.Flags().BoolVar(f.Cascade, "cascade", *f.Cascade, "If true, cascade the deletion of the resources managed by this resource (e.g. Pods created by a ReplicationController). Default true.")
|
||||
}
|
||||
if f.Now != nil {
|
||||
cmd.Flags().BoolVar(f.Now, "now", *f.Now, "If true, resources are signaled for immediate shutdown (same as --grace-period=1).")
|
||||
}
|
||||
if f.GracePeriod != nil {
|
||||
cmd.Flags().IntVar(f.GracePeriod, "grace-period", *f.GracePeriod, "Period of time in seconds given to the resource to terminate gracefully. Ignored if negative. Set to 1 for immediate shutdown. Can only be set to 0 when --force is true (force deletion).")
|
||||
}
|
||||
if f.Timeout != nil {
|
||||
cmd.Flags().DurationVar(f.Timeout, "timeout", *f.Timeout, "The length of time to wait before giving up on a delete, zero means determine a timeout from the size of the object")
|
||||
}
|
||||
if f.IgnoreNotFound != nil {
|
||||
cmd.Flags().BoolVar(f.IgnoreNotFound, "ignore-not-found", *f.IgnoreNotFound, "Treat \"resource not found\" as a successful delete. Defaults to \"true\" when --all is specified.")
|
||||
}
|
||||
if f.Wait != nil {
|
||||
cmd.Flags().BoolVar(f.Wait, "wait", *f.Wait, "If true, wait for resources to be gone before returning. This waits for finalizers.")
|
||||
}
|
||||
if f.Output != nil {
|
||||
cmd.Flags().StringVarP(f.Output, "output", "o", *f.Output, "Output mode. Use \"-o name\" for shorter output (resource/name).")
|
||||
}
|
||||
}
|
||||
|
||||
// NewDeleteCommandFlags provides default flags and values for use with the "delete" command
|
||||
func NewDeleteCommandFlags(usage string) *DeleteFlags {
|
||||
cascade := true
|
||||
gracePeriod := -1
|
||||
|
||||
// setup command defaults
|
||||
all := false
|
||||
force := false
|
||||
ignoreNotFound := false
|
||||
now := false
|
||||
output := ""
|
||||
labelSelector := ""
|
||||
fieldSelector := ""
|
||||
timeout := time.Duration(0)
|
||||
wait := true
|
||||
|
||||
filenames := []string{}
|
||||
recursive := false
|
||||
|
||||
return &DeleteFlags{
|
||||
FileNameFlags: &genericclioptions.FileNameFlags{Usage: usage, Filenames: &filenames, Recursive: &recursive},
|
||||
LabelSelector: &labelSelector,
|
||||
FieldSelector: &fieldSelector,
|
||||
|
||||
Cascade: &cascade,
|
||||
GracePeriod: &gracePeriod,
|
||||
|
||||
All: &all,
|
||||
Force: &force,
|
||||
IgnoreNotFound: &ignoreNotFound,
|
||||
Now: &now,
|
||||
Timeout: &timeout,
|
||||
Wait: &wait,
|
||||
Output: &output,
|
||||
}
|
||||
}
|
||||
|
||||
// NewDeleteFlags provides default flags and values for use in commands outside of "delete"
|
||||
func NewDeleteFlags(usage string) *DeleteFlags {
|
||||
cascade := true
|
||||
gracePeriod := -1
|
||||
|
||||
force := false
|
||||
timeout := time.Duration(0)
|
||||
wait := false
|
||||
|
||||
filenames := []string{}
|
||||
recursive := false
|
||||
|
||||
return &DeleteFlags{
|
||||
FileNameFlags: &genericclioptions.FileNameFlags{Usage: usage, Filenames: &filenames, Recursive: &recursive},
|
||||
|
||||
Cascade: &cascade,
|
||||
GracePeriod: &gracePeriod,
|
||||
|
||||
// add non-defaults
|
||||
Force: &force,
|
||||
Timeout: &timeout,
|
||||
Wait: &wait,
|
||||
}
|
||||
}
|
295
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/delete_test.go
generated
vendored
295
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/delete_test.go
generated
vendored
@ -17,47 +17,45 @@ limitations under the License.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"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/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
)
|
||||
|
||||
var unstructuredSerializer = dynamic.ContentConfig().NegotiatedSerializer
|
||||
var unstructuredSerializer = resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer
|
||||
|
||||
var fakecmd = &cobra.Command{
|
||||
Use: "delete ([-f FILENAME] | TYPE [(NAME | -l label | --all)])",
|
||||
DisableFlagsInUseLine: true,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
|
||||
},
|
||||
func fakecmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "delete ([-f FILENAME] | TYPE [(NAME | -l label | --all)])",
|
||||
DisableFlagsInUseLine: true,
|
||||
Run: func(cmd *cobra.Command, args []string) {},
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func TestDeleteObjectByTuple(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
_, _, rc := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -79,10 +77,9 @@ func TestDeleteObjectByTuple(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdDelete(tf, buf, errBuf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("namespace", "test")
|
||||
cmd.Flags().Set("cascade", "false")
|
||||
cmd.Flags().Set("output", "name")
|
||||
@ -92,8 +89,8 @@ func TestDeleteObjectByTuple(t *testing.T) {
|
||||
}
|
||||
|
||||
// Test cascading delete of object without client-side reaper doesn't make GET requests
|
||||
buf, errBuf = bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
cmd = NewCmdDelete(tf, buf, errBuf)
|
||||
streams, _, buf, _ = genericclioptions.NewTestIOStreams()
|
||||
cmd = NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("namespace", "test")
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{"secrets/mysecret"})
|
||||
@ -102,17 +99,17 @@ func TestDeleteObjectByTuple(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func hasExpectedOrphanDependents(body io.ReadCloser, expectedOrphanDependents *bool) bool {
|
||||
if body == nil || expectedOrphanDependents == nil {
|
||||
return body == nil && expectedOrphanDependents == nil
|
||||
func hasExpectedPropagationPolicy(body io.ReadCloser, policy *metav1.DeletionPropagation) bool {
|
||||
if body == nil || policy == nil {
|
||||
return body == nil && policy == nil
|
||||
}
|
||||
var parsedBody metav1.DeleteOptions
|
||||
rawBody, _ := ioutil.ReadAll(body)
|
||||
json.Unmarshal(rawBody, &parsedBody)
|
||||
if parsedBody.OrphanDependents == nil {
|
||||
if parsedBody.PropagationPolicy == nil {
|
||||
return false
|
||||
}
|
||||
return *expectedOrphanDependents == *parsedBody.OrphanDependents
|
||||
return *policy == *parsedBody.PropagationPolicy
|
||||
}
|
||||
|
||||
// Tests that DeleteOptions.OrphanDependents is appropriately set while deleting objects.
|
||||
@ -120,16 +117,18 @@ func TestOrphanDependentsInDeleteObject(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
_, _, rc := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
var expectedOrphanDependents *bool
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
var policy *metav1.DeletionPropagation
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch p, m, b := req.URL.Path, req.Method, req.Body; {
|
||||
|
||||
case p == "/namespaces/test/secrets/mysecret" && m == "DELETE" && hasExpectedOrphanDependents(b, expectedOrphanDependents):
|
||||
case p == "/namespaces/test/secrets/mysecret" && m == "DELETE" && hasExpectedPropagationPolicy(b, policy):
|
||||
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &rc.Items[0])}, nil
|
||||
default:
|
||||
@ -137,13 +136,12 @@ func TestOrphanDependentsInDeleteObject(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
|
||||
// DeleteOptions.OrphanDependents should be false, when cascade is true (default).
|
||||
falseVar := false
|
||||
expectedOrphanDependents = &falseVar
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdDelete(tf, buf, errBuf)
|
||||
// DeleteOptions.PropagationPolicy should be Background, when cascade is true (default).
|
||||
backgroundPolicy := metav1.DeletePropagationBackground
|
||||
policy = &backgroundPolicy
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("namespace", "test")
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{"secrets/mysecret"})
|
||||
@ -152,10 +150,10 @@ func TestOrphanDependentsInDeleteObject(t *testing.T) {
|
||||
}
|
||||
|
||||
// Test that delete options should be set to orphan when cascade is false.
|
||||
trueVar := true
|
||||
expectedOrphanDependents = &trueVar
|
||||
buf, errBuf = bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
cmd = NewCmdDelete(tf, buf, errBuf)
|
||||
orphanPolicy := metav1.DeletePropagationOrphan
|
||||
policy = &orphanPolicy
|
||||
streams, _, buf, _ = genericclioptions.NewTestIOStreams()
|
||||
cmd = NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("namespace", "test")
|
||||
cmd.Flags().Set("cascade", "false")
|
||||
cmd.Flags().Set("output", "name")
|
||||
@ -170,8 +168,10 @@ func TestDeleteNamedObject(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
_, _, rc := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -193,10 +193,9 @@ func TestDeleteNamedObject(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdDelete(tf, buf, errBuf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("namespace", "test")
|
||||
cmd.Flags().Set("cascade", "false")
|
||||
cmd.Flags().Set("output", "name")
|
||||
@ -206,8 +205,8 @@ func TestDeleteNamedObject(t *testing.T) {
|
||||
}
|
||||
|
||||
// Test cascading delete of object without client-side reaper doesn't make GET requests
|
||||
buf, errBuf = bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
cmd = NewCmdDelete(tf, buf, errBuf)
|
||||
streams, _, buf, _ = genericclioptions.NewTestIOStreams()
|
||||
cmd = NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("namespace", "test")
|
||||
cmd.Flags().Set("cascade", "false")
|
||||
cmd.Flags().Set("output", "name")
|
||||
@ -221,8 +220,10 @@ func TestDeleteObject(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
_, _, rc := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -236,11 +237,10 @@ func TestDeleteObject(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdDelete(tf, buf, errBuf)
|
||||
cmd.Flags().Set("filename", "../../../examples/guestbook/legacy/redis-master-controller.yaml")
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("filename", "../../../test/e2e/testing-manifests/guestbook/legacy/redis-master-controller.yaml")
|
||||
cmd.Flags().Set("cascade", "false")
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{})
|
||||
@ -251,37 +251,15 @@ func TestDeleteObject(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
type fakeReaper struct {
|
||||
namespace, name string
|
||||
timeout time.Duration
|
||||
deleteOptions *metav1.DeleteOptions
|
||||
err error
|
||||
}
|
||||
|
||||
func (r *fakeReaper) Stop(namespace, name string, timeout time.Duration, gracePeriod *metav1.DeleteOptions) error {
|
||||
r.namespace, r.name = namespace, name
|
||||
r.timeout = timeout
|
||||
r.deleteOptions = gracePeriod
|
||||
return r.err
|
||||
}
|
||||
|
||||
type fakeReaperFactory struct {
|
||||
cmdutil.Factory
|
||||
reaper kubectl.Reaper
|
||||
}
|
||||
|
||||
func (f *fakeReaperFactory) Reaper(mapping *meta.RESTMapping) (kubectl.Reaper, error) {
|
||||
return f.reaper, nil
|
||||
}
|
||||
|
||||
func TestDeleteObjectGraceZero(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
pods, _, _ := testData()
|
||||
|
||||
objectDeletionWaitInterval = time.Millisecond
|
||||
count := 0
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -306,12 +284,9 @@ func TestDeleteObjectGraceZero(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
|
||||
reaper := &fakeReaper{}
|
||||
fake := &fakeReaperFactory{Factory: tf, reaper: reaper}
|
||||
cmd := NewCmdDelete(fake, buf, errBuf)
|
||||
streams, _, buf, errBuf := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Flags().Set("grace-period", "0")
|
||||
cmd.Run(cmd, []string{"pods/nginx"})
|
||||
@ -320,17 +295,16 @@ func TestDeleteObjectGraceZero(t *testing.T) {
|
||||
if buf.String() != "pod/nginx\n" {
|
||||
t.Errorf("unexpected output: %s\n---\n%s", buf.String(), errBuf.String())
|
||||
}
|
||||
if reaper.deleteOptions == nil || reaper.deleteOptions.GracePeriodSeconds == nil || *reaper.deleteOptions.GracePeriodSeconds != 1 {
|
||||
t.Errorf("unexpected reaper options: %#v", reaper)
|
||||
}
|
||||
if count != 4 {
|
||||
if count != 0 {
|
||||
t.Errorf("unexpected calls to GET: %d", count)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteObjectNotFound(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
@ -343,18 +317,17 @@ func TestDeleteObjectNotFound(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
|
||||
options := &DeleteOptions{
|
||||
FilenameOptions: resource.FilenameOptions{
|
||||
Filenames: []string{"../../../examples/guestbook/legacy/redis-master-controller.yaml"},
|
||||
Filenames: []string{"../../../test/e2e/testing-manifests/guestbook/legacy/redis-master-controller.yaml"},
|
||||
},
|
||||
GracePeriod: -1,
|
||||
Cascade: false,
|
||||
Output: "name",
|
||||
IOStreams: genericclioptions.NewTestIOStreamsDiscard(),
|
||||
}
|
||||
err := options.Complete(tf, buf, errBuf, []string{}, fakecmd)
|
||||
err := options.Complete(tf, []string{}, fakecmd())
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
@ -366,7 +339,9 @@ func TestDeleteObjectNotFound(t *testing.T) {
|
||||
|
||||
func TestDeleteObjectIgnoreNotFound(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
@ -379,11 +354,10 @@ func TestDeleteObjectIgnoreNotFound(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
|
||||
cmd := NewCmdDelete(tf, buf, errBuf)
|
||||
cmd.Flags().Set("filename", "../../../examples/guestbook/legacy/redis-master-controller.yaml")
|
||||
cmd := NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("filename", "../../../test/e2e/testing-manifests/guestbook/legacy/redis-master-controller.yaml")
|
||||
cmd.Flags().Set("cascade", "false")
|
||||
cmd.Flags().Set("ignore-not-found", "true")
|
||||
cmd.Flags().Set("output", "name")
|
||||
@ -401,8 +375,10 @@ func TestDeleteAllNotFound(t *testing.T) {
|
||||
svc.Items = append(svc.Items, api.Service{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})
|
||||
notFoundError := &errors.NewNotFound(api.Resource("services"), "foo").ErrStatus
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -420,8 +396,6 @@ func TestDeleteAllNotFound(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
|
||||
// Make sure we can explicitly choose to fail on NotFound errors, even with --all
|
||||
options := &DeleteOptions{
|
||||
@ -431,8 +405,9 @@ func TestDeleteAllNotFound(t *testing.T) {
|
||||
DeleteAll: true,
|
||||
IgnoreNotFound: false,
|
||||
Output: "name",
|
||||
IOStreams: genericclioptions.NewTestIOStreamsDiscard(),
|
||||
}
|
||||
err := options.Complete(tf, buf, errBuf, []string{"services"}, fakecmd)
|
||||
err := options.Complete(tf, []string{"services"}, fakecmd())
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
@ -446,8 +421,10 @@ func TestDeleteAllIgnoreNotFound(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
_, svc, _ := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
// Add an item to the list which will result in a 404 on delete
|
||||
svc.Items = append(svc.Items, api.Service{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})
|
||||
@ -469,10 +446,9 @@ func TestDeleteAllIgnoreNotFound(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
|
||||
cmd := NewCmdDelete(tf, buf, errBuf)
|
||||
cmd := NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("all", "true")
|
||||
cmd.Flags().Set("cascade", "false")
|
||||
cmd.Flags().Set("output", "name")
|
||||
@ -487,8 +463,10 @@ func TestDeleteMultipleObject(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
_, svc, rc := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -504,12 +482,11 @@ func TestDeleteMultipleObject(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
|
||||
cmd := NewCmdDelete(tf, buf, errBuf)
|
||||
cmd.Flags().Set("filename", "../../../examples/guestbook/legacy/redis-master-controller.yaml")
|
||||
cmd.Flags().Set("filename", "../../../examples/guestbook/frontend-service.yaml")
|
||||
cmd := NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("filename", "../../../test/e2e/testing-manifests/guestbook/legacy/redis-master-controller.yaml")
|
||||
cmd.Flags().Set("filename", "../../../test/e2e/testing-manifests/guestbook/frontend-service.yaml")
|
||||
cmd.Flags().Set("cascade", "false")
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{})
|
||||
@ -523,8 +500,10 @@ func TestDeleteMultipleObjectContinueOnMissing(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
_, svc, _ := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -540,18 +519,18 @@ func TestDeleteMultipleObjectContinueOnMissing(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
|
||||
options := &DeleteOptions{
|
||||
FilenameOptions: resource.FilenameOptions{
|
||||
Filenames: []string{"../../../examples/guestbook/legacy/redis-master-controller.yaml", "../../../examples/guestbook/frontend-service.yaml"},
|
||||
Filenames: []string{"../../../test/e2e/testing-manifests/guestbook/legacy/redis-master-controller.yaml", "../../../test/e2e/testing-manifests/guestbook/frontend-service.yaml"},
|
||||
},
|
||||
GracePeriod: -1,
|
||||
Cascade: false,
|
||||
Output: "name",
|
||||
IOStreams: streams,
|
||||
}
|
||||
err := options.Complete(tf, buf, errBuf, []string{}, fakecmd)
|
||||
err := options.Complete(tf, []string{}, fakecmd())
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
@ -568,8 +547,10 @@ func TestDeleteMultipleObjectContinueOnMissing(t *testing.T) {
|
||||
func TestDeleteMultipleResourcesWithTheSameName(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
_, svc, rc := testData()
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -590,10 +571,9 @@ func TestDeleteMultipleResourcesWithTheSameName(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
|
||||
cmd := NewCmdDelete(tf, buf, errBuf)
|
||||
cmd := NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("namespace", "test")
|
||||
cmd.Flags().Set("cascade", "false")
|
||||
cmd.Flags().Set("output", "name")
|
||||
@ -607,8 +587,10 @@ func TestDeleteDirectory(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
_, _, rc := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -622,11 +604,10 @@ func TestDeleteDirectory(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
|
||||
cmd := NewCmdDelete(tf, buf, errBuf)
|
||||
cmd.Flags().Set("filename", "../../../examples/guestbook/legacy")
|
||||
cmd := NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("filename", "../../../test/e2e/testing-manifests/guestbook/legacy")
|
||||
cmd.Flags().Set("cascade", "false")
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{})
|
||||
@ -640,8 +621,10 @@ func TestDeleteMultipleSelector(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
pods, svc, _ := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -667,10 +650,9 @@ func TestDeleteMultipleSelector(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
|
||||
cmd := NewCmdDelete(tf, buf, errBuf)
|
||||
cmd := NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("selector", "a=b")
|
||||
cmd.Flags().Set("cascade", "false")
|
||||
cmd.Flags().Set("output", "name")
|
||||
@ -706,26 +688,29 @@ func TestResourceErrors(t *testing.T) {
|
||||
}
|
||||
|
||||
for k, testCase := range testCases {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
t.Run(k, func(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
options := &DeleteOptions{
|
||||
FilenameOptions: resource.FilenameOptions{},
|
||||
GracePeriod: -1,
|
||||
Cascade: false,
|
||||
Output: "name",
|
||||
}
|
||||
err := options.Complete(tf, buf, errBuf, testCase.args, fakecmd)
|
||||
if !testCase.errFn(err) {
|
||||
t.Errorf("%s: unexpected error: %v", k, err)
|
||||
continue
|
||||
}
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
options := &DeleteOptions{
|
||||
FilenameOptions: resource.FilenameOptions{},
|
||||
GracePeriod: -1,
|
||||
Cascade: false,
|
||||
Output: "name",
|
||||
IOStreams: streams,
|
||||
}
|
||||
err := options.Complete(tf, testCase.args, fakecmd())
|
||||
if !testCase.errFn(err) {
|
||||
t.Errorf("%s: unexpected error: %v", k, err)
|
||||
return
|
||||
}
|
||||
|
||||
if buf.Len() > 0 {
|
||||
t.Errorf("buffer should be empty: %s", string(buf.Bytes()))
|
||||
}
|
||||
if buf.Len() > 0 {
|
||||
t.Errorf("buffer should be empty: %s", string(buf.Bytes()))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
137
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/describe.go
generated
vendored
137
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/describe.go
generated
vendored
@ -18,21 +18,20 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"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/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -69,67 +68,103 @@ var (
|
||||
kubectl describe pods frontend`))
|
||||
)
|
||||
|
||||
func NewCmdDescribe(f cmdutil.Factory, out, cmdErr io.Writer) *cobra.Command {
|
||||
options := &resource.FilenameOptions{}
|
||||
describerSettings := &printers.DescriberSettings{}
|
||||
type DescribeOptions struct {
|
||||
CmdParent string
|
||||
Selector string
|
||||
Namespace string
|
||||
|
||||
// TODO: this should come from the factory, and may need to be loaded from the server, and so is probably
|
||||
// going to have to be removed
|
||||
validArgs := printersinternal.DescribableResources()
|
||||
argAliases := kubectl.ResourceAliases(validArgs)
|
||||
Describer func(*meta.RESTMapping) (printers.Describer, error)
|
||||
NewBuilder func() *resource.Builder
|
||||
|
||||
BuilderArgs []string
|
||||
|
||||
EnforceNamespace bool
|
||||
AllNamespaces bool
|
||||
IncludeUninitialized bool
|
||||
|
||||
DescriberSettings *printers.DescriberSettings
|
||||
FilenameOptions *resource.FilenameOptions
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
func NewCmdDescribe(parent string, f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := &DescribeOptions{
|
||||
FilenameOptions: &resource.FilenameOptions{},
|
||||
DescriberSettings: &printers.DescriberSettings{
|
||||
ShowEvents: true,
|
||||
},
|
||||
|
||||
CmdParent: parent,
|
||||
|
||||
IOStreams: streams,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "describe (-f FILENAME | TYPE [NAME_PREFIX | -l label] | TYPE/NAME)",
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: i18n.T("Show details of a specific resource or group of resources"),
|
||||
Long: describeLong + "\n\n" + cmdutil.ValidResourceTypeList(f),
|
||||
Long: describeLong + "\n\n" + cmdutil.SuggestApiResources(parent),
|
||||
Example: describeExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := RunDescribe(f, out, cmdErr, cmd, args, options, describerSettings)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(o.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(o.Run())
|
||||
},
|
||||
ValidArgs: validArgs,
|
||||
ArgAliases: argAliases,
|
||||
}
|
||||
usage := "containing the resource to describe"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, options, usage)
|
||||
cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
|
||||
cmd.Flags().Bool("all-namespaces", false, "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.")
|
||||
cmd.Flags().BoolVar(&describerSettings.ShowEvents, "show-events", true, "If true, display events related to the described object.")
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
cmdutil.AddFilenameOptionFlags(cmd, o.FilenameOptions, usage)
|
||||
cmd.Flags().StringVarP(&o.Selector, "selector", "l", o.Selector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
|
||||
cmd.Flags().BoolVar(&o.AllNamespaces, "all-namespaces", o.AllNamespaces, "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.")
|
||||
cmd.Flags().BoolVar(&o.DescriberSettings.ShowEvents, "show-events", o.DescriberSettings.ShowEvents, "If true, display events related to the described object.")
|
||||
cmdutil.AddIncludeUninitializedFlag(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, args []string, options *resource.FilenameOptions, describerSettings *printers.DescriberSettings) error {
|
||||
selector := cmdutil.GetFlagString(cmd, "selector")
|
||||
allNamespaces := cmdutil.GetFlagBool(cmd, "all-namespaces")
|
||||
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
func (o *DescribeOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
var err error
|
||||
o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if allNamespaces {
|
||||
enforceNamespace = false
|
||||
|
||||
if o.AllNamespaces {
|
||||
o.EnforceNamespace = false
|
||||
}
|
||||
if len(args) == 0 && cmdutil.IsFilenameSliceEmpty(options.Filenames) {
|
||||
fmt.Fprint(cmdErr, "You must specify the type of resource to describe. ", cmdutil.ValidResourceTypeList(f))
|
||||
return cmdutil.UsageErrorf(cmd, "Required resource not specified.")
|
||||
|
||||
if len(args) == 0 && cmdutil.IsFilenameSliceEmpty(o.FilenameOptions.Filenames) {
|
||||
return fmt.Errorf("You must specify the type of resource to describe. %s\n", cmdutil.SuggestApiResources(o.CmdParent))
|
||||
}
|
||||
|
||||
o.BuilderArgs = args
|
||||
|
||||
o.Describer = func(mapping *meta.RESTMapping) (printers.Describer, error) {
|
||||
return cmdutil.DescriberFn(f, mapping)
|
||||
}
|
||||
|
||||
o.NewBuilder = f.NewBuilder
|
||||
|
||||
// include the uninitialized objects by default
|
||||
// unless user explicitly set --include-uninitialized=false
|
||||
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, true)
|
||||
r := f.NewBuilder().
|
||||
o.IncludeUninitialized = cmdutil.ShouldIncludeUninitialized(cmd, true)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *DescribeOptions) Validate(args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *DescribeOptions) Run() error {
|
||||
r := o.NewBuilder().
|
||||
Unstructured().
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().AllNamespaces(allNamespaces).
|
||||
FilenameParam(enforceNamespace, options).
|
||||
LabelSelectorParam(selector).
|
||||
IncludeUninitialized(includeUninitialized).
|
||||
ResourceTypeOrNameArgs(true, args...).
|
||||
NamespaceParam(o.Namespace).DefaultNamespace().AllNamespaces(o.AllNamespaces).
|
||||
FilenameParam(o.EnforceNamespace, o.FilenameOptions).
|
||||
LabelSelectorParam(o.Selector).
|
||||
IncludeUninitialized(o.IncludeUninitialized).
|
||||
ResourceTypeOrNameArgs(true, o.BuilderArgs...).
|
||||
Flatten().
|
||||
Do()
|
||||
err = r.Err()
|
||||
err := r.Err()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -137,8 +172,8 @@ func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, a
|
||||
allErrs := []error{}
|
||||
infos, err := r.Infos()
|
||||
if err != nil {
|
||||
if apierrors.IsNotFound(err) && len(args) == 2 {
|
||||
return DescribeMatchingResources(f, cmdNamespace, args[0], args[1], describerSettings, out, err)
|
||||
if apierrors.IsNotFound(err) && len(o.BuilderArgs) == 2 {
|
||||
return o.DescribeMatchingResources(err, o.BuilderArgs[0], o.BuilderArgs[1])
|
||||
}
|
||||
allErrs = append(allErrs, err)
|
||||
}
|
||||
@ -147,7 +182,7 @@ func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, a
|
||||
first := true
|
||||
for _, info := range infos {
|
||||
mapping := info.ResourceMapping()
|
||||
describer, err := f.Describer(mapping)
|
||||
describer, err := o.Describer(mapping)
|
||||
if err != nil {
|
||||
if errs.Has(err.Error()) {
|
||||
continue
|
||||
@ -156,7 +191,7 @@ func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, a
|
||||
errs.Insert(err.Error())
|
||||
continue
|
||||
}
|
||||
s, err := describer.Describe(info.Namespace, info.Name, *describerSettings)
|
||||
s, err := describer.Describe(info.Namespace, info.Name, *o.DescriberSettings)
|
||||
if err != nil {
|
||||
if errs.Has(err.Error()) {
|
||||
continue
|
||||
@ -167,20 +202,20 @@ func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, a
|
||||
}
|
||||
if first {
|
||||
first = false
|
||||
fmt.Fprint(out, s)
|
||||
fmt.Fprint(o.Out, s)
|
||||
} else {
|
||||
fmt.Fprintf(out, "\n\n%s", s)
|
||||
fmt.Fprintf(o.Out, "\n\n%s", s)
|
||||
}
|
||||
}
|
||||
|
||||
return utilerrors.NewAggregate(allErrs)
|
||||
}
|
||||
|
||||
func DescribeMatchingResources(f cmdutil.Factory, namespace, rsrc, prefix string, describerSettings *printers.DescriberSettings, out io.Writer, originalError error) error {
|
||||
r := f.NewBuilder().
|
||||
func (o *DescribeOptions) DescribeMatchingResources(originalError error, resource, prefix string) error {
|
||||
r := o.NewBuilder().
|
||||
Unstructured().
|
||||
NamespaceParam(namespace).DefaultNamespace().
|
||||
ResourceTypeOrNameArgs(true, rsrc).
|
||||
NamespaceParam(o.Namespace).DefaultNamespace().
|
||||
ResourceTypeOrNameArgs(true, resource).
|
||||
SingleResourceType().
|
||||
Flatten().
|
||||
Do()
|
||||
@ -188,7 +223,7 @@ func DescribeMatchingResources(f cmdutil.Factory, namespace, rsrc, prefix string
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
describer, err := f.Describer(mapping)
|
||||
describer, err := o.Describer(mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -201,11 +236,11 @@ func DescribeMatchingResources(f cmdutil.Factory, namespace, rsrc, prefix string
|
||||
info := infos[ix]
|
||||
if strings.HasPrefix(info.Name, prefix) {
|
||||
isFound = true
|
||||
s, err := describer.Describe(info.Namespace, info.Name, *describerSettings)
|
||||
s, err := describer.Describe(info.Namespace, info.Name, *o.DescriberSettings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(out, "%s\n", s)
|
||||
fmt.Fprintf(o.Out, "%s\n", s)
|
||||
}
|
||||
}
|
||||
if !isFound {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user