Skip to content

Commit 3bbac10

Browse files
committedSep 11, 2024
create resource_iploadbalancing_ssl
1 parent c22ccde commit 3bbac10

5 files changed

+591
-0
lines changed
 

‎ovh/provider_new.go

+1
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ func (p *OvhProvider) Resources(_ context.Context) []func() resource.Resource {
215215
NewDomainZoneImportResource,
216216
NewIpFirewallResource,
217217
NewIpFirewallRuleResource,
218+
NewIploadbalancingSslResource,
218219
NewIploadbalancingUdpFrontendResource,
219220
NewIpMitigationResource,
220221
NewVpsResource,

‎ovh/resource_iploadbalancing_ssl.go

+178
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
package ovh
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net/url"
7+
"strconv"
8+
"strings"
9+
10+
"github.com/hashicorp/terraform-plugin-framework/path"
11+
"github.com/hashicorp/terraform-plugin-framework/resource"
12+
)
13+
14+
var (
15+
_ resource.ResourceWithConfigure = (*iploadbalancingSslResource)(nil)
16+
_ resource.ResourceWithImportState = (*iploadbalancingSslResource)(nil)
17+
)
18+
19+
func NewIploadbalancingSslResource() resource.Resource {
20+
return &iploadbalancingSslResource{}
21+
}
22+
23+
type iploadbalancingSslResource struct {
24+
config *Config
25+
}
26+
27+
func (r *iploadbalancingSslResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
28+
resp.TypeName = req.ProviderTypeName + "_iploadbalancing_ssl"
29+
}
30+
31+
func (d *iploadbalancingSslResource) 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 *iploadbalancingSslResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
49+
resp.Schema = IploadbalancingSslResourceSchema(ctx)
50+
}
51+
52+
func (r *iploadbalancingSslResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
53+
var data, responseData IploadbalancingSslModel
54+
55+
// Read Terraform plan data into the model
56+
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
57+
if resp.Diagnostics.HasError() {
58+
return
59+
}
60+
61+
endpoint := "/ipLoadbalancing/" + url.PathEscape(data.ServiceName.ValueString()) + "/ssl"
62+
if err := r.config.OVHClient.Post(endpoint, data.ToCreate(), &responseData); err != nil {
63+
resp.Diagnostics.AddError(
64+
fmt.Sprintf("Error calling Post %s", endpoint),
65+
err.Error(),
66+
)
67+
return
68+
}
69+
70+
responseData.MergeWith(&data)
71+
72+
// Save data into Terraform state
73+
resp.Diagnostics.Append(resp.State.Set(ctx, &responseData)...)
74+
}
75+
76+
func (r *iploadbalancingSslResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
77+
var data, responseData IploadbalancingSslModel
78+
79+
// Read Terraform prior state data into the model
80+
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
81+
if resp.Diagnostics.HasError() {
82+
return
83+
}
84+
85+
endpoint := "/ipLoadbalancing/" + url.PathEscape(data.ServiceName.ValueString()) + "/ssl/" + strconv.FormatInt(data.Id.ValueInt64(), 10)
86+
87+
if err := r.config.OVHClient.Get(endpoint, &responseData); err != nil {
88+
resp.Diagnostics.AddError(
89+
fmt.Sprintf("Error calling Get %s", endpoint),
90+
err.Error(),
91+
)
92+
return
93+
}
94+
95+
data.MergeWith(&responseData)
96+
97+
// Save updated data into Terraform state
98+
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
99+
}
100+
101+
func (r *iploadbalancingSslResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
102+
var data, planData, responseData IploadbalancingSslModel
103+
104+
// Read Terraform plan data into the model
105+
resp.Diagnostics.Append(req.Plan.Get(ctx, &planData)...)
106+
if resp.Diagnostics.HasError() {
107+
return
108+
}
109+
110+
// Read Terraform prior state data into the model
111+
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
112+
if resp.Diagnostics.HasError() {
113+
return
114+
}
115+
116+
// Update resource
117+
endpoint := "/ipLoadbalancing/" + url.PathEscape(data.ServiceName.ValueString()) + "/ssl/" + strconv.FormatInt(data.Id.ValueInt64(), 10)
118+
if err := r.config.OVHClient.Put(endpoint, planData.ToUpdate(), nil); err != nil {
119+
resp.Diagnostics.AddError(
120+
fmt.Sprintf("Error calling Put %s", endpoint),
121+
err.Error(),
122+
)
123+
return
124+
}
125+
126+
// Read updated resource
127+
endpoint = "/ipLoadbalancing/" + url.PathEscape(data.ServiceName.ValueString()) + "/ssl/" + strconv.FormatInt(data.Id.ValueInt64(), 10)
128+
if err := r.config.OVHClient.Get(endpoint, &responseData); err != nil {
129+
resp.Diagnostics.AddError(
130+
fmt.Sprintf("Error calling Get %s", endpoint),
131+
err.Error(),
132+
)
133+
return
134+
}
135+
136+
responseData.MergeWith(&planData)
137+
138+
// Save updated data into Terraform state
139+
resp.Diagnostics.Append(resp.State.Set(ctx, &responseData)...)
140+
}
141+
142+
func (r *iploadbalancingSslResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
143+
var data IploadbalancingSslModel
144+
145+
// Read Terraform prior state data into the model
146+
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
147+
148+
if resp.Diagnostics.HasError() {
149+
return
150+
}
151+
152+
// Delete API call logic
153+
endpoint := "/ipLoadbalancing/" + url.PathEscape(data.ServiceName.ValueString()) + "/ssl/" + strconv.FormatInt(data.Id.ValueInt64(), 10)
154+
if err := r.config.OVHClient.Delete(endpoint, nil); err != nil {
155+
resp.Diagnostics.AddError(
156+
fmt.Sprintf("Error calling Delete %s", endpoint),
157+
err.Error(),
158+
)
159+
}
160+
}
161+
162+
func (r *iploadbalancingSslResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
163+
splits := strings.Split(req.ID, "/")
164+
if len(splits) != 2 {
165+
resp.Diagnostics.AddError("Given ID is malformed", "ID must be formatted like the following: <service_name>/<sslId>")
166+
return
167+
}
168+
169+
serviceName := splits[0]
170+
sslId, err := strconv.Atoi(splits[1])
171+
if err != nil {
172+
resp.Diagnostics.AddError("Given ID is malformed", "ID must be formatted like the following: <service_name>/<sslId> where sslId is a number")
173+
return
174+
}
175+
176+
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("service_name"), serviceName)...)
177+
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), sslId)...)
178+
}

