launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/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  	errgo "launchpad.net/errgo/errors"
    10  	"launchpad.net/juju-core/charm"
    11  	"launchpad.net/juju-core/errors"
    12  	"launchpad.net/juju-core/names"
    13  	"launchpad.net/juju-core/state"
    14  	"launchpad.net/juju-core/state/api/params"
    15  	"launchpad.net/juju-core/state/apiserver/common"
    16  	"launchpad.net/juju-core/state/watcher"
    17  )
    18  
    19  var mask = errgo.Mask
    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),
    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  	entity, err := u.st.FindEntity(tag)
    77  	if err != nil {
    78  		return nil, mask(err, errors.IsNotFoundError)
    79  	}
    80  	return entity.(*state.Unit), nil
    81  }
    82  
    83  func (u *UniterAPI) getService(tag string) (*state.Service, error) {
    84  	entity, err := u.st.FindEntity(tag)
    85  	if err != nil {
    86  		return nil, mask(err, errors.IsNotFoundError)
    87  	}
    88  	return entity.(*state.Service), nil
    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{}, mask(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  // SetPublicAddress sets the public address of each of the given units.
   120  func (u *UniterAPI) SetPublicAddress(args params.SetEntityAddresses) (params.ErrorResults, error) {
   121  	result := params.ErrorResults{
   122  		Results: make([]params.ErrorResult, len(args.Entities)),
   123  	}
   124  	canAccess, err := u.accessUnit()
   125  	if err != nil {
   126  		return params.ErrorResults{}, mask(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  				err = unit.SetPublicAddress(entity.Address)
   135  			}
   136  		}
   137  		result.Results[i].Error = common.ServerError(err)
   138  	}
   139  	return result, nil
   140  }
   141  
   142  // PrivateAddress returns the private address for each given unit, if set.
   143  func (u *UniterAPI) PrivateAddress(args params.Entities) (params.StringResults, error) {
   144  	result := params.StringResults{
   145  		Results: make([]params.StringResult, len(args.Entities)),
   146  	}
   147  	canAccess, err := u.accessUnit()
   148  	if err != nil {
   149  		return params.StringResults{}, mask(err)
   150  	}
   151  	for i, entity := range args.Entities {
   152  		err := common.ErrPerm
   153  		if canAccess(entity.Tag) {
   154  			var unit *state.Unit
   155  			unit, err = u.getUnit(entity.Tag)
   156  			if err == nil {
   157  				address, ok := unit.PrivateAddress()
   158  				if ok {
   159  					result.Results[i].Result = address
   160  				} else {
   161  					err = common.NoAddressSetError(entity.Tag, "private")
   162  				}
   163  			}
   164  		}
   165  		result.Results[i].Error = common.ServerError(err)
   166  	}
   167  	return result, nil
   168  }
   169  
   170  // SetPrivateAddress sets the private address of each of the given units.
   171  func (u *UniterAPI) SetPrivateAddress(args params.SetEntityAddresses) (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{}, mask(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.SetPrivateAddress(entity.Address)
   186  			}
   187  		}
   188  		result.Results[i].Error = common.ServerError(err)
   189  	}
   190  	return result, nil
   191  }
   192  
   193  // Resolved returns the current resolved setting for each given unit.
   194  func (u *UniterAPI) Resolved(args params.Entities) (params.ResolvedModeResults, error) {
   195  	result := params.ResolvedModeResults{
   196  		Results: make([]params.ResolvedModeResult, len(args.Entities)),
   197  	}
   198  	canAccess, err := u.accessUnit()
   199  	if err != nil {
   200  		return params.ResolvedModeResults{}, mask(err)
   201  	}
   202  	for i, entity := range args.Entities {
   203  		err := common.ErrPerm
   204  		if canAccess(entity.Tag) {
   205  			var unit *state.Unit
   206  			unit, err = u.getUnit(entity.Tag)
   207  			if err == nil {
   208  				result.Results[i].Mode = params.ResolvedMode(unit.Resolved())
   209  			}
   210  		}
   211  		result.Results[i].Error = common.ServerError(err)
   212  	}
   213  	return result, nil
   214  }
   215  
   216  // ClearResolved removes any resolved setting from each given unit.
   217  func (u *UniterAPI) ClearResolved(args params.Entities) (params.ErrorResults, error) {
   218  	result := params.ErrorResults{
   219  		Results: make([]params.ErrorResult, len(args.Entities)),
   220  	}
   221  	canAccess, err := u.accessUnit()
   222  	if err != nil {
   223  		return params.ErrorResults{}, mask(err)
   224  	}
   225  	for i, entity := range args.Entities {
   226  		err := common.ErrPerm
   227  		if canAccess(entity.Tag) {
   228  			var unit *state.Unit
   229  			unit, err = u.getUnit(entity.Tag)
   230  			if err == nil {
   231  				err = unit.ClearResolved()
   232  			}
   233  		}
   234  		result.Results[i].Error = common.ServerError(err)
   235  	}
   236  	return result, nil
   237  }
   238  
   239  // GetPrincipal returns the result of calling PrincipalName() and
   240  // converting it to a tag, on each given unit.
   241  func (u *UniterAPI) GetPrincipal(args params.Entities) (params.StringBoolResults, error) {
   242  	result := params.StringBoolResults{
   243  		Results: make([]params.StringBoolResult, len(args.Entities)),
   244  	}
   245  	canAccess, err := u.accessUnit()
   246  	if err != nil {
   247  		return params.StringBoolResults{}, mask(err)
   248  	}
   249  	for i, entity := range args.Entities {
   250  		err := common.ErrPerm
   251  		if canAccess(entity.Tag) {
   252  			var unit *state.Unit
   253  			unit, err = u.getUnit(entity.Tag)
   254  			if err == nil {
   255  				principal, ok := unit.PrincipalName()
   256  				if principal != "" {
   257  					result.Results[i].Result = names.UnitTag(principal)
   258  				}
   259  				result.Results[i].Ok = ok
   260  			}
   261  		}
   262  		result.Results[i].Error = common.ServerError(err)
   263  	}
   264  	return result, nil
   265  }
   266  
   267  // Destroy advances all given Alive units' lifecycles as far as
   268  // possible. See state/Unit.Destroy().
   269  func (u *UniterAPI) Destroy(args params.Entities) (params.ErrorResults, error) {
   270  	result := params.ErrorResults{
   271  		Results: make([]params.ErrorResult, len(args.Entities)),
   272  	}
   273  	canAccess, err := u.accessUnit()
   274  	if err != nil {
   275  		return params.ErrorResults{}, mask(err)
   276  	}
   277  	for i, entity := range args.Entities {
   278  		err := common.ErrPerm
   279  		if canAccess(entity.Tag) {
   280  			var unit *state.Unit
   281  			unit, err = u.getUnit(entity.Tag)
   282  			if err == nil {
   283  				err = unit.Destroy()
   284  			}
   285  		}
   286  		result.Results[i].Error = common.ServerError(err)
   287  	}
   288  	return result, nil
   289  }
   290  
   291  func (u *UniterAPI) destroySubordinates(principal *state.Unit) error {
   292  	subordinates := principal.SubordinateNames()
   293  	for _, subName := range subordinates {
   294  		unit, err := u.getUnit(names.UnitTag(subName))
   295  		if err != nil {
   296  			return mask(err)
   297  		}
   298  		if err = unit.Destroy(); err != nil {
   299  			return mask(err)
   300  		}
   301  	}
   302  	return nil
   303  }
   304  
   305  // DestroyAllSubordinates destroys all subordinates of each given unit.
   306  func (u *UniterAPI) DestroyAllSubordinates(args params.Entities) (params.ErrorResults, error) {
   307  	result := params.ErrorResults{
   308  		Results: make([]params.ErrorResult, len(args.Entities)),
   309  	}
   310  	canAccess, err := u.accessUnit()
   311  	if err != nil {
   312  		return params.ErrorResults{}, mask(err)
   313  	}
   314  	for i, entity := range args.Entities {
   315  		err := common.ErrPerm
   316  		if canAccess(entity.Tag) {
   317  			var unit *state.Unit
   318  			unit, err = u.getUnit(entity.Tag)
   319  			if err == nil {
   320  				err = u.destroySubordinates(unit)
   321  			}
   322  		}
   323  		result.Results[i].Error = common.ServerError(err)
   324  	}
   325  	return result, nil
   326  }
   327  
   328  // HasSubordinates returns the whether each given unit has any subordinates.
   329  func (u *UniterAPI) HasSubordinates(args params.Entities) (params.BoolResults, error) {
   330  	result := params.BoolResults{
   331  		Results: make([]params.BoolResult, len(args.Entities)),
   332  	}
   333  	canAccess, err := u.accessUnit()
   334  	if err != nil {
   335  		return params.BoolResults{}, mask(err)
   336  	}
   337  	for i, entity := range args.Entities {
   338  		err := common.ErrPerm
   339  		if canAccess(entity.Tag) {
   340  			var unit *state.Unit
   341  			unit, err = u.getUnit(entity.Tag)
   342  			if err == nil {
   343  				subordinates := unit.SubordinateNames()
   344  				result.Results[i].Result = len(subordinates) > 0
   345  			}
   346  		}
   347  		result.Results[i].Error = common.ServerError(err)
   348  	}
   349  	return result, nil
   350  }
   351  
   352  // CharmURL returns the charm URL for all given units or services.
   353  func (u *UniterAPI) CharmURL(args params.Entities) (params.StringBoolResults, error) {
   354  	result := params.StringBoolResults{
   355  		Results: make([]params.StringBoolResult, len(args.Entities)),
   356  	}
   357  	accessUnitOrService := common.AuthEither(u.accessUnit, u.accessService)
   358  	canAccess, err := accessUnitOrService()
   359  	if err != nil {
   360  		return params.StringBoolResults{}, mask(err)
   361  	}
   362  	for i, entity := range args.Entities {
   363  		err := common.ErrPerm
   364  		if canAccess(entity.Tag) {
   365  			var unitOrService state.Entity
   366  			unitOrService, err = u.st.FindEntity(entity.Tag)
   367  			if err == nil {
   368  				charmURLer := unitOrService.(interface {
   369  					CharmURL() (*charm.URL, bool)
   370  				})
   371  				curl, ok := charmURLer.CharmURL()
   372  				if curl != nil {
   373  					result.Results[i].Result = curl.String()
   374  					result.Results[i].Ok = ok
   375  				}
   376  			}
   377  		}
   378  		result.Results[i].Error = common.ServerError(err)
   379  	}
   380  	return result, nil
   381  }
   382  
   383  // SetCharmURL sets the charm URL for each given unit. An error will
   384  // be returned if a unit is dead, or the charm URL is not know.
   385  func (u *UniterAPI) SetCharmURL(args params.EntitiesCharmURL) (params.ErrorResults, error) {
   386  	result := params.ErrorResults{
   387  		Results: make([]params.ErrorResult, len(args.Entities)),
   388  	}
   389  	canAccess, err := u.accessUnit()
   390  	if err != nil {
   391  		return params.ErrorResults{}, mask(err)
   392  	}
   393  	for i, entity := range args.Entities {
   394  		err := common.ErrPerm
   395  		if canAccess(entity.Tag) {
   396  			var unit *state.Unit
   397  			unit, err = u.getUnit(entity.Tag)
   398  			if err == nil {
   399  				var curl *charm.URL
   400  				curl, err = charm.ParseURL(entity.CharmURL)
   401  				if err == nil {
   402  					err = unit.SetCharmURL(curl)
   403  				}
   404  			}
   405  		}
   406  		result.Results[i].Error = common.ServerError(err)
   407  	}
   408  	return result, nil
   409  }
   410  
   411  // OpenPort sets the policy of the port with protocol an number to be
   412  // opened, for all given units.
   413  func (u *UniterAPI) OpenPort(args params.EntitiesPorts) (params.ErrorResults, error) {
   414  	result := params.ErrorResults{
   415  		Results: make([]params.ErrorResult, len(args.Entities)),
   416  	}
   417  	canAccess, err := u.accessUnit()
   418  	if err != nil {
   419  		return params.ErrorResults{}, mask(err)
   420  	}
   421  	for i, entity := range args.Entities {
   422  		err := common.ErrPerm
   423  		if canAccess(entity.Tag) {
   424  			var unit *state.Unit
   425  			unit, err = u.getUnit(entity.Tag)
   426  			if err == nil {
   427  				err = unit.OpenPort(entity.Protocol, entity.Port)
   428  			}
   429  		}
   430  		result.Results[i].Error = common.ServerError(err)
   431  	}
   432  	return result, nil
   433  }
   434  
   435  // ClosePort sets the policy of the port with protocol and number to
   436  // be closed, for all given units.
   437  func (u *UniterAPI) ClosePort(args params.EntitiesPorts) (params.ErrorResults, error) {
   438  	result := params.ErrorResults{
   439  		Results: make([]params.ErrorResult, len(args.Entities)),
   440  	}
   441  	canAccess, err := u.accessUnit()
   442  	if err != nil {
   443  		return params.ErrorResults{}, mask(err)
   444  	}
   445  	for i, entity := range args.Entities {
   446  		err := common.ErrPerm
   447  		if canAccess(entity.Tag) {
   448  			var unit *state.Unit
   449  			unit, err = u.getUnit(entity.Tag)
   450  			if err == nil {
   451  				err = unit.ClosePort(entity.Protocol, entity.Port)
   452  			}
   453  		}
   454  		result.Results[i].Error = common.ServerError(err)
   455  	}
   456  	return result, nil
   457  }
   458  
   459  func (u *UniterAPI) watchOneUnitConfigSettings(tag string) (string, error) {
   460  	unit, err := u.getUnit(tag)
   461  	if err != nil {
   462  		return "", mask(err, errors.IsNotFoundError)
   463  	}
   464  	watch, err := unit.WatchConfigSettings()
   465  	if err != nil {
   466  		return "", mask(err)
   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  	}
   472  
   473  	if _, ok := <-watch.Changes(); ok {
   474  		return u.resources.Register(watch), nil
   475  	}
   476  	return "", watcher.MustErr(watch)
   477  }
   478  
   479  // WatchConfigSettings returns a NotifyWatcher for observing changes
   480  // to each unit's service configuration settings. See also
   481  // state/watcher.go:Unit.WatchConfigSettings().
   482  func (u *UniterAPI) WatchConfigSettings(args params.Entities) (params.NotifyWatchResults, error) {
   483  	result := params.NotifyWatchResults{
   484  		Results: make([]params.NotifyWatchResult, len(args.Entities)),
   485  	}
   486  	canAccess, err := u.accessUnit()
   487  	if err != nil {
   488  		return params.NotifyWatchResults{}, mask(err)
   489  	}
   490  	for i, entity := range args.Entities {
   491  		err := common.ErrPerm
   492  		watcherId := ""
   493  		if canAccess(entity.Tag) {
   494  			watcherId, err = u.watchOneUnitConfigSettings(entity.Tag)
   495  		}
   496  		result.Results[i].NotifyWatcherId = watcherId
   497  		result.Results[i].Error = common.ServerError(err)
   498  	}
   499  	return result, nil
   500  }
   501  
   502  // ConfigSettings returns the complete set of service charm config
   503  // settings available to each given unit.
   504  func (u *UniterAPI) ConfigSettings(args params.Entities) (params.ConfigSettingsResults, error) {
   505  	result := params.ConfigSettingsResults{
   506  		Results: make([]params.ConfigSettingsResult, len(args.Entities)),
   507  	}
   508  	canAccess, err := u.accessUnit()
   509  	if err != nil {
   510  		return params.ConfigSettingsResults{}, mask(err)
   511  	}
   512  	for i, entity := range args.Entities {
   513  		err := common.ErrPerm
   514  		if canAccess(entity.Tag) {
   515  			var unit *state.Unit
   516  			unit, err = u.getUnit(entity.Tag)
   517  			if err == nil {
   518  				var settings charm.Settings
   519  				settings, err = unit.ConfigSettings()
   520  				if err == nil {
   521  					result.Results[i].Settings = params.ConfigSettings(settings)
   522  				}
   523  			}
   524  		}
   525  		result.Results[i].Error = common.ServerError(err)
   526  	}
   527  	return result, nil
   528  }
   529  
   530  func (u *UniterAPI) watchOneServiceRelations(tag string) (params.StringsWatchResult, error) {
   531  	nothing := params.StringsWatchResult{}
   532  	service, err := u.getService(tag)
   533  	if err != nil {
   534  		return nothing, mask(err)
   535  	}
   536  	watch := service.WatchRelations()
   537  	// Consume the initial event and forward it to the result.
   538  	if changes, ok := <-watch.Changes(); ok {
   539  		return params.StringsWatchResult{
   540  			StringsWatcherId: u.resources.Register(watch),
   541  			Changes:          changes,
   542  		}, nil
   543  	}
   544  	return nothing, watcher.MustErr(watch)
   545  }
   546  
   547  // WatchServiceRelations returns a StringsWatcher, for each given
   548  // service, that notifies of changes to the lifecycles of relations
   549  // involving that service.
   550  func (u *UniterAPI) WatchServiceRelations(args params.Entities) (params.StringsWatchResults, error) {
   551  	result := params.StringsWatchResults{
   552  		Results: make([]params.StringsWatchResult, len(args.Entities)),
   553  	}
   554  	canAccess, err := u.accessService()
   555  	if err != nil {
   556  		return params.StringsWatchResults{}, mask(err)
   557  	}
   558  	for i, entity := range args.Entities {
   559  		err := common.ErrPerm
   560  		if canAccess(entity.Tag) {
   561  			result.Results[i], err = u.watchOneServiceRelations(entity.Tag)
   562  		}
   563  		result.Results[i].Error = common.ServerError(err)
   564  	}
   565  	return result, nil
   566  }
   567  
   568  // CharmArchiveURL returns the URL, corresponding to the charm archive
   569  // (bundle) in the provider storage for each given charm URL, along
   570  // with the DisableSSLHostnameVerification flag.
   571  func (u *UniterAPI) CharmArchiveURL(args params.CharmURLs) (params.CharmArchiveURLResults, error) {
   572  	result := params.CharmArchiveURLResults{
   573  		Results: make([]params.CharmArchiveURLResult, len(args.URLs)),
   574  	}
   575  	// Get the SSL hostname verification environment setting.
   576  	envConfig, err := u.st.EnvironConfig()
   577  	if err != nil {
   578  		return result, mask(err)
   579  	}
   580  
   581  	// SSLHostnameVerification defaults to true, so we need to
   582  	// invert that, for backwards-compatibility (older versions
   583  	// will have DisableSSLHostnameVerification: false by default).
   584  	disableSSLHostnameVerification := !envConfig.SSLHostnameVerification()
   585  	for i, arg := range args.URLs {
   586  		curl, err := charm.ParseURL(arg.URL)
   587  		if err != nil {
   588  			err = common.ErrPerm
   589  		} else {
   590  			var sch *state.Charm
   591  			sch, err = u.st.Charm(curl)
   592  			if errors.IsNotFoundError(err) {
   593  				err = common.ErrPerm
   594  			}
   595  			if err == nil {
   596  				result.Results[i].Result = sch.BundleURL().String()
   597  				result.Results[i].DisableSSLHostnameVerification = disableSSLHostnameVerification
   598  			}
   599  		}
   600  		result.Results[i].Error = common.ServerError(err)
   601  	}
   602  	return result, nil
   603  }
   604  
   605  // CharmArchiveSha256 returns the SHA256 digest of the charm archive
   606  // (bundle) data for each charm url in the given parameters.
   607  func (u *UniterAPI) CharmArchiveSha256(args params.CharmURLs) (params.StringResults, error) {
   608  	result := params.StringResults{
   609  		Results: make([]params.StringResult, len(args.URLs)),
   610  	}
   611  	for i, arg := range args.URLs {
   612  		curl, err := charm.ParseURL(arg.URL)
   613  		if err != nil {
   614  			err = common.ErrPerm
   615  		} else {
   616  			var sch *state.Charm
   617  			sch, err = u.st.Charm(curl)
   618  			if errors.IsNotFoundError(err) {
   619  				err = common.ErrPerm
   620  			}
   621  			if err == nil {
   622  				result.Results[i].Result = sch.BundleSha256()
   623  			}
   624  		}
   625  		result.Results[i].Error = common.ServerError(err)
   626  	}
   627  	return result, nil
   628  }
   629  
   630  func (u *UniterAPI) getRelationAndUnit(canAccess common.AuthFunc, relTag, unitTag string) (*state.Relation, *state.Unit, error) {
   631  	_, key, err := names.ParseTag(relTag, names.RelationTagKind)
   632  	if err != nil {
   633  		return nil, nil, common.ErrPerm
   634  	}
   635  	rel, err := u.st.KeyRelation(key)
   636  	if errors.IsNotFoundError(err) {
   637  		return nil, nil, common.ErrPerm
   638  	} else if err != nil {
   639  		return nil, nil, mask(err)
   640  	}
   641  	if !canAccess(unitTag) {
   642  		return nil, nil, common.ErrPerm
   643  	}
   644  	unit, err := u.getUnit(unitTag)
   645  	return rel, unit, err
   646  }
   647  
   648  func (u *UniterAPI) prepareRelationResult(rel *state.Relation, unit *state.Unit) (params.RelationResult, error) {
   649  	nothing := params.RelationResult{}
   650  	ep, err := rel.Endpoint(unit.ServiceName())
   651  	if err != nil {
   652  		// An error here means the unit's service is not part of the
   653  		// relation.
   654  		return nothing, mask(err)
   655  	}
   656  	return params.RelationResult{
   657  		Id:   rel.Id(),
   658  		Key:  rel.String(),
   659  		Life: params.Life(rel.Life().String()),
   660  		Endpoint: params.Endpoint{
   661  			ServiceName: ep.ServiceName,
   662  			Relation:    ep.Relation,
   663  		},
   664  	}, nil
   665  }
   666  
   667  func (u *UniterAPI) getOneRelation(canAccess common.AuthFunc, relTag, unitTag string) (params.RelationResult, error) {
   668  	nothing := params.RelationResult{}
   669  	rel, unit, err := u.getRelationAndUnit(canAccess, relTag, unitTag)
   670  	if err != nil {
   671  		return nothing, mask(err, errgo.Any)
   672  	}
   673  	return u.prepareRelationResult(rel, unit)
   674  }
   675  
   676  func (u *UniterAPI) getOneRelationById(relId int) (params.RelationResult, error) {
   677  	nothing := params.RelationResult{}
   678  	rel, err := u.st.Relation(relId)
   679  	if errors.IsNotFoundError(err) {
   680  		return nothing, common.ErrPerm
   681  	} else if err != nil {
   682  		// Use the currently authenticated unit to get the endpoint.
   683  		return nothing, mask(err, errgo.Any)
   684  	}
   685  
   686  	unit, ok := u.auth.GetAuthEntity().(*state.Unit)
   687  	if !ok {
   688  		panic("authenticated entity is not a unit")
   689  	}
   690  	result, err := u.prepareRelationResult(rel, unit)
   691  	if err != nil {
   692  		// An error from prepareRelationResult means the authenticated
   693  		// unit's service is not part of the requested
   694  		// relation. That's why it's appropriate to return ErrPerm
   695  		// here.
   696  		return nothing, common.ErrPerm
   697  	}
   698  	return result, nil
   699  }
   700  
   701  func (u *UniterAPI) getRelationUnit(canAccess common.AuthFunc, relTag, unitTag string) (*state.RelationUnit, error) {
   702  	rel, unit, err := u.getRelationAndUnit(canAccess, relTag, unitTag)
   703  	if err != nil {
   704  		return nil, mask(err, errgo.Any)
   705  	}
   706  	return rel.Unit(unit)
   707  }
   708  
   709  // Relation returns information about all given relation/unit pairs,
   710  // including their id, key and the local endpoint.
   711  func (u *UniterAPI) Relation(args params.RelationUnits) (params.RelationResults, error) {
   712  	result := params.RelationResults{
   713  		Results: make([]params.RelationResult, len(args.RelationUnits)),
   714  	}
   715  	canAccess, err := u.accessUnit()
   716  	if err != nil {
   717  		return params.RelationResults{}, mask(err)
   718  	}
   719  	for i, rel := range args.RelationUnits {
   720  		relParams, err := u.getOneRelation(canAccess, rel.Relation, rel.Unit)
   721  		if err == nil {
   722  			result.Results[i] = relParams
   723  		}
   724  		result.Results[i].Error = common.ServerError(err)
   725  	}
   726  	return result, nil
   727  }
   728  
   729  // RelationById returns information about all given relations,
   730  // specified by their ids, including their key and the local
   731  // endpoint.
   732  func (u *UniterAPI) RelationById(args params.RelationIds) (params.RelationResults, error) {
   733  	result := params.RelationResults{
   734  		Results: make([]params.RelationResult, len(args.RelationIds)),
   735  	}
   736  	for i, relId := range args.RelationIds {
   737  		relParams, err := u.getOneRelationById(relId)
   738  		if err == nil {
   739  			result.Results[i] = relParams
   740  		}
   741  		result.Results[i].Error = common.ServerError(err)
   742  	}
   743  	return result, nil
   744  }
   745  
   746  // CurrentEnvironUUID returns the UUID for the current juju environment.
   747  func (u *UniterAPI) CurrentEnvironUUID() (params.StringResult, error) {
   748  	result := params.StringResult{}
   749  	env, err := u.st.Environment()
   750  	if err == nil {
   751  		result.Result = env.UUID()
   752  	}
   753  	return result, err
   754  }
   755  
   756  // CurrentEnvironment returns the name and UUID for the current juju environment.
   757  func (u *UniterAPI) CurrentEnvironment() (params.EnvironmentResult, error) {
   758  	result := params.EnvironmentResult{}
   759  	env, err := u.st.Environment()
   760  	if err == nil {
   761  		result.Name = env.Name()
   762  		result.UUID = env.UUID()
   763  	}
   764  	return result, err
   765  }
   766  
   767  // ProviderType returns the provider type used by the current juju
   768  // environment.
   769  //
   770  // TODO(dimitern): Refactor the uniter to call this instead of calling
   771  // EnvironConfig() just to get the provider type. Once we have machine
   772  // addresses, this might be completely unnecessary though.
   773  func (u *UniterAPI) ProviderType() (params.StringResult, error) {
   774  	result := params.StringResult{}
   775  	cfg, err := u.st.EnvironConfig()
   776  	if err == nil {
   777  		result.Result = cfg.Type()
   778  	}
   779  	return result, err
   780  }
   781  
   782  // EnterScope ensures each unit has entered its scope in the relation,
   783  // for all of the given relation/unit pairs. See also
   784  // state.RelationUnit.EnterScope().
   785  func (u *UniterAPI) EnterScope(args params.RelationUnits) (params.ErrorResults, error) {
   786  	result := params.ErrorResults{
   787  		Results: make([]params.ErrorResult, len(args.RelationUnits)),
   788  	}
   789  	canAccess, err := u.accessUnit()
   790  	if err != nil {
   791  		return params.ErrorResults{}, mask(err)
   792  	}
   793  	for i, arg := range args.RelationUnits {
   794  		relUnit, err := u.getRelationUnit(canAccess, arg.Relation, arg.Unit)
   795  		if err == nil {
   796  			// Construct the settings, passing the unit's
   797  			// private address (we already know it).
   798  			privateAddress, _ := relUnit.PrivateAddress()
   799  			settings := map[string]interface{}{
   800  				"private-address": privateAddress,
   801  			}
   802  			err = relUnit.EnterScope(settings)
   803  		}
   804  		result.Results[i].Error = common.ServerError(err)
   805  	}
   806  	return result, nil
   807  }
   808  
   809  // LeaveScope signals each unit has left its scope in the relation,
   810  // for all of the given relation/unit pairs. See also
   811  // state.RelationUnit.LeaveScope().
   812  func (u *UniterAPI) LeaveScope(args params.RelationUnits) (params.ErrorResults, error) {
   813  	result := params.ErrorResults{
   814  		Results: make([]params.ErrorResult, len(args.RelationUnits)),
   815  	}
   816  	canAccess, err := u.accessUnit()
   817  	if err != nil {
   818  		return params.ErrorResults{}, mask(err)
   819  	}
   820  	for i, arg := range args.RelationUnits {
   821  		relUnit, err := u.getRelationUnit(canAccess, arg.Relation, arg.Unit)
   822  		if err == nil {
   823  			err = relUnit.LeaveScope()
   824  		}
   825  		result.Results[i].Error = common.ServerError(err)
   826  	}
   827  	return result, nil
   828  }
   829  
   830  func convertRelationSettings(settings map[string]interface{}) (params.RelationSettings, error) {
   831  	result := make(params.RelationSettings)
   832  	for k, v := range settings {
   833  		// All relation settings should be strings.
   834  		sval, ok := v.(string)
   835  		if !ok {
   836  			return nil, errgo.Newf("unexpected relation setting %q: expected string, got %T", k, v)
   837  		}
   838  		result[k] = sval
   839  	}
   840  	return result, nil
   841  }
   842  
   843  // ReadSettings returns the local settings of each given set of
   844  // relation/unit.
   845  func (u *UniterAPI) ReadSettings(args params.RelationUnits) (params.RelationSettingsResults, error) {
   846  	result := params.RelationSettingsResults{
   847  		Results: make([]params.RelationSettingsResult, len(args.RelationUnits)),
   848  	}
   849  	canAccess, err := u.accessUnit()
   850  	if err != nil {
   851  		return params.RelationSettingsResults{}, mask(err)
   852  	}
   853  	for i, arg := range args.RelationUnits {
   854  		relUnit, err := u.getRelationUnit(canAccess, arg.Relation, arg.Unit)
   855  		if err == nil {
   856  			var settings *state.Settings
   857  			settings, err = relUnit.Settings()
   858  			if err == nil {
   859  				result.Results[i].Settings, err = convertRelationSettings(settings.Map())
   860  			}
   861  		}
   862  		result.Results[i].Error = common.ServerError(err)
   863  	}
   864  	return result, nil
   865  }
   866  
   867  func (u *UniterAPI) checkRemoteUnit(relUnit *state.RelationUnit, remoteUnitTag string) (string, error) {
   868  	// Make sure the unit is indeed remote.
   869  	if remoteUnitTag == u.auth.GetAuthTag() {
   870  		return "", common.ErrPerm
   871  	}
   872  	remoteUnit, err := u.getUnit(remoteUnitTag)
   873  	if err != nil {
   874  		return "", common.ErrPerm
   875  	}
   876  	// Check remoteUnit is indeed related.
   877  	rel := relUnit.Relation()
   878  	_, err = rel.RelatedEndpoints(remoteUnit.ServiceName())
   879  	if err != nil {
   880  		return "", common.ErrPerm
   881  	}
   882  	return remoteUnit.Name(), 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{}, mask(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{}, mask(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{}, mask(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, mask(err, errgo.Any)
   987  	}
   988  
   989  	return params.StringResult{
   990  		Result: service.GetOwnerTag(),
   991  	}, nil
   992  }