Skip to content

Commit 876bf38

Browse files
committed
add changelogs, adjust examples, implement new wait package
1 parent 6162246 commit 876bf38

File tree

10 files changed

+248
-27
lines changed

10 files changed

+248
-27
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88
- **Breaking change:** Renamed `TargetPoolTlsConfig` to `TlsConfig`
99
- `loadbalancer`: [v1.8.0](services/loadbalancer/CHANGELOG.md#v180)
1010
- **Feature:** Add new fields `AltPort` and `HttpHealthCheck` to `ActiveHealthCheck`
11+
- `resourcemanager`: [v0.19.0](services/resourcemanager/CHANGELOG.md#v0190)
12+
- **Feature:** Introduction of multi API version support for the resourcemanager SDK module. For more details please see the announcement on GitHub: https://github.com/stackitcloud/stackit-sdk-go/discussions/5062
13+
- `v0api`: New package which should be used for communication with the STACKIT Resourcemanager API in the future
14+
- **Deprecation:** The contents in the root of this SDK module including the `wait` package are marked as deprecated and will be removed after 2026-09-30. Switch to the new `v0api` package instead.
15+
- **Dependencies:** Bump STACKIT SDK core module from `v0.21.1` to `v0.22.0`
16+
- **Breaking Change:** Removal of deprecated constants `ActiveState` and `CreatingState` in `wait` package
1117

1218
## Release (2026-02-20)
1319
- `core`: [v0.21.1](core/CHANGELOG.md#v0211)

examples/resourcemanager/go.mod

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ module github.com/stackitcloud/stackit-sdk-go/examples/resourcemanager
22

33
go 1.21
44

5-
require (
6-
github.com/stackitcloud/stackit-sdk-go/core v0.21.1
7-
github.com/stackitcloud/stackit-sdk-go/services/resourcemanager v0.18.5
8-
)
5+
// This is not needed in production. This is only here to point the golangci linter to the local version instead of the last release on GitHub.
6+
replace github.com/stackitcloud/stackit-sdk-go/services/resourcemanager => ../../services/resourcemanager
7+
8+
require github.com/stackitcloud/stackit-sdk-go/services/resourcemanager v0.0.0-00010101000000-000000000000
99

1010
require (
1111
github.com/golang-jwt/jwt/v5 v5.3.1 // indirect
1212
github.com/google/uuid v1.6.0 // indirect
13+
github.com/stackitcloud/stackit-sdk-go/core v0.22.0 // indirect
1314
)

examples/resourcemanager/go.sum

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,5 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
44
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
55
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
66
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
7-
github.com/stackitcloud/stackit-sdk-go/core v0.21.1 h1:Y/PcAgM7DPYMNqum0MLv4n1mF9ieuevzcCIZYQfm3Ts=
8-
github.com/stackitcloud/stackit-sdk-go/core v0.21.1/go.mod h1:osMglDby4csGZ5sIfhNyYq1bS1TxIdPY88+skE/kkmI=
9-
github.com/stackitcloud/stackit-sdk-go/services/resourcemanager v0.18.5 h1:MZ5aTO2NQ1Jecmi67ByGskve5nKXHl91fE+z+vFjxt4=
10-
github.com/stackitcloud/stackit-sdk-go/services/resourcemanager v0.18.5/go.mod h1:CJLmdqWvJm5/3+lXPDKu8k4WXs2UG8euGoqQX5xE79k=
7+
github.com/stackitcloud/stackit-sdk-go/core v0.22.0 h1:6rViz7GnNwXSh51Lur5xuDzO8EWSZfN9J0HvEkBKq6c=
8+
github.com/stackitcloud/stackit-sdk-go/core v0.22.0/go.mod h1:osMglDby4csGZ5sIfhNyYq1bS1TxIdPY88+skE/kkmI=

examples/resourcemanager/resourcemanager.go

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ import (
55
"fmt"
66
"os"
77

8-
"github.com/stackitcloud/stackit-sdk-go/core/utils"
9-
"github.com/stackitcloud/stackit-sdk-go/services/resourcemanager"
8+
resourcemanager "github.com/stackitcloud/stackit-sdk-go/services/resourcemanager/v0api"
109
)
1110

1211
func main() {
@@ -21,28 +20,28 @@ func main() {
2120
}
2221

2322
// Get the projects under a specific resource (organization)
24-
getProjectsResp, err := client.ListProjects(context.Background()).ContainerParentId(parentOrganizationId).Execute()
23+
getProjectsResp, err := client.DefaultAPI.ListProjects(context.Background()).ContainerParentId(parentOrganizationId).Execute()
2524
if err != nil {
2625
fmt.Fprintf(os.Stderr, "Error when calling `GetProjects`: %v\n", err)
2726
} else {
28-
fmt.Printf("Number of projects: %v\n", len(*getProjectsResp.Items))
27+
fmt.Printf("Number of projects: %v\n", len(getProjectsResp.Items))
2928
}
3029

3130
// Create a project
3231
createProjectPayload := resourcemanager.CreateProjectPayload{
33-
ContainerParentId: utils.Ptr(parentOrganizationId),
34-
Name: utils.Ptr("my-project"),
35-
Members: &[]resourcemanager.Member{
32+
ContainerParentId: parentOrganizationId,
33+
Name: "my-project",
34+
Members: []resourcemanager.Member{
3635
{
37-
Role: utils.Ptr("project.owner"),
38-
Subject: utils.Ptr("owner-email@example.com"),
36+
Role: "project.owner",
37+
Subject: "owner-email@example.com",
3938
},
4039
},
4140
}
42-
createProjectResp, err := client.CreateProject(context.Background()).CreateProjectPayload(createProjectPayload).Execute()
41+
createProjectResp, err := client.DefaultAPI.CreateProject(context.Background()).CreateProjectPayload(createProjectPayload).Execute()
4342
if err != nil {
4443
fmt.Fprintf(os.Stderr, "Error when calling `CreateProject`: %v\n", err)
4544
} else {
46-
fmt.Printf("Created project with id \"%s\".\n", *createProjectResp.ProjectId)
45+
fmt.Printf("Created project with id \"%s\".\n", createProjectResp.ProjectId)
4746
}
4847
}

golang-ci.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,10 @@ linters:
9393
- unparam # false positives
9494
issues:
9595
exclude-use-default: false
96+
exclude-rules:
97+
# This ignores all deprecation warnings in the old wait packages while we have the compatibilty layer in place
98+
- path: ^wait/[^/]+\.go$
99+
linters:
100+
- staticcheck
101+
text: "SA1019:"
96102
go: 1.21

services/resourcemanager/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## v0.19.0
2+
- **Feature:** Introduction of multi API version support for the resourcemanager SDK module. For more details please see the announcement on GitHub: https://github.com/stackitcloud/stackit-sdk-go/discussions/5062
3+
- `v0api`: New package which should be used for communication with the STACKIT Resourcemanager API in the future
4+
- **Deprecation:** The contents in the root of this SDK module including the `wait` package are marked as deprecated and will be removed after 2026-09-30. Switch to the new `v0api` package instead.
5+
- **Dependencies:** Bump STACKIT SDK core module from `v0.21.1` to `v0.22.0`
6+
- **Breaking Change:** Removal of deprecated constants `ActiveState` and `CreatingState` in `wait` package
7+
18
## v0.18.5
29
- Bump STACKIT SDK core module from `v0.21.0` to `v0.21.1`
310

services/resourcemanager/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v0.18.5
1+
v0.19.0
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package wait
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net/http"
7+
"time"
8+
9+
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
10+
"github.com/stackitcloud/stackit-sdk-go/core/wait"
11+
resourcemanager "github.com/stackitcloud/stackit-sdk-go/services/resourcemanager/v0api"
12+
)
13+
14+
// CreateProjectWaitHandler will wait for project creation
15+
func CreateProjectWaitHandler(ctx context.Context, a resourcemanager.DefaultAPI, containerId string) *wait.AsyncActionHandler[resourcemanager.GetProjectResponse] {
16+
handler := wait.New(func() (waitFinished bool, response *resourcemanager.GetProjectResponse, err error) {
17+
p, err := a.GetProject(ctx, containerId).Execute()
18+
if err != nil {
19+
return false, nil, err
20+
}
21+
if p.ContainerId == containerId && p.LifecycleState == resourcemanager.LIFECYCLESTATE_ACTIVE {
22+
return true, p, nil
23+
}
24+
if p.ContainerId == containerId && p.LifecycleState == resourcemanager.LIFECYCLESTATE_CREATING {
25+
return false, nil, nil
26+
}
27+
return true, p, fmt.Errorf("creation failed: received project state '%s'", p.LifecycleState)
28+
})
29+
handler.SetSleepBeforeWait(1 * time.Minute)
30+
handler.SetTimeout(45 * time.Minute)
31+
return handler
32+
}
33+
34+
// DeleteProjectWaitHandler will wait for project deletion
35+
func DeleteProjectWaitHandler(ctx context.Context, a resourcemanager.DefaultAPI, containerId string) *wait.AsyncActionHandler[struct{}] {
36+
handler := wait.New(func() (waitFinished bool, response *struct{}, err error) {
37+
_, err = a.GetProject(ctx, containerId).Execute()
38+
if err == nil {
39+
return false, nil, nil
40+
}
41+
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped
42+
if !ok {
43+
return false, nil, fmt.Errorf("could not convert error to oapierror.GenericOpenAPIError")
44+
}
45+
if oapiErr.StatusCode == http.StatusNotFound || oapiErr.StatusCode == http.StatusForbidden {
46+
return true, nil, nil
47+
}
48+
return false, nil, err
49+
})
50+
handler.SetTimeout(15 * time.Minute)
51+
return handler
52+
}
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
package wait
2+
3+
import (
4+
"context"
5+
"net/http"
6+
"testing"
7+
"time"
8+
9+
"github.com/google/go-cmp/cmp"
10+
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
11+
"github.com/stackitcloud/stackit-sdk-go/core/utils"
12+
resourcemanager "github.com/stackitcloud/stackit-sdk-go/services/resourcemanager/v0api"
13+
)
14+
15+
type mockSettings struct {
16+
getFails bool
17+
getNotFound bool
18+
projectState resourcemanager.LifecycleState
19+
}
20+
21+
func newAPIMock(settings mockSettings) resourcemanager.DefaultAPI {
22+
return &resourcemanager.DefaultAPIServiceMock{
23+
GetProjectExecuteMock: utils.Ptr(func(_ resourcemanager.ApiGetProjectRequest) (*resourcemanager.GetProjectResponse, error) {
24+
if settings.getFails {
25+
return nil, &oapierror.GenericOpenAPIError{
26+
StatusCode: http.StatusInternalServerError,
27+
}
28+
}
29+
30+
if settings.getNotFound {
31+
return nil, &oapierror.GenericOpenAPIError{
32+
StatusCode: http.StatusNotFound,
33+
}
34+
}
35+
36+
return &resourcemanager.GetProjectResponse{
37+
LifecycleState: settings.projectState,
38+
ContainerId: "cid",
39+
}, nil
40+
}),
41+
}
42+
}
43+
44+
func TestCreateProjectWaitHandler(t *testing.T) {
45+
tests := []struct {
46+
desc string
47+
getFails bool
48+
projectState resourcemanager.LifecycleState
49+
wantErr bool
50+
wantResp bool
51+
}{
52+
{
53+
desc: "create_succeeded",
54+
getFails: false,
55+
projectState: resourcemanager.LIFECYCLESTATE_ACTIVE,
56+
wantErr: false,
57+
wantResp: true,
58+
},
59+
{
60+
desc: "creating",
61+
getFails: false,
62+
projectState: resourcemanager.LIFECYCLESTATE_CREATING,
63+
wantErr: true,
64+
wantResp: false,
65+
},
66+
{
67+
desc: "get_fails",
68+
getFails: true,
69+
projectState: resourcemanager.LifecycleState(""),
70+
wantErr: true,
71+
wantResp: false,
72+
},
73+
{
74+
desc: "unknown_state",
75+
getFails: false,
76+
projectState: resourcemanager.LifecycleState("ANOTHER STATE"),
77+
wantErr: true,
78+
wantResp: true,
79+
},
80+
}
81+
for _, tt := range tests {
82+
t.Run(tt.desc, func(t *testing.T) {
83+
apiClient := newAPIMock(mockSettings{
84+
getFails: tt.getFails,
85+
projectState: tt.projectState,
86+
})
87+
88+
var wantRes *resourcemanager.GetProjectResponse
89+
if tt.wantResp {
90+
wantRes = &resourcemanager.GetProjectResponse{
91+
LifecycleState: tt.projectState,
92+
ContainerId: "cid",
93+
}
94+
}
95+
96+
handler := CreateProjectWaitHandler(context.Background(), apiClient, "cid")
97+
98+
gotRes, err := handler.SetTimeout(10 * time.Millisecond).SetSleepBeforeWait(10 * time.Millisecond).WaitWithContext(context.Background())
99+
100+
if (err != nil) != tt.wantErr {
101+
t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr)
102+
}
103+
if !cmp.Equal(gotRes, wantRes) {
104+
t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes)
105+
}
106+
})
107+
}
108+
}
109+
110+
func TestDeleteProjectWaitHandler(t *testing.T) {
111+
tests := []struct {
112+
desc string
113+
getFails bool
114+
getNotFound bool
115+
projectState resourcemanager.LifecycleState
116+
wantErr bool
117+
}{
118+
{
119+
desc: "delete_succeeded",
120+
getFails: false,
121+
getNotFound: true,
122+
projectState: resourcemanager.LifecycleState(""),
123+
wantErr: false,
124+
},
125+
{
126+
desc: "get_fails",
127+
getFails: true,
128+
projectState: "",
129+
wantErr: true,
130+
},
131+
{
132+
desc: "timeout",
133+
getFails: false,
134+
projectState: "ANOTHER STATE",
135+
wantErr: true,
136+
},
137+
}
138+
for _, tt := range tests {
139+
t.Run(tt.desc, func(t *testing.T) {
140+
apiClient := newAPIMock(mockSettings{
141+
getFails: tt.getFails,
142+
getNotFound: tt.getNotFound,
143+
projectState: tt.projectState,
144+
})
145+
146+
handler := DeleteProjectWaitHandler(context.Background(), apiClient, "cid")
147+
148+
_, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background())
149+
150+
if (err != nil) != tt.wantErr {
151+
t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr)
152+
}
153+
})
154+
}
155+
}

