github.com/gwilym/terraform@v0.3.8-0.20151231151641-c7573de75b19/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:     getVolumesElem(),
   123  				Set:      resourceDockerVolumesHash,
   124  			},
   125  
   126  			"ports": &schema.Schema{
   127  				Type:     schema.TypeSet,
   128  				Optional: true,
   129  				ForceNew: true,
   130  				Elem:     getPortsElem(),
   131  				Set:      resourceDockerPortsHash,
   132  			},
   133  
   134  			"env": &schema.Schema{
   135  				Type:     schema.TypeSet,
   136  				Optional: true,
   137  				ForceNew: true,
   138  				Elem:     &schema.Schema{Type: schema.TypeString},
   139  				Set:      stringSetHash,
   140  			},
   141  
   142  			"links": &schema.Schema{
   143  				Type:     schema.TypeSet,
   144  				Optional: true,
   145  				ForceNew: true,
   146  				Elem:     &schema.Schema{Type: schema.TypeString},
   147  				Set:      stringSetHash,
   148  			},
   149  
   150  			"ip_address": &schema.Schema{
   151  				Type:     schema.TypeString,
   152  				Computed: true,
   153  			},
   154  
   155  			"ip_prefix_length": &schema.Schema{
   156  				Type:     schema.TypeInt,
   157  				Computed: true,
   158  			},
   159  
   160  			"gateway": &schema.Schema{
   161  				Type:     schema.TypeString,
   162  				Computed: true,
   163  			},
   164  
   165  			"bridge": &schema.Schema{
   166  				Type:     schema.TypeString,
   167  				Computed: true,
   168  			},
   169  
   170  			"privileged": &schema.Schema{
   171  				Type:     schema.TypeBool,
   172  				Optional: true,
   173  				ForceNew: true,
   174  			},
   175  
   176  			"labels": &schema.Schema{
   177  				Type:     schema.TypeMap,
   178  				Optional: true,
   179  				ForceNew: true,
   180  			},
   181  
   182  			"memory": &schema.Schema{
   183  				Type:     schema.TypeInt,
   184  				Optional: true,
   185  				ForceNew: true,
   186  				ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
   187  					value := v.(int)
   188  					if value < 0 {
   189  						es = append(es, fmt.Errorf("%q must be greater than or equal to 0", k))
   190  					}
   191  					return
   192  				},
   193  			},
   194  
   195  			"memory_swap": &schema.Schema{
   196  				Type:     schema.TypeInt,
   197  				Optional: true,
   198  				ForceNew: true,
   199  				ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
   200  					value := v.(int)
   201  					if value < -1 {
   202  						es = append(es, fmt.Errorf("%q must be greater than or equal to -1", k))
   203  					}
   204  					return
   205  				},
   206  			},
   207  
   208  			"cpu_shares": &schema.Schema{
   209  				Type:     schema.TypeInt,
   210  				Optional: true,
   211  				ForceNew: true,
   212  				ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
   213  					value := v.(int)
   214  					if value < 0 {
   215  						es = append(es, fmt.Errorf("%q must be greater than or equal to 0", k))
   216  					}
   217  					return
   218  				},
   219  			},
   220  
   221  			"log_driver": &schema.Schema{
   222  				Type:     schema.TypeString,
   223  				Optional: true,
   224  				ForceNew: true,
   225  				Default:  "json-file",
   226  				ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
   227  					value := v.(string)
   228  					if !regexp.MustCompile(`^(json-file|syslog|journald|gelf|fluentd)$`).MatchString(value) {
   229  						es = append(es, fmt.Errorf(
   230  							"%q must be one of \"json-file\", \"syslog\", \"journald\", \"gelf\", or \"fluentd\"", k))
   231  					}
   232  					return
   233  				},
   234  			},
   235  
   236  			"log_opts": &schema.Schema{
   237  				Type:     schema.TypeMap,
   238  				Optional: true,
   239  				ForceNew: true,
   240  			},
   241  		},
   242  	}
   243  }
   244  
   245  func getVolumesElem() *schema.Resource {
   246  	return &schema.Resource{
   247  		Schema: map[string]*schema.Schema{
   248  			"from_container": &schema.Schema{
   249  				Type:     schema.TypeString,
   250  				Optional: true,
   251  				ForceNew: true,
   252  			},
   253  
   254  			"container_path": &schema.Schema{
   255  				Type:     schema.TypeString,
   256  				Optional: true,
   257  				ForceNew: true,
   258  			},
   259  
   260  			"host_path": &schema.Schema{
   261  				Type:     schema.TypeString,
   262  				Optional: true,
   263  				ForceNew: true,
   264  			},
   265  
   266  			"read_only": &schema.Schema{
   267  				Type:     schema.TypeBool,
   268  				Optional: true,
   269  				ForceNew: true,
   270  			},
   271  		},
   272  	}
   273  }
   274  
   275  func getPortsElem() *schema.Resource {
   276  	return &schema.Resource{
   277  		Schema: map[string]*schema.Schema{
   278  			"internal": &schema.Schema{
   279  				Type:     schema.TypeInt,
   280  				Required: true,
   281  				ForceNew: true,
   282  			},
   283  
   284  			"external": &schema.Schema{
   285  				Type:     schema.TypeInt,
   286  				Optional: true,
   287  				ForceNew: true,
   288  			},
   289  
   290  			"ip": &schema.Schema{
   291  				Type:     schema.TypeString,
   292  				Optional: true,
   293  				ForceNew: true,
   294  			},
   295  
   296  			"protocol": &schema.Schema{
   297  				Type:     schema.TypeString,
   298  				Default:  "tcp",
   299  				Optional: true,
   300  				ForceNew: true,
   301  			},
   302  		},
   303  	}
   304  }
   305  
   306  func resourceDockerPortsHash(v interface{}) int {
   307  	var buf bytes.Buffer
   308  	m := v.(map[string]interface{})
   309  
   310  	buf.WriteString(fmt.Sprintf("%v-", m["internal"].(int)))
   311  
   312  	if v, ok := m["external"]; ok {
   313  		buf.WriteString(fmt.Sprintf("%v-", v.(int)))
   314  	}
   315  
   316  	if v, ok := m["ip"]; ok {
   317  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   318  	}
   319  
   320  	if v, ok := m["protocol"]; ok {
   321  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   322  	}
   323  
   324  	return hashcode.String(buf.String())
   325  }
   326  
   327  func resourceDockerVolumesHash(v interface{}) int {
   328  	var buf bytes.Buffer
   329  	m := v.(map[string]interface{})
   330  
   331  	if v, ok := m["from_container"]; ok {
   332  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   333  	}
   334  
   335  	if v, ok := m["container_path"]; ok {
   336  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   337  	}
   338  
   339  	if v, ok := m["host_path"]; ok {
   340  		buf.WriteString(fmt.Sprintf("%v-", v.(string)))
   341  	}
   342  
   343  	if v, ok := m["read_only"]; ok {
   344  		buf.WriteString(fmt.Sprintf("%v-", v.(bool)))
   345  	}
   346  
   347  	return hashcode.String(buf.String())
   348  }
   349  
   350  func stringSetHash(v interface{}) int {
   351  	return hashcode.String(v.(string))
   352  }