Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added certificate to load-balancer #396

Merged
merged 1 commit into from
Mar 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions scaleway/helpers_lb.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,39 @@ func expandLbHCHTTPS(raw interface{}) *lb.HealthCheckHTTPSConfig {
if raw == nil || len(raw.([]interface{})) != 1 {
return nil
}

rawMap := raw.([]interface{})[0].(map[string]interface{})
return &lb.HealthCheckHTTPSConfig{
URI: rawMap["uri"].(string),
Method: rawMap["method"].(string),
Code: expandInt32Ptr(rawMap["code"]),
}
}

func expandLbLetsEncrypt(raw interface{}) *lb.CreateCertificateRequestLetsencryptConfig {
if raw == nil || len(raw.([]interface{})) != 1 {
return nil
}

rawMap := raw.([]interface{})[0].(map[string]interface{})
QuentinBrosse marked this conversation as resolved.
Show resolved Hide resolved
alternativeNames := rawMap["subject_alternative_name"].([]interface{})
config := &lb.CreateCertificateRequestLetsencryptConfig{
CommonName: rawMap["common_name"].(string),
}
for _, alternativeName := range alternativeNames {
config.SubjectAlternativeName = append(config.SubjectAlternativeName, alternativeName.(string))
}
return config
}

func expandLbCustomCertificate(raw interface{}) *lb.CreateCertificateRequestCustomCertificate {
if raw == nil || len(raw.([]interface{})) != 1 {
return nil
}

rawMap := raw.([]interface{})[0].(map[string]interface{})
alekc marked this conversation as resolved.
Show resolved Hide resolved
config := &lb.CreateCertificateRequestCustomCertificate{
CertificateChain: rawMap["certificate_chain"].(string),
}
return config
}
1 change: 1 addition & 0 deletions scaleway/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ func Provider() terraform.ResourceProvider {
"scaleway_k8s_pool_beta": resourceScalewayK8SPoolBeta(),
"scaleway_lb_beta": resourceScalewayLbBeta(),
"scaleway_lb_backend_beta": resourceScalewayLbBackendBeta(),
"scaleway_lb_certificate_beta": resourceScalewayLbCertificateBeta(),
"scaleway_lb_frontend_beta": resourceScalewayLbFrontendBeta(),
"scaleway_registry_namespace_beta": resourceScalewayRegistryNamespaceBeta(),
"scaleway_rdb_instance_beta": resourceScalewayRdbInstanceBeta(),
Expand Down
201 changes: 201 additions & 0 deletions scaleway/resource_lb_certificate_beta.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
package scaleway

import (
"errors"

"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/scaleway/scaleway-sdk-go/api/lb/v1"
)

func resourceScalewayLbCertificateBeta() *schema.Resource {
return &schema.Resource{
Create: resourceScalewayLbCertificateBetaCreate,
Read: resourceScalewayLbCertificateBetaRead,
Update: resourceScalewayLbCertificateBetaUpdate,
Delete: resourceScalewayLbCertificateBetaDelete,
SchemaVersion: 0,
Schema: map[string]*schema.Schema{
"lb_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "The load-balancer ID",
},
"name": {
Type: schema.TypeString,
Description: "The name of the load-balancer certificate",
Optional: true,
Computed: true,
},
"letsencrypt": {
ConflictsWith: []string{"custom_certificate"},
MaxItems: 1,
Description: "The Let's Encrypt type certificate configuration",
Type: schema.TypeList,
Optional: true,
ForceNew: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"common_name": {
Type: schema.TypeString,
Required: true,
Description: "The main domain name of the certificate",
},
"subject_alternative_name": {
Type: schema.TypeList,
Elem: &schema.Schema{
Type: schema.TypeString,
},
Optional: true,
Description: "The alternative domain names of the certificate",
},
},
},
},
"custom_certificate": {
ConflictsWith: []string{"letsencrypt"},
MaxItems: 1,
Type: schema.TypeList,
Description: "The custom type certificate type configuration",
Optional: true,
ForceNew: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"certificate_chain": {
Type: schema.TypeString,
Required: true,
Description: "The full PEM-formatted certificate chain",
},
},
},
},

