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
11 changes: 7 additions & 4 deletions cmd/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,6 @@ overwrite the value in faas.yaml.
func runDelete(cmd *cobra.Command, args []string) (err error) {
config := newDeleteConfig(args).Prompt()

remover := knative.NewRemover(config.Namespace)
remover.Verbose = config.Verbose
remover.Namespace = config.Namespace

function, err := faas.NewFunction(config.Path)
if err != nil {
return
Expand All @@ -56,6 +52,13 @@ func runDelete(cmd *cobra.Command, args []string) (err error) {
return fmt.Errorf("the given path '%v' does not contain an initialized Function.", config.Path)
}

remover, err := knative.NewRemover(config.Namespace)
if err != nil {
return
}

remover.Verbose = config.Verbose

client := faas.New(
faas.WithVerbose(config.Verbose),
faas.WithRemover(remover))
Expand Down
1 change: 0 additions & 1 deletion cmd/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ func runDeploy(cmd *cobra.Command, _ []string) (err error) {
listener := progress.New()

deployer.Verbose = config.Verbose
deployer.Namespace = function.Namespace

client := faas.New(
faas.WithVerbose(config.Verbose),
Expand Down
63 changes: 44 additions & 19 deletions knative/client.go
Original file line number Diff line number Diff line change
@@ -1,43 +1,68 @@
package knative

import (
"bytes"
"fmt"
"io"
"os"
"time"

"k8s.io/client-go/tools/clientcmd"
"knative.dev/client/pkg/kn/commands"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

clienteventingv1beta1 "knative.dev/client/pkg/eventing/v1beta1"
clientservingv1 "knative.dev/client/pkg/serving/v1"
eventingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1beta1"
servingv1 "knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1"
)

const (
DefaultWaitingTimeout = 60 * time.Second
)

func NewClient(namespace string, verbose bool) (clientservingv1.KnServingClient, io.Writer, error) {
func NewServingClient(namespace string) (clientservingv1.KnServingClient, error) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good ! As a future step we might consider to take over those constructors methods to the knative client, too, so that the user doesn't have to specify the config on her own.


p := commands.KnParams{}
p.Initialize()
restConfig, err := getClientConfig().ClientConfig()
if err != nil {
return nil, fmt.Errorf("failed to create new serving client: %v", err)
}

// Capture output in a buffer if verbose is not enabled for output on error.
if verbose {
p.Output = os.Stdout
} else {
p.Output = &bytes.Buffer{}
servingClient, err := servingv1.NewForConfig(restConfig)
if err != nil {
return nil, fmt.Errorf("failed to create new serving client: %v", err)
}

if namespace == "" {
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})
namespace, _, _ = clientConfig.Namespace()
client := clientservingv1.NewKnServingClient(servingClient, namespace)

return client, nil
}

func NewEventingClient(namespace string) (clienteventingv1beta1.KnEventingClient, error) {

restConfig, err := getClientConfig().ClientConfig()
if err != nil {
return nil, fmt.Errorf("failed to create new serving client: %v", err)
}

client, err := p.NewServingClient(namespace)
eventingClient, err := eventingv1beta1.NewForConfig(restConfig)
if err != nil {
return nil, p.Output, fmt.Errorf("failed to create new serving client: %v", err)
return nil, fmt.Errorf("failed to create new eventing client: %v", err)
}

return client, p.Output, nil
client := clienteventingv1beta1.NewKnEventingClient(eventingClient, namespace)

return client, nil
}

func GetNamespace(defaultNamespace string) (namespace string, err error) {
namespace = defaultNamespace

if defaultNamespace == "" {
namespace, _, err = getClientConfig().Namespace()
if err != nil {
return
}
}
return
}

func getClientConfig() clientcmd.ClientConfig {
return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
clientcmd.NewDefaultClientConfigLoadingRules(),
&clientcmd.ConfigOverrides{})
}
48 changes: 13 additions & 35 deletions knative/deployer.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package knative

import (
"bytes"
"fmt"
"strings"
"time"
Expand All @@ -28,83 +27,62 @@ type Deployer struct {

func NewDeployer(namespaceOverride string) (deployer *Deployer, err error) {
deployer = &Deployer{}
_, namespace, err := newClientConfig(namespaceOverride)
namespace, err := GetNamespace(namespaceOverride)
if err != nil {
return
}
deployer.Namespace = namespace
// deployer.client, err = servingv1client.NewForConfig(config)
return
}

func (d *Deployer) Deploy(f faas.Function) (err error) {

// k8s does not support service names with dots. so encode it such that
// www.my-domain,com -> www-my--domain-com
encodedName, err := k8s.ToK8sAllowedName(f.Name)
serviceName, err := k8s.ToK8sAllowedName(f.Name)
if err != nil {
return
}

client, output, err := NewClient(d.Namespace, d.Verbose)
client, err := NewServingClient(d.Namespace)
if err != nil {
return
}

_, err = client.GetService(encodedName)
_, err = client.GetService(serviceName)
if err != nil {
if errors.IsNotFound(err) {

// Let's create a new Service
err := client.CreateService(generateNewService(encodedName, f.Image))
err := client.CreateService(generateNewService(serviceName, f.Image))
if err != nil {
if !d.Verbose {
err = fmt.Errorf("failed to deploy the service: %v.\nStdOut: %s", err, output.(*bytes.Buffer).String())
} else {
err = fmt.Errorf("failed to deploy the service: %v", err)
}
err = fmt.Errorf("knative deployer failed to deploy the service: %v", err)
return err
}

err, _ = client.WaitForService(encodedName, DefaultWaitingTimeout, wait.NoopMessageCallback())
err, _ = client.WaitForService(serviceName, DefaultWaitingTimeout, wait.NoopMessageCallback())
if err != nil {
if !d.Verbose {
err = fmt.Errorf("deployer failed to wait for the service to become ready: %v.\nStdOut: %s", err, output.(*bytes.Buffer).String())
} else {
err = fmt.Errorf("deployer failed to wait for the service to become ready: %v", err)
}
err = fmt.Errorf("knative deployer failed to wait for the service to become ready: %v", err)
return err
}

route, err := client.GetRoute(encodedName)
route, err := client.GetRoute(serviceName)
if err != nil {
if !d.Verbose {
err = fmt.Errorf("deployer failed to get the route: %v.\nStdOut: %s", err, output.(*bytes.Buffer).String())
} else {
err = fmt.Errorf("deployer failed to get the route: %v", err)
}
err = fmt.Errorf("knative deployer failed to get the route: %v", err)
return err
}

fmt.Println("Function deployed on: " + route.Status.URL.String())

} else {
if !d.Verbose {
err = fmt.Errorf("deployer failed to get the service: %v.\nStdOut: %s", err, output.(*bytes.Buffer).String())
} else {
err = fmt.Errorf("deployer failed to get the service: %v", err)
}
err = fmt.Errorf("knative deployer failed to get the service: %v", err)
return err
}
} else {
// Update the existing Service
err = client.UpdateServiceWithRetry(encodedName, updateEnvVars(f.EnvVars), 3)
err = client.UpdateServiceWithRetry(serviceName, updateEnvVars(f.EnvVars), 3)
if err != nil {
if !d.Verbose {
err = fmt.Errorf("deployer failed to update the service: %v.\nStdOut: %s", err, output.(*bytes.Buffer).String())
} else {
err = fmt.Errorf("deployer failed to update the service: %v", err)
}
err = fmt.Errorf("knative deployer failed to update the service: %v", err)
return err
}
}
Expand Down
50 changes: 19 additions & 31 deletions knative/describer.go
Original file line number Diff line number Diff line change
@@ -1,69 +1,57 @@
package knative

import (
"fmt"
"k8s.io/apimachinery/pkg/api/errors"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/rest"
v1 "knative.dev/client/pkg/serving/v1"
"knative.dev/eventing/pkg/apis/eventing/v1beta1"
eventingv1client "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1beta1"
servingv1client "knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1"

"github.com/boson-project/faas"
"github.com/boson-project/faas/k8s"
)

type Describer struct {
Verbose bool
namespace string
servingClient *servingv1client.ServingV1alpha1Client
eventingClient *eventingv1client.EventingV1beta1Client
config *rest.Config
Verbose bool
namespace string
}

func NewDescriber(namespaceOverride string) (describer *Describer, err error) {
describer = &Describer{}
config, namespace, err := newClientConfig(namespaceOverride)
namespace, err := GetNamespace(namespaceOverride)
if err != nil {
return
}
describer.namespace = namespace

describer.servingClient, err = servingv1client.NewForConfig(config)
if err != nil {
return
}
describer.eventingClient, err = eventingv1client.NewForConfig(config)
if err != nil {
return
}
describer.config = config
describer.namespace = namespace
return
}

// Describe by name. Note that the consuming API uses domain style notation, whereas Kubernetes
// restricts to label-syntax, which is thus escaped. Therefore as a knative (kube) implementation
// detal proper full names have to be escaped on the way in and unescaped on the way out. ex:
// www.example-site.com -> www-example--site-com
func (describer *Describer) Describe(name string) (description faas.Description, err error) {

namespace := describer.namespace
servingClient := describer.servingClient
eventingClient := describer.eventingClient
func (d *Describer) Describe(name string) (description faas.Description, err error) {

serviceName, err := k8s.ToK8sAllowedName(name)
if err != nil {
return
}

service, err := servingClient.Services(namespace).Get(serviceName, metav1.GetOptions{})
servingClient, err := NewServingClient(d.namespace)
if err != nil {
return
}

eventingClient, err := NewEventingClient(d.namespace)
if err != nil {
return
}

service, err := servingClient.GetService(serviceName)
if err != nil {
return
}

serviceLabel := fmt.Sprintf("serving.knative.dev/service=%s", serviceName)
routes, err := servingClient.Routes(namespace).List(metav1.ListOptions{LabelSelector: serviceLabel})
routes, err := servingClient.ListRoutes(v1.WithService(serviceName))
if err != nil {
return
}
Expand All @@ -73,7 +61,7 @@ func (describer *Describer) Describe(name string) (description faas.Description,
routeURLs = append(routeURLs, route.Status.URL.String())
}

triggers, err := eventingClient.Triggers(namespace).List(metav1.ListOptions{})
triggers, err := eventingClient.ListTriggers()
// IsNotFound -- Eventing is probably not installed on the cluster
if err != nil && !errors.IsNotFound(err) {
return
Expand Down
39 changes: 15 additions & 24 deletions knative/lister.go
Original file line number Diff line number Diff line change
@@ -1,40 +1,45 @@
package knative

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

"github.com/boson-project/faas/k8s"
)

const labelSelector = "bosonFunction"
const (
labelKey = "bosonFunction"
labelValue = "true"
)

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

func NewLister(namespaceOverride string) (l *Lister, err error) {
l = &Lister{}

config, namespace, err := newClientConfig(namespaceOverride)
namespace, err := GetNamespace(namespaceOverride)
if err != nil {
return
}
l.namespace = namespace
l.client, err = servingv1client.NewForConfig(config)

return
}

func (l *Lister) List() (names []string, err error) {
opts := metav1.ListOptions{LabelSelector: labelSelector}
lst, err := l.client.Services(l.namespace).List(opts)

client, err := NewServingClient(l.namespace)
if err != nil {
return
}

lst, err := client.ListServices(clientservingv1.WithLabel(labelKey, labelValue))
if err != nil {
return
}

for _, service := range lst.Items {
// Convert the "subdomain-encoded" (i.e. kube-service-friendly) name
// back out to a fully qualified service name.
Expand All @@ -46,17 +51,3 @@ func (l *Lister) List() (names []string, err error) {
}
return
}

func newClientConfig(defaultNamespace string) (c *restclient.Config, namespace string, err error) {
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})
namespace = defaultNamespace
if defaultNamespace == "" {
namespace, _, err = clientConfig.Namespace()
if err != nil {
return
}
}
c, err = clientConfig.ClientConfig()
return
}
Loading