Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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