2018-12-21 23:39:58 +00:00
package google
import (
"errors"
"fmt"
"log"
"strings"
"github.com/hashicorp/terraform/helper/schema"
"google.golang.org/api/cloudresourcemanager/v1"
)
var iamAuditConfigSchema = map [ string ] * schema . Schema {
"service" : {
Type : schema . TypeString ,
Required : true ,
} ,
"audit_log_config" : {
Type : schema . TypeSet ,
Required : true ,
Elem : & schema . Resource {
Schema : map [ string ] * schema . Schema {
"log_type" : {
Type : schema . TypeString ,
Required : true ,
} ,
"exempted_members" : {
Type : schema . TypeSet ,
Elem : & schema . Schema { Type : schema . TypeString } ,
Optional : true ,
} ,
} ,
} ,
} ,
"etag" : {
Type : schema . TypeString ,
Computed : true ,
} ,
}
func ResourceIamAuditConfig ( parentSpecificSchema map [ string ] * schema . Schema , newUpdaterFunc newResourceIamUpdaterFunc ) * schema . Resource {
return & schema . Resource {
Create : resourceIamAuditConfigCreate ( newUpdaterFunc ) ,
Read : resourceIamAuditConfigRead ( newUpdaterFunc ) ,
Update : resourceIamAuditConfigUpdate ( newUpdaterFunc ) ,
Delete : resourceIamAuditConfigDelete ( newUpdaterFunc ) ,
Schema : mergeSchemas ( iamAuditConfigSchema , parentSpecificSchema ) ,
}
}
func ResourceIamAuditConfigWithImport ( parentSpecificSchema map [ string ] * schema . Schema , newUpdaterFunc newResourceIamUpdaterFunc , resourceIdParser resourceIdParserFunc ) * schema . Resource {
r := ResourceIamAuditConfig ( parentSpecificSchema , newUpdaterFunc )
r . Importer = & schema . ResourceImporter {
State : iamAuditConfigImport ( resourceIdParser ) ,
}
return r
}
func resourceIamAuditConfigCreate ( newUpdaterFunc newResourceIamUpdaterFunc ) schema . CreateFunc {
return func ( d * schema . ResourceData , meta interface { } ) error {
config := meta . ( * Config )
updater , err := newUpdaterFunc ( d , config )
if err != nil {
return err
}
p := getResourceIamAuditConfig ( d )
err = iamPolicyReadModifyWrite ( updater , func ( ep * cloudresourcemanager . Policy ) error {
ep . AuditConfigs = mergeAuditConfigs ( append ( ep . AuditConfigs , p ) )
return nil
} )
if err != nil {
return err
}
d . SetId ( updater . GetResourceId ( ) + "/audit_config/" + p . Service )
return resourceIamAuditConfigRead ( newUpdaterFunc ) ( d , meta )
}
}
func resourceIamAuditConfigRead ( newUpdaterFunc newResourceIamUpdaterFunc ) schema . ReadFunc {
return func ( d * schema . ResourceData , meta interface { } ) error {
config := meta . ( * Config )
updater , err := newUpdaterFunc ( d , config )
if err != nil {
return err
}
eAuditConfig := getResourceIamAuditConfig ( d )
2019-04-19 20:15:51 +00:00
p , err := iamPolicyReadWithRetry ( updater )
2018-12-21 23:39:58 +00:00
if err != nil {
if isGoogleApiErrorWithCode ( err , 404 ) {
log . Printf ( "[DEBUG]: AuditConfig for service %q not found for non-existent resource %s, removing from state file." , eAuditConfig . Service , updater . DescribeResource ( ) )
d . SetId ( "" )
return nil
}
return err
}
log . Printf ( "[DEBUG]: Retrieved policy for %s: %+v" , updater . DescribeResource ( ) , p )
var ac * cloudresourcemanager . AuditConfig
for _ , b := range p . AuditConfigs {
if b . Service != eAuditConfig . Service {
continue
}
ac = b
break
}
if ac == nil {
log . Printf ( "[DEBUG]: AuditConfig for service %q not found in policy for %s, removing from state file." , eAuditConfig . Service , updater . DescribeResource ( ) )
d . SetId ( "" )
return nil
}
d . Set ( "etag" , p . Etag )
err = d . Set ( "audit_log_config" , flattenAuditLogConfigs ( ac . AuditLogConfigs ) )
if err != nil {
return fmt . Errorf ( "Error flattening audit log config: %s" , err )
}
d . Set ( "service" , ac . Service )
return nil
}
}
func iamAuditConfigImport ( resourceIdParser resourceIdParserFunc ) schema . StateFunc {
return func ( d * schema . ResourceData , m interface { } ) ( [ ] * schema . ResourceData , error ) {
if resourceIdParser == nil {
return nil , errors . New ( "Import not supported for this IAM resource." )
}
config := m . ( * Config )
s := strings . Fields ( d . Id ( ) )
if len ( s ) != 2 {
d . SetId ( "" )
return nil , fmt . Errorf ( "Wrong number of parts to AuditConfig id %s; expected 'resource_name service'." , s )
}
id , service := s [ 0 ] , s [ 1 ]
// Set the ID only to the first part so all IAM types can share the same resourceIdParserFunc.
d . SetId ( id )
d . Set ( "service" , service )
err := resourceIdParser ( d , config )
if err != nil {
return nil , err
}
// Set the ID again so that the ID matches the ID it would have if it had been created via TF.
// Use the current ID in case it changed in the resourceIdParserFunc.
d . SetId ( d . Id ( ) + "/audit_config/" + service )
return [ ] * schema . ResourceData { d } , nil
}
}
func resourceIamAuditConfigUpdate ( newUpdaterFunc newResourceIamUpdaterFunc ) schema . UpdateFunc {
return func ( d * schema . ResourceData , meta interface { } ) error {
config := meta . ( * Config )
updater , err := newUpdaterFunc ( d , config )
if err != nil {
return err
}
ac := getResourceIamAuditConfig ( d )
err = iamPolicyReadModifyWrite ( updater , func ( p * cloudresourcemanager . Policy ) error {
var found bool
for pos , b := range p . AuditConfigs {
if b . Service != ac . Service {
continue
}
found = true
p . AuditConfigs [ pos ] = ac
break
}
if ! found {
p . AuditConfigs = append ( p . AuditConfigs , ac )
}
return nil
} )
if err != nil {
return err
}
return resourceIamAuditConfigRead ( newUpdaterFunc ) ( d , meta )
}
}
func resourceIamAuditConfigDelete ( newUpdaterFunc newResourceIamUpdaterFunc ) schema . DeleteFunc {
return func ( d * schema . ResourceData , meta interface { } ) error {
config := meta . ( * Config )
updater , err := newUpdaterFunc ( d , config )
if err != nil {
return err
}
ac := getResourceIamAuditConfig ( d )
err = iamPolicyReadModifyWrite ( updater , func ( p * cloudresourcemanager . Policy ) error {
toRemove := - 1
for pos , b := range p . AuditConfigs {
if b . Service != ac . Service {
continue
}
toRemove = pos
break
}
if toRemove < 0 {
log . Printf ( "[DEBUG]: Policy audit configs for %s did not include an audit config for service %q" , updater . DescribeResource ( ) , ac . Service )
return nil
}
p . AuditConfigs = append ( p . AuditConfigs [ : toRemove ] , p . AuditConfigs [ toRemove + 1 : ] ... )
return nil
} )
if err != nil {
if isGoogleApiErrorWithCode ( err , 404 ) {
log . Printf ( "[DEBUG]: Resource %s is missing or deleted, marking policy audit config as deleted" , updater . DescribeResource ( ) )
return nil
}
return err
}
return resourceIamAuditConfigRead ( newUpdaterFunc ) ( d , meta )
}
}
func getResourceIamAuditConfig ( d * schema . ResourceData ) * cloudresourcemanager . AuditConfig {
auditLogConfigSet := d . Get ( "audit_log_config" ) . ( * schema . Set )
auditLogConfigs := make ( [ ] * cloudresourcemanager . AuditLogConfig , auditLogConfigSet . Len ( ) )
for x , y := range auditLogConfigSet . List ( ) {
logConfig := y . ( map [ string ] interface { } )
auditLogConfigs [ x ] = & cloudresourcemanager . AuditLogConfig {
LogType : logConfig [ "log_type" ] . ( string ) ,
ExemptedMembers : convertStringArr ( logConfig [ "exempted_members" ] . ( * schema . Set ) . List ( ) ) ,
}
}
return & cloudresourcemanager . AuditConfig {
AuditLogConfigs : auditLogConfigs ,
Service : d . Get ( "service" ) . ( string ) ,
}
}
func flattenAuditLogConfigs ( configs [ ] * cloudresourcemanager . AuditLogConfig ) * schema . Set {
res := schema . NewSet ( schema . HashResource ( iamAuditConfigSchema [ "audit_log_config" ] . Elem . ( * schema . Resource ) ) , [ ] interface { } { } )
for _ , conf := range configs {
res . Add ( map [ string ] interface { } {
"log_type" : conf . LogType ,
"exempted_members" : schema . NewSet ( schema . HashSchema ( iamAuditConfigSchema [ "audit_log_config" ] . Elem . ( * schema . Resource ) . Schema [ "exempted_members" ] . Elem . ( * schema . Schema ) ) , convertStringArrToInterface ( conf . ExemptedMembers ) ) ,
} )
}
return res
}