github.com/gabrielperezs/terraform@v0.7.0-rc2.0.20160715084931-f7da2612946f/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  	client := meta.(*dc.Client)
    45  	err := removeImage(d, client)
    46  	if err != nil {
    47  		return fmt.Errorf("Unable to remove Docker image: %s", err)
    48  	}
    49  	d.SetId("")
    50  	return nil
    51  }
    52  
    53  func searchLocalImages(data Data, imageName string) *dc.APIImages {
    54  	if apiImage, ok := data.DockerImages[imageName]; ok {
    55  		return apiImage
    56  	}
    57  	if apiImage, ok := data.DockerImages[imageName+":latest"]; ok {
    58  		imageName = imageName + ":latest"
    59  		return apiImage
    60  	}
    61  	return nil
    62  }
    63  
    64  func removeImage(d *schema.ResourceData, client *dc.Client) error {
    65  	var data Data
    66  
    67  	if keepLocally := d.Get("keep_locally").(bool); keepLocally {
    68  		return nil
    69  	}
    70  
    71  	if err := fetchLocalImages(&data, client); err != nil {
    72  		return err
    73  	}
    74  
    75  	imageName := d.Get("name").(string)
    76  	if imageName == "" {
    77  		return fmt.Errorf("Empty image name is not allowed")
    78  	}
    79  
    80  	foundImage := searchLocalImages(data, imageName)
    81  
    82  	if foundImage != nil {
    83  		err := client.RemoveImage(foundImage.ID)
    84  		if err != nil {
    85  			return err
    86  		}
    87  	}
    88  
    89  	return nil
    90  }
    91  
    92  func fetchLocalImages(data *Data, client *dc.Client) error {
    93  	images, err := client.ListImages(dc.ListImagesOptions{All: false})
    94  	if err != nil {
    95  		return fmt.Errorf("Unable to list Docker images: %s", err)
    96  	}
    97  
    98  	if data.DockerImages == nil {
    99  		data.DockerImages = make(map[string]*dc.APIImages)
   100  	}
   101  
   102  	// Docker uses different nomenclatures in different places...sometimes a short
   103  	// ID, sometimes long, etc. So we store both in the map so we can always find
   104  	// the same image object. We store the tags, too.
   105  	for i, image := range images {
   106  		data.DockerImages[image.ID[:12]] = &images[i]
   107  		data.DockerImages[image.ID] = &images[i]
   108  		for _, repotag := range image.RepoTags {
   109  			data.DockerImages[repotag] = &images[i]
   110  		}
   111  	}
   112  
   113  	return nil
   114  }
   115  
   116  func pullImage(data *Data, client *dc.Client, image string) error {
   117  	// TODO: Test local registry handling. It should be working
   118  	// based on the code that was ported over
   119  
   120  	pullOpts := dc.PullImageOptions{}
   121  
   122  	splitImageName := strings.Split(image, ":")
   123  	switch len(splitImageName) {
   124  
   125  	// It's in registry:port/username/repo:tag or registry:port/repo:tag format
   126  	case 3:
   127  		splitPortRepo := strings.Split(splitImageName[1], "/")
   128  		pullOpts.Registry = splitImageName[0] + ":" + splitPortRepo[0]
   129  		pullOpts.Tag = splitImageName[2]
   130  		pullOpts.Repository = pullOpts.Registry + "/" + strings.Join(splitPortRepo[1:], "/")
   131  
   132  	// It's either registry:port/username/repo, registry:port/repo,
   133  	// or repo:tag with default registry
   134  	case 2:
   135  		splitPortRepo := strings.Split(splitImageName[1], "/")
   136  		switch len(splitPortRepo) {
   137  		// repo:tag
   138  		case 1:
   139  			pullOpts.Repository = splitImageName[0]
   140  			pullOpts.Tag = splitImageName[1]
   141  
   142  		// registry:port/username/repo or registry:port/repo
   143  		default:
   144  			pullOpts.Registry = splitImageName[0] + ":" + splitPortRepo[0]
   145  			pullOpts.Repository = pullOpts.Registry + "/" + strings.Join(splitPortRepo[1:], "/")
   146  			pullOpts.Tag = "latest"
   147  		}
   148  
   149  	// Plain username/repo or repo
   150  	default:
   151  		pullOpts.Repository = image
   152  	}
   153  
   154  	if err := client.PullImage(pullOpts, dc.AuthConfiguration{}); err != nil {
   155  		return fmt.Errorf("Error pulling image %s: %s\n", image, err)
   156  	}
   157  
   158  	return fetchLocalImages(data, client)
   159  }
   160  
   161  func getImageTag(image string) string {
   162  	splitImageName := strings.Split(image, ":")
   163  	switch {
   164  
   165  	// It's in registry:port/repo:tag format
   166  	case len(splitImageName) == 3:
   167  		return splitImageName[2]
   168  
   169  	// It's either registry:port/repo or repo:tag with default registry
   170  	case len(splitImageName) == 2:
   171  		splitPortRepo := strings.Split(splitImageName[1], "/")
   172  		if len(splitPortRepo) == 2 {
   173  			return ""
   174  		} else {
   175  			return splitImageName[1]
   176  		}
   177  	}
   178  
   179  	return ""
   180  }
   181  
   182  func findImage(d *schema.ResourceData, client *dc.Client) (*dc.APIImages, error) {
   183  	var data Data
   184  	if err := fetchLocalImages(&data, client); err != nil {
   185  		return nil, err
   186  	}
   187  
   188  	imageName := d.Get("name").(string)
   189  	if imageName == "" {
   190  		return nil, fmt.Errorf("Empty image name is not allowed")
   191  	}
   192  
   193  	foundImage := searchLocalImages(data, imageName)
   194  
   195  	if d.Get("keep_updated").(bool) || foundImage == nil {
   196  		if err := pullImage(&data, client, imageName); err != nil {
   197  			return nil, fmt.Errorf("Unable to pull image %s: %s", imageName, err)
   198  		}
   199  	}
   200  
   201  	foundImage = searchLocalImages(data, imageName)
   202  	if foundImage != nil {
   203  		return foundImage, nil
   204  	}
   205  
   206  	return nil, fmt.Errorf("Unable to find or pull image %s", imageName)
   207  }