Skip to content

Commit

Permalink
provider/docker: added docker_image data source
Browse files Browse the repository at this point in the history
  • Loading branch information
kyhavlov committed Jun 3, 2016
1 parent 07b7e75 commit e39435a
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 9 deletions.
70 changes: 70 additions & 0 deletions builtin/providers/docker/data_source_docker_image.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package docker

import (
"encoding/json"
"fmt"
"strings"

"github.com/hashicorp/terraform/helper/schema"
"github.com/heroku/docker-registry-client/registry"
)

func dataSourceDockerImage() *schema.Resource {
return &schema.Resource{
Read: dataSourceDockerImageRead,

Schema: map[string]*schema.Schema{
"name": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},

"id": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
},
}
}

func dataSourceDockerImageRead(d *schema.ResourceData, meta interface{}) error {
pullOpts := parseImageOptions(d.Get("name").(string))
auth := getAuthConfig(pullOpts)

// Use the official Docker Hub if a registry isn't specified
if pullOpts.Registry == "" {
pullOpts.Registry = "registry.hub.docker.com"
} else {
pullOpts.Repository = strings.Replace(pullOpts.Repository, pullOpts.Registry+"/", "", 1)
}

// The docker registry prefixes 'library' to official images in the path; 'consul' becomes 'library/consul'
if !strings.Contains(pullOpts.Repository, "/") {
pullOpts.Repository = "library/" + pullOpts.Repository
}

url := "https://" + pullOpts.Registry
username := auth.Username
password := auth.Password
hub, err := registry.New(url, username, password)

if err != nil {
return fmt.Errorf("Error connecting to registry: %v", err)
}

manifest, err := hub.Manifest(pullOpts.Repository, pullOpts.Tag)
if err != nil {
return fmt.Errorf("Error getting manifest for image: %v", err)
}

m := map[string]interface{}{}
err = json.Unmarshal([]byte(manifest.History[0].V1Compatibility), &m)
if err != nil {
return fmt.Errorf("Error parsing manifest for image %s: %v", d.Get("name").(string), err)
}

d.SetId(m["id"].(string))
d.Set("id", m["id"].(string))

return nil
}
4 changes: 4 additions & 0 deletions builtin/providers/docker/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ func Provider() terraform.ResourceProvider {
"docker_volume": resourceDockerVolume(),
},

DataSourcesMap: map[string]*schema.Resource{
"docker_image": dataSourceDockerImage(),
},

ConfigureFunc: providerConfigure,
}
}
Expand Down
6 changes: 6 additions & 0 deletions builtin/providers/docker/resource_docker_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ func resourceDockerImage() *schema.Resource {
Required: true,
},

"registry_id": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},

"keep_updated": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Expand Down
48 changes: 39 additions & 9 deletions builtin/providers/docker/resource_docker_image_funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package docker

import (
"fmt"
"log"
"strings"

dc "github.com/fsouza/go-dockerclient"
Expand All @@ -10,7 +11,7 @@ import (

func resourceDockerImageCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*dc.Client)
apiImage, err := findImage(d, client)
apiImage, err := findImage(d, client, true)
if err != nil {
return fmt.Errorf("Unable to read Docker image into resource: %s", err)
}
Expand All @@ -23,7 +24,7 @@ func resourceDockerImageCreate(d *schema.ResourceData, meta interface{}) error {

func resourceDockerImageRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*dc.Client)
apiImage, err := findImage(d, client)
apiImage, err := findImage(d, client, false)
if err != nil {
return fmt.Errorf("Unable to read Docker image into resource: %s", err)
}
Expand All @@ -36,8 +37,15 @@ func resourceDockerImageRead(d *schema.ResourceData, meta interface{}) error {
func resourceDockerImageUpdate(d *schema.ResourceData, meta interface{}) error {
// We need to re-read in case switching parameters affects
// the value of "latest" or others
client := meta.(*dc.Client)
apiImage, err := findImage(d, client, true)
if err != nil {
return fmt.Errorf("Unable to read Docker image into resource: %s", err)
}

d.Set("latest", apiImage.ID)

return resourceDockerImageRead(d, meta)
return nil
}

func resourceDockerImageDelete(d *schema.ResourceData, meta interface{}) error {
Expand Down Expand Up @@ -117,6 +125,16 @@ func pullImage(data *Data, client *dc.Client, image string) error {
// TODO: Test local registry handling. It should be working
// based on the code that was ported over

pullOpts := parseImageOptions(image)

if err := client.PullImage(pullOpts, getAuthConfig(pullOpts)); err != nil {
return fmt.Errorf("Error pulling image %s: %s\n", image, err)
}

return fetchLocalImages(data, client)
}

func parseImageOptions(image string) dc.PullImageOptions {
pullOpts := dc.PullImageOptions{}

splitImageName := strings.Split(image, ":")
Expand Down Expand Up @@ -151,11 +169,21 @@ func pullImage(data *Data, client *dc.Client, image string) error {
pullOpts.Repository = image
}

if err := client.PullImage(pullOpts, dc.AuthConfiguration{}); err != nil {
return fmt.Errorf("Error pulling image %s: %s\n", image, err)
return pullOpts
}

func getAuthConfig(pullOpts dc.PullImageOptions) dc.AuthConfiguration {
log.Printf("[DEBUG] Registry: %s", pullOpts.Registry)
auth := dc.AuthConfiguration{}

if pullOpts.Registry != "" {
auths, _ := dc.NewAuthConfigurationsFromDockerCfg()
if auths != nil {
auth = auths.Configs["https://"+pullOpts.Registry]
}
}

return fetchLocalImages(data, client)
return auth
}

func getImageTag(image string) string {
Expand All @@ -179,7 +207,7 @@ func getImageTag(image string) string {
return ""
}

func findImage(d *schema.ResourceData, client *dc.Client) (*dc.APIImages, error) {
func findImage(d *schema.ResourceData, client *dc.Client, doPull bool) (*dc.APIImages, error) {
var data Data
if err := fetchLocalImages(&data, client); err != nil {
return nil, err
Expand All @@ -193,8 +221,10 @@ func findImage(d *schema.ResourceData, client *dc.Client) (*dc.APIImages, error)
foundImage := searchLocalImages(data, imageName)

if d.Get("keep_updated").(bool) || foundImage == nil {
if err := pullImage(&data, client, imageName); err != nil {
return nil, fmt.Errorf("Unable to pull image %s: %s", imageName, err)
if doPull {
if err := pullImage(&data, client, imageName); err != nil {
return nil, fmt.Errorf("Unable to pull image %s: %s", imageName, err)
}
}
}

Expand Down

0 comments on commit e39435a

Please sign in to comment.