github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/api/interface.go (about)

     1  // Copyright 2012-2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package api
     5  
     6  import (
     7  	"net/url"
     8  	"time"
     9  
    10  	"github.com/juju/errors"
    11  	"github.com/juju/version"
    12  	"gopkg.in/juju/names.v2"
    13  	"gopkg.in/macaroon-bakery.v1/httpbakery"
    14  	"gopkg.in/macaroon.v1"
    15  
    16  	"github.com/juju/juju/api/base"
    17  	"github.com/juju/juju/api/charmrevisionupdater"
    18  	"github.com/juju/juju/api/cleaner"
    19  	"github.com/juju/juju/api/discoverspaces"
    20  	"github.com/juju/juju/api/imagemetadata"
    21  	"github.com/juju/juju/api/instancepoller"
    22  	"github.com/juju/juju/api/reboot"
    23  	"github.com/juju/juju/api/unitassigner"
    24  	"github.com/juju/juju/api/uniter"
    25  	"github.com/juju/juju/api/upgrader"
    26  	"github.com/juju/juju/network"
    27  	"github.com/juju/utils/set"
    28  )
    29  
    30  // Info encapsulates information about a server holding juju state and
    31  // can be used to make a connection to it.
    32  type Info struct {
    33  
    34  	// This block of fields is sufficient to connect:
    35  
    36  	// Addrs holds the addresses of the controllers.
    37  	Addrs []string
    38  
    39  	// CACert holds the CA certificate that will be used
    40  	// to validate the controller's certificate, in PEM format.
    41  	// If this is empty, the standard system root certificates
    42  	// will be used.
    43  	CACert string
    44  
    45  	// ModelTag holds the model tag for the model we are
    46  	// trying to connect to. If this is empty, a controller-only
    47  	// login will be made.
    48  	ModelTag names.ModelTag
    49  
    50  	// ...but this block of fields is all about the authentication mechanism
    51  	// to use after connecting -- if any -- and should probably be extracted.
    52  
    53  	// SkipLogin, if true, skips the Login call on connection. It is an
    54  	// error to set Tag, Password, or Macaroons if SkipLogin is true.
    55  	SkipLogin bool `yaml:"-"`
    56  
    57  	// Tag holds the name of the entity that is connecting.
    58  	// If this is nil, and the password is empty, macaroon authentication
    59  	// will be used to log in unless SkipLogin is true.
    60  	Tag names.Tag
    61  
    62  	// Password holds the password for the administrator or connecting entity.
    63  	Password string
    64  
    65  	// Macaroons holds a slice of macaroon.Slice that may be used to
    66  	// authenticate with the API server.
    67  	Macaroons []macaroon.Slice `yaml:",omitempty"`
    68  
    69  	// Nonce holds the nonce used when provisioning the machine. Used
    70  	// only by the machine agent.
    71  	Nonce string `yaml:",omitempty"`
    72  }
    73  
    74  // Ports returns the unique ports for the api addresses.
    75  func (info *Info) Ports() []int {
    76  	ports := set.NewInts()
    77  	hostPorts, err := network.ParseHostPorts(info.Addrs...)
    78  	if err != nil {
    79  		// Addresses have already been validated.
    80  		panic(err)
    81  	}
    82  	for _, hp := range hostPorts {
    83  		ports.Add(hp.Port)
    84  	}
    85  	return ports.Values()
    86  }
    87  
    88  // Validate validates the API info.
    89  func (info *Info) Validate() error {
    90  	if len(info.Addrs) == 0 {
    91  		return errors.NotValidf("missing addresses")
    92  	}
    93  	if _, err := network.ParseHostPorts(info.Addrs...); err != nil {
    94  		return errors.NotValidf("host addresses: %v", err)
    95  	}
    96  	if info.SkipLogin {
    97  		if info.Tag != nil {
    98  			return errors.NotValidf("specifying Tag and SkipLogin")
    99  		}
   100  		if info.Password != "" {
   101  			return errors.NotValidf("specifying Password and SkipLogin")
   102  		}
   103  		if len(info.Macaroons) > 0 {
   104  			return errors.NotValidf("specifying Macaroons and SkipLogin")
   105  		}
   106  	}
   107  	return nil
   108  }
   109  
   110  // DialOpts holds configuration parameters that control the
   111  // Dialing behavior when connecting to a controller.
   112  type DialOpts struct {
   113  	// DialAddressInterval is the amount of time to wait
   114  	// before starting to dial another address.
   115  	DialAddressInterval time.Duration
   116  
   117  	// Timeout is the amount of time to wait contacting
   118  	// a controller.
   119  	Timeout time.Duration
   120  
   121  	// RetryDelay is the amount of time to wait between
   122  	// unsuccessful connection attempts.
   123  	RetryDelay time.Duration
   124  
   125  	// BakeryClient is the httpbakery Client, which
   126  	// is used to do the macaroon-based authorization.
   127  	// This and the *http.Client inside it are copied
   128  	// by Open, and any RoundTripper field
   129  	// the HTTP client is ignored.
   130  	BakeryClient *httpbakery.Client
   131  
   132  	// InsecureSkipVerify skips TLS certificate verification
   133  	// when connecting to the controller. This should only
   134  	// be used in tests, or when verification cannot be
   135  	// performed and the communication need not be secure.
   136  	InsecureSkipVerify bool
   137  }
   138  
   139  // DefaultDialOpts returns a DialOpts representing the default
   140  // parameters for contacting a controller.
   141  func DefaultDialOpts() DialOpts {
   142  	return DialOpts{
   143  		DialAddressInterval: 50 * time.Millisecond,
   144  		Timeout:             10 * time.Minute,
   145  		RetryDelay:          2 * time.Second,
   146  	}
   147  }
   148  
   149  // OpenFunc is the usual form of a function that opens an API connection.
   150  type OpenFunc func(*Info, DialOpts) (Connection, error)
   151  
   152  // Connection exists purely to make api-opening funcs mockable. It's just a
   153  // dumb copy of all the methods on api.state; we can and should be extracting
   154  // smaller and more relevant interfaces (and dropping some of them too).
   155  
   156  // Connection represents a connection to a Juju API server.
   157  type Connection interface {
   158  
   159  	// This first block of methods is pretty close to a sane Connection interface.
   160  	Close() error
   161  	Addr() string
   162  	APIHostPorts() [][]network.HostPort
   163  
   164  	// Broken returns a channel which will be closed if the connection
   165  	// is detected to be broken, either because the underlying
   166  	// connection has closed or because API pings have failed.
   167  	Broken() <-chan struct{}
   168  
   169  	// IsBroken returns whether the connection is broken. It checks
   170  	// the Broken channel and if that is open, attempts a connection
   171  	// ping.
   172  	IsBroken() bool
   173  
   174  	// These are a bit off -- ServerVersion is apparently not known until after
   175  	// Login()? Maybe evidence of need for a separate AuthenticatedConnection..?
   176  	Login(name names.Tag, password, nonce string, ms []macaroon.Slice) error
   177  	ServerVersion() (version.Number, bool)
   178  
   179  	// APICaller provides the facility to make API calls directly.
   180  	// This should not be used outside the api/* packages or tests.
   181  	base.APICaller
   182  
   183  	// ControllerTag returns the tag of the controller.
   184  	// This could be defined on base.APICaller.
   185  	ControllerTag() names.ControllerTag
   186  
   187  	// All the rest are strange and questionable and deserve extra attention
   188  	// and/or discussion.
   189  
   190  	// Ping makes an API request which checks if the connection is
   191  	// still functioning.
   192  	// NOTE: This method is deprecated. Please use IsBroken or Broken instead.
   193  	Ping() error
   194  
   195  	// I think this is actually dead code. It's tested, at least, so I'm
   196  	// keeping it for now, but it's not apparently used anywhere else.
   197  	AllFacadeVersions() map[string][]int
   198  
   199  	// AuthTag returns the tag of the authorized user of the state API
   200  	// connection.
   201  	AuthTag() names.Tag
   202  
   203  	// ModelAccess returns the access level of authorized user to the model.
   204  	ModelAccess() string
   205  
   206  	// ControllerAccess returns the access level of authorized user to the controller.
   207  	ControllerAccess() string
   208  
   209  	// CookieURL returns the URL that HTTP cookies for the API will be
   210  	// associated with.
   211  	CookieURL() *url.URL
   212  
   213  	// These methods expose a bunch of worker-specific facades, and basically
   214  	// just should not exist; but removing them is too noisy for a single CL.
   215  	// Client in particular is intimately coupled with State -- and the others
   216  	// will be easy to remove, but until we're using them via manifolds it's
   217  	// prohibitively ugly to do so.
   218  	Client() *Client
   219  	Uniter() (*uniter.State, error)
   220  	Upgrader() *upgrader.State
   221  	Reboot() (reboot.State, error)
   222  	DiscoverSpaces() *discoverspaces.API
   223  	InstancePoller() *instancepoller.API
   224  	CharmRevisionUpdater() *charmrevisionupdater.State
   225  	Cleaner() *cleaner.API
   226  	MetadataUpdater() *imagemetadata.Client
   227  	UnitAssigner() unitassigner.API
   228  }