github.com/leeprovoost/terraform@v0.6.10-0.20160119085442-96f3f76118e7/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 }