Improve examples

This commit is contained in:
Nadja Reitzenstein 2022-03-12 01:28:07 +01:00
parent f367207d01
commit 20a47d9444
12 changed files with 258 additions and 87 deletions

0
bffhd/actors/shelly.rs Normal file
View File

179
examples/actor.py Executable file
View File

@ -0,0 +1,179 @@
#!/usr/bin/env python3
import sys
import argparse
def on_free(args, actor_name):
"""
Function called when the state of the connected machine changes to Free
again
"""
if args.verbose > 2:
print("on_free called!")
if actor_name == "DoorControl1":
# Do whatever you want to do in case `DoorControl1` is returned back to free.
# Keep in mind that process actors should return quickly to not miss
# updates, so if you need to do things that take a while fork a new
# process e.g. with the `subprocess` Module
print("I'm locking door 1!")
pass
elif actor_name == "DoorControl2":
print("I'm locking door 2!")
pass # Close a different door
else:
if not args.quiet:
print("process called with unknown id %s for state `Free`" % actor_name)
# It's a good idea to exit with an error code in case something
# unexpected happens.
# The process module logs everything printed to stdout by actors into
# the server log, but marks them as `Error` in case the actor process
# exits with a code != 0, making debugging somewhat easier.
exit(-1)
def on_use(args, actor_name, user_id):
"""
Function called when an user takes control of the connected machine
user_id contains the UID of the user now using the machine
"""
if args.verbose > 2:
print("on_use called!")
if actor_name == "DoorControl1":
print("I'm opening door 1 for 10 seconds!")
pass # Open door one
elif actor_name == "DoorControl2":
print("I'm opening door 2 for 10 seconds!")
pass # Open a different door
else:
if not args.quiet:
print("process called with unknown id %s for state `InUse`" % actor_name)
# It's a good idea to exit with an error code in case something
# unexpected happens.
# The process module logs everything printed to stdout by actors into
# the server log, but marks them as `Error` in case the actor process
# exits with a code != 0, making debugging somewhat easier.
exit(-1)
def on_tocheck(args, actor_name, user_id):
"""
Function called when an user returns control and the connected machine is
configured to go to state `ToCheck` instead of `Free` in that case.
user_id contains the UID of the manager expected to check the machine.
The user that used the machine beforehand has to be taken from the last
user field using the API (via e.g. the mobile app)
"""
if args.verbose > 2:
print("on_tocheck called!")
if not args.quiet:
print("process called with unexpected combo id %s and state 'ToCheck'" % actor_name)
exit(-1)
def on_blocked(args, actor_name, user_id):
"""
Function called when an manager marks the connected machine as `Blocked`
user_id contains the UID of the manager that blocked the machine
"""
if args.verbose > 2:
print("on_blocked called!")
if not args.quiet:
print("process called with unexpected combo id %s and state 'Blocked'" % actor_name)
exit(-1)
def on_disabled(args, actor_name):
"""
Function called when the connected machine is marked `Disabled`
"""
if not args.quiet:
print("process called with unexpected combo id %s and state 'Disabled'" % actor_name)
exit(-1)
def on_reserve(args, actor_name, user_id):
"""
Function called when the connected machine has been reserved by somebody.
user_id contains the UID of the reserving user.
"""
if not args.quiet:
print("process called with unexpected combo id %s and state 'Reserved'" % actor_name)
exit(-1)
def main(args):
"""
Python example actor
This is an example how to use the `process` actor type to run a Python script.
"""
if args.verbose is not None:
if args.verbose == 1:
print("verbose output enabled")
elif args.verbose == 2:
print("loud output enabled!")
elif args.verbose == 3:
print("LOUD output enabled!!!")
elif args.verbose > 4:
print("Okay stop you're being ridiculous.")
sys.exit(-2)
else:
args.verbose = 0
# You could also check the actor name here and call different functions
# depending on that variable instead of passing it to the state change
# methods.
new_state = args.state
if new_state == "free":
on_free(args, args.name)
elif new_state == "inuse":
on_use(args, args.name, args.userid)
elif new_state == "tocheck":
on_tocheck(args, args.name, args.userid)
elif new_state == "blocked":
on_blocked(args, args.name, args.userid)
elif new_state == "disabled":
on_disabled(args, args.name)
elif new_state == "reserved":
on_reserve(args, args.name, args.userid)
else:
print("Process actor called with unknown state %s" % new_state)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
# Parameters are passed to the Process actor as follows:
# 1. the contents of params.args, split by whitespace as separate args
# 2. the configured id of the actor (e.g. "DoorControl1")
# 3. the new state as one of [free|inuse|tocheck|blocked|disabled|reserved]
parser.add_argument("-q", "--quiet", help="be less verbose", action="store_true")
parser.add_argument("-v", "--verbose", help="be more verbose", action="count")
parser.add_argument("name",
help="name of this actor as configured in bffh.dhall"
)
# We parse the new state using subparsers so that we only require a userid
# in case it's a state that sets one.
subparsers = parser.add_subparsers(required=True, dest="state")
parser_free = subparsers.add_parser("free")
parser_inuse = subparsers.add_parser("inuse")
parser_inuse.add_argument("userid", help="The user that is now using the machine")
parser_tocheck = subparsers.add_parser("tocheck")
parser_tocheck.add_argument("userid", help="The user that should go check the machine")
parser_blocked = subparsers.add_parser("blocked")
parser_blocked.add_argument("userid", help="The user that marked the machine as blocked")
parser_disabled = subparsers.add_parser("disabled")
parser_reserved = subparsers.add_parser("reserved")
parser_reserved.add_argument("userid", help="The user that reserved the machine")
args = parser.parse_args()
main(args)

