Expose via REST some useful info
[aquarium] / doc / manual / source / devguide.rst
index 599104e..d7577b2 100644 (file)
@@ -1,13 +1,91 @@
-Aquarium Development Guide
-==========================
+Development Guide
+=================
 
 The development guide includes descriptions of the APIs and extention points
 offered by Aquarium. It also includes design and development setup information.
 
+Obtaining and Compiling
+-----------------------
+
+The source code to the Aquarium project can be obtained through Git, by
+cloning the repository `http://code.grnet.gr/git/aquarium`. This will give
+you read-only access to the repository. You need to contact the Aquarium
+team to obtain read-write access.
+
+To compile Aquarium, you need the following software in your path:
+
+- Java SDK 6. Java 7 has not been tested yet.
+- `Maven <http://maven.apache.org>`_, version > 3
+
+After you install them, you can do the following:
+
+- ``mvn install``: To compile Aquarium and run the tests. This will also create 
+  the file ``target/aquarium-<ver>-jar-with-dependencies.jar`` which can be
+  used to start Aquarium from the command line. To skip the tests while compiling,
+  run ``mvn install --skipTests=true``.
+- ``mvn deploy``:  To deploy the Aquarium libraries to the remote Maven repository
+- ``mvn release:prepare``, ``mvn release:perform``: To prepare a release,
+  tag a new version and start the next development version
+- ``mvn scala:cctest``: To run the Scala compiler in continuous compilation
+  mode
+
+Aquarium can also be build with the Simple Build Tool
+(`SBT <https://github.com/harrah/xsbt/wiki>`_). Just run ``sbt`` in the directory 
+containing the Aquarium source code.
+
+Distributing
+^^^^^^^^^^^^
+
+To prepare a binary distribution of Aquarium, use the ``make-dist.sh`` script.
+If the script is run without an argument, it will create a TAR archive from
+the latest tagged version of Aquarium. The script also accepts a Git commit-ish,
+in which case it will build a TAR archive out of the provided Git commit.
+
 Overall architecture
 --------------------
 
+Aquarium's architectural design is mainly driven by two requirements: scaling
+and fault tolerance. Aquarium's functionality is based on event sourcing.
+`Event sourcing <http://en.wikipedia.org/wiki/Domain-driven_design>`_ 
+assumes that all changes to application state are stored as a
+sequence of events, in an immutable log. With such a log at hand, a system can
+rebuild the current application state by replaying the events in order. The event
+sourcing design pattern has some very interesting properties, which made it
+particularity suitable for basing Aquarium on it:
+
+- Multiple models can be used in order to process the events, concurrently. This means that Aquarium can provide a limited data view to its REST API and a more detailed one to a helpdesk frontend.
+
+- It is possible to perform queries on past system states by stopping the event replay at a certain point of interest. This would prove very possible for a future debugging interface.
 
+- In a carefully implemented event sourcing system, application crashes are not destructive, as long as event replay is fast enough and no state is inserted to the application without being recorded to the event log first.
+
+- After event log replay, new events only cause updates in the system’s in-memory state, which can be done very fast.
+
+Components
+^^^^^^^^^^
+
+.. image:: arch.png
+
+An overview of the Aquarium architecture is presented in the figure above.  The
+system is modeled as a collection of logically and functionally isolated
+components, which communicate by message passing. Withing each component, a
+number of actors take care of concurrently processing incoming messages through
+a load balancer component which is the gateway to requests targeted to the
+component. Each component is also monitored by its own supervisor; should an
+actor fail, the supervisor will automatically restart it. The architecture
+allows certain application paths to fail individually while the system is still
+responsive, while also enabling future distribution of multiple components on
+clusters of machines.
+
+The system receives input mainly from two sources: a queue for resource and
+user events and a REST API for credits and resource state queries. The queue
+component reads messages from a configurable number of queues and persists them
+in the application’s immutable log store. Both input components then forward
+incoming messages to a network of dispatcher handlers which do not do any
+processing by themselves, but know where the user actors lay. Actual processing
+of billing events is done within the user actors. Finally, a separate network
+of actors take care of scheduling periodic tasks, such as refiling of user
+credits; it does so by issuing events to the appropriate queue.
 
 The accounting system
 ----------------------