// Readonly attributes
"common_name": {
Type: schema.TypeString,
Computed: true,
Description: "The main domain name of the certificate",
},
"subject_alternative_name": {
Type: schema.TypeString,
Computed: true,
Description: "The alternative domain names of the certificate",
},
"fingerprint": {
Type: schema.TypeString,
Computed: true,
Description: "The identifier (SHA-1) of the certificate",
},
"not_valid_before": {
Type: schema.TypeString,
Computed: true,
Description: "The not valid before validity bound timestamp",
},
"not_valid_after": {
Type: schema.TypeString,
Computed: true,
Description: "The not valid after validity bound timestamp",
},
"status": {
Type: schema.TypeString,
Computed: true,
Description: "The status of certificate",
},
},
}
}

func resourceScalewayLbCertificateBetaCreate(d *schema.ResourceData, m interface{}) error {
alekc marked this conversation as resolved.
Show resolved Hide resolved
region, lbID, err := parseRegionalID(d.Get("lb_id").(string))
if err != nil {
return err
}

createReq := &lb.CreateCertificateRequest{
Region: region,
LbID: lbID,
Name: expandOrGenerateString(d.Get("name"), "lb-cert"),
Letsencrypt: expandLbLetsEncrypt(d.Get("letsencrypt")),
CustomCertificate: expandLbCustomCertificate(d.Get("custom_certificate")),
}
if createReq.Letsencrypt == nil && createReq.CustomCertificate == nil {
return errors.New("you need to define either letsencrypt or custom_certificate configuration")
}

lbAPI := lbAPI(m)
res, err := lbAPI.CreateCertificate(createReq)
if err != nil {
return err
}

d.SetId(newRegionalId(region, res.ID))

return resourceScalewayLbCertificateBetaRead(d, m)
}

func resourceScalewayLbCertificateBetaRead(d *schema.ResourceData, m interface{}) error {
lbAPI, region, ID, err := lbAPIWithRegionAndID(m, d.Id())
if err != nil {
return err
}

res, err := lbAPI.GetCertificate(&lb.GetCertificateRequest{
CertificateID: ID,
Region: region,
})

if err != nil {
if is404Error(err) {
d.SetId("")
return nil
}
return err
}

_ = d.Set("name", res.Name)
_ = d.Set("common_name", res.CommonName)
_ = d.Set("subject_alternative_name", res.SubjectAlternativeName)
_ = d.Set("fingerprint", res.Fingerprint)
_ = d.Set("not_valid_before", flattenTime(&res.NotValidBefore))
_ = d.Set("not_valid_after", flattenTime(&res.NotValidAfter))
_ = d.Set("status", res.Status)
return nil
}

func resourceScalewayLbCertificateBetaUpdate(d *schema.ResourceData, m interface{}) error {
alekc marked this conversation as resolved.
Show resolved Hide resolved
lbAPI, region, ID, err := lbAPIWithRegionAndID(m, d.Id())
if err != nil {
return err
}

req := &lb.UpdateCertificateRequest{
CertificateID: ID,
Region: region,
Name: d.Get("name").(string),
}

_, err = lbAPI.UpdateCertificate(req)
if err != nil {
return err
}

return resourceScalewayLbCertificateBetaRead(d, m)
}

func resourceScalewayLbCertificateBetaDelete(d *schema.ResourceData, m interface{}) error {
alekc marked this conversation as resolved.
Show resolved Hide resolved
lbAPI, region, ID, err := lbAPIWithRegionAndID(m, d.Id())
if err != nil {
return err
}

err = lbAPI.DeleteCertificate(&lb.DeleteCertificateRequest{
Region: region,
CertificateID: ID,
})

if err != nil && !is404Error(err) {
return err
}

return nil
}
141 changes: 141 additions & 0 deletions scaleway/resource_lb_certificate_beta_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package scaleway

