github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/state/apiserver/uniter/uniter.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
     5  // used by the uniter worker.
     6  package uniter
     7  
     8  import (
     9  	"fmt"
    10  
    11  	"github.com/juju/errors"
    12  	"github.com/juju/names"
    13  
    14  	"github.com/juju/juju/charm"
    15  	"github.com/juju/juju/state"
    16  	"github.com/juju/juju/state/api/params"
    17  	"github.com/juju/juju/state/apiserver/common"
    18  	"github.com/juju/juju/state/watcher"
    19  )
    20  
    21  // UniterAPI implements the API used by the uniter worker.
    22  type UniterAPI struct {
    23  	*common.LifeGetter
    24  	*common.StatusSetter
    25  	*common.DeadEnsurer
    26  	*common.AgentEntityWatcher
    27  	*common.APIAddresser
    28  	*common.EnvironWatcher
    29  
    30  	st            *state.State
    31  	auth          common.Authorizer
    32  	resources     *common.Resources
    33  	accessUnit    common.GetAuthFunc
    34  	accessService common.GetAuthFunc
    35  }
    36  
    37  // NewUniterAPI creates a new instance of the Uniter API.
    38  func NewUniterAPI(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*UniterAPI, error) {
    39  	if !authorizer.AuthUnitAgent() {
    40  		return nil, common.ErrPerm
    41  	}
    42  	accessUnit := func() (common.AuthFunc, error) {
    43  		return authorizer.AuthOwner, nil
    44  	}
    45  	accessService := func() (common.AuthFunc, error) {
    46  		unit, ok := authorizer.GetAuthEntity().(*state.Unit)
    47  		if !ok {
    48  			panic("authenticated entity is not a unit")
    49  		}
    50  		return func(tag string) bool {
    51  			return tag == names.ServiceTag(unit.ServiceName())
    52  		}, nil
    53  	}
    54  	accessUnitOrService := common.AuthEither(accessUnit, accessService)
    55  	// Uniter can always watch for environ changes.
    56  	getCanWatch := common.AuthAlways(true)
    57  	// Uniter can not get the secrets.
    58  	getCanReadSecrets := common.AuthAlways(false)
    59  	return &UniterAPI{
    60  		LifeGetter:         common.NewLifeGetter(st, accessUnitOrService),
    61  		StatusSetter:       common.NewStatusSetter(st, accessUnit),
    62  		DeadEnsurer:        common.NewDeadEnsurer(st, accessUnit),
    63  		AgentEntityWatcher: common.NewAgentEntityWatcher(st, resources, accessUnitOrService),
    64  		APIAddresser:       common.NewAPIAddresser(st, resources),
    65  		EnvironWatcher:     common.NewEnvironWatcher(st, resources, getCanWatch, getCanReadSecrets),
    66  
    67  		st:            st,
    68  		auth:          authorizer,
    69  		resources:     resources,
    70  		accessUnit:    accessUnit,
    71  		accessService: accessService,
    72  	}, nil
    73  }
    74  
    75  func (u *UniterAPI) getUnit(tag string) (*state.Unit, error) {
    76  	_, name, err := names.ParseTag(tag, names.UnitTagKind)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  	return u.st.Unit(name)
    81  }
    82  
    83  func (u *UniterAPI) getService(tag string) (*state.Service, error) {
    84  	_, name, err := names.ParseTag(tag, names.ServiceTagKind)
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  	return u.st.Service(name)
    89  }
    90  
    91  // PublicAddress returns the public address for each given unit, if set.
    92  func (u *UniterAPI) PublicAddress(args params.Entities) (params.StringResults, error) {
    93  	result := params.StringResults{
    94  		Results: make([]params.StringResult, len(args.Entities)),
    95  	}
    96  	canAccess, err := u.accessUnit()
    97  	if err != nil {
    98  		return params.StringResults{}, err
    99  	}
   100  	for i, entity := range args.Entities {
   101  		err := common.ErrPerm
   102  		if canAccess(entity.Tag) {
   103  			var unit *state.Unit
   104  			unit, err = u.getUnit(entity.Tag)
   105  			if err == nil {
   106  				address, ok := unit.PublicAddress()
   107  				if ok {
   108  					result.Results[i].Result = address
   109  				} else {
   110  					err = common.NoAddressSetError(entity.Tag, "public")
   111  				}
   112  			}
   113  		}
   114  		result.Results[i].Error = common.ServerError(err)
   115  	}
   116  	return result, nil
   117  }
   118  
   119  // PrivateAddress returns the private address for each given unit, if set.
   120  func (u *UniterAPI) PrivateAddress(args params.Entities) (params.StringResults, error) {
   121  	result := params.StringResults{
   122  		Results: make([]params.StringResult, len(args.Entities)),
   123  	}
   124  	canAccess, err := u.accessUnit()
   125  	if err != nil {
   126  		return params.StringResults{}, err
   127  	}
   128  	for i, entity := range args.Entities {
   129  		err := common.ErrPerm
   130  		if canAccess(entity.Tag) {
   131  			var unit *state.Unit
   132  			unit, err = u.getUnit(entity.Tag)
   133  			if err == nil {
   134  				address, ok := unit.PrivateAddress()
   135  				if ok {
   136  					result.Results[i].Result = address
   137  				} else {
   138  					err = common.NoAddressSetError(entity.Tag, "private")
   139  				}
   140  			}
   141  		}
   142  		result.Results[i].Error = common.ServerError(err)
   143  	}
   144  	return result, nil
   145  }
   146  
   147  // Resolved returns the current resolved setting for each given unit.
   148  func (u *UniterAPI) Resolved(args params.Entities) (params.ResolvedModeResults, error) {
   149  	result := params.ResolvedModeResults{
   150  		Results: make([]params.ResolvedModeResult, len(args.Entities)),
   151  	}
   152  	canAccess, err := u.accessUnit()
   153  	if err != nil {
   154  		return params.ResolvedModeResults{}, err
   155  	}
   156  	for i, entity := range args.Entities {
   157  		err := common.ErrPerm
   158  		if canAccess(entity.Tag) {
   159  			var unit *state.Unit
   160  			unit, err = u.getUnit(entity.Tag)
   161  			if err == nil {
   162  				result.Results[i].Mode = params.ResolvedMode(unit.Resolved())
   163  			}
   164  		}
   165  		result.Results[i].Error = common.ServerError(err)
   166  	}
   167  	return result, nil
   168  }
   169  
   170  // ClearResolved removes any resolved setting from each given unit.
   171  func (u *UniterAPI) ClearResolved(args params.Entities) (params.ErrorResults, error) {
   172  	result := params.ErrorResults{
   173  		Results: make([]params.ErrorResult, len(args.Entities)),
   174  	}
   175  	canAccess, err := u.accessUnit()
   176  	if err != nil {
   177  		return params.ErrorResults{}, err
   178  	}
   179  	for i, entity := range args.Entities {
   180  		err := common.ErrPerm
   181  		if canAccess(entity.Tag) {
   182  			var unit *state.Unit
   183  			unit, err = u.getUnit(entity.Tag)
   184  			if err == nil {
   185  				err = unit.ClearResolved()
   186  			}
   187  		}
   188  		result.Results[i].Error = common.ServerError(err)
   189  	}
   190  	return result, nil
   191  }
   192  
   193  // GetPrincipal returns the result of calling PrincipalName() and
   194  // converting it to a tag, on each given unit.
   195  func (u *UniterAPI) GetPrincipal(args params.Entities) (params.StringBoolResults, error) {
   196  	result := params.StringBoolResults{
   197  		Results: make([]params.StringBoolResult, len(args.Entities)),
   198  	}
   199  	canAccess, err := u.accessUnit()
   200  	if err != nil {
   201  		return params.StringBoolResults{}, err
   202  	}
   203  	for i, entity := range args.Entities {
   204  		err := common.ErrPerm
   205  		if canAccess(entity.Tag) {
   206  			var unit *state.Unit
   207  			unit, err = u.getUnit(entity.Tag)
   208  			if err == nil {
   209  				principal, ok := unit.PrincipalName()
   210  				if principal != "" {
   211  					result.Results[i].Result = names.UnitTag(principal)
   212  				}
   213  				result.Results[i].Ok = ok
   214  			}
   215  		}
   216  		result.Results[i].Error = common.ServerError(err)
   217  	}
   218  	return result, nil
   219  }
   220  
   221  // Destroy advances all given Alive units' lifecycles as far as
   222  // possible. See state/Unit.Destroy().
   223  func (u *UniterAPI) Destroy(args params.Entities) (params.ErrorResults, error) {
   224  	result := params.ErrorResults{
   225  		Results: make([]params.ErrorResult, len(args.Entities)),
   226  	}
   227  	canAccess, err := u.accessUnit()
   228  	if err != nil {
   229  		return params.ErrorResults{}, err
   230  	}
   231  	for i, entity := range args.Entities {
   232  		err := common.ErrPerm
   233  		if canAccess(entity.Tag) {
   234  			var unit *state.Unit
   235  			unit, err = u.getUnit(entity.Tag)
   236  			if err == nil {
   237  				err = unit.Destroy()
   238  			}
   239  		}
   240  		result.Results[i].Error = common.ServerError(err)
   241  	}
   242  	return result, nil
   243  }
   244  
   245  func (u *UniterAPI) destroySubordinates(principal *state.Unit) error {
   246  	subordinates := principal.SubordinateNames()
   247  	for _, subName := range subordinates {
   248  		unit, err := u.getUnit(names.UnitTag(subName))
   249  		if err != nil {
   250  			return err
   251  		}
   252  		if err = unit.Destroy(); err != nil {
   253  			return err
   254  		}
   255  	}
   256  	return nil
   257  }
   258  
   259  // DestroyAllSubordinates destroys all subordinates of each given unit.
   260  func (u *UniterAPI) DestroyAllSubordinates(args params.Entities) (params.ErrorResults, error) {
   261  	result := params.ErrorResults{
   262  		Results: make([]params.ErrorResult, len(args.Entities)),
   263  	}
   264  	canAccess, err := u.accessUnit()
   265  	if err != nil {
   266  		return params.ErrorResults{}, err
   267  	}
   268  	for i, entity := range args.Entities {
   269  		err := common.ErrPerm
   270  		if canAccess(entity.Tag) {
   271  			var unit *state.Unit
   272  			unit, err = u.getUnit(entity.Tag)
   273  			if err == nil {
   274  				err = u.destroySubordinates(unit)
   275  			}
   276  		}
   277  		result.Results[i].Error = common.ServerError(err)
   278  	}
   279  	return result, nil
   280  }
   281  
   282  // HasSubordinates returns the whether each given unit has any subordinates.
   283  func (u *UniterAPI) HasSubordinates(args params.Entities) (params.BoolResults, error) {
   284  	result := params.BoolResults{
   285  		Results: make([]params.BoolResult, len(args.Entities)),
   286  	}
   287  	canAccess, err := u.accessUnit()
   288  	if err != nil {
   289  		return params.BoolResults{}, err
   290  	}
   291  	for i, entity := range args.Entities {
   292  		err := common.ErrPerm
   293  		if canAccess(entity.Tag) {
   294  			var unit *state.Unit
   295  			unit, err = u.getUnit(entity.Tag)
   296  			if err == nil {
   297  				subordinates := unit.SubordinateNames()
   298  				result.Results[i].Result = len(subordinates) > 0
   299  			}
   300  		}
   301  		result.Results[i].Error = common.ServerError(err)
   302  	}
   303  	return result, nil
   304  }
   305  
   306  // CharmURL returns the charm URL for all given units or services.
   307  func (u *UniterAPI) CharmURL(args params.Entities) (params.StringBoolResults, error) {
   308  	result := params.StringBoolResults{
   309  		Results: make([]params.StringBoolResult, len(args.Entities)),
   310  	}
   311  	accessUnitOrService := common.AuthEither(u.accessUnit, u.accessService)
   312  	canAccess, err := accessUnitOrService()
   313  	if err != nil {
   314  		return params.StringBoolResults{}, err
   315  	}
   316  	for i, entity := range args.Entities {
   317  		err := common.ErrPerm
   318  		if canAccess(entity.Tag) {
   319  			var unitOrService state.Entity
   320  			unitOrService, err = u.st.FindEntity(entity.Tag)
   321  			if err == nil {
   322  				charmURLer := unitOrService.(interface {
   323  					CharmURL() (*charm.URL, bool)
   324  				})
   325  				curl, ok := charmURLer.CharmURL()
   326  				if curl != nil {
   327  					result.Results[i].Result = curl.String()
   328  					result.Results[i].Ok = ok
   329  				}
   330  			}
   331  		}
   332  		result.Results[i].Error = common.ServerError(err)
   333  	}
   334  	return result, nil
   335  }
   336  
   337  // SetCharmURL sets the charm URL for each given unit. An error will
   338  // be returned if a unit is dead, or the charm URL is not know.
   339  func (u *UniterAPI) SetCharmURL(args params.EntitiesCharmURL) (params.ErrorResults, error) {
   340  	result := params.ErrorResults{
   341  		Results: make([]params.ErrorResult, len(args.Entities)),
   342  	}
   343  	canAccess, err := u.accessUnit()
   344  	if err != nil {
   345  		return params.ErrorResults{}, err
   346  	}
   347  	for i, entity := range args.Entities {
   348  		err := common.ErrPerm
   349  		if canAccess(entity.Tag) {
   350  			var unit *state.Unit
   351  			unit, err = u.getUnit(entity.Tag)
   352  			if err == nil {
   353  				var curl *charm.URL
   354  				curl, err = charm.ParseURL(entity.CharmURL)
   355  				if err == nil {
   356  					err = unit.SetCharmURL(curl)
   357  				}
   358  			}
   359  		}
   360  		result.Results[i].Error = common.ServerError(err)
   361  	}
   362  	return result, nil
   363  }
   364  
   365  // OpenPort sets the policy of the port with protocol an number to be
   366  // opened, for all given units.
   367  func (u *UniterAPI) OpenPort(args params.EntitiesPorts) (params.ErrorResults, error) {
   368  	result := params.ErrorResults{
   369  		Results: make([]params.ErrorResult, len(args.Entities)),
   370  	}
   371  	canAccess, err := u.accessUnit()
   372  	if err != nil {
   373  		return params.ErrorResults{}, err
   374  	}
   375  	for i, entity := range args.Entities {
   376  		err := common.ErrPerm
   377  		if canAccess(entity.Tag) {
   378  			var unit *state.Unit
   379  			unit, err = u.getUnit(entity.Tag)
   380  			if err == nil {
   381  				err = unit.OpenPort(entity.Protocol, entity.Port)
   382  			}
   383  		}
   384  		result.Results[i].Error = common.ServerError(err)
   385  	}
   386  	return result, nil
   387  }
   388  
   389  // ClosePort sets the policy of the port with protocol and number to
   390  // be closed, for all given units.
   391  func (u *UniterAPI) ClosePort(args params.EntitiesPorts) (params.ErrorResults, error) {
   392  	result := params.ErrorResults{
   393  		Results: make([]params.ErrorResult, len(args.Entities)),
   394  	}
   395  	canAccess, err := u.accessUnit()
   396  	if err != nil {
   397  		return params.ErrorResults{}, err
   398  	}
   399  	for i, entity := range args.Entities {
   400  		err := common.ErrPerm
   401  		if canAccess(entity.Tag) {
   402  			var unit *state.Unit
   403  			unit, err = u.getUnit(entity.Tag)
   404  			if err == nil {
   405  				err = unit.ClosePort(entity.Protocol, entity.Port)
   406  			}
   407  		}
   408  		result.Results[i].Error = common.ServerError(err)
   409  	}
   410  	return result, nil
   411  }
   412  
   413  func (u *UniterAPI) watchOneUnitConfigSettings(tag string) (string, error) {
   414  	unit, err := u.getUnit(tag)
   415  	if err != nil {
   416  		return "", err
   417  	}
   418  	watch, err := unit.WatchConfigSettings()
   419  	if err != nil {
   420  		return "", err
   421  	}
   422  	// Consume the initial event. Technically, API
   423  	// calls to Watch 'transmit' the initial event
   424  	// in the Watch response. But NotifyWatchers
   425  	// have no state to transmit.
   426  	if _, ok := <-watch.Changes(); ok {
   427  		return u.resources.Register(watch), nil
   428  	}
   429  	return "", watcher.MustErr(watch)
   430  }
   431  
   432  // WatchConfigSettings returns a NotifyWatcher for observing changes
   433  // to each unit's service configuration settings. See also
   434  // state/watcher.go:Unit.WatchConfigSettings().
   435  func (u *UniterAPI) WatchConfigSettings(args params.Entities) (params.NotifyWatchResults, error) {
   436  	result := params.NotifyWatchResults{
   437  		Results: make([]params.NotifyWatchResult, len(args.Entities)),
   438  	}
   439  	canAccess, err := u.accessUnit()
   440  	if err != nil {
   441  		return params.NotifyWatchResults{}, err
   442  	}
   443  	for i, entity := range args.Entities {
   444  		err := common.ErrPerm
   445  		watcherId := ""
   446  		if canAccess(entity.Tag) {
   447  			watcherId, err = u.watchOneUnitConfigSettings(entity.Tag)
   448  		}
   449  		result.Results[i].NotifyWatcherId = watcherId
   450  		result.Results[i].Error = common.ServerError(err)
   451  	}
   452  	return result, nil
   453  }
   454  
   455  // ConfigSettings returns the complete set of service charm config
   456  // settings available to each given unit.
   457  func (u *UniterAPI) ConfigSettings(args params.Entities) (params.ConfigSettingsResults, error) {
   458  	result := params.ConfigSettingsResults{
   459  		Results: make([]params.ConfigSettingsResult, len(args.Entities)),
   460  	}
   461  	canAccess, err := u.accessUnit()
   462  	if err != nil {
   463  		return params.ConfigSettingsResults{}, err
   464  	}
   465  	for i, entity := range args.Entities {
   466  		err := common.ErrPerm
   467  		if canAccess(entity.Tag) {
   468  			var unit *state.Unit
   469  			unit, err = u.getUnit(entity.Tag)
   470  			if err == nil {
   471  				var settings charm.Settings
   472  				settings, err = unit.ConfigSettings()
   473  				if err == nil {
   474  					result.Results[i].Settings = params.ConfigSettings(settings)
   475  				}
   476  			}
   477  		}
   478  		result.Results[i].Error = common.ServerError(err)
   479  	}
   480  	return result, nil
   481  }
   482  
   483  func (u *UniterAPI) watchOneServiceRelations(tag string) (params.StringsWatchResult, error) {
   484  	nothing := params.StringsWatchResult{}
   485  	service, err := u.getService(tag)
   486  	if err != nil {
   487  		return nothing, err
   488  	}
   489  	watch := service.WatchRelations()
   490  	// Consume the initial event and forward it to the result.
   491  	if changes, ok := <-watch.Changes(); ok {
   492  		return params.StringsWatchResult{
   493  			StringsWatcherId: u.resources.Register(watch),
   494  			Changes:          changes,
   495  		}, nil
   496  	}
   497  	return nothing, watcher.MustErr(watch)
   498  }
   499  
   500  // WatchServiceRelations returns a StringsWatcher, for each given
   501  // service, that notifies of changes to the lifecycles of relations
   502  // involving that service.
   503  func (u *UniterAPI) WatchServiceRelations(args params.Entities) (params.StringsWatchResults, error) {
   504  	result := params.StringsWatchResults{
   505  		Results: make([]params.StringsWatchResult, len(args.Entities)),
   506  	}
   507  	canAccess, err := u.accessService()
   508  	if err != nil {
   509  		return params.StringsWatchResults{}, err
   510  	}
   511  	for i, entity := range args.Entities {
   512  		err := common.ErrPerm
   513  		if canAccess(entity.Tag) {
   514  			result.Results[i], err = u.watchOneServiceRelations(entity.Tag)
   515  		}
   516  		result.Results[i].Error = common.ServerError(err)
   517  	}
   518  	return result, nil
   519  }
   520  
   521  // CharmArchiveURL returns the URL, corresponding to the charm archive
   522  // (bundle) in the provider storage for each given charm URL, along
   523  // with the DisableSSLHostnameVerification flag.
   524  func (u *UniterAPI) CharmArchiveURL(args params.CharmURLs) (params.CharmArchiveURLResults, error) {
   525  	result := params.CharmArchiveURLResults{
   526  		Results: make([]params.CharmArchiveURLResult, len(args.URLs)),
   527  	}
   528  	// Get the SSL hostname verification environment setting.
   529  	envConfig, err := u.st.EnvironConfig()
   530  	if err != nil {
   531  		return result, err
   532  	}
   533  	// SSLHostnameVerification defaults to true, so we need to
   534  	// invert that, for backwards-compatibility (older versions
   535  	// will have DisableSSLHostnameVerification: false by default).
   536  	disableSSLHostnameVerification := !envConfig.SSLHostnameVerification()
   537  	for i, arg := range args.URLs {
   538  		curl, err := charm.ParseURL(arg.URL)
   539  		if err != nil {
   540  			err = common.ErrPerm
   541  		} else {
   542  			var sch *state.Charm
   543  			sch, err = u.st.Charm(curl)
   544  			if errors.IsNotFound(err) {
   545  				err = common.ErrPerm
   546  			}
   547  			if err == nil {
   548  				result.Results[i].Result = sch.BundleURL().String()
   549  				result.Results[i].DisableSSLHostnameVerification = disableSSLHostnameVerification
   550  			}
   551  		}
   552  		result.Results[i].Error = common.ServerError(err)
   553  	}
   554  	return result, nil
   555  }
   556  
   557  // CharmArchiveSha256 returns the SHA256 digest of the charm archive
   558  // (bundle) data for each charm url in the given parameters.
   559  func (u *UniterAPI) CharmArchiveSha256(args params.CharmURLs) (params.StringResults, error) {
   560  	result := params.StringResults{
   561  		Results: make([]params.StringResult, len(args.URLs)),
   562  	}
   563  	for i, arg := range args.URLs {
   564  		curl, err := charm.ParseURL(arg.URL)
   565  		if err != nil {
   566  			err = common.ErrPerm
   567  		} else {
   568  			var sch *state.Charm
   569  			sch, err = u.st.Charm(curl)
   570  			if errors.IsNotFound(err) {
   571  				err = common.ErrPerm
   572  			}
   573  			if err == nil {
   574  				result.Results[i].Result = sch.BundleSha256()
   575  			}
   576  		}
   577  		result.Results[i].Error = common.ServerError(err)
   578  	}
   579  	return result, nil
   580  }
   581  
   582  func (u *UniterAPI) getRelationAndUnit(canAccess common.AuthFunc, relTag, unitTag string) (*state.Relation, *state.Unit, error) {
   583  	_, key, err := names.ParseTag(relTag, names.RelationTagKind)
   584  	if err != nil {
   585  		return nil, nil, common.ErrPerm
   586  	}
   587  	rel, err := u.st.KeyRelation(key)
   588  	if errors.IsNotFound(err) {
   589  		return nil, nil, common.ErrPerm
   590  	} else if err != nil {
   591  		return nil, nil, err
   592  	}
   593  	if !canAccess(unitTag) {
   594  		return nil, nil, common.ErrPerm
   595  	}
   596  	unit, err := u.getUnit(unitTag)
   597  	return rel, unit, err
   598  }
   599  
   600  func (u *UniterAPI) prepareRelationResult(rel *state.Relation, unit *state.Unit) (params.RelationResult, error) {
   601  	nothing := params.RelationResult{}
   602  	ep, err := rel.Endpoint(unit.ServiceName())
   603  	if err != nil {
   604  		// An error here means the unit's service is not part of the
   605  		// relation.
   606  		return nothing, err
   607  	}
   608  	return params.RelationResult{
   609  		Id:   rel.Id(),
   610  		Key:  rel.String(),
   611  		Life: params.Life(rel.Life().String()),
   612  		Endpoint: params.Endpoint{
   613  			ServiceName: ep.ServiceName,
   614  			Relation:    ep.Relation,
   615  		},
   616  	}, nil
   617  }
   618  
   619  func (u *UniterAPI) getOneRelation(canAccess common.AuthFunc, relTag, unitTag string) (params.RelationResult, error) {
   620  	nothing := params.RelationResult{}
   621  	rel, unit, err := u.getRelationAndUnit(canAccess, relTag, unitTag)
   622  	if err != nil {
   623  		return nothing, err
   624  	}
   625  	return u.prepareRelationResult(rel, unit)
   626  }
   627  
   628  func (u *UniterAPI) getOneRelationById(relId int) (params.RelationResult, error) {
   629  	nothing := params.RelationResult{}
   630  	rel, err := u.st.Relation(relId)
   631  	if errors.IsNotFound(err) {
   632  		return nothing, common.ErrPerm
   633  	} else if err != nil {
   634  		return nothing, err
   635  	}
   636  	// Use the currently authenticated unit to get the endpoint.
   637  	unit, ok := u.auth.GetAuthEntity().(*state.Unit)
   638  	if !ok {
   639  		panic("authenticated entity is not a unit")
   640  	}
   641  	result, err := u.prepareRelationResult(rel, unit)
   642  	if err != nil {
   643  		// An error from prepareRelationResult means the authenticated
   644  		// unit's service is not part of the requested
   645  		// relation. That's why it's appropriate to return ErrPerm
   646  		// here.
   647  		return nothing, common.ErrPerm
   648  	}
   649  	return result, nil
   650  }
   651  
   652  func (u *UniterAPI) getRelationUnit(canAccess common.AuthFunc, relTag, unitTag string) (*state.RelationUnit, error) {
   653  	rel, unit, err := u.getRelationAndUnit(canAccess, relTag, unitTag)
   654  	if err != nil {
   655  		return nil, err
   656  	}
   657  	return rel.Unit(unit)
   658  }
   659  
   660  // Relation returns information about all given relation/unit pairs,
   661  // including their id, key and the local endpoint.
   662  func (u *UniterAPI) Relation(args params.RelationUnits) (params.RelationResults, error) {
   663  	result := params.RelationResults{
   664  		Results: make([]params.RelationResult, len(args.RelationUnits)),
   665  	}
   666  	canAccess, err := u.accessUnit()
   667  	if err != nil {
   668  		return params.RelationResults{}, err
   669  	}
   670  	for i, rel := range args.RelationUnits {
   671  		relParams, err := u.getOneRelation(canAccess, rel.Relation, rel.Unit)
   672  		if err == nil {
   673  			result.Results[i] = relParams
   674  		}
   675  		result.Results[i].Error = common.ServerError(err)
   676  	}
   677  	return result, nil
   678  }
   679  
   680  // RelationById returns information about all given relations,
   681  // specified by their ids, including their key and the local
   682  // endpoint.
   683  func (u *UniterAPI) RelationById(args params.RelationIds) (params.RelationResults, error) {
   684  	result := params.RelationResults{
   685  		Results: make([]params.RelationResult, len(args.RelationIds)),
   686  	}
   687  	for i, relId := range args.RelationIds {
   688  		relParams, err := u.getOneRelationById(relId)
   689  		if err == nil {
   690  			result.Results[i] = relParams
   691  		}
   692  		result.Results[i].Error = common.ServerError(err)
   693  	}
   694  	return result, nil
   695  }
   696  
   697  func relationsInScopeTags(unit *state.Unit) ([]string, error) {
   698  	relations, err := unit.RelationsInScope()
   699  	if err != nil {
   700  		return nil, err
   701  	}
   702  	tags := make([]string, len(relations))
   703  	for i, relation := range relations {
   704  		tags[i] = relation.Tag()
   705  	}
   706  	return tags, nil
   707  }
   708  
   709  // JoinedRelations returns the tags of all relations for which each supplied unit
   710  // has entered scope. It should be called RelationsInScope, but it's not convenient
   711  // to make that change until we have versioned APIs.
   712  func (u *UniterAPI) JoinedRelations(args params.Entities) (params.StringsResults, error) {
   713  	result := params.StringsResults{
   714  		Results: make([]params.StringsResult, len(args.Entities)),
   715  	}
   716  	if len(args.Entities) == 0 {
   717  		return result, nil
   718  	}
   719  	canRead, err := u.accessUnit()
   720  	if err != nil {
   721  		return params.StringsResults{}, err
   722  	}
   723  	for i, entity := range args.Entities {
   724  		err := common.ErrPerm
   725  		if canRead(entity.Tag) {
   726  			var unit *state.Unit
   727  			unit, err = u.getUnit(entity.Tag)
   728  			if err == nil {
   729  				result.Results[i].Result, err = relationsInScopeTags(unit)
   730  			}
   731  		}
   732  		result.Results[i].Error = common.ServerError(err)
   733  	}
   734  	return result, nil
   735  }
   736  
   737  // CurrentEnvironUUID returns the UUID for the current juju environment.
   738  func (u *UniterAPI) CurrentEnvironUUID() (params.StringResult, error) {
   739  	result := params.StringResult{}
   740  	env, err := u.st.Environment()
   741  	if err == nil {
   742  		result.Result = env.UUID()
   743  	}
   744  	return result, err
   745  }
   746  
   747  // CurrentEnvironment returns the name and UUID for the current juju environment.
   748  func (u *UniterAPI) CurrentEnvironment() (params.EnvironmentResult, error) {
   749  	result := params.EnvironmentResult{}
   750  	env, err := u.st.Environment()
   751  	if err == nil {
   752  		result.Name = env.Name()
   753  		result.UUID = env.UUID()
   754  	}
   755  	return result, err
   756  }
   757  
   758  // ProviderType returns the provider type used by the current juju
   759  // environment.
   760  //
   761  // TODO(dimitern): Refactor the uniter to call this instead of calling
   762  // EnvironConfig() just to get the provider type. Once we have machine
   763  // addresses, this might be completely unnecessary though.
   764  func (u *UniterAPI) ProviderType() (params.StringResult, error) {
   765  	result := params.StringResult{}
   766  	cfg, err := u.st.EnvironConfig()
   767  	if err == nil {
   768  		result.Result = cfg.Type()
   769  	}
   770  	return result, err
   771  }
   772  
   773  // EnterScope ensures each unit has entered its scope in the relation,
   774  // for all of the given relation/unit pairs. See also
   775  // state.RelationUnit.EnterScope().
   776  func (u *UniterAPI) EnterScope(args params.RelationUnits) (params.ErrorResults, error) {
   777  	result := params.ErrorResults{
   778  		Results: make([]params.ErrorResult, len(args.RelationUnits)),
   779  	}
   780  	canAccess, err := u.accessUnit()
   781  	if err != nil {
   782  		return params.ErrorResults{}, err
   783  	}
   784  	for i, arg := range args.RelationUnits {
   785  		relUnit, err := u.getRelationUnit(canAccess, arg.Relation, arg.Unit)
   786  		if err == nil {
   787  			// Construct the settings, passing the unit's
   788  			// private address (we already know it).
   789  			privateAddress, _ := relUnit.PrivateAddress()
   790  			settings := map[string]interface{}{
   791  				"private-address": privateAddress,
   792  			}
   793  			err = relUnit.EnterScope(settings)
   794  		}
   795  		result.Results[i].Error = common.ServerError(err)
   796  	}
   797  	return result, nil
   798  }
   799  
   800  // LeaveScope signals each unit has left its scope in the relation,
   801  // for all of the given relation/unit pairs. See also
   802  // state.RelationUnit.LeaveScope().
   803  func (u *UniterAPI) LeaveScope(args params.RelationUnits) (params.ErrorResults, error) {
   804  	result := params.ErrorResults{
   805  		Results: make([]params.ErrorResult, len(args.RelationUnits)),
   806  	}
   807  	canAccess, err := u.accessUnit()
   808  	if err != nil {
   809  		return params.ErrorResults{}, err
   810  	}
   811  	for i, arg := range args.RelationUnits {
   812  		relUnit, err := u.getRelationUnit(canAccess, arg.Relation, arg.Unit)
   813  		if err == nil {
   814  			err = relUnit.LeaveScope()
   815  		}
   816  		result.Results[i].Error = common.ServerError(err)
   817  	}
   818  	return result, nil
   819  }
   820  
   821  func convertRelationSettings(settings map[string]interface{}) (params.RelationSettings, error) {
   822  	result := make(params.RelationSettings)
   823  	for k, v := range settings {
   824  		// All relation settings should be strings.
   825  		sval, ok := v.(string)
   826  		if !ok {
   827  			return nil, fmt.Errorf("unexpected relation setting %q: expected string, got %T", k, v)
   828  		}
   829  		result[k] = sval
   830  	}
   831  	return result, nil
   832  }
   833  
   834  // ReadSettings returns the local settings of each given set of
   835  // relation/unit.
   836  func (u *UniterAPI) ReadSettings(args params.RelationUnits) (params.RelationSettingsResults, error) {
   837  	result := params.RelationSettingsResults{
   838  		Results: make([]params.RelationSettingsResult, len(args.RelationUnits)),
   839  	}
   840  	canAccess, err := u.accessUnit()
   841  	if err != nil {
   842  		return params.RelationSettingsResults{}, err
   843  	}
   844  	for i, arg := range args.RelationUnits {
   845  		relUnit, err := u.getRelationUnit(canAccess, arg.Relation, arg.Unit)
   846  		if err == nil {
   847  			var settings *state.Settings
   848  			settings, err = relUnit.Settings()
   849  			if err == nil {
   850  				result.Results[i].Settings, err = convertRelationSettings(settings.Map())
   851  			}
   852  		}
   853  		result.Results[i].Error = common.ServerError(err)
   854  	}
   855  	return result, nil
   856  }
   857  
   858  func (u *UniterAPI) checkRemoteUnit(relUnit *state.RelationUnit, remoteUnitTag string) (string, error) {
   859  	// Make sure the unit is indeed remote.
   860  	if remoteUnitTag == u.auth.GetAuthTag() {
   861  		return "", common.ErrPerm
   862  	}
   863  	// Check remoteUnit is indeed related. Note that we don't want to actually get
   864  	// the *Unit, because it might have been removed; but its relation settings will
   865  	// persist until the relation itself has been removed (and must remain accessible
   866  	// because the local unit's view of reality may be time-shifted).
   867  	_, remoteUnitName, err := names.ParseTag(remoteUnitTag, names.UnitTagKind)
   868  	if err != nil {
   869  		return "", err
   870  	}
   871  	remoteServiceName := names.UnitService(remoteUnitName)
   872  	rel := relUnit.Relation()
   873  	_, err = rel.RelatedEndpoints(remoteServiceName)
   874  	if err != nil {
   875  		return "", common.ErrPerm
   876  	}
   877  	return remoteUnitName, nil
   878  }
   879  
   880  // ReadRemoteSettings returns the remote settings of each given set of
   881  // relation/local unit/remote unit.
   882  func (u *UniterAPI) ReadRemoteSettings(args params.RelationUnitPairs) (params.RelationSettingsResults, error) {
   883  	result := params.RelationSettingsResults{
   884  		Results: make([]params.RelationSettingsResult, len(args.RelationUnitPairs)),
   885  	}
   886  	canAccess, err := u.accessUnit()
   887  	if err != nil {
   888  		return params.RelationSettingsResults{}, err
   889  	}
   890  	for i, arg := range args.RelationUnitPairs {
   891  		relUnit, err := u.getRelationUnit(canAccess, arg.Relation, arg.LocalUnit)
   892  		if err == nil {
   893  			remoteUnit := ""
   894  			remoteUnit, err = u.checkRemoteUnit(relUnit, arg.RemoteUnit)
   895  			if err == nil {
   896  				var settings map[string]interface{}
   897  				settings, err = relUnit.ReadSettings(remoteUnit)
   898  				if err == nil {
   899  					result.Results[i].Settings, err = convertRelationSettings(settings)
   900  				}
   901  			}
   902  		}
   903  		result.Results[i].Error = common.ServerError(err)
   904  	}
   905  	return result, nil
   906  }
   907  
   908  // UpdateSettings persists all changes made to the local settings of
   909  // all given pairs of relation and unit. Keys with empty values are
   910  // considered a signal to delete these values.
   911  func (u *UniterAPI) UpdateSettings(args params.RelationUnitsSettings) (params.ErrorResults, error) {
   912  	result := params.ErrorResults{
   913  		Results: make([]params.ErrorResult, len(args.RelationUnits)),
   914  	}
   915  	canAccess, err := u.accessUnit()
   916  	if err != nil {
   917  		return params.ErrorResults{}, err
   918  	}
   919  	for i, arg := range args.RelationUnits {
   920  		relUnit, err := u.getRelationUnit(canAccess, arg.Relation, arg.Unit)
   921  		if err == nil {
   922  			var settings *state.Settings
   923  			settings, err = relUnit.Settings()
   924  			if err == nil {
   925  				for k, v := range arg.Settings {
   926  					if v == "" {
   927  						settings.Delete(k)
   928  					} else {
   929  						settings.Set(k, v)
   930  					}
   931  				}
   932  				_, err = settings.Write()
   933  			}
   934  		}
   935  		result.Results[i].Error = common.ServerError(err)
   936  	}
   937  	return result, nil
   938  }
   939  
   940  func (u *UniterAPI) watchOneRelationUnit(relUnit *state.RelationUnit) (params.RelationUnitsWatchResult, error) {
   941  	watch := relUnit.Watch()
   942  	// Consume the initial event and forward it to the result.
   943  	if changes, ok := <-watch.Changes(); ok {
   944  		return params.RelationUnitsWatchResult{
   945  			RelationUnitsWatcherId: u.resources.Register(watch),
   946  			Changes:                changes,
   947  		}, nil
   948  	}
   949  	return params.RelationUnitsWatchResult{}, watcher.MustErr(watch)
   950  }
   951  
   952  // WatchRelationUnits returns a RelationUnitsWatcher for observing
   953  // changes to every unit in the supplied relation that is visible to
   954  // the supplied unit. See also state/watcher.go:RelationUnit.Watch().
   955  func (u *UniterAPI) WatchRelationUnits(args params.RelationUnits) (params.RelationUnitsWatchResults, error) {
   956  	result := params.RelationUnitsWatchResults{
   957  		Results: make([]params.RelationUnitsWatchResult, len(args.RelationUnits)),
   958  	}
   959  	canAccess, err := u.accessUnit()
   960  	if err != nil {
   961  		return params.RelationUnitsWatchResults{}, err
   962  	}
   963  	for i, arg := range args.RelationUnits {
   964  		relUnit, err := u.getRelationUnit(canAccess, arg.Relation, arg.Unit)
   965  		if err == nil {
   966  			result.Results[i], err = u.watchOneRelationUnit(relUnit)
   967  		}
   968  		result.Results[i].Error = common.ServerError(err)
   969  	}
   970  	return result, nil
   971  }
   972  
   973  // TODO(dimitern) bug #1270795 2014-01-20
   974  // Add a doc comment here and use u.accessService()
   975  // below in the body to check for permissions.
   976  func (u *UniterAPI) GetOwnerTag(args params.Entities) (params.StringResult, error) {
   977  
   978  	nothing := params.StringResult{}
   979  	service, err := u.getService(args.Entities[0].Tag)
   980  	if err != nil {
   981  		return nothing, err
   982  	}
   983  
   984  	return params.StringResult{
   985  		Result: service.GetOwnerTag(),
   986  	}, nil
   987  }