bhouse-nexthop opened a new pull request, #281:
URL: https://github.com/apache/cloudstack-terraform-provider/pull/281

   ## Overview
   Inserting a rule in the middle of other rules will cause every rule after to 
be shown as modified.  There is some logic to try to prevent the number of 
updates shown as being actually applied, but it causes alarm, and its not clear 
from the output what its actually doing.
   
   Its not possible to simply convert the existing TypeList into a TypeSet 
because without a rule_number specified, the order cannot be preserved (as 
TypeSet uses a hash of the field).  Terraform also doesn't provide any 
mechanism to do any inspection of the original order to auto-assign rule 
numbers in the right order for rules without a manually specified rule_number.
   
   The choice was made to create a parallel `ruleset` schema member with all 
the same child elements as the `rule` schema member.  The differences are a 
`rule_number` becomes a required field and it doesn't need to implement the 
legacy `ports` -> `port` conversion logic.
   
   Fixes #279 
   
   ## Usecase
   
   In my particular use-case, I auto-assign rule_numbers based on zones using a 
module as a helper.  The module handles creation of the rule_number for me, and 
takes a starting index for each block of rules so I can logically group rules 
together in a "reserved range" for a particular "purpose".
   
   ### Module Code
   `modules/cloudstack_network_acl/main.tf`:
   ```!hcl
   terraform {
     required_providers {
       cloudstack = {
         source  = "cloudstack/cloudstack"
       }
     }
   }
   
   variable "acl_id" {
     description = "ACL ID"
     type        = string
   }
   
   variable "managed" {
     description = "Managed"
     type        = bool
     default     = true
   }
   
   variable "rulelist" {
     description = "Rule List"
     type        = any
   }
   
   resource "cloudstack_network_acl_rule" "this" {
     acl_id             = var.acl_id
     managed            = var.managed
     dynamic "rule" {
       for_each = flatten([
           for list in concat(var.rulelist, 
var.bootstrap?[local.aclrules_bootstrap]:[]) : [
             for rule in list.rules : {
               rule_number  = "${list.start_idx + index(list.rules, rule) + 1}"
               description  = try(rule.description, "")
               action       = rule.action
               cidr_list    = rule.cidr_list
               protocol     = rule.protocol
               icmp_type    = try(rule.icmp_type, null)
               icmp_code    = try(rule.icmp_code, null)
               port         = try(rule.port, null)
               traffic_type = rule.traffic_type
             }
           ]
         ])
       content {
         rule_number  = rule.value.rule_number
         description  = "${rule.value.description}: ${rule.value.action} 
${rule.value.traffic_type}"
         action       = rule.value.action
         cidr_list    = rule.value.cidr_list
         protocol     = rule.value.protocol
         icmp_type    = rule.value.icmp_type
         icmp_code    = rule.value.icmp_code
         ports        = rule.value.port == null ? null : [ rule.value.port ]
         traffic_type = rule.value.traffic_type
       }
     }
   }
   ```
   
   ## Module Caller
   
   `myzone.tf`:
   ```
   locals {
     subnet_vpc = "10.252.0.0/16"
   
     aclrules_deny_all = {
       start_idx = 65500
       rules = [
         {
           description  = "deny egress by default"
           rule_number  = 65535
           action       = "deny"
           cidr_list    = [ "0.0.0.0/0" ]
           protocol     = "all"
           icmp_type    = null
           icmp_code    = null
           traffic_type = "egress"
         }
       ]
     }
   
     subnet_ntp = "10.0.1.0/24"
     aclrules_access_ntp = {
       start_idx = 1100
       rules     = [
         {
           description  = "ntp"
           action       = "allow"
           cidr_list    = [ local.subnet_ntp ]
           protocol     = "udp"
           port         = "123"
           traffic_type = "egress"
         }
       ]
     }
   
     subnet_ipa          = "10.0.2.0/24"
     aclrules_access_ipa = {
       start_idx = 1200
       rules     = [
         {
           description  = "IPA http"
           action       = "allow"
           cidr_list    = [ local.subnet_ipa ]
           protocol     = "tcp"
           port         = "80"
           traffic_type = "egress"
         },
         {
           description  = "IPA https"
           action       = "allow"
           cidr_list    = [ local.subnet_ipa ]
           protocol     = "tcp"
           port         = "443"
           traffic_type = "egress"
         },
         {
           description  = "IPA ldap"
           action       = "allow"
           cidr_list    = [ local.subnet_ipa ]
           protocol     = "tcp"
           port         = "389"
           traffic_type = "egress"
         },
         {
           description  = "IPA ldaps"
           action       = "allow"
           cidr_list    = [ local.subnet_ipa ]
           protocol     = "tcp"
           port         = "636"
           traffic_type = "egress"
         },
         {
           description  = "kerberos udp"
           action       = "allow"
           cidr_list    = [ local.subnet_ipa ]
           protocol     = "udp"
           port         = "88"
           traffic_type = "egress"
         },
         {
           description  = "kpasswd udp"
           action       = "allow"
           cidr_list    = [ local.subnet_ipa ]
           protocol     = "udp"
           port         = "464"
           traffic_type = "egress"
         },
         {
           description  = "kerberos tcp"
           action       = "allow"
           cidr_list    = [ local.subnet_ipa ]
           protocol     = "tcp"
           port         = "88"
           traffic_type = "egress"
         },
         {
           description  = "kpasswd tcp"
           action       = "allow"
           cidr_list    = [ local.subnet_ipa ]
           protocol     = "tcp"
           port         = "464"
           traffic_type = "egress"
         }
       ]
     }
   }
   
   resource "cloudstack_vpc" "infra_vpc" {
     name           = "infra_vpc"
     cidr           = local.subnet_vpc
     vpc_offering   = "VPC HA"
     network_domain = var.cloudstack_network_domain
     zone           = var.cloudstack_zone
     project        = var.cloudstack_project
   }
   
   resource "cloudstack_network_acl" "myzone" {
     name   = "myzone"
     vpc_id = cloudstack_vpc.infra_vpc.id
   }
   
   module "network_acl_su" {
     source    = "./modules/cloudstack_network_acl"
     acl_id    = cloudstack_network_acl.myzone.id
     managed   = true
     # Order doesn't matter here!
     rulelist  = [ local.aclrules_deny_all, local.aclrules_access_ntp, 
aclrules_access_ipa ]
   }
   ```


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to