feat: list command - improved output (#205)

Signed-off-by: Zbynek Roubalik <zroubali@redhat.com>
This commit is contained in:
Zbynek Roubalik 2020-11-04 13:15:06 +01:00 committed by GitHub
parent 745640d9b4
commit 29ca07768c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 70 additions and 29 deletions

View File

@ -67,7 +67,15 @@ type Remover interface {
// Lister of deployed services. // Lister of deployed services.
type Lister interface { type Lister interface {
// List the Functions currently deployed. // List the Functions currently deployed.
List() ([]string, error) List() ([]ListItem, error)
}
type ListItem struct {
Name string `json:"name" yaml:"name"`
Runtime string `json:"runtime" yaml:"runtime"`
URL string `json:"url" yaml:"url"`
KService string `json:"kservice" yaml:"kservice"`
Ready string `json:"ready" yaml:"ready"`
} }
// ProgressListener is notified of task progress. // ProgressListener is notified of task progress.
@ -476,7 +484,7 @@ func (c *Client) Run(root string) error {
} }
// List currently deployed Functions. // List currently deployed Functions.
func (c *Client) List() ([]string, error) { func (c *Client) List() ([]ListItem, error) {
// delegate to concrete implementation of lister entirely. // delegate to concrete implementation of lister entirely.
return c.lister.List() return c.lister.List()
} }
@ -549,7 +557,7 @@ func (n *noopRemover) Remove(string) error { return nil }
type noopLister struct{ output io.Writer } type noopLister struct{ output io.Writer }
func (n *noopLister) List() ([]string, error) { return []string{}, nil } func (n *noopLister) List() ([]ListItem, error) { return []ListItem{}, nil }
type noopDNSProvider struct{ output io.Writer } type noopDNSProvider struct{ output io.Writer }

View File

@ -18,12 +18,15 @@ func CompleteFunctionList(cmd *cobra.Command, args []string, toComplete string)
directive = cobra.ShellCompDirectiveError directive = cobra.ShellCompDirectiveError
return return
} }
s, err := lister.List() list, err := lister.List()
if err != nil { if err != nil {
directive = cobra.ShellCompDirectiveError directive = cobra.ShellCompDirectiveError
return return
} }
strings = s
for _, item := range list{
strings = append(strings, item.Name)
}
directive = cobra.ShellCompDirectiveDefault directive = cobra.ShellCompDirectiveDefault
return return
} }

View File

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"io" "io"
"os" "os"
"text/tabwriter"
"github.com/ory/viper" "github.com/ory/viper"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -54,12 +55,13 @@ func runList(cmd *cobra.Command, args []string) (err error) {
faas.WithVerbose(config.Verbose), faas.WithVerbose(config.Verbose),
faas.WithLister(lister)) faas.WithLister(lister))
nn, err := client.List() items, err := client.List()
if err != nil { if err != nil {
return return
} }
write(os.Stdout, names(nn), config.Format) write(os.Stdout, listItems(items), config.Format)
return return
} }
@ -83,30 +85,33 @@ func newListConfig() listConfig {
// Output Formatting (serializers) // Output Formatting (serializers)
// ------------------------------- // -------------------------------
type names []string type listItems []faas.ListItem
func (nn names) Human(w io.Writer) error { func (items listItems) Human(w io.Writer) error {
return nn.Plain(w) return items.Plain(w)
} }
func (nn names) Plain(w io.Writer) error { func (items listItems) Plain(w io.Writer) error {
for _, name := range nn {
fmt.Fprintln(w, name) // minwidth, tabwidth, padding, padchar, flags
tabWriter := tabwriter.NewWriter(w, 0, 8, 2, ' ', 0)
defer tabWriter.Flush()
fmt.Fprintf(tabWriter, "%s\t%s\t%s\t%s\t%s\n", "NAME", "RUNTIME", "URL", "KSERVICE", "READY")
for _, item := range items {
fmt.Fprintf(tabWriter, "%s\t%s\t%s\t%s\t%s\n", item.Name, item.Runtime, item.URL, item.KService, item.Ready)
} }
return nil return nil
} }
func (nn names) JSON(w io.Writer) error { func (items listItems) JSON(w io.Writer) error {
return json.NewEncoder(w).Encode(nn) return json.NewEncoder(w).Encode(items)
} }
func (nn names) XML(w io.Writer) error { func (items listItems) XML(w io.Writer) error {
return xml.NewEncoder(w).Encode(nn) return xml.NewEncoder(w).Encode(items)
} }
func (nn names) YAML(w io.Writer) error { func (items listItems) YAML(w io.Writer) error {
// the yaml.v2 package refuses to directly serialize a []string unless return yaml.NewEncoder(w).Encode(items)
// exposed as a public struct member; so an inline anonymous is used.
ff := struct{ Names []string }{nn}
return yaml.NewEncoder(w).Encode(ff.Names)
} }

1
go.mod
View File

@ -15,6 +15,7 @@ require (
k8s.io/client-go v11.0.1-0.20190805182717-6502b5e7b1b5+incompatible k8s.io/client-go v11.0.1-0.20190805182717-6502b5e7b1b5+incompatible
knative.dev/client v0.17.2 knative.dev/client v0.17.2
knative.dev/eventing v0.17.5 knative.dev/eventing v0.17.5
knative.dev/pkg v0.0.0-20200831162708-14fb2347fb77
knative.dev/serving v0.17.3 knative.dev/serving v0.17.3
) )

