github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/api/state.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package api
     5  
     6  import (
     7  	"net"
     8  	"strconv"
     9  
    10  	"github.com/juju/errors"
    11  	"github.com/juju/names"
    12  
    13  	"github.com/juju/juju/api/addresser"
    14  	"github.com/juju/juju/api/agent"
    15  	"github.com/juju/juju/api/base"
    16  	"github.com/juju/juju/api/charmrevisionupdater"
    17  	"github.com/juju/juju/api/cleaner"
    18  	"github.com/juju/juju/api/deployer"
    19  	"github.com/juju/juju/api/diskmanager"
    20  	"github.com/juju/juju/api/environment"
    21  	"github.com/juju/juju/api/firewaller"
    22  	"github.com/juju/juju/api/imagemetadata"
    23  	"github.com/juju/juju/api/instancepoller"
    24  	"github.com/juju/juju/api/keyupdater"
    25  	apilogger "github.com/juju/juju/api/logger"
    26  	"github.com/juju/juju/api/machiner"
    27  	"github.com/juju/juju/api/networker"
    28  	"github.com/juju/juju/api/provisioner"
    29  	"github.com/juju/juju/api/reboot"
    30  	"github.com/juju/juju/api/resumer"
    31  	"github.com/juju/juju/api/rsyslog"
    32  	"github.com/juju/juju/api/storageprovisioner"
    33  	"github.com/juju/juju/api/uniter"
    34  	"github.com/juju/juju/api/upgrader"
    35  	"github.com/juju/juju/apiserver/params"
    36  	"github.com/juju/juju/network"
    37  	"github.com/juju/juju/version"
    38  )
    39  
    40  // Login authenticates as the entity with the given name and password.
    41  // Subsequent requests on the state will act as that entity.  This
    42  // method is usually called automatically by Open. The machine nonce
    43  // should be empty unless logging in as a machine agent.
    44  func (st *State) Login(tag, password, nonce string) error {
    45  	err := st.loginV2(tag, password, nonce)
    46  	if params.IsCodeNotImplemented(err) {
    47  		err = st.loginV1(tag, password, nonce)
    48  		if params.IsCodeNotImplemented(err) {
    49  			// TODO (cmars): remove fallback once we can drop v0 compatibility
    50  			return st.loginV0(tag, password, nonce)
    51  		}
    52  	}
    53  	return err
    54  }
    55  
    56  func (st *State) loginV2(tag, password, nonce string) error {
    57  	var result params.LoginResultV1
    58  	request := &params.LoginRequest{
    59  		AuthTag:     tag,
    60  		Credentials: password,
    61  		Nonce:       nonce,
    62  	}
    63  	err := st.APICall("Admin", 2, "", "Login", request, &result)
    64  	if err != nil {
    65  		// If the server complains about an empty tag it may be that we are
    66  		// talking to an older server version that does not understand facades and
    67  		// expects a params.Creds request instead of a params.LoginRequest. We
    68  		// return a CodNotImplemented error to force login down to V1, which
    69  		// supports older server logins. This may mask an actual empty tag in
    70  		// params.LoginRequest, but that would be picked up in loginV1. V1 will
    71  		// also produce a warning that we are ignoring an invalid API, so we do not
    72  		// need to add one here.
    73  		if err.Error() == `"" is not a valid tag` {
    74  			return &params.Error{
    75  				Message: err.Error(),
    76  				Code:    params.CodeNotImplemented,
    77  			}
    78  		}
    79  		return errors.Trace(err)
    80  	}
    81  	servers := params.NetworkHostsPorts(result.Servers)
    82  	err = st.setLoginResult(tag, result.EnvironTag, result.ServerTag, servers, result.Facades)
    83  	if err != nil {
    84  		return errors.Trace(err)
    85  	}
    86  	st.serverVersion, err = version.Parse(result.ServerVersion)
    87  	if err != nil {
    88  		return errors.Trace(err)
    89  	}
    90  	return nil
    91  }
    92  
    93  func (st *State) loginV1(tag, password, nonce string) error {
    94  	var result struct {
    95  		// TODO (cmars): remove once we can drop 1.18 login compatibility
    96  		params.LoginResult
    97  
    98  		params.LoginResultV1
    99  	}
   100  	err := st.APICall("Admin", 1, "", "Login", &params.LoginRequestCompat{
   101  		LoginRequest: params.LoginRequest{
   102  			AuthTag:     tag,
   103  			Credentials: password,
   104  			Nonce:       nonce,
   105  		},
   106  		// TODO (cmars): remove once we can drop 1.18 login compatibility
   107  		Creds: params.Creds{
   108  			AuthTag:  tag,
   109  			Password: password,
   110  			Nonce:    nonce,
   111  		},
   112  	}, &result)
   113  	if err != nil {
   114  		return err
   115  	}
   116  
   117  	// We've either logged into an Admin v1 facade, or a pre-facade (1.18) API
   118  	// server.  The JSON field names between the structures are disjoint, so only
   119  	// one should have an environ tag set.
   120  
   121  	var environTag string
   122  	var serverTag string
   123  	var servers [][]network.HostPort
   124  	var facades []params.FacadeVersions
   125  	// For quite old servers, it is possible that they don't send down
   126  	// the environTag.
   127  	if result.LoginResult.EnvironTag != "" {
   128  		environTag = result.LoginResult.EnvironTag
   129  		// If the server doesn't support login v1, it doesn't support
   130  		// multiple environments, so don't store a server tag.
   131  		servers = params.NetworkHostsPorts(result.LoginResult.Servers)
   132  		facades = result.LoginResult.Facades
   133  	} else if result.LoginResultV1.EnvironTag != "" {
   134  		environTag = result.LoginResultV1.EnvironTag
   135  		serverTag = result.LoginResultV1.ServerTag
   136  		servers = params.NetworkHostsPorts(result.LoginResultV1.Servers)
   137  		facades = result.LoginResultV1.Facades
   138  	}
   139  
   140  	err = st.setLoginResult(tag, environTag, serverTag, servers, facades)
   141  	if err != nil {
   142  		return err
   143  	}
   144  	return nil
   145  }
   146  
   147  func (st *State) setLoginResult(tag, environTag, serverTag string, servers [][]network.HostPort, facades []params.FacadeVersions) error {
   148  	authtag, err := names.ParseTag(tag)
   149  	if err != nil {
   150  		return err
   151  	}
   152  	st.authTag = authtag
   153  	st.environTag = environTag
   154  	st.serverTag = serverTag
   155  
   156  	hostPorts, err := addAddress(servers, st.addr)
   157  	if err != nil {
   158  		if clerr := st.Close(); clerr != nil {
   159  			err = errors.Annotatef(err, "error closing state: %v", clerr)
   160  		}
   161  		return err
   162  	}
   163  	st.hostPorts = hostPorts
   164  
   165  	st.facadeVersions = make(map[string][]int, len(facades))
   166  	for _, facade := range facades {
   167  		st.facadeVersions[facade.Name] = facade.Versions
   168  	}
   169  	return nil
   170  }
   171  
   172  func (st *State) loginV0(tag, password, nonce string) error {
   173  	var result params.LoginResult
   174  	err := st.APICall("Admin", 0, "", "Login", &params.Creds{
   175  		AuthTag:  tag,
   176  		Password: password,
   177  		Nonce:    nonce,
   178  	}, &result)
   179  	if err != nil {
   180  		return err
   181  	}
   182  	servers := params.NetworkHostsPorts(result.Servers)
   183  	// Don't set a server tag.
   184  	if err = st.setLoginResult(tag, result.EnvironTag, "", servers, result.Facades); err != nil {
   185  		return err
   186  	}
   187  	return nil
   188  }
   189  
   190  // slideAddressToFront moves the address at the location (serverIndex, addrIndex) to be
   191  // the first address of the first server.
   192  func slideAddressToFront(servers [][]network.HostPort, serverIndex, addrIndex int) {
   193  	server := servers[serverIndex]
   194  	hostPort := server[addrIndex]
   195  	// Move the matching address to be the first in this server
   196  	for ; addrIndex > 0; addrIndex-- {
   197  		server[addrIndex] = server[addrIndex-1]
   198  	}
   199  	server[0] = hostPort
   200  	for ; serverIndex > 0; serverIndex-- {
   201  		servers[serverIndex] = servers[serverIndex-1]
   202  	}
   203  	servers[0] = server
   204  }
   205  
   206  // addAddress appends a new server derived from the given
   207  // address to servers if the address is not already found
   208  // there.
   209  func addAddress(servers [][]network.HostPort, addr string) ([][]network.HostPort, error) {
   210  	for i, server := range servers {
   211  		for j, hostPort := range server {
   212  			if hostPort.NetAddr() == addr {
   213  				slideAddressToFront(servers, i, j)
   214  				return servers, nil
   215  			}
   216  		}
   217  	}
   218  	host, portString, err := net.SplitHostPort(addr)
   219  	if err != nil {
   220  		return nil, err
   221  	}
   222  	port, err := strconv.Atoi(portString)
   223  	if err != nil {
   224  		return nil, err
   225  	}
   226  	result := make([][]network.HostPort, 0, len(servers)+1)
   227  	result = append(result, network.NewHostPorts(port, host))
   228  	result = append(result, servers...)
   229  	return result, nil
   230  }
   231  
   232  // Client returns an object that can be used
   233  // to access client-specific functionality.
   234  func (st *State) Client() *Client {
   235  	frontend, backend := base.NewClientFacade(st, "Client")
   236  	return &Client{ClientFacade: frontend, facade: backend, st: st}
   237  }
   238  
   239  // Machiner returns a version of the state that provides functionality
   240  // required by the machiner worker.
   241  func (st *State) Machiner() *machiner.State {
   242  	return machiner.NewState(st)
   243  }
   244  
   245  // Resumer returns a version of the state that provides functionality
   246  // required by the resumer worker.
   247  func (st *State) Resumer() *resumer.API {
   248  	return resumer.NewAPI(st)
   249  }
   250  
   251  // Networker returns a version of the state that provides functionality
   252  // required by the networker worker.
   253  func (st *State) Networker() networker.State {
   254  	return networker.NewState(st)
   255  }
   256  
   257  // Provisioner returns a version of the state that provides functionality
   258  // required by the provisioner worker.
   259  func (st *State) Provisioner() *provisioner.State {
   260  	return provisioner.NewState(st)
   261  }
   262  
   263  // Uniter returns a version of the state that provides functionality
   264  // required by the uniter worker.
   265  func (st *State) Uniter() (*uniter.State, error) {
   266  	unitTag, ok := st.authTag.(names.UnitTag)
   267  	if !ok {
   268  		return nil, errors.Errorf("expected UnitTag, got %T %v", st.authTag, st.authTag)
   269  	}
   270  	return uniter.NewState(st, unitTag), nil
   271  }
   272  
   273  // DiskManager returns a version of the state that provides functionality
   274  // required by the diskmanager worker.
   275  func (st *State) DiskManager() (*diskmanager.State, error) {
   276  	machineTag, ok := st.authTag.(names.MachineTag)
   277  	if !ok {
   278  		return nil, errors.Errorf("expected MachineTag, got %#v", st.authTag)
   279  	}
   280  	return diskmanager.NewState(st, machineTag), nil
   281  }
   282  
   283  // StorageProvisioner returns a version of the state that provides
   284  // functionality required by the storageprovisioner worker.
   285  // The scope tag defines the type of storage that is provisioned, either
   286  // either attached directly to a specified machine (machine scoped),
   287  // or provisioned on the underlying cloud for use by any machine in a
   288  // specified environment (environ scoped).
   289  func (st *State) StorageProvisioner(scope names.Tag) *storageprovisioner.State {
   290  	return storageprovisioner.NewState(st, scope)
   291  }
   292  
   293  // Firewaller returns a version of the state that provides functionality
   294  // required by the firewaller worker.
   295  func (st *State) Firewaller() *firewaller.State {
   296  	return firewaller.NewState(st)
   297  }
   298  
   299  // Agent returns a version of the state that provides
   300  // functionality required by the agent code.
   301  func (st *State) Agent() *agent.State {
   302  	return agent.NewState(st)
   303  }
   304  
   305  // Upgrader returns access to the Upgrader API
   306  func (st *State) Upgrader() *upgrader.State {
   307  	return upgrader.NewState(st)
   308  }
   309  
   310  // Reboot returns access to the Reboot API
   311  func (st *State) Reboot() (*reboot.State, error) {
   312  	switch tag := st.authTag.(type) {
   313  	case names.MachineTag:
   314  		return reboot.NewState(st, tag), nil
   315  	default:
   316  		return nil, errors.Errorf("expected names.MachineTag, got %T", tag)
   317  	}
   318  }
   319  
   320  // Deployer returns access to the Deployer API
   321  func (st *State) Deployer() *deployer.State {
   322  	return deployer.NewState(st)
   323  }
   324  
   325  // Addresser returns access to the Addresser API.
   326  func (st *State) Addresser() *addresser.API {
   327  	return addresser.NewAPI(st)
   328  }
   329  
   330  // Environment returns access to the Environment API
   331  func (st *State) Environment() *environment.Facade {
   332  	return environment.NewFacade(st)
   333  }
   334  
   335  // Logger returns access to the Logger API
   336  func (st *State) Logger() *apilogger.State {
   337  	return apilogger.NewState(st)
   338  }
   339  
   340  // KeyUpdater returns access to the KeyUpdater API
   341  func (st *State) KeyUpdater() *keyupdater.State {
   342  	return keyupdater.NewState(st)
   343  }
   344  
   345  // InstancePoller returns access to the InstancePoller API
   346  func (st *State) InstancePoller() *instancepoller.API {
   347  	return instancepoller.NewAPI(st)
   348  }
   349  
   350  // CharmRevisionUpdater returns access to the CharmRevisionUpdater API
   351  func (st *State) CharmRevisionUpdater() *charmrevisionupdater.State {
   352  	return charmrevisionupdater.NewState(st)
   353  }
   354  
   355  // Cleaner returns a version of the state that provides access to the cleaner API
   356  func (st *State) Cleaner() *cleaner.API {
   357  	return cleaner.NewAPI(st)
   358  }
   359  
   360  // Rsyslog returns access to the Rsyslog API
   361  func (st *State) Rsyslog() *rsyslog.State {
   362  	return rsyslog.NewState(st)
   363  }
   364  
   365  // ServerVersion holds the version of the API server that we are connected to.
   366  // It is possible that this version is Zero if the server does not report this
   367  // during login. The second result argument indicates if the version number is
   368  // set.
   369  func (st *State) ServerVersion() (version.Number, bool) {
   370  	return st.serverVersion, st.serverVersion != version.Zero
   371  }
   372  
   373  // MetadataUpdater returns access to the imageMetadata API
   374  func (st *State) MetadataUpdater() *imagemetadata.Client {
   375  	return imagemetadata.NewClient(st)
   376  }