github.com/andresvia/terraform@v0.6.15-0.20160412045437-d51c75946785/builtin/providers/aws/resource_aws_iam_server_certificate.go (about)

     1  package aws
     2  
     3  import (
     4  	"crypto/sha1"
     5  	"encoding/hex"
     6  	"fmt"
     7  	"log"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/aws/aws-sdk-go/aws"
    12  	"github.com/aws/aws-sdk-go/aws/awserr"
    13  	"github.com/aws/aws-sdk-go/service/iam"
    14  	"github.com/hashicorp/terraform/helper/resource"
    15  	"github.com/hashicorp/terraform/helper/schema"
    16  )
    17  
    18  func resourceAwsIAMServerCertificate() *schema.Resource {
    19  	return &schema.Resource{
    20  		Create: resourceAwsIAMServerCertificateCreate,
    21  		Read:   resourceAwsIAMServerCertificateRead,
    22  		Delete: resourceAwsIAMServerCertificateDelete,
    23  
    24  		Schema: map[string]*schema.Schema{
    25  			"certificate_body": &schema.Schema{
    26  				Type:      schema.TypeString,
    27  				Required:  true,
    28  				ForceNew:  true,
    29  				StateFunc: normalizeCert,
    30  			},
    31  
    32  			"certificate_chain": &schema.Schema{
    33  				Type:      schema.TypeString,
    34  				Optional:  true,
    35  				ForceNew:  true,
    36  				StateFunc: normalizeCert,
    37  			},
    38  
    39  			"path": &schema.Schema{
    40  				Type:     schema.TypeString,
    41  				Optional: true,
    42  				Default:  "/",
    43  				ForceNew: true,
    44  			},
    45  
    46  			"private_key": &schema.Schema{
    47  				Type:      schema.TypeString,
    48  				Required:  true,
    49  				ForceNew:  true,
    50  				StateFunc: normalizeCert,
    51  			},
    52  
    53  			"name": &schema.Schema{
    54  				Type:          schema.TypeString,
    55  				Optional:      true,
    56  				Computed:      true,
    57  				ForceNew:      true,
    58  				ConflictsWith: []string{"name_prefix"},
    59  				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
    60  					value := v.(string)
    61  					if len(value) > 128 {
    62  						errors = append(errors, fmt.Errorf(
    63  							"%q cannot be longer than 128 characters", k))
    64  					}
    65  					return
    66  				},
    67  			},
    68  
    69  			"name_prefix": &schema.Schema{
    70  				Type:     schema.TypeString,
    71  				Optional: true,
    72  				ForceNew: true,
    73  				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
    74  					value := v.(string)
    75  					if len(value) > 30 {
    76  						errors = append(errors, fmt.Errorf(
    77  							"%q cannot be longer than 30 characters, name is limited to 128", k))
    78  					}
    79  					return
    80  				},
    81  			},
    82  
    83  			"arn": &schema.Schema{
    84  				Type:     schema.TypeString,
    85  				Optional: true,
    86  				Computed: true,
    87  			},
    88  		},
    89  	}
    90  }
    91  
    92  func resourceAwsIAMServerCertificateCreate(d *schema.ResourceData, meta interface{}) error {
    93  	conn := meta.(*AWSClient).iamconn
    94  
    95  	var sslCertName string
    96  	if v, ok := d.GetOk("name"); ok {
    97  		sslCertName = v.(string)
    98  	} else if v, ok := d.GetOk("name_prefix"); ok {
    99  		sslCertName = resource.PrefixedUniqueId(v.(string))
   100  	} else {
   101  		sslCertName = resource.UniqueId()
   102  	}
   103  
   104  	createOpts := &iam.UploadServerCertificateInput{
   105  		CertificateBody:       aws.String(d.Get("certificate_body").(string)),
   106  		PrivateKey:            aws.String(d.Get("private_key").(string)),
   107  		ServerCertificateName: aws.String(sslCertName),
   108  	}
   109  
   110  	if v, ok := d.GetOk("certificate_chain"); ok {
   111  		createOpts.CertificateChain = aws.String(v.(string))
   112  	}
   113  
   114  	if v, ok := d.GetOk("path"); ok {
   115  		createOpts.Path = aws.String(v.(string))
   116  	}
   117  
   118  	log.Printf("[DEBUG] Creating IAM Server Certificate with opts: %s", createOpts)
   119  	resp, err := conn.UploadServerCertificate(createOpts)
   120  	if err != nil {
   121  		if awsErr, ok := err.(awserr.Error); ok {
   122  			return fmt.Errorf("[WARN] Error uploading server certificate, error: %s: %s", awsErr.Code(), awsErr.Message())
   123  		}
   124  		return fmt.Errorf("[WARN] Error uploading server certificate, error: %s", err)
   125  	}
   126  
   127  	d.SetId(*resp.ServerCertificateMetadata.ServerCertificateId)
   128  	d.Set("name", sslCertName)
   129  
   130  	return resourceAwsIAMServerCertificateRead(d, meta)
   131  }
   132  
   133  func resourceAwsIAMServerCertificateRead(d *schema.ResourceData, meta interface{}) error {
   134  	conn := meta.(*AWSClient).iamconn
   135  	resp, err := conn.GetServerCertificate(&iam.GetServerCertificateInput{
   136  		ServerCertificateName: aws.String(d.Get("name").(string)),
   137  	})
   138  
   139  	if err != nil {
   140  		if awsErr, ok := err.(awserr.Error); ok {
   141  			return fmt.Errorf("[WARN] Error reading IAM Server Certificate: %s: %s", awsErr.Code(), awsErr.Message())
   142  		}
   143  		return fmt.Errorf("[WARN] Error reading IAM Server Certificate: %s", err)
   144  	}
   145  
   146  	// these values should always be present, and have a default if not set in
   147  	// configuration, and so safe to reference with nil checks
   148  	d.Set("certificate_body", normalizeCert(resp.ServerCertificate.CertificateBody))
   149  
   150  	c := normalizeCert(resp.ServerCertificate.CertificateChain)
   151  	if c != "" {
   152  		d.Set("certificate_chain", c)
   153  	}
   154  
   155  	d.Set("path", resp.ServerCertificate.ServerCertificateMetadata.Path)
   156  	d.Set("arn", resp.ServerCertificate.ServerCertificateMetadata.Arn)
   157  
   158  	return nil
   159  }
   160  
   161  func resourceAwsIAMServerCertificateDelete(d *schema.ResourceData, meta interface{}) error {
   162  	conn := meta.(*AWSClient).iamconn
   163  	log.Printf("[INFO] Deleting IAM Server Certificate: %s", d.Id())
   164  	err := resource.Retry(1*time.Minute, func() *resource.RetryError {
   165  		_, err := conn.DeleteServerCertificate(&iam.DeleteServerCertificateInput{
   166  			ServerCertificateName: aws.String(d.Get("name").(string)),
   167  		})
   168  
   169  		if err != nil {
   170  			if awsErr, ok := err.(awserr.Error); ok {
   171  				if awsErr.Code() == "DeleteConflict" && strings.Contains(awsErr.Message(), "currently in use by arn") {
   172  					log.Printf("[WARN] Conflict deleting server certificate: %s, retrying", awsErr.Message())
   173  					return resource.RetryableError(err)
   174  				}
   175  			}
   176  			return resource.NonRetryableError(err)
   177  		}
   178  		return nil
   179  	})
   180  
   181  	if err != nil {
   182  		return err
   183  	}
   184  
   185  	d.SetId("")
   186  	return nil
   187  }
   188  
   189  func normalizeCert(cert interface{}) string {
   190  	if cert == nil || cert == (*string)(nil) {
   191  		return ""
   192  	}
   193  
   194  	switch cert.(type) {
   195  	case string:
   196  		hash := sha1.Sum([]byte(strings.TrimSpace(cert.(string))))
   197  		return hex.EncodeToString(hash[:])
   198  	case *string:
   199  		hash := sha1.Sum([]byte(strings.TrimSpace(*cert.(*string))))
   200  		return hex.EncodeToString(hash[:])
   201  	default:
   202  		return ""
   203  	}
   204  }