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  }