Home > Coeus

Coeus

Coeus is a project mainly written in PERL and SHELL, it's free.

Master's Thesis project

NAME coeus - The Planned Datacenter Language interpreter

SYNOPSIS coeus [options]

Runs the Coeus interpreter. If no input file is specified, reads from
STDIN.

 Options:
    --input -i      Specify the input file
    --trace -t      Display the parse trace
    --backtrace -b  Display backtraces when there is an interpreter error
    --hook          Load a hook
    --help -h       Show this help info
    --man           Show the full man page
    --target        Specify the run target (default: run)

For a complete explanation of the idea behind the interpreter and the
language read
https://github.com/zaphod42/Coeus/raw/master/doc/Masterarbeit.pdf

OPTIONS --input Specify the input file.

--trace Turns on the Parse::RecDescent trace. WARNING: The trace can be
        very long, even for small files.

--backtrace
        Turns on the displays a backtrace through the interpreter when
        an error occurs.

--hook  Register a hook with the interpreter.

        Hooks are called before and after each operation is completed
        during the interpretation of a program. See
        Coeus::Interpreter::Hook for more information on hooks.

         PACKAGE_NAME OPT1=VAL,OPT2=VAL,...

        For example to use the Coeus::Visual::DotMapper which has
        options FILE and NO_SYMTAB you can run:

         coeus --hook 'Coeus::Visual::DotMapper FILE=output.dot,NO_SYMTAB=1'

--help  Display the short help message (the SYNOPSIS).

--man   Display the entire man page.

--target
        Specify the target to run the interpreter to. One of: ast, run.

        The ast target will parse and print the ast to STDOUT. The run
        target will parse and execute the program.

LANGUAGE Language Elements A Coeus program consists of a list of declarations, statements, and expressions. Statements do not have any particular value that they evaluate to, whereas expressions also evaluate to a value that can be used for further evaluation. The majority of the language elements are expressions with only a few things for manipulating subscriptions being statements.

Expressions themselves are broken down into four types: regular
expressions, boolean expressions, policy expressions, and behavior
expressions. For the most part they have the same structure, with the
main difference between them being what is allowed as part of the
expression.

