Skip to content

Conversation

@Pearl1594
Copy link
Contributor

@Pearl1594 Pearl1594 commented Oct 22, 2025

Support for:

  • Userdata
  • Linking User data to a template
  • Passing parameters values for the userdata linked to the template

Example config:

terraform {
  required_providers {
    cloudstack = {
      source = "hashicorp.com/dev/cloudstack"
    }
  }
}

provider "cloudstack" {
  api_url    = "http://xx.xx.xx.xx:8080/client/api"
  api_key    = "LIN6rqXuaJwMPfGYFh13qDwYz5VNNz1J2J6qIOWcd3oLQOq0WtD4CwRundBL6rzXToa3lQOC_vKjI3nkHtiD8Q"
  secret_key = "R6QPwRUz09TVXBjXNwZk7grTjcPtsFRphH6xhN1oPvnc12YUk296t4KHytg8zRLczDA0X5NsLVi4d8rfMMx3yg"
  timeout    = 1800 
}


resource "cloudstack_user_data" "simple_web" {
  name = "simple-web-userdata"
  
  userdata = base64encode(<<-EOF
    #!/bin/bash
    apt-get update
    apt-get install -y nginx
    
    # Use parameters from userdata_details
    echo "<h1>Hello from $${app_name}!</h1>" > /var/www/html/index.html
    echo "<p>Environment: $${environment}</p>" >> /var/www/html/index.html
    echo "<p>Debug Mode: $${debug_mode}</p>" >> /var/www/html/index.html
    
    systemctl enable nginx
    systemctl start nginx
  EOF
  )
  params = ["app_name", "environment", "debug_mode"]
}

resource "cloudstack_template" "web_template" {
  name         = "simple-web-template-1"
  display_text = "Simple Web Server Template"
  format       = "QCOW2"
  hypervisor   = "KVM"
  os_type      = "Ubuntu 20.04"
  url          = "http://<template_url>"
  zone         = "ref-trl-9797-k-Mol8-pearl-dsilva"
  is_public        = false
  is_extractable   = true
  password_enabled = true
  is_ready_timeout = 1800
  
  # Link userdata to template
  userdata_link {
    userdata_id     = cloudstack_user_data.simple_web.id
    userdata_policy = "ALLOWOVERRIDE"  # Allow users to override userdata
  }
  
  tags = {
    Purpose = "demo"
  }
}

resource "cloudstack_instance" "web_server" {
  name            = "demo-web-server"
  display_name    = "Demo Web Server"
  template        = cloudstack_template.web_template.id
  service_offering = "CKSMinimum"
  network_id      = "09acfb00-fe9b-423d-b993-468dfe69776e"
  zone            = "ref-trl-9797-k-Mol8-pearl-dsilva"
  
  # Use the linked userdata from template
  userdata_id = cloudstack_user_data.simple_web.id
  
  # Pass parameters to the userdata script
  userdata_details = {
    "app_name"    = "My Demo App"
    "environment" = "production"
    "debug_mode"  = "false"
  }
  
  tags = {
    Environment = "demo"
    Purpose     = "web-server"
  }
}

output "userdata_info" {
  description = "Userdata information"
  value = {
    id   = cloudstack_user_data.simple_web.id
    name = cloudstack_user_data.simple_web.name
  }
}

output "template_info" {
  description = "Template information"
  value = {
    id            = cloudstack_template.web_template.id
    name          = cloudstack_template.web_template.name
    userdata_name = cloudstack_template.web_template.userdata_link[0].userdata_name
  }
}

output "instance_info" {
  description = "Instance information"
  value = {
    id         = cloudstack_instance.web_server.id
    name       = cloudstack_instance.web_server.name
    ip_address = cloudstack_instance.web_server.ip_address
  }
}

Copy link
Collaborator

@kiranchavala kiranchavala left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Tested with the config in the pr description

