github.com/tarrant/terraform@v0.3.8-0.20150402012457-f68c9eee638e/builtin/providers/docker/resource_docker_image_funcs.go (about)

     1  package docker
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	dc "github.com/fsouza/go-dockerclient"
     8  	"github.com/hashicorp/terraform/helper/schema"
     9  )
    10  
    11  func resourceDockerImageCreate(d *schema.ResourceData, meta interface{}) error {
    12  	client := meta.(*dc.Client)
    13  	apiImage, err := findImage(d, client)
    14  	if err != nil {
    15  		return fmt.Errorf("Unable to read Docker image into resource: %s", err)
    16  	}
    17  
    18  	d.SetId(apiImage.ID + d.Get("name").(string))
    19  	d.Set("latest", apiImage.ID)
    20  
    21  	return nil
    22  }
    23  
    24  func resourceDockerImageRead(d *schema.ResourceData, meta interface{}) error {
    25  	client := meta.(*dc.Client)
    26  	apiImage, err := findImage(d, client)
    27  	if err != nil {
    28  		return fmt.Errorf("Unable to read Docker image into resource: %s", err)
    29  	}
    30  
    31  	d.Set("latest", apiImage.ID)
    32  
    33  	return nil
    34  }
    35  
    36  func resourceDockerImageUpdate(d *schema.ResourceData, meta interface{}) error {
    37  	// We need to re-read in case switching parameters affects
    38  	// the value of "latest" or others
    39  
    40  	return resourceDockerImageRead(d, meta)
    41  }
    42  
    43  func resourceDockerImageDelete(d *schema.ResourceData, meta interface{}) error {
    44  	d.SetId("")
    45  	return nil
    46  }
    47  
    48  func fetchLocalImages(data *Data, client *dc.Client) error {
    49  	images, err := client.ListImages(dc.ListImagesOptions{All: false})
    50  	if err != nil {
    51  		return fmt.Errorf("Unable to list Docker images: %s", err)
    52  	}
    53  
    54  	if data.DockerImages == nil {
    55  		data.DockerImages = make(map[string]*dc.APIImages)
    56  	}
    57  
    58  	// Docker uses different nomenclatures in different places...sometimes a short
    59  	// ID, sometimes long, etc. So we store both in the map so we can always find
    60  	// the same image object. We store the tags, too.
    61  	for i, image := range images {
    62  		data.DockerImages[image.ID[:12]] = &images[i]
    63  		data.DockerImages[image.ID] = &images[i]
    64  		for _, repotag := range image.RepoTags {
    65  			data.DockerImages[repotag] = &images[i]
    66  		}
    67  	}
    68  
    69  	return nil
    70  }
    71  
    72  func pullImage(data *Data, client *dc.Client, image string) error {
    73  	// TODO: Test local registry handling. It should be working
    74  	// based on the code that was ported over
    75  
    76  	pullOpts := dc.PullImageOptions{}
    77  
    78  	splitImageName := strings.Split(image, ":")
    79  	switch {
    80  
    81  	// It's in registry:port/repo:tag format
    82  	case len(splitImageName) == 3:
    83  		splitPortRepo := strings.Split(splitImageName[1], "/")
    84  		pullOpts.Registry = splitImageName[0] + ":" + splitPortRepo[0]
    85  		pullOpts.Repository = splitPortRepo[1]
    86  		pullOpts.Tag = splitImageName[2]
    87  
    88  	// It's either registry:port/repo or repo:tag with default registry
    89  	case len(splitImageName) == 2:
    90  		splitPortRepo := strings.Split(splitImageName[1], "/")
    91  		switch len(splitPortRepo) {
    92  
    93  		// registry:port/repo
    94  		case 2:
    95  			pullOpts.Registry = splitImageName[0] + ":" + splitPortRepo[0]
    96  			pullOpts.Repository = splitPortRepo[1]
    97  			pullOpts.Tag = "latest"
    98  
    99  		// repo:tag
   100  		case 1:
   101  			pullOpts.Repository = splitImageName[0]
   102  			pullOpts.Tag = splitImageName[1]
   103  		}
   104  
   105  	default:
   106  		pullOpts.Repository = image
   107  	}
   108  
   109  	if err := client.PullImage(pullOpts, dc.AuthConfiguration{}); err != nil {
   110  		return fmt.Errorf("Error pulling image %s: %s\n", image, err)
   111  	}
   112  
   113  	return fetchLocalImages(data, client)
   114  }
   115  
   116  func getImageTag(image string) string {
   117  	splitImageName := strings.Split(image, ":")
   118  	switch {
   119  
   120  	// It's in registry:port/repo:tag format
   121  	case len(splitImageName) == 3:
   122  		return splitImageName[2]
   123  
   124  	// It's either registry:port/repo or repo:tag with default registry
   125  	case len(splitImageName) == 2:
   126  		splitPortRepo := strings.Split(splitImageName[1], "/")
   127  		if len(splitPortRepo) == 2 {
   128  			return ""
   129  		} else {
   130  			return splitImageName[1]
   131  		}
   132  	}
   133  
   134  	return ""
   135  }
   136  
   137  func findImage(d *schema.ResourceData, client *dc.Client) (*dc.APIImages, error) {
   138  	var data Data
   139  	if err := fetchLocalImages(&data, client); err != nil {
   140  		return nil, err
   141  	}
   142  
   143  	imageName := d.Get("name").(string)
   144  	if imageName == "" {
   145  		return nil, fmt.Errorf("Empty image name is not allowed")
   146  	}
   147  
   148  	searchLocal := func() *dc.APIImages {
   149  		if apiImage, ok := data.DockerImages[imageName]; ok {
   150  			return apiImage
   151  		}
   152  		if apiImage, ok := data.DockerImages[imageName+":latest"]; ok {
   153  			imageName = imageName + ":latest"
   154  			return apiImage
   155  		}
   156  		return nil
   157  	}
   158  
   159  	foundImage := searchLocal()
   160  
   161  	if d.Get("keep_updated").(bool) || foundImage == nil {
   162  		if err := pullImage(&data, client, imageName); err != nil {
   163  			return nil, fmt.Errorf("Unable to pull image %s: %s", imageName, err)
   164  		}
   165  	}
   166  
   167  	foundImage = searchLocal()
   168  	if foundImage != nil {
   169  		return foundImage, nil
   170  	}
   171  
   172  	return nil, fmt.Errorf("Unable to find or pull image %s", imageName)
   173  }