{"id":8158,"date":"2022-12-23T22:55:42","date_gmt":"2022-12-23T22:55:42","guid":{"rendered":"https:\/\/dmsretail.com\/RetailNews\/get-started-with-terraform-and-cisco-modeling-labs\/"},"modified":"2022-12-23T22:55:42","modified_gmt":"2022-12-23T22:55:42","slug":"get-started-with-terraform-and-cisco-modeling-labs","status":"publish","type":"post","link":"https:\/\/dmsretail.com\/RetailNews\/get-started-with-terraform-and-cisco-modeling-labs\/","title":{"rendered":"Get Started With Terraform and Cisco Modeling Labs"},"content":{"rendered":"<p> <p><a href=\"https:\/\/dmsretail.com\/online-workshops-list\/\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-496\" src=\"https:\/\/dmsretail.com\/RetailNews\/wp-content\/uploads\/2022\/05\/RETAIL-ONLINE-TRAINING-728-X-90.png\" alt=\"Retail Online Training\" width=\"729\" height=\"91\" srcset=\"https:\/\/dmsretail.com\/RetailNews\/wp-content\/uploads\/2022\/05\/RETAIL-ONLINE-TRAINING-728-X-90.png 729w, https:\/\/dmsretail.com\/RetailNews\/wp-content\/uploads\/2022\/05\/RETAIL-ONLINE-TRAINING-728-X-90-300x37.png 300w\" sizes=\"auto, (max-width: 729px) 100vw, 729px\" \/><\/a><\/p><br \/>\n<\/p>\n<div>\n<p><span data-contrast=\"auto\">Infrastructure as Code (IaC) is a hot topic these days, and the IaC tool of choice is Terraform by HashiCorp. Terraform is a cloud provisioning product that provides infrastructure for any application. You can refer to a long list of providers for any target platform.\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\"><strong>Terraform\u2019s list of providers now includes Cisco Modeling Labs (CML) 2<\/strong>, so we can use Terraform to control virtual network infrastructure running on CML2.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\"> Keep reading to learn how to get started with Terraform and CML, from the initial configuration through its advanced features.\u00a0<\/span><\/p>\n<h2><b><span data-contrast=\"none\">How does Terraform work?<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:200,&quot;335559739&quot;:0}\">\u00a0<\/span><\/h2>\n<p><span data-contrast=\"auto\">Terraform uses code to describe the desired state of the required infrastructure and track this state over the infrastructure\u2019s lifetime. This code is written in HashiCorp Configuration Language (HCL). If it changes, Terraform figures out all the differences (state changes) to update the infrastructure and help reach the new state. Eventually, when the infrastructure isn\u2019t needed anymore, Terraform can destroy it.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">A Terraform provider offers resources (things that have state) and data sources (read-only data without state). <\/span><\/p>\n<p><span data-contrast=\"auto\">In CML2 terms, examples include:<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<ul>\n<li><span data-contrast=\"auto\">Resources: Labs, nodes, links<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/li>\n<li><span data-contrast=\"auto\">Data sources: Labs, nodes, and links, as well as available nodes and image definitions, available bridges for external connectors, and user lists and groups, etc.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/li>\n<\/ul>\n<p><b><span data-contrast=\"auto\">NOTE: <\/span><\/b><span data-contrast=\"auto\">Currently, only a few data sources are implemented.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<h2><b><span data-contrast=\"none\">Getting started<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:200,&quot;335559739&quot;:0}\"> with Terraform and CML<\/span><\/h2>\n<p><strong>To get started with Terraform and CML, you\u2019ll need the following:\u00a0<\/strong><\/p>\n<h2><b><span data-contrast=\"none\">Define and initialize a workspace<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:200,&quot;335559739&quot;:0}\">\u00a0<\/span><\/h2>\n<p><span data-contrast=\"auto\">First, we\u2019ll create a new directory and change it as follows:<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<pre><span data-contrast=\"auto\">$ mkdir tftest<\/span>&#13;\n<span data-contrast=\"auto\">$ cd tftest<\/span><span data-ccp-props=\"{&quot;335559739&quot;:200}\">\u00a0<\/span><\/pre>\n<p><span data-contrast=\"auto\">All the configuration and state required by Terraform stays in this directory.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">The code snippets presented need to go into a Terraform configuration file, typically a file called <\/span><span data-contrast=\"auto\">main.tf<\/span><span data-contrast=\"auto\">. However, configuration blocks can also be spread across multiple files, as Terraform will combine all files with the <\/span><strong>.tf<\/strong><span data-contrast=\"auto\"> extension in the current working directory.<\/span><span data-ccp-props=\"{&quot;335559685&quot;:0,&quot;335559737&quot;:480,&quot;335559738&quot;:100,&quot;335559739&quot;:100}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">The following code block tells Terraform that we want to use the CML2 provider. It will download and install the latest available version from the registry at initialization. We add this to a new file called <\/span><strong>main.tf<\/strong><span data-contrast=\"auto\">:<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<pre><span data-contrast=\"auto\">terraform {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 required_providers {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0 cml2 = {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 source\u00a0 = \"registry.terraform.io\/ciscodevnet\/cml2\"<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0 }<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 }<\/span>&#13;\n<span data-contrast=\"auto\">}<\/span><span data-ccp-props=\"{&quot;335559739&quot;:200}\">\u00a0<\/span><\/pre>\n<p><span data-contrast=\"auto\">With the provider defined, we can now initialize the environment. This will download the provider binary from the Hashicorp registry and install it on the local computer. It will also create various files and a directory that holds additional Terraform configuration and state.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<pre><span data-contrast=\"auto\">$ terraform init<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">Initializing the backend...<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">Initializing provider plugins...<\/span>&#13;\n<span data-contrast=\"auto\">- Finding latest version of ciscodevnet\/cml2...<\/span>&#13;\n<span data-contrast=\"auto\">- Installing ciscodevnet\/cml2 v0.4.1...<\/span>&#13;\n<span data-contrast=\"auto\">- Installed ciscodevnet\/cml2 v0.4.1 (self-signed, key ID A97E6292972408AB)<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">Partner and community providers are signed by their developers.<\/span>&#13;\n<span data-contrast=\"auto\">If you'd like to know more about provider signing, you can read about it here:<\/span>&#13;\n<span data-contrast=\"auto\">https:\/\/www.terraform.io\/docs\/cli\/plugins\/signing.html<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">Terraform has created a lock file .terraform.lock.hcl to record the provider<\/span>&#13;\n<span data-contrast=\"auto\">selections it made above. Include this file in your version control repository so that Terraform can guarantee to make the same selections by default when you run \"terraform init\" in the future.<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">Terraform has been successfully initialized!<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">You may now begin working with Terraform. Try running \"terraform plan\" to see<\/span>&#13;\n<span data-contrast=\"auto\">any changes that are required for your infrastructure. All Terraform commands<\/span>&#13;\n<span data-contrast=\"auto\">should now work.<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">If you ever set or change modules or backend configuration for Terraform,<\/span>&#13;\n<span data-contrast=\"auto\">rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary.<\/span>&#13;\n<span data-contrast=\"auto\">$<\/span><span data-ccp-props=\"{&quot;335559739&quot;:200}\">\u00a0<\/span><\/pre>\n<h2><b><span data-contrast=\"none\">Configure the provider<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:200,&quot;335559739&quot;:0}\">\u00a0<\/span><\/h2>\n<p><span data-contrast=\"auto\">The CML2 terraform provider needs credentials to access CML2. These credentials are configured as shown in the following example. Of course, <\/span><span data-contrast=\"auto\">address<\/span><span data-contrast=\"auto\">, <\/span><span data-contrast=\"auto\">username<\/span><span data-contrast=\"auto\"> and <\/span><span data-contrast=\"auto\">password<\/span><span data-contrast=\"auto\"> need to match the actual environment:<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<pre><span data-contrast=\"auto\">provider \"cml2\" {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 address\u00a0\u00a0\u00a0\u00a0 = \"https:\/\/cml-controller.cml.lab\"<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 username\u00a0\u00a0\u00a0 = \"admin\"<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 password\u00a0\u00a0\u00a0 = \"supersecret\"<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 # skip_verify = true<\/span>&#13;\n<span data-contrast=\"auto\">}<\/span><span data-ccp-props=\"{&quot;335559739&quot;:200}\">\u00a0<\/span><\/pre>\n<p><span data-contrast=\"auto\">The <\/span><strong>skip_verify<\/strong><span data-contrast=\"auto\"> is commented out in the example. You might want to uncomment it to work with the default certificate that is shipped with the product, which is signed by the Cisco CML CA. Consider <\/span><span data-contrast=\"none\">installing a trusted certificate chain on the controller<\/span><span data-contrast=\"auto\">.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">While the above works OK, it\u2019s not advisable to configure clear-text credentials in files that might end up in source code management (SCM). A better approach is to use environment variables, ideally in combination with some tooling like <\/span><span data-contrast=\"auto\">direnv<\/span><span data-contrast=\"auto\">. As a prerequisite, the variables need to be defined within the configuration:<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<pre><span data-contrast=\"auto\">variable \"address\" {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 description = \"CML controller address\"<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 type\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = string<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 default\u00a0\u00a0\u00a0\u00a0 = \"https:\/\/cml-controller.cml.lab\"<\/span>&#13;\n<span data-contrast=\"auto\">}<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">variable \"username\" {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 description = \"cml2 username\"<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 type\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = string<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 default\u00a0\u00a0\u00a0\u00a0 = \"admin\"<\/span>&#13;\n<span data-contrast=\"auto\">}<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">variable \"password\" {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 description = \"cml2 password\"<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 type\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = string<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 sensitive\u00a0\u00a0 = true<\/span>&#13;\n<span data-contrast=\"auto\">}<\/span><span data-ccp-props=\"{&quot;335559739&quot;:200}\">\u00a0<\/span><\/pre>\n<p><b><span data-contrast=\"auto\">NOTE: <\/span><\/b><span data-contrast=\"auto\">Adding the \u201csensitive\u201d attribute ensures that this value is not printed in any output.<\/span><span data-ccp-props=\"{&quot;335559685&quot;:0,&quot;335559737&quot;:480,&quot;335559738&quot;:100,&quot;335559739&quot;:100}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">We now can create a <\/span><span data-contrast=\"auto\">direnv<\/span><span data-contrast=\"auto\"> configuration to insert values from the environment into our provider configuration by creating a <\/span><span data-contrast=\"auto\">.envrc<\/span><span data-contrast=\"auto\"> file. You can also achieve this by manually \u201csourcing\u201d this file using <\/span><span data-contrast=\"auto\">source .envrc<\/span><span data-contrast=\"auto\">. The benefit of <\/span><span data-contrast=\"auto\">direnv<\/span><span data-contrast=\"auto\"> is that this automatically happens when changing into the directory.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<pre><span data-contrast=\"none\">TF_VAR_address=<\/span><span data-contrast=\"none\">\"https:\/\/cml-controller.cml.lab\"<\/span>&#13;\n<span data-contrast=\"none\">TF_VAR_username=<\/span><span data-contrast=\"none\">\"admin\"<\/span>&#13;\n<span data-contrast=\"none\">TF_VAR_password=<\/span><span data-contrast=\"none\">\"secret\"<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">export <\/span><span data-contrast=\"none\">TF_VAR_username<\/span> <span data-contrast=\"none\">TF_VAR_password<\/span> <span data-contrast=\"none\">TF_VAR_address<\/span><span data-ccp-props=\"{&quot;335559739&quot;:200}\">\u00a0<\/span><\/pre>\n<p><span data-contrast=\"auto\">This decouples the Terraform configuration files from the credentials\/dynamic values so that they can easily be added to SCM, like Git, without exposing sensitive values, such as passwords or addresses.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<h2><b><span data-contrast=\"none\">Define the CML2 lab infrastructure<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:200,&quot;335559739&quot;:0}\">\u00a0<\/span><\/h2>\n<p><span data-contrast=\"auto\">With the basic configuration done, we can now describe our CML2 lab infrastructure. We have two options:<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<ol>\n<li data-leveltext=\"%1.\" data-font=\"Calibri\" data-listid=\"4\" data-list-defn-props=\"{&quot;335552541&quot;:0,&quot;335559684&quot;:-1,&quot;335559685&quot;:480,&quot;335559991&quot;:480,&quot;469769242&quot;:[65533,0],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;%1.&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"1\" data-aria-level=\"1\"><span data-contrast=\"auto\">Import-mode<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/li>\n<\/ol>\n<ol>\n<li data-leveltext=\"%1.\" data-font=\"Calibri\" data-listid=\"4\" data-list-defn-props=\"{&quot;335552541&quot;:0,&quot;335559684&quot;:-1,&quot;335559685&quot;:480,&quot;335559991&quot;:480,&quot;469769242&quot;:[65533,0],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;%1.&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"2\" data-aria-level=\"1\"><span data-contrast=\"auto\">Define-mode<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/li>\n<\/ol>\n<h3><b><span data-contrast=\"none\">Import-mode<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:200,&quot;335559739&quot;:0}\">\u00a0<\/span><\/h3>\n<p><span data-contrast=\"auto\">This imports an existing CML2 lab YAML topology file as a Terraform <\/span><span data-contrast=\"auto\">lifecycle<\/span><span data-contrast=\"auto\"> resource. This is the \u201cone-stop\u201d solution, defining all nodes, links and interfaces in one go. In addition, you can use Terraform templating to replace properties of the imported lab (see below).<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<h4><strong><i>Import-mode example<\/i>\u00a0<\/strong><\/h4>\n<p><span data-contrast=\"auto\">Here\u2019s a simple <\/span><i><span data-contrast=\"auto\">import-mode<\/span><\/i><span data-contrast=\"auto\"> example:<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<pre><span data-contrast=\"auto\">resource \"cml2_lifecycle\" \"this\" {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 topology = file(\"topology.yaml\")<\/span>&#13;\n<span data-contrast=\"auto\">}<\/span><span data-ccp-props=\"{&quot;335559739&quot;:200}\">\u00a0<\/span><\/pre>\n<p><span data-contrast=\"auto\">The file <\/span><span data-contrast=\"auto\">topology.yaml<\/span><span data-contrast=\"auto\"> will be imported into CML2 and then started. We now need to \u201cplan\u201d the change:<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<pre><span data-contrast=\"auto\">$ terraform plan<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 + create<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">Terraform will perform the following actions:<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">\u00a0 # cml2_lifecycle.this will be created<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 + resource \"cml2_lifecycle\" \"this\" {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + booted\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + id\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + lab_id\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + nodes\u00a0\u00a0\u00a0 = {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 } -&gt; (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + state\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + topology = (sensitive value)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0 }<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">Plan: 1 to add, 0 to change, 0 to destroy.<\/span>&#13;\n<span data-contrast=\"auto\">$<\/span><span data-ccp-props=\"{&quot;335559739&quot;:200}\">\u00a0<\/span><\/pre>\n<p><span data-contrast=\"auto\">Then apply it (<\/span><span data-contrast=\"auto\">-auto-approve<\/span><span data-contrast=\"auto\"> is a short-cut and should be handled with care):<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<pre><span data-contrast=\"auto\">$ terraform apply -auto-approve<\/span><\/pre>\n<pre><span data-contrast=\"auto\">Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 + create<\/span><\/pre>\n<pre><span data-contrast=\"auto\">Terraform will perform the following actions:<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">\u00a0 # cml2_lifecycle.this will be created<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 + resource \"cml2_lifecycle\" \"this\" {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + booted\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + id\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + lab_id\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + nodes\u00a0\u00a0\u00a0 = {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 } -&gt; (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + state\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + topology = (sensitive value)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0 }<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">Plan: 1 to add, 0 to change, 0 to destroy.<\/span>&#13;\n<span data-contrast=\"auto\">cml2_lifecycle.this: Creating...<\/span>&#13;\n<span data-contrast=\"auto\">cml2_lifecycle.this: Still creating... [10s elapsed]<\/span>&#13;\n<span data-contrast=\"auto\">cml2_lifecycle.this: Still creating... [20s elapsed]<\/span>&#13;\n<span data-contrast=\"auto\">cml2_lifecycle.this: Creation complete after 25s [id=b75992ec-d345-4638-a6fd-2c0b640a3c22]<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">Apply complete! Resources: 1 added, 0 changed, 0 destroyed.<\/span>&#13;\n<span data-contrast=\"auto\">$<\/span><span data-ccp-props=\"{&quot;335559739&quot;:200}\">\u00a0<\/span><\/pre>\n<p><span data-contrast=\"auto\">We can now look at the state:<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<pre><span data-contrast=\"auto\">$ terraform show<\/span>&#13;\n<span data-contrast=\"auto\"># cml2_lifecycle.this:<\/span>&#13;\n<span data-contrast=\"auto\">resource \"cml2_lifecycle\" \"this\" {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0 booted\u00a0\u00a0 = true<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0 id\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = \"b75992ec-d345-4638-a6fd-2c0b640a3c22\"<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0 nodes\u00a0\u00a0\u00a0 = {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 # (3 unchanged elements hidden)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0 }<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0 state\u00a0\u00a0\u00a0 = \"STARTED\"<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0 topology = (sensitive value)<\/span>&#13;\n<span data-contrast=\"auto\">}<\/span>&#13;\n<span data-contrast=\"auto\">$ terraform console<\/span>&#13;\n<span data-contrast=\"auto\">&gt; keys(cml2_lifecycle.this.nodes)<\/span>&#13;\n<span data-contrast=\"auto\">tolist([<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 \"0504773c-5396-44ff-b545-ccb734e11691\",<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 \"22271a81-1d3a-4403-97de-686ebf0f36bc\",<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 \"2bccca61-d4ee-459a-81bd-96b32bdaeaed\",<\/span>&#13;\n<span data-contrast=\"auto\">])<\/span>&#13;\n<span data-contrast=\"auto\">&gt; cml2_lifecycle.this.nodes[\"0504773c-5396-44ff-b545-ccb734e11691\"].interfaces[0].ip4[0]<\/span>&#13;\n<span data-contrast=\"auto\">\"192.168.122.227\"<\/span>&#13;\n<span data-contrast=\"auto\">&gt; exit\u00a0 <\/span>&#13;\n<span data-contrast=\"auto\">$<\/span><span data-ccp-props=\"{&quot;335559739&quot;:200}\">\u00a0<\/span><\/pre>\n<h4><strong><i>Simple import example with a template<\/i>\u00a0<\/strong><\/h4>\n<p><span data-contrast=\"auto\">This example is similar to the one above, but this time we import the topology using <\/span><span data-contrast=\"auto\">templatefile(),<\/span><span data-contrast=\"auto\"> which allows templating of the topology. Assuming that the CML2 topology YAML file starts with<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<pre><span style=\"color: #333399;\">lab<b>:<\/b><\/span>&#13;\n<span style=\"color: #333399;\">\u00a0 description<b>:<\/b> \"description\"<\/span>&#13;\n<span style=\"color: #333399;\">\u00a0 notes<b>:<\/b> \"notes\"<\/span>&#13;\n<span style=\"color: #333399;\">\u00a0 timestamp<b>:<\/b><\/span> <span style=\"color: #008000;\" data-contrast=\"none\">1606137179.2951126<\/span>&#13;\n<span data-contrast=\"none\">\u00a0 <\/span><span style=\"color: #333399;\">title<b>:<\/b><\/span><span style=\"color: #808000;\" data-contrast=\"none\"> ${toponame}<\/span>&#13;\n<span data-contrast=\"none\">\u00a0 <\/span><span style=\"color: #333399;\">version<b>:<\/b><\/span> <span style=\"color: #008000;\" data-contrast=\"none\">0.0.4<\/span>&#13;\n<span style=\"color: #333399;\">nodes<b>:<\/b><\/span>&#13;\n<span data-contrast=\"none\">\u00a0 <\/span><span style=\"color: #008000;\"><b>-<\/b><\/span> <span style=\"color: #333399;\">id<b>:<\/b><\/span><span style=\"color: #808000;\" data-contrast=\"none\"> n0<\/span>&#13;\n<span style=\"color: #008000;\"><b>[<\/b><\/span><span data-contrast=\"none\">...<\/span><span style=\"color: #008000;\"><b>]<\/b><\/span><span data-ccp-props=\"{&quot;335559739&quot;:200}\">\u00a0<\/span><\/pre>\n<p><span data-contrast=\"auto\">then using this HCL<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<pre><span data-contrast=\"auto\">resource \"cml2_lifecycle\" \"this\" {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 topology = templatefile(\"topology.yaml\", { toponame = \"yolo lab\" })<\/span>&#13;\n<span data-contrast=\"auto\">}<\/span><span data-ccp-props=\"{&quot;335559739&quot;:200}\">\u00a0<\/span><\/pre>\n<p><span data-contrast=\"auto\">will replace the <\/span><span data-contrast=\"auto\">title: <strong>${toponame}<\/strong><\/span><span data-contrast=\"auto\"> from the YAML with the content of the string <\/span><span data-contrast=\"auto\">\u201cyolo lab\u201d<\/span><span data-contrast=\"auto\"> at import time. Note that instead of a string literal, it\u2019s perfectly fine to use a variable like <\/span><strong>var.toponame<\/strong><span data-contrast=\"auto\"> or other HCL features!<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<h3><b><span data-contrast=\"none\">Define-mode usage<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:200,&quot;335559739&quot;:0}\">\u00a0<\/span><\/h3>\n<p><i><span data-contrast=\"auto\">Define-mode<\/span><\/i><span data-contrast=\"auto\"> starts with the definition of a <\/span><span data-contrast=\"auto\">lab<\/span><span data-contrast=\"auto\"> resource and then adds <\/span><span data-contrast=\"auto\">node<\/span><span data-contrast=\"auto\"> and <\/span><span data-contrast=\"auto\">link<\/span><span data-contrast=\"auto\"> resources. In this mode, resources will only be created. If we want to control the runtime state (e.g.,\u202fstart\/stop\/wipe the lab), then we need to link these elements to a <\/span><span data-contrast=\"auto\">lifecycle<\/span><span data-contrast=\"auto\"> resource.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">Here\u2019s an example:<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<pre><span data-contrast=\"auto\">resource \"cml2_lab\" \"this\" {<\/span>&#13;\n<span data-contrast=\"auto\">}<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">resource \"cml2_node\" \"ext\" {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 lab_id\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = cml2_lab.this.id<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 nodedefinition = \"external_connector\"<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 label\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = \"Internet\"<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 configuration\u00a0 = \"bridge0\"<\/span>&#13;\n<span data-contrast=\"auto\">}<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">resource \"cml2_node\" \"r1\" {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 lab_id\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = cml2_lab.this.id<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 label\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = \"R1\"<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 nodedefinition = \"alpine\"<\/span>&#13;\n<span data-contrast=\"auto\">}<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">resource \"cml2_link\" \"l1\" {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 lab_id = cml2_lab.this.id<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 node_a = cml2_node.ext.id<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 node_b = cml2_node.r1.id<\/span>&#13;\n<span data-contrast=\"auto\">}<\/span><span data-ccp-props=\"{&quot;335559739&quot;:200}\">\u00a0<\/span><\/pre>\n<p><span data-contrast=\"auto\">This will create the lab, the nodes, and the link between them. Without further configuration, nothing will be started. If these resources should be started, then you\u2019ll need a CML2 lifecycle resource:<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<pre><span data-contrast=\"auto\">resource \"cml2_lifecycle\" \"top\" {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 lab_id = cml2_lab.this.id<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 elements = [<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0 cml2_node.ext.id,<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0 cml2_node.r2.id,<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0 cml2_link.l1.id,<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 ]<\/span>&#13;\n<span data-contrast=\"auto\">}<\/span><span data-ccp-props=\"{&quot;335559739&quot;:200}\">\u00a0<\/span><\/pre>\n<p><span data-contrast=\"auto\">Here\u2019s what this looks like after applying the combined plan.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p><b><span data-contrast=\"auto\">NOTE:<\/span><\/b><span data-contrast=\"auto\"> For brevity, some attributes are omitted and have been replaced by <\/span><span data-contrast=\"auto\">[\u2026]<\/span><span data-contrast=\"auto\">:<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<pre><span data-contrast=\"auto\">$ terraform apply -auto-approve<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 + create<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">Terraform will perform the following actions:<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">\u00a0 # cml2_lab.this will be created<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 + resource \"cml2_lab\" \"this\" {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + created\u00a0\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + description = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + groups\u00a0\u00a0\u00a0\u00a0\u00a0 = [<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ] -&gt; (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + id\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 [...]<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + title\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0 }<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">\u00a0 # cml2_lifecycle.top will be created<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 + resource \"cml2_lifecycle\" \"top\" {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + booted\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + elements = [<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 + (known after apply),<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 + (known after apply),<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 + (known after apply),<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ]<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + id\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + lab_id\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + nodes\u00a0\u00a0\u00a0 = {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 } -&gt; (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + state\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0 }<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">\u00a0 # cml2_link.l1 will be created<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 + resource \"cml2_link\" \"l1\" {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + id\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + interface_a\u00a0\u00a0\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + interface_b\u00a0\u00a0\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + lab_id\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + label\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + link_capture_key = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + node_a\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + node_a_slot\u00a0\u00a0\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + node_b\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + node_b_slot\u00a0\u00a0\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + state\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0 }<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">\u00a0 # cml2_node.ext will be created<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 + resource \"cml2_node\" \"ext\" {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + configuration\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + cpu_limit\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + cpus\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 [...]<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + x\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + y\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0 }<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">\u00a0 # cml2_node.r1 will be created<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 + resource \"cml2_node\" \"r1\" {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + configuration\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + cpu_limit\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + cpus\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 [...]<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + x\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 + y\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = (known after apply)<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0 }<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">Plan: 5 to add, 0 to change, 0 to destroy.<\/span>&#13;\n<span data-contrast=\"auto\">cml2_lab.this: Creating...<\/span>&#13;\n<span data-contrast=\"auto\">cml2_lab.this: Creation complete after 0s [id=306f3ebf-c819-4b89-a99d-138a58ca7195]<\/span>&#13;\n<span data-contrast=\"auto\">cml2_node.ext: Creating...<\/span>&#13;\n<span data-contrast=\"auto\">cml2_node.r2: Creating...<\/span>&#13;\n<span data-contrast=\"auto\">cml2_node.ext: Creation complete after 1s [id=32f187bf-4f53-462a-8e36-43cd9b6e17a4]<\/span>&#13;\n<span data-contrast=\"auto\">cml2_node.r2: Creation complete after 1s [id=5d59a0d3-70a1-45a1-9b2a-4cecd9a4e696]<\/span>&#13;\n<span data-contrast=\"auto\">cml2_link.l1: Creating...<\/span>&#13;\n<span data-contrast=\"auto\">cml2_link.l1: Creation complete after 0s [id=a083c777-abab-47d2-95c3-09d897e01d2e]<\/span>&#13;\n<span data-contrast=\"auto\">cml2_lifecycle.top: Creating...<\/span>&#13;\n<span data-contrast=\"auto\">cml2_lifecycle.top: Still creating... [10s elapsed]<\/span>&#13;\n<span data-contrast=\"auto\">cml2_lifecycle.top: Still creating... [20s elapsed]<\/span>&#13;\n<span data-contrast=\"auto\">cml2_lifecycle.top: Creation complete after 22s [id=306f3ebf-c819-4b89-a99d-138a58ca7195]<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">Apply complete! Resources: 5 added, 0 changed, 0 destroyed.<\/span>&#13;\n&#13;\n<span data-contrast=\"auto\">$<\/span><span data-ccp-props=\"{&quot;335559739&quot;:200}\">\u00a0<\/span><\/pre>\n<p><span data-contrast=\"auto\">The <\/span><strong>elements<\/strong><span data-contrast=\"auto\"> lifecycle attribute is needed to tie the individual nodes and links into the lifecycle resource. This ensures the correct sequence of operations based on the dependencies between the resources.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p><b><span data-contrast=\"auto\">NOTE:<\/span><\/b><span data-contrast=\"auto\"> It\u2019s not possible to use both <\/span><span data-contrast=\"auto\">import<\/span><span data-contrast=\"auto\"> and <\/span><span data-contrast=\"auto\">elements<\/span><span data-contrast=\"auto\"> at the same time. In addition, when importing a topology using the <\/span><span data-contrast=\"auto\">topology<\/span><span data-contrast=\"auto\"> attribute, a <\/span><span data-contrast=\"auto\">lab_id<\/span><span data-contrast=\"auto\"> cannot be set.<\/span><span data-ccp-props=\"{&quot;335559685&quot;:0,&quot;335559737&quot;:480,&quot;335559738&quot;:100,&quot;335559739&quot;:100}\">\u00a0<\/span><\/p>\n<h3><b><span data-contrast=\"none\">Advanced usage<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:200,&quot;335559739&quot;:0}\">\u00a0<\/span><\/h3>\n<p><span data-contrast=\"auto\">The <\/span><span data-contrast=\"auto\">lifecycle<\/span><span data-contrast=\"auto\"> resource has a few more configuration parameters that control advanced features. Here\u2019s a list of those parameters and what they do:<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<ul>\n<li data-leveltext=\"\u2022\" data-font=\"Calibri\" data-listid=\"5\" data-list-defn-props=\"{&quot;335551671&quot;:0,&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:480,&quot;335559991&quot;:480,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\u2022&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"0\" data-aria-level=\"1\"><span data-contrast=\"auto\">configs<\/span><span data-contrast=\"auto\"> is a map of strings. The keys are node labels, and the values are node configurations. When these are present, the provider will check for all node labels to see whether they are matching and, if they are, replace the node\u2019s configuration with the provided configuration. This allows you to \u201cinject\u201d configurations into a topology file. The base topology file could have no configurations, in which case the actual configurations would be provided via an example <\/span><span data-contrast=\"auto\">file(\u201cnode1-config\u201d)<\/span><span data-contrast=\"auto\"> or a literal configuration string, as shown here:<\/span><span data-ccp-props=\"{&quot;335559739&quot;:200}\">\u00a0<\/span><\/li>\n<\/ul>\n<pre style=\"padding-left: 40px;\"><span data-contrast=\"auto\">configs = {<\/span>&#13;\n<span data-contrast=\"auto\"> \"node-1\": file(\"node1-config\")<\/span>&#13;\n<span data-contrast=\"auto\"> \"node-2\": \"hostname node2\"<\/span>&#13;\n<span data-contrast=\"auto\">}\u00a0<\/span><span data-ccp-props=\"{&quot;335559739&quot;:200}\">\u00a0<\/span><\/pre>\n<ul>\n<li data-leveltext=\"\u2022\" data-font=\"Calibri\" data-listid=\"5\" data-list-defn-props=\"{&quot;335551671&quot;:0,&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:480,&quot;335559991&quot;:480,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\u2022&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"0\" data-aria-level=\"1\"><span data-contrast=\"auto\">staging<\/span><span data-contrast=\"auto\"> defines the node start sequence when the lab is started. Node tags are used to achieve this. Here\u2019s an example:<\/span><span data-ccp-props=\"{&quot;335559739&quot;:200}\">\u00a0<\/span><\/li>\n<\/ul>\n<pre style=\"padding-left: 40px;\"><span data-contrast=\"auto\">staging = {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0 stages = [\"infra\", \"core\", \"site-1\"]<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0 start_remaining = true<\/span>&#13;\n<span data-contrast=\"auto\">}<\/span><span data-ccp-props=\"{&quot;335559739&quot;:200}\">\u00a0<\/span><\/pre>\n<p style=\"padding-left: 40px;\"><span data-contrast=\"auto\">The given example ensures that nodes with the tag \u201cinfra\u201d are started first. The provider waits until all nodes with this tag are marked as \u201cbooted.\u201d Then, all nodes with the tag \u201ccore\u201d are started, and so on. If, after the end of the stage list, there are still stopped nodes, then the <\/span><span data-contrast=\"auto\">start_remaining<\/span><span data-contrast=\"auto\"> flag determines whether they should remain stopped or should be started as well (the default is true, e.g.,\u202fthey will all be started).<\/span><span data-ccp-props=\"{&quot;335559739&quot;:200}\">\u00a0<\/span><\/p>\n<ul>\n<li data-leveltext=\"\u2022\" data-font=\"Calibri\" data-listid=\"5\" data-list-defn-props=\"{&quot;335551671&quot;:0,&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:480,&quot;335559991&quot;:480,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\u2022&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"0\" data-aria-level=\"1\"><strong>state<\/strong><span data-contrast=\"auto\"> defines the runtime state of the lab. By default this is <\/span><span data-contrast=\"auto\">STARTED,<\/span><span data-contrast=\"auto\"> which means the lab will be started. Options are <\/span><strong>STARTED<\/strong><span data-contrast=\"auto\">, <\/span><span data-contrast=\"auto\"><strong>STOPPED<\/strong>,<\/span><span data-contrast=\"auto\"> and <\/span><strong>DEFINED_ON_CORE\u00a0<\/strong><\/li>\n<\/ul>\n<p style=\"padding-left: 80px;\"><span data-contrast=\"auto\">\u2013\u00a0 \u00a0 STARTED<\/span><span data-contrast=\"auto\"> is the default<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/p>\n<p style=\"padding-left: 80px;\"><span data-contrast=\"auto\">\u2013\u00a0 \u00a0 STOPPED<\/span><span data-contrast=\"auto\"> can be set if the lab is currently started, otherwise it will produce a failure<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/p>\n<p style=\"padding-left: 80px;\"><span data-contrast=\"auto\">\u2013\u00a0 \u00a0 DEFINED_ON_CORE<\/span><span data-contrast=\"auto\"> is wiping the lab if the current state is either <\/span><span data-contrast=\"auto\">STARTED<\/span><span data-contrast=\"auto\"> or <\/span><span data-contrast=\"auto\">STOPPED<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/p>\n<ul>\n<li data-leveltext=\"\u2022\" data-font=\"Calibri\" data-listid=\"5\" data-list-defn-props=\"{&quot;335551671&quot;:0,&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:480,&quot;335559991&quot;:480,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\u2022&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"0\" data-aria-level=\"1\"><strong>timeouts<\/strong><span data-contrast=\"auto\"> can be used to set different timeouts for operations. This might be necessary for big labs that take a long time to start. The defaults are set to <\/span><span data-contrast=\"auto\">2h<\/span><span data-contrast=\"auto\"> .<\/span><span data-ccp-props=\"{&quot;335559739&quot;:200}\">\u00a0<\/span><\/li>\n<li data-leveltext=\"\u2022\" data-font=\"Calibri\" data-listid=\"5\" data-list-defn-props=\"{&quot;335551671&quot;:0,&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:480,&quot;335559991&quot;:480,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\u2022&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"0\" data-aria-level=\"1\"><strong>wait<\/strong><span data-contrast=\"auto\"> is a boolean flag, which defines whether the provider should wait for convergence (for example, when the lab starts, and this is set to <\/span><span data-contrast=\"auto\">false,<\/span><span data-contrast=\"auto\"> then the provider will start the lab but will not wait until all nodes within the lab are \u201cready\u201d).<\/span><\/li>\n<li data-leveltext=\"\u2022\" data-font=\"Calibri\" data-listid=\"5\" data-list-defn-props=\"{&quot;335551671&quot;:0,&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:480,&quot;335559991&quot;:480,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\u2022&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"0\" data-aria-level=\"1\"><strong>id<\/strong><span data-contrast=\"auto\"> is a read-only computed attribute. A UUIDv4 will be auto-generated at create time and assigned to this ID.<\/span><span data-ccp-props=\"{&quot;335559739&quot;:200}\">\u00a0<\/span><\/li>\n<\/ul>\n<h2><b><span data-contrast=\"none\">CRUD<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:200,&quot;335559739&quot;:0}\"> operations<\/span><\/h2>\n<p><span data-contrast=\"auto\">Of the four basic operations of resource management, create, read, update, and delete (CRUD), the previous sections primarily described the create and read aspect. But Terraform can also deal with update and delete.<\/span><span data-ccp-props=\"{&quot;335559739&quot;:0}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">Plans can be changed, new resources can be added, and existing resources can be removed or changed. This is always a result of editing\/changing your Terraform configuration files and then having Terraform figure out the required state changes via the <\/span><span data-contrast=\"auto\">terraform plan<\/span><span data-contrast=\"auto\"> followed by a <\/span><span data-contrast=\"auto\">terraform apply<\/span><span data-contrast=\"auto\"> once you are satisfied with those changes.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<h3><b><span data-contrast=\"none\">Updating resources<\/span><\/b><\/h3>\n<p><span data-contrast=\"auto\">It is possible to update resources, but not every combination is seamless. Here are a few things to consider:<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<ul>\n<li data-leveltext=\"\u2022\" data-font=\"Calibri\" data-listid=\"7\" data-list-defn-props=\"{&quot;335551671&quot;:0,&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:480,&quot;335559991&quot;:480,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\u2022&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"0\" data-aria-level=\"1\"><span data-contrast=\"auto\">Only a few node attributes can be changed seamlessly; examples are coordinates (x\/y), label, and configuration<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/li>\n<li data-leveltext=\"\u2022\" data-font=\"Calibri\" data-listid=\"10\" data-list-defn-props=\"{&quot;335551671&quot;:0,&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:480,&quot;335559991&quot;:480,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\u2022&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"0\" data-aria-level=\"1\"><span data-contrast=\"auto\">Some plan changes will re-create resources. For example, running nodes will be destroyed and restarted is if\u202fthe node definition is changed<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/li>\n<\/ul>\n<h3><b><span data-contrast=\"none\">Deleting resources<\/span><\/b><\/h3>\n<p><span data-contrast=\"auto\">Finally, a <\/span><span data-contrast=\"auto\">terraform destroy<\/span><span data-contrast=\"auto\"> will delete all created resources from the controller.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<h2><b><span data-contrast=\"none\">Data Sources<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:200,&quot;335559739&quot;:0}\">\u00a0<\/span><\/h2>\n<p><span data-contrast=\"auto\">As opposed to resources, data sources don\u2019t hold any state. They are used to read data from the controller. This data can then be used to reference elements in other data sources or resources. A good example, although not yet implemented, would be a list of available node- and image-definitions. By reading these into a data source, the HCL defining the infrastructure could take available definitions into account.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">There are, however, a few data sources implemented:<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<ul>\n<li data-leveltext=\"\u2022\" data-font=\"Calibri\" data-listid=\"8\" data-list-defn-props=\"{&quot;335551671&quot;:0,&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:480,&quot;335559991&quot;:480,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\u2022&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"0\" data-aria-level=\"1\"><span data-contrast=\"auto\">Node: Reads a node by providing a lab and a node ID<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/li>\n<\/ul>\n<ul>\n<li data-leveltext=\"\u2022\" data-font=\"Calibri\" data-listid=\"8\" data-list-defn-props=\"{&quot;335551671&quot;:0,&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:480,&quot;335559991&quot;:480,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\u2022&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"0\" data-aria-level=\"1\"><span data-contrast=\"auto\">Lab: Reads a lab by providing either a lab ID or a lab title<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/li>\n<\/ul>\n<h2><b><span data-contrast=\"none\">Output<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:200,&quot;335559739&quot;:0}\">\u00a0<\/span><\/h2>\n<p><span data-contrast=\"auto\">All data in resources and data sources can be used to drive output from Terraform. A useful example in the context of CML2 is the retrieval of IP addresses from running nodes. Here\u2019s the way to do it, assuming that the lifecycle resource is called <\/span><span data-contrast=\"auto\">this<\/span><span data-contrast=\"auto\"> and also assuming that <\/span><span data-contrast=\"auto\">R1<\/span><span data-contrast=\"auto\"> is able to acquire an IP address via an external connector:<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<pre><span data-contrast=\"auto\">cml2_lifecycle.this.nodes[\"0504773c-5396-44ff-b545-<\/span>&#13;\n<span data-contrast=\"auto\">ccb734e11691\"].interfaces[0].ip4[0]<\/span><span data-ccp-props=\"{&quot;335559739&quot;:200}\">\u00a0<\/span><\/pre>\n<p><span data-contrast=\"auto\">Note, however, that output is also calculated when resources might not exist, so the above will give an error due to the node not being found or the interface list being empty. To guard against this, you can use HCL:<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<pre><span data-contrast=\"auto\">output \"r1_ip_address\" {<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 value = (<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0 cml2_lifecycle.top.nodes[cml2_node.r1.id].interfaces[0].ip4 == null ?<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0 \"undefined\" : (<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 length(cml2_lifecycle.top.nodes[cml2_node.r1.id].interfaces[0].ip4) &gt; 0 ?<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 cml2_lifecycle.top.nodes[cml2_node.r1.id].interfaces[0].ip4[0] :<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0\u00a0\u00a0 \"no ip\"<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0\u00a0\u00a0 )<\/span>&#13;\n<span data-contrast=\"auto\">\u00a0 )<\/span>&#13;\n<span data-contrast=\"auto\">}<\/span><span data-ccp-props=\"{&quot;335559739&quot;:200}\">\u00a0<\/span><\/pre>\n<p><span data-contrast=\"auto\">Output:<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<pre><span data-contrast=\"auto\">r1_ip_address = \"192.168.255.115\"<\/span><span data-ccp-props=\"{&quot;335559739&quot;:200}\">\u00a0<\/span><\/pre>\n<h2><b><span data-contrast=\"none\">Conclusion<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:200,&quot;335559739&quot;:0}\">\u00a0<\/span><\/h2>\n<p><span data-contrast=\"auto\">The CML2 provider fits nicely into the overall Terraform eco-system. With the flexibility HCL provides and by combining it with other Terraform providers, it\u2019s never been easier to automate virtual network infrastructure inside CML2. What will you do with these new capabilities? We\u2019re curious to hear about it!<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span>Let\u2019s continue the conversation on the Cisco Learning Network\u2019s Cisco Modeling Labs Community.<\/p>\n<h3 style=\"text-align: left;\">Single users can purchase Cisco Modeling Labs \u2013 Personal and Cisco Modeling Labs \u2013 Personal Plus licenses from the Cisco Learning Network Store. For teams, explore CML \u2013 Enterprise and CML \u2013 Higher Education licensing and contact us to learn how Cisco Modeling Labs can power your NetDevOps transformation.<\/h3>\n<hr\/>\n<p style=\"text-align: center;\">Join the Cisco Learning Network today for free.<\/p>\n<blockquote>\n<h2 style=\"text-align: center;\"><strong>Follow Cisco Learning &amp; Certifications<\/strong><\/h2>\n<h3 style=\"text-align: center;\"><strong><a href=\"https:\/\/twitter.com\/LearningatCisco\">Twitter<\/a> | Facebook | LinkedIn | Instagram<\/strong><\/h3>\n<\/blockquote>\n<p style=\"text-align: center;\">Use <strong>#CiscoCert<\/strong> to join the conversation.<\/p>\n<p>\u00a0<\/p>\n<p><span data-contrast=\"auto\">References<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<ul>\n<li data-leveltext=\"\u2022\" data-font=\"Calibri\" data-listid=\"9\" data-list-defn-props=\"{&quot;335551671&quot;:0,&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:480,&quot;335559991&quot;:480,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\u2022&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"0\" data-aria-level=\"1\"><span data-contrast=\"auto\">https:\/\/developer.hashicorp.com\/terraform\/tutorials\/aws-get-started\/install-cli<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/li>\n<li data-leveltext=\"\u2022\" data-font=\"Calibri\" data-listid=\"9\" data-list-defn-props=\"{&quot;335551671&quot;:0,&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:480,&quot;335559991&quot;:480,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\u2022&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"0\" data-aria-level=\"1\"><span data-contrast=\"auto\">https:\/\/github.com\/CiscoDevNet\/terraform-provider-cml2<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/li>\n<li data-leveltext=\"\u2022\" data-font=\"Calibri\" data-listid=\"9\" data-list-defn-props=\"{&quot;335551671&quot;:0,&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:480,&quot;335559991&quot;:480,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\u2022&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"0\" data-aria-level=\"1\"><span data-contrast=\"auto\">https:\/\/registry.terraform.io\/providers\/CiscoDevNet\/cml2<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/li>\n<li data-leveltext=\"\u2022\" data-font=\"Calibri\" data-listid=\"9\" data-list-defn-props=\"{&quot;335551671&quot;:0,&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:480,&quot;335559991&quot;:480,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\u2022&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"0\" data-aria-level=\"1\"><span data-contrast=\"auto\">https:\/\/developer.hashicorp.com\/terraform\/language<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/li>\n<li data-leveltext=\"\u2022\" data-font=\"Calibri\" data-listid=\"9\" data-list-defn-props=\"{&quot;335551671&quot;:0,&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:480,&quot;335559991&quot;:480,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\u2022&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"0\" data-aria-level=\"1\"><span data-contrast=\"none\">https:\/\/direnv.net\/<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/li>\n<li data-leveltext=\"\u2022\" data-font=\"Calibri\" data-listid=\"9\" data-list-defn-props=\"{&quot;335551671&quot;:0,&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:480,&quot;335559991&quot;:480,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\u2022&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"0\" data-aria-level=\"1\"><span data-contrast=\"auto\">Image by Dall-E (https:\/\/labs.openai.com\/)<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/li>\n<\/ul>\n<p>Share:<\/p>\n<p>\n  \t<\/div>\n<p><script async src=\"\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"><\/script><script async defer src=\"https:\/\/platform.instagram.com\/en_US\/embeds.js\"><\/script><br \/>\n<br \/><p><a href=\"https:\/\/dmsretail.com\/online-workshops-list\/\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-496\" src=\"https:\/\/dmsretail.com\/RetailNews\/wp-content\/uploads\/2022\/05\/RETAIL-ONLINE-TRAINING-728-X-90.png\" alt=\"Retail Online Training\" width=\"729\" height=\"91\" srcset=\"https:\/\/dmsretail.com\/RetailNews\/wp-content\/uploads\/2022\/05\/RETAIL-ONLINE-TRAINING-728-X-90.png 729w, https:\/\/dmsretail.com\/RetailNews\/wp-content\/uploads\/2022\/05\/RETAIL-ONLINE-TRAINING-728-X-90-300x37.png 300w\" sizes=\"auto, (max-width: 729px) 100vw, 729px\" \/><\/a><\/p><br \/><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Infrastructure as Code (IaC) is a hot topic these days, and the IaC tool of choice is Terraform by HashiCorp. Terraform is a cloud provisioning [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":8159,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"class_list":["post-8158","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-technology"],"_links":{"self":[{"href":"https:\/\/dmsretail.com\/RetailNews\/wp-json\/wp\/v2\/posts\/8158","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dmsretail.com\/RetailNews\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dmsretail.com\/RetailNews\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dmsretail.com\/RetailNews\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dmsretail.com\/RetailNews\/wp-json\/wp\/v2\/comments?post=8158"}],"version-history":[{"count":0,"href":"https:\/\/dmsretail.com\/RetailNews\/wp-json\/wp\/v2\/posts\/8158\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/dmsretail.com\/RetailNews\/wp-json\/wp\/v2\/media\/8159"}],"wp:attachment":[{"href":"https:\/\/dmsretail.com\/RetailNews\/wp-json\/wp\/v2\/media?parent=8158"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dmsretail.com\/RetailNews\/wp-json\/wp\/v2\/categories?post=8158"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dmsretail.com\/RetailNews\/wp-json\/wp\/v2\/tags?post=8158"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}