Skip to content
This repository has been archived by the owner on Jun 12, 2024. It is now read-only.

Commit

Permalink
addd yaml output
Browse files Browse the repository at this point in the history
  • Loading branch information
pnickolov committed Sep 18, 2021
1 parent d46f968 commit 55551a8
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 66 deletions.
55 changes: 28 additions & 27 deletions app/model/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ type AppMetadata struct {
}

type AppSettings struct {
Replicas int
HpaEnabled bool
VpaEnabled bool
MpaEnabled bool
HpaMinReplicas int
HpaMaxReplicas int
WriteableVolume bool
Replicas int `yaml:"-"`
HpaEnabled bool `yaml:"-"`
VpaEnabled bool `yaml:"-"`
MpaEnabled bool `yaml:"-"`
HpaMinReplicas int `yaml:"-"`
HpaMaxReplicas int `yaml:"-"`
WriteableVolume bool `yaml:"writeable_volume"`
QosClass string `yaml:"qos_class"`
// TODO: consider adding replicas stats (min/max/avg/median)
}

Expand All @@ -30,36 +31,36 @@ type AppContainerResourceInfo struct {
}

type AppContainer struct {
Name string
Name string `yaml:"name"`
Cpu struct {
AppContainerResourceInfo
SecondsThrottled float64 // average rate across instances/time
Shares float64 // alt source for Cpu.Request, in CPU shares (1000-1024 per core)
}
AppContainerResourceInfo `yaml:"resource"`
SecondsThrottled float64 `yaml:"seconds_throttled"` // average rate across instances/time
Shares float64 `yaml:"shares"` // alt source for Cpu.Request, in CPU shares (1000-1024 per core)
} `yaml:"cpu"`
Memory struct {
AppContainerResourceInfo
}
RestartCount float64
AppContainerResourceInfo `yaml:"resource"`
} `yaml:"memory"`
RestartCount float64 `yaml:"restart_count"` // yaml: don't omit empty, since 0 is a valid value
}

type AppMetrics struct {
AverageReplicas float64
CpuUtilization float64 // aka Saturation, %
MemoryUtilization float64
AverageReplicas float64 `yaml:"average_replicas"`
CpuUtilization float64 `yaml:"cpu_saturation"` // aka Saturation, %
MemoryUtilization float64 `yaml:"memory_saturation"`
// TODO: add network traffic, esp. indication of traffic
}

type AppOpportunity struct {
Rating int // how suitable for optimization
Confidence int // how confident is the rating
Pros []string // list of pros for optimization
Cons []string // list of cons for optimizatoin
Rating int `yaml:"rating"` // how suitable for optimization
Confidence int `yaml:"confidence"` // how confident is the rating
Pros []string `yaml:"pros"` // list of pros for optimization
Cons []string `yaml:"cons"` // list of cons for optimizatoin
}

type App struct {
Metadata AppMetadata
Settings AppSettings
Containers []AppContainer
Metrics AppMetrics
Opportunity AppOpportunity
Metadata AppMetadata `yaml:"metadata"`
Settings AppSettings `yaml:"settings"`
Containers []AppContainer `yaml:"containers"`
Metrics AppMetrics `yaml:"metrics"`
Opportunity AppOpportunity `yaml:"analysis"`
}
4 changes: 1 addition & 3 deletions cmd/ignite.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,7 @@ func runIgnite(cmd *cobra.Command, args []string) {
}
display.WriteApp(table, app)
}
fmt.Println("")
table.Render()
fmt.Println("")
display.WriteOut(table)
if skipped > 0 {
log.Infof("%v applications were not shown due to low rating. Use --show-all to see all apps", skipped)
}
Expand Down
92 changes: 60 additions & 32 deletions cmd/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,32 @@ package cmd
import (
"fmt"
"io"
appmodel "opsani-ignite/app/model"
"strings"

"github.com/olekukonko/tablewriter"
log "github.com/sirupsen/logrus"
"gopkg.in/yaml.v3"

appmodel "opsani-ignite/app/model"
)

type AppTable struct {
tablewriter.Table // allows for adding methods locally
wr io.Writer
t tablewriter.Table // table writer, if used
yaml *yaml.Encoder // yaml encoder, if used
}

type DisplayMethods struct {
WriteHeader func(table *AppTable)
WriteApp func(table *AppTable, app *appmodel.App)
WriteOut func(table *AppTable)
}