View File

@ -1,8 +1,11 @@
package knative package knative
import ( import (
corev1 "k8s.io/api/core/v1"
clientservingv1 "knative.dev/client/pkg/serving/v1" clientservingv1 "knative.dev/client/pkg/serving/v1"
"knative.dev/pkg/apis"
"github.com/boson-project/faas"
"github.com/boson-project/faas/k8s" "github.com/boson-project/faas/k8s"
) )
@ -28,7 +31,7 @@ func NewLister(namespaceOverride string) (l *Lister, err error) {
return return
} }
func (l *Lister) List() (names []string, err error) { func (l *Lister) List() (items []faas.ListItem, err error) {
client, err := NewServingClient(l.namespace) client, err := NewServingClient(l.namespace)
if err != nil { if err != nil {
@ -41,13 +44,32 @@ func (l *Lister) List() (names []string, err error) {
} }
for _, service := range lst.Items { for _, service := range lst.Items {
// Convert the "subdomain-encoded" (i.e. kube-service-friendly) name // Convert the "subdomain-encoded" (i.e. kube-service-friendly) name
// back out to a fully qualified service name. // back out to a fully qualified service name.
n, err := k8s.FromK8sAllowedName(service.Name) name, err := k8s.FromK8sAllowedName(service.Name)
if err != nil { if err != nil {
return names, err return items, err
} }
names = append(names, n)
// get status
ready := corev1.ConditionUnknown
for _, con := range service.Status.Conditions {
if con.Type == apis.ConditionReady {
ready = con.Status
break
}
}
listItem := faas.ListItem{
Name: name,
Runtime: service.Labels["boson.dev/runtime"],
KService: service.Name,
URL: service.Status.URL.String(),
Ready: string(ready),
}
items = append(items, listItem)
} }
return return
} }

View File

@ -1,17 +1,19 @@
package mock package mock
import "github.com/boson-project/faas"
type Lister struct { type Lister struct {
ListInvoked bool ListInvoked bool
ListFn func() ([]string, error) ListFn func() ([]faas.ListItem, error)
} }
func NewLister() *Lister { func NewLister() *Lister {
return &Lister{ return &Lister{
ListFn: func() ([]string, error) { return []string{}, nil }, ListFn: func() ([]faas.ListItem, error) { return []faas.ListItem{}, nil },
} }
} }
func (l *Lister) List() ([]string, error) { func (l *Lister) List() ([]faas.ListItem, error) {
l.ListInvoked = true l.ListInvoked = true
return l.ListFn() return l.ListFn()
} }