import (
"testing"

"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
)

func TestAccScalewayLbCertificateBeta(t *testing.T) {
/**
* Note regarding the usage of xip.io
* See the discussion on https://github.com/terraform-providers/terraform-provider-scaleway/pull/396
* Long story short, scaleway API will not permit you to request a certificate in case common name is not pointed
* to the load balancer IP (which is unknown before creating it). In production, this can be overcome by introducing
* an additional step which creates a DNS record and depending on it, but for test purposes, xip.io is an ideal solution.
*/
resource.ParallelTest(t, resource.TestCase{
alekc marked this conversation as resolved.
Show resolved Hide resolved
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckScalewayLbBetaDestroy,
Steps: []resource.TestStep{
{
Config: `
resource scaleway_lb_beta lb01 {
name = "test-lb"
type = "lb-s"
}
resource scaleway_lb_certificate_beta cert01 {
lb_id = scaleway_lb_beta.lb01.id
name = "test-cert"
letsencrypt {
common_name = "${scaleway_lb_beta.lb01.ip_address}.xip.io"
}
}
`,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("scaleway_lb_certificate_beta.cert01", "name", "test-cert"),
resource.TestCheckResourceAttr("scaleway_lb_certificate_beta.cert01", "letsencrypt.#", "1"),
),
},
{
Config: `
resource scaleway_lb_beta lb01 {
name = "test-lb"
type = "lb-s"
}
resource scaleway_lb_certificate_beta cert01 {
lb_id = scaleway_lb_beta.lb01.id
name = "test-cert-new"
letsencrypt {
common_name = "${scaleway_lb_beta.lb01.ip_address}.xip.io"
}
}
`,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("scaleway_lb_certificate_beta.cert01", "name", "test-cert-new"),
),
},
{
Config: `
resource scaleway_lb_beta lb01 {
name = "test-lb"
type = "lb-s"
}
resource scaleway_lb_certificate_beta cert01 {
lb_id = scaleway_lb_beta.lb01.id
name = "test-cert"
letsencrypt {
common_name = "${scaleway_lb_beta.lb01.ip_address}.xip.io"
subject_alternative_name = [
"sub1.${scaleway_lb_beta.lb01.ip_address}.xip.io",
"sub2.${scaleway_lb_beta.lb01.ip_address}.xip.io"
]
}
}
`,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("scaleway_lb_certificate_beta.cert01", "name", "test-cert"),
resource.TestCheckResourceAttr("scaleway_lb_certificate_beta.cert01", "letsencrypt.#", "1"),
resource.TestCheckResourceAttr("scaleway_lb_certificate_beta.cert01", "letsencrypt.0.subject_alternative_name.#", "2"),
),
},
{
Config: `
resource scaleway_lb_beta lb01 {
name = "test-lb"
type = "lb-s"
}
resource scaleway_lb_certificate_beta cert01 {
lb_id = scaleway_lb_beta.lb01.id
name = "test-custom-cert"
custom_certificate {
certificate_chain = <<EOF
-----BEGIN CERTIFICATE REQUEST-----
MIIBZTCBzwIBADAmMQwwCgYDVQQKDANCYXIxFjAUBgNVBAMMDSouZXhhbXBsZS5j
b20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKM8iE+6xpL9ps2x/W/+0wf3
+5Kgcwl+AoqUTNmAT6eaLfj3PMtdAmN+IcGsYXK2F1FENAdfHd70m4mSBoMJeq+F
a2ZEYp+RlFQqldTBSUBld48z9DNkbNmb0cMyVmntnKhPZ5wjNjgsYee2Leesm2lx
Gw2BCpDxGLBmwKFca3bTAgMBAAGgADANBgkqhkiG9w0BAQsFAAOBgQBbelf1jYNX
Y+AbCpbsySJ32iDtlrZkcIDHMlRIefnoXnO8B1RiEY0SU/n/b2tFCAcvkhq0whKj
RPOH6lzT0x3lWxI+C6xpVyURlljHPygVRbD3fig1rFnH3sI2IE3fJEbGJdmmHacA
BRgm3RR+HWWLKB0ygUbOtZk0BLBUqPK+WQ==
-----END CERTIFICATE REQUEST-----
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQCjPIhPusaS/abNsf1v/tMH9/uSoHMJfgKKlEzZgE+nmi349zzL
XQJjfiHBrGFythdRRDQHXx3e9JuJkgaDCXqvhWtmRGKfkZRUKpXUwUlAZXePM/Qz
ZGzZm9HDMlZp7ZyoT2ecIzY4LGHnti3nrJtpcRsNgQqQ8RiwZsChXGt20wIDAQAB
AoGBAINGbhU4jvOtW9T2fGvyEgLJkp7zvC/5D9Akvbz5LJYML0aWhmTB0ubyi/E2
UVQwToZDhFgdTWd9bgxvzB7bo7Z1kiKWTXQSUDTjC3fchE12UU+1/s0LGh9B1cpV
YqFAu7QNG4maXdZ2h+u+T7dioHslS74PFCBExClkwDiUsdcRAkEAzufrw6zgC0R3
x6OMaaPsH2oX9KfR0+Kxj2m02TnwyFPSrSlIGfoSVtU5wBkvCwTBx/IPY70vNw3f
fPacJNldGwJBAMn3/2nqMJUhR3U7bZA3lI+T1z01D7dLbvCafh3oHTYRAbHO2f0z
k1uhn1+2r9QICwaugZwvx7biCfT3rTqXAKkCQGbINwphWnq+bHI0AJCJ6cZBQd07
cLS9LE99x2URr1cUrNdwZmzhGTMhgSq4V/I1Tr4wtQxq8oV60saVC0QS5nkCQQDI
W2NfuNlVN9xhqgC4zspr3KfrqlXa6dQ2j6yJEpjX5+scby3Fh4Kpph4qn1qyJwB5
MmiVfrjK7lYeVA3fT6lxAkAc1QlmGapJ3w9996v6OZ3UqNBzsHsMmze/zGemdMfc
VaSSB5OL7dZ8fLoJctv9EwgIBM3LFhSgAm9ASPHHR9fp
-----END RSA PRIVATE KEY-----
----BEGIN TRUSTED CERTIFICATE-----
MIIBmTCCAQICCQCb2NiBTIlkeTANBgkqhkiG9w0BAQUFADARMQ8wDQYDVQQKDAZG
b29CYXIwHhcNMjAwMzAzMTYwODQ4WhcNMzAwMzAxMTYwODQ4WjARMQ8wDQYDVQQK
DAZGb29CYXIwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALba1p/3sJ3E2J0J
Wa6N4Zw9aBAq4OedYszUCYqviG6XiCKZPeI1skfD9bef4pYG67R5OcccCsjwqfT4
HkwKj/2SG4VsJZpvVr9S1uOeiA70KywB9GvuiLZUflrDEy4IEA0s6UBALRgXllX+
QbnE8VC9brzgepQwO6tTU1Vjo9s9AgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAelXe
TxdxZWXZFldVl7LUS39lsc9CRgIcLbmk/s23zs92zyJcYvarulx2ku4Zrp507RzT
hPrE4kljWeyQnwIXeOSg5UZrsRtRxUTDLBtOrL3PmFZhBaDShSc+1DS4U/kjy/k+
F+6t5ymALbasChWwC7FFgSsF5PtGP4PxZHFdXiE=
-----END TRUSTED CERTIFICATE-----
EOF
}
}
`,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("scaleway_lb_certificate_beta.cert01", "name", "test-custom-cert"),
resource.TestCheckResourceAttr("scaleway_lb_certificate_beta.cert01", "custom_certificate.#", "1"),
),
},
},
})
}
Loading