@@ -5,12 +5,10 @@ import (
55 "encoding/json"
66 "fmt"
77 "net/http"
8- "time"
98
109 "github.com/hashicorp/terraform-plugin-framework/path"
1110 "github.com/hashicorp/terraform-plugin-framework/resource"
1211 "github.com/hashicorp/terraform-plugin-framework/types"
13- "github.com/hashicorp/terraform-plugin-log/tflog"
1412
1513 "github.com/couchbasecloud/terraform-provider-couchbase-capella/internal/api"
1614 "github.com/couchbasecloud/terraform-provider-couchbase-capella/internal/errors"
2422 _ resource.ResourceWithImportState = & PrivateEndpoint {}
2523)
2624
27- const (
28- privateEndpointLinkedStatus = "linked"
29- )
30-
3125// PrivateEndpoint is the private endpoint resource implementation.
3226type PrivateEndpoint struct {
3327 * providerschema.Data
@@ -98,28 +92,27 @@ func (p *PrivateEndpoint) Create(ctx context.Context, req resource.CreateRequest
9892 return
9993 }
10094
101- plan .Status = types .StringNull ()
102- plan .ServiceName = types .StringNull ()
103- plan .PrivateEndpointDNS = types .StringNull ()
104-
105- diags = resp .State .Set (ctx , plan )
95+ diags = resp .State .Set (ctx , initializePrivateEndpointPlan (plan ))
10696 resp .Diagnostics .Append (diags ... )
10797 if resp .Diagnostics .HasError () {
10898 return
10999 }
110100
111- err = p .waitUntilLinked (ctx , & plan )
101+ refreshedState , err : = p .getPrivateEndpointState (ctx , organizationId , projectId , clusterId , endpointId )
112102 if err != nil {
113103 resp .Diagnostics .AddError (
114- "Error waiting for private endpoint to be linked " ,
115- "Error waiting for private endpoint to be linked , unexpected error: " + err .Error (),
104+ "Error reading private endpoint service status " ,
105+ "Error reading private endpoint service status , unexpected error: " + err .Error (),
116106 )
117107
118108 return
119109 }
120110
121- diags = resp .State .Set (ctx , plan )
111+ diags = resp .State .Set (ctx , refreshedState )
122112 resp .Diagnostics .Append (diags ... )
113+ if resp .Diagnostics .HasError () {
114+ return
115+ }
123116}
124117
125118// Read reads the private endpoint status.
@@ -264,29 +257,37 @@ func validateAcceptPrivateEndpoint(plan providerschema.PrivateEndpoint) error {
264257 return nil
265258}
266259
260+ // initializePrivateEndpointPlan initializes an instance of providerschema.PrivateEndpoint
261+ // with the specified plan. It marks all computed fields as null.
262+ func initializePrivateEndpointPlan (plan providerschema.PrivateEndpoint ) providerschema.PrivateEndpoint {
263+ if plan .Status .IsNull () || plan .Status .IsUnknown () {
264+ plan .Status = types .StringNull ()
265+ }
266+ return plan
267+ }
268+
267269// getPrivateEndpointState morphs private endpoint status to terraform schema.
268270func (p * PrivateEndpoint ) getPrivateEndpointState (ctx context.Context , organizationId , projectId , clusterId , endpointId string ) (* providerschema.PrivateEndpoint , error ) {
269- status , serviceName , dns , err := p .getPrivateEndpointStatus (ctx , organizationId , projectId , clusterId , endpointId )
271+ status , serviceName , err := p .getPrivateEndpointStatus (ctx , organizationId , projectId , clusterId , endpointId )
270272 if err != nil {
271273 return nil , err
272274 }
273275
274276 state := providerschema.PrivateEndpoint {
275- EndpointId : types .StringValue (endpointId ),
276- Status : types .StringValue (status ),
277- ClusterId : types .StringValue (clusterId ),
278- ProjectId : types .StringValue (projectId ),
279- OrganizationId : types .StringValue (organizationId ),
280- ServiceName : types .StringValue (serviceName ),
281- PrivateEndpointDNS : types .StringValue (dns ),
277+ EndpointId : types .StringValue (endpointId ),
278+ Status : types .StringValue (status ),
279+ ClusterId : types .StringValue (clusterId ),
280+ ProjectId : types .StringValue (projectId ),
281+ OrganizationId : types .StringValue (organizationId ),
282+ ServiceName : types .StringValue (serviceName ),
282283 }
283284
284285 return & state , nil
285286}
286287
287288// There is currently no V4 endpoint to get a single private endpoint. We have to loop through the entire list to find
288289// the desired private endpoint.
289- func (p * PrivateEndpoint ) getPrivateEndpointStatus (ctx context.Context , organizationId , projectId , clusterId , endpointId string ) (string , string , string , error ) {
290+ func (p * PrivateEndpoint ) getPrivateEndpointStatus (ctx context.Context , organizationId , projectId , clusterId , endpointId string ) (string , string , error ) {
290291 url := fmt .Sprintf ("%s/v4/organizations/%s/projects/%s/clusters/%s/privateEndpointService/endpoints" , p .HostURL , organizationId , projectId , clusterId )
291292 cfg := api.EndpointCfg {Url : url , Method : http .MethodGet , SuccessStatus : http .StatusOK }
292293 response , err := p .ClientV1 .ExecuteWithRetry (
@@ -297,63 +298,20 @@ func (p *PrivateEndpoint) getPrivateEndpointStatus(ctx context.Context, organiza
297298 nil ,
298299 )
299300 if err != nil {
300- return "" , "" , "" , err
301+ return "" , "" , err
301302 }
302303
303304 privateEndpointsResp := api.GetPrivateEndpointsResponse {}
304305 err = json .Unmarshal (response .Body , & privateEndpointsResp )
305306 if err != nil {
306- return "" , "" , "" , err
307+ return "" , "" , err
307308 }
308309
309310 for _ , e := range privateEndpointsResp .Endpoints {
310311 if e .Id == endpointId {
311- return e .Status , e .ServiceName , privateEndpointsResp . PrivateEndpointDNS , nil
312+ return e .Status , e .ServiceName , nil
312313 }
313314 }
314315
315- return "" , "" , "" , errors .ErrNotFound
316- }
317-
318- // waitUntilLinked polls the private endpoint until it reaches linked status and DNS is populated.
319- func (p * PrivateEndpoint ) waitUntilLinked (ctx context.Context , plan * providerschema.PrivateEndpoint ) error {
320- var cancel context.CancelFunc
321- ctx , cancel = context .WithTimeout (ctx , time .Minute * 5 )
322- defer cancel ()
323-
324- timer := time .NewTimer (time .Second * 1 )
325- defer timer .Stop ()
326-
327- for {
328- select {
329- case <- ctx .Done ():
330- return errors .ErrPrivateEndpointTimeout
331-
332- case <- timer .C :
333- status , serviceName , dns , err := p .getPrivateEndpointStatus (
334- ctx ,
335- plan .OrganizationId .ValueString (),
336- plan .ProjectId .ValueString (),
337- plan .ClusterId .ValueString (),
338- plan .EndpointId .ValueString (),
339- )
340- if err != nil {
341- return err
342- }
343-
344- if status == privateEndpointLinkedStatus {
345- if dns == "" {
346- tflog .Info (ctx , "Private endpoint is linked but DNS is not populated." )
347- timer .Reset (time .Minute * 1 )
348- continue
349- }
350- plan .ServiceName = types .StringValue (serviceName )
351- plan .Status = types .StringValue (status )
352- plan .PrivateEndpointDNS = types .StringValue (dns )
353- return nil
354- }
355- tflog .Info (ctx , "Private endpoint is not linked." )
356- timer .Reset (time .Minute * 1 )
357- }
358- }
316+ return "" , "" , errors .ErrNotFound
359317}
0 commit comments