Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
- **Breaking Change:** Removal of unused model structs: `Area`, `AreaConfig`, `AreaPrefixConfigIPv4`, `UpdateAreaIPv4`, `NetworkAreaIPv4`, `CreateAreaAddressFamily`, `CreateAreaIPv4`, `CreateNetworkAddressFamily`, `CreateNetworkIPv4Body`, `CreateNetworkIPv6Body`, `CreateServerPayloadBootVolume`, `CreateServerPayloadNetworking`, `NullableUpdateAreaAddressFamily`, `CreateServerPayloadNetworking`, `UpdateNetworkAddressFamily`, `CreateServerPayloadNetworking`, `CreateServerPayloadNetworking`
- `cdn`: [v2.1.0](services/cdn/CHANGELOG.md#v210)
- **Breaking change:** Removal of unused model structs: `GetLogsSearchFiltersResponse`, `PatchLokiLogSink`
- `kms`: [v1.0.1](services/kms/CHANGELOG.md#v101)
- **Bugfix:** Fixed `DisableKeyVersionWaitHandler` to properly check for `disabled` state

## Release (2025-10-29)
- `stackitmarketplace`: [v1.15.0](services/stackitmarketplace/CHANGELOG.md#v1150)
Expand Down
3 changes: 3 additions & 0 deletions services/kms/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## v1.0.1
- **Bugfix:** Fixed `DisableKeyVersionWaitHandler` to properly check for `disabled` state

## v1.0.0
- Switch to API version `v1` of STACKIT KMS service (previously `v1beta`)
- **Breaking Change:** Removal of deprecated `Backend` model
Expand Down
2 changes: 1 addition & 1 deletion services/kms/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v1.0.0
v1.0.1
43 changes: 30 additions & 13 deletions services/kms/wait/wait.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package wait
import (
"context"
"errors"
"fmt"
"net/http"
"time"

Expand Down Expand Up @@ -58,7 +59,7 @@ func CreateKeyRingWaitHandler(ctx context.Context, client ApiKmsClient, projectI
return false, nil, err
}

if response.State != nil {
if response != nil && response.State != nil {
switch *response.State {
case kms.KEYRINGSTATE_CREATING:
return false, nil, nil
Expand All @@ -80,7 +81,7 @@ func CreateOrUpdateKeyWaitHandler(ctx context.Context, client ApiKmsClient, proj
return false, nil, err
}

if response.State != nil {
if response != nil && response.State != nil {
switch *response.State {
case kms.KEYSTATE_CREATING:
return false, nil, nil
Expand Down Expand Up @@ -117,16 +118,18 @@ func EnableKeyVersionWaitHandler(ctx context.Context, client ApiKmsClient, proje
handler := wait.New(func() (bool, *kms.Version, error) {
response, err := client.GetVersionExecute(ctx, projectId, region, keyRingId, keyId, version)
if err != nil {
var apiErr *oapierror.GenericOpenAPIError
if errors.As(err, &apiErr) {
if statusCode := apiErr.StatusCode; statusCode == http.StatusNotFound || statusCode == http.StatusGone {
return true, nil, fmt.Errorf("enabling failed for key %s version %d: version or key not found", keyId, version)
}
}
return false, nil, err
}

if response.State != nil {
if response != nil && response.State != nil {
switch *response.State {
case kms.VERSIONSTATE_DESTROYED:
return true, response, nil
case kms.VERSIONSTATE_KEY_MATERIAL_INVALID:
return true, response, nil
case kms.VERSIONSTATE_DISABLED:
case kms.VERSIONSTATE_DESTROYED, kms.VERSIONSTATE_KEY_MATERIAL_INVALID, kms.VERSIONSTATE_DISABLED:
return true, response, nil
case kms.VERSIONSTATE_CREATING:
return false, nil, nil
Expand All @@ -143,16 +146,30 @@ func EnableKeyVersionWaitHandler(ctx context.Context, client ApiKmsClient, proje

func DisableKeyVersionWaitHandler(ctx context.Context, client ApiKmsClient, projectId, region, keyRingId, keyId string, version int64) *wait.AsyncActionHandler[kms.Version] {
handler := wait.New(func() (bool, *kms.Version, error) {
_, err := client.GetVersionExecute(ctx, projectId, region, keyRingId, keyId, version)
response, err := client.GetVersionExecute(ctx, projectId, region, keyRingId, keyId, version)
if err != nil {
var apiErr *oapierror.GenericOpenAPIError
if errors.As(err, &apiErr) {
if statusCode := apiErr.StatusCode; statusCode == http.StatusNotFound || statusCode == http.StatusGone {
return true, nil, nil
return true, nil, fmt.Errorf("disabling failed for key %s version %d: version or key not found", keyId, version)
}
}
return true, nil, err
return false, nil, err
}

if response != nil && response.State != nil {
switch *response.State {
case kms.VERSIONSTATE_DISABLED:
return true, response, nil
case kms.VERSIONSTATE_ACTIVE, kms.VERSIONSTATE_CREATING, kms.VERSIONSTATE_KEY_MATERIAL_UNAVAILABLE:
return false, nil, nil
case kms.VERSIONSTATE_DESTROYED, kms.VERSIONSTATE_KEY_MATERIAL_INVALID:
return true, response, fmt.Errorf("disabling failed for key %s version %d: state %s", keyId, version, *response.State)
default:
return true, response, fmt.Errorf("key version %d for key %s has unexpected state %s", version, keyId, *response.State)
}
}

return false, nil, nil
})
handler.SetTimeout(10 * time.Minute)
Expand All @@ -166,8 +183,8 @@ func CreateWrappingKeyWaitHandler(ctx context.Context, client ApiKmsClient, proj
return false, nil, err
}

if state := response.State; state != nil {
switch *state {
if response != nil && response.State != nil {
switch *response.State {
case kms.WRAPPINGKEYSTATE_CREATING:
return false, nil, nil
default:
Expand Down
117 changes: 81 additions & 36 deletions services/kms/wait/wait_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ func TestCreateKeyRingWaitHandler(t *testing.T) {
}

if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("differing key %s", diff)
t.Errorf("differing key ring %s", diff)
}
})
}
Expand Down Expand Up @@ -435,6 +435,30 @@ func TestEnableKeyVersionWaitHandler(t *testing.T) {
fixtureVersion(1, false, "bogus"),
false,
},
{
"version not found (404)",
[]versionResponse{
{nil, oapierror.NewError(http.StatusNotFound, "not found")},
},
nil,
true,
},
{
"version gone (410)",
[]versionResponse{
{nil, oapierror.NewError(http.StatusGone, "gone")},
},
nil,
true,
},
{
"error fetching version",
[]versionResponse{
{nil, oapierror.NewError(http.StatusInternalServerError, "internal error")},
},
nil,
true,
},
// no special update tests needed as the states are the same
}
for _, tt := range tests {
Expand All @@ -454,7 +478,7 @@ func TestEnableKeyVersionWaitHandler(t *testing.T) {
}

if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("differing key %s", diff)
t.Errorf("differing version %s", diff)
}
})
}
Expand All @@ -464,61 +488,84 @@ func TestDisableKeyVersionWaitHandler(t *testing.T) {
tests := []struct {
name string
responses []versionResponse
want *kms.Version
wantErr bool
}{
{
"Delete with '404' succeeded immediately",
"disable succeeded immediately",
[]versionResponse{
{nil, oapierror.NewError(http.StatusNotFound, "not found")},
{fixtureVersion(1, true, kms.VERSIONSTATE_DISABLED), nil},
},
fixtureVersion(1, true, kms.VERSIONSTATE_DISABLED),
false,
},
{
"Delete with '404' delayed",
"disable succeeded delayed",
[]versionResponse{
{fixtureVersion(1, false, kms.VERSIONSTATE_ACTIVE), nil},
{fixtureVersion(1, false, kms.VERSIONSTATE_ACTIVE), nil},
{fixtureVersion(1, false, kms.VERSIONSTATE_ACTIVE), nil},
{fixtureVersion(1, true, kms.VERSIONSTATE_DISABLED), nil},
},
fixtureVersion(1, true, kms.VERSIONSTATE_DISABLED),
false,
},
{
"disable succeeded from creating state",
[]versionResponse{
{fixtureVersion(1, false, kms.VERSIONSTATE_CREATING), nil},
{fixtureVersion(1, false, kms.VERSIONSTATE_CREATING), nil},
{fixtureVersion(1, false, kms.VERSIONSTATE_CREATING), nil},
{nil, oapierror.NewError(http.StatusNotFound, "not found")},
{fixtureVersion(1, true, kms.VERSIONSTATE_DISABLED), nil},
},
fixtureVersion(1, true, kms.VERSIONSTATE_DISABLED),
false,
},
{
"Delete with 'gone' succeeded immediately",
"version already destroyed",
[]versionResponse{
{nil, oapierror.NewError(http.StatusGone, "gone")},
{fixtureVersion(1, false, kms.VERSIONSTATE_DESTROYED), nil},
},
false,
fixtureVersion(1, false, kms.VERSIONSTATE_DESTROYED),
true,
},
{
"Delete with 'gone' delayed",
"version key material invalid",
[]versionResponse{
{fixtureVersion(1, false, kms.VERSIONSTATE_CREATING), nil},
{fixtureVersion(1, false, kms.VERSIONSTATE_CREATING), nil},
{fixtureVersion(1, false, kms.VERSIONSTATE_CREATING), nil},
{nil, oapierror.NewError(http.StatusGone, "not found")},
{fixtureVersion(1, false, kms.VERSIONSTATE_KEY_MATERIAL_INVALID), nil},
},
false,
fixtureVersion(1, false, kms.VERSIONSTATE_KEY_MATERIAL_INVALID),
true,
},
{
"Delete with error delayed",
"timeout waiting for disabled state",
[]versionResponse{
{fixtureVersion(1, false, kms.VERSIONSTATE_CREATING), nil},
{fixtureVersion(1, false, kms.VERSIONSTATE_CREATING), nil},

{fixtureVersion(1, false, kms.VERSIONSTATE_CREATING), nil},
{fixtureVersion(1, false, kms.VERSIONSTATE_DESTROYED), oapierror.NewError(http.StatusInternalServerError, "kapow")},
{fixtureVersion(1, false, kms.VERSIONSTATE_ACTIVE), nil},
},
nil,
true,
},
{
"version not found (404)",
[]versionResponse{
{nil, oapierror.NewError(http.StatusNotFound, "not found")},
},
nil,
true,
},
{
"Cannot delete",
"version gone (410)",
[]versionResponse{
{fixtureVersion(1, false, kms.VERSIONSTATE_CREATING), nil},
{fixtureVersion(1, false, kms.VERSIONSTATE_CREATING), nil},
{fixtureVersion(1, false, kms.VERSIONSTATE_CREATING), nil},
{fixtureVersion(1, false, kms.VERSIONSTATE_DESTROYED), oapierror.NewError(http.StatusOK, "ok")},
{nil, oapierror.NewError(http.StatusGone, "gone")},
},
nil,
true,
},
{
"error fetching version",
[]versionResponse{
{nil, oapierror.NewError(http.StatusInternalServerError, "internal error")},
},
nil,
true,
},
}
Expand All @@ -529,18 +576,16 @@ func TestDisableKeyVersionWaitHandler(t *testing.T) {
versionResponses: tt.responses,
}
handler := DisableKeyVersionWaitHandler(ctx, client, testProject, testRegion, testKeyRingId, testKeyId, 1)
_, err := handler.SetTimeout(1 * time.Second).
got, err := handler.SetTimeout(1 * time.Second).
SetThrottle(250 * time.Millisecond).
WaitWithContext(ctx)

if tt.wantErr != (err != nil) {
t.Fatalf("wrong error result. want err: %v got %v", tt.wantErr, err)
if (err != nil) != tt.wantErr {
t.Fatalf("unexpected error response. want %v but got %v ", tt.wantErr, err)
}
if tt.wantErr {
var apiErr *oapierror.GenericOpenAPIError
if !errors.As(err, &apiErr) {
t.Fatalf("expected openapi error, got %v", err)
}

if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("differing version %s", diff)
}
})
}
Expand Down Expand Up @@ -618,7 +663,7 @@ func TestCreateWrappingWaitHandler(t *testing.T) {
}

if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("differing key %s", diff)
t.Errorf("differing wrapping key %s", diff)
}
})
}
Expand Down
Loading