@@ -34,7 +112,7 @@ Glossary of Entities
   correspond to real money.
 - *Resource*: A resource represents an entity that can be charged for its usage. The 
   currently charged resources are: Time of VM usage, bytes uploaded and downloaded and bytes used for storage
-- *Resource Event*: A resource event is generated from an external source and are permanently appended in an immutable event log. A raw event carries information about changes in an external system that could affect the status of a user's wallet.
+- *Resource Event*: A resource event is generated from an external source and are permanently appended in an immutable event log. A raw event carries information about changes in an external system that could affect the status of a user's wallet (See more about `Resource Event`_).
 - *AccountingEntry*: An accounting entry is the result of processing a resource event and is what gets stored to the user's wallet.
 - *Price List*: A price list contains information of the cost of a resource. 
   A pricelist is only applied within a specified time frame.
@@ -43,11 +121,49 @@ Glossary of Entities
   configurable amount of credits.
 - *Agreement*: An agreement associates pricelists with algorithms and credit
   plans. An agreement is assigned to one or more users/credit holders.
+- *Billing Period*: A billing period defines a recurring timeslot at the end
+  of which the accumulated resource usage is accounted for and reset.
+
+Overall Schema
+^^^^^^^^^^^^^^
+
+The Aquarium policy DSL allows the hierarchical definition of agreements, by
+means of compositing ingredients and specifying validity periods for individual
+components or for the policies themselves. The DSL also allows overriding
+between items of the same class (i.e. an algorithm definition can override
+certain fields of another algorithm definition, while both definitions can 
+be referenced individually). 
+
+The top-level schema for the DSL is as follows.
+
+.. code-block:: yaml
+
+  aquariumpolicy:
+    resources:
+      - resource:
+        ... [see Resources]
+
+    algorithms:
+      - algorithm:
+        ... [see Algorithms]
+
+    pricelists:
+      - pricelist:
+        ... [see Pricelists]
+
+    creditplans:
+      - creditplan:
+        ... [see Creditplans]
+
+    agreements:
+      - agreement:
+        ... [see Agreements]
+
 
 Time frames
 ^^^^^^^^^^^
 
-Time frames allow the specification of applicability periods for policies,
+Time frames allow the specification of applicability periods for algorithms,
 pricelists and agreements. A timeframe is by default continuous and has a
 starting point; if there is no ending point, the timeframe is considered open
 and its ending point is the time at the time of evaluation. 
@@ -64,20 +180,21 @@ syntax reminisent of the `cron <http://en.wikipedia.org/wiki/Cron>`_ format.
 
 .. code-block:: yaml
 
-  applicable:
-    from:                            # Milliseconds since the epoch
-    to:                              # [opt] Milliseconds since the epoch
+  effective:
+    from: %d                         # Milliseconds since the epoch
+    to:  %d                          # [opt] Milliseconds since the epoch
     repeat:                          # [opt] Defines a repetion list
       - every:                       # [opt] A repetion entry 
         start: "min hr dom moy dow"  # 5-elem cron string
         end:   "min hr dom moy dow"  # 5-elem cron string 
 
+
 The following declaration defines a timeframe starting at the designated
 timestamp and ending at the time of evaluation.
 
 .. code-block:: yaml
 
-  applicable:
+  effective:
     from: 1293703200  #(30/12/2010 10:00)
 
 The following declaration defines a timeframe of one year, within which the
@@ -87,7 +204,7 @@ and 15:00 Sat to 15:00 Sun.
 
 .. code-block:: yaml
 
-  applicable:
+  effective:
     from: 1293703200  #(30/12/2010 10:00)
     to:   1325239200  #(30/12/2011 10:00)
     repeat:
@@ -101,16 +218,64 @@ and 15:00 Sat to 15:00 Sun.
 Resources
 ^^^^^^^^^
 