func getDisplayMethods() map[string]DisplayMethods {
return map[string]DisplayMethods{
OUTPUT_TABLE: {(*AppTable).outputTableHeader, (*AppTable).outputTableApp},
OUTPUT_DETAIL: {(*AppTable).outputDetailHeader, (*AppTable).outputDetailApp},
OUTPUT_TABLE: {(*AppTable).outputTableHeader, (*AppTable).outputTableApp, (*AppTable).outputAnyTableOut},
OUTPUT_DETAIL: {(*AppTable).outputDetailHeader, (*AppTable).outputDetailApp, (*AppTable).outputAnyTableOut},
OUTPUT_YAML: {(*AppTable).outputYamlHeader, (*AppTable).outputYamlApp, (*AppTable).outputYamlOut},
}
}

Expand Down Expand Up @@ -72,14 +79,14 @@ func (table *AppTable) outputTableHeader() {
const RIGHT = tablewriter.ALIGN_RIGHT
const LEFT = tablewriter.ALIGN_LEFT

table.SetHeader([]string{"Rating", "Confidence", "Namespace", "Deployment", "Instances", "CPU", "Mem", "Reason"})
table.SetColumnAlignment([]int{RIGHT, RIGHT, LEFT, LEFT, RIGHT, RIGHT, RIGHT, LEFT})
table.SetFooter([]string{})
table.SetCenterSeparator("")
table.SetColumnSeparator("")
table.SetRowSeparator("")
table.SetHeaderLine(false)
table.SetBorder(false)
table.t.SetHeader([]string{"Rating", "Confidence", "Namespace", "Deployment", "Instances", "CPU", "Mem", "Reason"})
table.t.SetColumnAlignment([]int{RIGHT, RIGHT, LEFT, LEFT, RIGHT, RIGHT, RIGHT, LEFT})
table.t.SetFooter([]string{})
table.t.SetCenterSeparator("")
table.t.SetColumnSeparator("")
table.t.SetRowSeparator("")
table.t.SetHeaderLine(false)
table.t.SetBorder(false)
}

