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

     1  package docker
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  
     7  	"regexp"
     8  
     9  	"github.com/hashicorp/terraform/helper/hashcode"
    10  	"github.com/hashicorp/terraform/helper/schema"
    11  )
    12  
    13  func resourceDockerContainer() *schema.Resource {
    14  	return &schema.Resource{
    15  		Create: resourceDockerContainerCreate,
    16  		Read:   resourceDockerContainerRead,
    17  		Update: resourceDockerContainerUpdate,
    18  		Delete: resourceDockerContainerDelete,
    19  
    20  		Schema: map[string]*schema.Schema{
    21  			"name": &schema.Schema{
    22  				Type:     schema.TypeString,
    23  				Required: true,
    24  				ForceNew: true,
    25  			},
    26  
    27  			// Indicates whether the container must be running.
    28  			//
    29  			// An assumption is made that configured containers
    30  			// should be running; if not, they should not be in
    31  			// the configuration. Therefore a stopped container
    32  			// should be started. Set to false to have the
    33  			// provider leave the container alone.
    34  			//
    35  			// Actively-debugged containers are likely to be
    36  			// stopped and started manually, and Docker has
    37  			// some provisions for restarting containers that
    38  			// stop. The utility here comes from the fact that
    39  			// this will delete and re-create the container
    40  			// following the principle that the containers
    41  			// should be pristine when started.
    42  			"must_run": &schema.Schema{
    43  				Type:     schema.TypeBool,
    44  				Default:  true,
    45  				Optional: true,
    46  			},
    47  
    48  			// ForceNew is not true for image because we need to
    49  			// sane this against Docker image IDs, as each image
    50  			// can have multiple names/tags attached do it.
    51  			"image": &schema.Schema{
    52  				Type:     schema.TypeString,
    53  				Required: true,
    54  				ForceNew: true,
    55  			},
    56  
    57  			"hostname": &schema.Schema{
    58  				Type:     schema.TypeString,
    59  				Optional: true,
    60  				ForceNew: true,
    61  			},
    62  
    63  			"domainname": &schema.Schema{
    64  				Type:     schema.TypeString,
    65  				Optional: true,
    66  				ForceNew: true,
    67  			},
    68  
    69  			"command": &schema.Schema{
    70  				Type:     schema.TypeList,
    71  				Optional: true,
    72  				ForceNew: true,
    73  				Elem:     &schema.Schema{Type: schema.TypeString},
    74  			},
    75  
    76  			"entrypoint": &schema.Schema{
    77  				Type:     schema.TypeList,
    78  				Optional: true,
    79  				ForceNew: true,
    80  				Elem:     &schema.Schema{Type: schema.TypeString},
    81  			},
    82  
    83  			"user": &schema.Schema{
    84  				Type:     schema.TypeString,
    85  				Optional: true,
    86  				ForceNew: true,
    87  				Elem:     &schema.Schema{Type: schema.TypeString},
    88  			},
    89  
    90  			"dns": &schema.Schema{
    91  				Type:     schema.TypeSet,
    92  				Optional: true,
    93  				ForceNew: true,
    94  				Elem:     &schema.Schema{Type: schema.TypeString},
    95  				Set:      schema.HashString,
    96  			},
    97  
    98  			"publish_all_ports": &schema.Schema{
    99  				Type:     schema.TypeBool,
   100  				Optional: true,
   101  				ForceNew: true,
   102  			},
   103  
   104  			"restart": &schema.Schema{
   105  				Type:     schema.TypeString,
   106  				Optional: true,
   107  				ForceNew: true,
   108  				Default:  "no",
   109  				ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
   110  					value := v.(string)
   111  					if !regexp.MustCompile(`^(no|on-failure|always|unless-stopped)$`).MatchString(value) {
   112  						es = append(es, fmt.Errorf(
   113  							"%q must be one of \"no\", \"on-failure\", \"always\" or \"unless-stopped\"", k))
   114  					}
   115  					return
   116  				},
   117  			},
   118  
   119  			"max_retry_count": &schema.Schema{
   120  				Type:     schema.TypeInt,
   121  				Optional: true,
   122  				ForceNew: true,
   123  			},
   124  
   125  			"volumes": &schema.Schema{
   126  				Type:     schema.TypeSet,
   127  				Optional: true,
   128  				ForceNew: true,
   129  				Elem: &schema.Resource{
   130  					Schema: map[string]*schema.Schema{
   131  						"from_container": &schema.Schema{
   132  							Type:     schema.TypeString,
   133  							Optional: true,
   134  							ForceNew: true,
   135  						},
   136  
   137  						"container_path": &schema.Schema{
   138  							Type:     schema.TypeString,
   139  							Optional: true,
   140  							ForceNew: true,
   141  						},
   142  
   143  						"host_path": &schema.Schema{
   144  							Type:     schema.TypeString,
   145  							Optional: true,
   146  							ForceNew: true,
   147  							ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
   148  								value := v.(string)
   149  								if !regexp.MustCompile(`^/`).MatchString(value) {
   150  									es = append(es, fmt.Errorf(
   151  										"%q must be an absolute path", k))
   152  								}
   153  								return
   154  							},
   155  						},
   156  
   157  						"volume_name": &schema.Schema{
   158  							Type:     schema.TypeString,
   159  							Optional: true,
   160  							ForceNew: true,
   161  						},
   162  
   163  						"read_only": &schema.Schema{
   164  							Type:     schema.TypeBool,
   165  							Optional: true,
   166  							ForceNew: true,
   167  						},
   168  					},
   169  				},
   170  				Set: resourceDockerVolumesHash,
   171  			},
   172  
   173  			"ports": &schema.Schema{
   174  				Type:     schema.TypeSet,
   175  				Optional: true,
   176  				ForceNew: true,
   177  				Elem: &schema.Resource{
   178  					Schema: map[string]*schema.Schema{
   179  						"internal": &schema.Schema{
   180  							Type:     schema.TypeInt,
   181  							Required: true,
   182  							ForceNew: true,
   183  						},
   184  
   185  						"external": &schema.Schema{
   186  							Type:     schema.TypeInt,
   187  							Optional: true,
   188  							ForceNew: true,
   189  						},
   190  
   191  						"ip": &schema.Schema{
   192  							Type:     schema.TypeString,
   193  							Optional: true,
   194  							ForceNew: true,
   195  						},
   196  
   197  						"protocol": &schema.Schema{
   198  							Type:     schema.TypeString,
   199  							Default:  "tcp",
   200  							Optional: true,
   201  							ForceNew: true,
   202  						},
   203  					},
   204  				},
   205  				Set: resourceDockerPortsHash,
   206  			},
   207  
   208  			"host": &schema.Schema{
   209  				Type:     schema.TypeSet,
   210  				Optional: true,
   211  				ForceNew: true,
   212  				Elem: &schema.Resource{
   213  					Schema: map[string]*schema.Schema{
   214  						"ip": &schema.Schema{
   215  							Type:     schema.TypeString,
   216  							Optional: true,
   217  							ForceNew: true,
   218  						},
   219  
   220  						"host": &schema.Schema{
   221  							Type:     schema.TypeString,
   222  							Optional: true,
   223  							ForceNew: true,
   224  						},
   225  					},
   226  				},
   227  				Set: resourceDockerHostsHash,
   228  			},
   229  
   230  			"env": &schema.Schema{
   231  				Type:     schema.TypeSet,
   232  				Optional: true,
   233  				ForceNew: true,
   234  				Elem:     &schema.Schema{Type: schema.TypeString},
   235  				Set:      schema.HashString,
   236  			},
   237  
   238  			"links": &schema.Schema{
   239  				Type:     schema.TypeSet,
   240  				Optional: true,
   241  				ForceNew: true,
   242  				Elem:     &schema.Schema{Type: schema.TypeString},
   243  				Set:      schema.HashString,
   244  			},
   245  
   246  			"ip_address": &schema.Schema{
   247  				Type:     schema.TypeString,
   248  				Computed: true,
   249  			},
   250  
   251  			"ip_prefix_length": &schema.Schema{
   252  				Type:     schema.TypeInt,
   253  				Computed: true,
   254  			},
   255  
   256  			"gateway": &schema.Schema{
   257  				Type:     schema.TypeString,
   258  				Computed: true,
   259  			},
   260  
   261  			"bridge": &schema.Schema{
   262  				Type:     schema.TypeString,
   263  				Computed: true,
   264  			},
   265  
   266  			"privileged": &schema.Schema{
   267  				Type:     schema.TypeBool,
   268  				Optional: true,
   269  				ForceNew: true,
   270  			},
   271  
   272  			"labels": &schema.Schema{
   273  				Type:     schema.TypeMap,
   274  				Optional: true,
   275  				ForceNew: true,
   276  			},
   277  
   278  			"memory": &schema.Schema{
   279  				Type:     schema.TypeInt,
   280  				Optional: true,
   281  				ForceNew: true,
   282  				ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
   283  					value := v.(int)
   284  					if value < 0 {
   285  						es = append(es, fmt.Errorf("%q must be greater than or equal to 0", k))
   286  					}
   287  					return
   288  				},
   289  			},
   290  
   291  			"memory_swap": &schema.Schema{
   292  				Type:     schema.TypeInt,
   293  				Optional: true,
   294  				ForceNew: true,
   295  				ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
   296  					value := v.(int)
   297  					if value < -1 {
   298  						es = append(es, fmt.Errorf("%q must be greater than or equal to -1", k))
   299  					}
   300  					return
   301  				},
   302  			},
   303  
   304  			"cpu_shares": &schema.Schema{
   305  				Type:     schema.TypeInt,
   306  				Optional: true,
   307  				ForceNew: true,
   308  				ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
   309  					value := v.(int)
   310  					if value < 0 {
   311  						es = append(es, fmt.Errorf("%q must be greater than or equal to 0", k))
   312  					}
   313  					return
   314  				},
   315  			},
   316  
   317  			"log_driver": &schema.Schema{
   318  				Type:     schema.TypeString,
   319  				Optional: true,
   320  				ForceNew: true,
   321  				Default:  "json-file",
   322  				ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
   323  					value := v.(string)
   324  					if !regexp.MustCompile(`^(json-file|syslog|journald|gelf|fluentd)$`).MatchString(value) {
   325  						es = append(es, fmt.Errorf(
   326  							"%q must be one of \"json-file\", \"syslog\", \"journald\", \"gelf\", or \"fluentd\"", k))
   327  					}
   328  					return
   329  				},
   330  			},
   331  
   332  			"log_opts": &schema.Schema{
   333  				Type:     schema.TypeMap,
   334  				Optional: true,
   335  				ForceNew: true,
   336  			},
   337  
   338  			"network_mode": &schema.Schema{
   339  				Type:     schema.TypeString,
   340  				Optional: true,
   341  				ForceNew: true,
   342  			},
   343  
   344  			"networks": &schema.Schema{
   345  				Type:     schema.TypeSet,
   346  				Optional: true,
   347  				ForceNew: true,
   348  				Elem:     &schema.Schema{Type: schema.TypeString},
   349  				Set:      schema.HashString,
   350  			},
   351  		},
   352  	}
   353  }
   354  
   355  func resourceDockerPortsHash(v interface{}) int {
   356  	var buf bytes.Buffer
   357  	m := v.(map[string]interface{})
   358  
   359  	buf.WriteString(fmt.Sprintf("%v-", m["internal"].(int)))
   360  
   361  	if v, ok := m["external"]; ok {
   362  		buf.WriteString(fmt.Sprintf("%v-", v.(int)))
   363  	}
   364  
   365  	if v, ok := m["ip"]; ok {
   366  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   367  	}
   368  
   369  	if v, ok := m["protocol"]; ok {
   370  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   371  	}
   372  
   373  	return hashcode.String(buf.String())
   374  }
   375  
   376  func resourceDockerHostsHash(v interface{}) int {
   377  	var buf bytes.Buffer
   378  	m := v.(map[string]interface{})
   379  
   380  	if v, ok := m["ip"]; ok {
   381  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   382  	}
   383  
   384  	if v, ok := m["host"]; ok {
   385  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   386  	}
   387  
   388  	return hashcode.String(buf.String())
   389  }
   390  
   391  func resourceDockerVolumesHash(v interface{}) int {
   392  	var buf bytes.Buffer
   393  	m := v.(map[string]interface{})
   394  
   395  	if v, ok := m["from_container"]; ok {
   396  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   397  	}
   398  
   399  	if v, ok := m["container_path"]; ok {
   400  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   401  	}
   402  
   403  	if v, ok := m["host_path"]; ok {
   404  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   405  	}
   406  
   407  	if v, ok := m["volume_name"]; ok {
   408  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   409  	}
   410  
   411  	if v, ok := m["read_only"]; ok {
   412  		buf.WriteString(fmt.Sprintf("%v-", v.(bool)))
   413  	}
   414  
   415  	return hashcode.String(buf.String())
   416  }