github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/tools/lxdclient/remote.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  // +build go1.3
     5  
     6  package lxdclient
     7  
     8  import (
     9  	"github.com/juju/errors"
    10  	lxdshared "github.com/lxc/lxd/shared"
    11  )
    12  
    13  const (
    14  	// remoteLocalName is a specific remote name in the default LXD config.
    15  	// See https://github.com/lxc/lxd/blob/master/config.go:DefaultRemotes.
    16  	remoteLocalName  = "local"
    17  	remoteIDForLocal = remoteLocalName
    18  )
    19  
    20  // Local is LXD's default "remote". Essentially it is an unencrypted,
    21  // unauthenticated connection to localhost over a unix socket.
    22  // However it does require users to be in the lxd group.
    23  var Local = Remote{
    24  	Name: remoteLocalName,
    25  	Host: "", // If Host is empty we will translate it into the local Unix socket
    26  	// No certificates are used when connecting to the Unix socket
    27  	Protocol:      LXDProtocol,
    28  	Cert:          nil,
    29  	ServerPEMCert: "",
    30  }
    31  
    32  type Protocol string
    33  
    34  const (
    35  	LXDProtocol           Protocol = "lxd"
    36  	SimplestreamsProtocol Protocol = "simplestreams"
    37  )
    38  
    39  /* The "releases" stream for images. This consists of blessed releases by the
    40   * Canonical team.
    41   */
    42  var CloudImagesRemote = Remote{
    43  	Name:          "cloud-images.ubuntu.com",
    44  	Host:          "https://cloud-images.ubuntu.com/releases",
    45  	Protocol:      SimplestreamsProtocol,
    46  	Cert:          nil,
    47  	ServerPEMCert: "",
    48  }
    49  
    50  /* The "daily" stream. This consists of images that are built from the daily
    51   * package builds. These images have not been independently tested, but in
    52   * theory "should" be good, since they're build from packages from the released
    53   * archive.
    54   */
    55  var CloudImagesDailyRemote = Remote{
    56  	Name:          "cloud-images.ubuntu.com",
    57  	Host:          "https://cloud-images.ubuntu.com/daily",
    58  	Protocol:      SimplestreamsProtocol,
    59  	Cert:          nil,
    60  	ServerPEMCert: "",
    61  }
    62  
    63  var generateCertificate = func() ([]byte, []byte, error) { return lxdshared.GenerateMemCert(true) }
    64  var DefaultImageSources = []Remote{CloudImagesRemote, CloudImagesDailyRemote}
    65  
    66  // Remote describes a LXD "remote" server for a client. In
    67  // particular it holds the information needed for the client
    68  // to connect to the remote.
    69  type Remote struct {
    70  	// Name is a label for this remote.
    71  	Name string
    72  
    73  	// Host identifies the host to which the client should connect.
    74  	// An empty string is interpreted as:
    75  	//   "localhost over a unix socket (unencrypted)".
    76  	Host string
    77  
    78  	// Protocol indicates whether this Remote is accessed via the normal
    79  	// "LXD" protocol, or whether it is a Simplestreams source. The value
    80  	// is only useful for Remotes that are image sources
    81  	Protocol Protocol
    82  
    83  	// Cert holds the TLS certificate data for the client to use.
    84  	Cert *Cert
    85  
    86  	// ServerPEMCert is the certificate to be supplied as the acceptable
    87  	// server certificate when connecting to the remote.
    88  	ServerPEMCert string
    89  }
    90  
    91  // isLocal determines if the remote is the implicit "local" remote,
    92  // an unencrypted, unauthenticated unix socket to a locally running LXD.
    93  func (r Remote) isLocal() bool {
    94  	return r.Host == Local.Host
    95  }
    96  
    97  // ID identifies the remote to the raw LXD client code. For the
    98  // non-local case this is Remote.Name. For the local case it is the
    99  // remote name that LXD special-cases for the local unix socket.
   100  func (r Remote) ID() string {
   101  	if r.isLocal() {
   102  		return remoteIDForLocal
   103  	}
   104  	return r.Name
   105  }
   106  
   107  // WithDefaults updates a copy of the remote with default values
   108  // where needed.
   109  func (r Remote) WithDefaults() (Remote, error) {
   110  	// Note that r is a value receiver, so it is an implicit copy.
   111  
   112  	if r.isLocal() {
   113  		return r.withLocalDefaults(), nil
   114  	}
   115  
   116  	if r.Protocol == "" {
   117  		r.Protocol = LXDProtocol
   118  	}
   119  
   120  	if r.Cert == nil {
   121  		certPEM, keyPEM, err := generateCertificate()
   122  		if err != nil {
   123  			return r, errors.Trace(err)
   124  		}
   125  		cert := NewCert(certPEM, keyPEM)
   126  		r.Cert = &cert
   127  	}
   128  
   129  	cert, err := r.Cert.WithDefaults()
   130  	if err != nil {
   131  		return r, errors.Trace(err)
   132  	}
   133  	r.Cert = &cert
   134  
   135  	return r, nil
   136  }
   137  
   138  func (r Remote) withLocalDefaults() Remote {
   139  	if r.Name == "" {
   140  		r.Name = remoteLocalName
   141  	}
   142  	if r.Protocol == "" {
   143  		r.Protocol = LXDProtocol
   144  	}
   145  
   146  	return r
   147  }
   148  
   149  // Validate checks the Remote fields for invalid values.
   150  func (r Remote) Validate() error {
   151  	if r.Name == "" {
   152  		return errors.NotValidf("remote missing name,")
   153  	}
   154  
   155  	if r.isLocal() {
   156  		if err := r.validateLocal(); err != nil {
   157  			return errors.Trace(err)
   158  		}
   159  		return nil
   160  	}
   161  
   162  	if r.Protocol == "" {
   163  		return errors.NotValidf("missing Protocol")
   164  	}
   165  	if r.Protocol != LXDProtocol && r.Protocol != SimplestreamsProtocol {
   166  		return errors.NotValidf("unknown Protocol %q", r.Protocol)
   167  	}
   168  
   169  	// r.Cert is allowed to be nil for Public remotes
   170  	if r.Cert != nil {
   171  		if err := r.Cert.Validate(); err != nil {
   172  			return errors.Trace(err)
   173  		}
   174  	}
   175  
   176  	return nil
   177  }
   178  
   179  func (r Remote) validateLocal() error {
   180  	if r.Cert != nil {
   181  		return errors.NotValidf("hostless remote with cert")
   182  	}
   183  	if r.Protocol != LXDProtocol {
   184  		return errors.NotValidf("localhost always talks LXD protocol not: %s", r.Protocol)
   185  	}
   186  
   187  	return nil
   188  }