@@ -331,10 +331,12 @@ func createEgressFirewallRule(d *schema.ResourceData, meta interface{}, rule map
331331 // by not setting startport and endport parameters
332332 r , err := cs .Firewall .CreateEgressFirewallRule (p )
333333 if err != nil {
334- return err
334+ return fmt . Errorf ( "failed to create all-ports egress firewall rule: %w" , err )
335335 }
336336 uuids ["all" ] = r .Id
337337 rule ["uuids" ] = uuids
338+ // Remove the ports field since we're creating an all-ports rule
339+ delete (rule , "ports" )
338340 }
339341 }
340342
@@ -501,10 +503,50 @@ func resourceCloudStackEgressFirewallRead(d *schema.ResourceData, meta interface
501503 // Update the values
502504 rule ["protocol" ] = r .Protocol
503505 rule ["cidr_list" ] = cidrs
506+ // Remove ports field for all-ports rules
507+ delete (rule , "ports" )
504508 rules .Add (rule )
505509 }
506510 }
507511
512+ // Fallback: Check if any remaining rules in ruleMap match our expected all-ports pattern
513+ // This handles cases where CloudStack might return all-ports rules in unexpected formats
514+ if rule ["protocol" ].(string ) != "icmp" && strings .ToLower (rule ["protocol" ].(string )) != "all" {
515+ // Look for any remaining rules that might be our all-ports rule
516+ for ruleID , r := range ruleMap {
517+ // Get local CIDR set for comparison
518+ localCidrSet , ok := rule ["cidr_list" ].(* schema.Set )
519+ if ! ok {
520+ continue
521+ }
522+
523+ if isAllPortsTCPUDP (r .Protocol , r .Startport , r .Endport ) &&
524+ strings .EqualFold (r .Protocol , rule ["protocol" ].(string )) &&
525+ cidrSetsEqual (r .Cidrlist , localCidrSet ) {
526+ // This looks like our all-ports rule, add it to state
527+ cidrs := & schema.Set {F : schema .HashString }
528+ if r .Cidrlist != "" {
529+ for _ , cidr := range strings .Split (r .Cidrlist , "," ) {
530+ cidr = strings .TrimSpace (cidr )
531+ if cidr != "" {
532+ cidrs .Add (cidr )
533+ }
534+ }
535+ }
536+
537+ rule ["protocol" ] = r .Protocol
538+ rule ["cidr_list" ] = cidrs
539+ // Remove ports field for all-ports rules
540+ delete (rule , "ports" )
541+ rules .Add (rule )
542+
543+ // Remove from ruleMap so it's not processed again
544+ delete (ruleMap , ruleID )
545+ break
546+ }
547+ }
548+ }
549+
508550 if strings .ToLower (rule ["protocol" ].(string )) == "all" {
509551 id , ok := uuids ["all" ]
510552 if ! ok {
@@ -715,7 +757,7 @@ func verifyEgressFirewallParams(d *schema.ResourceData) error {
715757
716758 if ! rules && ! managed {
717759 return fmt .Errorf (
718- "You must supply at least one 'rule' when not using the 'managed' firewall feature" )
760+ "you must supply at least one 'rule' when not using the 'managed' firewall feature" )
719761 }
720762
721763 return nil
@@ -731,11 +773,11 @@ func verifyEgressFirewallRuleParams(d *schema.ResourceData, rule map[string]inte
731773 if protocol == "icmp" {
732774 if _ , ok := rule ["icmp_type" ]; ! ok {
733775 return fmt .Errorf (
734- "Parameter icmp_type is a required parameter when using protocol 'icmp'" )
776+ "parameter icmp_type is a required parameter when using protocol 'icmp'" )
735777 }
736778 if _ , ok := rule ["icmp_code" ]; ! ok {
737779 return fmt .Errorf (
738- "Parameter icmp_code is a required parameter when using protocol 'icmp'" )
780+ "parameter icmp_code is a required parameter when using protocol 'icmp'" )
739781 }
740782 } else if strings .ToLower (protocol ) != "all" {
741783 if ports , ok := rule ["ports" ].(* schema.Set ); ok {
@@ -752,7 +794,7 @@ func verifyEgressFirewallRuleParams(d *schema.ResourceData, rule map[string]inte
752794 } else if strings .ToLower (protocol ) == "all" {
753795 if ports , _ := rule ["ports" ].(* schema.Set ); ports .Len () > 0 {
754796 return fmt .Errorf (
755- "Parameter ports is not required when using protocol 'ALL'" )
797+ "parameter ports is not required when using protocol 'ALL'" )
756798 }
757799 }
758800
0 commit comments