launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/state/apiserver/upgrader/upgrader.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package upgrader
     5  
     6  import (
     7  	errgo "launchpad.net/errgo/errors"
     8  
     9  	"launchpad.net/juju-core/environs/config"
    10  	"launchpad.net/juju-core/errors"
    11  	"launchpad.net/juju-core/state"
    12  	"launchpad.net/juju-core/state/api/params"
    13  	"launchpad.net/juju-core/state/apiserver/common"
    14  	"launchpad.net/juju-core/state/watcher"
    15  	"launchpad.net/juju-core/version"
    16  )
    17  
    18  var mask = errgo.Mask
    19  
    20  // UpgraderAPI provides access to the Upgrader API facade.
    21  type UpgraderAPI struct {
    22  	*common.ToolsGetter
    23  
    24  	st         *state.State
    25  	resources  *common.Resources
    26  	authorizer common.Authorizer
    27  }
    28  
    29  // NewUpgraderAPI creates a new client-side UpgraderAPI facade.
    30  func NewUpgraderAPI(
    31  	st *state.State,
    32  	resources *common.Resources,
    33  	authorizer common.Authorizer,
    34  ) (*UpgraderAPI, error) {
    35  	if !authorizer.AuthMachineAgent() && !authorizer.AuthUnitAgent() {
    36  		return nil, common.ErrPerm
    37  	}
    38  	getCanRead := func() (common.AuthFunc, error) {
    39  		return authorizer.AuthOwner, nil
    40  	}
    41  	return &UpgraderAPI{
    42  		ToolsGetter: common.NewToolsGetter(st, getCanRead),
    43  		st:          st,
    44  		resources:   resources,
    45  		authorizer:  authorizer,
    46  	}, nil
    47  }
    48  
    49  // WatchAPIVersion starts a watcher to track if there is a new version
    50  // of the API that we want to upgrade to
    51  func (u *UpgraderAPI) WatchAPIVersion(args params.Entities) (params.NotifyWatchResults, error) {
    52  	result := params.NotifyWatchResults{
    53  		Results: make([]params.NotifyWatchResult, len(args.Entities)),
    54  	}
    55  	for i, agent := range args.Entities {
    56  		err := common.ErrPerm
    57  		if u.authorizer.AuthOwner(agent.Tag) {
    58  			watch := u.st.WatchForEnvironConfigChanges()
    59  			// Consume the initial event. Technically, API
    60  			// calls to Watch 'transmit' the initial event
    61  			// in the Watch response. But NotifyWatchers
    62  			// have no state to transmit.
    63  			if _, ok := <-watch.Changes(); ok {
    64  				result.Results[i].NotifyWatcherId = u.resources.Register(watch)
    65  				err = nil
    66  			} else {
    67  				err = watcher.MustErr(watch)
    68  			}
    69  		}
    70  		result.Results[i].Error = common.ServerError(err)
    71  	}
    72  	return result, nil
    73  }
    74  
    75  func (u *UpgraderAPI) getGlobalAgentVersion() (version.Number, *config.Config, error) {
    76  	// Get the Agent Version requested in the Environment Config
    77  	cfg, err := u.st.EnvironConfig()
    78  	if err != nil {
    79  		return version.Number{}, nil, mask(err)
    80  	}
    81  	agentVersion, ok := cfg.AgentVersion()
    82  	if !ok {
    83  		return version.Number{}, nil, errgo.New("agent version not set in environment config")
    84  	}
    85  	return agentVersion, cfg, nil
    86  }
    87  
    88  // DesiredVersion reports the Agent Version that we want that agent to be running
    89  func (u *UpgraderAPI) DesiredVersion(args params.Entities) (params.VersionResults, error) {
    90  	results := make([]params.VersionResult, len(args.Entities))
    91  	if len(args.Entities) == 0 {
    92  		return params.VersionResults{}, nil
    93  	}
    94  	agentVersion, _, err := u.getGlobalAgentVersion()
    95  	if err != nil {
    96  		return params.VersionResults{}, common.ServerError(err)
    97  	}
    98  	for i, entity := range args.Entities {
    99  		err := common.ErrPerm
   100  		if u.authorizer.AuthOwner(entity.Tag) {
   101  			results[i].Version = &agentVersion
   102  			err = nil
   103  		}
   104  		results[i].Error = common.ServerError(err)
   105  	}
   106  	return params.VersionResults{results}, nil
   107  }
   108  
   109  // SetTools updates the recorded tools version for the agents.
   110  func (u *UpgraderAPI) SetTools(args params.EntitiesVersion) (params.ErrorResults, error) {
   111  	results := params.ErrorResults{
   112  		Results: make([]params.ErrorResult, len(args.AgentTools)),
   113  	}
   114  	for i, agentTools := range args.AgentTools {
   115  		err := u.setOneAgentVersion(agentTools.Tag, agentTools.Tools.Version)
   116  		results.Results[i].Error = common.ServerError(err)
   117  	}
   118  	return results, nil
   119  }
   120  
   121  func (u *UpgraderAPI) setOneAgentVersion(tag string, vers version.Binary) error {
   122  	if !u.authorizer.AuthOwner(tag) {
   123  		return common.ErrPerm
   124  	}
   125  	entity, err := u.findEntity(tag)
   126  	if err != nil {
   127  		return mask(err)
   128  	}
   129  	return entity.SetAgentVersion(vers)
   130  }
   131  
   132  func (u *UpgraderAPI) findEntity(tag string) (state.AgentTooler, error) {
   133  	entity0, err := u.st.FindEntity(tag)
   134  	if err != nil {
   135  		return nil, mask(err, errors.IsNotFoundError)
   136  	}
   137  	entity, ok := entity0.(state.AgentTooler)
   138  	if !ok {
   139  		return nil, common.NotSupportedError(tag, "agent tools")
   140  	}
   141  	return entity, nil
   142  }