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  }