Skip to content

Commit d8b9771

Browse files
committed
feat(okms): add resource for kms credentials
1 parent a7ceda9 commit d8b9771

File tree

2 files changed

+486
-0
lines changed

2 files changed

+486
-0
lines changed

ovh/resource_okms_credential.go

+203
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
package ovh
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
"net/url"
8+
"strings"
9+
"time"
10+
11+
"github.com/hashicorp/terraform-plugin-framework/path"
12+
"github.com/hashicorp/terraform-plugin-framework/resource"
13+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
14+
)
15+
16+
var _ resource.ResourceWithConfigure = (*okmsCredentialResource)(nil)
17+
var _ resource.ResourceWithImportState = (*okmsCredentialResource)(nil)
18+
19+
func NewOkmsCredentialResource() resource.Resource {
20+
return &okmsCredentialResource{}
21+
}
22+
23+
type okmsCredentialResource struct {
24+
config *Config
25+
}
26+
27+
func (r *okmsCredentialResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
28+
resp.TypeName = req.ProviderTypeName + "_okms_credential"
29+
}
30+
31+
func (d *okmsCredentialResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
32+
if req.ProviderData == nil {
33+
return
34+
}
35+
36+
config, ok := req.ProviderData.(*Config)
37+
if !ok {
38+
resp.Diagnostics.AddError(
39+
"Unexpected Resource Configure Type",
40+
fmt.Sprintf("Expected *Config, got: %T. Please report this issue to the provider developers.", req.ProviderData),
41+
)
42+
return
43+
}
44+
45+
d.config = config
46+
}
47+
48+
func (d *okmsCredentialResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
49+
resp.Schema = OkmsCredentialResourceSchema(ctx)
50+
}
51+
52+
func (r *okmsCredentialResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
53+
54+
ids := strings.Split(req.ID, "/")
55+
if len(ids) != 2 {
56+
resp.Diagnostics.AddError("Error importing okms_credential resource.", "ID should be of the format '{okmsId}/{credentialId}'")
57+
return
58+
}
59+
60+
// Set ID attributes in the state
61+
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("okms_id"), ids[0])...)
62+
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), ids[1])...)
63+
64+
var data OkmsCredentialResourceModel
65+
resp.Diagnostics.Append(resp.State.Get(ctx, &data)...)
66+
if resp.Diagnostics.HasError() {
67+
return
68+
}
69+
70+
endpoint := "/v2/okms/resource/" + ids[0] + "/credential/" + ids[1]
71+
if err := r.config.OVHClient.Get(endpoint, &data); err != nil {
72+
resp.Diagnostics.AddError(
73+
fmt.Sprintf("Error importing credential in GET %s", endpoint),
74+
err.Error(),
75+
)
76+
return
77+
}
78+
79+
// Save data into Terraform state
80+
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
81+
}
82+
83+
func (r *okmsCredentialResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
84+
var data, responseData OkmsCredentialResourceModel
85+
86+
// Read Terraform plan data into the model
87+
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
88+
if resp.Diagnostics.HasError() {
89+
return
90+
}
91+
92+
okmsId := url.PathEscape(data.OkmsId.ValueString())
93+
endpoint := "/v2/okms/resource/" + okmsId + "/credential"
94+
if err := r.config.OVHClient.Post(endpoint, data.ToCreate(), &responseData); err != nil {
95+
resp.Diagnostics.AddError(
96+
fmt.Sprintf("Error calling Post %s", endpoint),
97+
err.Error(),
98+
)
99+
return
100+
}
101+
102+
responseData.MergeWith(&data)
103+
104+
var updateData OkmsCredentialResourceModel
105+
// Read updated credential to get the certificate
106+
err := retry.RetryContext(ctx, 2*time.Minute, func() *retry.RetryError {
107+
// Read updated resource
108+
credId := url.PathEscape(responseData.Id.ValueString())
109+
endpoint := "/v2/okms/resource/" + okmsId + "/credential/" + credId
110+
111+
if err := r.config.OVHClient.Get(endpoint, &updateData); err != nil {
112+
return retry.NonRetryableError(fmt.Errorf("error reading credential %s", credId))
113+
}
114+
115+
status := updateData.Status.ValueString()
116+
if status == "READY" {
117+
// KMS was created successfully, return
118+
return nil
119+
} else if status != "CREATING" {
120+
return retry.NonRetryableError(
121+
fmt.Errorf("Unexpected credential status : %s",
122+
status,
123+
))
124+
}
125+
126+
return retry.RetryableError(errors.New("Waiting for KMS credential readiness"))
127+
})
128+
129+
if err != nil {
130+
resp.Diagnostics.AddError("Failed to create KMS, creation timeout", err.Error())
131+
}
132+
133+
responseData.MergeWith(&updateData)
134+
responseData.Status = updateData.Status
135+
136+
// Save data into Terraform state
137+
resp.Diagnostics.Append(resp.State.Set(ctx, &responseData)...)
138+
}
139+
140+
func (r *okmsCredentialResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
141+
var data, responseData OkmsCredentialResourceModel
142+
143+
// Read Terraform prior state data into the model
144+
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
145+
if resp.Diagnostics.HasError() {
146+
return
147+
}
148+
149+
endpoint := "/v2/okms/resource/" + url.PathEscape(data.OkmsId.ValueString()) + "/credential/" + url.PathEscape(data.Id.ValueString()) + ""
150+
151+
if err := r.config.OVHClient.Get(endpoint, &responseData); err != nil {
152+
resp.Diagnostics.AddError(
153+
fmt.Sprintf("Error reading credential with GET %s", endpoint),
154+
err.Error(),
155+
)
156+
return
157+
}
158+
159+
data.MergeWith(&responseData)
160+
161+
// Save updated data into Terraform state
162+
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
163+
}
164+
165+
func (r *okmsCredentialResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
166+
var data, planData OkmsCredentialResourceModel
167+
168+
// Read Terraform plan data into the model
169+
resp.Diagnostics.Append(req.Plan.Get(ctx, &planData)...)
170+
if resp.Diagnostics.HasError() {
171+
return
172+
}
173+
174+
// Read Terraform prior state data into the model
175+
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
176+
if resp.Diagnostics.HasError() {
177+
return
178+
}
179+
180+
// We should only get an update request if the CSR can be replaced without recreation
181+
data.Csr = planData.Csr
182+
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
183+
}
184+
185+
func (r *okmsCredentialResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
186+
var data OkmsCredentialResourceModel
187+
188+
// Read Terraform prior state data into the model
189+
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
190+
191+
if resp.Diagnostics.HasError() {
192+
return
193+
}
194+
195+
// Delete API call logic
196+
endpoint := "/v2/okms/resource/" + url.PathEscape(data.OkmsId.ValueString()) + "/credential/" + url.PathEscape(data.Id.ValueString()) + ""
197+
if err := r.config.OVHClient.Delete(endpoint, nil); err != nil {
198+
resp.Diagnostics.AddError(
199+
fmt.Sprintf("Error calling Delete %s", endpoint),
200+
err.Error(),
201+
)
202+
}
203+
}

0 commit comments

Comments
 (0)