Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 50f834b

Browse files
committedAug 23, 2024
feat(okms): add resource for kms service keys
1 parent d8b9771 commit 50f834b

File tree

3 files changed

+460
-0
lines changed

3 files changed

+460
-0
lines changed
 

‎ovh/provider_new.go

+9
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,12 @@ func (p *OvhProvider) DataSources(_ context.Context) []func() datasource.DataSou
202202
NewIpFirewallDataSource,
203203
NewIpFirewallRuleDataSource,
204204
NewIpMitigationDataSource,
205+
NewOkmsCredentialDataSource,
206+
NewOkmsCredentialsDataSource,
207+
NewOkmsResourceDataSource,
208+
NewOkmsServiceKeysDataSource,
209+
NewOkmsServiceKeyDataSource,
210+
NewOkmsServiceKeyJwkDataSource,
205211
}
206212
}
207213

@@ -216,6 +222,9 @@ func (p *OvhProvider) Resources(_ context.Context) []func() resource.Resource {
216222
NewIpFirewallRuleResource,
217223
NewIploadbalancingUdpFrontendResource,
218224
NewIpMitigationResource,
225+
NewOkmsResource,
226+
NewOkmsCredentialResource,
227+
NewOkmsServiceKeyResource,
219228
NewVpsResource,
220229
}
221230
}

‎ovh/resource_okms_service_key.go

+165
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
package ovh
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net/url"
7+
8+
"github.com/hashicorp/terraform-plugin-framework/resource"
9+
ovhtypes "github.com/ovh/terraform-provider-ovh/ovh/types"
10+
)
11+
12+
var _ resource.ResourceWithConfigure = (*okmsServiceKeyResource)(nil)
13+
14+
func NewOkmsServiceKeyResource() resource.Resource {
15+
return &okmsServiceKeyResource{}
16+
}
17+
18+
type okmsServiceKeyResource struct {
19+
config *Config
20+
}
21+
22+
func (r *okmsServiceKeyResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
23+
resp.TypeName = req.ProviderTypeName + "_okms_service_key"
24+
}
25+
26+
func (d *okmsServiceKeyResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
27+
if req.ProviderData == nil {
28+
return
29+
}
30+
31+
config, ok := req.ProviderData.(*Config)
32+
if !ok {
33+
resp.Diagnostics.AddError(
34+
"Unexpected Resource Configure Type",
35+
fmt.Sprintf("Expected *Config, got: %T. Please report this issue to the provider developers.", req.ProviderData),
36+
)
37+
return
38+
}
39+
40+
d.config = config
41+
}
42+
43+
func (d *okmsServiceKeyResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
44+
resp.Schema = OkmsServiceKeyResourceSchema(ctx)
45+
}
46+
47+
func (r *okmsServiceKeyResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
48+
var data, responseData OkmsServiceKeyResourceModel
49+
50+
// Read Terraform plan data into the model
51+
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
52+
if resp.Diagnostics.HasError() {
53+
return
54+
}
55+
56+
endpoint := "/v2/okms/resource/" + url.PathEscape(data.OkmsId.ValueString()) + "/serviceKey"
57+
if err := r.config.OVHClient.Post(endpoint, data.ToCreate(), &responseData); err != nil {
58+
resp.Diagnostics.AddError(
59+
fmt.Sprintf("Error calling Post %s", endpoint),
60+
err.Error(),
61+
)
62+
return
63+
}
64+
65+
responseData.MergeWith(&data)
66+
67+
// Save data into Terraform state
68+
resp.Diagnostics.Append(resp.State.Set(ctx, &responseData)...)
69+
}
70+
71+
func (r *okmsServiceKeyResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
72+
var data, responseData OkmsServiceKeyResourceModel
73+
74+
// Read Terraform prior state data into the model
75+
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
76+
if resp.Diagnostics.HasError() {
77+
return
78+
}
79+
80+
endpoint := "/v2/okms/resource/" + url.PathEscape(data.OkmsId.ValueString()) + "/serviceKey/" + url.PathEscape(data.Id.ValueString())
81+
82+
if err := r.config.OVHClient.Get(endpoint, &responseData); err != nil {
83+
resp.Diagnostics.AddError(
84+
fmt.Sprintf("Error calling Get %s", endpoint),
85+
err.Error(),
86+
)
87+
return
88+
}
89+
90+
data.MergeWith(&responseData)
91+
92+
// Save updated data into Terraform state
93+
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
94+
}
95+
96+
func (r *okmsServiceKeyResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
97+
var data, planData, responseData OkmsServiceKeyResourceModel
98+
99+
// Read Terraform plan data into the model
100+
resp.Diagnostics.Append(req.Plan.Get(ctx, &planData)...)
101+
if resp.Diagnostics.HasError() {
102+
return
103+
}
104+
105+
// Read Terraform prior state data into the model
106+
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
107+
if resp.Diagnostics.HasError() {
108+
return
109+
}
110+
111+
// Update resource
112+
endpoint := "/v2/okms/resource/" + url.PathEscape(data.OkmsId.ValueString()) + "/serviceKey/" + url.PathEscape(data.Id.ValueString())
113+
if err := r.config.OVHClient.Put(endpoint, planData.ToUpdate(), nil); err != nil {
114+
resp.Diagnostics.AddError(
115+
fmt.Sprintf("Error calling Put %s", endpoint),
116+
err.Error(),
117+
)
118+
return
119+
}
120+
121+
// Read updated resource
122+
if err := r.config.OVHClient.Get(endpoint, &responseData); err != nil {
123+
resp.Diagnostics.AddError(
124+
fmt.Sprintf("Error calling Get %s", endpoint),
125+
err.Error(),
126+
)
127+
return
128+
}
129+
130+
responseData.MergeWith(&planData)
131+
132+
// Save updated data into Terraform state
133+
resp.Diagnostics.Append(resp.State.Set(ctx, &responseData)...)
134+
}
135+
136+
func (r *okmsServiceKeyResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
137+
var data OkmsServiceKeyResourceModel
138+
139+
// Read Terraform prior state data into the model
140+
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
141+
142+
if resp.Diagnostics.HasError() {
143+
return
144+
}
145+
146+
data.State = ovhtypes.NewTfStringValue("DEACTIVATED")
147+
data.DeactivationReason = ovhtypes.NewTfStringValue("UNSPECIFIED")
148+
// Deactivate key first
149+
endpoint := "/v2/okms/resource/" + url.PathEscape(data.OkmsId.ValueString()) + "/serviceKey/" + url.PathEscape(data.Id.ValueString())
150+
if err := r.config.OVHClient.Put(endpoint, data.ToUpdate(), nil); err != nil {
151+
resp.Diagnostics.AddError(
152+
fmt.Sprintf("Error deactivating key %s", endpoint),
153+
err.Error(),
154+
)
155+
return
156+
}
157+
158+
// Delete API call logic
159+
if err := r.config.OVHClient.Delete(endpoint, nil); err != nil {
160+
resp.Diagnostics.AddError(
161+
fmt.Sprintf("Error calling Delete %s", endpoint),
162+
err.Error(),
163+
)
164+
}
165+
}

