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