terraform apply 

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:

  # cloudstack_instance.web_server will be created
  + resource "cloudstack_instance" "web_server" {
      + disk_offering          = (known after apply)
      + display_name           = "Demo Web Server-2"
      + expunge                = false
      + group                  = (known after apply)
      + id                     = (known after apply)
      + ip_address             = (known after apply)
      + name                   = "demo-web-server-2"
      + network_id             = "ed555c51-d816-4680-b423-543ef917b216"
      + override_disk_offering = (known after apply)
      + project                = (known after apply)
      + root_disk_size         = (known after apply)
      + service_offering       = "CKSMinimum"
      + start_vm               = true
      + tags                   = {
          + "Environment" = "demo"
          + "Purpose"     = "web-server"
        }
      + template               = (known after apply)
      + uefi                   = false
      + userdata_details       = {
          + "app_name"    = "My Demo App"
          + "debug_mode"  = "false"
          + "environment" = "production"
        }
      + userdata_id            = (known after apply)
      + zone                   = "ref-trl-9805-k-Mol8-kiran-chavala"
    }

  # cloudstack_template.web_template will be created
  + resource "cloudstack_template" "web_template" {
      + display_text            = "Simple Web Server Template"
      + for_cks                 = (known after apply)
      + format                  = "QCOW2"
      + hypervisor              = "KVM"
      + id                      = (known after apply)
      + is_dynamically_scalable = (known after apply)
      + is_extractable          = true
      + is_featured             = (known after apply)
      + is_public               = false
      + is_ready                = (known after apply)
      + is_ready_timeout        = 1800
      + name                    = "simple-web-template-2"
      + os_type                 = "Ubuntu 20.04"
      + password_enabled        = true
      + project                 = (known after apply)
      + tags                    = {
          + "Purpose" = "demo"
        }
      + url                     = "http://10.0.3.130/cks/custom_templates/ubuntu/22.04/cks-ubuntu-2204-kvm.qcow2.bz2"
      + zone                    = "ref-trl-9805-k-Mol8-kiran-chavala"

      + userdata_link {
          + userdata_id     = (known after apply)
          + userdata_name   = (known after apply)
          + userdata_params = (known after apply)
          + userdata_policy = "ALLOWOVERRIDE"
        }
    }

  # cloudstack_userdata.simple_web will be created
  + resource "cloudstack_userdata" "simple_web" {
      + id       = (known after apply)
      + name     = "simple-web-userdata2"
      + params   = [
          + "app_name",
          + "debug_mode",
          + "environment",
        ]
      + userdata = "IyEvYmluL2Jhc2gKYXB0LWdldCB1cGRhdGUKYXB0LWdldCBpbnN0YWxsIC15IG5naW54CiAgICAKIyBVc2UgcGFyYW1ldGVycyBmcm9tIHVzZXJkYXRhX2RldGFpbHMKZWNobyAiPGgxPkhlbGxvIGZyb20gJHthcHBfbmFtZX0hPC9oMT4iID4gL3Zhci93d3cvaHRtbC9pbmRleC5odG1sCmVjaG8gIjxwPkVudmlyb25tZW50OiAke2Vudmlyb25tZW50fTwvcD4iID4+IC92YXIvd3d3L2h0bWwvaW5kZXguaHRtbAplY2hvICI8cD5EZWJ1ZyBNb2RlOiAke2RlYnVnX21vZGV9PC9wPiIgPj4gL3Zhci93d3cvaHRtbC9pbmRleC5odG1sCiAgICAKc3lzdGVtY3RsIGVuYWJsZSBuZ2lueApzeXN0ZW1jdGwgc3RhcnQgbmdpbngK"
    }

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

Changes to Outputs:
  + instance_info = {
      + id         = (known after apply)
      + ip_address = (known after apply)
      + name       = "demo-web-server-2"
    }
  + template_info = {
      + id            = (known after apply)
      + name          = "simple-web-template-2"
      + userdata_name = (known after apply)
    }
  + userdata_info = {
      + id   = (known after apply)
      + name = "simple-web-userdata2"
    }

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