func (table *AppTable) outputTableApp(app *appmodel.App) {
Expand All @@ -99,16 +106,16 @@ func (table *AppTable) outputTableApp(app *appmodel.App) {
for i := range rowColors {
rowColors[i] = cellColors
}
table.Rich(rowValues, rowColors)
table.t.Rich(rowValues, rowColors)
}

func (table *AppTable) outputDetailHeader() {
table.SetCenterSeparator("")
table.SetColumnSeparator(":")
table.SetRowSeparator("")
table.SetHeaderLine(false)
table.SetBorder(false)
table.SetAlignment(tablewriter.ALIGN_LEFT)
table.t.SetCenterSeparator("")
table.t.SetColumnSeparator(":")
table.t.SetRowSeparator("")
table.t.SetHeaderLine(false)
table.t.SetBorder(false)
table.t.SetAlignment(tablewriter.ALIGN_LEFT)
}

func (table *AppTable) outputDetailApp(app *appmodel.App) {
Expand All @@ -121,30 +128,51 @@ func (table *AppTable) outputDetailApp(app *appmodel.App) {
consColors = []tablewriter.Colors{[]int{0}, []int{tablewriter.FgRedColor}}
}

table.Rich([]string{"Namespace", app.Metadata.Namespace}, nil)
table.Rich([]string{"Deployment", app.Metadata.Workload}, nil)
table.Rich([]string{"Kind", fmt.Sprintf("%v (%v)", app.Metadata.WorkloadKind, app.Metadata.WorkloadApiVersion)}, nil)
table.t.Rich([]string{"Namespace", app.Metadata.Namespace}, nil)
table.t.Rich([]string{"Deployment", app.Metadata.Workload}, nil)
table.t.Rich([]string{"Kind", fmt.Sprintf("%v (%v)", app.Metadata.WorkloadKind, app.Metadata.WorkloadApiVersion)}, nil)

table.Rich([]string{"Rating", fmt.Sprintf("%4d%%", app.Opportunity.Rating)}, appColors)
table.Rich([]string{"Confidence", fmt.Sprintf("%4d%%", app.Opportunity.Confidence)}, appColors)
table.t.Rich([]string{"Rating", fmt.Sprintf("%4d%%", app.Opportunity.Rating)}, appColors)
table.t.Rich([]string{"Confidence", fmt.Sprintf("%4d%%", app.Opportunity.Confidence)}, appColors)

//table.Rich(blank, nil)
if len(app.Opportunity.Pros) > 0 {
table.Rich([]string{"Pros", strings.Join(app.Opportunity.Pros, "\n")}, prosColors)
table.t.Rich([]string{"Pros", strings.Join(app.Opportunity.Pros, "\n")}, prosColors)
}
if len(app.Opportunity.Cons) > 0 {
table.Rich([]string{"Cons", strings.Join(app.Opportunity.Cons, "\n")}, consColors)
table.t.Rich([]string{"Cons", strings.Join(app.Opportunity.Cons, "\n")}, consColors)
}

//table.Rich(blank, nil)
table.Rich([]string{"Average Replica Count", fmt.Sprintf("%3.0f%%", app.Metrics.AverageReplicas)}, nil)
table.Rich([]string{"Container Count", fmt.Sprintf("%3d", len(app.Containers))}, nil)
table.Rich([]string{"CPU Utilization", fmt.Sprintf("%3.0f%%", app.Metrics.CpuUtilization)}, nil)
table.Rich([]string{"Memory Utilization", fmt.Sprintf("%3.0f%%", app.Metrics.MemoryUtilization)}, nil)
table.t.Rich([]string{"Average Replica Count", fmt.Sprintf("%3.0f%%", app.Metrics.AverageReplicas)}, nil)
table.t.Rich([]string{"Container Count", fmt.Sprintf("%3d", len(app.Containers))}, nil)
table.t.Rich([]string{"CPU Utilization", fmt.Sprintf("%3.0f%%", app.Metrics.CpuUtilization)}, nil)
table.t.Rich([]string{"Memory Utilization", fmt.Sprintf("%3.0f%%", app.Metrics.MemoryUtilization)}, nil)

table.t.Rich(blank, nil)
}

func (table *AppTable) outputAnyTableOut() {
fmt.Println("")
table.t.Render()
fmt.Println("")
}

func (table *AppTable) outputYamlHeader() {
table.yaml = yaml.NewEncoder(table.wr)
}

func (table *AppTable) outputYamlApp(app *appmodel.App) {
err := table.yaml.Encode(*app)
if err != nil {
log.Errorf("Failed to write app %v to yaml: %v", app.Metadata, err)
}
}

table.Rich(blank, nil)
func (table *AppTable) outputYamlOut() {
table.yaml.Close()
}

func newAppTable(wr io.Writer) *AppTable {
return &AppTable{*tablewriter.NewWriter(wr)}
return &AppTable{wr, *tablewriter.NewWriter(wr), nil}
}
4 changes: 2 additions & 2 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ var showDebug bool
const (
OUTPUT_TABLE = "table"
OUTPUT_DETAIL = "detail"
// TODO: add JSON and YAML
OUTPUT_YAML = "yaml"
)

// constant table - format types, keep in sync with OUTPUT_xxx constants above
func getOutputFormats() []string {
return []string{OUTPUT_TABLE, OUTPUT_DETAIL}
return []string{OUTPUT_TABLE, OUTPUT_DETAIL, OUTPUT_YAML}
}

// rootCmd represents the base command when called without any subcommands
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ require (
github.com/olekukonko/tablewriter v0.0.5
github.com/prometheus/client_golang v1.11.0
github.com/prometheus/common v0.26.0
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/sirupsen/logrus v1.8.1
github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/cobra v1.2.1
github.com/spf13/viper v1.8.1
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect
golang.org/x/text v0.3.7 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
)
5 changes: 4 additions & 1 deletion sources/prometheus/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,10 @@ func collectContainersInfo(ctx context.Context, promApi v1.API, app *appmodel.Ap
if len(labels) != 1 || !ok {
return warnings, fmt.Errorf("Query %q returned labels %v, expected %v", query, labels, []string{"container"})
}
app.Containers = append(app.Containers, appmodel.AppContainer{Name: string(name)})
container := appmodel.AppContainer{Name: string(name)}
container.Cpu.Unit = "cores"
container.Memory.Unit = "bytes"
app.Containers = append(app.Containers, container)
}

// Get resource requests
Expand Down

0 comments on commit 55551a8

Please sign in to comment.