‎ovh/resource_iploadbalancing_ssl_gen.go

+200
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
+154
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
package ovh
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"testing"
7+
8+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
9+
"github.com/hashicorp/terraform-plugin-testing/terraform"
10+
)
11+
12+
const certificate = `
13+
-----BEGIN CERTIFICATE-----
14+
MIIDnzCCAoegAwIBAgIUchdtmNBNsdO0rJFBZEr14/5zAe4wDQYJKoZIhvcNAQEL
15+
BQAwXzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
16+
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAwwPd3d3LmV4YW1wbGUu
17+
Y29tMB4XDTI0MDkwNTEzNTkxNVoXDTI1MDkwNTEzNTkxNVowXzELMAkGA1UEBhMC
18+
QVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdp
19+
dHMgUHR5IEx0ZDEYMBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tMIIBIjANBgkqhkiG
20+
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2MNhJknJe62vUehYuzcRFUC3Xh3L4t5H2ZqD
21+
xWloB6SUpzIhAmXtjmAvdwTfdB8Ne5+paOjki1/9HfV4OU3s5RAU21yGENEaZ7x/
22+
DJJnTyqwrFJY+iV+szvxRww5qt3SKVkRsDDwtk2yG7cEw4d2mlYoJAEAfL3EQeTt
23+
/m/y+39Kq1ScnjcCslm9BdQUXiq8gqx+z6GyaZakVO8Kks0Sb45mkcN0KA71m9is
24+
giLWVIrMy2Sb0pUprVZm8kd87pUBVM3bhbdv0iQTZRKirLJKLKnnq5wGFnb0yRer
25+
8L7f91sMnZmohkWGJZ+oirzbjmX/H3h3wRkn1ns0I5PTkpQcUQIDAQABo1MwUTAd
26+
BgNVHQ4EFgQUKrQqUfXiw0OaOD4d5GtNmKEe+CYwHwYDVR0jBBgwFoAUKrQqUfXi
27+
w0OaOD4d5GtNmKEe+CYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC
28+
AQEAVH1KHduXXKVeFXKLUnSpFMyjw/yw7WKiDH2myen8dA6UDUMj4W01PyoWx3Ic
29+
U1D37zNgIXFr8+ViEi5Bpfz1FAGsRCNfP42Wi52xygkm7tezMT+VQN7WLRqPs4n9
30+
ogwNAm9HrYFuEBAeQZlCL1VIJhvk02JHELyZh+kUz77JjO/RcRS/qNIsHbf3TxT0
31+
6mNVQsoYWeBgKR894kGbCjsHFEKJT2Hf5IpsRy8fD70qSx/dE3paXHFzAXDybVxu
32+
e5fge2/fk/rSbUm5CUsOwoxjNx100eRbH0BQTpdtgV1SzF3G127XTldZVkcdai6G
33+
TOP9quQjYN/Q8Q+sMud9sDFeKA==
34+
-----END CERTIFICATE-----
35+
`
36+
37+
const key = `
38+
-----BEGIN PRIVATE KEY-----
39+
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDYw2EmScl7ra9R
40+
6Fi7NxEVQLdeHcvi3kfZmoPFaWgHpJSnMiECZe2OYC93BN90Hw17n6lo6OSLX/0d
41+
9Xg5TezlEBTbXIYQ0RpnvH8MkmdPKrCsUlj6JX6zO/FHDDmq3dIpWRGwMPC2TbIb
42+
twTDh3aaVigkAQB8vcRB5O3+b/L7f0qrVJyeNwKyWb0F1BReKryCrH7PobJplqRU
43+
7wqSzRJvjmaRw3QoDvWb2KyCItZUiszLZJvSlSmtVmbyR3zulQFUzduFt2/SJBNl
44+
EqKsskosqeernAYWdvTJF6vwvt/3WwydmaiGRYYln6iKvNuOZf8feHfBGSfWezQj
45+
k9OSlBxRAgMBAAECggEAWlUl1c53NF7/ypsQ60g6CsjTAdpZ/twSRklhs7HHJDQ+
46+
rOSzo+u1UZmc/jUeKCbOuB+j+m/f2oNwmP0UkpD6ccU/Y+FNj5GMtwFzUtpqSjAo
47+
u09//BMHF4uZ87lRCPdzHz8ao3npvpdna6xcRF3eG9he1w5B1TpCIRHV6qxdrter
48+
IS99GIJvA96OUgDe1jBSjJl9IsnaE4dMNyBQkMajo7NFgwPRIJk/XBbUUe7t+iaM
49+
L/9dGKIZ+WIFsXqXc++wdTCo8ECEMT5/Yy/sFpUOvraeBLYm/+F1PQEoTQZ0c+p6
50+
ZI+owxIDCGv/wJivt2qX9+HHJWHKaKfFuFunEStoDwKBgQD6e9+hjrVd9L8kilfx
51+
Jso1aC51SrCE6tuLx5Q4CnklEyYidFBhEcxMUUgQiK2EQP2+GA/e+ma/IZbO+b2E
52+
2nYkoxKHn8afa6JbXx4HO5q6fZDgcwfI4pX64R1IBpFikUySJM0hUBWVIY+2UF0f
53+
NOLGCBiUU/i4yx5HNxufKPILxwKBgQDdiWcFawqgExaNNdpvU8lCL81hW+V3jNzC
54+
CqhFw0n20MObd5qZwSk3voCAhav30KYHjr8Smecp6rbmLpei0rd8CGa30tL9FdtR
55+
P152YlxHYoYHU2KdWD46/rgClvMMGYAc+1dJv58OiHvehQmzGOKbci0u21MxPxe/
56+
KDsAkM8nJwKBgQCUE5ztribL538EBADfH/ZUQkWMs13NBeZKKO8XfiGF6F8X6TkH
57+
WXUz/K0kkRg64gzfTuw6/j61aQ71RrBiFJ/ZIso2gR7zabbuWzmuPu9Gpip6daY5
58+
fLH7QQ+FX9Sct5bToovd0LEhm1iRB8s1Qpd5SJn3PfkAjZtVsF9U5OjKSwKBgQCm
59+
zyYeY0od3CGX9Fvkhb8+MgZAb9Spnww+o42u8exIh0syTe3AJjzl93CE1aH2OEo7
60+
2JUw6WexHUXYrm6JMIbuQtktQvaRkJqSY9e55jg7nAj1jSjs9xvsig1+DbE2hCD+
61+
MZa5NisK42P52kzCaVN/3on9BTJwG2TDEATVWTRR8wKBgBJ5Wv/pjAQK3JconXw9
62+
AaDcfFXW9/LkdRdHBNDcj8hFPuSlQiMyLNztYuzUH3DPK9HpACtKEfoOGA53QeqZ
63+
tLT0VQ+kvGVHp3ff1oFXslRw4USnjD9wTfhCSDtPZUtZQKD33575FISRV8kVToba
64+
s9niPsoEYo3+0dm/OhJymKKD
65+
-----END PRIVATE KEY-----
66+
`
67+
68+
const testAccCheckOvhIpLoadbalancingSslConfig = `
69+
resource "ovh_iploadbalancing_ssl" "testssl" {
70+
service_name = "%s"
71+
display_name = "%s"
72+
certificate = <<EOT
73+
%s
74+
EOT
75+
key = <<EOT
76+
%s
77+
EOT
78+
chain = <<EOT
79+
%s
80+
EOT
81+
}
82+
`
83+
84+
func TestAccIpLoadbalancingSsl_basic(t *testing.T) {
85+
iplb := os.Getenv("OVH_IPLB_SERVICE_TEST")
86+
87+
resource.Test(t, resource.TestCase{
88+
PreCheck: func() { testAccPreCheckIpLoadbalancing(t) },
89+
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
90+
Steps: []resource.TestStep{
91+
{
92+
Config: fmt.Sprintf(testAccCheckOvhIpLoadbalancingSslConfig, iplb, "aaa", certificate, key, certificate),
93+
Check: resource.ComposeTestCheckFunc(
94+
resource.TestCheckResourceAttr(
95+
"ovh_iploadbalancing_ssl.testssl", "display_name", "aaa"),
96+
resource.TestCheckResourceAttr(
97+
"ovh_iploadbalancing_ssl.testssl", "certificate", fmt.Sprintf("%s\n", certificate)),
98+
resource.TestCheckResourceAttr(
99+
"ovh_iploadbalancing_ssl.testssl", "key", fmt.Sprintf("%s\n", key)),
100+
resource.TestCheckResourceAttr(
101+
"ovh_iploadbalancing_ssl.testssl", "chain", fmt.Sprintf("%s\n", certificate)),
102+
),
103+
},
104+
{
105+
Config: fmt.Sprintf(testAccCheckOvhIpLoadbalancingSslConfig, iplb, "bbb", certificate, key, certificate),
106+
Check: resource.ComposeTestCheckFunc(
107+
resource.TestCheckResourceAttr(
108+
"ovh_iploadbalancing_ssl.testssl", "display_name", "bbb"),
109+
resource.TestCheckResourceAttr(
110+
"ovh_iploadbalancing_ssl.testssl", "certificate", fmt.Sprintf("%s\n", certificate)),
111+
resource.TestCheckResourceAttr(
112+
"ovh_iploadbalancing_ssl.testssl", "key", fmt.Sprintf("%s\n", key)),
113+
resource.TestCheckResourceAttr(
114+
"ovh_iploadbalancing_ssl.testssl", "chain", fmt.Sprintf("%s\n", certificate)),
115+
),
116+
},
117+
},
118+
})
119+
}
120+
121+
func TestAccIpLoadbalancingSsl_importBasic(t *testing.T) {
122+
iplb := os.Getenv("OVH_IPLB_SERVICE_TEST")
123+
124+
resource.Test(t, resource.TestCase{
125+
PreCheck: func() { testAccPreCheckIpLoadbalancing(t) },
126+
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
127+
Steps: []resource.TestStep{
128+
{
129+
Config: fmt.Sprintf(testAccCheckOvhIpLoadbalancingSslConfig, iplb, "aaa", certificate, key, certificate),
130+
},
131+
{
132+
ResourceName: "ovh_iploadbalancing_ssl.testssl",
133+
ImportState: true,
134+
ImportStateVerify: true,
135+
ImportStateVerifyIgnore: []string{"certificate", "key", "chain"},
136+
ImportStateIdFunc: testAccIpLoadbalancingSsl_import("ovh_iploadbalancing_ssl.testssl"),
137+
},
138+
},
139+
})
140+
}
141+
142+
func testAccIpLoadbalancingSsl_import(resourceName string) resource.ImportStateIdFunc {
143+
return func(s *terraform.State) (string, error) {
144+
testIpLoadbalancingSsl, ok := s.RootModule().Resources[resourceName]
145+
if !ok {
146+
return "", fmt.Errorf("ovh_iploadbalancing_ssl not found: %s", resourceName)
147+
}
148+
return fmt.Sprintf(
149+
"%s/%s",
150+
testIpLoadbalancingSsl.Primary.Attributes["service_name"],
151+
testIpLoadbalancingSsl.Primary.Attributes["id"],
152+
), nil
153+
}
154+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
---
2+
subcategory : "Load Balancer (IPLB)"
3+
---
4+
5+
# ovh_iploadbalancing_ssl
6+
7+
Creates a new custom SSL certificate on your IP Load Balancing
8+
9+
## Example Usage
10+
11+
```hcl
12+
data "ovh_iploadbalancing" "lb" {
13+
service_name = "ip-1.2.3.4"
14+
state = "ok"
15+
}
16+
17+
resource "ovh_iploadbalancing_ssl" "sslname" {
18+
service_name = "${data.ovh_iploadbalancing.lb.service_name}"
19+
display_name = "test"
20+
certificate = "..."
21+
key = "..."
22+
chain = "..."
23+
}
24+
```
25+
26+
## Argument Reference
27+
28+
The following arguments are supported:
29+
30+
* `service_name` - (Required) The internal name of your IP load balancing
31+
* `display_name` - Readable label for loadbalancer ssl
32+
* `certificate` - Certificate
33+
* `chain` - Certificate chain
34+
* `key` - Certificate key
35+
36+
## Attributes Reference
37+
38+
The following attributes are exported:
39+
40+
* `service_name` - See Argument Reference above.
41+
* `display_name` - See Argument Reference above.
42+
* `certificate` - See Argument Reference above.
43+
* `chain` - See Argument Reference above.
44+
* `expire_date` - Expire date of your SSL certificate.
45+
* `fingerprint` - Fingerprint of your SSL certificate.
46+
* `id` - Id of your SSL certificate.
47+
* `san` - Subject Alternative Name of your SSL certificate.
48+
* `serial` - Serial of your SSL certificate (Deprecated, use fingerprint instead !)
49+
* `subject` - Subject of your SSL certificate.
50+
* `type` - Type of your SSL certificate. 'built' for SSL certificates managed by the IP Load Balancing. 'custom' for user manager certificates.
51+
52+
## Import
53+
54+
SSL can be imported using the following format `service_name` and the `id` of the ssl, separated by "/" e.g.
55+
56+
```bash
57+
$ terraform import ovh_iploadbalancing_ssl.sslname service_name/ssl_id
58+
```

0 commit comments

Comments
 (0)
Please sign in to comment.