-A resource represents an entity that can be charged for.
+A resource represents an entity that can be charged for. Aquarium does not
+assume a fixed set of resource types and is extensible to any number of
+resources. A resource has a ``name`` and a ``unit``; both are free form
+strings. The resource name is used to uniquely identify the resource both inside
+Aquarium and among external systems.
+
+A resource definition also has a two fields that define how a resource is
+charged and whether a user can be assigned more instances of a resource.
+Specifically, the ``costpolicy`` field can have the following values:
+
+- `continuous:` For ``continuous`` resources, the charging algorithm calculates the
+  total amount of resource usage over time, per billing period. Each new
+  resource event modifies the resource usage counter and forces Aquarium
+  to calculate a new cost for the previous amount of resource usage. A typical
+  example  of a continuous resource is disk space.
+- `onoff:` ``onoff`` resources are a category of continuous resources where the
+  resource can only be in two states, on or off. In such cases, maintaining a usage
+  counter is not necessary; the charging algorithm uses time as the unit of
+  calculation. Virtual machine time is a typical example.
+- `discrete:` ``discrete`` resources are charged for instantly for the
+  reported resource value. Examples are bandwidth and every resource whose usage
+  is not a function of time (books, hits to an API etc). 
+
+Regarding resource complexity, a resource can either be labeled complex 
+or not. In the former case, a resource can have more than one instances per
+user, and resource usage is tracked individually per instance. The 
+``instance-id`` field in the resource event message (See `Resource Event`_) 
+helps Aquarium separate resource instances at charge time. 
+
+The following resource definition defines the `bandwidthup` 
+resource. 
+
+.. code-block:: yaml
+
+  resource:
+    name: bandwidthup
+    unit: MB/hr
+    complex: false
+    costpolicy: discrete
 
-The DSL does not assume a fixed set of resource types and is extensible to any
-number of resources. The default set of resources that the DSL supports 
-are the following: 
+Algorithms
+^^^^^^^^^^
 
-- ``vmtime``: Time a specific VM is operating
-- ``diskspace``: Space on disk being used for storing data
-- ``bandwidthup``: Bandwidth used for uploading data
-- ``bandwidthdown``: Bandwidth used for downloading data
+An algorithm specifies the algorithm used to perform the cost calculation, by
+combining the reported resource usage with the applicable pricelist. As opposed
+to price lists, algorithms define behaviours, which have certain
+validity periods. 
+
+.. code-block:: yaml
+
+  algorithm:
+    name: default
+    bandwidthup:   {price} times {volume} 
+    bandwidthdown: {price} times {volume}
+    vmtime: {price} times {volume}
+    diskspace: {price} times {volume}
+    effective: 
+      [see Time frames]
 
 Price lists
 ^^^^^^^^^^^
@@ -131,41 +296,34 @@ following:
     bandwidthdown:            # Price for used downstream bandwidth per MB
     vmtime:                   # Price for time 
     diskspace:                # Price for used diskspace, per MB
-    applicable:
+    effective:
       [see Timeframe format]
 
-Algorithms
-^^^^^^^^^^
+Credit Plans
+^^^^^^^^^^^^
 
-An algorithm specifies the algorithm used to perform the cost calculation, by
-combining the reported resource usage with the applicable pricelist. As opposed
-to price lists, policies define behaviours (algorithms), which have certain
-validity periods. Algorithms can either be defined inline or referenced from
-the list of defined algorithms. 
+Credit plans define how user accounts are refilled with credits.  Apart from
+the usual ``name`` and ``effective`` attributes, a credit plan has an ``at``
+attribute (a five-field Cron string) which defines how offen the refilling
+operation will run and a ``credits`` attribute which defines the number of
+credits to add to the user's wallet.
 
 .. code-block:: yaml
 
-  algorithm:
+  creditplan:
     name: default
-    bandwidthup:   {price} times {volume} 
-    bandwidthdown: {price} times {volume}
-    vmtime: {price} times {volume}
-    diskspace: {price} times {volume}
-    applicable: 
-      [see Timeframe format]
-
-
-Credit Plans
-^^^^^^^^^^^^
-
-
+    credits: 100
+    at: "00 00 1 * *"
+    effective:
+      from: 0
 
 Agreements
 ^^^^^^^^^^
 
-An agreement is the result of combining a policy with a pricelist. As the
+An agreement is the result of combining an with algorithm with a pricelist
+and a creditplan. As the
 accounting DSL's main purpose is to facilitate the construction of agreements
-(which are then associated to entities), the agreement is the centerpiece of
+(which are then associated to users), the agreement is the centerpiece of
 the language. An agreement is defined in full using the following template:
 
 .. code-block:: yaml
@@ -175,19 +333,17 @@ the language. An agreement is defined in full using the following template:
     extends: other            # [opt] name of inhereted agreement 
     pricelist: plname         # Name of declared pricelist
       resourse: value         # [opt] Overiding of price for resource
-    policy: polname           # Name of declared policy
+    algorithm: polname        # Name of declared policy
       resourse: value         # [opt] Overiding of algorithm for resourse
 
