github.com/adrian-bl/terraform@v0.7.0-rc2.0.20160705220747-de0a34fc3517/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  			"dns_opts": &schema.Schema{
    99  				Type:     schema.TypeSet,
   100  				Optional: true,
   101  				ForceNew: true,
   102  				Elem:     &schema.Schema{Type: schema.TypeString},
   103  				Set:      schema.HashString,
   104  			},
   105  
   106  			"dns_search": &schema.Schema{
   107  				Type:     schema.TypeSet,
   108  				Optional: true,
   109  				ForceNew: true,
   110  				Elem:     &schema.Schema{Type: schema.TypeString},
   111  				Set:      schema.HashString,
   112  			},
   113  
   114  			"publish_all_ports": &schema.Schema{
   115  				Type:     schema.TypeBool,
   116  				Optional: true,
   117  				ForceNew: true,
   118  			},
   119  
   120  			"restart": &schema.Schema{
   121  				Type:     schema.TypeString,
   122  				Optional: true,
   123  				ForceNew: true,
   124  				Default:  "no",
   125  				ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
   126  					value := v.(string)
   127  					if !regexp.MustCompile(`^(no|on-failure|always|unless-stopped)$`).MatchString(value) {
   128  						es = append(es, fmt.Errorf(
   129  							"%q must be one of \"no\", \"on-failure\", \"always\" or \"unless-stopped\"", k))
   130  					}
   131  					return
   132  				},
   133  			},
   134  
   135  			"max_retry_count": &schema.Schema{
   136  				Type:     schema.TypeInt,
   137  				Optional: true,
   138  				ForceNew: true,
   139  			},
   140  
   141  			"volumes": &schema.Schema{
   142  				Type:     schema.TypeSet,
   143  				Optional: true,
   144  				ForceNew: true,
   145  				Elem: &schema.Resource{
   146  					Schema: map[string]*schema.Schema{
   147  						"from_container": &schema.Schema{
   148  							Type:     schema.TypeString,
   149  							Optional: true,
   150  							ForceNew: true,
   151  						},
   152  
   153  						"container_path": &schema.Schema{
   154  							Type:     schema.TypeString,
   155  							Optional: true,
   156  							ForceNew: true,
   157  						},
   158  
   159  						"host_path": &schema.Schema{
   160  							Type:     schema.TypeString,
   161  							Optional: true,
   162  							ForceNew: true,
   163  							ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
   164  								value := v.(string)
   165  								if !regexp.MustCompile(`^/`).MatchString(value) {
   166  									es = append(es, fmt.Errorf(
   167  										"%q must be an absolute path", k))
   168  								}
   169  								return
   170  							},
   171  						},
   172  
   173  						"volume_name": &schema.Schema{
   174  							Type:     schema.TypeString,
   175  							Optional: true,
   176  							ForceNew: true,
   177  						},
   178  
   179  						"read_only": &schema.Schema{
   180  							Type:     schema.TypeBool,
   181  							Optional: true,
   182  							ForceNew: true,
   183  						},
   184  					},
   185  				},
   186  				Set: resourceDockerVolumesHash,
   187  			},
   188  
   189  			"ports": &schema.Schema{
   190  				Type:     schema.TypeSet,
   191  				Optional: true,
   192  				ForceNew: true,
   193  				Elem: &schema.Resource{
   194  					Schema: map[string]*schema.Schema{
   195  						"internal": &schema.Schema{
   196  							Type:     schema.TypeInt,
   197  							Required: true,
   198  							ForceNew: true,
   199  						},
   200  
   201  						"external": &schema.Schema{
   202  							Type:     schema.TypeInt,
   203  							Optional: true,
   204  							ForceNew: true,
   205  						},
   206  
   207  						"ip": &schema.Schema{
   208  							Type:     schema.TypeString,
   209  							Optional: true,
   210  							ForceNew: true,
   211  						},
   212  
   213  						"protocol": &schema.Schema{
   214  							Type:     schema.TypeString,
   215  							Default:  "tcp",
   216  							Optional: true,
   217  							ForceNew: true,
   218  						},
   219  					},
   220  				},
   221  				Set: resourceDockerPortsHash,
   222  			},
   223  
   224  			"host": &schema.Schema{
   225  				Type:     schema.TypeSet,
   226  				Optional: true,
   227  				ForceNew: true,
   228  				Elem: &schema.Resource{
   229  					Schema: map[string]*schema.Schema{
   230  						"ip": &schema.Schema{
   231  							Type:     schema.TypeString,
   232  							Optional: true,
   233  							ForceNew: true,
   234  						},
   235  
   236  						"host": &schema.Schema{
   237  							Type:     schema.TypeString,
   238  							Optional: true,
   239  							ForceNew: true,
   240  						},
   241  					},
   242  				},
   243  				Set: resourceDockerHostsHash,
   244  			},
   245  
   246  			"env": &schema.Schema{
   247  				Type:     schema.TypeSet,
   248  				Optional: true,
   249  				ForceNew: true,
   250  				Elem:     &schema.Schema{Type: schema.TypeString},
   251  				Set:      schema.HashString,
   252  			},
   253  
   254  			"links": &schema.Schema{
   255  				Type:     schema.TypeSet,
   256  				Optional: true,
   257  				ForceNew: true,
   258  				Elem:     &schema.Schema{Type: schema.TypeString},
   259  				Set:      schema.HashString,
   260  			},
   261  
   262  			"ip_address": &schema.Schema{
   263  				Type:     schema.TypeString,
   264  				Computed: true,
   265  			},
   266  
   267  			"ip_prefix_length": &schema.Schema{
   268  				Type:     schema.TypeInt,
   269  				Computed: true,
   270  			},
   271  
   272  			"gateway": &schema.Schema{
   273  				Type:     schema.TypeString,
   274  				Computed: true,
   275  			},
   276  
   277  			"bridge": &schema.Schema{
   278  				Type:     schema.TypeString,
   279  				Computed: true,
   280  			},
   281  
   282  			"privileged": &schema.Schema{
   283  				Type:     schema.TypeBool,
   284  				Optional: true,
   285  				ForceNew: true,
   286  			},
   287  
   288  			"labels": &schema.Schema{
   289  				Type:     schema.TypeMap,
   290  				Optional: true,
   291  				ForceNew: true,
   292  			},
   293  
   294  			"memory": &schema.Schema{
   295  				Type:     schema.TypeInt,
   296  				Optional: true,
   297  				ForceNew: true,
   298  				ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
   299  					value := v.(int)
   300  					if value < 0 {
   301  						es = append(es, fmt.Errorf("%q must be greater than or equal to 0", k))
   302  					}
   303  					return
   304  				},
   305  			},
   306  
   307  			"memory_swap": &schema.Schema{
   308  				Type:     schema.TypeInt,
   309  				Optional: true,
   310  				ForceNew: true,
   311  				ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
   312  					value := v.(int)
   313  					if value < -1 {
   314  						es = append(es, fmt.Errorf("%q must be greater than or equal to -1", k))
   315  					}
   316  					return
   317  				},
   318  			},
   319  
   320  			"cpu_shares": &schema.Schema{
   321  				Type:     schema.TypeInt,
   322  				Optional: true,
   323  				ForceNew: true,
   324  				ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
   325  					value := v.(int)
   326  					if value < 0 {
   327  						es = append(es, fmt.Errorf("%q must be greater than or equal to 0", k))
   328  					}
   329  					return
   330  				},
   331  			},
   332  
   333  			"log_driver": &schema.Schema{
   334  				Type:     schema.TypeString,
   335  				Optional: true,
   336  				ForceNew: true,
   337  				Default:  "json-file",
   338  				ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
   339  					value := v.(string)
   340  					if !regexp.MustCompile(`^(json-file|syslog|journald|gelf|fluentd)$`).MatchString(value) {
   341  						es = append(es, fmt.Errorf(
   342  							"%q must be one of \"json-file\", \"syslog\", \"journald\", \"gelf\", or \"fluentd\"", k))
   343  					}
   344  					return
   345  				},
   346  			},
   347  
   348  			"log_opts": &schema.Schema{
   349  				Type:     schema.TypeMap,
   350  				Optional: true,
   351  				ForceNew: true,
   352  			},
   353  
   354  			"network_mode": &schema.Schema{
   355  				Type:     schema.TypeString,
   356  				Optional: true,
   357  				ForceNew: true,
   358  			},
   359  
   360  			"networks": &schema.Schema{
   361  				Type:     schema.TypeSet,
   362  				Optional: true,
   363  				ForceNew: true,
   364  				Elem:     &schema.Schema{Type: schema.TypeString},
   365  				Set:      schema.HashString,
   366  			},
   367  		},
   368  	}
   369  }
   370  
   371  func resourceDockerPortsHash(v interface{}) int {
   372  	var buf bytes.Buffer
   373  	m := v.(map[string]interface{})
   374  
   375  	buf.WriteString(fmt.Sprintf("%v-", m["internal"].(int)))
   376  
   377  	if v, ok := m["external"]; ok {
   378  		buf.WriteString(fmt.Sprintf("%v-", v.(int)))
   379  	}
   380  
   381  	if v, ok := m["ip"]; ok {
   382  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   383  	}
   384  
   385  	if v, ok := m["protocol"]; ok {
   386  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   387  	}
   388  
   389  	return hashcode.String(buf.String())
   390  }
   391  
   392  func resourceDockerHostsHash(v interface{}) int {
   393  	var buf bytes.Buffer
   394  	m := v.(map[string]interface{})
   395  
   396  	if v, ok := m["ip"]; ok {
   397  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   398  	}
   399  
   400  	if v, ok := m["host"]; ok {
   401  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   402  	}
   403  
   404  	return hashcode.String(buf.String())
   405  }
   406  
   407  func resourceDockerVolumesHash(v interface{}) int {
   408  	var buf bytes.Buffer
   409  	m := v.(map[string]interface{})
   410  
   411  	if v, ok := m["from_container"]; ok {
   412  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   413  	}
   414  
   415  	if v, ok := m["container_path"]; ok {
   416  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   417  	}
   418  
   419  	if v, ok := m["host_path"]; ok {
   420  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   421  	}
   422  
   423  	if v, ok := m["volume_name"]; ok {
   424  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   425  	}
   426  
   427  	if v, ok := m["read_only"]; ok {
   428  		buf.WriteString(fmt.Sprintf("%v-", v.(bool)))
   429  	}
   430  
   431  	return hashcode.String(buf.String())
   432  }