mirror of
https://github.com/openfaas/faasd.git
synced 2025-06-23 23:33:23 +00:00
Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
3fe0d8d8d3 | |||
5aa4c69e03 | |||
12b5e8ca7f | |||
195e81f595 | |||
06fbca83bf | |||
e71d2c27c5 | |||
13f4a487ce | |||
13412841aa |
@ -109,7 +109,16 @@ func binExists(folder, name string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
func ensureSecretsDir(folder string) error {
|
||||||
|
if _, err := os.Stat(folder); err != nil {
|
||||||
|
err = os.MkdirAll(folder, secretDirPermission)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
func ensureWorkingDir(folder string) error {
|
func ensureWorkingDir(folder string) error {
|
||||||
if _, err := os.Stat(folder); err != nil {
|
if _, err := os.Stat(folder); err != nil {
|
||||||
err = os.MkdirAll(folder, workingDirectoryPermission)
|
err = os.MkdirAll(folder, workingDirectoryPermission)
|
||||||
|
@ -2,6 +2,7 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -21,6 +22,8 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const secretDirPermission = 0755
|
||||||
|
|
||||||
func makeProviderCmd() *cobra.Command {
|
func makeProviderCmd() *cobra.Command {
|
||||||
var command = &cobra.Command{
|
var command = &cobra.Command{
|
||||||
Use: "provider",
|
Use: "provider",
|
||||||
@ -82,25 +85,25 @@ func makeProviderCmd() *cobra.Command {
|
|||||||
|
|
||||||
invokeResolver := handlers.NewInvokeResolver(client)
|
invokeResolver := handlers.NewInvokeResolver(client)
|
||||||
|
|
||||||
userSecretPath := path.Join(wd, "secrets")
|
baseUserSecretsPath := path.Join(wd, "secrets")
|
||||||
|
if err := moveSecretsToDefaultNamespaceSecrets(
|
||||||
err = moveSecretsToDefaultNamespaceSecrets(userSecretPath, faasd.FunctionNamespace)
|
baseUserSecretsPath,
|
||||||
if err != nil {
|
faasd.DefaultFunctionNamespace); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
bootstrapHandlers := types.FaaSHandlers{
|
bootstrapHandlers := types.FaaSHandlers{
|
||||||
FunctionProxy: proxy.NewHandlerFunc(*config, invokeResolver),
|
FunctionProxy: proxy.NewHandlerFunc(*config, invokeResolver),
|
||||||
DeleteHandler: handlers.MakeDeleteHandler(client, cni),
|
DeleteHandler: handlers.MakeDeleteHandler(client, cni),
|
||||||
DeployHandler: handlers.MakeDeployHandler(client, cni, userSecretPath, alwaysPull),
|
DeployHandler: handlers.MakeDeployHandler(client, cni, baseUserSecretsPath, alwaysPull),
|
||||||
FunctionReader: handlers.MakeReadHandler(client),
|
FunctionReader: handlers.MakeReadHandler(client),
|
||||||
ReplicaReader: handlers.MakeReplicaReaderHandler(client),
|
ReplicaReader: handlers.MakeReplicaReaderHandler(client),
|
||||||
ReplicaUpdater: handlers.MakeReplicaUpdateHandler(client, cni),
|
ReplicaUpdater: handlers.MakeReplicaUpdateHandler(client, cni),
|
||||||
UpdateHandler: handlers.MakeUpdateHandler(client, cni, userSecretPath, alwaysPull),
|
UpdateHandler: handlers.MakeUpdateHandler(client, cni, baseUserSecretsPath, alwaysPull),
|
||||||
HealthHandler: func(w http.ResponseWriter, r *http.Request) {},
|
HealthHandler: func(w http.ResponseWriter, r *http.Request) {},
|
||||||
InfoHandler: handlers.MakeInfoHandler(Version, GitCommit),
|
InfoHandler: handlers.MakeInfoHandler(Version, GitCommit),
|
||||||
ListNamespaceHandler: handlers.MakeNamespacesLister(client),
|
ListNamespaceHandler: handlers.MakeNamespacesLister(client),
|
||||||
SecretHandler: handlers.MakeSecretHandler(client, userSecretPath),
|
SecretHandler: handlers.MakeSecretHandler(client, baseUserSecretsPath),
|
||||||
LogHandler: logs.NewLogHandlerFunc(faasdlogs.New(), config.ReadTimeout),
|
LogHandler: logs.NewLogHandlerFunc(faasdlogs.New(), config.ReadTimeout),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,29 +119,58 @@ func makeProviderCmd() *cobra.Command {
|
|||||||
* Mutiple namespace support was added after release 0.13.0
|
* Mutiple namespace support was added after release 0.13.0
|
||||||
* Function will help users to migrate on multiple namespace support of faasd
|
* Function will help users to migrate on multiple namespace support of faasd
|
||||||
*/
|
*/
|
||||||
func moveSecretsToDefaultNamespaceSecrets(secretPath string, namespace string) error {
|
func moveSecretsToDefaultNamespaceSecrets(baseSecretPath string, defaultNamespace string) error {
|
||||||
newSecretPath := path.Join(secretPath, namespace)
|
newSecretPath := path.Join(baseSecretPath, defaultNamespace)
|
||||||
|
|
||||||
err := ensureWorkingDir(newSecretPath)
|
err := ensureSecretsDir(newSecretPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
files, err := ioutil.ReadDir(secretPath)
|
files, err := ioutil.ReadDir(baseSecretPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
if !f.IsDir() {
|
if !f.IsDir() {
|
||||||
oldPath := path.Join(secretPath, f.Name())
|
|
||||||
newPath := path.Join(newSecretPath, f.Name())
|
newPath := path.Join(newSecretPath, f.Name())
|
||||||
err = os.Rename(oldPath, newPath)
|
|
||||||
if err != nil {
|
// A non-nil error means the file wasn't found in the
|
||||||
|
// destination path
|
||||||
|
if _, err := os.Stat(newPath); err != nil {
|
||||||
|
oldPath := path.Join(baseSecretPath, f.Name())
|
||||||
|
|
||||||
|
if err := copyFile(oldPath, newPath); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("[Migration] Copied %s to %s", oldPath, newPath)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func copyFile(src, dst string) error {
|
||||||
|
inputFile, err := os.Open(src)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("opening %s failed %w", src, err)
|
||||||
|
}
|
||||||
|
defer inputFile.Close()
|
||||||
|
|
||||||
|
outputFile, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_APPEND, secretDirPermission)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("opening %s failed %w", dst, err)
|
||||||
|
}
|
||||||
|
defer outputFile.Close()
|
||||||
|
|
||||||
|
// Changed from os.Rename due to issue in #201
|
||||||
|
if _, err := io.Copy(outputFile, inputFile); err != nil {
|
||||||
|
return fmt.Errorf("writing into %s failed %w", outputFile.Name(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
package pkg
|
package pkg
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// FunctionNamespace is the default containerd namespace functions are created
|
// DefaultFunctionNamespace is the default containerd namespace functions are created
|
||||||
FunctionNamespace = "openfaas-fn"
|
DefaultFunctionNamespace = "openfaas-fn"
|
||||||
|
|
||||||
|
// NamespaceLabel indicates that a namespace is managed by faasd
|
||||||
|
NamespaceLabel = "openfaas"
|
||||||
|
|
||||||
// FaasdNamespace is the containerd namespace services are created
|
// FaasdNamespace is the containerd namespace services are created
|
||||||
FaasdNamespace = "openfaas"
|
FaasdNamespace = "openfaas"
|
||||||
|
@ -71,7 +71,7 @@ func buildCmd(ctx context.Context, req logs.Request) *exec.Cmd {
|
|||||||
|
|
||||||
namespace := req.Namespace
|
namespace := req.Namespace
|
||||||
if namespace == "" {
|
if namespace == "" {
|
||||||
namespace = faasd.FunctionNamespace
|
namespace = faasd.DefaultFunctionNamespace
|
||||||
}
|
}
|
||||||
|
|
||||||
// find the description of the fields here
|
// find the description of the fields here
|
||||||
|
@ -42,6 +42,18 @@ func MakeDeleteHandler(client *containerd.Client, cni gocni.CNI) func(w http.Res
|
|||||||
|
|
||||||
lookupNamespace := getRequestNamespace(readNamespaceFromQuery(r))
|
lookupNamespace := getRequestNamespace(readNamespaceFromQuery(r))
|
||||||
|
|
||||||
|
// Check if namespace exists, and it has the openfaas label
|
||||||
|
valid, err := validNamespace(client, lookupNamespace)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !valid {
|
||||||
|
http.Error(w, "namespace not valid", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
name := req.FunctionName
|
name := req.FunctionName
|
||||||
|
|
||||||
function, err := GetFunction(client, name, lookupNamespace)
|
function, err := GetFunction(client, name, lookupNamespace)
|
||||||
|
@ -52,10 +52,25 @@ func MakeDeployHandler(client *containerd.Client, cni gocni.CNI, secretMountPath
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace := getRequestNamespace(req.Namespace)
|
namespace := getRequestNamespace(req.Namespace)
|
||||||
|
|
||||||
|
// Check if namespace exists, and it has the openfaas label
|
||||||
|
valid, err := validNamespace(client, namespace)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !valid {
|
||||||
|
http.Error(w, "namespace not valid", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
namespaceSecretMountPath := getNamespaceSecretMountPath(secretMountPath, namespace)
|
namespaceSecretMountPath := getNamespaceSecretMountPath(secretMountPath, namespace)
|
||||||
err = validateSecrets(namespaceSecretMountPath, req.Secrets)
|
err = validateSecrets(namespaceSecretMountPath, req.Secrets)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
name := req.Service
|
name := req.Service
|
||||||
@ -111,7 +126,7 @@ func deploy(ctx context.Context, req types.FunctionDeployment, client *container
|
|||||||
}
|
}
|
||||||
|
|
||||||
envs := prepareEnv(req.EnvProcess, req.EnvVars)
|
envs := prepareEnv(req.EnvProcess, req.EnvVars)
|
||||||
mounts := getMounts()
|
mounts := getOSMounts()
|
||||||
|
|
||||||
for _, secret := range req.Secrets {
|
for _, secret := range req.Secrets {
|
||||||
mounts = append(mounts, specs.Mount{
|
mounts = append(mounts, specs.Mount{
|
||||||
@ -126,7 +141,7 @@ func deploy(ctx context.Context, req types.FunctionDeployment, client *container
|
|||||||
|
|
||||||
labels, err := buildLabels(&req)
|
labels, err := buildLabels(&req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Unable to apply labels to conatiner: %s, error: %s", name, err)
|
return fmt.Errorf("unable to apply labels to container: %s, error: %w", name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var memory *specs.LinuxMemory
|
var memory *specs.LinuxMemory
|
||||||
@ -157,7 +172,7 @@ func deploy(ctx context.Context, req types.FunctionDeployment, client *container
|
|||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create container: %s, error: %s", name, err)
|
return fmt.Errorf("unable to create container: %s, error: %w", name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return createTask(ctx, client, container, cni)
|
return createTask(ctx, client, container, cni)
|
||||||
@ -195,7 +210,7 @@ func createTask(ctx context.Context, client *containerd.Client, container contai
|
|||||||
task, taskErr := container.NewTask(ctx, cio.BinaryIO("/usr/local/bin/faasd", nil))
|
task, taskErr := container.NewTask(ctx, cio.BinaryIO("/usr/local/bin/faasd", nil))
|
||||||
|
|
||||||
if taskErr != nil {
|
if taskErr != nil {
|
||||||
return fmt.Errorf("unable to start task: %s, error: %s", name, taskErr)
|
return fmt.Errorf("unable to start task: %s, error: %w", name, taskErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Container ID: %s\tTask ID %s:\tTask PID: %d\t\n", name, task.ID(), task.Pid())
|
log.Printf("Container ID: %s\tTask ID %s:\tTask PID: %d\t\n", name, task.ID(), task.Pid())
|
||||||
@ -247,7 +262,9 @@ func prepareEnv(envProcess string, reqEnvVars map[string]string) []string {
|
|||||||
return envs
|
return envs
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMounts() []specs.Mount {
|
// getOSMounts provides a mount for os-specific files such
|
||||||
|
// as the hosts file and resolv.conf
|
||||||
|
func getOSMounts() []specs.Mount {
|
||||||
// Prior to hosts_dir env-var, this value was set to
|
// Prior to hosts_dir env-var, this value was set to
|
||||||
// os.Getwd()
|
// os.Getwd()
|
||||||
hostsDir := "/var/lib/faasd"
|
hostsDir := "/var/lib/faasd"
|
||||||
|
@ -53,7 +53,7 @@ func Test_BuildLabels_WithAnnotations(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(val, tc.result) {
|
if !reflect.DeepEqual(val, tc.result) {
|
||||||
t.Errorf("Got: %s, expected %s", val, tc.result)
|
t.Errorf("Want: %s, got: %s", val, tc.result)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package handlers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
@ -11,6 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containerd/containerd"
|
"github.com/containerd/containerd"
|
||||||
"github.com/containerd/containerd/namespaces"
|
"github.com/containerd/containerd/namespaces"
|
||||||
|
"github.com/openfaas/faasd/pkg"
|
||||||
faasd "github.com/openfaas/faasd/pkg"
|
faasd "github.com/openfaas/faasd/pkg"
|
||||||
"github.com/openfaas/faasd/pkg/cninetwork"
|
"github.com/openfaas/faasd/pkg/cninetwork"
|
||||||
)
|
)
|
||||||
@ -32,6 +34,17 @@ type Function struct {
|
|||||||
|
|
||||||
// ListFunctions returns a map of all functions with running tasks on namespace
|
// ListFunctions returns a map of all functions with running tasks on namespace
|
||||||
func ListFunctions(client *containerd.Client, namespace string) (map[string]*Function, error) {
|
func ListFunctions(client *containerd.Client, namespace string) (map[string]*Function, error) {
|
||||||
|
|
||||||
|
// Check if namespace exists, and it has the openfaas label
|
||||||
|
valid, err := validNamespace(client, namespace)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !valid {
|
||||||
|
return nil, errors.New("namespace not valid")
|
||||||
|
}
|
||||||
|
|
||||||
ctx := namespaces.WithNamespace(context.Background(), namespace)
|
ctx := namespaces.WithNamespace(context.Background(), namespace)
|
||||||
functions := make(map[string]*Function)
|
functions := make(map[string]*Function)
|
||||||
|
|
||||||
@ -60,7 +73,7 @@ func GetFunction(client *containerd.Client, name string, namespace string) (Func
|
|||||||
|
|
||||||
c, err := client.LoadContainer(ctx, name)
|
c, err := client.LoadContainer(ctx, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Function{}, fmt.Errorf("unable to find function: %s, error %s", name, err)
|
return Function{}, fmt.Errorf("unable to find function: %s, error %w", name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
image, err := c.Image(ctx)
|
image, err := c.Image(ctx)
|
||||||
@ -72,19 +85,19 @@ func GetFunction(client *containerd.Client, name string, namespace string) (Func
|
|||||||
allLabels, labelErr := c.Labels(ctx)
|
allLabels, labelErr := c.Labels(ctx)
|
||||||
|
|
||||||
if labelErr != nil {
|
if labelErr != nil {
|
||||||
log.Printf("cannot list container %s labels: %s", containerName, labelErr.Error())
|
log.Printf("cannot list container %s labels: %s", containerName, labelErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
labels, annotations := buildLabelsAndAnnotations(allLabels)
|
labels, annotations := buildLabelsAndAnnotations(allLabels)
|
||||||
|
|
||||||
spec, err := c.Spec(ctx)
|
spec, err := c.Spec(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Function{}, fmt.Errorf("unable to load function spec for reading secrets: %s, error %s", name, err)
|
return Function{}, fmt.Errorf("unable to load function spec for reading secrets: %s, error %w", name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err := c.Info(ctx)
|
info, err := c.Info(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Function{}, fmt.Errorf("can't load info for: %s, error %s", name, err)
|
return Function{}, fmt.Errorf("can't load info for: %s, error %w", name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
envVars, envProcess := readEnvFromProcessEnv(spec.Process.Env)
|
envVars, envProcess := readEnvFromProcessEnv(spec.Process.Env)
|
||||||
@ -106,7 +119,7 @@ func GetFunction(client *containerd.Client, name string, namespace string) (Func
|
|||||||
// Task for container exists
|
// Task for container exists
|
||||||
svc, err := task.Status(ctx)
|
svc, err := task.Status(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Function{}, fmt.Errorf("unable to get task status for container: %s %s", name, err)
|
return Function{}, fmt.Errorf("unable to get task status for container: %s %w", name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if svc.Status == "running" {
|
if svc.Status == "running" {
|
||||||
@ -187,7 +200,7 @@ func ListNamespaces(client *containerd.Client) []string {
|
|||||||
namespaces, err := store.List(context.Background())
|
namespaces, err := store.List(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error listing namespaces: %s", err.Error())
|
log.Printf("Error listing namespaces: %s", err.Error())
|
||||||
set = append(set, faasd.FunctionNamespace)
|
set = append(set, faasd.DefaultFunctionNamespace)
|
||||||
return set
|
return set
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,12 +211,12 @@ func ListNamespaces(client *containerd.Client) []string {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, found := labels["openfaas"]; found {
|
if _, found := labels[pkg.NamespaceLabel]; found {
|
||||||
set = append(set, namespace)
|
set = append(set, namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !findNamespace(faasd.FunctionNamespace, set) {
|
if !findNamespace(faasd.DefaultFunctionNamespace, set) {
|
||||||
set = append(set, faasd.FunctionNamespace)
|
set = append(set, faasd.DefaultFunctionNamespace)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ func (i *InvokeResolver) Resolve(functionName string) (url.URL, error) {
|
|||||||
actualFunctionName := functionName
|
actualFunctionName := functionName
|
||||||
log.Printf("Resolve: %q\n", actualFunctionName)
|
log.Printf("Resolve: %q\n", actualFunctionName)
|
||||||
|
|
||||||
namespace := getNamespace(functionName, faasd.FunctionNamespace)
|
namespace := getNamespace(functionName, faasd.DefaultFunctionNamespace)
|
||||||
|
|
||||||
if strings.Contains(functionName, ".") {
|
if strings.Contains(functionName, ".") {
|
||||||
actualFunctionName = strings.TrimSuffix(functionName, "."+namespace)
|
actualFunctionName = strings.TrimSuffix(functionName, "."+namespace)
|
||||||
|
@ -14,6 +14,17 @@ func MakeReadHandler(client *containerd.Client) func(w http.ResponseWriter, r *h
|
|||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
lookupNamespace := getRequestNamespace(readNamespaceFromQuery(r))
|
lookupNamespace := getRequestNamespace(readNamespaceFromQuery(r))
|
||||||
|
// Check if namespace exists, and it has the openfaas label
|
||||||
|
valid, err := validNamespace(client, lookupNamespace)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !valid {
|
||||||
|
http.Error(w, "namespace not valid", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
res := []types.FunctionStatus{}
|
res := []types.FunctionStatus{}
|
||||||
fns, err := ListFunctions(client, lookupNamespace)
|
fns, err := ListFunctions(client, lookupNamespace)
|
||||||
|
@ -16,6 +16,18 @@ func MakeReplicaReaderHandler(client *containerd.Client) func(w http.ResponseWri
|
|||||||
functionName := vars["name"]
|
functionName := vars["name"]
|
||||||
lookupNamespace := getRequestNamespace(readNamespaceFromQuery(r))
|
lookupNamespace := getRequestNamespace(readNamespaceFromQuery(r))
|
||||||
|
|
||||||
|
// Check if namespace exists, and it has the openfaas label
|
||||||
|
valid, err := validNamespace(client, lookupNamespace)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !valid {
|
||||||
|
http.Error(w, "namespace not valid", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if f, err := GetFunction(client, functionName, lookupNamespace); err == nil {
|
if f, err := GetFunction(client, functionName, lookupNamespace); err == nil {
|
||||||
found := types.FunctionStatus{
|
found := types.FunctionStatus{
|
||||||
Name: functionName,
|
Name: functionName,
|
||||||
|
@ -41,6 +41,18 @@ func MakeReplicaUpdateHandler(client *containerd.Client, cni gocni.CNI) func(w h
|
|||||||
|
|
||||||
namespace := getRequestNamespace(readNamespaceFromQuery(r))
|
namespace := getRequestNamespace(readNamespaceFromQuery(r))
|
||||||
|
|
||||||
|
// Check if namespace exists, and it has the openfaas label
|
||||||
|
valid, err := validNamespace(client, namespace)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !valid {
|
||||||
|
http.Error(w, "namespace not valid", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
name := req.ServiceName
|
name := req.ServiceName
|
||||||
|
|
||||||
if _, err := GetFunction(client, name, namespace); err != nil {
|
if _, err := GetFunction(client, name, namespace); err != nil {
|
||||||
|
@ -49,6 +49,18 @@ func MakeSecretHandler(c *containerd.Client, mountPath string) func(w http.Respo
|
|||||||
func listSecrets(c *containerd.Client, w http.ResponseWriter, r *http.Request, mountPath string) {
|
func listSecrets(c *containerd.Client, w http.ResponseWriter, r *http.Request, mountPath string) {
|
||||||
|
|
||||||
lookupNamespace := getRequestNamespace(readNamespaceFromQuery(r))
|
lookupNamespace := getRequestNamespace(readNamespaceFromQuery(r))
|
||||||
|
// Check if namespace exists, and it has the openfaas label
|
||||||
|
valid, err := validNamespace(c, lookupNamespace)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !valid {
|
||||||
|
http.Error(w, "namespace not valid", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
mountPath = getNamespaceSecretMountPath(mountPath, lookupNamespace)
|
mountPath = getNamespaceSecretMountPath(mountPath, lookupNamespace)
|
||||||
|
|
||||||
files, err := ioutil.ReadDir(mountPath)
|
files, err := ioutil.ReadDir(mountPath)
|
||||||
|
@ -41,6 +41,19 @@ func MakeUpdateHandler(client *containerd.Client, cni gocni.CNI, secretMountPath
|
|||||||
}
|
}
|
||||||
name := req.Service
|
name := req.Service
|
||||||
namespace := getRequestNamespace(req.Namespace)
|
namespace := getRequestNamespace(req.Namespace)
|
||||||
|
|
||||||
|
// Check if namespace exists, and it has the openfaas label
|
||||||
|
valid, err := validNamespace(client, namespace)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !valid {
|
||||||
|
http.Error(w, "namespace not valid", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
namespaceSecretMountPath := getNamespaceSecretMountPath(secretMountPath, namespace)
|
namespaceSecretMountPath := getNamespaceSecretMountPath(secretMountPath, namespace)
|
||||||
|
|
||||||
function, err := GetFunction(client, name, namespace)
|
function, err := GetFunction(client, name, namespace)
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd"
|
||||||
|
|
||||||
|
"github.com/openfaas/faasd/pkg"
|
||||||
faasd "github.com/openfaas/faasd/pkg"
|
faasd "github.com/openfaas/faasd/pkg"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -12,7 +16,7 @@ func getRequestNamespace(namespace string) string {
|
|||||||
if len(namespace) > 0 {
|
if len(namespace) > 0 {
|
||||||
return namespace
|
return namespace
|
||||||
}
|
}
|
||||||
return faasd.FunctionNamespace
|
return faasd.DefaultFunctionNamespace
|
||||||
}
|
}
|
||||||
|
|
||||||
func readNamespaceFromQuery(r *http.Request) string {
|
func readNamespaceFromQuery(r *http.Request) string {
|
||||||
@ -23,3 +27,23 @@ func readNamespaceFromQuery(r *http.Request) string {
|
|||||||
func getNamespaceSecretMountPath(userSecretPath string, namespace string) string {
|
func getNamespaceSecretMountPath(userSecretPath string, namespace string) string {
|
||||||
return path.Join(userSecretPath, namespace)
|
return path.Join(userSecretPath, namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validNamespace indicates whether the namespace is eligable to be
|
||||||
|
// used for OpenFaaS functions.
|
||||||
|
func validNamespace(client *containerd.Client, namespace string) (bool, error) {
|
||||||
|
if namespace == faasd.DefaultFunctionNamespace {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
store := client.NamespaceService()
|
||||||
|
labels, err := store.Labels(context.Background(), namespace)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if value, found := labels[pkg.NamespaceLabel]; found && value == "true" {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
@ -15,7 +15,7 @@ func Test_getRequestNamespace(t *testing.T) {
|
|||||||
requestNamespace string
|
requestNamespace string
|
||||||
expectedNamespace string
|
expectedNamespace string
|
||||||
}{
|
}{
|
||||||
{name: "RequestNamespace is not provided", requestNamespace: "", expectedNamespace: faasd.FunctionNamespace},
|
{name: "RequestNamespace is not provided", requestNamespace: "", expectedNamespace: faasd.DefaultFunctionNamespace},
|
||||||
{name: "RequestNamespace is provided", requestNamespace: "user-namespace", expectedNamespace: "user-namespace"},
|
{name: "RequestNamespace is provided", requestNamespace: "user-namespace", expectedNamespace: "user-namespace"},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ func Test_getRequestNamespace(t *testing.T) {
|
|||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
actualNamespace := getRequestNamespace(tc.requestNamespace)
|
actualNamespace := getRequestNamespace(tc.requestNamespace)
|
||||||
if actualNamespace != tc.expectedNamespace {
|
if actualNamespace != tc.expectedNamespace {
|
||||||
t.Errorf("Got: %s, expected %s", actualNamespace, tc.expectedNamespace)
|
t.Errorf("Want: %s, got: %s", actualNamespace, tc.expectedNamespace)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -36,7 +36,7 @@ func Test_getNamespaceSecretMountPath(t *testing.T) {
|
|||||||
requestNamespace string
|
requestNamespace string
|
||||||
expectedSecretPath string
|
expectedSecretPath string
|
||||||
}{
|
}{
|
||||||
{name: "Default Namespace is provided", requestNamespace: faasd.FunctionNamespace, expectedSecretPath: "/var/openfaas/secrets/" + faasd.FunctionNamespace},
|
{name: "Default Namespace is provided", requestNamespace: faasd.DefaultFunctionNamespace, expectedSecretPath: "/var/openfaas/secrets/" + faasd.DefaultFunctionNamespace},
|
||||||
{name: "User Namespace is provided", requestNamespace: "user-namespace", expectedSecretPath: "/var/openfaas/secrets/user-namespace"},
|
{name: "User Namespace is provided", requestNamespace: "user-namespace", expectedSecretPath: "/var/openfaas/secrets/user-namespace"},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ func Test_getNamespaceSecretMountPath(t *testing.T) {
|
|||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
actualNamespace := getNamespaceSecretMountPath(userSecretPath, tc.requestNamespace)
|
actualNamespace := getNamespaceSecretMountPath(userSecretPath, tc.requestNamespace)
|
||||||
if actualNamespace != tc.expectedSecretPath {
|
if actualNamespace != tc.expectedSecretPath {
|
||||||
t.Errorf("Got: %s, expected %s", actualNamespace, tc.expectedSecretPath)
|
t.Errorf("Want: %s, got: %s", actualNamespace, tc.expectedSecretPath)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -68,7 +68,7 @@ func Test_readNamespaceFromQuery(t *testing.T) {
|
|||||||
|
|
||||||
actualNamespace := readNamespaceFromQuery(r)
|
actualNamespace := readNamespaceFromQuery(r)
|
||||||
if actualNamespace != tc.expectedNamespace {
|
if actualNamespace != tc.expectedNamespace {
|
||||||
t.Errorf("Got: %s, expected %s", actualNamespace, tc.expectedNamespace)
|
t.Errorf("Want: %s, got: %s", actualNamespace, tc.expectedNamespace)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ func Remove(ctx context.Context, client *containerd.Client, name string) error {
|
|||||||
if errdefs.IsNotFound(err) {
|
if errdefs.IsNotFound(err) {
|
||||||
taskFound = false
|
taskFound = false
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("unable to get task %s: ", err)
|
return fmt.Errorf("unable to get task %w: ", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,12 +47,12 @@ func Remove(ctx context.Context, client *containerd.Client, name string) error {
|
|||||||
|
|
||||||
log.Printf("Need to kill task: %s\n", name)
|
log.Printf("Need to kill task: %s\n", name)
|
||||||
if err = killTask(ctx, t); err != nil {
|
if err = killTask(ctx, t); err != nil {
|
||||||
return fmt.Errorf("error killing task %s, %s, %s", container.ID(), name, err)
|
return fmt.Errorf("error killing task %s, %s, %w", container.ID(), name, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := container.Delete(ctx, containerd.WithSnapshotCleanup); err != nil {
|
if err := container.Delete(ctx, containerd.WithSnapshotCleanup); err != nil {
|
||||||
return fmt.Errorf("error deleting container %s, %s, %s", container.ID(), name, err)
|
return fmt.Errorf("error deleting container %s, %s, %w", container.ID(), name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -79,9 +79,10 @@ func killTask(ctx context.Context, task containerd.Task) error {
|
|||||||
if task != nil {
|
if task != nil {
|
||||||
wait, err := task.Wait(ctx)
|
wait, err := task.Wait(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("error waiting on task: %s", err)
|
log.Printf("error waiting on task: %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := task.Kill(ctx, unix.SIGTERM, containerd.WithKillAll); err != nil {
|
if err := task.Kill(ctx, unix.SIGTERM, containerd.WithKillAll); err != nil {
|
||||||
log.Printf("error killing container task: %s", err)
|
log.Printf("error killing container task: %s", err)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user