View File

@ -1,11 +0,0 @@
{ Shelly_1234 = { module = "Shelly", params = {=} }
, Bash =
{ module = "Process"
, params = { cmd = "./examples/actor.sh", args = "your ad could be here" }
}
, Bash2 =
{ module = "Process"
, params = { cmd = "./examples/actor.sh", args = "this is a different one" }
}
, FailBash = { module = "Process", params.cmd = "./examples/fail-actor.sh" }
}

View File

@ -38,6 +38,11 @@
-- access into them.
db_path = "/tmp/bffh",
-- Audit log path. Bffh will log state changes into this file, one per line.
-- Audit log entries are for now JSON:
-- {"timestamp":1641497361,"machine":"Testmachine","state":{"state":{"InUse":{"uid":"Testuser","subuid":null,"realm":null}}}}
auditlog_path = "/tmp/bffh.audit",
-- In dhall you can also easily import definitions from other files, e.g. you could write
-- roles = ./roles.dhall
roles = {
@ -175,6 +180,30 @@
args = "your ad could be here"
}
},
DoorControl1 = {
-- This actor calls the actor.py script in examples/
-- It gets passed it's own name, so you can have several actors
-- from the same script.
-- If you need to pass more arguments to the command you can use the `args` key in
-- `params` as is done with the actor `Bash`
module = "Process",
-- the `args` are passed in front of all other parameters so they are best suited to
-- optional parameters like e.g. the verboseness
params = { cmd = "./examples/actor.py", args = "-vvv" }
},
DoorControl2 = {
module = "Process",
params = { cmd = "./examples/actor.py" }
},
DoorControl3 = {
-- This is an example for how it looks like if an actor is misconfigured.
-- the actor.py doesn't know anything about DoorControl3 and, if this actor is enabled,
-- will return with an error showing up in the server logs.
module = "Process",
params = { cmd = "./examples/actor.py" }
},
Bash2 = { module = "Process", params = { cmd = "./examples/actor.sh" , args = "this is a different one" }},
FailBash = { module = "Process", params = { cmd = "./examples/fail-actor.sh" }}
},
@ -195,11 +224,11 @@
initiators = {=},
-- The "Dummy" initiator will try to use and return a machine as the given user every few seconds. It's good to
-- test your system but will spam your log so is disabled by default.
--{ Initiator = { module = "Dummy", params = { uid = "Testuser" } } }
--initiators = { Initiator = { module = "Dummy", params = { uid = "Testuser" } } },
-- Linking up machines to initiators. Similar to actors a machine can have several initiators assigned but an
-- initiator can only be assigned to one machine.
-- The below is once again how you have to define *no* initiators.
init_connections = [] : List { machine : Text, initiator : Text }
-- init_connections = [{ machine = "Testmachine", initiator = "Initiator" }]
}
--init_connections = [{ machine = "Testmachine", initiator = "Initiator" }]
}

