From 741c58be7f0b78983233b539500433b465a870b4 Mon Sep 17 00:00:00 2001 From: wackxu Date: Tue, 31 Oct 2017 17:16:25 +0800 Subject: [PATCH] add create subcommand for priorityclass --- docs/.generated_docs | 2 + docs/man/man1/kubectl-create-priorityclass.1 | 3 + .../kubectl/kubectl_create_priorityclass.md | 3 + pkg/kubectl/BUILD | 4 + pkg/kubectl/cmd/BUILD | 2 + pkg/kubectl/cmd/create.go | 1 + pkg/kubectl/cmd/create_priorityclass.go | 90 +++++++++++++++++++ pkg/kubectl/cmd/create_priorityclass_test.go | 59 ++++++++++++ pkg/kubectl/cmd/util/factory_client_access.go | 1 + pkg/kubectl/cmd/util/helpers.go | 11 ++- pkg/kubectl/priorityclass.go | 85 ++++++++++++++++++ pkg/kubectl/priorityclass_test.go | 90 +++++++++++++++++++ 12 files changed, 350 insertions(+), 1 deletion(-) create mode 100644 docs/man/man1/kubectl-create-priorityclass.1 create mode 100644 docs/user-guide/kubectl/kubectl_create_priorityclass.md create mode 100644 pkg/kubectl/cmd/create_priorityclass.go create mode 100644 pkg/kubectl/cmd/create_priorityclass_test.go create mode 100644 pkg/kubectl/priorityclass.go create mode 100644 pkg/kubectl/priorityclass_test.go diff --git a/docs/.generated_docs b/docs/.generated_docs index 8437cf81ae5..96bdea8ee7d 100644 --- a/docs/.generated_docs +++ b/docs/.generated_docs @@ -170,6 +170,7 @@ docs/man/man1/kubectl-create-configmap.1 docs/man/man1/kubectl-create-deployment.1 docs/man/man1/kubectl-create-namespace.1 docs/man/man1/kubectl-create-poddisruptionbudget.1 +docs/man/man1/kubectl-create-priorityclass.1 docs/man/man1/kubectl-create-quota.1 docs/man/man1/kubectl-create-role.1 docs/man/man1/kubectl-create-rolebinding.1 @@ -269,6 +270,7 @@ docs/user-guide/kubectl/kubectl_create_configmap.md docs/user-guide/kubectl/kubectl_create_deployment.md docs/user-guide/kubectl/kubectl_create_namespace.md docs/user-guide/kubectl/kubectl_create_poddisruptionbudget.md +docs/user-guide/kubectl/kubectl_create_priorityclass.md docs/user-guide/kubectl/kubectl_create_quota.md docs/user-guide/kubectl/kubectl_create_role.md docs/user-guide/kubectl/kubectl_create_rolebinding.md diff --git a/docs/man/man1/kubectl-create-priorityclass.1 b/docs/man/man1/kubectl-create-priorityclass.1 new file mode 100644 index 00000000000..b6fd7a0f989 --- /dev/null +++ b/docs/man/man1/kubectl-create-priorityclass.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/user-guide/kubectl/kubectl_create_priorityclass.md b/docs/user-guide/kubectl/kubectl_create_priorityclass.md new file mode 100644 index 00000000000..b6fd7a0f989 --- /dev/null +++ b/docs/user-guide/kubectl/kubectl_create_priorityclass.md @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/pkg/kubectl/BUILD b/pkg/kubectl/BUILD index ff86f12f78e..6237573380d 100644 --- a/pkg/kubectl/BUILD +++ b/pkg/kubectl/BUILD @@ -18,6 +18,7 @@ go_test( "generate_test.go", "namespace_test.go", "pdb_test.go", + "priorityclass_test.go", "quota_test.go", "resource_filter_test.go", "rolebinding_test.go", @@ -61,6 +62,7 @@ go_test( "//vendor/k8s.io/api/policy/v1beta1:go_default_library", "//vendor/k8s.io/api/rbac/v1:go_default_library", "//vendor/k8s.io/api/rbac/v1beta1:go_default_library", + "//vendor/k8s.io/api/scheduling/v1alpha1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library", @@ -97,6 +99,7 @@ go_library( "kubectl.go", "namespace.go", "pdb.go", + "priorityclass.go", "quota.go", "resource_filter.go", "rolebinding.go", @@ -152,6 +155,7 @@ go_library( "//vendor/k8s.io/api/policy/v1beta1:go_default_library", "//vendor/k8s.io/api/rbac/v1:go_default_library", "//vendor/k8s.io/api/rbac/v1beta1:go_default_library", + "//vendor/k8s.io/api/scheduling/v1alpha1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library", diff --git a/pkg/kubectl/cmd/BUILD b/pkg/kubectl/cmd/BUILD index 58a7af370a3..16787df80f7 100644 --- a/pkg/kubectl/cmd/BUILD +++ b/pkg/kubectl/cmd/BUILD @@ -30,6 +30,7 @@ go_library( "create_deployment.go", "create_namespace.go", "create_pdb.go", + "create_priorityclass.go", "create_quota.go", "create_role.go", "create_rolebinding.go", @@ -164,6 +165,7 @@ go_test( "create_deployment_test.go", "create_namespace_test.go", "create_pdb_test.go", + "create_priorityclass_test.go", "create_quota_test.go", "create_role_test.go", "create_rolebinding_test.go", diff --git a/pkg/kubectl/cmd/create.go b/pkg/kubectl/cmd/create.go index 8caa921870d..4e2af145a80 100644 --- a/pkg/kubectl/cmd/create.go +++ b/pkg/kubectl/cmd/create.go @@ -108,6 +108,7 @@ func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command { cmd.AddCommand(NewCmdCreateRole(f, out)) cmd.AddCommand(NewCmdCreateRoleBinding(f, out)) cmd.AddCommand(NewCmdCreatePodDisruptionBudget(f, out)) + cmd.AddCommand(NewCmdCreatePriorityClass(f, out)) return cmd } diff --git a/pkg/kubectl/cmd/create_priorityclass.go b/pkg/kubectl/cmd/create_priorityclass.go new file mode 100644 index 00000000000..7f3561ae614 --- /dev/null +++ b/pkg/kubectl/cmd/create_priorityclass.go @@ -0,0 +1,90 @@ +/* +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 cmd + +import ( + "io" + + "github.com/spf13/cobra" + + "k8s.io/kubernetes/pkg/kubectl" + "k8s.io/kubernetes/pkg/kubectl/cmd/templates" + cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" + "k8s.io/kubernetes/pkg/kubectl/util/i18n" +) + +var ( + pcLong = templates.LongDesc(i18n.T(` + Create a priorityclass with the specified name, value, globalDefault and description`)) + + pcExample = templates.Examples(i18n.T(` + # Create a priorityclass named high-priority + kubectl create priorityclass default-priority --value=1000 --description="high priority" + + # Create a priorityclass named default-priority that considered as the global default priority + kubectl create priorityclass default-priority --value=1000 --global-default=true --description="default priority"`)) +) + +// NewCmdCreatePriorityClass is a macro command to create a new priorityClass. +func NewCmdCreatePriorityClass(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { + cmd := &cobra.Command{ + Use: "priorityclass NAME --value=VALUE --global-default=BOOL [--dry-run]", + Aliases: []string{"pc"}, + Short: i18n.T("Create a priorityclass with the specified name."), + Long: pcLong, + Example: pcExample, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(CreatePriorityClass(f, cmdOut, cmd, args)) + }, + } + + cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddValidateFlags(cmd) + cmdutil.AddPrinterFlags(cmd) + cmdutil.AddGeneratorFlags(cmd, cmdutil.PriorityClassV1Alpha1GeneratorName) + + cmd.Flags().Int32("value", 0, i18n.T("the value of this priority class.")) + cmd.Flags().Bool("global-default", false, i18n.T("global-default specifies whether this PriorityClass should be considered as the default priority.")) + cmd.Flags().String("description", "", i18n.T("description is an arbitrary string that usually provides guidelines on when this priority class should be used.")) + return cmd +} + +// CreatePriorityClass implements the behavior to run the create priorityClass command. +func CreatePriorityClass(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error { + name, err := NameFromCommandArgs(cmd, args) + if err != nil { + return err + } + var generator kubectl.StructuredGenerator + switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName { + case cmdutil.PriorityClassV1Alpha1GeneratorName: + generator = &kubectl.PriorityClassV1Generator{ + Name: name, + Value: cmdutil.GetFlagInt32(cmd, "value"), + GlobalDefault: cmdutil.GetFlagBool(cmd, "global-default"), + Description: cmdutil.GetFlagString(cmd, "description"), + } + default: + return errUnsupportedGenerator(cmd, generatorName) + } + return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ + Name: name, + StructuredGenerator: generator, + DryRun: cmdutil.GetFlagBool(cmd, "dry-run"), + OutputFormat: cmdutil.GetFlagString(cmd, "output"), + }) +} diff --git a/pkg/kubectl/cmd/create_priorityclass_test.go b/pkg/kubectl/cmd/create_priorityclass_test.go new file mode 100644 index 00000000000..2ef8b143a9d --- /dev/null +++ b/pkg/kubectl/cmd/create_priorityclass_test.go @@ -0,0 +1,59 @@ +/* +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 cmd + +import ( + "bytes" + "io/ioutil" + "net/http" + "testing" + + "k8s.io/apimachinery/pkg/runtime/schema" + restclient "k8s.io/client-go/rest" + "k8s.io/client-go/rest/fake" + cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" +) + +func TestCreatePriorityClass(t *testing.T) { + pcName := "my-pc" + f, tf, _, ns := cmdtesting.NewAPIFactory() + tf.Client = &fake.RESTClient{ + GroupVersion: schema.GroupVersion{Group: "scheduling.k8s.io", Version: "v1alpha1"}, + NegotiatedSerializer: ns, + Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { + return &http.Response{ + StatusCode: http.StatusOK, + Body: ioutil.NopCloser(&bytes.Buffer{}), + }, nil + }), + } + tf.ClientConfig = &restclient.Config{} + tf.Printer = &testPrinter{} + buf := bytes.NewBuffer([]byte{}) + + cmd := NewCmdCreatePriorityClass(f, buf) + cmd.Flags().Set("value", "1000") + cmd.Flags().Set("global-default", "true") + cmd.Flags().Set("description", "my priority") + cmd.Flags().Set("dry-run", "true") + cmd.Flags().Set("output", "name") + CreatePriorityClass(f, buf, cmd, []string{pcName}) + expectedOutput := "priorityclass/" + pcName + "\n" + if buf.String() != expectedOutput { + t.Errorf("expected output: %s, but got: %s", expectedOutput, buf.String()) + } +} diff --git a/pkg/kubectl/cmd/util/factory_client_access.go b/pkg/kubectl/cmd/util/factory_client_access.go index 6c12da8a355..e0783e0b680 100644 --- a/pkg/kubectl/cmd/util/factory_client_access.go +++ b/pkg/kubectl/cmd/util/factory_client_access.go @@ -498,6 +498,7 @@ const ( ClusterV1Beta1GeneratorName = "cluster/v1beta1" PodDisruptionBudgetV1GeneratorName = "poddisruptionbudget/v1beta1" PodDisruptionBudgetV2GeneratorName = "poddisruptionbudget/v1beta1/v2" + PriorityClassV1Alpha1GeneratorName = "priorityclass/v1alpha1" ) // DefaultGenerators returns the set of default generators for use in Factory instances diff --git a/pkg/kubectl/cmd/util/helpers.go b/pkg/kubectl/cmd/util/helpers.go index ee094f85d16..b982d86b873 100644 --- a/pkg/kubectl/cmd/util/helpers.go +++ b/pkg/kubectl/cmd/util/helpers.go @@ -27,7 +27,7 @@ import ( "strings" "time" - jsonpatch "github.com/evanphx/json-patch" + "github.com/evanphx/json-patch" "github.com/golang/glog" "github.com/spf13/cobra" @@ -362,6 +362,15 @@ func GetFlagInt(cmd *cobra.Command, flag string) int { return i } +// Assumes the flag has a default value. +func GetFlagInt32(cmd *cobra.Command, flag string) int32 { + i, err := cmd.Flags().GetInt32(flag) + if err != nil { + glog.Fatalf("error accessing flag %s for command %s: %v", flag, cmd.Name(), err) + } + return i +} + // Assumes the flag has a default value. func GetFlagInt64(cmd *cobra.Command, flag string) int64 { i, err := cmd.Flags().GetInt64(flag) diff --git a/pkg/kubectl/priorityclass.go b/pkg/kubectl/priorityclass.go new file mode 100644 index 00000000000..fd600ae3253 --- /dev/null +++ b/pkg/kubectl/priorityclass.go @@ -0,0 +1,85 @@ +/* +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 kubectl + +import ( + "fmt" + + scheduling "k8s.io/api/scheduling/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// PriorityClassV1Generator supports stable generation of a priorityClass. +type PriorityClassV1Generator struct { + Name string + Value int32 + GlobalDefault bool + Description string +} + +// Ensure it supports the generator pattern that uses parameters specified during construction. +var _ StructuredGenerator = &PriorityClassV1Generator{} + +func (PriorityClassV1Generator) ParamNames() []GeneratorParam { + return []GeneratorParam{ + {"name", true}, + {"value", true}, + {"global-default", false}, + {"description", false}, + } +} + +func (s PriorityClassV1Generator) Generate(params map[string]interface{}) (runtime.Object, error) { + if err := 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) + } + delegate := &PriorityClassV1Generator{Name: name, Value: value, GlobalDefault: globalDefault, Description: description} + 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, + }, nil +} diff --git a/pkg/kubectl/priorityclass_test.go b/pkg/kubectl/priorityclass_test.go new file mode 100644 index 00000000000..2702ce33bb3 --- /dev/null +++ b/pkg/kubectl/priorityclass_test.go @@ -0,0 +1,90 @@ +/* +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 kubectl + +import ( + scheduling "k8s.io/api/scheduling/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "reflect" + "testing" +) + +func TestPriorityClassV1Generator(t *testing.T) { + tests := map[string]struct { + params map[string]interface{} + expected *scheduling.PriorityClass + expectErr bool + }{ + "test valid case": { + params: map[string]interface{}{ + "name": "foo", + "value": int32(1000), + "global-default": false, + "description": "high priority class", + }, + expected: &scheduling.PriorityClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Value: int32(1000), + GlobalDefault: false, + Description: "high priority class", + }, + expectErr: false, + }, + "test valid case that as default priority": { + params: map[string]interface{}{ + "name": "foo", + "value": int32(1000), + "global-default": true, + "description": "high priority class", + }, + expected: &scheduling.PriorityClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Value: int32(1000), + GlobalDefault: true, + Description: "high priority class", + }, + expectErr: false, + }, + "test missing required param": { + params: map[string]interface{}{ + "name": "foo", + "global-default": true, + "description": "high priority class", + }, + expectErr: true, + }, + } + + generator := PriorityClassV1Generator{} + for name, test := range tests { + obj, err := generator.Generate(test.params) + if !test.expectErr && err != nil { + t.Errorf("%s: unexpected error: %v", name, err) + } + if test.expectErr && err != nil { + continue + } + if !reflect.DeepEqual(obj.(*scheduling.PriorityClass), test.expected) { + t.Errorf("%s:\nexpected:\n%#v\nsaw:\n%#v", name, test.expected, obj.(*scheduling.PriorityClass)) + } + } +}