github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/watcher.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package apiserver
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/kr/pretty"
     9  
    10  	"github.com/juju/juju/apiserver/common"
    11  	"github.com/juju/juju/apiserver/common/crossmodel"
    12  	"github.com/juju/juju/apiserver/common/storagecommon"
    13  	apiservererrors "github.com/juju/juju/apiserver/errors"
    14  	"github.com/juju/juju/apiserver/facade"
    15  	"github.com/juju/juju/apiserver/facades/controller/crossmodelrelations"
    16  	"github.com/juju/juju/controller"
    17  	"github.com/juju/juju/core/cache"
    18  	"github.com/juju/juju/core/migration"
    19  	"github.com/juju/juju/core/multiwatcher"
    20  	"github.com/juju/juju/core/network"
    21  	coresecrets "github.com/juju/juju/core/secrets"
    22  	"github.com/juju/juju/core/status"
    23  	corewatcher "github.com/juju/juju/core/watcher"
    24  	"github.com/juju/juju/environs/config"
    25  	"github.com/juju/juju/rpc/params"
    26  	"github.com/juju/juju/state"
    27  )
    28  
    29  type watcherCommon struct {
    30  	id         string
    31  	resources  facade.Resources
    32  	dispose    func()
    33  	controller *cache.Controller
    34  }
    35  
    36  func newWatcherCommon(context facade.Context) watcherCommon {
    37  	return watcherCommon{
    38  		context.ID(),
    39  		context.Resources(),
    40  		context.Dispose,
    41  		context.Controller(),
    42  	}
    43  }
    44  
    45  // Stop stops the watcher.
    46  func (w *watcherCommon) Stop() error {
    47  	w.dispose()
    48  	return w.resources.Stop(w.id)
    49  }
    50  
    51  // SrvAllWatcher defines the API methods on a state.Multiwatcher.
    52  // which watches any changes to the state. Each client has its own
    53  // current set of watchers, stored in resources. It is used by both
    54  // the AllWatcher and AllModelWatcher facades.
    55  type SrvAllWatcher struct {
    56  	watcherCommon
    57  	watcher multiwatcher.Watcher
    58  
    59  	deltaTranslater DeltaTranslater
    60  }
    61  
    62  func newAllWatcher(context facade.Context, deltaTranslater DeltaTranslater) (*SrvAllWatcher, error) {
    63  	id := context.ID()
    64  	auth := context.Auth()
    65  	resources := context.Resources()
    66  
    67  	if !auth.AuthClient() {
    68  		// Note that we don't need to check specific permissions
    69  		// here, as the AllWatcher can only do anything if the
    70  		// watcher resource has already been created, so we can
    71  		// rely on the permission check there to ensure that
    72  		// this facade can't do anything it shouldn't be allowed
    73  		// to.
    74  		//
    75  		// This is useful because the AllWatcher is reused for
    76  		// both the WatchAll (requires model access rights) and
    77  		// the WatchAllModels (requring controller superuser
    78  		// rights) API calls.
    79  		return nil, apiservererrors.ErrPerm
    80  	}
    81  	watcher, ok := resources.Get(id).(multiwatcher.Watcher)
    82  	if !ok {
    83  		return nil, apiservererrors.ErrUnknownWatcher
    84  	}
    85  	return &SrvAllWatcher{
    86  		watcherCommon:   newWatcherCommon(context),
    87  		watcher:         watcher,
    88  		deltaTranslater: deltaTranslater,
    89  	}, nil
    90  }
    91  
    92  // NewAllWatcher returns a new API server endpoint for interacting
    93  // with a watcher created by the WatchAll and WatchAllModels API calls.
    94  func NewAllWatcher(context facade.Context) (facade.Facade, error) {
    95  	return newAllWatcher(context, newAllWatcherDeltaTranslater())
    96  }
    97  
    98  // Next will return the current state of everything on the first call
    99  // and subsequent calls will
   100  func (aw *SrvAllWatcher) Next() (params.AllWatcherNextResults, error) {
   101  	deltas, err := aw.watcher.Next()
   102  	return params.AllWatcherNextResults{
   103  		Deltas: translate(aw.deltaTranslater, deltas),
   104  	}, err
   105  }
   106  
   107  type allWatcherDeltaTranslater struct {
   108  	DeltaTranslater
   109  }
   110  
   111  func newAllWatcherDeltaTranslater() DeltaTranslater {
   112  	return &allWatcherDeltaTranslater{}
   113  }
   114  
   115  // DeltaTranslater defines methods for translating multiwatcher.EntityInfo to params.EntityInfo.
   116  type DeltaTranslater interface {
   117  	TranslateModel(multiwatcher.EntityInfo) params.EntityInfo
   118  	TranslateApplication(multiwatcher.EntityInfo) params.EntityInfo
   119  	TranslateRemoteApplication(multiwatcher.EntityInfo) params.EntityInfo
   120  	TranslateMachine(multiwatcher.EntityInfo) params.EntityInfo
   121  	TranslateUnit(multiwatcher.EntityInfo) params.EntityInfo
   122  	TranslateCharm(multiwatcher.EntityInfo) params.EntityInfo
   123  	TranslateRelation(multiwatcher.EntityInfo) params.EntityInfo
   124  	TranslateBranch(multiwatcher.EntityInfo) params.EntityInfo
   125  	TranslateAnnotation(multiwatcher.EntityInfo) params.EntityInfo
   126  	TranslateBlock(multiwatcher.EntityInfo) params.EntityInfo
   127  	TranslateAction(multiwatcher.EntityInfo) params.EntityInfo
   128  	TranslateApplicationOffer(multiwatcher.EntityInfo) params.EntityInfo
   129  }
   130  
   131  func translate(dt DeltaTranslater, deltas []multiwatcher.Delta) []params.Delta {
   132  	response := make([]params.Delta, 0, len(deltas))
   133  	for _, delta := range deltas {
   134  		id := delta.Entity.EntityID()
   135  		var converted params.EntityInfo
   136  		switch id.Kind {
   137  		case multiwatcher.ModelKind:
   138  			converted = dt.TranslateModel(delta.Entity)
   139  		case multiwatcher.ApplicationKind:
   140  			converted = dt.TranslateApplication(delta.Entity)
   141  		case multiwatcher.RemoteApplicationKind:
   142  			converted = dt.TranslateRemoteApplication(delta.Entity)
   143  		case multiwatcher.MachineKind:
   144  			converted = dt.TranslateMachine(delta.Entity)
   145  		case multiwatcher.UnitKind:
   146  			converted = dt.TranslateUnit(delta.Entity)
   147  		case multiwatcher.CharmKind:
   148  			converted = dt.TranslateCharm(delta.Entity)
   149  		case multiwatcher.RelationKind:
   150  			converted = dt.TranslateRelation(delta.Entity)
   151  		case multiwatcher.BranchKind:
   152  			converted = dt.TranslateBranch(delta.Entity)
   153  		case multiwatcher.AnnotationKind: // THIS SEEMS WEIRD
   154  			// FIXME: annotations should be part of the underlying entity.
   155  			converted = dt.TranslateAnnotation(delta.Entity)
   156  		case multiwatcher.BlockKind:
   157  			converted = dt.TranslateBlock(delta.Entity)
   158  		case multiwatcher.ActionKind:
   159  			converted = dt.TranslateAction(delta.Entity)
   160  		case multiwatcher.ApplicationOfferKind:
   161  			converted = dt.TranslateApplicationOffer(delta.Entity)
   162  		default:
   163  			// converted stays nil
   164  		}
   165  		// It is possible that there are some multiwatcher elements that are
   166  		// internal, and not exposed outside the controller.
   167  		// Also this is a key place to start versioning the all watchers.
   168  		if converted != nil {
   169  			response = append(response, params.Delta{
   170  				Removed: delta.Removed,
   171  				Entity:  converted})
   172  		}
   173  	}
   174  	return response
   175  }
   176  
   177  func (aw allWatcherDeltaTranslater) TranslateModel(info multiwatcher.EntityInfo) params.EntityInfo {
   178  	orig, ok := info.(*multiwatcher.ModelInfo)
   179  	if !ok {
   180  		logger.Criticalf("consistency error: %s", pretty.Sprint(info))
   181  		return nil
   182  	}
   183  
   184  	var version string
   185  	if cfg, err := config.New(config.NoDefaults, orig.Config); err == nil {
   186  		versionNumber, _ := cfg.AgentVersion()
   187  		version = versionNumber.String()
   188  	}
   189  
   190  	return &params.ModelUpdate{
   191  		ModelUUID:      orig.ModelUUID,
   192  		Name:           orig.Name,
   193  		Life:           orig.Life,
   194  		Owner:          orig.Owner,
   195  		ControllerUUID: orig.ControllerUUID,
   196  		IsController:   orig.IsController,
   197  		Config:         orig.Config,
   198  		Status:         aw.translateStatus(orig.Status),
   199  		Constraints:    orig.Constraints,
   200  		SLA: params.ModelSLAInfo{
   201  			Level: orig.SLA.Level,
   202  			Owner: orig.SLA.Owner,
   203  		},
   204  		Type:        orig.Type.String(),
   205  		Cloud:       orig.Cloud,
   206  		CloudRegion: orig.CloudRegion,
   207  		Version:     version,
   208  	}
   209  }
   210  
   211  func (aw allWatcherDeltaTranslater) translateStatus(info multiwatcher.StatusInfo) params.StatusInfo {
   212  	return params.StatusInfo{
   213  		Err:     info.Err, // CHECK THIS
   214  		Current: info.Current,
   215  		Message: info.Message,
   216  		Since:   info.Since,
   217  		Version: info.Version,
   218  		Data:    info.Data,
   219  	}
   220  }
   221  
   222  func (aw allWatcherDeltaTranslater) TranslateApplication(info multiwatcher.EntityInfo) params.EntityInfo {
   223  	orig, ok := info.(*multiwatcher.ApplicationInfo)
   224  	if !ok {
   225  		logger.Criticalf("consistency error: %s", pretty.Sprint(info))
   226  		return nil
   227  	}
   228  
   229  	// If the application status is unset, then set it to unknown. It is
   230  	// expected that downstream clients (model cache, pylibjuju, jslibjuju)
   231  	// correctly interpret the unknown status from the unit status. If the unit
   232  	// status is not found, then fall back to unknown.
   233  	// If a charm author has set the application status, then show that instead.
   234  	applicationStatus := multiwatcher.StatusInfo{Current: status.Unset}
   235  	if orig.Status.Current != status.Unset {
   236  		applicationStatus = orig.Status
   237  	}
   238  
   239  	return &params.ApplicationInfo{
   240  		ModelUUID:       orig.ModelUUID,
   241  		Name:            orig.Name,
   242  		Exposed:         orig.Exposed,
   243  		CharmURL:        orig.CharmURL,
   244  		OwnerTag:        orig.OwnerTag,
   245  		Life:            orig.Life,
   246  		MinUnits:        orig.MinUnits,
   247  		Constraints:     orig.Constraints,
   248  		Config:          orig.Config,
   249  		Subordinate:     orig.Subordinate,
   250  		Status:          aw.translateStatus(applicationStatus),
   251  		WorkloadVersion: orig.WorkloadVersion,
   252  	}
   253  }
   254  
   255  func (aw allWatcherDeltaTranslater) TranslateMachine(info multiwatcher.EntityInfo) params.EntityInfo {
   256  	orig, ok := info.(*multiwatcher.MachineInfo)
   257  	if !ok {
   258  		logger.Criticalf("consistency error: %s", pretty.Sprint(info))
   259  		return nil
   260  	}
   261  	return &params.MachineInfo{
   262  		ModelUUID:                orig.ModelUUID,
   263  		Id:                       orig.ID,
   264  		InstanceId:               orig.InstanceID,
   265  		AgentStatus:              aw.translateStatus(orig.AgentStatus),
   266  		InstanceStatus:           aw.translateStatus(orig.InstanceStatus),
   267  		Life:                     orig.Life,
   268  		Config:                   orig.Config,
   269  		Base:                     orig.Base,
   270  		ContainerType:            orig.ContainerType,
   271  		IsManual:                 orig.IsManual,
   272  		SupportedContainers:      orig.SupportedContainers,
   273  		SupportedContainersKnown: orig.SupportedContainersKnown,
   274  		HardwareCharacteristics:  orig.HardwareCharacteristics,
   275  		CharmProfiles:            orig.CharmProfiles,
   276  		Jobs:                     orig.Jobs,
   277  		Addresses:                aw.translateAddresses(orig.Addresses),
   278  		HasVote:                  orig.HasVote,
   279  		WantsVote:                orig.WantsVote,
   280  		Hostname:                 orig.Hostname,
   281  	}
   282  }
   283  
   284  func (aw allWatcherDeltaTranslater) translateAddresses(addresses []network.ProviderAddress) []params.Address {
   285  	if addresses == nil {
   286  		return nil
   287  	}
   288  	result := make([]params.Address, 0, len(addresses))
   289  	for _, address := range addresses {
   290  		result = append(result, params.Address{
   291  			Value:           address.Value,
   292  			Type:            string(address.Type),
   293  			Scope:           string(address.Scope),
   294  			SpaceName:       string(address.SpaceName),
   295  			ProviderSpaceID: string(address.ProviderSpaceID),
   296  		})
   297  	}
   298  	return result
   299  }
   300  
   301  func (aw allWatcherDeltaTranslater) TranslateCharm(info multiwatcher.EntityInfo) params.EntityInfo {
   302  	orig, ok := info.(*multiwatcher.CharmInfo)
   303  	if !ok {
   304  		logger.Criticalf("consistency error: %s", pretty.Sprint(info))
   305  		return nil
   306  	}
   307  	return &params.CharmInfo{
   308  		ModelUUID:     orig.ModelUUID,
   309  		CharmURL:      orig.CharmURL,
   310  		CharmVersion:  orig.CharmVersion,
   311  		Life:          orig.Life,
   312  		LXDProfile:    aw.translateProfile(orig.LXDProfile),
   313  		DefaultConfig: orig.DefaultConfig,
   314  	}
   315  }
   316  
   317  func (aw allWatcherDeltaTranslater) translateProfile(profile *multiwatcher.Profile) *params.Profile {
   318  	if profile == nil {
   319  		return nil
   320  	}
   321  	return &params.Profile{
   322  		Config:      profile.Config,
   323  		Description: profile.Description,
   324  		Devices:     profile.Devices,
   325  	}
   326  }
   327  
   328  func (aw allWatcherDeltaTranslater) TranslateRemoteApplication(info multiwatcher.EntityInfo) params.EntityInfo {
   329  	orig, ok := info.(*multiwatcher.RemoteApplicationUpdate)
   330  	if !ok {
   331  		logger.Criticalf("consistency error: %s", pretty.Sprint(info))
   332  		return nil
   333  	}
   334  	return &params.RemoteApplicationUpdate{
   335  		ModelUUID: orig.ModelUUID,
   336  		Name:      orig.Name,
   337  		OfferURL:  orig.OfferURL,
   338  		Life:      orig.Life,
   339  		Status:    aw.translateStatus(orig.Status),
   340  	}
   341  }
   342  
   343  func (aw allWatcherDeltaTranslater) TranslateApplicationOffer(info multiwatcher.EntityInfo) params.EntityInfo {
   344  	orig, ok := info.(*multiwatcher.ApplicationOfferInfo)
   345  	if !ok {
   346  		logger.Criticalf("consistency error: %s", pretty.Sprint(info))
   347  		return nil
   348  	}
   349  	return &params.ApplicationOfferInfo{
   350  		ModelUUID:            orig.ModelUUID,
   351  		OfferName:            orig.OfferName,
   352  		OfferUUID:            orig.OfferUUID,
   353  		ApplicationName:      orig.ApplicationName,
   354  		CharmName:            orig.CharmName,
   355  		TotalConnectedCount:  orig.TotalConnectedCount,
   356  		ActiveConnectedCount: orig.ActiveConnectedCount,
   357  	}
   358  }
   359  
   360  func (aw allWatcherDeltaTranslater) TranslateUnit(info multiwatcher.EntityInfo) params.EntityInfo {
   361  	orig, ok := info.(*multiwatcher.UnitInfo)
   362  	if !ok {
   363  		logger.Criticalf("consistency error: %s", pretty.Sprint(info))
   364  		return nil
   365  	}
   366  
   367  	translatedPortRanges := aw.translatePortRanges(orig.OpenPortRangesByEndpoint)
   368  
   369  	return &params.UnitInfo{
   370  		ModelUUID:      orig.ModelUUID,
   371  		Name:           orig.Name,
   372  		Application:    orig.Application,
   373  		Base:           orig.Base,
   374  		CharmURL:       orig.CharmURL,
   375  		Life:           orig.Life,
   376  		PublicAddress:  orig.PublicAddress,
   377  		PrivateAddress: orig.PrivateAddress,
   378  		MachineId:      orig.MachineID,
   379  		Ports:          aw.mapRangesIntoPorts(translatedPortRanges),
   380  		PortRanges:     translatedPortRanges,
   381  		Principal:      orig.Principal,
   382  		Subordinate:    orig.Subordinate,
   383  		WorkloadStatus: aw.translateStatus(orig.WorkloadStatus),
   384  		AgentStatus:    aw.translateStatus(orig.AgentStatus),
   385  	}
   386  }
   387  
   388  func (aw allWatcherDeltaTranslater) mapRangesIntoPorts(portRanges []params.PortRange) []params.Port {
   389  	if portRanges == nil {
   390  		return nil
   391  	}
   392  	result := make([]params.Port, 0, len(portRanges))
   393  	for _, pr := range portRanges {
   394  		for portNum := pr.FromPort; portNum <= pr.ToPort; portNum++ {
   395  			result = append(result, params.Port{
   396  				Protocol: pr.Protocol,
   397  				Number:   portNum,
   398  			})
   399  		}
   400  	}
   401  	return result
   402  }
   403  
   404  // translatePortRanges flattens a set of port ranges grouped by endpoint into
   405  // a list of unique port ranges. This method ignores subnet IDs and is provided
   406  // for backwards compatibility with pre 2.9 clients that assume that open-ports
   407  // applies to all subnets.
   408  func (aw allWatcherDeltaTranslater) translatePortRanges(portsByEndpoint network.GroupedPortRanges) []params.PortRange {
   409  	if portsByEndpoint == nil {
   410  		return nil
   411  	}
   412  
   413  	uniquePortRanges := portsByEndpoint.UniquePortRanges()
   414  	network.SortPortRanges(uniquePortRanges)
   415  
   416  	result := make([]params.PortRange, len(uniquePortRanges))
   417  	for i, pr := range uniquePortRanges {
   418  		result[i] = params.FromNetworkPortRange(pr)
   419  	}
   420  
   421  	return result
   422  }
   423  
   424  func (aw allWatcherDeltaTranslater) TranslateAction(info multiwatcher.EntityInfo) params.EntityInfo {
   425  	orig, ok := info.(*multiwatcher.ActionInfo)
   426  	if !ok {
   427  		logger.Criticalf("consistency error: %s", pretty.Sprint(info))
   428  		return nil
   429  	}
   430  	return &params.ActionInfo{
   431  		ModelUUID: orig.ModelUUID,
   432  		Id:        orig.ID,
   433  		Receiver:  orig.Receiver,
   434  		Name:      orig.Name,
   435  		Status:    orig.Status,
   436  		Message:   orig.Message,
   437  		Enqueued:  orig.Enqueued,
   438  		Started:   orig.Started,
   439  		Completed: orig.Completed,
   440  	}
   441  }
   442  
   443  func (aw allWatcherDeltaTranslater) TranslateRelation(info multiwatcher.EntityInfo) params.EntityInfo {
   444  	orig, ok := info.(*multiwatcher.RelationInfo)
   445  	if !ok {
   446  		logger.Criticalf("consistency error: %s", pretty.Sprint(info))
   447  		return nil
   448  	}
   449  	return &params.RelationInfo{
   450  		ModelUUID: orig.ModelUUID,
   451  		Key:       orig.Key,
   452  		Id:        orig.ID,
   453  		Endpoints: aw.translateEndpoints(orig.Endpoints),
   454  	}
   455  }
   456  
   457  func (aw allWatcherDeltaTranslater) translateEndpoints(eps []multiwatcher.Endpoint) []params.Endpoint {
   458  	if eps == nil {
   459  		return nil
   460  	}
   461  	result := make([]params.Endpoint, 0, len(eps))
   462  	for _, ep := range eps {
   463  		result = append(result, params.Endpoint{
   464  			ApplicationName: ep.ApplicationName,
   465  			Relation: params.CharmRelation{
   466  				Name:      ep.Relation.Name,
   467  				Role:      ep.Relation.Role,
   468  				Interface: ep.Relation.Interface,
   469  				Optional:  ep.Relation.Optional,
   470  				Limit:     ep.Relation.Limit,
   471  				Scope:     ep.Relation.Scope,
   472  			},
   473  		})
   474  	}
   475  	return result
   476  }
   477  
   478  func (aw allWatcherDeltaTranslater) TranslateAnnotation(info multiwatcher.EntityInfo) params.EntityInfo {
   479  	orig, ok := info.(*multiwatcher.AnnotationInfo)
   480  	if !ok {
   481  		logger.Criticalf("consistency error: %s", pretty.Sprint(info))
   482  		return nil
   483  	}
   484  	return &params.AnnotationInfo{
   485  		ModelUUID:   orig.ModelUUID,
   486  		Tag:         orig.Tag,
   487  		Annotations: orig.Annotations,
   488  	}
   489  }
   490  
   491  func (aw allWatcherDeltaTranslater) TranslateBlock(info multiwatcher.EntityInfo) params.EntityInfo {
   492  	orig, ok := info.(*multiwatcher.BlockInfo)
   493  	if !ok {
   494  		logger.Criticalf("consistency error: %s", pretty.Sprint(info))
   495  		return nil
   496  	}
   497  	return &params.BlockInfo{
   498  		ModelUUID: orig.ModelUUID,
   499  		Id:        orig.ID,
   500  		Type:      orig.Type,
   501  		Message:   orig.Message,
   502  		Tag:       orig.Tag,
   503  	}
   504  }
   505  
   506  func (aw allWatcherDeltaTranslater) TranslateBranch(info multiwatcher.EntityInfo) params.EntityInfo {
   507  	orig, ok := info.(*multiwatcher.BranchInfo)
   508  	if !ok {
   509  		logger.Criticalf("consistency error: %s", pretty.Sprint(info))
   510  		return nil
   511  	}
   512  	return &params.BranchInfo{
   513  		ModelUUID:     orig.ModelUUID,
   514  		Id:            orig.ID,
   515  		Name:          orig.Name,
   516  		AssignedUnits: orig.AssignedUnits,
   517  		Config:        aw.translateBranchConfig(orig.Config),
   518  		Created:       orig.Created,
   519  		CreatedBy:     orig.CreatedBy,
   520  		Completed:     orig.Completed,
   521  		CompletedBy:   orig.CompletedBy,
   522  		GenerationId:  orig.GenerationID,
   523  	}
   524  }
   525  
   526  func (aw allWatcherDeltaTranslater) translateBranchConfig(config map[string][]multiwatcher.ItemChange) map[string][]params.ItemChange {
   527  	if config == nil {
   528  		return nil
   529  	}
   530  	result := make(map[string][]params.ItemChange)
   531  	for key, value := range config {
   532  		if value == nil {
   533  			result[key] = nil
   534  		} else {
   535  			changes := make([]params.ItemChange, 0, len(value))
   536  			for _, change := range value {
   537  				changes = append(changes, params.ItemChange{
   538  					Type:     change.Type,
   539  					Key:      change.Key,
   540  					OldValue: change.OldValue,
   541  					NewValue: change.NewValue,
   542  				})
   543  			}
   544  			result[key] = changes
   545  		}
   546  	}
   547  	return result
   548  }
   549  
   550  func isAgent(auth facade.Authorizer) bool {
   551  	return auth.AuthMachineAgent() || auth.AuthUnitAgent() || auth.AuthApplicationAgent() || auth.AuthModelAgent()
   552  }
   553  
   554  func isAgentOrUser(auth facade.Authorizer) bool {
   555  	return isAgent(auth) || auth.AuthClient()
   556  }
   557  
   558  func newNotifyWatcher(context facade.Context) (facade.Facade, error) {
   559  	id := context.ID()
   560  	auth := context.Auth()
   561  	resources := context.Resources()
   562  
   563  	// TODO(wallyworld) - enhance this watcher to support
   564  	// anonymous api calls with macaroons.
   565  	if auth.GetAuthTag() != nil && !isAgentOrUser(auth) {
   566  		return nil, apiservererrors.ErrPerm
   567  	}
   568  
   569  	watcher, ok := resources.Get(id).(cache.NotifyWatcher)
   570  	if !ok {
   571  		return nil, apiservererrors.ErrUnknownWatcher
   572  	}
   573  
   574  	return &srvNotifyWatcher{
   575  		watcherCommon: newWatcherCommon(context),
   576  		watcher:       watcher,
   577  	}, nil
   578  }
   579  
   580  // srvNotifyWatcher defines the API access to methods on a NotifyWatcher.
   581  // Each client has its own current set of watchers, stored in resources.
   582  type srvNotifyWatcher struct {
   583  	watcherCommon
   584  	watcher cache.NotifyWatcher
   585  }
   586  
   587  // state watchers have an Err method, but cache watchers do not.
   588  type hasErr interface {
   589  	Err() error
   590  }
   591  
   592  // Next returns when a change has occurred to the
   593  // entity being watched since the most recent call to Next
   594  // or the Watch call that created the NotifyWatcher.
   595  func (w *srvNotifyWatcher) Next() error {
   596  	if _, ok := <-w.watcher.Changes(); ok {
   597  		return nil
   598  	}
   599  
   600  	var err error
   601  	if e, ok := w.watcher.(hasErr); ok {
   602  		err = e.Err()
   603  	}
   604  	if err == nil {
   605  		err = apiservererrors.ErrStoppedWatcher
   606  	}
   607  	return err
   608  }
   609  
   610  // srvStringsWatcher defines the API for methods on a state.StringsWatcher.
   611  // Each client has its own current set of watchers, stored in resources.
   612  // srvStringsWatcher notifies about changes for all entities of a given kind,
   613  // sending the changes as a list of strings.
   614  type srvStringsWatcher struct {
   615  	watcherCommon
   616  	watcher cache.StringsWatcher
   617  }
   618  
   619  func newStringsWatcher(context facade.Context) (facade.Facade, error) {
   620  	id := context.ID()
   621  	auth := context.Auth()
   622  	resources := context.Resources()
   623  
   624  	// TODO(wallyworld) - enhance this watcher to support
   625  	// anonymous api calls with macaroons.
   626  	if auth.GetAuthTag() != nil && !isAgentOrUser(auth) {
   627  		return nil, apiservererrors.ErrPerm
   628  	}
   629  	watcher, ok := resources.Get(id).(cache.StringsWatcher)
   630  	if !ok {
   631  		return nil, apiservererrors.ErrUnknownWatcher
   632  	}
   633  	return &srvStringsWatcher{
   634  		watcherCommon: newWatcherCommon(context),
   635  		watcher:       watcher,
   636  	}, nil
   637  }
   638  
   639  // Next returns when a change has occurred to an entity of the
   640  // collection being watched since the most recent call to Next
   641  // or the Watch call that created the srvStringsWatcher.
   642  func (w *srvStringsWatcher) Next() (params.StringsWatchResult, error) {
   643  	if changes, ok := <-w.watcher.Changes(); ok {
   644  		return params.StringsWatchResult{
   645  			Changes: changes,
   646  		}, nil
   647  	}
   648  	var err error
   649  	if e, ok := w.watcher.(hasErr); ok {
   650  		err = e.Err()
   651  	}
   652  	if err == nil {
   653  		err = apiservererrors.ErrStoppedWatcher
   654  	}
   655  	return params.StringsWatchResult{}, err
   656  }
   657  
   658  // srvRelationUnitsWatcher defines the API wrapping a state.RelationUnitsWatcher.
   659  // It notifies about units entering and leaving the scope of a RelationUnit,
   660  // and changes to the settings of those units known to have entered.
   661  type srvRelationUnitsWatcher struct {
   662  	watcherCommon
   663  	watcher common.RelationUnitsWatcher
   664  }
   665  
   666  func newRelationUnitsWatcher(context facade.Context) (facade.Facade, error) {
   667  	id := context.ID()
   668  	auth := context.Auth()
   669  	resources := context.Resources()
   670  
   671  	// TODO(wallyworld) - enhance this watcher to support
   672  	// anonymous api calls with macaroons.
   673  	if auth.GetAuthTag() != nil && !isAgent(auth) {
   674  		return nil, apiservererrors.ErrPerm
   675  	}
   676  	watcher, ok := resources.Get(id).(common.RelationUnitsWatcher)
   677  	if !ok {
   678  		return nil, apiservererrors.ErrUnknownWatcher
   679  	}
   680  	return &srvRelationUnitsWatcher{
   681  		watcherCommon: newWatcherCommon(context),
   682  		watcher:       watcher,
   683  	}, nil
   684  }
   685  
   686  // Next returns when a change has occurred to an entity of the
   687  // collection being watched since the most recent call to Next
   688  // or the Watch call that created the srvRelationUnitsWatcher.
   689  func (w *srvRelationUnitsWatcher) Next() (params.RelationUnitsWatchResult, error) {
   690  	if changes, ok := <-w.watcher.Changes(); ok {
   691  		return params.RelationUnitsWatchResult{
   692  			Changes: changes,
   693  		}, nil
   694  	}
   695  	err := w.watcher.Err()
   696  	if err == nil {
   697  		err = apiservererrors.ErrStoppedWatcher
   698  	}
   699  	return params.RelationUnitsWatchResult{}, err
   700  }
   701  
   702  // srvRemoteRelationWatcher defines the API wrapping a
   703  // state.RelationUnitsWatcher but serving the events it emits as
   704  // fully-expanded params.RemoteRelationChangeEvents so they can be
   705  // used across model/controller boundaries.
   706  type srvRemoteRelationWatcher struct {
   707  	watcherCommon
   708  	backend crossmodel.Backend
   709  	watcher *crossmodel.WrappedUnitsWatcher
   710  }
   711  
   712  func newRemoteRelationWatcher(context facade.Context) (facade.Facade, error) {
   713  	id := context.ID()
   714  	auth := context.Auth()
   715  	resources := context.Resources()
   716  
   717  	// TODO(wallyworld) - enhance this watcher to support
   718  	// anonymous api calls with macaroons.
   719  	if auth.GetAuthTag() != nil && !isAgent(auth) {
   720  		return nil, apiservererrors.ErrPerm
   721  	}
   722  	watcher, ok := resources.Get(id).(*crossmodel.WrappedUnitsWatcher)
   723  	if !ok {
   724  		return nil, apiservererrors.ErrUnknownWatcher
   725  	}
   726  	return &srvRemoteRelationWatcher{
   727  		watcherCommon: newWatcherCommon(context),
   728  		backend:       crossmodel.GetBackend(context.State()),
   729  		watcher:       watcher,
   730  	}, nil
   731  }
   732  
   733  func (w *srvRemoteRelationWatcher) Next() (params.RemoteRelationWatchResult, error) {
   734  	if change, ok := <-w.watcher.Changes(); ok {
   735  		// Expand the change into a cross-model event.
   736  		expanded, err := crossmodel.ExpandChange(
   737  			w.backend,
   738  			w.watcher.RelationToken,
   739  			w.watcher.ApplicationToken,
   740  			change,
   741  		)
   742  		if err != nil {
   743  			return params.RemoteRelationWatchResult{
   744  				Error: apiservererrors.ServerError(err),
   745  			}, nil
   746  		}
   747  		return params.RemoteRelationWatchResult{
   748  			Changes: expanded,
   749  		}, nil
   750  	}
   751  	err := w.watcher.Err()
   752  	if err == nil {
   753  		err = apiservererrors.ErrStoppedWatcher
   754  	}
   755  	return params.RemoteRelationWatchResult{}, err
   756  }
   757  
   758  // srvRelationStatusWatcher defines the API wrapping a state.RelationStatusWatcher.
   759  type srvRelationStatusWatcher struct {
   760  	watcherCommon
   761  	st      *state.State
   762  	watcher state.StringsWatcher
   763  }
   764  
   765  func newRelationStatusWatcher(context facade.Context) (facade.Facade, error) {
   766  	id := context.ID()
   767  	auth := context.Auth()
   768  	resources := context.Resources()
   769  
   770  	// TODO(wallyworld) - enhance this watcher to support
   771  	// anonymous api calls with macaroons.
   772  	if auth.GetAuthTag() != nil && !isAgent(auth) {
   773  		return nil, apiservererrors.ErrPerm
   774  	}
   775  	watcher, ok := resources.Get(id).(state.StringsWatcher)
   776  	if !ok {
   777  		return nil, apiservererrors.ErrUnknownWatcher
   778  	}
   779  	return &srvRelationStatusWatcher{
   780  		watcherCommon: newWatcherCommon(context),
   781  		st:            context.State(),
   782  		watcher:       watcher,
   783  	}, nil
   784  }
   785  
   786  // Next returns when a change has occurred to an entity of the
   787  // collection being watched since the most recent call to Next
   788  // or the Watch call that created the srvRelationStatusWatcher.
   789  func (w *srvRelationStatusWatcher) Next() (params.RelationLifeSuspendedStatusWatchResult, error) {
   790  	if changes, ok := <-w.watcher.Changes(); ok {
   791  		changesParams := make([]params.RelationLifeSuspendedStatusChange, len(changes))
   792  		for i, key := range changes {
   793  			change, err := crossmodel.GetRelationLifeSuspendedStatusChange(crossmodel.GetBackend(w.st), key)
   794  			if err != nil {
   795  				return params.RelationLifeSuspendedStatusWatchResult{
   796  					Error: apiservererrors.ServerError(err),
   797  				}, nil
   798  			}
   799  			changesParams[i] = *change
   800  		}
   801  		return params.RelationLifeSuspendedStatusWatchResult{
   802  			Changes: changesParams,
   803  		}, nil
   804  	}
   805  	err := w.watcher.Err()
   806  	if err == nil {
   807  		err = apiservererrors.ErrStoppedWatcher
   808  	}
   809  	return params.RelationLifeSuspendedStatusWatchResult{}, err
   810  }
   811  
   812  // srvOfferStatusWatcher defines the API wrapping a crossmodelrelations.OfferStatusWatcher.
   813  type srvOfferStatusWatcher struct {
   814  	watcherCommon
   815  	st      *state.State
   816  	watcher crossmodelrelations.OfferWatcher
   817  }
   818  
   819  func newOfferStatusWatcher(context facade.Context) (facade.Facade, error) {
   820  	id := context.ID()
   821  	auth := context.Auth()
   822  	resources := context.Resources()
   823  
   824  	st := context.State()
   825  
   826  	// TODO(wallyworld) - enhance this watcher to support
   827  	// anonymous api calls with macaroons.
   828  	if auth.GetAuthTag() != nil && !isAgent(auth) {
   829  		return nil, apiservererrors.ErrPerm
   830  	}
   831  	watcher, ok := resources.Get(id).(crossmodelrelations.OfferWatcher)
   832  	if !ok {
   833  		return nil, apiservererrors.ErrUnknownWatcher
   834  	}
   835  	return &srvOfferStatusWatcher{
   836  		watcherCommon: newWatcherCommon(context),
   837  		st:            st,
   838  		watcher:       watcher,
   839  	}, nil
   840  }
   841  
   842  // Next returns when a change has occurred to an entity of the
   843  // collection being watched since the most recent call to Next
   844  // or the Watch call that created the srvOfferStatusWatcher.
   845  func (w *srvOfferStatusWatcher) Next() (params.OfferStatusWatchResult, error) {
   846  	if _, ok := <-w.watcher.Changes(); ok {
   847  		change, err := crossmodel.GetOfferStatusChange(
   848  			crossmodel.GetBackend(w.st),
   849  			w.watcher.OfferUUID(), w.watcher.OfferName())
   850  		if err != nil {
   851  			// For the specific case where we are informed that a migration is
   852  			// in progress, we want to return an error that causes the client
   853  			// to stop watching, rather than in the payload.
   854  			if errors.Is(err, migration.ErrMigrating) {
   855  				return params.OfferStatusWatchResult{}, err
   856  			}
   857  
   858  			return params.OfferStatusWatchResult{Error: apiservererrors.ServerError(err)}, nil
   859  		}
   860  		return params.OfferStatusWatchResult{
   861  			Changes: []params.OfferStatusChange{*change},
   862  		}, nil
   863  	}
   864  	err := w.watcher.Err()
   865  	if err == nil {
   866  		err = apiservererrors.ErrStoppedWatcher
   867  	}
   868  	return params.OfferStatusWatchResult{}, err
   869  }
   870  
   871  // srvMachineStorageIdsWatcher defines the API wrapping a state.StringsWatcher
   872  // watching machine/storage attachments. This watcher notifies about storage
   873  // entities (volumes/filesystems) being attached to and detached from machines.
   874  //
   875  // TODO(axw) state needs a new watcher, this is a bt of a hack. State watchers
   876  // could do with some deduplication of logic, and I don't want to add to that
   877  // spaghetti right now.
   878  type srvMachineStorageIdsWatcher struct {
   879  	watcherCommon
   880  	watcher state.StringsWatcher
   881  	parser  func([]string) ([]params.MachineStorageId, error)
   882  }
   883  
   884  func newVolumeAttachmentsWatcher(context facade.Context) (facade.Facade, error) {
   885  	return newMachineStorageIdsWatcher(
   886  		context,
   887  		storagecommon.ParseVolumeAttachmentIds,
   888  	)
   889  }
   890  
   891  func newVolumeAttachmentPlansWatcher(context facade.Context) (facade.Facade, error) {
   892  	return newMachineStorageIdsWatcher(
   893  		context,
   894  		storagecommon.ParseVolumeAttachmentIds,
   895  	)
   896  }
   897  
   898  func newFilesystemAttachmentsWatcher(context facade.Context) (facade.Facade, error) {
   899  	return newMachineStorageIdsWatcher(
   900  		context,
   901  		storagecommon.ParseFilesystemAttachmentIds,
   902  	)
   903  }
   904  
   905  func newMachineStorageIdsWatcher(
   906  	context facade.Context,
   907  	parser func([]string) ([]params.MachineStorageId, error),
   908  ) (facade.Facade, error) {
   909  	id := context.ID()
   910  	auth := context.Auth()
   911  	resources := context.Resources()
   912  	if !isAgent(auth) {
   913  		return nil, apiservererrors.ErrPerm
   914  	}
   915  	watcher, ok := resources.Get(id).(state.StringsWatcher)
   916  	if !ok {
   917  		return nil, apiservererrors.ErrUnknownWatcher
   918  	}
   919  	return &srvMachineStorageIdsWatcher{
   920  		watcherCommon: newWatcherCommon(context),
   921  		watcher:       watcher,
   922  		parser:        parser,
   923  	}, nil
   924  }
   925  
   926  // Next returns when a change has occurred to an entity of the
   927  // collection being watched since the most recent call to Next
   928  // or the Watch call that created the srvMachineStorageIdsWatcher.
   929  func (w *srvMachineStorageIdsWatcher) Next() (params.MachineStorageIdsWatchResult, error) {
   930  	if stringChanges, ok := <-w.watcher.Changes(); ok {
   931  		changes, err := w.parser(stringChanges)
   932  		if err != nil {
   933  			return params.MachineStorageIdsWatchResult{}, err
   934  		}
   935  		return params.MachineStorageIdsWatchResult{
   936  			Changes: changes,
   937  		}, nil
   938  	}
   939  	err := w.watcher.Err()
   940  	if err == nil {
   941  		err = apiservererrors.ErrStoppedWatcher
   942  	}
   943  	return params.MachineStorageIdsWatchResult{}, err
   944  }
   945  
   946  // EntitiesWatcher defines an interface based on the StringsWatcher
   947  // but also providing a method for the mapping of the received
   948  // strings to the tags of the according entities.
   949  type EntitiesWatcher interface {
   950  	state.StringsWatcher
   951  
   952  	// MapChanges maps the received strings to their according tag strings.
   953  	// The EntityFinder interface representing state or a mock has to be
   954  	// upcasted into the needed sub-interface of state for the real mapping.
   955  	MapChanges(in []string) ([]string, error)
   956  }
   957  
   958  // srvEntitiesWatcher defines the API for methods on a state.StringsWatcher.
   959  // Each client has its own current set of watchers, stored in resources.
   960  // srvEntitiesWatcher notifies about changes for all entities of a given kind,
   961  // sending the changes as a list of strings, which could be transformed
   962  // from state entity ids to their corresponding entity tags.
   963  type srvEntitiesWatcher struct {
   964  	watcherCommon
   965  	watcher EntitiesWatcher
   966  }
   967  
   968  func newEntitiesWatcher(context facade.Context) (facade.Facade, error) {
   969  	id := context.ID()
   970  	auth := context.Auth()
   971  	resources := context.Resources()
   972  
   973  	if !isAgent(auth) {
   974  		return nil, apiservererrors.ErrPerm
   975  	}
   976  	watcher, ok := resources.Get(id).(EntitiesWatcher)
   977  	if !ok {
   978  		return nil, apiservererrors.ErrUnknownWatcher
   979  	}
   980  	return &srvEntitiesWatcher{
   981  		watcherCommon: newWatcherCommon(context),
   982  		watcher:       watcher,
   983  	}, nil
   984  }
   985  
   986  // Next returns when a change has occurred to an entity of the
   987  // collection being watched since the most recent call to Next
   988  // or the Watch call that created the srvEntitiesWatcher.
   989  func (w *srvEntitiesWatcher) Next() (params.EntitiesWatchResult, error) {
   990  	if changes, ok := <-w.watcher.Changes(); ok {
   991  		mapped, err := w.watcher.MapChanges(changes)
   992  		if err != nil {
   993  			return params.EntitiesWatchResult{}, errors.Annotate(err, "cannot map changes")
   994  		}
   995  		return params.EntitiesWatchResult{
   996  			Changes: mapped,
   997  		}, nil
   998  	}
   999  	err := w.watcher.Err()
  1000  	if err == nil {
  1001  		err = apiservererrors.ErrStoppedWatcher
  1002  	}
  1003  	return params.EntitiesWatchResult{}, err
  1004  }
  1005  
  1006  var getMigrationBackend = func(st *state.State) migrationBackend {
  1007  	return st
  1008  }
  1009  
  1010  var getControllerBackend = func(pool *state.StatePool) (controllerBackend, error) {
  1011  	return pool.SystemState()
  1012  }
  1013  
  1014  // migrationBackend defines model State functionality required by the
  1015  // migration watchers.
  1016  type migrationBackend interface {
  1017  	LatestMigration() (state.ModelMigration, error)
  1018  }
  1019  
  1020  // migrationBackend defines controller State functionality required by the
  1021  // migration watchers.
  1022  type controllerBackend interface {
  1023  	APIHostPortsForClients() ([]network.SpaceHostPorts, error)
  1024  	ControllerConfig() (controller.Config, error)
  1025  }
  1026  
  1027  func newMigrationStatusWatcher(context facade.Context) (facade.Facade, error) {
  1028  	id := context.ID()
  1029  	auth := context.Auth()
  1030  	resources := context.Resources()
  1031  	st := context.State()
  1032  	pool := context.StatePool()
  1033  
  1034  	if !isAgent(auth) {
  1035  		return nil, apiservererrors.ErrPerm
  1036  	}
  1037  	w, ok := resources.Get(id).(state.NotifyWatcher)
  1038  	if !ok {
  1039  		return nil, apiservererrors.ErrUnknownWatcher
  1040  	}
  1041  	controllerBackend, err := getControllerBackend(pool)
  1042  	if err != nil {
  1043  		return nil, errors.Trace(err)
  1044  	}
  1045  	return &srvMigrationStatusWatcher{
  1046  		watcherCommon: newWatcherCommon(context),
  1047  		watcher:       w,
  1048  		st:            getMigrationBackend(st),
  1049  		ctrlSt:        controllerBackend,
  1050  	}, nil
  1051  }
  1052  
  1053  type srvMigrationStatusWatcher struct {
  1054  	watcherCommon
  1055  	watcher state.NotifyWatcher
  1056  	st      migrationBackend
  1057  	ctrlSt  controllerBackend
  1058  }
  1059  
  1060  // Next returns when the status for a model migration for the
  1061  // associated model changes. The current details for the active
  1062  // migration are returned.
  1063  func (w *srvMigrationStatusWatcher) Next() (params.MigrationStatus, error) {
  1064  	empty := params.MigrationStatus{}
  1065  
  1066  	if _, ok := <-w.watcher.Changes(); !ok {
  1067  		err := w.watcher.Err()
  1068  		if err == nil {
  1069  			err = apiservererrors.ErrStoppedWatcher
  1070  		}
  1071  		return empty, err
  1072  	}
  1073  
  1074  	mig, err := w.st.LatestMigration()
  1075  	if errors.IsNotFound(err) {
  1076  		return params.MigrationStatus{
  1077  			Phase: migration.NONE.String(),
  1078  		}, nil
  1079  	} else if err != nil {
  1080  		return empty, errors.Annotate(err, "migration lookup")
  1081  	}
  1082  
  1083  	phase, err := mig.Phase()
  1084  	if err != nil {
  1085  		return empty, errors.Annotate(err, "retrieving migration phase")
  1086  	}
  1087  
  1088  	sourceAddrs, err := w.getLocalHostPorts()
  1089  	if err != nil {
  1090  		return empty, errors.Annotate(err, "retrieving source addresses")
  1091  	}
  1092  
  1093  	sourceCACert, err := getControllerCACert(w.ctrlSt)
  1094  	if err != nil {
  1095  		return empty, errors.Annotate(err, "retrieving source CA cert")
  1096  	}
  1097  
  1098  	target, err := mig.TargetInfo()
  1099  	if err != nil {
  1100  		return empty, errors.Annotate(err, "retrieving target info")
  1101  	}
  1102  
  1103  	return params.MigrationStatus{
  1104  		MigrationId:    mig.Id(),
  1105  		Attempt:        mig.Attempt(),
  1106  		Phase:          phase.String(),
  1107  		SourceAPIAddrs: sourceAddrs,
  1108  		SourceCACert:   sourceCACert,
  1109  		TargetAPIAddrs: target.Addrs,
  1110  		TargetCACert:   target.CACert,
  1111  	}, nil
  1112  }
  1113  
  1114  func (w *srvMigrationStatusWatcher) getLocalHostPorts() ([]string, error) {
  1115  	hostports, err := w.ctrlSt.APIHostPortsForClients()
  1116  	if err != nil {
  1117  		return nil, errors.Trace(err)
  1118  	}
  1119  	var out []string
  1120  	for _, section := range hostports {
  1121  		for _, hostport := range section {
  1122  			out = append(out, hostport.String())
  1123  		}
  1124  	}
  1125  	return out, nil
  1126  }
  1127  
  1128  // This is a shim to avoid the need to use a working State into the
  1129  // unit tests. It is tested as part of the client side API tests.
  1130  var getControllerCACert = func(st controllerBackend) (string, error) {
  1131  	cfg, err := st.ControllerConfig()
  1132  	if err != nil {
  1133  		return "", errors.Trace(err)
  1134  	}
  1135  
  1136  	cacert, ok := cfg.CACert()
  1137  	if !ok {
  1138  		return "", errors.New("missing CA cert for controller model")
  1139  	}
  1140  	return cacert, nil
  1141  }
  1142  
  1143  // newModelSummaryWatcher exists solely to be registered with regRaw.
  1144  // Standard registration doesn't handle watcher types (it checks for
  1145  // and empty ID in the context).
  1146  func newModelSummaryWatcher(context facade.Context) (facade.Facade, error) {
  1147  	return NewModelSummaryWatcher(context)
  1148  }
  1149  
  1150  // NewModelSummaryWatcher returns a new API server endpoint for interacting with
  1151  // a watcher created by the WatchModelSummaries and WatchAllModelSummaries API
  1152  // calls.
  1153  func NewModelSummaryWatcher(context facade.Context) (*SrvModelSummaryWatcher, error) {
  1154  	id := context.ID()
  1155  	auth := context.Auth()
  1156  	resources := context.Resources()
  1157  
  1158  	if !auth.AuthClient() {
  1159  		// Note that we don't need to check specific permissions
  1160  		// here, as the AllWatcher can only do anything if the
  1161  		// watcher resource has already been created, so we can
  1162  		// rely on the permission check there to ensure that
  1163  		// this facade can't do anything it shouldn't be allowed
  1164  		// to.
  1165  		//
  1166  		// This is useful because the AllWatcher is reused for
  1167  		// both the WatchAll (requires model access rights) and
  1168  		// the WatchAllModels (requring controller superuser
  1169  		// rights) API calls.
  1170  		return nil, apiservererrors.ErrPerm
  1171  	}
  1172  	watcher, ok := resources.Get(id).(cache.ModelSummaryWatcher)
  1173  	if !ok {
  1174  		return nil, errors.Annotatef(apiservererrors.ErrUnknownWatcher, "watcher id: %s", id)
  1175  	}
  1176  	return &SrvModelSummaryWatcher{
  1177  		watcherCommon: newWatcherCommon(context),
  1178  		watcher:       watcher,
  1179  	}, nil
  1180  }
  1181  
  1182  // SrvModelSummaryWatcher defines the API methods on a ModelSummaryWatcher.
  1183  type SrvModelSummaryWatcher struct {
  1184  	watcherCommon
  1185  	watcher cache.ModelSummaryWatcher
  1186  }
  1187  
  1188  // Next will return the current state of everything on the first call
  1189  // and subsequent calls will return just those model summaries that have
  1190  // changed.
  1191  func (w *SrvModelSummaryWatcher) Next() (params.SummaryWatcherNextResults, error) {
  1192  	if summaries, ok := <-w.watcher.Changes(); ok {
  1193  		return params.SummaryWatcherNextResults{
  1194  			Models: w.translate(summaries),
  1195  		}, nil
  1196  	}
  1197  	return params.SummaryWatcherNextResults{}, apiservererrors.ErrStoppedWatcher
  1198  }
  1199  
  1200  func (w *SrvModelSummaryWatcher) translate(summaries []cache.ModelSummary) []params.ModelAbstract {
  1201  	response := make([]params.ModelAbstract, 0, len(summaries))
  1202  	for _, summary := range summaries {
  1203  		if summary.Removed {
  1204  			response = append(response, params.ModelAbstract{
  1205  				UUID:    summary.UUID,
  1206  				Removed: true,
  1207  			})
  1208  			continue
  1209  		}
  1210  
  1211  		result := params.ModelAbstract{
  1212  			UUID:       summary.UUID,
  1213  			Controller: summary.Controller,
  1214  			Name:       summary.Name,
  1215  			Admins:     summary.Admins,
  1216  			Cloud:      summary.Cloud,
  1217  			Region:     summary.Region,
  1218  			Credential: summary.Credential,
  1219  			Size: params.ModelSummarySize{
  1220  				Machines:     summary.MachineCount,
  1221  				Containers:   summary.ContainerCount,
  1222  				Applications: summary.ApplicationCount,
  1223  				Units:        summary.UnitCount,
  1224  				Relations:    summary.RelationCount,
  1225  			},
  1226  			Status:      summary.Status,
  1227  			Messages:    w.translateMessages(summary.Messages),
  1228  			Annotations: summary.Annotations,
  1229  		}
  1230  		response = append(response, result)
  1231  	}
  1232  	return response
  1233  }
  1234  
  1235  func (w *SrvModelSummaryWatcher) translateMessages(messages []cache.ModelSummaryMessage) []params.ModelSummaryMessage {
  1236  	if messages == nil {
  1237  		return nil
  1238  	}
  1239  	result := make([]params.ModelSummaryMessage, len(messages))
  1240  	for i, m := range messages {
  1241  		result[i] = params.ModelSummaryMessage{
  1242  			Agent:   m.Agent,
  1243  			Message: m.Message,
  1244  		}
  1245  	}
  1246  	return result
  1247  }
  1248  
  1249  // srvSecretTriggerWatcher defines the API wrapping a SecretsTriggerWatcher.
  1250  type srvSecretTriggerWatcher struct {
  1251  	watcherCommon
  1252  	st      *state.State
  1253  	watcher state.SecretsTriggerWatcher
  1254  }
  1255  
  1256  func newSecretsTriggerWatcher(context facade.Context) (facade.Facade, error) {
  1257  	id := context.ID()
  1258  	auth := context.Auth()
  1259  	resources := context.Resources()
  1260  
  1261  	st := context.State()
  1262  
  1263  	if !isAgent(auth) {
  1264  		return nil, apiservererrors.ErrPerm
  1265  	}
  1266  	watcher, ok := resources.Get(id).(state.SecretsTriggerWatcher)
  1267  	if !ok {
  1268  		return nil, apiservererrors.ErrUnknownWatcher
  1269  	}
  1270  	return &srvSecretTriggerWatcher{
  1271  		watcherCommon: newWatcherCommon(context),
  1272  		st:            st,
  1273  		watcher:       watcher,
  1274  	}, nil
  1275  }
  1276  
  1277  // Next returns when a change has occurred to an entity of the
  1278  // collection being watched since the most recent call to Next
  1279  // or the Watch call that created the srvSecretRotationWatcher.
  1280  func (w *srvSecretTriggerWatcher) Next() (params.SecretTriggerWatchResult, error) {
  1281  	if changes, ok := <-w.watcher.Changes(); ok {
  1282  		return params.SecretTriggerWatchResult{
  1283  			Changes: w.translateChanges(changes),
  1284  		}, nil
  1285  	}
  1286  	err := w.watcher.Err()
  1287  	if err == nil {
  1288  		err = apiservererrors.ErrStoppedWatcher
  1289  	}
  1290  	return params.SecretTriggerWatchResult{}, err
  1291  }
  1292  
  1293  func (w *srvSecretTriggerWatcher) translateChanges(changes []corewatcher.SecretTriggerChange) []params.SecretTriggerChange {
  1294  	if changes == nil {
  1295  		return nil
  1296  	}
  1297  	result := make([]params.SecretTriggerChange, len(changes))
  1298  	for i, c := range changes {
  1299  		result[i] = params.SecretTriggerChange{
  1300  			URI:             c.URI.String(),
  1301  			Revision:        c.Revision,
  1302  			NextTriggerTime: c.NextTriggerTime,
  1303  		}
  1304  	}
  1305  	return result
  1306  }
  1307  
  1308  // srvSecretBackendsRotateWatcher defines the API wrapping a SecretBackendsRotateWatcher.
  1309  type srvSecretBackendsRotateWatcher struct {
  1310  	watcherCommon
  1311  	st      *state.State
  1312  	watcher state.SecretBackendRotateWatcher
  1313  }
  1314  
  1315  func newSecretBackendsRotateWatcher(context facade.Context) (facade.Facade, error) {
  1316  	id := context.ID()
  1317  	auth := context.Auth()
  1318  	resources := context.Resources()
  1319  
  1320  	st := context.State()
  1321  
  1322  	if !isAgent(auth) {
  1323  		return nil, apiservererrors.ErrPerm
  1324  	}
  1325  	watcher, ok := resources.Get(id).(state.SecretBackendRotateWatcher)
  1326  	if !ok {
  1327  		return nil, apiservererrors.ErrUnknownWatcher
  1328  	}
  1329  	return &srvSecretBackendsRotateWatcher{
  1330  		watcherCommon: newWatcherCommon(context),
  1331  		st:            st,
  1332  		watcher:       watcher,
  1333  	}, nil
  1334  }
  1335  
  1336  // Next returns when a change has occurred to an entity of the
  1337  // collection being watched since the most recent call to Next
  1338  // or the Watch call that created the srvSecretRotationWatcher.
  1339  func (w *srvSecretBackendsRotateWatcher) Next() (params.SecretBackendRotateWatchResult, error) {
  1340  	if changes, ok := <-w.watcher.Changes(); ok {
  1341  		return params.SecretBackendRotateWatchResult{
  1342  			Changes: w.translateChanges(changes),
  1343  		}, nil
  1344  	}
  1345  	err := w.watcher.Err()
  1346  	if err == nil {
  1347  		err = apiservererrors.ErrStoppedWatcher
  1348  	}
  1349  	return params.SecretBackendRotateWatchResult{}, err
  1350  }
  1351  
  1352  func (w *srvSecretBackendsRotateWatcher) translateChanges(changes []corewatcher.SecretBackendRotateChange) []params.SecretBackendRotateChange {
  1353  	if changes == nil {
  1354  		return nil
  1355  	}
  1356  	result := make([]params.SecretBackendRotateChange, len(changes))
  1357  	for i, c := range changes {
  1358  		result[i] = params.SecretBackendRotateChange{
  1359  			ID:              c.ID,
  1360  			Name:            c.Name,
  1361  			NextTriggerTime: c.NextTriggerTime,
  1362  		}
  1363  	}
  1364  	return result
  1365  }
  1366  
  1367  // srvSecretsRevisionWatcher defines the API wrapping a SecretsRevisionWatcher.
  1368  type srvSecretsRevisionWatcher struct {
  1369  	watcherCommon
  1370  	st      *state.State
  1371  	watcher state.StringsWatcher
  1372  }
  1373  
  1374  func newSecretsRevisionWatcher(context facade.Context) (facade.Facade, error) {
  1375  	id := context.ID()
  1376  	auth := context.Auth()
  1377  	resources := context.Resources()
  1378  
  1379  	st := context.State()
  1380  
  1381  	// TODO(wallyworld) - enhance this watcher to support
  1382  	// anonymous api calls with macaroons.
  1383  	if auth.GetAuthTag() != nil && !isAgent(auth) {
  1384  		return nil, apiservererrors.ErrPerm
  1385  	}
  1386  	watcher, ok := resources.Get(id).(state.StringsWatcher)
  1387  	if !ok {
  1388  		return nil, apiservererrors.ErrUnknownWatcher
  1389  	}
  1390  	return &srvSecretsRevisionWatcher{
  1391  		watcherCommon: newWatcherCommon(context),
  1392  		st:            st,
  1393  		watcher:       watcher,
  1394  	}, nil
  1395  }
  1396  
  1397  // Next returns when a change has occurred to an entity of the
  1398  // collection being watched since the most recent call to Next
  1399  // or the Watch call that created the srvSecretRotationWatcher.
  1400  func (w *srvSecretsRevisionWatcher) Next() (params.SecretRevisionWatchResult, error) {
  1401  	if changes, ok := <-w.watcher.Changes(); ok {
  1402  		ch, err := w.translateChanges(changes)
  1403  		if err != nil {
  1404  			return params.SecretRevisionWatchResult{}, errors.Trace(err)
  1405  		}
  1406  		return params.SecretRevisionWatchResult{
  1407  			Changes: ch,
  1408  		}, nil
  1409  	}
  1410  	err := w.watcher.Err()
  1411  	if err == nil {
  1412  		err = apiservererrors.ErrStoppedWatcher
  1413  	}
  1414  	return params.SecretRevisionWatchResult{}, err
  1415  }
  1416  
  1417  func (w *srvSecretsRevisionWatcher) translateChanges(changes []string) ([]params.SecretRevisionChange, error) {
  1418  	if changes == nil {
  1419  		return nil, nil
  1420  	}
  1421  	secrets := state.NewSecrets(w.st)
  1422  	result := make([]params.SecretRevisionChange, len(changes))
  1423  	for i, uriStr := range changes {
  1424  		uri, err := coresecrets.ParseURI(uriStr)
  1425  		if err != nil {
  1426  			return nil, errors.Trace(err)
  1427  		}
  1428  		md, err := secrets.GetSecret(uri)
  1429  		if err != nil {
  1430  			return nil, errors.Trace(err)
  1431  		}
  1432  		result[i] = params.SecretRevisionChange{
  1433  			URI:      uri.String(),
  1434  			Revision: md.LatestRevision,
  1435  		}
  1436  	}
  1437  	return result, nil
  1438  }