Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add '-o name' to mutations #10652

Merged
merged 1 commit into from
Jul 29, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions contrib/completions/bash/kubectl
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,8 @@ _kubectl_create()
flags_completion+=("__handle_filename_extension_flag json|yaml|yml")
flags+=("--help")
flags+=("-h")
flags+=("--output=")
two_word_flags+=("-o")

must_have_one_flag=()
must_have_one_flag+=("--filename=")
Expand Down Expand Up @@ -342,6 +344,8 @@ _kubectl_replace()
flags+=("--grace-period=")
flags+=("--help")
flags+=("-h")
flags+=("--output=")
two_word_flags+=("-o")
flags+=("--timeout=")

must_have_one_flag=()
Expand All @@ -362,6 +366,8 @@ _kubectl_patch()

flags+=("--help")
flags+=("-h")
flags+=("--output=")
two_word_flags+=("-o")
flags+=("--patch=")
two_word_flags+=("-p")

Expand Down Expand Up @@ -393,6 +399,8 @@ _kubectl_delete()
flags+=("--help")
flags+=("-h")
flags+=("--ignore-not-found")
flags+=("--output=")
two_word_flags+=("-o")
flags+=("--selector=")
two_word_flags+=("-l")
flags+=("--timeout=")
Expand Down Expand Up @@ -487,6 +495,8 @@ _kubectl_scale()
flags+=("--current-replicas=")
flags+=("--help")
flags+=("-h")
flags+=("--output=")
two_word_flags+=("-o")
flags+=("--replicas=")
flags+=("--resource-version=")

Expand Down Expand Up @@ -625,6 +635,8 @@ _kubectl_stop()
flags+=("--help")
flags+=("-h")
flags+=("--ignore-not-found")
flags+=("--output=")
two_word_flags+=("-o")
flags+=("--selector=")
two_word_flags+=("-l")
flags+=("--timeout=")
Expand Down
4 changes: 4 additions & 0 deletions docs/man/man1/kubectl-create.1
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ JSON and YAML formats are accepted.
\fB\-h\fP, \fB\-\-help\fP=false
help for create

.PP
\fB\-o\fP, \fB\-\-output\fP=""
Output mode. Use "\-o name" for shorter output (resource/name).


.SH OPTIONS INHERITED FROM PARENT COMMANDS
.PP
Expand Down
4 changes: 4 additions & 0 deletions docs/man/man1/kubectl-delete.1
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ will be lost along with the rest of the resource.
\fB\-\-ignore\-not\-found\fP=false
Treat "resource not found" as a successful delete. Defaults to "true" when \-\-all is specified.

.PP
\fB\-o\fP, \fB\-\-output\fP=""
Output mode. Use "\-o name" for shorter output (resource/name).

.PP
\fB\-l\fP, \fB\-\-selector\fP=""
Selector (label query) to filter on.
Expand Down
4 changes: 4 additions & 0 deletions docs/man/man1/kubectl-patch.1
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ JSON and YAML formats are accepted.
\fB\-h\fP, \fB\-\-help\fP=false
help for patch

.PP
\fB\-o\fP, \fB\-\-output\fP=""
Output mode. Use "\-o name" for shorter output (resource/name).

.PP
\fB\-p\fP, \fB\-\-patch\fP=""
The patch to be applied to the resource JSON file.
Expand Down
4 changes: 4 additions & 0 deletions docs/man/man1/kubectl-replace.1
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ JSON and YAML formats are accepted.
\fB\-h\fP, \fB\-\-help\fP=false
help for replace

.PP
\fB\-o\fP, \fB\-\-output\fP=""
Output mode. Use "\-o name" for shorter output (resource/name).

.PP
\fB\-\-timeout\fP=0
Only relevant during a force replace. The length of time to wait before giving up on a delete of the old resource, zero means determine a timeout from the size of the object
Expand Down
4 changes: 4 additions & 0 deletions docs/man/man1/kubectl-scale.1
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ scale is sent to the server.
\fB\-h\fP, \fB\-\-help\fP=false
help for scale

.PP
\fB\-o\fP, \fB\-\-output\fP=""
Output mode. Use "\-o name" for shorter output (resource/name).

.PP
\fB\-\-replicas\fP=\-1
The new desired number of replicas. Required.
Expand Down
4 changes: 4 additions & 0 deletions docs/man/man1/kubectl-stop.1
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ If the resource is scalable it will be scaled to 0 before deletion.
\fB\-\-ignore\-not\-found\fP=false
Treat "resource not found" as a successful stop.

