github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/tools/lxdclient/config.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 ) 11 12 // Config contains the config values used for a connection to the LXD API. 13 type Config struct { 14 // Namespace identifies the namespace to associate with containers 15 // and other resources with which the client interacts. It may be 16 // blank. 17 // TODO(jam) This doesn't appear to do much at the moment. 18 Namespace string 19 20 // Remote identifies the remote server to which the client should 21 // connect. For the default "remote" use Local. 22 Remote Remote 23 } 24 25 // WithDefaults updates a copy of the config with default values 26 // where needed. 27 func (cfg Config) WithDefaults() (Config, error) { 28 // We leave a blank namespace alone. 29 // Also, note that cfg is a value receiver, so it is an implicit copy. 30 31 var err error 32 cfg.Remote, err = cfg.Remote.WithDefaults() 33 if err != nil { 34 return cfg, errors.Trace(err) 35 } 36 return cfg, nil 37 } 38 39 // Validate checks the client's fields for invalid values. 40 func (cfg Config) Validate() error { 41 // TODO(ericsnow) Check cfg.Namespace (if provided)? 42 if err := cfg.Remote.Validate(); err != nil { 43 return errors.Trace(err) 44 } 45 46 return nil 47 } 48 49 // UsingTCPRemote converts the config into a "non-local" version. An 50 // already non-local remote is left alone. 51 // 52 // For a "local" remote (see Local), the remote is changed to a one 53 // with the host set to the IP address of the local lxcbr0 bridge 54 // interface. The LXD server is also set up for remote access, exposing 55 // the TCP port and adding a certificate for remote access. 56 func (cfg Config) UsingTCPRemote() (Config, error) { 57 // Note that cfg is a value receiver, so it is an implicit copy. 58 59 if !cfg.Remote.isLocal() { 60 return cfg, nil 61 } 62 63 client, err := Connect(cfg) 64 if err != nil { 65 return cfg, errors.Trace(err) 66 } 67 68 /* UsingTCP will try to figure out the network name of the lxdbr0, 69 * which means that lxdbr0 needs to be up. If this lxd has never had 70 * anything done to it, it hasn't been socket activated yet, and lxdbr0 71 * won't exist. So, we rely on this poke to get lxdbr0 started. 72 */ 73 _, err = client.ServerStatus() 74 if err != nil { 75 return cfg, errors.Trace(err) 76 } 77 78 remote, err := cfg.Remote.UsingTCP() 79 if err != nil { 80 return cfg, errors.Trace(err) 81 } 82 83 // Update the server config and authorized certs. 84 serverCert, err := prepareRemote(client, *remote.Cert) 85 if err != nil { 86 return cfg, errors.Trace(err) 87 } 88 // Note: jam 2016-02-25 setting ServerPEMCert feels like something 89 // that would have been done in UsingTCP. However, we can't know the 90 // server's certificate until we've actually connected to it, which 91 // happens in prepareRemote 92 remote.ServerPEMCert = serverCert 93 94 cfg.Remote = remote 95 return cfg, nil 96 } 97 98 func prepareRemote(client *Client, newCert Cert) (string, error) { 99 // Make sure the LXD service is configured to listen to local https 100 // requests, rather than only via the Unix socket. 101 // TODO: jam 2016-02-25 This tells LXD to listen on all addresses, 102 // which does expose the LXD to outside requests. It would 103 // probably be better to only tell LXD to listen for requests on 104 // the loopback and LXC bridges that we are using. 105 if err := client.SetConfig("core.https_address", "[::]"); err != nil { 106 return "", errors.Trace(err) 107 } 108 109 // Make sure the LXD service will allow our certificate to connect 110 if err := client.AddCert(newCert); err != nil { 111 return "", errors.Trace(err) 112 } 113 114 st, err := client.ServerStatus() 115 if err != nil { 116 return "", errors.Trace(err) 117 } 118 119 return st.Environment.Certificate, nil 120 }