github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/api/agent/uniter/leadership.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package uniter
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/names/v5"
     9  
    10  	"github.com/juju/juju/core/watcher"
    11  	"github.com/juju/juju/rpc/params"
    12  )
    13  
    14  // NewLeadershipSettingsAccessor returns a new LeadershipSettingsAccessor.
    15  func NewLeadershipSettingsAccessor(
    16  	caller FacadeCallFn,
    17  	newWatcher NewNotifyWatcherFn,
    18  ) *LeadershipSettingsAccessor {
    19  	return &LeadershipSettingsAccessor{caller, newWatcher}
    20  }
    21  
    22  type FacadeCallFn func(request string, params, response interface{}) error
    23  type NewNotifyWatcherFn func(params.NotifyWatchResult) watcher.NotifyWatcher
    24  
    25  // LeadershipSettingsAccessor provides a type that can make RPC calls
    26  // to a service which can read, write, and watch leadership settings.
    27  type LeadershipSettingsAccessor struct {
    28  	facadeCaller     FacadeCallFn
    29  	newNotifyWatcher NewNotifyWatcherFn
    30  }
    31  
    32  // Merge merges the provided settings into the leadership settings for
    33  // the given application and unit. Only leaders of a given application may perform
    34  // this operation.
    35  func (lsa *LeadershipSettingsAccessor) Merge(appId, unitId string, settings map[string]string) error {
    36  	results, err := lsa.bulkMerge(lsa.prepareMerge(appId, unitId, settings))
    37  	if err != nil {
    38  		return errors.Annotatef(err, "failed to call leadership api")
    39  	}
    40  	if count := len(results.Results); count != 1 {
    41  		return errors.Errorf("expected 1 result from leadership api, got %d", count)
    42  	}
    43  	if results.Results[0].Error != nil {
    44  		return errors.Annotatef(results.Results[0].Error, "failed to merge leadership settings")
    45  	}
    46  	return nil
    47  }
    48  
    49  // Read retrieves the leadership settings for the given application
    50  // ID. Anyone may perform this operation.
    51  func (lsa *LeadershipSettingsAccessor) Read(appId string) (map[string]string, error) {
    52  	results, err := lsa.bulkRead(lsa.prepareRead(appId))
    53  	if err != nil {
    54  		return nil, errors.Annotatef(err, "failed to call leadership api")
    55  	}
    56  	if count := len(results.Results); count != 1 {
    57  		return nil, errors.Errorf("expected 1 result from leadership api, got %d", count)
    58  	}
    59  	if results.Results[0].Error != nil {
    60  		return nil, errors.Annotatef(results.Results[0].Error, "failed to read leadership settings")
    61  	}
    62  	return results.Results[0].Settings, nil
    63  }
    64  
    65  // WatchLeadershipSettings returns a watcher which can be used to wait
    66  // for leadership settings changes to be made for a given application ID.
    67  func (lsa *LeadershipSettingsAccessor) WatchLeadershipSettings(appId string) (watcher.NotifyWatcher, error) {
    68  	var results params.NotifyWatchResults
    69  	if err := lsa.facadeCaller(
    70  		"WatchLeadershipSettings",
    71  		params.Entities{[]params.Entity{{names.NewApplicationTag(appId).String()}}},
    72  		&results,
    73  	); err != nil {
    74  		return nil, errors.Annotate(err, "failed to call leadership api")
    75  	}
    76  	if count := len(results.Results); count != 1 {
    77  		return nil, errors.Errorf("expected 1 result from leadership api, got %d", count)
    78  	}
    79  	if results.Results[0].Error != nil {
    80  		return nil, errors.Annotatef(results.Results[0].Error, "failed to watch leadership settings")
    81  	}
    82  	return lsa.newNotifyWatcher(results.Results[0]), nil
    83  }
    84  
    85  //
    86  // Prepare functions for building bulk-calls.
    87  //
    88  
    89  func (lsa *LeadershipSettingsAccessor) prepareMerge(appId, unitId string, settings map[string]string) params.MergeLeadershipSettingsParam {
    90  	return params.MergeLeadershipSettingsParam{
    91  		ApplicationTag: names.NewApplicationTag(appId).String(),
    92  		UnitTag:        names.NewUnitTag(unitId).String(),
    93  		Settings:       settings,
    94  	}
    95  }
    96  
    97  func (lsa *LeadershipSettingsAccessor) prepareRead(appId string) params.Entity {
    98  	return params.Entity{Tag: names.NewApplicationTag(appId).String()}
    99  }
   100  
   101  //
   102  // Bulk calls.
   103  //
   104  
   105  func (lsa *LeadershipSettingsAccessor) bulkMerge(args ...params.MergeLeadershipSettingsParam) (*params.ErrorResults, error) {
   106  	// Don't make the jump over the network if we don't have to.
   107  	if len(args) <= 0 {
   108  		return &params.ErrorResults{}, nil
   109  	}
   110  
   111  	bulkArgs := params.MergeLeadershipSettingsBulkParams{Params: args}
   112  	var results params.ErrorResults
   113  	return &results, lsa.facadeCaller("Merge", bulkArgs, &results)
   114  }
   115  
   116  func (lsa *LeadershipSettingsAccessor) bulkRead(args ...params.Entity) (*params.GetLeadershipSettingsBulkResults, error) {
   117  
   118  	// Don't make the jump over the network if we don't have to.
   119  	if len(args) <= 0 {
   120  		return &params.GetLeadershipSettingsBulkResults{}, nil
   121  	}
   122  
   123  	bulkArgs := params.Entities{Entities: args}
   124  	var results params.GetLeadershipSettingsBulkResults
   125  	return &results, lsa.facadeCaller("Read", bulkArgs, &results)
   126  }