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

addressing issue #39427 adding a flag --output to 'kubectl version' #39858

Merged
merged 1 commit into from
Mar 28, 2017

Conversation

alejandroEsc
Copy link
Contributor

@alejandroEsc alejandroEsc commented Jan 13, 2017

What this PR does / why we need it:
Addressing Issue #39427 we all

Which issue this PR fixes (optional, in fixes #<issue number>(, fixes #<issue_number>, ...) format, will close that issue when PR gets merged): fixes #39427

Release note:

kubectl version has new flag --output (=json or yaml) allowing result of the command to be parsed in either json format or yaml. 

@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label Jan 13, 2017
@k8s-reviewable
Copy link

This change is Reviewable

@k8s-github-robot k8s-github-robot added size/M Denotes a PR that changes 30-99 lines, ignoring generated files. release-note-label-needed size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Jan 13, 2017
@alejandroEsc
Copy link
Contributor Author

There seems to be some issue upstream, never had these tests fail, local shows things working properly.

@k8s-github-robot k8s-github-robot added release-note Denotes a PR that will be considered when it comes time to generate release notes. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed release-note-label-needed size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Jan 13, 2017
@alejandroEsc
Copy link
Contributor Author

@kubernetes/api-reviewers could i get some available eyes here?

GoVersion string `json:"goVersion"`
Compiler string `json:"compiler"`
Platform string `json:"platform"`
Major string `json:"major,omitempty" yaml:"major"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't change this, this is being returned from the /version API endpoint

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you mean all these vars? do I make the changes there then?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, revert this change. it's ok to print empty strings for these fields

}

type ClientAndServerVersionObj struct {
ClientVersion version.Info `json:"Client Version" yaml:"Client Version"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

english language keys is odd here... I'd expect something like client and server

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I totally agree, was trying to keep it inline with the original keys. I dont want too much variation between what was expected before and what they will get now. What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for programmatic output, I would go short and lowercase

@@ -46,36 +59,92 @@ func NewCmdVersion(f cmdutil.Factory, out io.Writer) *cobra.Command {
}
cmd.Flags().BoolP("client", "c", false, "Client version only (no server required).")
cmd.Flags().BoolP("short", "", false, "Print just the version number.")
// default behavior is std.
cmd.Flags().String("output", "std", "output format, options available are yaml and json")
Copy link
Member

@liggitt liggitt Jan 13, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

leave default empty (not "std") for normal human-readable output?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i was going back and forth on this. I settled on std simply because i thought empty string would be a bit more difficult to understand? Not sure, but i'll change it to empty string if you are ok with that?

"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/version"
)

// We include both struct objects because json marshal does not handle the idea
// of empty struct objects well and will include and empty server object in results
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

really? omitempty doesn't work with an empty server struct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it doesnt. You can try it out, i wasnt happy with that either.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can make it a pointer to the struct and set it to nil when unused, then

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@liggitt ahhh, good point, will try this.

