From 4b8c7c898e20def317b3478de960ed59e42e87c0 Mon Sep 17 00:00:00 2001 From: "alex.mabry" Date: Mon, 24 Jul 2017 10:19:10 -0500 Subject: [PATCH 1/3] Add aws_iot_certificate resource based on work from @jhedev --- aws/provider.go | 1 + aws/resource_aws_iot_certificate.go | 147 +++++++++++++++++++ aws/resource_aws_iot_certificate_test.go | 73 +++++++++ aws/test-fixtures/iot-csr.pem | 16 ++ website/aws.erb | 4 + website/docs/r/iot_certificate.html.markdown | 32 ++++ 6 files changed, 273 insertions(+) create mode 100644 aws/resource_aws_iot_certificate.go create mode 100644 aws/resource_aws_iot_certificate_test.go create mode 100644 aws/test-fixtures/iot-csr.pem create mode 100644 website/docs/r/iot_certificate.html.markdown diff --git a/aws/provider.go b/aws/provider.go index fe99eeada26..8522665f090 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -356,6 +356,7 @@ func Provider() terraform.ResourceProvider { "aws_inspector_resource_group": resourceAWSInspectorResourceGroup(), "aws_instance": resourceAwsInstance(), "aws_internet_gateway": resourceAwsInternetGateway(), + "aws_iot_certificate": resourceAwsIotCertificate(), "aws_iot_policy": resourceAwsIotPolicy(), "aws_key_pair": resourceAwsKeyPair(), "aws_kinesis_firehose_delivery_stream": resourceAwsKinesisFirehoseDeliveryStream(), diff --git a/aws/resource_aws_iot_certificate.go b/aws/resource_aws_iot_certificate.go new file mode 100644 index 00000000000..16a7893bdaa --- /dev/null +++ b/aws/resource_aws_iot_certificate.go @@ -0,0 +1,147 @@ +package aws + +import ( + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/iot" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsIotCertificate() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsIotCertificateCreate, + Read: resourceAwsIotCertificateRead, + Update: resourceAwsIotCertificateUpdate, + Delete: resourceAwsIotCertificateDelete, + Schema: map[string]*schema.Schema{ + "csr": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "active": &schema.Schema{ + Type: schema.TypeBool, + Required: true, + }, + "arn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceAwsIotCertificateCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).iotconn + + log.Printf("[DEBUG] Creating certificate from csr") + out, err := conn.CreateCertificateFromCsr(&iot.CreateCertificateFromCsrInput{ + CertificateSigningRequest: aws.String(d.Get("csr").(string)), + SetAsActive: aws.Bool(d.Get("active").(bool)), + }) + + if err != nil { + log.Printf("[ERROR] %s", err) + return err + } + log.Printf("[DEBUG] Created certificate from csr") + + d.SetId(*out.CertificateId) + + return resourceAwsIotCertificateRead(d, meta) +} + +func resourceAwsIotCertificateRead(d *schema.ResourceData, meta interface{}) error { + + conn := meta.(*AWSClient).iotconn + + out, err := conn.DescribeCertificate(&iot.DescribeCertificateInput{ + CertificateId: aws.String(d.Id()), + }) + + if err != nil { + log.Printf("[ERROR] %s", err) + return err + } + + d.Set("arn", out.CertificateDescription.CertificateArn) + + return nil +} + +func resourceAwsIotCertificateUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).iotconn + + if d.HasChange("csr") { + // First create certificate with new CSR + out, err := conn.CreateCertificateFromCsr(&iot.CreateCertificateFromCsrInput{ + CertificateSigningRequest: aws.String(d.Get("csr").(string)), + SetAsActive: aws.Bool(d.Get("active").(bool)), + }) + + if err != nil { + log.Printf("[ERROR] %s", err) + return nil + } + + // If everything worked, make the old one inactive + _, err = conn.UpdateCertificate(&iot.UpdateCertificateInput{ + CertificateId: aws.String(d.Id()), + NewStatus: aws.String("INACTIVE"), + }) + + if err != nil { + log.Printf("[ERROR] %s", err) + return err + } + + d.SetId(*out.CertificateId) + + } else { + + if d.HasChange("active") { + status := "INACTIVE" + if d.Get("active").(bool) { + status = "ACTIVE" + } + + _, err := conn.UpdateCertificate(&iot.UpdateCertificateInput{ + CertificateId: aws.String(d.Id()), + NewStatus: aws.String(status), + }) + + if err != nil { + log.Printf("[ERROR] %s", err) + return err + } + } + } + + return resourceAwsIotCertificateRead(d, meta) +} + +func resourceAwsIotCertificateDelete(d *schema.ResourceData, meta interface{}) error { + + conn := meta.(*AWSClient).iotconn + + _, err := conn.UpdateCertificate(&iot.UpdateCertificateInput{ + CertificateId: aws.String(d.Id()), + NewStatus: aws.String("INACTIVE"), + }) + + if err != nil { + log.Printf("[ERROR], %s", err) + return err + } + + _, err = conn.DeleteCertificate(&iot.DeleteCertificateInput{ + CertificateId: aws.String(d.Id()), + }) + + if err != nil { + log.Printf("[ERROR] %s", err) + return err + } + + return nil +} diff --git a/aws/resource_aws_iot_certificate_test.go b/aws/resource_aws_iot_certificate_test.go new file mode 100644 index 00000000000..f2c52410c31 --- /dev/null +++ b/aws/resource_aws_iot_certificate_test.go @@ -0,0 +1,73 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/iot" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccAWSIoTCertificate_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSIoTCertificateDestroy_basic, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSIoTCertificate_basic, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("aws_iot_certificate.foo_cert", "arn"), + resource.TestCheckResourceAttrSet("aws_iot_certificate.foo_cert", "csr"), + resource.TestCheckResourceAttr("aws_iot_certificate.foo_cert", "active", "true"), + ), + }, + }, + }) +} + + +func testAccCheckAWSIoTCertificateDestroy_basic(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).iotconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_iot_certificate" { + continue + } + + // Try to find the Cert + DescribeCertOpts := &iot.DescribeCertificateInput{ + CertificateId: aws.String(rs.Primary.ID), + } + + resp, err := conn.DescribeCertificate(DescribeCertOpts) + + if err == nil { + if resp.CertificateDescription != nil { + return fmt.Errorf("Device Certificate still exists") + } + } + + // Verify the error is what we want + if err != nil { + iotErr, ok := err.(awserr.Error) + if !ok || iotErr.Code() != "ResourceNotFoundException" { + return err + } + } + + } + + return nil +} + + +var testAccAWSIoTCertificate_basic = ` +resource "aws_iot_certificate" "foo_cert" { + csr = "${file("test-fixtures/iot-csr.pem")}" + active = true +} +` diff --git a/aws/test-fixtures/iot-csr.pem b/aws/test-fixtures/iot-csr.pem new file mode 100644 index 00000000000..7d5c743f557 --- /dev/null +++ b/aws/test-fixtures/iot-csr.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICijCCAXICAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUx +ITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAMSUg2mO7mYnhvYUB55K0/ay9WLLgPjOHnbduyCv +N+udkJaZc+A65ux9LvVo33VHDTlV2Ms9H/42on902WtuS3BNuxdXfD068CpN2lb6 +bSAeuKc6Fdu4BIP2bFYKCyejqBoOmTEhYA8bOM1Wu/pRsq1PkAmcGkvw3mlRx45E +B2LRicWcg3YEleEBGyLYohyeMu0pnlsc7zsu5T4bwrjetdbDPVbzgu0Mf/evU9hJ +G/IisXNxQhzPh/DTQsKZSNddZ4bmkAQrRN1nmNXD6QoxBiVyjjgKGrPnX+hz4ugm +aaN9CsOO/cad1E3C0KiI0BQCjxRb80wOpI4utz4pEcY97sUCAwEAAaAAMA0GCSqG +SIb3DQEBBQUAA4IBAQC64L4JHvwxdxmnXT9Lv12p5CGx99d7VOXQXy29b1yH9cJ+ +FaQ2TH377uOdorSCS4bK7eje9/HLsCNgqftR0EruwSNnukF695BWN8e/AJSZe0vA +3J/llZ6G7MWuOIhCswsOxqNnM1htu3o6ujXVrgBMeMgQy2tfylWfI7SGR6UmtLYF +ZrPaqXdkpt47ROJNCm2Oht1B0J3QEOmbIp/2XMxrfknzwH6se/CjuliiXVPYxrtO +5hbZcRqjhugb8FWtaLirqh3Q3+1UIJ+CW0ZczsblP7DNdqqt8YQZpWVIqR64mSXV +Ajq/cupsJST9fey8chcNSTt4nKxOGs3OgXu1ftgy +-----END CERTIFICATE REQUEST----- diff --git a/website/aws.erb b/website/aws.erb index a7becca732f..56f8d0a72c7 100644 --- a/website/aws.erb +++ b/website/aws.erb @@ -882,6 +882,10 @@ IoT Resources