github.com/minamijoyo/terraform@v0.7.8-0.20161029001309-18b3736ba44b/builtin/providers/packet/resource_packet_volume.go (about)

     1  package packet
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"time"
     7  
     8  	"github.com/hashicorp/terraform/helper/resource"
     9  	"github.com/hashicorp/terraform/helper/schema"
    10  	"github.com/packethost/packngo"
    11  )
    12  
    13  func resourcePacketVolume() *schema.Resource {
    14  	return &schema.Resource{
    15  		Create: resourcePacketVolumeCreate,
    16  		Read:   resourcePacketVolumeRead,
    17  		Update: resourcePacketVolumeUpdate,
    18  		Delete: resourcePacketVolumeDelete,
    19  
    20  		Schema: map[string]*schema.Schema{
    21  			"id": &schema.Schema{
    22  				Type:     schema.TypeString,
    23  				Computed: true,
    24  			},
    25  
    26  			"project_id": &schema.Schema{
    27  				Type:     schema.TypeString,
    28  				Required: true,
    29  				ForceNew: true,
    30  			},
    31  
    32  			"name": &schema.Schema{
    33  				Type:     schema.TypeString,
    34  				Computed: true,
    35  			},
    36  
    37  			"description": &schema.Schema{
    38  				Type:     schema.TypeString,
    39  				Required: false,
    40  				Optional: true,
    41  			},
    42  
    43  			"size": &schema.Schema{
    44  				Type:     schema.TypeInt,
    45  				Required: true,
    46  			},
    47  
    48  			"facility": &schema.Schema{
    49  				Type:     schema.TypeString,
    50  				Required: true,
    51  				ForceNew: true,
    52  			},
    53  
    54  			"plan": &schema.Schema{
    55  				Type:     schema.TypeString,
    56  				Required: true,
    57  			},
    58  
    59  			"billing_cycle": &schema.Schema{
    60  				Type:     schema.TypeString,
    61  				Computed: true,
    62  				Optional: true,
    63  			},
    64  
    65  			"state": &schema.Schema{
    66  				Type:     schema.TypeString,
    67  				Computed: true,
    68  			},
    69  
    70  			"locked": &schema.Schema{
    71  				Type:     schema.TypeBool,
    72  				Optional: true,
    73  			},
    74  
    75  			"snapshot_policies": &schema.Schema{
    76  				Type:     schema.TypeList,
    77  				Optional: true,
    78  				Elem: &schema.Resource{
    79  					Schema: map[string]*schema.Schema{
    80  						"snapshot_frequency": &schema.Schema{
    81  							Type:     schema.TypeString,
    82  							Required: true,
    83  							ForceNew: true,
    84  						},
    85  						"snapshot_count": &schema.Schema{
    86  							Type:     schema.TypeInt,
    87  							Required: true,
    88  							ForceNew: true,
    89  						},
    90  					},
    91  				},
    92  			},
    93  
    94  			"attachments": &schema.Schema{
    95  				Type:     schema.TypeList,
    96  				Computed: true,
    97  				Elem: &schema.Resource{
    98  					Schema: map[string]*schema.Schema{
    99  						"href": &schema.Schema{
   100  							Type:     schema.TypeString,
   101  							Computed: true,
   102  						},
   103  					},
   104  				},
   105  			},
   106  
   107  			"created": &schema.Schema{
   108  				Type:     schema.TypeString,
   109  				Computed: true,
   110  			},
   111  
   112  			"updated": &schema.Schema{
   113  				Type:     schema.TypeString,
   114  				Computed: true,
   115  			},
   116  		},
   117  	}
   118  }
   119  
   120  func resourcePacketVolumeCreate(d *schema.ResourceData, meta interface{}) error {
   121  	client := meta.(*packngo.Client)
   122  
   123  	createRequest := &packngo.VolumeCreateRequest{
   124  		PlanID:     d.Get("plan").(string),
   125  		FacilityID: d.Get("facility").(string),
   126  		ProjectID:  d.Get("project_id").(string),
   127  		Size:       d.Get("size").(int),
   128  	}
   129  
   130  	if attr, ok := d.GetOk("billing_cycle"); ok {
   131  		createRequest.BillingCycle = attr.(string)
   132  	} else {
   133  		createRequest.BillingCycle = "hourly"
   134  	}
   135  
   136  	if attr, ok := d.GetOk("description"); ok {
   137  		createRequest.Description = attr.(string)
   138  	}
   139  
   140  	snapshot_count := d.Get("snapshot_policies.#").(int)
   141  	if snapshot_count > 0 {
   142  		createRequest.SnapshotPolicies = make([]*packngo.SnapshotPolicy, 0, snapshot_count)
   143  		for i := 0; i < snapshot_count; i++ {
   144  			policy := new(packngo.SnapshotPolicy)
   145  			policy.SnapshotFrequency = d.Get(fmt.Sprintf("snapshot_policies.%d.snapshot_frequency", i)).(string)
   146  			policy.SnapshotCount = d.Get(fmt.Sprintf("snapshot_policies.%d.snapshot_count", i)).(int)
   147  			createRequest.SnapshotPolicies = append(createRequest.SnapshotPolicies, policy)
   148  		}
   149  	}
   150  
   151  	newVolume, _, err := client.Volumes.Create(createRequest)
   152  	if err != nil {
   153  		return friendlyError(err)
   154  	}
   155  
   156  	d.SetId(newVolume.ID)
   157  
   158  	_, err = waitForVolumeAttribute(d, "active", []string{"queued", "provisioning"}, "state", meta)
   159  	if err != nil {
   160  		if isForbidden(err) {
   161  			// If the volume doesn't get to the active state, we can't recover it from here.
   162  			d.SetId("")
   163  
   164  			return errors.New("provisioning time limit exceeded; the Packet team will investigate")
   165  		}
   166  		return err
   167  	}
   168  
   169  	return resourcePacketVolumeRead(d, meta)
   170  }
   171  
   172  func waitForVolumeAttribute(d *schema.ResourceData, target string, pending []string, attribute string, meta interface{}) (interface{}, error) {
   173  	stateConf := &resource.StateChangeConf{
   174  		Pending:    pending,
   175  		Target:     []string{target},
   176  		Refresh:    newVolumeStateRefreshFunc(d, attribute, meta),
   177  		Timeout:    60 * time.Minute,
   178  		Delay:      10 * time.Second,
   179  		MinTimeout: 3 * time.Second,
   180  	}
   181  	return stateConf.WaitForState()
   182  }
   183  
   184  func newVolumeStateRefreshFunc(d *schema.ResourceData, attribute string, meta interface{}) resource.StateRefreshFunc {
   185  	client := meta.(*packngo.Client)
   186  
   187  	return func() (interface{}, string, error) {
   188  		if err := resourcePacketVolumeRead(d, meta); err != nil {
   189  			return nil, "", err
   190  		}
   191  
   192  		if attr, ok := d.GetOk(attribute); ok {
   193  			volume, _, err := client.Volumes.Get(d.Id())
   194  			if err != nil {
   195  				return nil, "", friendlyError(err)
   196  			}
   197  			return &volume, attr.(string), nil
   198  		}
   199  
   200  		return nil, "", nil
   201  	}
   202  }
   203  
   204  func resourcePacketVolumeRead(d *schema.ResourceData, meta interface{}) error {
   205  	client := meta.(*packngo.Client)
   206  
   207  	volume, _, err := client.Volumes.Get(d.Id())
   208  	if err != nil {
   209  		err = friendlyError(err)
   210  
   211  		// If the volume somehow already destroyed, mark as succesfully gone.
   212  		if isNotFound(err) {
   213  			d.SetId("")
   214  			return nil
   215  		}
   216  
   217  		return err
   218  	}
   219  
   220  	d.Set("name", volume.Name)
   221  	d.Set("description", volume.Description)
   222  	d.Set("size", volume.Size)
   223  	d.Set("plan", volume.Plan.Slug)
   224  	d.Set("facility", volume.Facility.Code)
   225  	d.Set("state", volume.State)
   226  	d.Set("billing_cycle", volume.BillingCycle)
   227  	d.Set("locked", volume.Locked)
   228  	d.Set("created", volume.Created)
   229  	d.Set("updated", volume.Updated)
   230  
   231  	snapshot_policies := make([]map[string]interface{}, 0, len(volume.SnapshotPolicies))
   232  	for _, snapshot_policy := range volume.SnapshotPolicies {
   233  		policy := map[string]interface{}{
   234  			"snapshot_frequency": snapshot_policy.SnapshotFrequency,
   235  			"snapshot_count":     snapshot_policy.SnapshotCount,
   236  		}
   237  		snapshot_policies = append(snapshot_policies, policy)
   238  	}
   239  	d.Set("snapshot_policies", snapshot_policies)
   240  
   241  	attachments := make([]*packngo.Attachment, 0, len(volume.Attachments))
   242  	for _, attachment := range volume.Attachments {
   243  		attachments = append(attachments, attachment)
   244  	}
   245  	d.Set("attachments", attachments)
   246  
   247  	return nil
   248  }
   249  
   250  func resourcePacketVolumeUpdate(d *schema.ResourceData, meta interface{}) error {
   251  	client := meta.(*packngo.Client)
   252  
   253  	updateRequest := &packngo.VolumeUpdateRequest{
   254  		ID: d.Get("id").(string),
   255  	}
   256  
   257  	if attr, ok := d.GetOk("description"); ok {
   258  		updateRequest.Description = attr.(string)
   259  	}
   260  
   261  	if attr, ok := d.GetOk("plan"); ok {
   262  		updateRequest.Plan = attr.(string)
   263  	}
   264  
   265  	_, _, err := client.Volumes.Update(updateRequest)
   266  	if err != nil {
   267  		return friendlyError(err)
   268  	}
   269  
   270  	return resourcePacketVolumeRead(d, meta)
   271  }
   272  
   273  func resourcePacketVolumeDelete(d *schema.ResourceData, meta interface{}) error {
   274  	client := meta.(*packngo.Client)
   275  
   276  	if _, err := client.Volumes.Delete(d.Id()); err != nil {
   277  		return friendlyError(err)
   278  	}
   279  
   280  	return nil
   281  }