services/resourcemanager/wait/wait.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Deprecated: Will be removed after 2026-09-30. Move to the packages generated for each available API version instead
12
package wait
23

34
import (
@@ -11,19 +12,14 @@ import (
1112
"github.com/stackitcloud/stackit-sdk-go/services/resourcemanager"
1213
)
1314

14-
const (
15-
// Deprecated: ActiveState is deprecated and will be removed after 14th November 2025. Use [resourcemanager.LIFECYCLESTATE_ACTIVE] instead.
16-
ActiveState = resourcemanager.LifecycleState("ACTIVE")
17-
// Deprecated: CreatingState is deprecated and will be removed after 14th November 2025. Use [resourcemanager.LIFECYCLESTATE_CREATING] instead.
18-
CreatingState = resourcemanager.LifecycleState("CREATING")
19-
)
20-
2115
// Interfaces needed for tests
16+
// Deprecated: Will be removed after 2026-09-30. Move to the packages generated for each available API version instead
2217
type APIClientInterface interface {
2318
GetProjectExecute(ctx context.Context, containerId string) (*resourcemanager.GetProjectResponse, error)
2419
}
2520

2621
// CreateProjectWaitHandler will wait for project creation
22+
// Deprecated: Will be removed after 2026-09-30. Move to the packages generated for each available API version instead
2723
func CreateProjectWaitHandler(ctx context.Context, a APIClientInterface, containerId string) *wait.AsyncActionHandler[resourcemanager.GetProjectResponse] {
2824
handler := wait.New(func() (waitFinished bool, response *resourcemanager.GetProjectResponse, err error) {
2925
p, err := a.GetProjectExecute(ctx, containerId)
@@ -47,6 +43,7 @@ func CreateProjectWaitHandler(ctx context.Context, a APIClientInterface, contain
4743
}
4844

4945
// DeleteProjectWaitHandler will wait for project deletion
46+
// Deprecated: Will be removed after 2026-09-30. Move to the packages generated for each available API version instead
5047
func DeleteProjectWaitHandler(ctx context.Context, a APIClientInterface, containerId string) *wait.AsyncActionHandler[struct{}] {
5148
handler := wait.New(func() (waitFinished bool, response *struct{}, err error) {
5249
_, err = a.GetProjectExecute(ctx, containerId)

0 commit comments

Comments
 (0)