cloudstack_userdata.simple_web: Creating...
cloudstack_userdata.simple_web: Creation complete after 0s [id=f304cc81-ca43-46b0-b539-0a2066eff2fc]
cloudstack_template.web_template: Creating...
cloudstack_template.web_template: Still creating... [00m10s elapsed]
cloudstack_template.web_template: Still creating... [00m20s elapsed]
cloudstack_template.web_template: Still creating... [00m30s elapsed]
cloudstack_template.web_template: Still creating... [00m40s elapsed]
cloudstack_template.web_template: Still creating... [00m50s elapsed]
cloudstack_template.web_template: Still creating... [01m00s elapsed]
cloudstack_template.web_template: Still creating... [01m10s elapsed]
cloudstack_template.web_template: Still creating... [01m20s elapsed]
cloudstack_template.web_template: Still creating... [01m30s elapsed]
cloudstack_template.web_template: Still creating... [01m40s elapsed]
cloudstack_template.web_template: Still creating... [01m50s elapsed]
cloudstack_template.web_template: Still creating... [02m00s elapsed]
cloudstack_template.web_template: Still creating... [02m10s elapsed]
cloudstack_template.web_template: Still creating... [02m20s elapsed]
cloudstack_template.web_template: Still creating... [02m30s elapsed]
cloudstack_template.web_template: Still creating... [02m40s elapsed]
cloudstack_template.web_template: Still creating... [02m50s elapsed]
cloudstack_template.web_template: Still creating... [03m00s elapsed]
cloudstack_template.web_template: Still creating... [03m10s elapsed]
cloudstack_template.web_template: Still creating... [03m20s elapsed]
cloudstack_template.web_template: Still creating... [03m30s elapsed]
cloudstack_template.web_template: Still creating... [03m40s elapsed]
cloudstack_template.web_template: Still creating... [03m50s elapsed]
cloudstack_template.web_template: Still creating... [04m00s elapsed]
cloudstack_template.web_template: Still creating... [04m10s elapsed]
cloudstack_template.web_template: Still creating... [04m20s elapsed]
cloudstack_template.web_template: Still creating... [04m30s elapsed]
cloudstack_template.web_template: Still creating... [04m40s elapsed]
cloudstack_template.web_template: Still creating... [04m50s elapsed]
cloudstack_template.web_template: Still creating... [05m00s elapsed]
cloudstack_template.web_template: Still creating... [05m10s elapsed]
cloudstack_template.web_template: Still creating... [05m20s elapsed]
cloudstack_template.web_template: Still creating... [05m30s elapsed]
cloudstack_template.web_template: Still creating... [05m40s elapsed]
cloudstack_template.web_template: Still creating... [05m50s elapsed]
cloudstack_template.web_template: Still creating... [06m00s elapsed]
cloudstack_template.web_template: Still creating... [06m10s elapsed]
cloudstack_template.web_template: Still creating... [06m20s elapsed]
cloudstack_template.web_template: Still creating... [06m30s elapsed]
cloudstack_template.web_template: Still creating... [06m40s elapsed]
cloudstack_template.web_template: Creation complete after 6m50s [id=77368fb8-076f-493a-843b-1b6ec15360a9]
cloudstack_instance.web_server: Creating...
cloudstack_instance.web_server: Still creating... [00m10s elapsed]
cloudstack_instance.web_server: Still creating... [00m20s elapsed]
cloudstack_instance.web_server: Creation complete after 24s [id=63386c7f-51b0-4c6d-8a0c-0a41988b5004]

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

Outputs:

instance_info = {
  "id" = "63386c7f-51b0-4c6d-8a0c-0a41988b5004"
  "ip_address" = "10.1.1.189"
  "name" = "demo-web-server-2"
}
template_info = {
  "id" = "77368fb8-076f-493a-843b-1b6ec15360a9"
  "name" = "simple-web-template-2"
  "userdata_name" = "simple-web-userdata2"
}
userdata_info = {
  "id" = "f304cc81-ca43-46b0-b539-0a2066eff2fc"
  "name" = "simple-web-userdata2"
}

Screenshot 2025-10-22 at 11 22 36 AM

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds support for userdata management and linking in the CloudStack Terraform provider. It introduces a new cloudstack_userdata resource for registering user data scripts, adds the ability to link user data to templates with configurable override policies, and enables instances to use registered user data with parameterized values.

Key changes:

  • New cloudstack_userdata resource and data source for managing user data scripts with parameter support
  • Template userdata_link block to associate user data with templates, including override policies (ALLOWOVERRIDE, APPEND, DENYOVERRIDE)
  • Instance support for userdata_id and userdata_details fields to use registered user data with parameter substitution

