github.com/mwhudson/juju@v0.0.0-20160512215208-90ff01f3497f/container/image.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package container 5 6 import ( 7 "fmt" 8 "os" 9 "os/exec" 10 "path" 11 "strings" 12 13 "github.com/juju/errors" 14 15 "github.com/juju/juju/instance" 16 ) 17 18 // ImageURLGetter implementations provide a getter which returns a URL which 19 // can be used to fetch an image blob. 20 type ImageURLGetter interface { 21 // ImageURL returns a URL which can be used to fetch an image of the 22 // specified kind, series, and arch. 23 ImageURL(kind instance.ContainerType, series, arch string) (string, error) 24 25 // CACert returns the ca certificate used to validate the controller 26 // certificate when using wget. 27 CACert() []byte 28 } 29 30 type ImageURLGetterConfig struct { 31 ServerRoot string 32 ModelUUID string 33 CACert []byte 34 CloudimgBaseUrl string 35 Stream string 36 ImageDownloadFunc func(kind instance.ContainerType, series, arch, stream, cloudimgBaseUrl string) (string, error) 37 } 38 39 type imageURLGetter struct { 40 config ImageURLGetterConfig 41 } 42 43 // NewImageURLGetter returns an ImageURLGetter for the specified state 44 // server address and environment UUID. 45 func NewImageURLGetter(config ImageURLGetterConfig) ImageURLGetter { 46 return &imageURLGetter{config} 47 } 48 49 // ImageURL is specified on the NewImageURLGetter interface. 50 func (ug *imageURLGetter) ImageURL(kind instance.ContainerType, series, arch string) (string, error) { 51 imageURL, err := ug.config.ImageDownloadFunc(kind, series, arch, ug.config.Stream, ug.config.CloudimgBaseUrl) 52 if err != nil { 53 return "", errors.Annotatef(err, "cannot determine LXC image URL: %v", err) 54 } 55 imageFilename := path.Base(imageURL) 56 57 imageUrl := fmt.Sprintf( 58 "https://%s/model/%s/images/%v/%s/%s/%s", ug.config.ServerRoot, ug.config.ModelUUID, kind, series, arch, imageFilename, 59 ) 60 return imageUrl, nil 61 } 62 63 // CACert is specified on the NewImageURLGetter interface. 64 func (ug *imageURLGetter) CACert() []byte { 65 return ug.config.CACert 66 } 67 68 // ImageDownloadURL determines the public URL which can be used to obtain an 69 // image blob with the specified parameters. 70 func ImageDownloadURL(kind instance.ContainerType, series, arch, stream, cloudimgBaseUrl string) (string, error) { 71 // TODO - we currently only need to support LXC images - kind is ignored. 72 if kind != instance.LXC { 73 return "", errors.Errorf("unsupported container type: %v", kind) 74 } 75 76 // Use the ubuntu-cloudimg-query command to get the url from which to fetch the image. 77 // This will be somewhere on http://cloud-images.ubuntu.com. 78 cmd := exec.Command("ubuntu-cloudimg-query", series, stream, arch, "--format", "%{url}") 79 if cloudimgBaseUrl != "" { 80 // If the base url isn't specified, we don't need to copy the current 81 // environment, because this is the default behaviour of the exec package. 82 cmd.Env = append(os.Environ(), fmt.Sprintf("UBUNTU_CLOUDIMG_QUERY_BASEURL=%s", cloudimgBaseUrl)) 83 } 84 urlBytes, err := cmd.CombinedOutput() 85 if err != nil { 86 stderr := string(urlBytes) 87 return "", errors.Annotatef(err, "cannot determine LXC image URL: %v", stderr) 88 } 89 logger.Debugf("%s image for %s (%s) is %s", kind, series, arch, urlBytes) 90 imageURL := strings.Replace(string(urlBytes), ".tar.gz", "-root.tar.gz", -1) 91 return imageURL, nil 92 }