Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"strings"

"golang.org/x/net/publicsuffix"
"gopkg.in/yaml.v3"
"gopkg.in/yaml.v2"
)

// Client for a given Service Function.
Expand All @@ -28,6 +28,7 @@ type Client struct {
updater Updater // Updates a deployed Service Function
runner Runner // Runs the function locally
remover Remover // Removes remote services
lister Lister // Lists remote services
}

// ConfigFileName is an optional file checked for in the function root.
Expand Down Expand Up @@ -95,6 +96,12 @@ type Remover interface {
Remove(name string) error
}

// Lister of deployed services.
type Lister interface {
// List the service functions currently deployed.
List() ([]string, error)
}

// Option defines a function which when passed to the Client constructor optionally
// mutates private members at time of instantiation.
type Option func(*Client)
Expand Down Expand Up @@ -182,6 +189,13 @@ func WithRemover(r Remover) Option {
}
}

// WithLister provides the concrete implementation of a lister.
func WithLister(l Lister) Option {
return func(c *Client) {
c.lister = l
}
}

// 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.
Expand Down Expand Up @@ -341,6 +355,12 @@ func (c *Client) Run() error {
return c.runner.Run(c.root)
}

// List currently deployed service functions.
func (c *Client) List() ([]string, error) {
// delegate to concrete implementation of lister entirely.
return c.lister.List()
}

// 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
Expand Down
53 changes: 21 additions & 32 deletions client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -483,38 +483,6 @@ func TestRemove(t *testing.T) {
}
}

// TestRemoveExplicit ensures that a call to remove an explicit name, which
// may differ from the service function the client is associated wtith, is
// respected and passed along to the concrete remover implementation.
func TestRemoveExplicit(t *testing.T) {
var (
root = "./testdata/example.com/admin"
name = "www.example.com" // Differs from that derived from root.
remover = mock.NewRemover()
)

// Create the test function root
os.MkdirAll(root, 0700)
defer os.RemoveAll(root)

client, err := client.New(root,
client.WithRemover(remover))
if err != nil {
t.Fatal(err)
}
remover.RemoveFn = func(name2 string) error {
if name2 != name {
t.Fatalf("remover expected name '%v' got '%v'", name, name2)
}
return nil
}
// Call remove with an explicit name which differs from that associated
// to the current client instance.
if err := client.Remove(name); err != nil {
t.Fatal(err)
}
}

// TestWithName ensures that an explicitly passed name is used in leau of the
// path derived name when provide, and persists through instantiations.
// This also ensures that an initialized service function's name persists if
Expand Down Expand Up @@ -570,3 +538,24 @@ func TestWithName(t *testing.T) {
}

}

// TestList ensures that the client invokes the configured lister.
func TestList(t *testing.T) {
var lister = mock.NewLister()

client, err := client.New("",
client.WithLister(lister), // lists deployed service functions.
)
if err != nil {
t.Fatal(err)
}

_, err = client.List()
if err != nil {
t.Fatal(err)
}

if !lister.ListInvoked {
t.Fatal("list did not invoke lister implementation")
}
}
17 changes: 17 additions & 0 deletions client/mock/lister.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package mock

type Lister struct {
ListInvoked bool
ListFn func() ([]string, error)
}

func NewLister() *Lister {
return &Lister{
ListFn: func() ([]string, error) { return []string{}, nil },
}
}

func (l *Lister) List() ([]string, error) {
l.ListInvoked = true
return l.ListFn()
}
37 changes: 22 additions & 15 deletions cmd/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ package cmd

import (
"fmt"

"github.com/lkingland/faas/client"
"github.com/lkingland/faas/knative"
"github.com/ory/viper"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/clientcmd"
servingv1client "knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1"
)

const (
Expand All @@ -21,31 +21,38 @@ func init() {

var listCmd = &cobra.Command{
Use: "list",
Short: "Lists deployed Service Function",
Long: `Lists deployed Service Function`,
Short: "Lists deployed Service Functions",
Long: `Lists deployed Service Functions`,
SuggestFor: []string{"ls"},
RunE: list,
}

func list(cmd *cobra.Command, args []string) (err error) {
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})
config, err := clientConfig.ClientConfig()
var (
namespace = viper.GetString(nsFlag)
verbose = viper.GetBool("verbose")
)

lister, err := knative.NewLister(namespace)
if err != nil {
return
}
client, err := servingv1client.NewForConfig(config)
lister.Verbose = verbose

client, err := client.New(".",
client.WithVerbose(verbose),
client.WithLister(lister),
)
if err != nil {
return
}
opts := metav1.ListOptions{LabelSelector: "bosonFunction"}
ns := viper.GetString(nsFlag)
lst, err := client.Services(ns).List(opts)

names, err := client.List()
if err != nil {
return
}
for _, service := range lst.Items {
fmt.Printf("%s/%s", service.Namespace, service.Name)
for _, name := range names {
fmt.Printf("%s\n", name)
}
return nil
return
}
2 changes: 1 addition & 1 deletion cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (

// Version
// Printed on subcommand `version` or flag `--version`
const Version = "v0.0.14"
const Version = "v0.0.15"

func init() {
root.AddCommand(versionCmd)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ require (
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.v3 v3.0.0-20200313102051-9f266ea9e77c
gopkg.in/yaml.v2 v2.2.8
k8s.io/apimachinery v0.17.4
k8s.io/client-go v0.17.4
knative.dev/pkg v0.0.0-20200414233146-0eed424fa4ee // indirect
Expand Down
42 changes: 42 additions & 0 deletions knative/lister.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package knative

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/clientcmd"
servingv1client "knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1"
)

const labelSelector = "bosonFunction"

type Lister struct {
Verbose bool
namespace string
client *servingv1client.ServingV1Client
}

func NewLister(namespace string) (l *Lister, err error) {
l = &Lister{}
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})
config, err := clientConfig.ClientConfig()
if err != nil {
return
}
l.client, err = servingv1client.NewForConfig(config)
if err != nil {
return
}
return
}

func (l *Lister) List() (names []string, err error) {
opts := metav1.ListOptions{LabelSelector: "bosonFunction"}
lst, err := l.client.Services(l.namespace).List(opts)
if err != nil {
return
}
for _, service := range lst.Items {
names = append(names, service.Name)
}
return
}