Reviewed Changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
website/docs/r/userdata.html.markdown Documentation for the new cloudstack_userdata resource
website/docs/r/template.html.markdown Documentation for the userdata_link block in templates
website/docs/r/instance.html.markdown Documentation for instance userdata integration
website/docs/d/user_data.html.markdown Documentation for the cloudstack_user_data data source
website/docs/README.md Updated index with new resource and data source
cloudstack/resource_cloudstack_user_data.go Implementation of the cloudstack_userdata resource
cloudstack/resource_cloudstack_template.go Template userdata linking functionality
cloudstack/resource_cloudstack_instance.go Instance userdata support implementation
cloudstack/provider.go Provider registration of new resource and data source
cloudstack/data_source_cloudstack_user_data.go Implementation of the cloudstack_user_data data source

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

},

"userdata_link": {
Type: schema.TypeList,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it need to be a list since MaxItems is only 1?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it fine to use TypeList with MaxItems set to 1 to represent a single nested object.

Copy link
Collaborator

@kiranchavala kiranchavala left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested again with the latest changes and the resource created fine

cloudstack_user_data


provider "cloudstack" {
  api_url    = var.cloudstack_api_url
  api_key    = var.cloudstack_api_key
  secret_key = var.cloudstack_secret_key

}

resource "cloudstack_user_data" "simple_web" {
  name = "simple-web-userdata3"
  
  userdata = base64encode(<<-EOF
    #!/bin/bash
    apt-get update
    apt-get install -y nginx
    
    # Use parameters from userdata_details
    echo "<h1>Hello from $${app_name}!</h1>" > /var/www/html/index.html
    echo "<p>Environment: $${environment}</p>" >> /var/www/html/index.html
    echo "<p>Debug Mode: $${debug_mode}</p>" >> /var/www/html/index.html
    
    systemctl enable nginx
    systemctl start nginx
  EOF
  )
  params = ["app_name", "environment", "debug_mode"]
}

resource "cloudstack_template" "web_template" {
  name         = "simple-web-template-3"
  display_text = "Simple Web Server Template"
  format       = "QCOW2"
  hypervisor   = "KVM"
  os_type      = "Ubuntu 20.04"
  url          = "http://10.0.3.130/cks/custom_templates/ubuntu/22.04/cks-ubuntu-2204-kvm.qcow2.bz2"
  zone         = "ref-trl-9805-k-Mol8-kiran-chavala"
  is_public        = false
  is_extractable   = true
  password_enabled = true
  is_ready_timeout = 1800
  
  # Link userdata to template
  userdata_link {
    userdata_id     = cloudstack_user_data.simple_web.id
    userdata_policy = "ALLOWOVERRIDE"  # Allow users to override userdata
  }
  
  tags = {
    Purpose = "demo"
  }
}

resource "cloudstack_instance" "web_server" {
  name            = "demo-web-server-3"
  display_name    = "Demo Web Server-3"
  template        = cloudstack_template.web_template.id
  service_offering = "CKSMinimum"
  network_id      = "ed555c51-d816-4680-b423-543ef917b216"
  zone            = "ref-trl-9805-k-Mol8-kiran-chavala"
  
  # Use the linked userdata from template
  userdata_id = cloudstack_user_data.simple_web.id
  
  # Pass parameters to the userdata script
  userdata_details = {
    "app_name"    = "My Demo App"
    "environment" = "production"
    "debug_mode"  = "false"
  }
  
  tags = {
    Environment = "demo"
    Purpose     = "web-server"
  }
}

output "userdata_info" {
  description = "Userdata information"
  value = {
    id   = cloudstack_user_data.simple_web.id
    name = cloudstack_user_data.simple_web.name
  }
}

output "template_info" {
  description = "Template information"
  value = {
    id            = cloudstack_template.web_template.id
    name          = cloudstack_template.web_template.name
    userdata_name = cloudstack_template.web_template.userdata_link[0].userdata_name
  }
}

output "instance_info" {
  description = "Instance information"
  value = {
    id         = cloudstack_instance.web_server.id
    name       = cloudstack_instance.web_server.name
    ip_address = cloudstack_instance.web_server.ip_address
  }
}

@kiranchavala kiranchavala merged commit 6421746 into main Oct 22, 2025
64 of 68 checks passed
@DaanHoogland DaanHoogland deleted the add-userdata-support branch October 22, 2025 14:49
@kiranchavala kiranchavala added this to the v0.6.0 milestone Oct 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants