tsh request search, add support for --format flag#62015
Conversation
b53ef20 to
c09a073
Compare
tool/tsh/common/access_request.go
Outdated
| var err error | ||
|
|
||
| if format == teleport.JSON { | ||
| out, err = utils.FastMarshalIndent(rows, "", " ") |
There was a problem hiding this comment.
Should we use utils.WriteJSONArray here instead? I think that ensures we write an empty [] if there was no data.
(Similarly, we have utils.WriteYAML for the same purpose)
There was a problem hiding this comment.
I ended up adding utils.WriteYAMLArray, because utils.WriteYAML serializes slices as multi-document YAML, which isn’t consistent with how other tsh commands print YAML.
There was also an issue with utils.WriteJSONArray, it printed an empty array without a trailing newline, so I changed it.
46e3e54 to
783b3cb
Compare
ravicious
left a comment
There was a problem hiding this comment.
Submitted a couple of suggestions but no major issues, looks fine.
There was a problem hiding this comment.
I noticed that the order of the columns is consistent between text and json but not yaml. Do you think it's something we could improve?
Example output between three formats
$ tsh request search --kind=node --format text
Name Hostname Labels Resource ID
------------------------------------ -------------------- ------ -----------------------------------------------------------
339cc7f2-2d53-458a-92e2-09e96798c64d mbp.enterprise-local /enterprise-local/node/339cc7f2-2d53-458a-92e2-09e96798c64d
To request access to these resources, run
> tsh request create --resource /enterprise-local/node/339cc7f2-2d53-458a-92e2-09e96798c64d \
--reason <request reason>
$ tsh request search --kind=node --format json
[
{
"Name": "339cc7f2-2d53-458a-92e2-09e96798c64d",
"Hostname": "mbp.enterprise-local",
"Labels": "",
"ResourceID": "/enterprise-local/node/339cc7f2-2d53-458a-92e2-09e96798c64d"
}
]
$ tsh request search --kind=node --format yaml
- Hostname: mbp.enterprise-local
Labels: ""
Name: 339cc7f2-2d53-458a-92e2-09e96798c64d
ResourceID: /enterprise-local/node/339cc7f2-2d53-458a-92e2-09e96798c64d
There was a problem hiding this comment.
I'm not sure this is something I can improve in this PR.
The inconsistency comes from the YAML library we use github.com/ghodss/yaml, which firstly converts structs into JSON, then unmarshals that JSON into a generic interface{} using gopkg.in/yaml.v2, and then marshals it back to YAML.
Here is the function it uses:
func yamlToJSON(y []byte, jsonTarget *reflect.Value) ([]byte, error) {
// Convert the YAML to an object.
var yamlObj interface{}
err := yaml.Unmarshal(y, &yamlObj)
if err != nil {
return nil, err
}
// YAML objects are not completely compatible with JSON objects (e.g. you
// can have non-string keys in YAML). So, convert the YAML-compatible object
// to a JSON-compatible object, failing with an error if irrecoverable
// incompatibilties happen along the way.
jsonObj, err := convertToJSONableObject(yamlObj, jsonTarget)
if err != nil {
return nil, err
}
// Convert this object to JSON and return the data.
return json.Marshal(jsonObj)
}Unmarshalling into interface{} turns the object into a map[interface{}]interface{}, and yaml.v2 marshals map keys in alphabetical order.
This library also depends on gopkg.in/yaml.v2, even though v3 already exists, and the library itself hasn’t been updated in over four years.
To fix this, we would likely need to switch to using Go’s gopkg.in/yaml.v3 directly.
There was a problem hiding this comment.
Thanks for looking into this. In that case let's just not worry about it. It'd have been nice but it doesn't seem like it's worth the effort.
783b3cb to
626a237
Compare
|
@tangyatsu See the table below for backport results.
|
* tsh request search, add support for --format flag * fix missing newline when WriteJSONArray serializes empty arrays
What
Resolves #41953
This PR adds support for the
--formatflag totsh request search, enabling output in json and yaml formats in addition to text format.This PR also adds a new helper func MakeAsciitableColumnsAndRows() in
teleport/lib/asciitable.The function converts a slice of structs into column names and row values suitable for use with
MakeTable(). Column names are derived from struct field names.It also supports struct tags:
asciitable:"Custom Name": sets a custom column nameasciitable:"-": excludes the field from outputResourceIDtoResource ID)changelog: Added support for --format flag for
tsh request searchManual Tests
A local test cluster was created with an Web application, SSH node, a PostgreSQL database and Minikube.
The following tests were performed:
tsh request search --kind=dbprints tabletsh request search --kind=db --format textprints tabletsh request search --kind=db --format jsonprints valid jsontsh request search --kind=db --format yamlprints valid yamlsame for other resources like node, kube_cluster, etc.