github.com/koding/terraform@v0.6.4-0.20170608090606-5d7e0339779d/builtin/providers/azurerm/resource_arm_storage_container.go (about)

     1  package azurerm
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strings"
     7  
     8  	"regexp"
     9  
    10  	"github.com/Azure/azure-sdk-for-go/storage"
    11  	"github.com/hashicorp/terraform/helper/schema"
    12  )
    13  
    14  func resourceArmStorageContainer() *schema.Resource {
    15  	return &schema.Resource{
    16  		Create: resourceArmStorageContainerCreate,
    17  		Read:   resourceArmStorageContainerRead,
    18  		Exists: resourceArmStorageContainerExists,
    19  		Delete: resourceArmStorageContainerDelete,
    20  
    21  		Schema: map[string]*schema.Schema{
    22  			"name": {
    23  				Type:         schema.TypeString,
    24  				Required:     true,
    25  				ForceNew:     true,
    26  				ValidateFunc: validateArmStorageContainerName,
    27  			},
    28  			"resource_group_name": {
    29  				Type:     schema.TypeString,
    30  				Required: true,
    31  				ForceNew: true,
    32  			},
    33  			"storage_account_name": {
    34  				Type:     schema.TypeString,
    35  				Required: true,
    36  				ForceNew: true,
    37  			},
    38  			"container_access_type": {
    39  				Type:         schema.TypeString,
    40  				Optional:     true,
    41  				ForceNew:     true,
    42  				Default:      "private",
    43  				ValidateFunc: validateArmStorageContainerAccessType,
    44  			},
    45  			"properties": {
    46  				Type:     schema.TypeMap,
    47  				Computed: true,
    48  			},
    49  		},
    50  	}
    51  }
    52  
    53  //Following the naming convention as laid out in the docs
    54  func validateArmStorageContainerName(v interface{}, k string) (ws []string, errors []error) {
    55  	value := v.(string)
    56  	if !regexp.MustCompile(`^\$root$|^[0-9a-z-]+$`).MatchString(value) {
    57  		errors = append(errors, fmt.Errorf(
    58  			"only lowercase alphanumeric characters and hyphens allowed in %q: %q",
    59  			k, value))
    60  	}
    61  	if len(value) < 3 || len(value) > 63 {
    62  		errors = append(errors, fmt.Errorf(
    63  			"%q must be between 3 and 63 characters: %q", k, value))
    64  	}
    65  	if regexp.MustCompile(`^-`).MatchString(value) {
    66  		errors = append(errors, fmt.Errorf(
    67  			"%q cannot begin with a hyphen: %q", k, value))
    68  	}
    69  	return
    70  }
    71  
    72  func validateArmStorageContainerAccessType(v interface{}, k string) (ws []string, errors []error) {
    73  	value := strings.ToLower(v.(string))
    74  	validTypes := map[string]struct{}{
    75  		"private":   struct{}{},
    76  		"blob":      struct{}{},
    77  		"container": struct{}{},
    78  	}
    79  
    80  	if _, ok := validTypes[value]; !ok {
    81  		errors = append(errors, fmt.Errorf("Storage container access type %q is invalid, must be %q, %q or %q", value, "private", "blob", "page"))
    82  	}
    83  	return
    84  }
    85  
    86  func resourceArmStorageContainerCreate(d *schema.ResourceData, meta interface{}) error {
    87  	armClient := meta.(*ArmClient)
    88  
    89  	resourceGroupName := d.Get("resource_group_name").(string)
    90  	storageAccountName := d.Get("storage_account_name").(string)
    91  
    92  	blobClient, accountExists, err := armClient.getBlobStorageClientForStorageAccount(resourceGroupName, storageAccountName)
    93  	if err != nil {
    94  		return err
    95  	}
    96  	if !accountExists {
    97  		return fmt.Errorf("Storage Account %q Not Found", storageAccountName)
    98  	}
    99  
   100  	name := d.Get("name").(string)
   101  
   102  	var accessType storage.ContainerAccessType
   103  	if d.Get("container_access_type").(string) == "private" {
   104  		accessType = storage.ContainerAccessType("")
   105  	} else {
   106  		accessType = storage.ContainerAccessType(d.Get("container_access_type").(string))
   107  	}
   108  
   109  	log.Printf("[INFO] Creating container %q in storage account %q.", name, storageAccountName)
   110  	reference := blobClient.GetContainerReference(name)
   111  
   112  	createOptions := &storage.CreateContainerOptions{}
   113  	_, err = reference.CreateIfNotExists(createOptions)
   114  	if err != nil {
   115  		return fmt.Errorf("Error creating container %q in storage account %q: %s", name, storageAccountName, err)
   116  	}
   117  
   118  	permissions := storage.ContainerPermissions{
   119  		AccessType: accessType,
   120  	}
   121  	permissionOptions := &storage.SetContainerPermissionOptions{}
   122  	err = reference.SetPermissions(permissions, permissionOptions)
   123  	if err != nil {
   124  		return fmt.Errorf("Error setting permissions for container %s in storage account %s: %+v", name, storageAccountName, err)
   125  	}
   126  
   127  	d.SetId(name)
   128  	return resourceArmStorageContainerRead(d, meta)
   129  }
   130  
   131  // resourceAzureStorageContainerRead does all the necessary API calls to
   132  // read the status of the storage container off Azure.
   133  func resourceArmStorageContainerRead(d *schema.ResourceData, meta interface{}) error {
   134  	armClient := meta.(*ArmClient)
   135  
   136  	resourceGroupName := d.Get("resource_group_name").(string)
   137  	storageAccountName := d.Get("storage_account_name").(string)
   138  
   139  	blobClient, accountExists, err := armClient.getBlobStorageClientForStorageAccount(resourceGroupName, storageAccountName)
   140  	if err != nil {
   141  		return err
   142  	}
   143  	if !accountExists {
   144  		log.Printf("[DEBUG] Storage account %q not found, removing container %q from state", storageAccountName, d.Id())
   145  		d.SetId("")
   146  		return nil
   147  	}
   148  
   149  	name := d.Get("name").(string)
   150  	containers, err := blobClient.ListContainers(storage.ListContainersParameters{
   151  		Prefix:  name,
   152  		Timeout: 90,
   153  	})
   154  	if err != nil {
   155  		return fmt.Errorf("Failed to retrieve storage containers in account %q: %s", name, err)
   156  	}
   157  
   158  	var found bool
   159  	for _, cont := range containers.Containers {
   160  		if cont.Name == name {
   161  			found = true
   162  
   163  			props := make(map[string]interface{})
   164  			props["last_modified"] = cont.Properties.LastModified
   165  			props["lease_status"] = cont.Properties.LeaseStatus
   166  			props["lease_state"] = cont.Properties.LeaseState
   167  			props["lease_duration"] = cont.Properties.LeaseDuration
   168  
   169  			d.Set("properties", props)
   170  		}
   171  	}
   172  
   173  	if !found {
   174  		log.Printf("[INFO] Storage container %q does not exist in account %q, removing from state...", name, storageAccountName)
   175  		d.SetId("")
   176  	}
   177  
   178  	return nil
   179  }
   180  
   181  func resourceArmStorageContainerExists(d *schema.ResourceData, meta interface{}) (bool, error) {
   182  	armClient := meta.(*ArmClient)
   183  
   184  	resourceGroupName := d.Get("resource_group_name").(string)
   185  	storageAccountName := d.Get("storage_account_name").(string)
   186  
   187  	blobClient, accountExists, err := armClient.getBlobStorageClientForStorageAccount(resourceGroupName, storageAccountName)
   188  	if err != nil {
   189  		return false, err
   190  	}
   191  	if !accountExists {
   192  		log.Printf("[DEBUG] Storage account %q not found, removing container %q from state", storageAccountName, d.Id())
   193  		d.SetId("")
   194  		return false, nil
   195  	}
   196  
   197  	name := d.Get("name").(string)
   198  
   199  	log.Printf("[INFO] Checking existence of storage container %q in storage account %q", name, storageAccountName)
   200  	reference := blobClient.GetContainerReference(name)
   201  	exists, err := reference.Exists()
   202  	if err != nil {
   203  		return false, fmt.Errorf("Error querying existence of storage container %q in storage account %q: %s", name, storageAccountName, err)
   204  	}
   205  
   206  	if !exists {
   207  		log.Printf("[INFO] Storage container %q does not exist in account %q, removing from state...", name, storageAccountName)
   208  		d.SetId("")
   209  	}
   210  
   211  	return exists, nil
   212  }
   213  
   214  // resourceAzureStorageContainerDelete does all the necessary API calls to
   215  // delete a storage container off Azure.
   216  func resourceArmStorageContainerDelete(d *schema.ResourceData, meta interface{}) error {
   217  	armClient := meta.(*ArmClient)
   218  
   219  	resourceGroupName := d.Get("resource_group_name").(string)
   220  	storageAccountName := d.Get("storage_account_name").(string)
   221  
   222  	blobClient, accountExists, err := armClient.getBlobStorageClientForStorageAccount(resourceGroupName, storageAccountName)
   223  	if err != nil {
   224  		return err
   225  	}
   226  	if !accountExists {
   227  		log.Printf("[INFO]Storage Account %q doesn't exist so the container won't exist", storageAccountName)
   228  		return nil
   229  	}
   230  
   231  	name := d.Get("name").(string)
   232  
   233  	log.Printf("[INFO] Deleting storage container %q in account %q", name, storageAccountName)
   234  	reference := blobClient.GetContainerReference(name)
   235  	deleteOptions := &storage.DeleteContainerOptions{}
   236  	if _, err := reference.DeleteIfExists(deleteOptions); err != nil {
   237  		return fmt.Errorf("Error deleting storage container %q from storage account %q: %s", name, storageAccountName, err)
   238  	}
   239  
   240  	d.SetId("")
   241  	return nil
   242  }