Statistics
| Branch: | Tag: | Revision:

root / doc / manual / source / devguide.rst @ 743d083c

History | View | Annotate | Download (22.9 kB)

1
Development Guide
2
=================
3

    
4
The development guide includes descriptions of the APIs and extention points
5
offered by Aquarium. It also includes design and development setup information.
6

    
7
Obtaining and Compiling
8
-----------------------
9

    
10
The source code to the Aquarium project can be obtained through Git, by
11
cloning the repository `http://code.grnet.gr/git/aquarium`. This will give
12
you read-only access to the repository. You need to contact the Aquarium
13
team to obtain read-write access.
14

    
15
To compile Aquarium, you need the following software in your path:
16

    
17
- Java SDK 6. Java 7 has not been tested yet.
18
- `Maven <http://maven.apache.org>`_, version > 3
19

    
20
After you install them, you can do the following:
21

    
22
- ``mvn install``: To compile Aquarium and run the tests. This will also create 
23
  the file ``target/aquarium-<ver>-jar-with-dependencies.jar`` which can be
24
  used to start Aquarium from the command line. To skip the tests while compiling,
25
  run ``mvn install --skipTests=true``.
26
- ``mvn deploy``:  To deploy the Aquarium libraries to the remote Maven repository
27
- ``mvn release:prepare``, ``mvn release:perform``: To prepare a release,
28
  tag a new version and start the next development version
29
- ``mvn scala:cctest``: To run the Scala compiler in continuous compilation
30
  mode
31

    
32
Aquarium can also be build with the Simple Build Tool
33
(`SBT <https://github.com/harrah/xsbt/wiki>`_). Just run ``sbt`` in the directory 
34
containing the Aquarium source code.
35

    
36
Distributing
37
^^^^^^^^^^^^
38

    
39
To prepare a binary distribution of Aquarium, use the ``make-dist.sh`` script.
40
If the script is run without an argument, it will create a TAR archive from
41
the latest tagged version of Aquarium. The script also accepts a Git commit-ish,
42
in which case it will build a TAR archive out of the provided Git commit.
43

    
44
Overall architecture
45
--------------------
46

    
47
Aquarium's architectural design is mainly driven by two requirements: scaling
48
and fault tolerance. Aquarium's functionality is based on event sourcing.
49
`Event sourcing <http://en.wikipedia.org/wiki/Domain-driven_design>`_ 
50
assumes that all changes to application state are stored as a
51
sequence of events, in an immutable log. With such a log at hand, a system can
52
rebuild the current application state by replaying the events in order. The event
53
sourcing design pattern has some very interesting properties, which made it
54
particularity suitable for basing Aquarium on it:
55

    
56
- 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.
57

    
58
- 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.
59

    
60
- 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.
61

    
62
- After event log replay, new events only cause updates in the system’s in-memory state, which can be done very fast.
63

    
64
Components
65
^^^^^^^^^^
66

    
67
.. image:: arch.png
68

    
69
An overview of the Aquarium architecture is presented in the figure above.  The
70
system is modeled as a collection of logically and functionally isolated
71
components, which communicate by message passing. Withing each component, a
72
number of actors take care of concurrently processing incoming messages through
73
a load balancer component which is the gateway to requests targeted to the
74
component. Each component is also monitored by its own supervisor; should an
75
actor fail, the supervisor will automatically restart it. The architecture
76
allows certain application paths to fail individually while the system is still
77
responsive, while also enabling future distribution of multiple components on
78
clusters of machines.
79

    
80
The system receives input mainly from two sources: a queue for resource and
81
user events and a REST API for credits and resource state queries. The queue
82
component reads messages from a configurable number of queues and persists them
83
in the application’s immutable log store. Both input components then forward
84
incoming messages to a network of dispatcher handlers which do not do any
85
processing by themselves, but know where the user actors lay. Actual processing
86
of billing events is done within the user actors. Finally, a separate network
87
of actors take care of scheduling periodic tasks, such as refiling of user
88
credits; it does so by issuing events to the appropriate queue.
89

    
90
The accounting system
91
----------------------
92

    
93
The accounting subsystem deals with charging users for services used and 
94
providing them with credits in order to be able to use the provided services.
95
As with the rest of the Aquarium, the architecture is open-ended: the accounting
96
system does not know in advance which services it supports or what resources
97
are being offered. The configuration of the accounting system is done
98
using a Domain Specific Language (DSL) described below. 
99

    
100
Data exchange with external systems is done through events, which are
101
persisted to an *immutable log*.
102

    
103
The accounting system is a generic event-processing engine that is configured by a
104
DSL. The DSL is mostly based on the
105
`YAML <http://en.wikipedia.org/wiki/Yaml>`_ 
106
format. The DSL supports limited algorithm definitions through integration of the Javascript language as defined below.
107

    
108
Glossary of Entities
109
^^^^^^^^^^^^^^^^^^^^
110

    
111
- *Credit*: A credit is the unit of currency used in Aquarium. It may or may not 
112
  correspond to real money.
