Photo by Zbynek Burival on Unsplash
Here is my Log book
Today I managed to learn more about OpenFaaS as well as refresh some Swift knowledge.
OpenFaaS
Learning action point: Is it possible to bundle up functions to be in the same docker container image? At the moment it looks like 1 function = 1 docker image
Supplying configuration values via environment variables
In Serverless for Everyone Else, Alex gives us an example of how environment variables can be supplied to the node.js function via the YAML file.
I am going to see if I can modify my Python function from yesterday to be configurable in the same way.
Added the section environment
to my "helloworld.yml" file to configure how the JSON will be prettified.
version: 1.0
provider:
name: openfaas
gateway: http://192.168.64.4:8080
functions:
helloworld:
lang: python3
handler: ./helloworld
image: dockername/helloworld:latest
environment:
indent: 2
sort_keys: false
Changed the "handler.py" to read the values for the indentation level and whether to sort the JSON keys from the environment variables. The default indentation level is 4 spaces and to not sort the keys.
import json
import os
def handle(req):
indent = int(os.environ.get('indent', '4'))
sort_keys = os.environ.get('sort_keys', 'false').lower() in ['true', 'yes', '1']
data = json.loads(req)
response = json.dumps(data, indent=indent, sort_keys=sort_keys)
return response
Deploy
$ faas-cli up -f helloworld.yml
...
<Had a few issues because the YAML contained TABS in the wrong places>
...
Deployed. 200 OK.
URL: http://192.168.64.4:8080/function/helloworld.openfaas-fn
Test
$ curl --data-binary '{"z": 1, "a": 2, "c": 3, "b": 4}' --header "Content-Type: application/json" http://192.168.64.4:8080/function/helloworld
{
"z": 1,
"a": 2,
"c": 3,
"b": 4
}
So what is the benefit in using environment variables? It allows you to not hardcode values all over the place in your code. Also I noticed that creating the docker image is quicker when only the yaml has changed.
NOTE: Do not use environment variables to store secret information! See the official OpenFaaS documentation for more information. Also there is a really nice example in Serverless for Everyone Else that shows how to protect your API using a secret token.
Supplying secret values to your function
To explore this I am going to deploy a new function that will read a stored secret and return it back to the caller.
Note:
Secret name must start and end with an alphanumeric character and can only contain lower-case alphanumeric characters, ‘-‘ or ‘.’
# Remember to first mkdir the directory for the function!
╭ ~/Learning/faasd/expose [20:05:44]
╰ $ faas-cli new --lang python3 expose
Add the names of secrets you want access to the yaml file
version: 1.0
provider:
name: openfaas
gateway: http://192.168.64.4:8080
functions:
expose:
lang: python3
handler: ./expose
image: dockername/expose:latest
secrets:
- expose-me
I have added a secret with the name "expose-me" and thus our function will have access to it by the file "/var/openfaas/secrets/expose-me"
Edit the handler.py file
def handle(req):
with open('/var/openfaas/secrets/expose-me') as f:
secret = f.read()
return secret
Deploy
$ faas-cli up -f expose.yml
...
Unexpected status: 400, message: unable to find secret: expose-me
Right ok, need to first actually add the secret to be used
$ faas-cli secret create expose-me --from-literal 'All your secrets have been exposed'
...
Creating secret: expose-me
Created: 200 OK
$ faas-cli secret list
NAME
expose-me
Deploy mk2
$ faas-cli up -f expose.yml
...
Deployed. 200 OK.
URL: http://192.168.64.4:8080/function/expose.openfaas-fn
Test
$ curl http://192.168.64.4:8080/function/expose
All your secrets have been exposed
Ouch! our secret was exposed. Let us see if we can change the secret.
$ faas-cli secret help
...
Available Commands:
create Create a new secret
list List all secrets
remove remove a secret
update Update a secret
$ faas-cli secret update expose-me --from-literal 'Honeypot'
Updating secret: expose-me
Updated: 200 OK
$ curl http://192.168.64.4:8080/function/expose
Honeypot
Nuke the exposed secret and hopefully the Python code will blow up.
$ faas-cli secret remove expose-me
Removed.. OK.
$ curl http://192.168.64.4:8080/function/expose
Honeypot
# Ouch! ok I wasn't expecting that. My guess is the /var/... file still exists
Learning action point: Will need to read the docs and possibly the code to see how the secrets are stored / communicated over to the faasd instance and why remove didn’t remove the stored file.
Swift: Mutating Objects is different than Mutating Structs
Objects (instances of a Class) are reference types.
Structs are value types
If you have a number of variables pointing to an object and you mutate the object, then each one of the variables will be pointing to the same mutated object. This could become dangerous if the object are being accessed from different threads and leads to the classic concurrency issue of a race condition.
Structs in Swift allow you to mutate without having the global side effects.
Mutating a struct only changes a single variable and not all variables with the same value.
var a = [3, 1, 2]
let b = a // a copy is made (but it will be copy-on-write)
a.sort() // mutating method
a // [1, 2, 3]
b // [3, 1, 2]
Members of a struct that are declared as var, is still protected based on how the variable is declared.
struct Event {
var count: Int // member count can be mutated
mutating func increment(_ amount: Int) {
count += amount
}
}
let e = Event()
e.increment(10) // This won't compile because the variable e is let
In order to mutate the member count
even though it has been declared as var balance
the variable doing the mutation needs to be declared with var
var e = Event()
e.increment(10) // This will now work because the variable is declared as var