Quick start

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

Quick start

Variables

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.

Optional field 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

Scripts

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

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: create, update, delete of field or remove of whole object. You also could create listeners that will be executed after object is: created, updated or field was deleted.

Listeners could be also called when change is related to owned objects (with private key present on local machine): owned_created, owned_update, owned_updated, owned_delete, owned_deleted, owned_remove. To authorized changes (when update was not done by one of objects listed in update_authorized): authorized_update, authorized_updated, authorized_delete, authorized_deleted and authorized_remove. The same is for unauthorized changes.

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 create, created and 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 some_fileld only.
  • * – 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.

Use 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 to field.

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

Models

Create definitions of models in database. Use can_update and can_read to define how field should be handled by Dinemic.

If only 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]

The 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