113
- *Resource*: A resource represents an entity that can be charged for its usage. The 
114
  currently charged resources are: Time of VM usage, bytes uploaded and downloaded and bytes used for storage
115
- *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`_).
116
- *AccountingEntry*: An accounting entry is the result of processing a resource event and is what gets stored to the user's wallet.
117
- *Price List*: A price list contains information of the cost of a resource. 
118
  A pricelist is only applied within a specified time frame.
119
- *Algorithm*: An algorithm specifies the way the charging calculation is done. It can be vary  depending on resource usage, time of raw event or other information.
120
- *Credit Plan*: Defines a periodic operation of refiling a user's wallet with a
121
  configurable amount of credits.
122
- *Agreement*: An agreement associates pricelists with algorithms and credit
123
  plans. An agreement is assigned to one or more users/credit holders.
124
- *Billing Period*: A billing period defines a recurring timeslot at the end
125
  of which the accumulated resource usage is accounted for and reset.
126

    
127
Overall Schema
128
^^^^^^^^^^^^^^
129

    
130
The Aquarium policy DSL allows the hierarchical definition of agreements, by
131
means of compositing ingredients and specifying validity periods for individual
132
components or for the policies themselves. The DSL also allows overriding
133
between items of the same class (i.e. an algorithm definition can override
134
certain fields of another algorithm definition, while both definitions can 
135
be referenced individually). 
136

    
137
The top-level schema for the DSL is as follows.
138

    
139
.. code-block:: yaml
140

    
141
  aquariumpolicy:
142
    resources:
143
      - resource:
144
        ... [see Resources]
145

    
146
    algorithms:
147
      - algorithm:
148
        ... [see Algorithms]
149

    
150
    pricelists:
151
      - pricelist:
152
        ... [see Pricelists]
153

    
154
    creditplans:
155
      - creditplan:
156
        ... [see Creditplans]
157

    
158
    agreements:
159
      - agreement:
160
        ... [see Agreements]
161

    
162

    
163
Time frames
164
^^^^^^^^^^^
165

    
166
Time frames allow the specification of applicability periods for algorithms,
167
pricelists and agreements. A timeframe is by default continuous and has a
168
starting point; if there is no ending point, the timeframe is considered open
169
and its ending point is the time at the time of evaluation. 
170

    
171
A time frame definition can contain repeating time ranges that dissect it and
172
consequently constrain the applicability of the time frame to the defined
173
ranges only. A range always has a start and end point. A range is repeated
174
within a timeframe, until the timeframe end point is reached. In case a
175
repeating range ends later than the containing timeframe, the ending time is
176
adjusted to match that of the timeframe.
177

    
178
The definition of the starting and ending point of a time range is done in a 
179
syntax reminisent of the `cron <http://en.wikipedia.org/wiki/Cron>`_ format. 
180

    
181
.. code-block:: yaml
182

    
183
  effective:
184
    from: %d                         # Milliseconds since the epoch
185
    to:  %d                          # [opt] Milliseconds since the epoch
186
    repeat:                          # [opt] Defines a repetion list
187
      - every:                       # [opt] A repetion entry 
188
        start: "min hr dom moy dow"  # 5-elem cron string
189
        end:   "min hr dom moy dow"  # 5-elem cron string 
190

    
191

    
192
The following declaration defines a timeframe starting at the designated
193
timestamp and ending at the time of evaluation.
194

    
195
.. code-block:: yaml
196

    
197
  effective:
198
    from: 1293703200  #(30/12/2010 10:00)
199

    
200
The following declaration defines a timeframe of one year, within which the
201
applicability of the specified policy, agreement or pricelist is constrained to
202
time ranges from 12:00 Mon to 14:00 Fri  (first ``every`` definition)
203
and 15:00 Sat to 15:00 Sun.
204

    
205
.. code-block:: yaml
206

    
207
  effective:
208
    from: 1293703200  #(30/12/2010 10:00)
209
    to:   1325239200  #(30/12/2011 10:00)
210
    repeat:
211
      - every:
212
        start: "00 12 * * Mon"
213
        end:   "00 14 * * Fri"
