Skip to content

Commit b776e8c

Browse files
authored
chore(kms): switch to new multi-API support SDK structure (#1340)
relates to STACKITTPR-558
1 parent 153cbe9 commit b776e8c

File tree

13 files changed

+144
-246
lines changed

13 files changed

+144
-246
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ require (
1818
github.com/stackitcloud/stackit-sdk-go/services/edge v0.7.0
1919
github.com/stackitcloud/stackit-sdk-go/services/git v0.11.0
2020
github.com/stackitcloud/stackit-sdk-go/services/iaas v1.3.5
21-
github.com/stackitcloud/stackit-sdk-go/services/kms v1.3.2
21+
github.com/stackitcloud/stackit-sdk-go/services/kms v1.6.0
2222
github.com/stackitcloud/stackit-sdk-go/services/loadbalancer v1.8.0
2323
github.com/stackitcloud/stackit-sdk-go/services/logme v0.27.1
2424
github.com/stackitcloud/stackit-sdk-go/services/logs v0.7.1

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,8 @@ github.com/stackitcloud/stackit-sdk-go/services/git v0.11.0 h1:siKBCYl7BwR5S25Y4
167167
github.com/stackitcloud/stackit-sdk-go/services/git v0.11.0/go.mod h1:QKy74hhLVZKXItw3y+elF8s9QezFqpEsAUmaqvNDzYs=
168168
github.com/stackitcloud/stackit-sdk-go/services/iaas v1.3.5 h1:W57+XRa8wTLsi5CV9Tqa7mGgt/PvlRM//RurXSmvII8=
169169
github.com/stackitcloud/stackit-sdk-go/services/iaas v1.3.5/go.mod h1:lTWjW57eAq1bwfM6nsNinhoBr3MHFW/GaFasdAsYfDM=
170-
github.com/stackitcloud/stackit-sdk-go/services/kms v1.3.2 h1:2ulSL2IkIAKND59eAjbEhVkOoBMyvm48ojwz1a3t0U0=
171-
github.com/stackitcloud/stackit-sdk-go/services/kms v1.3.2/go.mod h1:cuIaMMiHeHQsbvy7BOFMutoV3QtN+ZBx7Tg3GmYUw7s=
170+
github.com/stackitcloud/stackit-sdk-go/services/kms v1.6.0 h1:WWU2LpqmazsPDgoRAVrhLzo2MiNU9dNim81z793DbBU=
171+
github.com/stackitcloud/stackit-sdk-go/services/kms v1.6.0/go.mod h1:FuyCm3s/Ihw+tkpVLGMXwgTtlhrijd31cUCUBWpn1p8=
172172
github.com/stackitcloud/stackit-sdk-go/services/loadbalancer v1.8.0 h1:DxrN85V738CRLynu6MULQHO+OXyYnkhVPgoZKULfFIs=
173173
github.com/stackitcloud/stackit-sdk-go/services/loadbalancer v1.8.0/go.mod h1:ClPE4TOM1FeaJiwTXvApq4gWaSgTLq6nU3PPHAIQDN4=
174174
github.com/stackitcloud/stackit-sdk-go/services/logme v0.27.1 h1:6AaWxQNtOEvIvbtyySi5KIrNzxGbKgOayUnA3fpuqns=

stackit/internal/services/kms/key/datasource.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
1212
"github.com/hashicorp/terraform-plugin-log/tflog"
1313
sdkUtils "github.com/stackitcloud/stackit-sdk-go/core/utils"
14-
"github.com/stackitcloud/stackit-sdk-go/services/kms"
14+
kms "github.com/stackitcloud/stackit-sdk-go/services/kms/v1api"
1515
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion"
1616
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
1717
kmsUtils "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/kms/utils"
@@ -159,7 +159,7 @@ func (k *keyDataSource) Read(ctx context.Context, req datasource.ReadRequest, re
159159
ctx = tflog.SetField(ctx, "region", region)
160160
ctx = tflog.SetField(ctx, "key_id", keyId)
161161

162-
keyResponse, err := k.client.GetKey(ctx, projectId, region, keyRingId, keyId).Execute()
162+
keyResponse, err := k.client.DefaultAPI.GetKey(ctx, projectId, region, keyRingId, keyId).Execute()
163163
if err != nil {
164164
utils.LogError(
165165
ctx,

stackit/internal/services/kms/key/resource.go

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
"strings"
99

1010
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
11-
"github.com/stackitcloud/stackit-sdk-go/services/kms/wait"
11+
"github.com/stackitcloud/stackit-sdk-go/services/kms/v1api/wait"
1212

1313
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
1414
"github.com/hashicorp/terraform-plugin-framework/resource"
@@ -20,7 +20,7 @@ import (
2020
"github.com/hashicorp/terraform-plugin-log/tflog"
2121
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
2222
sdkUtils "github.com/stackitcloud/stackit-sdk-go/core/utils"
23-
"github.com/stackitcloud/stackit-sdk-go/services/kms"
23+
kms "github.com/stackitcloud/stackit-sdk-go/services/kms/v1api"
2424
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion"
2525
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
2626
kmsUtils "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/kms/utils"
@@ -259,29 +259,28 @@ func (r *keyResource) Create(ctx context.Context, req resource.CreateRequest, re
259259
return
260260
}
261261

262-
createResponse, err := r.client.CreateKey(ctx, projectId, region, keyRingId).CreateKeyPayload(*payload).Execute()
262+
createResponse, err := r.client.DefaultAPI.CreateKey(ctx, projectId, region, keyRingId).CreateKeyPayload(*payload).Execute()
263263
if err != nil {
264264
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating key", fmt.Sprintf("Calling API: %v", err))
265265
return
266266
}
267267

268268
ctx = core.LogResponse(ctx)
269269

270-
if createResponse == nil || createResponse.Id == nil {
270+
if createResponse == nil {
271271
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating key", "API returned empty response")
272272
return
273273
}
274274

275-
keyId := *createResponse.Id
276275
// Write id attributes to state before polling via the wait handler - just in case anything goes wrong during the wait handler
277276
ctx = utils.SetAndLogStateFields(ctx, &resp.Diagnostics, &resp.State, map[string]any{
278277
"project_id": projectId,
279278
"region": region,
280279
"keyring_id": keyRingId,
281-
"key_id": keyId,
280+
"key_id": createResponse.Id,
282281
})
283282

284-
waitHandlerResp, err := wait.CreateOrUpdateKeyWaitHandler(ctx, r.client, projectId, region, keyRingId, keyId).WaitWithContext(ctx)
283+
waitHandlerResp, err := wait.CreateOrUpdateKeyWaitHandler(ctx, r.client.DefaultAPI, projectId, region, keyRingId, createResponse.Id).WaitWithContext(ctx)
285284
if err != nil {
286285
core.LogAndAddError(ctx, &resp.Diagnostics, "Error waiting for key creation", fmt.Sprintf("Calling API: %v", err))
287286
return
@@ -321,7 +320,7 @@ func (r *keyResource) Read(ctx context.Context, req resource.ReadRequest, resp *
321320
ctx = tflog.SetField(ctx, "region", region)
322321
ctx = tflog.SetField(ctx, "key_id", keyId)
323322

324-
keyResponse, err := r.client.GetKey(ctx, projectId, region, keyRingId, keyId).Execute()
323+
keyResponse, err := r.client.DefaultAPI.GetKey(ctx, projectId, region, keyRingId, keyId).Execute()
325324
if err != nil {
326325
var oapiErr *oapierror.GenericOpenAPIError
327326
ok := errors.As(err, &oapiErr)
@@ -368,7 +367,7 @@ func (r *keyResource) Delete(ctx context.Context, req resource.DeleteRequest, re
368367
region := r.providerData.GetRegionWithOverride(model.Region)
369368
keyId := model.KeyId.ValueString()
370369

371-
err := r.client.DeleteKey(ctx, projectId, region, keyRingId, keyId).Execute()
370+
err := r.client.DefaultAPI.DeleteKey(ctx, projectId, region, keyRingId, keyId).Execute()
372371
if err != nil {
373372
core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting key", fmt.Sprintf("Calling API: %v", err))
374373
}
@@ -413,28 +412,20 @@ func mapFields(key *kms.Key, model *Model, region string) error {
413412
var keyId string
414413
if model.KeyId.ValueString() != "" {
415414
keyId = model.KeyId.ValueString()
416-
} else if key.Id != nil {
417-
keyId = *key.Id
418415
} else {
419-
return fmt.Errorf("key id not present")
416+
keyId = key.Id
420417
}
421418

422419
model.Id = utils.BuildInternalTerraformId(model.ProjectId.ValueString(), region, model.KeyRingId.ValueString(), keyId)
423420
model.KeyId = types.StringValue(keyId)
424-
model.DisplayName = types.StringPointerValue(key.DisplayName)
421+
model.DisplayName = types.StringValue(key.DisplayName)
425422
model.Region = types.StringValue(region)
426-
model.ImportOnly = types.BoolPointerValue(key.ImportOnly)
423+
model.ImportOnly = types.BoolValue(key.ImportOnly)
427424
model.AccessScope = types.StringValue(string(key.GetAccessScope()))
428425
model.Algorithm = types.StringValue(string(key.GetAlgorithm()))
429426
model.Purpose = types.StringValue(string(key.GetPurpose()))
430427
model.Protection = types.StringValue(string(key.GetProtection()))
431-
432-
// TODO: workaround - remove once STACKITKMS-377 is resolved (just write the return value from the API to the state then)
433-
if !(model.Description.IsNull() && key.Description != nil && *key.Description == "") {
434-
model.Description = types.StringPointerValue(key.Description)
435-
} else {
436-
model.Description = types.StringNull()
437-
}
428+
model.Description = types.StringPointerValue(key.Description)
438429

439430
return nil
440431
}
@@ -443,13 +434,19 @@ func toCreatePayload(model *Model) (*kms.CreateKeyPayload, error) {
443434
if model == nil {
444435
return nil, fmt.Errorf("nil model")
445436
}
437+
438+
var accessScope *kms.AccessScope
439+
if !utils.IsUndefined(model.AccessScope) {
440+
accessScope = new(kms.AccessScope(model.AccessScope.ValueString()))
441+
}
442+
446443
return &kms.CreateKeyPayload{
447-
AccessScope: kms.CreateKeyPayloadGetAccessScopeAttributeType(conversion.StringValueToPointer(model.AccessScope)),
448-
Algorithm: kms.CreateKeyPayloadGetAlgorithmAttributeType(conversion.StringValueToPointer(model.Algorithm)),
449-
Protection: kms.CreateKeyPayloadGetProtectionAttributeType(conversion.StringValueToPointer(model.Protection)),
444+
AccessScope: accessScope,
445+
Algorithm: kms.Algorithm(model.Algorithm.ValueString()),
446+
Protection: kms.Protection(model.Protection.ValueString()),
450447
Description: conversion.StringValueToPointer(model.Description),
451-
DisplayName: conversion.StringValueToPointer(model.DisplayName),
448+
DisplayName: model.DisplayName.ValueString(),
452449
ImportOnly: conversion.BoolValueToPointer(model.ImportOnly),
453-
Purpose: kms.CreateKeyPayloadGetPurposeAttributeType(conversion.StringValueToPointer(model.Purpose)),
450+
Purpose: kms.Purpose(model.Purpose.ValueString()),
454451
}, nil
455452
}

stackit/internal/services/kms/key/resource_test.go

Lines changed: 19 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ import (
88

99
"github.com/google/go-cmp/cmp"
1010
"github.com/hashicorp/terraform-plugin-framework/types"
11-
"github.com/stackitcloud/stackit-sdk-go/core/utils"
12-
"github.com/stackitcloud/stackit-sdk-go/services/kms"
11+
kms "github.com/stackitcloud/stackit-sdk-go/services/kms/v1api"
1312
)
1413

1514
var (
@@ -39,17 +38,19 @@ func TestMapFields(t *testing.T) {
3938
ProjectId: types.StringValue(projectId),
4039
},
4140
input: &kms.Key{
42-
Id: new(keyId),
43-
Protection: utils.Ptr(kms.PROTECTION_SOFTWARE),
44-
Algorithm: utils.Ptr(kms.ALGORITHM_ECDSA_P256_SHA256),
45-
Purpose: utils.Ptr(kms.PURPOSE_ASYMMETRIC_SIGN_VERIFY),
46-
AccessScope: utils.Ptr(kms.ACCESSSCOPE_PUBLIC),
41+
Id: keyId,
42+
DisplayName: "display-name",
43+
Protection: kms.PROTECTION_SOFTWARE,
44+
Algorithm: kms.ALGORITHM_ECDSA_P256_SHA256,
45+
Purpose: kms.PURPOSE_ASYMMETRIC_SIGN_VERIFY,
46+
AccessScope: kms.ACCESSSCOPE_PUBLIC,
47+
ImportOnly: true,
4748
},
4849
region: "eu01",
4950
},
5051
expected: Model{
5152
Description: types.StringNull(),
52-
DisplayName: types.StringNull(),
53+
DisplayName: types.StringValue("display-name"),
5354
KeyRingId: types.StringValue(keyRingId),
5455
KeyId: types.StringValue(keyId),
5556
Id: types.StringValue(fmt.Sprintf("%s,eu01,%s,%s", projectId, keyRingId, keyId)),
@@ -59,6 +60,7 @@ func TestMapFields(t *testing.T) {
5960
Algorithm: types.StringValue(string(kms.ALGORITHM_ECDSA_P256_SHA256)),
6061
Purpose: types.StringValue(string(kms.PURPOSE_ASYMMETRIC_SIGN_VERIFY)),
6162
AccessScope: types.StringValue(string(kms.ACCESSSCOPE_PUBLIC)),
63+
ImportOnly: types.BoolValue(true),
6264
},
6365
isValid: true,
6466
},
@@ -71,14 +73,14 @@ func TestMapFields(t *testing.T) {
7173
ProjectId: types.StringValue(projectId),
7274
},
7375
input: &kms.Key{
74-
Id: new(keyId),
76+
Id: keyId,
7577
Description: new("descr"),
76-
DisplayName: new("name"),
77-
ImportOnly: new(true),
78-
Protection: utils.Ptr(kms.PROTECTION_SOFTWARE),
79-
Algorithm: utils.Ptr(kms.ALGORITHM_AES_256_GCM),
80-
Purpose: utils.Ptr(kms.PURPOSE_MESSAGE_AUTHENTICATION_CODE),
81-
AccessScope: utils.Ptr(kms.ACCESSSCOPE_SNA),
78+
DisplayName: "name",
79+
ImportOnly: true,
80+
Protection: kms.PROTECTION_SOFTWARE,
81+
Algorithm: kms.ALGORITHM_AES_256_GCM,
82+
Purpose: kms.PURPOSE_MESSAGE_AUTHENTICATION_CODE,
83+
AccessScope: kms.ACCESSSCOPE_SNA,
8284
},
8385
region: "eu01",
8486
},
@@ -98,17 +100,6 @@ func TestMapFields(t *testing.T) {
98100
},
99101
isValid: true,
100102
},
101-
{
102-
description: "nil_response_field",
103-
args: args{
104-
state: Model{},
105-
input: &kms.Key{
106-
Id: nil,
107-
},
108-
},
109-
expected: Model{},
110-
isValid: false,
111-
},
112103
{
113104
description: "nil_response",
114105
args: args{
@@ -118,18 +109,6 @@ func TestMapFields(t *testing.T) {
118109
expected: Model{},
119110
isValid: false,
120111
},
121-
{
122-
description: "no_resource_id",
123-
args: args{
124-
state: Model{
125-
Region: types.StringValue("eu01"),
126-
ProjectId: types.StringValue(projectId),
127-
},
128-
input: &kms.Key{},
129-
},
130-
expected: Model{},
131-
isValid: false,
132-
},
133112
}
134113
for _, tt := range tests {
135114
t.Run(tt.description, func(t *testing.T) {
@@ -173,7 +152,7 @@ func TestToCreatePayload(t *testing.T) {
173152
DisplayName: types.StringValue("name"),
174153
},
175154
expected: &kms.CreateKeyPayload{
176-
DisplayName: new("name"),
155+
DisplayName: "name",
177156
},
178157
isValid: true,
179158
},
@@ -184,7 +163,7 @@ func TestToCreatePayload(t *testing.T) {
184163
Description: types.StringValue(""),
185164
},
186165
expected: &kms.CreateKeyPayload{
187-
DisplayName: new(""),
166+
DisplayName: "",
188167
Description: new(""),
189168
},
190169
isValid: true,

stackit/internal/services/kms/keyring/datasource.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
1010
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
1111
"github.com/hashicorp/terraform-plugin-log/tflog"
12-
"github.com/stackitcloud/stackit-sdk-go/services/kms"
12+
kms "github.com/stackitcloud/stackit-sdk-go/services/kms/v1api"
1313
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion"
1414
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
1515
kmsUtils "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/kms/utils"
@@ -111,7 +111,7 @@ func (k *keyRingDataSource) Read(ctx context.Context, request datasource.ReadReq
111111
ctx = tflog.SetField(ctx, "project_id", projectId)
112112
ctx = tflog.SetField(ctx, "region", region)
113113

114-
keyRingResponse, err := k.client.GetKeyRing(ctx, projectId, region, keyRingId).Execute()
114+
keyRingResponse, err := k.client.DefaultAPI.GetKeyRing(ctx, projectId, region, keyRingId).Execute()
115115
if err != nil {
116116
utils.LogError(
117117
ctx,

stackit/internal/services/kms/keyring/resource.go

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ import (
1717
"github.com/hashicorp/terraform-plugin-framework/types"
1818
"github.com/hashicorp/terraform-plugin-log/tflog"
1919
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
20-
"github.com/stackitcloud/stackit-sdk-go/services/kms"
21-
"github.com/stackitcloud/stackit-sdk-go/services/kms/wait"
20+
kms "github.com/stackitcloud/stackit-sdk-go/services/kms/v1api"
21+
"github.com/stackitcloud/stackit-sdk-go/services/kms/v1api/wait"
2222
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion"
2323
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
2424
kmsUtils "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/kms/utils"
@@ -191,28 +191,28 @@ func (r *keyRingResource) Create(ctx context.Context, req resource.CreateRequest
191191
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating keyring", fmt.Sprintf("Creating API payload: %v", err))
192192
return
193193
}
194-
createResponse, err := r.client.CreateKeyRing(ctx, projectId, region).CreateKeyRingPayload(*payload).Execute()
194+
createResponse, err := r.client.DefaultAPI.CreateKeyRing(ctx, projectId, region).CreateKeyRingPayload(*payload).Execute()
195195
if err != nil {
196196
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating keyring", fmt.Sprintf("Calling API: %v", err))
197197
return
198198
}
199199

200200
ctx = core.LogResponse(ctx)
201201

202-
if createResponse == nil || createResponse.Id == nil {
202+
if createResponse == nil {
203203
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating keyring", "API returned empty response")
204204
return
205205
}
206206

207-
keyRingId := *createResponse.Id
207+
keyRingId := createResponse.Id
208208
// Write id attributes to state before polling via the wait handler - just in case anything goes wrong during the wait handler
209209
ctx = utils.SetAndLogStateFields(ctx, &resp.Diagnostics, &resp.State, map[string]any{
210210
"project_id": projectId,
211211
"region": region,
212212
"keyring_id": keyRingId,
213213
})
214214

215-
waitResp, err := wait.CreateKeyRingWaitHandler(ctx, r.client, projectId, region, keyRingId).SetSleepBeforeWait(5 * time.Second).WaitWithContext(ctx)
215+
waitResp, err := wait.CreateKeyRingWaitHandler(ctx, r.client.DefaultAPI, projectId, region, keyRingId).SetSleepBeforeWait(5 * time.Second).WaitWithContext(ctx)
216216
if err != nil {
217217
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating keyring", fmt.Sprintf("Key Ring creation waiting: %v", err))
218218
return
@@ -250,7 +250,7 @@ func (r *keyRingResource) Read(ctx context.Context, req resource.ReadRequest, re
250250
ctx = tflog.SetField(ctx, "project_id", projectId)
251251
ctx = tflog.SetField(ctx, "region", region)
252252

253-
keyRingResponse, err := r.client.GetKeyRing(ctx, projectId, region, keyRingId).Execute()
253+
keyRingResponse, err := r.client.DefaultAPI.GetKeyRing(ctx, projectId, region, keyRingId).Execute()
254254
if err != nil {
255255
var oapiErr *oapierror.GenericOpenAPIError
256256
ok := errors.As(err, &oapiErr)
@@ -328,23 +328,15 @@ func mapFields(keyRing *kms.KeyRing, model *Model, region string) error {
328328
var keyRingId string
329329
if model.KeyRingId.ValueString() != "" {
330330
keyRingId = model.KeyRingId.ValueString()
331-
} else if keyRing.Id != nil {
332-
keyRingId = *keyRing.Id
333331
} else {
334-
return fmt.Errorf("keyring id not present")
332+
keyRingId = keyRing.Id
335333
}
336334

337335
model.Id = utils.BuildInternalTerraformId(model.ProjectId.ValueString(), region, keyRingId)
338336
model.KeyRingId = types.StringValue(keyRingId)
339-
model.DisplayName = types.StringPointerValue(keyRing.DisplayName)
337+
model.DisplayName = types.StringValue(keyRing.DisplayName)
340338
model.Region = types.StringValue(region)
341-
342-
// TODO: workaround - remove once STACKITKMS-377 is resolved (just write the return value from the API to the state then)
343-
if !(model.Description.IsNull() && keyRing.Description != nil && *keyRing.Description == "") {
344-
model.Description = types.StringPointerValue(keyRing.Description)
345-
} else {
346-
model.Description = types.StringNull()
347-
}
339+
model.Description = types.StringPointerValue(keyRing.Description)
348340

349341
return nil
350342
}
@@ -356,6 +348,6 @@ func toCreatePayload(model *Model) (*kms.CreateKeyRingPayload, error) {
356348

357349
return &kms.CreateKeyRingPayload{
358350
Description: conversion.StringValueToPointer(model.Description),
359-
DisplayName: conversion.StringValueToPointer(model.DisplayName),
351+
DisplayName: model.DisplayName.ValueString(),
360352
}, nil
361353
}

0 commit comments

Comments
 (0)