‎ovh/resource_okms_service_key_gen.go

+286
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
package ovh
2+
3+
import (
4+
"context"
5+
6+
"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
7+
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
8+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
9+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier"
10+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
11+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
12+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
13+
ovhtypes "github.com/ovh/terraform-provider-ovh/ovh/types"
14+
15+
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
16+
)
17+
18+
func OkmsServiceKeyResourceSchema(ctx context.Context) schema.Schema {
19+
attrs := map[string]schema.Attribute{
20+
"context": schema.StringAttribute{
21+
CustomType: ovhtypes.TfStringType{},
22+
Optional: true,
23+
Computed: true,
24+
Description: "Context of the key",
25+
MarkdownDescription: "Context of the key",
26+
PlanModifiers: []planmodifier.String{
27+
stringplanmodifier.RequiresReplaceIfConfigured(),
28+
stringplanmodifier.UseStateForUnknown(),
29+
},
30+
},
31+
"created_at": schema.StringAttribute{
32+
CustomType: ovhtypes.TfStringType{},
33+
Computed: true,
34+
Description: "Creation time of the key",
35+
MarkdownDescription: "Creation time of the key",
36+
PlanModifiers: []planmodifier.String{
37+
stringplanmodifier.UseStateForUnknown(),
38+
},
39+
},
40+
"curve": schema.StringAttribute{
41+
CustomType: ovhtypes.TfStringType{},
42+
Optional: true,
43+
Computed: true,
44+
Description: "Curve type for Elliptic Curve (EC) keys",
45+
MarkdownDescription: "Curve type for Elliptic Curve (EC) keys",
46+
PlanModifiers: []planmodifier.String{
47+
stringplanmodifier.RequiresReplaceIfConfigured(),
48+
stringplanmodifier.UseStateForUnknown(),
49+
},
50+
Validators: []validator.String{
51+
stringvalidator.OneOf(
52+
"P-256",
53+
"P-384",
54+
"P-521",
55+
),
56+
},
57+
},
58+
"deactivation_reason": schema.StringAttribute{
59+
CustomType: ovhtypes.TfStringType{},
60+
Computed: true,
61+
Description: "Key deactivation reason",
62+
MarkdownDescription: "Key deactivation reason",
63+
Validators: []validator.String{
64+
stringvalidator.OneOf(
65+
"AFFILIATION_CHANGED",
66+
"CA_COMPROMISE",
67+
"CESSATION_OF_OPERATION",
68+
"KEY_COMPROMISE",
69+
"PRIVILEGE_WITHDRAWN",
70+
"SUPERSEDED",
71+
"UNSPECIFIED",
72+
),
73+
},
74+
},
75+
"id": schema.StringAttribute{
76+
CustomType: ovhtypes.TfStringType{},
77+
Computed: true,
78+
Description: "Key ID",
79+
MarkdownDescription: "Key ID",
80+
PlanModifiers: []planmodifier.String{
81+
stringplanmodifier.UseStateForUnknown(),
82+
},
83+
},
84+
"name": schema.StringAttribute{
85+
CustomType: ovhtypes.TfStringType{},
86+
Required: true,
87+
Description: "Key name",
88+
MarkdownDescription: "Key name",
89+
},
90+
"okms_id": schema.StringAttribute{
91+
CustomType: ovhtypes.TfStringType{},
92+
Required: true,
93+
Description: "Okms ID",
94+
MarkdownDescription: "Okms ID",
95+
PlanModifiers: []planmodifier.String{
96+
stringplanmodifier.RequiresReplace(),
97+
stringplanmodifier.UseStateForUnknown(),
98+
},
99+
},
100+
"operations": schema.ListAttribute{
101+
CustomType: ovhtypes.NewTfListNestedType[ovhtypes.TfStringValue](ctx),
102+
Required: true,
103+
Description: "The operations for which the key is intended to be used",
104+
MarkdownDescription: "The operations for which the key is intended to be used",
105+
PlanModifiers: []planmodifier.List{
106+
listplanmodifier.RequiresReplace(),
107+
listplanmodifier.UseStateForUnknown(),
108+
},
109+
},
110+
"size": schema.Int64Attribute{
111+
CustomType: ovhtypes.TfInt64Type{},
112+
Optional: true,
113+
Computed: true,
114+
Description: "Size of the key to be created",
115+
MarkdownDescription: "Size of the key to be created",
116+
PlanModifiers: []planmodifier.Int64{
117+
int64planmodifier.RequiresReplaceIfConfigured(),
118+
int64planmodifier.UseStateForUnknown(),
119+
},
120+
Validators: []validator.Int64{
121+
int64validator.OneOf(
122+
128,
123+
192,
124+
256,
125+
2048,
126+
3072,
127+
4096,
128+
),
129+
},
130+
},
131+
"state": schema.StringAttribute{
132+
CustomType: ovhtypes.TfStringType{},
133+
Computed: true,
134+
Description: "State of the key",
135+
MarkdownDescription: "State of the key",
136+
Validators: []validator.String{
137+
stringvalidator.OneOf(
138+
"ACTIVE",
139+
"COMPROMISED",
140+
"DEACTIVATED",
141+
),
142+
},
143+
},
144+
"type": schema.StringAttribute{
145+
CustomType: ovhtypes.TfStringType{},
146+
Required: true,
147+
Description: "Type of the key to be created",
148+
MarkdownDescription: "Type of the key to be created",
149+
PlanModifiers: []planmodifier.String{
150+
stringplanmodifier.RequiresReplace(),
151+
stringplanmodifier.UseStateForUnknown(),
152+
},
153+
Validators: []validator.String{
154+
stringvalidator.OneOf(
155+
"EC",
156+
"RSA",
157+
"oct",
158+
),
159+
},
160+
},
161+
}
162+
163+
return schema.Schema{
164+
Attributes: attrs,
165+
}
166+
}
167+
168+
type OkmsServiceKeyResourceModel struct {
169+
Context ovhtypes.TfStringValue `tfsdk:"context" json:"context"`
170+
CreatedAt ovhtypes.TfStringValue `tfsdk:"created_at" json:"createdAt"`
171+
Curve ovhtypes.TfStringValue `tfsdk:"curve" json:"curve"`
172+
DeactivationReason ovhtypes.TfStringValue `tfsdk:"deactivation_reason" json:"deactivationReason"`
173+
Id ovhtypes.TfStringValue `tfsdk:"id" json:"id"`
174+
Name ovhtypes.TfStringValue `tfsdk:"name" json:"name"`
175+
OkmsId ovhtypes.TfStringValue `tfsdk:"okms_id" json:"okmsId"`
176+
Operations ovhtypes.TfListNestedValue[ovhtypes.TfStringValue] `tfsdk:"operations" json:"operations"`
177+
Size ovhtypes.TfInt64Value `tfsdk:"size" json:"size"`
178+
State ovhtypes.TfStringValue `tfsdk:"state" json:"state"`
179+
Type ovhtypes.TfStringValue `tfsdk:"type" json:"type"`
180+
}
181+
182+
func (v *OkmsServiceKeyResourceModel) MergeWith(other *OkmsServiceKeyResourceModel) {
183+
184+
if (v.Context.IsUnknown() || v.Context.IsNull()) && !other.Context.IsUnknown() {
185+
v.Context = other.Context
186+
}
187+
188+
if (v.CreatedAt.IsUnknown() || v.CreatedAt.IsNull()) && !other.CreatedAt.IsUnknown() {
189+
v.CreatedAt = other.CreatedAt
190+
}
191+
192+
if (v.Curve.IsUnknown() || v.Curve.IsNull()) && !other.Curve.IsUnknown() {
193+
v.Curve = other.Curve
194+
}
195+
196+
if (v.DeactivationReason.IsUnknown() || v.DeactivationReason.IsNull()) && !other.DeactivationReason.IsUnknown() {
197+
v.DeactivationReason = other.DeactivationReason
198+
}
199+
200+
if (v.Id.IsUnknown() || v.Id.IsNull()) && !other.Id.IsUnknown() {
201+
v.Id = other.Id
202+
}
203+
204+
if (v.Name.IsUnknown() || v.Name.IsNull()) && !other.Name.IsUnknown() {
205+
v.Name = other.Name
206+
}
207+
208+
if (v.OkmsId.IsUnknown() || v.OkmsId.IsNull()) && !other.OkmsId.IsUnknown() {
209+
v.OkmsId = other.OkmsId
210+
}
211+
212+
if (v.Operations.IsUnknown() || v.Operations.IsNull()) && !other.Operations.IsUnknown() {
213+
v.Operations = other.Operations
214+
}
215+
216+
if (v.Size.IsUnknown() || v.Size.IsNull()) && !other.Size.IsUnknown() {
217+
v.Size = other.Size
218+
}
219+
220+
if (v.State.IsUnknown() || v.State.IsNull()) && !other.State.IsUnknown() {
221+
v.State = other.State
222+
}
223+
224+
if (v.Type.IsUnknown() || v.Type.IsNull()) && !other.Type.IsUnknown() {
225+
v.Type = other.Type
226+
}
227+
}
228+
229+
type OkmsServiceKeyWritableModel struct {
230+
Context *ovhtypes.TfStringValue `tfsdk:"context" json:"context,omitempty"`
231+
Curve *ovhtypes.TfStringValue `tfsdk:"curve" json:"curve,omitempty"`
232+
DeactivationReason *ovhtypes.TfStringValue `tfsdk:"deactivation_reason" json:"deactivationReason,omitempty"`
233+
Name *ovhtypes.TfStringValue `tfsdk:"name" json:"name,omitempty"`
234+
Operations *ovhtypes.TfListNestedValue[ovhtypes.TfStringValue] `tfsdk:"operations" json:"operations,omitempty"`
235+
Size *ovhtypes.TfInt64Value `tfsdk:"size" json:"size,omitempty"`
236+
State *ovhtypes.TfStringValue `tfsdk:"state" json:"state,omitempty"`
237+
Type *ovhtypes.TfStringValue `tfsdk:"type" json:"type,omitempty"`
238+
}
239+
240+
func (v OkmsServiceKeyResourceModel) ToCreate() *OkmsServiceKeyWritableModel {
241+
res := &OkmsServiceKeyWritableModel{}
242+
243+
if !v.Context.IsUnknown() {
244+
res.Context = &v.Context
245+
}
246+
247+
if !v.Curve.IsUnknown() {
248+
res.Curve = &v.Curve
249+
}
250+
251+
if !v.Name.IsUnknown() {
252+
res.Name = &v.Name
253+
}
254+
255+
if !v.Operations.IsUnknown() {
256+
res.Operations = &v.Operations
257+
}
258+
259+
if !v.Size.IsUnknown() {
260+
res.Size = &v.Size
261+
}
262+
263+
if !v.Type.IsUnknown() {
264+
res.Type = &v.Type
265+
}
266+
267+
return res
268+
}
269+
270+
func (v OkmsServiceKeyResourceModel) ToUpdate() *OkmsServiceKeyWritableModel {
271+
res := &OkmsServiceKeyWritableModel{}
272+
273+
if !v.DeactivationReason.IsUnknown() {
274+
res.DeactivationReason = &v.DeactivationReason
275+
}
276+
277+
if !v.Name.IsUnknown() {
278+
res.Name = &v.Name
279+
}
280+
281+
if !v.State.IsUnknown() {
282+
res.State = &v.State
283+
}
284+
285+
return res
286+
}

0 commit comments

Comments
 (0)
Please sign in to comment.