214
      - every:
215
        start: "00 15 * * Sat"
216
        end:   "00 15 * * Sun"
217

    
218
Resources
219
^^^^^^^^^
220

    
221
A resource represents an entity that can be charged for. Aquarium does not
222
assume a fixed set of resource types and is extensible to any number of
223
resources. A resource has a ``name`` and a ``unit``; both are free form
224
strings. The resource name is used to uniquely identify the resource both inside
225
Aquarium and among external systems.
226

    
227
A resource definition also has a two fields that define how a resource is
228
charged and whether a user can be assigned more instances of a resource.
229
Specifically, the ``costpolicy`` field can have the following values:
230

    
231
- `continuous:` For ``continuous`` resources, the charging algorithm calculates the
232
  total amount of resource usage over time, per billing period. Each new
233
  resource event modifies the resource usage counter and forces Aquarium
234
  to calculate a new cost for the previous amount of resource usage. A typical
235
  example  of a continuous resource is disk space.
236
- `onoff:` ``onoff`` resources are a category of continuous resources where the
237
  resource can only be in two states, on or off. In such cases, maintaining a usage
238
  counter is not necessary; the charging algorithm uses time as the unit of
239
  calculation. Virtual machine time is a typical example.
240
- `discrete:` ``discrete`` resources are charged for instantly for the
241
  reported resource value. Examples are bandwidth and every resource whose usage
242
  is not a function of time (books, hits to an API etc). 
243

    
244
Regarding resource complexity, a resource can either be labeled complex 
245
or not. In the former case, a resource can have more than one instances per
246
user, and resource usage is tracked individually per instance. The 
247
``instance-id`` field in the resource event message (See `Resource Event`_) 
248
helps Aquarium separate resource instances at charge time. 
249

    
250
The following resource definition defines the `bandwidthup` 
251
resource. 
252

    
253
.. code-block:: yaml
254

    
255
  resource:
256
    name: bandwidthup
257
    unit: MB/hr
258
    complex: false
259
    costpolicy: discrete
260

    
261
Algorithms
262
^^^^^^^^^^
263

    
264
An algorithm specifies the algorithm used to perform the cost calculation, by
265
combining the reported resource usage with the applicable pricelist. As opposed
266
to price lists, algorithms define behaviours, which have certain
267
validity periods. 
268

    
269
.. code-block:: yaml
270

    
271
  algorithm:
272
    name: default
273
    bandwidthup:   {price} times {volume} 
274
    bandwidthdown: {price} times {volume}
275
    vmtime: {price} times {volume}
276
    diskspace: {price} times {volume}
277
    effective: 
278
      [see Time frames]
279

    
280
Price lists
281
^^^^^^^^^^^
282

    
283
A price list defines the prices applicable for a resource within a validity
284
period. Prices are attached to resource types and denote the policies that
285
should be deducted from an entity's wallet in response to the entity's resource
286
usage within a given charging period (currently, a month). The format is the
287
following:
288

    
289
.. code-block:: yaml
290

    
291
  pricelist:                  # Pricelist structure definition  
292
    name: apricelist          # Name for the price list, no spaces, must be unique
293
    [extends: anotherpl]      # [Optional] Inheritance operation: all optional fields  
294
                              # are inherited from the named pricelist
295
    bandwidthup:              # Price for used upstream bandwidth per MB 
296
    bandwidthdown:            # Price for used downstream bandwidth per MB
297
    vmtime:                   # Price for time 
298
    diskspace:                # Price for used diskspace, per MB
299
    effective:
300
      [see Timeframe format]
301

    
302
Credit Plans
303
^^^^^^^^^^^^
304

    
305
Credit plans define how user accounts are refilled with credits.  Apart from
306
the usual ``name`` and ``effective`` attributes, a credit plan has an ``at``
307
attribute (a five-field Cron string) which defines how offen the refilling
308
operation will run and a ``credits`` attribute which defines the number of
309
credits to add to the user's wallet.
310

    
311
.. code-block:: yaml
312

    
313
  creditplan:
314
    name: default
315
    credits: 100
316
    at: "00 00 1 * *"
317
    effective:
318
      from: 0
319

    
320
Agreements
321
^^^^^^^^^^
322

    
323
An agreement is the result of combining an with algorithm with a pricelist
324
and a creditplan. As the
325
accounting DSL's main purpose is to facilitate the construction of agreements
326
(which are then associated to users), the agreement is the centerpiece of
327
the language. An agreement is defined in full using the following template:
328

    
329
.. code-block:: yaml
330

    
331
  agreement:
