github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/apiserver/leadership/settings.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package leadership
     5  
     6  import (
     7  	"gopkg.in/juju/names.v2"
     8  
     9  	"github.com/juju/juju/apiserver/common"
    10  	"github.com/juju/juju/apiserver/facade"
    11  	"github.com/juju/juju/apiserver/params"
    12  	"github.com/juju/juju/core/leadership"
    13  )
    14  
    15  // NewLeadershipSettingsAccessor creates a new
    16  // LeadershipSettingsAccessor.
    17  func NewLeadershipSettingsAccessor(
    18  	authorizer facade.Authorizer,
    19  	registerWatcherFn RegisterWatcherFn,
    20  	getSettingsFn GetSettingsFn,
    21  	leaderCheckFn LeaderCheckFn,
    22  	mergeSettingsChunkFn MergeSettingsChunkFn,
    23  ) *LeadershipSettingsAccessor {
    24  
    25  	return &LeadershipSettingsAccessor{
    26  		authorizer:           authorizer,
    27  		registerWatcherFn:    registerWatcherFn,
    28  		getSettingsFn:        getSettingsFn,
    29  		leaderCheckFn:        leaderCheckFn,
    30  		mergeSettingsChunkFn: mergeSettingsChunkFn,
    31  	}
    32  }
    33  
    34  // SettingsChangeNotifierFn declares a function-type which will return
    35  // a channel that can be blocked on to be notified of setting changes
    36  // for the provided document key.
    37  type RegisterWatcherFn func(serviceId string) (watcherId string, _ error)
    38  
    39  // GetSettingsFn declares a function-type which will return leadership
    40  // settings for the given service ID.
    41  type GetSettingsFn func(serviceId string) (map[string]string, error)
    42  
    43  // LeaderCheckFn returns a Token whose Check method will return an error
    44  // if the unit is not leader of the service.
    45  type LeaderCheckFn func(serviceId, unitId string) leadership.Token
    46  
    47  // MergeSettingsChunk declares a function-type which will write the
    48  // provided settings chunk into the greater leadership settings for
    49  // the provided service ID, so long as the supplied Token remains
    50  // valid.
    51  type MergeSettingsChunkFn func(token leadership.Token, serviceId string, settings map[string]string) error
    52  
    53  // LeadershipSettingsAccessor provides a type which can read, write,
    54  // and watch leadership settings.
    55  type LeadershipSettingsAccessor struct {
    56  	authorizer           facade.Authorizer
    57  	registerWatcherFn    RegisterWatcherFn
    58  	getSettingsFn        GetSettingsFn
    59  	leaderCheckFn        LeaderCheckFn
    60  	mergeSettingsChunkFn MergeSettingsChunkFn
    61  }
    62  
    63  // Merge merges in the provided leadership settings. Only leaders for
    64  // the given service may perform this operation.
    65  func (lsa *LeadershipSettingsAccessor) Merge(bulkArgs params.MergeLeadershipSettingsBulkParams) (params.ErrorResults, error) {
    66  
    67  	callerUnitId := lsa.authorizer.GetAuthTag().Id()
    68  	requireServiceId, err := names.UnitApplication(callerUnitId)
    69  	if err != nil {
    70  		return params.ErrorResults{}, err
    71  	}
    72  	results := make([]params.ErrorResult, len(bulkArgs.Params))
    73  
    74  	for i, arg := range bulkArgs.Params {
    75  		result := &results[i]
    76  
    77  		// TODO(fwereade): we shoudn't assume a ApplicationTag: we should
    78  		// use an actual auth func to determine permissions.
    79  		ApplicationTag, err := names.ParseApplicationTag(arg.ApplicationTag)
    80  		if err != nil {
    81  			result.Error = common.ServerError(err)
    82  			continue
    83  		}
    84  
    85  		serviceId := ApplicationTag.Id()
    86  		if serviceId != requireServiceId {
    87  			result.Error = common.ServerError(common.ErrPerm)
    88  			continue
    89  		}
    90  
    91  		token := lsa.leaderCheckFn(serviceId, callerUnitId)
    92  		err = lsa.mergeSettingsChunkFn(token, serviceId, arg.Settings)
    93  		if err != nil {
    94  			result.Error = common.ServerError(err)
    95  		}
    96  	}
    97  
    98  	return params.ErrorResults{Results: results}, nil
    99  }
   100  
   101  // Read reads leadership settings for the provided service ID. Any
   102  // unit of the service may perform this operation.
   103  func (lsa *LeadershipSettingsAccessor) Read(bulkArgs params.Entities) (params.GetLeadershipSettingsBulkResults, error) {
   104  
   105  	callerUnitId := lsa.authorizer.GetAuthTag().Id()
   106  	requireServiceId, err := names.UnitApplication(callerUnitId)
   107  	if err != nil {
   108  		return params.GetLeadershipSettingsBulkResults{}, err
   109  	}
   110  	results := make([]params.GetLeadershipSettingsResult, len(bulkArgs.Entities))
   111  
   112  	for i, arg := range bulkArgs.Entities {
   113  		result := &results[i]
   114  
   115  		// TODO(fwereade): we shoudn't assume a ApplicationTag: we should
   116  		// use an actual auth func to determine permissions.
   117  		ApplicationTag, err := names.ParseApplicationTag(arg.Tag)
   118  		if err != nil {
   119  			result.Error = common.ServerError(err)
   120  			continue
   121  		}
   122  
   123  		serviceId := ApplicationTag.Id()
   124  		if serviceId != requireServiceId {
   125  			result.Error = common.ServerError(common.ErrPerm)
   126  			continue
   127  		}
   128  
   129  		settings, err := lsa.getSettingsFn(serviceId)
   130  		if err != nil {
   131  			result.Error = common.ServerError(err)
   132  			continue
   133  		}
   134  
   135  		result.Settings = settings
   136  	}
   137  
   138  	return params.GetLeadershipSettingsBulkResults{results}, nil
   139  }
   140  
   141  // WatchLeadershipSettings will block the caller until leadership settings
   142  // for the given service ID change.
   143  func (lsa *LeadershipSettingsAccessor) WatchLeadershipSettings(bulkArgs params.Entities) (params.NotifyWatchResults, error) {
   144  
   145  	callerUnitId := lsa.authorizer.GetAuthTag().Id()
   146  	requireServiceId, err := names.UnitApplication(callerUnitId)
   147  	if err != nil {
   148  		return params.NotifyWatchResults{}, err
   149  	}
   150  	results := make([]params.NotifyWatchResult, len(bulkArgs.Entities))
   151  
   152  	for i, arg := range bulkArgs.Entities {
   153  		result := &results[i]
   154  
   155  		// TODO(fwereade): we shoudn't assume a ApplicationTag: we should
   156  		// use an actual auth func to determine permissions.
   157  		ApplicationTag, err := names.ParseApplicationTag(arg.Tag)
   158  		if err != nil {
   159  			result.Error = common.ServerError(err)
   160  			continue
   161  		}
   162  
   163  		serviceId := ApplicationTag.Id()
   164  		if serviceId != requireServiceId {
   165  			result.Error = common.ServerError(common.ErrPerm)
   166  			continue
   167  		}
   168  
   169  		watcherId, err := lsa.registerWatcherFn(serviceId)
   170  		if err != nil {
   171  			result.Error = common.ServerError(err)
   172  			continue
   173  		}
   174  
   175  		result.NotifyWatcherId = watcherId
   176  	}
   177  	return params.NotifyWatchResults{Results: results}, nil
   178  }