Skip to main content

Introducing the Packer Provisioner for Salt

·9 mins
Projects VMware vExpert Salt HashiCorp Packer Golang Plugin Community Provisioner
Table of Contents
You’ve probably heard the expression about a thing being more than the sum of its parts? I’d like to think that this is a thing. I’ve taken two technology interests, combined them, and I’m very happy with the result!

I’ve been meaning to create this plugin for many months now. I saw that there was a Salt plugin on the HashiCorp Developer site some time ago, but it was unmaintained and that made me reluctant to rely on it. With changes to the plugin interface for Packer several versions ago, the plugin disappeared completely. Well today there is a new plugin. I created it using the SDK provided by HashiCorp and it has just been listed as a Community plugin.

Salt
#

Salt is an open-source desired state automation solution. It’s used by many, many, many people worldwide for a wide variety of use-cases. If you’ve heard of Ansible, Puppet, or Chef then you already know a bit about what Salt can do.

Salt is used to manage workloads or systems that are known as “Minions”. These Minions are managed by a central (but scalable) component known as a “Master”. The following diagram illustrates this relationship.

Simple diagram illustrating the relationship between Salt Masters and Salt Minions
Figure 1 - The relationship between Salt Minions and Salt Masters

The next few sections provide a brief introduction to Salt. A more in-depth overview can be found on the Salt documentation site.

Minion
#

A Salt Minion is any workload, system or device that is managed by a Master. It is also an installable component of Salt. Whilst you can use Salt without installing the Salt Minion component, it is much easier, more scalable, and more powerful if you do. The Salt Minion effectively acts as a remote execution environment for applying States, taking some of the load away from the Salt Master.

For this plugin to work, we need to install the Salt Minion inside our image. More on that later.

Master
#

A Salt Master is the central control component of Salt. Salt Minions communicate with the Master via an event bus to receive instructions (States) and return results. The relationship between a Salt Minion and a Salt Master is established using an exchange of unique keys that are then used to secure communications between the two.

We don’t need a Salt Master for the plugin to work. We won’t actually be registering the Minion with a Master at all. Salt has a mode called “Salt Masterless” that this plugin makes use of.

States
#

A state is a declarative instruction based on a module that abstracts common functions from their underlying implementation. Multiple states can be combined into a state file (usually written in YAML) that can then be applied to one or more Minions.

An overview of states and their general structure can be found on the Salt documentation site.

Packer
#

HashiCorp Packer is a tool that allows you to create golden images (or templates) to use for repeated deployments across multiple cloud platforms. I first started using Packer a number of years ago to create vSphere templates for my Homelab. Over time I standardized the builds of these images and have made all of my Packer templates available in a repository. I’ve also blogged about my experiences in the past, although most of those posts are probably out-of-date now.

mpoore/packer

Packer build repository

HCL
2
0

Packer utilizes a plugin-based architecture with several commonly-used plugins developed and manitained by HashiCorp themselves. These plugins can expose platform / technology specific functions at one or more of the stages involved in building a template or image. Those “stages” are:

  • Builder
  • Data Source
  • Provisioner
  • Post-Processor

For the Salt plugin that I created, the only stage that it interacts with Packer is at the “Provisioner” stage.

Provisioner
#

A provisioner is used to configure an image or template after its initial creation and it has first booted. Typical use-cases for a provisioner are to customize a vanilla image to install extra packages, etc. This is something that is right up Salt’s alley!

Salt Plugin
#

Enough background now. Let’s have a look at the plugin.

Like most Packer plugins, the Salt one is maintained in a public source control repository. You can see the source code used to create the plugin so you can verify that it’s not trying to do something dodgy.

mpoore/packer-plugin-salt

Packer plugin for Salt provisioner

Go
1
0

To create the plugin, HashiCorp have made an SDK available that provides the basic framework and integration with Packer itself. This is a great starting point, but still very much an advanced topic! I had to spend quite a bit of time getting to grips with Go and customizing the plugin framework to get initial versions of the plugin to build. After that it actually wasn’t too difficult as I understood the Salt elements well already.

Creating the required documentation also took some time to complete. Maintenance of it should be easier going forwards though.

Installing
#

Installing the plugin is straightforward. You simply need to require it in your Packer template file:

packer {
  required_plugins {
    salt = {
      # source represents the GitHub URI to the plugin repository without the `packer-plugin-` prefix.
      source  = "github.com/mpoore/salt"
      version = ">=0.1.2"
    }
  }
}

When you run packer init . in the directory where your template is stored, Packer will download and install the plugin.

Requirements
#

As I mentioned earlier, to make use of the Salt plugin you need to have to install the Salt Minion inside your image before you use the provisioner. I won’t go into massive detail about how to do that right now because the steps vary slightly depending the operating system being used. When developing the plugin I customized an existing RedHat Enterprise Linux (RHEL) template that I had and installed the Minion using some post-installation commands in the KickStart file. Specifically for RHEL 9, these commands were:

rpm --import https://repo.saltproject.io/saly/py3/redhat/9/x86_64/SALT-PROJECT-GPG-PUBKEY-2023.pub
curl -fsSL https://repo.saltproject.io/salt/py3/redhat/9/x86_64/latest.repo | tee /etc/yum.repos.d/salt.repo
dnf install -y salt-minion

