Skip to content

Conversation

@Pearl1594
Copy link
Contributor

Addresses #242 (comment)

@CodeBleu
Copy link
Collaborator

@Pearl1594 Below you will see why I have a concern about the current state of #242 . I feel like there shouldn't be this many issues when "upgrading" the provider for things that will have ACL rules like this. I'm OK, with having to split up and replace ports to port, but even after that, there are a lot of issues. This is why originally I mentioned I had to delete all the rules and create them fresh ( which we shouldn't have to do )

Here were steps taken.

I used 0.5.0 initially and made sure all was good with TF plan.

I updated my TF binary to be the one created from this branch and ran plan

image

I then fixed the ports -> port with creating new rules and splitting them up. I originally had 7 rules and 2 of the rules had multiple ports in them.

This is the plan after that
image
image

Then I ran apply and get this
image

Then I immediately run another plan again to see what it shows and this is it
image
image

Tried to apply what it showed again, and I get this
image

resulting in this
image

When my original was this
image

@CodeBleu
Copy link
Collaborator

@Pearl1594 After deleting all rules and applying, I then tested doing things with rule_number 1 again and nothing for that rule will actually update, even though plan and apply in TF show successful. In CS, nothing is changed

However, I was able to change the rule_number of one of the other rules and it was able to see the correct rule_number and change it accordingly. So that's good! 😄

This worked:
image

But nothing on rule_number 1 will update
image

This rule still stays the same and no rule_number 9 even exists either
image

@Pearl1594
Copy link
Contributor Author

Pearl1594 commented Oct 15, 2025

Thanks @CodeBleu - taking your feedback, I tried to see if it was possible to map if the rules in the new schema (with port) matches existing ones and update it should there be any change, but was hitting with multiple issues, so I went ahead with a workflow of replacing the rules.

So this is how it works now

  1. Created an ACL with 4 rules using provider version 0.5.0 - such that this is how the state looks
$ terraform state show cloudstack_network_acl_rule.default
# cloudstack_network_acl_rule.default:
resource "cloudstack_network_acl_rule" "default" {
    acl_id      = "bc83887d-b84e-45c4-b1ee-8a5de3162368"
    id          = "bc83887d-b84e-45c4-b1ee-8a5de3162368"
    managed     = false
    parallelism = 2

    rule {
        action       = "allow"
        cidr_list    = [
            "10.0.0.0/24",
        ]
        icmp_code    = 0
        icmp_type    = 0
        ports        = [
            "2222-2224",
            "443",
            "80-81",
            "8080",
        ]
        protocol     = "tcp"
        traffic_type = "ingress"
        uuids        = {
            "2222-2224" = "ee243655-bcc6-40cf-8596-53c2083fd1de"
            "443"       = "57bba974-11b5-4dad-a714-7197bd8dd6c7"
            "80-81"     = "68b1db70-2cde-4912-95b6-4860ca49c2ce"
            "8080"      = "83b61cf7-45d6-46e1-965a-af08ef8cc0c0"
        }
    }
}

I then applied the new config, where I separated ports to the new schema - i.e., use port: And this is how it looks

$ terraform apply
╷
│ Warning: Provider development overrides are in effect
│ 
│ The following provider development overrides are set in the CLI configuration:
│  - hashicorp.com/dev/cloudstack in /home/pdsilva/sb/terraform/local-providers/hashicorp.com/dev/cloudstack/1.0.0/linux_amd64
│ 
│ The behavior may therefore not match any released version of the provider and applying changes may cause the state to become incompatible with published releases.
╵
cloudstack_vpc.default: Refreshing state... [id=9c3d41ae-95fd-4ec4-929d-e9328c79d2e6]
cloudstack_network_acl.default: Refreshing state... [id=bc83887d-b84e-45c4-b1ee-8a5de3162368]
cloudstack_network_acl_rule.default: Refreshing state... [id=bc83887d-b84e-45c4-b1ee-8a5de3162368]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # cloudstack_network_acl_rule.default must be replaced
-/+ resource "cloudstack_network_acl_rule" "default" {
      ~ id          = "bc83887d-b84e-45c4-b1ee-8a5de3162368" -> (known after apply)
        # (3 unchanged attributes hidden)

      ~ rule { # forces replacement
          ~ icmp_code    = 0 -> (known after apply)
          ~ icmp_type    = 0 -> (known after apply)
          + port         = "80-81"
          - ports        = [
              - "2222-2224",
              - "443",
              - "80-81",
              - "8080",
            ] -> null
          ~ rule_number  = 4 -> (known after apply)
          ~ uuids        = {
              - "2222-2224" = "ee243655-bcc6-40cf-8596-53c2083fd1de"
              - "443"       = "57bba974-11b5-4dad-a714-7197bd8dd6c7"
              - "80-81"     = "68b1db70-2cde-4912-95b6-4860ca49c2ce"
              - "8080"      = "83b61cf7-45d6-46e1-965a-af08ef8cc0c0"
            } -> (known after apply)
            # (5 unchanged attributes hidden)
        }
      + rule { # forces replacement
          + action       = "allow"
          + cidr_list    = [
              + "10.0.0.0/24",
            ]
          + icmp_code    = (known after apply)
          + icmp_type    = (known after apply)
          + port         = "8080"
          + protocol     = "tcp"
          + rule_number  = (known after apply)
          + traffic_type = "ingress"
          + uuids        = (known after apply)
        }
      + rule { # forces replacement
          + action       = "allow"
          + cidr_list    = [
              + "10.0.0.0/24",
            ]
          + icmp_code    = (known after apply)
          + icmp_type    = (known after apply)
          + port         = "443"
          + protocol     = "tcp"
          + rule_number  = 5
          + traffic_type = "ingress"
          + uuids        = (known after apply)
        }
      + rule { # forces replacement
          + action       = "allow"
          + cidr_list    = [
              + "10.0.0.0/24",
            ]
          + icmp_code    = (known after apply)
          + icmp_type    = (known after apply)
          + port         = "2222-2224"
          + protocol     = "tcp"
          + rule_number  = (known after apply)
          + traffic_type = "ingress"
          + uuids        = (known after apply)
        }
    }

