What is starsheep?
Imagine git repositories. Each developer has his own copy of repository with own branch and commits changes to files. Each time when two developers meet, then they synchronize changes by merge across theirs branches.
Sounds familiar, isn’t it? Now replace git with Dinemic framework and files to objects in your application. Each time your schema defined in YAML updates any field in object of class, then it synchronizes own chain of changes with others. Let’s go further and add listeners, which work similar to the Git’s webhooks. Now you have fully event driven applications, written using only YAML and your favorite scripting language(s). No public services, no central databases, even no compilation. Just exchange based on cryptographic backend.
A deeper look
Starsheep is open source provisioning tool for applications deployment and configuration management in fully decentralized way.
With once defined application schema in YAML you can manage nodes across your network from any place, even during split brain configuration, when part of cluster is not available.
Starsheep allows to define data models, to keep any detail of your application or infrastructure organized in objects. Next step of creating application is defining scripts, which could be easily triggered when model’s data is changed, by defining listeners. To make all tasks more flexible, you could define own variables, which could take output of scripts or just keep global configurations in one place.
When your application is ready, you can spread it across whole cluster and start filling your models with data. See quick introduction below or go to examples in documentation for more information
Create new application with single, global variable
version: 2020.02 application: variables: variable_name_a: value: variable_value
Define new variable based on field’s value in object of model. Value could be read directly, from object of model, when model is set with id.
To select owned model, prepend @ sign to model name, to get first owned obejct of given model. If model is not present on local machine, value of variable will be empty.
Value is dynamically obtained from object each time, when accessed.
read_as could be used to obtain encryted vaule as owned object. This should be used, if field is encrypted and owned object’s keys could be used to decrypt.
version: 2020.02 application: variables: variable_b: from_object: model: @PersonModel field: last_name variable_c: from_object: model: PersonModel:3pt340qr... list: work_places,1 read_as: Employer:af1234.... variable_d: from_object: model: model: @Person dict: my_contacts read_as: @Person
Create variable calculated from script output
version: 2020.02 application: variables: current_users: from_script: script_name: execute_w scripts: execute_w: interpreter: /bin/bash variables: ADDITIONAL_VARIABLE: YYY script: /usr/bin/w
Create new script with single, static local variable
version: 2020.02 application: script: say_something: interpreter: /bin/bash variables: phrase: value: hello_world script: echo $phrase
Listeners could be used to change default behavior of Dinemic database (accept all, including not signed updates). You can declare listeners that will be called before object:
delete of field or
remove of whole object. You also could create listeners that will be executed after object is:
updated or field was
Listeners could be also called when change is related to owned objects (with private key present on local machine):
owned_remove. To authorized changes (when update was not done by one of objects listed in update_authorized):
authorized_remove. The same is for
Mention, that there is no authorized/unauthorized create and created. Object creation is always authorized action, which is related to local key creation for such object. So, only
owned_created actions are allowed.
The action trigger is one part of listener trigger. Second is the model filter. You can specify your listener to be called only when update is related model or its field. Set in action one of following tokens to match update:
Model:[id]– will match only creat or delete of whole object
Model:*– will match anything related to model
Model:[id]:*– will match updates and deletes of model’s fields
Model:[id]:value_some_field– will match updates of field
*– will match any update
!– will cause that listener is not assigned globally and will be used in model definition for certain fields
Check for more in Dinemic framework documentation, in Listeners chapter. Listeners with exclamation mark could be used widely, in models definitions, to create clear assignments of listeners by models.
Create new listener that will be attached to any update of fields in model Person. Listener will reject unauthorized updates.
on field to determine when listener should be executed.
version: 2020.02 application: listeners: reject_unaithorized_persons: call_on: - update_unauthorized - remove_unauthorized trigger: Person:[id]:* action: reject reason: This was not authorized
Create new listener that will execute predefined script on certain action in database
Script should return code 0. Otherwise updated will be rejected on any machine, which calls this script.
version: 2020.02 application: listeners: call_some_script: call_on: - owned_updated - owned_removed trigger: Node:[id]:* action: script script_name: say_something
Update model by listener. Update is signed as owned model and is related to object defined in
update:in_owned model. New value of its field is calculated as selected in
Update is executed always, unless the
when statement is not present.
To limit behavior to make updates of related fields, use
when statement, as in example.
version: 2020.02 application: listeners: assign_my_car: call_on: updated trigger: Car:[id]:field_owner action: update update: in_owned: model: Person field: my_car to: changed_field: owner when: value: is_owned_model model: Person
Create definitions of models in database. Use can_update and can_read to define how field should be handled by Dinemic.
authorized could update, then new, default listener will be applied to field to reject unauthorized updates or removes.
If can_read is
authorized, then field will be created as encypted.
Any listeners assigned directly to field, list or dict will be automatically assigned as fllowing: ModelName:[id]:field_… , or respectively to list or dict.
If listener is assigned to model, then it will be assigned to whole model, as: ModelName:[id]:* and ModelName:[id]
unique field could be used to determine if objects of this model should be created in multiple instances, if only there is different value of this field. Unique allows to inject data model for multilpe instances of the same model
instances field defines if there should be created none (0), exactly one (1) or more than one instances of model.
version: 2020.02 application: models: Person: instances: 0|1|+ unique: NAME fields: NAME: can_update: authorized can_read: all listeners: - reject_unauthorized_persons EMAIL: can_update: authorized can_read: authorized LIKES: can_update: all can_read: all listeners: - call_some_script lists: FRIENDS: can_update: authorized can_read: authorized dicts: CONTACTS: can_update: authorized can_read: authorized listeners: - assign_my_car Car: fields: BRAND: can_update: authorized can_read: all SHEEPPOWER: can_update: authorized can_read: all