Graph Definition

The Graph

The graph is the central element in Roboconf’s configuration files.
It defines Software components and their relations. At runtime, it will be used to determine what can be instantiated, and how it can be deployed.

The graph defines relations between components.
A component by itself is just a definition (like a Java class). At runtime, we do not manipulate components but instances of a component.

Software components include the deployment roots (virtual machines, devices, remote hosts), databases, application servers and application modules (WAR, ZIP, etc). They list what you want to deploy (or possibly deploy). Two kinds of relations are modeled:

What is modeled in the graph is really a user choice.
Various granularity can be described. It can goes very deeply in the description…

High Granularity

… or bundle things together (associate a given WAR with an application server).

Low Granularity

Multi-IaaS is supported by defining several root components.
Each one will be associated with various properties (IaaS provider, VM type, etc).
The following graph means my deployable can be deployed either on EC2 virtual machine or on an Openstack VM.

Graph for Multi-Iaas

Until now, we have talked of a graph.
However, if you look at Roboconf’s source code, we manipulate *graphs. In fact, you can define a single graph, or a collection of graphs. The interest of having several graphs is to define virtual appliances. As an example, you could define the following graphs inside a same project:

Or you could define a single graph, with a single root VM and three possible children (Tomcat, MySQL and Apache Load Balancer). The IaaS on which the VM is will be created is defined in the component’s resources directory. We will see this later.

Graph Configuration

A Roboconf project must contain an graph directory with the definition of a graph.
As a reminder, like a Java class, a Roboconf component is only a definition. It needs to be instantiated to be used.

By convention, graph definitions are expected in files with the graph extension. The parser will not be difficult if you use another extension. However, notice that tools may rely on the extension (such as editors, to provide syntax highlighting).

A component starts with the component name, followed by an opening curly bracket.
Components can be defined in any order.


# This is a comment
# There are only in-line comments

# The VM
VM {
	alias: Virtual Machine;
	installer: iaas;
	children: MySQL, Tomcat, Apache;
}

# MySQL database
MySQL {
	alias: MySQL;
	installer: puppet;
	exports: ip, port = 3306;
}

# Tomcat
Tomcat {
	alias: Tomcat with Rubis;
	installer: puppet;
	exports: ip, portAJP = 8009;
	imports: MySQL.ip, MySQL.port;
}

# Apache Load Balancer
Apache {
	alias: Apache Load Balancer;
	installer: puppet;
	imports: Tomcat.portAJP, Tomcat.ip;
}

Important!
Every component property must be defined on a single line.

Components can be defined in separate files (think to the case where you have several graphs in your graph model, you could have one file per graph).

The import mechanism will be documented later.

Let’s see the properties you can or have to set for a component.

The IP address is a special variable.
In fact, other network properties should be supported soon.

A component instance will not be able to start until all its runtime dependencies are resolved.
It means all the variable it imports must be exported by another instance. If one variable has no value, then it cannot start.

Import can also be marked as optional.
In this case, the instance will be able to start even if the imported variables are not resolved. As an example, if you think to a cluster mode, a cluster member may need to know where are the other members.


ClusterMember {
	alias: a Cluster member;
	exports: varA, varB;
	imports: ClusterMember.varA (optional), ClusterMember.varB (optional);
}

Facets

Sometimes, components may share a lot of configuration.
To limit redundancy, Roboconf added the notion of facet. A facet groups properties that can then be applied to components. A component may inherit from several facets.

Let’s take a look at an example.


###################################
## First, components...
###################################

# The VM
VM_EC2 {
	alias: Virtual Machine on EC2;
	facets: VM;
}

VM_Azure {
	alias: Virtual Machine on Azure;
	facets: VM;
}

# MySQL database
MySQL {
	alias: MySQL;
	facets: deployable;
	installer: puppet;
	exports: ip, port = 3306;
}

# Tomcat
Tomcat {
	alias: Tomcat with Rubis;
	facets: deployable;
	installer: puppet;
	exports: ip, portAJP = 8009;
	imports: MySQL.ip, MySQL.port;
}

# Apache Load Balancer
Apache {
	alias: Apache Load Balancer;
	facets: deployable;
	installer: puppet;
	imports: Tomcat.portAJP, Tomcat.ip;
}


###################################
## Then, facets...
###################################

# The VM facet
facet VM {
	children: deployable;
	installer: iaas;
}

# The deployable facet
facet deployable {
	# nothing
}

# Facets are not very useful here. We could put everything in components (see lamp-legacy-1).
# However, it shows what can be seen as a good practice for bigger VM deployments.

A component lists the facets it uses with the property named facets.
It will inherit all the imported and exported variables, as well as the children and installer name. If a component inherits several installers, and does not specify one, then an error is thrown. In case of ambiguity in the inheritance, the component has to override the installer. There can be only one installer.

Imported and exported variables are only added to the component.
A facet supports the following properties: children, exports, imports and installer.

Facets are only a way to group properties.
At runtime, there is no “facet” object in Roboconf’s internal model. This is a parsing commodity to reduce the size of configuration files.

System Requirements

The graph model allows define multi-container and distributed topologies.
We can go from the machine (VM, device…) to an application module (e.g. a Web Application). However, and even if the model could support it, it is not considered as a good practice to define system requirements as graph nodes.

What does it mean?
Let’s take an example.

If an application server needs a JVM or a library to run (such as Python), you should not rely on Roboconf to install it. It is not that you could not achieve it with a Bash script or something else. But it may be better to pre-install and configure such dependencies directly in the virtual images. As an example, there are mechanisms in Java Virtual Machines such as endorsed and policies that would be painful to configure with Roboconf. And, again, the problem here is not Roboconf, but the way you would implement it with a Roboconf plug-in (Bash, Puppet…).

This has been experimented with NodeJS application.
Write a Bash script that respect Roboconf’s requirements (be idem-potent) that installs NodeJS and NPM was quite painful to do. Pre-installing them on virtual images was much more convenient.

System requirements should not be deployed with Roboconf.
They should be deployed and configured in the virtual images.