Jump to content

Deployment Guide: Using Terraform for Daily Administrative Operations

  • Contributed By: Gerhard Krenn

Deployment Guide: Using Terraform for Daily Administrative Operations
 

This guide focuses on daily administrative operations using Terraform after the initial deployment:

  • Keeping the .tfstate file safe
  • Importing an existing Infrastructure into Terraform
  • Checking an Infrastructure for changes after the initial deployment
  • Checking the Endpoint App settings (Workspace App, Enterprise Browser) for changes after the initial deployment
  • Changing settings/configurations of already deployed entities (Machine Catalogs, Delivery Groups, Policies, Workspace App configurations)
  • Adding/removing entities to/from the infrastructure

Terraform's flexibility and wide range of integrations make it a valuable tool for DevOps and infrastructure management.
 

Overview

Terraform is an Infrastructure-as-Code (IaC) tool that defines cloud and on-prem resources in easy-readable configuration files rather than through a GUI.

These configurations can be versioned, reused, and shared and are created in its native declarative configuration language known as HashiCorp Configuration Language (HCL), or optionally using JSON.

IaC allows you to build, change, manage, and check your infrastructure safely and consistently by defining resource configurations.

Terraform is declarative:
You tell the Terraform provider the desired state of your planned deployment.
You do not need to write every step in your code to achieve this goal.
The provider takes care of all needed steps.

Terraform is idempotent:
No matter how often you execute the same Terraform code - your Infrastructure will remain the same unless you change the code.
You will see in the examples below, that we change only the code parts we need to alter the Infrastructure and rerun the complete Terraform code.


On Citrix Tech Zone´s Automation page, you can find various guides on initially deploying Citrix DaaS or Citrix CVAD using Terraform.
 

Note:

Please find a description of installing Terraform and initial configurations in our Tech Zone Deployment Guide: Installing Terraform and Configuring the Citrix Terraform Provider.

If you want to see all the mentioned examples in this guide in action, please watch our Tech Insight video on our YouTube channel.
 

 

The State

Terraform stores information about your infrastructure and configuration in its State.
It primarily maps the deployed resources to the infrastructure and keeps needed metadata.

The State is stored by default in a local file named "terraform.tfstate".
Terraform uses the State to determine which changes must be made to your infrastructure. Terraform automatically refreshes the state with the existing infrastructure before any alterations are initiated.

Important:

Be very careful with a locally saved .tfstate file—it is recommended that you store it in a safe, encrypted manner with limited access and use a versioning control system.
 

 

Caution:

Terraform´s .tfstate can contain sensitive data like database passwords, user passwords, or private keys.

If you use locally stored State files (=Local State), they are stored on your machine as plain-text JSON files.
If you use remote stored State files (=Remote State), the State is only transferred from the remote backend to memory when Terraform uses it. Be aware that the transport can be unencrypted.

 

The .tfstate file can grow quite large—for example, the .tfstate file in our demo environment is more than 5MB.

Example of a representation of a Machine Catalog in a locally stored .tfstate file:

...,

 {

      "mode": "managed",

      "type": "citrix_machine_catalog",

      "name": "machine_catalog_0",

      "provider": "provider[\"registry.terraform.io/citrix/citrix\"]",

      "instances": [

        {

          "schema_version": 0,

          "attributes": {

            "allocation_type": "Random",

            "built_in_scopes": [

              "00000000-0000-0000-0000-000000000000"

            ],

            "description": "Machine Catalog on Azure based on Windows 11 Single-Session  for TMM-Gerhard",

            "id": "95d6xxxx-xxxx-xxxx-xxxx-xxxxxxxxdc35",

            "inherited_scopes": [],

            "is_power_managed": null,

            "is_remote_pc": null,

            "machine_accounts": null,

            "machine_catalog_folder_path": null,

            "metadata": null,

            "minimum_functional_level": "L7_34",

            "name": "MC-TMM-GK-AZURE-W11-SS",

            "provisioning_scheme": {

              "availability_zones": [

                "1"

              ],

              "aws_machine_config": null,

              "azure_machine_config": {

                "azure_master_image": {

                  "container": null,

                  "gallery_image": null,

                  "master_image": "TMM-GK-W11-SS-M_OsDisk_1_7d8xxxxxxxx",

                  "resource_group": "tmm_gerhard_westeurope",

                  "shared_subscription": null,

                  "storage_account": null

                },

                "azure_pvs_config": null,

                "disk_encryption_set": null,

                "enroll_in_intune": null,

                "image_update_reboot_options": null,

                "license_type": "Windows_Client",

                "machine_profile": {

                  "machine_profile_resource_group": "tmm_gerhard_westeurope",

                  "machine_profile_template_spec_name": null,

                  "machine_profile_template_spec_version": null,

                  "machine_profile_vm_name": "TMM-GK-W11-SS-M"

                },

                "master_image_note": "",

                "service_offering": "Standard_D2s_v5",

                "storage_type": "Premium_LRS",

                "use_azure_compute_gallery": null,

                "use_managed_disks": true,

                "vda_resource_group": "tmm_gerhard_westeurope",

                "writeback_cache": null

              },

              "custom_properties": null,

              "gcp_machine_config": null,

              "hypervisor": "bec2xxxx-xxxx-xxxx-xxxx-xxxxxxxxf8f0",

              "hypervisor_resource_pool": "2c70xxxx-xxxx-xxxx-xxxx-xxxxxxxx87cb",

              "identity_type": "ActiveDirectory",

              "machine_account_creation_rules": {

                "naming_scheme": "TMM-GK-W11-SS-#",

                "naming_scheme_type": "Numeric"

              },

              "machine_domain_identity": {

                "domain": "democloud.corp",

                "domain_ou": "OU=_AZURE,OU=_WORKER,OU=_CITRIX,OU=TACG,OU=EBC-TMM,DC=democloud,DC=corp",

                "service_account": "xxxxxxxxxxxxxxxxxxxxxxxx",

                "service_account_password": "xxxxxxxxxxxxxxxxxxxxxxxx"

              },

              "metadata": null,

              "network_mapping": null,

              "number_of_total_machines": 1,

              "nutanix_machine_config": null,

              "scvmm_machine_config": null,

              "vsphere_machine_config": null,

              "xenserver_machine_config": null

            },

            "provisioning_type": "MCS",

            "remote_pc_ous": null,

            "scopes": [],

            "session_support": "SingleSession",

            "tags": null,

            "tenants": null,

            "vda_upgrade_type": null,

            "zone": "4050xxxx-xxxx-xxxx-xxxx-xxxxxxxxc507"

          },

          "sensitive_attributes": [

            [

              {

                "type": "get_attr",

                "value": "provisioning_scheme"

              },

              {

                "type": "get_attr",

                "value": "machine_domain_identity"

              },

              {

                "type": "get_attr",

                "value": "service_account_password"

              }

            ]

          ]

        }

      ]

    },

...Sensitive data would be readable in clear text.

Sensitive data would be readable in clear text.

Keeping the State safe

The recommended way to keep the State secure is not to use Local State but Remote State.
The State is written to a remote data store. Terraform supports HCP Terraform, HashiCorp Consul, Amazon S3, Azure Blob Storage, Google Cloud Storage, Alibaba Cloud OSS, and more.

As mentioned, Terraform will not persist the State anywhere on the local disk.
It will write the State locally only in the case of a non-recoverable error, where writing the State to the backend fails. This is to prevent data loss.

We use an Azure Storage Account to store the State in this example.
You can use Terraform to create the needed Storage Account:

data "azurerm_resource_group" "GetAzureRG" {

  name = "TMM-Gerhard-WestEurope"

}

 

resource "azurerm_storage_account" "AzureStorageAccountForTerraform" {

  name                              = "${var.TF-StorageAccount-Name}"

  resource_group_name               = data.azurerm_resource_group.GetAzureRG.name

  location                          = data.azurerm_resource_group.GetAzureRG.location

  account_tier                      = "Standard"

  account_replication_type          = "LRS"

  allow_nested_items_to_be_public   = false

 

  tags                              = {

                                            environment  = "TMM-Gerhard"

  }

}

 

resource "azurerm_storage_container" "AzureStorageAccountContainerForTerraform" {

    depends_on = [ azurerm_storage_account.AzureStorageAccountForTerraform ]

  name                              = "${var.TF-StorageAccountContainer-Name}"

  storage_account_name              = azurerm_storage_account.AzureStorageAccountForTerraform.name

  container_access_type             = "private"

}

 

Or you can use PowerShell to create the needed Storage Account:

# Get Azure Resource Group
$ResourceGroup = Get-AzResourceGroup -Name $RESOURCE_GROUP_NAME

# Create Azure Storage Account
$StorageAccount = New-AzStorageAccount -ResourceGroupName $ResourceGroup.Name -Name $TF_StorageAccount_Name -SkuName Standard_LRS -Location $ResourceGroup.Location -AllowBlobPublicAccess $false

# Create Azure Blob Container
New-AzStorageContainer -Name $TF_StorageAccountContainer_Name -Context $StorageAccount.context

# Retrieve Storage Container Access Key
$SC_Access_Key=(Get-AzStorageAccountKey -ResourceGroupName $ResourceGroup.Name -Name $StorageAccount.Name)[0].value

Now you can configure Terraform to use Remote State using a backend configuration:

