Dynamic Check_MK Inventory Management with Terraform Infrastructure Code

January 31, 2017 |

Recently we came across a use case to dynamically manage the *Check_MK inventory at the same instant the infrastructure is created/modified using the Terraform code. Since Terraform doesn’t provide the Check_MK provider Out of the Box (OOB), we had to write one on our own. This blog aims at sharing this experience of developing our check_mk provider for Terraform.

MK Check pic


  • The provider is written in Golang, and some basics are needed that can be learnt fairly quickly with a lot of online videos and reading material available.
  • Before you start getting into the detail of developing the provider, visit the official Terraform documentation page.


Step 1: Design

As a good starting point, decide the attributes for your provider.We generally start designing with the end usage in mind, and  here is how we envision the usage of our Check_MK provider once it is ready.

provider “checkmk” {

 user     = “<user-name>”

 password = “<password>”

 host     =  “<ip-address>”

 sitename = “<site-name>”


Similarly, also decide on the actual resources you are going to manage via this provider. In our case, the checkmk_host was one important resource to be managed.

resource “checkmk_host” “winxp_1” {

 hostname = “winxp_1”

 folder = “os/windows”

 attribute_alias = “Alias of winxp_1”

 attribute_tag_agent  = cmk-agent

 attribute_tag_criticality = “prod”

 attribute_ipaddress = “”

Thus the design phase brings out the actual attributes for the provider, as well as the resources and their attributes.

With reference to the Check_MK provider, the following four attributes are required to define a provider.

  • user
  • password
  • host
  • sitename

A resource called ‘host’ (Because of the way Terraform works, the resource name is prefixed with the name of your provider, hence checkmk_host and not just host) exposes the following attributes:

  • hostname
  • folder
  • attribute_alias
  • attribute_tag_agent
  • attribute_tag_criticality
  • attribute_ipaddress


Step 2: The Dummy Provider

After deciding the attributes for our provider and the resources it will manage, let’s create the dummy provider.

First let’s create the needed files. You will need three files to start with.

  1. main.go
  2. provider.go
  3. resource_host.go ( for each resource, you will need a different file )


This calls plugin.Serve, and passes a “provider” function for the plugin that returns a terraform.ResourceProvider.

The provider.go will define a provider function that returns an object that implements the terraform.ResourceProvider interface, especifically the “schema.Provider”.

The schema.Provider struct has three attributes:

  • Schema: List of all the attributes for your provider to work with.

In our Check_MK example it would be “user, password, host, sitename”.

The value of this attribute is a map[string]*schema.Schema, a linked list where the key is a string and the value is a pointer to a schema.Schema.

  • ResourcesMap: List of resources that you want to support in your Terraform configuration file.

In our Check_MK example, currently we are dealing with only one resource named host.

The value of this attribute is a map[string]*schema.Resource, similar to one of the Schema attribute, the difference being that this list points to schema.Resource.

  • ConfigureFunc: This is the function when you need to initialize the api client with the credentials defined in the Schema part.

Next, for each of the resource defined in ResourcesMap, we need to create a file named resource_<resourcename>.go

Since, we have defined a resource named checkmk_host , let’s create the file named resource_host.go

Implement the function name defined in ResourcesMap for that resource.

Resource declaration has its own structure which is made out of a:

  1. schema.Schema (this is pretty much similar to schema.Provider)
  2. SchemaVersion
  3. And most importantly the Create, Read, Update & Delete.

These are the four operations that Terraform will perform over the resources of your infrastructure and they will be called according to the case for each resource. This means that if you are creating ten resources the Create function will be called ten times. The same applies to the rest.

The signature for these functions is func(*ResourceData, interface{}).

The ResourceData type will provide you the following methods for getting values from the configuration:

  • Get(key string): Fetches the value for the given key. If the given key is not defined in the structure it will return nil. e.g. Hostname: d.Get(“hostname”).(string),

if the key has not been set in the configuration file then it will return the key’s

default value (0 for integers, “” for strings and so on).

GetChange(key string): Returns the old and new value for the given key.

  • HasChange(key string): Returns whether or not the given key has been changed.
  • SetId(): Sets the id for the given resource. **If set to blank then the resource will be marked for deletion.

It also offers a couple more methods (GetOk, Set, ConnInfo, SetPartial).

Since we don’t have any actual Check_MK API defined, we are using the dummy ExampleClient and Machine functions (We will update it once we have the actual API written for Check_MK).

All the three files are available on Gist – https://gist.github.com/junaid18183/750d267a9333764e26689389eb0f0f18


Step 2 : Compile the Dummy Provider :

Once we have the basic code ready, try compiling it.

# go build -o terraform-provider-checkmk

Make sure you name the resulting package as terraform-provider-<name> since Terraform expects that name.

After successful building of the package, you can test it.

root@vagrant-ubuntu-trusty-64:/home/junedm/terraform-provider-checkmk# ./terraform-provider-checkmk

This binary is a plugin. These are not meant to be executed directly.

Please execute the program that consumes these plugins, which will load any plugins automatically


Step 3 : Test the Dummy Provider :

Since you have the provider ready, you can actually create the sample terraform file and attempt the plan out of it (You can apply as well, since this is just a dummy it will not do anything).

root@vagrant-ubuntu-trusty-64:/home/junedm/terraform-provider-checkmk# terraform plan

Refreshing Terraform state in-memory prior to plan…

The refreshed state will be used to calculate this plan, but

will not be persisted to local or remote state storage.

The Terraform execution plan has been generated and is shown below. Resources are shown in alphabetical order for quick scanning. Green resources will be created (or destroyed and then created if an existing resource exists), yellow resources are being changed in-place, and red resources will be destroyed. Cyan entries are data sources to be read.

Note: You didn’t specify an “-out” parameter to save this plan, so when

“apply” is called, Terraform can’t guarantee this is what will execute.

+ checkmk_host.winxp_1

   attribute_alias:           “Alias of winxp_1”

   attribute_ipaddress:       “”

   attribute_tag_agent:       “cmk-agent”

   attribute_tag_criticality: “prod”

   folder:                    “os/windows”

   hostname:                  “winxp_1”
Plan: 1 to add, 0 to change, 0 to destroy.

If the plan and apply is successful, our dummy provider is working perfectly.


Step 4 :  Actual Implementation

Now we have to change the provider to make the actual API call to Check_MK and perform addition and deletion of the host. The Check_MK exposes the webapi for it.

But to interact with that webapi we need to write a GO client SDK. We have written the same and published it at – https://github.com/reancloud/cmkapi

Once we have the client SDK handy, remove the sample ExampleClient and sample functions from the dummy providers and use the actual methods exposed by the cmkapi.

Also enable the environment variable support to provide the attributes via environment (Refer built-in providers for reference). The complete project is available at –  reancloud/terraform-provider-checkmk

* Check_MK is an extension to the Nagios monitoring system that allows creating rule-based configuration using Python and offloading work from the Nagios core to make it scale better, allowing more systems to be monitored from a single Nagios server.

If you are interested in having our team help you in your projects, please contact us at info@reancloud.com. Also, if you like these kind of problems and want to join our team please contact us at careers@reancloud.com or visit us at http://www.reancloud.com/company/careers/.

Other Blog Posts


Top 5 Reasons to Utilize Cloud Computing in Financial Services
Read More

Is Migrating to the Cloud Safe for Financial Sector Companies?
Read More

REAN Cloud is one of the few AWS Premier Partners to achieve both AWS DevOps Competency and MSP Designation
Read More

7 Ways DevOps Can Save Your Company…Time and Money
Read More
Request Consultation
close slider