v = serverVersion.GitVersion
func printRightFormat(out io.Writer, outputFormat string, vo interface{}) error {
if outputFormat == "yaml" {
fmt.Println(vo)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this doesn't seem right

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:face_palm: arggghhh sorry about this.

@alejandroEsc
Copy link
Contributor Author

@liggitt left some questions there for you just to get some direction, thank you soooo much for taking your time to review, much appreciated!

@alejandroEsc
Copy link
Contributor Author

@liggitt one more question, have you taken a look at the issue ticket, just wanted your opinion on the output now vs older format.

@alejandroEsc
Copy link
Contributor Author

@liggitt made changes requested, please have another look, and thank you again!

cmd.Flags().MarkShorthandDeprecated("client", "please use --client instead.")
return cmd
}

func RunVersion(f cmdutil.Factory, out io.Writer, cmd *cobra.Command) error {
v := fmt.Sprintf("%#v", version.Get())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would order it like this:

  1. get the client and (optionally) server versions
  2. build the VersionObj struct with nil set appropriately
  3. switch on cmdutil.GetFlagString(cmd, "output") (don't normalize their arg)
  4. in the "" case, have all the existing output, including short output handling
  5. in the json/yaml cases, marshal and output
  6. in the default case, error

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be the ideal case. However, the "" case makes it a bit difficult because the output is actually label: version.Info{...} which makes this approach difficult to do. I have to keep the old output because legacy tests etc.. still use this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, in the "" case, include all the old output code

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, i think i understand what you are saying... let me try it out. it will most likely be submitted later tonight though, fyi.

return nil
}
case of == "yaml" || of == "json":
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please avoid duplicated code of generating version info.

@alejandroEsc
Copy link
Contributor Author

ok @liggitt that was fun, take a look when you are ready and thank you again.

@k8s-github-robot k8s-github-robot added size/M Denotes a PR that changes 30-99 lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Jan 14, 2017
v := fmt.Sprintf("%#v", version.Get())
vo := VersionObj{nil, nil}

cvg := version.Get()
if cmdutil.GetFlagBool(cmd, "short") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only handle short output in the human readable case

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clarify why this is the case?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only point of json/yaml output is to consume specific fields programmatically. Truncating to a single field doesn't make that any easier

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree, regardless of the consumer we should respect the expectations of the flag.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then disallow short output combined with json/yaml output

}
serverVersion, err := clientSet.Discovery().ServerVersion()
if err != nil {
return err
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Store this, but don't return it yet. Otherwise a server error prevents us from seeing our client version and is a behavior change

return err
sv := serverVersion
if cmdutil.GetFlagBool(cmd, "short") {
sv = &version.Info{GitVersion: serverVersion.GitVersion}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same, don't truncate data here. Truncate in short mode only in the human readable case

switch of := cmdutil.GetFlagString(cmd, "output"); of {
case "":
fmt.Fprintf(out, "Client Version: %s\n", fmt.Sprintf("%#v", *vo.ClientVersion))
if cmdutil.GetFlagBool(cmd, "client") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can just check whether you have a non nil server version

}

fmt.Fprintf(out, "Server Version: %s\n", fmt.Sprintf("%#v", *vo.ServerVersion))
return nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Return server error here if you got one

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, return server error after the switch statement

@alejandroEsc
Copy link
Contributor Author

Very good points, I'll try to make changes before the end of the day.

@liggitt liggitt removed their assignment Mar 17, 2017
@k8s-github-robot k8s-github-robot removed the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Mar 17, 2017
@alejandroEsc
Copy link
Contributor Author

@adohe could I get the lgtm applied again? Sorry for the trouble.

@alejandroEsc
Copy link
Contributor Author

@ethernetdan should you remove that donotmerge label and add a 1.7 label instead? also the bot removed the lgtm because of a flake.

"fmt"
"io"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did this get removed. Isn't the import standard

import (
    std libs
    [blank line]
    other people's packages
    [blank line]
    pkg's from kubernetes
)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eparis yeah probably got deleted and re-added after some change, ill go ahead and make the format change.

"fmt"
"io"

"encoding/json"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

encoding/json is part of the standard lib.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ha, i totally missed that during moving things around. thanks for the catch. Could you give this pr and lgtm? i got this dropped after an automatic retest.

… either json or yaml.

updating with PR changes requested.

latest changes to having short for human readable only, and error cases moved a bit to the end.

rebase fixes

latest pr. changes.

small change moving return nil out of switch.

updated the nil check for the error in the humanreadable case.

more optimization in humanreadable code.

pushed up current test changes, this is purely temporary

finished writing tests

updated test and function names.

changed output extensions from .sh to output.

updated version, version struct now just called Version and not VersionObj.

made a few changes to testing.

fixed testing issues, created better test and cleanup

go format change.
@0xmichalis
Copy link
Contributor

@alejandroEsc does this also address #43750? Can you post the output of kubectl version with your fix?

@0xmichalis 0xmichalis removed the do-not-merge DEPRECATED. Indicates that a PR should not merge. Label can only be manually applied/removed. label Mar 28, 2017
@0xmichalis
Copy link
Contributor

/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Mar 28, 2017
@k8s-github-robot
Copy link

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: adohe, alejandroEsc, deads2k, kargakis

Needs approval from an approver in each of these OWNERS Files:

You can indicate your approval by writing /approve in a comment
You can cancel your approval by writing /approve cancel in a comment

@alejandroEsc
Copy link
Contributor Author

@Kargakis please look at the original ticket: #39427, here i post the output. Thanks again for having a look, hopefully we arent hit with a flake again.

@0xmichalis
Copy link
Contributor

Those are looking good but I am asking specifically about the output of the command w/o using -o (the default case)

@alejandroEsc
Copy link
Contributor Author

alejandroEsc commented Mar 28, 2017

the default, without any additional output flag, has not changed, the intend here is to keep default behavior and only allow the option to make it human readable if we want it.

@0xmichalis
Copy link
Contributor

That's what I thought. Thanks for clarifying. cc: @php-coder

@alejandroEsc
Copy link
Contributor Author

@k8s-bot bazel test this

what is going on with bazel?

@ixdy
Copy link
Member

ixdy commented Mar 28, 2017

Looks like the bazel build is just broken - the upstream busybox dependency no longer exists. cc @mikedanese @spxtr

W0328 18:37:19.565] ERROR: /workspace/k8s.io/kubernetes/build/BUILD:21:1: no such package '@busybox_deb//file': Error downloading [http://ftp.us.debian.org/debian/pool/main/b/busybox/busybox-static_1.22.0-19+b1_amd64.deb] to /root/.cache/bazel/_bazel_root/e9f728bbd90b3fba632eb31b20e1dacd/external/busybox_deb/busybox-static_1.22.0-19+b1_amd64.deb: GET returned 404 Not Found and referenced by '//build:busybox'.
W0328 18:37:19.875] ERROR: Analysis of target '//build/release-tars:release-tars' failed; build aborted.

@k8s-github-robot
Copy link

Automatic merge from submit-queue

@k8s-github-robot k8s-github-robot merged commit c01baaf into kubernetes:master Mar 28, 2017
@alejandroEsc alejandroEsc deleted the ae/issue/39427 branch March 30, 2017 14:06
k8s-github-robot pushed a commit that referenced this pull request Apr 26, 2017
Automatic merge from submit-queue

add --output flag to `kubeadm version`

ref to kubectl #39858
k8s-github-robot pushed a commit that referenced this pull request Jul 22, 2017
Automatic merge from submit-queue (batch tested with PRs 46210, 48607, 46874, 46598, 49240)

Make "kubectl version" json format output more readable.

**What this PR does / why we need it**:
##39858 adds a flag --output to `kubectl version`, but the json format output is displayed in one line. It's not so readable. This PR fixes it.

and

- adds a shorthand for `output`
- ~~refactors that: if `--short` is specified, `--output` will be ignored~~

**Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes #43750

**Special notes for your reviewer**:
/cc @php-coder @alejandroEsc 

**Release note**:

```release-note
NONE
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lgtm "Looks good to me", indicates that a PR is ready to be merged. release-note Denotes a PR that will be considered when it comes time to generate release notes. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add a short and a json output option for kubectl version