-
Notifications
You must be signed in to change notification settings - Fork 9.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial commit. This adds the initial bits of a Docker provider.
Docker's API is huge and only a small subset is currently implemented, but this is expected to grow over time. Currently it's enough to satisfy the use cases of probably 95% of Docker users. I'm preparing this initial pull request as a preview step for feedback. My ideal scenario would be to develop this within a branch in the main repository; the more eyes and testing and pitching in on the code, the better (this would avoid a merge request-to-the-merge-request scenario, as I figure this will be built up over the longer term, even before a merge into master). Unit tests do not exist yet. Right now I've just been focused on getting initial functionality ported over. I've been testing each option extensively via the Docker inspect capabilities. This code (C)2014-2015 Akamai Technologies, Inc. <opensource@akamai.com>
- Loading branch information
Jeff Mitchell
committed
Mar 10, 2015
1 parent
d2c6ae0
commit f7512ca
Showing
10 changed files
with
786 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package main | ||
|
||
import ( | ||
"github.com/hashicorp/terraform/builtin/providers/docker" | ||
"github.com/hashicorp/terraform/plugin" | ||
) | ||
|
||
func main() { | ||
plugin.Serve(&plugin.ServeOpts{ | ||
ProviderFunc: docker.Provider, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
package main |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package docker | ||
|
||
import dc "github.com/fsouza/go-dockerclient" | ||
|
||
type Config struct { | ||
DockerHost string | ||
SkipPull bool | ||
} | ||
|
||
type Data struct { | ||
DockerImages map[string]*dc.APIImages | ||
} | ||
|
||
// NewClient() returns a new Docker client. | ||
func (c *Config) NewClient() (*dc.Client, error) { | ||
return dc.NewClient(c.DockerHost) | ||
} | ||
|
||
// NewData() returns a new data struct. | ||
func (c *Config) NewData() *Data { | ||
return &Data{ | ||
DockerImages: map[string]*dc.APIImages{}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package docker | ||
|
||
import ( | ||
"github.com/hashicorp/terraform/helper/schema" | ||
"github.com/hashicorp/terraform/terraform" | ||
) | ||
|
||
func Provider() terraform.ResourceProvider { | ||
return &schema.Provider{ | ||
Schema: map[string]*schema.Schema{ | ||
"docker_host": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
DefaultFunc: schema.EnvDefaultFunc("DOCKER_HOST", "unix:/run/docker.sock"), | ||
Description: "The Docker daemon endpoint", | ||
}, | ||
}, | ||
|
||
ResourcesMap: map[string]*schema.Resource{ | ||
"docker_container": resourceDockerContainer(), | ||
"docker_image": resourceDockerImage(), | ||
}, | ||
|
||
ConfigureFunc: providerConfigure, | ||
} | ||
} | ||
|
||
func providerConfigure(d *schema.ResourceData) (interface{}, error) { | ||
config := Config{ | ||
DockerHost: d.Get("docker_host").(string), | ||
} | ||
|
||
return &config, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
package docker | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
|
||
"github.com/hashicorp/terraform/helper/hashcode" | ||
"github.com/hashicorp/terraform/helper/schema" | ||
) | ||
|
||
func resourceDockerContainer() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: resourceDockerContainerCreate, | ||
Read: resourceDockerContainerRead, | ||
Update: resourceDockerContainerUpdate, | ||
Delete: resourceDockerContainerDelete, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"name": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
|
||
// Indicates whether the container must be running. | ||
// | ||
// An assumption is made that configured containers | ||
// should be running; if not, they should not be in | ||
// the configuration. Therefore a stopped container | ||
// should be started. Set to false to have the | ||
// provider leave the container alone. | ||
// | ||
// Actively-debugged containers are likely to be | ||
// stopped and started manually, and Docker has | ||
// some provisions for restarting containers that | ||
// stop. The utility here comes from the fact that | ||
// this will delete and re-create the container | ||
// following the principle that the containers | ||
// should be pristine when started. | ||
"must_run": &schema.Schema{ | ||
Type: schema.TypeBool, | ||
Default: true, | ||
Optional: true, | ||
}, | ||
|
||
// ForceNew is not true for image because we need to | ||
// sane this against Docker image IDs, as each image | ||
// can have multiple names/tags attached do it. | ||
"image": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
|
||
"hostname": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Optional: true, | ||
ForceNew: true, | ||
}, | ||
|
||
"domainname": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Optional: true, | ||
ForceNew: true, | ||
}, | ||
|
||
"command": &schema.Schema{ | ||
Type: schema.TypeList, | ||
Optional: true, | ||
ForceNew: true, | ||
Elem: &schema.Schema{Type: schema.TypeString}, | ||
}, | ||
|
||
"dns": &schema.Schema{ | ||
Type: schema.TypeSet, | ||
Optional: true, | ||
ForceNew: true, | ||
Elem: &schema.Schema{Type: schema.TypeString}, | ||
Set: stringSetHash, | ||
}, | ||
|
||
"publish_all_ports": &schema.Schema{ | ||
Type: schema.TypeBool, | ||
Optional: true, | ||
ForceNew: true, | ||
}, | ||
|
||
"volumes": &schema.Schema{ | ||
Type: schema.TypeSet, | ||
Optional: true, | ||
ForceNew: true, | ||
Elem: getVolumesElem(), | ||
Set: resourceDockerVolumesHash, | ||
}, | ||
|
||
"ports": &schema.Schema{ | ||
Type: schema.TypeSet, | ||
Optional: true, | ||
ForceNew: true, | ||
Elem: getPortsElem(), | ||
Set: resourceDockerPortsHash, | ||
}, | ||
|
||
"env": &schema.Schema{ | ||
Type: schema.TypeSet, | ||
Optional: true, | ||
ForceNew: true, | ||
Elem: &schema.Schema{Type: schema.TypeString}, | ||
Set: stringSetHash, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func getVolumesElem() *schema.Resource { | ||
return &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"from_container": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Optional: true, | ||
ForceNew: true, | ||
}, | ||
|
||
"container_path": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Optional: true, | ||
ForceNew: true, | ||
}, | ||
|
||
"host_path": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Optional: true, | ||
ForceNew: true, | ||
}, | ||
|
||
"read_only": &schema.Schema{ | ||
Type: schema.TypeBool, | ||
Optional: true, | ||
ForceNew: true, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func getPortsElem() *schema.Resource { | ||
return &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"internal": &schema.Schema{ | ||
Type: schema.TypeInt, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
|
||
"external": &schema.Schema{ | ||
Type: schema.TypeInt, | ||
Optional: true, | ||
ForceNew: true, | ||
}, | ||
|
||
"ip": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Optional: true, | ||
ForceNew: true, | ||
}, | ||
|
||
"protocol": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Default: "tcp", | ||
Optional: true, | ||
ForceNew: true, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceDockerPortsHash(v interface{}) int { | ||
var buf bytes.Buffer | ||
m := v.(map[string]interface{}) | ||
|
||
buf.WriteString(fmt.Sprintf("%v-", m["internal"].(int))) | ||
|
||
if v, ok := m["external"]; ok { | ||
buf.WriteString(fmt.Sprintf("%v-", v.(int))) | ||
} | ||
|
||
if v, ok := m["ip"]; ok { | ||
buf.WriteString(fmt.Sprintf("%v-", v.(string))) | ||
} | ||
|
||
if v, ok := m["protocol"]; ok { | ||
buf.WriteString(fmt.Sprintf("%v-", v.(string))) | ||
} | ||
|
||
return hashcode.String(buf.String()) | ||
} | ||
|
||
func resourceDockerVolumesHash(v interface{}) int { | ||
var buf bytes.Buffer | ||
m := v.(map[string]interface{}) | ||
|
||
if v, ok := m["from_container"]; ok { | ||
buf.WriteString(fmt.Sprintf("%v-", v.(string))) | ||
} | ||
|
||
if v, ok := m["container_path"]; ok { | ||
buf.WriteString(fmt.Sprintf("%v-", v.(string))) | ||
} | ||
|
||
if v, ok := m["host_path"]; ok { | ||
buf.WriteString(fmt.Sprintf("%v-", v.(string))) | ||
} | ||
|
||
if v, ok := m["read_only"]; ok { | ||
buf.WriteString(fmt.Sprintf("%v-", v.(bool))) | ||
} | ||
|
||
return hashcode.String(buf.String()) | ||
} | ||
|
||
func stringSetHash(v interface{}) int { | ||
return hashcode.String(v.(string)) | ||
} |
Oops, something went wrong.