From da19e5b2583fa00a13110de97448bf6452010988 Mon Sep 17 00:00:00 2001 From: Maciej Szulik Date: Wed, 3 Mar 2021 22:47:53 +0100 Subject: [PATCH] Clean unused generators --- .../pkg/generate/versioned/autoscale.go | 86 ---- .../pkg/generate/versioned/autoscale_test.go | 130 ------ .../generate/versioned/clusterrolebinding.go | 159 ------- .../versioned/clusterrolebinding_test.go | 231 ---------- .../pkg/generate/versioned/configmap.go | 299 ------------- .../pkg/generate/versioned/configmap_test.go | 416 ------------------ .../pkg/generate/versioned/deployment.go | 193 -------- .../pkg/generate/versioned/deployment_test.go | 105 ----- .../pkg/generate/versioned/generator.go | 126 +----- .../pkg/generate/versioned/namespace.go | 80 ---- .../pkg/generate/versioned/namespace_test.go | 108 ----- .../kubectl/pkg/generate/versioned/pdb.go | 214 --------- .../pkg/generate/versioned/pdb_test.go | 368 ---------------- .../pkg/generate/versioned/priorityclass.go | 93 ---- .../generate/versioned/priorityclass_test.go | 126 ------ .../kubectl/pkg/generate/versioned/quota.go | 126 ------ .../pkg/generate/versioned/quota_test.go | 123 ------ .../pkg/generate/versioned/rolebinding.go | 174 -------- .../generate/versioned/rolebinding_test.go | 144 ------ .../kubectl/pkg/generate/versioned/secret.go | 273 ------------ .../versioned/secret_for_docker_registry.go | 189 -------- .../secret_for_docker_registry_test.go | 132 ------ .../pkg/generate/versioned/secret_for_tls.go | 146 ------ .../generate/versioned/secret_for_tls_test.go | 233 ---------- .../pkg/generate/versioned/secret_test.go | 371 ---------------- .../pkg/generate/versioned/service_basic.go | 257 ----------- .../generate/versioned/service_basic_test.go | 326 -------------- .../pkg/generate/versioned/serviceaccount.go | 52 --- .../generate/versioned/serviceaccount_test.go | 63 --- test/cmd/apps.sh | 6 +- test/cmd/core.sh | 10 +- 31 files changed, 6 insertions(+), 5353 deletions(-) delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/autoscale.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/autoscale_test.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/clusterrolebinding.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/clusterrolebinding_test.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/configmap.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/configmap_test.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/deployment.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/deployment_test.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/namespace.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/namespace_test.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/pdb.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/pdb_test.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/priorityclass.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/priorityclass_test.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/quota.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/quota_test.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/rolebinding.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/rolebinding_test.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/secret.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/secret_for_docker_registry.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/secret_for_docker_registry_test.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/secret_for_tls.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/secret_for_tls_test.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/secret_test.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/service_basic.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/service_basic_test.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/serviceaccount.go delete mode 100644 staging/src/k8s.io/kubectl/pkg/generate/versioned/serviceaccount_test.go diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/autoscale.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/autoscale.go deleted file mode 100644 index 5d1669a0d93..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/autoscale.go +++ /dev/null @@ -1,86 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package versioned - -import ( - "fmt" - - autoscalingv1 "k8s.io/api/autoscaling/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/kubectl/pkg/generate" -) - -// HorizontalPodAutoscalerGeneratorV1 supports stable generation of a horizontal pod autoscaler. -type HorizontalPodAutoscalerGeneratorV1 struct { - Name string - ScaleRefKind string - ScaleRefName string - ScaleRefAPIVersion string - MinReplicas int32 - MaxReplicas int32 - CPUPercent int32 -} - -// Ensure it supports the generator pattern that uses parameters specified during construction. -var _ generate.StructuredGenerator = &HorizontalPodAutoscalerGeneratorV1{} - -// StructuredGenerate outputs a horizontal pod autoscaler object using the configured fields. -func (s *HorizontalPodAutoscalerGeneratorV1) StructuredGenerate() (runtime.Object, error) { - if err := s.validate(); err != nil { - return nil, err - } - - scaler := autoscalingv1.HorizontalPodAutoscaler{ - ObjectMeta: metav1.ObjectMeta{ - Name: s.Name, - }, - Spec: autoscalingv1.HorizontalPodAutoscalerSpec{ - ScaleTargetRef: autoscalingv1.CrossVersionObjectReference{ - Kind: s.ScaleRefKind, - Name: s.ScaleRefName, - APIVersion: s.ScaleRefAPIVersion, - }, - MaxReplicas: s.MaxReplicas, - }, - } - - if s.MinReplicas > 0 { - v := int32(s.MinReplicas) - scaler.Spec.MinReplicas = &v - } - if s.CPUPercent >= 0 { - c := int32(s.CPUPercent) - scaler.Spec.TargetCPUUtilizationPercentage = &c - } - - return &scaler, nil -} - -// validate check if the caller has set the right fields. -func (s HorizontalPodAutoscalerGeneratorV1) validate() error { - if len(s.Name) == 0 { - return fmt.Errorf("name must be specified") - } - if s.MaxReplicas < 1 { - return fmt.Errorf("'max' is a required parameter and must be at least 1") - } - if s.MinReplicas > s.MaxReplicas { - return fmt.Errorf("'max' must be greater than or equal to 'min'") - } - return nil -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/autoscale_test.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/autoscale_test.go deleted file mode 100644 index c5f8ae74d45..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/autoscale_test.go +++ /dev/null @@ -1,130 +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 versioned - -import ( - "reflect" - "testing" - - autoscalingv1 "k8s.io/api/autoscaling/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - utilpointer "k8s.io/utils/pointer" -) - -func TestHPAGenerate(t *testing.T) { - tests := []struct { - name string - HPAName string - scaleRefKind string - scaleRefName string - scaleRefAPIVersion string - minReplicas int32 - maxReplicas int32 - CPUPercent int32 - expected *autoscalingv1.HorizontalPodAutoscaler - expectErr bool - }{ - { - name: "valid case", - HPAName: "foo", - minReplicas: 1, - maxReplicas: 10, - CPUPercent: 80, - scaleRefKind: "kind", - scaleRefName: "name", - scaleRefAPIVersion: "apiVersion", - expected: &autoscalingv1.HorizontalPodAutoscaler{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: autoscalingv1.HorizontalPodAutoscalerSpec{ - TargetCPUUtilizationPercentage: utilpointer.Int32Ptr(80), - ScaleTargetRef: autoscalingv1.CrossVersionObjectReference{ - Kind: "kind", - Name: "name", - APIVersion: "apiVersion", - }, - MaxReplicas: int32(10), - MinReplicas: utilpointer.Int32Ptr(1), - }, - }, - expectErr: false, - }, - { - name: "'name' is a required parameter", - scaleRefKind: "kind", - scaleRefName: "name", - scaleRefAPIVersion: "apiVersion", - expectErr: true, - }, - { - name: "'max' is a required parameter", - HPAName: "foo", - scaleRefKind: "kind", - scaleRefName: "name", - scaleRefAPIVersion: "apiVersion", - expectErr: true, - }, - { - name: "'max' must be greater than or equal to 'min'", - HPAName: "foo", - minReplicas: 10, - maxReplicas: 1, - scaleRefKind: "kind", - scaleRefName: "name", - scaleRefAPIVersion: "apiVersion", - expectErr: true, - }, - { - name: "'max' must be at least 1", - HPAName: "foo", - minReplicas: 1, - maxReplicas: -10, - scaleRefKind: "kind", - scaleRefName: "name", - scaleRefAPIVersion: "apiVersion", - expectErr: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - generator := HorizontalPodAutoscalerGeneratorV1{ - Name: tt.HPAName, - ScaleRefKind: tt.scaleRefKind, - ScaleRefName: tt.scaleRefName, - ScaleRefAPIVersion: tt.scaleRefAPIVersion, - MinReplicas: tt.minReplicas, - MaxReplicas: tt.maxReplicas, - CPUPercent: tt.CPUPercent, - } - obj, err := generator.StructuredGenerate() - if tt.expectErr && err != nil { - return - } - if !tt.expectErr && err != nil { - t.Errorf("[%s] unexpected error: %v", tt.name, err) - } - if tt.expectErr && err == nil { - t.Errorf("[%s] expect error, got nil", tt.name) - } - if !reflect.DeepEqual(obj.(*autoscalingv1.HorizontalPodAutoscaler), tt.expected) { - t.Errorf("[%s] want:\n%#v\ngot:\n%#v", tt.name, tt.expected, obj.(*autoscalingv1.HorizontalPodAutoscaler)) - } - }) - } -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/clusterrolebinding.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/clusterrolebinding.go deleted file mode 100644 index b1778cb4135..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/clusterrolebinding.go +++ /dev/null @@ -1,159 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package versioned - -import ( - "fmt" - - "strings" - - rbacv1 "k8s.io/api/rbac/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/kubectl/pkg/generate" -) - -// ClusterRoleBindingGeneratorV1 supports stable generation of a clusterRoleBinding. -type ClusterRoleBindingGeneratorV1 struct { - // Name of clusterRoleBinding (required) - Name string - // ClusterRole for the clusterRoleBinding (required) - ClusterRole string - // Users to derive the clusterRoleBinding from (optional) - Users []string - // Groups to derive the clusterRoleBinding from (optional) - Groups []string - // ServiceAccounts to derive the clusterRoleBinding from in namespace:name format(optional) - ServiceAccounts []string -} - -// Ensure it supports the generator pattern that uses parameter injection. -var _ generate.Generator = &ClusterRoleBindingGeneratorV1{} - -// Ensure it supports the generator pattern that uses parameters specified during construction. -var _ generate.StructuredGenerator = &ClusterRoleBindingGeneratorV1{} - -// Generate returns a clusterRoleBinding using the specified parameters. -func (s ClusterRoleBindingGeneratorV1) Generate(genericParams map[string]interface{}) (runtime.Object, error) { - err := generate.ValidateParams(s.ParamNames(), genericParams) - if err != nil { - return nil, err - } - delegate := &ClusterRoleBindingGeneratorV1{} - userStrings, found := genericParams["user"] - if found { - fromFileArray, isArray := userStrings.([]string) - if !isArray { - return nil, fmt.Errorf("expected []string, found :%v", userStrings) - } - delegate.Users = fromFileArray - delete(genericParams, "user") - } - groupStrings, found := genericParams["group"] - if found { - fromLiteralArray, isArray := groupStrings.([]string) - if !isArray { - return nil, fmt.Errorf("expected []string, found :%v", groupStrings) - } - delegate.Groups = fromLiteralArray - delete(genericParams, "group") - } - saStrings, found := genericParams["serviceaccount"] - if found { - fromLiteralArray, isArray := saStrings.([]string) - if !isArray { - return nil, fmt.Errorf("expected []string, found :%v", saStrings) - } - delegate.ServiceAccounts = fromLiteralArray - delete(genericParams, "serviceaccount") - } - params := map[string]string{} - for key, value := range genericParams { - strVal, isString := value.(string) - if !isString { - return nil, fmt.Errorf("expected string, saw %v for '%s'", value, key) - } - params[key] = strVal - } - delegate.Name = params["name"] - delegate.ClusterRole = params["clusterrole"] - return delegate.StructuredGenerate() -} - -// ParamNames returns the set of supported input parameters when using the parameter injection generator pattern. -func (s ClusterRoleBindingGeneratorV1) ParamNames() []generate.GeneratorParam { - return []generate.GeneratorParam{ - {Name: "name", Required: true}, - {Name: "clusterrole", Required: false}, - {Name: "user", Required: false}, - {Name: "group", Required: false}, - {Name: "serviceaccount", Required: false}, - } -} - -// StructuredGenerate outputs a clusterRoleBinding object using the configured fields. -func (s ClusterRoleBindingGeneratorV1) StructuredGenerate() (runtime.Object, error) { - if err := s.validate(); err != nil { - return nil, err - } - clusterRoleBinding := &rbacv1.ClusterRoleBinding{} - clusterRoleBinding.Name = s.Name - clusterRoleBinding.RoleRef = rbacv1.RoleRef{ - APIGroup: rbacv1.GroupName, - Kind: "ClusterRole", - Name: s.ClusterRole, - } - for _, user := range sets.NewString(s.Users...).List() { - clusterRoleBinding.Subjects = append(clusterRoleBinding.Subjects, rbacv1.Subject{ - Kind: rbacv1.UserKind, - APIGroup: rbacv1.GroupName, - Name: user, - }) - } - for _, group := range sets.NewString(s.Groups...).List() { - clusterRoleBinding.Subjects = append(clusterRoleBinding.Subjects, rbacv1.Subject{ - Kind: rbacv1.GroupKind, - APIGroup: rbacv1.GroupName, - Name: group, - }) - } - for _, sa := range sets.NewString(s.ServiceAccounts...).List() { - tokens := strings.Split(sa, ":") - if len(tokens) != 2 || tokens[0] == "" || tokens[1] == "" { - return nil, fmt.Errorf("serviceaccount must be :") - } - clusterRoleBinding.Subjects = append(clusterRoleBinding.Subjects, rbacv1.Subject{ - Kind: rbacv1.ServiceAccountKind, - APIGroup: "", - Namespace: tokens[0], - Name: tokens[1], - }) - } - - return clusterRoleBinding, nil -} - -// validate validates required fields are set to support structured generation. -func (s ClusterRoleBindingGeneratorV1) validate() error { - if len(s.Name) == 0 { - return fmt.Errorf("name must be specified") - } - if len(s.ClusterRole) == 0 { - return fmt.Errorf("clusterrole must be specified") - } - return nil -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/clusterrolebinding_test.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/clusterrolebinding_test.go deleted file mode 100644 index 75afa561dba..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/clusterrolebinding_test.go +++ /dev/null @@ -1,231 +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 versioned - -import ( - "reflect" - "testing" - - rbacv1 "k8s.io/api/rbac/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func TestClusterRoleBindingGenerate(t *testing.T) { - tests := []struct { - name string - params map[string]interface{} - expected *rbacv1.ClusterRoleBinding - expectErr bool - }{ - { - name: "valid case 1", - params: map[string]interface{}{ - "name": "foo", - "clusterrole": "admin", - "user": []string{"user"}, - "group": []string{"group"}, - "serviceaccount": []string{"ns1:name1"}, - }, - expected: &rbacv1.ClusterRoleBinding{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - RoleRef: rbacv1.RoleRef{ - APIGroup: rbacv1.GroupName, - Kind: "ClusterRole", - Name: "admin", - }, - Subjects: []rbacv1.Subject{ - { - APIGroup: rbacv1.GroupName, - Kind: rbacv1.UserKind, - Name: "user", - }, - { - APIGroup: rbacv1.GroupName, - Kind: rbacv1.GroupKind, - Name: "group", - }, - { - Kind: rbacv1.ServiceAccountKind, - APIGroup: "", - Namespace: "ns1", - Name: "name1", - }, - }, - }, - expectErr: false, - }, - { - name: "valid case 2", - params: map[string]interface{}{ - "name": "foo", - "clusterrole": "admin", - "user": []string{"user1", "user2"}, - "group": []string{"group1", "group2"}, - "serviceaccount": []string{"ns1:name1", "ns2:name2"}, - }, - expected: &rbacv1.ClusterRoleBinding{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - RoleRef: rbacv1.RoleRef{ - APIGroup: rbacv1.GroupName, - Kind: "ClusterRole", - Name: "admin", - }, - Subjects: []rbacv1.Subject{ - { - APIGroup: rbacv1.GroupName, - Kind: rbacv1.UserKind, - Name: "user1", - }, - { - APIGroup: rbacv1.GroupName, - Kind: rbacv1.UserKind, - Name: "user2", - }, - { - APIGroup: rbacv1.GroupName, - Kind: rbacv1.GroupKind, - Name: "group1", - }, - { - APIGroup: rbacv1.GroupName, - Kind: rbacv1.GroupKind, - Name: "group2", - }, - { - Kind: rbacv1.ServiceAccountKind, - APIGroup: "", - Namespace: "ns1", - Name: "name1", - }, - { - Kind: rbacv1.ServiceAccountKind, - APIGroup: "", - Namespace: "ns2", - Name: "name2", - }, - }, - }, - expectErr: false, - }, - { - name: "valid case 3", - params: map[string]interface{}{ - "name": "foo", - "clusterrole": "admin", - }, - expected: &rbacv1.ClusterRoleBinding{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - RoleRef: rbacv1.RoleRef{ - APIGroup: rbacv1.GroupName, - Kind: "ClusterRole", - Name: "admin", - }, - }, - expectErr: false, - }, - { - name: "invalid serviceaccount, expected format: ", - params: map[string]interface{}{ - "name": "role", - "clusterrole": "admin", - "user": []string{"user"}, - "group": []string{"group"}, - "serviceaccount": []string{"ns1-name1"}, - }, - expectErr: true, - }, - { - name: "name must be specified", - params: map[string]interface{}{ - "name": "", - "clusterrole": "admin", - "user": []string{"user"}, - "group": []string{"group"}, - "serviceaccount": []string{"ns1:name1"}, - }, - expectErr: true, - }, - { - name: "clusterrole must be specified", - params: map[string]interface{}{ - "name": "foo", - "clusterrole": "", - "user": []string{"user"}, - "group": []string{"group"}, - "serviceaccount": []string{"ns1:name1"}, - }, - expectErr: true, - }, - { - name: "expected user []string", - params: map[string]interface{}{ - "name": "role", - "clusterrole": "admin", - "user": "user", - "group": []string{"group"}, - "serviceaccount": []string{"ns1:name1"}, - }, - expectErr: true, - }, - { - name: "expected group []string", - params: map[string]interface{}{ - "name": "role", - "clusterrole": "admin", - "user": []string{"user"}, - "group": "group", - "serviceaccount": []string{"ns1:name1"}, - }, - expectErr: true, - }, - { - name: "expected serviceaccount []string", - params: map[string]interface{}{ - "name": "role", - "clusterrole": "admin", - "user": []string{"user"}, - "group": []string{"group"}, - "serviceaccount": "ns1", - }, - expectErr: true, - }, - } - generator := ClusterRoleBindingGeneratorV1{} - for i, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - obj, err := generator.Generate(tt.params) - if !tt.expectErr && err != nil { - t.Errorf("[%d] unexpected error: %v", i, err) - } - if tt.expectErr && err != nil { - return - } - if tt.expectErr && err == nil { - t.Errorf("[%s] expect error, got nil", tt.name) - } - if !reflect.DeepEqual(obj.(*rbacv1.ClusterRoleBinding), tt.expected) { - t.Errorf("\n[%s] want:\n%#v\ngot:\n%#v", tt.name, tt.expected, obj.(*rbacv1.ClusterRoleBinding)) - } - }) - } -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/configmap.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/configmap.go deleted file mode 100644 index 76b4676cdbd..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/configmap.go +++ /dev/null @@ -1,299 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package versioned - -import ( - "fmt" - "io/ioutil" - "os" - "path" - "strings" - "unicode/utf8" - - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/validation" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - "k8s.io/kubectl/pkg/generate" - "k8s.io/kubectl/pkg/util" - "k8s.io/kubectl/pkg/util/hash" -) - -// ConfigMapGeneratorV1 supports stable generation of a configMap. -type ConfigMapGeneratorV1 struct { - // Name of configMap (required) - Name string - // Type of configMap (optional) - Type string - // FileSources to derive the configMap from (optional) - FileSources []string - // LiteralSources to derive the configMap from (optional) - LiteralSources []string - // EnvFileSource to derive the configMap from (optional) - EnvFileSource string - // AppendHash; if true, derive a hash from the ConfigMap and append it to the name - AppendHash bool -} - -// Ensure it supports the generator pattern that uses parameter injection. -var _ generate.Generator = &ConfigMapGeneratorV1{} - -// Ensure it supports the generator pattern that uses parameters specified during construction. -var _ generate.StructuredGenerator = &ConfigMapGeneratorV1{} - -// Generate returns a configMap using the specified parameters. -func (s ConfigMapGeneratorV1) Generate(genericParams map[string]interface{}) (runtime.Object, error) { - err := generate.ValidateParams(s.ParamNames(), genericParams) - if err != nil { - return nil, err - } - delegate := &ConfigMapGeneratorV1{} - fromFileStrings, found := genericParams["from-file"] - if found { - fromFileArray, isArray := fromFileStrings.([]string) - if !isArray { - return nil, fmt.Errorf("expected []string, found :%v", fromFileStrings) - } - delegate.FileSources = fromFileArray - delete(genericParams, "from-file") - } - fromLiteralStrings, found := genericParams["from-literal"] - if found { - fromLiteralArray, isArray := fromLiteralStrings.([]string) - if !isArray { - return nil, fmt.Errorf("expected []string, found :%v", fromLiteralStrings) - } - delegate.LiteralSources = fromLiteralArray - delete(genericParams, "from-literal") - } - fromEnvFileString, found := genericParams["from-env-file"] - if found { - fromEnvFile, isString := fromEnvFileString.(string) - if !isString { - return nil, fmt.Errorf("expected string, found :%v", fromEnvFileString) - } - delegate.EnvFileSource = fromEnvFile - delete(genericParams, "from-env-file") - } - hashParam, found := genericParams["append-hash"] - if found { - hashBool, isBool := hashParam.(bool) - if !isBool { - return nil, fmt.Errorf("expected bool, found :%v", hashParam) - } - delegate.AppendHash = hashBool - delete(genericParams, "append-hash") - } - params := map[string]string{} - for key, value := range genericParams { - strVal, isString := value.(string) - if !isString { - return nil, fmt.Errorf("expected string, saw %v for '%s'", value, key) - } - params[key] = strVal - } - delegate.Name = params["name"] - delegate.Type = params["type"] - - return delegate.StructuredGenerate() -} - -// ParamNames returns the set of supported input parameters when using the parameter injection generator pattern. -func (s ConfigMapGeneratorV1) ParamNames() []generate.GeneratorParam { - return []generate.GeneratorParam{ - {Name: "name", Required: true}, - {Name: "type", Required: false}, - {Name: "from-file", Required: false}, - {Name: "from-literal", Required: false}, - {Name: "from-env-file", Required: false}, - {Name: "force", Required: false}, - {Name: "hash", Required: false}, - } -} - -// StructuredGenerate outputs a configMap object using the configured fields. -func (s ConfigMapGeneratorV1) StructuredGenerate() (runtime.Object, error) { - if err := s.validate(); err != nil { - return nil, err - } - configMap := &v1.ConfigMap{} - configMap.Name = s.Name - configMap.Data = map[string]string{} - configMap.BinaryData = map[string][]byte{} - if len(s.FileSources) > 0 { - if err := handleConfigMapFromFileSources(configMap, s.FileSources); err != nil { - return nil, err - } - } - if len(s.LiteralSources) > 0 { - if err := handleConfigMapFromLiteralSources(configMap, s.LiteralSources); err != nil { - return nil, err - } - } - if len(s.EnvFileSource) > 0 { - if err := handleConfigMapFromEnvFileSource(configMap, s.EnvFileSource); err != nil { - return nil, err - } - } - if s.AppendHash { - h, err := hash.ConfigMapHash(configMap) - if err != nil { - return nil, err - } - configMap.Name = fmt.Sprintf("%s-%s", configMap.Name, h) - } - return configMap, nil -} - -// validate validates required fields are set to support structured generation. -func (s ConfigMapGeneratorV1) validate() error { - if len(s.Name) == 0 { - return fmt.Errorf("name must be specified") - } - if len(s.EnvFileSource) > 0 && (len(s.FileSources) > 0 || len(s.LiteralSources) > 0) { - return fmt.Errorf("from-env-file cannot be combined with from-file or from-literal") - } - return nil -} - -// handleConfigMapFromLiteralSources adds the specified literal source -// information into the provided configMap. -func handleConfigMapFromLiteralSources(configMap *v1.ConfigMap, literalSources []string) error { - for _, literalSource := range literalSources { - keyName, value, err := util.ParseLiteralSource(literalSource) - if err != nil { - return err - } - err = addKeyFromLiteralToConfigMap(configMap, keyName, value) - if err != nil { - return err - } - } - return nil -} - -// handleConfigMapFromFileSources adds the specified file source information -// into the provided configMap -func handleConfigMapFromFileSources(configMap *v1.ConfigMap, fileSources []string) error { - for _, fileSource := range fileSources { - keyName, filePath, err := util.ParseFileSource(fileSource) - if err != nil { - return err - } - info, err := os.Stat(filePath) - if err != nil { - switch err := err.(type) { - case *os.PathError: - return fmt.Errorf("error reading %s: %v", filePath, err.Err) - default: - return fmt.Errorf("error reading %s: %v", filePath, err) - } - } - if info.IsDir() { - if strings.Contains(fileSource, "=") { - return fmt.Errorf("cannot give a key name for a directory path.") - } - fileList, err := ioutil.ReadDir(filePath) - if err != nil { - return fmt.Errorf("error listing files in %s: %v", filePath, err) - } - for _, item := range fileList { - itemPath := path.Join(filePath, item.Name()) - if item.Mode().IsRegular() { - keyName = item.Name() - err = addKeyFromFileToConfigMap(configMap, keyName, itemPath) - if err != nil { - return err - } - } - } - } else { - if err := addKeyFromFileToConfigMap(configMap, keyName, filePath); err != nil { - return err - } - } - } - - return nil -} - -// handleConfigMapFromEnvFileSource adds the specified env file source information -// into the provided configMap -func handleConfigMapFromEnvFileSource(configMap *v1.ConfigMap, envFileSource string) error { - info, err := os.Stat(envFileSource) - if err != nil { - switch err := err.(type) { - case *os.PathError: - return fmt.Errorf("error reading %s: %v", envFileSource, err.Err) - default: - return fmt.Errorf("error reading %s: %v", envFileSource, err) - } - } - if info.IsDir() { - return fmt.Errorf("env config file cannot be a directory") - } - - return cmdutil.AddFromEnvFile(envFileSource, func(key, value string) error { - return addKeyFromLiteralToConfigMap(configMap, key, value) - }) -} - -// addKeyFromFileToConfigMap adds a key with the given name to a ConfigMap, populating -// the value with the content of the given file path, or returns an error. -func addKeyFromFileToConfigMap(configMap *v1.ConfigMap, keyName, filePath string) error { - data, err := ioutil.ReadFile(filePath) - if err != nil { - return err - } - - if utf8.Valid(data) { - return addKeyFromLiteralToConfigMap(configMap, keyName, string(data)) - } - - err = validateNewConfigMap(configMap, keyName) - if err != nil { - return err - } - configMap.BinaryData[keyName] = data - return nil -} - -// addKeyFromLiteralToConfigMap adds the given key and data to the given config map, -// returning an error if the key is not valid or if the key already exists. -func addKeyFromLiteralToConfigMap(configMap *v1.ConfigMap, keyName, data string) error { - err := validateNewConfigMap(configMap, keyName) - if err != nil { - return err - } - configMap.Data[keyName] = data - return nil -} - -func validateNewConfigMap(configMap *v1.ConfigMap, keyName string) error { - // Note, the rules for ConfigMap keys are the exact same as the ones for SecretKeys. - if errs := validation.IsConfigMapKey(keyName); len(errs) != 0 { - return fmt.Errorf("%q is not a valid key name for a ConfigMap: %s", keyName, strings.Join(errs, ";")) - } - - if _, exists := configMap.Data[keyName]; exists { - return fmt.Errorf("cannot add key %q, another key by that name already exists in Data for ConfigMap %q", keyName, configMap.Name) - } - if _, exists := configMap.BinaryData[keyName]; exists { - return fmt.Errorf("cannot add key %q, another key by that name already exists in BinaryData for ConfigMap %q", keyName, configMap.Name) - } - return nil -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/configmap_test.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/configmap_test.go deleted file mode 100644 index 7fbcd5ca53d..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/configmap_test.go +++ /dev/null @@ -1,416 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package versioned - -import ( - "io/ioutil" - "os" - "reflect" - "testing" - - "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func TestConfigMapGenerate(t *testing.T) { - tests := []struct { - name string - setup func(t *testing.T, params map[string]interface{}) func() - params map[string]interface{} - expected *v1.ConfigMap - expectErr bool - }{ - { - name: "test1", - params: map[string]interface{}{ - "name": "foo", - }, - expected: &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Data: map[string]string{}, - BinaryData: map[string][]byte{}, - }, - expectErr: false, - }, - { - name: "test2", - params: map[string]interface{}{ - "name": "foo", - "append-hash": true, - }, - expected: &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo-867km9574f", - }, - Data: map[string]string{}, - BinaryData: map[string][]byte{}, - }, - expectErr: false, - }, - { - name: "test3", - params: map[string]interface{}{ - "name": "foo", - "type": "my-type", - }, - expected: &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Data: map[string]string{}, - BinaryData: map[string][]byte{}, - }, - expectErr: false, - }, - { - name: "test4", - params: map[string]interface{}{ - "name": "foo", - "type": "my-type", - "append-hash": true, - }, - expected: &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo-867km9574f", - }, - Data: map[string]string{}, - BinaryData: map[string][]byte{}, - }, - expectErr: false, - }, - { - name: "test5", - params: map[string]interface{}{ - "name": "foo", - "from-literal": []string{"key1=value1", "key2=value2"}, - }, - expected: &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Data: map[string]string{ - "key1": "value1", - "key2": "value2", - }, - BinaryData: map[string][]byte{}, - }, - expectErr: false, - }, - { - name: "test6", - params: map[string]interface{}{ - "name": "foo", - "from-literal": []string{"key1=value1", "key2=value2"}, - "append-hash": true, - }, - expected: &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo-gcb75dd9gb", - }, - Data: map[string]string{ - "key1": "value1", - "key2": "value2", - }, - BinaryData: map[string][]byte{}, - }, - expectErr: false, - }, - { - name: "test7", - params: map[string]interface{}{ - "name": "foo", - "from-literal": []string{"key1value1"}, - }, - expectErr: true, - }, - { - name: "test8", - params: map[string]interface{}{ - "name": "foo", - "from-file": []string{"key1=/file=2"}, - }, - expectErr: true, - }, - { - name: "test9", - params: map[string]interface{}{ - "name": "foo", - "from-file": []string{"key1==value"}, - }, - expectErr: true, - }, - { - name: "test10", - setup: setupBinaryFile([]byte{0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64}), - params: map[string]interface{}{ - "name": "foo", - "from-file": []string{"foo1"}, - }, - expected: &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Data: map[string]string{"foo1": "hello world"}, - BinaryData: map[string][]byte{}, - }, - expectErr: false, - }, - { - name: "test11", - setup: setupBinaryFile([]byte{0xff, 0xfd}), - params: map[string]interface{}{ - "name": "foo", - "from-file": []string{"foo1"}, - }, - expected: &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Data: map[string]string{}, - BinaryData: map[string][]byte{"foo1": {0xff, 0xfd}}, - }, - expectErr: false, - }, - { - name: "test12", - params: map[string]interface{}{ - "name": "foo", - "from-literal": []string{"key1==value1"}, - }, - expected: &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Data: map[string]string{ - "key1": "=value1", - }, - BinaryData: map[string][]byte{}, - }, - expectErr: false, - }, - { - name: "test13", - params: map[string]interface{}{ - "name": "foo", - "from-literal": []string{"key1==value1"}, - "append-hash": true, - }, - expected: &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo-bdgk9ttt7m", - }, - Data: map[string]string{ - "key1": "=value1", - }, - BinaryData: map[string][]byte{}, - }, - expectErr: false, - }, - { - name: "test14", - setup: setupEnvFile("key1=value1", "#", "", "key2=value2"), - params: map[string]interface{}{ - "name": "valid_env", - "from-env-file": "file.env", - }, - expected: &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "valid_env", - }, - Data: map[string]string{ - "key1": "value1", - "key2": "value2", - }, - BinaryData: map[string][]byte{}, - }, - expectErr: false, - }, - { - name: "test15", - setup: setupEnvFile("key1=value1", "#", "", "key2=value2"), - params: map[string]interface{}{ - "name": "valid_env", - "from-env-file": "file.env", - "append-hash": true, - }, - expected: &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "valid_env-2cgh8552ch", - }, - Data: map[string]string{ - "key1": "value1", - "key2": "value2", - }, - BinaryData: map[string][]byte{}, - }, - expectErr: false, - }, - { - name: "test16", - setup: func() func(t *testing.T, params map[string]interface{}) func() { - os.Setenv("g_key1", "1") - os.Setenv("g_key2", "2") - return setupEnvFile("g_key1", "g_key2=") - }(), - params: map[string]interface{}{ - "name": "getenv", - "from-env-file": "file.env", - }, - expected: &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "getenv", - }, - Data: map[string]string{ - "g_key1": "1", - "g_key2": "", - }, - BinaryData: map[string][]byte{}, - }, - expectErr: false, - }, - { - name: "test17", - setup: func() func(t *testing.T, params map[string]interface{}) func() { - os.Setenv("g_key1", "1") - os.Setenv("g_key2", "2") - return setupEnvFile("g_key1", "g_key2=") - }(), - params: map[string]interface{}{ - "name": "getenv", - "from-env-file": "file.env", - "append-hash": true, - }, - expected: &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "getenv-b4hh92hgdk", - }, - Data: map[string]string{ - "g_key1": "1", - "g_key2": "", - }, - BinaryData: map[string][]byte{}, - }, - expectErr: false, - }, - { - name: "test18", - params: map[string]interface{}{ - "name": "too_many_args", - "from-literal": []string{"key1=value1"}, - "from-env-file": "file.env", - }, - expectErr: true, - }, - {name: "test19", - setup: setupEnvFile("key#1=value1"), - params: map[string]interface{}{ - "name": "invalid_key", - "from-env-file": "file.env", - }, - expectErr: true, - }, - { - name: "test20", - setup: setupEnvFile(" key1= value1"), - params: map[string]interface{}{ - "name": "with_spaces", - "from-env-file": "file.env", - }, - expected: &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "with_spaces", - }, - Data: map[string]string{ - "key1": " value1", - }, - BinaryData: map[string][]byte{}, - }, - expectErr: false, - }, - { - name: "test21", - setup: setupEnvFile(" key1= value1"), - params: map[string]interface{}{ - "name": "with_spaces", - "from-env-file": "file.env", - "append-hash": true, - }, - expected: &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "with_spaces-bfc558b4ct", - }, - Data: map[string]string{ - "key1": " value1", - }, - BinaryData: map[string][]byte{}, - }, - expectErr: false, - }, - } - generator := ConfigMapGeneratorV1{} - for i, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if tt.setup != nil { - if teardown := tt.setup(t, tt.params); teardown != nil { - defer teardown() - } - } - obj, err := generator.Generate(tt.params) - if !tt.expectErr && err != nil { - t.Errorf("case %d, unexpected error: %v", i, err) - } - if tt.expectErr && err != nil { - return - } - if !reflect.DeepEqual(obj.(*v1.ConfigMap), tt.expected) { - t.Errorf("\ncase %d, expected:\n%#v\nsaw:\n%#v", i, tt.expected, obj.(*v1.ConfigMap)) - } - }) - } -} - -func setupEnvFile(lines ...string) func(*testing.T, map[string]interface{}) func() { - return func(t *testing.T, params map[string]interface{}) func() { - f, err := ioutil.TempFile("", "cme") - if err != nil { - t.Errorf("unexpected error: %v", err) - } - for _, l := range lines { - f.WriteString(l) - f.WriteString("\r\n") - } - f.Close() - params["from-env-file"] = f.Name() - return func() { - os.Remove(f.Name()) - } - } -} - -func setupBinaryFile(data []byte) func(*testing.T, map[string]interface{}) func() { - return func(t *testing.T, params map[string]interface{}) func() { - tmp, _ := ioutil.TempDir("", "") - f := tmp + "/foo1" - ioutil.WriteFile(f, data, 0644) - params["from-file"] = []string{f} - return func() { - os.Remove(f) - } - } -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/deployment.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/deployment.go deleted file mode 100644 index c6bae8885df..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/deployment.go +++ /dev/null @@ -1,193 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package versioned - -import ( - "fmt" - "strings" - - appsv1 "k8s.io/api/apps/v1" - appsv1beta1 "k8s.io/api/apps/v1beta1" - "k8s.io/api/core/v1" - extensionsv1beta1 "k8s.io/api/extensions/v1beta1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - utilrand "k8s.io/apimachinery/pkg/util/rand" - "k8s.io/kubectl/pkg/generate" -) - -// BaseDeploymentGenerator implements the common functionality of -// DeploymentBasicGeneratorV1, DeploymentBasicAppsGeneratorV1Beta1 and DeploymentBasicAppsGeneratorV1. To reduce -// confusion, it's best to keep this struct in the same file as those -// generators. -type BaseDeploymentGenerator struct { - Name string - Images []string -} - -// validate: check if the caller has forgotten to set one of our fields. -func (b BaseDeploymentGenerator) validate() error { - if len(b.Name) == 0 { - return fmt.Errorf("name must be specified") - } - if len(b.Images) == 0 { - return fmt.Errorf("at least one image must be specified") - } - return nil -} - -// structuredGenerate: determine the fields of a deployment. The struct that -// embeds BaseDeploymentGenerator should assemble these pieces into a -// runtime.Object. -func (b BaseDeploymentGenerator) structuredGenerate() ( - podSpec v1.PodSpec, - labels map[string]string, - selector metav1.LabelSelector, - err error, -) { - err = b.validate() - if err != nil { - return - } - podSpec = buildPodSpec(b.Images) - labels = map[string]string{} - labels["app"] = b.Name - selector = metav1.LabelSelector{MatchLabels: labels} - return -} - -// buildPodSpec: parse the image strings and assemble them into the Containers -// of a PodSpec. This is all you need to create the PodSpec for a deployment. -func buildPodSpec(images []string) v1.PodSpec { - podSpec := v1.PodSpec{Containers: []v1.Container{}} - for _, imageString := range images { - // Retain just the image name - imageSplit := strings.Split(imageString, "/") - name := imageSplit[len(imageSplit)-1] - // Remove any tag or hash - if strings.Contains(name, ":") { - name = strings.Split(name, ":")[0] - } - if strings.Contains(name, "@") { - name = strings.Split(name, "@")[0] - } - name = sanitizeAndUniquify(name) - podSpec.Containers = append(podSpec.Containers, v1.Container{Name: name, Image: imageString}) - } - return podSpec -} - -// sanitizeAndUniquify: replaces characters like "." or "_" into "-" to follow DNS1123 rules. -// Then add random suffix to make it uniquified. -func sanitizeAndUniquify(name string) string { - if strings.Contains(name, "_") || strings.Contains(name, ".") { - name = strings.Replace(name, "_", "-", -1) - name = strings.Replace(name, ".", "-", -1) - name = fmt.Sprintf("%s-%s", name, utilrand.String(5)) - } - return name -} - -// DeploymentBasicGeneratorV1 supports stable generation of a deployment -type DeploymentBasicGeneratorV1 struct { - BaseDeploymentGenerator -} - -// Ensure it supports the generator pattern that uses parameters specified during construction -var _ generate.StructuredGenerator = &DeploymentBasicGeneratorV1{} - -// StructuredGenerate outputs a deployment object using the configured fields -func (s *DeploymentBasicGeneratorV1) StructuredGenerate() (runtime.Object, error) { - podSpec, labels, selector, err := s.structuredGenerate() - one := int32(1) - return &extensionsv1beta1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: s.Name, - Labels: labels, - }, - Spec: extensionsv1beta1.DeploymentSpec{ - Replicas: &one, - Selector: &selector, - Template: v1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: labels, - }, - Spec: podSpec, - }, - }, - }, err -} - -// DeploymentBasicAppsGeneratorV1Beta1 supports stable generation of a deployment under apps/v1beta1 endpoint -type DeploymentBasicAppsGeneratorV1Beta1 struct { - BaseDeploymentGenerator -} - -// Ensure it supports the generator pattern that uses parameters specified during construction -var _ generate.StructuredGenerator = &DeploymentBasicAppsGeneratorV1Beta1{} - -// StructuredGenerate outputs a deployment object using the configured fields -func (s *DeploymentBasicAppsGeneratorV1Beta1) StructuredGenerate() (runtime.Object, error) { - podSpec, labels, selector, err := s.structuredGenerate() - one := int32(1) - return &appsv1beta1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: s.Name, - Labels: labels, - }, - Spec: appsv1beta1.DeploymentSpec{ - Replicas: &one, - Selector: &selector, - Template: v1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: labels, - }, - Spec: podSpec, - }, - }, - }, err -} - -// DeploymentBasicAppsGeneratorV1 supports stable generation of a deployment under apps/v1 endpoint -type DeploymentBasicAppsGeneratorV1 struct { - BaseDeploymentGenerator -} - -// Ensure it supports the generator pattern that uses parameters specified during construction -var _ generate.StructuredGenerator = &DeploymentBasicAppsGeneratorV1{} - -// StructuredGenerate outputs a deployment object using the configured fields -func (s *DeploymentBasicAppsGeneratorV1) StructuredGenerate() (runtime.Object, error) { - podSpec, labels, selector, err := s.structuredGenerate() - one := int32(1) - return &appsv1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: s.Name, - Labels: labels, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: &one, - Selector: &selector, - Template: v1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: labels, - }, - Spec: podSpec, - }, - }, - }, err -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/deployment_test.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/deployment_test.go deleted file mode 100644 index 8319a1fc925..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/deployment_test.go +++ /dev/null @@ -1,105 +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 versioned - -import ( - "reflect" - "testing" - - appsv1 "k8s.io/api/apps/v1" - "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func TestDeploymentBasicGenerate(t *testing.T) { - one := int32(1) - tests := []struct { - name string - deploymentName string - images []string - expected *appsv1.Deployment - expectErr bool - }{ - { - name: "deployment name and images ok", - deploymentName: "images-name-ok", - images: []string{"nn/image1", "registry/nn/image2", "nn/image3:tag", "nn/image4@digest", "nn/image5@sha256:digest"}, - expected: &appsv1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: "images-name-ok", - Labels: map[string]string{"app": "images-name-ok"}, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: &one, - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"app": "images-name-ok"}, - }, - Template: v1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{"app": "images-name-ok"}, - }, - Spec: v1.PodSpec{ - Containers: []v1.Container{ - {Name: "image1", Image: "nn/image1"}, - {Name: "image2", Image: "registry/nn/image2"}, - {Name: "image3", Image: "nn/image3:tag"}, - {Name: "image4", Image: "nn/image4@digest"}, - {Name: "image5", Image: "nn/image5@sha256:digest"}, - }, - }, - }, - }, - }, - expectErr: false, - }, - { - name: "empty images", - deploymentName: "images-empty", - images: []string{}, - expectErr: true, - }, - { - name: "no images", - deploymentName: "images-missing", - expectErr: true, - }, - { - name: "no deployment name and images", - expectErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - generator := &DeploymentBasicAppsGeneratorV1{ - BaseDeploymentGenerator{ - Name: tt.deploymentName, - Images: tt.images, - }, - } - obj, err := generator.StructuredGenerate() - if !tt.expectErr && err != nil { - t.Errorf("unexpected error: %v", err) - } - if tt.expectErr && err != nil { - return - } - if !reflect.DeepEqual(obj.(*appsv1.Deployment), tt.expected) { - t.Errorf("test: %v\nexpected:\n%#v\nsaw:\n%#v", tt.name, tt.expected, obj.(*appsv1.Deployment)) - } - }) - } -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/generator.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/generator.go index 20856d39bb6..b36f631e640 100644 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/generator.go +++ b/staging/src/k8s.io/kubectl/pkg/generate/versioned/generator.go @@ -17,14 +17,6 @@ limitations under the License. package versioned import ( - "fmt" - "io" - - appsv1 "k8s.io/api/apps/v1" - appsv1beta1 "k8s.io/api/apps/v1beta1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/client-go/discovery" "k8s.io/kubectl/pkg/generate" ) @@ -35,31 +27,8 @@ const ( // TODO(sig-cli): Enforce consistent naming for generators here. // See discussion in https://github.com/kubernetes/kubernetes/issues/46237 // before you add any more. - RunPodV1GeneratorName = "run-pod/v1" - ServiceV1GeneratorName = "service/v1" - ServiceV2GeneratorName = "service/v2" - ServiceNodePortGeneratorV1Name = "service-nodeport/v1" - ServiceClusterIPGeneratorV1Name = "service-clusterip/v1" - ServiceLoadBalancerGeneratorV1Name = "service-loadbalancer/v1" - ServiceExternalNameGeneratorV1Name = "service-externalname/v1" - ServiceAccountV1GeneratorName = "serviceaccount/v1" - HorizontalPodAutoscalerV1GeneratorName = "horizontalpodautoscaler/v1" - DeploymentBasicV1Beta1GeneratorName = "deployment-basic/v1beta1" - DeploymentBasicAppsV1Beta1GeneratorName = "deployment-basic/apps.v1beta1" - DeploymentBasicAppsV1GeneratorName = "deployment-basic/apps.v1" - NamespaceV1GeneratorName = "namespace/v1" - ResourceQuotaV1GeneratorName = "resourcequotas/v1" - SecretV1GeneratorName = "secret/v1" - SecretForDockerRegistryV1GeneratorName = "secret-for-docker-registry/v1" - SecretForTLSV1GeneratorName = "secret-for-tls/v1" - ConfigMapV1GeneratorName = "configmap/v1" - ClusterRoleBindingV1GeneratorName = "clusterrolebinding.rbac.authorization.k8s.io/v1alpha1" - RoleBindingV1GeneratorName = "rolebinding.rbac.authorization.k8s.io/v1alpha1" - PodDisruptionBudgetV1GeneratorName = "poddisruptionbudget/v1beta1" - PodDisruptionBudgetV2GeneratorName = "poddisruptionbudget/v1beta1/v2" - PriorityClassV1Alpha1GeneratorName = "priorityclass/v1alpha1" - PriorityClassV1Beta1GeneratorName = "priorityclass/v1beta1" - PriorityClassV1GeneratorName = "priorityclass/v1" + RunPodV1GeneratorName = "run-pod/v1" + ServiceV2GeneratorName = "service/v2" ) // DefaultGenerators returns the set of default generators for use in Factory instances @@ -68,104 +37,13 @@ func DefaultGenerators(cmdName string) map[string]generate.Generator { switch cmdName { case "expose": generator = map[string]generate.Generator{ - ServiceV1GeneratorName: ServiceGeneratorV1{}, ServiceV2GeneratorName: ServiceGeneratorV2{}, } - case "service-clusterip": - generator = map[string]generate.Generator{ - ServiceClusterIPGeneratorV1Name: ServiceClusterIPGeneratorV1{}, - } - case "service-nodeport": - generator = map[string]generate.Generator{ - ServiceNodePortGeneratorV1Name: ServiceNodePortGeneratorV1{}, - } - case "service-loadbalancer": - generator = map[string]generate.Generator{ - ServiceLoadBalancerGeneratorV1Name: ServiceLoadBalancerGeneratorV1{}, - } - case "deployment": - // Create Deployment has only StructuredGenerators and no - // param-based Generators. - // The StructuredGenerators are as follows (as of 2018-03-16): - // DeploymentBasicV1Beta1GeneratorName -> DeploymentBasicGeneratorV1 - // DeploymentBasicAppsV1Beta1GeneratorName -> DeploymentBasicAppsGeneratorV1Beta1 - // DeploymentBasicAppsV1GeneratorName -> DeploymentBasicAppsGeneratorV1 - generator = map[string]generate.Generator{} case "run": generator = map[string]generate.Generator{ RunPodV1GeneratorName: BasicPod{}, } - case "namespace": - generator = map[string]generate.Generator{ - NamespaceV1GeneratorName: NamespaceGeneratorV1{}, - } - case "quota": - generator = map[string]generate.Generator{ - ResourceQuotaV1GeneratorName: ResourceQuotaGeneratorV1{}, - } - case "secret": - generator = map[string]generate.Generator{ - SecretV1GeneratorName: SecretGeneratorV1{}, - } - case "secret-for-docker-registry": - generator = map[string]generate.Generator{ - SecretForDockerRegistryV1GeneratorName: SecretForDockerRegistryGeneratorV1{}, - } - case "secret-for-tls": - generator = map[string]generate.Generator{ - SecretForTLSV1GeneratorName: SecretForTLSGeneratorV1{}, - } } return generator } - -// FallbackGeneratorNameIfNecessary returns the name of the old generator -// if server does not support new generator. Otherwise, the -// generator string is returned unchanged. -// -// If the generator name is changed, print a warning message to let the user -// know. -func FallbackGeneratorNameIfNecessary( - generatorName string, - discoveryClient discovery.DiscoveryInterface, - cmdErr io.Writer, -) (string, error) { - switch generatorName { - case DeploymentBasicAppsV1GeneratorName: - hasResource, err := HasResource(discoveryClient, appsv1.SchemeGroupVersion.WithResource("deployments")) - if err != nil { - return "", err - } - if !hasResource { - return FallbackGeneratorNameIfNecessary(DeploymentBasicAppsV1Beta1GeneratorName, discoveryClient, cmdErr) - } - case DeploymentBasicAppsV1Beta1GeneratorName: - hasResource, err := HasResource(discoveryClient, appsv1beta1.SchemeGroupVersion.WithResource("deployments")) - if err != nil { - return "", err - } - if !hasResource { - return DeploymentBasicV1Beta1GeneratorName, nil - } - } - return generatorName, nil -} - -func HasResource(client discovery.DiscoveryInterface, resource schema.GroupVersionResource) (bool, error) { - resources, err := client.ServerResourcesForGroupVersion(resource.GroupVersion().String()) - if apierrors.IsNotFound(err) { - // entire group is missing - return false, nil - } - if err != nil { - // other errors error - return false, fmt.Errorf("failed to discover supported resources: %v", err) - } - for _, serverResource := range resources.APIResources { - if serverResource.Name == resource.Resource { - return true, nil - } - } - return false, nil -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/namespace.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/namespace.go deleted file mode 100644 index 23cdbfa5aeb..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/namespace.go +++ /dev/null @@ -1,80 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package versioned - -import ( - "fmt" - - "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/kubectl/pkg/generate" -) - -// NamespaceGeneratorV1 supports stable generation of a namespace -type NamespaceGeneratorV1 struct { - // Name of namespace - Name string -} - -// Ensure it supports the generator pattern that uses parameter injection -var _ generate.Generator = &NamespaceGeneratorV1{} - -// Ensure it supports the generator pattern that uses parameters specified during construction -var _ generate.StructuredGenerator = &NamespaceGeneratorV1{} - -// Generate returns a namespace using the specified parameters -func (g NamespaceGeneratorV1) Generate(genericParams map[string]interface{}) (runtime.Object, error) { - err := generate.ValidateParams(g.ParamNames(), genericParams) - if err != nil { - return nil, err - } - params := map[string]string{} - for key, value := range genericParams { - strVal, isString := value.(string) - if !isString { - return nil, fmt.Errorf("expected string, saw %v for '%s'", value, key) - } - params[key] = strVal - } - delegate := &NamespaceGeneratorV1{Name: params["name"]} - return delegate.StructuredGenerate() -} - -// ParamNames returns the set of supported input parameters when using the parameter injection generator pattern -func (g NamespaceGeneratorV1) ParamNames() []generate.GeneratorParam { - return []generate.GeneratorParam{ - {Name: "name", Required: true}, - } -} - -// StructuredGenerate outputs a namespace object using the configured fields -func (g *NamespaceGeneratorV1) StructuredGenerate() (runtime.Object, error) { - if err := g.validate(); err != nil { - return nil, err - } - namespace := &v1.Namespace{} - namespace.Name = g.Name - return namespace, nil -} - -// validate validates required fields are set to support structured generation -func (g *NamespaceGeneratorV1) validate() error { - if len(g.Name) == 0 { - return fmt.Errorf("name must be specified") - } - return nil -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/namespace_test.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/namespace_test.go deleted file mode 100644 index b99fcc8939b..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/namespace_test.go +++ /dev/null @@ -1,108 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package versioned - -import ( - "reflect" - "testing" - - "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func TestNamespaceGenerate(t *testing.T) { - tests := []struct { - name string - params map[string]interface{} - expected *v1.Namespace - expectErr bool - }{ - { - name: "test1", - params: map[string]interface{}{ - "name": "foo", - }, - expected: &v1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - }, - expectErr: false, - }, - { - name: "test2", - params: map[string]interface{}{}, - expectErr: true, - }, - { - name: "test3", - params: map[string]interface{}{ - "name": 1, - }, - expectErr: true, - }, - { - name: "test4", - params: map[string]interface{}{ - "name": "", - }, - expectErr: true, - }, - { - name: "test5", - params: map[string]interface{}{ - "name": nil, - }, - expectErr: true, - }, - { - name: "test6", - params: map[string]interface{}{ - "name_wrong_key": "some_value", - }, - expectErr: true, - }, - { - name: "test7", - params: map[string]interface{}{ - "NAME": "some_value", - }, - expectErr: true, - }, - } - generator := NamespaceGeneratorV1{} - for index, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - obj, err := generator.Generate(tt.params) - switch { - case tt.expectErr && err != nil: - return // loop, since there's no output to check - case tt.expectErr && err == nil: - t.Errorf("%v: expected error and didn't get one", index) - return // loop, no expected output object - case !tt.expectErr && err != nil: - t.Errorf("%v: unexpected error %v", index, err) - return // loop, no output object - case !tt.expectErr && err == nil: - // do nothing and drop through - } - if !reflect.DeepEqual(obj.(*v1.Namespace), tt.expected) { - t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", tt.expected, obj.(*v1.Namespace)) - } - }) - } -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/pdb.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/pdb.go deleted file mode 100644 index a28fcefcc10..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/pdb.go +++ /dev/null @@ -1,214 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package versioned - -import ( - "fmt" - - policy "k8s.io/api/policy/v1beta1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/intstr" - "k8s.io/kubectl/pkg/generate" -) - -// PodDisruptionBudgetV1Generator supports stable generation of a pod disruption budget. -type PodDisruptionBudgetV1Generator struct { - Name string - MinAvailable string - Selector string -} - -// Ensure it supports the generator pattern that uses parameters specified during construction. -var _ generate.StructuredGenerator = &PodDisruptionBudgetV1Generator{} - -func (PodDisruptionBudgetV1Generator) ParamNames() []generate.GeneratorParam { - return []generate.GeneratorParam{ - {Name: "name", Required: true}, - {Name: "min-available", Required: false}, - {Name: "selector", Required: true}, - } -} - -func (s PodDisruptionBudgetV1Generator) Generate(params map[string]interface{}) (runtime.Object, error) { - err := generate.ValidateParams(s.ParamNames(), params) - if err != nil { - return nil, err - } - name, isString := params["name"].(string) - if !isString { - return nil, fmt.Errorf("expected string, found %T for 'name'", params["name"]) - } - minAvailable, isString := params["min-available"].(string) - if !isString { - return nil, fmt.Errorf("expected string, found %T for 'min-available'", params["min-available"]) - } - selector, isString := params["selector"].(string) - if !isString { - return nil, fmt.Errorf("expected string, found %T for 'selector'", params["selector"]) - } - delegate := &PodDisruptionBudgetV1Generator{Name: name, MinAvailable: minAvailable, Selector: selector} - return delegate.StructuredGenerate() -} - -// StructuredGenerate outputs a pod disruption budget object using the configured fields. -func (s *PodDisruptionBudgetV1Generator) StructuredGenerate() (runtime.Object, error) { - if len(s.MinAvailable) == 0 { - // defaulting behavior seen in Kubernetes 1.6 and below. - s.MinAvailable = "1" - } - - if err := s.validate(); err != nil { - return nil, err - } - - selector, err := metav1.ParseToLabelSelector(s.Selector) - if err != nil { - return nil, err - } - - minAvailable := intstr.Parse(s.MinAvailable) - return &policy.PodDisruptionBudget{ - ObjectMeta: metav1.ObjectMeta{ - Name: s.Name, - }, - Spec: policy.PodDisruptionBudgetSpec{ - MinAvailable: &minAvailable, - Selector: selector, - }, - }, nil -} - -// validate validates required fields are set to support structured generation. -func (s *PodDisruptionBudgetV1Generator) validate() error { - if len(s.Name) == 0 { - return fmt.Errorf("name must be specified") - } - if len(s.Selector) == 0 { - return fmt.Errorf("a selector must be specified") - } - if len(s.MinAvailable) == 0 { - return fmt.Errorf("the minimum number of available pods required must be specified") - } - return nil -} - -// PodDisruptionBudgetV2Generator supports stable generation of a pod disruption budget. -type PodDisruptionBudgetV2Generator struct { - Name string - MinAvailable string - MaxUnavailable string - Selector string -} - -// Ensure it supports the generator pattern that uses parameters specified during construction. -var _ generate.StructuredGenerator = &PodDisruptionBudgetV2Generator{} - -func (PodDisruptionBudgetV2Generator) ParamNames() []generate.GeneratorParam { - return []generate.GeneratorParam{ - {Name: "name", Required: true}, - {Name: "min-available", Required: false}, - {Name: "max-unavailable", Required: false}, - {Name: "selector", Required: true}, - } -} - -func (s PodDisruptionBudgetV2Generator) Generate(params map[string]interface{}) (runtime.Object, error) { - err := generate.ValidateParams(s.ParamNames(), params) - if err != nil { - return nil, err - } - - name, isString := params["name"].(string) - if !isString { - return nil, fmt.Errorf("expected string, found %T for 'name'", params["name"]) - } - - minAvailable, isString := params["min-available"].(string) - if !isString { - return nil, fmt.Errorf("expected string, found %T for 'min-available'", params["min-available"]) - } - - maxUnavailable, isString := params["max-unavailable"].(string) - if !isString { - return nil, fmt.Errorf("expected string, found %T for 'max-unavailable'", params["max-unavailable"]) - } - - selector, isString := params["selector"].(string) - if !isString { - return nil, fmt.Errorf("expected string, found %T for 'selector'", params["selector"]) - } - delegate := &PodDisruptionBudgetV2Generator{Name: name, MinAvailable: minAvailable, MaxUnavailable: maxUnavailable, Selector: selector} - return delegate.StructuredGenerate() -} - -// StructuredGenerate outputs a pod disruption budget object using the configured fields. -func (s *PodDisruptionBudgetV2Generator) StructuredGenerate() (runtime.Object, error) { - if err := s.validate(); err != nil { - return nil, err - } - - selector, err := metav1.ParseToLabelSelector(s.Selector) - if err != nil { - return nil, err - } - - if len(s.MaxUnavailable) > 0 { - maxUnavailable := intstr.Parse(s.MaxUnavailable) - return &policy.PodDisruptionBudget{ - ObjectMeta: metav1.ObjectMeta{ - Name: s.Name, - }, - Spec: policy.PodDisruptionBudgetSpec{ - MaxUnavailable: &maxUnavailable, - Selector: selector, - }, - }, nil - } - - if len(s.MinAvailable) > 0 { - minAvailable := intstr.Parse(s.MinAvailable) - return &policy.PodDisruptionBudget{ - ObjectMeta: metav1.ObjectMeta{ - Name: s.Name, - }, - Spec: policy.PodDisruptionBudgetSpec{ - MinAvailable: &minAvailable, - Selector: selector, - }, - }, nil - } - - return nil, err -} - -// validate validates required fields are set to support structured generation. -func (s *PodDisruptionBudgetV2Generator) validate() error { - if len(s.Name) == 0 { - return fmt.Errorf("name must be specified") - } - if len(s.Selector) == 0 { - return fmt.Errorf("a selector must be specified") - } - if len(s.MaxUnavailable) == 0 && len(s.MinAvailable) == 0 { - return fmt.Errorf("one of min-available or max-unavailable must be specified") - } - if len(s.MaxUnavailable) > 0 && len(s.MinAvailable) > 0 { - return fmt.Errorf("min-available and max-unavailable cannot be both specified") - } - return nil -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/pdb_test.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/pdb_test.go deleted file mode 100644 index ab16c5b8f46..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/pdb_test.go +++ /dev/null @@ -1,368 +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 versioned - -import ( - "reflect" - "testing" - - policy "k8s.io/api/policy/v1beta1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/intstr" -) - -func TestPodDisruptionBudgetV1Generate(t *testing.T) { - name := "foo" - minAvailable := "5" - minAvailableIS := intstr.Parse(minAvailable) - defaultMinAvailableIS := intstr.Parse("1") - selector := "app=foo" - labelSelector, err := metav1.ParseToLabelSelector(selector) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - - tests := []struct { - name string - params map[string]interface{} - expectErrMsg string - expectPDB *policy.PodDisruptionBudget - }{ - { - name: "test-valid-use", - params: map[string]interface{}{ - "name": name, - "min-available": minAvailable, - "selector": selector, - }, - expectPDB: &policy.PodDisruptionBudget{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - }, - Spec: policy.PodDisruptionBudgetSpec{ - MinAvailable: &minAvailableIS, - Selector: labelSelector, - }, - }, - }, - { - name: "test-missing-name-param", - params: map[string]interface{}{ - "min-available": minAvailable, - "selector": selector, - }, - expectErrMsg: "Parameter: name is required", - }, - { - name: "test-blank-name-param", - params: map[string]interface{}{ - "name": "", - "min-available": minAvailable, - "selector": selector, - }, - expectErrMsg: "Parameter: name is required", - }, - { - name: "test-invalid-name-param", - params: map[string]interface{}{ - "name": 1, - "min-available": minAvailable, - "selector": selector, - }, - expectErrMsg: "expected string, found int for 'name'", - }, - { - name: "test-missing-min-available-param", - params: map[string]interface{}{ - "name": name, - "selector": selector, - }, - expectErrMsg: "expected string, found for 'min-available'", - }, - { - name: "test-blank-min-available-param", - params: map[string]interface{}{ - "name": name, - "min-available": "", - "selector": selector, - }, - expectPDB: &policy.PodDisruptionBudget{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - }, - Spec: policy.PodDisruptionBudgetSpec{ - MinAvailable: &defaultMinAvailableIS, - Selector: labelSelector, - }, - }, - }, - { - name: "test-invalid-min-available-param", - params: map[string]interface{}{ - "name": name, - "min-available": 1, - "selector": selector, - }, - expectErrMsg: "expected string, found int for 'min-available'", - }, - { - name: "test-missing-selector-param", - params: map[string]interface{}{ - "name": name, - "min-available": minAvailable, - }, - expectErrMsg: "Parameter: selector is required", - }, - { - name: "test-blank-selector-param", - params: map[string]interface{}{ - "name": name, - "min-available": minAvailable, - "selector": "", - }, - expectErrMsg: "Parameter: selector is required", - }, - { - name: "test-invalid-selector-param", - params: map[string]interface{}{ - "name": name, - "min-available": minAvailable, - "selector": 1, - }, - expectErrMsg: "expected string, found int for 'selector'", - }, - } - - generator := PodDisruptionBudgetV1Generator{} - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - obj, err := generator.Generate(tt.params) - switch { - case tt.expectErrMsg != "" && err != nil: - if err.Error() != tt.expectErrMsg { - t.Errorf("test '%s': expect error '%s', but saw '%s'", tt.name, tt.expectErrMsg, err.Error()) - } - return - case tt.expectErrMsg != "" && err == nil: - t.Errorf("test '%s': expected error '%s' and didn't get one", tt.name, tt.expectErrMsg) - return - case tt.expectErrMsg == "" && err != nil: - t.Errorf("test '%s': unexpected error %s", tt.name, err.Error()) - return - } - if !reflect.DeepEqual(obj.(*policy.PodDisruptionBudget), tt.expectPDB) { - t.Errorf("test '%s': expected:\n%#v\nsaw:\n%#v", tt.name, tt.expectPDB, obj.(*policy.PodDisruptionBudget)) - } - }) - } -} - -func TestPodDisruptionBudgetV2Generate(t *testing.T) { - name := "foo" - minAvailable := "1" - minAvailableIS := intstr.Parse(minAvailable) - maxUnavailable := "5%" - maxUnavailableIS := intstr.Parse(maxUnavailable) - selector := "app=foo" - labelSelector, err := metav1.ParseToLabelSelector(selector) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - - tests := []struct { - name string - params map[string]interface{} - expectErrMsg string - expectPDB *policy.PodDisruptionBudget - }{ - { - name: "test-valid-min-available", - params: map[string]interface{}{ - "name": name, - "min-available": minAvailable, - "max-unavailable": "", - "selector": selector, - }, - expectPDB: &policy.PodDisruptionBudget{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - }, - Spec: policy.PodDisruptionBudgetSpec{ - MinAvailable: &minAvailableIS, - Selector: labelSelector, - }, - }, - }, - { - name: "test-valid-max-available", - params: map[string]interface{}{ - "name": name, - "min-available": "", - "max-unavailable": maxUnavailable, - "selector": selector, - }, - expectPDB: &policy.PodDisruptionBudget{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - }, - Spec: policy.PodDisruptionBudgetSpec{ - MaxUnavailable: &maxUnavailableIS, - Selector: labelSelector, - }, - }, - }, - { - name: "test-missing-name-param", - params: map[string]interface{}{ - "min-available": "", - "max-unavailable": "", - "selector": selector, - }, - expectErrMsg: "Parameter: name is required", - }, - { - name: "test-blank-name-param", - params: map[string]interface{}{ - "name": "", - "min-available": "", - "max-unavailable": "", - "selector": selector, - }, - expectErrMsg: "Parameter: name is required", - }, - { - name: "test-invalid-name-param", - params: map[string]interface{}{ - "name": 1, - "min-available": "", - "max-unavailable": "", - "selector": selector, - }, - expectErrMsg: "expected string, found int for 'name'", - }, - { - name: "test-missing-min-available-param", - params: map[string]interface{}{ - "name": name, - "max-unavailable": "", - "selector": selector, - }, - expectErrMsg: "expected string, found for 'min-available'", - }, - { - name: "test-invalid-min-available-param", - params: map[string]interface{}{ - "name": name, - "min-available": 1, - "max-unavailable": "", - "selector": selector, - }, - expectErrMsg: "expected string, found int for 'min-available'", - }, - { - name: "test-missing-max-available-param", - params: map[string]interface{}{ - "name": name, - "min-available": "", - "selector": selector, - }, - expectErrMsg: "expected string, found for 'max-unavailable'", - }, - { - name: "test-invalid-max-available-param", - params: map[string]interface{}{ - "name": name, - "min-available": "", - "max-unavailable": 1, - "selector": selector, - }, - expectErrMsg: "expected string, found int for 'max-unavailable'", - }, - { - name: "test-blank-min-available-max-unavailable-param", - params: map[string]interface{}{ - "name": name, - "min-available": "", - "max-unavailable": "", - "selector": selector, - }, - expectErrMsg: "one of min-available or max-unavailable must be specified", - }, - { - name: "test-min-available-max-unavailable-param", - params: map[string]interface{}{ - "name": name, - "min-available": minAvailable, - "max-unavailable": maxUnavailable, - "selector": selector, - }, - expectErrMsg: "min-available and max-unavailable cannot be both specified", - }, - { - name: "test-missing-selector-param", - params: map[string]interface{}{ - "name": name, - "min-available": "", - "max-unavailable": "", - }, - expectErrMsg: "Parameter: selector is required", - }, - { - name: "test-blank-selector-param", - params: map[string]interface{}{ - "name": name, - "min-available": "", - "max-unavailable": "", - "selector": "", - }, - expectErrMsg: "Parameter: selector is required", - }, - { - name: "test-invalid-selector-param", - params: map[string]interface{}{ - "name": name, - "min-available": "", - "max-unavailable": "", - "selector": 1, - }, - expectErrMsg: "expected string, found int for 'selector'", - }, - } - - generator := PodDisruptionBudgetV2Generator{} - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - obj, err := generator.Generate(tt.params) - switch { - case tt.expectErrMsg != "" && err != nil: - if err.Error() != tt.expectErrMsg { - t.Errorf("test '%s': expect error '%s', but saw '%s'", tt.name, tt.expectErrMsg, err.Error()) - } - return - case tt.expectErrMsg != "" && err == nil: - t.Errorf("test '%s': expected error '%s' and didn't get one", tt.name, tt.expectErrMsg) - return - case tt.expectErrMsg == "" && err != nil: - t.Errorf("test '%s': unexpected error %s", tt.name, err.Error()) - return - } - if !reflect.DeepEqual(obj.(*policy.PodDisruptionBudget), tt.expectPDB) { - t.Errorf("test '%s': expected:\n%#v\nsaw:\n%#v", tt.name, tt.expectPDB, obj.(*policy.PodDisruptionBudget)) - } - }) - } -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/priorityclass.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/priorityclass.go deleted file mode 100644 index a819ece3d4c..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/priorityclass.go +++ /dev/null @@ -1,93 +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 versioned - -import ( - "fmt" - - apiv1 "k8s.io/api/core/v1" - scheduling "k8s.io/api/scheduling/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/kubectl/pkg/generate" -) - -// PriorityClassV1Generator supports stable generation of a priorityClass. -type PriorityClassV1Generator struct { - Name string - Value int32 - GlobalDefault bool - Description string - PreemptionPolicy apiv1.PreemptionPolicy -} - -// Ensure it supports the generator pattern that uses parameters specified during construction. -var _ generate.StructuredGenerator = &PriorityClassV1Generator{} - -func (PriorityClassV1Generator) ParamNames() []generate.GeneratorParam { - return []generate.GeneratorParam{ - {Name: "name", Required: true}, - {Name: "value", Required: true}, - {Name: "global-default", Required: false}, - {Name: "description", Required: false}, - {Name: "preemption-policy", Required: false}, - } -} - -func (s PriorityClassV1Generator) Generate(params map[string]interface{}) (runtime.Object, error) { - if err := generate.ValidateParams(s.ParamNames(), params); err != nil { - return nil, err - } - - name, found := params["name"].(string) - if !found { - return nil, fmt.Errorf("expected string, saw %v for 'name'", name) - } - - value, found := params["value"].(int32) - if !found { - return nil, fmt.Errorf("expected int32, found %v", value) - } - - globalDefault, found := params["global-default"].(bool) - if !found { - return nil, fmt.Errorf("expected bool, found %v", globalDefault) - } - - description, found := params["description"].(string) - if !found { - return nil, fmt.Errorf("expected string, found %v", description) - } - - preemptionPolicy := apiv1.PreemptionPolicy(params["preemption-policy"].(string)) - - delegate := &PriorityClassV1Generator{Name: name, Value: value, GlobalDefault: globalDefault, Description: description, PreemptionPolicy: preemptionPolicy} - return delegate.StructuredGenerate() -} - -// StructuredGenerate outputs a priorityClass object using the configured fields. -func (s *PriorityClassV1Generator) StructuredGenerate() (runtime.Object, error) { - return &scheduling.PriorityClass{ - ObjectMeta: metav1.ObjectMeta{ - Name: s.Name, - }, - Value: s.Value, - GlobalDefault: s.GlobalDefault, - Description: s.Description, - PreemptionPolicy: &s.PreemptionPolicy, - }, nil -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/priorityclass_test.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/priorityclass_test.go deleted file mode 100644 index 968a53ad9a0..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/priorityclass_test.go +++ /dev/null @@ -1,126 +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 versioned - -import ( - apiv1 "k8s.io/api/core/v1" - scheduling "k8s.io/api/scheduling/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "reflect" - "testing" -) - -func TestPriorityClassV1Generator(t *testing.T) { - var ( - preemptLowerPriority = apiv1.PreemptLowerPriority - preemptNever = apiv1.PreemptNever - ) - tests := []struct { - name string - params map[string]interface{} - expected *scheduling.PriorityClass - expectErr bool - }{ - { - name: "test valid case", - params: map[string]interface{}{ - "name": "foo", - "value": int32(1000), - "global-default": false, - "description": "high priority class", - "preemption-policy": "PreemptLowerPriority", - }, - expected: &scheduling.PriorityClass{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Value: int32(1000), - GlobalDefault: false, - Description: "high priority class", - PreemptionPolicy: &preemptLowerPriority, - }, - expectErr: false, - }, - { - name: "test valid case that field non-preempting is set", - params: map[string]interface{}{ - "name": "foo", - "value": int32(1000), - "global-default": false, - "description": "high priority class", - "preemption-policy": "Never", - }, - expected: &scheduling.PriorityClass{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Value: int32(1000), - GlobalDefault: false, - Description: "high priority class", - PreemptionPolicy: &preemptNever, - }, - expectErr: false, - }, - { - name: "test valid case that as default priority", - params: map[string]interface{}{ - "name": "foo", - "value": int32(1000), - "global-default": true, - "description": "high priority class", - "preemption-policy": "PreemptLowerPriority", - }, - expected: &scheduling.PriorityClass{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Value: int32(1000), - GlobalDefault: true, - Description: "high priority class", - PreemptionPolicy: &preemptLowerPriority, - }, - expectErr: false, - }, - { - name: "test missing required param", - params: map[string]interface{}{ - "name": "foo", - "global-default": true, - "description": "high priority class", - "preemption-policy": "PreemptLowerPriority", - }, - expectErr: true, - }, - } - - generator := PriorityClassV1Generator{} - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - obj, err := generator.Generate(tt.params) - if !tt.expectErr && err != nil { - t.Errorf("%s: unexpected error: %v", tt.name, err) - } - if tt.expectErr && err != nil { - return - } - if !reflect.DeepEqual(obj.(*scheduling.PriorityClass), tt.expected) { - t.Errorf("%s:\nexpected:\n%#v\nsaw:\n%#v", tt.name, tt.expected, obj.(*scheduling.PriorityClass)) - } - }) - } -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/quota.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/quota.go deleted file mode 100644 index 1a59b6e37df..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/quota.go +++ /dev/null @@ -1,126 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package versioned - -import ( - "fmt" - "strings" - - "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/kubectl/pkg/generate" -) - -// ResourceQuotaGeneratorV1 supports stable generation of a resource quota -type ResourceQuotaGeneratorV1 struct { - // The name of a quota object. - Name string - - // The hard resource limit string before parsing. - Hard string - - // The scopes of a quota object before parsing. - Scopes string -} - -// ParamNames returns the set of supported input parameters when using the parameter injection generator pattern -func (g ResourceQuotaGeneratorV1) ParamNames() []generate.GeneratorParam { - return []generate.GeneratorParam{ - {Name: "name", Required: true}, - {Name: "hard", Required: true}, - {Name: "scopes", Required: false}, - } -} - -// Ensure it supports the generator pattern that uses parameter injection -var _ generate.Generator = &ResourceQuotaGeneratorV1{} - -// Ensure it supports the generator pattern that uses parameters specified during construction -var _ generate.StructuredGenerator = &ResourceQuotaGeneratorV1{} - -func (g ResourceQuotaGeneratorV1) Generate(genericParams map[string]interface{}) (runtime.Object, error) { - err := generate.ValidateParams(g.ParamNames(), genericParams) - if err != nil { - return nil, err - } - - params := map[string]string{} - for key, value := range genericParams { - strVal, isString := value.(string) - if !isString { - return nil, fmt.Errorf("expected string, saw %v for '%s'", value, key) - } - params[key] = strVal - } - - delegate := &ResourceQuotaGeneratorV1{} - delegate.Name = params["name"] - delegate.Hard = params["hard"] - delegate.Scopes = params["scopes"] - return delegate.StructuredGenerate() -} - -// StructuredGenerate outputs a ResourceQuota object using the configured fields -func (g *ResourceQuotaGeneratorV1) StructuredGenerate() (runtime.Object, error) { - if err := g.validate(); err != nil { - return nil, err - } - - resourceList, err := populateResourceListV1(g.Hard) - if err != nil { - return nil, err - } - - scopes, err := parseScopes(g.Scopes) - if err != nil { - return nil, err - } - - resourceQuota := &v1.ResourceQuota{} - resourceQuota.Name = g.Name - resourceQuota.Spec.Hard = resourceList - resourceQuota.Spec.Scopes = scopes - return resourceQuota, nil -} - -// validate validates required fields are set to support structured generation -func (r *ResourceQuotaGeneratorV1) validate() error { - if len(r.Name) == 0 { - return fmt.Errorf("name must be specified") - } - return nil -} - -func parseScopes(spec string) ([]v1.ResourceQuotaScope, error) { - // empty input gets a nil response to preserve generator test expected behaviors - if spec == "" { - return nil, nil - } - - scopes := strings.Split(spec, ",") - result := make([]v1.ResourceQuotaScope, 0, len(scopes)) - for _, scope := range scopes { - // intentionally do not verify the scope against the valid scope list. This is done by the apiserver anyway. - - if scope == "" { - return nil, fmt.Errorf("invalid resource quota scope \"\"") - } - - result = append(result, v1.ResourceQuotaScope(scope)) - } - return result, nil -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/quota_test.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/quota_test.go deleted file mode 100644 index 65380a6395d..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/quota_test.go +++ /dev/null @@ -1,123 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package versioned - -import ( - "reflect" - "testing" - - "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func TestQuotaGenerate(t *testing.T) { - hard := "cpu=10,memory=5G,pods=10,services=7" - resourceQuotaSpecList, err := populateResourceListV1(hard) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - - tests := []struct { - name string - params map[string]interface{} - expected *v1.ResourceQuota - expectErr bool - }{ - { - name: "test-valid-use", - params: map[string]interface{}{ - "name": "foo", - "hard": hard, - }, - expected: &v1.ResourceQuota{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: v1.ResourceQuotaSpec{Hard: resourceQuotaSpecList}, - }, - expectErr: false, - }, - { - name: "test-missing-required-param", - params: map[string]interface{}{ - "name": "foo", - }, - expectErr: true, - }, - { - name: "test-valid-scopes", - params: map[string]interface{}{ - "name": "foo", - "hard": hard, - "scopes": "BestEffort,NotTerminating", - }, - expected: &v1.ResourceQuota{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: v1.ResourceQuotaSpec{ - Hard: resourceQuotaSpecList, - Scopes: []v1.ResourceQuotaScope{ - v1.ResourceQuotaScopeBestEffort, - v1.ResourceQuotaScopeNotTerminating, - }, - }, - }, - expectErr: false, - }, - { - name: "test-empty-scopes", - params: map[string]interface{}{ - "name": "foo", - "hard": hard, - "scopes": "", - }, - expected: &v1.ResourceQuota{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: v1.ResourceQuotaSpec{Hard: resourceQuotaSpecList}, - }, - expectErr: false, - }, - { - name: "test-invalid-scopes", - params: map[string]interface{}{ - "name": "foo", - "hard": hard, - "scopes": "abc,", - }, - expectErr: true, - }, - } - - generator := ResourceQuotaGeneratorV1{} - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - obj, err := generator.Generate(tt.params) - if !tt.expectErr && err != nil { - t.Errorf("%s: unexpected error: %v", tt.name, err) - } - if tt.expectErr && err != nil { - return - } - if !reflect.DeepEqual(obj.(*v1.ResourceQuota), tt.expected) { - t.Errorf("%s:\nexpected:\n%#v\nsaw:\n%#v", tt.name, tt.expected, obj.(*v1.ResourceQuota)) - } - }) - } -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/rolebinding.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/rolebinding.go deleted file mode 100644 index f811750c91f..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/rolebinding.go +++ /dev/null @@ -1,174 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package versioned - -import ( - "fmt" - - "strings" - - rbacv1 "k8s.io/api/rbac/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/kubectl/pkg/generate" -) - -// RoleBindingGeneratorV1 supports stable generation of a roleBinding. -type RoleBindingGeneratorV1 struct { - // Name of roleBinding (required) - Name string - // ClusterRole for the roleBinding - ClusterRole string - // Role for the roleBinding - Role string - // Users to derive the roleBinding from (optional) - Users []string - // Groups to derive the roleBinding from (optional) - Groups []string - // ServiceAccounts to derive the roleBinding from in namespace:name format(optional) - ServiceAccounts []string -} - -// Ensure it supports the generator pattern that uses parameter injection. -var _ generate.Generator = &RoleBindingGeneratorV1{} - -// Ensure it supports the generator pattern that uses parameters specified during construction. -var _ generate.StructuredGenerator = &RoleBindingGeneratorV1{} - -// Generate returns a roleBinding using the specified parameters. -func (s RoleBindingGeneratorV1) Generate(genericParams map[string]interface{}) (runtime.Object, error) { - err := generate.ValidateParams(s.ParamNames(), genericParams) - if err != nil { - return nil, err - } - delegate := &RoleBindingGeneratorV1{} - userStrings, found := genericParams["user"] - if found { - fromFileArray, isArray := userStrings.([]string) - if !isArray { - return nil, fmt.Errorf("expected []string, found :%v", userStrings) - } - delegate.Users = fromFileArray - delete(genericParams, "user") - } - groupStrings, found := genericParams["group"] - if found { - fromLiteralArray, isArray := groupStrings.([]string) - if !isArray { - return nil, fmt.Errorf("expected []string, found :%v", groupStrings) - } - delegate.Groups = fromLiteralArray - delete(genericParams, "group") - } - saStrings, found := genericParams["serviceaccount"] - if found { - fromLiteralArray, isArray := saStrings.([]string) - if !isArray { - return nil, fmt.Errorf("expected []string, found :%v", saStrings) - } - delegate.ServiceAccounts = fromLiteralArray - delete(genericParams, "serviceaccount") - } - params := map[string]string{} - for key, value := range genericParams { - strVal, isString := value.(string) - if !isString { - return nil, fmt.Errorf("expected string, saw %v for '%s'", value, key) - } - params[key] = strVal - } - delegate.Name = params["name"] - delegate.ClusterRole = params["clusterrole"] - delegate.Role = params["role"] - return delegate.StructuredGenerate() -} - -// ParamNames returns the set of supported input parameters when using the parameter injection generator pattern. -func (s RoleBindingGeneratorV1) ParamNames() []generate.GeneratorParam { - return []generate.GeneratorParam{ - {Name: "name", Required: true}, - {Name: "clusterrole", Required: false}, - {Name: "role", Required: false}, - {Name: "user", Required: false}, - {Name: "group", Required: false}, - {Name: "serviceaccount", Required: false}, - } -} - -// StructuredGenerate outputs a roleBinding object using the configured fields. -func (s RoleBindingGeneratorV1) StructuredGenerate() (runtime.Object, error) { - if err := s.validate(); err != nil { - return nil, err - } - roleBinding := &rbacv1.RoleBinding{} - roleBinding.Name = s.Name - - switch { - case len(s.Role) > 0: - roleBinding.RoleRef = rbacv1.RoleRef{ - APIGroup: rbacv1.GroupName, - Kind: "Role", - Name: s.Role, - } - case len(s.ClusterRole) > 0: - roleBinding.RoleRef = rbacv1.RoleRef{ - APIGroup: rbacv1.GroupName, - Kind: "ClusterRole", - Name: s.ClusterRole, - } - } - - for _, user := range sets.NewString(s.Users...).List() { - roleBinding.Subjects = append(roleBinding.Subjects, rbacv1.Subject{ - Kind: rbacv1.UserKind, - APIGroup: rbacv1.GroupName, - Name: user, - }) - } - for _, group := range sets.NewString(s.Groups...).List() { - roleBinding.Subjects = append(roleBinding.Subjects, rbacv1.Subject{ - Kind: rbacv1.GroupKind, - APIGroup: rbacv1.GroupName, - Name: group, - }) - } - for _, sa := range sets.NewString(s.ServiceAccounts...).List() { - tokens := strings.Split(sa, ":") - if len(tokens) != 2 || tokens[1] == "" { - return nil, fmt.Errorf("serviceaccount must be :") - } - roleBinding.Subjects = append(roleBinding.Subjects, rbacv1.Subject{ - Kind: rbacv1.ServiceAccountKind, - APIGroup: "", - Namespace: tokens[0], - Name: tokens[1], - }) - } - - return roleBinding, nil -} - -// validate validates required fields are set to support structured generation. -func (s RoleBindingGeneratorV1) validate() error { - if len(s.Name) == 0 { - return fmt.Errorf("name must be specified") - } - if (len(s.ClusterRole) == 0) == (len(s.Role) == 0) { - return fmt.Errorf("exactly one of clusterrole or role must be specified") - } - return nil -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/rolebinding_test.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/rolebinding_test.go deleted file mode 100644 index 0e7073ac611..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/rolebinding_test.go +++ /dev/null @@ -1,144 +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 versioned - -import ( - "reflect" - "testing" - - rbac "k8s.io/api/rbac/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func TestRoleBindingGenerate(t *testing.T) { - tests := []struct { - name string - params map[string]interface{} - expectErrMsg string - expectBinding *rbac.RoleBinding - }{ - { - name: "test-missing-name", - params: map[string]interface{}{ - "role": "fake-role", - "groups": []string{"fake-group"}, - "serviceaccount": []string{"fake-namespace:fake-account"}, - }, - expectErrMsg: "Parameter: name is required", - }, - { - name: "test-missing-role-and-clusterrole", - params: map[string]interface{}{ - "name": "fake-binding", - "group": []string{"fake-group"}, - "serviceaccount": []string{"fake-namespace:fake-account"}, - }, - expectErrMsg: "exactly one of clusterrole or role must be specified", - }, - { - name: "test-both-role-and-clusterrole-provided", - params: map[string]interface{}{ - "name": "fake-binding", - "role": "fake-role", - "clusterrole": "fake-clusterrole", - "group": []string{"fake-group"}, - "serviceaccount": []string{"fake-namespace:fake-account"}, - }, - expectErrMsg: "exactly one of clusterrole or role must be specified", - }, - { - name: "test-invalid-parameter-type", - params: map[string]interface{}{ - "name": "fake-binding", - "role": []string{"fake-role"}, - "group": []string{"fake-group"}, - "serviceaccount": []string{"fake-namespace:fake-account"}, - }, - expectErrMsg: "expected string, saw [fake-role] for 'role'", - }, - { - name: "test-invalid-serviceaccount", - params: map[string]interface{}{ - "name": "fake-binding", - "role": "fake-role", - "group": []string{"fake-group"}, - "serviceaccount": []string{"fake-account"}, - }, - expectErrMsg: "serviceaccount must be :", - }, - { - name: "test-valid-case", - params: map[string]interface{}{ - "name": "fake-binding", - "role": "fake-role", - "user": []string{"fake-user"}, - "group": []string{"fake-group"}, - "serviceaccount": []string{"fake-namespace:fake-account"}, - }, - expectBinding: &rbac.RoleBinding{ - ObjectMeta: v1.ObjectMeta{ - Name: "fake-binding", - }, - RoleRef: rbac.RoleRef{ - APIGroup: rbac.GroupName, - Kind: "Role", - Name: "fake-role", - }, - Subjects: []rbac.Subject{ - { - Kind: rbac.UserKind, - APIGroup: "rbac.authorization.k8s.io", - Name: "fake-user", - }, - { - Kind: rbac.GroupKind, - APIGroup: "rbac.authorization.k8s.io", - Name: "fake-group", - }, - { - Kind: rbac.ServiceAccountKind, - Namespace: "fake-namespace", - Name: "fake-account", - }, - }, - }, - }, - } - - generator := RoleBindingGeneratorV1{} - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - obj, err := generator.Generate(tt.params) - switch { - case tt.expectErrMsg != "" && err != nil: - if err.Error() != tt.expectErrMsg { - t.Errorf("test '%s': expect error '%s', but saw '%s'", tt.name, tt.expectErrMsg, err.Error()) - } - return - case tt.expectErrMsg != "" && err == nil: - t.Errorf("test '%s': expected error '%s' and didn't get one", tt.name, tt.expectErrMsg) - return - case tt.expectErrMsg == "" && err != nil: - t.Errorf("test '%s': unexpected error %s", tt.name, err.Error()) - return - } - if !reflect.DeepEqual(obj.(*rbac.RoleBinding), tt.expectBinding) { - t.Errorf("test '%s': expected:\n%#v\nsaw:\n%#v", tt.name, tt.expectBinding, obj.(*rbac.RoleBinding)) - } - }) - } -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/secret.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/secret.go deleted file mode 100644 index 9a331b7467b..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/secret.go +++ /dev/null @@ -1,273 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package versioned - -import ( - "fmt" - "io/ioutil" - "os" - "path" - "strings" - - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/validation" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - "k8s.io/kubectl/pkg/generate" - "k8s.io/kubectl/pkg/util" - "k8s.io/kubectl/pkg/util/hash" -) - -// SecretGeneratorV1 supports stable generation of an opaque secret -type SecretGeneratorV1 struct { - // Name of secret (required) - Name string - // Type of secret (optional) - Type string - // FileSources to derive the secret from (optional) - FileSources []string - // LiteralSources to derive the secret from (optional) - LiteralSources []string - // EnvFileSource to derive the secret from (optional) - EnvFileSource string - // AppendHash; if true, derive a hash from the Secret data and type and append it to the name - AppendHash bool -} - -// Ensure it supports the generator pattern that uses parameter injection -var _ generate.Generator = &SecretGeneratorV1{} - -// Ensure it supports the generator pattern that uses parameters specified during construction -var _ generate.StructuredGenerator = &SecretGeneratorV1{} - -// Generate returns a secret using the specified parameters -func (s SecretGeneratorV1) Generate(genericParams map[string]interface{}) (runtime.Object, error) { - err := generate.ValidateParams(s.ParamNames(), genericParams) - if err != nil { - return nil, err - } - delegate := &SecretGeneratorV1{} - fromFileStrings, found := genericParams["from-file"] - if found { - fromFileArray, isArray := fromFileStrings.([]string) - if !isArray { - return nil, fmt.Errorf("expected []string, found :%v", fromFileStrings) - } - delegate.FileSources = fromFileArray - delete(genericParams, "from-file") - } - fromLiteralStrings, found := genericParams["from-literal"] - if found { - fromLiteralArray, isArray := fromLiteralStrings.([]string) - if !isArray { - return nil, fmt.Errorf("expected []string, found :%v", fromLiteralStrings) - } - delegate.LiteralSources = fromLiteralArray - delete(genericParams, "from-literal") - } - fromEnvFileString, found := genericParams["from-env-file"] - if found { - fromEnvFile, isString := fromEnvFileString.(string) - if !isString { - return nil, fmt.Errorf("expected string, found :%v", fromEnvFileString) - } - delegate.EnvFileSource = fromEnvFile - delete(genericParams, "from-env-file") - } - - hashParam, found := genericParams["append-hash"] - if found { - hashBool, isBool := hashParam.(bool) - if !isBool { - return nil, fmt.Errorf("expected bool, found :%v", hashParam) - } - delegate.AppendHash = hashBool - delete(genericParams, "append-hash") - } - - params := map[string]string{} - for key, value := range genericParams { - strVal, isString := value.(string) - if !isString { - return nil, fmt.Errorf("expected string, saw %v for '%s'", value, key) - } - params[key] = strVal - } - delegate.Name = params["name"] - delegate.Type = params["type"] - - return delegate.StructuredGenerate() -} - -// ParamNames returns the set of supported input parameters when using the parameter injection generator pattern -func (s SecretGeneratorV1) ParamNames() []generate.GeneratorParam { - return []generate.GeneratorParam{ - {Name: "name", Required: true}, - {Name: "type", Required: false}, - {Name: "from-file", Required: false}, - {Name: "from-literal", Required: false}, - {Name: "from-env-file", Required: false}, - {Name: "force", Required: false}, - {Name: "append-hash", Required: false}, - } -} - -// StructuredGenerate outputs a secret object using the configured fields -func (s SecretGeneratorV1) StructuredGenerate() (runtime.Object, error) { - if err := s.validate(); err != nil { - return nil, err - } - secret := &v1.Secret{} - secret.SetGroupVersionKind(v1.SchemeGroupVersion.WithKind("Secret")) - secret.Name = s.Name - secret.Data = map[string][]byte{} - if len(s.Type) > 0 { - secret.Type = v1.SecretType(s.Type) - } - if len(s.FileSources) > 0 { - if err := handleFromFileSources(secret, s.FileSources); err != nil { - return nil, err - } - } - if len(s.LiteralSources) > 0 { - if err := handleFromLiteralSources(secret, s.LiteralSources); err != nil { - return nil, err - } - } - if len(s.EnvFileSource) > 0 { - if err := handleFromEnvFileSource(secret, s.EnvFileSource); err != nil { - return nil, err - } - } - if s.AppendHash { - h, err := hash.SecretHash(secret) - if err != nil { - return nil, err - } - secret.Name = fmt.Sprintf("%s-%s", secret.Name, h) - } - return secret, nil -} - -// validate validates required fields are set to support structured generation -func (s SecretGeneratorV1) validate() error { - if len(s.Name) == 0 { - return fmt.Errorf("name must be specified") - } - if len(s.EnvFileSource) > 0 && (len(s.FileSources) > 0 || len(s.LiteralSources) > 0) { - return fmt.Errorf("from-env-file cannot be combined with from-file or from-literal") - } - return nil -} - -// handleFromLiteralSources adds the specified literal source information into the provided secret -func handleFromLiteralSources(secret *v1.Secret, literalSources []string) error { - for _, literalSource := range literalSources { - keyName, value, err := util.ParseLiteralSource(literalSource) - if err != nil { - return err - } - if err = addKeyFromLiteralToSecret(secret, keyName, []byte(value)); err != nil { - return err - } - } - return nil -} - -// handleFromFileSources adds the specified file source information into the provided secret -func handleFromFileSources(secret *v1.Secret, fileSources []string) error { - for _, fileSource := range fileSources { - keyName, filePath, err := util.ParseFileSource(fileSource) - if err != nil { - return err - } - info, err := os.Stat(filePath) - if err != nil { - switch err := err.(type) { - case *os.PathError: - return fmt.Errorf("error reading %s: %v", filePath, err.Err) - default: - return fmt.Errorf("error reading %s: %v", filePath, err) - } - } - if info.IsDir() { - if strings.Contains(fileSource, "=") { - return fmt.Errorf("cannot give a key name for a directory path") - } - fileList, err := ioutil.ReadDir(filePath) - if err != nil { - return fmt.Errorf("error listing files in %s: %v", filePath, err) - } - for _, item := range fileList { - itemPath := path.Join(filePath, item.Name()) - if item.Mode().IsRegular() { - keyName = item.Name() - if err = addKeyFromFileToSecret(secret, keyName, itemPath); err != nil { - return err - } - } - } - } else { - if err := addKeyFromFileToSecret(secret, keyName, filePath); err != nil { - return err - } - } - } - - return nil -} - -// handleFromEnvFileSource adds the specified env file source information -// into the provided secret -func handleFromEnvFileSource(secret *v1.Secret, envFileSource string) error { - info, err := os.Stat(envFileSource) - if err != nil { - switch err := err.(type) { - case *os.PathError: - return fmt.Errorf("error reading %s: %v", envFileSource, err.Err) - default: - return fmt.Errorf("error reading %s: %v", envFileSource, err) - } - } - if info.IsDir() { - return fmt.Errorf("env secret file cannot be a directory") - } - - return cmdutil.AddFromEnvFile(envFileSource, func(key, value string) error { - return addKeyFromLiteralToSecret(secret, key, []byte(value)) - }) -} - -func addKeyFromFileToSecret(secret *v1.Secret, keyName, filePath string) error { - data, err := ioutil.ReadFile(filePath) - if err != nil { - return err - } - return addKeyFromLiteralToSecret(secret, keyName, data) -} - -func addKeyFromLiteralToSecret(secret *v1.Secret, keyName string, data []byte) error { - if errs := validation.IsConfigMapKey(keyName); len(errs) != 0 { - return fmt.Errorf("%q is not a valid key name for a Secret: %s", keyName, strings.Join(errs, ";")) - } - - if _, entryExists := secret.Data[keyName]; entryExists { - return fmt.Errorf("cannot add key %s, another key by that name already exists", keyName) - } - secret.Data[keyName] = data - return nil -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/secret_for_docker_registry.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/secret_for_docker_registry.go deleted file mode 100644 index 67f689903c4..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/secret_for_docker_registry.go +++ /dev/null @@ -1,189 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package versioned - -import ( - "encoding/base64" - "encoding/json" - "fmt" - - "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/kubectl/pkg/generate" - "k8s.io/kubectl/pkg/util/hash" -) - -// SecretForDockerRegistryGeneratorV1 supports stable generation of a docker registry secret -type SecretForDockerRegistryGeneratorV1 struct { - // Name of secret (required) - Name string - // FileSources to derive the secret from (optional) - FileSources []string - // Username for registry (required) - Username string - // Email for registry (optional) - Email string - // Password for registry (required) - Password string `datapolicy:"password"` - // Server for registry (required) - Server string - // AppendHash; if true, derive a hash from the Secret and append it to the name - AppendHash bool -} - -// Ensure it supports the generator pattern that uses parameter injection -var _ generate.Generator = &SecretForDockerRegistryGeneratorV1{} - -// Ensure it supports the generator pattern that uses parameters specified during construction -var _ generate.StructuredGenerator = &SecretForDockerRegistryGeneratorV1{} - -// Generate returns a secret using the specified parameters -func (s SecretForDockerRegistryGeneratorV1) Generate(genericParams map[string]interface{}) (runtime.Object, error) { - err := generate.ValidateParams(s.ParamNames(), genericParams) - if err != nil { - return nil, err - } - delegate := &SecretForDockerRegistryGeneratorV1{} - hashParam, found := genericParams["append-hash"] - if found { - hashBool, isBool := hashParam.(bool) - if !isBool { - return nil, fmt.Errorf("expected bool, found :%v", hashParam) - } - delegate.AppendHash = hashBool - delete(genericParams, "append-hash") - } - params := map[string]string{} - for key, value := range genericParams { - strVal, isString := value.(string) - if !isString { - return nil, fmt.Errorf("expected string, saw %v for '%s'", value, key) - } - params[key] = strVal - } - delegate.Name = params["name"] - delegate.Username = params["docker-username"] - delegate.Email = params["docker-email"] - delegate.Password = params["docker-password"] - delegate.Server = params["docker-server"] - return delegate.StructuredGenerate() -} - -// StructuredGenerate outputs a secret object using the configured fields -func (s SecretForDockerRegistryGeneratorV1) StructuredGenerate() (runtime.Object, error) { - if err := s.validate(); err != nil { - return nil, err - } - secret := &v1.Secret{} - secret.Name = s.Name - secret.Type = v1.SecretTypeDockerConfigJson - secret.Data = map[string][]byte{} - if len(s.FileSources) > 0 { - if err := handleFromFileSources(secret, s.FileSources); err != nil { - return nil, err - } - } - if len(s.FileSources) == 0 { - dockercfgJSONContent, err := handleDockerCfgJSONContent(s.Username, s.Password, s.Email, s.Server) - if err != nil { - return nil, err - } - secret.Data[v1.DockerConfigJsonKey] = dockercfgJSONContent - } - if s.AppendHash { - h, err := hash.SecretHash(secret) - if err != nil { - return nil, err - } - secret.Name = fmt.Sprintf("%s-%s", secret.Name, h) - } - return secret, nil -} - -// ParamNames returns the set of supported input parameters when using the parameter injection generator pattern -func (s SecretForDockerRegistryGeneratorV1) ParamNames() []generate.GeneratorParam { - return []generate.GeneratorParam{ - {Name: "name", Required: true}, - {Name: "from-file", Required: false}, - {Name: "docker-username", Required: true}, - {Name: "docker-email", Required: false}, - {Name: "docker-password", Required: true}, - {Name: "docker-server", Required: true}, - {Name: "append-hash", Required: false}, - } -} - -// validate validates required fields are set to support structured generation -func (s SecretForDockerRegistryGeneratorV1) validate() error { - if len(s.Name) == 0 { - return fmt.Errorf("name must be specified") - } - - if len(s.FileSources) == 0 { - if len(s.Username) == 0 { - return fmt.Errorf("username must be specified") - } - if len(s.Password) == 0 { - return fmt.Errorf("password must be specified") - } - if len(s.Server) == 0 { - return fmt.Errorf("server must be specified") - } - } - return nil -} - -// handleDockerCfgJSONContent serializes a ~/.docker/config.json file -func handleDockerCfgJSONContent(username, password, email, server string) ([]byte, error) { - dockercfgAuth := DockerConfigEntry{ - Username: username, - Password: password, - Email: email, - Auth: encodeDockerConfigFieldAuth(username, password), - } - - dockerCfgJSON := DockerConfigJSON{ - Auths: map[string]DockerConfigEntry{server: dockercfgAuth}, - } - - return json.Marshal(dockerCfgJSON) -} - -func encodeDockerConfigFieldAuth(username, password string) string { - fieldValue := username + ":" + password - return base64.StdEncoding.EncodeToString([]byte(fieldValue)) -} - -// DockerConfigJSON represents a local docker auth config file -// for pulling images. -type DockerConfigJSON struct { - Auths DockerConfig `json:"auths" datapolicy:"token"` - // +optional - HttpHeaders map[string]string `json:"HttpHeaders,omitempty" datapolicy:"token"` -} - -// DockerConfig represents the config file used by the docker CLI. -// This config that represents the credentials that should be used -// when pulling images from specific image repositories. -type DockerConfig map[string]DockerConfigEntry - -type DockerConfigEntry struct { - Username string `json:"username,omitempty"` - Password string `json:"password,omitempty" datapolicy:"password"` - Email string `json:"email,omitempty"` - Auth string `json:"auth,omitempty" datapolicy:"token"` -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/secret_for_docker_registry_test.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/secret_for_docker_registry_test.go deleted file mode 100644 index 97384a8fab1..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/secret_for_docker_registry_test.go +++ /dev/null @@ -1,132 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package versioned - -import ( - "reflect" - "testing" - - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func TestSecretForDockerRegistryGenerate(t *testing.T) { - // Fake values for testing. - username, password, email, server := "test-user", "test-password", "test-user@example.org", "https://index.docker.io/v1/" - secretData, err := handleDockerCfgJSONContent(username, password, email, server) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - secretDataNoEmail, err := handleDockerCfgJSONContent(username, password, "", server) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - - tests := []struct { - name string - params map[string]interface{} - expected *v1.Secret - expectErr bool - }{ - { - name: "test-valid-use", - params: map[string]interface{}{ - "name": "foo", - "docker-server": server, - "docker-username": username, - "docker-password": password, - "docker-email": email, - }, - expected: &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Data: map[string][]byte{ - v1.DockerConfigJsonKey: secretData, - }, - Type: v1.SecretTypeDockerConfigJson, - }, - expectErr: false, - }, - { - name: "test-valid-use-append-hash", - params: map[string]interface{}{ - "name": "foo", - "docker-server": server, - "docker-username": username, - "docker-password": password, - "docker-email": email, - "append-hash": true, - }, - expected: &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo-548cm7fgdh", - }, - Data: map[string][]byte{ - v1.DockerConfigJsonKey: secretData, - }, - Type: v1.SecretTypeDockerConfigJson, - }, - expectErr: false, - }, - { - name: "test-valid-use-no-email", - params: map[string]interface{}{ - "name": "foo", - "docker-server": server, - "docker-username": username, - "docker-password": password, - }, - expected: &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Data: map[string][]byte{ - v1.DockerConfigJsonKey: secretDataNoEmail, - }, - Type: v1.SecretTypeDockerConfigJson, - }, - expectErr: false, - }, - { - name: "test-missing-required-param", - params: map[string]interface{}{ - "name": "foo", - "docker-server": server, - "docker-password": password, - "docker-email": email, - }, - expectErr: true, - }, - } - - generator := SecretForDockerRegistryGeneratorV1{} - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - obj, err := generator.Generate(tt.params) - if !tt.expectErr && err != nil { - t.Errorf("unexpected error: %v", err) - } - if tt.expectErr && err != nil { - return - } - if !reflect.DeepEqual(obj.(*v1.Secret), tt.expected) { - t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", tt.expected, obj.(*v1.Secret)) - } - }) - } -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/secret_for_tls.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/secret_for_tls.go deleted file mode 100644 index 7c65f0b41c9..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/secret_for_tls.go +++ /dev/null @@ -1,146 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package versioned - -import ( - "crypto/tls" - "fmt" - "io/ioutil" - - "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/kubectl/pkg/generate" - "k8s.io/kubectl/pkg/util/hash" -) - -// SecretForTLSGeneratorV1 supports stable generation of a TLS secret. -type SecretForTLSGeneratorV1 struct { - // Name is the name of this TLS secret. - Name string - // Key is the path to the user's private key. - Key string - // Cert is the path to the user's public key certificate. - Cert string - // AppendHash; if true, derive a hash from the Secret and append it to the name - AppendHash bool -} - -// Ensure it supports the generator pattern that uses parameter injection -var _ generate.Generator = &SecretForTLSGeneratorV1{} - -// Ensure it supports the generator pattern that uses parameters specified during construction -var _ generate.StructuredGenerator = &SecretForTLSGeneratorV1{} - -// Generate returns a secret using the specified parameters -func (s SecretForTLSGeneratorV1) Generate(genericParams map[string]interface{}) (runtime.Object, error) { - err := generate.ValidateParams(s.ParamNames(), genericParams) - if err != nil { - return nil, err - } - delegate := &SecretForTLSGeneratorV1{} - hashParam, found := genericParams["append-hash"] - if found { - hashBool, isBool := hashParam.(bool) - if !isBool { - return nil, fmt.Errorf("expected bool, found :%v", hashParam) - } - delegate.AppendHash = hashBool - delete(genericParams, "append-hash") - } - params := map[string]string{} - for key, value := range genericParams { - strVal, isString := value.(string) - if !isString { - return nil, fmt.Errorf("expected string, saw %v for '%s'", value, key) - } - params[key] = strVal - } - delegate.Name = params["name"] - delegate.Key = params["key"] - delegate.Cert = params["cert"] - return delegate.StructuredGenerate() -} - -// StructuredGenerate outputs a secret object using the configured fields -func (s SecretForTLSGeneratorV1) StructuredGenerate() (runtime.Object, error) { - if err := s.validate(); err != nil { - return nil, err - } - tlsCrt, err := readFile(s.Cert) - if err != nil { - return nil, err - } - tlsKey, err := readFile(s.Key) - if err != nil { - return nil, err - } - - if _, err := tls.X509KeyPair(tlsCrt, tlsKey); err != nil { - return nil, fmt.Errorf("failed to load key pair %v", err) - } - // TODO: Add more validation. - // 1. If the certificate contains intermediates, it is a valid chain. - // 2. Format etc. - - secret := &v1.Secret{} - secret.Name = s.Name - secret.Type = v1.SecretTypeTLS - secret.Data = map[string][]byte{} - secret.Data[v1.TLSCertKey] = []byte(tlsCrt) - secret.Data[v1.TLSPrivateKeyKey] = []byte(tlsKey) - if s.AppendHash { - h, err := hash.SecretHash(secret) - if err != nil { - return nil, err - } - secret.Name = fmt.Sprintf("%s-%s", secret.Name, h) - } - return secret, nil -} - -// readFile just reads a file into a byte array. -func readFile(file string) ([]byte, error) { - b, err := ioutil.ReadFile(file) - if err != nil { - return []byte{}, fmt.Errorf("Cannot read file %v, %v", file, err) - } - return b, nil -} - -// ParamNames returns the set of supported input parameters when using the parameter injection generator pattern -func (s SecretForTLSGeneratorV1) ParamNames() []generate.GeneratorParam { - return []generate.GeneratorParam{ - {Name: "name", Required: true}, - {Name: "key", Required: true}, - {Name: "cert", Required: true}, - {Name: "append-hash", Required: false}, - } -} - -// validate validates required fields are set to support structured generation -func (s SecretForTLSGeneratorV1) validate() error { - // TODO: This is not strictly necessary. We can generate a self signed cert - // if no key/cert is given. The only requirement is that we either get both - // or none. See test/e2e/ingress_utils for self signed cert generation. - if len(s.Key) == 0 { - return fmt.Errorf("key must be specified") - } - if len(s.Cert) == 0 { - return fmt.Errorf("certificate must be specified") - } - return nil -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/secret_for_tls_test.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/secret_for_tls_test.go deleted file mode 100644 index aa8ff3bbe75..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/secret_for_tls_test.go +++ /dev/null @@ -1,233 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package versioned - -import ( - "fmt" - "os" - "path" - "reflect" - "testing" - - "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - utiltesting "k8s.io/client-go/util/testing" -) - -var rsaCertPEM = `-----BEGIN CERTIFICATE----- -MIIB0zCCAX2gAwIBAgIJAI/M7BYjwB+uMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQwHhcNMTIwOTEyMjE1MjAyWhcNMTUwOTEyMjE1MjAyWjBF -MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 -ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANLJ -hPHhITqQbPklG3ibCVxwGMRfp/v4XqhfdQHdcVfHap6NQ5Wok/4xIA+ui35/MmNa -rtNuC+BdZ1tMuVCPFZcCAwEAAaNQME4wHQYDVR0OBBYEFJvKs8RfJaXTH08W+SGv -zQyKn0H8MB8GA1UdIwQYMBaAFJvKs8RfJaXTH08W+SGvzQyKn0H8MAwGA1UdEwQF -MAMBAf8wDQYJKoZIhvcNAQEFBQADQQBJlffJHybjDGxRMqaRmDhX0+6v02TUKZsW -r5QuVbpQhH6u+0UgcW0jp9QwpxoPTLTWGXEWBBBurxFwiCBhkQ+V ------END CERTIFICATE----- -` - -var rsaKeyPEM = `-----BEGIN RSA PRIVATE KEY----- -MIIBOwIBAAJBANLJhPHhITqQbPklG3ibCVxwGMRfp/v4XqhfdQHdcVfHap6NQ5Wo -k/4xIA+ui35/MmNartNuC+BdZ1tMuVCPFZcCAwEAAQJAEJ2N+zsR0Xn8/Q6twa4G -6OB1M1WO+k+ztnX/1SvNeWu8D6GImtupLTYgjZcHufykj09jiHmjHx8u8ZZB/o1N -MQIhAPW+eyZo7ay3lMz1V01WVjNKK9QSn1MJlb06h/LuYv9FAiEA25WPedKgVyCW -SmUwbPw8fnTcpqDWE3yTO3vKcebqMSsCIBF3UmVue8YU3jybC3NxuXq3wNm34R8T -xVLHwDXh/6NJAiEAl2oHGGLz64BuAfjKrqwz7qMYr9HCLIe/YsoWq/olzScCIQDi -D2lWusoe2/nEqfDVVWGWlyJ7yOmqaVm/iNUN9B2N2g== ------END RSA PRIVATE KEY----- -` - -const mismatchRSAKeyPEM = `-----BEGIN PRIVATE KEY----- -MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC/665h55hWD4V2 -kiQ+B/G9NNfBw69eBibEhI9vWkPUyn36GO2r3HPtRE63wBfFpV486ns9DoZnnAYE -JaGjVNCCqS5tQyMBWp843o66KBrEgBpuddChigvyul33FhD1ImFnN+Vy0ajOJ+1/ -Zai28zBXWbxCWEbqz7s8e2UsPlBd0Caj4gcd32yD2BwiHqzB8odToWRUT7l+pS8R -qA1BruQvtjEIrcoWVlE170ZYe7+Apm96A+WvtVRkozPynxHF8SuEiw4hAh0lXR6b -4zZz4tZVV8ev2HpffveV/68GiCyeFDbglqd4sZ/Iga/rwu7bVY/BzFApHwu2hmmV -XLnaa3uVAgMBAAECggEAG+kvnCdtPR7Wvw6z3J2VJ3oW4qQNzfPBEZVhssUC1mB4 -f7W+Yt8VsOzdMdXq3yCUmvFS6OdC3rCPI21Bm5pLFKV8DgHUhm7idwfO4/3PHsKu -lV/m7odAA5Xc8oEwCCZu2e8EHHWnQgwGex+SsMCfSCTRvyhNb/qz9TDQ3uVVFL9e -9a4OKqZl/GlRspJSuXhy+RSVulw9NjeX1VRjIbhqpdXAmQNXgShA+gZSQh8T/tgv -XQYsMtg+FUDvcunJQf4OW5BY7IenYBV/GvsnJU8L7oD0wjNSAwe/iLKqV/NpYhre -QR4DsGnmoRYlUlHdHFTTJpReDjWm+vH3T756yDdFAQKBgQD2/sP5dM/aEW7Z1TgS -TG4ts1t8Rhe9escHxKZQR81dfOxBeCJMBDm6ySfR8rvyUM4VsogxBL/RhRQXsjJM -7wN08MhdiXG0J5yy/oNo8W6euD8m8Mk1UmqcZjSgV4vA7zQkvkr6DRJdybKsT9mE -jouEwev8sceS6iBpPw/+Ws8z1QKBgQDG6uYHMfMcS844xKQQWhargdN2XBzeG6TV -YXfNFstNpD84d9zIbpG/AKJF8fKrseUhXkJhkDjFGJTriD3QQsntOFaDOrHMnveV -zGzvC4OTFUUFHe0SVJ0HuLf8YCHoZ+DXEeCKCN6zBXnUue+bt3NvLOf2yN5o9kYx -SIa8O1vIwQKBgEdONXWG65qg/ceVbqKZvhUjen3eHmxtTZhIhVsX34nlzq73567a -aXArMnvB/9Bs05IgAIFmRZpPOQW+RBdByVWxTabzTwgbh3mFUJqzWKQpvNGZIf1q -1axhNUA1BfulEwCojyyxKWQ6HoLwanOCU3T4JxDEokEfpku8EPn1bWwhAoGAAN8A -eOGYHfSbB5ac3VF3rfKYmXkXy0U1uJV/r888vq9Mc5PazKnnS33WOBYyKNxTk4zV -H5ZBGWPdKxbipmnUdox7nIGCS9IaZXaKt5VGUzuRnM8fvafPNDxz2dAV9e2Wh3qV -kCUvzHrmqK7TxMvN3pvEvEju6GjDr+2QYXylD0ECgYAGK5r+y+EhtKkYFLeYReUt -znvSsWq+JCQH/cmtZLaVOldCaMRL625hSl3XPPcMIHE14xi3d4njoXWzvzPcg8L6 -vNXk3GiNldACS+vwk4CwEqe5YlZRm5doD07wIdsg2zRlnKsnXNM152OwgmcchDul -rLTt0TTazzwBCgCD0Jkoqg== ------END PRIVATE KEY-----` - -func tearDown(tmpDir string) { - err := os.RemoveAll(tmpDir) - if err != nil { - fmt.Printf("Error in cleaning up test: %v", err) - } -} - -func write(path, contents string, t *testing.T) { - f, err := os.Create(path) - if err != nil { - t.Fatalf("Failed to create %v.", path) - } - defer f.Close() - _, err = f.WriteString(contents) - if err != nil { - t.Fatalf("Failed to write to %v.", path) - } -} - -func writeKeyPair(tmpDirPath, key, cert string, t *testing.T) (keyPath, certPath string) { - keyPath = path.Join(tmpDirPath, "tls.key") - certPath = path.Join(tmpDirPath, "tls.cert") - write(keyPath, key, t) - write(certPath, cert, t) - return -} - -func TestSecretForTLSGenerate(t *testing.T) { - invalidCertTmpDir := utiltesting.MkTmpdirOrDie("tls-test") - defer tearDown(invalidCertTmpDir) - invalidKeyPath, invalidCertPath := writeKeyPair(invalidCertTmpDir, "test", "test", t) - - validCertTmpDir := utiltesting.MkTmpdirOrDie("tls-test") - defer tearDown(validCertTmpDir) - validKeyPath, validCertPath := writeKeyPair(validCertTmpDir, rsaKeyPEM, rsaCertPEM, t) - - mismatchCertTmpDir := utiltesting.MkTmpdirOrDie("tls-mismatch-test") - defer tearDown(mismatchCertTmpDir) - mismatchKeyPath, mismatchCertPath := writeKeyPair(mismatchCertTmpDir, mismatchRSAKeyPEM, rsaCertPEM, t) - - tests := []struct { - name string - params map[string]interface{} - expected *v1.Secret - expectErr bool - }{ - { - name: "test-valid-tls-secret", - params: map[string]interface{}{ - "name": "foo", - "key": validKeyPath, - "cert": validCertPath, - }, - expected: &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Data: map[string][]byte{ - v1.TLSCertKey: []byte(rsaCertPEM), - v1.TLSPrivateKeyKey: []byte(rsaKeyPEM), - }, - Type: v1.SecretTypeTLS, - }, - expectErr: false, - }, - { - name: "test-valid-tls-secret-append-hash", - params: map[string]interface{}{ - "name": "foo", - "key": validKeyPath, - "cert": validCertPath, - "append-hash": true, - }, - expected: &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo-272h6tt825", - }, - Data: map[string][]byte{ - v1.TLSCertKey: []byte(rsaCertPEM), - v1.TLSPrivateKeyKey: []byte(rsaKeyPEM), - }, - Type: v1.SecretTypeTLS, - }, - expectErr: false, - }, - { - name: "test-invalid-key-pair", - params: map[string]interface{}{ - "name": "foo", - "key": invalidKeyPath, - "cert": invalidCertPath, - }, - expected: &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Data: map[string][]byte{ - v1.TLSCertKey: []byte("test"), - v1.TLSPrivateKeyKey: []byte("test"), - }, - Type: v1.SecretTypeTLS, - }, - expectErr: true, - }, - { - name: "test-mismatched-key-pair", - params: map[string]interface{}{ - "name": "foo", - "key": mismatchKeyPath, - "cert": mismatchCertPath, - }, - expected: &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Data: map[string][]byte{ - v1.TLSCertKey: []byte(rsaCertPEM), - v1.TLSPrivateKeyKey: []byte(mismatchRSAKeyPEM), - }, - Type: v1.SecretTypeTLS, - }, - expectErr: true, - }, - { - name: "test-missing-required-param", - params: map[string]interface{}{ - "name": "foo", - "key": "/tmp/foo.key", - }, - expectErr: true, - }, - } - - generator := SecretForTLSGeneratorV1{} - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - obj, err := generator.Generate(tt.params) - if !tt.expectErr && err != nil { - t.Errorf("unexpected error: %v", err) - } - if tt.expectErr && err != nil { - return - } - if !reflect.DeepEqual(obj.(*v1.Secret), tt.expected) { - t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", tt.expected, obj.(*v1.Secret)) - } - }) - } -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/secret_test.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/secret_test.go deleted file mode 100644 index 9f80ee6f8fc..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/secret_test.go +++ /dev/null @@ -1,371 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package versioned - -import ( - "os" - "reflect" - "testing" - - "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func TestSecretGenerate(t *testing.T) { - tests := []struct { - name string - setup func(t *testing.T, params map[string]interface{}) func() - params map[string]interface{} - expected *v1.Secret - expectErr bool - }{ - { - name: "test1", - params: map[string]interface{}{ - "name": "foo", - }, - expected: &v1.Secret{ - // this is ok because we know exactly how we want to be serialized - TypeMeta: metav1.TypeMeta{APIVersion: v1.SchemeGroupVersion.String(), Kind: "Secret"}, - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Data: map[string][]byte{}, - }, - expectErr: false, - }, - { - name: "test2", - params: map[string]interface{}{ - "name": "foo", - "append-hash": true, - }, - expected: &v1.Secret{ - // this is ok because we know exactly how we want to be serialized - TypeMeta: metav1.TypeMeta{APIVersion: v1.SchemeGroupVersion.String(), Kind: "Secret"}, - ObjectMeta: metav1.ObjectMeta{ - Name: "foo-949tdgdkgg", - }, - Data: map[string][]byte{}, - }, - expectErr: false, - }, - { - name: "test3", - params: map[string]interface{}{ - "name": "foo", - "type": "my-type", - }, - expected: &v1.Secret{ - // this is ok because we know exactly how we want to be serialized - TypeMeta: metav1.TypeMeta{APIVersion: v1.SchemeGroupVersion.String(), Kind: "Secret"}, - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Data: map[string][]byte{}, - Type: "my-type", - }, - expectErr: false, - }, - { - name: "test4", - params: map[string]interface{}{ - "name": "foo", - "type": "my-type", - "append-hash": true, - }, - expected: &v1.Secret{ - // this is ok because we know exactly how we want to be serialized - TypeMeta: metav1.TypeMeta{APIVersion: v1.SchemeGroupVersion.String(), Kind: "Secret"}, - ObjectMeta: metav1.ObjectMeta{ - Name: "foo-dg474f9t76", - }, - Data: map[string][]byte{}, - Type: "my-type", - }, - expectErr: false, - }, - { - name: "test5", - params: map[string]interface{}{ - "name": "foo", - "from-literal": []string{"key1=value1", "key2=value2"}, - }, - expected: &v1.Secret{ - // this is ok because we know exactly how we want to be serialized - TypeMeta: metav1.TypeMeta{APIVersion: v1.SchemeGroupVersion.String(), Kind: "Secret"}, - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Data: map[string][]byte{ - "key1": []byte("value1"), - "key2": []byte("value2"), - }, - }, - expectErr: false, - }, - { - name: "test6", - params: map[string]interface{}{ - "name": "foo", - "from-literal": []string{"key1=value1", "key2=value2"}, - "append-hash": true, - }, - expected: &v1.Secret{ - // this is ok because we know exactly how we want to be serialized - TypeMeta: metav1.TypeMeta{APIVersion: v1.SchemeGroupVersion.String(), Kind: "Secret"}, - ObjectMeta: metav1.ObjectMeta{ - Name: "foo-tf72c228m4", - }, - Data: map[string][]byte{ - "key1": []byte("value1"), - "key2": []byte("value2"), - }, - }, - expectErr: false, - }, - { - name: "test7", - params: map[string]interface{}{ - "name": "foo", - "from-literal": []string{"key1value1"}, - }, - expectErr: true, - }, - { - name: "test8", - params: map[string]interface{}{ - "name": "foo", - "from-file": []string{"key1=/file=2"}, - }, - expectErr: true, - }, - { - name: "test9", - params: map[string]interface{}{ - "name": "foo", - "from-file": []string{"key1==value"}, - }, - expectErr: true, - }, - { - name: "test10", - params: map[string]interface{}{ - "name": "foo", - "from-literal": []string{"key1==value1"}, - }, - expected: &v1.Secret{ - // this is ok because we know exactly how we want to be serialized - TypeMeta: metav1.TypeMeta{APIVersion: v1.SchemeGroupVersion.String(), Kind: "Secret"}, - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Data: map[string][]byte{ - "key1": []byte("=value1"), - }, - }, - expectErr: false, - }, - { - name: "test11", - params: map[string]interface{}{ - "name": "foo", - "from-literal": []string{"key1==value1"}, - "append-hash": true, - }, - expected: &v1.Secret{ - // this is ok because we know exactly how we want to be serialized - TypeMeta: metav1.TypeMeta{APIVersion: v1.SchemeGroupVersion.String(), Kind: "Secret"}, - ObjectMeta: metav1.ObjectMeta{ - Name: "foo-fdcc8tkhh5", - }, - Data: map[string][]byte{ - "key1": []byte("=value1"), - }, - }, - expectErr: false, - }, - { - name: "test12", - setup: setupEnvFile("key1=value1", "#", "", "key2=value2"), - params: map[string]interface{}{ - "name": "valid_env", - "from-env-file": "file.env", - }, - expected: &v1.Secret{ - // this is ok because we know exactly how we want to be serialized - TypeMeta: metav1.TypeMeta{APIVersion: v1.SchemeGroupVersion.String(), Kind: "Secret"}, - ObjectMeta: metav1.ObjectMeta{ - Name: "valid_env", - }, - Data: map[string][]byte{ - "key1": []byte("value1"), - "key2": []byte("value2"), - }, - }, - expectErr: false, - }, - { - name: "test13", - setup: setupEnvFile("key1=value1", "#", "", "key2=value2"), - params: map[string]interface{}{ - "name": "valid_env", - "from-env-file": "file.env", - "append-hash": true, - }, - expected: &v1.Secret{ - // this is ok because we know exactly how we want to be serialized - TypeMeta: metav1.TypeMeta{APIVersion: v1.SchemeGroupVersion.String(), Kind: "Secret"}, - ObjectMeta: metav1.ObjectMeta{ - Name: "valid_env-bkb2m2965h", - }, - Data: map[string][]byte{ - "key1": []byte("value1"), - "key2": []byte("value2"), - }, - }, - expectErr: false, - }, - { - name: "test14", - setup: func() func(t *testing.T, params map[string]interface{}) func() { - os.Setenv("g_key1", "1") - os.Setenv("g_key2", "2") - return setupEnvFile("g_key1", "g_key2=") - }(), - params: map[string]interface{}{ - "name": "getenv", - "from-env-file": "file.env", - }, - expected: &v1.Secret{ - // this is ok because we know exactly how we want to be serialized - TypeMeta: metav1.TypeMeta{APIVersion: v1.SchemeGroupVersion.String(), Kind: "Secret"}, - ObjectMeta: metav1.ObjectMeta{ - Name: "getenv", - }, - Data: map[string][]byte{ - "g_key1": []byte("1"), - "g_key2": []byte(""), - }, - }, - expectErr: false, - }, - { - name: "test15", - setup: func() func(t *testing.T, params map[string]interface{}) func() { - os.Setenv("g_key1", "1") - os.Setenv("g_key2", "2") - return setupEnvFile("g_key1", "g_key2=") - }(), - params: map[string]interface{}{ - "name": "getenv", - "from-env-file": "file.env", - "append-hash": true, - }, - expected: &v1.Secret{ - // this is ok because we know exactly how we want to be serialized - TypeMeta: metav1.TypeMeta{APIVersion: v1.SchemeGroupVersion.String(), Kind: "Secret"}, - ObjectMeta: metav1.ObjectMeta{ - Name: "getenv-m7kg2khdb4", - }, - Data: map[string][]byte{ - "g_key1": []byte("1"), - "g_key2": []byte(""), - }, - }, - expectErr: false, - }, - { - name: "test16", - params: map[string]interface{}{ - "name": "too_many_args", - "from-literal": []string{"key1=value1"}, - "from-env-file": "file.env", - }, - expectErr: true, - }, - { - name: "test17", - setup: setupEnvFile("key#1=value1"), - params: map[string]interface{}{ - "name": "invalid_key", - "from-env-file": "file.env", - }, - expectErr: true, - }, - { - name: "test18", - setup: setupEnvFile(" key1= value1"), - params: map[string]interface{}{ - "name": "with_spaces", - "from-env-file": "file.env", - }, - expected: &v1.Secret{ - // this is ok because we know exactly how we want to be serialized - TypeMeta: metav1.TypeMeta{APIVersion: v1.SchemeGroupVersion.String(), Kind: "Secret"}, - ObjectMeta: metav1.ObjectMeta{ - Name: "with_spaces", - }, - Data: map[string][]byte{ - "key1": []byte(" value1"), - }, - }, - expectErr: false, - }, - { - name: "test19", - setup: setupEnvFile(" key1= value1"), - params: map[string]interface{}{ - "name": "with_spaces", - "from-env-file": "file.env", - "append-hash": true, - }, - expected: &v1.Secret{ - // this is ok because we know exactly how we want to be serialized - TypeMeta: metav1.TypeMeta{APIVersion: v1.SchemeGroupVersion.String(), Kind: "Secret"}, - ObjectMeta: metav1.ObjectMeta{ - Name: "with_spaces-4488d5b57d", - }, - Data: map[string][]byte{ - "key1": []byte(" value1"), - }, - }, - expectErr: false, - }, - } - generator := SecretGeneratorV1{} - for i, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if tt.setup != nil { - if teardown := tt.setup(t, tt.params); teardown != nil { - defer teardown() - } - } - obj, err := generator.Generate(tt.params) - if !tt.expectErr && err != nil { - t.Errorf("case %d, unexpected error: %v", i, err) - return - } - if tt.expectErr && err != nil { - return - } - if !reflect.DeepEqual(obj.(*v1.Secret), tt.expected) { - t.Errorf("\ncase %d, expected:\n%#v\nsaw:\n%#v", i, tt.expected, obj.(*v1.Secret)) - } - }) - } -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/service_basic.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/service_basic.go deleted file mode 100644 index b0b584ab7c7..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/service_basic.go +++ /dev/null @@ -1,257 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package versioned - -import ( - "fmt" - "strconv" - "strings" - - "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/intstr" - "k8s.io/apimachinery/pkg/util/validation" - "k8s.io/kubectl/pkg/generate" - utilsnet "k8s.io/utils/net" -) - -type ServiceCommonGeneratorV1 struct { - Name string - TCP []string - Type v1.ServiceType - ClusterIP string - NodePort int - ExternalName string -} - -type ServiceClusterIPGeneratorV1 struct { - ServiceCommonGeneratorV1 -} - -type ServiceNodePortGeneratorV1 struct { - ServiceCommonGeneratorV1 -} - -type ServiceLoadBalancerGeneratorV1 struct { - ServiceCommonGeneratorV1 -} - -// TODO: is this really necessary? -type ServiceExternalNameGeneratorV1 struct { - ServiceCommonGeneratorV1 -} - -func (ServiceClusterIPGeneratorV1) ParamNames() []generate.GeneratorParam { - return []generate.GeneratorParam{ - {Name: "name", Required: true}, - {Name: "tcp", Required: true}, - {Name: "clusterip", Required: false}, - } -} -func (ServiceNodePortGeneratorV1) ParamNames() []generate.GeneratorParam { - return []generate.GeneratorParam{ - {Name: "name", Required: true}, - {Name: "tcp", Required: true}, - {Name: "nodeport", Required: true}, - } -} -func (ServiceLoadBalancerGeneratorV1) ParamNames() []generate.GeneratorParam { - return []generate.GeneratorParam{ - {Name: "name", Required: true}, - {Name: "tcp", Required: true}, - } -} - -func (ServiceExternalNameGeneratorV1) ParamNames() []generate.GeneratorParam { - return []generate.GeneratorParam{ - {Name: "name", Required: true}, - {Name: "externalname", Required: true}, - } -} - -func parsePorts(portString string) (int32, intstr.IntOrString, error) { - portStringSlice := strings.Split(portString, ":") - - port, err := utilsnet.ParsePort(portStringSlice[0], true) - if err != nil { - return 0, intstr.FromInt(0), err - } - - if len(portStringSlice) == 1 { - return int32(port), intstr.FromInt(int(port)), nil - } - - var targetPort intstr.IntOrString - if portNum, err := strconv.Atoi(portStringSlice[1]); err != nil { - if errs := validation.IsValidPortName(portStringSlice[1]); len(errs) != 0 { - return 0, intstr.FromInt(0), fmt.Errorf(strings.Join(errs, ",")) - } - targetPort = intstr.FromString(portStringSlice[1]) - } else { - if errs := validation.IsValidPortNum(portNum); len(errs) != 0 { - return 0, intstr.FromInt(0), fmt.Errorf(strings.Join(errs, ",")) - } - targetPort = intstr.FromInt(portNum) - } - return int32(port), targetPort, nil -} - -func (s ServiceCommonGeneratorV1) GenerateCommon(params map[string]interface{}) error { - name, isString := params["name"].(string) - if !isString { - return fmt.Errorf("expected string, saw %v for 'name'", name) - } - tcpStrings, isArray := params["tcp"].([]string) - if !isArray { - return fmt.Errorf("expected []string, found :%v", tcpStrings) - } - clusterip, isString := params["clusterip"].(string) - if !isString { - return fmt.Errorf("expected string, saw %v for 'clusterip'", clusterip) - } - externalname, isString := params["externalname"].(string) - if !isString { - return fmt.Errorf("expected string, saw %v for 'externalname'", externalname) - } - s.Name = name - s.TCP = tcpStrings - s.ClusterIP = clusterip - s.ExternalName = externalname - return nil -} - -func (s ServiceLoadBalancerGeneratorV1) Generate(params map[string]interface{}) (runtime.Object, error) { - err := generate.ValidateParams(s.ParamNames(), params) - if err != nil { - return nil, err - } - delegate := &ServiceCommonGeneratorV1{Type: v1.ServiceTypeLoadBalancer, ClusterIP: ""} - err = delegate.GenerateCommon(params) - if err != nil { - return nil, err - } - return delegate.StructuredGenerate() -} - -func (s ServiceNodePortGeneratorV1) Generate(params map[string]interface{}) (runtime.Object, error) { - err := generate.ValidateParams(s.ParamNames(), params) - if err != nil { - return nil, err - } - delegate := &ServiceCommonGeneratorV1{Type: v1.ServiceTypeNodePort, ClusterIP: ""} - err = delegate.GenerateCommon(params) - if err != nil { - return nil, err - } - return delegate.StructuredGenerate() -} - -func (s ServiceClusterIPGeneratorV1) Generate(params map[string]interface{}) (runtime.Object, error) { - err := generate.ValidateParams(s.ParamNames(), params) - if err != nil { - return nil, err - } - delegate := &ServiceCommonGeneratorV1{Type: v1.ServiceTypeClusterIP, ClusterIP: ""} - err = delegate.GenerateCommon(params) - if err != nil { - return nil, err - } - return delegate.StructuredGenerate() -} - -func (s ServiceExternalNameGeneratorV1) Generate(params map[string]interface{}) (runtime.Object, error) { - err := generate.ValidateParams(s.ParamNames(), params) - if err != nil { - return nil, err - } - delegate := &ServiceCommonGeneratorV1{Type: v1.ServiceTypeExternalName, ClusterIP: ""} - err = delegate.GenerateCommon(params) - if err != nil { - return nil, err - } - return delegate.StructuredGenerate() -} - -// validate validates required fields are set to support structured generation -// TODO(xiangpengzhao): validate ports are identity mapped for headless service when we enforce that in validation.validateServicePort. -func (s ServiceCommonGeneratorV1) validate() error { - if len(s.Name) == 0 { - return fmt.Errorf("name must be specified") - } - if len(s.Type) == 0 { - return fmt.Errorf("type must be specified") - } - if s.ClusterIP == v1.ClusterIPNone && s.Type != v1.ServiceTypeClusterIP { - return fmt.Errorf("ClusterIP=None can only be used with ClusterIP service type") - } - if s.ClusterIP != v1.ClusterIPNone && len(s.TCP) == 0 && s.Type != v1.ServiceTypeExternalName { - return fmt.Errorf("at least one tcp port specifier must be provided") - } - if s.Type == v1.ServiceTypeExternalName { - if errs := validation.IsDNS1123Subdomain(s.ExternalName); len(errs) != 0 { - return fmt.Errorf("invalid service external name %s", s.ExternalName) - } - } - return nil -} - -func (s ServiceCommonGeneratorV1) StructuredGenerate() (runtime.Object, error) { - err := s.validate() - if err != nil { - return nil, err - } - ports := []v1.ServicePort{} - for _, tcpString := range s.TCP { - port, targetPort, err := parsePorts(tcpString) - if err != nil { - return nil, err - } - - portName := strings.Replace(tcpString, ":", "-", -1) - ports = append(ports, v1.ServicePort{ - Name: portName, - Port: port, - TargetPort: targetPort, - Protocol: v1.Protocol("TCP"), - NodePort: int32(s.NodePort), - }) - } - - // setup default label and selector - labels := map[string]string{} - labels["app"] = s.Name - selector := map[string]string{} - selector["app"] = s.Name - - service := v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: s.Name, - Labels: labels, - }, - Spec: v1.ServiceSpec{ - Type: v1.ServiceType(s.Type), - Selector: selector, - Ports: ports, - ExternalName: s.ExternalName, - }, - } - if len(s.ClusterIP) > 0 { - service.Spec.ClusterIP = s.ClusterIP - } - return &service, nil -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/service_basic_test.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/service_basic_test.go deleted file mode 100644 index a7044afd8d1..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/service_basic_test.go +++ /dev/null @@ -1,326 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package versioned - -import ( - "reflect" - "strings" - "testing" - - "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/intstr" -) - -func TestServiceBasicGenerate(t *testing.T) { - tests := []struct { - name string - serviceType v1.ServiceType - tcp []string - clusterip string - expected *v1.Service - expectErr bool - }{ - { - name: "clusterip-ok", - tcp: []string{"456", "321:908"}, - clusterip: "", - serviceType: v1.ServiceTypeClusterIP, - expected: &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "clusterip-ok", - Labels: map[string]string{"app": "clusterip-ok"}, - }, - Spec: v1.ServiceSpec{Type: "ClusterIP", - Ports: []v1.ServicePort{{Name: "456", Protocol: "TCP", Port: 456, TargetPort: intstr.IntOrString{Type: 0, IntVal: 456, StrVal: ""}, NodePort: 0}, - {Name: "321-908", Protocol: "TCP", Port: 321, TargetPort: intstr.IntOrString{Type: 0, IntVal: 908, StrVal: ""}, NodePort: 0}}, - Selector: map[string]string{"app": "clusterip-ok"}, - ClusterIP: "", ExternalIPs: []string(nil), LoadBalancerIP: ""}, - }, - expectErr: false, - }, - { - name: "clusterip-missing", - serviceType: v1.ServiceTypeClusterIP, - expectErr: true, - }, - { - name: "clusterip-none-wrong-type", - tcp: []string{}, - clusterip: "None", - serviceType: v1.ServiceTypeNodePort, - expectErr: true, - }, - { - name: "clusterip-none-ok", - tcp: []string{}, - clusterip: "None", - serviceType: v1.ServiceTypeClusterIP, - expected: &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "clusterip-none-ok", - Labels: map[string]string{"app": "clusterip-none-ok"}, - }, - Spec: v1.ServiceSpec{Type: "ClusterIP", - Ports: []v1.ServicePort{}, - Selector: map[string]string{"app": "clusterip-none-ok"}, - ClusterIP: "None", ExternalIPs: []string(nil), LoadBalancerIP: ""}, - }, - expectErr: false, - }, - { - name: "clusterip-none-and-port-mapping", - tcp: []string{"456:9898"}, - clusterip: "None", - serviceType: v1.ServiceTypeClusterIP, - expected: &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "clusterip-none-and-port-mapping", - Labels: map[string]string{"app": "clusterip-none-and-port-mapping"}, - }, - Spec: v1.ServiceSpec{Type: "ClusterIP", - Ports: []v1.ServicePort{{Name: "456-9898", Protocol: "TCP", Port: 456, TargetPort: intstr.IntOrString{Type: 0, IntVal: 9898, StrVal: ""}, NodePort: 0}}, - Selector: map[string]string{"app": "clusterip-none-and-port-mapping"}, - ClusterIP: "None", ExternalIPs: []string(nil), LoadBalancerIP: ""}, - }, - expectErr: false, - }, - { - name: "loadbalancer-ok", - tcp: []string{"456:9898"}, - clusterip: "", - serviceType: v1.ServiceTypeLoadBalancer, - expected: &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "loadbalancer-ok", - Labels: map[string]string{"app": "loadbalancer-ok"}, - }, - Spec: v1.ServiceSpec{Type: "LoadBalancer", - Ports: []v1.ServicePort{{Name: "456-9898", Protocol: "TCP", Port: 456, TargetPort: intstr.IntOrString{Type: 0, IntVal: 9898, StrVal: ""}, NodePort: 0}}, - Selector: map[string]string{"app": "loadbalancer-ok"}, - ClusterIP: "", ExternalIPs: []string(nil), LoadBalancerIP: ""}, - }, - expectErr: false, - }, - { - name: "invalid-port", - tcp: []string{"65536"}, - clusterip: "None", - serviceType: v1.ServiceTypeClusterIP, - expectErr: true, - }, - { - name: "invalid-port-mapping", - tcp: []string{"8080:-abc"}, - clusterip: "None", - serviceType: v1.ServiceTypeClusterIP, - expectErr: true, - }, - { - expectErr: true, - }, - } - for _, test := range tests { - generator := ServiceCommonGeneratorV1{ - Name: test.name, - TCP: test.tcp, - Type: test.serviceType, - ClusterIP: test.clusterip, - } - obj, err := generator.StructuredGenerate() - if !test.expectErr && err != nil { - t.Errorf("unexpected error: %v", err) - } - if test.expectErr && err != nil { - continue - } - if !reflect.DeepEqual(obj.(*v1.Service), test.expected) { - t.Errorf("test: %v\nexpected:\n%#v\nsaw:\n%#v", test.name, test.expected, obj.(*v1.Service)) - } - } -} - -func TestParsePorts(t *testing.T) { - tests := []struct { - portString string - expectPort int32 - expectTargetPort intstr.IntOrString - expectErr string - }{ - { - portString: "3232", - expectPort: 3232, - expectTargetPort: intstr.IntOrString{Type: intstr.Int, IntVal: 3232}, - }, - { - portString: "1:65535", - expectPort: 1, - expectTargetPort: intstr.IntOrString{Type: intstr.Int, IntVal: 65535}, - }, - { - portString: "-5:1234", - expectPort: 0, - expectTargetPort: intstr.IntOrString{Type: intstr.Int, IntVal: 0}, - expectErr: "parsing \"-5\": invalid syntax", - }, - { - portString: "0:1234", - expectPort: 0, - expectTargetPort: intstr.IntOrString{Type: intstr.Int, IntVal: 1234}, - }, - { - portString: "5:65536", - expectPort: 0, - expectTargetPort: intstr.IntOrString{Type: intstr.Int, IntVal: 0}, - expectErr: "must be between 1 and 65535, inclusive", - }, - { - portString: "test-5:443", - expectPort: 0, - expectTargetPort: intstr.IntOrString{Type: intstr.Int, IntVal: 0}, - expectErr: "invalid syntax", - }, - { - portString: "5:test-443", - expectPort: 5, - expectTargetPort: intstr.IntOrString{Type: intstr.String, StrVal: "test-443"}, - }, - { - portString: "5:test*443", - expectPort: 0, - expectTargetPort: intstr.IntOrString{Type: intstr.Int, IntVal: 0}, - expectErr: "must contain only alpha-numeric characters (a-z, 0-9), and hyphens (-)", - }, - { - portString: "5:", - expectPort: 0, - expectTargetPort: intstr.IntOrString{Type: intstr.Int, IntVal: 0}, - expectErr: "must contain at least one letter or number (a-z, 0-9)", - }, - { - portString: "5:test--443", - expectPort: 0, - expectTargetPort: intstr.IntOrString{Type: intstr.Int, IntVal: 0}, - expectErr: "must not contain consecutive hyphens", - }, - { - portString: "5:test443-", - expectPort: 0, - expectTargetPort: intstr.IntOrString{Type: intstr.Int, IntVal: 0}, - expectErr: "must not begin or end with a hyphen", - }, - { - portString: "3232:1234:4567", - expectPort: 3232, - expectTargetPort: intstr.IntOrString{Type: intstr.Int, IntVal: 1234}, - }, - } - - for _, test := range tests { - t.Run(test.portString, func(t *testing.T) { - port, targetPort, err := parsePorts(test.portString) - if len(test.expectErr) != 0 { - if !strings.Contains(err.Error(), test.expectErr) { - t.Errorf("parse ports string: %s. Expected err: %s, Got err: %v.", test.portString, test.expectErr, err) - } - } - if !reflect.DeepEqual(targetPort, test.expectTargetPort) || port != test.expectPort { - t.Errorf("parse ports string: %s. Expected port:%d, targetPort:%v, Got port:%d, targetPort:%v.", test.portString, test.expectPort, test.expectTargetPort, port, targetPort) - } - }) - } -} - -func TestValidateServiceCommonGeneratorV1(t *testing.T) { - tests := []struct { - name string - s ServiceCommonGeneratorV1 - expectErr string - }{ - { - name: "validate-ok", - s: ServiceCommonGeneratorV1{ - Name: "validate-ok", - Type: v1.ServiceTypeClusterIP, - TCP: []string{"123", "234:1234"}, - ClusterIP: "", - }, - }, - { - name: "Name-none", - s: ServiceCommonGeneratorV1{ - Type: v1.ServiceTypeClusterIP, - TCP: []string{"123", "234:1234"}, - ClusterIP: "", - }, - expectErr: "name must be specified", - }, - { - name: "Type-none", - s: ServiceCommonGeneratorV1{ - Name: "validate-ok", - TCP: []string{"123", "234:1234"}, - ClusterIP: "", - }, - expectErr: "type must be specified", - }, - { - name: "invalid-ClusterIPNone", - s: ServiceCommonGeneratorV1{ - Name: "validate-ok", - Type: v1.ServiceTypeNodePort, - TCP: []string{"123", "234:1234"}, - ClusterIP: v1.ClusterIPNone, - }, - expectErr: "ClusterIP=None can only be used with ClusterIP service type", - }, - { - name: "TCP-none", - s: ServiceCommonGeneratorV1{ - Name: "validate-ok", - Type: v1.ServiceTypeClusterIP, - ClusterIP: "", - }, - expectErr: "at least one tcp port specifier must be provided", - }, - { - name: "invalid-ExternalName", - s: ServiceCommonGeneratorV1{ - Name: "validate-ok", - Type: v1.ServiceTypeExternalName, - TCP: []string{"123", "234:1234"}, - ClusterIP: "", - ExternalName: "@oi:test", - }, - expectErr: "invalid service external name", - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - err := test.s.validate() - if err != nil { - if !strings.Contains(err.Error(), test.expectErr) { - t.Errorf("validate:%s Expected err: %s, Got err: %v", test.name, test.expectErr, err) - } - } - if err == nil && len(test.expectErr) != 0 { - t.Errorf("validate:%s Expected success, Got err: %v", test.name, err) - } - }) - } -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/serviceaccount.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/serviceaccount.go deleted file mode 100644 index 659d151580d..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/serviceaccount.go +++ /dev/null @@ -1,52 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package versioned - -import ( - "fmt" - - "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/kubectl/pkg/generate" -) - -// ServiceAccountGeneratorV1 supports stable generation of a service account -type ServiceAccountGeneratorV1 struct { - // Name of service account - Name string -} - -// Ensure it supports the generator pattern that uses parameters specified during construction -var _ generate.StructuredGenerator = &ServiceAccountGeneratorV1{} - -// StructuredGenerate outputs a service account object using the configured fields -func (g *ServiceAccountGeneratorV1) StructuredGenerate() (runtime.Object, error) { - if err := g.validate(); err != nil { - return nil, err - } - serviceAccount := &v1.ServiceAccount{} - serviceAccount.Name = g.Name - return serviceAccount, nil -} - -// validate validates required fields are set to support structured generation -func (g *ServiceAccountGeneratorV1) validate() error { - if len(g.Name) == 0 { - return fmt.Errorf("name must be specified") - } - return nil -} diff --git a/staging/src/k8s.io/kubectl/pkg/generate/versioned/serviceaccount_test.go b/staging/src/k8s.io/kubectl/pkg/generate/versioned/serviceaccount_test.go deleted file mode 100644 index 136f11de9ed..00000000000 --- a/staging/src/k8s.io/kubectl/pkg/generate/versioned/serviceaccount_test.go +++ /dev/null @@ -1,63 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package versioned - -import ( - "reflect" - "testing" - - "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func TestServiceAccountGenerate(t *testing.T) { - tests := []struct { - name string - expected *v1.ServiceAccount - expectErr bool - }{ - { - name: "foo", - expected: &v1.ServiceAccount{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - }, - expectErr: false, - }, - { - expectErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - generator := ServiceAccountGeneratorV1{ - Name: tt.name, - } - obj, err := generator.StructuredGenerate() - if !tt.expectErr && err != nil { - t.Errorf("unexpected error: %v", err) - } - if tt.expectErr && err != nil { - return - } - if !reflect.DeepEqual(obj.(*v1.ServiceAccount), tt.expected) { - t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", tt.expected, obj.(*v1.ServiceAccount)) - } - }) - } -} diff --git a/test/cmd/apps.sh b/test/cmd/apps.sh index 31b3d81e377..69e0dd9ab56 100755 --- a/test/cmd/apps.sh +++ b/test/cmd/apps.sh @@ -636,12 +636,8 @@ run_rs_tests() { kubectl expose rs frontend --port=80 "${kube_flags[@]:?}" # Post-condition: service exists and the port is unnamed kube::test::get_object_assert 'service frontend' "{{${port_name:?}}} {{${port_field:?}}}" ' 80' - # Create a service using service/v1 generator - kubectl expose rs frontend --port=80 --name=frontend-2 --generator=service/v1 "${kube_flags[@]:?}" - # Post-condition: service exists and the port is named default. - kube::test::get_object_assert 'service frontend-2' "{{${port_name:?}}} {{${port_field:?}}}" 'default 80' # Cleanup services - kubectl delete service frontend{,-2} "${kube_flags[@]:?}" + kubectl delete service frontend "${kube_flags[@]:?}" # Test set commands # Pre-condition: frontend replica set exists at generation 1 diff --git a/test/cmd/core.sh b/test/cmd/core.sh index a2ffc056dbf..d3b61c0acb5 100755 --- a/test/cmd/core.sh +++ b/test/cmd/core.sh @@ -1313,17 +1313,13 @@ run_rc_tests() { kubectl expose pod valid-pod --port=444 --name=frontend-3 "${kube_flags[@]}" # Post-condition: service exists and the port is unnamed kube::test::get_object_assert 'service frontend-3' "{{$port_name}} {{$port_field}}" ' 444' - # Create a service using service/v1 generator - kubectl expose rc frontend --port=80 --name=frontend-4 --generator=service/v1 "${kube_flags[@]}" - # Post-condition: service exists and the port is named default. - kube::test::get_object_assert 'service frontend-4' "{{$port_name}} {{$port_field}}" 'default 80' # Verify that expose service works without specifying a port. - kubectl expose service frontend --name=frontend-5 "${kube_flags[@]}" + kubectl expose service frontend --name=frontend-4 "${kube_flags[@]}" # Post-condition: service exists with the same port as the original service. - kube::test::get_object_assert 'service frontend-5' "{{$port_field}}" '80' + kube::test::get_object_assert 'service frontend-4' "{{$port_field}}" '80' # Cleanup services kubectl delete pod valid-pod "${kube_flags[@]}" - kubectl delete service frontend{,-2,-3,-4,-5} "${kube_flags[@]}" + kubectl delete service frontend{,-2,-3,-4} "${kube_flags[@]}" ### Expose negative invalid resource test # Pre-condition: don't need