This installs the Salt Minion but does not activate or enable it as a service. The plugin does not need it to be running as a service.

One other requirement is that you configure the communicator as part of your Packer build. Many people do this anyway if you’re going to use most other provisioners, but I thought it important to call this out!

Using the Plugin
#

Now for the fun part!

I’m working on moving my Packer templates away from using shell scripts to using this provisioner as I write this. I have a couple of examples but they’re not quite public yet. So for the time being, I’ll have to describe how it works.

Using a provisioner in a Packer template is pretty simple if you’ve made the plugin required. Just add the provisioner stanza to the HCL file as shown in the example below:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
build {
    # Build sources
    sources                 = [ "source.vsphere-iso.rhel9-salt" ]

    # Salt State provisioning
    provisioner "salt" {
        state_tree          = var.state_tree
        environment_vars    = [ "RHSM_USER=${ var.rhsm_user }",
                                "RHSM_PASS=${ var.rhsm_pass }",
                                "BUILDVERSION=${ local.build_version }",
                                "BUILDREPO=${ var.build_repo }",
                                "BUILDBRANCH=${ var.build_branch }"
        ]
    }
}

Lines 6 - 14 are the ones that invoke the provisioner. Let’s step through them…

  • Line 6 - Tells Packer to use the salt provisioner.
  • Line 7 - One of the options for the provisioner is to give it a State Tree to work with. This is just passing the location of that from a variable.
  • Lines 8-12 - This is an array of environment variables that I want to make available when Salt applies configurations. I could hardcode these values into my Salt states but that’s really not a good practice!

With this template, after RHEL is installed and reboots Packer will learn from VMware vCenter (because it’s a vSphere VM we’re building) that the OS has an IP address and it will try to connect via SSH. This is the communicator functionality that I mentioned above. Packer then invokes the Salt provisioner.

With the example above, it uses the communicator to transfer the files present in the state tree to the OS. Finally, the environment variables are set and a salt-call --local command is used to execute Salt. The environment variables are only set for the execution of the Salt command, not as system or user specific variables.

Execution time will vary depending on what you ask Salt to do. However, it will return output eventually. As long as all states are applied without error then the provisioner finishes and Packer continues with its next task.

State Tree / Highstate
#

At the time of writing there are two modes of operation for the provisioner. The first is shown in the example above. If a state tree is provided, the provisioner assumes that a “Highstate” file (top.sls) exists within the tree. This highstate determines which individual states are applied based on the evaluation of conditions within the file.

# salt/top.sls
base:
  'kernel:Linux':
    - match: grain
    - linux/rhsm/rhel_register
    - linux/updates
    - linux/motd
    - linux/rhsm/rhel_unregister
    - linux/clean

The contents of my top.sls file that I used for testing are given above. Basically Salt applies the five ’linux/…’ state files to any Minion that has a Linux kernel.

Individual State Files
#

The other mode allows you to provide an array of specific state files. Each will be uploaded and applied individually and in order. Personally I’d go with using the Highstate myself, but this was the first functionality that I got working and I decided to leave it in.

Roadmap
#

So, what’s next? Version 0.1.2 is the first working and documented version. I have plans to extend the functionality as follows:

  1. Support for Windows-based Minions. It may already work but most of my testing has been with RHEL so far.
  2. Support for providing Pillar data. This is a Salt specific way of providing customization data to Salt to use with states. At present the only option is to use environment variables.
  3. Support for installing the Salt Minion. Personally I’m unsure if I should complete this as it may involve a lot of work to pull together different installation methods for different operating systems.

Feedback
#

If you have problems with the plugin or have feedback on its use or for future enhancements, the best thing to do is to create an issue in the GitHub repository for the plugin. Here it is again.

mpoore/packer-plugin-salt

Packer plugin for Salt provisioner

Go
1
0

Summary
#

It’s been fun to create this plugin along with the learning that I’ve done along the way, but let me wrap up by including some useful resources.

  • Salt Documentation - Specifically the Salt user guide, where you can learn more about Salt and find documentation and examples of how it can be used.
  • Salt Community - Got questions about Salt or you want to share something with the community, Salt has a passionate and vibrant community on Discord.
  • Tanzu Salt - if you want to take Salt to the next level with a UI, an API, and both compliance and vulnerability manage capabilities then look no further than Tanzu Salt (part of the VMware Tanzu Platform).

Related

Elevating Enterprise Compliance - Bitnami's game changing Salt integration unveiled
·6 mins
Salt VMware Tanzu vExpert Bitnami OSS Compliance
Bitnami have embedded the Salt Minion into every single OVA and cloud image in the Bitnami Application Catalog - this is a good thing!
VMware Explore US 2024 - Why you should go!
·5 mins
Events VMware vExpert VMware Explore VMworld Las Vegas
Seven reasons why I think that you should register for VMware Explore 2024 in Las Vegas.
Startup plan for vSphere clusters hosting a Kubernetes Supervisor
·5 mins
vSphere VMware vExpert Homelab Kubernetes
A runbook of steps to complete to startup a vSphere cluster that hosts a Kubernetes Supervisor.