mirror of
https://github.com/openfaas/faasd.git
synced 2025-06-19 12:36:38 +00:00
Compare commits
6 Commits
0.15.0-rc1
...
0.15.0-rc2
Author | SHA1 | Date | |
---|---|---|---|
8ac45f5379 | |||
3579061423 | |||
761d1847bf | |||
8003748b73 | |||
a2ea804d2c | |||
551e6645b7 |
4
.github/ISSUE_TEMPLATE.md
vendored
4
.github/ISSUE_TEMPLATE.md
vendored
@ -1,3 +1,7 @@
|
|||||||
|
## Due diligence
|
||||||
|
|
||||||
|
Before you for help or support, make sure that you've [consulted the faasd manual "Serverless For Everyone Else"](https://openfaas.gumroad.com/l/serverless-for-everyone-else).
|
||||||
|
|
||||||
<!--- Provide a general summary of the issue in the Title above -->
|
<!--- Provide a general summary of the issue in the Title above -->
|
||||||
|
|
||||||
## Expected Behaviour
|
## Expected Behaviour
|
||||||
|
@ -10,17 +10,7 @@ packages:
|
|||||||
- git
|
- git
|
||||||
|
|
||||||
runcmd:
|
runcmd:
|
||||||
- curl -sLSf https://github.com/containerd/containerd/releases/download/v1.5.4/containerd-1.5.4-linux-amd64.tar.gz > /tmp/containerd.tar.gz && tar -xvf /tmp/containerd.tar.gz -C /usr/local/bin/ --strip-components=1
|
- curl -sfL https://raw.githubusercontent.com/openfaas/faasd/master/hack/install.sh | sh -s -
|
||||||
- curl -SLfs https://raw.githubusercontent.com/containerd/containerd/v1.5.4/containerd.service | tee /etc/systemd/system/containerd.service
|
|
||||||
- systemctl daemon-reload && systemctl start containerd
|
|
||||||
- systemctl enable containerd
|
|
||||||
- /sbin/sysctl -w net.ipv4.conf.all.forwarding=1
|
|
||||||
- mkdir -p /opt/cni/bin
|
|
||||||
- curl -sSL https://github.com/containernetworking/plugins/releases/download/v0.8.5/cni-plugins-linux-amd64-v0.8.5.tgz | tar -xz -C /opt/cni/bin
|
|
||||||
- mkdir -p /go/src/github.com/openfaas/
|
|
||||||
- cd /go/src/github.com/openfaas/ && git clone --depth 1 --branch 0.13.0 https://github.com/openfaas/faasd
|
|
||||||
- curl -fSLs "https://github.com/openfaas/faasd/releases/download/0.13.0/faasd" --output "/usr/local/bin/faasd" && chmod a+x "/usr/local/bin/faasd"
|
|
||||||
- cd /go/src/github.com/openfaas/faasd/ && /usr/local/bin/faasd install
|
|
||||||
- systemctl status -l containerd --no-pager
|
- systemctl status -l containerd --no-pager
|
||||||
- journalctl -u faasd-provider --no-pager
|
- journalctl -u faasd-provider --no-pager
|
||||||
- systemctl status -l faasd-provider --no-pager
|
- systemctl status -l faasd-provider --no-pager
|
||||||
|
@ -103,7 +103,7 @@ func makeProviderCmd() *cobra.Command {
|
|||||||
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, baseUserSecretsPath),
|
SecretHandler: handlers.MakeSecretHandler(client.NamespaceService(), baseUserSecretsPath),
|
||||||
LogHandler: logs.NewLogHandlerFunc(faasdlogs.New(), config.ReadTimeout),
|
LogHandler: logs.NewLogHandlerFunc(faasdlogs.New(), config.ReadTimeout),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ services:
|
|||||||
- "127.0.0.1:9090:9090"
|
- "127.0.0.1:9090:9090"
|
||||||
|
|
||||||
gateway:
|
gateway:
|
||||||
image: ghcr.io/openfaas/gateway:0.21.0
|
image: ghcr.io/openfaas/gateway:0.21.3
|
||||||
environment:
|
environment:
|
||||||
- basic_auth=true
|
- basic_auth=true
|
||||||
- functions_provider_url=http://faasd-provider:8081/
|
- functions_provider_url=http://faasd-provider:8081/
|
||||||
|
@ -27,111 +27,112 @@ It took me about 2-3 minutes to run through everything after installing multipas
|
|||||||
|
|
||||||
* Get my cloud-config.txt file
|
* Get my cloud-config.txt file
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
curl -sSLO https://raw.githubusercontent.com/openfaas/faasd/master/cloud-config.txt
|
curl -sSLO https://raw.githubusercontent.com/openfaas/faasd/master/cloud-config.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
* Update the SSH key to match your own, edit `cloud-config.txt`:
|
|
||||||
|
|
||||||
Replace the 2nd line with the contents of `~/.ssh/id_rsa.pub`:
|
|
||||||
|
|
||||||
```
|
|
||||||
ssh_authorized_keys:
|
|
||||||
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8Q/aUYUr3P1XKVucnO9mlWxOjJm+K01lHJR90MkHC9zbfTqlp8P7C3J26zKAuzHXOeF+VFxETRr6YedQKW9zp5oP7sN+F2gr/pO7GV3VmOqHMV7uKfyUQfq7H1aVzLfCcI7FwN2Zekv3yB7kj35pbsMa1Za58aF6oHRctZU6UWgXXbRxP+B04DoVU7jTstQ4GMoOCaqYhgPHyjEAS3DW0kkPW6HzsvJHkxvVcVlZ/wNJa1Ie/yGpzOzWIN0Ol0t2QT/RSWOhfzO1A2P0XbPuZ04NmriBonO9zR7T1fMNmmtTuK7WazKjQT3inmYRAqU6pe8wfX8WIWNV7OowUjUsv alex@alexr.local
|
|
||||||
```
|
|
||||||
|
|
||||||
* Boot the VM
|
* Boot the VM
|
||||||
|
|
||||||
```sh
|
The `cloud-config.txt` contains an ssh key to allow your local machine to access the VM. However, this must be updated with your local ssh key.
|
||||||
multipass launch --cloud-init cloud-config.txt --name faasd
|
This command will update the key with your local public key value and start the VM.
|
||||||
```
|
|
||||||
|
```sh
|
||||||
|
sed "s/ssh-rsa.*/$(cat $HOME/.ssh/id_*.pub)/" cloud-config.txt | multipass launch --name faasd --cloud-init -
|
||||||
|
```
|
||||||
|
|
||||||
|
This can also be done manually, just replace the 2nd line of the `cloud-config.txt` with the coPntents of your public ssh key, usually either `~/.ssh/id_rsa.pub` or `~/.ssh/id_ed25519.pub`
|
||||||
|
|
||||||
|
```
|
||||||
|
ssh_authorized_keys:
|
||||||
|
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8Q/aUYUr3P1XKVucnO9mlWxOjJm+K01lHJR90MkHC9zbfTqlp8P7C3J26zKAuzHXOeF+VFxETRr6YedQKW9zp5oP7sN+F2gr/pO7GV3VmOqHMV7uKfyUQfq7H1aVzLfCcI7FwN2Zekv3yB7kj35pbsMa1Za58aF6oHRctZU6UWgXXbRxP+B04DoVU7jTstQ4GMoOCaqYhgPHyjEAS3DW0kkPW6HzsvJHkxvVcVlZ/wNJa1Ie/yGpzOzWIN0Ol0t2QT/RSWOhfzO1A2P0XbPuZ04NmriBonO9zR7T1fMNmmtTuK7WazKjQT3inmYRAqU6pe8wfX8WIWNV7OowUjUsv alex@alexr.local
|
||||||
|
```
|
||||||
|
|
||||||
* Get the VM's IP and connect with `ssh`
|
* Get the VM's IP and connect with `ssh`
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
multipass info faasd
|
multipass info faasd
|
||||||
Name: faasd
|
Name: faasd
|
||||||
State: Running
|
State: Running
|
||||||
IPv4: 192.168.64.14
|
IPv4: 192.168.64.14
|
||||||
Release: Ubuntu 18.04.3 LTS
|
Release: Ubuntu 18.04.3 LTS
|
||||||
Image hash: a720c34066dc (Ubuntu 18.04 LTS)
|
Image hash: a720c34066dc (Ubuntu 18.04 LTS)
|
||||||
Load: 0.79 0.19 0.06
|
Load: 0.79 0.19 0.06
|
||||||
Disk usage: 1.1G out of 4.7G
|
Disk usage: 1.1G out of 4.7G
|
||||||
Memory usage: 145.6M out of 985.7M
|
Memory usage: 145.6M out of 985.7M
|
||||||
```
|
```
|
||||||
|
|
||||||
Set the variable `IP`:
|
Set the variable `IP`:
|
||||||
|
|
||||||
```
|
```
|
||||||
export IP="192.168.64.14"
|
export IP="192.168.64.14"
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also try to use `jq` to get the IP into a variable:
|
You can also try to use `jq` to get the IP into a variable:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
export IP=$(multipass info faasd --format json| jq -r '.info.faasd.ipv4[0]')
|
export IP=$(multipass info faasd --format json| jq -r '.info.faasd.ipv4[0]')
|
||||||
```
|
```
|
||||||
|
|
||||||
Connect to the IP listed:
|
Connect to the IP listed:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
ssh ubuntu@$IP
|
ssh ubuntu@$IP
|
||||||
```
|
```
|
||||||
|
|
||||||
Log out once you know it works.
|
Log out once you know it works.
|
||||||
|
|
||||||
* Let's capture the authentication password into a file for use with `faas-cli`
|
* Let's capture the authentication password into a file for use with `faas-cli`
|
||||||
|
|
||||||
```
|
```
|
||||||
ssh ubuntu@$IP "sudo cat /var/lib/faasd/secrets/basic-auth-password" > basic-auth-password
|
ssh ubuntu@$IP "sudo cat /var/lib/faasd/secrets/basic-auth-password" > basic-auth-password
|
||||||
```
|
```
|
||||||
|
|
||||||
## Try faasd (OpenFaaS)
|
## Try faasd (OpenFaaS)
|
||||||
|
|
||||||
* Login from your laptop (the host)
|
* Login from your laptop (the host)
|
||||||
|
|
||||||
```
|
```
|
||||||
export OPENFAAS_URL=http://$IP:8080
|
export OPENFAAS_URL=http://$IP:8080
|
||||||
cat basic-auth-password | faas-cli login -s
|
cat basic-auth-password | faas-cli login -s
|
||||||
```
|
```
|
||||||
|
|
||||||
* Deploy a function and invoke it
|
* Deploy a function and invoke it
|
||||||
|
|
||||||
```
|
```
|
||||||
faas-cli store deploy figlet --env write_timeout=1s
|
faas-cli store deploy figlet --env write_timeout=1s
|
||||||
echo "faasd" | faas-cli invoke figlet
|
echo "faasd" | faas-cli invoke figlet
|
||||||
|
|
||||||
faas-cli describe figlet
|
faas-cli describe figlet
|
||||||
|
|
||||||
# Run async
|
# Run async
|
||||||
curl -i -d "faasd-async" $OPENFAAS_URL/async-function/figlet
|
curl -i -d "faasd-async" $OPENFAAS_URL/async-function/figlet
|
||||||
|
|
||||||
# Run async with a callback
|
# Run async with a callback
|
||||||
|
|
||||||
curl -i -d "faasd-async" -H "X-Callback-Url: http://some-request-bin.com/path" $OPENFAAS_URL/async-function/figlet
|
curl -i -d "faasd-async" -H "X-Callback-Url: http://some-request-bin.com/path" $OPENFAAS_URL/async-function/figlet
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also checkout the other store functions: `faas-cli store list`
|
You can also checkout the other store functions: `faas-cli store list`
|
||||||
|
|
||||||
* Try the UI
|
* Try the UI
|
||||||
|
|
||||||
Head over to the UI from your laptop and remember that your password is in the `basic-auth-password` file. The username is `admin`:
|
Head over to the UI from your laptop and remember that your password is in the `basic-auth-password` file. The username is `admin`:
|
||||||
|
|
||||||
```
|
```
|
||||||
echo http://$IP:8080
|
echo http://$IP:8080
|
||||||
```
|
```
|
||||||
|
|
||||||
* Stop/start the instance
|
* Stop/start the instance
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
multipass stop faasd
|
multipass stop faasd
|
||||||
```
|
```
|
||||||
|
|
||||||
* Delete, if you want to:
|
* Delete, if you want to:
|
||||||
|
|
||||||
```
|
```
|
||||||
multipass delete --purge faasd
|
multipass delete --purge faasd
|
||||||
```
|
```
|
||||||
|
|
||||||
You now have a faasd appliance on your Mac. You can also use this cloud-init file with public cloud like AWS or DigitalOcean.
|
You now have a faasd appliance on your Mac. You can also use this cloud-init file with public cloud like AWS or DigitalOcean.
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ 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
|
// Check if namespace exists, and it has the openfaas label
|
||||||
valid, err := validNamespace(client, lookupNamespace)
|
valid, err := validNamespace(client.NamespaceService(), lookupNamespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
|
@ -54,7 +54,7 @@ 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
|
// Check if namespace exists, and it has the openfaas label
|
||||||
valid, err := validNamespace(client, namespace)
|
valid, err := validNamespace(client.NamespaceService(), namespace)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
@ -37,7 +37,7 @@ type Function struct {
|
|||||||
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
|
// Check if namespace exists, and it has the openfaas label
|
||||||
valid, err := validNamespace(client, namespace)
|
valid, err := validNamespace(client.NamespaceService(), namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,11 @@ package handlers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
|
|
||||||
"github.com/containerd/containerd"
|
"github.com/containerd/containerd"
|
||||||
"github.com/openfaas/faas-provider/types"
|
"github.com/openfaas/faas-provider/types"
|
||||||
)
|
)
|
||||||
@ -16,7 +17,7 @@ func MakeReadHandler(client *containerd.Client) func(w http.ResponseWriter, r *h
|
|||||||
|
|
||||||
lookupNamespace := getRequestNamespace(readNamespaceFromQuery(r))
|
lookupNamespace := getRequestNamespace(readNamespaceFromQuery(r))
|
||||||
// Check if namespace exists, and it has the openfaas label
|
// Check if namespace exists, and it has the openfaas label
|
||||||
valid, err := validNamespace(client, lookupNamespace)
|
valid, err := validNamespace(client.NamespaceService(), lookupNamespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
@ -39,7 +40,7 @@ func MakeReadHandler(client *containerd.Client) func(w http.ResponseWriter, r *h
|
|||||||
annotations := &fn.annotations
|
annotations := &fn.annotations
|
||||||
labels := &fn.labels
|
labels := &fn.labels
|
||||||
memory := resource.NewQuantity(fn.memoryLimit, resource.BinarySI)
|
memory := resource.NewQuantity(fn.memoryLimit, resource.BinarySI)
|
||||||
res = append(res, types.FunctionStatus{
|
status := types.FunctionStatus{
|
||||||
Name: fn.name,
|
Name: fn.name,
|
||||||
Image: fn.image,
|
Image: fn.image,
|
||||||
Replicas: uint64(fn.replicas),
|
Replicas: uint64(fn.replicas),
|
||||||
@ -49,9 +50,17 @@ func MakeReadHandler(client *containerd.Client) func(w http.ResponseWriter, r *h
|
|||||||
Secrets: fn.secrets,
|
Secrets: fn.secrets,
|
||||||
EnvVars: fn.envVars,
|
EnvVars: fn.envVars,
|
||||||
EnvProcess: fn.envProcess,
|
EnvProcess: fn.envProcess,
|
||||||
Limits: &types.FunctionResources{Memory: memory.String()},
|
|
||||||
CreatedAt: fn.createdAt,
|
CreatedAt: fn.createdAt,
|
||||||
})
|
}
|
||||||
|
|
||||||
|
// Do not remove below memory check for 0
|
||||||
|
// Memory limit should not be included in status until set explicitly
|
||||||
|
limit := &types.FunctionResources{Memory: memory.String()}
|
||||||
|
if limit.Memory != "0" {
|
||||||
|
status.Limits = limit
|
||||||
|
}
|
||||||
|
|
||||||
|
res = append(res, status)
|
||||||
}
|
}
|
||||||
|
|
||||||
body, _ := json.Marshal(res)
|
body, _ := json.Marshal(res)
|
||||||
|
@ -17,7 +17,7 @@ func MakeReplicaReaderHandler(client *containerd.Client) func(w http.ResponseWri
|
|||||||
lookupNamespace := getRequestNamespace(readNamespaceFromQuery(r))
|
lookupNamespace := getRequestNamespace(readNamespaceFromQuery(r))
|
||||||
|
|
||||||
// Check if namespace exists, and it has the openfaas label
|
// Check if namespace exists, and it has the openfaas label
|
||||||
valid, err := validNamespace(client, lookupNamespace)
|
valid, err := validNamespace(client.NamespaceService(), lookupNamespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
|
@ -42,7 +42,7 @@ 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
|
// Check if namespace exists, and it has the openfaas label
|
||||||
valid, err := validNamespace(client, namespace)
|
valid, err := validNamespace(client.NamespaceService(), namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
|
@ -10,14 +10,14 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/containerd/containerd"
|
|
||||||
"github.com/openfaas/faas-provider/types"
|
"github.com/openfaas/faas-provider/types"
|
||||||
|
provider "github.com/openfaas/faasd/pkg/provider"
|
||||||
)
|
)
|
||||||
|
|
||||||
const secretFilePermission = 0644
|
const secretFilePermission = 0644
|
||||||
const secretDirPermission = 0755
|
const secretDirPermission = 0755
|
||||||
|
|
||||||
func MakeSecretHandler(c *containerd.Client, mountPath string) func(w http.ResponseWriter, r *http.Request) {
|
func MakeSecretHandler(store provider.Labeller, mountPath string) func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
err := os.MkdirAll(mountPath, secretFilePermission)
|
err := os.MkdirAll(mountPath, secretFilePermission)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -31,13 +31,13 @@ func MakeSecretHandler(c *containerd.Client, mountPath string) func(w http.Respo
|
|||||||
|
|
||||||
switch r.Method {
|
switch r.Method {
|
||||||
case http.MethodGet:
|
case http.MethodGet:
|
||||||
listSecrets(c, w, r, mountPath)
|
listSecrets(store, w, r, mountPath)
|
||||||
case http.MethodPost:
|
case http.MethodPost:
|
||||||
createSecret(c, w, r, mountPath)
|
createSecret(w, r, mountPath)
|
||||||
case http.MethodPut:
|
case http.MethodPut:
|
||||||
createSecret(c, w, r, mountPath)
|
createSecret(w, r, mountPath)
|
||||||
case http.MethodDelete:
|
case http.MethodDelete:
|
||||||
deleteSecret(c, w, r, mountPath)
|
deleteSecret(w, r, mountPath)
|
||||||
default:
|
default:
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
@ -46,11 +46,11 @@ 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(store provider.Labeller, 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
|
// Check if namespace exists, and it has the openfaas label
|
||||||
valid, err := validNamespace(c, lookupNamespace)
|
valid, err := validNamespace(store, lookupNamespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
@ -63,8 +63,15 @@ func listSecrets(c *containerd.Client, w http.ResponseWriter, r *http.Request, m
|
|||||||
|
|
||||||
mountPath = getNamespaceSecretMountPath(mountPath, lookupNamespace)
|
mountPath = getNamespaceSecretMountPath(mountPath, lookupNamespace)
|
||||||
|
|
||||||
files, err := ioutil.ReadDir(mountPath)
|
files, err := os.ReadDir(mountPath)
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
bytesOut, _ := json.Marshal([]types.Secret{})
|
||||||
|
w.Write(bytesOut)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fmt.Printf("Error Occured: %s \n", err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -78,7 +85,7 @@ func listSecrets(c *containerd.Client, w http.ResponseWriter, r *http.Request, m
|
|||||||
w.Write(bytesOut)
|
w.Write(bytesOut)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createSecret(c *containerd.Client, w http.ResponseWriter, r *http.Request, mountPath string) {
|
func createSecret(w http.ResponseWriter, r *http.Request, mountPath string) {
|
||||||
secret, err := parseSecret(r)
|
secret, err := parseSecret(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[secret] error %s", err.Error())
|
log.Printf("[secret] error %s", err.Error())
|
||||||
@ -118,7 +125,7 @@ func createSecret(c *containerd.Client, w http.ResponseWriter, r *http.Request,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteSecret(c *containerd.Client, w http.ResponseWriter, r *http.Request, mountPath string) {
|
func deleteSecret(w http.ResponseWriter, r *http.Request, mountPath string) {
|
||||||
secret, err := parseSecret(r)
|
secret, err := parseSecret(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[secret] error %s", err.Error())
|
log.Printf("[secret] error %s", err.Error())
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"os"
|
"os"
|
||||||
@ -10,6 +13,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/openfaas/faas-provider/types"
|
"github.com/openfaas/faas-provider/types"
|
||||||
|
"github.com/openfaas/faasd/pkg"
|
||||||
|
provider "github.com/openfaas/faasd/pkg/provider"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_parseSecret(t *testing.T) {
|
func Test_parseSecret(t *testing.T) {
|
||||||
@ -161,3 +166,87 @@ func TestSecretCreation(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestListSecrets(t *testing.T) {
|
||||||
|
mountPath, err := os.MkdirTemp("", "test_secret_creation")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while creating temp directory: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer os.RemoveAll(mountPath)
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
name string
|
||||||
|
verb string
|
||||||
|
namespace string
|
||||||
|
labels map[string]string
|
||||||
|
status int
|
||||||
|
secretPath string
|
||||||
|
secret string
|
||||||
|
err string
|
||||||
|
expected []types.Secret
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Get empty secret list for default namespace having no secret",
|
||||||
|
verb: http.MethodGet,
|
||||||
|
status: http.StatusOK,
|
||||||
|
secretPath: "/test-fn/foo",
|
||||||
|
secret: "bar",
|
||||||
|
expected: make([]types.Secret, 0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get empty secret list for non-default namespace having no secret",
|
||||||
|
verb: http.MethodGet,
|
||||||
|
status: http.StatusOK,
|
||||||
|
secretPath: "/test-fn/foo",
|
||||||
|
secret: "bar",
|
||||||
|
expected: make([]types.Secret, 0),
|
||||||
|
namespace: "other-ns",
|
||||||
|
labels: map[string]string{
|
||||||
|
pkg.NamespaceLabel: "true",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range cases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
labelStore := provider.NewFakeLabeller(tc.labels)
|
||||||
|
|
||||||
|
handler := MakeSecretHandler(labelStore, mountPath)
|
||||||
|
|
||||||
|
path := "http://example.com/foo"
|
||||||
|
if len(tc.namespace) > 0 {
|
||||||
|
path = path + fmt.Sprintf("?namespace=%s", tc.namespace)
|
||||||
|
}
|
||||||
|
req := httptest.NewRequest(tc.verb, path, nil)
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
handler(w, req)
|
||||||
|
|
||||||
|
resp := w.Result()
|
||||||
|
if resp.StatusCode != tc.status {
|
||||||
|
t.Fatalf("want status: %d, but got: %d", tc.status, resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK && w.Body.String() != tc.err {
|
||||||
|
t.Fatalf("want error message: %q, but got %q", tc.err, w.Body.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("can't read response of list %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var res []types.Secret
|
||||||
|
err = json.Unmarshal(body, &res)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to unmarshal %q, error: %v", string(body), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(res, tc.expected) {
|
||||||
|
t.Fatalf("want response: %v, but got: %v", tc.expected, res)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -43,7 +43,7 @@ func MakeUpdateHandler(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
|
// Check if namespace exists, and it has the openfaas label
|
||||||
valid, err := validNamespace(client, namespace)
|
valid, err := validNamespace(client.NamespaceService(), namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
|
@ -5,10 +5,9 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
"github.com/containerd/containerd"
|
|
||||||
|
|
||||||
"github.com/openfaas/faasd/pkg"
|
"github.com/openfaas/faasd/pkg"
|
||||||
faasd "github.com/openfaas/faasd/pkg"
|
faasd "github.com/openfaas/faasd/pkg"
|
||||||
|
provider "github.com/openfaas/faasd/pkg/provider"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getRequestNamespace(namespace string) string {
|
func getRequestNamespace(namespace string) string {
|
||||||
@ -30,12 +29,11 @@ func getNamespaceSecretMountPath(userSecretPath string, namespace string) string
|
|||||||
|
|
||||||
// validNamespace indicates whether the namespace is eligable to be
|
// validNamespace indicates whether the namespace is eligable to be
|
||||||
// used for OpenFaaS functions.
|
// used for OpenFaaS functions.
|
||||||
func validNamespace(client *containerd.Client, namespace string) (bool, error) {
|
func validNamespace(store provider.Labeller, namespace string) (bool, error) {
|
||||||
if namespace == faasd.DefaultFunctionNamespace {
|
if namespace == faasd.DefaultFunctionNamespace {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
store := client.NamespaceService()
|
|
||||||
labels, err := store.Labels(context.Background(), namespace)
|
labels, err := store.Labels(context.Background(), namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
|
25
pkg/provider/labeller.go
Normal file
25
pkg/provider/labeller.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package provider
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
// Labeller can return labels for a namespace from containerd.
|
||||||
|
type Labeller interface {
|
||||||
|
Labels(ctx context.Context, namespace string) (map[string]string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// FakeLabeller can be used to fake labels applied on namespace to mark
|
||||||
|
// them valid/invalid for openfaas functions
|
||||||
|
type FakeLabeller struct {
|
||||||
|
labels map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFakeLabeller(labels map[string]string) Labeller {
|
||||||
|
return &FakeLabeller{
|
||||||
|
labels: labels,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FakeLabeller) Labels(ctx context.Context, namespace string) (map[string]string, error) {
|
||||||
|
return s.labels, nil
|
||||||
|
}
|
Reference in New Issue
Block a user