Requirements
Ufora development is done on 64-bit Ubuntu 14.04. However, to simplify development on other operating systems, a docker image is available with all the necessary build-related packages and dependencies.
All that is required is a 64-bit OS capable of running docker.
Install Docker
Go to docker.com and click “Get Started” to download and install docker.
On Ubuntu 14.04 it’s as simple as running:
$ sudo apt-get update
$ sudo apt-get install docker.io
Then to enable command-line TAB completion either restart your shell or run:
$ source /etc/bash_completion.d/docker.io
You can optionally follow these instructions
to be able to run docker without sudo
. Note that it still runs the docker daemon as root -
it just saves you five keystrokes when running docker commands.
Before proceeding you must make sure the docker deamon is started.
Pull Ufora Build Image
The Ufora build image is based on Ubuntu-14.04. To download it to your local docker image repository:
$ sudo docker pull ufora/build
To see the downloaded images, run:
$ sudo docker images | grep ufora
ufora/build latest 7405aad675a3 2 days ago 1.569 GB
The output should look something like the above though the number and ids of images will vary over time.
To try it out run:
$ sudo docker run -it --rm=true ufora/build bash
root@4cdcdd1b4d6c:
Congratulations! You now have a container running an interactive bash
session in on Ubuntu 14.04.
You can terminate the container at any time by exiting the bash session (i.e. $ exit
).
Note: Any changes you make to the state of the container (e.g. installing packages, editing files, etc.)
are lost when you exit the container due to the --rm=true
argument, which tells docker to delete the container when it exits.
Setup Mounted Volumes
Docker lets you share directories between containers and the host. This is done using Volumes.
There are many ways to work with volumes in docker. One of the easiest and most convenient ways is by creating a container on your machine that maps one or more directories from your host file-system into docker volumes. You can then easily mount all volumes from that data container into any new containers you launch.
Start by creating a directory in your host file-system that will act as your mount point:
$ mkdir ~/volumes
Pull the base Ubuntu-14.04 image if you haven’t already done so:
$ sudo docker pull ubuntu:14.04
Pulling repository ubuntu
5ba9dab47459: Download complete
511136ea3c5a: Download complete
27d47432a69b: Download complete
5f92234dcf1e: Download complete
51a9c7c1f8bb: Download complete
Create a named, daemonized container called DATA
and mount your volumes directory into it:
$ sudo docker run -d --name DATA -v /home/user/volumes:/volumes ubuntu:14.04
051f5275583c726d80a7a484a5fea01a580c3f2900ee6ee93130d84be10cd9e7
The -v
argument defines a mapping between a path in the host file-system and the container.
In the example above, the directory /home/user/volumes/
will appear in the container under /volumes
.
You can now run containers and map volumes from DATA
into them using docker’s --volumes-from
option. For example:
$ touch ~/volumes/test.file
$ sudo docker run -it --volumes-from DATA ufora/build bash
> ls /volumes
test.file
> touch /volumes/test2.file
> exit
$ ls ~/volumes
test.file test2.file
Clone the Ufora Repo
You will want to have a clone of the repo inside your volumes directory. The easiest way is to simply create a new clone:
$ git clone git@github.com:ufora/ufora.git ~/volumes/src
Note that you cannot create a symbolic link to an existing repo inside your volumes directory because
the link will not be resolvable inside docker containers.
If you absolutely must expose an existing directory, you can either add it as another volume in your DATA
container,
or use mount --bind
to mount it into a subdirectory of ~/volumes
.
Note that if you use the mount
approach, the newly mounted directory will be visible to new containers,
but not to ones that were already running when the directory was mounted.
Running a Dev Container
You are now ready to launch a container from the image you downloaded.
The docker run
command is used to create a container from a specified image and run a command in it.
To launch a container run:
$ sudo docker run -it --volumes-from DATA -p 30000:30000 --privileged=true --rm=true ufora/build bash
Let’s take a look at the arguments:
-it
- runs the container interactively in the terminal (and creates a pseudo-tty)--volumes-from DATA
- mount all volumes mounted to the container named “DATA”-p 30000:30000
- map port 30000 in the container (the HTTP port of the ufora-web service) to the same port in the host OS. This lets you run Python code that uses thepyfora
package on your host OS and connect to the Ufora backedn running in the container usingpyfora.connect('http://localhost:30000')
.--privileged=true
- run the container in privileged mode. This is necessary if you want to usegdb
to debug processes inside the container.--rm=true
- delete the container when it exists.
You are now in a bash session inside your newly launched container and are ready to build.
Building the Project
To build the project run (replacing /volumes/src
with the mount point of your repo):
> cd /volumes/src
> export PYTHONPATH=`pwd`
> ./waf configure
> ufora/scripts/resetAxiomSearchFunction.py
> ./waf install
> ufora/scripts/rebuildAxiomSearchFunction.py
> ./waf install
This will take between 12 and 30 minutes, depending on the speed of your computer.
Notice that we run a two-phase build. Some source files are generated, but the generator itself uses the Ufora shared-object. We first build with a stub version of the generated code, then run the code-generator (line 4) to produce the “real” code and then build again. The second build should be much faster.
You only need to run resetAxiomSearchFunction.py
when you build a clean repo for the first time,
and you only need to run rebuildAxiomSearchFunction.py
after pulling a new revision or after
making changes to AxiomSearch.cpp
or AxiomSearch2.cpp
in /ufora/Fora/Axioms/
.
Running the Ufora Services
You will need to set a couple of environment variables, install node.js
modules required by the
web front-end, and install the pyfora
package in development mode.
Assuming you mounted your repo to /volumes/src
, run:
> cd /volumes/src
> export PYTHONPATH=`pwd`
> export ROOT_DATA_DIR=/volumes/ufora
> pip install -e packages/python
> cd ufora/web/relay
> npm install
Start the ufora backend services and a worker:
> cd /volumes/src
> ufora/scripts/init/start
> ufora/scripts/init/ufora-worker start
The Ufora services should now be running using the forever
watchdog service.
To list all running services run:
> forever list
info: Forever processes running
data: uid command script forever pid id logfile uptime
data: [0] 7xUM python /volumes/src/ufora/distributed/SharedState/sharedStateMainline.py --logging=info 1047 1063 /volumes/ufora/logs/ufora-store.log 0:0:1:41.859
data: [1] __r7 python /volumes/src/ufora/scripts/init/ufora-gateway.py 1068 1085 /volumes/ufora/logs/ufora-gateway.log 0:0:1:41.611
data: [2] wCvy coffee /volumes/src/ufora/web/relay/server.coffee --gatewayport=30008 --port=30000 1090 1099 /volumes/ufora/logs/ufora-web.log 0:0:1:41.365
data: [3] QEGg python /volumes/src/ufora/scripts/init/ufora-worker.py 1176 1181 /volumes/ufora/logs/ufora-worker.log 0:0:0:3.301
The service logs are placed in the logs
directory of ROOT_DATA_DIR
.
Ufora Services
The Ufora platform consists of several services that work in concert.
ufora-worker
This is the workhorse of the platform and is the only service that runs on all machines in a cluster (although it doesn’t have to run on the cluster manager machine). The ufora-worker is the service that runs computations and loads data.
ufora-web
The ufora-web service is the HTTP front-end that runs on the cluster-manager machine. Clients use
the pyfora
python package to connect to a cluster using socket.io over HTTP, and this is the service
that handles their connections.
ufora-gateway
This service runs on the cluster-manager machine and acts as an intermediate between the web front-end and the worker nodes. It maintains connections to the workers, submits computations, tracks their progress, and sends results back to users.
ufora-store
This is a simple in-memory key-value store with publish-subscribe capabilities. It is mainly used by workers to discover each other. The ufora-store service runs on the cluster-manager machine.
Stopping the Ufora Services
To stop all Ufora services run:
> forever stopall
Running Tests
The main entry point for running tests is the script test.py
at the root of the repo.
Tests are broken up into several categories:
native
: C++ unit testslang
: Unit tests for the fora language.py
: Python unit tests - these are the majority of tests. These are all single-process tests.scripts
: Multi-process tests that run a full Ufora backend. The test scripts live in the repo under/test_scripts/
.
You can run all test by running:
python test.py
However, running all tests can take a very long time on a single machine. You can also run a single test category with:
python test.py -native
python test.py -lang
python test.py -py [-filter=test_name] [-modpair i n]
python test.py -scripts [--scriptPath test_scripts/<path>]
CCache
The Ufora dev image has ccache
installed and configured to use /volumes/ccache
as its cache directory.
This allows you to reuse the cache across container instances and also speeds up the build within a container
because mounted volumes don’t use docker’s AUFS layered file-system.
If you mount your volumes to a directory other than /volumes
,
you will need to set the CCACHE_DIR
environment variable accordingly.