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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ $ uname -a | curl http://127.0.0.1:8080/function/nodejs-echo--data-binary @-
* `OPENFAAS_TEMPLATE_URL` - to set the default URL to pull templates from
* `OPENFAAS_PREFIX` - for use with `faas-cli new` - this can act in place of `--prefix`
* `OPENFAAS_URL` - to override the default gateway URL
* `OPENFAAS_NS` - to set the default function namespace
* `OPENFAAS_REMOTE_BUILDER` - default value for `--remote-builder`
* `OPENFAAS_PAYLOAD_SECRET` - default value for `--payload-secret`
* `OPENFAAS_BUILDER_PUBLIC_KEY` - builder public key as a literal value, or a path to a file containing raw base64 or the JSON response from `/public-key`
Expand Down
4 changes: 2 additions & 2 deletions commands/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ func runDeployCommand(args []string, image string, fprocess string, functionName

// Check if there is a functionNamespace flag passed, if so, override the namespace value
// defined in the stack.yaml
function.Namespace = getNamespace(functionNamespace, function.Namespace)
function.Namespace = getNamespace(functionNamespace, function.Namespace, os.Getenv(openFaaSNamespaceEnvironment))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't think I would have added os.Getenv(openFaaSNamespaceEnvironment) to every callsight - given it's consistent I would have perhaps not even have changed the signature at all and have had it self-contained.

Go unit tests can setenv dynamically when needed.


fileEnvironment, err := readFiles(function.EnvironmentFile)
if err != nil {
Expand Down Expand Up @@ -319,7 +319,7 @@ Error: %s`, fprocessErr.Error())
tlsInsecure,
defaultReadOnlyRFS,
token,
functionNamespace,
getNamespace(functionNamespace, "", os.Getenv(openFaaSNamespaceEnvironment)),
cpuRequest,
cpuLimit,
memoryRequest,
Expand Down
7 changes: 4 additions & 3 deletions commands/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,15 @@ func runDescribe(cmd *cobra.Command, args []string) error {
}

ctx := context.Background()
namespace := getNamespace(functionNamespace, "", os.Getenv(openFaaSNamespaceEnvironment))

function, err := cliClient.GetFunctionInfo(ctx, functionName, functionNamespace)
function, err := cliClient.GetFunctionInfo(ctx, functionName, namespace)
if err != nil {
return err
}

//To get correct value for invocation count from /system/functions endpoint
functionList, err := cliClient.ListFunctions(ctx, functionNamespace)
functionList, err := cliClient.ListFunctions(ctx, namespace)
if err != nil {
return err
}
Expand All @@ -108,7 +109,7 @@ func runDescribe(cmd *cobra.Command, args []string) error {
status = "Ready"
}

url, asyncURL := getFunctionURLs(gatewayAddress, functionName, functionNamespace)
url, asyncURL := getFunctionURLs(gatewayAddress, functionName, namespace)

funcDesc := schema.FunctionDescription{
FunctionStatus: function,
Expand Down
73 changes: 44 additions & 29 deletions commands/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,16 +94,11 @@ func runDiff(cmd *cobra.Command, args []string) error {
return err
}

functions, err := proxyClient.ListFunctions(context.Background(), functionNamespace)
if err != nil {
return err
}

yamlFns := parsedServices.Functions

yamlMap := make(map[string]funcDiff)
for name, fn := range yamlFns {
key := diffKey(name, namespaceForDiffKey(functionNamespace, fn.Namespace))
key := diffKey(name, getNamespace(functionNamespace, fn.Namespace, os.Getenv(openFaaSNamespaceEnvironment)))

imageName, err := buildDiffImageName(fn.Image, fn.Handler, tagFormat)
if err != nil {
Expand All @@ -129,27 +124,19 @@ func runDiff(cmd *cobra.Command, args []string) error {
}

deployedMap := make(map[string]funcDiff)
for _, fn := range functions {
envMap := fn.EnvVars
if envMap == nil {
envMap = make(map[string]string)
ctx := context.Background()
for _, namespace := range namespacesForDiff(functionNamespace, parsedServices.Functions, os.Getenv(openFaaSNamespaceEnvironment)) {
deployed, err := proxyClient.ListFunctions(ctx, namespace)
if err != nil {
return err
}

fnDiff := funcDiff{
Image: fn.Image,
FProcess: fn.EnvProcess,
Env: envMap,
Secrets: fn.Secrets,
Constraints: fn.Constraints,
Labels: mapFromPtr(fn.Labels),
Annotations: mapFromPtr(fn.Annotations),
Limits: resourcesFromStatus(fn.Limits),
Requests: resourcesFromStatus(fn.Requests),
ReadOnlyRootFilesystem: fn.ReadOnlyRootFilesystem,
}
deployedMap[diffKey(fn.Name, "")] = fnDiff
if fn.Namespace != "" {
deployedMap[diffKey(fn.Name, fn.Namespace)] = fnDiff
for _, fn := range deployed {
key := diffKey(fn.Name, namespace)
if _, ok := yamlMap[key]; !ok {
continue
}
deployedMap[key] = functionStatusToDiff(fn)
}
}

Expand Down Expand Up @@ -177,6 +164,26 @@ func runDiff(cmd *cobra.Command, args []string) error {
return fmt.Errorf("differences found")
}

func functionStatusToDiff(fn types.FunctionStatus) funcDiff {
env := fn.EnvVars
if env == nil {
env = make(map[string]string)
}

return funcDiff{
Image: fn.Image,
FProcess: fn.EnvProcess,
Env: env,
Secrets: fn.Secrets,
Constraints: fn.Constraints,
Labels: mapFromPtr(fn.Labels),
Annotations: mapFromPtr(fn.Annotations),
Limits: resourcesFromStatus(fn.Limits),
Requests: resourcesFromStatus(fn.Requests),
ReadOnlyRootFilesystem: fn.ReadOnlyRootFilesystem,
}
}

func buildDiffImageName(image string, handler string, tagMode schema.BuildFormat) (string, error) {
branch, version, err := builder.GetImageTagValues(tagMode, handler)
if err != nil {
Expand Down Expand Up @@ -434,11 +441,19 @@ func sortedAttrKeys(m map[string]string) []string {
return keys
}

func namespaceForDiffKey(flagNamespace string, stackNamespace string) string {
if flagNamespace != "" {
return flagNamespace
func namespacesForDiff(flagNamespace string, functions map[string]stack.Function, environmentNamespace string) []string {
namespaces := map[string]struct{}{}
for _, function := range functions {
namespace := getNamespace(flagNamespace, function.Namespace, environmentNamespace)
namespaces[namespace] = struct{}{}
}

result := make([]string, 0, len(namespaces))
for namespace := range namespaces {
result = append(result, namespace)
}
return stackNamespace
sort.Strings(result)
return result
}

func diffKey(name string, namespace string) string {
Expand Down
120 changes: 120 additions & 0 deletions commands/diff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import (
"net/http"
"os"
"path/filepath"
"reflect"
"strings"
"testing"

"github.com/openfaas/faas-cli/builder"
"github.com/openfaas/faas-cli/schema"
"github.com/openfaas/faas-cli/test"
types "github.com/openfaas/faas-provider/types"
"github.com/openfaas/go-sdk/stack"
)

func Test_diff_no_changes(t *testing.T) {
Expand Down Expand Up @@ -126,6 +128,124 @@ functions:
}
}

func TestNamespacesForDiffPrecedence(t *testing.T) {
functions := map[string]stack.Function{
"first": {Namespace: "stack-a"},
"second": {Namespace: "stack-b"},
"third": {},
}

got := namespacesForDiff("", functions, "environment")
want := []string{"environment", "stack-a", "stack-b"}
if !reflect.DeepEqual(got, want) {
t.Fatalf("want namespaces %v, got %v", want, got)
}

got = namespacesForDiff("flag", functions, "environment")
want = []string{"flag"}
if !reflect.DeepEqual(got, want) {
t.Fatalf("want flag namespace %v, got %v", want, got)
}
}

func TestDiffDoesNotMatchDefaultFunctionFromAnotherNamespace(t *testing.T) {
t.Setenv(openFaaSNamespaceEnvironment, "")
yamlPath := filepath.Join(t.TempDir(), "stack.yaml")
yamlContent := `version: 1.0
provider:
name: openfaas
gateway: http://127.0.0.1:8080
functions:
echo:
image: ttl.sh/test/echo:latest
worker:
image: ttl.sh/test/worker:latest
namespace: team-a
`
if err := os.WriteFile(yamlPath, []byte(yamlContent), 0o600); err != nil {
t.Fatal(err)
}

s := test.MockHttpServer(t, []test.Request{
{
Method: http.MethodGet,
Uri: "/system/functions",
ResponseStatusCode: http.StatusOK,
ResponseBody: []types.FunctionStatus{},
},
{
Method: http.MethodGet,
Uri: "/system/functions?namespace=team-a",
ResponseStatusCode: http.StatusOK,
ResponseBody: []types.FunctionStatus{
{Name: "echo", Namespace: "team-a", Image: "ttl.sh/test/echo:latest"},
{Name: "worker", Namespace: "team-a", Image: "ttl.sh/test/worker:latest"},
},
},
})
defer s.Close()

resetForTest()
var executeErr error
stdOut := test.CaptureStdout(func() {
faasCmd.SetArgs([]string{"diff", "--yaml", yamlPath, "--gateway", s.URL})
executeErr = faasCmd.Execute()
})

if executeErr == nil || !strings.Contains(executeErr.Error(), "differences found") {
t.Fatalf("want missing default function to produce a difference, got: %v", executeErr)
}
if !strings.Contains(stdOut, "echo") || !strings.Contains(stdOut, "not deployed") {
t.Fatalf("want default namespace echo to be reported as not deployed, got:\n%s", stdOut)
}
if strings.Contains(stdOut, "worker.team-a") {
t.Fatalf("want matching namespaced worker to be omitted from diff, got:\n%s", stdOut)
}
}

func TestDiffUsesQueriedNamespaceWhenStatusOmitsNamespace(t *testing.T) {
t.Setenv(openFaaSNamespaceEnvironment, "")
yamlPath := filepath.Join(t.TempDir(), "stack.yaml")
yamlContent := `version: 1.0
provider:
name: openfaas
gateway: http://127.0.0.1:8080
functions:
worker:
image: ttl.sh/test/worker:latest
namespace: team-a
`
if err := os.WriteFile(yamlPath, []byte(yamlContent), 0o600); err != nil {
t.Fatal(err)
}

s := test.MockHttpServer(t, []test.Request{
{
Method: http.MethodGet,
Uri: "/system/functions?namespace=team-a",
ResponseStatusCode: http.StatusOK,
ResponseBody: []types.FunctionStatus{
{Name: "worker", Image: "ttl.sh/test/worker:latest"},
},
},
})
defer s.Close()

resetForTest()
var executeErr error
stdOut := test.CaptureStdout(func() {
faasCmd.SetArgs([]string{"diff", "--yaml", yamlPath, "--gateway", s.URL})
executeErr = faasCmd.Execute()
})

if executeErr != nil {
t.Fatalf("want queried namespace to match stack function, got: %v\n%s", executeErr, stdOut)
}
if !strings.Contains(stdOut, "no differences found") {
t.Fatalf("want no differences, got:\n%s", stdOut)
}
}

func Test_diff_image_changed(t *testing.T) {
tmpDir := t.TempDir()
yamlPath := filepath.Join(tmpDir, "stack.yaml")
Expand Down
4 changes: 2 additions & 2 deletions commands/invoke.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func runInvoke(cmd *cobra.Command, args []string) error {
}
}
}
functionNamespace = getNamespace(functionInvokeNamespace, stackNamespace)
functionNamespace = getNamespace(functionInvokeNamespace, stackNamespace, os.Getenv(openFaaSNamespaceEnvironment))

if missingSignFlag(sigHeader, key) {
return fmt.Errorf("signing requires both --sign <header-value> and --key <key-value>")
Expand Down Expand Up @@ -180,7 +180,7 @@ func runInvoke(cmd *cobra.Command, args []string) error {
}
req.Header = httpHeader

res, err = client.InvokeFunction(functionName, functionInvokeNamespace, invokeAsync, authenticate, req)
res, err = client.InvokeFunction(functionName, functionNamespace, invokeAsync, authenticate, req)
if err != nil {
return fmt.Errorf("failed to invoke function: %s", err)
}
Expand Down
3 changes: 2 additions & 1 deletion commands/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ func runList(cmd *cobra.Command, args []string) error {
return err
}

functions, err := proxyClient.ListFunctions(context.Background(), functionNamespace)
namespace := getNamespace(functionNamespace, "", os.Getenv(openFaaSNamespaceEnvironment))
functions, err := proxyClient.ListFunctions(context.Background(), namespace)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion commands/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ func logRequestFromFlags(cmd *cobra.Command, args []string) logs.Request {

return logs.Request{
Name: args[0],
Namespace: ns,
Namespace: getNamespace(ns, "", os.Getenv(openFaaSNamespaceEnvironment)),
Tail: logFlagValues.lines,
Since: sinceValue(logFlagValues.sinceTime.AsTime(), logFlagValues.since),
Follow: logFlagValues.tail,
Expand Down
29 changes: 29 additions & 0 deletions commands/logs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
)

func Test_logsCmdFlagParsing(t *testing.T) {
t.Setenv(openFaaSNamespaceEnvironment, "")
nowFunc = func() time.Time {
ts, _ := time.Parse(time.RFC3339, "2019-01-01T01:00:00Z")
return ts
Expand Down Expand Up @@ -46,6 +47,34 @@ func Test_logsCmdFlagParsing(t *testing.T) {
}
}

func TestLogsNamespacePrecedence(t *testing.T) {
t.Setenv(openFaaSNamespaceEnvironment, "environment")

tests := []struct {
name string
args []string
want string
}{
{name: "environment default", args: []string{"echo"}, want: "environment"},
{name: "flag override", args: []string{"echo", "--namespace=flag"}, want: "flag"},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
functionLogsCmd.ResetFlags()
initLogCmdFlags(functionLogsCmd)
if err := functionLogsCmd.ParseFlags(test.args); err != nil {
t.Fatal(err)
}

request := logRequestFromFlags(functionLogsCmd, functionLogsCmd.Flags().Args())
if request.Namespace != test.want {
t.Fatalf("want namespace %q, got %q", test.want, request.Namespace)
}
})
}
}

func strP(s string) *string {
return &s
}
Expand Down
Loading
Loading