github.com/minamijoyo/terraform@v0.7.8-0.20161029001309-18b3736ba44b/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  							Required: true,
   233  							ForceNew: true,
   234  						},
   235  
   236  						"host": &schema.Schema{
   237  							Type:     schema.TypeString,
   238  							Required: 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  			"destroy_grace_seconds": &schema.Schema{
   289  				Type:     schema.TypeInt,
   290  				Optional: true,
   291  			},
   292  
   293  			"labels": &schema.Schema{
   294  				Type:     schema.TypeMap,
   295  				Optional: true,
   296  				ForceNew: true,
   297  			},
   298  
   299  			"memory": &schema.Schema{
   300  				Type:     schema.TypeInt,
   301  				Optional: true,
   302  				ForceNew: true,
   303  				ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
   304  					value := v.(int)
   305  					if value < 0 {
   306  						es = append(es, fmt.Errorf("%q must be greater than or equal to 0", k))
   307  					}
   308  					return
   309  				},
   310  			},
   311  
   312  			"memory_swap": &schema.Schema{
   313  				Type:     schema.TypeInt,
   314  				Optional: true,
   315  				ForceNew: true,
   316  				ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
   317  					value := v.(int)
   318  					if value < -1 {
   319  						es = append(es, fmt.Errorf("%q must be greater than or equal to -1", k))
   320  					}
   321  					return
   322  				},
   323  			},
   324  
   325  			"cpu_shares": &schema.Schema{
   326  				Type:     schema.TypeInt,
   327  				Optional: true,
   328  				ForceNew: true,
   329  				ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
   330  					value := v.(int)
   331  					if value < 0 {
   332  						es = append(es, fmt.Errorf("%q must be greater than or equal to 0", k))
   333  					}
   334  					return
   335  				},
   336  			},
   337  
   338  			"log_driver": &schema.Schema{
   339  				Type:     schema.TypeString,
   340  				Optional: true,
   341  				ForceNew: true,
   342  				Default:  "json-file",
   343  				ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
   344  					value := v.(string)
   345  					if !regexp.MustCompile(`^(json-file|syslog|journald|gelf|fluentd)$`).MatchString(value) {
   346  						es = append(es, fmt.Errorf(
   347  							"%q must be one of \"json-file\", \"syslog\", \"journald\", \"gelf\", or \"fluentd\"", k))
   348  					}
   349  					return
   350  				},
   351  			},
   352  
   353  			"log_opts": &schema.Schema{
   354  				Type:     schema.TypeMap,
   355  				Optional: true,
   356  				ForceNew: true,
   357  			},
   358  
   359  			"network_mode": &schema.Schema{
   360  				Type:     schema.TypeString,
   361  				Optional: true,
   362  				ForceNew: true,
   363  			},
   364  
   365  			"networks": &schema.Schema{
   366  				Type:     schema.TypeSet,
   367  				Optional: true,
   368  				ForceNew: true,
   369  				Elem:     &schema.Schema{Type: schema.TypeString},
   370  				Set:      schema.HashString,
   371  			},
   372  		},
   373  	}
   374  }
   375  
   376  func resourceDockerPortsHash(v interface{}) int {
   377  	var buf bytes.Buffer
   378  	m := v.(map[string]interface{})
   379  
   380  	buf.WriteString(fmt.Sprintf("%v-", m["internal"].(int)))
   381  
   382  	if v, ok := m["external"]; ok {
   383  		buf.WriteString(fmt.Sprintf("%v-", v.(int)))
   384  	}
   385  
   386  	if v, ok := m["ip"]; ok {
   387  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   388  	}
   389  
   390  	if v, ok := m["protocol"]; ok {
   391  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   392  	}
   393  
   394  	return hashcode.String(buf.String())
   395  }
   396  
   397  func resourceDockerHostsHash(v interface{}) int {
   398  	var buf bytes.Buffer
   399  	m := v.(map[string]interface{})
   400  
   401  	if v, ok := m["ip"]; ok {
   402  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   403  	}
   404  
   405  	if v, ok := m["host"]; ok {
   406  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   407  	}
   408  
   409  	return hashcode.String(buf.String())
   410  }
   411  
   412  func resourceDockerVolumesHash(v interface{}) int {
   413  	var buf bytes.Buffer
   414  	m := v.(map[string]interface{})
   415  
   416  	if v, ok := m["from_container"]; ok {
   417  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   418  	}
   419  
   420  	if v, ok := m["container_path"]; ok {
   421  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   422  	}
   423  
   424  	if v, ok := m["host_path"]; ok {
   425  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   426  	}
   427  
   428  	if v, ok := m["volume_name"]; ok {
   429  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   430  	}
   431  
   432  	if v, ok := m["read_only"]; ok {
   433  		buf.WriteString(fmt.Sprintf("%v-", v.(bool)))
   434  	}
   435  
   436  	return hashcode.String(buf.String())
   437  }