View File

@ -1 +0,0 @@
{=}

View File

@ -1,28 +0,0 @@
{ Testmachine =
{ description = Some "A test machine"
, name = "Textmachine"
, manage = "lab.test.admin"
, read = "lab.test.read"
, write = "lab.test.write"
, disclose = "lab.test.read"
}
, Another =
{ description = Some "Another test machine"
, name = "Another"
, disclose = "lab.test.read"
, manage = "lab.test.admin"
, read = "lab.test.read"
, write = "lab.test.write"
},
Yetmore =
{ description = Some "Yet more test machines"
, name = "Yetmore"
, disclose = "lab.test.read"
, manage = "lab.test.admin"
, read = "lab.test.read"
, write = "lab.test.write"
}
}

View File

@ -1 +0,0 @@
Testuser = "secret"

View File

@ -1,14 +0,0 @@
{ testrole =
{ permissions = [ "lab.test.*" ] }
, somerole =
{ parents = ["testparent"]
, permissions = [ "lab.some.admin" ]
}
, testparent =
{ permissions =
[ "lab.some.write"
, "lab.some.read"
, "lab.some.disclose"
]
}
}

View File

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDFzCCAf+gAwIBAgIUDr+1F3zzyza+soLtiurKEXW9pGIwDQYJKoZIhvcNAQEL
BQAwGzEZMBcGA1UEAwwQYmZmaC1kZXZlbG9wbWVudDAeFw0yMTEyMDkxODQ2Mjla
Fw0zMTEyMDkxODQ2MjlaMBsxGTAXBgNVBAMMEGJmZmgtZGV2ZWxvcG1lbnQwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGwNy7yGaURR08dWfoDmnJeyx1
0FVRmozoGCIb3Oj6c2t+84QUxqTdknE7Cdcz5Wi1o0x2CWPZG4z1vgTaCcJVhcME
hxn+7eK1NtDQEjs8Ojs7uaraVvooIe8R7jat0qs7Dmf8RO9P0I4MMZlvijhI7aLw
0C6vNsr1ebeppIiwO5aUuCGuKqxJGghHeqZv18ZcPayunyNrxMC6uyX7y6nUVkfq
x0m9gDsN112Iv9Dd/ZE5Gxivm8jZvVUGZgJD2szK7zbeCDeo5aU3cRWfYaoN0QDx
AKmo4bjciJzfMDDgvcIBq9lGS3FxEv394Mc5YX/ZdP+KRTiHcYCXfBzr3B6HAgMB
AAGjUzBRMB0GA1UdDgQWBBTtUvvWXlo5tU8cEoxbs5UJdodOVDAfBgNVHSMEGDAW
gBTtUvvWXlo5tU8cEoxbs5UJdodOVDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
DQEBCwUAA4IBAQAB3IxRnWi/LrxCvlHNaWEi3ZvlbN+KpegWZeKtjHwQoizhR/Fi
SMC7z4y6trJE7LXUOSb9Pu8QQSvpVQZd3W4XCPZMl10Lt7iV8vc3pVviCseDnT9r
X1gXdbeuyYm9lE8KtlhX03jD/CiEx7Qe/q8Rc20AQIKAAJzvl7sXU2tmJ5kpzMEO
v5czlLaX2ajlD/QMgNBUuDyw6wPo3wx9Khph484RygN2LHeT6kfu/PBiF0dGDTUu
mgxg4K0GfwTcHgtz5Bag/HyuuJEKx8Wv7jth59PyKPT+lMVBznxIm3gLS5U+Nnr1
uAws8dgLXRlPo5HJORuJCcZWVBClruZUpyDT
-----END CERTIFICATE-----

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDGwNy7yGaURR08
dWfoDmnJeyx10FVRmozoGCIb3Oj6c2t+84QUxqTdknE7Cdcz5Wi1o0x2CWPZG4z1
vgTaCcJVhcMEhxn+7eK1NtDQEjs8Ojs7uaraVvooIe8R7jat0qs7Dmf8RO9P0I4M
MZlvijhI7aLw0C6vNsr1ebeppIiwO5aUuCGuKqxJGghHeqZv18ZcPayunyNrxMC6
uyX7y6nUVkfqx0m9gDsN112Iv9Dd/ZE5Gxivm8jZvVUGZgJD2szK7zbeCDeo5aU3
cRWfYaoN0QDxAKmo4bjciJzfMDDgvcIBq9lGS3FxEv394Mc5YX/ZdP+KRTiHcYCX
fBzr3B6HAgMBAAECggEAS5DGG6ssvRCt9e+ZatQYCl+HXt+voJAHJLMQPNG3zokV
hLXnMNL5mbh0zoKGTJfbQLvudS5KxR/BbykoxRFSzptFszH+gztEp6tIpuNXnCVz
odiMiejpwVptf763EU14hsKKbJJ0/j6H00EEWjEOB0Q6YB52sW0+qyf02U3SHlZN
k2PZYkpHi3YCONtOGj7jOdW7M3RfvcBNg9EW7fZc1KkiRAlscUAYLMkKcOLevil0
lUuF/JWj4iH22Oq6+JeSiecf6izF6lyIGvMXPry+woa8Iq0BBdmbZsK7r/Pa+wlz
+E6xHGn2rcyrnYB2pPc+RfHhYlodaOo69DxAYlRYaQKBgQDxnKySmlcfHe8lMqR4
2LvqMyGjNRo2+q9VZYej2mvr6+TGyd7Op/fRJ1t5f9DgtINomNQYSOtYAsPiEnl+
43z2N/Rdh6XSmOj4gLkDeiYNSpy86L/F39uCWZpkkqiy2zxYLWOs15MA0GWOtQGh
dz4cM0b/jyZOdHZR//L5WiMLawKBgQDSltEfQKqCEKJTqp4SU9BCHQmyheIjepY2
eKakgcsjpFjRBK2VrUalDLOQV74rtd7wp8F8kqqPJpRshb+oVuDCg6JB17UxYd34
iB+5cMdLRpg8f0HOqcYz4KOql2QhJQhFc3jzY7n1piPEhFO/MqFwmlUB4RdgJ3ix
HqX+F/T8VQKBgGos76l9KcwC25T9LEnu9KV20tFmBJ8kiuh8NZ9L3SFQCLlS/RbT
uZOwOAKsqJ4WtajBgHMrmECU9n/inoGkdsW80SZI9hYWHEsYRjXA9/ffUgGyRpQu
S8h8l9yalogC0AHv8F2EXpV8/yQ3ZwAN5r19yzWDMtJHW7etQplRgxUBAoGAGeOy
t+3iSHU1D6YlIsmtC8O4Int1LrluaCnzCrxuNeaJiMDTelhAHCBwnuk6lvMYAmwN
THxXfZvXmXPj+RUdMqyuMPwM6ZJHkLtjcw/bYHTAWIeolnimxk/yrxFHnQ+Jcchd
cUasYPfY49sE1Lerw0Ul+EIs9oRDwTqsW42kb7UCgYEA2y+oc7Fz2eq38hSbTfy7
OcATtny+xQ1+4IELtQIP7VctkMInJs57J+vS//IT41P0L2K1YjvL8RacnvG7yMvP
GnwHBcKgvL6zuoy11I3zPPYtbKGwcJoVGomPX7W0csfl4gdST3uugd9iCDEB8NsS
QmOYM/dk8x8aWpndBjRF5ig=
-----END PRIVATE KEY-----

View File

@ -1,15 +0,0 @@
let Map = https://prelude.dhall-lang.org/v20.2.0/Map/Type
sha256:210c7a9eba71efbb0f7a66b3dcf8b9d3976ffc2bc0e907aadfb6aa29c333e8ed
let Machine =
{ Type =
{ description : Optional Text
, manage : Text
, write : Text
, read : Text
, disclose : Text
}
, default = { description = None }
}
in Machine

View File

@ -11,17 +11,3 @@ passwd = "secret"
# It will get stored in the `kv` field in UserData.
# This is not used for anything at the moment
noot = "noot!"
[Differentuser]
# Define them in roles.toml as well
roles = ["somerole/internal", "testrole/internal"]
# If two or more users want to use the same machine at once the higher prio
# wins
priority = 0
passwd = "secret"
# You can add whatever random data you want.
# It will get stored in the `kv` field in UserData.
noot = "noot!"