.PP
\fB\-o\fP, \fB\-\-output\fP=""
Output mode. Use "\-o name" for shorter output (resource/name).

.PP
\fB\-l\fP, \fB\-\-selector\fP=""
Selector (label query) to filter on.
Expand Down
1 change: 1 addition & 0 deletions docs/user-guide/kubectl/kubectl_create.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ $ cat pod.json | kubectl create -f -
```
-f, --filename=[]: Filename, directory, or URL to file to use to create the resource
-h, --help=false: help for create
-o, --output="": Output mode. Use "-o name" for shorter output (resource/name).
```

### Options inherited from parent commands
Expand Down
1 change: 1 addition & 0 deletions docs/user-guide/kubectl/kubectl_delete.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ $ kubectl delete pods --all
--grace-period=-1: Period of time in seconds given to the resource to terminate gracefully. Ignored if negative.
-h, --help=false: help for delete
--ignore-not-found=false: Treat "resource not found" as a successful delete. Defaults to "true" when --all is specified.
-o, --output="": Output mode. Use "-o name" for shorter output (resource/name).
-l, --selector="": Selector (label query) to filter on.
--timeout=0: The length of time to wait before giving up on a delete, zero means determine a timeout from the size of the object
```
Expand Down
1 change: 1 addition & 0 deletions docs/user-guide/kubectl/kubectl_patch.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ kubectl patch node k8s-node-1 -p '{"spec":{"unschedulable":true}}'

```
-h, --help=false: help for patch
-o, --output="": Output mode. Use "-o name" for shorter output (resource/name).
-p, --patch="": The patch to be applied to the resource JSON file.
```

Expand Down
1 change: 1 addition & 0 deletions docs/user-guide/kubectl/kubectl_replace.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ kubectl replace --force -f ./pod.json
--force=false: Delete and re-create the specified resource
--grace-period=-1: Only relevant during a force replace. Period of time in seconds given to the old resource to terminate gracefully. Ignored if negative.
-h, --help=false: help for replace
-o, --output="": Output mode. Use "-o name" for shorter output (resource/name).
--timeout=0: Only relevant during a force replace. The length of time to wait before giving up on a delete of the old resource, zero means determine a timeout from the size of the object
```

