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 }