Plan: 1 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

cloudstack_network_acl_rule.default: Destroying... [id=bc83887d-b84e-45c4-b1ee-8a5de3162368]
cloudstack_network_acl_rule.default: Destruction complete after 2s
cloudstack_network_acl_rule.default: Creating...
cloudstack_network_acl_rule.default: Creation complete after 2s [id=bc83887d-b84e-45c4-b1ee-8a5de3162368]

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

This results in the following in acs:
image

Then I attempt to update rule number 1:

l$ terraform apply
╷
│ Warning: Provider development overrides are in effect
│ 
│ The following provider development overrides are set in the CLI configuration:
│  - hashicorp.com/dev/cloudstack in /home/pdsilva/sb/terraform/local-providers/hashicorp.com/dev/cloudstack/1.0.0/linux_amd64
│ 
│ The behavior may therefore not match any released version of the provider and applying changes may cause the state to become incompatible with published releases.
╵
cloudstack_vpc.default: Refreshing state... [id=9c3d41ae-95fd-4ec4-929d-e9328c79d2e6]
cloudstack_network_acl.default: Refreshing state... [id=bc83887d-b84e-45c4-b1ee-8a5de3162368]
cloudstack_network_acl_rule.default: Refreshing state... [id=bc83887d-b84e-45c4-b1ee-8a5de3162368]

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:

  # cloudstack_network_acl_rule.default will be updated in-place
  ~ resource "cloudstack_network_acl_rule" "default" {
        id          = "bc83887d-b84e-45c4-b1ee-8a5de3162368"
        # (3 unchanged attributes hidden)

      ~ rule {
          + description  = "updating rule number from 1 -> 7"
          ~ rule_number  = 1 -> 7
            # (9 unchanged attributes hidden)
        }

        # (3 unchanged blocks 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

cloudstack_network_acl_rule.default: Modifying... [id=bc83887d-b84e-45c4-b1ee-8a5de3162368]
cloudstack_network_acl_rule.default: Modifications complete after 1s [id=bc83887d-b84e-45c4-b1ee-8a5de3162368]

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

Outputs:

acl_id = "bc83887d-b84e-45c4-b1ee-8a5de3162368"
vpc_id = "9c3d41ae-95fd-4ec4-929d-e9328c79d2e6"

Successfully updated rule 1 , and is seen on ACS as well:

image

Do you see this as an acceptable workflow @CodeBleu ?

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.

@Pearl1594

I am observing that existing acl rules are deleted and created or added again after upgrading the provider

With terraform provider 0.5.0 release and the following config.

Created acl rules

terraform {
  required_providers {
    cloudstack = {
      source = "cloudstack/cloudstack"
      version = "0.5.0"
    }

}
}
resource "cloudstack_network_acl_rule" "test" {
  acl_id = "1f1d916b-30c3-41bd-bc00-88cef443a0e2"


  rule {
    
    action       = "allow"
    cidr_list    = ["10.0.0.0/24"]
    protocol     = "tcp"
    ports       = ["81-83"]
    traffic_type = "ingress"
    
  }

  rule {
    
    action       = "allow"
    cidr_list    = ["10.0.0.0/24"]
    protocol     = "tcp"
    ports        = ["2222-2223"]
    traffic_type = "ingress"
    
  }

  rule {
    
    action       = "allow"
    cidr_list    = ["10.0.0.0/24"]
    protocol     = "tcp"
    ports        = ["8081"]
    traffic_type = "ingress"
    
  }

  rule {
    
    action       = "allow"
    cidr_list    = ["10.0.0.0/24"]
    protocol     = "tcp"
    ports        = ["8086"]
    traffic_type = "egress"
    
  }
}
mysql> select * from network_acl_item;
+----+--------------------------------------+--------+------------+----------+--------+----------+---------------------+-----------+-----------+--------------+--------+--------+---------+--------+
| id | uuid                                 | acl_id | start_port | end_port | state  | protocol | created             | icmp_code | icmp_type | traffic_type | number | action | display | reason |
+----+--------------------------------------+--------+------------+----------+--------+----------+---------------------+-----------+-----------+--------------+--------+--------+---------+--------+
| 63 | 99cbb31a-5ffe-4fa3-b8d6-8382fc01ecb8 |     11 |       8086 |     8086 | Active | tcp      | 2025-10-16 07:21:58 |      NULL |      NULL | Egress       |      1 | Allow  |       1 | NULL   |
| 64 | ff35f826-2164-48ca-ad6c-9394bdb85d08 |     11 |       2222 |     2223 | Active | tcp      | 2025-10-16 07:21:58 |      NULL |      NULL | Ingress      |      2 | Allow  |       1 | NULL   |
| 65 | 22896291-6a17-40ed-b65e-f8caa852af25 |     11 |         81 |       83 | Active | tcp      | 2025-10-16 07:21:59 |      NULL |      NULL | Ingress      |      3 | Allow  |       1 | NULL   |
| 66 | 006b69b3-43fe-4323-bf72-ea3d1a6bebdc |     11 |       8081 |     8081 | Active | tcp      | 2025-10-16 07:21:59 |      NULL |      NULL | Ingress      |      4 | Allow  |       1 | NULL   |
+----+--------------------------------------+--------+------------+----------+--------+----------+---------------------+-----------+-----------+--------------+--------+--------+---------+--------+
4 rows in set (0.00 sec)

based on ur pr , built the terraform binary locally and updated the following config


terraform {
  required_providers {
    cloudstack = {
      source = "localdomain/provider/cloudstack"
      version = "0.4.0"
    }

}
}


resource "cloudstack_network_acl_rule" "test" {
  acl_id = "1f1d916b-30c3-41bd-bc00-88cef443a0e2"


  rule {
    
    action       = "allow"
    cidr_list    = ["10.0.0.0/24"]
    protocol     = "tcp"
    port       = "81-83"
    traffic_type = "ingress"
    
  }

  rule {
    
    action       = "allow"
    cidr_list    = ["10.0.0.0/24"]
    protocol     = "tcp"
    port        = "2222-2223"
    traffic_type = "ingress"
    
  }

  rule {
    
    action       = "allow"
    cidr_list    = ["10.0.0.0/24"]
    protocol     = "tcp"
    port        = "8081"
    traffic_type = "ingress"
    
  }

  rule {
    
    action       = "allow"
    cidr_list    = ["10.0.0.0/24"]
    protocol     = "tcp"
    port        = "8086"
    traffic_type = "egress"
    
  }
}

Did terraform upgrade

terraform init --upgrade
Initializing the backend...
Initializing provider plugins...
- Finding localdomain/provider/cloudstack versions matching "0.4.0"...
- Finding latest version of cloudstack/cloudstack...
- Installing localdomain/provider/cloudstack v0.4.0...
- Installed localdomain/provider/cloudstack v0.4.0 (unauthenticated)
- Using previously-installed cloudstack/cloudstack v0.5.0
Terraform has made some changes to the provider dependency selections recorded
in the .terraform.lock.hcl file. Review those changes and commit them to your
version control system if they represent changes you intended to make.

Terraform apply

terraform apply         
cloudstack_network_acl_rule.test: Refreshing state... [id=1f1d916b-30c3-41bd-bc00-88cef443a0e2]

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:

  # cloudstack_network_acl_rule.test will be updated in-place
  ~ resource "cloudstack_network_acl_rule" "test" {
        id          = "1f1d916b-30c3-41bd-bc00-88cef443a0e2"
        # (3 unchanged attributes hidden)

      ~ rule {
          + port         = "81-83"
          ~ ports        = [
              - "2222-2223",
            ]
            # (9 unchanged attributes hidden)
        }
      ~ rule {
          + port         = "2222-2223"
          ~ ports        = [
              - "8081",
            ]
            # (9 unchanged attributes hidden)
        }
      ~ rule {
          + port         = "8081"
          ~ ports        = [
              - "8086",
            ]
          ~ traffic_type = "egress" -> "ingress"
            # (8 unchanged attributes hidden)
        }
      ~ rule {
          + port         = "8086"
          ~ ports        = [
              - "81-83",
            ]
          ~ traffic_type = "ingress" -> "egress"
            # (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

cloudstack_network_acl_rule.test: Modifying... [id=1f1d916b-30c3-41bd-bc00-88cef443a0e2]
cloudstack_network_acl_rule.test: Modifications complete after 8s [id=1f1d916b-30c3-41bd-bc00-88cef443a0e2]

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

New resources got created

mysql> select * from network_acl_item;
+----+--------------------------------------+--------+------------+----------+--------+----------+---------------------+-----------+-----------+--------------+--------+--------+---------+--------+
| id | uuid                                 | acl_id | start_port | end_port | state  | protocol | created             | icmp_code | icmp_type | traffic_type | number | action | display | reason |
+----+--------------------------------------+--------+------------+----------+--------+----------+---------------------+-----------+-----------+--------------+--------+--------+---------+--------+
| 67 | d38f29e1-207b-4456-8e5c-e995bcc6d985 |     11 |         81 |       83 | Active | tcp      | 2025-10-16 07:24:29 |      NULL |      NULL | Ingress      |      2 | Allow  |       1 | NULL   |
| 68 | a6685e26-62e8-4a00-8e11-5299f4805a11 |     11 |       2222 |     2223 | Active | tcp      | 2025-10-16 07:24:29 |      NULL |      NULL | Ingress      |      4 | Allow  |       1 | NULL   |
| 69 | f2792fb8-2454-4da7-904b-d2487ccb5abb |     11 |       8081 |     8081 | Active | tcp      | 2025-10-16 07:24:30 |      NULL |      NULL | Ingress      |      1 | Allow  |       1 | NULL   |
| 70 | 454d4d66-8c9c-4038-a646-1c07c3f83314 |     11 |       8086 |     8086 | Active | tcp      | 2025-10-16 07:24:30 |      NULL |      NULL | Egress       |      3 | Allow  |       1 | NULL   |
+----+--------------------------------------+--------+------------+----------+--------+----------+---------------------+-----------+-----------+--------------+--------+--------+---------+--------+
4 rows in set (0.00 sec)

Now add a rule_number to one of the rules another 4 acl rules got created


    action       = "allow"
    cidr_list    = ["10.0.0.0/24"]
    protocol     = "tcp"
    port        = "8086"
    traffic_type = "egress"
    rule_number = 190

mysql> select * from network_acl_item;
+----+--------------------------------------+--------+------------+----------+--------+----------+---------------------+-----------+-----------+--------------+--------+--------+---------+--------+
| id | uuid                                 | acl_id | start_port | end_port | state  | protocol | created             | icmp_code | icmp_type | traffic_type | number | action | display | reason |
+----+--------------------------------------+--------+------------+----------+--------+----------+---------------------+-----------+-----------+--------------+--------+--------+---------+--------+
| 67 | d38f29e1-207b-4456-8e5c-e995bcc6d985 |     11 |         81 |       83 | Active | tcp      | 2025-10-16 07:24:29 |      NULL |      NULL | Ingress      |      2 | Allow  |       1 | NULL   |
| 68 | a6685e26-62e8-4a00-8e11-5299f4805a11 |     11 |       2222 |     2223 | Active | tcp      | 2025-10-16 07:24:29 |      NULL |      NULL | Ingress      |      4 | Allow  |       1 | NULL   |
| 69 | f2792fb8-2454-4da7-904b-d2487ccb5abb |     11 |       8081 |     8081 | Active | tcp      | 2025-10-16 07:24:30 |      NULL |      NULL | Ingress      |      1 | Allow  |       1 | NULL   |
| 70 | 454d4d66-8c9c-4038-a646-1c07c3f83314 |     11 |       8086 |     8086 | Active | tcp      | 2025-10-16 07:24:30 |      NULL |      NULL | Egress       |      3 | Allow  |       1 | NULL   |
| 71 | faa678c2-7538-484b-a268-6d665e0519e4 |     11 |         81 |       83 | Active | tcp      | 2025-10-16 07:27:47 |      NULL |      NULL | Ingress      |      5 | Allow  |       1 | NULL   |
| 72 | 4569c2d8-3a80-4a48-a943-e40dab7992a0 |     11 |       2222 |     2223 | Active | tcp      | 2025-10-16 07:27:48 |      NULL |      NULL | Ingress      |      6 | Allow  |       1 | NULL   |
| 73 | 74031fc7-18cd-48b3-83f2-9e2136583847 |     11 |       8081 |     8081 | Active | tcp      | 2025-10-16 07:27:48 |      NULL |      NULL | Ingress      |      7 | Allow  |       1 | NULL   |
| 74 | 953c1734-d701-4408-9c17-b6a4aea8c947 |     11 |       8086 |     8086 | Active | tcp      | 2025-10-16 07:27:49 |      NULL |      NULL | Egress       |    190 | Allow  |       1 | NULL   |
+----+--------------------------------------+--------+------------+----------+--------+----------+---------------------+-----------+-----------+--------------+--------+--------+---------+--------+
8 rows in set (0.00 sec)

@kiranchavala
Copy link
Collaborator

@Pearl1594

Strangely not hitting when i use your config

resource "cloudstack_network_acl_rule" "default" {
  acl_id = cloudstack_network_acl.default.id

  rule {
    action       = "allow"
    cidr_list    = ["10.0.0.0/24"]
    protocol     = "tcp"
    ports        = ["80-81", "8080", "443", "2222-2224"]
    traffic_type = "ingress"
  }
}

Afer terraform init upgrade


resource "cloudstack_network_acl_rule" "default" {
  acl_id = cloudstack_network_acl.default.id

  rule {
    action       = "allow"
    cidr_list    = ["10.0.0.0/24"]
    protocol     = "tcp"
    port         = "80-81"
    traffic_type = "ingress"
  }
 
  rule {
    action       = "allow"
    cidr_list    = ["10.0.0.0/24"]
    protocol     = "tcp"
    port         = "8080"
    traffic_type = "ingress"
  }

  rule {
    action       = "allow"
    cidr_list    = ["10.0.0.0/24"]
    protocol     = "tcp"
    port         = "443"
    traffic_type = "ingress"
    rule_number  = 5
  }

  rule {
    action       = "allow"
    cidr_list    = ["10.0.0.0/24"]
    protocol     = "tcp"
    port         = "2222-2224"
    traffic_type = "ingress"
  }
}

@CodeBleu
Copy link
Collaborator

CodeBleu commented Oct 16, 2025

@Pearl1594 I was actually doing other TF work and still using this PR provider code and saw the following that was a concern. If I revert my provider version back, I do not see that replace/destroy

OpenTofu will perform the following actions:

  # cloudstack_kubernetes_cluster.tf-capi-mgmt-1[0] will be created
  + resource "cloudstack_kubernetes_cluster" "tf-capi-mgmt-1" {
      + autoscaling_enabled = false
      + control_nodes_size  = 3
      + description         = "An HA example Kubernetes cluster-TF"
      + id                  = (known after apply)
      + ip_address          = (known after apply)
      + keypair             = "ace-g2lt"
      + kubernetes_version  = "1.28.4"
      + max_size            = 5
      + min_size            = 1
      + name                = "tf-capi-mgmt-1"
      + network_id          = "b01e0a11-45a7-4ade-9040-f050f15e4521"
      + noderootdisksize    = 8
      + service_offering    = "ACE 2 vCPU 4GB Ram - c0 - local"
      + size                = 1
      + state               = "Running"
      + zone                = "us-west-0b"
    }

  # cloudstack_kubernetes_cluster.tf-k8s must be replaced
-/+ resource "cloudstack_kubernetes_cluster" "tf-k8s" {
      - account             = "n8widgets" -> null # forces replacement
      - domain_id           = "5b3f11f0-ef3b-4c0d-9960-c41527bf73a4" -> null # forces replacement
      - etcd_nodes_size     = 0 -> null
      ~ id                  = "512e47c5-5b74-4ed5-9c1a-309e77f0e9e7" -> (known after apply)
      ~ ip_address          = "1.1.1.1" -> (known after apply)
        name                = "tf-k8s-cluster"
        # (13 unchanged attributes hidden)
    }

Plan: 2 to add, 0 to change, 1 to destroy.
╷
│ Warning: Argument is deprecated
│
│   with cloudstack_network_acl_rule.net-acl-rules,
│   on net-acl.tf line 34, in resource "cloudstack_network_acl_rule" "net-acl-rules":
│   34:     ports        = ["22"]
│
│ Use 'port' instead. The 'ports' field is deprecated and will be removed in a future version.
│
│ (and one more similar warning elsewhere)

I went ahead to change it from ports -> port and get the following:

OpenTofu will perform the following actions:

  # cloudstack_kubernetes_cluster.tf-capi-mgmt-1[0] will be created
  + resource "cloudstack_kubernetes_cluster" "tf-capi-mgmt-1" {
      + autoscaling_enabled = false
      + control_nodes_size  = 3
      + description         = "An HA example Kubernetes cluster-TF"
      + id                  = (known after apply)
      + ip_address          = (known after apply)
      + keypair             = "ace-g2lt"
      + kubernetes_version  = "1.28.4"
      + max_size            = 5
      + min_size            = 1
      + name                = "tf-capi-mgmt-1"
      + network_id          = "b01e0a11-45a7-4ade-9040-f050f15e4521"
      + noderootdisksize    = 8
      + service_offering    = "ACE 2 vCPU 4GB Ram - c0 - local"
      + size                = 1
      + state               = "Running"
      + zone                = "us-west-0b"
    }

  # cloudstack_kubernetes_cluster.tf-k8s must be replaced
-/+ resource "cloudstack_kubernetes_cluster" "tf-k8s" {
      - account             = "n8widgets" -> null # forces replacement
      - domain_id           = "5b3f11f0-ef3b-4c0d-9960-c41527bf73a4" -> null # forces replacement
      - etcd_nodes_size     = 0 -> null
      ~ id                  = "512e47c5-5b74-4ed5-9c1a-309e77f0e9e7" -> (known after apply)
      ~ ip_address          = "1.1.1.1" -> (known after apply)
        name                = "tf-k8s-cluster"
        # (13 unchanged attributes hidden)
    }

  # cloudstack_network_acl_rule.net-acl-rules will be updated in-place
  ~ resource "cloudstack_network_acl_rule" "net-acl-rules" {
        id          = "8590d921-9972-4a71-9d28-e4b5616faed2"
        # (3 unchanged attributes hidden)

      ~ rule {
          + port         = "22"
          ~ ports        = [
              - "22",
            ]
            # (8 unchanged attributes hidden)
        }

        # (1 unchanged block hidden)
    }

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

I would assume the ACL rule updates should NOT impact other things like this

@Pearl1594
Copy link
Contributor Author

@CodeBleu Is this the latest code change that you were testing with? And by reverting you provider version back - you mean to version 0.5.0?

@CodeBleu
Copy link
Collaborator

CodeBleu commented Oct 16, 2025

@CodeBleu Is this the latest code change that you were testing with? And by reverting you provider version back - you mean to version 0.5.0?

@Pearl1594
Yes to 0.5.0 and
Yes, I tested with the latest code change here, original code change here and the regular 0.6.0-rc3 as well. They all behave the same on my last comment.

@kiranchavala
Copy link
Collaborator

@CodeBleu could you please share you terraform config , so that I can test it out

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

Followed the same steps mentioned in the comment and works fine

#245 (review)

When a end user does a upgrade from ( 0.5 to 0.6 ) release

terraform init --upgrade

The migration happens from ports to port - terrafrom will delete and recreate the same acl rules

Because during migration from ports to port, one may decide to add rule_number and description parameter

In order to keep it simple, terraform deletes and recreates the same acl rules

The issue will not occur if the user decides to modify / add new rules, on the same release of 0.6

Terraform does not delete and recreate the rules

@kiranchavala
Copy link
Collaborator

@CodeBleu Also, i would suggest limiting testing only to terraform for now and ignore opentofu

Also support is only included terraform provider upgrade i.e 0.5 to 0.6 and not for downgrade of provider i.e 0.6 to 0.5

@CodeBleu
Copy link
Collaborator

@CodeBleu Also, i would suggest limiting testing only to terraform for now and ignore opentofu

Also support is only included terraform provider upgrade i.e 0.5 to 0.6 and not for downgrade of provider i.e 0.6 to 0.5

@kiranchavala
I need opentofu. This should be something we are supporting and testing from the get go. I would really like that when a release is cut, that one is cut for opentofu too. There are a lot of people using OpenTofu now and we should be treating that as a first class citizen as well IMHO.

@CodeBleu
Copy link
Collaborator

@CodeBleu could you please share you terraform config , so that I can test it out

My biggest concern is why does upgrading the provider cause it to want to delete/replace my k8s cluster?

  # cloudstack_kubernetes_cluster.tf-k8s must be replaced
-/+ resource "cloudstack_kubernetes_cluster" "tf-k8s" {
      - account             = "n8widgets" -> null # forces replacement
      - domain_id           = "5b3f11f0-ef3b-4c0d-9960-c41527bf73a4" -> null # forces replacement
      - etcd_nodes_size     = 0 -> null
      ~ id                  = "512e47c5-5b74-4ed5-9c1a-309e77f0e9e7" -> (known after apply)
      ~ ip_address          = "1.1.1.1" -> (known after apply)
        name                = "tf-k8s-cluster"
        # (13 unchanged attributes hidden)
    }

My terraform code is a lot more than this, but this is the parts that are being impacted when I test.

k8s.tf

resource "cloudstack_kubernetes_cluster" "tf-k8s" {
    name = "tf-k8s-cluster"
    zone = "us-west-0b"
    kubernetes_version = "1.27.3"
    service_offering = "ACE 2 vCPU 4GB Ram - c0 - local"
    size = 1
    autoscaling_enabled = true
    min_size = 1
    max_size = 5
    control_nodes_size = 1
    description = "An example Kubernetes cluster-TF"
    keypair = "ace-g2lt"
    network_id = cloudstack_network.capi-mgmt-net-1.id
    state = "Running"
    depends_on = [
        cloudstack_network.capi-mgmt-net-1
    ]
}

acl.tf

resource "cloudstack_network_acl_rule" "net-acl-rules" {
  acl_id = cloudstack_network_acl.net_acl.id

  rule {
    action       = "allow"
    cidr_list    = ["10.0.0.0/16"]
    protocol     = "tcp"
    ports        = ["22"] < - original
    # port        = "22" < - testing with new
    traffic_type = "ingress"
  }
  rule {
    action       = "allow"
    cidr_list    = ["10.0.0.0/16"]
    protocol     = "icmp"
    traffic_type = "ingress"
  }
}

@Pearl1594
Copy link
Contributor Author

This change you are observing with cks cluster - is most likely unrelated to the acl rule resource.

@CodeBleu
Copy link
Collaborator

This change you are observing with cks cluster - is most likely unrelated to the acl rule resource.

@Pearl1594 Only change is the updated provider from here! So, how is it not related to the new provider version?

@Pearl1594
Copy link
Contributor Author

Was the diff in CKS resource not observed on the 0.6.0-rc3 version? I haven't tested it, I'll give it a go; I've been testing just the network ACL rules with this PR.

@CodeBleu
Copy link
Collaborator

Was the diff in CKS resource not observed on the 0.6.0-rc3 version? I haven't tested it, I'll give it a go; I've been testing just the network ACL rules with this PR.

Yes. This is what I saying here.
#245 (comment)

@Pearl1594
Copy link
Contributor Author

Pearl1594 commented Oct 16, 2025

My apologies @CodeBleu - I didn't understand that comment previously. I've tried addressing that issue now by adding some checks to the cloudstack_kubernetes_cluster resource read function to set the state parameters accordingly. Hope this will address the issue. It would be helpful if you could also review it. Thanks

@kiranchavala
Copy link
Collaborator

@CodeBleu @Pearl1594

I have also tested with cks resource and with the latest build found that cks resource is not affected

  1. With terraform provider 0.5 release

Deploy a cks cluster in a vpc network and add a acl rule


resource "cloudstack_vpc" "default" {
  name         = "test-vpc-cks3"
  cidr         = "10.0.0.0/16"
  vpc_offering = "Default VPC offering"
  zone         = "4c5a0032-9270-4e4b-9dd0-4b861e8b7e19"
}



resource "cloudstack_network" "default" {
  name             = "test-network"
  cidr             = "10.0.0.0/24"
  network_offering = "DefaultIsolatedNetworkOfferingForVpcNetworks"
  zone             = "4c5a0032-9270-4e4b-9dd0-4b861e8b7e19"
  vpc_id = cloudstack_vpc.default.id
  acl_id = cloudstack_network_acl.default.id
  depends_on = [ cloudstack_vpc.default,cloudstack_network_acl.default ]
}


resource "cloudstack_network_acl" "default" {
  name   = "test-acl-cks"
  vpc_id = cloudstack_vpc.default.id
  depends_on = [ cloudstack_vpc.default ]
}



resource "cloudstack_network_acl_rule" "default" {
  acl_id = cloudstack_network_acl.default.id

 rule {
    action       = "allow"
    cidr_list    = ["10.0.0.0/16"]
    protocol     = "tcp"
    ports        = ["22"]
    traffic_type = "ingress"
  }
  rule {
    action       = "allow"
    cidr_list    = ["10.0.0.0/16"]
    protocol     = "icmp"
    traffic_type = "ingress"
  }
}


resource "cloudstack_kubernetes_cluster" "example" {
    name = "example-cluster"
    zone = "4c5a0032-9270-4e4b-9dd0-4b861e8b7e19"
    kubernetes_version = "v1.33.1"
    service_offering = "CKS"
    size = 1
    control_nodes_size = 1
    description = "An example Kubernetes cluster"
    network_id = cloudstack_network.default.id
    depends_on = [
        cloudstack_vpc.default,cloudstack_network.default,cloudstack_network_acl.default
    ]
    
}

output "vpc_id" {
   value= cloudstack_vpc.default.id
}

output "acl_id" {
   value= cloudstack_network_acl.default.id   
}

output "network_id" {
   value= cloudstack_network.default.id   
}

output "kubernetes_id" {
   value= cloudstack_kubernetes_cluster.example.id
}

  1. Terraform apply
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_kubernetes_cluster.example will be created
  + resource "cloudstack_kubernetes_cluster" "example" {
      + control_nodes_size = 1
      + description        = "An example Kubernetes cluster"
      + id                 = (known after apply)
      + ip_address         = (known after apply)
      + kubernetes_version = "v1.33.1"
      + name               = "example-cluster"
      + network_id         = (known after apply)
      + noderootdisksize   = 8
      + service_offering   = "CKS"
      + size               = 1
      + state              = (known after apply)
      + zone               = "4c5a0032-9270-4e4b-9dd0-4b861e8b7e19"
    }

  # cloudstack_network.default will be created
  + resource "cloudstack_network" "default" {
      + acl_id                = (known after apply)
      + cidr                  = "10.0.0.0/24"
      + display_text          = (known after apply)
      + endip                 = (known after apply)
      + gateway               = (known after apply)
      + id                    = (known after apply)
      + name                  = "test-network"
      + network_domain        = (known after apply)
      + network_offering      = "DefaultIsolatedNetworkOfferingForVpcNetworks"
      + project               = (known after apply)
      + source_nat_ip_address = (known after apply)
      + source_nat_ip_id      = (known after apply)
      + startip               = (known after apply)
      + tags                  = (known after apply)
      + vpc_id                = (known after apply)
      + zone                  = "4c5a0032-9270-4e4b-9dd0-4b861e8b7e19"
    }

  # cloudstack_network_acl.default will be created
  + resource "cloudstack_network_acl" "default" {
      + description = (known after apply)
      + id          = (known after apply)
      + name        = "test-acl-cks"
      + vpc_id      = (known after apply)
    }

  # cloudstack_network_acl_rule.default will be created
  + resource "cloudstack_network_acl_rule" "default" {
      + acl_id      = (known after apply)
      + id          = (known after apply)
      + managed     = false
      + parallelism = 2

      + rule {
          + action       = "allow"
          + cidr_list    = [
              + "10.0.0.0/16",
            ]
          + icmp_code    = (known after apply)
          + icmp_type    = (known after apply)
          + ports        = [
              + "22",
            ]
          + protocol     = "tcp"
          + traffic_type = "ingress"
          + uuids        = (known after apply)
        }
      + rule {
          + action       = "allow"
          + cidr_list    = [
              + "10.0.0.0/16",
            ]
          + icmp_code    = (known after apply)
          + icmp_type    = (known after apply)
          + ports        = []
          + protocol     = "icmp"
          + traffic_type = "ingress"
          + uuids        = (known after apply)
        }
    }

  # cloudstack_vpc.default will be created
  + resource "cloudstack_vpc" "default" {
      + cidr           = "10.0.0.0/16"
      + display_text   = (known after apply)
      + id             = (known after apply)
      + name           = "test-vpc-cks3"
      + network_domain = (known after apply)
      + project        = (known after apply)
      + source_nat_ip  = (known after apply)
      + tags           = (known after apply)
      + vpc_offering   = "Default VPC offering"
      + zone           = "4c5a0032-9270-4e4b-9dd0-4b861e8b7e19"
    }

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

Changes to Outputs:
  + acl_id        = (known after apply)
  + kubernetes_id = (known after apply)
  + network_id    = (known after apply)
  + vpc_id        = (known after apply)

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_vpc.default: Creating...
cloudstack_vpc.default: Still creating... [00m10s elapsed]
cloudstack_vpc.default: Still creating... [00m20s elapsed]
cloudstack_vpc.default: Still creating... [00m30s elapsed]
cloudstack_vpc.default: Still creating... [00m40s elapsed]
cloudstack_vpc.default: Still creating... [00m50s elapsed]
cloudstack_vpc.default: Creation complete after 59s [id=f00f04c6-abc4-454f-a91f-2846dda3fb55]
cloudstack_network_acl.default: Creating...
cloudstack_network_acl.default: Creation complete after 0s [id=5bb5989d-5830-4fd3-9157-94bc7dfb524e]
cloudstack_network.default: Creating...
cloudstack_network_acl_rule.default: Creating...
cloudstack_network.default: Creation complete after 1s [id=12d27633-7c32-4bcb-9c2c-3f8177fc3efe]
cloudstack_kubernetes_cluster.example: Creating...
cloudstack_network_acl_rule.default: Creation complete after 2s [id=5bb5989d-5830-4fd3-9157-94bc7dfb524e]
cloudstack_kubernetes_cluster.example: Still creating... [00m10s elapsed]
cloudstack_kubernetes_cluster.example: Still creating... [00m20s elapsed]
cloudstack_kubernetes_cluster.example: Still creating... [00m30s elapsed]
cloudstack_kubernetes_cluster.example: Still creating... [00m40s elapsed]
cloudstack_kubernetes_cluster.example: Still creating... [00m50s elapsed]
cloudstack_kubernetes_cluster.example: Still creating... [01m00s elapsed]
cloudstack_kubernetes_cluster.example: Still creating... [01m10s elapsed]
cloudstack_kubernetes_cluster.example: Still creating... [01m20s elapsed]
cloudstack_kubernetes_cluster.example: Still creating... [01m30s elapsed]
cloudstack_kubernetes_cluster.example: Still creating... [01m40s elapsed]
cloudstack_kubernetes_cluster.example: Still creating... [01m50s elapsed]
cloudstack_kubernetes_cluster.example: Still creating... [02m00s elapsed]
cloudstack_kubernetes_cluster.example: Still creating... [02m10s elapsed]
cloudstack_kubernetes_cluster.example: Still creating... [02m20s elapsed]
cloudstack_kubernetes_cluster.example: Still creating... [02m30s elapsed]
cloudstack_kubernetes_cluster.example: Still creating... [02m40s elapsed]
cloudstack_kubernetes_cluster.example: Still creating... [02m50s elapsed]
cloudstack_kubernetes_cluster.example: Still creating... [03m00s elapsed]
cloudstack_kubernetes_cluster.example: Creation complete after 3m5s [id=d96961fa-c742-4980-89c1-993d496d0fa0]

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

Outputs:

acl_id = "5bb5989d-5830-4fd3-9157-94bc7dfb524e"
kubernetes_id = "d96961fa-c742-4980-89c1-993d496d0fa0"
network_id = "12d27633-7c32-4bcb-9c2c-3f8177fc3efe"
vpc_id = "f00f04c6-abc4-454f-a91f-2846dda3fb55"

  1. Upgrade the provider to the latest build for the pr

terraform init --upgrade

terraform init --upgrade
Initializing the backend...
Initializing provider plugins...
- Finding localdomain/provider/cloudstack versions matching "0.4.0"...
- Finding latest version of cloudstack/cloudstack...
- Installing localdomain/provider/cloudstack v0.4.0...
- Installed localdomain/provider/cloudstack v0.4.0 (unauthenticated)
- Using previously-installed cloudstack/cloudstack v0.5.0
Terraform has made some changes to the provider dependency selections recorded
in the .terraform.lock.hcl file. Review those changes and commit them to your
version control system if they represent changes you intended to make.

╷
│ Warning: Incomplete lock file information for providers
│ 
│ Due to your customized provider installation methods, Terraform was forced to calculate lock file checksums locally for the following providers:
│   - localdomain/provider/cloudstack
│ 
│ The current .terraform.lock.hcl file only includes checksums for darwin_arm64, so Terraform running on another platform will fail to install these providers.
│ 
│ To calculate additional checksums for another platform, run:
│   terraform providers lock -platform=linux_amd64
│ (where linux_amd64 is the platform to generate)
╵
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.

  1. Change the value from ports to port for the acl rule
resource "cloudstack_network_acl_rule" "default" {
  acl_id = cloudstack_network_acl.default.id

 rule {
    action       = "allow"
    cidr_list    = ["10.0.0.0/16"]
    protocol     = "tcp"
    port        = "22"
    traffic_type = "ingress"
  }
  rule {
    action       = "allow"
    cidr_list    = ["10.0.0.0/16"]
    protocol     = "icmp"
    traffic_type = "ingress"
  }
}
  1. terraform apply
 terraform apply         
cloudstack_vpc.default: Refreshing state... [id=f00f04c6-abc4-454f-a91f-2846dda3fb55]
cloudstack_network_acl.default: Refreshing state... [id=5bb5989d-5830-4fd3-9157-94bc7dfb524e]
cloudstack_network.default: Refreshing state... [id=12d27633-7c32-4bcb-9c2c-3f8177fc3efe]
cloudstack_network_acl_rule.default: Refreshing state... [id=5bb5989d-5830-4fd3-9157-94bc7dfb524e]
cloudstack_kubernetes_cluster.example: Refreshing state... [id=d96961fa-c742-4980-89c1-993d496d0fa0]

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:

  # cloudstack_network_acl_rule.default will be updated in-place
  ~ resource "cloudstack_network_acl_rule" "default" {
        id          = "5bb5989d-5830-4fd3-9157-94bc7dfb524e"
        # (3 unchanged attributes hidden)

      ~ rule {
          + port         = "22"
          ~ ports        = [
              - "22",
            ]
            # (9 unchanged attributes hidden)
        }

        # (1 unchanged block 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

cloudstack_network_acl_rule.default: Modifying... [id=5bb5989d-5830-4fd3-9157-94bc7dfb524e]
cloudstack_network_acl_rule.default: Still modifying... [id=5bb5989d-5830-4fd3-9157-94bc7dfb524e, 00m10s elapsed]
cloudstack_network_acl_rule.default: Modifications complete after 13s [id=5bb5989d-5830-4fd3-9157-94bc7dfb524e]

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

Outputs:

acl_id = "5bb5989d-5830-4fd3-9157-94bc7dfb524e"
kubernetes_id = "d96961fa-c742-4980-89c1-993d496d0fa0"
network_id = "12d27633-7c32-4bcb-9c2c-3f8177fc3efe"
vpc_id = "f00f04c6-abc4-454f-a91f-2846dda3fb55"

@kiranchavala
Copy link
Collaborator

@CodeBleu Also, i would suggest limiting testing only to terraform for now and ignore opentofu
Also support is only included terraform provider upgrade i.e 0.5 to 0.6 and not for downgrade of provider i.e 0.6 to 0.5

@kiranchavala I need opentofu. This should be something we are supporting and testing from the get go. I would really like that when a release is cut, that one is cut for opentofu too. There are a lot of people using OpenTofu now and we should be treating that as a first class citizen as well IMHO.

Thanks @CodeBleu

I found that there is existing automation in opentofu registry to get latest release of cloudstack terraform whenever there is a release

opentofu/registry@a59630f

Copy link
Collaborator

@CodeBleu CodeBleu left a comment

Choose a reason for hiding this comment

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

I was able to run the terraform plan with the CKS and it worked fine this time without trying to replace it.

@Pearl1594 I am curious why the resource_cloudstack_kubernetes_cluster.go file had to have these modifications, as it doesn't appear the changes in 0.6.0-rc3 included modifying that file and the issue didn't happen on provider before.

I was able to modify ACL rule_number on rules as well, and confirm they are changing as expected now.

@Pearl1594
Copy link
Contributor Author

@CodeBleu I was able to reproduce the issue you mentioned regarding change in cks config, despite only changing acls on the rc3 packages as well. The changes in Network ACL rule didn't cause the behavioural change in CKS resource as they are independent of each other. It could have been that the configuration used while testing rc3 (0.6.0) didn't use parameters like autoscaler, etc. Im not sure why you weren't able to see the same on the 0.6.0-rc3 package.

@Pearl1594 Pearl1594 marked this pull request as ready for review October 17, 2025 13:41
@CodeBleu
Copy link
Collaborator

@CodeBleu I was able to reproduce the issue you mentioned regarding change in cks config, despite only changing acls on the rc3 packages as well. The changes in Network ACL rule didn't cause the behavioural change in CKS resource as they are independent of each other. It could have been that the configuration used while testing rc3 (0.6.0) didn't use parameters like autoscaler, etc. Im not sure why you weren't able to see the same on the 0.6.0-rc3 package.

I did see the same behaviour with the CKS issue with 0.6.0-rc3 😄

@kiranchavala kiranchavala merged commit 01840be into main Oct 21, 2025
47 checks passed
@kiranchavala kiranchavala added this to the v0.6.0 milestone Oct 21, 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