Skip to content

JTAF Build Steps

David Gee edited this page Nov 29, 2021 · 3 revisions

The best way to get familiar with JTAF is to build a provider. Let's go!

Navigate to your /var/tmp directory and create the jtaf_demo directory. This is your working directory for running a provider build.

Next, grab the JTAF project, which is written in Go.

go get github.com/Juniper/junos-terraform

Navigate to the junos-terraform directory and build both the cmd/processYang and cmd/processProviders binary.

Next, copy the contents of the samples/tf_module_template directory to your working directory.

# Inside the /junos-terrform directory
cp -rf Samples/tf_module_template /var/tmp/jtaf_demo

One of the first steps is to process the YANG files and create YIN and .txt representations of the YANG contents. For this example, the YANG files are ready to go and you don't have to worry about a thing.

The processing is done via pyang and we have a requirement to install a Python venv and install Pyang.

Navigate to the processYang directory.

python -m venv ./venv
source ./venv/bin/activate
pip install pyang
go build
./processYang -config /var/tmp/jtaf_demo/jtaf_config.toml

At this point, the first part of JTAF will kick in and process the YANG files. This can take some time. Each YANG file is being converted into the YIN type (XML) and there is also a .txt file being generated which contains the XPaths, which is effectively an index into each YIN file.

Next, navigate to the cmd/processProviders directory and execute that program. This shouldn't take too long.

go build
./processProviders -config /var/tmp/jtaf_demo/jtaf_config.toml

If all goes well, you now all have the .go files in the terraform_providers directory within your working directory. Navigate to the terraform_providers directory. You can now build the provider with:

go mod tidy
go build

Enough data is stored in the go.mod file to instruct the Go compiler what to do.

Next, move the provider to the default Terraform provider directory with the correct version directory. In this example case, the YANG models are for a 20.3xx vSRX and the specifics for the minor numbers, mirror the version vSRX.

mkdir -p ~/.terraform.d/plugins/juniper/providers/junos-vsrx/20.32.0101/darwin_amd64
mv terraform-provider-junos-vsrx ~/.terraform.d/plugins/juniper/providers/junos-vsrx/20.32.0101/darwin_amd64

It might be a good idea to export an environment variable as a shortcut for this directory!

You're now in a position to run Terraform through it's paces.

Remember, whatever you call the provider in the .toml config file, is what you'll need to refer to it as in any Terraform module.

Next, let's interact with Terraform with our fancy new module. Navigate to the /module directory within your working directory. Now, there are some important things you will need to adjust inside the file main.tf. See the provider section? By default it will look like this:

provider "junos-vsrx" {
    host = "localhost"
    port = 8300
    username = "root"
    password = "juniper123"
    sshkey = ""
}

Make sure this data is accurate for the host, port, user, password (or sshkey).

Before we dive in with Terraform, here are some mental notes as to how this example is structured. Here is the entire file.

terraform {
  required_providers {
    junos-vsrx = {
      source = "juniper/providers/junos-vsrx"
      version = "20.32.0101"
    }
  }
}

provider "junos-vsrx" {
    host = "localhost"
    port = 8300
    username = "root"
    password = "juniper123"
    sshkey = ""
}

module "vsrx_1" {
  source = "./vsrx_1"

  providers = {junos-vsrx = junos-vsrx}

  depends_on = [junos-vsrx_destroycommit.commit-main]
}


resource "junos-vsrx_commit" "commit-main" {
  resource_name = "commit"
  depends_on = [module.vsrx_1]
}

resource "junos-vsrx_destroycommit" "commit-main" {
  resource_name = "destroycommit"
}

Notice that the provider we have just created is now identified in. Secondly we have the provider block with the device details. Then we get to the interesting bits.

module

The module vsrx_1 contains our desired declarative intent (the resources!). The module is a directory with another main.tf file. Within that second level main.tf is a list of resources we want Terraform to add to our vSRX. The provider information is passed down (so that the same credentials etc can be used). The most interesting piece however is the depends_on key. Notice that the module depends on a destroycommit resource. Also notice that the next resource down in the file is a commit, that depends on the module.

What happens from Terraform's perspective on create is this:

  1. Terraform applies first a destroycommit resource (which does nothing when created).
  2. Terraform applies the resources in the module.
  3. Terraform after the module resources have been created, applies the top level commit (which is an actual commit).

Because the commits are essentially NETCONF payloads and not data, nothing is stored in local state for commits, so if you look at the source code, you'll notice that the junos-vsrx_commit resource has the create function completed but nothing else. If you look at the junos-vsrx_destroycommit function, you'll notice that the create function is empty, yet the delete function has the commit logic.

When Terraform applies destroy this is what happens:

  1. Terraform deletes the commit (nothing happens, there is no local state and no remote state).
  2. Terraform deletes each resource in the module (resources are deleted one by one without commits).
  3. Terraform deletes the destroycommit resource, in which a commit is issued against Junos.

Terraform Exercise

terraform init
terraform plan

Notice in the output that Terraform gives you a plan of what it's going to do. You an output this as an SVG too if you want a graphic.

Next, let's run the apply. Because this is a greenfield site, let's auto-approve it.

terraform apply -auto-approve

From here, you can check the configuration groups on the vSRX that have been configured. They should all be there. You can also run another plan to make sure Terraform's local declarative desired state reflects the remote (vSRX) based state.

terraform plan

You can also delete a resource inside the module or change one, but if you do this, ensure to run a taint command on the commit object.

terraform taint junos-vsrx_commit.commit-main

You need this because Terraform thinks the commit object hasn't changed (and it hasn't). In order to push a commit after the update (Junos config group deletion and creation), the taint command tells Junos that the resource needs to be re-created.

terraform apply -auto-approve

Whatever you've adjusted for, will be applied. You can run plan if you've done a taint, but on the apply phase, Terraform will pick up on it anyway.

You can now destroy the config entirely on the vSRX with:

terraform destroy -auto-approve

Now, more coolness. When Terraform does a create, it automatically does a read on the configured remote state, which means we do not have to run tests through tools like jSnappy. Parts of your Terraform configuration can be your 'golden configuration' and to do a remote check, you can run a terraform plan on the resources that form your golden config. Nice eh?

This was tested with Terraform version 0.15.5 on darwin_amd64 (OSX). If you're running on Linux, ensure to change the darwin to linux on the examples above.

If there are any issues with this write-up, please raise an issue on this repository with enough data for us to re-create the scenario and find a fix.

Clone this wiki locally