How to provision VMs with Foreman and ManageIQ

Posted by cjung on Thu, Apr 30, 2015

The Foreman is a very powerful tool for system management. Red Hat’s new version of Satellite is also using Foreman as one of its core components. It’s only consequent to setup both tools so they can benefit from each other.

While Foreman is the better tool for deployment and configuration management, ManageIQ acting as an open hybrid cloud management platform has the better understanding of the multiple cloud and virtualization environments. One simple scenario is that ManageIQ decides which particular cloud provider has to be used based on user provided input and then Foreman will do the actual installation of the guest operating system including configuration of the installed application.

Right now ManageIQ can not directly use Foreman to deploy new virtual machines. Due to ManageIQ’s very extensible Automate Framework, this can be solved quite easily with some custom code.

To accomplish the goal, a number of changes have to be implemented and are described further below:

  • disable automatic VM start during provisioning

  • create a new class “register_foreman”

  • provide all the necessary credentials and data to “register_foreman”

  • modify the provisioning state machine to add an additional step

All the scripts described below can be found on GitHub.

Disable VM autostart

During provisoning of virtual machines, ManageIQ will automatically power on the new VM. This is usually exactly what you want. In some scenarios you better want the VM to be powered on in a later stage of the provisioning process - this is possible by setting the option “vm_auto_start” to false.

In most cases you use the entry point /Service/Provisioning/StateMachines/ServiceProvision_Template/CatalogItemInitialization to kick of the service provisioning task. This instance is pointing to a method with the same name. Copy the method to your datastore and do a small modification. In the code block which populates all options into the child object, set the provisioning option “vm_auto_start” to false:

1  gc.set_option(:vm_auto_start,[false,0])

An example can be found in my GitHub repository.

Register in Foreman

The Foreman provides an REST API which is used to register the new virtual machine. Since Satellite 6 is using the same API, the script will work with both versions.

To utilize Foreman from ManageIQ the following data has to be stored in the Automate class:

  • Organization

  • Location

  • Host group

The necessary steps are described below.

Here’s a quick outline what the code does:

  • parse variables from the Automate class and store them locally (foreman_host, foreman_user, foreman_password, hostgroup_name, organization_name, location_name)

  • establish a connection to Foreman

  • query the hostgroup ID, location ID and organization ID from Foreman

  • create a new host record in Foreman with VM name, MAC address, hostgroup ID, location ID and organization ID

  • query host and store details in the logs

There is still a huge potential for future improvements. Error handling is very basic for example.

The full script can be found in my GitHub repository.

Creating the register_foreman class

To use the register_foreman method during provisining, a new class has to be created. It’s a very simple one though and easy to create.

First create a new datastore with the namespace /custom/methods or anything else you prefer. In that namespace, create a new class and call it “register_foreman”.

Modify the schema of the class according to this screenshot:

Pay special attention to the foreman_password attribute which is a password field. This makes sure that ManageIQ never shows the clear text password in the UI or in the log files.

After defining the schema, add a new instance and method called “register_foreman”. Import the code found on GitHub into the “register_foreman” method. When creating the “register_foreman” instance, you obviously have to fill out all the data:

  • foreman_host: the FQDN of your Foreman server

  • foreman_user: the user which ManageIQ will use to log into Foreman. Make sure this user has enough privileges to query hosts, locations, organizations and host groups and can also add new hosts

  • foreman_password: password of this user. Make sure the attribute is set to “password” to never expose it as clear text

  • location_name: the location of the new host

  • organization_name: the name of your organization

  • hostgroup_name: the name of the host group used during registration. Host groups define which OS is installed, which puppet groups are used etc.

Modify the provisioning state machine

The state machines in ManageIQ are very powerful and flexible. Although there is no step to register a host in Foreman, it’s quite easy to add one. As an alternative, you could re-use one of the existing states. It’s important that you re-use one of the states following “provisioning” to make sure all the requirements (e.g. the VM must exist before the “register_foreman” method is executed) are met.

To be able to modify an existing state machine, it has to be copied first. Navigate to /Infrastructure/VM/Provisioning/StateMachines/VMProvision_VM/Provision VM from Template (template) and copy that instance to your datastore.

After the instance has been copied, it becomes editable. First modify the parent class (VMProvision_VM) and change the schema. Add an additional state “register_foreman”. If you used the structure and name described in the previous step, use /custom/methods/register_foreman/register_foreman as the default value. Also set the Max Retries to 100 to avoid endless loops in case of an error.

Now you have to change the sequence and move the new step “register_foreman” between “CheckProvisioned” and “PostProvision”. The result should look similar to this:


All of the above was successfully implemented and tested with CloudForms Management Engine 5.3.3 and Satellite 6.0.8. All the relevant APIs in Satellite and Foreman should be the same, but I haven’t tested this in detail. Nevertheless the provided scripts should give you an idea on how to implement this level of integration.