Using Adamalib

This notebook shows an example of using adamalib to control Adama.

Setup

First, define the location of the Adama server.

The official server is:

https://api.araport.org/community/v0.3

For a development environment the URL may differ (for example: http://localhost/community/v0.3). Use a URL such that URL/status reaches the status endpoint of your server.


In [29]:
API = 'http://192.168.35.10/community/v0.3'

The official Adama server requires a bearer token, but other test services may not need it. Leave it empty in such case.


In [30]:
TOKEN = 'mytoken'

Create an adama object bound to the API server:


In [31]:
import adamalib
reload(adamalib.adamalib)
adama = adamalib.Adama(API, token=TOKEN)

Check that the object is correctly linked by asking the status of the server. This is equivalent to performing a GET request to the endpoint API/status. It should return a dictionary of the form:

{u'api': u'Adama v0.3',
 u'hash': u'...',
 u'status': u'success'}

In [32]:
adama.status


Out[32]:
{u'api': u'Adama v0.3',
 u'hash': u'53bb1fc25b19b7c253f21ad1e518d30d88179a4f',
 u'status': u'success'}

Namespaces

Namespaces are accessed with the property namespaces. It returns a list of namespace objects, each of them can be queried for its information:


In [33]:
adama.namespaces


Out[33]:
[Namespace(ex_ea),
 Namespace(quia_sunt),
 Namespace(foo),
 Namespace(copulationesque_primum),
 Namespace(pleraque_pleraque),
 Namespace(quarum_quia),
 Namespace(quam_quae),
 Namespace(sunt_tuum),
 Namespace(reges_fecimus)]

Let's create a new random namespace.

First, a detour for a simple function to generate random names, so we don't overwrite existing ones (not likely, at least):


In [34]:
import requests
import string
import random

lorem = requests.get('http://loripsum.net/api/plaintext').text
WORDS = [word.lower() 
         for word in filter(lambda c: c not in string.punctuation, lorem).split()]

def random_words(n=2):
    return '_'.join(random.choice(WORDS) for i in range(n))

Create a namespace with a random name:


In [35]:
namespace = adama.namespaces.add(name=random_words())
namespace


Out[35]:
Namespace(liberius_et)

The new namespace should appear if we ask again:


In [36]:
adama.namespaces


Out[36]:
[Namespace(ex_ea),
 Namespace(quia_sunt),
 Namespace(foo),
 Namespace(copulationesque_primum),
 Namespace(pleraque_pleraque),
 Namespace(quarum_quia),
 Namespace(quam_quae),
 Namespace(sunt_tuum),
 Namespace(liberius_et),
 Namespace(reges_fecimus)]

A particular namespace, say foo, can be accessed directly as adama.foo.

Services

List the services contained in a namespace with:


In [37]:
namespace.services


Out[37]:
[]

The result should be the empty list, since we just created a new namespace.

Creating a service

Let's create a simple service that prints the local time. adamalib provides functions to initialize an empty service in the local machine, and then to register it in the remote API server.

The following command creates a service with a random name, creating a directory with the same name and with the bare minimum information necessary to register the service.


In [38]:
SERVICE = random_words(n=1)
adama.utils.create(SERVICE, 'query')
SERVICE


Out[38]:
u'sine'

The metadata file created contains only the most basic information. Consult the docs for the full list of fields.


In [46]:
!cat $SERVICE/metadata.yml


---
name: sine
version: 0.1
type: query

The following function is an example of a very basic service, which just prints an argument, and the localtime.

The first line (%%writefile ...) is a "magic" command to save the cell to the newly created service.


In [39]:
%%writefile {SERVICE}/main.py

import json
import datetime

def search(args, adama):
    print(json.dumps({'name': args.get('name', 'no name given')}))
    print('---')
    print(json.dumps({'localtime': datetime.datetime.now().isoformat(' ')}))


Overwriting sine/main.py

Import the module just created:


In [40]:
import importlib
service_module = importlib.import_module(SERVICE+'.main')
reload(service_module)


Out[40]:
<module 'sine.main' from 'sine/main.pyc'>

It can be tested immediately:


In [41]:
service_module.search({'name': 'foo'}, adama)


{"name": "foo"}
---
{"localtime": "2015-04-24 20:25:12.662103"}

The last three cells can be edited and re-evaluated until satisfied with the output of the service.

Registering a service

Next, we proceed to register the service. We use adamalib to add the module to the services list of the proper namespace. adamalib takes care of uploading any other module needed by service_module, including the file metadata.yml.


In [42]:
service = namespace.services.add(service_module)
service


Out[42]:
Service(/liberius_et/sine_v0.1)

The basic operation on the service of type query is to perform a search. The following command performs a GET request to the /search endpoint of the service:


In [43]:
service.search(name='bar')


Out[43]:
[{u'name': u'bar'}, {u'localtime': u'2015-04-24 20:25:28.403111'}]

Cleaning up

To tidy things up, we delete the service and the namespace:


In [44]:
service.delete()
namespace.delete()