Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement namespace support using go-sdk #976

Merged
merged 1 commit into from
Sep 22, 2023
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
31 changes: 31 additions & 0 deletions commands/general.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import (
"crypto/tls"
"net"
"net/http"
"net/url"
"os"
"time"

"github.com/openfaas/faas-cli/proxy"
"github.com/openfaas/go-sdk"
)

var (
Expand Down Expand Up @@ -36,3 +41,29 @@ func GetDefaultCLITransport(tlsInsecure bool, timeout *time.Duration) *http.Tran
}
return nil
}

func GetDefaultSDKClient() (*sdk.Client, error) {
gatewayAddress := getGatewayURL(gateway, defaultGateway, "", os.Getenv(openFaaSURLEnvironment))
gatewayURL, err := url.Parse(gatewayAddress)
if err != nil {
return nil, err
}

transport := GetDefaultCLITransport(tlsInsecure, &commandTimeout)

httpClient := &http.Client{}
httpClient.Timeout = commandTimeout

if transport != nil {
httpClient.Transport = transport
}

clientAuth, err := proxy.NewCLIAuth(token, gateway)
if err != nil {
return nil, err
}

client := sdk.NewClient(gatewayURL, clientAuth, http.DefaultClient)

return client, nil
}
24 changes: 24 additions & 0 deletions commands/namespace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) OpenFaaS Author(s) 2023. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

package commands

import (
"github.com/spf13/cobra"
)

func init() {
// Setup flags that are used by multiple commands (variables defined in faas.go)
namespaceCmd.PersistentFlags().StringVarP(&gateway, "gateway", "g", defaultGateway, "Gateway URL starting with http(s)://")
namespaceCmd.PersistentFlags().BoolVar(&tlsInsecure, "tls-no-verify", false, "Disable TLS validation")
namespaceCmd.PersistentFlags().StringVarP(&token, "token", "k", "", "Pass a JWT token to use instead of basic auth")

faasCmd.AddCommand(namespaceCmd)
}

var namespaceCmd = &cobra.Command{
Use: `namespace [--gateway GATEWAY_URL] [--tls-no-verify] [--token JWT_TOKEN]`,
Aliases: []string{"ns"},
Short: "Manage OpenFaaS namespace",
Long: "Manage OpenFaaS namespace either on local or remote gateway",
}
87 changes: 87 additions & 0 deletions commands/namespace_create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright (c) OpenFaaS Author(s) 2023. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

package commands

import (
"context"
"fmt"

"github.com/openfaas/faas-cli/util"
"github.com/openfaas/faas-provider/types"
"github.com/spf13/cobra"
)

// NamespaceCreateFlags holds flags that are to be added to commands.
type NamespaceCreateFlags struct {
labelOpts []string
annotationOpts []string
}

var namespaceCreateFlags NamespaceCreateFlags

var namespaceCreateCmd = &cobra.Command{
Use: `create NAME
[--label LABEL=VALUE ...]
[--annotation ANNOTATION=VALUE ...]`,
Short: "Create a new namespace",
Long: "Create command creates a new namespace",
Example: `faas-cli namespace create NAME
faas-cli namespace create NAME --label demo=true
faas-cli namespace create NAME --annotation demo=true
faas-cli namespace create NAME --label demo=true \
--annotation demo=true`,
RunE: createNamespace,
PreRunE: preCreateNamespace,
}

func init() {
namespaceCreateCmd.Flags().StringArrayVarP(&namespaceCreateFlags.labelOpts, "label", "l", []string{}, "Set one or more label (LABEL=VALUE)")
namespaceCreateCmd.Flags().StringArrayVarP(&namespaceCreateFlags.annotationOpts, "annotation", "", []string{}, "Set one or more annotation (ANNOTATION=VALUE)")

namespaceCmd.AddCommand(namespaceCreateCmd)
}

func preCreateNamespace(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return fmt.Errorf("namespace name required")
}

if len(args) > 1 {
return fmt.Errorf("too many values for namespace name")
}

return nil
}

func createNamespace(cmd *cobra.Command, args []string) error {
client, err := GetDefaultSDKClient()
if err != nil {
return err
}

labels, err := util.ParseMap(namespaceCreateFlags.labelOpts, "labels")
if err != nil {
return err
}

annotations, err := util.ParseMap(namespaceCreateFlags.annotationOpts, "annotations")
if err != nil {
return err
}

req := types.FunctionNamespace{
Name: args[0],
Labels: labels,
Annotations: annotations,
}

fmt.Printf("Creating Namespace: %s\n", req.Name)
if _, err = client.CreateNamespace(context.Background(), req); err != nil {
return err
}

fmt.Printf("Namespace Created: %s\n", req.Name)

return nil
}
34 changes: 34 additions & 0 deletions commands/namespace_create_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package commands

import "testing"

func Test_preCreateNamespace_NoArgs_Fails(t *testing.T) {
res := preCreateNamespace(nil, []string{})

want := "namespace name required"
if res.Error() != want {
t.Errorf("want %q, got %q", want, res.Error())
}
}

