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 }