mirror of
https://github.com/openfaas/faasd.git
synced 2025-06-19 12:36:38 +00:00
Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
e76d0d34ba | |||
dec02f3240 | |||
73c7349e36 | |||
b8ada0d46b | |||
5ac51663da | |||
1e9d8fffa0 | |||
57322c4947 | |||
6b840f0226 |
@ -18,8 +18,8 @@ runcmd:
|
||||
- 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.12.5 https://github.com/openfaas/faasd
|
||||
- curl -fSLs "https://github.com/openfaas/faasd/releases/download/0.12.5/faasd" --output "/usr/local/bin/faasd" && chmod a+x "/usr/local/bin/faasd"
|
||||
- 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
|
||||
- journalctl -u faasd-provider --no-pager
|
||||
|
@ -1,7 +1,6 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
@ -14,6 +13,7 @@ import (
|
||||
"github.com/openfaas/faas-provider/logs"
|
||||
"github.com/openfaas/faas-provider/proxy"
|
||||
"github.com/openfaas/faas-provider/types"
|
||||
faasd "github.com/openfaas/faasd/pkg"
|
||||
"github.com/openfaas/faasd/pkg/cninetwork"
|
||||
faasdlogs "github.com/openfaas/faasd/pkg/logs"
|
||||
"github.com/openfaas/faasd/pkg/provider/config"
|
||||
@ -84,6 +84,11 @@ func makeProviderCmd() *cobra.Command {
|
||||
|
||||
userSecretPath := path.Join(wd, "secrets")
|
||||
|
||||
err = moveSecretsToDefaultNamespaceSecrets(userSecretPath, faasd.FunctionNamespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bootstrapHandlers := types.FaaSHandlers{
|
||||
FunctionProxy: proxy.NewHandlerFunc(*config, invokeResolver),
|
||||
DeleteHandler: handlers.MakeDeleteHandler(client, cni),
|
||||
@ -94,7 +99,7 @@ func makeProviderCmd() *cobra.Command {
|
||||
UpdateHandler: handlers.MakeUpdateHandler(client, cni, userSecretPath, alwaysPull),
|
||||
HealthHandler: func(w http.ResponseWriter, r *http.Request) {},
|
||||
InfoHandler: handlers.MakeInfoHandler(Version, GitCommit),
|
||||
ListNamespaceHandler: listNamespaces(),
|
||||
ListNamespaceHandler: handlers.MakeNamespacesLister(client),
|
||||
SecretHandler: handlers.MakeSecretHandler(client, userSecretPath),
|
||||
LogHandler: logs.NewLogHandlerFunc(faasdlogs.New(), config.ReadTimeout),
|
||||
}
|
||||
@ -107,10 +112,33 @@ func makeProviderCmd() *cobra.Command {
|
||||
return command
|
||||
}
|
||||
|
||||
func listNamespaces() func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
list := []string{""}
|
||||
out, _ := json.Marshal(list)
|
||||
w.Write(out)
|
||||
/*
|
||||
* Mutiple namespace support was added after release 0.13.0
|
||||
* Function will help users to migrate on multiple namespace support of faasd
|
||||
*/
|
||||
func moveSecretsToDefaultNamespaceSecrets(secretPath string, namespace string) error {
|
||||
newSecretPath := path.Join(secretPath, namespace)
|
||||
|
||||
err := ensureWorkingDir(newSecretPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
files, err := ioutil.ReadDir(secretPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, f := range files {
|
||||
if !f.IsDir() {
|
||||
oldPath := path.Join(secretPath, f.Name())
|
||||
newPath := path.Join(newSecretPath, f.Name())
|
||||
err = os.Rename(oldPath, newPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -233,7 +233,7 @@ export SUFFIX="-armhf"
|
||||
export SUFFIX="-arm64"
|
||||
|
||||
# Then download
|
||||
curl -fSLs "https://github.com/openfaas/faasd/releases/download/0.12.5/faasd$SUFFIX" \
|
||||
curl -fSLs "https://github.com/openfaas/faasd/releases/download/0.13.0/faasd$SUFFIX" \
|
||||
-o "/tmp/faasd" \
|
||||
&& chmod +x "/tmp/faasd"
|
||||
sudo mv /tmp/faasd /usr/local/bin/
|
||||
|
66
docs/bootstrap/.terraform.lock.hcl
generated
Normal file
66
docs/bootstrap/.terraform.lock.hcl
generated
Normal file
@ -0,0 +1,66 @@
|
||||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/digitalocean/digitalocean" {
|
||||
version = "2.11.0"
|
||||
constraints = "2.11.0"
|
||||
hashes = [
|
||||
"h1:/qAnTOSP5KeZkF7wqLai34SKAs7aefulcUA3I8R7rRg=",
|
||||
"h1:PbXtjUfvxwmkycJ0Y9Dyn66Arrpk5L8/P381SXMx2O0=",
|
||||
"h1:lXLX9tmuxV7azTHd0xB0FAVrxyfBtotIz5LEJp8YUk0=",
|
||||
"zh:2191adc79bdfdb3b733e0619e4f391ae91c1631c5dafda42dab561d943651fa4",
|
||||
"zh:21a4f67e42dcdc10fbd7f8579247594844d09a469a3a54862d565913e4d6121d",
|
||||
"zh:557d98325fafcf2db91ea6d92f65373a48c4e995a1a7aeb57009661fee675250",
|
||||
"zh:68c0238cafc37433627e288fcd2c7e14f4f0afdd50b4f265d8d1f1addab6f19f",
|
||||
"zh:7e6d69720734455eb1c69880f049650276089b7fa09085e130d224abaeec887a",
|
||||
"zh:95bd93a696ec050c1cb5e724498fd12b1d69760d01e97c869be3252025691434",
|
||||
"zh:b1b075049e33aa08c032f41a497351c9894f16287a4449032d8b805bc6dcb596",
|
||||
"zh:ba91aa853372c828f808c09dbab2a5bc9493a7cf93210d1487f9637b2cac8ca4",
|
||||
"zh:bc43d27dfe014266697c2ac259f4311300391aa6aa7c5d23e382fe296df938d5",
|
||||
"zh:d3a04d2c76bfc1f46a117b1af7870a97353319ee8f924a37fe77861519f59525",
|
||||
"zh:d3da997c05a653df6cabb912c6c05ceb6bf77219b699f04daf44fd795c81c6ed",
|
||||
"zh:edd0659021b6634acf0f581d1be1985a81fcd1182e3ccb43de6eac6c43be9ab4",
|
||||
"zh:f588ace57b6c35d509ecaa7136e6a8049d227b0674104a1f958359b84862d8e3",
|
||||
"zh:f894ed195a3b9ebbfa1ba7c5d71be06df3a96d783ff064d22dd693ace34d638e",
|
||||
"zh:fb6b0d4b111fafdcb3bb9a7dbab88e2110a6ce6324de64ecf62933ee8b651ccf",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/random" {
|
||||
version = "3.1.0"
|
||||
hashes = [
|
||||
"h1:BZMEPucF+pbu9gsPk0G0BHx7YP04+tKdq2MrRDF1EDM=",
|
||||
"h1:EPIax4Ftp2SNdB9pUfoSjxoueDoLc/Ck3EUoeX0Dvsg=",
|
||||
"h1:rKYu5ZUbXwrLG1w81k7H3nce/Ys6yAxXhWcbtk36HjY=",
|
||||
"zh:2bbb3339f0643b5daa07480ef4397bd23a79963cc364cdfbb4e86354cb7725bc",
|
||||
"zh:3cd456047805bf639fbf2c761b1848880ea703a054f76db51852008b11008626",
|
||||
"zh:4f251b0eda5bb5e3dc26ea4400dba200018213654b69b4a5f96abee815b4f5ff",
|
||||
"zh:7011332745ea061e517fe1319bd6c75054a314155cb2c1199a5b01fe1889a7e2",
|
||||
"zh:738ed82858317ccc246691c8b85995bc125ac3b4143043219bd0437adc56c992",
|
||||
"zh:7dbe52fac7bb21227acd7529b487511c91f4107db9cc4414f50d04ffc3cab427",
|
||||
"zh:a3a9251fb15f93e4cfc1789800fc2d7414bbc18944ad4c5c98f466e6477c42bc",
|
||||
"zh:a543ec1a3a8c20635cf374110bd2f87c07374cf2c50617eee2c669b3ceeeaa9f",
|
||||
"zh:d9ab41d556a48bd7059f0810cf020500635bfc696c9fc3adab5ea8915c1d886b",
|
||||
"zh:d9e13427a7d011dbd654e591b0337e6074eef8c3b9bb11b2e39eaaf257044fd7",
|
||||
"zh:f7605bd1437752114baf601bdf6931debe6dc6bfe3006eb7e9bb9080931dca8a",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/template" {
|
||||
version = "2.2.0"
|
||||
hashes = [
|
||||
"h1:0wlehNaxBX7GJQnPfQwTNvvAf38Jm0Nv7ssKGMaG6Og=",
|
||||
"h1:94qn780bi1qjrbC3uQtjJh3Wkfwd5+tTtJHOb7KTg9w=",
|
||||
"h1:LN84cu+BZpVRvYlCzrbPfCRDaIelSyEx/W9Iwwgbnn4=",
|
||||
"zh:01702196f0a0492ec07917db7aaa595843d8f171dc195f4c988d2ffca2a06386",
|
||||
"zh:09aae3da826ba3d7df69efeb25d146a1de0d03e951d35019a0f80e4f58c89b53",
|
||||
"zh:09ba83c0625b6fe0a954da6fbd0c355ac0b7f07f86c91a2a97849140fea49603",
|
||||
"zh:0e3a6c8e16f17f19010accd0844187d524580d9fdb0731f675ffcf4afba03d16",
|
||||
"zh:45f2c594b6f2f34ea663704cc72048b212fe7d16fb4cfd959365fa997228a776",
|
||||
"zh:77ea3e5a0446784d77114b5e851c970a3dde1e08fa6de38210b8385d7605d451",
|
||||
"zh:8a154388f3708e3df5a69122a23bdfaf760a523788a5081976b3d5616f7d30ae",
|
||||
"zh:992843002f2db5a11e626b3fc23dc0c87ad3729b3b3cff08e32ffb3df97edbde",
|
||||
"zh:ad906f4cebd3ec5e43d5cd6dc8f4c5c9cc3b33d2243c89c5fc18f97f7277b51d",
|
||||
"zh:c979425ddb256511137ecd093e23283234da0154b7fa8b21c2687182d9aea8b2",
|
||||
]
|
||||
}
|
@ -5,11 +5,18 @@
|
||||
3) Clone this gist using the URL from the address bar
|
||||
4) Run `terraform init`
|
||||
5) Run `terraform apply -var="do_token=$(cat $HOME/digitalocean-access-token)"`
|
||||
6) View the output for the login command and gateway URL i.e.
|
||||
6) View the output for the gateway URL
|
||||
|
||||
```
|
||||
gateway_url = http://178.128.39.201:8080/
|
||||
```
|
||||
7) View the output for sensitive data via `terraform output` command
|
||||
|
||||
```bash
|
||||
terraform output login_cmd
|
||||
login_cmd = faas-cli login -g http://178.128.39.201:8080/ -p rvIU49CEcFcHmqxj
|
||||
|
||||
terraform output password
|
||||
password = rvIU49CEcFcHmqxj
|
||||
```
|
||||
|
||||
|
@ -1,8 +1,4 @@
|
||||
#cloud-config
|
||||
ssh_authorized_keys:
|
||||
## Note: Replace with your own public key
|
||||
- ${ssh_key}
|
||||
|
||||
package_update: true
|
||||
|
||||
packages:
|
||||
@ -20,8 +16,8 @@ runcmd:
|
||||
- mkdir -p /var/lib/faasd/secrets/
|
||||
- echo ${gw_password} > /var/lib/faasd/secrets/basic-auth-password
|
||||
- echo admin > /var/lib/faasd/secrets/basic-auth-user
|
||||
- cd /go/src/github.com/openfaas/ && git clone --depth 1 --branch 0.12.5 https://github.com/openfaas/faasd
|
||||
- curl -fSLs "https://github.com/openfaas/faasd/releases/download/0.12.5/faasd" --output "/usr/local/bin/faasd" && chmod a+x "/usr/local/bin/faasd"
|
||||
- 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
|
||||
- journalctl -u faasd-provider --no-pager
|
||||
|
66
docs/bootstrap/digitalocean-terraform/.terraform.lock.hcl
generated
Normal file
66
docs/bootstrap/digitalocean-terraform/.terraform.lock.hcl
generated
Normal file
@ -0,0 +1,66 @@
|
||||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/digitalocean/digitalocean" {
|
||||
version = "2.11.0"
|
||||
constraints = "2.11.0"
|
||||
hashes = [
|
||||
"h1:/qAnTOSP5KeZkF7wqLai34SKAs7aefulcUA3I8R7rRg=",
|
||||
"h1:PbXtjUfvxwmkycJ0Y9Dyn66Arrpk5L8/P381SXMx2O0=",
|
||||
"h1:lXLX9tmuxV7azTHd0xB0FAVrxyfBtotIz5LEJp8YUk0=",
|
||||
"zh:2191adc79bdfdb3b733e0619e4f391ae91c1631c5dafda42dab561d943651fa4",
|
||||
"zh:21a4f67e42dcdc10fbd7f8579247594844d09a469a3a54862d565913e4d6121d",
|
||||
"zh:557d98325fafcf2db91ea6d92f65373a48c4e995a1a7aeb57009661fee675250",
|
||||
"zh:68c0238cafc37433627e288fcd2c7e14f4f0afdd50b4f265d8d1f1addab6f19f",
|
||||
"zh:7e6d69720734455eb1c69880f049650276089b7fa09085e130d224abaeec887a",
|
||||
"zh:95bd93a696ec050c1cb5e724498fd12b1d69760d01e97c869be3252025691434",
|
||||
"zh:b1b075049e33aa08c032f41a497351c9894f16287a4449032d8b805bc6dcb596",
|
||||
"zh:ba91aa853372c828f808c09dbab2a5bc9493a7cf93210d1487f9637b2cac8ca4",
|
||||
"zh:bc43d27dfe014266697c2ac259f4311300391aa6aa7c5d23e382fe296df938d5",
|
||||
"zh:d3a04d2c76bfc1f46a117b1af7870a97353319ee8f924a37fe77861519f59525",
|
||||
"zh:d3da997c05a653df6cabb912c6c05ceb6bf77219b699f04daf44fd795c81c6ed",
|
||||
"zh:edd0659021b6634acf0f581d1be1985a81fcd1182e3ccb43de6eac6c43be9ab4",
|
||||
"zh:f588ace57b6c35d509ecaa7136e6a8049d227b0674104a1f958359b84862d8e3",
|
||||
"zh:f894ed195a3b9ebbfa1ba7c5d71be06df3a96d783ff064d22dd693ace34d638e",
|
||||
"zh:fb6b0d4b111fafdcb3bb9a7dbab88e2110a6ce6324de64ecf62933ee8b651ccf",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/random" {
|
||||
version = "3.1.0"
|
||||
hashes = [
|
||||
"h1:BZMEPucF+pbu9gsPk0G0BHx7YP04+tKdq2MrRDF1EDM=",
|
||||
"h1:EPIax4Ftp2SNdB9pUfoSjxoueDoLc/Ck3EUoeX0Dvsg=",
|
||||
"h1:rKYu5ZUbXwrLG1w81k7H3nce/Ys6yAxXhWcbtk36HjY=",
|
||||
"zh:2bbb3339f0643b5daa07480ef4397bd23a79963cc364cdfbb4e86354cb7725bc",
|
||||
"zh:3cd456047805bf639fbf2c761b1848880ea703a054f76db51852008b11008626",
|
||||
"zh:4f251b0eda5bb5e3dc26ea4400dba200018213654b69b4a5f96abee815b4f5ff",
|
||||
"zh:7011332745ea061e517fe1319bd6c75054a314155cb2c1199a5b01fe1889a7e2",
|
||||
"zh:738ed82858317ccc246691c8b85995bc125ac3b4143043219bd0437adc56c992",
|
||||
"zh:7dbe52fac7bb21227acd7529b487511c91f4107db9cc4414f50d04ffc3cab427",
|
||||
"zh:a3a9251fb15f93e4cfc1789800fc2d7414bbc18944ad4c5c98f466e6477c42bc",
|
||||
"zh:a543ec1a3a8c20635cf374110bd2f87c07374cf2c50617eee2c669b3ceeeaa9f",
|
||||
"zh:d9ab41d556a48bd7059f0810cf020500635bfc696c9fc3adab5ea8915c1d886b",
|
||||
"zh:d9e13427a7d011dbd654e591b0337e6074eef8c3b9bb11b2e39eaaf257044fd7",
|
||||
"zh:f7605bd1437752114baf601bdf6931debe6dc6bfe3006eb7e9bb9080931dca8a",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/template" {
|
||||
version = "2.2.0"
|
||||
hashes = [
|
||||
"h1:0wlehNaxBX7GJQnPfQwTNvvAf38Jm0Nv7ssKGMaG6Og=",
|
||||
"h1:94qn780bi1qjrbC3uQtjJh3Wkfwd5+tTtJHOb7KTg9w=",
|
||||
"h1:LN84cu+BZpVRvYlCzrbPfCRDaIelSyEx/W9Iwwgbnn4=",
|
||||
"zh:01702196f0a0492ec07917db7aaa595843d8f171dc195f4c988d2ffca2a06386",
|
||||
"zh:09aae3da826ba3d7df69efeb25d146a1de0d03e951d35019a0f80e4f58c89b53",
|
||||
"zh:09ba83c0625b6fe0a954da6fbd0c355ac0b7f07f86c91a2a97849140fea49603",
|
||||
"zh:0e3a6c8e16f17f19010accd0844187d524580d9fdb0731f675ffcf4afba03d16",
|
||||
"zh:45f2c594b6f2f34ea663704cc72048b212fe7d16fb4cfd959365fa997228a776",
|
||||
"zh:77ea3e5a0446784d77114b5e851c970a3dde1e08fa6de38210b8385d7605d451",
|
||||
"zh:8a154388f3708e3df5a69122a23bdfaf760a523788a5081976b3d5616f7d30ae",
|
||||
"zh:992843002f2db5a11e626b3fc23dc0c87ad3729b3b3cff08e32ffb3df97edbde",
|
||||
"zh:ad906f4cebd3ec5e43d5cd6dc8f4c5c9cc3b33d2243c89c5fc18f97f7277b51d",
|
||||
"zh:c979425ddb256511137ecd093e23283234da0154b7fa8b21c2687182d9aea8b2",
|
||||
]
|
||||
}
|
@ -27,10 +27,20 @@
|
||||
```
|
||||
droplet_ip = 178.128.39.201
|
||||
gateway_url = https://faasd.example.com/
|
||||
login_cmd = faas-cli login -g https://faasd.example.com/ -p rvIU49CEcFcHmqxj
|
||||
```
|
||||
|
||||
8) View the output for sensitive data via `terraform output` command
|
||||
|
||||
```bash
|
||||
terraform output login_cmd
|
||||
login_cmd = faas-cli login -g http://178.128.39.201:8080/ -p rvIU49CEcFcHmqxj
|
||||
|
||||
terraform output password
|
||||
password = rvIU49CEcFcHmqxj
|
||||
```
|
||||
8) Use your browser to access the OpenFaaS interface
|
||||
|
||||
|
||||
9) Use your browser to access the OpenFaaS interface
|
||||
|
||||
Note that the user-data may take a couple of minutes to come up since it will be pulling in various components and preparing the machine.
|
||||
Also take into consideration the DNS propagation time for the new DNS record.
|
||||
|
@ -1,7 +1,4 @@
|
||||
#cloud-config
|
||||
ssh_authorized_keys:
|
||||
- ${ssh_key}
|
||||
|
||||
groups:
|
||||
- caddy
|
||||
|
||||
@ -41,8 +38,8 @@ runcmd:
|
||||
- mkdir -p /var/lib/faasd/secrets/
|
||||
- echo ${gw_password} > /var/lib/faasd/secrets/basic-auth-password
|
||||
- echo admin > /var/lib/faasd/secrets/basic-auth-user
|
||||
- cd /go/src/github.com/openfaas/ && git clone --depth 1 --branch 0.12.5 https://github.com/openfaas/faasd
|
||||
- curl -fSLs "https://github.com/openfaas/faasd/releases/download/0.12.5/faasd" --output "/usr/local/bin/faasd" && chmod a+x "/usr/local/bin/faasd"
|
||||
- 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
|
||||
- journalctl -u faasd-provider --no-pager
|
||||
|
@ -1,5 +1,11 @@
|
||||
terraform {
|
||||
required_version = ">= 0.12"
|
||||
required_version = ">= 1.0.4"
|
||||
required_providers {
|
||||
digitalocean = {
|
||||
source = "digitalocean/digitalocean"
|
||||
version = "2.11.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
variable "do_token" {
|
||||
@ -10,7 +16,7 @@ variable "do_domain" {
|
||||
}
|
||||
variable "do_subdomain" {
|
||||
description = "Your public subdomain"
|
||||
default = "faasd"
|
||||
default = "faasd"
|
||||
}
|
||||
variable "letsencrypt_email" {
|
||||
description = "Email used to order a certificate from Letsencrypt"
|
||||
@ -32,41 +38,44 @@ provider "digitalocean" {
|
||||
token = var.do_token
|
||||
}
|
||||
|
||||
data "local_file" "ssh_key"{
|
||||
filename = pathexpand(var.ssh_key_file)
|
||||
}
|
||||
|
||||
resource "random_password" "password" {
|
||||
length = 16
|
||||
special = true
|
||||
length = 16
|
||||
special = true
|
||||
override_special = "_-#"
|
||||
}
|
||||
|
||||
data "template_file" "cloud_init" {
|
||||
template = "${file("cloud-config.tpl")}"
|
||||
vars = {
|
||||
gw_password=random_password.password.result,
|
||||
ssh_key=data.local_file.ssh_key.content,
|
||||
faasd_domain_name="${var.do_subdomain}.${var.do_domain}"
|
||||
letsencrypt_email=var.letsencrypt_email
|
||||
}
|
||||
template = file("cloud-config.tpl")
|
||||
vars = {
|
||||
gw_password = random_password.password.result,
|
||||
faasd_domain_name = "${var.do_subdomain}.${var.do_domain}"
|
||||
letsencrypt_email = var.letsencrypt_email
|
||||
}
|
||||
}
|
||||
|
||||
resource "digitalocean_ssh_key" "faasd_ssh_key" {
|
||||
name = "ssh-key"
|
||||
public_key = file(var.ssh_key_file)
|
||||
}
|
||||
|
||||
resource "digitalocean_droplet" "faasd" {
|
||||
region = var.do_region
|
||||
image = "ubuntu-18-04-x64"
|
||||
name = "faasd"
|
||||
size = "s-1vcpu-1gb"
|
||||
region = var.do_region
|
||||
image = "ubuntu-18-04-x64"
|
||||
name = "faasd"
|
||||
size = "s-1vcpu-1gb"
|
||||
user_data = data.template_file.cloud_init.rendered
|
||||
ssh_keys = [
|
||||
digitalocean_ssh_key.faasd_ssh_key.id
|
||||
]
|
||||
}
|
||||
|
||||
resource "digitalocean_record" "faasd" {
|
||||
domain = var.do_domain
|
||||
type = "A"
|
||||
name = "faasd"
|
||||
name = var.do_subdomain
|
||||
value = digitalocean_droplet.faasd.ipv4_address
|
||||
# Only creates record if do_create_record is true
|
||||
count = var.do_create_record == true ? 1 : 0
|
||||
count = var.do_create_record == true ? 1 : 0
|
||||
}
|
||||
|
||||
output "droplet_ip" {
|
||||
@ -78,9 +87,11 @@ output "gateway_url" {
|
||||
}
|
||||
|
||||
output "password" {
|
||||
value = random_password.password.result
|
||||
value = random_password.password.result
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
output "login_cmd" {
|
||||
value = "faas-cli login -g https://${var.do_subdomain}.${var.do_domain}/ -p ${random_password.password.result}"
|
||||
value = "faas-cli login -g https://${var.do_subdomain}.${var.do_domain}/ -p ${random_password.password.result}"
|
||||
sensitive = true
|
||||
}
|
||||
|
@ -1,5 +1,11 @@
|
||||
terraform {
|
||||
required_version = ">= 0.12"
|
||||
required_version = ">= 1.0.4"
|
||||
required_providers {
|
||||
digitalocean = {
|
||||
source = "digitalocean/digitalocean"
|
||||
version = "2.11.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
variable "do_token" {}
|
||||
@ -10,25 +16,25 @@ variable "ssh_key_file" {
|
||||
}
|
||||
|
||||
provider "digitalocean" {
|
||||
token = var.do_token
|
||||
token = var.do_token
|
||||
}
|
||||
|
||||
resource "random_password" "password" {
|
||||
length = 16
|
||||
special = true
|
||||
length = 16
|
||||
special = true
|
||||
override_special = "_-#"
|
||||
}
|
||||
|
||||
data "local_file" "ssh_key"{
|
||||
filename = pathexpand(var.ssh_key_file)
|
||||
data "template_file" "cloud_init" {
|
||||
template = file("cloud-config.tpl")
|
||||
vars = {
|
||||
gw_password = random_password.password.result
|
||||
}
|
||||
}
|
||||
|
||||
data "template_file" "cloud_init" {
|
||||
template = "${file("cloud-config.tpl")}"
|
||||
vars = {
|
||||
gw_password=random_password.password.result,
|
||||
ssh_key=data.local_file.ssh_key.content,
|
||||
}
|
||||
resource "digitalocean_ssh_key" "faasd_ssh_key" {
|
||||
name = "ssh-key"
|
||||
public_key = file(var.ssh_key_file)
|
||||
}
|
||||
|
||||
resource "digitalocean_droplet" "faasd" {
|
||||
@ -38,12 +44,16 @@ resource "digitalocean_droplet" "faasd" {
|
||||
name = "faasd"
|
||||
# Plans: https://developers.digitalocean.com/documentation/changelog/api-v2/new-size-slugs-for-droplet-plan-changes/
|
||||
#size = "512mb"
|
||||
size = "s-1vcpu-1gb"
|
||||
size = "s-1vcpu-1gb"
|
||||
user_data = data.template_file.cloud_init.rendered
|
||||
ssh_keys = [
|
||||
digitalocean_ssh_key.faasd_ssh_key.id
|
||||
]
|
||||
}
|
||||
|
||||
output "password" {
|
||||
value = random_password.password.result
|
||||
value = random_password.password.result
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
output "gateway_url" {
|
||||
@ -51,6 +61,7 @@ output "gateway_url" {
|
||||
}
|
||||
|
||||
output "login_cmd" {
|
||||
value = "faas-cli login -g http://${digitalocean_droplet.faasd.ipv4_address}:8080/ -p ${random_password.password.result}"
|
||||
value = "faas-cli login -g http://${digitalocean_droplet.faasd.ipv4_address}:8080/ -p ${random_password.password.result}"
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
|
37
hack/build-containerd-arm64.sh
Normal file
37
hack/build-containerd-arm64.sh
Normal file
@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
|
||||
# See pre-reqs:
|
||||
# https://github.com/alexellis/containerd-arm
|
||||
|
||||
export ARCH="arm64"
|
||||
|
||||
if [ ! -d "/usr/local/go/bin" ]; then
|
||||
echo "Downloading Go.."
|
||||
|
||||
curl -SLsf https://golang.org/dl/go1.16.6.linux-$ARCH.tar.gz --output /tmp/go.tgz
|
||||
sudo rm -rf /usr/local/go/
|
||||
sudo mkdir -p /usr/local/go/
|
||||
sudo tar -xvf /tmp/go.tgz -C /usr/local/go/ --strip-components=1
|
||||
else
|
||||
echo "Go already present, skipping."
|
||||
fi
|
||||
|
||||
export GOPATH=$HOME/go/
|
||||
export PATH=$PATH:/usr/local/go/bin/
|
||||
|
||||
go version
|
||||
|
||||
echo "Building containerd"
|
||||
|
||||
mkdir -p $GOPATH/src/github.com/containerd
|
||||
cd $GOPATH/src/github.com/containerd
|
||||
git clone https://github.com/containerd/containerd
|
||||
|
||||
cd containerd
|
||||
git fetch origin --tags
|
||||
git checkout v1.5.4
|
||||
|
||||
make
|
||||
sudo make install
|
||||
|
||||
sudo containerd --version
|
@ -1,12 +1,20 @@
|
||||
#!/bin/bash
|
||||
|
||||
export ARCH="armv6l"
|
||||
echo "Downloading Go"
|
||||
# See pre-reqs:
|
||||
# https://github.com/alexellis/containerd-arm
|
||||
|
||||
curl -SLsf https://golang.org/dl/go1.16.6.linux-$ARCH.tar.gz --output /tmp/go.tgz
|
||||
sudo rm -rf /usr/local/go/
|
||||
sudo mkdir -p /usr/local/go/
|
||||
sudo tar -xvf /tmp/go.tgz -C /usr/local/go/ --strip-components=1
|
||||
export ARCH="arm64"
|
||||
|
||||
if [ ! -d "/usr/local/go/bin" ]; then
|
||||
echo "Downloading Go.."
|
||||
|
||||
curl -SLsf https://golang.org/dl/go1.16.6.linux-$ARCH.tar.gz --output /tmp/go.tgz
|
||||
sudo rm -rf /usr/local/go/
|
||||
sudo mkdir -p /usr/local/go/
|
||||
sudo tar -xvf /tmp/go.tgz -C /usr/local/go/ --strip-components=1
|
||||
else
|
||||
echo "Go already present, skipping."
|
||||
fi
|
||||
|
||||
export GOPATH=$HOME/go/
|
||||
export PATH=$PATH:/usr/local/go/bin/
|
||||
|
@ -1,12 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
export ARCH="amd64"
|
||||
echo "Downloading Go"
|
||||
|
||||
curl -SLsf https://golang.org/dl/go1.16.6.linux-$ARCH.tar.gz --output /tmp/go.tgz
|
||||
sudo rm -rf /usr/local/go/
|
||||
sudo mkdir -p /usr/local/go/
|
||||
sudo tar -xvf /tmp/go.tgz -C /usr/local/go/ --strip-components=1
|
||||
# See pre-reqs:
|
||||
# https://github.com/alexellis/containerd-arm
|
||||
|
||||
export ARCH="arm64"
|
||||
|
||||
if [ ! -d "/usr/local/go/bin" ]; then
|
||||
echo "Downloading Go.."
|
||||
|
||||
curl -SLsf https://golang.org/dl/go1.16.6.linux-$ARCH.tar.gz --output /tmp/go.tgz
|
||||
sudo rm -rf /usr/local/go/
|
||||
sudo mkdir -p /usr/local/go/
|
||||
sudo tar -xvf /tmp/go.tgz -C /usr/local/go/ --strip-components=1
|
||||
else
|
||||
echo "Go already present, skipping."
|
||||
fi
|
||||
|
||||
export GOPATH=$HOME/go/
|
||||
export PATH=$PATH:/usr/local/go/bin/
|
||||
|
@ -5,6 +5,7 @@ Description=faasd-provider
|
||||
MemoryLimit=500M
|
||||
Environment="secret_mount_path={{.SecretMountPath}}"
|
||||
Environment="basic_auth=true"
|
||||
Environment="hosts_dir=/var/lib/faasd"
|
||||
ExecStart=/usr/local/bin/faasd provider
|
||||
Restart=on-failure
|
||||
RestartSec=10s
|
||||
|
@ -39,6 +39,10 @@ has_apt_get() {
|
||||
[ -n "$(command -v apt-get)" ]
|
||||
}
|
||||
|
||||
has_pacman() {
|
||||
[ -n "$(command -v pacman)" ]
|
||||
}
|
||||
|
||||
install_required_packages() {
|
||||
if $(has_apt_get); then
|
||||
$SUDO apt-get update -y
|
||||
@ -46,8 +50,11 @@ install_required_packages() {
|
||||
elif $(has_yum); then
|
||||
$SUDO yum check-update -y
|
||||
$SUDO yum install -y curl runc
|
||||
elif $(has_pacman); then
|
||||
$SUDO pacman -Syy
|
||||
$SUDO pacman -Sy curl runc bridge-utils
|
||||
else
|
||||
fatal "Could not find apt-get or yum. Cannot install dependencies on this OS."
|
||||
fatal "Could not find apt-get, yum, or pacman. Cannot install dependencies on this OS."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
@ -4,8 +4,8 @@ const (
|
||||
// FunctionNamespace is the default containerd namespace functions are created
|
||||
FunctionNamespace = "openfaas-fn"
|
||||
|
||||
// faasdNamespace is the containerd namespace services are created
|
||||
faasdNamespace = "openfaas"
|
||||
// FaasdNamespace is the containerd namespace services are created
|
||||
FaasdNamespace = "openfaas"
|
||||
|
||||
faasServicesPullAlways = false
|
||||
|
||||
|
@ -13,7 +13,6 @@ import (
|
||||
gocni "github.com/containerd/go-cni"
|
||||
"github.com/openfaas/faas/gateway/requests"
|
||||
|
||||
faasd "github.com/openfaas/faasd/pkg"
|
||||
cninetwork "github.com/openfaas/faasd/pkg/cninetwork"
|
||||
"github.com/openfaas/faasd/pkg/service"
|
||||
)
|
||||
@ -41,9 +40,11 @@ func MakeDeleteHandler(client *containerd.Client, cni gocni.CNI) func(w http.Res
|
||||
return
|
||||
}
|
||||
|
||||
lookupNamespace := getRequestNamespace(readNamespaceFromQuery(r))
|
||||
|
||||
name := req.FunctionName
|
||||
|
||||
function, err := GetFunction(client, name)
|
||||
function, err := GetFunction(client, name, lookupNamespace)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("service %s not found", name)
|
||||
log.Printf("[Delete] %s\n", msg)
|
||||
@ -51,7 +52,7 @@ func MakeDeleteHandler(client *containerd.Client, cni gocni.CNI) func(w http.Res
|
||||
return
|
||||
}
|
||||
|
||||
ctx := namespaces.WithNamespace(context.Background(), faasd.FunctionNamespace)
|
||||
ctx := namespaces.WithNamespace(context.Background(), lookupNamespace)
|
||||
|
||||
// TODO: this needs to still happen if the task is paused
|
||||
if function.replicas != 0 {
|
||||
|
@ -20,7 +20,6 @@ import (
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/openfaas/faas-provider/types"
|
||||
faasd "github.com/openfaas/faasd/pkg"
|
||||
cninetwork "github.com/openfaas/faasd/pkg/cninetwork"
|
||||
"github.com/openfaas/faasd/pkg/service"
|
||||
"github.com/pkg/errors"
|
||||
@ -52,15 +51,17 @@ func MakeDeployHandler(client *containerd.Client, cni gocni.CNI, secretMountPath
|
||||
return
|
||||
}
|
||||
|
||||
err = validateSecrets(secretMountPath, req.Secrets)
|
||||
namespace := getRequestNamespace(req.Namespace)
|
||||
namespaceSecretMountPath := getNamespaceSecretMountPath(secretMountPath, namespace)
|
||||
err = validateSecrets(namespaceSecretMountPath, req.Secrets)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
}
|
||||
|
||||
name := req.Service
|
||||
ctx := namespaces.WithNamespace(context.Background(), faasd.FunctionNamespace)
|
||||
ctx := namespaces.WithNamespace(context.Background(), namespace)
|
||||
|
||||
deployErr := deploy(ctx, req, client, cni, secretMountPath, alwaysPull)
|
||||
deployErr := deploy(ctx, req, client, cni, namespaceSecretMountPath, alwaysPull)
|
||||
if deployErr != nil {
|
||||
log.Printf("[Deploy] error deploying %s, error: %s\n", name, deployErr)
|
||||
http.Error(w, deployErr.Error(), http.StatusBadRequest)
|
||||
@ -247,19 +248,25 @@ func prepareEnv(envProcess string, reqEnvVars map[string]string) []string {
|
||||
}
|
||||
|
||||
func getMounts() []specs.Mount {
|
||||
wd, _ := os.Getwd()
|
||||
// Prior to hosts_dir env-var, this value was set to
|
||||
// os.Getwd()
|
||||
hostsDir := "/var/lib/faasd"
|
||||
if v, ok := os.LookupEnv("hosts_dir"); ok && len(v) > 0 {
|
||||
hostsDir = v
|
||||
}
|
||||
|
||||
mounts := []specs.Mount{}
|
||||
mounts = append(mounts, specs.Mount{
|
||||
Destination: "/etc/resolv.conf",
|
||||
Type: "bind",
|
||||
Source: path.Join(wd, "resolv.conf"),
|
||||
Source: path.Join(hostsDir, "resolv.conf"),
|
||||
Options: []string{"rbind", "ro"},
|
||||
})
|
||||
|
||||
mounts = append(mounts, specs.Mount{
|
||||
Destination: "/etc/hosts",
|
||||
Type: "bind",
|
||||
Source: path.Join(wd, "hosts"),
|
||||
Source: path.Join(hostsDir, "hosts"),
|
||||
Options: []string{"rbind", "ro"},
|
||||
})
|
||||
return mounts
|
||||
|
@ -11,9 +11,8 @@ import (
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/openfaas/faasd/pkg/cninetwork"
|
||||
|
||||
faasd "github.com/openfaas/faasd/pkg"
|
||||
"github.com/openfaas/faasd/pkg/cninetwork"
|
||||
)
|
||||
|
||||
type Function struct {
|
||||
@ -32,8 +31,8 @@ type Function struct {
|
||||
}
|
||||
|
||||
// ListFunctions returns a map of all functions with running tasks on namespace
|
||||
func ListFunctions(client *containerd.Client) (map[string]*Function, error) {
|
||||
ctx := namespaces.WithNamespace(context.Background(), faasd.FunctionNamespace)
|
||||
func ListFunctions(client *containerd.Client, namespace string) (map[string]*Function, error) {
|
||||
ctx := namespaces.WithNamespace(context.Background(), namespace)
|
||||
functions := make(map[string]*Function)
|
||||
|
||||
containers, err := client.Containers(ctx)
|
||||
@ -43,7 +42,7 @@ func ListFunctions(client *containerd.Client) (map[string]*Function, error) {
|
||||
|
||||
for _, c := range containers {
|
||||
name := c.ID()
|
||||
f, err := GetFunction(client, name)
|
||||
f, err := GetFunction(client, name, namespace)
|
||||
if err != nil {
|
||||
log.Printf("error getting function %s: ", name)
|
||||
return functions, err
|
||||
@ -55,8 +54,8 @@ func ListFunctions(client *containerd.Client) (map[string]*Function, error) {
|
||||
}
|
||||
|
||||
// GetFunction returns a function that matches name
|
||||
func GetFunction(client *containerd.Client, name string) (Function, error) {
|
||||
ctx := namespaces.WithNamespace(context.Background(), faasd.FunctionNamespace)
|
||||
func GetFunction(client *containerd.Client, name string, namespace string) (Function, error) {
|
||||
ctx := namespaces.WithNamespace(context.Background(), namespace)
|
||||
fn := Function{}
|
||||
|
||||
c, err := client.LoadContainer(ctx, name)
|
||||
@ -92,7 +91,7 @@ func GetFunction(client *containerd.Client, name string) (Function, error) {
|
||||
secrets := readSecretsFromMounts(spec.Mounts)
|
||||
|
||||
fn.name = containerName
|
||||
fn.namespace = faasd.FunctionNamespace
|
||||
fn.namespace = namespace
|
||||
fn.image = image.Name()
|
||||
fn.labels = labels
|
||||
fn.annotations = annotations
|
||||
@ -181,3 +180,41 @@ func buildLabelsAndAnnotations(ctrLabels map[string]string) (map[string]string,
|
||||
|
||||
return labels, annotations
|
||||
}
|
||||
|
||||
func ListNamespaces(client *containerd.Client) []string {
|
||||
set := []string{}
|
||||
store := client.NamespaceService()
|
||||
namespaces, err := store.List(context.Background())
|
||||
if err != nil {
|
||||
log.Printf("Error listing namespaces: %s", err.Error())
|
||||
set = append(set, faasd.FunctionNamespace)
|
||||
return set
|
||||
}
|
||||
|
||||
for _, namespace := range namespaces {
|
||||
labels, err := store.Labels(context.Background(), namespace)
|
||||
if err != nil {
|
||||
log.Printf("Error listing label for namespace %s: %s", namespace, err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
if _, found := labels["openfaas"]; found {
|
||||
set = append(set, namespace)
|
||||
}
|
||||
|
||||
if !findNamespace(faasd.FunctionNamespace, set) {
|
||||
set = append(set, faasd.FunctionNamespace)
|
||||
}
|
||||
}
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
func findNamespace(target string, items []string) bool {
|
||||
for _, n := range items {
|
||||
if n == target {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -2,9 +2,10 @@ package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
func Test_BuildLabelsAndAnnotationsFromServiceSpec_Annotations(t *testing.T) {
|
||||
@ -84,3 +85,25 @@ func Test_ProcessEnvToEnvVars(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_findNamespace(t *testing.T) {
|
||||
type test struct {
|
||||
Name string
|
||||
foundNamespaces []string
|
||||
namespace string
|
||||
Expected bool
|
||||
}
|
||||
tests := []test{
|
||||
{Name: "Namespace Found", namespace: "fn", foundNamespaces: []string{"fn", "openfaas-fn"}, Expected: true},
|
||||
{Name: "namespace Not Found", namespace: "fn", foundNamespaces: []string{"openfaas-fn"}, Expected: false},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
got := findNamespace(tc.namespace, tc.foundNamespaces)
|
||||
if got != tc.Expected {
|
||||
t.Fatalf("expected %t, got %t", tc.Expected, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,10 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
faasd "github.com/openfaas/faasd/pkg"
|
||||
)
|
||||
|
||||
const watchdogPort = 8080
|
||||
@ -19,11 +21,18 @@ func NewInvokeResolver(client *containerd.Client) *InvokeResolver {
|
||||
}
|
||||
|
||||
func (i *InvokeResolver) Resolve(functionName string) (url.URL, error) {
|
||||
log.Printf("Resolve: %q\n", functionName)
|
||||
actualFunctionName := functionName
|
||||
log.Printf("Resolve: %q\n", actualFunctionName)
|
||||
|
||||
function, err := GetFunction(i.client, functionName)
|
||||
namespace := getNamespace(functionName, faasd.FunctionNamespace)
|
||||
|
||||
if strings.Contains(functionName, ".") {
|
||||
actualFunctionName = strings.TrimSuffix(functionName, "."+namespace)
|
||||
}
|
||||
|
||||
function, err := GetFunction(i.client, actualFunctionName, namespace)
|
||||
if err != nil {
|
||||
return url.URL{}, fmt.Errorf("%s not found", functionName)
|
||||
return url.URL{}, fmt.Errorf("%s not found", actualFunctionName)
|
||||
}
|
||||
|
||||
serviceIP := function.IP
|
||||
@ -37,3 +46,11 @@ func (i *InvokeResolver) Resolve(functionName string) (url.URL, error) {
|
||||
|
||||
return *urlRes, nil
|
||||
}
|
||||
|
||||
func getNamespace(name, defaultNamespace string) string {
|
||||
namespace := defaultNamespace
|
||||
if strings.Contains(name, ".") {
|
||||
namespace = name[strings.LastIndexAny(name, ".")+1:]
|
||||
}
|
||||
return namespace
|
||||
}
|
||||
|
18
pkg/provider/handlers/namespaces.go
Normal file
18
pkg/provider/handlers/namespaces.go
Normal file
@ -0,0 +1,18 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
)
|
||||
|
||||
func MakeNamespacesLister(client *containerd.Client) func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
list := ListNamespaces(client)
|
||||
body, _ := json.Marshal(list)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(body)
|
||||
}
|
||||
}
|
@ -13,8 +13,10 @@ func MakeReadHandler(client *containerd.Client) func(w http.ResponseWriter, r *h
|
||||
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
lookupNamespace := getRequestNamespace(readNamespaceFromQuery(r))
|
||||
|
||||
res := []types.FunctionStatus{}
|
||||
fns, err := ListFunctions(client)
|
||||
fns, err := ListFunctions(client, lookupNamespace)
|
||||
if err != nil {
|
||||
log.Printf("[Read] error listing functions. Error: %s\n", err)
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
|
@ -14,8 +14,9 @@ func MakeReplicaReaderHandler(client *containerd.Client) func(w http.ResponseWri
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
functionName := vars["name"]
|
||||
lookupNamespace := getRequestNamespace(readNamespaceFromQuery(r))
|
||||
|
||||
if f, err := GetFunction(client, functionName); err == nil {
|
||||
if f, err := GetFunction(client, functionName, lookupNamespace); err == nil {
|
||||
found := types.FunctionStatus{
|
||||
Name: functionName,
|
||||
AvailableReplicas: uint64(f.replicas),
|
||||
|
@ -13,7 +13,6 @@ import (
|
||||
gocni "github.com/containerd/go-cni"
|
||||
|
||||
"github.com/openfaas/faas-provider/types"
|
||||
faasd "github.com/openfaas/faasd/pkg"
|
||||
)
|
||||
|
||||
func MakeReplicaUpdateHandler(client *containerd.Client, cni gocni.CNI) func(w http.ResponseWriter, r *http.Request) {
|
||||
@ -40,16 +39,18 @@ func MakeReplicaUpdateHandler(client *containerd.Client, cni gocni.CNI) func(w h
|
||||
return
|
||||
}
|
||||
|
||||
namespace := getRequestNamespace(readNamespaceFromQuery(r))
|
||||
|
||||
name := req.ServiceName
|
||||
|
||||
if _, err := GetFunction(client, name); err != nil {
|
||||
if _, err := GetFunction(client, name, namespace); err != nil {
|
||||
msg := fmt.Sprintf("service %s not found", name)
|
||||
log.Printf("[Scale] %s\n", msg)
|
||||
http.Error(w, msg, http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := namespaces.WithNamespace(context.Background(), faasd.FunctionNamespace)
|
||||
ctx := namespaces.WithNamespace(context.Background(), namespace)
|
||||
|
||||
ctr, ctrErr := client.LoadContainer(ctx, name)
|
||||
if ctrErr != nil {
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
)
|
||||
|
||||
const secretFilePermission = 0644
|
||||
const secretDirPermission = 0755
|
||||
|
||||
func MakeSecretHandler(c *containerd.Client, mountPath string) func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@ -46,6 +47,10 @@ func MakeSecretHandler(c *containerd.Client, mountPath string) func(w http.Respo
|
||||
}
|
||||
|
||||
func listSecrets(c *containerd.Client, w http.ResponseWriter, r *http.Request, mountPath string) {
|
||||
|
||||
lookupNamespace := getRequestNamespace(readNamespaceFromQuery(r))
|
||||
mountPath = getNamespaceSecretMountPath(mountPath, lookupNamespace)
|
||||
|
||||
files, err := ioutil.ReadDir(mountPath)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@ -54,7 +59,7 @@ func listSecrets(c *containerd.Client, w http.ResponseWriter, r *http.Request, m
|
||||
|
||||
secrets := []types.Secret{}
|
||||
for _, f := range files {
|
||||
secrets = append(secrets, types.Secret{Name: f.Name()})
|
||||
secrets = append(secrets, types.Secret{Name: f.Name(), Namespace: lookupNamespace})
|
||||
}
|
||||
|
||||
bytesOut, _ := json.Marshal(secrets)
|
||||
@ -69,6 +74,16 @@ func createSecret(c *containerd.Client, w http.ResponseWriter, r *http.Request,
|
||||
return
|
||||
}
|
||||
|
||||
namespace := getRequestNamespace(secret.Namespace)
|
||||
mountPath = getNamespaceSecretMountPath(mountPath, namespace)
|
||||
|
||||
err = os.MkdirAll(mountPath, secretDirPermission)
|
||||
if err != nil {
|
||||
log.Printf("[secret] error %s", err.Error())
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(path.Join(mountPath, secret.Name), []byte(secret.Value), secretFilePermission)
|
||||
|
||||
if err != nil {
|
||||
@ -86,6 +101,9 @@ func deleteSecret(c *containerd.Client, w http.ResponseWriter, r *http.Request,
|
||||
return
|
||||
}
|
||||
|
||||
namespace := getRequestNamespace(readNamespaceFromQuery(r))
|
||||
mountPath = getNamespaceSecretMountPath(mountPath, namespace)
|
||||
|
||||
err = os.Remove(path.Join(mountPath, secret.Name))
|
||||
|
||||
if err != nil {
|
||||
|
@ -13,7 +13,6 @@ import (
|
||||
gocni "github.com/containerd/go-cni"
|
||||
"github.com/openfaas/faas-provider/types"
|
||||
|
||||
faasd "github.com/openfaas/faasd/pkg"
|
||||
"github.com/openfaas/faasd/pkg/cninetwork"
|
||||
"github.com/openfaas/faasd/pkg/service"
|
||||
)
|
||||
@ -41,8 +40,10 @@ func MakeUpdateHandler(client *containerd.Client, cni gocni.CNI, secretMountPath
|
||||
return
|
||||
}
|
||||
name := req.Service
|
||||
namespace := getRequestNamespace(req.Namespace)
|
||||
namespaceSecretMountPath := getNamespaceSecretMountPath(secretMountPath, namespace)
|
||||
|
||||
function, err := GetFunction(client, name)
|
||||
function, err := GetFunction(client, name, namespace)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("service %s not found", name)
|
||||
log.Printf("[Update] %s\n", msg)
|
||||
@ -50,12 +51,12 @@ func MakeUpdateHandler(client *containerd.Client, cni gocni.CNI, secretMountPath
|
||||
return
|
||||
}
|
||||
|
||||
err = validateSecrets(secretMountPath, req.Secrets)
|
||||
err = validateSecrets(namespaceSecretMountPath, req.Secrets)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
}
|
||||
|
||||
ctx := namespaces.WithNamespace(context.Background(), faasd.FunctionNamespace)
|
||||
ctx := namespaces.WithNamespace(context.Background(), namespace)
|
||||
|
||||
if _, err := prepull(ctx, req, client, alwaysPull); err != nil {
|
||||
log.Printf("[Update] error with pre-pull: %s, %s\n", name, err)
|
||||
@ -78,7 +79,7 @@ func MakeUpdateHandler(client *containerd.Client, cni gocni.CNI, secretMountPath
|
||||
// The pull has already been done in prepull, so we can force this pull to "false"
|
||||
pull := false
|
||||
|
||||
if err := deploy(ctx, req, client, cni, secretMountPath, pull); err != nil {
|
||||
if err := deploy(ctx, req, client, cni, namespaceSecretMountPath, pull); err != nil {
|
||||
log.Printf("[Update] error deploying %s, error: %s\n", name, err)
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
|
25
pkg/provider/handlers/utils.go
Normal file
25
pkg/provider/handlers/utils.go
Normal file
@ -0,0 +1,25 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"path"
|
||||
|
||||
faasd "github.com/openfaas/faasd/pkg"
|
||||
)
|
||||
|
||||
func getRequestNamespace(namespace string) string {
|
||||
|
||||
if len(namespace) > 0 {
|
||||
return namespace
|
||||
}
|
||||
return faasd.FunctionNamespace
|
||||
}
|
||||
|
||||
func readNamespaceFromQuery(r *http.Request) string {
|
||||
q := r.URL.Query()
|
||||
return q.Get("namespace")
|
||||
}
|
||||
|
||||
func getNamespaceSecretMountPath(userSecretPath string, namespace string) string {
|
||||
return path.Join(userSecretPath, namespace)
|
||||
}
|
75
pkg/provider/handlers/utils_test.go
Normal file
75
pkg/provider/handlers/utils_test.go
Normal file
@ -0,0 +1,75 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
faasd "github.com/openfaas/faasd/pkg"
|
||||
)
|
||||
|
||||
func Test_getRequestNamespace(t *testing.T) {
|
||||
tables := []struct {
|
||||
name string
|
||||
requestNamespace string
|
||||
expectedNamespace string
|
||||
}{
|
||||
{name: "RequestNamespace is not provided", requestNamespace: "", expectedNamespace: faasd.FunctionNamespace},
|
||||
{name: "RequestNamespace is provided", requestNamespace: "user-namespace", expectedNamespace: "user-namespace"},
|
||||
}
|
||||
|
||||
for _, tc := range tables {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
actualNamespace := getRequestNamespace(tc.requestNamespace)
|
||||
if actualNamespace != tc.expectedNamespace {
|
||||
t.Errorf("Got: %s, expected %s", actualNamespace, tc.expectedNamespace)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_getNamespaceSecretMountPath(t *testing.T) {
|
||||
userSecretPath := "/var/openfaas/secrets"
|
||||
tables := []struct {
|
||||
name string
|
||||
requestNamespace string
|
||||
expectedSecretPath string
|
||||
}{
|
||||
{name: "Default Namespace is provided", requestNamespace: faasd.FunctionNamespace, expectedSecretPath: "/var/openfaas/secrets/" + faasd.FunctionNamespace},
|
||||
{name: "User Namespace is provided", requestNamespace: "user-namespace", expectedSecretPath: "/var/openfaas/secrets/user-namespace"},
|
||||
}
|
||||
|
||||
for _, tc := range tables {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
actualNamespace := getNamespaceSecretMountPath(userSecretPath, tc.requestNamespace)
|
||||
if actualNamespace != tc.expectedSecretPath {
|
||||
t.Errorf("Got: %s, expected %s", actualNamespace, tc.expectedSecretPath)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_readNamespaceFromQuery(t *testing.T) {
|
||||
tables := []struct {
|
||||
name string
|
||||
queryNamespace string
|
||||
expectedNamespace string
|
||||
}{
|
||||
{name: "No Namespace is provided", queryNamespace: "", expectedNamespace: ""},
|
||||
{name: "User Namespace is provided", queryNamespace: "user-namespace", expectedNamespace: "user-namespace"},
|
||||
}
|
||||
|
||||
for _, tc := range tables {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
|
||||
url := fmt.Sprintf("/test?namespace=%s", tc.queryNamespace)
|
||||
r := httptest.NewRequest(http.MethodGet, url, nil)
|
||||
|
||||
actualNamespace := readNamespaceFromQuery(r)
|
||||
if actualNamespace != tc.expectedNamespace {
|
||||
t.Errorf("Got: %s, expected %s", actualNamespace, tc.expectedNamespace)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -79,7 +79,7 @@ func NewSupervisor(sock string) (*Supervisor, error) {
|
||||
}
|
||||
|
||||
func (s *Supervisor) Start(svcs []Service) error {
|
||||
ctx := namespaces.WithNamespace(context.Background(), faasdNamespace)
|
||||
ctx := namespaces.WithNamespace(context.Background(), FaasdNamespace)
|
||||
|
||||
wd, _ := os.Getwd()
|
||||
|
||||
@ -243,7 +243,7 @@ func (s *Supervisor) Close() {
|
||||
}
|
||||
|
||||
func (s *Supervisor) Remove(svcs []Service) error {
|
||||
ctx := namespaces.WithNamespace(context.Background(), faasdNamespace)
|
||||
ctx := namespaces.WithNamespace(context.Background(), FaasdNamespace)
|
||||
|
||||
for _, svc := range svcs {
|
||||
err := cninetwork.DeleteCNINetwork(ctx, s.cni, s.client, svc.Name)
|
||||
|
Reference in New Issue
Block a user