332
    name: someuniqname        # Unique name for 
333
    extends: other            # [opt] name of inhereted agreement 
334
    pricelist: plname         # Name of declared pricelist
335
      resourse: value         # [opt] Overiding of price for resource
336
    algorithm: polname        # Name of declared policy
337
      resourse: value         # [opt] Overiding of algorithm for resourse
338

    
339
An agreement definition can either reuse the pricelists, algorithms and creditplans 
340
defined above (referenced by name) or define the effective algorithm or pricelist
341
in place.
342
If a ``pricelist`` or ``algorithm`` name has not been defined explicitely (and
343
therefore referenced by name), all prices or algorithms for the declared
344
resources must be defined in either the  ``agreement`` or one of its parents.
345

    
346
As with all DSL resources, agreements can be overriden by other agreements.
347

    
348
Examples
349
^^^^^^^^^
350
.. toctree::
351

    
352
  unicase 
353

    
354

    
355
Events
356
------
357

    
358
Aquarium communicates with external systems through events published on an `AMQP <http://en.wikipedia.org/wiki/AMQP>`_ queue. Aquarium only understands events in the
359
`JSON <http://www.json.org/>`_ format.
360

    
361
Aquarium events share a common base format consisting of the following fields:
362

    
363
.. code-block:: javascript
364

    
365
  {
366
    id: "SHA-1",
367
    occurredMillis: 12345,
368
    receivedMillis: 12346 
369
  }
370

    
371
- *id* [``string``] A per message unique string. Should be able to identify messages of the same type uniquely across
372
  Aquarium clients. Preferably a SHA-1.
373
- *occurredMillis* [``long``] The timestamp at the event creation time. In milliseconds since the epoch.
374
- *receivedMillis* [``long``] For Aquarium internal use. Clients should not set a value. If a value is set,
375
  it will be overwritten upon receipt.
376

    
377
In the following sections, we describe the exact format of each one of the concrete messages that Aquarium can process.
378

    
379
Resource Event
380
^^^^^^^^^^^^^^
381
.. _resource_event:
382

    
383
A resource event is sent by Aquarium clients to signify a change in a resource's
384
state. This change is processed by Aquarium's accounting and charging system according to
385
the provisions of the configured policy in order to create entries to the user's
386
wallet.
387

    
388
.. code-block:: javascript
389

    
390
  {
391
    id: "<SHA-1>",
392
    occurredMillis: 1321020852,
393
    receivedMillis: 1321020852,
394
    clientID: "platform-wide-unique-ID",
395
    userID: "administrator@admin.grnet.gr",
396
    resource: "vmtime",
397
    instanceID: "vmtime-01.02.123X.Z",
398
    eventVersion: "1.0", 
399
    value: 0.3,
400
    details: {
401
      keyA: "value1",
402
      keyB: "value2",
403
    }
404
  }
405

    
406
The meaning of the fields is as follows:
407

    
408
- *id* As above.
409
- *occurredMillis* As above.
410
- *receivedMillis* As above.
411
- *clientID* [``string``] A unique name for each message producer.
412
- *userID* [``string``] The ID of the user that will be charged for the resource usage details reported in the
413
  resource event.
414
- *resource* [``string``] The name of the resource as declared in the Aquarium DSL. See `Resources`_ for more.
415
- *instanceID* [``string``] If the resource is complex, then this field is set to a unique identifier for the specific
416
  instance of the resource. In case of a non-complex resource, Aquarium does not examine this value but it must be
417
  present.
418
- *eventVersion* [``string``] The event version. Currently fixed to "1.0".
419
- *value* [``double``] The value of resource usage. Depends on the cost policy defined for the resource as follows:
420
   + For ``continuous`` resources, the value indicates the amount of resource usage since the last resource event for the specific resource.
421
   + For ``onoff`` resources, it is set to 1 when the resource is actively used and to 0 when the resource usage has stopped.
422
   + For ``discrete`` resources, the field indicates the amount of resource usage at the time of the event.
423
- *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.
424

    
425
User Event
426
^^^^^^^^^^
427
.. _user_event:
428

    
429
A user event is sent by an external identity provider system to signify
430
changes in user states. The message format is the following:
431

    
432
.. code-block:: javascript
433

    
434
   {
435
    id: "<SHA-1>",
436
    occurredMillis: 1321020852,
437
    receivedMillis: 1321020852,
438
    clientID: "platform-wide-unique-ID",
439
    userID: "administrator@admin.grnet.gr",
440
    isActive: "true",
441
    role: "STUDENT",
442
    eventVersion: "1", 
443
    eventType: "ACTIVE",
444
    details: {
445
      keyA: "value1",
446
      keyB: "value2",
447
    }
448
  }
