Vagoth provides a cluster management framework that you can build upon to create interesting applications where you have the concept of nodes
which can have relationships to one another, finite resources that must be tracked, and a lifecycle which starts with provisioning and ends with deprovisioning. What they do along the way is up to the specific implementation, but it can make use of a job scheduler and actions to perform tasks in the background. Is that abstract enough for you?
A more concrete example is managing a cluster of virtual machines and the servers they run upon. In fact, Vagoth comes with a set of components to do just that.
You can find more documentation under doc/
Vagoth comes with a VM-management focused CLI which wraps around the Python API.
In this example, I'm using the Geats driver
to provision an LXC container according to a definition that's created by a custom provisioner
plugin. The provisioner adds an entry to DHCP and DNS for the new node before saving it using the registry
plugin.
Here I'm using the included synchronous job scheduler
plugin which runs the action
immediately. The messages prefixed by 'vagoth:' are the logging.info() messages generated by the actions.
# ask the provisioner to create a new VM called 'devnode1' using the 'debian' template
$ vagoth new devnode1 template=debian
new: OK (devnode1)
# list the new node. It doesn't yet have a state or a parent assigned.
$ vagoth list devnode1
devnode1 state=unknown type=vm parent=
# Call devnode1.start(), which triggers the 'start' action. It also
# sees that it's not defined (deployed) anywhere yet, so it calls the
# define action first, to assign the 'devnode1' node to a server.
$ vagoth start devnode1
vagoth: txid=6e2bc0fb source=myuser action=start vm=devnode1
vagoth: txid=6e2bc0fb source=myuser action=define vm=devnode1
start: OK (devnode1)
# The action has set the state 'starting'
$ vagoth list devnode1
devnode1 state=starting type=vm parent=hyper1
# Call the monitor plugin to poll all the hv nodes for the latest state.
$ vagoth poll
# It picked up the new running state
$ vagoth list devnode1
devnode1 state=running type=vm parent=hyper1
$ ssh root@devnode1
root@devnode1:~# ip route ls
default via 192.168.1.1 dev eth0
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.46
root@devnode1:~# exit
Connection to devnode1 closed.
$ vagoth
usage: vagoth [-h] [-v]
{list,tree,listvm,listhv,start,stop,shutdown,info,undefine,define,provision,deprovision,new,delete,rename,poll}
...
vagoth: error: too few arguments
# call devnode1.deprovision(), which for the geats driver will wipe the filesystem too
$ vagoth deprovision devnode1
vagoth: txid=d01ca1bc source=myuser action=deprovision vm=devnode1
deprovision: OK (devnode1)
$ vagoth list devnode1
devnode1 state=unassigned type=vm parent=
$ vagoth delete devnode1
delete: OK (devnode1)
One of Vagoth's goals is to represent distributed state via a simple API. Individual plugins may become complicated, but the API should remain simple. Normally, the state updates with manager.action('poll')
would happen in a background process or even via another mechanism completely, but in this example we call it explicitly.
>>> import vagoth
>>> manager = vagoth.get_manager()
>>> dir(manager)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_instantiate_node', 'action', 'cleanup', 'config', 'get_node', 'get_node_by_key', 'get_node_by_name', 'get_nodes', 'get_nodes_with_parent', 'get_nodes_with_tag', 'get_nodes_with_type', 'list_nodes', 'provisioner', 'registry', 'scheduler']
>>> manager.list_nodes()
['hyper1']
>>> manager.get_node('hyper1')
<Hypervisor hyper1 at 2ce8fd0>
>>> manager.provisioner.provision("devnode1", node_name="devnode1", node_type="vm", definition={"template": "debian"})
>>> node = manager.get_node('devnode1')
>>> node
<VirtualMachine devnode1 at 1d66450>
>>> node.state
'unknown'
>>> node.start()
>>> manager.action('poll'); node.refresh(); node.state
'running'
>>> node.stop()
>>> manager.action('poll'); node.refresh(); node.state
'stopped'
>>> manager.provisioner.deprovision('devnode1')
Traceback:
<snip>
vagoth.exceptions.ProvisioningException: Cannot deprovision node while it's still assigned to a parent
>>> node.deprovision()
>>> manager.action('poll')
>>> node.refresh(); node.state, node.parent
('unassigned', None)
>>> manager.provisioner.deprovision('devnode1')
>>> node.refresh()
Traceback:
<snip>
vagoth.exceptions.NodeNotFoundException: Node devnode1 not found in registry.
A REST or other remote API is a great idea! I'd build a web interface around the REST API, however, to make it easy to support multiple clusters.
I haven't implemented a REST API myself because it starts to delve into authentication and authorization aspects, which is something I'd like to avoid in Vagoth itself.