From: Alexandre Garand Date: Thu, 27 Jun 2019 10:02:56 +0000 (+0200) Subject: add ssl tests to terraform provider X-Git-Tag: v0.1.1~13 X-Git-Url: https://git.immae.eu/?a=commitdiff_plain;h=82cbfd586d4853b8ef6beafc12c7f2aa015f3c23;p=github%2Ffretlink%2Fterraform-provider-statuscake.git add ssl tests to terraform provider --- diff --git a/statuscake/provider.go b/statuscake/provider.go index 93c691f..7f38d7f 100644 --- a/statuscake/provider.go +++ b/statuscake/provider.go @@ -25,6 +25,7 @@ func Provider() terraform.ResourceProvider { ResourcesMap: map[string]*schema.Resource{ "statuscake_test": resourceStatusCakeTest(), + "statuscake_ssl": resourceStatusCakeSsl(), }, ConfigureFunc: providerConfigure, diff --git a/statuscake/provider_test.go b/statuscake/provider_test.go index b1da050..4537960 100644 --- a/statuscake/provider_test.go +++ b/statuscake/provider_test.go @@ -38,4 +38,7 @@ func testAccPreCheck(t *testing.T) { if v := os.Getenv("STATUSCAKE_TEST_CONTACT_GROUP_ID"); v == "" { t.Fatal("STATUSCAKE_TEST_CONTACT_GROUP_ID must be set for acceptance tests") } + if v := os.Getenv("STATUSCAKE_SSL_CONTACT_GROUP_ID"); v == "" { + t.Fatal("STATUSCAKE_SSL_CONTACT_GROUP_ID must be set for acceptance tests") + } } diff --git a/statuscake/resource_statuscakessl.go b/statuscake/resource_statuscakessl.go new file mode 100644 index 0000000..3dba5bd --- /dev/null +++ b/statuscake/resource_statuscakessl.go @@ -0,0 +1,283 @@ +package statuscake + +import ( + "fmt" + "strconv" + + "log" + + "github.com/DreamItGetIT/statuscake" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceStatusCakeSsl() *schema.Resource { + return &schema.Resource{ + Create: CreateSsl, + Update: UpdateSsl, + Delete: DeleteSsl, + Read: ReadSsl, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "ssl_id": { + Type: schema.TypeString, + Computed: true, + }, + + "domain": { + Type: schema.TypeString, + Required: true, + }, + + "contact_groups": { + Type: schema.TypeList, + Elem: &schema.Schema{Type: schema.TypeString}, + Computed: true, + }, + + "contact_groups_c": { + Type: schema.TypeString, + Required: true, + }, + + "checkrate": { + Type: schema.TypeInt, + Required: true, + }, + + "alert_at": { + Type: schema.TypeString, + Required: true, + }, + + "alert_reminder": { + Type: schema.TypeBool, + Required: true, + }, + + "alert_expiry": { + Type: schema.TypeBool, + Required: true, + }, + + "alert_broken": { + Type: schema.TypeBool, + Required: true, + }, + + "alert_mixed": { + Type: schema.TypeBool, + Required: true, + }, + + "paused": { + Type: schema.TypeBool, + Computed: true, + }, + + "issuer_cn": { + Type: schema.TypeString, + Computed: true, + }, + + "cert_score": { + Type: schema.TypeString, + Computed: true, + }, + + "cipher_score": { + Type: schema.TypeString, + Computed: true, + }, + + "cert_status": { + Type: schema.TypeString, + Computed: true, + }, + + "cipher": { + Type: schema.TypeString, + Computed: true, + }, + + "valid_from_utc": { + Type: schema.TypeString, + Computed: true, + }, + + "valid_until_utc": { + Type: schema.TypeString, + Computed: true, + }, + + "mixed_content": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeMap, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + Computed: true, + }, + + "flags": { + Type: schema.TypeMap, + Elem: &schema.Schema{Type: schema.TypeBool}, + Computed: true, + }, + + "last_reminder": { + Type: schema.TypeInt, + Computed: true, + }, + + "last_updated_utc": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func CreateSsl(d *schema.ResourceData, meta interface{}) error { + client := meta.(*statuscake.Client) + + newSsl := &statuscake.PartialSsl{ + Domain: d.Get("domain").(string), + Checkrate: strconv.Itoa(d.Get("checkrate").(int)), + ContactGroupsC: d.Get("contact_groups_c").(string), + AlertReminder: d.Get("alert_reminder").(bool), + AlertExpiry: d.Get("alert_expiry").(bool), + AlertBroken: d.Get("alert_broken").(bool), + AlertMixed: d.Get("alert_mixed").(bool), + AlertAt: d.Get("alert_at").(string), + } + + log.Printf("[DEBUG] Creating new StatusCake Ssl: %s", d.Get("domain").(string)) + + response, err := statuscake.NewSsls(client).Create(newSsl) + if err != nil { + fmt.Println(newSsl) + fmt.Println(client) + return fmt.Errorf("Error creating StatusCake Ssl: %s", err.Error()) + } + + d.Set("ssl_id", response.ID) + d.Set("contact_groups", response.ContactGroups) + d.Set("paused", response.Paused) + d.Set("issuer_cn", response.IssuerCn) + d.Set("cert_score", response.CertScore) + d.Set("cipher_score", response.CipherScore) + d.Set("cert_status", response.CertStatus) + d.Set("cipher", response.Cipher) + d.Set("valid_from_utc", response.ValidFromUtc) + d.Set("valid_until_utc", response.ValidUntilUtc) + d.Set("mixed_content", response.MixedContent) + d.Set("flags", response.Flags) + d.Set("last_reminder", response.LastReminder) + d.Set("last_updated_utc", response.LastUpdatedUtc) + d.SetId(response.ID) + + return ReadSsl(d, meta) +} + +func UpdateSsl(d *schema.ResourceData, meta interface{}) error { + client := meta.(*statuscake.Client) + + params := getStatusCakeSslInput(d) + + log.Printf("[DEBUG] StatusCake Ssl Update for %s", d.Id()) + _, err := statuscake.NewSsls(client).Update(params) + if err != nil { + return fmt.Errorf("Error Updating StatusCake Ssl: %s", err.Error()) + } + return nil +} + +func DeleteSsl(d *schema.ResourceData, meta interface{}) error { + client := meta.(*statuscake.Client) + + log.Printf("[DEBUG] Deleting StatusCake Ssl: %s", d.Id()) + err := statuscake.NewSsls(client).Delete(d.Id()) + + return err +} + +func ReadSsl(d *schema.ResourceData, meta interface{}) error { + client := meta.(*statuscake.Client) + + response, err := statuscake.NewSsls(client).Detail(d.Id()) + if err != nil { + return fmt.Errorf("Error Getting StatusCake Ssl Details for %s: Error: %s", d.Id(), err) + } + d.Set("domain", response.Domain) + d.Set("checkrate", response.Checkrate) + d.Set("contact_groups_c", response.ContactGroupsC) + d.Set("alert_reminder", response.AlertReminder) + d.Set("alert_expiry", response.AlertExpiry) + d.Set("alert_broken", response.AlertBroken) + d.Set("alert_mixed", response.AlertMixed) + d.Set("alert_at", response.AlertAt) + d.Set("ssl_id", response.ID) + d.Set("contact_groups", response.ContactGroups) + d.Set("paused", response.Paused) + d.Set("issuer_cn", response.IssuerCn) + d.Set("cert_score", response.CertScore) + d.Set("cipher_score", response.CipherScore) + d.Set("cert_status", response.CertStatus) + d.Set("cipher", response.Cipher) + d.Set("valid_from_utc", response.ValidFromUtc) + d.Set("valid_until_utc", response.ValidUntilUtc) + d.Set("mixed_content", response.MixedContent) + d.Set("flags", response.Flags) + d.Set("last_reminder", response.LastReminder) + d.Set("last_updated_utc", response.LastUpdatedUtc) + d.SetId(response.ID) + + return nil +} + +func getStatusCakeSslInput(d *schema.ResourceData) *statuscake.PartialSsl { + sslId, parseErr := strconv.Atoi(d.Id()) + if parseErr != nil { + log.Printf("[DEBUG] Error Parsing StatusCake Id: %s", d.Id()) + } + ssl := &statuscake.PartialSsl{ + ID: sslId, + } + + if v, ok := d.GetOk("domain"); ok { + ssl.Domain = v.(string) + } + + if v, ok := d.GetOk("checkrate"); ok { + ssl.Checkrate = strconv.Itoa(v.(int)) + } + + if v, ok := d.GetOk("contact_groups_c"); ok { + ssl.ContactGroupsC = v.(string) + } + + if v, ok := d.GetOk("alert_reminder"); ok { + ssl.AlertReminder = v.(bool) + } + + if v, ok := d.GetOk("alert_expiry"); ok { + ssl.AlertExpiry = v.(bool) + } + + if v, ok := d.GetOk("alert_broken"); ok { + ssl.AlertBroken = v.(bool) + } + + if v, ok := d.GetOk("alert_mixed"); ok { + ssl.AlertMixed = v.(bool) + } + + if v, ok := d.GetOk("alert_at"); ok { + ssl.AlertAt = v.(string) + } + + return ssl +} diff --git a/statuscake/resource_statuscakessl_test.go b/statuscake/resource_statuscakessl_test.go new file mode 100644 index 0000000..a9a83da --- /dev/null +++ b/statuscake/resource_statuscakessl_test.go @@ -0,0 +1,222 @@ +package statuscake + +import ( + "fmt" + "os" + "strconv" + "testing" + + "github.com/DreamItGetIT/statuscake" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccStatusCakeSsl_basic(t *testing.T) { + var ssl statuscake.Ssl + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccSslCheckDestroy(&ssl), + Steps: []resource.TestStep{ + { + Config: interpolateTerraformTemplateSsl(testAccSslConfig_basic), + Check: resource.ComposeTestCheckFunc( + testAccSslCheckExists("statuscake_ssl.exemple", &ssl), + testAccSslCheckAttributes("statuscake_ssl.exemple", &ssl), + ), + }, + }, + }) +} + +func TestAccStatusCakeSsl_withUpdate(t *testing.T) { + var ssl statuscake.Ssl + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccSslCheckDestroy(&ssl), + Steps: []resource.TestStep{ + { + Config: interpolateTerraformTemplateSsl(testAccSslConfig_basic), + Check: resource.ComposeTestCheckFunc( + testAccSslCheckExists("statuscake_ssl.exemple", &ssl), + testAccSslCheckAttributes("statuscake_ssl.exemple", &ssl), + ), + }, + + { + Config: testAccSslConfig_update, + Check: resource.ComposeTestCheckFunc( + testAccSslCheckExists("statuscake_ssl.exemple", &ssl), + testAccSslCheckAttributes("statuscake_ssl.exemple", &ssl), + resource.TestCheckResourceAttr("statuscake_ssl.exemple", "check_rate", "86400"), + resource.TestCheckResourceAttr("statuscake_ssl.exemple", "domain", "https://www.exemple.com"), + resource.TestCheckResourceAttr("statuscake_ssl.exemple", "contact_group_c", ""), + resource.TestCheckResourceAttr("statuscake_ssl.exemple", "alert_at", "18,8,2019"), + resource.TestCheckResourceAttr("statuscake_ssl.exemple", "alert_reminder", "false"), + resource.TestCheckResourceAttr("statuscake_ssl.exemple", "alert_expiry", "false"), + resource.TestCheckResourceAttr("statuscake_ssl.exemple", "alert_broken", "true"), + resource.TestCheckResourceAttr("statuscake_ssl.exemple", "alert_mixed", "false"), + ), + }, + }, + }) +} + +func testAccSslCheckExists(rn string, ssl *statuscake.Ssl) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[rn] + if !ok { + return fmt.Errorf("resource not found: %s", rn) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("SslID not set") + } + + client := testAccProvider.Meta().(*statuscake.Client) + sslId := rs.Primary.ID + + gotSsl, err := statuscake.NewSsls(client).Detail(sslId) + if err != nil { + return fmt.Errorf("error getting ssl: %s", err) + } + + *ssl = *gotSsl + + return nil + } +} + +func testAccSslCheckAttributes(rn string, ssl *statuscake.Ssl) resource.TestCheckFunc { + return func(s *terraform.State) error { + attrs := s.RootModule().Resources[rn].Primary.Attributes + + check := func(key, stateValue, sslValue string) error { + if sslValue != stateValue { + return fmt.Errorf("different values for %s in state (%s) and in statuscake (%s)", + key, stateValue, sslValue) + } + return nil + } + + for key, value := range attrs { + var err error + + switch key { + case "domain": + err = check(key, value, ssl.Domain) + case "contact_groups_c": + err = check(key, value, ssl.ContactGroupsC) + case "checkrate": + err = check(key, value, strconv.Itoa(ssl.Checkrate)) + case "alert_at": + err = check(key, value, ssl.AlertAt) + case "alert_reminder": + err = check(key, value, strconv.FormatBool(ssl.AlertReminder)) + case "alert_expiry": + err = check(key, value, strconv.FormatBool(ssl.AlertExpiry)) + case "alert_broken": + err = check(key, value, strconv.FormatBool(ssl.AlertBroken)) + case "alert_mixed": + err = check(key, value, strconv.FormatBool(ssl.AlertMixed)) + case "paused": + err = check(key, value, strconv.FormatBool(ssl.Paused)) + case "issuer_cn": + err = check(key, value, ssl.IssuerCn) + case "contact_groups": + for _, tv := range ssl.ContactGroups { + err = check(key, value, tv) + if err != nil { + return err + } + } + case "cert_score": + err = check(key, value, ssl.CertScore) + case "cert_status": + err = check(key, value, ssl.CertStatus) + case "cipher": + err = check(key, value, ssl.Cipher) + case "valid_from_utc": + err = check(key, value, ssl.ValidFromUtc) + case "valid_until_utc": + err = check(key, value, ssl.ValidUntilUtc) + case "last_reminder": + err = check(key, value, strconv.Itoa(ssl.LastReminder)) + case "last_updated_utc": + err = check(key, value, ssl.LastUpdatedUtc) + case "flags": + for _, tv := range ssl.Flags { + err = check(key, value, strconv.FormatBool(tv)) + if err != nil { + return err + } + } + + case "mixed_content": + for _, tv := range ssl.MixedContent { + for _, tv2 := range tv { + err = check(key, value, tv2) + if err != nil { + return err + } + } + } + } + if err != nil { + return err + } + } + return nil + } +} + +func testAccSslCheckDestroy(ssl *statuscake.Ssl) resource.TestCheckFunc { + return func(s *terraform.State) error { + client := testAccProvider.Meta().(*statuscake.Client) + _, err := statuscake.NewSsls(client).Detail(ssl.ID) + if err == nil { + return fmt.Errorf("ssl still exists") + } + + return nil + } +} + +func interpolateTerraformTemplateSsl(template string) string { + sslContactGroupId := "43402" + + if v := os.Getenv("STATUSCAKE_SSL_CONTACT_GROUP_ID"); v != "" { + sslContactGroupId = v + } + + return fmt.Sprintf(template, sslContactGroupId) +} + +const testAccSslConfig_basic = ` +resource "statuscake_ssl" "exemple" { + domain = "https://www.exemple.com" + contact_groups_c = "%s" + checkrate = 3600 + alert_at = "18,7,2019" + alert_reminder = true + alert_expiry = true + alert_broken = false + alert_mixed = true +} +` + +const testAccSslConfig_update = ` +resource "statuscake_ssl" "exemple" { + domain = "https://www.exemple.com" + contact_groups_c = "" + checkrate = 86400 + alert_at = "18,8,2019" + alert_reminder = false + alert_expiry = false + alert_broken = true + alert_mixed = false +} +`