This is an automated email from the ASF dual-hosted git repository.
dahn pushed a commit to branch main
in repository
https://gitbox.apache.org/repos/asf/cloudstack-terraform-provider.git
The following commit(s) were added to refs/heads/main by this push:
new e4ecc98 Add support for the new parameters added to CKS cluster
deployement (#230)
e4ecc98 is described below
commit e4ecc98ee38ca5f93d43fc529a5d2fb917d0f5f4
Author: Pearl Dsilva <[email protected]>
AuthorDate: Mon Sep 29 08:35:35 2025 -0400
Add support for the new parameters added to CKS cluster deployement (#230)
Co-authored-by: vishesh92 <[email protected]>
---
cloudstack/provider.go | 1 +
.../resource_cloudstack_cni_configuration.go | 222 +++++++++++++++++++++
.../resource_cloudstack_cni_configuration_test.go | 153 ++++++++++++++
.../resource_cloudstack_kubernetes_cluster.go | 148 +++++++++++++-
.../resource_cloudstack_kubernetes_version.go | 2 +-
cloudstack/resource_cloudstack_static_route.go | 5 +-
cloudstack/resource_cloudstack_template.go | 12 ++
go.mod | 2 +-
go.sum | 4 +-
website/docs/r/cni_configuration.html.markdown | 172 ++++++++++++++++
website/docs/r/kubernetes_cluster.html.markdown | 178 +++++++++++++----
website/docs/r/template.html.markdown | 117 +++++++++--
12 files changed, 952 insertions(+), 64 deletions(-)
diff --git a/cloudstack/provider.go b/cloudstack/provider.go
index 277dfae..0e0f6cf 100644
--- a/cloudstack/provider.go
+++ b/cloudstack/provider.go
@@ -109,6 +109,7 @@ func Provider() *schema.Provider {
"cloudstack_autoscale_policy":
resourceCloudStackAutoScalePolicy(),
"cloudstack_autoscale_vm_group":
resourceCloudStackAutoScaleVMGroup(),
"cloudstack_autoscale_vm_profile":
resourceCloudStackAutoScaleVMProfile(),
+ "cloudstack_cni_configuration":
resourceCloudStackCniConfiguration(),
"cloudstack_condition":
resourceCloudStackCondition(),
"cloudstack_configuration":
resourceCloudStackConfiguration(),
"cloudstack_counter":
resourceCloudStackCounter(),
diff --git a/cloudstack/resource_cloudstack_cni_configuration.go
b/cloudstack/resource_cloudstack_cni_configuration.go
new file mode 100644
index 0000000..60b320c
--- /dev/null
+++ b/cloudstack/resource_cloudstack_cni_configuration.go
@@ -0,0 +1,222 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+package cloudstack
+
+import (
+ "fmt"
+ "log"
+ "strings"
+
+ "github.com/apache/cloudstack-go/v2/cloudstack"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+func resourceCloudStackCniConfiguration() *schema.Resource {
+ return &schema.Resource{
+ Create: resourceCloudStackCniConfigurationCreate,
+ Read: resourceCloudStackCniConfigurationRead,
+ Delete: resourceCloudStackCniConfigurationDelete,
+ Importer: &schema.ResourceImporter{
+ State: importStatePassthrough,
+ },
+
+ Schema: map[string]*schema.Schema{
+ "name": {
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ Description: "Name of the CNI configuration",
+ },
+
+ "cni_config": {
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ Description: "CNI Configuration content to be
registered",
+ },
+
+ "account": {
+ Type: schema.TypeString,
+ Optional: true,
+ ForceNew: true,
+ Description: "An optional account for the CNI
configuration. Must be used with domain_id.",
+ },
+
+ "domain_id": {
+ Type: schema.TypeString,
+ Optional: true,
+ ForceNew: true,
+ Description: "An optional domain ID for the CNI
configuration. If the account parameter is used, domain_id must also be used.",
+ },
+
+ "project_id": {
+ Type: schema.TypeString,
+ Optional: true,
+ ForceNew: true,
+ Description: "An optional project for the CNI
configuration",
+ },
+
+ "params": {
+ Type: schema.TypeSet,
+ Optional: true,
+ ForceNew: true,
+ Description: "List of variables declared in CNI
configuration content",
+ Elem: &schema.Schema{
+ Type: schema.TypeString,
+ },
+ },
+ },
+ }
+}
+
+func resourceCloudStackCniConfigurationCreate(d *schema.ResourceData, meta
interface{}) error {
+ cs := meta.(*cloudstack.CloudStackClient)
+
+ name := d.Get("name").(string)
+ log.Printf("[DEBUG] Creating CNI configuration: %s", name)
+
+ p := cs.Configuration.NewRegisterCniConfigurationParams(name)
+
+ if v, ok := d.GetOk("cni_config"); ok {
+ cniConfig := v.(string)
+ log.Printf("[DEBUG] CNI config data length: %d bytes",
len(cniConfig))
+ p.SetCniconfig(cniConfig)
+ } else {
+ return fmt.Errorf("CNI configuration content is required but
not provided")
+ }
+
+ if account := d.Get("account").(string); account != "" {
+ log.Printf("[DEBUG] Setting account: %s", account)
+ p.SetAccount(account)
+ }
+
+ if domainID := d.Get("domain_id").(string); domainID != "" {
+ log.Printf("[DEBUG] Setting domain ID: %s", domainID)
+ p.SetDomainid(domainID)
+ }
+
+ if projectID := d.Get("project_id").(string); projectID != "" {
+ log.Printf("[DEBUG] Setting project ID: %s", projectID)
+ p.SetProjectid(projectID)
+ }
+
+ if params, ok := d.GetOk("params"); ok {
+ paramsList := []string{}
+ for _, param := range params.(*schema.Set).List() {
+ paramsList = append(paramsList, param.(string))
+ }
+ if len(paramsList) > 0 {
+ paramsStr := strings.Join(paramsList, ",")
+ log.Printf("[DEBUG] Setting params: %s", paramsStr)
+ p.SetParams(paramsStr)
+ }
+ }
+
+ resp, err := cs.Configuration.RegisterCniConfiguration(p)
+ if err != nil {
+ return fmt.Errorf("Error creating CNI configuration %s: %s",
name, err)
+ }
+
+ log.Printf("[DEBUG] CNI configuration creation response: %+v", resp)
+
+ // List configurations to find the created one by name since direct ID
access is not available
+ listParams := cs.Configuration.NewListCniConfigurationParams()
+ listParams.SetName(name)
+
+ // Add context parameters if available
+ if account := d.Get("account").(string); account != "" {
+ listParams.SetAccount(account)
+ }
+ if domainID := d.Get("domain_id").(string); domainID != "" {
+ listParams.SetDomainid(domainID)
+ }
+ if projectID := d.Get("project_id").(string); projectID != "" {
+ listParams.SetProjectid(projectID)
+ }
+
+ listResp, err := cs.Configuration.ListCniConfiguration(listParams)
+ if err != nil {
+ return fmt.Errorf("Error listing CNI configurations after
creation: %s", err)
+ }
+
+ if listResp.Count == 0 {
+ return fmt.Errorf("CNI configuration %s was created but could
not be found", name)
+ }
+
+ // Use the first (and should be only) result
+ config := listResp.CniConfiguration[0]
+ d.SetId(config.Id)
+ log.Printf("[DEBUG] CNI configuration %s successfully created with ID:
%s", name, d.Id())
+
+ return resourceCloudStackCniConfigurationRead(d, meta)
+}
+
+func resourceCloudStackCniConfigurationRead(d *schema.ResourceData, meta
interface{}) error {
+ cs := meta.(*cloudstack.CloudStackClient)
+
+ log.Printf("[DEBUG] Reading CNI configuration: %s", d.Id())
+
+ p := cs.Configuration.NewListCniConfigurationParams()
+ p.SetId(d.Id())
+
+ config, err := cs.Configuration.ListCniConfiguration(p)
+ if err != nil {
+ return fmt.Errorf("Error listing CNI configuration: %s", err)
+ }
+ if config.Count == 0 {
+ log.Printf("[DEBUG] CNI configuration %s no longer exists",
d.Id())
+ d.SetId("")
+ return nil
+ }
+
+ d.Set("name", config.CniConfiguration[0].Name)
+ d.Set("cni_config", config.CniConfiguration[0].Userdata)
+ d.Set("account", config.CniConfiguration[0].Account)
+ d.Set("domain_id", config.CniConfiguration[0].Domainid)
+ d.Set("project_id", config.CniConfiguration[0].Projectid)
+
+ if config.CniConfiguration[0].Params != "" {
+ paramsList := strings.Split(config.CniConfiguration[0].Params,
",")
+ d.Set("params", paramsList)
+ }
+
+ return nil
+}
+
+func resourceCloudStackCniConfigurationDelete(d *schema.ResourceData, meta
interface{}) error {
+ cs := meta.(*cloudstack.CloudStackClient)
+
+ log.Printf("[DEBUG] Deleting CNI configuration: %s", d.Id())
+
+ p := cs.Configuration.NewDeleteCniConfigurationParams(d.Id())
+
+ _, err := cs.Configuration.DeleteCniConfiguration(p)
+ if err != nil {
+ if strings.Contains(err.Error(), "does not exist") ||
+ strings.Contains(err.Error(), "not found") {
+ log.Printf("[DEBUG] CNI configuration %s already
deleted", d.Id())
+ return nil
+ }
+ return fmt.Errorf("Error deleting CNI configuration %s: %s",
d.Id(), err)
+ }
+
+ log.Printf("[DEBUG] CNI configuration %s deleted", d.Id())
+ return nil
+}
diff --git a/cloudstack/resource_cloudstack_cni_configuration_test.go
b/cloudstack/resource_cloudstack_cni_configuration_test.go
new file mode 100644
index 0000000..96b2692
--- /dev/null
+++ b/cloudstack/resource_cloudstack_cni_configuration_test.go
@@ -0,0 +1,153 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+package cloudstack
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/apache/cloudstack-go/v2/cloudstack"
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+ "github.com/hashicorp/terraform-plugin-testing/terraform"
+)
+
+func TestAccCloudStackCniConfiguration_basic(t *testing.T) {
+ var cniConfig cloudstack.UserData
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t);
testAccPreCheckCniSupport(t) },
+ Providers: testAccProviders,
+ CheckDestroy: testAccCheckCloudStackCniConfigurationDestroy,
+ Steps: []resource.TestStep{
+ {
+ Config: testAccCloudStackCniConfiguration_basic,
+ Check: resource.ComposeTestCheckFunc(
+
testAccCheckCloudStackCniConfigurationExists("cloudstack_cni_configuration.foo",
&cniConfig),
+
resource.TestCheckResourceAttr("cloudstack_cni_configuration.foo", "name",
"test-cni-config"),
+
resource.TestCheckResourceAttr("cloudstack_cni_configuration.foo", "params.#",
"2"),
+ ),
+ },
+ },
+ })
+}
+
+func testAccCheckCloudStackCniConfigurationExists(n string, cniConfig
*cloudstack.UserData) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ rs, ok := s.RootModule().Resources[n]
+ if !ok {
+ return fmt.Errorf("Not found: %s", n)
+ }
+
+ if rs.Primary.ID == "" {
+ return fmt.Errorf("No CNI configuration ID is set")
+ }
+
+ cs := testAccProvider.Meta().(*cloudstack.CloudStackClient)
+ p := cs.Configuration.NewListCniConfigurationParams()
+ p.SetId(rs.Primary.ID)
+
+ resp, err := cs.Configuration.ListCniConfiguration(p)
+ if err != nil {
+ return err
+ }
+
+ if resp.Count != 1 {
+ return fmt.Errorf("CNI configuration not found")
+ }
+
+ config := resp.CniConfiguration[0]
+ if config.Id != rs.Primary.ID {
+ return fmt.Errorf("CNI configuration not found")
+ }
+
+ *cniConfig = *config
+ return nil
+ }
+}
+
+func testAccCheckCloudStackCniConfigurationDestroy(s *terraform.State) error {
+ cs := testAccProvider.Meta().(*cloudstack.CloudStackClient)
+
+ for _, rs := range s.RootModule().Resources {
+ if rs.Type != "cloudstack_cni_configuration" {
+ continue
+ }
+
+ if rs.Primary.ID == "" {
+ return fmt.Errorf("No CNI configuration ID is set")
+ }
+
+ p := cs.Configuration.NewListCniConfigurationParams()
+ p.SetId(rs.Primary.ID)
+
+ resp, err := cs.Configuration.ListCniConfiguration(p)
+ if err == nil && resp.Count > 0 {
+ return fmt.Errorf("CNI configuration %s still exists",
rs.Primary.ID)
+ }
+ }
+
+ return nil
+}
+
+const testAccCloudStackCniConfiguration_basic = `
+resource "cloudstack_cni_configuration" "foo" {
+ name = "test-cni-config"
+ cni_config = base64encode(jsonencode({
+ "name": "test-network",
+ "cniVersion": "0.4.0",
+ "plugins": [
+ {
+ "type": "calico",
+ "log_level": "info",
+ "datastore_type": "kubernetes",
+ "nodename": "KUBERNETES_NODE_NAME",
+ "mtu": "CNI_MTU",
+ "ipam": {
+ "type": "calico-ipam"
+ },
+ "policy": {
+ "type": "k8s"
+ },
+ "kubernetes": {
+ "kubeconfig": "KUBECONFIG_FILEPATH"
+ }
+ },
+ {
+ "type": "portmap",
+ "snat": true,
+ "capabilities": {"portMappings": true}
+ }
+ ]
+ }))
+
+ params = ["KUBERNETES_NODE_NAME", "CNI_MTU"]
+}
+`
+
+func testAccPreCheckCniSupport(t *testing.T) {
+ cs := testAccProvider.Meta().(*cloudstack.CloudStackClient)
+
+ // Try to list CNI configurations to check if the feature is available
+ p := cs.Configuration.NewListCniConfigurationParams()
+ _, err := cs.Configuration.ListCniConfiguration(p)
+ if err != nil {
+ t.Skipf("CNI configuration not supported in this CloudStack
version (requires 4.21.0+): %v", err)
+ }
+}
diff --git a/cloudstack/resource_cloudstack_kubernetes_cluster.go
b/cloudstack/resource_cloudstack_kubernetes_cluster.go
index 44b500f..7333c25 100644
--- a/cloudstack/resource_cloudstack_kubernetes_cluster.go
+++ b/cloudstack/resource_cloudstack_kubernetes_cluster.go
@@ -121,6 +121,20 @@ func resourceCloudStackKubernetesCluster()
*schema.Resource {
// Default: "Running",
},
+ "account": {
+ Type: schema.TypeString,
+ Optional: true,
+ ForceNew: true,
+ Description: "An optional account for the
Kubernetes cluster. Must be used with domain_id.",
+ },
+
+ "domain_id": {
+ Type: schema.TypeString,
+ Optional: true,
+ ForceNew: true,
+ Description: "An optional domain ID for the
Kubernetes cluster. If the account parameter is used, domain_id must also be
used. Hosts dedicated to the specified domain will be used for deploying the
cluster",
+ },
+
"project": {
Type: schema.TypeString,
Optional: true,
@@ -151,6 +165,55 @@ func resourceCloudStackKubernetesCluster()
*schema.Resource {
ForceNew: true,
Sensitive: true,
},
+
+ "as_number": {
+ Type: schema.TypeInt,
+ Optional: true,
+ ForceNew: true,
+ Description: "An optional as number for the
Kubernetes cluster",
+ },
+
+ "cni_config_details": {
+ Type: schema.TypeMap,
+ Optional: true,
+ ForceNew: true,
+ Description: "An optional map of CNI
configuration details. It is used to specify the parameters values for the
variables in userdata",
+ },
+
+ "cni_configuration_id": {
+ Type: schema.TypeString,
+ Optional: true,
+ ForceNew: true,
+ Description: "An optional CNI configuration ID
for the Kubernetes cluster. If not specified, the default CNI configuration
will be used",
+ },
+
+ "etcd_nodes_size": {
+ Type: schema.TypeInt,
+ Optional: true,
+ ForceNew: true, // For now
+ Description: "Number of etcd nodes in the
Kubernetes cluster. Default is 0",
+ },
+
+ "hypervisor": {
+ Type: schema.TypeString,
+ Optional: true,
+ ForceNew: true,
+ Description: "The hypervisor on which to deploy
the cluster.",
+ },
+
+ "node_offerings": {
+ Type: schema.TypeMap,
+ Optional: true,
+ ForceNew: true,
+ Description: "An optional map of node roles to
service offerings. If not specified, the service_offering parameter will be
used for all node roles. Valid roles are: worker, control, etcd",
+ },
+
+ "node_templates": {
+ Type: schema.TypeMap,
+ Optional: true,
+ ForceNew: true,
+ Description: "An optional map of node roles to
instance templates. If not specified, system VM template will be used. Valid
roles are: worker, control, etcd",
+ },
},
}
}
@@ -214,6 +277,69 @@ func resourceCloudStackKubernetesClusterCreate(d
*schema.ResourceData, meta inte
return err
}
+ if account, ok := d.GetOk("account"); ok {
+ p.SetAccount(account.(string))
+ }
+ if domainID, ok := d.GetOk("domain_id"); ok {
+ p.SetDomainid(domainID.(string))
+ }
+
+ if asNumber, ok := d.GetOk("as_number"); ok {
+ p.SetAsnumber(int64(asNumber.(int)))
+ }
+
+ if etcdNodesSize, ok := d.GetOk("etcd_nodes_size"); ok {
+ p.SetEtcdnodes(int64(etcdNodesSize.(int)))
+ }
+
+ if hypervisor, ok := d.GetOk("hypervisor"); ok {
+ p.SetHypervisor(hypervisor.(string))
+ }
+
+ if cniConfigID, ok := d.GetOk("cni_configuration_id"); ok {
+ p.SetCniconfigurationid(cniConfigID.(string))
+ }
+
+ if nodeOfferings, ok := d.GetOk("node_offerings"); ok {
+ nodeOfferingsMap := nodeOfferings.(map[string]interface{})
+ nodeOfferingsFormatted := make(map[string]string)
+ for nodeType, offeringName := range nodeOfferingsMap {
+ // Retrieve the offering ID
+ offeringID, e := retrieveID(cs, "service_offering",
offeringName.(string))
+ if e != nil {
+ return e.Error()
+ }
+ nodeOfferingsFormatted[nodeType] = offeringID
+ }
+ p.SetNodeofferings(nodeOfferingsFormatted)
+ }
+
+ if nodeTemplates, ok := d.GetOk("node_templates"); ok {
+ nodeTemplatesMap := nodeTemplates.(map[string]interface{})
+ nodeTemplatesFormatted := make(map[string]string)
+ for nodeType, templateName := range nodeTemplatesMap {
+ zoneID, err := retrieveID(cs, "zone",
d.Get("zone").(string))
+ if err != nil {
+ return err.Error()
+ }
+ templateID, e := retrieveTemplateID(cs, zoneID,
templateName.(string))
+ if e != nil {
+ return e.Error()
+ }
+ nodeTemplatesFormatted[nodeType] = templateID
+ }
+ p.SetNodetemplates(nodeTemplatesFormatted)
+ }
+
+ if cniConfigDetails, ok := d.GetOk("cni_config_details"); ok {
+ cniConfigDetailsMap := cniConfigDetails.(map[string]interface{})
+ cniConfigDetailsFormatted := make(map[string]string)
+ for key, value := range cniConfigDetailsMap {
+ cniConfigDetailsFormatted[key] = value.(string)
+ }
+ p.SetCniconfigdetails(cniConfigDetailsFormatted)
+ }
+
log.Printf("[DEBUG] Creating Kubernetes Cluster %s", name)
r, err := cs.Kubernetes.CreateKubernetesCluster(p)
if err != nil {
@@ -273,6 +399,10 @@ func resourceCloudStackKubernetesClusterRead(d
*schema.ResourceData, meta interf
d.Set("network_id", cluster.Networkid)
d.Set("ip_address", cluster.Ipaddress)
d.Set("state", cluster.State)
+ d.Set("account", cluster.Account)
+ d.Set("domain_id", cluster.Domainid)
+ d.Set("etcd_nodes_size", cluster.Etcdnodes)
+ d.Set("cni_configuration_id", cluster.Cniconfigurationid)
setValueOrID(d, "kubernetes_version", cluster.Kubernetesversionname,
cluster.Kubernetesversionid)
setValueOrID(d, "service_offering", cluster.Serviceofferingname,
cluster.Serviceofferingid)
@@ -295,7 +425,7 @@ func autoscaleKubernetesCluster(d *schema.ResourceData,
meta interface{}) error
func resourceCloudStackKubernetesClusterUpdate(d *schema.ResourceData, meta
interface{}) error {
cs := meta.(*cloudstack.CloudStackClient)
- if d.HasChange("service_offering") || d.HasChange("size") {
+ if d.HasChange("service_offering") || d.HasChange("size") ||
d.HasChange("node_offerings") {
p := cs.Kubernetes.NewScaleKubernetesClusterParams(d.Id())
serviceOfferingID, e := retrieveID(cs, "service_offering",
d.Get("service_offering").(string))
if e != nil {
@@ -303,6 +433,22 @@ func resourceCloudStackKubernetesClusterUpdate(d
*schema.ResourceData, meta inte
}
p.SetServiceofferingid(serviceOfferingID)
p.SetSize(int64(d.Get("size").(int)))
+
+ // Handle node offerings if they changed
+ if nodeOfferings, ok := d.GetOk("node_offerings"); ok {
+ nodeOfferingsMap :=
nodeOfferings.(map[string]interface{})
+ nodeOfferingsFormatted := make(map[string]string)
+ for nodeType, offeringName := range nodeOfferingsMap {
+ // Retrieve the offering ID
+ offeringID, e := retrieveID(cs,
"service_offering", offeringName.(string))
+ if e != nil {
+ return e.Error()
+ }
+ nodeOfferingsFormatted[nodeType] = offeringID
+ }
+ p.SetNodeofferings(nodeOfferingsFormatted)
+ }
+
_, err := cs.Kubernetes.ScaleKubernetesCluster(p)
if err != nil {
return fmt.Errorf(
diff --git a/cloudstack/resource_cloudstack_kubernetes_version.go
b/cloudstack/resource_cloudstack_kubernetes_version.go
index a389d3a..b1e6d1f 100644
--- a/cloudstack/resource_cloudstack_kubernetes_version.go
+++ b/cloudstack/resource_cloudstack_kubernetes_version.go
@@ -115,7 +115,7 @@ func resourceCloudStackKubernetesVersionCreate(d
*schema.ResourceData, meta inte
p.SetName(name.(string))
}
if checksum, ok := d.GetOk("checksum"); ok {
- p.SetName(checksum.(string))
+ p.SetChecksum(checksum.(string))
}
if zone, ok := d.GetOk("zone"); ok {
zoneID, e := retrieveID(cs, "zone", zone.(string))
diff --git a/cloudstack/resource_cloudstack_static_route.go
b/cloudstack/resource_cloudstack_static_route.go
index 0970532..d9240b7 100644
--- a/cloudstack/resource_cloudstack_static_route.go
+++ b/cloudstack/resource_cloudstack_static_route.go
@@ -56,9 +56,12 @@ func resourceCloudStackStaticRouteCreate(d
*schema.ResourceData, meta interface{
// Create a new parameter struct
p := cs.VPC.NewCreateStaticRouteParams(
d.Get("cidr").(string),
- d.Get("gateway_id").(string),
)
+ if v, ok := d.GetOk("gateway_id"); ok {
+ p.SetGatewayid(v.(string))
+ }
+
// Create the new private gateway
r, err := cs.VPC.CreateStaticRoute(p)
if err != nil {
diff --git a/cloudstack/resource_cloudstack_template.go
b/cloudstack/resource_cloudstack_template.go
index edf41c1..4316c7e 100644
--- a/cloudstack/resource_cloudstack_template.go
+++ b/cloudstack/resource_cloudstack_template.go
@@ -126,6 +126,13 @@ func resourceCloudStackTemplate() *schema.Resource {
Default: 300,
},
+ "for_cks": {
+ Type: schema.TypeBool,
+ Optional: true,
+ Computed: true,
+ ForceNew: true,
+ },
+
"tags": tagsSchema(),
},
}
@@ -182,6 +189,10 @@ func resourceCloudStackTemplateCreate(d
*schema.ResourceData, meta interface{})
p.SetPasswordenabled(v.(bool))
}
+ if v, ok := d.GetOk("for_cks"); ok {
+ p.SetForcks(v.(bool))
+ }
+
// Retrieve the zone ID
if v, ok := d.GetOk("zone"); ok {
if v.(string) != "all" {
@@ -277,6 +288,7 @@ func resourceCloudStackTemplateRead(d *schema.ResourceData,
meta interface{}) er
d.Set("is_public", t.Ispublic)
d.Set("password_enabled", t.Passwordenabled)
d.Set("is_ready", t.Isready)
+ d.Set("for_cks", t.Forcks)
tags := make(map[string]interface{})
for _, tag := range t.Tags {
diff --git a/go.mod b/go.mod
index 339e856..6e69966 100644
--- a/go.mod
+++ b/go.mod
@@ -18,7 +18,7 @@
module github.com/terraform-providers/terraform-provider-cloudstack
require (
- github.com/apache/cloudstack-go/v2 v2.17.2
+ github.com/apache/cloudstack-go/v2 v2.18.1
github.com/go-ini/ini v1.67.0
github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/terraform-plugin-framework v1.12.0
diff --git a/go.sum b/go.sum
index 4b49b66..d60bbe4 100644
--- a/go.sum
+++ b/go.sum
@@ -6,8 +6,8 @@ github.com/ProtonMail/go-crypto v1.1.0-alpha.0
h1:nHGfwXmFvJrSR9xu8qL7BkO4DqTHXE
github.com/ProtonMail/go-crypto v1.1.0-alpha.0/go.mod
h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
github.com/agext/levenshtein v1.2.2
h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE=
github.com/agext/levenshtein v1.2.2/go.mod
h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
-github.com/apache/cloudstack-go/v2 v2.17.2
h1:fMqLUTpHZeJoSVQiD2hDBSoqOvGJ9QMoOaWABW8lc/0=
-github.com/apache/cloudstack-go/v2 v2.17.2/go.mod
h1:p/YBUwIEkQN6CQxFhw8Ff0wzf1MY0qRRRuGYNbcb1F8=
+github.com/apache/cloudstack-go/v2 v2.18.1
h1:SgdRUEj5x17wSPfwAacjWgTqbtS/u7iaqnbpILWzE1c=
+github.com/apache/cloudstack-go/v2 v2.18.1/go.mod
h1:p/YBUwIEkQN6CQxFhw8Ff0wzf1MY0qRRRuGYNbcb1F8=
github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod
h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec=
github.com/apparentlymart/go-textseg/v15 v15.0.0
h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=
github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod
h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
diff --git a/website/docs/r/cni_configuration.html.markdown
b/website/docs/r/cni_configuration.html.markdown
new file mode 100644
index 0000000..de80a76
--- /dev/null
+++ b/website/docs/r/cni_configuration.html.markdown
@@ -0,0 +1,172 @@
+---
+layout: default
+page_title: "CloudStack: cloudstack_cni_configuration"
+sidebar_current: "docs-cloudstack-resource-cni_configuration"
+description: |-
+ Creates and manages a CloudStack CNI (Container Network Interface)
configuration
+---
+
+# CloudStack: cloudstack_cni_configuration
+
+A `cloudstack_cni_configuration` resource manages a Container Network
Interface (CNI) configuration for CloudStack Kubernetes Service (CKS) clusters.
CNI configurations define how network connectivity is provided to Kubernetes
pods.
+
+## Example Usage
+
+### Basic Calico CNI Configuration
+
+```hcl
+resource "cloudstack_cni_configuration" "calico" {
+ name = "calico-cni-config"
+ cni_config = base64encode(jsonencode({
+ "name" = "k8s-pod-network",
+ "cniVersion" = "0.3.1",
+ "plugins" = [
+ {
+ "type" = "calico",
+ "log_level" = "info",
+ "datastore_type" = "kubernetes",
+ "nodename" = "KUBERNETES_NODE_NAME",
+ "mtu" = "CNI_MTU",
+ "ipam" = {
+ "type" = "calico-ipam"
+ },
+ "policy" = {
+ "type" = "k8s"
+ },
+ "kubernetes" = {
+ "kubeconfig" = "KUBECONFIG_FILEPATH"
+ }
+ },
+ {
+ "type" = "portmap",
+ "snat" = true,
+ "capabilities" = { "portMappings" = true }
+ }
+ ]
+ }))
+
+ params = [
+ "KUBERNETES_NODE_NAME",
+ "CNI_MTU",
+ "KUBECONFIG_FILEPATH"
+ ]
+}
+```
+
+### Flannel CNI Configuration
+
+```hcl
+resource "cloudstack_cni_configuration" "flannel" {
+ name = "flannel-cni-config"
+ cni_config = base64encode(jsonencode({
+ "name" = "cbr0",
+ "cniVersion" = "0.3.1",
+ "plugins" = [
+ {
+ "type" = "flannel",
+ "delegate" = {
+ "hairpinMode" = true,
+ "isDefaultGateway" = true
+ }
+ },
+ {
+ "type" = "portmap",
+ "capabilities" = {
+ "portMappings" = true
+ }
+ }
+ ]
+ }))
+
+ params = ["FLANNEL_NETWORK", "FLANNEL_SUBNET"]
+
+ domain_id = "domain-uuid"
+ account = "admin"
+}
+```
+
+## Argument Reference
+
+The following arguments are supported:
+
+### Required Arguments
+
+* `name` - (Required) The name of the CNI configuration. Must be unique within
the account/domain.
+* `cni_config` - (Required) The CNI configuration in base64-encoded JSON
format. This should contain the complete CNI plugin configuration according to
the CNI specification.
+
+### Optional Arguments
+
+* `params` - (Optional) A list of parameter names that can be substituted in
the CNI configuration. These parameters can be provided with actual values when
creating a Kubernetes cluster using `cni_config_details`.
+* `domain_id` - (Optional) The domain ID for the CNI configuration. If not
specified, uses the default domain.
+* `account` - (Optional) The account name for the CNI configuration. If not
specified, uses the account of the authenticated user.
+* `project_id` - (Optional) The project ID to assign the CNI configuration to.
+
+## Attributes Reference
+
+In addition to all arguments above, the following attributes are exported:
+
+* `id` - The ID of the CNI configuration.
+* `created` - The timestamp when the CNI configuration was created.
+* `domain` - The domain name where the CNI configuration belongs.
+* `project` - The project name if the CNI configuration is assigned to a
project.
+
+## CNI Configuration Format
+
+The `cni_config` should be a base64-encoded JSON string that follows the CNI
specification. The configuration supports parameter substitution using
placeholder names that can be defined in the `params` list.
+
+### Parameter Substitution
+
+Parameters in the CNI configuration can be specified as placeholders and will
be replaced with actual values when the configuration is used in a Kubernetes
cluster:
+
+```json
+{
+ "name": "k8s-pod-network",
+ "cniVersion": "0.3.1",
+ "plugins": [
+ {
+ "type": "calico",
+ "nodename": "KUBERNETES_NODE_NAME",
+ "mtu": "CNI_MTU"
+ }
+ ]
+}
+```
+
+The `KUBERNETES_NODE_NAME` and `CNI_MTU` placeholders will be replaced when
creating a cluster using this configuration.
+
+### Supported CNI Plugins
+
+CloudStack supports various CNI plugins including:
+
+* **Calico** - Provides networking and network policy for Kubernetes
+* **Flannel** - Simple overlay network for Kubernetes
+* **Weave** - Container networking solution
+* **Custom plugins** - Any CNI-compliant plugin can be configured
+
+## Usage with Kubernetes Clusters
+
+CNI configurations are used with Kubernetes clusters by referencing the
configuration ID:
+
+```hcl
+resource "cloudstack_kubernetes_cluster" "example" {
+ name = "example-cluster"
+ zone = "zone1"
+ kubernetes_version = "1.25.0"
+ service_offering = "Medium Instance"
+
+ cni_configuration_id = cloudstack_cni_configuration.calico.id
+ cni_config_details = {
+ "CNI_MTU" = "1450"
+ "KUBERNETES_NODE_NAME" = "spec.nodeName"
+ "KUBECONFIG_FILEPATH" = "/etc/cni/net.d/calico-kubeconfig"
+ }
+}
+```
+
+## Import
+
+CNI configurations can be imported using the configuration ID:
+
+```shell
+$ terraform import cloudstack_cni_configuration.example <CNI_CONFIGURATION_ID>
+```
diff --git a/website/docs/r/kubernetes_cluster.html.markdown
b/website/docs/r/kubernetes_cluster.html.markdown
index 8bb61c8..ac2ec62 100644
--- a/website/docs/r/kubernetes_cluster.html.markdown
+++ b/website/docs/r/kubernetes_cluster.html.markdown
@@ -3,31 +3,103 @@ layout: default
page_title: "CloudStack: cloudstack_kubernetes_cluster"
sidebar_current: "docs-cloudstack-resource-kubernetes_cluster"
description: |-
- Creates a Kubernetes Cluster
+ Creates and manages a CloudStack Kubernetes Service (CKS) cluster
---
# CloudStack: cloudstack_kubernetes_cluster
-A `cloudstack_kubernetes_cluster` resource manages a Kubernetes cluster within
CloudStack.
+A `cloudstack_kubernetes_cluster` resource manages a CloudStack Kubernetes
Service (CKS) cluster within CloudStack. This resource supports advanced
features including mixed node types, custom templates, CNI configurations, and
autoscaling.
## Example Usage
+### Basic Cluster
+
```hcl
-resource "cloudstack_kubernetes_cluster" "example" {
- name = "example-cluster"
- zone = "zone-id"
- kubernetes_version = "1.18.6"
- service_offering = "small"
- size = 1
- autoscaling_enabled = true
- min_size = 1
- max_size = 5
- control_nodes_size = 1
- description = "An example Kubernetes cluster"
- keypair = "my-ssh-key"
- network_id = "net-id"
- state = "Running"
- project = "my-project"
+resource "cloudstack_kubernetes_cluster" "basic" {
+ name = "basic-cluster"
+ zone = "zone1"
+ kubernetes_version = "1.25.0"
+ service_offering = "Medium Instance"
+ size = 3
+ description = "Basic Kubernetes cluster"
+}
+```
+
+### Advanced Cluster with CKS Features
+
+```hcl
+# Kubernetes version resource
+resource "cloudstack_kubernetes_version" "k8s_v1_25" {
+ semantic_version = "1.25.0"
+ name = "Kubernetes v1.25.0 with Calico"
+ url = "http://example.com/k8s-setup-v1.25.0.iso"
+ min_cpu = 2
+ min_memory = 2048
+ zone = "zone1"
+ state = "Enabled"
+}
+
+# CNI configuration
+resource "cloudstack_cni_configuration" "calico" {
+ name = "calico-cni-config"
+ cni_config = base64encode(jsonencode({
+ "name" = "k8s-pod-network",
+ "cniVersion" = "0.3.1",
+ "plugins" = [
+ {
+ "type" = "calico",
+ "datastore_type" = "kubernetes",
+ "nodename" = "KUBERNETES_NODE_NAME",
+ "mtu" = "CNI_MTU"
+ }
+ ]
+ }))
+
+ params = ["KUBERNETES_NODE_NAME", "CNI_MTU"]
+}
+
+# Advanced cluster with mixed node types
+resource "cloudstack_kubernetes_cluster" "advanced" {
+ name = "production-cluster"
+ zone = "zone1"
+ kubernetes_version = cloudstack_kubernetes_version.k8s_v1_25.semantic_version
+ service_offering = "Medium Instance"
+
+ # Cluster configuration
+ size = 3
+ control_nodes_size = 3
+ etcd_nodes_size = 3
+
+ # Autoscaling
+ autoscaling_enabled = true
+ min_size = 2
+ max_size = 10
+
+ # Node configuration
+ noderootdisksize = 50
+
+ # Mixed node offerings
+ node_offerings = {
+ "control" = "Large Instance"
+ "worker" = "Medium Instance"
+ "etcd" = "Medium Instance"
+ }
+
+ # Custom templates
+ node_templates = {
+ "control" = "ubuntu-20.04-k8s-template"
+ "worker" = "ubuntu-20.04-k8s-template"
+ }
+
+ # CNI Configuration
+ cni_configuration_id = cloudstack_cni_configuration.calico.id
+ cni_config_details = {
+ "CNI_MTU" = "1450"
+ "KUBERNETES_NODE_NAME" = "spec.nodeName"
+ }
+
+ description = "Production cluster with mixed node types"
+ hypervisor = "KVM"
}
```
@@ -36,43 +108,67 @@ resource "cloudstack_kubernetes_cluster" "example" {
The following arguments are supported:
+### Required Arguments
+
* `name` - (Required) The name of the Kubernetes cluster.
* `zone` - (Required) The zone where the Kubernetes cluster will be deployed.
* `kubernetes_version` - (Required) The Kubernetes version for the cluster.
* `service_offering` - (Required) The service offering for the nodes in the
cluster.
-* `size` - (Optional) The initial size of the Kubernetes cluster. Defaults to
`1`.
-* `autoscaling_enabled` - (Optional) Whether autoscaling is enabled for the
cluster.
-* `min_size` - (Optional) The minimum size of the Kubernetes cluster when
autoscaling is enabled.
-* `max_size` - (Optional) The maximum size of the Kubernetes cluster when
autoscaling is enabled.
-* `control_nodes_size` - (Optional) The size of the control nodes in the
cluster.
+
+### Basic Configuration
+
+* `size` - (Optional) The number of worker nodes in the Kubernetes cluster.
Defaults to `1`.
+* `control_nodes_size` - (Optional) The number of control plane nodes in the
cluster. Defaults to `1`.
+* `etcd_nodes_size` - (Optional) The number of etcd nodes in the cluster.
Defaults to `0` (uses control nodes for etcd).
* `description` - (Optional) A description for the Kubernetes cluster.
-* `keypair` - (Optional) The SSH key pair to use for the nodes in the cluster.
-* `network_id` - (Optional) The network ID to connect the Kubernetes cluster
to.
-* `ip_address` - (Computed) The IP address of the Kubernetes cluster.
-* `state` - (Optional) The state of the Kubernetes cluster. Defaults to
`"Running"`.
-* `project` - (Optional) The project to assign the Kubernetes cluster to.
-* `noderootdisksize` - (Optional) root disk size in GB for each node.
+* `hypervisor` - (Optional) The hypervisor type for the cluster nodes.
Defaults to `"KVM"`.
* `docker_registry_url` - (Optional) URL for the docker image private registry
* `docker_registry_username` - (Optional) password for the docker image
private registry
* `docker_registry_password"` - (Optional) user name for the docker image
private registry
+### Autoscaling Configuration
+
+* `autoscaling_enabled` - (Optional) Whether autoscaling is enabled for the
cluster. Defaults to `false`.
+* `min_size` - (Optional) The minimum number of worker nodes when autoscaling
is enabled.
+* `max_size` - (Optional) The maximum number of worker nodes when autoscaling
is enabled.
+
+### Node Configuration
+
+* `noderootdisksize` - (Optional) Root disk size in GB for each node. Defaults
to `20`.
+* `node_offerings` - (Optional) A map of node roles to service offerings.
Valid roles are `control`, `worker`, and `etcd`. If not specified, the main
`service_offering` is used for all nodes.
+* `node_templates` - (Optional) A map of node roles to instance templates.
Valid roles are `control`, `worker`, and `etcd`. If not specified, system VM
template will be used.
+
+### CNI Configuration
+
+* `cni_configuration_id` - (Optional) The ID of a CNI configuration to use for
the cluster. If not specified, the default CNI configuration will be used.
+* `cni_config_details` - (Optional) A map of CNI configuration parameter
values to substitute in the CNI configuration.
+
+### Network and Security
+
+* `keypair` - (Optional) The SSH key pair to use for the nodes in the cluster.
+* `network_id` - (Optional) The network ID to connect the Kubernetes cluster
to.
+
+### Project and Domain
+
+* `project` - (Optional) The project to assign the Kubernetes cluster to.
+* `domain_id` - (Optional) The domain ID for the cluster.
+* `account` - (Optional) The account name for the cluster.
+
## Attributes Reference
-The following attributes are exported:
+In addition to all arguments above, the following attributes are exported:
* `id` - The ID of the Kubernetes cluster.
-* `name` - The name of the Kubernetes cluster.
-* `description` - The description of the Kubernetes cluster.
-* `control_nodes_size` - The size of the control nodes in the cluster.
-* `size` - The size of the Kubernetes cluster.
-* `autoscaling_enabled` - Whether autoscaling is enabled for the cluster.
-* `min_size` - The minimum size of the Kubernetes cluster when autoscaling is
enabled.
-* `max_size` - The maximum size of the Kubernetes cluster when autoscaling is
enabled.
-* `keypair` - The SSH key pair used for the nodes in the cluster.
-* `network_id` - The network ID connected to the Kubernetes cluster.
-* `ip_address` - The IP address of the Kubernetes cluster.
-* `state` - The state of the Kubernetes cluster.
-* `project` - The project assigned to the Kubernetes cluster.
+* `ip_address` - The IP address of the Kubernetes cluster API server.
+* `state` - The current state of the Kubernetes cluster.
+* `created` - The timestamp when the cluster was created.
+* `zone_id` - The zone ID where the cluster is deployed.
+* `zone_name` - The zone name where the cluster is deployed.
+* `kubernetes_version_id` - The ID of the Kubernetes version used.
+* `service_offering_id` - The ID of the service offering used.
+* `master_nodes` - The number of master/control nodes in the cluster.
+* `cpu_number` - The number of CPUs allocated to the cluster.
+* `memory` - The amount of memory (in MB) allocated to the cluster.
## Import
diff --git a/website/docs/r/template.html.markdown
b/website/docs/r/template.html.markdown
index 1b2f8a6..52eb7fa 100644
--- a/website/docs/r/template.html.markdown
+++ b/website/docs/r/template.html.markdown
@@ -3,51 +3,98 @@ layout: "cloudstack"
page_title: "CloudStack: cloudstack_template"
sidebar_current: "docs-cloudstack-resource-template"
description: |-
- Registers an existing template into the CloudStack cloud.
+ Registers a template into the CloudStack cloud, including support for
CloudStack Kubernetes Service (CKS) templates.
---
# cloudstack_template
-Registers an existing template into the CloudStack cloud.
+Registers a template into the CloudStack cloud. This resource supports both
regular VM templates and specialized templates for CloudStack Kubernetes
Service (CKS) clusters.
## Example Usage
+### Basic Template
+
```hcl
resource "cloudstack_template" "centos64" {
name = "CentOS 6.4 x64"
format = "VHD"
hypervisor = "XenServer"
os_type = "CentOS 6.4 (64bit)"
- url = "http://someurl.com/template.vhd"
+ url = "http://example.com/template.vhd"
zone = "zone-1"
}
```
+### CKS Template for Kubernetes
+
+```hcl
+resource "cloudstack_template" "cks_ubuntu_template" {
+ name = "cks-ubuntu-2204-template"
+ display_text = "CKS Ubuntu 22.04 Template for Kubernetes"
+ url = "http://example.com/cks-ubuntu-2204-kvm.qcow2.bz2"
+ format = "QCOW2"
+ hypervisor = "KVM"
+ os_type = "Ubuntu 22.04 LTS"
+ zone = "zone1"
+
+ # CKS specific flag
+ for_cks = true
+
+ # Template properties
+ is_extractable = false
+ is_featured = false
+ is_public = false
+ password_enabled = true
+ is_dynamically_scalable = true
+
+ # Wait for template to be ready
+ is_ready_timeout = 1800
+
+ tags = {
+ Environment = "CKS"
+ Purpose = "Kubernetes"
+ OS = "Ubuntu-22.04"
+ }
+}
+```
+
## Argument Reference
The following arguments are supported:
+### Required Arguments
+
* `name` - (Required) The name of the template.
+* `format` - (Required) The format of the template. Valid values are `QCOW2`,
`RAW`, `VHD`, `OVA`, and `ISO`.
+* `hypervisor` - (Required) The target hypervisor for the template. Valid
values include `KVM`, `XenServer`, `VMware`, `Hyperv`, and `LXC`. Changing this
forces a new resource to be created.
+* `os_type` - (Required) The OS Type that best represents the OS of this
template.
+* `url` - (Required) The URL of where the template is hosted. Changing this
forces a new resource to be created.
-* `display_text` - (Optional) The display name of the template.
+### Optional Arguments
-* `format` - (Required) The format of the template. Valid values are `QCOW2`,
- `RAW`, and `VHD`.
+* `display_text` - (Optional) The display name of the template. If not
specified, defaults to the `name`.
+* `zone` - (Optional) The name or ID of the zone where this template will be
created. Changing this forces a new resource to be created.
+* `project` - (Optional) The name or ID of the project to create this template
for. Changing this forces a new resource to be created.
+* `account` - (Optional) The account name for the template.
+* `domain_id` - (Optional) The domain ID for the template.
-* `hypervisor` - (Required) The target hypervisor for the template. Changing
- this forces a new resource to be created.
+### CKS-Specific Arguments
-* `os_type` - (Required) The OS Type that best represents the OS of this
- template.
+* `for_cks` - (Optional) Set to `true` to indicate this template is for
CloudStack Kubernetes Service (CKS). CKS templates have special requirements
and capabilities. Defaults to `false`.
-* `url` - (Required) The URL of where the template is hosted. Changing this
- forces a new resource to be created.
+### Template Properties
-* `project` - (Optional) The name or ID of the project to create this template
for.
- Changing this forces a new resource to be created.
+* `is_dynamically_scalable` - (Optional) Set to indicate if the template
contains tools to support dynamic scaling of VM cpu/memory. Defaults to `false`.
+* `is_extractable` - (Optional) Set to indicate if the template is
extractable. Defaults to `false`.
+* `is_featured` - (Optional) Set to indicate if the template is featured.
Defaults to `false`.
+* `is_public` - (Optional) Set to indicate if the template is available for
all accounts. Defaults to `true`.
+* `password_enabled` - (Optional) Set to indicate if the template should be
password enabled. Defaults to `false`.
+* `sshkey_enabled` - (Optional) Set to indicate if the template supports SSH
key injection. Defaults to `false`.
+* `is_ready_timeout` - (Optional) The maximum time in seconds to wait until
the template is ready for use. Defaults to `300` seconds.
-* `zone` - (Optional) The name or ID of the zone where this template will be
created.
- Changing this forces a new resource to be created.
+### Metadata and Tagging
+
+* `tags` - (Optional) A mapping of tags to assign to the template.
* `is_dynamically_scalable` - (Optional) Set to indicate if the template
contains
tools to support dynamic scaling of VM cpu/memory (defaults false)
@@ -78,4 +125,40 @@ The following attributes are exported:
* `is_featured` - Set to "true" if the template is featured.
* `is_public` - Set to "true" if the template is public.
* `password_enabled` - Set to "true" if the template is password enabled.
-* `is_ready` - Set to "true" once the template is ready for use.
+* `is_ready` - Set to `true` once the template is ready for use.
+* `created` - The timestamp when the template was created.
+* `size` - The size of the template in bytes.
+* `checksum` - The checksum of the template.
+* `status` - The current status of the template.
+* `zone_id` - The zone ID where the template is registered.
+* `zone_name` - The zone name where the template is registered.
+* `account` - The account name owning the template.
+* `domain` - The domain name where the template belongs.
+* `project` - The project name if the template is assigned to a project.
+
+### Example CKS Template Usage
+
+```hcl
+# Data source to use existing CKS template
+data "cloudstack_template" "cks_template" {
+ template_filter = "executable"
+
+ filter {
+ name = "name"
+ value = "cks-ubuntu-2204-template"
+ }
+}
+
+# Use in Kubernetes cluster
+resource "cloudstack_kubernetes_cluster" "example" {
+ name = "example-cluster"
+ zone = "zone1"
+ kubernetes_version = "1.25.0"
+ service_offering = "Medium Instance"
+
+ node_templates = {
+ "control" = data.cloudstack_template.cks_template.name
+ "worker" = data.cloudstack_template.cks_template.name
+ }
+}
+```