2020package vpcaccess
2121
2222import (
23+ "context"
2324 "fmt"
2425 "log"
2526 "net/http"
2627 "reflect"
28+ "strings"
2729 "time"
2830
2931 "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff"
@@ -34,10 +36,20 @@ import (
3436 transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport"
3537)
3638
39+ func isInstanceShrinkage (_ context.Context , old , new , _ interface {}) bool {
40+ // max and min instances can only increase in-place,
41+ // so we must create a new resource if it is decreased.
42+ if old == nil || new == nil {
43+ return false
44+ }
45+ return new .(int ) < old .(int )
46+ }
47+
3748func ResourceVPCAccessConnector () * schema.Resource {
3849 return & schema.Resource {
3950 Create : resourceVPCAccessConnectorCreate ,
4051 Read : resourceVPCAccessConnectorRead ,
52+ Update : resourceVPCAccessConnectorUpdate ,
4153 Delete : resourceVPCAccessConnectorDelete ,
4254
4355 Importer : & schema.ResourceImporter {
@@ -46,10 +58,13 @@ func ResourceVPCAccessConnector() *schema.Resource {
4658
4759 Timeouts : & schema.ResourceTimeout {
4860 Create : schema .DefaultTimeout (20 * time .Minute ),
61+ Update : schema .DefaultTimeout (20 * time .Minute ),
4962 Delete : schema .DefaultTimeout (20 * time .Minute ),
5063 },
5164
5265 CustomizeDiff : customdiff .All (
66+ customdiff .ForceNewIfChange ("min_instances" , isInstanceShrinkage ),
67+ customdiff .ForceNewIfChange ("max_instances" , isInstanceShrinkage ),
5368 tpgresource .DefaultProviderProject ,
5469 ),
5570
@@ -70,18 +85,17 @@ func ResourceVPCAccessConnector() *schema.Resource {
7085 "machine_type" : {
7186 Type : schema .TypeString ,
7287 Optional : true ,
73- ForceNew : true ,
7488 Description : `Machine type of VM Instance underlying connector. Default is e2-micro` ,
7589 Default : "e2-micro" ,
7690 },
7791 "max_instances" : {
7892 Type : schema .TypeInt ,
7993 Computed : true ,
8094 Optional : true ,
81- ForceNew : true ,
8295 Description : `Maximum value of instances in autoscaling group underlying the connector. Value must be between 3 and 10, inclusive. Must be
8396higher than the value specified by min_instances.` ,
8497 ConflictsWith : []string {"max_throughput" },
98+ RequiredWith : []string {"min_instances" },
8599 },
86100 "max_throughput" : {
87101 Type : schema .TypeInt ,
@@ -98,10 +112,10 @@ min_throughput. Only one of 'max_throughput' and 'max_instances' can be specifie
98112 Type : schema .TypeInt ,
99113 Computed : true ,
100114 Optional : true ,
101- ForceNew : true ,
102115 Description : `Minimum value of instances in autoscaling group underlying the connector. Value must be between 2 and 9, inclusive. Must be
103116lower than the value specified by max_instances.` ,
104117 ConflictsWith : []string {"min_throughput" },
118+ RequiredWith : []string {"max_instances" },
105119 },
106120 "min_throughput" : {
107121 Type : schema .TypeInt ,
@@ -427,6 +441,124 @@ func resourceVPCAccessConnectorRead(d *schema.ResourceData, meta interface{}) er
427441 return nil
428442}
429443
444+ func resourceVPCAccessConnectorUpdate (d * schema.ResourceData , meta interface {}) error {
445+ config := meta .(* transport_tpg.Config )
446+ userAgent , err := tpgresource .GenerateUserAgentString (d , config .UserAgent )
447+ if err != nil {
448+ return err
449+ }
450+
451+ billingProject := ""
452+
453+ project , err := tpgresource .GetProject (d , config )
454+ if err != nil {
455+ return fmt .Errorf ("Error fetching project for Connector: %s" , err )
456+ }
457+ billingProject = project
458+
459+ obj := make (map [string ]interface {})
460+ machineTypeProp , err := expandVPCAccessConnectorMachineType (d .Get ("machine_type" ), d , config )
461+ if err != nil {
462+ return err
463+ } else if v , ok := d .GetOkExists ("machine_type" ); ! tpgresource .IsEmptyValue (reflect .ValueOf (v )) && (ok || ! reflect .DeepEqual (v , machineTypeProp )) {
464+ obj ["machineType" ] = machineTypeProp
465+ }
466+ minInstancesProp , err := expandVPCAccessConnectorMinInstances (d .Get ("min_instances" ), d , config )
467+ if err != nil {
468+ return err
469+ } else if v , ok := d .GetOkExists ("min_instances" ); ! tpgresource .IsEmptyValue (reflect .ValueOf (v )) && (ok || ! reflect .DeepEqual (v , minInstancesProp )) {
470+ obj ["minInstances" ] = minInstancesProp
471+ }
472+ maxInstancesProp , err := expandVPCAccessConnectorMaxInstances (d .Get ("max_instances" ), d , config )
473+ if err != nil {
474+ return err
475+ } else if v , ok := d .GetOkExists ("max_instances" ); ! tpgresource .IsEmptyValue (reflect .ValueOf (v )) && (ok || ! reflect .DeepEqual (v , maxInstancesProp )) {
476+ obj ["maxInstances" ] = maxInstancesProp
477+ }
478+
479+ obj , err = resourceVPCAccessConnectorEncoder (d , meta , obj )
480+ if err != nil {
481+ return err
482+ }
483+
484+ url , err := tpgresource .ReplaceVars (d , config , "{{VPCAccessBasePath}}projects/{{project}}/locations/{{region}}/connectors/{{name}}" )
485+ if err != nil {
486+ return err
487+ }
488+
489+ log .Printf ("[DEBUG] Updating Connector %q: %#v" , d .Id (), obj )
490+ headers := make (http.Header )
491+ updateMask := []string {}
492+
493+ if d .HasChange ("machine_type" ) {
494+ updateMask = append (updateMask , "machineType" )
495+ }
496+
497+ if d .HasChange ("min_instances" ) {
498+ updateMask = append (updateMask , "minInstances" )
499+ }
500+
501+ if d .HasChange ("max_instances" ) {
502+ updateMask = append (updateMask , "maxInstances" )
503+ }
504+ // updateMask is a URL parameter but not present in the schema, so ReplaceVars
505+ // won't set it
506+ url , err = transport_tpg .AddQueryParams (url , map [string ]string {"updateMask" : strings .Join (updateMask , "," )})
507+ if err != nil {
508+ return err
509+ }
510+ if d .HasChange ("min_instances" ) && ! d .HasChange ("max_instances" ) {
511+ obj ["maxInstances" ] = d .Get ("max_instances" ).(int )
512+ updateMask = append (updateMask , "maxInstances" , "minInstances" )
513+ }
514+
515+ if d .HasChange ("max_instances" ) && ! d .HasChange ("min_instances" ) {
516+ obj ["minInstances" ] = d .Get ("min_instances" ).(int )
517+ updateMask = append (updateMask , "maxInstances" , "minInstances" )
518+ }
519+
520+ // Overwrite the previously set mask.
521+ url , err = transport_tpg .AddQueryParams (url , map [string ]string {"updateMask" : strings .Join (updateMask , "," )})
522+ if err != nil {
523+ return err
524+ }
525+
526+ // err == nil indicates that the billing_project value was found
527+ if bp , err := tpgresource .GetBillingProject (d , config ); err == nil {
528+ billingProject = bp
529+ }
530+
531+ // if updateMask is empty we are not updating anything so skip the post
532+ if len (updateMask ) > 0 {
533+ res , err := transport_tpg .SendRequest (transport_tpg.SendRequestOptions {
534+ Config : config ,
535+ Method : "PATCH" ,
536+ Project : billingProject ,
537+ RawURL : url ,
538+ UserAgent : userAgent ,
539+ Body : obj ,
540+ Timeout : d .Timeout (schema .TimeoutUpdate ),
541+ Headers : headers ,
542+ })
543+
544+ if err != nil {
545+ return fmt .Errorf ("Error updating Connector %q: %s" , d .Id (), err )
546+ } else {
547+ log .Printf ("[DEBUG] Finished updating Connector %q: %#v" , d .Id (), res )
548+ }
549+
550+ err = VPCAccessOperationWaitTime (
551+ config , res , project , "Updating Connector" , userAgent ,
552+ d .Timeout (schema .TimeoutUpdate ))
553+
554+ if err != nil {
555+ return err
556+ }
557+ }
558+
559+ return resourceVPCAccessConnectorRead (d , meta )
560+ }
561+
430562func resourceVPCAccessConnectorDelete (d * schema.ResourceData , meta interface {}) error {
431563 config := meta .(* transport_tpg.Config )
432564 userAgent , err := tpgresource .GenerateUserAgentString (d , config .UserAgent )
0 commit comments