Skip to content

Commit 0037fbf

Browse files
committed
feat(kms): waiter for wrapping keys
1 parent 8f425a8 commit 0037fbf

File tree

2 files changed

+143
-4
lines changed

2 files changed

+143
-4
lines changed

services/kms/wait/wait.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,17 @@ const (
2525
StatusKeyVersionDestroyed = "destroyed"
2626
)
2727

28+
const (
29+
StatusWrappingKeyActive = "active"
30+
StatusWrappingKeyKeyMaterialNotReady = "key_material_not_ready"
31+
StatusWrappingKeyExpired = "expired"
32+
StatusWrappingKeyDeleting = "deleting"
33+
)
34+
2835
type ApiKmsClient interface {
2936
GetKeyExecute(ctx context.Context, projectId string, regionId string, keyRingId string, keyId string) (*kms.Key, error)
3037
GetVersionExecute(ctx context.Context, projectId string, regionId string, keyRingId string, keyId string, versionNumber int64) (*kms.Version, error)
38+
GetWrappingKeyExecute(ctx context.Context, projectId string, regionId string, keyRingId string, wrappingKeyId string) (*kms.WrappingKey, error)
3139
}
3240

3341
func CreateOrUpdateKeyWaitHandler(ctx context.Context, client ApiKmsClient, projectId, region, keyRingId, keyId string) *wait.AsyncActionHandler[kms.Key] {
@@ -115,3 +123,25 @@ func DisableKeyVersionWaitHandler(ctx context.Context, client ApiKmsClient, proj
115123
handler.SetTimeout(10 * time.Minute)
116124
return handler
117125
}
126+
127+
func CreateWrappingKeyWaitHandler(ctx context.Context, client ApiKmsClient, projectId, region, keyRingId, wrappingKeyId string) *wait.AsyncActionHandler[kms.WrappingKey] {
128+
handler := wait.New(func() (bool, *kms.WrappingKey, error) {
129+
response, err := client.GetWrappingKeyExecute(ctx, projectId, region, keyRingId, wrappingKeyId)
130+
if err != nil {
131+
return false, nil, err
132+
}
133+
134+
if state := response.State; state != nil {
135+
switch *state {
136+
case StatusWrappingKeyKeyMaterialNotReady:
137+
return false, nil, nil
138+
default:
139+
return true, response, nil
140+
}
141+
}
142+
143+
return false, nil, nil
144+
})
145+
handler.SetTimeout(10 * time.Minute)
146+
return handler
147+
}

services/kms/wait/wait_test.go

Lines changed: 113 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,26 @@ type versionResponse struct {
3535
err error
3636
}
3737

38+
type wrappingKeyResponse struct {
39+
wrappingKey *kms.WrappingKey
40+
err error
41+
}
42+
3843
type apiKmsMocked struct {
39-
idxKeyResponse int
40-
idxVersionResponse int
41-
keyResponses []keyResponse
42-
versionResponses []versionResponse
44+
idxKeyResponse int
45+
idxVersionResponse int
46+
idxWrappingKeyResponse int
47+
keyResponses []keyResponse
48+
versionResponses []versionResponse
49+
wrappingKeyResponses []wrappingKeyResponse
50+
}
51+
52+
// GetWrappingKeyExecute implements ApiKmsClient.
53+
func (a *apiKmsMocked) GetWrappingKeyExecute(_ context.Context, _, _, _, _ string) (*kms.WrappingKey, error) {
54+
resp := a.wrappingKeyResponses[a.idxWrappingKeyResponse]
55+
a.idxWrappingKeyResponse++
56+
a.idxWrappingKeyResponse %= len(a.wrappingKeyResponses)
57+
return resp.wrappingKey, resp.err
4358
}
4459

4560
// GetVersionExecute implements ApiKmsClient.
@@ -74,6 +89,22 @@ func fixtureKey(state string) *kms.Key {
7489
}
7590
}
7691