-**Consistency requirements:**
-
-- If a ``pricelist`` or ``policy`` name has not been specified, all prices or
-  algorithms for the declared resources must be defined in either the processed 
-  ``agreement`` or a parent ``agreement``.
-
-The charging algorithm
-^^^^^^^^^^^^^^^^^^^^^^
-
+An agreement definition can either reuse the pricelists, algorithms and creditplans 
+defined above (referenced by name) or define the effective algorithm or pricelist
+in place.
+If a ``pricelist`` or ``algorithm`` name has not been defined explicitely (and
+therefore referenced by name), all prices or algorithms for the declared
+resources must be defined in either the  ``agreement`` or one of its parents.
 
+As with all DSL resources, agreements can be overriden by other agreements.
 
 Examples
 ^^^^^^^^^
@@ -196,14 +352,196 @@ Examples
   unicase 
 
 
+Events
+------
+
+Aquarium communicates with external systems through events published on an `AMQP <http://en.wikipedia.org/wiki/AMQP>`_ queue. Aquarium only understands events in the
+`JSON <http://www.json.org/>`_ format.
+
+Aquarium events share a common base format consisting of the following fields:
+
+.. code-block:: javascript
+
+  {
+    id: "SHA-1",
+    occurredMillis: 12345,
+    receivedMillis: 12346 
+  }
+
+- *id* [``string``] A per message unique string. Should be able to identify messages of the same type uniquely across
+  Aquarium clients. Preferably a SHA-1.
+- *occurredMillis* [``long``] The timestamp at the event creation time. In milliseconds since the epoch.
+- *receivedMillis* [``long``] For Aquarium internal use. Clients should not set a value. If a value is set,
+  it will be overwritten upon receipt.
+
+In the following sections, we describe the exact format of each one of the concrete messages that Aquarium can process.
+
+Resource Event
+^^^^^^^^^^^^^^
+.. _resource_event:
+
+A resource event is sent by Aquarium clients to signify a change in a resource's
+state. This change is processed by Aquarium's accounting and charging system according to
+the provisions of the configured policy in order to create entries to the user's
+wallet.
+
+.. code-block:: javascript
+
+  {
+    id: "<SHA-1>",
+    occurredMillis: 1321020852,
+    receivedMillis: 1321020852,
+    clientID: "platform-wide-unique-ID",
+    userID: "administrator@admin.grnet.gr",
+    resource: "vmtime",
+    instanceID: "vmtime-01.02.123X.Z",
+    eventVersion: "1.0", 
+    value: 0.3,
+    details: {
+      keyA: "value1",
+      keyB: "value2",
+    }
+  }
+
+The meaning of the fields is as follows:
+
+- *id* As above.
+- *occurredMillis* As above.
+- *receivedMillis* As above.
+- *clientID* [``string``] A unique name for each message producer.
+- *userID* [``string``] The ID of the user that will be charged for the resource usage details reported in the
+  resource event.
+- *resource* [``string``] The name of the resource as declared in the Aquarium DSL. See `Resources`_ for more.
+- *instanceID* [``string``] If the resource is complex, then this field is set to a unique identifier for the specific
+  instance of the resource. In case of a non-complex resource, Aquarium does not examine this value but it must be
+  present.
+- *eventVersion* [``string``] The event version. Currently fixed to "1.0".
+- *value* [``double``] The value of resource usage. Depends on the cost policy defined for the resource as follows:
+   + For ``continuous`` resources, the value indicates the amount of resource usage since the last resource event for the specific resource.
+   + For ``onoff`` resources, it is set to 1 when the resource is actively used and to 0 when the resource usage has stopped.
+   + For ``discrete`` resources, the field indicates the amount of resource usage at the time of the event.
+- *details* ``map[string, string]`` A map/dictionary indicating extra metadata for this resource event. Aquarium does not process this metadata. The field must always be present, even if it is empty.
+
+User Event
+^^^^^^^^^^
+.. _user_event:
+
+A user event is sent by an external identity provider system to signify
+changes in user states. The message format is the following:
+
+.. code-block:: javascript
+
+   {
+    id: "<SHA-1>",
+    occurredMillis: 1321020852,
+    receivedMillis: 1321020852,
+    clientID: "platform-wide-unique-ID",
+    userID: "administrator@admin.grnet.gr",
+    isActive: "true",
+    role: "STUDENT",
+    eventVersion: "1", 
+    eventType: "ACTIVE",
+    details: {
+      keyA: "value1",
+      keyB: "value2",
+    }
+  }
+
+The meaning of the fields is as follows:
+
+- *id* As above.
+- *occurredMillis* As above.
+- *receivedMillis* As above.
+- *clientID* [``string``] A unique name for each message producer.
+- *userID* [``string``] The ID of the user whom this event concerns
+- *isActive* [``boolean``] Whether the user is active or not (allowed values are ``true`` or ``false``)
+- *eventVersion* [``string``] The event version. Currently fixed to "1".
+- *role* [``string``] The role of the user. If different than the role currently stored, the role will be changed.
+- *eventType* [``string (ACTIVE/SUSPENDED)``] The requested change to the user profile.
+- *details* [``map[string, string]``] A map/dictionary indicating extra metadata for this resource event. Aquarium
+  does not process this metadata. The field must always be present, even if it is empty.
+
+
+The charging algorithm
+----------------------
+
+The charging algorithm translates resource state changes into credits. These credits are subtracted from the user's
+total credit amount until it reaches either the value of zero or some negative threshold. The threshold may be
+configured on a per-user basis. The charging algorithm can be run in two modes: near real-time and batch. The former is
+the default mode of operation for Aquarium while the latter is used to make the final bill for each billing month.
+
+Near real-time charging
+^^^^^^^^^^^^^^^^
+Every resource event that arrives in Aquarium may lead to some credit calculation.
+
+As a first step, the charging algorithm has to decide whether this event alone can
+lead to a respective credit charge or some more information is needed. For example,
+an event that designates a VM switch off cannot, by itself, lead to a credit calculation but needs a
+corresponding VM switch on event. On the other hand, an event for uploading bandwidth usage has all the necessary
+information in order to compute credit charges.
+
+The next step is to specify the time frame for which the credit charges will be applied. This is rather
+straightforward, given the outcome of the previous step, since all events record their time of occurrence via their
+`occurredMillis` attribute.
+
+Then, Aquarium must decide for the given time frame which agreements are in effect. Thus it may break the time frame
+into smaller ones. Each one is tagged with the corresponding agreement. Aquarium uses the agreement to discover
+effective price units and the applicable charging algorithms. In essence, after this step is complete,
+Aquarium has all the necessary information to proceed to a charging calculation.
+
+Aquarium combines all the time frames and their associated information regarding price units and charging algorithms
+in order to calculate the sum of charges. This is subtracted from the current credit total.
+
+Batch-mode billing
+^^^^^^^^^^^
+Aquarium uses a modification of the above algorithm, which operates on a bigger time frame (the one of a billing
+month), in order to come up with the monthly use bills. In effect, the time frame is "stretched" to one month period
+and all the relevant events that occurred within the billing period are "replayed". The difference of the credit
+total between the beginning of the billing month and the end of the billing month is the credit amount charged to the
+user for that particular billing month.
+
+
+The Aquarium REST API
+---------------------
+
+External systems can communicate directly with Aquarium via a REST API. As Aquarium is a backend system, clients are
+trusted and therefore no authentication is required for accessing Aquarium's API. The main function of the REST API is
+currently to serve requests about a user's credit balance. Such requests have the form of a GET HTTP method with
+a specific URL that contains the user's unique identifier. Upon successful completion of the request,
+a response is returned back, in JSON format.
+
+
+Get User Balance
+^^^^^^^^^^^^^^^^
+
+**GET** /user/*id*/balance
+
+**Normal Response Code**: 200
+
+**Error Response Codes**: itemNotFound (404), timeout (500) 
+
+The operation returns the current balance for a user. 
+
+**Example get balance response**
+
+.. code-block:: javascript
+
+  {
+    userId: "1234"
+    balance: "321.32"
+  }
+
+
 Document Revisions
-^^^^^^^^^^^^^^^^^^
+------------------
 
 ==================    ================================
 Revision              Description
 ==================    ================================
 0.1 (Nov 2, 2011)     Initial release. Credit and debit policy descriptions 
 0.2 (Feb 23, 2012)    Update definitions, remove company use case
+0.3 (Feb 28, 2012)    Event and resource descriptions
+0.4 (Apr 6, 2012)     Minor fixes, additions
 ==================    ================================