terraform {

  required_providers {

    azurerm = {

      source  = "hashicorp/azurerm"

      version = "=>4.9"

    }

  }

 

  backend "azurerm" {

    resource_group_name  = "tmm_gerhard_westeurope"

    storage_account_name = "tmmgkstorageaccount"

    container_name       = "terraform"

    key                  = "terraform.tfstate"

    use_oidc             = true

    client_id            = "a99fxXxX-xXxX-xXxX-xXxX-xXxXxXxXxd2de"

    client_secret        = "xXxX-xXxX-xXxX-xXxX-xXxXxXxXx"

    subscription_id      = "893axXxX-xXxX-xXxX-xXxX-xXxXxXxXx2de793"

    tenant_id            = "db32xXxX-xXxX-xXxX-xXxX-xXxXxXxXx2de49f"

  }

 

}

 

provider "azurerm" {

  features {}

}

 

Caution:

You cannot use variables in the backend configuration part. You need to use define the settings in clear text, including all sensitive settings.
 

 

Important:

Azure Storage blobs are automatically locked before any operation writes State.
This prevents concurrent State operations.


All Data stored in an Azure blob is encrypted.
Terraform retrieves the State from the backend and stores it in local memory.
The Transport is usually encrypted, as accessing the Azure Storage Container enforces a TLS-capable connection.

 

Terraform initializes successfully using Remote State:

PS C:\_TERRAFORM\_BACKEND> terraform init
Initializing the backend...

Successfully configured the backend "azurerm"! Terraform will automatically
use this backend unless the backend configuration changes.
Initializing provider plugins...
- Finding hashicorp/azurerm versions matching ">= 4.6.0"...
- Finding citrix/citrix versions matching ">= 1.0.5"...
- Installing hashicorp/azurerm v4.10.0...
- Installed hashicorp/azurerm v4.10.0 (signed by HashiCorp)
- Installing citrix/citrix v1.0.7...
- Installed citrix/citrix v1.0.7 (self-signed, key ID BD4BD0E690CB7D88)
Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html
Terraform has created a lock file .terraform.lock.hcl to record the provider
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.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
PS C:\_TERRAFORM\_BACKEND>

You can see the .tfstate file in the Azure Storage Container:
azurestoragecontainer.png

You have successfully configured Terraform to use Remote State.
 

Importing an existing Infrastructure into Terraform

You can import an existing Infrastructure using a PowerShell script, which enables you to use all the benefits of Terraform.

The script works with Citrix DaaS- and Citrix CVAD-based environments.
The script collects the list of resources, imports them into Terraform, and generates the Terraform skeletons for the resources.

OnboardingAutomationWorkflow.png

Note:

The Onboarding script is still in Tech Preview.
You can download the actual version of the Onboarding script from our GitHub repository.

 

The needed Terraform configuration is straightforward:

terraform {

  required_version = ">= 1.9.7"

 

  required_providers {

    citrix = {

      source  = "citrix/citrix"

      version = "=1.0.7"

    }

  }

 

  backend "local" {}

}

We altered the script to insert all sensitive information directly into the script and do not need to store sensitive information in variables:

...

[CmdletBinding()]

Param (

    [Parameter(Mandatory = $false)]

    [string] $CustomerId = "dcxXxXxXxXx",

 

    [Parameter(Mandatory = $false)]

    [string] $ClientId = "4045xXxX-xXxX-xXxX-xXxX-xXxXxXxXxd2dea,

   

    [Parameter(Mandatory = $false)]

    [string] $ClientSecret ="xXxXxXxXxXxXxXxXx",

 

    [Parameter(Mandatory = $false)]

    [string] $DomainFqdn,

 

    [Parameter(Mandatory = $false)]

    [string] $Hostname = "api.cloud.com",

 

    [Parameter(Mandatory = $false)]

    [ValidateSet("Production", "Staging")]

    [string] $Environment = "Production",

 

    [Parameter(Mandatory = $false)]

    [switch] $SetDependencyRelationship,

 

    [Parameter(Mandatory = $false)]

    [switch] $DisableSSLValidation

)

...

Before running the script, the Terraform provider must be initialized.
Afterwards, you can start the script:

PS C:\_TERRAFORM\_ONBOARDING> .\terraform-onboarding-v3.ps1


    Directory: C:\_TERRAFORM\_ONBOARDING


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        11/12/2024  11:41 AM              0 citrix.tf
-a----        11/12/2024  11:41 AM              0 import.tf
-a----        11/12/2024  11:41 AM              0 resource.tf
Initializing the backend...
Initializing provider plugins...
- Reusing previous version of citrix/citrix from the dependency lock file
- Using previously-installed citrix/citrix v1.0.6

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
citrix_azure_hypervisor_resource_pool.azure_hypervisor_resource_pool_1_0: Importing from ID "903f991f-5eb1-45b7-b85a-8e6b35529a64,d10c0943-ec66-4435-982f-1ec88e6d83d9"...
citrix_azure_hypervisor_resource_pool.azure_hypervisor_resource_pool_1_0: Import prepared!
  Prepared citrix_azure_hypervisor_resource_pool for import
citrix_azure_hypervisor_resource_pool.azure_hypervisor_resource_pool_1_0: Refreshing state... [id=d10c0943-ec66-4435-982f-1ec88e6d83d9]

Import successful!

The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.

citrix_application_icon.application_icon_11: Importing from ID "3"...
citrix_application_icon.application_icon_11: Import prepared!
  Prepared citrix_application_icon for import
citrix_application_icon.application_icon_11: Refreshing state... [id=3]

Import successful!

...

The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.

citrix.tf
citrix_admin_role.tf
citrix_admin_scope.tf
citrix_application.tf
citrix_application_icon.tf
citrix_azure_hypervisor.tf
citrix_azure_hypervisor_resource_pool.tf
citrix_delivery_group.tf
citrix_machine_catalog.tf
citrix_policy_set.tf
citrix_vsphere_hypervisor.tf
citrix_vsphere_hypervisor_resource_pool.tf
citrix_zone.tf


PS C:\_TERRAFORM\_ONBOARDING>

After about 5 minutes, the script has successfully imported the environment.
You now have all entities transformed into Terraform files which can be viewed and edited e.g., in Visual Studio Code:

visualstudiocode-tf.png

You have successfully transformed your existing Infrastructure in Infrastructure-as-Code (IaC).
 

Checking an Infrastructure for changes after the initial deployment

You can leverage Terraform to check your infrastructure for alterations/changes that might not have been wanted or that accidentally happened.

Terraform will notify you about these changes and can revert them after asking for consent.
You need a connection to your Infrastructure and a valid State.

 

Example 1: Deactivation of AutoScale

In our sample Infrastructure, AutoScale is usually enabled for all Delivery Groups, but someone changed the AutoScale Settings of a Delivery Group. This is unwanted, as additional costs could arise if AutoScale is disabled.
Citrix WebStudio shows the deactivation of AutoScale:

dg-as-disabled.png

As it would be impracticable to check all essential settings using WebStudio, we leverage Terraform to scan our environment for changes:
You only need to run terraform plan in your Terraform directory, where your Terraform files are saved to scan for changes:

