github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/arukas/resource_arukas_container.go (about)

     1  package arukas
     2  
     3  import (
     4  	"fmt"
     5  	API "github.com/arukasio/cli"
     6  	"github.com/hashicorp/terraform/helper/schema"
     7  	"strings"
     8  	"time"
     9  )
    10  
    11  func resourceArukasContainer() *schema.Resource {
    12  	return &schema.Resource{
    13  		Create: resourceArukasContainerCreate,
    14  		Read:   resourceArukasContainerRead,
    15  		Update: resourceArukasContainerUpdate,
    16  		Delete: resourceArukasContainerDelete,
    17  		Importer: &schema.ResourceImporter{
    18  			State: schema.ImportStatePassthrough,
    19  		},
    20  		Schema: map[string]*schema.Schema{
    21  			"name": &schema.Schema{
    22  				Type:     schema.TypeString,
    23  				Required: true,
    24  				ForceNew: true,
    25  			},
    26  			"image": &schema.Schema{
    27  				Type:     schema.TypeString,
    28  				Required: true,
    29  			},
    30  			"instances": &schema.Schema{
    31  				Type:         schema.TypeInt,
    32  				Optional:     true,
    33  				Default:      1,
    34  				ValidateFunc: validateIntegerInRange(1, 10),
    35  			},
    36  			"memory": &schema.Schema{
    37  				Type:         schema.TypeInt,
    38  				Optional:     true,
    39  				Default:      256,
    40  				ValidateFunc: validateIntInWord([]string{"256", "512"}),
    41  			},
    42  			"endpoint": &schema.Schema{
    43  				Type:     schema.TypeString,
    44  				Optional: true,
    45  				Computed: true,
    46  			},
    47  			"ports": &schema.Schema{
    48  				Type:     schema.TypeList,
    49  				Required: true,
    50  				MaxItems: 20,
    51  				Elem: &schema.Resource{
    52  					Schema: map[string]*schema.Schema{
    53  						"protocol": &schema.Schema{
    54  							Type:         schema.TypeString,
    55  							Optional:     true,
    56  							Default:      "tcp",
    57  							ValidateFunc: validateStringInWord([]string{"tcp", "udp"}),
    58  						},
    59  						"number": &schema.Schema{
    60  							Type:         schema.TypeInt,
    61  							Optional:     true,
    62  							Default:      "80",
    63  							ValidateFunc: validateIntegerInRange(1, 65535),
    64  						},
    65  					},
    66  				},
    67  			},
    68  			"environments": &schema.Schema{
    69  				Type:     schema.TypeList,
    70  				Optional: true,
    71  				MaxItems: 20,
    72  				Elem: &schema.Resource{
    73  					Schema: map[string]*schema.Schema{
    74  						"key": &schema.Schema{
    75  							Type:     schema.TypeString,
    76  							Required: true,
    77  						},
    78  						"value": &schema.Schema{
    79  							Type:     schema.TypeString,
    80  							Required: true,
    81  						},
    82  					},
    83  				},
    84  			},
    85  			"cmd": &schema.Schema{
    86  				Type:     schema.TypeString,
    87  				Optional: true,
    88  			},
    89  			"port_mappings": &schema.Schema{
    90  				Type:     schema.TypeList,
    91  				Computed: true,
    92  				Elem: &schema.Resource{
    93  					Schema: map[string]*schema.Schema{
    94  						"host": &schema.Schema{
    95  							Type:     schema.TypeString,
    96  							Computed: true,
    97  						},
    98  						"ipaddress": &schema.Schema{
    99  							Type:     schema.TypeString,
   100  							Computed: true,
   101  						},
   102  						"container_port": &schema.Schema{
   103  							Type:     schema.TypeInt,
   104  							Computed: true,
   105  						},
   106  						"service_port": &schema.Schema{
   107  							Type:     schema.TypeInt,
   108  							Computed: true,
   109  						},
   110  					},
   111  				},
   112  			},
   113  			"endpoint_full_hostname": &schema.Schema{
   114  				Type:     schema.TypeString,
   115  				Computed: true,
   116  			},
   117  			"endpoint_full_url": &schema.Schema{
   118  				Type:     schema.TypeString,
   119  				Computed: true,
   120  			},
   121  			"app_id": &schema.Schema{
   122  				Type:     schema.TypeString,
   123  				Computed: true,
   124  			},
   125  		},
   126  	}
   127  }
   128  
   129  func resourceArukasContainerCreate(d *schema.ResourceData, meta interface{}) error {
   130  	client := meta.(*ArukasClient)
   131  
   132  	var appSet API.AppSet
   133  
   134  	// create an app
   135  	newApp := API.App{Name: d.Get("name").(string)}
   136  
   137  	var parsedEnvs API.Envs
   138  	var parsedPorts API.Ports
   139  
   140  	if rawEnvs, ok := d.GetOk("environments"); ok {
   141  		parsedEnvs = expandEnvs(rawEnvs)
   142  	}
   143  	if rawPorts, ok := d.GetOk("ports"); ok {
   144  		parsedPorts = expandPorts(rawPorts)
   145  	}
   146  
   147  	newContainer := API.Container{
   148  		Envs:      parsedEnvs,
   149  		Ports:     parsedPorts,
   150  		ImageName: d.Get("image").(string),
   151  		Mem:       d.Get("memory").(int),
   152  		Instances: d.Get("instances").(int),
   153  		Cmd:       d.Get("cmd").(string),
   154  
   155  		Name: d.Get("endpoint").(string),
   156  	}
   157  	newAppSet := API.AppSet{
   158  		App:       newApp,
   159  		Container: newContainer,
   160  	}
   161  
   162  	// create
   163  	if err := client.Post(&appSet, "/app-sets", newAppSet); err != nil {
   164  		return err
   165  	}
   166  
   167  	// start container
   168  	if err := client.Post(nil, fmt.Sprintf("/containers/%s/power", appSet.Container.ID), nil); err != nil {
   169  		return err
   170  	}
   171  
   172  	if err := sleepUntilUp(client, appSet.Container.ID, client.Timeout); err != nil {
   173  		return err
   174  	}
   175  
   176  	d.SetId(appSet.Container.ID)
   177  	return resourceArukasContainerRead(d, meta)
   178  }
   179  
   180  func resourceArukasContainerRead(d *schema.ResourceData, meta interface{}) error {
   181  	client := meta.(*ArukasClient)
   182  
   183  	var container API.Container
   184  	var app API.App
   185  
   186  	if err := client.Get(&container, fmt.Sprintf("/containers/%s", d.Id())); err != nil {
   187  		return err
   188  	}
   189  	if err := client.Get(&app, fmt.Sprintf("/apps/%s", container.AppID)); err != nil {
   190  		return err
   191  	}
   192  
   193  	d.Set("app_id", container.AppID)
   194  	d.Set("name", app.Name)
   195  	d.Set("image", container.ImageName)
   196  	d.Set("instances", container.Instances)
   197  	d.Set("memory", container.Mem)
   198  	endpoint := container.Endpoint
   199  	if strings.HasSuffix(endpoint, ".arukascloud.io") {
   200  		endpoint = strings.Replace(endpoint, ".arukascloud.io", "", -1)
   201  	}
   202  
   203  	d.Set("endpoint", endpoint)
   204  	d.Set("endpoint_full_hostname", container.Endpoint)
   205  	d.Set("endpoint_full_url", fmt.Sprintf("https://%s", container.Endpoint))
   206  
   207  	d.Set("cmd", container.Cmd)
   208  
   209  	//ports
   210  	d.Set("ports", flattenPorts(container.Ports))
   211  
   212  	//port mappings
   213  	d.Set("port_mappings", flattenPortMappings(container.PortMappings))
   214  
   215  	//envs
   216  	d.Set("environments", flattenEnvs(container.Envs))
   217  
   218  	return nil
   219  }
   220  
   221  func resourceArukasContainerUpdate(d *schema.ResourceData, meta interface{}) error {
   222  
   223  	client := meta.(*ArukasClient)
   224  	var container API.Container
   225  
   226  	if err := client.Get(&container, fmt.Sprintf("/containers/%s", d.Id())); err != nil {
   227  		return err
   228  	}
   229  
   230  	var parsedEnvs API.Envs
   231  	var parsedPorts API.Ports
   232  
   233  	if rawEnvs, ok := d.GetOk("environments"); ok {
   234  		parsedEnvs = expandEnvs(rawEnvs)
   235  	}
   236  	if rawPorts, ok := d.GetOk("ports"); ok {
   237  		parsedPorts = expandPorts(rawPorts)
   238  	}
   239  
   240  	newContainer := API.Container{
   241  		Envs:      parsedEnvs,
   242  		Ports:     parsedPorts,
   243  		ImageName: d.Get("image").(string),
   244  		Mem:       d.Get("memory").(int),
   245  		Instances: d.Get("instances").(int),
   246  		Cmd:       d.Get("cmd").(string),
   247  		Name:      d.Get("endpoint").(string),
   248  	}
   249  
   250  	// update
   251  	if err := client.Patch(nil, fmt.Sprintf("/containers/%s", d.Id()), newContainer); err != nil {
   252  		return err
   253  	}
   254  
   255  	return resourceArukasContainerRead(d, meta)
   256  
   257  }
   258  
   259  func resourceArukasContainerDelete(d *schema.ResourceData, meta interface{}) error {
   260  	client := meta.(*ArukasClient)
   261  	var container API.Container
   262  
   263  	if err := client.Get(&container, fmt.Sprintf("/containers/%s", d.Id())); err != nil {
   264  		return err
   265  	}
   266  
   267  	if err := client.Delete(fmt.Sprintf("/apps/%s", container.AppID)); err != nil {
   268  		return err
   269  	}
   270  
   271  	return nil
   272  }
   273  
   274  func sleepUntilUp(client *ArukasClient, containerID string, timeout time.Duration) error {
   275  	current := 0 * time.Second
   276  	interval := 5 * time.Second
   277  	for {
   278  		var container API.Container
   279  		if err := client.Get(&container, fmt.Sprintf("/containers/%s", containerID)); err != nil {
   280  			return err
   281  		}
   282  
   283  		if container.IsRunning {
   284  			return nil
   285  		}
   286  		time.Sleep(interval)
   287  		current += interval
   288  
   289  		if timeout > 0 && current > timeout {
   290  			return fmt.Errorf("Timeout: sleepUntilUp")
   291  		}
   292  	}
   293  }