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 }