~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/tools/lxdclient/remote.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
        "github.com/juju/utils"
 
11
        lxdshared "github.com/lxc/lxd/shared"
 
12
)
 
13
 
 
14
const (
 
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
 
19
)
 
20
 
 
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.
 
24
var Local = Remote{
 
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,
 
29
        Cert:          nil,
 
30
        ServerPEMCert: "",
 
31
}
 
32
 
 
33
type Protocol string
 
34
 
 
35
const (
 
36
        LXDProtocol           Protocol = "lxd"
 
37
        SimplestreamsProtocol Protocol = "simplestreams"
 
38
)
 
39
 
 
40
var CloudImagesRemote = Remote{
 
41
        Name:          "cloud-images.ubuntu.com",
 
42
        Host:          "https://cloud-images.ubuntu.com/releases",
 
43
        Protocol:      SimplestreamsProtocol,
 
44
        Cert:          nil,
 
45
        ServerPEMCert: "",
 
46
}
 
47
 
 
48
var generateCertificate = lxdshared.GenerateMemCert
 
49
var DefaultImageSources = []Remote{CloudImagesRemote}
 
50
 
 
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.
 
54
type Remote struct {
 
55
        // Name is a label for this remote.
 
56
        Name string
 
57
 
 
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)".
 
61
        Host string
 
62
 
 
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
 
66
        Protocol Protocol
 
67
 
 
68
        // Cert holds the TLS certificate data for the client to use.
 
69
        Cert *Cert
 
70
 
 
71
        // ServerPEMCert is the certificate to be supplied as the acceptable
 
72
        // server certificate when connecting to the remote.
 
73
        ServerPEMCert string
 
74
}
 
75
 
 
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
 
80
}
 
81
 
 
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 {
 
86
        if r.isLocal() {
 
87
                return remoteIDForLocal
 
88
        }
 
89
        return r.Name
 
90
}
 
91
 
 
92
// WithDefaults updates a copy of the remote with default values
 
93
// where needed.
 
94
func (r Remote) WithDefaults() (Remote, error) {
 
95
        // Note that r is a value receiver, so it is an implicit copy.
 
96
 
 
97
        if r.isLocal() {
 
98
                return r.withLocalDefaults(), nil
 
99
        }
 
100
 
 
101
        if r.Protocol == "" {
 
102
                r.Protocol = LXDProtocol
 
103
        }
 
104
 
 
105
        if r.Cert == nil {
 
106
                certPEM, keyPEM, err := generateCertificate()
 
107
                if err != nil {
 
108
                        return r, errors.Trace(err)
 
109
                }
 
110
                cert := NewCert(certPEM, keyPEM)
 
111
                r.Cert = &cert
 
112
        }
 
113
 
 
114
        cert, err := r.Cert.WithDefaults()
 
115
        if err != nil {
 
116
                return r, errors.Trace(err)
 
117
        }
 
118
        r.Cert = &cert
 
119
 
 
120
        return r, nil
 
121
}
 
122
 
 
123
func (r Remote) withLocalDefaults() Remote {
 
124
        if r.Name == "" {
 
125
                r.Name = remoteLocalName
 
126
        }
 
127
        if r.Protocol == "" {
 
128
                r.Protocol = LXDProtocol
 
129
        }
 
130
 
 
131
        return r
 
132
}
 
133
 
 
134
// Validate checks the Remote fields for invalid values.
 
135
func (r Remote) Validate() error {
 
136
        if r.Name == "" {
 
137
                return errors.NotValidf("remote missing name,")
 
138
        }
 
139
 
 
140
        if r.isLocal() {
 
141
                if err := r.validateLocal(); err != nil {
 
142
                        return errors.Trace(err)
 
143
                }
 
144
                return nil
 
145
        }
 
146
 
 
147
        if r.Protocol == "" {
 
148
                return errors.NotValidf("missing Protocol")
 
149
        }
 
150
        if r.Protocol != LXDProtocol && r.Protocol != SimplestreamsProtocol {
 
151
                return errors.NotValidf("unknown Protocol %q", r.Protocol)
 
152
        }
 
153
 
 
154
        // r.Cert is allowed to be nil for Public remotes
 
155
        if r.Cert != nil {
 
156
                if err := r.Cert.Validate(); err != nil {
 
157
                        return errors.Trace(err)
 
158
                }
 
159
        }
 
160
 
 
161
        return nil
 
162
}
 
163
 
 
164
func (r Remote) validateLocal() error {
 
165
        if r.Cert != nil {
 
166
                return errors.NotValidf("hostless remote with cert")
 
167
        }
 
168
        if r.Protocol != LXDProtocol {
 
169
                return errors.NotValidf("localhost always talks LXD protocol not: %s", r.Protocol)
 
170
        }
 
171
 
 
172
        return nil
 
173
}
 
174
 
 
175
// UsingTCP converts the remote into a non-local version. For non-local remotes
 
176
// this is a no-op.
 
177
//
 
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.
 
183
 
 
184
        if !r.isLocal() {
 
185
                return r, nil
 
186
        }
 
187
 
 
188
        address, err := utils.GetAddressForInterface(bridgeName)
 
189
        if err != nil {
 
190
                return r, errors.Trace(err)
 
191
        }
 
192
        r.Host = address
 
193
 
 
194
        // TODO(ericsnow) Change r.Name if "local"? Prepend "juju-"?
 
195
 
 
196
        r, err = r.WithDefaults()
 
197
        if err != nil {
 
198
                return r, errors.Trace(err)
 
199
        }
 
200
 
 
201
        return r, nil
 
202
}