@@ -6,12 +6,11 @@ import (
66 "bytes"
77 "context"
88 "fmt"
9+ "strings"
910
1011 "github.com/hashicorp/terraform/helper/hashcode"
1112 "github.com/hashicorp/terraform/helper/schema"
1213
13- "strings"
14-
1514 oci_core "github.com/oracle/oci-go-sdk/core"
1615)
1716
@@ -107,16 +106,13 @@ func CoreVirtualCircuitResource() *schema.Resource {
107106 "public_prefixes" : {
108107 Type : schema .TypeSet ,
109108 Optional : true ,
110- Computed : true ,
111- ForceNew : true ,
112109 Set : publicPrefixesHashCodeForSets ,
113110 Elem : & schema.Resource {
114111 Schema : map [string ]* schema.Schema {
115112 // Required
116113 "cidr_block" : {
117114 Type : schema .TypeString ,
118115 Required : true ,
119- ForceNew : true ,
120116 },
121117
122118 // Optional
@@ -356,27 +352,35 @@ func (s *CoreVirtualCircuitResourceCrud) Get() error {
356352
357353 s .Res = & response .VirtualCircuit
358354
359- // VirtualCircuitPublicPrefixes are returned from another API, make a List call on them if the VirtualCircuit is of type 'PUBLIC'
360- if type_ , ok := s .D .GetOkExists ("type" ); ok && strings .EqualFold (type_ .(string ), string (oci_core .VirtualCircuitTypePublic )) && s .Res .PublicPrefixes == nil {
361- request2 := oci_core.ListVirtualCircuitPublicPrefixesRequest {}
362- request2 .VirtualCircuitId = request .VirtualCircuitId
363-
364- response2 , err2 := s .Client .ListVirtualCircuitPublicPrefixes (context .Background (), request2 )
355+ ppRequest := oci_core.ListVirtualCircuitPublicPrefixesRequest {}
356+ ppRequest .RequestMetadata .RetryPolicy = getRetryPolicy (s .DisableNotFoundRetries , "core" )
357+ ppRequest .VirtualCircuitId = request .VirtualCircuitId
365358
366- publicPrefixes := [] string {}
367- for _ , item := range response2 . Items {
368- publicPrefixes = append ( publicPrefixes , * item . CidrBlock )
369- }
359+ ppResponse , ppErr := s . Client . ListVirtualCircuitPublicPrefixes ( context . Background (), ppRequest )
360+ if ppErr != nil {
361+ return ppErr
362+ }
370363
371- s .Res .PublicPrefixes = publicPrefixes
372- if err2 != nil {
373- return err2
374- }
364+ publicPrefixes := []string {}
365+ for _ , item := range ppResponse .Items {
366+ publicPrefixes = append (publicPrefixes , * item .CidrBlock )
375367 }
368+
369+ s .Res .PublicPrefixes = publicPrefixes
370+
376371 return nil
377372}
378373
379374func (s * CoreVirtualCircuitResourceCrud ) Update () error {
375+ // Update public prefixes, if changed
376+ // Cannot update PublicPrefix when the VirtualCircuit is in state PROVISIONING so public prefixes should be updated first
377+ if s .D .HasChange ("public_prefixes" ) {
378+ err := s .updatePublicPrefixes ()
379+ if err != nil {
380+ return fmt .Errorf ("unable to update 'public_prefixes', error: %v" , err )
381+ }
382+ }
383+
380384 request := oci_core.UpdateVirtualCircuitRequest {}
381385
382386 if bandwidthShapeName , ok := s .D .GetOkExists ("bandwidth_shape_name" ); ok {
@@ -435,6 +439,73 @@ func (s *CoreVirtualCircuitResourceCrud) Update() error {
435439 }
436440
437441 s .Res = & response .VirtualCircuit
442+ return nil
443+ }
444+
445+ // Update public prefixes using BulkAdd and BulkDelete APIs by computing the diff
446+ func (s * CoreVirtualCircuitResourceCrud ) updatePublicPrefixes () error {
447+ virtualCircuitId := s .D .Id ()
448+
449+ o , n := s .D .GetChange ("public_prefixes" )
450+ if o == nil {
451+ o = new (schema.Set )
452+ }
453+ if n == nil {
454+ n = new (schema.Set )
455+ }
456+
457+ os := o .(* schema.Set )
458+ ns := n .(* schema.Set )
459+
460+ newPublicPrefixesToAdd := ns .Difference (os ).List ()
461+ oldPublicPrefixesToDelete := os .Difference (ns ).List ()
462+
463+ var publicPrefixesToAdd []oci_core.CreateVirtualCircuitPublicPrefixDetails
464+ var publicPrefixesToDelete []oci_core.DeleteVirtualCircuitPublicPrefixDetails
465+
466+ for _ , nppMap := range newPublicPrefixesToAdd {
467+ npp := mapToCreateVirtualCircuitPublicPrefixDetails (nppMap .(map [string ]interface {}))
468+ publicPrefixesToAdd = append (publicPrefixesToAdd , npp )
469+ }
470+
471+ for _ , oppMap := range oldPublicPrefixesToDelete {
472+ opp := mapToDeleteVirtualCircuitPublicPrefixDetails (oppMap .(map [string ]interface {}))
473+ publicPrefixesToDelete = append (publicPrefixesToDelete , opp )
474+ }
475+
476+ // Add the public prefixes first, if any
477+ // And, wait for the update to complete before proceeding for subsequent updates if state is PROVISIONING
478+ if len (publicPrefixesToAdd ) > 0 {
479+ addRequest := oci_core.BulkAddVirtualCircuitPublicPrefixesRequest {}
480+ addRequest .RequestMetadata .RetryPolicy = getRetryPolicy (s .DisableNotFoundRetries , "core" )
481+ addRequest .PublicPrefixes = publicPrefixesToAdd
482+ addRequest .VirtualCircuitId = & virtualCircuitId
483+ addErr := s .Client .BulkAddVirtualCircuitPublicPrefixes (context .Background (), addRequest )
484+ if addErr != nil {
485+ return fmt .Errorf ("failed to add public prefixes, error: %v" , addErr )
486+ }
487+
488+ if waitErr := waitForUpdatedState (s .D , s ); waitErr != nil {
489+ return waitErr
490+ }
491+ }
492+
493+ // Delete the old public prefixes, if any, after adding new ones
494+ // And, wait for the update to complete before proceeding for subsequent updates if state is PROVISIONING
495+ if len (publicPrefixesToDelete ) > 0 {
496+ deleteRequest := oci_core.BulkDeleteVirtualCircuitPublicPrefixesRequest {}
497+ deleteRequest .RequestMetadata .RetryPolicy = getRetryPolicy (s .DisableNotFoundRetries , "core" )
498+ deleteRequest .PublicPrefixes = publicPrefixesToDelete
499+ deleteRequest .VirtualCircuitId = & virtualCircuitId
500+ deleteErr := s .Client .BulkDeleteVirtualCircuitPublicPrefixes (context .Background (), deleteRequest )
501+ if deleteErr != nil {
502+ return fmt .Errorf ("failed to delete public prefixes, error: %v" , deleteErr )
503+ }
504+
505+ if waitErr := waitForUpdatedState (s .D , s ); waitErr != nil {
506+ return waitErr
507+ }
508+ }
438509
439510 return nil
440511}
@@ -492,13 +563,11 @@ func (s *CoreVirtualCircuitResourceCrud) SetData() error {
492563
493564 s .D .Set ("provider_state" , s .Res .ProviderState )
494565
495- if s .Res .PublicPrefixes != nil {
496- publicPrefixes := []interface {}{}
497- for _ , item := range s .Res .PublicPrefixes {
498- publicPrefixes = append (publicPrefixes , CreateVirtualCircuitPublicPrefixDetailsToMap (item ))
499- }
500- s .D .Set ("public_prefixes" , schema .NewSet (publicPrefixesHashCodeForSets , publicPrefixes ))
566+ publicPrefixes := []interface {}{}
567+ for _ , item := range s .Res .PublicPrefixes {
568+ publicPrefixes = append (publicPrefixes , CreateVirtualCircuitPublicPrefixDetailsToMap (item ))
501569 }
570+ s .D .Set ("public_prefixes" , schema .NewSet (publicPrefixesHashCodeForSets , publicPrefixes ))
502571
503572 if s .Res .ReferenceComment != nil {
504573 s .D .Set ("reference_comment" , * s .Res .ReferenceComment )
@@ -521,6 +590,30 @@ func (s *CoreVirtualCircuitResourceCrud) SetData() error {
521590 return nil
522591}
523592
593+ // Converting raw set data from state diff to DeleteVirtualCircuitPublicPrefixDetails
594+ func mapToDeleteVirtualCircuitPublicPrefixDetails (publicPrefix map [string ]interface {}) oci_core.DeleteVirtualCircuitPublicPrefixDetails {
595+ result := oci_core.DeleteVirtualCircuitPublicPrefixDetails {}
596+
597+ if cidrBlock , ok := publicPrefix ["cidr_block" ]; ok {
598+ tmp := cidrBlock .(string )
599+ result .CidrBlock = & tmp
600+ }
601+
602+ return result
603+ }
604+
605+ // Converting raw set data from state diff to CreateVirtualCircuitPublicPrefixDetails
606+ func mapToCreateVirtualCircuitPublicPrefixDetails (publicPrefix map [string ]interface {}) oci_core.CreateVirtualCircuitPublicPrefixDetails {
607+ result := oci_core.CreateVirtualCircuitPublicPrefixDetails {}
608+
609+ if cidrBlock , ok := publicPrefix ["cidr_block" ]; ok {
610+ tmp := cidrBlock .(string )
611+ result .CidrBlock = & tmp
612+ }
613+
614+ return result
615+ }
616+
524617func (s * CoreVirtualCircuitResourceCrud ) mapToCreateVirtualCircuitPublicPrefixDetails (fieldKeyFormat string ) (oci_core.CreateVirtualCircuitPublicPrefixDetails , error ) {
525618 result := oci_core.CreateVirtualCircuitPublicPrefixDetails {}
526619
@@ -553,20 +646,24 @@ func (s *CoreVirtualCircuitResourceCrud) mapToCrossConnectMapping(fieldKeyFormat
553646 result .CrossConnectOrCrossConnectGroupId = & tmp
554647 }
555648
556- if customerBgpPeeringIp , ok := s .D .GetOkExists (fmt .Sprintf (fieldKeyFormat , "customer_bgp_peering_ip" )); ok {
557- tmp := customerBgpPeeringIp .(string )
558- result .CustomerBgpPeeringIp = & tmp
559- }
649+ // customer_bgp_peering_ip, oracleBgpPeeringIp are not allowed in requests for PUBLIC virtual circuit
650+ if vcType , ok := s .D .GetOkExists ("type" ); ok && ! strings .EqualFold (vcType .(string ), string (oci_core .VirtualCircuitTypePublic )) {
651+ if customerBgpPeeringIp , ok := s .D .GetOkExists (fmt .Sprintf (fieldKeyFormat , "customer_bgp_peering_ip" )); ok {
652+ tmp := customerBgpPeeringIp .(string )
653+ result .CustomerBgpPeeringIp = & tmp
654+ }
560655
561- if oracleBgpPeeringIp , ok := s .D .GetOkExists (fmt .Sprintf (fieldKeyFormat , "oracle_bgp_peering_ip" )); ok {
562- tmp := oracleBgpPeeringIp .(string )
563- result .OracleBgpPeeringIp = & tmp
656+ if oracleBgpPeeringIp , ok := s .D .GetOkExists (fmt .Sprintf (fieldKeyFormat , "oracle_bgp_peering_ip" )); ok {
657+ tmp := oracleBgpPeeringIp .(string )
658+ result .OracleBgpPeeringIp = & tmp
659+ }
564660 }
565661
566662 if vlan , ok := s .D .GetOkExists (fmt .Sprintf (fieldKeyFormat , "vlan" )); ok {
567663 tmp := vlan .(int )
568- //Vlan value must be greater than or equal to 100. It cannot be specified for certain circuit types.
569- if tmp >= 100 {
664+ // Vlan value must be greater than or equal to 100.
665+ // It cannot be specified for certain circuit types, hence protecting against default '0' values
666+ if tmp > 0 {
570667 result .Vlan = & tmp
571668 }
572669 }
0 commit comments