Expand Down
1 change: 1 addition & 0 deletions docs/user-guide/kubectl/kubectl_scale.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ $ kubectl scale --current-replicas=2 --replicas=3 replicationcontrollers foo
```
--current-replicas=-1: Precondition for current size. Requires that the current size of the replication controller match this value in order to scale.
-h, --help=false: help for scale
-o, --output="": Output mode. Use "-o name" for shorter output (resource/name).
--replicas=-1: The new desired number of replicas. Required.
--resource-version="": Precondition for resource version. Requires that the current resource version match this value in order to scale.
```
Expand Down
1 change: 1 addition & 0 deletions docs/user-guide/kubectl/kubectl_stop.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ $ kubectl stop -f path/to/resources
--grace-period=-1: Period of time in seconds given to the resource to terminate gracefully. Ignored if negative.
-h, --help=false: help for stop
--ignore-not-found=false: Treat "resource not found" as a successful stop.
-o, --output="": Output mode. Use "-o name" for shorter output (resource/name).
-l, --selector="": Selector (label query) to filter on.
--timeout=0: The length of time to wait before giving up on a delete, zero means determine a timeout from the size of the object
```
Expand Down
1 change: 1 addition & 0 deletions pkg/api/meta/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,5 @@ type RESTMapper interface {
VersionAndKindForResource(resource string) (defaultVersion, kind string, err error)
RESTMapping(kind string, versions ...string) (*RESTMapping, error)
AliasesForResource(resource string) ([]string, bool)
ResourceSingularizer(resource string) (singular string, err error)
}
32 changes: 31 additions & 1 deletion pkg/api/meta/restmapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ type DefaultRESTMapper struct {
reverse map[typeMeta]string
scopes map[typeMeta]RESTScope
versions []string
plurals map[string]string
singulars map[string]string
interfacesFunc VersionInterfacesFunc
}

Expand All @@ -93,19 +95,25 @@ func NewDefaultRESTMapper(versions []string, f VersionInterfacesFunc) *DefaultRE
mapping := make(map[string]typeMeta)
reverse := make(map[typeMeta]string)
scopes := make(map[typeMeta]RESTScope)
plurals := make(map[string]string)
singulars := make(map[string]string)
// TODO: verify name mappings work correctly when versions differ

return &DefaultRESTMapper{
mapping: mapping,
reverse: reverse,
scopes: scopes,
versions: versions,
plurals: plurals,
singulars: singulars,
interfacesFunc: f,
}
}

func (m *DefaultRESTMapper) Add(scope RESTScope, kind string, version string, mixedCase bool) {
plural, singular := kindToResource(kind, mixedCase)
m.plurals[singular] = plural
m.singulars[plural] = singular
meta := typeMeta{APIVersion: version, Kind: kind}
_, ok1 := m.mapping[plural]
_, ok2 := m.mapping[strings.ToLower(plural)]
Expand Down Expand Up @@ -133,7 +141,7 @@ func kindToResource(kind string, mixedCase bool) (plural, singular string) {
singular = strings.ToLower(kind)
}
if strings.HasSuffix(singular, "status") {
plural = strings.TrimSuffix(singular, "status") + "statuses"
plural = singular + "es"
} else {
switch string(singular[len(singular)-1]) {
case "s":
Expand All @@ -147,6 +155,16 @@ func kindToResource(kind string, mixedCase bool) (plural, singular string) {
return
}

// ResourceSingularizer implements RESTMapper
// It converts a resource name from plural to singular (e.g., from pods to pod)
func (m *DefaultRESTMapper) ResourceSingularizer(resource string) (singular string, err error) {
singular, ok := m.singulars[resource]
if !ok {
return resource, fmt.Errorf("no singular of resource %q has been defined", resource)
}
return singular, nil
}

// VersionAndKindForResource implements RESTMapper
func (m *DefaultRESTMapper) VersionAndKindForResource(resource string) (defaultVersion, kind string, err error) {
meta, ok := m.mapping[strings.ToLower(resource)]
Expand Down Expand Up @@ -249,6 +267,18 @@ func (m *DefaultRESTMapper) AliasesForResource(alias string) ([]string, bool) {
// MultiRESTMapper is a wrapper for multiple RESTMappers.
type MultiRESTMapper []RESTMapper

// ResourceSingularizer converts a REST resource name from plural to singular (e.g., from pods to pod)
// This implementation supports multiple REST schemas and return the first match.
func (m MultiRESTMapper) ResourceSingularizer(resource string) (singular string, err error) {
for _, t := range m {
singular, err = t.ResourceSingularizer(resource)
if err == nil {
return
}
}
return
}

// VersionAndKindForResource provides the Version and Kind mappings for the
// REST resources. This implementation supports multiple REST schemas and return
// the first match.
Expand Down
34 changes: 34 additions & 0 deletions pkg/api/meta/restmapper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,40 @@ func TestKindToResource(t *testing.T) {
}
}

func TestRESTMapperResourceSingularizer(t *testing.T) {
testCases := []struct {
Kind, APIVersion string
MixedCase bool
Plural string
Singular string
}{
{Kind: "Pod", APIVersion: "test", MixedCase: true, Plural: "pods", Singular: "pod"},
{Kind: "Pod", APIVersion: "test", MixedCase: false, Plural: "pods", Singular: "pod"},

{Kind: "ReplicationController", APIVersion: "test", MixedCase: true, Plural: "replicationControllers", Singular: "replicationController"},
{Kind: "ReplicationController", APIVersion: "test", MixedCase: false, Plural: "replicationcontrollers", Singular: "replicationcontroller"},

{Kind: "ImageRepository", APIVersion: "test", MixedCase: true, Plural: "imageRepositories", Singular: "imageRepository"},
{Kind: "ImageRepository", APIVersion: "test", MixedCase: false, Plural: "imagerepositories", Singular: "imagerepository"},

{Kind: "Status", APIVersion: "test", MixedCase: true, Plural: "statuses", Singular: "status"},
{Kind: "Status", APIVersion: "test", MixedCase: false, Plural: "statuses", Singular: "status"},

{Kind: "lowercase", APIVersion: "test", MixedCase: false, Plural: "lowercases", Singular: "lowercase"},
// Don't add extra s if the original object is already plural
{Kind: "lowercases", APIVersion: "test", MixedCase: false, Plural: "lowercases", Singular: "lowercases"},
}
for i, testCase := range testCases {
mapper := NewDefaultRESTMapper([]string{"test"}, fakeInterfaces)
// create singular/plural mapping
mapper.Add(RESTScopeNamespace, testCase.Kind, testCase.APIVersion, testCase.MixedCase)
singular, _ := mapper.ResourceSingularizer(testCase.Plural)
if singular != testCase.Singular {
t.Errorf("%d: mismatched singular: %s, should be %s", i, singular, testCase.Singular)
}
}
}

func TestRESTMapperRESTMapping(t *testing.T) {
testCases := []struct {
Kind string
Expand Down
13 changes: 9 additions & 4 deletions pkg/kubectl/cmd/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,17 @@ func NewCmdCreate(f *cmdutil.Factory, out io.Writer) *cobra.Command {
Example: create_example,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(ValidateArgs(cmd, args))
cmdutil.CheckErr(RunCreate(f, out, filenames))
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
shortOutput := cmdutil.GetFlagString(cmd, "output") == "name"
cmdutil.CheckErr(RunCreate(f, out, filenames, shortOutput))
},
}

usage := "Filename, directory, or URL to file to use to create the resource"
kubectl.AddJsonFilenameFlag(cmd, &filenames, usage)
cmd.MarkFlagRequired("filename")

cmdutil.AddOutputFlagsForMutation(cmd)
return cmd
}

Expand All @@ -69,7 +72,7 @@ func ValidateArgs(cmd *cobra.Command, args []string) error {
return nil
}

func RunCreate(f *cmdutil.Factory, out io.Writer, filenames util.StringList) error {
func RunCreate(f *cmdutil.Factory, out io.Writer, filenames util.StringList, shortOutput bool) error {
schema, err := f.Validator()
if err != nil {
return err
Expand Down Expand Up @@ -105,8 +108,10 @@ func RunCreate(f *cmdutil.Factory, out io.Writer, filenames util.StringList) err
}
count++
info.Refresh(obj, true)
printObjectSpecificMessage(info.Object, out)
fmt.Fprintf(out, "%s/%s\n", info.Mapping.Resource, info.Name)
if !shortOutput {
printObjectSpecificMessage(info.Object, out)
}
cmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, "created")
return nil
})
if err != nil {
Expand Down
9 changes: 6 additions & 3 deletions pkg/kubectl/cmd/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,11 @@ func TestCreateObject(t *testing.T) {

cmd := NewCmdCreate(f, buf)
cmd.Flags().Set("filename", "../../../examples/guestbook/redis-master-controller.yaml")
cmd.Flags().Set("output", "name")
cmd.Run(cmd, []string{})

// uses the name from the file, not the response
if buf.String() != "replicationcontrollers/redis-master-controller\n" {
if buf.String() != "replicationcontroller/redis-master-controller\n" {
t.Errorf("unexpected output: %s", buf.String())
}
}
Expand Down Expand Up @@ -92,10 +93,11 @@ func TestCreateMultipleObject(t *testing.T) {
cmd := NewCmdCreate(f, buf)
cmd.Flags().Set("filename", "../../../examples/guestbook/redis-master-controller.yaml")
cmd.Flags().Set("filename", "../../../examples/guestbook/frontend-service.yaml")
cmd.Flags().Set("output", "name")
cmd.Run(cmd, []string{})

// Names should come from the REST response, NOT the files
if buf.String() != "replicationcontrollers/rc1\nservices/baz\n" {
if buf.String() != "replicationcontroller/rc1\nservice/baz\n" {
t.Errorf("unexpected output: %s", buf.String())
}
}
Expand Down Expand Up @@ -125,9 +127,10 @@ func TestCreateDirectory(t *testing.T) {

cmd := NewCmdCreate(f, buf)
cmd.Flags().Set("filename", "../../../examples/guestbook")
cmd.Flags().Set("output", "name")
cmd.Run(cmd, []string{})

if buf.String() != "replicationcontrollers/name\nservices/baz\nreplicationcontrollers/name\nservices/baz\nreplicationcontrollers/name\nservices/baz\n" {
if buf.String() != "replicationcontroller/name\nservice/baz\nreplicationcontroller/name\nservice/baz\nreplicationcontroller/name\nservice/baz\n" {
t.Errorf("unexpected output: %s", buf.String())
}
}
Expand Down
Loading