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