mirror of
https://github.com/kubevela/kubevela.git
synced 2026-02-14 10:00:06 +00:00
Merge pull request #249 from captainroy-hy/app-topology
implement "vela app status"
This commit is contained in:
@@ -24,6 +24,7 @@ var _ = ginkgo.Describe("Application", func() {
|
||||
e2e.TraitManualScalerAttachContext("vela attach trait", traitAlias, applicationName)
|
||||
//e2e.ApplicationListContext("app ls", applicationName, traitAlias)
|
||||
e2e.ApplicationShowContext("app show", applicationName, workloadType)
|
||||
e2e.ApplicationStatusContext("comp status", applicationName, workloadType)
|
||||
e2e.ApplicationStatusContext("app status", applicationName, workloadType)
|
||||
e2e.ApplicationCompStatusContext("comp status", applicationName, workloadType)
|
||||
e2e.WorkloadDeleteContext("delete", applicationName)
|
||||
})
|
||||
|
||||
@@ -177,6 +177,18 @@ var (
|
||||
ApplicationStatusContext = func(context string, applicationName string, workloadType string) bool {
|
||||
return ginkgo.Context(context, func() {
|
||||
ginkgo.It("should get status for the application", func() {
|
||||
cli := fmt.Sprintf("vela app status %s", applicationName)
|
||||
output, err := Exec(cli)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
gomega.Expect(output).To(gomega.ContainSubstring(applicationName))
|
||||
// TODO(roywang) add more assertion to check health status
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
ApplicationCompStatusContext = func(context string, applicationName string, workloadType string) bool {
|
||||
return ginkgo.Context(context, func() {
|
||||
ginkgo.It("should get status for the component", func() {
|
||||
cli := fmt.Sprintf("vela comp status %s", applicationName)
|
||||
output, err := Exec(cli)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
|
||||
6
go.mod
6
go.mod
@@ -7,7 +7,8 @@ require (
|
||||
github.com/Azure/go-autorest v12.2.0+incompatible // Don't remove. https://github.com/kubernetes/client-go/issues/628
|
||||
github.com/coreos/prometheus-operator v0.41.1
|
||||
github.com/crossplane/crossplane-runtime v0.9.0
|
||||
github.com/crossplane/oam-kubernetes-runtime v0.0.9
|
||||
github.com/crossplane/oam-kubernetes-runtime v0.1.1-0.20200909070723-78b84f2c4799
|
||||
github.com/fatih/color v1.9.0
|
||||
github.com/gertd/go-pluralize v0.1.7
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/gin-gonic/gin v1.6.3
|
||||
@@ -15,11 +16,11 @@ require (
|
||||
github.com/google/go-cmp v0.5.2
|
||||
github.com/google/go-github/v32 v32.1.0
|
||||
github.com/gosuri/uitable v0.0.4
|
||||
github.com/oam-dev/catalog/traits/metricstrait v0.0.0-20200826071236-d96c1d64e221
|
||||
github.com/oam-dev/trait-injector v0.0.0-20200331033130-0a27b176ffc4
|
||||
github.com/onsi/ginkgo v1.11.0
|
||||
github.com/onsi/gomega v1.8.1
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/rs/xid v1.2.1 // indirect
|
||||
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b
|
||||
github.com/spf13/cobra v1.0.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
@@ -36,6 +37,7 @@ require (
|
||||
k8s.io/cli-runtime v0.18.6
|
||||
k8s.io/client-go v12.0.0+incompatible
|
||||
k8s.io/klog v1.0.0
|
||||
k8s.io/kube-openapi v0.0.0-20200410145947-bcb3869e6f29 // indirect
|
||||
k8s.io/kubectl v0.18.6 // indirect
|
||||
k8s.io/utils v0.0.0-20200414100711-2df71ebbae66
|
||||
rsc.io/letsencrypt v0.0.3 // indirect
|
||||
|
||||
6
go.sum
6
go.sum
@@ -46,6 +46,7 @@ github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7O
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||
github.com/Azure/go-autorest v10.8.1+incompatible h1:u0jVQf+a6k6x8A+sT60l6EY9XZu+kHdnZVPAYqpVRo0=
|
||||
github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||
github.com/Azure/go-autorest v11.2.8+incompatible h1:Q2feRPMlcfVcqz3pF87PJzkm5lZrL+x6BDtzhODzNJM=
|
||||
github.com/Azure/go-autorest v11.2.8+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||
github.com/Azure/go-autorest v12.2.0+incompatible h1:2Fxszbg492oAJrcvJlgyVaTqnQYRkxmEK6VPCLLVpBI=
|
||||
github.com/Azure/go-autorest v12.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||
@@ -237,7 +238,6 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc
|
||||
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/coreos/prometheus-operator v0.40.0/go.mod h1:QOoL5cVI3b1OHgpw8s+pH+Ok4AFRp2HOUvBpqs7UWcg=
|
||||
github.com/coreos/prometheus-operator v0.41.1 h1:MEhY9syliPlQg+VlFRUfNodUEVXRXJ2n1pFG0aBp+mI=
|
||||
github.com/coreos/prometheus-operator v0.41.1/go.mod h1:LhLfEBydppl7nvfEA1jIqlF3xJ9myHCnzrU+HHDxRd4=
|
||||
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
|
||||
@@ -251,9 +251,10 @@ github.com/crossplane/crossplane-runtime v0.8.0/go.mod h1:gNY/21MLBaz5KNP7hmfXbB
|
||||
github.com/crossplane/crossplane-runtime v0.9.0 h1:K6/tLhXKzhsEUUddTvEWWnQLLrawWyw1ptNK7NBDpDU=
|
||||
github.com/crossplane/crossplane-runtime v0.9.0/go.mod h1:gNY/21MLBaz5KNP7hmfXbBXp8reYRbwY5B/97Kp4tgM=
|
||||
github.com/crossplane/crossplane-tools v0.0.0-20200219001116-bb8b2ce46330/go.mod h1:C735A9X0x0lR8iGVOOxb49Mt70Ua4EM2b7PGaRPBLd4=
|
||||
github.com/crossplane/oam-kubernetes-runtime v0.0.7/go.mod h1:f5xqmo0B2WtaOTZh8jhP+0f0XuzqhJG2xRtxfMZR3jA=
|
||||
github.com/crossplane/oam-kubernetes-runtime v0.0.9 h1:cZMT7p1jZ6MsJqAuzVIZwvOxVdD+PGEQgCYHHuwR7Pc=
|
||||
github.com/crossplane/oam-kubernetes-runtime v0.0.9/go.mod h1:f5xqmo0B2WtaOTZh8jhP+0f0XuzqhJG2xRtxfMZR3jA=
|
||||
github.com/crossplane/oam-kubernetes-runtime v0.1.1-0.20200909070723-78b84f2c4799 h1:424LLFb7C8Qvy3wFZZ7HzmawlCeF32PNRTXXK5rKOk0=
|
||||
github.com/crossplane/oam-kubernetes-runtime v0.1.1-0.20200909070723-78b84f2c4799/go.mod h1:UZ4eXkl/e4lKrAhK81Pz1sR90wqeuE9PgdwVXr8kDgI=
|
||||
github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg=
|
||||
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
|
||||
github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=
|
||||
@@ -874,7 +875,6 @@ github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi
|
||||
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
|
||||
github.com/oam-dev/catalog/traits/metricstrait v0.0.0-20200826071236-d96c1d64e221/go.mod h1:mpYuuccw79F/yddIODjdDCzUyvXNnuksPWVx/z5vZBw=
|
||||
github.com/oam-dev/stern v1.13.0-alpha h1:EVjM8Qvh6LssB6t4RZrjf9DtCq1cz+/cy6OF7fpy9wk=
|
||||
github.com/oam-dev/stern v1.13.0-alpha/go.mod h1:AOkvfFUv0Arz7GBi0jz7S0Jsu4K/kdvSjNsnRt1+BIg=
|
||||
github.com/oam-dev/trait-injector v0.0.0-20200331033130-0a27b176ffc4 h1:fc41JCTc9w140pE/WPtpmL3uiCjC3DEfzbtvHT6h6xY=
|
||||
|
||||
@@ -19,6 +19,7 @@ func NewAppsCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
}
|
||||
|
||||
cmd.AddCommand(NewAppListCommand(c, ioStreams),
|
||||
NewAppStatusCommand(c, ioStreams),
|
||||
NewDeleteCommand(c, ioStreams),
|
||||
NewAppShowCommand(ioStreams),
|
||||
NewRunCommand(c, ioStreams))
|
||||
|
||||
@@ -2,10 +2,14 @@ package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2"
|
||||
"github.com/fatih/color"
|
||||
"github.com/gosuri/uitable"
|
||||
|
||||
"github.com/cloud-native-application/rudrx/pkg/application"
|
||||
|
||||
@@ -16,12 +20,50 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
func NewCompStatusCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
// HealthStatus represents health status strings.
|
||||
type HealthStatus = v1alpha2.HealthStatus
|
||||
|
||||
const (
|
||||
// StatusNotFound means there's no health check info returned from the scope.
|
||||
StatusNotFound HealthStatus = "NOT DIAGNOSED"
|
||||
)
|
||||
|
||||
const (
|
||||
// StatusHealthy represents healthy status.
|
||||
StatusHealthy = v1alpha2.StatusHealthy
|
||||
// StatusUnhealthy represents unhealthy status.
|
||||
StatusUnhealthy = v1alpha2.StatusUnhealthy
|
||||
// StatusUnknown represents unknown status.
|
||||
StatusUnknown = v1alpha2.StatusUnknown
|
||||
)
|
||||
|
||||
// WorkloadHealthCondition holds health status of any resource
|
||||
type WorkloadHealthCondition = v1alpha2.WorkloadHealthCondition
|
||||
|
||||
// ScopeHealthCondition holds health condition of a scope
|
||||
type ScopeHealthCondition = v1alpha2.ScopeHealthCondition
|
||||
|
||||
const (
|
||||
firstElemPrefix = `├─`
|
||||
lastElemPrefix = `└─`
|
||||
indent = " "
|
||||
pipe = `│ `
|
||||
)
|
||||
|
||||
var (
|
||||
gray = color.New(color.FgHiBlack)
|
||||
red = color.New(color.FgRed)
|
||||
green = color.New(color.FgGreen)
|
||||
yellow = color.New(color.FgYellow)
|
||||
white = color.New(color.Bold, color.FgWhite)
|
||||
)
|
||||
|
||||
func NewAppStatusCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
ctx := context.Background()
|
||||
cmd := &cobra.Command{
|
||||
Use: "status <APPLICATION-NAME>",
|
||||
Short: "get status of an application",
|
||||
Long: "get status of an application, including its workload and trait",
|
||||
Long: "get status of an application, including workloads and traits of each components.",
|
||||
Example: `vela status <APPLICATION-NAME>`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
argsLength := len(args)
|
||||
@@ -29,6 +71,119 @@ func NewCompStatusCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Comm
|
||||
ioStreams.Errorf("Hint: please specify an application")
|
||||
os.Exit(1)
|
||||
}
|
||||
appName := args[0]
|
||||
env, err := GetEnv(cmd)
|
||||
if err != nil {
|
||||
ioStreams.Errorf("Error: failed to get Env: %s", err)
|
||||
return err
|
||||
}
|
||||
newClient, err := client.New(c.Config, client.Options{Scheme: c.Schema})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return printAppStatus(ctx, newClient, ioStreams, appName, env)
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
types.TagCommandType: types.TypeApp,
|
||||
},
|
||||
}
|
||||
cmd.SetOut(ioStreams.Out)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func printAppStatus(ctx context.Context, c client.Client, ioStreams cmdutil.IOStreams, appName string, env *types.EnvMeta) error {
|
||||
app, err := application.Load(env.Name, appName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
namespace := env.Name
|
||||
tbl := uitable.New()
|
||||
tbl.Separator = " "
|
||||
tbl.AddRow(
|
||||
white.Sprint("NAMESPCAE"),
|
||||
white.Sprint("NAME"),
|
||||
white.Sprint("INFO"))
|
||||
|
||||
tbl.AddRow(
|
||||
namespace,
|
||||
fmt.Sprintf("%s/%s",
|
||||
"Application",
|
||||
appName))
|
||||
|
||||
components := app.GetComponents()
|
||||
// get a map coantaining all workloads health condition
|
||||
wlConditionsMap, err := getWorkloadHealthConditions(ctx, c, app, namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for cIndex, compName := range components {
|
||||
var cPrefix string
|
||||
switch cIndex {
|
||||
case len(components) - 1:
|
||||
cPrefix = lastElemPrefix
|
||||
default:
|
||||
cPrefix = firstElemPrefix
|
||||
}
|
||||
|
||||
wlHealthCondition := wlConditionsMap[compName]
|
||||
wlHealthStatus := wlHealthCondition.HealthStatus
|
||||
healthColor := getHealthStatusColor(wlHealthStatus)
|
||||
|
||||
// print component info
|
||||
tbl.AddRow("",
|
||||
fmt.Sprintf("%s%s/%s",
|
||||
gray.Sprint(printPrefix(cPrefix)),
|
||||
"Component",
|
||||
compName),
|
||||
healthColor.Sprintf("%s %s", wlHealthStatus, wlHealthCondition.Diagnosis))
|
||||
}
|
||||
ioStreams.Info(tbl)
|
||||
return nil
|
||||
}
|
||||
|
||||
// map componentName <=> WorkloadHealthCondition
|
||||
func getWorkloadHealthConditions(ctx context.Context, c client.Client, app *application.Application, ns string) (map[string]*WorkloadHealthCondition, error) {
|
||||
|
||||
hs := &v1alpha2.HealthScope{}
|
||||
// only use default health scope
|
||||
hsName := application.FormatDefaultHealthScopeName(app.Name)
|
||||
if err := c.Get(ctx, client.ObjectKey{Namespace: ns, Name: hsName}, hs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wlConditions := hs.Status.WorkloadHealthConditions
|
||||
r := map[string]*WorkloadHealthCondition{}
|
||||
components := app.GetComponents()
|
||||
for _, compName := range components {
|
||||
for _, wlhc := range wlConditions {
|
||||
if wlhc.ComponentName == compName {
|
||||
r[compName] = wlhc
|
||||
break
|
||||
}
|
||||
}
|
||||
if r[compName] == nil {
|
||||
r[compName] = &WorkloadHealthCondition{
|
||||
HealthStatus: StatusNotFound,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func NewCompStatusCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
ctx := context.Background()
|
||||
cmd := &cobra.Command{
|
||||
Use: "status <COMPONENT-NAME>",
|
||||
Short: "get status of a component",
|
||||
Long: "get status of a component, including its workload and health status",
|
||||
Example: `vela comp status <COMPONENT-NAME>`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
argsLength := len(args)
|
||||
if argsLength == 0 {
|
||||
ioStreams.Errorf("Hint: please specify a component")
|
||||
os.Exit(1)
|
||||
}
|
||||
compName := args[0]
|
||||
env, err := GetEnv(cmd)
|
||||
if err != nil {
|
||||
@@ -67,16 +222,103 @@ func printComponentStatus(ctx context.Context, c client.Client, ioStreams cmduti
|
||||
if err = c.Get(ctx, client.ObjectKey{Namespace: env.Namespace, Name: application.FormatDefaultHealthScopeName(app.Name)}, &health); err != nil {
|
||||
return err
|
||||
}
|
||||
ioStreams.Info("Component Status:")
|
||||
//TODO(wonderflow): add more information from health scope
|
||||
ioStreams.Infof("\n %s \n\n", health.Status.Health)
|
||||
|
||||
ioStreams.Infof(white.Sprint("Component Status:\n"))
|
||||
var wlhc *v1alpha2.WorkloadHealthCondition
|
||||
for _, v := range health.Status.WorkloadHealthConditions {
|
||||
if v.ComponentName == compName {
|
||||
wlhc = v
|
||||
}
|
||||
}
|
||||
var (
|
||||
healthColor *color.Color
|
||||
healthStatus HealthStatus
|
||||
healthInfo string
|
||||
workloadType string
|
||||
)
|
||||
if wlhc == nil {
|
||||
workloadType = ""
|
||||
healthStatus = StatusNotFound
|
||||
healthInfo = fmt.Sprintf("%s %s", healthStatus, "Cannot get health status")
|
||||
} else {
|
||||
workloadType = wlhc.TargetWorkload.Kind
|
||||
healthStatus = wlhc.HealthStatus
|
||||
healthInfo = fmt.Sprintf("%s %s", healthStatus, wlhc.Diagnosis)
|
||||
}
|
||||
healthColor = getHealthStatusColor(healthStatus)
|
||||
|
||||
ioStreams.Infof("\tName: %s %s(type) %s \n", compName, workloadType, healthColor.Sprint(healthInfo))
|
||||
|
||||
traits, err := app.GetTraits(compName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(traits) > 0 {
|
||||
// print tree structure of Traits
|
||||
tbl := uitable.New()
|
||||
tbl.Separator = " "
|
||||
traitNames := []string{}
|
||||
for k := range traits {
|
||||
traitNames = append(traitNames, k)
|
||||
}
|
||||
for tIndex, tName := range traitNames {
|
||||
var tPrefix string
|
||||
switch tIndex {
|
||||
case len(traitNames) - 1:
|
||||
tPrefix = lastElemPrefix
|
||||
default:
|
||||
tPrefix = firstElemPrefix
|
||||
}
|
||||
tbl.AddRow(
|
||||
"\t",
|
||||
fmt.Sprintf("%s%s%s/%s",
|
||||
indent,
|
||||
gray.Sprint(printPrefix(tPrefix)),
|
||||
"Trait",
|
||||
tName))
|
||||
}
|
||||
ioStreams.Info("\tTraits")
|
||||
ioStreams.Info(tbl)
|
||||
}
|
||||
|
||||
var appConfig v1alpha2.ApplicationConfiguration
|
||||
if err = c.Get(ctx, client.ObjectKey{Namespace: env.Namespace, Name: app.Name}, &appConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
ioStreams.Infof("Last Deployment:\n\n")
|
||||
ioStreams.Infof("\tCreated at:\t%v\n", appConfig.CreationTimestamp)
|
||||
ioStreams.Infof("\tUpdated at:\t%v\n", app.UpdateTime.Format(time.RFC3339))
|
||||
ioStreams.Infof(white.Sprint("\nLast Deployment:\n"))
|
||||
ioStreams.Infof("\tCreated at: %v\n", appConfig.CreationTimestamp)
|
||||
ioStreams.Infof("\tUpdated at: %v\n", app.UpdateTime.Format(time.RFC3339))
|
||||
return nil
|
||||
}
|
||||
|
||||
func printPrefix(p string) string {
|
||||
if strings.HasSuffix(p, firstElemPrefix) {
|
||||
p = strings.Replace(p, firstElemPrefix, pipe, strings.Count(p, firstElemPrefix)-1)
|
||||
} else {
|
||||
p = strings.ReplaceAll(p, firstElemPrefix, pipe)
|
||||
}
|
||||
|
||||
if strings.HasSuffix(p, lastElemPrefix) {
|
||||
p = strings.Replace(p, lastElemPrefix, strings.Repeat(" ", len([]rune(lastElemPrefix))), strings.Count(p, lastElemPrefix)-1)
|
||||
} else {
|
||||
p = strings.ReplaceAll(p, lastElemPrefix, strings.Repeat(" ", len([]rune(lastElemPrefix))))
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func getHealthStatusColor(s HealthStatus) *color.Color {
|
||||
var c *color.Color
|
||||
switch s {
|
||||
case StatusHealthy:
|
||||
c = green
|
||||
case StatusUnhealthy:
|
||||
c = red
|
||||
case StatusUnknown:
|
||||
c = yellow
|
||||
case StatusNotFound:
|
||||
c = yellow
|
||||
default:
|
||||
c = red
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
@@ -38,4 +38,3 @@ func printWorkloadList(workloadList []types.Capability, ioStreams cmdutil.IOStre
|
||||
ioStreams.Info(table.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user