Modify the JSON output of kpod ps

Changed the JSON output to hold the actual type of the data.
For example the creation time of a container will be of form time.Time.
The human readable output modifies all the fields to type string, which
is not helpful when the JSON output wants to be used for further processing.

Signed-off-by: umohnani8 <umohnani@redhat.com>
This commit is contained in:
umohnani8 2017-08-23 21:26:09 -04:00
parent 6473eec86a
commit d76e500b59

View file

@ -1,7 +1,6 @@
package main package main
import ( import (
"fmt"
"reflect" "reflect"
"regexp" "regexp"
"strconv" "strconv"
@ -33,18 +32,37 @@ type psOptions struct {
label string label string
} }
type psOutputParams struct { type psTemplateParams struct {
ID string
Image string
Command string
CreatedAt string
RunningFor string
Status string
Ports string
Size string
Names string
Labels string
Mounts string
}
// psJSONParams is only used when the JSON format is specified,
// and is better for data processing from JSON.
// psJSONParams will be populated by data from libkpod.ContainerData,
// the members of the struct are the sama data types as their sources.
type psJSONParams struct {
ID string `json:"id"` ID string `json:"id"`
Image string `json:"image"` Image string `json:"image"`
Command string `json:"command"` Command string `json:"command"`
CreatedAt string `json:"created"` CreatedAt time.Time `json:"createdAt"`
RunningFor string `json:"running"` RunningFor time.Duration `json:"runningFor"`
Status string `json:"status"` Status string `json:"status"`
Ports string `json:"ports"` Ports map[string]struct{} `json:"ports"`
Size string `json:"size"` Size uint `json:"size"`
Names string `json:"names"` Names string `json:"names"`
Labels string `json:"labels"` Labels fields.Set `json:"labels"`
Mounts string `json:"mounts"` Mounts []specs.Mount `json:"mounts"`
ContainerRunning bool `json:"ctrRunning"`
} }
const runningState = "running" const runningState = "running"
@ -159,7 +177,7 @@ func psCmd(c *cli.Context) error {
containerList := getContainersMatchingFilter(containers, params, server) containerList := getContainersMatchingFilter(containers, params, server)
return psOutput(containerList, server, opts) return generatePsOutput(containerList, server, opts)
} }
// generate the template based on conditions given // generate the template based on conditions given
@ -174,16 +192,21 @@ func genPsFormat(quiet, size bool) (format string) {
return return
} }
func psToGeneric(params []psOutputParams) []interface{} { func psToGeneric(templParams []psTemplateParams, JSONParams []psJSONParams) (genericParams []interface{}) {
genericParams := make([]interface{}, len(params)) if len(templParams) > 0 {
for i, v := range params { for _, v := range templParams {
genericParams[i] = interface{}(v) genericParams = append(genericParams, interface{}(v))
} }
return genericParams return
}
for _, v := range JSONParams {
genericParams = append(genericParams, interface{}(v))
}
return
} }
// generate the accurate header based on template given // generate the accurate header based on template given
func (p *psOutputParams) headerMap() map[string]string { func (p *psTemplateParams) headerMap() map[string]string {
v := reflect.Indirect(reflect.ValueOf(p)) v := reflect.Indirect(reflect.ValueOf(p))
values := make(map[string]string) values := make(map[string]string)
@ -221,38 +244,19 @@ func getContainers(containers []*libkpod.ContainerData, opts psOptions) []*libkp
return containersOutput return containersOutput
} }
func psOutput(containers []*libkpod.ContainerData, server *libkpod.ContainerServer, opts psOptions) error { // getTemplateOutput returns the modified container information
var ( func getTemplateOutput(containers []*libkpod.ContainerData, opts psOptions) (psOutput []psTemplateParams) {
output []psOutputParams var status string
containersOutput []*libkpod.ContainerData for _, ctr := range containers {
status string ctrID := ctr.ID
ctrID string runningFor := units.HumanDuration(time.Since(ctr.State.Created))
command string createdAt := runningFor + " ago"
runningFor string command := getCommand(ctr.ImageCreatedBy)
imageName string imageName := ctr.FromImage
mounts string mounts := getMounts(ctr.Mounts, opts.noTrunc)
ports string ports := getPorts(ctr.Config.ExposedPorts)
size string size := units.HumanSize(float64(ctr.SizeRootFs))
labels string labels := getLabels(ctr.Labels)
createdAt string
)
if len(containers) == 0 {
fmt.Println("hereee")
return nil
}
containersOutput = getContainers(containers, opts)
for _, ctr := range containersOutput {
ctrID = ctr.ID
runningFor = units.HumanDuration(time.Since(ctr.State.Created))
createdAt = runningFor + " ago"
command = getCommand(ctr.ImageCreatedBy)
imageName = ctr.FromImage
mounts = getMounts(ctr.Mounts, opts.noTrunc)
ports = getPorts(ctr.Config.ExposedPorts)
size = units.HumanSize(float64(ctr.SizeRootFs))
labels = getLabels(ctr.Labels)
switch ctr.State.Status { switch ctr.State.Status {
case "stopped": case "stopped":
@ -268,7 +272,7 @@ func psOutput(containers []*libkpod.ContainerData, server *libkpod.ContainerServ
imageName = getImageName(ctr.FromImage) imageName = getImageName(ctr.FromImage)
} }
params := psOutputParams{ params := psTemplateParams{
ID: ctrID, ID: ctrID,
Image: imageName, Image: imageName,
Command: command, Command: command,
@ -281,10 +285,36 @@ func psOutput(containers []*libkpod.ContainerData, server *libkpod.ContainerServ
Labels: labels, Labels: labels,
Mounts: mounts, Mounts: mounts,
} }
output = append(output, params) psOutput = append(psOutput, params)
} }
return
}
if len(output) == 0 { // getJSONOutput returns the container info in its raw form
func getJSONOutput(containers []*libkpod.ContainerData) (psOutput []psJSONParams) {
for _, ctr := range containers {
params := psJSONParams{
ID: ctr.ID,
Image: ctr.FromImage,
Command: ctr.ImageCreatedBy,
CreatedAt: ctr.State.Created,
RunningFor: time.Since(ctr.State.Created),
Status: ctr.State.Status,
Ports: ctr.Config.ExposedPorts,
Size: ctr.SizeRootFs,
Names: ctr.Name,
Labels: ctr.Labels,
Mounts: ctr.Mounts,
ContainerRunning: ctr.State.Status == runningState,
}
psOutput = append(psOutput, params)
}
return
}
func generatePsOutput(containers []*libkpod.ContainerData, server *libkpod.ContainerServer, opts psOptions) error {
containersOutput := getContainers(containers, opts)
if len(containersOutput) == 0 {
return nil return nil
} }
@ -292,9 +322,11 @@ func psOutput(containers []*libkpod.ContainerData, server *libkpod.ContainerServ
switch opts.format { switch opts.format {
case formats.JSONString: case formats.JSONString:
out = formats.JSONStructArray{Output: psToGeneric(output)} psOutput := getJSONOutput(containersOutput)
out = formats.JSONStructArray{Output: psToGeneric([]psTemplateParams{}, psOutput)}
default: default:
out = formats.StdoutTemplateArray{Output: psToGeneric(output), Template: opts.format, Fields: output[0].headerMap()} psOutput := getTemplateOutput(containersOutput, opts)
out = formats.StdoutTemplateArray{Output: psToGeneric(psOutput, []psJSONParams{}), Template: opts.format, Fields: psOutput[0].headerMap()}
} }
return formats.Writer(out).Out() return formats.Writer(out).Out()