github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/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 len(splitImageName) { 80 81 // It's in registry:port/username/repo:tag or registry:port/repo:tag format 82 case 3: 83 splitPortRepo := strings.Split(splitImageName[1], "/") 84 pullOpts.Registry = splitImageName[0] + ":" + splitPortRepo[0] 85 pullOpts.Tag = splitImageName[2] 86 pullOpts.Repository = pullOpts.Registry + "/" + strings.Join(splitPortRepo[1:], "/") 87 88 // It's either registry:port/username/repo, registry:port/repo, 89 // or repo:tag with default registry 90 case 2: 91 splitPortRepo := strings.Split(splitImageName[1], "/") 92 switch len(splitPortRepo) { 93 // repo:tag 94 case 1: 95 pullOpts.Repository = splitImageName[0] 96 pullOpts.Tag = splitImageName[1] 97 98 // registry:port/username/repo or registry:port/repo 99 default: 100 pullOpts.Registry = splitImageName[0] + ":" + splitPortRepo[0] 101 pullOpts.Repository = pullOpts.Registry + "/" + strings.Join(splitPortRepo[1:], "/") 102 pullOpts.Tag = "latest" 103 } 104 105 // Plain username/repo or repo 106 default: 107 pullOpts.Repository = image 108 } 109 110 if err := client.PullImage(pullOpts, dc.AuthConfiguration{}); err != nil { 111 return fmt.Errorf("Error pulling image %s: %s\n", image, err) 112 } 113 114 return fetchLocalImages(data, client) 115 } 116 117 func getImageTag(image string) string { 118 splitImageName := strings.Split(image, ":") 119 switch { 120 121 // It's in registry:port/repo:tag format 122 case len(splitImageName) == 3: 123 return splitImageName[2] 124 125 // It's either registry:port/repo or repo:tag with default registry 126 case len(splitImageName) == 2: 127 splitPortRepo := strings.Split(splitImageName[1], "/") 128 if len(splitPortRepo) == 2 { 129 return "" 130 } else { 131 return splitImageName[1] 132 } 133 } 134 135 return "" 136 } 137 138 func findImage(d *schema.ResourceData, client *dc.Client) (*dc.APIImages, error) { 139 var data Data 140 if err := fetchLocalImages(&data, client); err != nil { 141 return nil, err 142 } 143 144 imageName := d.Get("name").(string) 145 if imageName == "" { 146 return nil, fmt.Errorf("Empty image name is not allowed") 147 } 148 149 searchLocal := func() *dc.APIImages { 150 if apiImage, ok := data.DockerImages[imageName]; ok { 151 return apiImage 152 } 153 if apiImage, ok := data.DockerImages[imageName+":latest"]; ok { 154 imageName = imageName + ":latest" 155 return apiImage 156 } 157 return nil 158 } 159 160 foundImage := searchLocal() 161 162 if d.Get("keep_updated").(bool) || foundImage == nil { 163 if err := pullImage(&data, client, imageName); err != nil { 164 return nil, fmt.Errorf("Unable to pull image %s: %s", imageName, err) 165 } 166 } 167 168 foundImage = searchLocal() 169 if foundImage != nil { 170 return foundImage, nil 171 } 172 173 return nil, fmt.Errorf("Unable to find or pull image %s", imageName) 174 }