diff --git a/resource_digitalocean_certificate.go b/resource_digitalocean_certificate.go new file mode 100644 index 00000000..d04af32c --- /dev/null +++ b/resource_digitalocean_certificate.go @@ -0,0 +1,119 @@ +package digitalocean + +import ( + "context" + "fmt" + "log" + + "github.com/digitalocean/godo" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceDigitalOceanCertificate() *schema.Resource { + return &schema.Resource{ + Create: resourceDigitalOceanCertificateCreate, + Read: resourceDigitalOceanCertificateRead, + Delete: resourceDigitalOceanCertificateDelete, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "private_key": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "leaf_certificate": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "certificate_chain": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + + "not_after": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + + "sha1_fingerprint": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + }, + } +} + +func buildCertificateRequest(d *schema.ResourceData) (*godo.CertificateRequest, error) { + req := &godo.CertificateRequest{ + Name: d.Get("name").(string), + PrivateKey: d.Get("private_key").(string), + LeafCertificate: d.Get("leaf_certificate").(string), + CertificateChain: d.Get("certificate_chain").(string), + } + + return req, nil +} + +func resourceDigitalOceanCertificateCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*godo.Client) + + log.Printf("[INFO] Create a Certificate Request") + + certReq, err := buildCertificateRequest(d) + if err != nil { + return err + } + + log.Printf("[DEBUG] Certificate Create: %#v", certReq) + cert, _, err := client.Certificates.Create(context.Background(), certReq) + if err != nil { + return fmt.Errorf("Error creating Certificate: %s", err) + } + + d.SetId(cert.ID) + + return resourceDigitalOceanCertificateRead(d, meta) +} + +func resourceDigitalOceanCertificateRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*godo.Client) + + log.Printf("[INFO] Reading the details of the Certificate %s", d.Id()) + cert, _, err := client.Certificates.Get(context.Background(), d.Id()) + if err != nil { + return fmt.Errorf("Error retrieving Certificate: %s", err) + } + + d.Set("name", cert.Name) + d.Set("not_after", cert.NotAfter) + d.Set("sha1_fingerprint", cert.SHA1Fingerprint) + + return nil + +} + +func resourceDigitalOceanCertificateDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*godo.Client) + + log.Printf("[INFO] Deleting Certificate: %s", d.Id()) + _, err := client.Certificates.Delete(context.Background(), d.Id()) + if err != nil { + return fmt.Errorf("Error deleting Certificate: %s", err) + } + + d.SetId("") + return nil + +} diff --git a/resource_digitalocean_certificate_test.go b/resource_digitalocean_certificate_test.go new file mode 100644 index 00000000..1ae6ae8b --- /dev/null +++ b/resource_digitalocean_certificate_test.go @@ -0,0 +1,117 @@ +package digitalocean + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/digitalocean/godo" + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccDigitalOceanCertificate_Basic(t *testing.T) { + var cert godo.Certificate + rInt := acctest.RandInt() + leafCertMaterial, privateKeyMaterial, err := acctest.RandTLSCert("Acme Co") + if err != nil { + t.Fatalf("Cannot generate test TLS certificate: %s", err) + } + rootCertMaterial, _, err := acctest.RandTLSCert("Acme Go") + if err != nil { + t.Fatalf("Cannot generate test TLS certificate: %s", err) + } + certChainMaterial := fmt.Sprintf("%s\n%s", strings.TrimSpace(rootCertMaterial), leafCertMaterial) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckDigitalOceanCertificateDestroy, + Steps: []resource.TestStep{ + { + ExpectNonEmptyPlan: true, + Config: testAccCheckDigitalOceanCertificateConfig_basic(rInt, privateKeyMaterial, leafCertMaterial, certChainMaterial), + Check: resource.ComposeTestCheckFunc( + testAccCheckDigitalOceanCertificateExists("digitalocean_certificate.foobar", &cert), + resource.TestCheckResourceAttr( + "digitalocean_certificate.foobar", "name", fmt.Sprintf("certificate-%d", rInt)), + resource.TestCheckResourceAttr( + "digitalocean_certificate.foobar", "private_key", fmt.Sprintf("%s\n", privateKeyMaterial)), + resource.TestCheckResourceAttr( + "digitalocean_certificate.foobar", "leaf_certificate", fmt.Sprintf("%s\n", leafCertMaterial)), + resource.TestCheckResourceAttr( + "digitalocean_certificate.foobar", "certificate_chain", fmt.Sprintf("%s\n", certChainMaterial)), + ), + }, + }, + }) +} + +func testAccCheckDigitalOceanCertificateDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*godo.Client) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "digitalocean_certificate" { + continue + } + + _, _, err := client.Certificates.Get(context.Background(), rs.Primary.ID) + + if err != nil && !strings.Contains(err.Error(), "404") { + return fmt.Errorf( + "Error waiting for certificate (%s) to be destroyed: %s", + rs.Primary.ID, err) + } + } + + return nil +} + +func testAccCheckDigitalOceanCertificateExists(n string, cert *godo.Certificate) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No Certificate ID is set") + } + + client := testAccProvider.Meta().(*godo.Client) + + c, _, err := client.Certificates.Get(context.Background(), rs.Primary.ID) + + if err != nil { + return err + } + + if c.ID != rs.Primary.ID { + return fmt.Errorf("Certificate not found") + } + + *cert = *c + + return nil + } +} + +func testAccCheckDigitalOceanCertificateConfig_basic(rInt int, privateKeyMaterial, leafCert, certChain string) string { + return fmt.Sprintf(` +resource "digitalocean_certificate" "foobar" { + name = "certificate-%d" + private_key = <