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 }