92+
func fixtureWrappingKey(state string) *kms.WrappingKey {
93+
return &kms.WrappingKey{
94+
Algorithm: kms.WRAPPINGALGORITHM__2048_OAEP_SHA256.Ptr(),
95+
Backend: kms.BACKEND_SOFTWARE.Ptr(),
96+
CreatedAt: &testDate,
97+
Description: utils.Ptr("test-description"),
98+
DisplayName: utils.Ptr("test-displayname"),
99+
Id: &testKeyId,
100+
KeyRingId: &testKeyRingId,
101+
Purpose: kms.WRAPPINGPURPOSE_SYMMETRIC_KEY.Ptr(),
102+
State: &state,
103+
ExpiresAt: &testDate,
104+
PublicKey: &testPublicKey,
105+
}
106+
}
107+
77108
func fixtureVersion(version int, disabled bool, state string) *kms.Version {
78109
return &kms.Version{
79110
CreatedAt: &testDate,
@@ -414,3 +445,81 @@ func TestDisableKeyVersionWaitHandler(t *testing.T) {
414445
})
415446
}
416447
}
448+
449+
func TestCreateWrappingWaitHandler(t *testing.T) {
450+
tests := []struct {
451+
name string
452+
responses []wrappingKeyResponse
453+
want *kms.WrappingKey
454+
wantErr bool
455+
}{
456+
{
457+
"create succeeded immediately",
458+
[]wrappingKeyResponse{
459+
{fixtureWrappingKey(StatusWrappingKeyActive), nil},
460+
},
461+
fixtureWrappingKey(StatusWrappingKeyActive),
462+
false,
463+
},
464+
{
465+
"create succeeded delayed",
466+
[]wrappingKeyResponse{
467+
{fixtureWrappingKey(StatusWrappingKeyKeyMaterialNotReady), nil},
468+
{fixtureWrappingKey(StatusWrappingKeyKeyMaterialNotReady), nil},
469+
{fixtureWrappingKey(StatusWrappingKeyKeyMaterialNotReady), nil},
470+
{fixtureWrappingKey(StatusWrappingKeyActive), nil},
471+
},
472+
fixtureWrappingKey(StatusWrappingKeyActive),
473+
false,
474+
},
475+
{
476+
"create failed delayed",
477+
[]wrappingKeyResponse{
478+
{fixtureWrappingKey(StatusWrappingKeyKeyMaterialNotReady), nil},
479+
{fixtureWrappingKey(StatusWrappingKeyKeyMaterialNotReady), nil},
480+
{fixtureWrappingKey(StatusWrappingKeyKeyMaterialNotReady), nil},
481+
{fixtureWrappingKey(StatusWrappingKeyDeleting), nil},
482+
},
483+
fixtureWrappingKey(StatusWrappingKeyDeleting),
484+
false,
485+
},
486+
{
487+
"timeout",
488+
[]wrappingKeyResponse{
489+
{fixtureWrappingKey(StatusWrappingKeyKeyMaterialNotReady), nil},
490+
},
491+
nil,
492+
true,
493+
},
494+
{
495+
"broken state",
496+
[]wrappingKeyResponse{
497+
{fixtureWrappingKey("bogus"), nil},
498+
},
499+
fixtureWrappingKey("bogus"),
500+
false,
501+
},
502+
// no special update tests needed as the states are the same
503+
}
504+
for _, tt := range tests {
505+
t.Run(tt.name, func(t *testing.T) {
506+
ctx := context.Background()
507+
client := &apiKmsMocked{
508+
wrappingKeyResponses: tt.responses,
509+
}
510+
511+
handler := CreateWrappingKeyWaitHandler(ctx, client, testProject, testRegion, testKeyRingId, testKeyId)
512+
got, err := handler.SetTimeout(1 * time.Second).
513+
SetThrottle(250 * time.Millisecond).
514+
WaitWithContext(ctx)
515+
516+
if (err != nil) != tt.wantErr {
517+
t.Fatalf("unexpected error response. want %v but got %v ", tt.wantErr, err)
518+
}
519+
520+
if diff := cmp.Diff(tt.want, got); diff != "" {
521+
t.Errorf("differing key %s", diff)
522+
}
523+
})
524+
}
525+
}

0 commit comments

Comments
 (0)