Implement `compose_url` helper for Sinatra

This is a helper to wrap the process of building a URL from component parts,
some of which may need to be URL-escaped.  It takes many arguments, treating
each as a part of the 'relative to the app' URL, and composes them together.

Example:

    compose_url
    => '/'

    compose_url 'api', 'images'
    => '/api/images'

    compose_url 'api', 'images', image.name
    => '/api/images/correctly%20escaped%20name

Signed-off-by: Daniel Pittman <daniel@rimspace.net>
Create top level API navigation message handler

This handles an HTTP message fetching the API table: which endpoints are
available for use, and what do they do.  It includes testing and, as a side
effect, an assertion that the client is willing to accept our (only) content
response type across the board.

Signed-off-by: Daniel Pittman <daniel@rimspace.net>
Implement the `create_new_image` API message handler.

This implements the create new image message, which starts the process of
loading a new ISO image into Razor, along with creating and binding components
together to allow it to be used for later installation.

Much of the work happens in the background; this simply triggers the process,
after performing appropriate validation and transformation of the image.

Signed-off-by: Daniel Pittman <daniel@rimspace.net>
Implement the new image schema in the database

This updates the database schema, in the existing migration, to reflect the
current needs of the Image model as part of the command.  This removes a pile
of the existing data, which is not actually part of the new world
understanding of how images operate.

This also ties in the appropriate validation, ensuring that we have correct
data -- including assertions that the data passed to the command matches the
publicly modifiable parts of the model.

Some of the validation code is a little convoluted, to work around limits of
regular expressions that are compatible with both Ruby and PostgreSQL
semantics.  The great thing about POSIX regular expressions is how wonderfully
varied the implementations turn out to be.

Signed-off-by: Daniel Pittman <daniel@rimspace.net>
Implement Sequel::Model message infrastructure for TorqueBox

This provides a general purpose message handler for routing messages to
Sequel::Model instances using the TorqueBox infrastructure.  Rather than
having hand-crafted message handlers for every message, this provides a single
instance of the "load the instance, send a message to it" pattern that shows
up time and again internally.

The expected use from a user point of view will be through a Sequel::Model
plugin, providing the syntax:

    Razor::Data::ModelDerivedClass.new(...).publish(message, arg, arg, arg)

That is, roughly analogous behaviour to `public_send`, modified by the fact we
will travel through a message queue.

Internally this uses the EDN encoding, via the `edn-ruby` gem, to encode and
decode values; unlike JSON, this is capable of representing Ruby symbols, and
Time objects, allowing higher fidelity transmission of message arguments
through the queue.

These messages are not intended for use outside the single class, so
interoperatibility is not a substantial concern in the choice of encoding, and
EDN is supported in TorqueBox out of the box.

Signed-off-by: Daniel Pittman <daniel@rimspace.net>
Sequel::Model plugin to add `publish` to all instances

This adds a plugin that adds the sugary `publish` method to all Sequel::Model
instances, allowing callers to publish that message for later consumption
using the TorqueBox message queue.

Signed-off-by: Daniel Pittman <daniel@rimspace.net>
INCOMPLETE: Implement the image file download and unpack workflow

Implement the image download, unpack, and related behaviour using the
background messaging capabilities of the image instance.  The individual steps
are broken down into distinct functions to make them more comprehensible than
a single, giant, function performing all actions.

This is currently incomplete: it can download the remote file, or validate a
local file, but the unpacking and validation are not yet implemented, and no
error handling is in place.

Signed-off-by: Daniel Pittman <daniel@rimspace.net>