@@ -2,15 +2,16 @@ package wait
22
33import (
44 "context"
5+ "errors"
56 "fmt"
67 "net/http"
8+ "strings"
79 "time"
810
9- "errors"
10-
1111 "github.com/stackitcloud/stackit-sdk-go/core/oapierror"
1212 "github.com/stackitcloud/stackit-sdk-go/core/wait"
1313 "github.com/stackitcloud/stackit-sdk-go/services/iaas"
14+ "github.com/stackitcloud/stackit-sdk-go/services/resourcemanager"
1415)
1516
1617const (
@@ -48,6 +49,7 @@ const (
4849// Interfaces needed for tests
4950type APIClientInterface interface {
5051 GetNetworkAreaExecute (ctx context.Context , organizationId , areaId string ) (* iaas.NetworkArea , error )
52+ ListNetworkAreaProjectsExecute (ctx context.Context , organizationId , areaId string ) (* iaas.ProjectListResponse , error )
5153 GetProjectRequestExecute (ctx context.Context , projectId string , requestId string ) (* iaas.Request , error )
5254 GetNetworkExecute (ctx context.Context , projectId , networkId string ) (* iaas.Network , error )
5355 GetVolumeExecute (ctx context.Context , projectId string , volumeId string ) (* iaas.Volume , error )
@@ -58,6 +60,10 @@ type APIClientInterface interface {
5860 GetSnapshotExecute (ctx context.Context , projectId string , snapshotId string ) (* iaas.Snapshot , error )
5961}
6062
63+ type ResourceManagerAPIClientInterface interface {
64+ GetProjectExecute (ctx context.Context , id string ) (* resourcemanager.GetProjectResponse , error )
65+ }
66+
6167// CreateNetworkAreaWaitHandler will wait for network area creation
6268func CreateNetworkAreaWaitHandler (ctx context.Context , a APIClientInterface , organizationId , areaId string ) * wait.AsyncActionHandler [iaas.NetworkArea ] {
6369 handler := wait .New (func () (waitFinished bool , response * iaas.NetworkArea , err error ) {
@@ -98,6 +104,52 @@ func UpdateNetworkAreaWaitHandler(ctx context.Context, a APIClientInterface, org
98104 return handler
99105}
100106
107+ // ReadyForNetworkAreaDeletionWaitHandler will wait until a deletion of network area is possible
108+ // Workaround for https://github.com/stackitcloud/terraform-provider-stackit/issues/907.
109+ // When the deletion for a project is triggered, the backend starts a workflow in the background which cleans up all resources
110+ // within a project and deletes the project in each service. When the project is attached to an SNA, the SNA can't be
111+ // deleted until the workflow inform the IaaS-API that the project is deleted.
112+ func ReadyForNetworkAreaDeletionWaitHandler (ctx context.Context , a APIClientInterface , r ResourceManagerAPIClientInterface , organizationId , areaId string ) * wait.AsyncActionHandler [iaas.ProjectListResponse ] {
113+ handler := wait .New (func () (waitFinished bool , response * iaas.ProjectListResponse , err error ) {
114+ projectList , err := a .ListNetworkAreaProjectsExecute (ctx , organizationId , areaId )
115+ if err != nil {
116+ return false , projectList , err
117+ }
118+ if projectList == nil || projectList .Items == nil {
119+ return false , nil , fmt .Errorf ("read failed for projects in network area with id %s, the response is not valid: the items are missing" , areaId )
120+ }
121+ if len (* projectList .Items ) == 0 {
122+ return true , projectList , nil
123+ }
124+ var activeProjects , forbiddenProjects []string
125+ for _ , projectId := range * projectList .Items {
126+ _ , err := r .GetProjectExecute (ctx , projectId )
127+ if err == nil {
128+ activeProjects = append (activeProjects , projectId )
129+ continue
130+ }
131+ var oapiErr * oapierror.GenericOpenAPIError
132+ ok := errors .As (err , & oapiErr )
133+ if ! ok {
134+ return false , nil , fmt .Errorf ("could not convert error to oapierror.GenericOpenAPIError" )
135+ }
136+ // The resource manager api responds with StatusForbidden(=403) when a project is deleted or if the project does not exist
137+ if oapiErr .StatusCode == http .StatusNotFound || oapiErr .StatusCode == http .StatusForbidden {
138+ forbiddenProjects = append (forbiddenProjects , projectId )
139+ }
140+ }
141+ if len (activeProjects ) > 0 {
142+ return false , nil , fmt .Errorf ("network area with id %s has still active projects: %s" , areaId , strings .Join (activeProjects , "," ))
143+ }
144+ if len (forbiddenProjects ) > 0 {
145+ return false , nil , nil
146+ }
147+ return true , projectList , nil
148+ })
149+ handler .SetTimeout (1 * time .Minute )
150+ return handler
151+ }
152+
101153// DeleteNetworkAreaWaitHandler will wait for network area deletion
102154func DeleteNetworkAreaWaitHandler (ctx context.Context , a APIClientInterface , organizationId , areaId string ) * wait.AsyncActionHandler [iaas.NetworkArea ] {
103155 handler := wait .New (func () (waitFinished bool , response * iaas.NetworkArea , err error ) {
0 commit comments