PS C:\_TERRAFORM\_CCOnAzureV2\CCOnAzureV2-DeployCCEntities> terraform plan
data.citrix_zone.GetTFAzureZoneID: Reading...
data.citrix_zone.GetTFAzureZoneID: Read complete after 0s [id=12f9de5d-fa7f-4739-aaa2-8338daabe878]
citrix_azure_hypervisor.CreateAzureHostingConnection: Refreshing state... [id=903f991f-5eb1-45b7-b85a-8e6b35529a64]
time_sleep.wait_30_seconds: Refreshing state... [id=2024-10-23T17:42:53Z]
citrix_azure_hypervisor_resource_pool.CreateAzureHostingConnectionPool: Refreshing state... [id=d10c0943-ec66-4435-982f-1ec88e6d83d9]
time_sleep.wait_30_seconds1: Refreshing state... [id=2024-10-23T17:44:59Z]
citrix_machine_catalog.CreateAzureImgDefMCSCatalog: Refreshing state... [id=c7364b7a-c045-41cc-af81-7a3da2c5d84f]
data.azurerm_shared_image_gallery.GetAzureSIG: Reading...
data.azurerm_shared_image_gallery.GetAzureSIG: Read complete after 0s [id=/subscriptions/893a4812-27ad-4135-a95a-6e1d6e0bd793/resourceGroups/tmm_gerhard_westeurope/providers/Microsoft.Compute/galleries/TMM_GK_TF_SIG]
data.azurerm_shared_image.GetAzureSIGDefinition: Reading...
data.azurerm_shared_image.GetAzureSIGDefinition: Read complete after 0s [id=/subscriptions/893a4812-27ad-4135-a95a-6e1d6e0bd793/resourceGroups/tmm_gerhard_westeurope/providers/Microsoft.Compute/galleries/TMM_GK_TF_SIG/images/TMM-GK-CC-W11-SS]
data.azurerm_shared_image_version.GetAzureSIGDefinitionVersion: Reading...
data.azurerm_shared_image_version.GetAzureSIGDefinitionVersion: Read complete after 0s [id=/subscriptions/893a4812-27ad-4135-a95a-6e1d6e0bd793/resourceGroups/tmm_gerhard_westeurope/providers/Microsoft.Compute/galleries/TMM_GK_TF_SIG/images/TMM-GK-CC-W11-SS/versions/1.0.0]
citrix_machine_catalog.CreateAzureMCSCatalog: Refreshing state... [id=50f78ac2-906f-490f-b25f-2bb921df7041]
time_sleep.wait_30_seconds_2: Refreshing state... [id=2024-10-23T18:24:28Z]
citrix_delivery_group.CreateDG: Refreshing state... [id=3dee598d-3a66-4a43-b3ce-1d989e75a3c4]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # citrix_delivery_group.CreateDG will be updated in-place
  ~ resource "citrix_delivery_group" "CreateDG" {
      ~ autoscale_settings          = {
          ~ autoscale_enabled                                     = false -> true
            # (22 unchanged attributes hidden)
        }
        id                          = "3dee598d-3a66-4a43-b3ce-1d989e75a3c4"
      ~ inherited_scopes            = [] -> (known after apply)
        name                        = "DG-TMM-GK-TF-Azure"
      + tenants                     = (known after apply)
      ~ total_machines              = 1 -> (known after apply)
        # (10 unchanged attributes hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

PS C:\_TERRAFORM\_CCOnAzureV2\CCOnAzureV2-DeployCCEntities>

Terraform found the change and notifies accordingly:

  # citrix_delivery_group.CreateDG will be updated in-place
  ~ resource "citrix_delivery_group" "CreateDG" {
      ~ autoscale_settings          = {
          ~ autoscale_enabled                                     = false -> true
 

If you now run terraform apply, these changes will be remitted, and your infrastructure will match the initial State again:

Caution:

Terraform will ask for your confirmation before remitting.
Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

Be aware that the remittance can severely affect the currently running infrastructure, as the changes will take effect immediately.

 

 

PS C:\_TERRAFORM\_CCOnAzureV2\CCOnAzureV2-DeployCCEntities> terraform apply
data.citrix_zone.GetTFAzureZoneID: Reading...
data.citrix_zone.GetTFAzureZoneID: Read complete after 0s [id=12f9de5d-fa7f-4739-aaa2-8338daabe878]
...
citrix_delivery_group.CreateDG: Refreshing state... [id=3dee598d-3a66-4a43-b3ce-1d989e75a3c4]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # citrix_delivery_group.CreateDG will be updated in-place
  ~ resource "citrix_delivery_group" "CreateDG" {
      ~ autoscale_settings          = {
          ~ autoscale_enabled                                     = false -> true
            # (22 unchanged attributes hidden)
        }
        id                          = "3dee598d-3a66-4a43-b3ce-1d989e75a3c4"
      ~ inherited_scopes            = [] -> (known after apply)
        name                        = "DG-TMM-GK-TF-Azure"
      + tenants                     = (known after apply)
      ~ total_machines              = 1 -> (known after apply)
        # (10 unchanged attributes hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

citrix_delivery_group.CreateDG: Modifying... [id=3dee598d-3a66-4a43-b3ce-1d989e75a3c4]
citrix_delivery_group.CreateDG: Modifications complete after 9s [id=3dee598d-3a66-4a43-b3ce-1d989e75a3c4]

Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
PS C:\_TERRAFORM\_CCOnAzureV2\CCOnAzureV2-DeployCCEntities>

Terraform has successfully remitted the change to the original State.
Running terraform plan shows that the Infrastructure matches the original State again:

PS C:\_TERRAFORM\_CCOnAzureV2\CCOnAzureV2-DeployCCEntities> terraform plan
data.citrix_zone.GetTFAzureZoneID: Reading...
data.citrix_zone.GetTFAzureZoneID: Read complete after 0s [id=12f9de5d-fa7f-4739-aaa2-8338daabe878]

...

citrix_delivery_group.CreateDG: Refreshing state... [id=3dee598d-3a66-4a43-b3ce-1d989e75a3c4]

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
PS C:\_TERRAFORM\_CCOnAzureV2\CCOnAzureV2-DeployCCEntities>

Citrix WebStudio also reflects the re-enablement of AutoScale:
dg-as-enabled.png
 

Example 2: Policy Changes

Another important aspect of keeping an Infrastructure in a desired state are the Policies.
Changes in Policies can have various negative consequences. In this example, IT does not want Native Printer Drivers installed. You can leverage Terraform to detect these changes as well: 

PS C:\_TERRAFORM\_CCOnAzureV2\CCOnAzureV2-CreatePoliciesAndScopes> terraform plan
data.citrix_admin_scope.GetDefaultMonitorScope: Reading...
data.citrix_delivery_group.GetDeliveryGroup: Reading...
...

citrix_policy_set.CreatePolicyExampleSet: Refreshing state... [id=3658867a-c55a-4a76-996a-03be1c0560a2]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # citrix_policy_set.CreatePolicyExampleSet will be updated in-place
  ~ resource "citrix_policy_set" "CreatePolicyExampleSet" {
      ~ assigned    = true -> (known after apply)
        id          = "3658867a-c55a-4a76-996a-03be1c0560a2"
        name        = "PolSet-TF-GK-Default"
      ~ policies    = [
          ~ {
              + access_control_filters      = (known after apply)
              + client_ip_filters           = (known after apply)
              + client_name_filters         = (known after apply)
              + delivery_group_type_filters = (known after apply)
                id                          = "dd887432-9b66-489d-a7a2-ea96d979c4f6"
                name                        = "Printing"
              + ou_filters                  = (known after apply)
              ~ policy_settings             = [
                  - {
                      - name        = "UniversalPrintDriverUsage" -> null
                      - use_default = false -> null
                      - value       = "SpecificOnly" -> null
                    },
                  + {
                      + name        = "UniversalPrintDriverUsage"
                      + use_default = false
                      + value       = "FallbackToSpecific"
                    },
                    # (1 unchanged element hidden)
                ]
              + tag_filters                 = (known after apply)
                # (4 unchanged attributes hidden)
            },
          ~ {
              + access_control_filters      = (known after apply)
              + client_name_filters         = (known after apply)
              + delivery_group_type_filters = (known after apply)
                id                          = "5243115e-fb99-42e2-9139-31c83dd03bca"
                name                        = "HDX Graphics"
              + ou_filters                  = (known after apply)
              + tag_filters                 = (known after apply)
                # (6 unchanged attributes hidden)
            },
          ~ {
              + access_control_filters      = (known after apply)
              + client_name_filters         = (known after apply)
              + delivery_group_type_filters = (known after apply)
                id                          = "723dc9c9-e3d4-414c-a65b-0137ae0face9"
                name                        = "Client Drives"
              + ou_filters                  = (known after apply)
              + tag_filters                 = (known after apply)
                # (6 unchanged attributes hidden)
            },
        ]
        # (3 unchanged attributes hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────


PS C:\_TERRAFORM\_CCOnAzureV2\CCOnAzureV2-CreatePoliciesAndScopes>

You can now run terraform apply, to remit these changes, and your infrastructure matches the initial State again:

PS C:\_TERRAFORM\_CCOnAzureV2\CCOnAzureV2-CreatePoliciesAndScopes> terraform apply
citrix_admin_scope.CreateMonitorScopeExample: Refreshing state... [id=74d03cc1-1fd1-430d-90b0-fe2a1c8f8d52]
...

citrix_policy_set.CreatePolicyExampleSet: Refreshing state... [id=3658867a-c55a-4a76-996a-03be1c0560a2]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # citrix_policy_set.CreatePolicyExampleSet will be updated in-place
  ~ resource "citrix_policy_set" "CreatePolicyExampleSet" {
      ~ assigned    = true -> (known after apply)
        id          = "3658867a-c55a-4a76-996a-03be1c0560a2"
        name        = "PolSet-TF-GK-Default"
      ~ policies    = [
          ~ {
              + access_control_filters      = (known after apply)
              + client_ip_filters           = (known after apply)
              + client_name_filters         = (known after apply)
              + delivery_group_type_filters = (known after apply)
                id                          = "dd887432-9b66-489d-a7a2-ea96d979c4f6"
                name                        = "Printing"
              + ou_filters                  = (known after apply)
              ~ policy_settings             = [
                  - {
                      - name        = "UniversalPrintDriverUsage" -> null
                      - use_default = false -> null
                      - value       = "SpecificOnly" -> null
                    },
                  + {
                      + name        = "UniversalPrintDriverUsage"
                      + use_default = false
                      + value       = "FallbackToSpecific"
                    },
                    # (1 unchanged element hidden)
                ]
              + tag_filters                 = (known after apply)
                # (4 unchanged attributes hidden)
            },
          ~ {
              + access_control_filters      = (known after apply)
              + client_name_filters         = (known after apply)
              + delivery_group_type_filters = (known after apply)
                id                          = "5243115e-fb99-42e2-9139-31c83dd03bca"
                name                        = "HDX Graphics"
              + ou_filters                  = (known after apply)
              + tag_filters                 = (known after apply)
                # (6 unchanged attributes hidden)
            },
          ~ {
              + access_control_filters      = (known after apply)
              + client_name_filters         = (known after apply)
              + delivery_group_type_filters = (known after apply)
                id                          = "723dc9c9-e3d4-414c-a65b-0137ae0face9"
                name                        = "Client Drives"
              + ou_filters                  = (known after apply)
              + tag_filters                 = (known after apply)
                # (6 unchanged attributes hidden)
            },
        ]
        # (3 unchanged attributes hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

citrix_policy_set.CreatePolicyExampleSet: Modifying... [id=3658867a-c55a-4a76-996a-03be1c0560a2]
citrix_policy_set.CreatePolicyExampleSet: Still modifying... [id=3658867a-c55a-4a76-996a-03be1c0560a2, 10s elapsed]
citrix_policy_set.CreatePolicyExampleSet: Still modifying... [id=3658867a-c55a-4a76-996a-03be1c0560a2, 20s elapsed]
citrix_policy_set.CreatePolicyExampleSet: Still modifying... [id=3658867a-c55a-4a76-996a-03be1c0560a2, 30s elapsed]
citrix_policy_set.CreatePolicyExampleSet: Modifications complete after 37s [id=3658867a-c55a-4a76-996a-03be1c0560a2]

Apply complete! Resources: 0 added, 1 changed, 0 destroyed.

PS C:\_TERRAFORM\_CCOnAzureV2\CCOnAzureV2-CreatePoliciesAndScopes>

Terraform has successfully remitted the change to the original State.
Running terraform plan shows that the Infrastructure matches the original State again:

PS C:\_TERRAFORM\_CCOnAzureV2\CCOnAzureV2-CreatePoliciesAndScopes> terraform plan
citrix_admin_scope.CreateMonitorScopeExample: Refreshing state... [id=74d03cc1-1fd1-430d-90b0-fe2a1c8f8d52]...
citrix_policy_set.CreatePolicyExampleSet: Refreshing state... [id=3658867a-c55a-4a76-996a-03be1c0560a2]


No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
PS C:\_TERRAFORM\_CCOnAzureV2\CCOnAzureV2-CreatePoliciesAndScopes>

 

Example 3: Automating the Checks using the Config Drift Notification Script

Automating the check for Infrastructure changes might be helpful so you do not need to run terraform plan manually. There are various ways to do this, so use your preferred method according to your needs.

Note:

You can automate this process using our Provider Config Drift Notification script on GitHub.
 

The output of the Config Drift Notification script shows the changes:


PS C:\_TERRAFORM\_CCOnAzureV2\CCOnAzureV2-DeployCCEntities> .\config-drift.ps1
Terraform Config Drift Detected:
 ---------------------------------------------------------------------------------------------------

  # citrix_delivery_group.CreateDG has changed
  ~ resource "citrix_delivery_group" "CreateDG" {
      ~ autoscale_settings          = {
          ~ autoscale_enabled                                     = true -> false
            # (22 unchanged attributes hidden)
        }
        id                          = "3dee598d-3a66-4a43-b3ce-1d989e75a3c4"
        name                        = "DG-TMM-GK-TF-Azure"
        # (12 unchanged attributes hidden)
    }


PS C:\_TERRAFORM\_CCOnAzureV2\CCOnAzureV2-DeployCCEntities>

You can hook onto the output and take further steps, as we will show in the new script shortly.
 

Example 4: Using PowerShell to get Details about Changes

After creating a repetitive task to check for Infrastructure changes, getting more details about the changes would make sense.
We assume you run a daily task to check for changes.

Note:

If you have configured Configuration Logging, you could get more insights about an unwanted change. Check the Configuration Logging events in Citrix WebStudio for details or use PowerShell or REST-API calls to retrieve them.
 

You must install the Citrix Remote PowerShell SDK to retrieve the Configuration Logging events.

Add-PSSnapin Citrix.*
$Date = Get-Date -Format "yyyy-MM-dd"
$OutDirFull = "C:\_TEMP\ConfigDrift\" + $Date
$StartRange = $Date + " 00:00"
$EndRange = $Date + " 23:59"
Set-XDCredentials -StoreAs TACG -ProfileType CloudApi -CustomerId xXxXxXxXxXxXx -APIKey yYyYyYyYyYyYyYy -SecretKey zZzZzZzZzZzZzZz
Get-XDAuthentication -ProfileName TACG
New-Item -Path $OutDirFull -ItemType "directory" -Force
Export-LogReportHtml -OutputDirectory $OutDirFull -StartDateRange $StartRange -EndDateRange $EndRange

The HTML-based reports contain all changes to your Infrastructure on the particular day (example):

18.11.2024 10:30:41

tmm-xxxxx@az.the-austrian-citrix-guy.at

Edit Delivery Group 'DG-TMM-GK-AZ-W11-SS'

Erfolgreich

172.29.77.84

Details

18.11.2024 10:45:35

tmm-xxxxx@az.the-austrian-citrix-guy.at

Edit Delivery Group 'DG-TMM-GK-TF-Azure'

Erfolgreich

172.29.77.84

Details

18.11.2024 11:08:20

tmm-xxxxx@az.the-austrian-citrix-guy.at

Edit Delivery Group 'DG-TMM-GK-TF-Azure'

Erfolgreich

172.29.77.84

Details

18.11.2024 11:10:02

tmm-xxxxx@az.the-austrian-citrix-guy.at

Edit Delivery Group 'DG-TMM-GK-TF-Azure'

Erfolgreich

172.29.77.84

Details

18.11.2024 11:31:39

tmm-xxxxx@az.the-austrian-citrix-guy.at

Edit Delivery Group 'DG-TMM-GK-TF-Azure'

Erfolgreich

172.29.77.84

Details

18.11.2024 11:33:35

tmm-xxxxx@az.the-austrian-citrix-guy.at

Edit Delivery Group 'DG-TMM-GK-TF-Azure'

Erfolgreich

172.29.77.84

Details

18.11.2024 11:33:36

tmm-xxxxx@az.the-austrian-citrix-guy.at

Edit 'TMM-GK-TF-RebootSchedule'

Erfolgreich

172.29.77.84

Details

18.11.2024 11:38:37

tmm-xxxxx@az.the-austrian-citrix-guy.at

Edit Delivery Group 'DG-TMM-GK-TF-Azure'

Erfolgreich

172.29.77.84

Details

18.11.2024 11:38:37

tmm-xxxxx@az.the-austrian-citrix-guy.at

Remove Power Time Scheme 'DG-TMM-GK-TF-Azure_AS-TMM-GK-TF-Azure-Weekday'

Erfolgreich

172.29.77.84

Details

18.11.2024 11:38:37

tmm-xxxxx@az.the-austrian-citrix-guy.at

Create Power Time Scheme 'DG-TMM-GK-TF-Azure_AS-TMM-GK-TF-Azure-Weekday'

Erfolgreich

172.29.77.84

Details

18.11.2024 11:38:38

tmm-xxxxx@az.the-austrian-citrix-guy.at

Remove 'TMM-GK-TF-RebootSchedule'

Erfolgreich

172.29.77.84

Details

18.11.2024 11:38:38

tmm-xxxxx@az.the-austrian-citrix-guy.at

Create 'TMM-GK-TF-RebootSchedule'

Erfolgreich

172.29.77.84

Details

18.11.2024 11:38:56

tmm-xxxxx@az.the-austrian-citrix-guy.at

Edit Delivery Group 'DG-TMM-GK-TF-Azure'

Erfolgreich

172.29.77.84

Details

18.11.2024 11:39:29

tmm-xxxxx@az.the-austrian-citrix-guy.at

Edit Delivery Group 'DG-TMM-GK-TF-Azure'

Erfolgreich

172.29.77.84

Details

18.11.2024 11:39:29

tmm-xxxxx@az.the-austrian-citrix-guy.at

Remove Power Time Scheme 'DG-TMM-GK-TF-Azure_AS-TMM-GK-TF-Azure-Weekday'

Erfolgreich

172.29.77.84

Details

18.11.2024 11:39:29

tmm-xxxxx@az.the-austrian-citrix-guy.at

Create Power Time Scheme 'DG-TMM-GK-TF-Azure_AS-TMM-GK-TF-Azure-Weekday'

Erfolgreich

172.29.77.84

Details

18.11.2024 11:39:30

tmm-xxxxx@az.the-austrian-citrix-guy.at

Remove 'TMM-GK-TF-RebootSchedule'

Erfolgreich

172.29.77.84

Details

18.11.2024 11:39:30

tmm-xxxxx@az.the-austrian-citrix-guy.at

Create 'TMM-GK-TF-RebootSchedule'

Erfolgreich

172.29.77.84

Details

18.11.2024 11:53:45

tmm-xxxxx@az.the-austrian-citrix-guy.at

Edit Delivery Group 'DG-TMM-GK-TF-Azure'

Erfolgreich

172.29.77.84

Details

18.11.2024 11:54:16

tmm-xxxxx@az.the-austrian-citrix-guy.at

Edit Delivery Group 'DG-TMM-GK-TF-Azure'

Erfolgreich

172.29.77.84

Details

18.11.2024 12:05:46

tmm-xxxxx@az.the-austrian-citrix-guy.at

Edit Delivery Group 'DG-TMM-GK-TF-Azure'

Erfolgreich

172.29.77.84

Details

You can now align the events in the report with the changes detected by Terraform to get more information.
 

Example 5: Using Azure Automation to periodically check for Changes and Receiving Notifications

The most convenient and recommended way is to automate the checks and the remediation using a script and, in this case, Azure Automation.
We are currently combining all functionalities of the 3 previously mentioned examples in one new script, which will run on Azure Automation.
We will update this section as soon as all tests are completed. Stay tuned.

 

Altering an Infrastructure after the Initial Deployment

You can leverage Terraform to check your Infrastructure for alterations/changes that might not be wanted or accidentally happened and alter it as new needs arise programmatically.
You can alter any Terraform-supporting entity in all layers: the Compute Layer, the Resource Layer, the Control Layer, the Access Layer, and the User Layer.
Therefore, you can leverage different providers in the same code – like this example from a current project:
multipleproviders.png

  

Example 1: User Layer: Reconfiguring the Citrix Workspace App/Enterprise Browser

In this example, we will reconfigure the Citrix Workspace App by altering the settings used by the Citrix Global App Configuration service. You can access the current settings using Citrix WebStudio:
workspace-1.png

If you click Configure, you can choose the Endpoint app – Citrix Workspace App or Citrix Enterprise Browser. All corresponding settings of the respective application can be shown by clicking on View configured changes:
workspace-2.png

Leverage Terraform to alter the settings – for example, showing the Connection Center option in the Advance Preferences of the Workspace App – this setting is currently set to hide it:

# Configuring Citrix Cloud Global App Configuration Service

## Create Settings

resource "citrix_gac_settings" "SetWorkspaceAppConfiguration" {

    service_url = "${var.GACS-ServiceURL}"

    name        = "${var.GACS-Settings-Name}"

    description = "${var.GACS-Settings-Description}"

 

    app_settings = {

        windows = [

            {

                user_override = false,

                category = "Root",

                settings = [

                    {

                        name = "Hide advanced preferences",

                        value_string = "true"

                    },

                   {

                        name = "Hide connection center",

                        value_string = "true"

                    }  

                ]

            },

...

To change this setting, comment the corresponding code segment and apply the Terraform code using terraform apply.

# Configuring Citrix Cloud Global App Configuration Service

## Create Settings

resource "citrix_gac_settings" "SetWorkspaceAppConfiguration" {

    service_url = "${var.GACS-ServiceURL}"

    name        = "${var.GACS-Settings-Name}"

    description = "${var.GACS-Settings-Description}"

 

    app_settings = {

        windows = [

            {

                user_override = false,

                category = "Root",

                settings = [

                    {

                        name = "Hide advanced preferences",

                        value_string = "true"

                    },

                  /*  {

                        name = "Hide connection center",

                        value_string = "true"

                    }    */

                ]

Terraform changes the setting as intended:

PS C:\_TERRAFORM\_TMM-CC-GACS> terraform apply
citrix_gac_settings.test_settings_configuration: Refreshing state... [name=GACS-TMM-GK-TF-Settings]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # citrix_gac_settings.test_settings_configuration will be updated in-place
  ~ resource "citrix_gac_settings" "test_settings_configuration" {
      ~ app_settings       = {
          ~ windows = [
              -               - {
                  - category      = "root" -> null
                  - settings      = [
                      - {
                          - name         = "hide advanced preferences" -> null
                          - value_string = "true" -> null
                        },
                      - {
                          - name         = "hide connection center" -> null
                          - value_string = "true" -> null
                        },
                    ] -> null
                  - user_override = false -> null
                },
              + {
                  + category      = "Root"
                  + settings      = [
                      + {
                          + name         = "Hide advanced preferences"
                          + value_string = "true"
                        },
                    ]
                  + user_override = false
                },
                # (1 unchanged element hidden)
            ]
            # (2 unchanged attributes hidden)
        }
        name               = "GACS-TMM-GK-TF-Settings"
        # (3 unchanged attributes hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

 
Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

citrix_gac_settings.test_settings_configuration: Modifying... [name=GACS-TMM-GK-TF-Settings]
citrix_gac_settings.test_settings_configuration: Modifications complete after 4s [name=GACS-TMM-GK-TF-Settings]

 
Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
PS C:\_TERRAFORM\_TMM-CC-GACS>

The settings in WebStudio reflect the change:
workspace-3.png

The changed configuration item is no longer shown. Terraform has successfully changed a Workspace App setting.
 

Example 2: Platform Layer: Updating the Azure Machine Types

In this example, we will update the Machine Types of the Cloud Connector Machines.
cc1.png

We have defined the Machine Type in a Terraform Variable:

...
   "TACG-TMM-CCX-VM-Size":"Standard_D2s_v5",

...

We change this variable´s value to a new value:

...
   "TACG-TMM-CCX-VM-Size":"Standard_D4s_v5",

...

terraform plan shows that it can update the VMs in place and change the size from Standard_D2s_v5 to Standard_D4s_v5 – nothing will be destroyed or re-created:

PS C:\_TERRAFORM\_CCOnAzureV2\CCOnAzureV2-ChangeVMSize> terraform plan
data.azurerm_virtual_network.TACG-TMM-VNet: Reading...
data.azurerm_network_security_group.TACG-TMM-NSG: Reading...
data.azurerm_network_interface.TACG-TMM-TF-CC1-NIC: Reading...
data.azurerm_network_interface.TACG-TMM-TF-CC2-NIC: Reading...
data.azurerm_network_interface.TACG-TMM-TF-CC1-NIC: Read complete after 0s [id=/subscriptions/893a4812-27ad-4135-a95a-6e1d6e0bd793/resourceGroups/tmm_gerhard_westeurope/providers/Microsoft.Network/networkInterfaces/TACG-TMM-TF-CC1-NIC]
data.azurerm_network_security_group.TACG-TMM-NSG: Read complete after 0s [id=/subscriptions/893a4812-27ad-4135-a95a-6e1d6e0bd793/resourceGroups/tmm_gerhard_westeurope/providers/Microsoft.Network/networkSecurityGroups/TMM-GK-CC1-nsg]
data.azurerm_network_interface.TACG-TMM-TF-CC2-NIC: Read complete after 0s [id=/subscriptions/893a4812-27ad-4135-a95a-6e1d6e0bd793/resourceGroups/tmm_gerhard_westeurope/providers/Microsoft.Network/networkInterfaces/TACG-TMM-TF-CC2-NIC]
azurerm_windows_virtual_machine.TACG-TMM-CC1: Refreshing state... [id=/subscriptions/893a4812-27ad-4135-a95a-6e1d6e0bd793/resourceGroups/tmm_gerhard_westeurope/providers/Microsoft.Compute/virtualMachines/TACG-TMM-TF-CC1]
azurerm_windows_virtual_machine.TACG-TMM-CC2: Refreshing state... [id=/subscriptions/893a4812-27ad-4135-a95a-6e1d6e0bd793/resourceGroups/tmm_gerhard_westeurope/providers/Microsoft.Compute/virtualMachines/TACG-TMM-TF-CC2]
data.azurerm_virtual_network.TACG-TMM-VNet: Read complete after 0s [id=/subscriptions/893a4812-27ad-4135-a95a-6e1d6e0bd793/resourceGroups/tmm_gerhard_westeurope/providers/Microsoft.Network/virtualNetworks/TMM-GK-WestEurope]
data.azurerm_subnet.TACG-TMM-Subnet: Reading...
data.azurerm_subnet.TACG-TMM-Subnet: Read complete after 0s [id=/subscriptions/893a4812-27ad-4135-a95a-6e1d6e0bd793/resourceGroups/tmm_gerhard_westeurope/providers/Microsoft.Network/virtualNetworks/TMM-GK-WestEurope/subnets/default]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # azurerm_windows_virtual_machine.TACG-TMM-CC1 will be updated in-place
  ~ resource "azurerm_windows_virtual_machine" "TACG-TMM-CC1" {
        id                                                     = "/subscriptions/893a4812-27ad-4135-a95a-6e1d6e0bd793/resourceGroups/tmm_gerhard_westeurope/providers/Microsoft.Compute/virtualMachines/TACG-TMM-TF-CC1"
        name                                                   = "TACG-TMM-TF-CC1"
      ~ size                                                   = "Standard_D2s_v5" -> "Standard_D4s_v5"
        tags                                                   = {
            "Environment" = "TMM-Gerhard"
        }
        # (41 unchanged attributes hidden)

        # (2 unchanged blocks hidden)
    }

  # azurerm_windows_virtual_machine.TACG-TMM-CC2 will be updated in-place
  ~ resource "azurerm_windows_virtual_machine" "TACG-TMM-CC2" {
        id                                                     = "/subscriptions/893a4812-27ad-4135-a95a-6e1d6e0bd793/resourceGroups/tmm_gerhard_westeurope/providers/Microsoft.Compute/virtualMachines/TACG-TMM-TF-CC2"
        name                                                   = "TACG-TMM-TF-CC2"
      ~ size                                                   = "Standard_D2s_v5" -> "Standard_D4s_v5"
        tags                                                   = {
            "Environment" = "TMM-Gerhard"
        }
        # (41 unchanged attributes hidden)

        # (2 unchanged blocks hidden)
    }

Plan: 0 to add, 2 to change, 0 to destroy.

──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

PS C:\_TERRAFORM\_CCOnAzureV2\CCOnAzureV2-ChangeVMSize>

terraform apply will change the VM size in-place:

 

Terraform will perform the following actions:

  # azurerm_windows_virtual_machine.TACG-TMM-CC1 will be updated in-place
  ~ resource "azurerm_windows_virtual_machine" "TACG-TMM-CC1" {
        id                                                     = "/subscriptions/893a4812-27ad-4135-a95a-6e1d6e0bd793/resourceGroups/tmm_gerhard_westeurope/providers/Microsoft.Compute/virtualMachines/TACG-TMM-TF-CC1"
        name                                                   = "TACG-TMM-TF-CC1"
      ~ size                                                   = "Standard_D2s_v5" -> "Standard_D4s_v5"
        tags                                                   = {
            "Environment" = "TMM-Gerhard"
        }
        # (41 unchanged attributes hidden)

        # (2 unchanged blocks hidden)
    }

  # azurerm_windows_virtual_machine.TACG-TMM-CC2 will be updated in-place
  ~ resource "azurerm_windows_virtual_machine" "TACG-TMM-CC2" {
        id                                                     = "/subscriptions/893a4812-27ad-4135-a95a-6e1d6e0bd793/resourceGroups/tmm_gerhard_westeurope/providers/Microsoft.Compute/virtualMachines/TACG-TMM-TF-CC2"
        name                                                   = "TACG-TMM-TF-CC2"
      ~ size                                                   = "Standard_D2s_v5" -> "Standard_D4s_v5"
        tags                                                   = {
            "Environment" = "TMM-Gerhard"
        }
        # (41 unchanged attributes hidden)

        # (2 unchanged blocks hidden)
    }

Plan: 0 to add, 2 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

azurerm_windows_virtual_machine.TACG-TMM-CC2: Modifying... [id=/subscriptions/893a4812-27ad-4135-a95a-6e1d6e0bd793/resourceGroups/tmm_gerhard_westeurope/providers/Microsoft.Compute/virtualMachines/TACG-TMM-TF-CC2]
azurerm_windows_virtual_machine.TACG-TMM-CC1: Modifying... [id=/subscriptions/893a4812-27ad-4135-a95a-6e1d6e0bd793/resourceGroups/tmm_gerhard_westeurope/providers/Microsoft.Compute/virtualMachines/TACG-TMM-TF-CC1]
azurerm_windows_virtual_machine.TACG-TMM-CC1: Still modifying... [id=/subscriptions/893a4812-27ad-4135-a95a-...ompute/virtualMachines/TACG-TMM-TF-CC1, 10s elapsed]
azurerm_windows_virtual_machine.TACG-TMM-CC2: Still modifying... [id=/subscriptions/893a4812-27ad-4135-a95a-...ompute/virtualMachines/TACG-TMM-TF-CC2, 10s elapsed]
azurerm_windows_virtual_machine.TACG-TMM-CC1: Modifications complete after 12s [id=/subscriptions/893a4812-27ad-4135-a95a-6e1d6e0bd793/resourceGroups/tmm_gerhard_westeurope/providers/Microsoft.Compute/virtualMachines/TACG-TMM-TF-CC1]
azurerm_windows_virtual_machine.TACG-TMM-CC2: Modifications complete after 12s [id=/subscriptions/893a4812-27ad-4135-a95a-6e1d6e0bd793/resourceGroups/tmm_gerhard_westeurope/providers/Microsoft.Compute/virtualMachines/TACG-TMM-TF-CC2]

Apply complete! Resources: 0 added, 2 changed, 0 destroyed.

PS C:\_TERRAFORM\_CCOnAzureV2\CCOnAzureV2-ChangeVMSize>

Terraform has successfully changed the VM size.
cc1ch.png
 

Example 3: Resource Layer: Updating a Machine Catalog – Deploy a New Master Image Version

In this example, we will update a Machine Catalog and deploy a new Master Image version.
You can access the current settings using Citrix WebStudio:
mcv1.png

The current Master Image version is W11-BaseImageDefinition-1-baseDisk-3w0te.
This is also reflected in the initially deployed Terraform code:

#### Creating the Machine Catalog based on Image Definitions and Image Versions

resource "citrix_machine_catalog" "CreateAzureImgDefMCSCatalog" {

  depends_on            = [ time_sleep.wait_30_seconds1 ]

    name                        = "${var.CC-Azure-MCImgDef-Name}"

    description                 = "${var.CC-Azure-MCImgDef-Description}"

    allocation_type             = "${var.CC-Azure-MCImgDef-AllocationType}"

    session_support             = "${var.CC-Azure-MCImgDef-SessionType}"

    provisioning_type           = "MCS"

    #zone                = data.local_file.LoadZoneID.content

    zone                = data.citrix_zone.GetTFAzureZoneID.id

    provisioning_scheme         =   {

        hypervisor               = citrix_azure_hypervisor.CreateAzureHostingConnection.id

        hypervisor_resource_pool = citrix_azure_hypervisor_resource_pool.CreateAzureHostingConnectionPool.id

        identity_type            = "${var.CC-Azure-MCImgDef-IDPType}"

 

        machine_domain_identity  = {

            domain                   = "${var.CC-Azure-MCImgDef-Domain}"

            domain_ou                = "${var.CC-Azure-MCImgDef-DomainOU}"

            service_account          = "${var.CC-Azure-MCImgDef-DomainAdmin-Username-UPN}"

            service_account_password = "${var.CC-Azure-MCImgDef-DomainAdmin-Password}"

        }

 

        azure_machine_config = {

            storage_type             = "Standard_LRS"

            use_managed_disks        = true

            service_offering         = "${var.CC-Azure-MCImgDef-VMSize}"

 

            azure_master_image = {

                resource_group       = "${var.CC-Azure-MCImgDef-MasterImage-RG}"

                master_image         = "${var.CC-Azure-MCImgDef-MasterImage}"

                #master_image         = "${var.CC-Azure-MCImgDef-MasterImage-V3}"

            }

 

            machine_profile = {

              machine_profile_resource_group = "${var.TACG-TMM-ResourceGroup-Name}"

              machine_profile_vm_name        = "${var.CC-Azure-MCImgDef-VMProfileName}"

            }

 

        }

 

       number_of_total_machines                =  1

     

       machine_account_creation_rules          = {

            naming_scheme      = "${var.CC-Azure-MCImgDef-NamingScheme-Name}"

            naming_scheme_type = "${var.CC-Azure-MCImgDef-NamingScheme-Type}"

        }

    }

}

The Terraform code references to a variable which holds the current Master Image name:

master_image         = "${var.CC-Azure-MCImgDef-MasterImage}"

This variable´s value is:

...

"CC-Azure-MCImgDef-MasterImage":"W11-BaseImageDefinition-1-baseDisk-3w0te",

...

We now change the Terraform code to use a new Master Image version:

azure_master_image = {

                resource_group       = "${var.CC-Azure-MCImgDef-MasterImage-RG}"

                master_image         = "${var.CC-Azure-MCImgDef-MasterImage}"

                #master_image         = "${var.CC-Azure-MCImgDef-MasterImage-V3}"

            }

to 

azure_master_image = {

                resource_group       = "${var.CC-Azure-MCImgDef-MasterImage-RG}"

                #master_image         = "${var.CC-Azure-MCImgDef-MasterImage}"

                master_image         = "${var.CC-Azure-MCImgDef-MasterImage-V3}"

            }

The new variable´s value is:

...

"CC-Azure-MCImgDef-MasterImage-V3":" W11-BaseImageDefinition-3-baseDisk-my3dm",

...

Running terraform apply will change the Machine Catalog and apply the new Image version:

PS C:\_TERRAFORM\_CCOnAzureV2\CCOnAzureV2-DeployCCEntities> terraform apply
data.citrix_zone.GetTFAzureZoneID: Reading...
data.citrix_zone.GetTFAzureZoneID: Read complete after 0s [id=12f9de5d-fa7f-4739-aaa2-8338daabe878]
citrix_azure_hypervisor.CreateAzureHostingConnection: Refreshing state... [id=903f991f-5eb1-45b7-b85a-8e6b35529a64]
time_sleep.wait_30_seconds: Refreshing state... [id=2024-10-23T17:42:53Z]
citrix_azure_hypervisor_resource_pool.CreateAzureHostingConnectionPool: Refreshing state... [id=d10c0943-ec66-4435-982f-1ec88e6d83d9]
time_sleep.wait_30_seconds1: Refreshing state... [id=2024-10-23T17:44:59Z]
citrix_machine_catalog.CreateAzureImgDefMCSCatalog: Refreshing state... [id=c7364b7a-c045-41cc-af81-7a3da2c5d84f]
data.azurerm_shared_image_gallery.GetAzureSIG: Reading...
data.azurerm_shared_image_gallery.GetAzureSIG: Read complete after 1s [id=/subscriptions/893a4812-27ad-4135-a95a-6e1d6e0bd793/resourceGroups/tmm_gerhard_westeurope/providers/Microsoft.Compute/galleries/TMM_GK_TF_SIG]
data.azurerm_shared_image.GetAzureSIGDefinition: Reading...
data.azurerm_shared_image.GetAzureSIGDefinition: Read complete after 0s [id=/subscriptions/893a4812-27ad-4135-a95a-6e1d6e0bd793/resourceGroups/tmm_gerhard_westeurope/providers/Microsoft.Compute/galleries/TMM_GK_TF_SIG/images/TMM-GK-CC-W11-SS]
data.azurerm_shared_image_version.GetAzureSIGDefinitionVersion: Reading...
data.azurerm_shared_image_version.GetAzureSIGDefinitionVersion: Read complete after 0s [id=/subscriptions/893a4812-27ad-4135-a95a-6e1d6e0bd793/resourceGroups/tmm_gerhard_westeurope/providers/Microsoft.Compute/galleries/TMM_GK_TF_SIG/images/TMM-GK-CC-W11-SS/versions/1.0.0]
citrix_machine_catalog.CreateAzureMCSCatalog: Refreshing state... [id=50f78ac2-906f-490f-b25f-2bb921df7041]
time_sleep.wait_30_seconds_2: Refreshing state... [id=2024-10-23T18:24:28Z]
citrix_delivery_group.CreateDG: Refreshing state... [id=3dee598d-3a66-4a43-b3ce-1d989e75a3c4]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # citrix_machine_catalog.CreateAzureImgDefMCSCatalog will be updated in-place
  ~ resource "citrix_machine_catalog" "CreateAzureImgDefMCSCatalog" {
        id                       = "c7364b7a-c045-41cc-af81-7a3da2c5d84f"
      ~ inherited_scopes         = [] -> (known after apply)
        name                     = "MC-TMM-GK-TF-Azure-ImgDef-Win11"
      ~ provisioning_scheme      = {
          ~ azure_machine_config           = {
              ~ azure_master_image = {
                  ~ master_image   = "W11-BaseImageDefinition-1-baseDisk-3w0te" -> "W11-BaseImageDefinition-3-baseDisk-my3dm"
                    # (1 unchanged attribute hidden)
                }
                # (5 unchanged attributes hidden)
            }
            # (6 unchanged attributes hidden)
        }
      + tenants                  = (known after apply)
        # (8 unchanged attributes hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

citrix_machine_catalog.CreateAzureImgDefMCSCatalog: Modifying... [id=c7364b7a-c045-41cc-af81-7a3da2c5d84f]
citrix_machine_catalog.CreateAzureImgDefMCSCatalog: Still modifying... [id=c7364b7a-c045-41cc-af81-7a3da2c5d84f, 10s elapsed]
citrix_machine_catalog.CreateAzureImgDefMCSCatalog: Still modifying... [id=c7364b7a-c045-41cc-af81-7a3da2c5d84f, 20s elapsed]
citrix_machine_catalog.CreateAzureImgDefMCSCatalog: Still modifying... [id=c7364b7a-c045-41cc-af81-7a3da2c5d84f, 30s elapsed]
...
citrix_machine_catalog.CreateAzureImgDefMCSCatalog: Still modifying... [id=c7364b7a-c045-41cc-af81-7a3da2c5d84f, 7m30s elapsed]

citrix_machine_catalog.CreateAzureImgDefMCSCatalog: Still modifying... [id=c7364b7a-c045-41cc-af81-7a3da2c5d84f, 7m40s elapsed]
citrix_machine_catalog.CreateAzureImgDefMCSCatalog: Still modifying... [id=c7364b7a-c045-41cc-af81-7a3da2c5d84f, 7m50s elapsed]
citrix_machine_catalog.CreateAzureImgDefMCSCatalog: Modifications complete after 7m53s [id=c7364b7a-c045-41cc-af81-7a3da2c5d84f]

Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
PS C:\_TERRAFORM\_CCOnAzureV2\CCOnAzureV2-DeployCCEntities>

Terraform has successfully changed the Master Image version.
WebStudio reflects this change:

mcv3.png
 

Adding/Removing Entities to/from an Infrastructure after the initial Deployment

At last, you can leverage Terraform to add or remove whole entities if needed.
 

Example 1: Adding a Delivery Group

We will add a new Delivery Group to our environment in this example. You can access the current Delivery Groups using Citrix WebStudio:
dg.png

We just need to alter the Terraform code to add the new Delivery Group – currently, it is uncommented, and this needs to be removed:

#### Create the Delivery Group based on the Image Definition-based Machine Catalog

/* resource "citrix_delivery_group" "CreateImgDefDG" {

    name                                    = "${var.CC-Azure-DGImgDef-Name}"

    associated_machine_catalogs             = [

        {

            machine_catalog                 = citrix_machine_catalog.CreateAzureImgDefMCSCatalog.id

            machine_count                   = "${var.CC-Azure-MCImgDef-Machine_Count}"

        }

    ]

    desktops                                = [

        {

            published_name                  = "${var.CC-Azure-DGImgDef-PublishedDesktopName}"

            description                     = "${var.CC-Azure-DGImgDef-Description}"

            restricted_access_users         = {

                                               allow_list = [ "xXxXxXxXxXxXxXxXx", ]

                                              }

            enabled                         = true

        }

       

    ]

    autoscale_settings                      = {

            autoscale_enabled                                   = true

            disconnect_peak_idle_session_after_seconds          = 60

            disconnect_off_peak_idle_session_after_seconds      = 60

            log_off_off_peak_disconnected_session_after_seconds = 60

            log_off_peak_disconnected_session_after_seconds     = 60

 

            peak_log_off_action                             = "Suspend"

            off_peak_log_off_action                         = "Suspend"

            peak_disconnect_action                          = "Suspend"

            off_peak_disconnect_action                      = "Suspend"

 

            power_time_schemes              = [

                                              {

                                               days_of_week = [

                                                              "Monday",

                                                              "Tuesday",

                                                              "Wednesday",

                                                              "Thursday",

                                                              "Friday"

                                                              ]

                name                        = "${var.CC-Azure-DGImgDef-AS-Name}"

                display_name                = "${var.CC-Azure-DGImgDef-AS-Name}"

                peak_time_ranges            = [

                                                "09:00-17:00"

                                              ]

                pool_size_schedules         = [

                                               {

                                                 time_range = "09:00-17:00",

                                                 pool_size = 1

                                               }

                                              ]

                pool_using_percentage       = false

            },

        ]

    }

    restricted_access_users                 = {

                                                    allow_list = [ "xXxXxXxXxXx", ]

                                              }

    reboot_schedules                        = [

                                               {

                                                 name = "TMM-GK-TF-RebootSchedule1"

                                                 reboot_schedule_enabled = true

                                                 frequency = "Weekly"

                                                 frequency_factor = 1

                                                 days_in_week = [

                                                   "Sunday",

                                                       ]

                                                 start_time = "02:00"

                                                 start_date = "2024-01-01"

                                                 reboot_duration_minutes = 0

                                                 ignore_maintenance_mode = true

                                                 natural_reboot_schedule = false

                                               }

  ]

 

  policy_set_id               = "3658867a-c55a-4a76-996a-03be1c0560a2"

 

}

*/

terraform apply adds the Delivery Group to the Infrastructure:

PS C:\_TERRAFORM\_CCOnAzureV2\CCOnAzureV2-DeployCCEntities> terraform apply
data.azurerm_shared_image_gallery.GetAzureSIG: Reading...
data.azurerm_shared_image_gallery.GetAzureSIG: Read complete after 1s [id=/subscriptions/893a4812-27ad-4135-a95a-6e1d6e0bd793/resourceGroups/tmm_gerhard_westeurope/providers/Microsoft.Compute/galleries/TMM_GK_TF_SIG]
...

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # citrix_delivery_group.CreateImgDefDG will be created
  + resource "citrix_delivery_group" "CreateImgDefDG" {
      + associated_machine_catalogs = [
          + {
              + machine_catalog = "c7364b7a-c045-41cc-af81-7a3da2c5d84f"
              + machine_count   = 1
            },
        ]
      + autoscale_settings          = {
          + autoscale_enabled                                     = true
          + disconnect_off_peak_idle_session_after_seconds        = 60
          + disconnect_peak_idle_session_after_seconds            = 60
          + log_off_off_peak_disconnected_session_after_seconds   = 60
          + log_off_peak_disconnected_session_after_seconds       = 60
          + off_peak_buffer_size_percent                          = 0
          + off_peak_disconnect_action                            = "Suspend"
          + off_peak_disconnect_timeout_minutes                   = 0
          + off_peak_extended_disconnect_action                   = "Nothing"
          + off_peak_extended_disconnect_timeout_minutes          = 0
          + off_peak_log_off_action                               = "Suspend"
          + off_peak_log_off_timeout_minutes                      = 0
          + peak_autoscale_assigned_power_on_idle_action          = "Nothing"
          + peak_autoscale_assigned_power_on_idle_timeout_minutes = 0
          + peak_buffer_size_percent                              = 0
          + peak_disconnect_action                                = "Suspend"
          + peak_disconnect_timeout_minutes                       = 0
          + peak_extended_disconnect_action                       = "Nothing"
          + peak_extended_disconnect_timeout_minutes              = 0
          + peak_log_off_action                                   = "Suspend"
          + peak_log_off_timeout_minutes                          = 0
          + power_off_delay_minutes                               = 30
          + power_time_schemes                                    = [
              + {
                  + days_of_week          = [
                      + "Friday",
                      + "Monday",
                      + "Thursday",
                      + "Tuesday",
                      + "Wednesday",
                    ]
                  + display_name          = "AS-TMM-GK-TF-Azure-ImgDef-Weekday"
                  + peak_time_ranges      = [
                      + "09:00-17:00",
                    ]
                  + pool_size_schedules   = [
                      + {
                          + pool_size  = 1
                          + time_range = "09:00-17:00"
                        },
                    ]
                  + pool_using_percentage = false
                },
            ]
        }
      + built_in_scopes             = (known after apply)
      + default_desktop_icon        = "1"
      + description                 = ""
      + desktops                    = [
          + {
              + description             = "Terraform-based Delivery Group based on Image Definitions and Image Versions running on Azure"
              + enabled                 = true
              + published_name          = "DG-TMM-TACG-TF-Azure-ImgDef"
              + restricted_access_users = {
                  + allow_list = [
                      + "xXxXxXxXxXxXxXxXx",
                    ]
                }
            },
        ]
      + id                          = (known after apply)
      + inherited_scopes            = (known after apply)
      + minimum_functional_level    = "L7_20"
      + name                        = "DG-TMM-GK-TF-Azure-ImgDef"
      + policy_set_id               = "3658867a-c55a-4a76-996a-03be1c0560a2"
      + reboot_schedules            = [
          + {
              + days_in_week            = [
                  + "Sunday",
                ]
              + frequency               = "Weekly"
              + frequency_factor        = 1
              + ignore_maintenance_mode = true
              + name                    = "TMM-GK-TF-RebootSchedule1"
              + natural_reboot_schedule = false
              + reboot_duration_minutes = 0
              + reboot_schedule_enabled = true
              + start_date              = "2024-01-01"
              + start_time              = "02:00"
                # (1 unchanged attribute hidden)
            },
        ]
      + restricted_access_users     = {
          + allow_list = [
              + "xXxXxXxXxXxXxXxXx",
            ]
        }
      + scopes                      = []
      + tenants                     = (known after apply)
      + total_machines              = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

citrix_delivery_group.CreateImgDefDG: Creating...
citrix_delivery_group.CreateImgDefDG: Still creating... [10s elapsed]
citrix_delivery_group.CreateImgDefDG: Creation complete after 10s [id=4d9e2b43-1364-44e1-9884-2e7b9a128e2f]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
PS C:\_TERRAFORM\_CCOnAzureV2\CCOnAzureV2-DeployCCEntities>

Terraform has successfully added the Delivery Group in 10 seconds - compare this to the time it would take to manually create it using WebStudio.
WebStudio reflects the addition:
dgadd.png
 

Example 2: Removing the Delivery Group

In this example, we will remove the just created Delivery Group from our environment to show that Terraform can decommission and completely wipe entities or whole infrastructures.

Caution:

You cannot stop the process as soon as you give consent to Terraform's application to destroy the entity/entities. Terraform will decommission whatever it has to.
 

We only need to uncomment or remove the snippet from the Terraform code to remove the just-created Delivery Group.

We just need to alter the Terraform code to add the new Delivery Group – currently, it is uncommented, and this needs to be removed:

#### Create the Delivery Group based on the Image Definition-based Machine Catalog

/* resource "citrix_delivery_group" "CreateImgDefDG" {

    name                                    = "${var.CC-Azure-DGImgDef-Name}"

    associated_machine_catalogs             = [

        {

            machine_catalog                 = citrix_machine_catalog.CreateAzureImgDefMCSCatalog.id

            machine_count                   = "${var.CC-Azure-MCImgDef-Machine_Count}"

        }

    ]

    desktops                                = [

        {

            published_name                  = "${var.CC-Azure-DGImgDef-PublishedDesktopName}"

            description                     = "${var.CC-Azure-DGImgDef-Description}"

            restricted_access_users         = {

                                               allow_list = [ "xXxXxXxXxXxXxXxXx", ]

                                              }

            enabled                         = true

        }

       

    ]

    autoscale_settings                      = {

            autoscale_enabled                                   = true

            disconnect_peak_idle_session_after_seconds          = 60

            disconnect_off_peak_idle_session_after_seconds      = 60

            log_off_off_peak_disconnected_session_after_seconds = 60

            log_off_peak_disconnected_session_after_seconds     = 60

 

            peak_log_off_action                             = "Suspend"

            off_peak_log_off_action                         = "Suspend"

            peak_disconnect_action                          = "Suspend"

            off_peak_disconnect_action                      = "Suspend"

 

            power_time_schemes              = [

                                              {

                                               days_of_week = [

                                                              "Monday",

                                                              "Tuesday",

                                                              "Wednesday",

                                                              "Thursday",

                                                              "Friday"

                                                              ]

                name                        = "${var.CC-Azure-DGImgDef-AS-Name}"

                display_name                = "${var.CC-Azure-DGImgDef-AS-Name}"

                peak_time_ranges            = [

                                                "09:00-17:00"

                                              ]

                pool_size_schedules         = [

                                               {

                                                 time_range = "09:00-17:00",

                                                 pool_size = 1

                                               }

                                              ]

                pool_using_percentage       = false

            },

        ]

    }

    restricted_access_users                 = {

                                                    allow_list = [ "xXxXxXxXxXx", ]

                                              }

    reboot_schedules                        = [

                                               {

                                                 name = "TMM-GK-TF-RebootSchedule1"

                                                 reboot_schedule_enabled = true

                                                 frequency = "Weekly"

                                                 frequency_factor = 1

                                                 days_in_week = [

                                                   "Sunday",

                                                       ]

                                                 start_time = "02:00"

                                                 start_date = "2024-01-01"

                                                 reboot_duration_minutes = 0

                                                 ignore_maintenance_mode = true

                                                 natural_reboot_schedule = false

                                               }

  ]

 

  policy_set_id               = "3658867a-c55a-4a76-996a-03be1c0560a2"

 

}

*/

Terraform recognizes that the Delivery Group is not part of the IaC anymore and decommissions the Delivery Group:

PS C:\_TERRAFORM\_CCOnAzureV2\CCOnAzureV2-DeployCCEntities> terraform apply
data.citrix_zone.GetTFAzureZoneID: Reading...
citrix_delivery_group.CreateImgDefDG: Refreshing state... [id=4d9e2b43-1364-44e1-9884-2e7b9a128e2f]
data.citrix_zone.GetTFAzureZoneID: Read complete after 0s [id=12f9de5d-fa7f-4739-aaa2-8338daabe878]
...

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # citrix_delivery_group.CreateImgDefDG will be destroyed
  # (because citrix_delivery_group.CreateImgDefDG is not in configuration)
  - resource "citrix_delivery_group" "CreateImgDefDG" {
      - associated_machine_catalogs = [
          - {
              - machine_catalog = "c7364b7a-c045-41cc-af81-7a3da2c5d84f" -> null
              - machine_count   = 1 -> null
            },
        ] -> null
      - autoscale_settings          = {
          - autoscale_enabled                                     = true -> null
          - disconnect_off_peak_idle_session_after_seconds        = 60 -> null
          - disconnect_peak_idle_session_after_seconds            = 60 -> null
          - log_off_off_peak_disconnected_session_after_seconds   = 60 -> null
          - log_off_peak_disconnected_session_after_seconds       = 60 -> null
          - off_peak_buffer_size_percent                          = 0 -> null
          - off_peak_disconnect_action                            = "Suspend" -> null
          - off_peak_disconnect_timeout_minutes                   = 0 -> null
          - off_peak_extended_disconnect_action                   = "Nothing" -> null
          - off_peak_extended_disconnect_timeout_minutes          = 0 -> null
          - off_peak_log_off_action                               = "Suspend" -> null
          - off_peak_log_off_timeout_minutes                      = 0 -> null
          - peak_autoscale_assigned_power_on_idle_action          = "Nothing" -> null
          - peak_autoscale_assigned_power_on_idle_timeout_minutes = 0 -> null
          - peak_buffer_size_percent                              = 0 -> null
          - peak_disconnect_action                                = "Suspend" -> null
          - peak_disconnect_timeout_minutes                       = 0 -> null
          - peak_extended_disconnect_action                       = "Nothing" -> null
          - peak_extended_disconnect_timeout_minutes              = 0 -> null
          - peak_log_off_action                                   = "Suspend" -> null
          - peak_log_off_timeout_minutes                          = 0 -> null
          - power_off_delay_minutes                               = 30 -> null
          - power_time_schemes                                    = [
              - {
                  - days_of_week          = [
                      - "Friday",
                      - "Monday",
                      - "Thursday",
                      - "Tuesday",
                      - "Wednesday",
                    ] -> null
                  - display_name          = "AS-TMM-GK-TF-Azure-ImgDef-Weekday" -> null
                  - peak_time_ranges      = [
                      - "09:00-17:00",
                    ] -> null
                  - pool_size_schedules   = [
                      - {
                          - pool_size  = 1 -> null
                          - time_range = "09:00-17:00" -> null
                        },
                    ] -> null
                  - pool_using_percentage = false -> null
                },
            ] -> null
        } -> null
      - built_in_scopes             = [
          - "00000000-0000-0000-0000-000000000000",
        ] -> null
      - default_desktop_icon        = "1" -> null
      - description                 = "" -> null
      - desktops                    = [
          - {
              - description             = "Terraform-based Delivery Group based on Image Definitions and Image Versions running on Azure" -> null
              - enabled                 = true -> null
              - published_name          = "DG-TMM-TACG-TF-Azure-ImgDef" -> null
              - restricted_access_users = {
                  - allow_list = [
                      - "xXxXxXxXxXxXxXxXx",
                    ] -> null
                } -> null
            },
        ] -> null
      - id                          = "4d9e2b43-1364-44e1-9884-2e7b9a128e2f" -> null
      - inherited_scopes            = [] -> null
      - minimum_functional_level    = "L7_20" -> null
      - name                        = "DG-TMM-GK-TF-Azure-ImgDef" -> null
      - policy_set_id               = "3658867a-c55a-4a76-996a-03be1c0560a2" -> null
      - reboot_schedules            = [
          - {
              - days_in_week            = [
                  - "Sunday",
                ] -> null
              - frequency               = "Weekly" -> null
              - frequency_factor        = 1 -> null
              - ignore_maintenance_mode = true -> null
              - name                    = "TMM-GK-TF-RebootSchedule1" -> null
              - natural_reboot_schedule = false -> null
              - reboot_duration_minutes = 0 -> null
              - reboot_schedule_enabled = true -> null
              - start_date              = "2024-01-01" -> null
              - start_time              = "02:00" -> null
                # (1 unchanged attribute hidden)
            },
        ] -> null
      - restricted_access_users     = {
          - allow_list = [
              - "xXxXxXxXxXxXxXxXx",
            ] -> null
        } -> null
      - scopes                      = [] -> null
      - total_machines              = 1 -> null
    }

Plan: 0 to add, 0 to change, 1 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

citrix_delivery_group.CreateImgDefDG: Destroying... [id=4d9e2b43-1364-44e1-9884-2e7b9a128e2f]
citrix_delivery_group.CreateImgDefDG: Destruction complete after 3s

Apply complete! Resources: 0 added, 0 changed, 1 destroyed.
PS C:\_TERRAFORM\_CCOnAzureV2\CCOnAzureV2-DeployCCEntities>

Terraform has decommissioned the Delivery Group and its adjacent entities.
 

Summary

Using Terraform for daily administration tasks can significantly streamline your workflow and improve efficiency:

Automation:
Terraform automates repetitive tasks, such as provisioning and managing infrastructure. This reduces the need for manual intervention and minimizes the risk of human error.

Consistency:
By defining your IaC, Terraform ensures that your environments are consistent and reproducible. This is particularly useful for maintaining multiple environments
like development, staging, and production.

Scalability:
Terraform makes it easy to scale your infrastructure up or down based on demand. You can define your desired state
, and Terraform will handle the necessary changes to achieve that state.

Collaboration:
Terraform configurations can be stored in version control systems like Git, enabling team collaboration. Team members can review, comment on, and approve changes before they are applied.

Visibility:
Terraform provides a clear and auditable record of changes to your infrastructure. This makes it easier to track changes, troubleshoot issues, and ensure compliance with organizational policies.

Integration:
Terraform integrates with various tools and services, such as CI/CD pipelines, monitoring systems, and configuration management tools. This allows you to create a seamless
, automated workflow for managing your infrastructure.

Cost Management:
By automating
resource provisioning and de-provisioning, Terraform helps you optimize resource usage and control costs. You can easily identify and eliminate unused or underutilized resources.

Using Terraform for daily administration tasks can help you achieve greater efficiency, consistency, and control over your infrastructure.


User Feedback


There are no comments to display.



Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...