mirror of https://github.com/knative/func.git
feat: 'describe' sub-command for faas cli
This commit is contained in:
parent
130751b01e
commit
380cc2f3ef
|
@ -32,6 +32,7 @@ type Client struct {
|
|||
runner Runner // Runs the function locally
|
||||
remover Remover // Removes remote services
|
||||
lister Lister // Lists remote services
|
||||
describer Describer
|
||||
}
|
||||
|
||||
// ConfigFileName is an optional file checked for in the function root.
|
||||
|
@ -105,6 +106,22 @@ type Lister interface {
|
|||
List() ([]string, error)
|
||||
}
|
||||
|
||||
type Subscription struct {
|
||||
Source string `json:"source" yaml:"source"`
|
||||
Type string `json:"type" yaml:"type"`
|
||||
Broker string `json:"broker" yaml:"broker"`
|
||||
}
|
||||
|
||||
type FunctionDescription struct {
|
||||
Name string `json:"name" yaml:"name"`
|
||||
Routes []string `json:"routes" yaml:"routes"`
|
||||
Subscriptions []Subscription `json:"subscriptions" yaml:"subscriptions"`
|
||||
}
|
||||
|
||||
type Describer interface {
|
||||
Describe(name string) (description FunctionDescription, err error)
|
||||
}
|
||||
|
||||
// Option defines a function which when passed to the Client constructor optionally
|
||||
// mutates private members at time of instantiation.
|
||||
type Option func(*Client)
|
||||
|
@ -199,6 +216,12 @@ func WithLister(l Lister) Option {
|
|||
}
|
||||
}
|
||||
|
||||
func WithDescriber(describer Describer) Option {
|
||||
return func(c *Client) {
|
||||
c.describer = describer
|
||||
}
|
||||
}
|
||||
|
||||
// New client for a function service rooted at the given directory (default .) or
|
||||
// that explicitly set via the option. Will fail if the directory already contains
|
||||
// config files or other non-hidden files.
|
||||
|
@ -370,6 +393,10 @@ func (c *Client) List() ([]string, error) {
|
|||
return c.lister.List()
|
||||
}
|
||||
|
||||
func (c *Client) Describe(name string) (FunctionDescription, error) {
|
||||
return c.describer.Describe(name)
|
||||
}
|
||||
|
||||
// Remove a function from remote, bringing the service funciton
|
||||
// to the same state as if it had been created --local only.
|
||||
// Name is the presently configured client's name, which was
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/boson-project/faas/client"
|
||||
"github.com/boson-project/faas/knative"
|
||||
"github.com/ory/viper"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
root.AddCommand(describeCmd)
|
||||
|
||||
describeCmd.Flags().StringP("output", "o", "yaml", "optionally specify output format (yaml,xml,json).")
|
||||
viper.BindPFlag("output", describeCmd.Flags().Lookup("output"))
|
||||
}
|
||||
|
||||
var describeCmd = &cobra.Command{
|
||||
Use: "describe",
|
||||
Short: "Describe Service Function",
|
||||
Long: `Describe Service Function`,
|
||||
SuggestFor: []string{"desc"},
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: describe,
|
||||
}
|
||||
|
||||
func describe(cmd *cobra.Command, args []string) (err error) {
|
||||
var (
|
||||
verbose = viper.GetBool("verbose")
|
||||
format = viper.GetString("output")
|
||||
)
|
||||
name := args[0]
|
||||
|
||||
describer, err := knative.NewDescriber(client.FaasNamespace)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
describer.Verbose = verbose
|
||||
|
||||
client, err := client.New(".",
|
||||
client.WithVerbose(verbose),
|
||||
client.WithDescriber(describer),
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
description, err := client.Describe(name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
formatFunctions := map[string] func(interface{})([]byte, error) {
|
||||
"json" : json.Marshal,
|
||||
"yaml" : yaml.Marshal,
|
||||
"xml" : xml.Marshal,
|
||||
}
|
||||
|
||||
formatFun, found := formatFunctions[format]
|
||||
if !found {
|
||||
return errors.New("unknown output format")
|
||||
}
|
||||
data, err := formatFun(description)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fmt.Println(string(data))
|
||||
|
||||
return
|
||||
}
|
|
@ -9,14 +9,8 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
nsFlag = "namespace"
|
||||
)
|
||||
|
||||
func init() {
|
||||
root.AddCommand(listCmd)
|
||||
listCmd.Flags().StringP(nsFlag, "n", "", "optionally specify a namespace")
|
||||
viper.BindPFlag(nsFlag, listCmd.Flags().Lookup(nsFlag))
|
||||
}
|
||||
|
||||
var listCmd = &cobra.Command{
|
||||
|
@ -29,11 +23,10 @@ var listCmd = &cobra.Command{
|
|||
|
||||
func list(cmd *cobra.Command, args []string) (err error) {
|
||||
var (
|
||||
namespace = viper.GetString(nsFlag)
|
||||
verbose = viper.GetBool("verbose")
|
||||
)
|
||||
|
||||
lister, err := knative.NewLister(namespace)
|
||||
lister, err := knative.NewLister(client.FaasNamespace)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
2
go.mod
2
go.mod
|
@ -9,12 +9,14 @@ require (
|
|||
github.com/google/go-containerregistry v0.0.0-20200423114255-8f808463544c // indirect
|
||||
github.com/openzipkin/zipkin-go v0.2.2 // indirect
|
||||
github.com/ory/viper v1.7.4
|
||||
github.com/robfig/cron v1.2.0 // indirect
|
||||
github.com/spf13/cobra v1.0.0
|
||||
golang.org/x/net v0.0.0-20200421231249-e086a090c8fd
|
||||
gomodules.xyz/jsonpatch/v2 v2.1.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.8
|
||||
k8s.io/apimachinery v0.17.4
|
||||
k8s.io/client-go v0.17.4
|
||||
knative.dev/eventing v0.14.1
|
||||
knative.dev/pkg v0.0.0-20200414233146-0eed424fa4ee // indirect
|
||||
knative.dev/serving v0.14.0
|
||||
)
|
||||
|
|
6
go.sum
6
go.sum
|
@ -320,6 +320,8 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT
|
|||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
|
||||
github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
|
||||
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto=
|
||||
|
@ -581,8 +583,6 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
@ -612,6 +612,8 @@ k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKf
|
|||
k8s.io/legacy-cloud-providers v0.17.4/go.mod h1:FikRNoD64ECjkxO36gkDgJeiQWwyZTuBkhu+yxOc1Js=
|
||||
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo=
|
||||
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
knative.dev/eventing v0.14.1 h1:YmnEl3IBVRkBcVYWPMWZegRGifeI7ibcA9xuhHWvAaw=
|
||||
knative.dev/eventing v0.14.1/go.mod h1:UxweNv8yXhsdHJitcb9R6rmfNaUD2DFi9GWwNRyIs58=
|
||||
knative.dev/pkg v0.0.0-20200414233146-0eed424fa4ee h1:G1QedLB/RxF4QTyL1Pq9M1QK1uj8khQgTypofUXrG20=
|
||||
knative.dev/pkg v0.0.0-20200414233146-0eed424fa4ee/go.mod h1:pgODObA1dTyhNoFxPZTTjNWfx6F0aKsKzn+vaT9XO/Q=
|
||||
knative.dev/serving v0.14.0 h1:9iDyOqTciNuAh2D5KJP0soOq23FDR4HQHdIQNBQ/rAE=
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
package knative
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/boson-project/faas/client"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"knative.dev/eventing/pkg/apis/eventing/v1alpha1"
|
||||
eventingv1client "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1alpha1"
|
||||
servingv1client "knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1"
|
||||
)
|
||||
|
||||
type Describer struct {
|
||||
Verbose bool
|
||||
namespace string
|
||||
servingClient *servingv1client.ServingV1alpha1Client
|
||||
eventingClient *eventingv1client.EventingV1alpha1Client
|
||||
config *rest.Config
|
||||
}
|
||||
|
||||
func NewDescriber(namespace string) (describer *Describer, err error) {
|
||||
describer = &Describer{namespace: namespace}
|
||||
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
|
||||
clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})
|
||||
if describer.namespace == "" {
|
||||
namespace, _, err := clientConfig.Namespace()
|
||||
if err == nil {
|
||||
describer.namespace = namespace
|
||||
}
|
||||
}
|
||||
config, err := clientConfig.ClientConfig()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
describer.servingClient, err = servingv1client.NewForConfig(config)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
describer.eventingClient, err = eventingv1client.NewForConfig(config)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
describer.config = config
|
||||
return
|
||||
}
|
||||
|
||||
func (describer *Describer) Describe(name string) (description client.FunctionDescription, err error) {
|
||||
|
||||
namespace := describer.namespace
|
||||
servingClient := describer.servingClient
|
||||
eventingClient := describer.eventingClient
|
||||
|
||||
service, err := servingClient.Services(namespace).Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
serviceLabel := fmt.Sprintf("serving.knative.dev/service=%s", name)
|
||||
routes, err := servingClient.Routes(namespace).List(metav1.ListOptions{LabelSelector: serviceLabel})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
routeURLs := make([]string, 0, len(routes.Items))
|
||||
for _, route := range routes.Items {
|
||||
routeURLs = append(routeURLs, route.Status.URL.String())
|
||||
}
|
||||
|
||||
triggers, err := eventingClient.Triggers(namespace).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
triggerMatches := func(t *v1alpha1.Trigger) bool {
|
||||
return (t.Spec.Subscriber.Ref != nil && t.Spec.Subscriber.Ref.Name == service.Name) ||
|
||||
(t.Spec.Subscriber.URI != nil && service.Status.Address != nil && service.Status.Address.URL != nil &&
|
||||
t.Spec.Subscriber.URI.Path == service.Status.Address.URL.Path)
|
||||
|
||||
}
|
||||
|
||||
subscriptions := make([]client.Subscription, 0, len(triggers.Items))
|
||||
for _, trigger := range triggers.Items {
|
||||
if triggerMatches(&trigger) {
|
||||
filterAttrs := *trigger.Spec.Filter.Attributes
|
||||
subscription := client.Subscription{
|
||||
Source: filterAttrs["source"],
|
||||
Type: filterAttrs["type"],
|
||||
Broker: trigger.Spec.Broker,
|
||||
}
|
||||
subscriptions = append(subscriptions, subscription)
|
||||
}
|
||||
}
|
||||
|
||||
description.Name = service.Name
|
||||
description.Routes = routeURLs
|
||||
description.Subscriptions = subscriptions
|
||||
|
||||
return
|
||||
}
|
Loading…
Reference in New Issue