Skip to content

Commit

Permalink
Ability to output ls/ps in json format (lf-edge#889)
Browse files Browse the repository at this point in the history
Allow to use --format=json option to display lists in machine-readable format.

```
$ ./eden volume ls --format=json
[
    {
        "Name": "pedantic_ganguly_0_m_0",
        "UUID": "77a786a5-fc09-4b3d-946c-fbb4d77a72ce",
        "Image": "lfedge/eden-eclient:b1c1de6",
        "VolumeType": "CONTAINER",
        "Size": "82 MB",
        "MaxSize": "-",
        "AdamState": "IN_CONFIG",
        "EveState": "DELIVERED",
        "LastError": "",
        "Ref": "app: pedantic_ganguly",
        "MountPoint": "/",
        "OriginType": "VCOT_DOWNLOAD"
    }
]
```

```
$ ./eden network ls --format=json
[
    {
        "Name": "flamboyant_goldstine",
        "UUID": "c7b73fe8-f2eb-4304-b07a-9f8adcca8178",
        "NetworkType": "ZnetInstLocal",
        "CIDR": "10.11.12.0/24",
        "Stats": "rx:{totalPackets:570 totalBytes:54758} tx:{totalPackets:2260 totalBytes:2607824}",
        "AdamState": "IN_CONFIG",
        "EveState": "ACTIVATED",
        "Activated": true
    }
]
```

```
$ ./eden pod ps --format=json
[
    {
        "Name": "pedantic_ganguly",
        "UUID": "2877759b-5443-4952-b95e-004f244c87ad",
        "Image": "lfedge/eden-eclient:b1c1de6",
        "AdamState": "IN_CONFIG",
        "EVEState": "RUNNING",
        "InternalIP": [
            "10.11.12.2"
        ],
        "ExternalIP": "127.0.0.1",
        "InternalPort": "22",
        "ExternalPort": "8027",
        "MemoryUsed": 181,
        "MemoryAvail": 896,
        "CPUUsage": 0,
        "Macs": [
            "ce:5b:cd:11:50:0f"
        ],
        "Volumes": {
            "77a786a5-fc09-4b3d-946c-fbb4d77a72ce": 100
        }
    }
]
```

Signed-off-by: Petr Fedchenkov <giggsoff@gmail.com>
  • Loading branch information
giggsoff authored Aug 25, 2023
1 parent 8690d7a commit 4f562e4
Show file tree
Hide file tree
Showing 9 changed files with 144 additions and 48 deletions.
7 changes: 6 additions & 1 deletion cmd/edenNetwork.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,21 @@ func newNetworkCmd() *cobra.Command {
}

func newNetworkLsCmd() *cobra.Command {
var outputFormat types.OutputFormat
//networkLsCmd is a command to list deployed network instances
var networkLsCmd = &cobra.Command{
Use: "ls",
Short: "List networks",
Run: func(cmd *cobra.Command, args []string) {
if err := openevec.NetworkLs(); err != nil {
if err := openevec.NetworkLs(outputFormat); err != nil {
log.Fatal(err)
}
},
}
networkLsCmd.Flags().Var(
enumflag.New(&outputFormat, "format", outputFormatIds, enumflag.EnumCaseInsensitive),
"format",
"Format to print logs, supports: lines, json")
return networkLsCmd
}

Expand Down
7 changes: 6 additions & 1 deletion cmd/edenPod.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,15 +127,20 @@ You can set access VLAN ID (VID) for a particular network in the format '<networ
}

func newPodPsCmd(cfg *openevec.EdenSetupArgs) *cobra.Command {
var outputFormat types.OutputFormat
var podPsCmd = &cobra.Command{
Use: "ps",
Short: "List pods",
Run: func(cmd *cobra.Command, args []string) {
if err := openevec.PodPs(cfg); err != nil {
if err := openevec.PodPs(cfg, outputFormat); err != nil {
log.Fatalf("EVE pod deploy failed: %s", err)
}
},
}
podPsCmd.Flags().Var(
enumflag.New(&outputFormat, "format", outputFormatIds, enumflag.EnumCaseInsensitive),
"format",
"Format to print logs, supports: lines, json")

return podPsCmd
}
Expand Down
9 changes: 8 additions & 1 deletion cmd/edenVolume.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package cmd

import (
"github.com/dustin/go-humanize"
"github.com/lf-edge/eden/pkg/controller/types"
"github.com/lf-edge/eden/pkg/openevec"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/thediveo/enumflag"
)

func newVolumeCmd() *cobra.Command {
Expand All @@ -31,16 +33,21 @@ func newVolumeCmd() *cobra.Command {
}

func newVolumeLsCmd() *cobra.Command {
var outputFormat types.OutputFormat
//volumeLsCmd is a command to list deployed volumes
var volumeLsCmd = &cobra.Command{
Use: "ls",
Short: "List volumes",
Run: func(cmd *cobra.Command, args []string) {
if err := openevec.VolumeLs(); err != nil {
if err := openevec.VolumeLs(outputFormat); err != nil {
log.Fatal(err)
}
},
}
volumeLsCmd.Flags().Var(
enumflag.New(&outputFormat, "format", outputFormatIds, enumflag.EnumCaseInsensitive),
"format",
"Format to print logs, supports: lines, json")
return volumeLsCmd
}

Expand Down
81 changes: 58 additions & 23 deletions pkg/eve/applications.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package eve

import (
"encoding/json"
"fmt"
"os"
"sort"
Expand All @@ -11,13 +12,14 @@ import (

"github.com/dustin/go-humanize"
"github.com/lf-edge/eden/pkg/controller"
"github.com/lf-edge/eden/pkg/controller/types"
"github.com/lf-edge/eden/pkg/device"
"github.com/lf-edge/eve/api/go/config"
"github.com/lf-edge/eve/api/go/info"
"github.com/lf-edge/eve/api/go/metrics"
)

//AppInstState stores state of app
// AppInstState stores state of app
type AppInstState struct {
Name string
UUID string
Expand All @@ -28,11 +30,16 @@ type AppInstState struct {
ExternalIP string
InternalPort string
ExternalPort string
Memory string
macs []string
volumes map[string]uint32
deleted bool
infoTime time.Time
MemoryUsed uint32
MemoryAvail uint32
CPUUsage int
Macs []string
Volumes map[string]uint32

prevCPUNS uint64
prevCPUNSTime time.Time
deleted bool
infoTime time.Time
}

func appStateHeader() string {
Expand Down Expand Up @@ -66,9 +73,12 @@ func (appStateObj *AppInstState) toString() string {
if appStateObj.ExternalPort == "" {
external = "-"
}
memory := fmt.Sprintf("%s/%s",
humanize.Bytes((uint64)(appStateObj.MemoryUsed*humanize.MByte)),
humanize.Bytes((uint64)(appStateObj.MemoryAvail*humanize.MByte)))
return fmt.Sprintf("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s",
appStateObj.Name, appStateObj.Image, appStateObj.UUID,
internal, external, appStateObj.Memory,
internal, external, memory,
appStateObj.AdamState, appStateObj.EVEState)
}

Expand Down Expand Up @@ -131,7 +141,7 @@ func (ctx *State) initApplications(ctrl controller.Cloud, dev *device.Ctx) error
ExternalIP: "-",
InternalPort: intPort,
ExternalPort: extPort,
volumes: volumes,
Volumes: volumes,
UUID: app.Uuidandversion.Uuid,
}
ctx.applications[app.Uuidandversion.Uuid] = appStateObj
Expand All @@ -144,9 +154,14 @@ func (ctx *State) processApplicationsByMetric(msg *metrics.ZMetricMsg) {
for _, appMetric := range appMetrics {
for _, el := range ctx.applications {
if appMetric.AppID == el.UUID {
el.Memory = fmt.Sprintf("%s/%s",
humanize.Bytes((uint64)(appMetric.Memory.GetUsedMem()*humanize.MByte)),
humanize.Bytes((uint64)(appMetric.Memory.GetAvailMem()*humanize.MByte)))
el.MemoryAvail = appMetric.Memory.GetAvailMem()
el.MemoryUsed = appMetric.Memory.GetUsedMem()
// if not restarted
if el.prevCPUNS < appMetric.Cpu.TotalNs {
el.CPUUsage = int(float32(appMetric.Cpu.TotalNs-el.prevCPUNS) / float32(msg.GetAtTimeStamp().AsTime().Sub(el.prevCPUNSTime).Nanoseconds()) * 100.0)
}
el.prevCPUNS = appMetric.Cpu.TotalNs
el.prevCPUNSTime = msg.GetAtTimeStamp().AsTime()
break
}
}
Expand All @@ -158,19 +173,19 @@ func (ctx *State) processApplicationsByInfo(im *info.ZInfoMsg) {
switch im.GetZtype() {
case info.ZInfoTypes_ZiVolume:
for _, app := range ctx.applications {
if len(app.volumes) == 0 {
if len(app.Volumes) == 0 {
continue
}
var percent uint32
for vol := range app.volumes {
percent += app.volumes[vol] //we sum all percents of all volumes and will divide them by count
for vol := range app.Volumes {
percent += app.Volumes[vol] //we sum all percents of all volumes and will divide them by count
if im.GetVinfo().Uuid == vol {
app.volumes[vol] = im.GetVinfo().ProgressPercentage
app.Volumes[vol] = im.GetVinfo().ProgressPercentage
break
}
}
if strings.HasPrefix(app.EVEState, info.ZSwState_DOWNLOAD_STARTED.String()) {
app.EVEState = fmt.Sprintf("%s (%d%%)", info.ZSwState_DOWNLOAD_STARTED.String(), int(percent)/len(app.volumes))
app.EVEState = fmt.Sprintf("%s (%d%%)", info.ZSwState_DOWNLOAD_STARTED.String(), int(percent)/len(app.Volumes))
}
}
case info.ZInfoTypes_ZiApp:
Expand All @@ -192,22 +207,22 @@ func (ctx *State) processApplicationsByInfo(im *info.ZInfoMsg) {
if len(im.GetAinfo().Network) != 0 && len(im.GetAinfo().Network[0].IPAddrs) != 0 {
if len(im.GetAinfo().Network) > 1 {
appStateObj.InternalIP = []string{}
appStateObj.macs = []string{}
appStateObj.Macs = []string{}
for _, el := range im.GetAinfo().Network {
if len(el.IPAddrs) != 0 {
appStateObj.InternalIP = append(appStateObj.InternalIP, el.IPAddrs[0])
appStateObj.macs = append(appStateObj.macs, el.MacAddr)
appStateObj.Macs = append(appStateObj.Macs, el.MacAddr)
}
}
} else {
if len(im.GetAinfo().Network[0].IPAddrs) != 0 {
appStateObj.InternalIP = []string{im.GetAinfo().Network[0].IPAddrs[0]}
appStateObj.macs = []string{im.GetAinfo().Network[0].MacAddr}
appStateObj.Macs = []string{im.GetAinfo().Network[0].MacAddr}
}
}
} else {
appStateObj.InternalIP = []string{"-"}
appStateObj.macs = []string{}
appStateObj.Macs = []string{}
}
//check appStateObj not defined in adam
if appStateObj.AdamState != inControllerConfig {
Expand All @@ -222,7 +237,7 @@ func (ctx *State) processApplicationsByInfo(im *info.ZInfoMsg) {
case info.ZInfoTypes_ZiNetworkInstance: //try to find ips from NetworkInstances
for _, el := range im.GetNiinfo().IpAssignments {
for _, appStateObj := range ctx.applications {
for ind, mac := range appStateObj.macs {
for ind, mac := range appStateObj.Macs {
if mac == el.MacAddress {
appStateObj.InternalIP[ind] = el.IpAddress[0]
}
Expand Down Expand Up @@ -283,8 +298,7 @@ func (ctx *State) processApplicationsByInfo(im *info.ZInfoMsg) {
}
}

//PodsList prints applications
func (ctx *State) PodsList() error {
func (ctx *State) printPodListLines() error {
w := new(tabwriter.Writer)
w.Init(os.Stdout, 0, 8, 1, '\t', 0)
if _, err := fmt.Fprintln(w, appStateHeader()); err != nil {
Expand All @@ -302,3 +316,24 @@ func (ctx *State) PodsList() error {
}
return w.Flush()
}

func (ctx *State) printPodListJSON() error {
result, err := json.MarshalIndent(ctx.Applications(), "", " ")
if err != nil {
return err
}
//nolint:forbidigo
fmt.Println(string(result))
return nil
}

// PodsList prints applications
func (ctx *State) PodsList(outputFormat types.OutputFormat) error {
switch outputFormat {
case types.OutputFormatLines:
return ctx.printPodListLines()
case types.OutputFormatJSON:
return ctx.printPodListJSON()
}
return fmt.Errorf("unimplemented output format")
}
32 changes: 27 additions & 5 deletions pkg/eve/networks.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package eve

import (
"encoding/json"
"fmt"
"os"
"sort"
"text/tabwriter"

"github.com/lf-edge/eden/pkg/controller"
"github.com/lf-edge/eden/pkg/controller/types"
"github.com/lf-edge/eden/pkg/device"
"github.com/lf-edge/eve/api/go/config"
"github.com/lf-edge/eve/api/go/info"
Expand All @@ -17,7 +19,7 @@ import (
type NetInstState struct {
Name string
UUID string
NetworkType config.ZNetworkInstType
NetworkType string
CIDR string
Stats string
AdamState string
Expand Down Expand Up @@ -51,7 +53,7 @@ func (ctx *State) initNetworks(ctrl controller.Cloud, dev *device.Ctx) error {
AdamState: inControllerConfig,
EveState: "UNKNOWN",
CIDR: ni.Ip.Subnet,
NetworkType: ni.InstType,
NetworkType: ni.InstType.String(),
}
ctx.networks[ni.Uuidandversion.Uuid] = netInstStateObj
}
Expand All @@ -69,7 +71,7 @@ func (ctx *State) processNetworksByInfo(im *info.ZInfoMsg) {
Stats: "-",
AdamState: notInControllerConfig,
EveState: "UNKNOWN",
NetworkType: (config.ZNetworkInstType)(int32(im.GetNiinfo().InstType)),
NetworkType: (config.ZNetworkInstType)(int32(im.GetNiinfo().InstType)).String(),
}
ctx.networks[im.GetNiinfo().GetNetworkID()] = netInstStateObj
}
Expand Down Expand Up @@ -120,8 +122,7 @@ func (ctx *State) processNetworksByMetric(msg *metrics.ZMetricMsg) {
}
}

// NetList prints networks
func (ctx *State) NetList() error {
func (ctx *State) printNetListLines() error {
w := new(tabwriter.Writer)
w.Init(os.Stdout, 0, 8, 1, '\t', 0)
if _, err := fmt.Fprintln(w, netInstStateHeader()); err != nil {
Expand All @@ -139,3 +140,24 @@ func (ctx *State) NetList() error {
}
return w.Flush()
}

func (ctx *State) printNetListJSON() error {
result, err := json.MarshalIndent(ctx.Networks(), "", " ")
if err != nil {
return err
}
//nolint:forbidigo
fmt.Println(string(result))
return nil
}

// NetList prints networks
func (ctx *State) NetList(outputFormat types.OutputFormat) error {
switch outputFormat {
case types.OutputFormatLines:
return ctx.printNetListLines()
case types.OutputFormatJSON:
return ctx.printNetListJSON()
}
return fmt.Errorf("unimplemented output format")
}
Loading

0 comments on commit 4f562e4

Please sign in to comment.