github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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  var CloudImagesRemote = Remote{
    40  	Name:          "cloud-images.ubuntu.com",
    41  	Host:          "https://cloud-images.ubuntu.com/releases",
    42  	Protocol:      SimplestreamsProtocol,
    43  	Cert:          nil,
    44  	ServerPEMCert: "",
    45  }
    46  
    47  var generateCertificate = lxdshared.GenerateMemCert
    48  var DefaultImageSources = []Remote{CloudImagesRemote}
    49  
    50  // Remote describes a LXD "remote" server for a client. In
    51  // particular it holds the information needed for the client
    52  // to connect to the remote.
    53  type Remote struct {
    54  	// Name is a label for this remote.
    55  	Name string
    56  
    57  	// Host identifies the host to which the client should connect.
    58  	// An empty string is interpreted as:
    59  	//   "localhost over a unix socket (unencrypted)".
    60  	Host string
    61  
    62  	// Protocol indicates whether this Remote is accessed via the normal
    63  	// "LXD" protocol, or whether it is a Simplestreams source. The value
    64  	// is only useful for Remotes that are image sources
    65  	Protocol Protocol
    66  
    67  	// Cert holds the TLS certificate data for the client to use.
    68  	Cert *Cert
    69  
    70  	// ServerPEMCert is the certificate to be supplied as the acceptable
    71  	// server certificate when connecting to the remote.
    72  	ServerPEMCert string
    73  }
    74  
    75  // isLocal determines if the remote is the implicit "local" remote,
    76  // an unencrypted, unauthenticated unix socket to a locally running LXD.
    77  func (r Remote) isLocal() bool {
    78  	return r.Host == Local.Host
    79  }
    80  
    81  // ID identifies the remote to the raw LXD client code. For the
    82  // non-local case this is Remote.Name. For the local case it is the
    83  // remote name that LXD special-cases for the local unix socket.
    84  func (r Remote) ID() string {
    85  	if r.isLocal() {
    86  		return remoteIDForLocal
    87  	}
    88  	return r.Name
    89  }
    90  
    91  // WithDefaults updates a copy of the remote with default values
    92  // where needed.
    93  func (r Remote) WithDefaults() (Remote, error) {
    94  	// Note that r is a value receiver, so it is an implicit copy.
    95  
    96  	if r.isLocal() {
    97  		return r.withLocalDefaults(), nil
    98  	}
    99  
   100  	if r.Protocol == "" {
   101  		r.Protocol = LXDProtocol
   102  	}
   103  
   104  	if r.Cert == nil {
   105  		certPEM, keyPEM, err := generateCertificate()
   106  		if err != nil {
   107  			return r, errors.Trace(err)
   108  		}
   109  		cert := NewCert(certPEM, keyPEM)
   110  		r.Cert = &cert
   111  	}
   112  
   113  	cert, err := r.Cert.WithDefaults()
   114  	if err != nil {
   115  		return r, errors.Trace(err)
   116  	}
   117  	r.Cert = &cert
   118  
   119  	return r, nil
   120  }
   121  
   122  func (r Remote) withLocalDefaults() Remote {
   123  	if r.Name == "" {
   124  		r.Name = remoteLocalName
   125  	}
   126  	if r.Protocol == "" {
   127  		r.Protocol = LXDProtocol
   128  	}
   129  
   130  	return r
   131  }
   132  
   133  // Validate checks the Remote fields for invalid values.
   134  func (r Remote) Validate() error {
   135  	if r.Name == "" {
   136  		return errors.NotValidf("remote missing name,")
   137  	}
   138  
   139  	if r.isLocal() {
   140  		if err := r.validateLocal(); err != nil {
   141  			return errors.Trace(err)
   142  		}
   143  		return nil
   144  	}
   145  
   146  	if r.Protocol == "" {
   147  		return errors.NotValidf("missing Protocol")
   148  	}
   149  	if r.Protocol != LXDProtocol && r.Protocol != SimplestreamsProtocol {
   150  		return errors.NotValidf("unknown Protocol %q", r.Protocol)
   151  	}
   152  
   153  	// r.Cert is allowed to be nil for Public remotes
   154  	if r.Cert != nil {
   155  		if err := r.Cert.Validate(); err != nil {
   156  			return errors.Trace(err)
   157  		}
   158  	}
   159  
   160  	return nil
   161  }
   162  
   163  func (r Remote) validateLocal() error {
   164  	if r.Cert != nil {
   165  		return errors.NotValidf("hostless remote with cert")
   166  	}
   167  	if r.Protocol != LXDProtocol {
   168  		return errors.NotValidf("localhost always talks LXD protocol not: %s", r.Protocol)
   169  	}
   170  
   171  	return nil
   172  }