@@ -27,7 +27,6 @@ import (
2727 "github.com/hashicorp/terraform-plugin-sdk/helper/hashcode"
2828 "github.com/hashicorp/terraform-plugin-sdk/helper/schema"
2929 "github.com/hashicorp/terraform-plugin-sdk/helper/validation"
30- "google.golang.org/api/googleapi"
3130)
3231
3332func resourceComputeFirewallRuleHash (v interface {}) int {
@@ -53,6 +52,30 @@ func compareCaseInsensitive(k, old, new string, d *schema.ResourceData) bool {
5352 return strings .ToLower (old ) == strings .ToLower (new )
5453}
5554
55+ func diffSuppressEnableLogging (k , old , new string , d * schema.ResourceData ) bool {
56+ if k == "log_config.#" {
57+ if new == "0" && d .Get ("enable_logging" ).(bool ) {
58+ return true
59+ }
60+ }
61+
62+ return false
63+ }
64+
65+ func resourceComputeFirewallEnableLoggingCustomizeDiff (diff * schema.ResourceDiff , v interface {}) error {
66+ enableLogging , enableExists := diff .GetOkExists ("enable_logging" )
67+ if ! enableExists {
68+ return nil
69+ }
70+
71+ logConfigExists := diff .Get ("log_config.#" ).(int ) != 0
72+ if logConfigExists && enableLogging == false {
73+ return fmt .Errorf ("log_config cannot be defined when enable_logging is false" )
74+ }
75+
76+ return nil
77+ }
78+
5679func resourceComputeFirewall () * schema.Resource {
5780 return & schema.Resource {
5881 Create : resourceComputeFirewallCreate ,
@@ -72,6 +95,7 @@ func resourceComputeFirewall() *schema.Resource {
7295
7396 SchemaVersion : 1 ,
7497 MigrateState : resourceComputeFirewallMigrateState ,
98+ CustomizeDiff : resourceComputeFirewallEnableLoggingCustomizeDiff ,
7599
76100 Schema : map [string ]* schema.Schema {
77101 "name" : {
@@ -150,14 +174,24 @@ network it is associated with. When set to true, the firewall rule is
150174not enforced and the network behaves as if it did not exist. If this
151175is unspecified, the firewall rule will be enabled.` ,
152176 },
153- "enable_logging" : {
154- Type : schema .TypeBool ,
155- Optional : true ,
156- Description : `This field denotes whether to enable logging for a particular
157- firewall rule. If logging is enabled, logs will be exported to
158- Stackdriver.` ,
177+ "log_config" : {
178+ Type : schema .TypeList ,
179+ Optional : true ,
180+ DiffSuppressFunc : diffSuppressEnableLogging ,
181+ Description : `This field denotes the logging options for a particular firewall rule.
182+ If defined, logging is enabled, and logs will be exported to Cloud Logging.` ,
183+ MaxItems : 1 ,
184+ Elem : & schema.Resource {
185+ Schema : map [string ]* schema.Schema {
186+ "metadata" : {
187+ Type : schema .TypeString ,
188+ Required : true ,
189+ ValidateFunc : validation .StringInSlice ([]string {"EXCLUDE_ALL_METADATA" , "INCLUDE_ALL_METADATA" }, false ),
190+ Description : `This field denotes whether to include or exclude metadata for firewall logs. Possible values: ["EXCLUDE_ALL_METADATA", "INCLUDE_ALL_METADATA"]` ,
191+ },
192+ },
193+ },
159194 },
160-
161195 "priority" : {
162196 Type : schema .TypeInt ,
163197 Optional : true ,
@@ -261,6 +295,13 @@ instances on the specified network.`,
261295 Computed : true ,
262296 Description : `Creation timestamp in RFC3339 text format.` ,
263297 },
298+ "enable_logging" : {
299+ Type : schema .TypeBool ,
300+ Optional : true ,
301+ Computed : true ,
302+ Deprecated : "Deprecated in favor of log_config" ,
303+ Description : "This field denotes whether to enable logging for a particular firewall rule. If logging is enabled, logs will be exported to Stackdriver." ,
304+ },
264305 "project" : {
265306 Type : schema .TypeString ,
266307 Optional : true ,
@@ -375,10 +416,10 @@ func resourceComputeFirewallCreate(d *schema.ResourceData, meta interface{}) err
375416 } else if v , ok := d .GetOkExists ("disabled" ); ok || ! reflect .DeepEqual (v , disabledProp ) {
376417 obj ["disabled" ] = disabledProp
377418 }
378- logConfigProp , err := expandComputeFirewallLogConfig (nil , d , config )
419+ logConfigProp , err := expandComputeFirewallLogConfig (d . Get ( "log_config" ) , d , config )
379420 if err != nil {
380421 return err
381- } else if ! isEmptyValue ( reflect .ValueOf ( logConfigProp ) ) {
422+ } else if v , ok := d . GetOkExists ( "log_config" ); ok || ! reflect .DeepEqual ( v , logConfigProp ) {
382423 obj ["logConfig" ] = logConfigProp
383424 }
384425 nameProp , err := expandComputeFirewallName (d .Get ("name" ), d , config )
@@ -509,18 +550,8 @@ func resourceComputeFirewallRead(d *schema.ResourceData, meta interface{}) error
509550 if err := d .Set ("disabled" , flattenComputeFirewallDisabled (res ["disabled" ], d , config )); err != nil {
510551 return fmt .Errorf ("Error reading Firewall: %s" , err )
511552 }
512- // Terraform must set the top level schema field, but since this object contains collapsed properties
513- // it's difficult to know what the top level should be. Instead we just loop over the map returned from flatten.
514- if flattenedProp := flattenComputeFirewallLogConfig (res ["logConfig" ], d , config ); flattenedProp != nil {
515- if gerr , ok := flattenedProp .(* googleapi.Error ); ok {
516- return fmt .Errorf ("Error reading Firewall: %s" , gerr )
517- }
518- casted := flattenedProp .([]interface {})[0 ]
519- if casted != nil {
520- for k , v := range casted .(map [string ]interface {}) {
521- d .Set (k , v )
522- }
523- }
553+ if err := d .Set ("log_config" , flattenComputeFirewallLogConfig (res ["logConfig" ], d , config )); err != nil {
554+ return fmt .Errorf ("Error reading Firewall: %s" , err )
524555 }
525556 if err := d .Set ("name" , flattenComputeFirewallName (res ["name" ], d , config )); err != nil {
526557 return fmt .Errorf ("Error reading Firewall: %s" , err )
@@ -592,10 +623,10 @@ func resourceComputeFirewallUpdate(d *schema.ResourceData, meta interface{}) err
592623 } else if v , ok := d .GetOkExists ("disabled" ); ok || ! reflect .DeepEqual (v , disabledProp ) {
593624 obj ["disabled" ] = disabledProp
594625 }
595- logConfigProp , err := expandComputeFirewallLogConfig (nil , d , config )
626+ logConfigProp , err := expandComputeFirewallLogConfig (d . Get ( "log_config" ) , d , config )
596627 if err != nil {
597628 return err
598- } else if ! isEmptyValue ( reflect .ValueOf ( logConfigProp ) ) {
629+ } else if v , ok := d . GetOkExists ( "log_config" ); ok || ! reflect .DeepEqual ( v , logConfigProp ) {
599630 obj ["logConfig" ] = logConfigProp
600631 }
601632 networkProp , err := expandComputeFirewallNetwork (d .Get ("network" ), d , config )
@@ -802,14 +833,16 @@ func flattenComputeFirewallLogConfig(v interface{}, d *schema.ResourceData, conf
802833 if len (original ) == 0 {
803834 return nil
804835 }
836+
837+ v , ok := original ["enable" ]
838+ if ok && ! v .(bool ) {
839+ return nil
840+ }
841+
805842 transformed := make (map [string ]interface {})
806- transformed ["enable_logging" ] =
807- flattenComputeFirewallLogConfigEnableLogging (original ["enable" ], d , config )
843+ transformed ["metadata" ] = original ["metadata" ]
808844 return []interface {}{transformed }
809845}
810- func flattenComputeFirewallLogConfigEnableLogging (v interface {}, d * schema.ResourceData , config * Config ) interface {} {
811- return v
812- }
813846
814847func flattenComputeFirewallName (v interface {}, d * schema.ResourceData , config * Config ) interface {} {
815848 return v
@@ -968,19 +1001,23 @@ func expandComputeFirewallDisabled(v interface{}, d TerraformResourceData, confi
9681001}
9691002
9701003func expandComputeFirewallLogConfig (v interface {}, d TerraformResourceData , config * Config ) (interface {}, error ) {
1004+ l := v .([]interface {})
9711005 transformed := make (map [string ]interface {})
972- transformedEnableLogging , err := expandComputeFirewallLogConfigEnableLogging ( d . Get ( "enable_logging" ), d , config )
973- if err ! = nil {
974- return nil , err
975- } else {
976- transformed [ "enable" ] = transformedEnableLogging
1006+
1007+ if len ( l ) == 0 || l [ 0 ] = = nil {
1008+ // send enable = enable_logging value to ensure correct logging status if there is no config
1009+ transformed [ "enable" ] = d . Get ( "enable_logging" ).( bool )
1010+ return transformed , nil
9771011 }
9781012
979- return transformed , nil
980- }
1013+ raw := l [ 0 ]
1014+ original := raw .( map [ string ] interface {})
9811015
982- func expandComputeFirewallLogConfigEnableLogging (v interface {}, d TerraformResourceData , config * Config ) (interface {}, error ) {
983- return v , nil
1016+ // The log_config block is specified, so logging should be enabled
1017+ transformed ["enable" ] = true
1018+ transformed ["metadata" ] = original ["metadata" ]
1019+
1020+ return transformed , nil
9841021}
9851022
9861023func expandComputeFirewallName (v interface {}, d TerraformResourceData , config * Config ) (interface {}, error ) {
0 commit comments