func Test_preCreateNamespace_MoreThan1Arg_Fails(t *testing.T) {
res := preCreateNamespace(nil, []string{
"secret1",
"secret2",
})

want := "too many values for namespace name"
if res.Error() != want {
t.Errorf("want %q, got %q", want, res.Error())
}
}

func Test_preCreateNamespace_ExtactlyOneArgIsFine(t *testing.T) {
res := preCreateNamespace(nil, []string{
"namespace1",
})

if res != nil {
t.Errorf("expected no validation error, but got %q", res.Error())
}
}
54 changes: 54 additions & 0 deletions commands/namespace_delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright (c) OpenFaaS Author(s) 2023. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

package commands

import (
"context"
"fmt"

"github.com/spf13/cobra"
)

var namespaceDeleteCmd = &cobra.Command{
Use: `delete NAME`,
Short: "Delete existing namespace",
Long: "Delete existing namespace",
Example: `faas-cli namespace delete NAME`,
RunE: deleteNamespace,
PreRunE: preDeleteNamespace,
}

func init() {
namespaceCmd.AddCommand(namespaceDeleteCmd)
}

func preDeleteNamespace(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return fmt.Errorf("namespace name required")
}

if len(args) > 1 {
return fmt.Errorf("too many values for namespace name")
}

return nil
}

func deleteNamespace(cmd *cobra.Command, args []string) error {
client, err := GetDefaultSDKClient()
if err != nil {
return err
}

ns := args[0]

fmt.Printf("Deleting Namespace: %s\n", ns)
if err = client.DeleteNamespace(context.Background(), ns); err != nil {
return err
}

fmt.Printf("Namespace Deleted: %s\n", ns)

return nil
}
34 changes: 34 additions & 0 deletions commands/namespace_delete_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package commands

import "testing"

func Test_preDeleteNamespace_NoArgs_Fails(t *testing.T) {
res := preDeleteNamespace(nil, []string{})

want := "namespace name required"
if res.Error() != want {
t.Errorf("want %q, got %q", want, res.Error())
}
}

func Test_preDeleteNamespace_MoreThan1Arg_Fails(t *testing.T) {
res := preDeleteNamespace(nil, []string{
"secret1",
"secret2",
})

want := "too many values for namespace name"
if res.Error() != want {
t.Errorf("want %q, got %q", want, res.Error())
}
}

func Test_preDeleteNamespace_ExtactlyOneArgIsFine(t *testing.T) {
res := preDeleteNamespace(nil, []string{
"namespace1",
})

if res != nil {
t.Errorf("expected no validation error, but got %q", res.Error())
}
}
78 changes: 78 additions & 0 deletions commands/namespace_get.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright (c) OpenFaaS Author(s) 2023. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

package commands

import (
"context"
"fmt"
"io"
"text/tabwriter"

"github.com/openfaas/faas-provider/types"
"github.com/spf13/cobra"
)

var namespaceGetCmd = &cobra.Command{
Use: `get NAMESPACE_NAME`,
Short: "Get existing namespace",
Long: "Get existing namespace",
Example: `faas-cli namespace get NAME`,
RunE: get_namespace,
PreRunE: preGetNamespace,
}

func init() {
namespaceCmd.AddCommand(namespaceGetCmd)
}

func preGetNamespace(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return fmt.Errorf("namespace name required")
}

if len(args) > 1 {
return fmt.Errorf("too many values for namespace name")
}

return nil
}

func get_namespace(cmd *cobra.Command, args []string) error {
client, err := GetDefaultSDKClient()
if err != nil {
return err
}

ns := args[0]

res, err := client.GetNamespace(context.Background(), ns)
if err != nil {
return err
}

printNamespaceDetail(cmd.OutOrStdout(), res)

return nil
}

func printNamespaceDetail(dst io.Writer, nsDetail types.FunctionNamespace) {
w := tabwriter.NewWriter(dst, 0, 0, 1, ' ', tabwriter.TabIndent)
defer w.Flush()

out := printer{
w: w,
verbose: verbose,
}
out.Printf("Name:\t%s\n", nsDetail.Name)
if len(nsDetail.Labels) > 1 {
out.Printf("Labels", nsDetail.Labels)
} else {
out.Printf("Labels", map[string]string{})
}
if len(nsDetail.Annotations) > 1 {
out.Printf("Annotations", nsDetail.Annotations)
} else {
out.Printf("Annotations", map[string]string{})
}
}
34 changes: 34 additions & 0 deletions commands/namespace_get_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package commands

import "testing"

func Test_preGetNamespace_NoArgs_Fails(t *testing.T) {
res := preGetNamespace(nil, []string{})

want := "namespace name required"
if res.Error() != want {
t.Errorf("want %q, got %q", want, res.Error())
}
}

func Test_preGetNamespace_MoreThan1Arg_Fails(t *testing.T) {
res := preGetNamespace(nil, []string{
"secret1",
"secret2",
})

want := "too many values for namespace name"
if res.Error() != want {
t.Errorf("want %q, got %q", want, res.Error())
}
}

func Test_preGetNamespace_ExtactlyOneArgIsFine(t *testing.T) {
res := preGetNamespace(nil, []string{
"namespace1",
})

if res != nil {
t.Errorf("expected no validation error, but got %q", res.Error())
}
}
Loading