github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/apiserver/uniter/uniter_base.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  // The uniter package implements the API interface used by the uniter
     5  // worker. This file contains code common to all API versions.
     6  package uniter
     7  
     8  import (
     9  	"fmt"
    10  	"net/url"
    11  	"path"
    12  
    13  	"github.com/juju/errors"
    14  	"github.com/juju/names"
    15  	"gopkg.in/juju/charm.v5"
    16  
    17  	"github.com/juju/juju/apiserver/common"
    18  	leadershipapiserver "github.com/juju/juju/apiserver/leadership"
    19  	"github.com/juju/juju/apiserver/meterstatus"
    20  	"github.com/juju/juju/apiserver/params"
    21  	"github.com/juju/juju/leadership"
    22  	"github.com/juju/juju/network"
    23  	"github.com/juju/juju/state"
    24  	"github.com/juju/juju/state/multiwatcher"
    25  	"github.com/juju/juju/state/watcher"
    26  )
    27  
    28  // uniterBaseAPI implements common methods used by all API versions,
    29  // and it's intended for embedding.
    30  type uniterBaseAPI struct {
    31  	*common.LifeGetter
    32  	*StatusAPI
    33  	*common.DeadEnsurer
    34  	*common.AgentEntityWatcher
    35  	*common.APIAddresser
    36  	*common.EnvironWatcher
    37  	*common.RebootRequester
    38  	*leadershipapiserver.LeadershipSettingsAccessor
    39  
    40  	st            *state.State
    41  	auth          common.Authorizer
    42  	resources     *common.Resources
    43  	accessUnit    common.GetAuthFunc
    44  	accessService common.GetAuthFunc
    45  	unit          *state.Unit
    46  }
    47  
    48  // newUniterBaseAPI creates a new instance of the uniter base API.
    49  func newUniterBaseAPI(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*uniterBaseAPI, error) {
    50  	if !authorizer.AuthUnitAgent() {
    51  		return nil, common.ErrPerm
    52  	}
    53  	var unit *state.Unit
    54  	var err error
    55  	switch tag := authorizer.GetAuthTag().(type) {
    56  	case names.UnitTag:
    57  		unit, err = st.Unit(tag.Id())
    58  		if err != nil {
    59  			return nil, errors.Trace(err)
    60  		}
    61  	default:
    62  		return nil, errors.Errorf("expected names.UnitTag, got %T", tag)
    63  	}
    64  	accessUnit := func() (common.AuthFunc, error) {
    65  		return authorizer.AuthOwner, nil
    66  	}
    67  	accessService := func() (common.AuthFunc, error) {
    68  		switch tag := authorizer.GetAuthTag().(type) {
    69  		case names.UnitTag:
    70  			entity, err := st.Unit(tag.Id())
    71  			if err != nil {
    72  				return nil, errors.Trace(err)
    73  			}
    74  			serviceName := entity.ServiceName()
    75  			serviceTag := names.NewServiceTag(serviceName)
    76  			return func(tag names.Tag) bool {
    77  				return tag == serviceTag
    78  			}, nil
    79  		default:
    80  			return nil, errors.Errorf("expected names.UnitTag, got %T", tag)
    81  		}
    82  	}
    83  	accessMachine := func() (common.AuthFunc, error) {
    84  		machineId, err := unit.AssignedMachineId()
    85  		if err != nil {
    86  			return nil, errors.Trace(err)
    87  		}
    88  		machine, err := st.Machine(machineId)
    89  		if err != nil {
    90  			return nil, errors.Trace(err)
    91  		}
    92  		return func(tag names.Tag) bool {
    93  			return tag == machine.Tag()
    94  		}, nil
    95  	}
    96  
    97  	accessUnitOrService := common.AuthEither(accessUnit, accessService)
    98  	return &uniterBaseAPI{
    99  		LifeGetter:                 common.NewLifeGetter(st, accessUnitOrService),
   100  		DeadEnsurer:                common.NewDeadEnsurer(st, accessUnit),
   101  		AgentEntityWatcher:         common.NewAgentEntityWatcher(st, resources, accessUnitOrService),
   102  		APIAddresser:               common.NewAPIAddresser(st, resources),
   103  		EnvironWatcher:             common.NewEnvironWatcher(st, resources, authorizer),
   104  		RebootRequester:            common.NewRebootRequester(st, accessMachine),
   105  		LeadershipSettingsAccessor: leadershipSettingsAccessorFactory(st, resources, authorizer),
   106  
   107  		// TODO(fwereade): so *every* unit should be allowed to get/set its
   108  		// own status *and* its service's? This is not a pleasing arrangement.
   109  		StatusAPI: NewStatusAPI(st, accessUnitOrService),
   110  
   111  		st:            st,
   112  		auth:          authorizer,
   113  		resources:     resources,
   114  		accessUnit:    accessUnit,
   115  		accessService: accessService,
   116  		unit:          unit,
   117  	}, nil
   118  }
   119  
   120  // PublicAddress returns the public address for each given unit, if set.
   121  func (u *uniterBaseAPI) PublicAddress(args params.Entities) (params.StringResults, error) {
   122  	result := params.StringResults{
   123  		Results: make([]params.StringResult, len(args.Entities)),
   124  	}
   125  	canAccess, err := u.accessUnit()
   126  	if err != nil {
   127  		return params.StringResults{}, err
   128  	}
   129  	for i, entity := range args.Entities {
   130  		tag, err := names.ParseUnitTag(entity.Tag)
   131  		if err != nil {
   132  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   133  			continue
   134  		}
   135  		err = common.ErrPerm
   136  		if canAccess(tag) {
   137  			var unit *state.Unit
   138  			unit, err = u.getUnit(tag)
   139  			if err == nil {
   140  				address, ok := unit.PublicAddress()
   141  				if ok {
   142  					result.Results[i].Result = address
   143  				} else {
   144  					err = common.NoAddressSetError(tag, "public")
   145  				}
   146  			}
   147  		}
   148  		result.Results[i].Error = common.ServerError(err)
   149  	}
   150  	return result, nil
   151  }
   152  
   153  // PrivateAddress returns the private address for each given unit, if set.
   154  func (u *uniterBaseAPI) PrivateAddress(args params.Entities) (params.StringResults, error) {
   155  	result := params.StringResults{
   156  		Results: make([]params.StringResult, len(args.Entities)),
   157  	}
   158  	canAccess, err := u.accessUnit()
   159  	if err != nil {
   160  		return params.StringResults{}, err
   161  	}
   162  	for i, entity := range args.Entities {
   163  		tag, err := names.ParseUnitTag(entity.Tag)
   164  		if err != nil {
   165  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   166  			continue
   167  		}
   168  		err = common.ErrPerm
   169  		if canAccess(tag) {
   170  			var unit *state.Unit
   171  			unit, err = u.getUnit(tag)
   172  			if err == nil {
   173  				address, ok := unit.PrivateAddress()
   174  				if ok {
   175  					result.Results[i].Result = address
   176  				} else {
   177  					err = common.NoAddressSetError(tag, "private")
   178  				}
   179  			}
   180  		}
   181  		result.Results[i].Error = common.ServerError(err)
   182  	}
   183  	return result, nil
   184  }
   185  
   186  // TODO(ericsnow) Factor out the common code amongst the many methods here.
   187  
   188  var getZone = func(st *state.State, tag names.Tag) (string, error) {
   189  	unit, err := st.Unit(tag.Id())
   190  	if err != nil {
   191  		return "", errors.Trace(err)
   192  	}
   193  	zone, err := unit.AvailabilityZone()
   194  	return zone, errors.Trace(err)
   195  }
   196  
   197  // AvailabilityZone returns the availability zone for each given unit, if applicable.
   198  func (u *uniterBaseAPI) AvailabilityZone(args params.Entities) (params.StringResults, error) {
   199  	var results params.StringResults
   200  
   201  	canAccess, err := u.accessUnit()
   202  	if err != nil {
   203  		return results, errors.Trace(err)
   204  	}
   205  
   206  	// Prep the results.
   207  	results = params.StringResults{
   208  		Results: make([]params.StringResult, len(args.Entities)),
   209  	}
   210  
   211  	// Collect the zones. No zone will be collected for any entity where
   212  	// the tag is invalid or not authorized. Instead the corresponding
   213  	// result will be updated with the error.
   214  	for i, entity := range args.Entities {
   215  		tag, err := names.ParseUnitTag(entity.Tag)
   216  		if err != nil {
   217  			results.Results[i].Error = common.ServerError(common.ErrPerm)
   218  			continue
   219  		}
   220  		err = common.ErrPerm
   221  		if canAccess(tag) {
   222  			var zone string
   223  			zone, err = getZone(u.st, tag)
   224  			if err == nil {
   225  				results.Results[i].Result = zone
   226  			}
   227  		}
   228  		results.Results[i].Error = common.ServerError(err)
   229  	}
   230  
   231  	return results, nil
   232  }
   233  
   234  // Resolved returns the current resolved setting for each given unit.
   235  func (u *uniterBaseAPI) Resolved(args params.Entities) (params.ResolvedModeResults, error) {
   236  	result := params.ResolvedModeResults{
   237  		Results: make([]params.ResolvedModeResult, len(args.Entities)),
   238  	}
   239  	canAccess, err := u.accessUnit()
   240  	if err != nil {
   241  		return params.ResolvedModeResults{}, err
   242  	}
   243  	for i, entity := range args.Entities {
   244  		tag, err := names.ParseUnitTag(entity.Tag)
   245  		if err != nil {
   246  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   247  			continue
   248  		}
   249  		err = common.ErrPerm
   250  		if canAccess(tag) {
   251  			var unit *state.Unit
   252  			unit, err = u.getUnit(tag)
   253  			if err == nil {
   254  				result.Results[i].Mode = params.ResolvedMode(unit.Resolved())
   255  			}
   256  		}
   257  		result.Results[i].Error = common.ServerError(err)
   258  	}
   259  	return result, nil
   260  }
   261  
   262  // ClearResolved removes any resolved setting from each given unit.
   263  func (u *uniterBaseAPI) ClearResolved(args params.Entities) (params.ErrorResults, error) {
   264  	result := params.ErrorResults{
   265  		Results: make([]params.ErrorResult, len(args.Entities)),
   266  	}
   267  	canAccess, err := u.accessUnit()
   268  	if err != nil {
   269  		return params.ErrorResults{}, err
   270  	}
   271  	for i, entity := range args.Entities {
   272  		tag, err := names.ParseUnitTag(entity.Tag)
   273  		if err != nil {
   274  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   275  			continue
   276  		}
   277  		err = common.ErrPerm
   278  		if canAccess(tag) {
   279  			var unit *state.Unit
   280  			unit, err = u.getUnit(tag)
   281  			if err == nil {
   282  				err = unit.ClearResolved()
   283  			}
   284  		}
   285  		result.Results[i].Error = common.ServerError(err)
   286  	}
   287  	return result, nil
   288  }
   289  
   290  // GetPrincipal returns the result of calling PrincipalName() and
   291  // converting it to a tag, on each given unit.
   292  func (u *uniterBaseAPI) GetPrincipal(args params.Entities) (params.StringBoolResults, error) {
   293  	result := params.StringBoolResults{
   294  		Results: make([]params.StringBoolResult, len(args.Entities)),
   295  	}
   296  	canAccess, err := u.accessUnit()
   297  	if err != nil {
   298  		return params.StringBoolResults{}, err
   299  	}
   300  	for i, entity := range args.Entities {
   301  		tag, err := names.ParseUnitTag(entity.Tag)
   302  		if err != nil {
   303  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   304  			continue
   305  		}
   306  		err = common.ErrPerm
   307  		if canAccess(tag) {
   308  			var unit *state.Unit
   309  			unit, err = u.getUnit(tag)
   310  			if err == nil {
   311  				principal, ok := unit.PrincipalName()
   312  				if principal != "" {
   313  					result.Results[i].Result = names.NewUnitTag(principal).String()
   314  				}
   315  				result.Results[i].Ok = ok
   316  			}
   317  		}
   318  		result.Results[i].Error = common.ServerError(err)
   319  	}
   320  	return result, nil
   321  }
   322  
   323  // Destroy advances all given Alive units' lifecycles as far as
   324  // possible. See state/Unit.Destroy().
   325  func (u *uniterBaseAPI) Destroy(args params.Entities) (params.ErrorResults, error) {
   326  	result := params.ErrorResults{
   327  		Results: make([]params.ErrorResult, len(args.Entities)),
   328  	}
   329  	canAccess, err := u.accessUnit()
   330  	if err != nil {
   331  		return params.ErrorResults{}, err
   332  	}
   333  	for i, entity := range args.Entities {
   334  		tag, err := names.ParseUnitTag(entity.Tag)
   335  		if err != nil {
   336  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   337  			continue
   338  		}
   339  		err = common.ErrPerm
   340  		if canAccess(tag) {
   341  			var unit *state.Unit
   342  			unit, err = u.getUnit(tag)
   343  			if err == nil {
   344  				err = unit.Destroy()
   345  			}
   346  		}
   347  		result.Results[i].Error = common.ServerError(err)
   348  	}
   349  	return result, nil
   350  }
   351  
   352  // DestroyAllSubordinates destroys all subordinates of each given unit.
   353  func (u *uniterBaseAPI) DestroyAllSubordinates(args params.Entities) (params.ErrorResults, error) {
   354  	result := params.ErrorResults{
   355  		Results: make([]params.ErrorResult, len(args.Entities)),
   356  	}
   357  	canAccess, err := u.accessUnit()
   358  	if err != nil {
   359  		return params.ErrorResults{}, err
   360  	}
   361  	for i, entity := range args.Entities {
   362  		tag, err := names.ParseUnitTag(entity.Tag)
   363  		if err != nil {
   364  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   365  			continue
   366  		}
   367  		err = common.ErrPerm
   368  		if canAccess(tag) {
   369  			var unit *state.Unit
   370  			unit, err = u.getUnit(tag)
   371  			if err == nil {
   372  				err = u.destroySubordinates(unit)
   373  			}
   374  		}
   375  		result.Results[i].Error = common.ServerError(err)
   376  	}
   377  	return result, nil
   378  }
   379  
   380  // HasSubordinates returns the whether each given unit has any subordinates.
   381  func (u *uniterBaseAPI) HasSubordinates(args params.Entities) (params.BoolResults, error) {
   382  	result := params.BoolResults{
   383  		Results: make([]params.BoolResult, len(args.Entities)),
   384  	}
   385  	canAccess, err := u.accessUnit()
   386  	if err != nil {
   387  		return params.BoolResults{}, err
   388  	}
   389  	for i, entity := range args.Entities {
   390  		tag, err := names.ParseUnitTag(entity.Tag)
   391  		if err != nil {
   392  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   393  			continue
   394  		}
   395  		err = common.ErrPerm
   396  		if canAccess(tag) {
   397  			var unit *state.Unit
   398  			unit, err = u.getUnit(tag)
   399  			if err == nil {
   400  				subordinates := unit.SubordinateNames()
   401  				result.Results[i].Result = len(subordinates) > 0
   402  			}
   403  		}
   404  		result.Results[i].Error = common.ServerError(err)
   405  	}
   406  	return result, nil
   407  }
   408  
   409  // CharmURL returns the charm URL for all given units or services.
   410  func (u *uniterBaseAPI) CharmURL(args params.Entities) (params.StringBoolResults, error) {
   411  	result := params.StringBoolResults{
   412  		Results: make([]params.StringBoolResult, len(args.Entities)),
   413  	}
   414  	accessUnitOrService := common.AuthEither(u.accessUnit, u.accessService)
   415  	canAccess, err := accessUnitOrService()
   416  	if err != nil {
   417  		return params.StringBoolResults{}, err
   418  	}
   419  	for i, entity := range args.Entities {
   420  		tag, err := names.ParseTag(entity.Tag)
   421  		if err != nil {
   422  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   423  			continue
   424  		}
   425  		err = common.ErrPerm
   426  		if canAccess(tag) {
   427  			var unitOrService state.Entity
   428  			unitOrService, err = u.st.FindEntity(tag)
   429  			if err == nil {
   430  				charmURLer := unitOrService.(interface {
   431  					CharmURL() (*charm.URL, bool)
   432  				})
   433  				curl, ok := charmURLer.CharmURL()
   434  				if curl != nil {
   435  					result.Results[i].Result = curl.String()
   436  					result.Results[i].Ok = ok
   437  				}
   438  			}
   439  		}
   440  		result.Results[i].Error = common.ServerError(err)
   441  	}
   442  	return result, nil
   443  }
   444  
   445  // SetCharmURL sets the charm URL for each given unit. An error will
   446  // be returned if a unit is dead, or the charm URL is not know.
   447  func (u *uniterBaseAPI) SetCharmURL(args params.EntitiesCharmURL) (params.ErrorResults, error) {
   448  	result := params.ErrorResults{
   449  		Results: make([]params.ErrorResult, len(args.Entities)),
   450  	}
   451  	canAccess, err := u.accessUnit()
   452  	if err != nil {
   453  		return params.ErrorResults{}, err
   454  	}
   455  	for i, entity := range args.Entities {
   456  		tag, err := names.ParseUnitTag(entity.Tag)
   457  		if err != nil {
   458  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   459  			continue
   460  		}
   461  		err = common.ErrPerm
   462  		if canAccess(tag) {
   463  			var unit *state.Unit
   464  			unit, err = u.getUnit(tag)
   465  			if err == nil {
   466  				var curl *charm.URL
   467  				curl, err = charm.ParseURL(entity.CharmURL)
   468  				if err == nil {
   469  					err = unit.SetCharmURL(curl)
   470  				}
   471  			}
   472  		}
   473  		result.Results[i].Error = common.ServerError(err)
   474  	}
   475  	return result, nil
   476  }
   477  
   478  // OpenPorts sets the policy of the port range with protocol to be
   479  // opened, for all given units.
   480  func (u *uniterBaseAPI) OpenPorts(args params.EntitiesPortRanges) (params.ErrorResults, error) {
   481  	result := params.ErrorResults{
   482  		Results: make([]params.ErrorResult, len(args.Entities)),
   483  	}
   484  	canAccess, err := u.accessUnit()
   485  	if err != nil {
   486  		return params.ErrorResults{}, err
   487  	}
   488  	for i, entity := range args.Entities {
   489  		tag, err := names.ParseUnitTag(entity.Tag)
   490  		if err != nil {
   491  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   492  			continue
   493  		}
   494  		err = common.ErrPerm
   495  		if canAccess(tag) {
   496  			var unit *state.Unit
   497  			unit, err = u.getUnit(tag)
   498  			if err == nil {
   499  				err = unit.OpenPorts(entity.Protocol, entity.FromPort, entity.ToPort)
   500  			}
   501  		}
   502  		result.Results[i].Error = common.ServerError(err)
   503  	}
   504  	return result, nil
   505  }
   506  
   507  // ClosePorts sets the policy of the port range with protocol to be
   508  // closed, for all given units.
   509  func (u *uniterBaseAPI) ClosePorts(args params.EntitiesPortRanges) (params.ErrorResults, error) {
   510  	result := params.ErrorResults{
   511  		Results: make([]params.ErrorResult, len(args.Entities)),
   512  	}
   513  	canAccess, err := u.accessUnit()
   514  	if err != nil {
   515  		return params.ErrorResults{}, err
   516  	}
   517  	for i, entity := range args.Entities {
   518  		tag, err := names.ParseUnitTag(entity.Tag)
   519  		if err != nil {
   520  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   521  			continue
   522  		}
   523  		err = common.ErrPerm
   524  		if canAccess(tag) {
   525  			var unit *state.Unit
   526  			unit, err = u.getUnit(tag)
   527  			if err == nil {
   528  				err = unit.ClosePorts(entity.Protocol, entity.FromPort, entity.ToPort)
   529  			}
   530  		}
   531  		result.Results[i].Error = common.ServerError(err)
   532  	}
   533  	return result, nil
   534  }
   535  
   536  // OpenPort sets the policy of the port with protocol an number to be
   537  // opened, for all given units.
   538  //
   539  // TODO(dimitern): This is deprecated and is kept for
   540  // backwards-compatibility. Use OpenPorts instead.
   541  func (u *uniterBaseAPI) OpenPort(args params.EntitiesPorts) (params.ErrorResults, error) {
   542  	rangesArgs := params.EntitiesPortRanges{
   543  		Entities: make([]params.EntityPortRange, len(args.Entities)),
   544  	}
   545  	for i, entity := range args.Entities {
   546  		rangesArgs.Entities[i] = params.EntityPortRange{
   547  			Tag:      entity.Tag,
   548  			Protocol: entity.Protocol,
   549  			FromPort: entity.Port,
   550  			ToPort:   entity.Port,
   551  		}
   552  	}
   553  	return u.OpenPorts(rangesArgs)
   554  }
   555  
   556  // ClosePort sets the policy of the port with protocol and number to
   557  // be closed, for all given units.
   558  //
   559  // TODO(dimitern): This is deprecated and is kept for
   560  // backwards-compatibility. Use ClosePorts instead.
   561  func (u *uniterBaseAPI) ClosePort(args params.EntitiesPorts) (params.ErrorResults, error) {
   562  	rangesArgs := params.EntitiesPortRanges{
   563  		Entities: make([]params.EntityPortRange, len(args.Entities)),
   564  	}
   565  	for i, entity := range args.Entities {
   566  		rangesArgs.Entities[i] = params.EntityPortRange{
   567  			Tag:      entity.Tag,
   568  			Protocol: entity.Protocol,
   569  			FromPort: entity.Port,
   570  			ToPort:   entity.Port,
   571  		}
   572  	}
   573  	return u.ClosePorts(rangesArgs)
   574  }
   575  
   576  // WatchConfigSettings returns a NotifyWatcher for observing changes
   577  // to each unit's service configuration settings. See also
   578  // state/watcher.go:Unit.WatchConfigSettings().
   579  func (u *uniterBaseAPI) WatchConfigSettings(args params.Entities) (params.NotifyWatchResults, error) {
   580  	result := params.NotifyWatchResults{
   581  		Results: make([]params.NotifyWatchResult, len(args.Entities)),
   582  	}
   583  	canAccess, err := u.accessUnit()
   584  	if err != nil {
   585  		return params.NotifyWatchResults{}, err
   586  	}
   587  	for i, entity := range args.Entities {
   588  		tag, err := names.ParseUnitTag(entity.Tag)
   589  		if err != nil {
   590  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   591  			continue
   592  		}
   593  		err = common.ErrPerm
   594  		watcherId := ""
   595  		if canAccess(tag) {
   596  			watcherId, err = u.watchOneUnitConfigSettings(tag)
   597  		}
   598  		result.Results[i].NotifyWatcherId = watcherId
   599  		result.Results[i].Error = common.ServerError(err)
   600  	}
   601  	return result, nil
   602  }
   603  
   604  // WatchMeterStatus returns a NotifyWatcher for observing changes
   605  // to each unit's meter status.
   606  func (u *uniterBaseAPI) WatchMeterStatus(args params.Entities) (params.NotifyWatchResults, error) {
   607  	result := params.NotifyWatchResults{
   608  		Results: make([]params.NotifyWatchResult, len(args.Entities)),
   609  	}
   610  	canAccess, err := u.accessUnit()
   611  	if err != nil {
   612  		return params.NotifyWatchResults{}, err
   613  	}
   614  	for i, entity := range args.Entities {
   615  		tag, err := names.ParseUnitTag(entity.Tag)
   616  		if err != nil {
   617  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   618  			continue
   619  		}
   620  		err = common.ErrPerm
   621  		watcherId := ""
   622  		if canAccess(tag) {
   623  			watcherId, err = u.watchOneUnitMeterStatus(tag)
   624  		}
   625  		result.Results[i].NotifyWatcherId = watcherId
   626  		result.Results[i].Error = common.ServerError(err)
   627  	}
   628  	return result, nil
   629  }
   630  
   631  // WatchActionNotifications returns a StringsWatcher for observing
   632  // incoming action calls to a unit. See also state/watcher.go
   633  // Unit.WatchActionNotifications(). This method is called from
   634  // api/uniter/uniter.go WatchActionNotifications().
   635  func (u *uniterBaseAPI) WatchActionNotifications(args params.Entities) (params.StringsWatchResults, error) {
   636  	nothing := params.StringsWatchResults{}
   637  
   638  	result := params.StringsWatchResults{
   639  		Results: make([]params.StringsWatchResult, len(args.Entities)),
   640  	}
   641  	canAccess, err := u.accessUnit()
   642  	if err != nil {
   643  		return nothing, err
   644  	}
   645  	for i, entity := range args.Entities {
   646  		tag, err := names.ParseUnitTag(entity.Tag)
   647  		if err != nil {
   648  			return nothing, err
   649  		}
   650  		err = common.ErrPerm
   651  		if canAccess(tag) {
   652  			result.Results[i], err = u.watchOneUnitActionNotifications(tag)
   653  		}
   654  		result.Results[i].Error = common.ServerError(err)
   655  	}
   656  	return result, nil
   657  }
   658  
   659  // ConfigSettings returns the complete set of service charm config
   660  // settings available to each given unit.
   661  func (u *uniterBaseAPI) ConfigSettings(args params.Entities) (params.ConfigSettingsResults, error) {
   662  	result := params.ConfigSettingsResults{
   663  		Results: make([]params.ConfigSettingsResult, len(args.Entities)),
   664  	}
   665  	canAccess, err := u.accessUnit()
   666  	if err != nil {
   667  		return params.ConfigSettingsResults{}, err
   668  	}
   669  	for i, entity := range args.Entities {
   670  		tag, err := names.ParseUnitTag(entity.Tag)
   671  		if err != nil {
   672  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   673  			continue
   674  		}
   675  		err = common.ErrPerm
   676  		if canAccess(tag) {
   677  			var unit *state.Unit
   678  			unit, err = u.getUnit(tag)
   679  			if err == nil {
   680  				var settings charm.Settings
   681  				settings, err = unit.ConfigSettings()
   682  				if err == nil {
   683  					result.Results[i].Settings = params.ConfigSettings(settings)
   684  				}
   685  			}
   686  		}
   687  		result.Results[i].Error = common.ServerError(err)
   688  	}
   689  	return result, nil
   690  }
   691  
   692  // WatchServiceRelations returns a StringsWatcher, for each given
   693  // service, that notifies of changes to the lifecycles of relations
   694  // involving that service.
   695  func (u *uniterBaseAPI) WatchServiceRelations(args params.Entities) (params.StringsWatchResults, error) {
   696  	result := params.StringsWatchResults{
   697  		Results: make([]params.StringsWatchResult, len(args.Entities)),
   698  	}
   699  	canAccess, err := u.accessService()
   700  	if err != nil {
   701  		return params.StringsWatchResults{}, err
   702  	}
   703  	for i, entity := range args.Entities {
   704  		tag, err := names.ParseServiceTag(entity.Tag)
   705  		if err != nil {
   706  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   707  			continue
   708  		}
   709  		err = common.ErrPerm
   710  		if canAccess(tag) {
   711  			result.Results[i], err = u.watchOneServiceRelations(tag)
   712  		}
   713  		result.Results[i].Error = common.ServerError(err)
   714  	}
   715  	return result, nil
   716  }
   717  
   718  // CharmArchiveSha256 returns the SHA256 digest of the charm archive
   719  // (bundle) data for each charm url in the given parameters.
   720  func (u *uniterBaseAPI) CharmArchiveSha256(args params.CharmURLs) (params.StringResults, error) {
   721  	result := params.StringResults{
   722  		Results: make([]params.StringResult, len(args.URLs)),
   723  	}
   724  	for i, arg := range args.URLs {
   725  		curl, err := charm.ParseURL(arg.URL)
   726  		if err != nil {
   727  			err = common.ErrPerm
   728  		} else {
   729  			var sch *state.Charm
   730  			sch, err = u.st.Charm(curl)
   731  			if errors.IsNotFound(err) {
   732  				err = common.ErrPerm
   733  			}
   734  			if err == nil {
   735  				result.Results[i].Result = sch.BundleSha256()
   736  			}
   737  		}
   738  		result.Results[i].Error = common.ServerError(err)
   739  	}
   740  	return result, nil
   741  }
   742  
   743  // CharmArchiveURLs returns the URLS for the charm archive
   744  // (bundle) data for each charm url in the given parameters.
   745  func (u *uniterBaseAPI) CharmArchiveURLs(args params.CharmURLs) (params.StringsResults, error) {
   746  	apiHostPorts, err := u.st.APIHostPorts()
   747  	if err != nil {
   748  		return params.StringsResults{}, err
   749  	}
   750  	envUUID := u.st.EnvironUUID()
   751  	result := params.StringsResults{
   752  		Results: make([]params.StringsResult, len(args.URLs)),
   753  	}
   754  	for i, curl := range args.URLs {
   755  		if _, err := charm.ParseURL(curl.URL); err != nil {
   756  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   757  			continue
   758  		}
   759  		urlPath := "/"
   760  		if envUUID != "" {
   761  			urlPath = path.Join(urlPath, "environment", envUUID)
   762  		}
   763  		urlPath = path.Join(urlPath, "charms")
   764  		archiveURLs := make([]string, len(apiHostPorts))
   765  		for j, server := range apiHostPorts {
   766  			archiveURL := &url.URL{
   767  				Scheme: "https",
   768  				Host:   network.SelectInternalHostPort(server, false),
   769  				Path:   urlPath,
   770  			}
   771  			q := archiveURL.Query()
   772  			q.Set("url", curl.URL)
   773  			q.Set("file", "*")
   774  			archiveURL.RawQuery = q.Encode()
   775  			archiveURLs[j] = archiveURL.String()
   776  		}
   777  		result.Results[i].Result = archiveURLs
   778  	}
   779  	return result, nil
   780  }
   781  
   782  // Relation returns information about all given relation/unit pairs,
   783  // including their id, key and the local endpoint.
   784  func (u *uniterBaseAPI) Relation(args params.RelationUnits) (params.RelationResults, error) {
   785  	result := params.RelationResults{
   786  		Results: make([]params.RelationResult, len(args.RelationUnits)),
   787  	}
   788  	canAccess, err := u.accessUnit()
   789  	if err != nil {
   790  		return params.RelationResults{}, err
   791  	}
   792  	for i, rel := range args.RelationUnits {
   793  		relParams, err := u.getOneRelation(canAccess, rel.Relation, rel.Unit)
   794  		if err == nil {
   795  			result.Results[i] = relParams
   796  		}
   797  		result.Results[i].Error = common.ServerError(err)
   798  	}
   799  	return result, nil
   800  }
   801  
   802  // Actions returns the Actions by Tags passed and ensures that the Unit asking
   803  // for them is the same Unit that has the Actions.
   804  func (u *uniterBaseAPI) Actions(args params.Entities) (params.ActionsQueryResults, error) {
   805  	nothing := params.ActionsQueryResults{}
   806  
   807  	actionFn, err := u.authAndActionFromTagFn()
   808  	if err != nil {
   809  		return nothing, err
   810  	}
   811  
   812  	results := params.ActionsQueryResults{
   813  		Results: make([]params.ActionsQueryResult, len(args.Entities)),
   814  	}
   815  
   816  	for i, arg := range args.Entities {
   817  		action, err := actionFn(arg.Tag)
   818  		if err != nil {
   819  			results.Results[i].Error = common.ServerError(err)
   820  			continue
   821  		}
   822  		if action.Status() != state.ActionPending {
   823  			results.Results[i].Error = common.ServerError(common.ErrActionNotAvailable)
   824  			continue
   825  		}
   826  		results.Results[i].Action.Action = &params.Action{
   827  			Name:       action.Name(),
   828  			Parameters: action.Parameters(),
   829  		}
   830  	}
   831  
   832  	return results, nil
   833  }
   834  
   835  // BeginActions marks the actions represented by the passed in Tags as running.
   836  func (u *uniterBaseAPI) BeginActions(args params.Entities) (params.ErrorResults, error) {
   837  	nothing := params.ErrorResults{}
   838  
   839  	actionFn, err := u.authAndActionFromTagFn()
   840  	if err != nil {
   841  		return nothing, err
   842  	}
   843  
   844  	results := params.ErrorResults{Results: make([]params.ErrorResult, len(args.Entities))}
   845  
   846  	for i, arg := range args.Entities {
   847  		action, err := actionFn(arg.Tag)
   848  		if err != nil {
   849  			results.Results[i].Error = common.ServerError(err)
   850  			continue
   851  		}
   852  
   853  		_, err = action.Begin()
   854  		if err != nil {
   855  			results.Results[i].Error = common.ServerError(err)
   856  			continue
   857  		}
   858  	}
   859  
   860  	return results, nil
   861  }
   862  
   863  // FinishActions saves the result of a completed Action
   864  func (u *uniterBaseAPI) FinishActions(args params.ActionExecutionResults) (params.ErrorResults, error) {
   865  	nothing := params.ErrorResults{}
   866  
   867  	actionFn, err := u.authAndActionFromTagFn()
   868  	if err != nil {
   869  		return nothing, err
   870  	}
   871  
   872  	results := params.ErrorResults{Results: make([]params.ErrorResult, len(args.Results))}
   873  
   874  	for i, arg := range args.Results {
   875  		action, err := actionFn(arg.ActionTag)
   876  		if err != nil {
   877  			results.Results[i].Error = common.ServerError(err)
   878  			continue
   879  		}
   880  		actionResults, err := paramsActionExecutionResultsToStateActionResults(arg)
   881  		if err != nil {
   882  			results.Results[i].Error = common.ServerError(err)
   883  			continue
   884  		}
   885  
   886  		_, err = action.Finish(actionResults)
   887  		if err != nil {
   888  			results.Results[i].Error = common.ServerError(err)
   889  			continue
   890  		}
   891  	}
   892  
   893  	return results, nil
   894  }
   895  
   896  // paramsActionExecutionResultsToStateActionResults does exactly what
   897  // the name implies.
   898  func paramsActionExecutionResultsToStateActionResults(arg params.ActionExecutionResult) (state.ActionResults, error) {
   899  	var status state.ActionStatus
   900  	switch arg.Status {
   901  	case params.ActionCancelled:
   902  		status = state.ActionCancelled
   903  	case params.ActionCompleted:
   904  		status = state.ActionCompleted
   905  	case params.ActionFailed:
   906  		status = state.ActionFailed
   907  	case params.ActionPending:
   908  		status = state.ActionPending
   909  	default:
   910  		return state.ActionResults{}, errors.Errorf("unrecognized action status '%s'", arg.Status)
   911  	}
   912  	return state.ActionResults{
   913  		Status:  status,
   914  		Results: arg.Results,
   915  		Message: arg.Message,
   916  	}, nil
   917  }
   918  
   919  // RelationById returns information about all given relations,
   920  // specified by their ids, including their key and the local
   921  // endpoint.
   922  func (u *uniterBaseAPI) RelationById(args params.RelationIds) (params.RelationResults, error) {
   923  	result := params.RelationResults{
   924  		Results: make([]params.RelationResult, len(args.RelationIds)),
   925  	}
   926  	for i, relId := range args.RelationIds {
   927  		relParams, err := u.getOneRelationById(relId)
   928  		if err == nil {
   929  			result.Results[i] = relParams
   930  		}
   931  		result.Results[i].Error = common.ServerError(err)
   932  	}
   933  	return result, nil
   934  }
   935  
   936  // JoinedRelations returns the tags of all relations for which each supplied unit
   937  // has entered scope. It should be called RelationsInScope, but it's not convenient
   938  // to make that change until we have versioned APIs.
   939  func (u *uniterBaseAPI) JoinedRelations(args params.Entities) (params.StringsResults, error) {
   940  	result := params.StringsResults{
   941  		Results: make([]params.StringsResult, len(args.Entities)),
   942  	}
   943  	if len(args.Entities) == 0 {
   944  		return result, nil
   945  	}
   946  	canRead, err := u.accessUnit()
   947  	if err != nil {
   948  		return params.StringsResults{}, err
   949  	}
   950  	for i, entity := range args.Entities {
   951  		tag, err := names.ParseUnitTag(entity.Tag)
   952  		if err != nil {
   953  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   954  			continue
   955  		}
   956  		err = common.ErrPerm
   957  		if canRead(tag) {
   958  			var unit *state.Unit
   959  			unit, err = u.getUnit(tag)
   960  			if err == nil {
   961  				result.Results[i].Result, err = relationsInScopeTags(unit)
   962  			}
   963  		}
   964  		result.Results[i].Error = common.ServerError(err)
   965  	}
   966  	return result, nil
   967  }
   968  
   969  // CurrentEnvironUUID returns the UUID for the current juju environment.
   970  func (u *uniterBaseAPI) CurrentEnvironUUID() (params.StringResult, error) {
   971  	result := params.StringResult{}
   972  	env, err := u.st.Environment()
   973  	if err == nil {
   974  		result.Result = env.UUID()
   975  	}
   976  	return result, err
   977  }
   978  
   979  // CurrentEnvironment returns the name and UUID for the current juju environment.
   980  func (u *uniterBaseAPI) CurrentEnvironment() (params.EnvironmentResult, error) {
   981  	result := params.EnvironmentResult{}
   982  	env, err := u.st.Environment()
   983  	if err == nil {
   984  		result.Name = env.Name()
   985  		result.UUID = env.UUID()
   986  	}
   987  	return result, err
   988  }
   989  
   990  // ProviderType returns the provider type used by the current juju
   991  // environment.
   992  //
   993  // TODO(dimitern): Refactor the uniter to call this instead of calling
   994  // EnvironConfig() just to get the provider type. Once we have machine
   995  // addresses, this might be completely unnecessary though.
   996  func (u *uniterBaseAPI) ProviderType() (params.StringResult, error) {
   997  	result := params.StringResult{}
   998  	cfg, err := u.st.EnvironConfig()
   999  	if err == nil {
  1000  		result.Result = cfg.Type()
  1001  	}
  1002  	return result, err
  1003  }
  1004  
  1005  // EnterScope ensures each unit has entered its scope in the relation,
  1006  // for all of the given relation/unit pairs. See also
  1007  // state.RelationUnit.EnterScope().
  1008  func (u *uniterBaseAPI) EnterScope(args params.RelationUnits) (params.ErrorResults, error) {
  1009  	result := params.ErrorResults{
  1010  		Results: make([]params.ErrorResult, len(args.RelationUnits)),
  1011  	}
  1012  	canAccess, err := u.accessUnit()
  1013  	if err != nil {
  1014  		return params.ErrorResults{}, err
  1015  	}
  1016  	for i, arg := range args.RelationUnits {
  1017  		tag, err := names.ParseUnitTag(arg.Unit)
  1018  		if err != nil {
  1019  			result.Results[i].Error = common.ServerError(common.ErrPerm)
  1020  			continue
  1021  		}
  1022  		relUnit, err := u.getRelationUnit(canAccess, arg.Relation, tag)
  1023  		if err == nil {
  1024  			// Construct the settings, passing the unit's
  1025  			// private address (we already know it).
  1026  			privateAddress, _ := relUnit.PrivateAddress()
  1027  			settings := map[string]interface{}{
  1028  				"private-address": privateAddress,
  1029  			}
  1030  			err = relUnit.EnterScope(settings)
  1031  		}
  1032  		result.Results[i].Error = common.ServerError(err)
  1033  	}
  1034  	return result, nil
  1035  }
  1036  
  1037  // LeaveScope signals each unit has left its scope in the relation,
  1038  // for all of the given relation/unit pairs. See also
  1039  // state.RelationUnit.LeaveScope().
  1040  func (u *uniterBaseAPI) LeaveScope(args params.RelationUnits) (params.ErrorResults, error) {
  1041  	result := params.ErrorResults{
  1042  		Results: make([]params.ErrorResult, len(args.RelationUnits)),
  1043  	}
  1044  	canAccess, err := u.accessUnit()
  1045  	if err != nil {
  1046  		return params.ErrorResults{}, err
  1047  	}
  1048  	for i, arg := range args.RelationUnits {
  1049  		unit, err := names.ParseUnitTag(arg.Unit)
  1050  		if err != nil {
  1051  			result.Results[i].Error = common.ServerError(common.ErrPerm)
  1052  			continue
  1053  		}
  1054  		relUnit, err := u.getRelationUnit(canAccess, arg.Relation, unit)
  1055  		if err == nil {
  1056  			err = relUnit.LeaveScope()
  1057  		}
  1058  		result.Results[i].Error = common.ServerError(err)
  1059  	}
  1060  	return result, nil
  1061  }
  1062  
  1063  // ReadSettings returns the local settings of each given set of
  1064  // relation/unit.
  1065  func (u *uniterBaseAPI) ReadSettings(args params.RelationUnits) (params.SettingsResults, error) {
  1066  	result := params.SettingsResults{
  1067  		Results: make([]params.SettingsResult, len(args.RelationUnits)),
  1068  	}
  1069  	canAccess, err := u.accessUnit()
  1070  	if err != nil {
  1071  		return params.SettingsResults{}, err
  1072  	}
  1073  	for i, arg := range args.RelationUnits {
  1074  		unit, err := names.ParseUnitTag(arg.Unit)
  1075  		if err != nil {
  1076  			result.Results[i].Error = common.ServerError(common.ErrPerm)
  1077  			continue
  1078  		}
  1079  		relUnit, err := u.getRelationUnit(canAccess, arg.Relation, unit)
  1080  		if err == nil {
  1081  			var settings *state.Settings
  1082  			settings, err = relUnit.Settings()
  1083  			if err == nil {
  1084  				result.Results[i].Settings, err = convertRelationSettings(settings.Map())
  1085  			}
  1086  		}
  1087  		result.Results[i].Error = common.ServerError(err)
  1088  	}
  1089  	return result, nil
  1090  }
  1091  
  1092  // ReadRemoteSettings returns the remote settings of each given set of
  1093  // relation/local unit/remote unit.
  1094  func (u *uniterBaseAPI) ReadRemoteSettings(args params.RelationUnitPairs) (params.SettingsResults, error) {
  1095  	result := params.SettingsResults{
  1096  		Results: make([]params.SettingsResult, len(args.RelationUnitPairs)),
  1097  	}
  1098  	canAccess, err := u.accessUnit()
  1099  	if err != nil {
  1100  		return params.SettingsResults{}, err
  1101  	}
  1102  	for i, arg := range args.RelationUnitPairs {
  1103  		unit, err := names.ParseUnitTag(arg.LocalUnit)
  1104  		if err != nil {
  1105  			result.Results[i].Error = common.ServerError(common.ErrPerm)
  1106  			continue
  1107  		}
  1108  		relUnit, err := u.getRelationUnit(canAccess, arg.Relation, unit)
  1109  		if err == nil {
  1110  			// TODO(dfc) rework this logic
  1111  			remoteUnit := ""
  1112  			remoteUnit, err = u.checkRemoteUnit(relUnit, arg.RemoteUnit)
  1113  			if err == nil {
  1114  				var settings map[string]interface{}
  1115  				settings, err = relUnit.ReadSettings(remoteUnit)
  1116  				if err == nil {
  1117  					result.Results[i].Settings, err = convertRelationSettings(settings)
  1118  				}
  1119  			}
  1120  		}
  1121  		result.Results[i].Error = common.ServerError(err)
  1122  	}
  1123  	return result, nil
  1124  }
  1125  
  1126  // UpdateSettings persists all changes made to the local settings of
  1127  // all given pairs of relation and unit. Keys with empty values are
  1128  // considered a signal to delete these values.
  1129  func (u *uniterBaseAPI) UpdateSettings(args params.RelationUnitsSettings) (params.ErrorResults, error) {
  1130  	result := params.ErrorResults{
  1131  		Results: make([]params.ErrorResult, len(args.RelationUnits)),
  1132  	}
  1133  	canAccess, err := u.accessUnit()
  1134  	if err != nil {
  1135  		return params.ErrorResults{}, err
  1136  	}
  1137  	for i, arg := range args.RelationUnits {
  1138  		unit, err := names.ParseUnitTag(arg.Unit)
  1139  		if err != nil {
  1140  			result.Results[i].Error = common.ServerError(common.ErrPerm)
  1141  			continue
  1142  		}
  1143  		relUnit, err := u.getRelationUnit(canAccess, arg.Relation, unit)
  1144  		if err == nil {
  1145  			var settings *state.Settings
  1146  			settings, err = relUnit.Settings()
  1147  			if err == nil {
  1148  				for k, v := range arg.Settings {
  1149  					if v == "" {
  1150  						settings.Delete(k)
  1151  					} else {
  1152  						settings.Set(k, v)
  1153  					}
  1154  				}
  1155  				_, err = settings.Write()
  1156  			}
  1157  		}
  1158  		result.Results[i].Error = common.ServerError(err)
  1159  	}
  1160  	return result, nil
  1161  }
  1162  
  1163  // WatchRelationUnits returns a RelationUnitsWatcher for observing
  1164  // changes to every unit in the supplied relation that is visible to
  1165  // the supplied unit. See also state/watcher.go:RelationUnit.Watch().
  1166  func (u *uniterBaseAPI) WatchRelationUnits(args params.RelationUnits) (params.RelationUnitsWatchResults, error) {
  1167  	result := params.RelationUnitsWatchResults{
  1168  		Results: make([]params.RelationUnitsWatchResult, len(args.RelationUnits)),
  1169  	}
  1170  	canAccess, err := u.accessUnit()
  1171  	if err != nil {
  1172  		return params.RelationUnitsWatchResults{}, err
  1173  	}
  1174  	for i, arg := range args.RelationUnits {
  1175  		unit, err := names.ParseUnitTag(arg.Unit)
  1176  		if err != nil {
  1177  			result.Results[i].Error = common.ServerError(common.ErrPerm)
  1178  			continue
  1179  		}
  1180  		relUnit, err := u.getRelationUnit(canAccess, arg.Relation, unit)
  1181  		if err == nil {
  1182  			result.Results[i], err = u.watchOneRelationUnit(relUnit)
  1183  		}
  1184  		result.Results[i].Error = common.ServerError(err)
  1185  	}
  1186  	return result, nil
  1187  }
  1188  
  1189  // WatchAddresses returns a NotifyWatcher for observing changes
  1190  // to each unit's addresses.
  1191  func (u *uniterBaseAPI) WatchUnitAddresses(args params.Entities) (params.NotifyWatchResults, error) {
  1192  	result := params.NotifyWatchResults{
  1193  		Results: make([]params.NotifyWatchResult, len(args.Entities)),
  1194  	}
  1195  	canAccess, err := u.accessUnit()
  1196  	if err != nil {
  1197  		return params.NotifyWatchResults{}, err
  1198  	}
  1199  	for i, entity := range args.Entities {
  1200  		unit, err := names.ParseUnitTag(entity.Tag)
  1201  		if err != nil {
  1202  			result.Results[i].Error = common.ServerError(common.ErrPerm)
  1203  			continue
  1204  		}
  1205  		err = common.ErrPerm
  1206  		watcherId := ""
  1207  		if canAccess(unit) {
  1208  			watcherId, err = u.watchOneUnitAddresses(unit)
  1209  		}
  1210  		result.Results[i].NotifyWatcherId = watcherId
  1211  		result.Results[i].Error = common.ServerError(err)
  1212  	}
  1213  	return result, nil
  1214  }
  1215  
  1216  // GetMeterStatus returns meter status information for each unit.
  1217  func (u *uniterBaseAPI) GetMeterStatus(args params.Entities) (params.MeterStatusResults, error) {
  1218  	result := params.MeterStatusResults{
  1219  		Results: make([]params.MeterStatusResult, len(args.Entities)),
  1220  	}
  1221  	canAccess, err := u.accessUnit()
  1222  	if err != nil {
  1223  		return params.MeterStatusResults{}, common.ErrPerm
  1224  	}
  1225  	for i, entity := range args.Entities {
  1226  		unitTag, err := names.ParseUnitTag(entity.Tag)
  1227  		if err != nil {
  1228  			result.Results[i].Error = common.ServerError(common.ErrPerm)
  1229  			continue
  1230  		}
  1231  		err = common.ErrPerm
  1232  		var status state.MeterStatus
  1233  		if canAccess(unitTag) {
  1234  			var unit *state.Unit
  1235  			unit, err = u.getUnit(unitTag)
  1236  			if err == nil {
  1237  				status, err = meterstatus.MeterStatusWrapper(unit.GetMeterStatus)
  1238  			}
  1239  			result.Results[i].Code = status.Code.String()
  1240  			result.Results[i].Info = status.Info
  1241  		}
  1242  		result.Results[i].Error = common.ServerError(err)
  1243  	}
  1244  	return result, nil
  1245  }
  1246  
  1247  func (u *uniterBaseAPI) getUnit(tag names.UnitTag) (*state.Unit, error) {
  1248  	return u.st.Unit(tag.Id())
  1249  }
  1250  
  1251  func (u *uniterBaseAPI) getService(tag names.ServiceTag) (*state.Service, error) {
  1252  	return u.st.Service(tag.Id())
  1253  }
  1254  
  1255  func (u *uniterBaseAPI) getRelationUnit(canAccess common.AuthFunc, relTag string, unitTag names.UnitTag) (*state.RelationUnit, error) {
  1256  	rel, unit, err := u.getRelationAndUnit(canAccess, relTag, unitTag)
  1257  	if err != nil {
  1258  		return nil, err
  1259  	}
  1260  	return rel.Unit(unit)
  1261  }
  1262  
  1263  func (u *uniterBaseAPI) getOneRelationById(relId int) (params.RelationResult, error) {
  1264  	nothing := params.RelationResult{}
  1265  	rel, err := u.st.Relation(relId)
  1266  	if errors.IsNotFound(err) {
  1267  		return nothing, common.ErrPerm
  1268  	} else if err != nil {
  1269  		return nothing, err
  1270  	}
  1271  	tag := u.auth.GetAuthTag()
  1272  	switch tag.(type) {
  1273  	case names.UnitTag:
  1274  		// do nothing
  1275  	default:
  1276  		panic("authenticated entity is not a unit")
  1277  	}
  1278  	unit, err := u.st.FindEntity(tag)
  1279  	if err != nil {
  1280  		return nothing, err
  1281  	}
  1282  	// Use the currently authenticated unit to get the endpoint.
  1283  	result, err := u.prepareRelationResult(rel, unit.(*state.Unit))
  1284  	if err != nil {
  1285  		// An error from prepareRelationResult means the authenticated
  1286  		// unit's service is not part of the requested
  1287  		// relation. That's why it's appropriate to return ErrPerm
  1288  		// here.
  1289  		return nothing, common.ErrPerm
  1290  	}
  1291  	return result, nil
  1292  }
  1293  
  1294  func (u *uniterBaseAPI) getRelationAndUnit(canAccess common.AuthFunc, relTag string, unitTag names.UnitTag) (*state.Relation, *state.Unit, error) {
  1295  	tag, err := names.ParseRelationTag(relTag)
  1296  	if err != nil {
  1297  		return nil, nil, common.ErrPerm
  1298  	}
  1299  	rel, err := u.st.KeyRelation(tag.Id())
  1300  	if errors.IsNotFound(err) {
  1301  		return nil, nil, common.ErrPerm
  1302  	} else if err != nil {
  1303  		return nil, nil, err
  1304  	}
  1305  	if !canAccess(unitTag) {
  1306  		return nil, nil, common.ErrPerm
  1307  	}
  1308  	unit, err := u.getUnit(unitTag)
  1309  	return rel, unit, err
  1310  }
  1311  
  1312  func (u *uniterBaseAPI) prepareRelationResult(rel *state.Relation, unit *state.Unit) (params.RelationResult, error) {
  1313  	nothing := params.RelationResult{}
  1314  	ep, err := rel.Endpoint(unit.ServiceName())
  1315  	if err != nil {
  1316  		// An error here means the unit's service is not part of the
  1317  		// relation.
  1318  		return nothing, err
  1319  	}
  1320  	return params.RelationResult{
  1321  		Id:   rel.Id(),
  1322  		Key:  rel.String(),
  1323  		Life: params.Life(rel.Life().String()),
  1324  		Endpoint: multiwatcher.Endpoint{
  1325  			ServiceName: ep.ServiceName,
  1326  			Relation:    ep.Relation,
  1327  		},
  1328  	}, nil
  1329  }
  1330  
  1331  func (u *uniterBaseAPI) getOneRelation(canAccess common.AuthFunc, relTag, unitTag string) (params.RelationResult, error) {
  1332  	nothing := params.RelationResult{}
  1333  	tag, err := names.ParseUnitTag(unitTag)
  1334  	if err != nil {
  1335  		return nothing, common.ErrPerm
  1336  	}
  1337  	rel, unit, err := u.getRelationAndUnit(canAccess, relTag, tag)
  1338  	if err != nil {
  1339  		return nothing, err
  1340  	}
  1341  	return u.prepareRelationResult(rel, unit)
  1342  }
  1343  
  1344  func (u *uniterBaseAPI) destroySubordinates(principal *state.Unit) error {
  1345  	subordinates := principal.SubordinateNames()
  1346  	for _, subName := range subordinates {
  1347  		unit, err := u.getUnit(names.NewUnitTag(subName))
  1348  		if err != nil {
  1349  			return err
  1350  		}
  1351  		if err = unit.Destroy(); err != nil {
  1352  			return err
  1353  		}
  1354  	}
  1355  	return nil
  1356  }
  1357  
  1358  func (u *uniterBaseAPI) watchOneServiceRelations(tag names.ServiceTag) (params.StringsWatchResult, error) {
  1359  	nothing := params.StringsWatchResult{}
  1360  	service, err := u.getService(tag)
  1361  	if err != nil {
  1362  		return nothing, err
  1363  	}
  1364  	watch := service.WatchRelations()
  1365  	// Consume the initial event and forward it to the result.
  1366  	if changes, ok := <-watch.Changes(); ok {
  1367  		return params.StringsWatchResult{
  1368  			StringsWatcherId: u.resources.Register(watch),
  1369  			Changes:          changes,
  1370  		}, nil
  1371  	}
  1372  	return nothing, watcher.EnsureErr(watch)
  1373  }
  1374  
  1375  func (u *uniterBaseAPI) watchOneUnitConfigSettings(tag names.UnitTag) (string, error) {
  1376  	unit, err := u.getUnit(tag)
  1377  	if err != nil {
  1378  		return "", err
  1379  	}
  1380  	watch, err := unit.WatchConfigSettings()
  1381  	if err != nil {
  1382  		return "", err
  1383  	}
  1384  	// Consume the initial event. Technically, API
  1385  	// calls to Watch 'transmit' the initial event
  1386  	// in the Watch response. But NotifyWatchers
  1387  	// have no state to transmit.
  1388  	if _, ok := <-watch.Changes(); ok {
  1389  		return u.resources.Register(watch), nil
  1390  	}
  1391  	return "", watcher.EnsureErr(watch)
  1392  }
  1393  
  1394  func (u *uniterBaseAPI) watchOneUnitActionNotifications(tag names.UnitTag) (params.StringsWatchResult, error) {
  1395  	nothing := params.StringsWatchResult{}
  1396  	unit, err := u.getUnit(tag)
  1397  	if err != nil {
  1398  		return nothing, err
  1399  	}
  1400  	watch := unit.WatchActionNotifications()
  1401  
  1402  	if changes, ok := <-watch.Changes(); ok {
  1403  		return params.StringsWatchResult{
  1404  			StringsWatcherId: u.resources.Register(watch),
  1405  			Changes:          changes,
  1406  		}, nil
  1407  	}
  1408  	return nothing, watcher.EnsureErr(watch)
  1409  }
  1410  
  1411  func (u *uniterBaseAPI) watchOneUnitAddresses(tag names.UnitTag) (string, error) {
  1412  	unit, err := u.getUnit(tag)
  1413  	if err != nil {
  1414  		return "", err
  1415  	}
  1416  	machineId, err := unit.AssignedMachineId()
  1417  	if err != nil {
  1418  		return "", err
  1419  	}
  1420  	machine, err := u.st.Machine(machineId)
  1421  	if err != nil {
  1422  		return "", err
  1423  	}
  1424  	watch := machine.WatchAddresses()
  1425  	// Consume the initial event. Technically, API
  1426  	// calls to Watch 'transmit' the initial event
  1427  	// in the Watch response. But NotifyWatchers
  1428  	// have no state to transmit.
  1429  	if _, ok := <-watch.Changes(); ok {
  1430  		return u.resources.Register(watch), nil
  1431  	}
  1432  	return "", watcher.EnsureErr(watch)
  1433  }
  1434  
  1435  func (u *uniterBaseAPI) watchOneRelationUnit(relUnit *state.RelationUnit) (params.RelationUnitsWatchResult, error) {
  1436  	watch := relUnit.Watch()
  1437  	// Consume the initial event and forward it to the result.
  1438  	if changes, ok := <-watch.Changes(); ok {
  1439  		return params.RelationUnitsWatchResult{
  1440  			RelationUnitsWatcherId: u.resources.Register(watch),
  1441  			Changes:                changes,
  1442  		}, nil
  1443  	}
  1444  	return params.RelationUnitsWatchResult{}, watcher.EnsureErr(watch)
  1445  }
  1446  
  1447  func (u *uniterBaseAPI) watchOneUnitMeterStatus(tag names.UnitTag) (string, error) {
  1448  	unit, err := u.getUnit(tag)
  1449  	if err != nil {
  1450  		return "", err
  1451  	}
  1452  	watch := unit.WatchMeterStatus()
  1453  	if _, ok := <-watch.Changes(); ok {
  1454  		return u.resources.Register(watch), nil
  1455  	}
  1456  	return "", watcher.EnsureErr(watch)
  1457  }
  1458  
  1459  func (u *uniterBaseAPI) checkRemoteUnit(relUnit *state.RelationUnit, remoteUnitTag string) (string, error) {
  1460  	// Make sure the unit is indeed remote.
  1461  	if remoteUnitTag == u.auth.GetAuthTag().String() {
  1462  		return "", common.ErrPerm
  1463  	}
  1464  	// Check remoteUnit is indeed related. Note that we don't want to actually get
  1465  	// the *Unit, because it might have been removed; but its relation settings will
  1466  	// persist until the relation itself has been removed (and must remain accessible
  1467  	// because the local unit's view of reality may be time-shifted).
  1468  	tag, err := names.ParseUnitTag(remoteUnitTag)
  1469  	if err != nil {
  1470  		return "", common.ErrPerm
  1471  	}
  1472  	remoteUnitName := tag.Id()
  1473  	remoteServiceName, err := names.UnitService(remoteUnitName)
  1474  	if err != nil {
  1475  		return "", common.ErrPerm
  1476  	}
  1477  	rel := relUnit.Relation()
  1478  	_, err = rel.RelatedEndpoints(remoteServiceName)
  1479  	if err != nil {
  1480  		return "", common.ErrPerm
  1481  	}
  1482  	return remoteUnitName, nil
  1483  }
  1484  
  1485  // authAndActionFromTagFn first authenticates the request, and then returns
  1486  // a function with which to authenticate and retrieve each action in the
  1487  // request.
  1488  func (u *uniterBaseAPI) authAndActionFromTagFn() (func(string) (*state.Action, error), error) {
  1489  	canAccess, err := u.accessUnit()
  1490  	if err != nil {
  1491  		return nil, err
  1492  	}
  1493  	unit, ok := u.auth.GetAuthTag().(names.UnitTag)
  1494  	if !ok {
  1495  		return nil, fmt.Errorf("calling entity is not a unit")
  1496  	}
  1497  
  1498  	return func(tag string) (*state.Action, error) {
  1499  		actionTag, err := names.ParseActionTag(tag)
  1500  		if err != nil {
  1501  			return nil, err
  1502  		}
  1503  		action, err := u.st.ActionByTag(actionTag)
  1504  		if err != nil {
  1505  			return nil, err
  1506  		}
  1507  		receiverTag, err := names.ActionReceiverTag(action.Receiver())
  1508  		if err != nil {
  1509  			return nil, err
  1510  		}
  1511  		if unit != receiverTag {
  1512  			return nil, common.ErrPerm
  1513  		}
  1514  
  1515  		if !canAccess(receiverTag) {
  1516  			return nil, common.ErrPerm
  1517  		}
  1518  		return action, nil
  1519  	}, nil
  1520  }
  1521  
  1522  func convertRelationSettings(settings map[string]interface{}) (params.Settings, error) {
  1523  	result := make(params.Settings)
  1524  	for k, v := range settings {
  1525  		// All relation settings should be strings.
  1526  		sval, ok := v.(string)
  1527  		if !ok {
  1528  			return nil, fmt.Errorf("unexpected relation setting %q: expected string, got %T", k, v)
  1529  		}
  1530  		result[k] = sval
  1531  	}
  1532  	return result, nil
  1533  }
  1534  
  1535  func relationsInScopeTags(unit *state.Unit) ([]string, error) {
  1536  	relations, err := unit.RelationsInScope()
  1537  	if err != nil {
  1538  		return nil, err
  1539  	}
  1540  	tags := make([]string, len(relations))
  1541  	for i, relation := range relations {
  1542  		tags[i] = relation.Tag().String()
  1543  	}
  1544  	return tags, nil
  1545  }
  1546  
  1547  func leadershipSettingsAccessorFactory(
  1548  	st *state.State,
  1549  	resources *common.Resources,
  1550  	auth common.Authorizer,
  1551  ) *leadershipapiserver.LeadershipSettingsAccessor {
  1552  	registerWatcher := func(serviceId string) (string, error) {
  1553  		service, err := st.Service(serviceId)
  1554  		if err != nil {
  1555  			return "", err
  1556  		}
  1557  		w := service.WatchLeaderSettings()
  1558  		if _, ok := <-w.Changes(); ok {
  1559  			return resources.Register(w), nil
  1560  		}
  1561  		return "", watcher.EnsureErr(w)
  1562  	}
  1563  	getSettings := func(serviceId string) (map[string]string, error) {
  1564  		service, err := st.Service(serviceId)
  1565  		if err != nil {
  1566  			return nil, err
  1567  		}
  1568  		return service.LeaderSettings()
  1569  	}
  1570  	writeSettings := func(token leadership.Token, serviceId string, settings map[string]string) error {
  1571  		service, err := st.Service(serviceId)
  1572  		if err != nil {
  1573  			return err
  1574  		}
  1575  		return service.UpdateLeaderSettings(token, settings)
  1576  	}
  1577  	return leadershipapiserver.NewLeadershipSettingsAccessor(
  1578  		auth,
  1579  		registerWatcher,
  1580  		getSettings,
  1581  		st.LeadershipChecker().LeadershipCheck,
  1582  		writeSettings,
  1583  	)
  1584  }