From 0a2876d39e37cef982d9b61c32131a2de180cc7f Mon Sep 17 00:00:00 2001 From: Xing Zhou Date: Tue, 10 Jan 2017 13:59:49 +0800 Subject: [PATCH 1/3] Added kubectl create role command. Added kubectl create role command. --- pkg/kubectl/cmd/BUILD | 4 + pkg/kubectl/cmd/create.go | 1 + pkg/kubectl/cmd/create_role.go | 237 +++++++++++++++++++++++++++++++++ 3 files changed, 242 insertions(+) create mode 100644 pkg/kubectl/cmd/create_role.go diff --git a/pkg/kubectl/cmd/BUILD b/pkg/kubectl/cmd/BUILD index 390a91eb28d..6fdcc41b6ea 100644 --- a/pkg/kubectl/cmd/BUILD +++ b/pkg/kubectl/cmd/BUILD @@ -30,6 +30,7 @@ go_library( "create_namespace.go", "create_pdb.go", "create_quota.go", + "create_role.go", "create_rolebinding.go", "create_secret.go", "create_service.go", @@ -70,6 +71,7 @@ go_library( "//pkg/apis/certificates:go_default_library", "//pkg/apis/extensions/v1beta1:go_default_library", "//pkg/apis/policy:go_default_library", + "//pkg/apis/rbac:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library", "//pkg/client/unversioned:go_default_library", @@ -143,6 +145,7 @@ go_test( "create_deployment_test.go", "create_namespace_test.go", "create_quota_test.go", + "create_role_test.go", "create_secret_test.go", "create_service_test.go", "create_serviceaccount_test.go", @@ -183,6 +186,7 @@ go_test( "//pkg/apis/batch:go_default_library", "//pkg/apis/extensions:go_default_library", "//pkg/apis/policy:go_default_library", + "//pkg/apis/rbac:go_default_library", "//pkg/kubectl:go_default_library", "//pkg/kubectl/cmd/testing:go_default_library", "//pkg/kubectl/cmd/util:go_default_library", diff --git a/pkg/kubectl/cmd/create.go b/pkg/kubectl/cmd/create.go index 25af726ba48..36bb5174b38 100644 --- a/pkg/kubectl/cmd/create.go +++ b/pkg/kubectl/cmd/create.go @@ -96,6 +96,7 @@ func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command { cmd.AddCommand(NewCmdCreateService(f, out, errOut)) cmd.AddCommand(NewCmdCreateDeployment(f, out)) cmd.AddCommand(NewCmdCreateClusterRoleBinding(f, out)) + cmd.AddCommand(NewCmdCreateRole(f, out)) cmd.AddCommand(NewCmdCreateRoleBinding(f, out)) cmd.AddCommand(NewCmdCreatePodDisruptionBudget(f, out)) return cmd diff --git a/pkg/kubectl/cmd/create_role.go b/pkg/kubectl/cmd/create_role.go new file mode 100644 index 00000000000..c88632879cd --- /dev/null +++ b/pkg/kubectl/cmd/create_role.go @@ -0,0 +1,237 @@ +/* +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 ( + "fmt" + "io" + "strings" + + "github.com/spf13/cobra" + + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/kubernetes/pkg/apis/rbac" + "k8s.io/kubernetes/pkg/kubectl/cmd/templates" + cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" +) + +var ( + roleLong = templates.LongDesc(` + Create a role with single rule.`) + + roleExample = templates.Examples(` + # Create a Role named "pod-reader" that allows user to perform "get", "watch" and "list" on pods + kubectl create role pod-reader --verb=get --verb=list --verb=watch --resource=pods + + # Create a Role named "pod-reader" with ResourceName specified + kubectl create role pod-reader --verb=get --verg=list --verb=watch --resource=pods --resource-name=readablepod`) + + // Valid resource verb list for validation. + validResourceVerbs = []string{"*", "get", "delete", "list", "create", "update", "patch", "watch", "proxy", "redirect", "deletecollection"} + + // Valid non-resource verb list for validation. + validNonResourceVerbs = []string{"get", "post", "put", "delete"} +) + +type CreateRoleOptions struct { + Name string + Verbs []string + Resources []schema.GroupVersionResource + ResourceNames []string +} + +// Role is a command to ease creating Roles. +func NewCmdCreateRole(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { + c := &CreateRoleOptions{} + cmd := &cobra.Command{ + Use: "role NAME --verb=verb --resource=resource.group [--resource-name=resourcename] [--dry-run]", + Short: roleLong, + Long: roleLong, + Example: roleExample, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(c.Complete(cmd, args)) + cmdutil.CheckErr(c.Validate(f)) + cmdutil.CheckErr(c.RunCreateRole(f, cmdOut, cmd, args)) + }, + } + cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddValidateFlags(cmd) + cmdutil.AddPrinterFlags(cmd) + cmdutil.AddDryRunFlag(cmd) + cmd.Flags().StringSliceVar(&c.Verbs, "verb", []string{}, "verb that applies to the resources contained in the rule") + cmd.Flags().StringSlice("resource", []string{}, "resource that the rule applies to") + cmd.Flags().StringSliceVar(&c.ResourceNames, "resource-name", []string{}, "resource in the white list that the rule applies to") + + return cmd +} + +func (c *CreateRoleOptions) Complete(cmd *cobra.Command, args []string) error { + name, err := NameFromCommandArgs(cmd, args) + if err != nil { + return err + } + c.Name = name + + // Remove duplicate verbs. + verbs := []string{} + for _, v := range c.Verbs { + // VerbAll respresents all kinds of verbs. + if v == "*" { + verbs = []string{"*"} + break + } + if !arrayContains(verbs, v) { + verbs = append(verbs, v) + } + } + c.Verbs = verbs + + // Support resource.group pattern. If no API Group specified, use "" as core API Group. + // e.g. --resource=pods,deployments.extensions + resources := cmdutil.GetFlagStringSlice(cmd, "resource") + for _, r := range resources { + sections := strings.Split(r, ".") + + if len(sections) == 1 { + c.Resources = append(c.Resources, schema.GroupVersionResource{Resource: r}) + } else { + c.Resources = append(c.Resources, schema.GroupVersionResource{Resource: sections[0], Group: strings.Join(sections[1:], ".")}) + } + } + + // Remove duplicate resource names. + resourceNames := []string{} + for _, n := range c.ResourceNames { + if !arrayContains(resourceNames, n) { + resourceNames = append(resourceNames, n) + } + } + c.ResourceNames = resourceNames + + return nil +} + +func (c *CreateRoleOptions) Validate(f cmdutil.Factory) error { + if c.Name == "" { + return fmt.Errorf("name must be specified") + } + + // validate verbs. + if len(c.Verbs) == 0 { + return fmt.Errorf("at least one verb must be specified") + } + + for _, v := range c.Verbs { + if !arrayContains(validResourceVerbs, v) && !arrayContains(validNonResourceVerbs, v) { + return fmt.Errorf("invalid verb: '%s'", v) + } + } + + // validate resources. + mapper, _ := f.Object() + + if len(c.Resources) == 0 { + return fmt.Errorf("at least one resource must be specified") + } + + for _, r := range c.Resources { + _, err := mapper.ResourceFor(r) + if err != nil { + return err + } + } + + // validate resource names, can not apply resource names to multiple resources. + if len(c.ResourceNames) > 0 && len(c.Resources) > 1 { + return fmt.Errorf("resource name(s) can not be applied to multiple resources") + } + + return nil +} + +func (c *CreateRoleOptions) RunCreateRole(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error { + mapper, _ := f.Object() + dryRun, outputFormat := cmdutil.GetDryRunFlag(cmd), cmdutil.GetFlagString(cmd, "output") + + // groupResourceMapping is a apigroup-resource map. The key of this map is api group, while the value + // is a string array of resources under this api group. + // E.g. groupResourceMapping = {"extensions": ["replicasets", "deployments"], "batch":["jobs"]} + groupResourceMapping := map[string][]string{} + + // This loop does the following work: + // 1. Constructs groupResourceMapping based on input resources. + // 2. Prevents pointing to non-existent resources. + // 3. Transfers resource short name to long name. E.g. rs.extensions is transferred to replicasets.extensions + for _, r := range c.Resources { + resource, err := mapper.ResourceFor(r) + if err != nil { + return err + } + if !arrayContains(groupResourceMapping[resource.Group], resource.Resource) { + groupResourceMapping[resource.Group] = append(groupResourceMapping[resource.Group], resource.Resource) + } + } + + role := &rbac.Role{} + + // Create separate rule for each of the api group. + rules := []rbac.PolicyRule{} + for _, g := range sets.StringKeySet(groupResourceMapping).List() { + rule := rbac.PolicyRule{} + rule.Verbs = c.Verbs + rule.Resources = groupResourceMapping[g] + rule.APIGroups = []string{g} + rule.ResourceNames = c.ResourceNames + rules = append(rules, rule) + } + role.Name = c.Name + role.Rules = rules + + // Create role. + namespace, _, err := f.DefaultNamespace() + if err != nil { + return err + } + + if !dryRun { + client, err := f.ClientSet() + if err != nil { + return err + } + _, err = client.Rbac().Roles(namespace).Create(role) + if err != nil { + return err + } + } + + if useShortOutput := outputFormat == "name"; useShortOutput || len(outputFormat) == 0 { + cmdutil.PrintSuccess(mapper, useShortOutput, cmdOut, "roles", c.Name, dryRun, "created") + return nil + } + + return f.PrintObject(cmd, mapper, role, cmdOut) +} + +func arrayContains(s []string, e string) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +} From b9c6fb52ab1bd41ee56639ed15eaae7919dab79d Mon Sep 17 00:00:00 2001 From: Xing Zhou Date: Fri, 13 Jan 2017 10:15:50 +0800 Subject: [PATCH 2/3] Added unit tests for kubectl create role command. Added unit tests for kubectl create role command. --- hack/make-rules/test-cmd-util.sh | 17 ++ pkg/kubectl/cmd/create_role_test.go | 359 ++++++++++++++++++++++++++++ 2 files changed, 376 insertions(+) create mode 100644 pkg/kubectl/cmd/create_role_test.go diff --git a/hack/make-rules/test-cmd-util.sh b/hack/make-rules/test-cmd-util.sh index 0b7495df050..efe9c58e057 100644 --- a/hack/make-rules/test-cmd-util.sh +++ b/hack/make-rules/test-cmd-util.sh @@ -57,6 +57,7 @@ pods="pods" podtemplates="podtemplates" replicasets="replicasets" replicationcontrollers="replicationcontrollers" +roles="roles" secrets="secrets" serviceaccounts="serviceaccounts" services="services" @@ -2817,6 +2818,22 @@ runTests() { kube::test::get_object_assert rolebinding/sarole "{{range.subjects}}{{.namespace}}:{{end}}" 'otherns:' kube::test::get_object_assert rolebinding/sarole "{{range.subjects}}{{.name}}:{{end}}" 'sa-name:' fi + + if kube::test::if_supports_resource "${roles}" ; then + kubectl create "${kube_flags[@]}" role pod-admin --verb=* --resource=pods + kube::test::get_object_assert role/pod-admin "{{range.rules}}{{range.verbs}}{{.}}:{{end}}{{end}}" '\*:' + kube::test::get_object_assert role/pod-admin "{{range.rules}}{{range.resources}}{{.}}:{{end}}{{end}}" 'pods:' + kube::test::get_object_assert role/pod-admin "{{range.rules}}{{range.apiGroups}}{{.}}:{{end}}{{end}}" ':' + kubectl create "${kube_flags[@]}" role resource-reader --verb=get,list --resource=pods,deployments.extensions + kube::test::get_object_assert role/resource-reader "{{range.rules}}{{range.verbs}}{{.}}:{{end}}{{end}}" 'get:list:get:list:' + kube::test::get_object_assert role/resource-reader "{{range.rules}}{{range.resources}}{{.}}:{{end}}{{end}}" 'pods:deployments:' + kube::test::get_object_assert role/resource-reader "{{range.rules}}{{range.apiGroups}}{{.}}:{{end}}{{end}}" ':extensions:' + kubectl create "${kube_flags[@]}" role resourcename-reader --verb=get,list --resource=pods --resource-name=foo + kube::test::get_object_assert role/resourcename-reader "{{range.rules}}{{range.verbs}}{{.}}:{{end}}{{end}}" 'get:list:' + kube::test::get_object_assert role/resourcename-reader "{{range.rules}}{{range.resources}}{{.}}:{{end}}{{end}}" 'pods:' + kube::test::get_object_assert role/resourcename-reader "{{range.rules}}{{range.apiGroups}}{{.}}:{{end}}{{end}}" ':' + kube::test::get_object_assert role/resourcename-reader "{{range.rules}}{{range.resourceNames}}{{.}}:{{end}}{{end}}" 'foo:' + fi ######################### # Assert short name # diff --git a/pkg/kubectl/cmd/create_role_test.go b/pkg/kubectl/cmd/create_role_test.go new file mode 100644 index 00000000000..76a4c5d1e85 --- /dev/null +++ b/pkg/kubectl/cmd/create_role_test.go @@ -0,0 +1,359 @@ +/* +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" + "reflect" + "testing" + + "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/kubernetes/pkg/apis/rbac" + cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" +) + +type testRolePrinter struct { + CachedRole *rbac.Role +} + +func (t *testRolePrinter) PrintObj(obj runtime.Object, out io.Writer) error { + t.CachedRole = obj.(*rbac.Role) + return nil +} + +func (t *testRolePrinter) AfterPrint(output io.Writer, res string) error { + return nil +} + +func (t *testRolePrinter) HandledResources() []string { + return []string{} +} + +func TestCreateRole(t *testing.T) { + roleName := "my-role" + + f, tf, _, _ := cmdtesting.NewAPIFactory() + printer := &testRolePrinter{} + tf.Printer = printer + tf.Namespace = "test" + + tests := map[string]struct { + verbs string + resources string + resourceNames string + expectedRole *rbac.Role + }{ + "test-duplicate-resources": { + verbs: "get,watch,list", + resources: "pods,pods", + expectedRole: &rbac.Role{ + ObjectMeta: v1.ObjectMeta{ + Name: roleName, + }, + Rules: []rbac.PolicyRule{ + { + Verbs: []string{"get", "watch", "list"}, + Resources: []string{"pods"}, + APIGroups: []string{""}, + ResourceNames: []string{}, + }, + }, + }, + }, + "test-valid-case-with-multiple-apigroups": { + verbs: "get,watch,list", + resources: "pods,deployments.extensions", + expectedRole: &rbac.Role{ + ObjectMeta: v1.ObjectMeta{ + Name: roleName, + }, + Rules: []rbac.PolicyRule{ + { + Verbs: []string{"get", "watch", "list"}, + Resources: []string{"pods"}, + APIGroups: []string{""}, + ResourceNames: []string{}, + }, + { + Verbs: []string{"get", "watch", "list"}, + Resources: []string{"deployments"}, + APIGroups: []string{"extensions"}, + ResourceNames: []string{}, + }, + }, + }, + }, + } + + for name, test := range tests { + buf := bytes.NewBuffer([]byte{}) + cmd := NewCmdCreateRole(f, buf) + cmd.Flags().Set("dry-run", "true") + cmd.Flags().Set("output", "object") + cmd.Flags().Set("verb", test.verbs) + cmd.Flags().Set("resource", test.resources) + if test.resourceNames != "" { + cmd.Flags().Set("resource-name", test.resourceNames) + } + cmd.Run(cmd, []string{roleName}) + if !reflect.DeepEqual(test.expectedRole, printer.CachedRole) { + t.Errorf("%s:\nexpected:\n%#v\nsaw:\n%#v", name, test.expectedRole, printer.CachedRole) + } + } +} + +func TestValidate(t *testing.T) { + f, tf, _, _ := cmdtesting.NewAPIFactory() + tf.Printer = &testPrinter{} + tf.Namespace = "test" + + tests := map[string]struct { + roleOptions *CreateRoleOptions + expectErr bool + }{ + "test-missing-name": { + roleOptions: &CreateRoleOptions{}, + expectErr: true, + }, + "test-missing-verb": { + roleOptions: &CreateRoleOptions{ + Name: "my-role", + }, + expectErr: true, + }, + "test-missing-resource": { + roleOptions: &CreateRoleOptions{ + Name: "my-role", + Verbs: []string{"get"}, + }, + expectErr: true, + }, + "test-invalid-verb": { + roleOptions: &CreateRoleOptions{ + Name: "my-role", + Verbs: []string{"invalid-verb"}, + Resources: []schema.GroupVersionResource{ + { + Resource: "pods", + }, + }, + }, + expectErr: true, + }, + "test-invalid-resource": { + roleOptions: &CreateRoleOptions{ + Name: "my-role", + Verbs: []string{"get"}, + Resources: []schema.GroupVersionResource{ + { + Resource: "invalid-resource", + }, + }, + }, + expectErr: true, + }, + "test-resource-name-with-multiple-resources": { + roleOptions: &CreateRoleOptions{ + Name: "my-role", + Verbs: []string{"get"}, + Resources: []schema.GroupVersionResource{ + { + Resource: "pods", + }, + { + Resource: "deployments", + Group: "extensions", + }, + }, + ResourceNames: []string{"foo"}, + }, + expectErr: true, + }, + "test-valid-case": { + roleOptions: &CreateRoleOptions{ + Name: "my-role", + Verbs: []string{"get", "list"}, + Resources: []schema.GroupVersionResource{ + { + Resource: "pods", + }, + }, + ResourceNames: []string{"foo"}, + }, + expectErr: false, + }, + } + + for name, test := range tests { + err := test.roleOptions.Validate(f) + if test.expectErr && err != nil { + continue + } + if !test.expectErr && err != nil { + t.Errorf("%s: unexpected error: %v", name, err) + } + } +} + +func TestComplete(t *testing.T) { + roleName := "my-role" + + f, tf, _, _ := cmdtesting.NewAPIFactory() + tf.Printer = &testPrinter{} + tf.Namespace = "test" + + buf := bytes.NewBuffer([]byte{}) + cmd := NewCmdCreateRole(f, buf) + cmd.Flags().Set("resource", "pods,deployments.extensions") + + tests := map[string]struct { + params []string + roleOptions *CreateRoleOptions + expected *CreateRoleOptions + expectErr bool + }{ + "test-missing-name": { + params: []string{}, + roleOptions: &CreateRoleOptions{}, + expectErr: true, + }, + "test-duplicate-verbs": { + params: []string{roleName}, + roleOptions: &CreateRoleOptions{ + Name: roleName, + Verbs: []string{ + "get", + "watch", + "list", + "get", + }, + }, + expected: &CreateRoleOptions{ + Name: roleName, + Verbs: []string{ + "get", + "watch", + "list", + }, + Resources: []schema.GroupVersionResource{ + { + Resource: "pods", + Group: "", + }, + { + Resource: "deployments", + Group: "extensions", + }, + }, + ResourceNames: []string{}, + }, + expectErr: false, + }, + "test-verball": { + params: []string{roleName}, + roleOptions: &CreateRoleOptions{ + Name: roleName, + Verbs: []string{ + "get", + "watch", + "list", + "*", + }, + }, + expected: &CreateRoleOptions{ + Name: roleName, + Verbs: []string{"*"}, + Resources: []schema.GroupVersionResource{ + { + Resource: "pods", + Group: "", + }, + { + Resource: "deployments", + Group: "extensions", + }, + }, + ResourceNames: []string{}, + }, + expectErr: false, + }, + "test-duplicate-resourcenames": { + params: []string{roleName}, + roleOptions: &CreateRoleOptions{ + Name: roleName, + Verbs: []string{"*"}, + ResourceNames: []string{"foo", "foo"}, + }, + expected: &CreateRoleOptions{ + Name: roleName, + Verbs: []string{"*"}, + Resources: []schema.GroupVersionResource{ + { + Resource: "pods", + Group: "", + }, + { + Resource: "deployments", + Group: "extensions", + }, + }, + ResourceNames: []string{"foo"}, + }, + expectErr: false, + }, + "test-valid-complete-case": { + params: []string{roleName}, + roleOptions: &CreateRoleOptions{ + Name: roleName, + Verbs: []string{"*"}, + ResourceNames: []string{"foo"}, + }, + expected: &CreateRoleOptions{ + Name: roleName, + Verbs: []string{"*"}, + Resources: []schema.GroupVersionResource{ + { + Resource: "pods", + Group: "", + }, + { + Resource: "deployments", + Group: "extensions", + }, + }, + ResourceNames: []string{"foo"}, + }, + expectErr: false, + }, + } + + for name, test := range tests { + err := test.roleOptions.Complete(cmd, test.params) + if !test.expectErr && err != nil { + t.Errorf("%s: unexpected error: %v", name, err) + } + if test.expectErr && err != nil { + continue + } + if !reflect.DeepEqual(test.roleOptions, test.expected) { + t.Errorf("%s:\nexpected:\n%#v\nsaw:\n%#v", name, test.expected, test.roleOptions) + } + } +} From 89021157b0a3c99ed15377fed2c221e3a15fc5f9 Mon Sep 17 00:00:00 2001 From: Xing Zhou Date: Fri, 10 Feb 2017 10:43:10 +0800 Subject: [PATCH 3/3] Added generated docs for kubectl create role command. Added generated docs for kubectl create role command. --- .generated_docs | 2 ++ docs/man/man1/kubectl-create-role.1 | 3 +++ docs/user-guide/kubectl/kubectl_create_role.md | 3 +++ hack/verify-flags/known-flags.txt | 3 +++ 4 files changed, 11 insertions(+) create mode 100644 docs/man/man1/kubectl-create-role.1 create mode 100644 docs/user-guide/kubectl/kubectl_create_role.md diff --git a/.generated_docs b/.generated_docs index 1d24a4e88ad..2a84cbedb4e 100644 --- a/.generated_docs +++ b/.generated_docs @@ -43,6 +43,7 @@ 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-quota.1 +docs/man/man1/kubectl-create-role.1 docs/man/man1/kubectl-create-rolebinding.1 docs/man/man1/kubectl-create-secret-docker-registry.1 docs/man/man1/kubectl-create-secret-generic.1 @@ -127,6 +128,7 @@ 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_quota.md +docs/user-guide/kubectl/kubectl_create_role.md docs/user-guide/kubectl/kubectl_create_rolebinding.md docs/user-guide/kubectl/kubectl_create_secret.md docs/user-guide/kubectl/kubectl_create_secret_docker-registry.md diff --git a/docs/man/man1/kubectl-create-role.1 b/docs/man/man1/kubectl-create-role.1 new file mode 100644 index 00000000000..b6fd7a0f989 --- /dev/null +++ b/docs/man/man1/kubectl-create-role.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_role.md b/docs/user-guide/kubectl/kubectl_create_role.md new file mode 100644 index 00000000000..b6fd7a0f989 --- /dev/null +++ b/docs/user-guide/kubectl/kubectl_create_role.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/hack/verify-flags/known-flags.txt b/hack/verify-flags/known-flags.txt index f2b64c149db..447afb38a13 100644 --- a/hack/verify-flags/known-flags.txt +++ b/hack/verify-flags/known-flags.txt @@ -517,7 +517,9 @@ requestheader-username-headers require-kubeconfig required-contexts resolv-conf +resource resource-container +resource-name resource-quota-sync-period resource-version results-dir @@ -622,6 +624,7 @@ use-service-account-credentials use-kubernetes-cluster-service use-kubernetes-version user-whitelist +verb verify-only versioned-clientset-package viper-config