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