1
// Copyright 2015 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
9
"github.com/juju/errors"
10
"github.com/juju/utils"
11
lxdshared "github.com/lxc/lxd/shared"
15
// remoteLocalName is a specific remote name in the default LXD config.
16
// See https://github.com/lxc/lxd/blob/master/config.go:DefaultRemotes.
17
remoteLocalName = "local"
18
remoteIDForLocal = remoteLocalName
21
// Local is LXD's default "remote". Essentially it is an unencrypted,
22
// unauthenticated connection to localhost over a unix socket.
23
// However it does require users to be in the lxd group.
25
Name: remoteLocalName,
26
Host: "", // If Host is empty we will translate it into the local Unix socket
27
// No certificates are used when connecting to the Unix socket
28
Protocol: LXDProtocol,
36
LXDProtocol Protocol = "lxd"
37
SimplestreamsProtocol Protocol = "simplestreams"
40
var CloudImagesRemote = Remote{
41
Name: "cloud-images.ubuntu.com",
42
Host: "https://cloud-images.ubuntu.com/releases",
43
Protocol: SimplestreamsProtocol,
48
var generateCertificate = lxdshared.GenerateMemCert
49
var DefaultImageSources = []Remote{CloudImagesRemote}
51
// Remote describes a LXD "remote" server for a client. In
52
// particular it holds the information needed for the client
53
// to connect to the remote.
55
// Name is a label for this remote.
58
// Host identifies the host to which the client should connect.
59
// An empty string is interpreted as:
60
// "localhost over a unix socket (unencrypted)".
63
// Protocol indicates whether this Remote is accessed via the normal
64
// "LXD" protocol, or whether it is a Simplestreams source. The value
65
// is only useful for Remotes that are image sources
68
// Cert holds the TLS certificate data for the client to use.
71
// ServerPEMCert is the certificate to be supplied as the acceptable
72
// server certificate when connecting to the remote.
76
// isLocal determines if the remote is the implicit "local" remote,
77
// an unencrypted, unauthenticated unix socket to a locally running LXD.
78
func (r Remote) isLocal() bool {
79
return r.Host == Local.Host
82
// ID identifies the remote to the raw LXD client code. For the
83
// non-local case this is Remote.Name. For the local case it is the
84
// remote name that LXD special-cases for the local unix socket.
85
func (r Remote) ID() string {
87
return remoteIDForLocal
92
// WithDefaults updates a copy of the remote with default values
94
func (r Remote) WithDefaults() (Remote, error) {
95
// Note that r is a value receiver, so it is an implicit copy.
98
return r.withLocalDefaults(), nil
101
if r.Protocol == "" {
102
r.Protocol = LXDProtocol
106
certPEM, keyPEM, err := generateCertificate()
108
return r, errors.Trace(err)
110
cert := NewCert(certPEM, keyPEM)
114
cert, err := r.Cert.WithDefaults()
116
return r, errors.Trace(err)
123
func (r Remote) withLocalDefaults() Remote {
125
r.Name = remoteLocalName
127
if r.Protocol == "" {
128
r.Protocol = LXDProtocol
134
// Validate checks the Remote fields for invalid values.
135
func (r Remote) Validate() error {
137
return errors.NotValidf("remote missing name,")
141
if err := r.validateLocal(); err != nil {
142
return errors.Trace(err)
147
if r.Protocol == "" {
148
return errors.NotValidf("missing Protocol")
150
if r.Protocol != LXDProtocol && r.Protocol != SimplestreamsProtocol {
151
return errors.NotValidf("unknown Protocol %q", r.Protocol)
154
// r.Cert is allowed to be nil for Public remotes
156
if err := r.Cert.Validate(); err != nil {
157
return errors.Trace(err)
164
func (r Remote) validateLocal() error {
166
return errors.NotValidf("hostless remote with cert")
168
if r.Protocol != LXDProtocol {
169
return errors.NotValidf("localhost always talks LXD protocol not: %s", r.Protocol)
175
// UsingTCP converts the remote into a non-local version. For non-local remotes
178
// For a "local" remote (see Local), the remote is changed to a one with the
179
// host set to the first IPv4 address assigned to the given bridgeName. The
180
// remote is also set up for remote access, setting the cert if not already set.
181
func (r Remote) UsingTCP(bridgeName string) (Remote, error) {
182
// Note that r is a value receiver, so it is an implicit copy.
188
address, err := utils.GetAddressForInterface(bridgeName)
190
return r, errors.Trace(err)
194
// TODO(ericsnow) Change r.Name if "local"? Prepend "juju-"?
196
r, err = r.WithDefaults()
198
return r, errors.Trace(err)