449

    
450
The meaning of the fields is as follows:
451

    
452
- *id* As above.
453
- *occurredMillis* As above.
454
- *receivedMillis* As above.
455
- *clientID* [``string``] A unique name for each message producer.
456
- *userID* [``string``] The ID of the user whom this event concerns
457
- *isActive* [``boolean``] Whether the user is active or not (allowed values are ``true`` or ``false``)
458
- *eventVersion* [``string``] The event version. Currently fixed to "1".
459
- *role* [``string``] The role of the user. If different than the role currently stored, the role will be changed.
460
- *eventType* [``string (ACTIVE/SUSPENDED)``] The requested change to the user profile.
461
- *details* [``map[string, string]``] A map/dictionary indicating extra metadata for this resource event. Aquarium
462
  does not process this metadata. The field must always be present, even if it is empty.
463

    
464

    
465
The charging algorithm
466
----------------------
467

    
468
The charging algorithm translates resource state changes into credits. These credits are subtracted from the user's
469
total credit amount until it reaches either the value of zero or some negative threshold. The threshold may be
470
configured on a per-user basis. The charging algorithm can be run in two modes: near real-time and batch. The former is
471
the default mode of operation for Aquarium while the latter is used to make the final bill for each billing month.
472

    
473
Near real-time charging
474
^^^^^^^^^^^^^^^^
475
Every resource event that arrives in Aquarium may lead to some credit calculation.
476

    
477
As a first step, the charging algorithm has to decide whether this event alone can
478
lead to a respective credit charge or some more information is needed. For example,
479
an event that designates a VM switch off cannot, by itself, lead to a credit calculation but needs a
480
corresponding VM switch on event. On the other hand, an event for uploading bandwidth usage has all the necessary
481
information in order to compute credit charges.
482

    
483
The next step is to specify the time frame for which the credit charges will be applied. This is rather
484
straightforward, given the outcome of the previous step, since all events record their time of occurrence via their
485
`occurredMillis` attribute.
486

    
487
Then, Aquarium must decide for the given time frame which agreements are in effect. Thus it may break the time frame
488
into smaller ones. Each one is tagged with the corresponding agreement. Aquarium uses the agreement to discover
489
effective price units and the applicable charging algorithms. In essence, after this step is complete,
490
Aquarium has all the necessary information to proceed to a charging calculation.
491

    
492
Aquarium combines all the time frames and their associated information regarding price units and charging algorithms
493
in order to calculate the sum of charges. This is subtracted from the current credit total.
494

    
495
Batch-mode billing
496
^^^^^^^^^^^
497
Aquarium uses a modification of the above algorithm, which operates on a bigger time frame (the one of a billing
498
month), in order to come up with the monthly use bills. In effect, the time frame is "stretched" to one month period
499
and all the relevant events that occurred within the billing period are "replayed". The difference of the credit
500
total between the beginning of the billing month and the end of the billing month is the credit amount charged to the
501
user for that particular billing month.
502

    
503

    
504
The Aquarium REST API
505
---------------------
506

    
507
External systems can communicate directly with Aquarium via a REST API. As Aquarium is a backend system, clients are
508
trusted and therefore no authentication is required for accessing Aquarium's API. The main function of the REST API is
509
currently to serve requests about a user's credit balance. Such requests have the form of a GET HTTP method with
510
a specific URL that contains the user's unique identifier. Upon successful completion of the request,
511
a response is returned back, in JSON format.
512

    
513

    
514
Get User Balance
515
^^^^^^^^^^^^^^^^
516

    
517
**GET** /user/*id*/balance
518

    
519
**Normal Response Code**: 200
520

    
521
**Error Response Codes**: itemNotFound (404), timeout (500) 
522

    
523
The operation returns the current balance for a user. 
524

    
525
**Example get balance response**
526

    
527
.. code-block:: javascript
528

    
529
  {
530
    userId: "1234"
531
    balance: "321.32"
532
  }
533

    
534

    
535
Document Revisions
536
------------------
537

    
538
==================    ================================
539
Revision              Description
540
==================    ================================
541
0.1 (Nov 2, 2011)     Initial release. Credit and debit policy descriptions 
542
0.2 (Feb 23, 2012)    Update definitions, remove company use case
543
0.3 (Feb 28, 2012)    Event and resource descriptions
544
0.4 (Apr 6, 2012)     Minor fixes, additions
545
==================    ================================
546

    
547