Using CURL to Add Additional NIC to Packer Image

Recently I was working on a project to streamline virtual machine images for clustered databases. I was using Packer to create the base images and Terraform to deploy them for new requests. This all runs via Linux containers that do not have PowerCLI installed (though I could ask to get it installed).

The issue I ran into is Packer doesn’t allow you to create additional network adapters and Terraform needs all of them to exist on the image before you can clone from it. Images were being created within the same vCenter as they are deployed to.

What I needed was a way to add a second NIC to the VM after it was created by Packer and before Terraform ever deployed from it. Luckily I am creating Packer images via Jenkins so I was able to create the following script to complete this.

Software Versions:

  • vSphere 6.7
  • Packer 1.3.1
  • JetBrains Packer Builder ISO 2.1 (works a million times better than HashiCorp Packer builder.
  • Terraform 0.11.10
  • Terraform vSphere Provider 1.9.0
  • jq 1.6

Script

Initially, I would run the Packer command directly within Jenkins. In order for this to work I need to send vCenter credentials into Jenkins command line as well as the Packer script. Luckily I was already passing variables into the Packer script via this method so I could utilize those same variables. I created a bash script for this process and call it within Jenkins.

I then added the following code to the script.


## Set image name based on current date
IMAGENAME="RHEL-db_`date '+%Y%m%d%H%M'`"

## Packer build
packer build -var-file="vars.json" -var "image_name=$IMAGENAME" build.json

## Connect to vCenter
SESSION_ID="$(curl -k -X POST -H 'Accept: application/json' \
--basic -u $VCENTER_USER:$VCENTER_PASSWORD \
$VCENTER_Server/rest/com/vmware/cis/session | jq -r '.value')"

## Get network ID of network image is built on (can be any portgroup)
NETWORK_ID="$(curl -k -X GET -H 'Accept: application/json' -H \
"vmware-api-session-id: $SESSION_ID" \
$VCENTER_Server/rest/vcenter/network?filter.names=$GUESTNETWORK_NAME \
| jq -r '.value[0] .network')"

## Get VM ID
VMID="$(curl -k -X GET -H 'Accept: application/json' -H \
"vmware-api-session-id: $SESSION_ID" \
$VCENTER_Server/rest/vcenter/vm?filter.names=$IMAGENAME \
| jq -r '.value[0] .vm')"

## Add nic to VM and assign return code to variable
NIC_ADDED="$((curl -k -X POST -H 'Accept: application/json' -H \
"Content-Type: application/json" -H \
"vmware-api-session-id: $SESSION_ID" \
-d @- \
$VCENTER_Server/rest/vcenter/vm/$VMID/hardware/ethernet \
<<- JSON
{
    "spec": {
        "backing": {
            "network": "$NETWORK_ID",
            "type": "DISTRIBUTED_PORTGROUP"
        },
        "start_connected": true,
        "type": "VMXNET3",
        "wake_on_lan_enabled": true
    }
}
JSON
) | jq -r '.value')"

# Validate it was added successfully
if [ $NIC_ADDED = 4001 ];
then
    NIC successfully added
else
    echo Process Failed
    exit 1
fi

I use the last section as a check that the process was successful. If it is, I update a variable in the back-end with the latest image name. This is what Terraform uses to know which image to clone from.

This post also shows how to use jq to parse JSON output within bash scripts.

Hit me up if you have any questions on this.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Website Powered by WordPress.com.

Up ↑