Declaring Types type {

# capability declaration -> # conditional capability # instances have the # capability only when # the expression evaluates # to true }
A TypeName must always start with an uppercase letter. The condition on
conditional capabilities can be any boolean expression (see below for an
explanation of what a boolean expression is). What makes it a behavior
expression is that no variable references are allowed in the expression
except for the "_" variable, which is bound to the instance whose
capabilities are being calculated.

Declaring Landscapes landscape {

([resilient = ], [comment = ]): }
The PolicyName is the name to be given to the policy. The attributes
resilient and comment are both optional. Comment provides a longer name
for the policy and is used during error reporting to provide nicer error
messages. Resilient specifies the minimum number of failures that this
policy needs to be able to handle. The resiliency of policies is not
also simple to understand so it is a good idea to understand how it will
be calculated and check by reading the Coeus::Model::Policy and
Coeus::Interpreter::PolicyCheck documentation.

A landscape must have one default policy (the one that will be in effect
when a subscription for the landscape is first made). The default policy
is marked by prefixing the PolicyName with an asterisk (*).

A PolicyExpression is very similar to a BehaviorExpression except that
"_" is not bound to anything (except inside queries) and references to
other policies is allowed (they use the same syntax as variable
references in standard expressions). For example:

 landscape Foo {
    *start:
        other && ?[A]
    other:
        ?[Bar | _.baz == 2] >= 2
 }

Creates a landscape "Foo" that will begin with the policy "start". The
"start" policy requires that the policy "other" is true as well as there
being at least one instance of type "A". The "other" policy requires
that there are at least two instances of "Bar" that have their parameter
"baz" set to 2.

Declaring Actions action ([]) {

}
An action evaluates to the last command evaluated in the body of the
action. The ParameterList is a comma seperated list of identifiers that
will be bound to the values passed into the action when it is called.

Statements There are seven statements in Coeus: subscribe, unsubscribe, in, policy, start, stop, and include.

Subscribe and unsubscribe create and destroy subscriptions to
landscapes. The syntax for subscribe is:

 subscribe(<LandscapeName>, <Expression>)

The Expression is evaluated to get the name of the subscription. The
subscription starts with the default policy of the landscape and a
configuration with no instances or usages in it. To remove a
subscription, unsubscribe is used.

 unsubscribe(<Expression>)

Just as with subscribe the Expression evaluates to the name of the
subscription to remove. When a subscription is remove the instances and
usages are simply de-associated from the subscription, they are not
decommissioned.

When a change to a subscription needs to be made, then the "in"
statement is used.

 in <Expression> {
    ...
 }

Expression evaluates to the name of the subscription to work with and
the block is executed in the context of the subscriptions configuration.

The policy statement changes the current policy of the current
subscription.

 policy[<PolicyName>]

Both start and stop control the lifecycles of instances and usages.
Start places an instance or usage in the running state, and stop places
them in the stopped state.

 start[<Expression>]
 stop[<Expression>]

The include statement simply includes the text of file into the current
source code during interpretation, very much like #include in C.

 include <String>

Expressions Operators are boolean (&&, ||, not), arithmetic (+, -, *, /), numeric relational (>, <, >=, <=, !=, ==), string relational (lt, gt, eq, ne), assignment (:=), and string concatenation (~).

Truth of an expression is based on the same criteria as truth in Perl.
In Perl 0, "", "0", " ", and undefined are all false and everything else
is true.

Additionally there are constructors:

 ![<Type>]
 ![<Type>:<identifier>]
 ![<var> <- <Type>]
 ![<var> <- <Type>:<identifier>]
 ![<var> -> <capability> <var>]

The first form commissions a new instance of type Type. The second can
be understood as "commission if needed". If there is not an instance of
type Type with the given identifier then it will be created, otherwise
it will simply be returned. If the wanted instance is in the system, but
not yet in the subscription in which the command is executed then the
instance will be brought into the subscription's configuration. This
allows for sharing the same instance between subscriptions.

The third and fourth forms commission or commission if needed,
respectively, an instance and install it on the instance held in var.
The fifth form commissions a usage relationship.

In the third and fifth forms if the vars hold more than one instance
then the commission will be performed for each instance, or each pair of
instances, in the vars. The fourth form will error in this case since it
would mean attempting to install the same instance in multiple places.

Decommissioning is accomplished by:

 X[ <expression> ]

It evaluates the expression and then removes the instance(s) or usage(s)
from the configuration.

Decommissioning instances when currently inside a subscription will
simply remove the association between the instance and the subscription.
If, on the other hand, the instance is removed outside the context of a
subscription, then the instance will be completely removed from the
system (meaning removing it from all subscriptions it may be in).

Decommissioning a usage will always completely remove it!

NOTE: Decommissioning things can have unexpected consequences. Variables
may be unbound!

All expressions can have a "topic block" added to them as well. The
topic block is a block of expressions that have the variable "_" bound
to the value of the expression that comes before the block. If the
expression that is before the block evaluates to a list (such as in the
case of queries), the block is applied repeatedly to each element of the
list.

 <Expression> {
    ...
 }

Queries are used to find instances and uses within the current
configuration (either the system's or a subscription's).

 ?[ <query> ]

The queries can have several forms

 <TypePattern>                # finds all instances 
                              # of a given type pattern

 <TypePattern> : <identifier> # finds the instance of 
                              # type pattern with the 
                              # given identifier

 <Expression> <- <TypePattern> # finds instances installed 
                               # on Expression of a given 
                               # type pattern

 <Expression> <- <TypePattern> : <identifier> # finds the 
                               # instance installed on 
                               # Expression of a given type 
                               # pattern and identifier

 <InstancePattern> -> <CapabilityPattern> <InstancePattern> 
                               # finds use relationships

The TypePatterns can be either a TypeName, variable reference, or "?".
The TypeName searches for instances of the given TypeName, a variable
reference searchs for the instances held in the variable, and "?" finds
all instances.

The InstancePatterns in the usage query form can be either Expressions
or "?". Expressions are handled the same as variable references in the
TypePatterns, and "?" is exactly the same as the "?" in the
TypePatterns. The CapabilityPattern can be either a capability name, in
which case only usages for the given capability will be returned, or "?"
in which case all usages that match the InstancePatterns will be
returned.

In addition to the simple querying possible with these patterns, the
four instance query forms can have a filter specified as:

 <Query> | <Expression>

In which case for each instance found by Query, Expression will be
evaluated with "_" set to the instance. When the expression returns true
then the instance will be included in the final result, otherwise it
will not.

Action invocations look like function calls in most languages:

    <ActionName>(arg, arg, ...)

Predicates There are two predicates available for looking at an instance: running?, and can?.

"running?(<Instance>)" returns true if the given instance is currently
in the running state.

"can?(<Capability>)" returns true if the instance held in "_" has the
given Capability.

BUGS AND TODO

  •   The parser does not provide good error messages when something
      is wrong.
  • Specifying parameters for plugin modules interferes with specifying file paths.

AUTHOR Andrew Parker [email protected]