github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/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  	"errors"
     8  
     9  	"launchpad.net/juju-core/environs/config"
    10  	"launchpad.net/juju-core/state"
    11  	"launchpad.net/juju-core/state/api/params"
    12  	"launchpad.net/juju-core/state/apiserver/common"
    13  	"launchpad.net/juju-core/state/watcher"
    14  	"launchpad.net/juju-core/version"
    15  )
    16  
    17  type Upgrader interface {
    18  	WatchAPIVersion(args params.Entities) (params.NotifyWatchResults, error)
    19  	DesiredVersion(args params.Entities) (params.VersionResults, error)
    20  	Tools(args params.Entities) (params.ToolsResults, error)
    21  	SetTools(args params.EntitiesVersion) (params.ErrorResults, error)
    22  }
    23  
    24  // UpgraderAPI provides access to the Upgrader API facade.
    25  type UpgraderAPI struct {
    26  	*common.ToolsGetter
    27  	*common.ToolsSetter
    28  
    29  	st         *state.State
    30  	resources  *common.Resources
    31  	authorizer common.Authorizer
    32  }
    33  
    34  // NewUpgraderAPI creates a new client-side UpgraderAPI facade.
    35  func NewUpgraderAPI(
    36  	st *state.State,
    37  	resources *common.Resources,
    38  	authorizer common.Authorizer,
    39  ) (*UpgraderAPI, error) {
    40  	if !authorizer.AuthMachineAgent() {
    41  		return nil, common.ErrPerm
    42  	}
    43  	getCanReadWrite := func() (common.AuthFunc, error) {
    44  		return authorizer.AuthOwner, nil
    45  	}
    46  	return &UpgraderAPI{
    47  		ToolsGetter: common.NewToolsGetter(st, getCanReadWrite),
    48  		ToolsSetter: common.NewToolsSetter(st, getCanReadWrite),
    49  		st:          st,
    50  		resources:   resources,
    51  		authorizer:  authorizer,
    52  	}, nil
    53  }
    54  
    55  // WatchAPIVersion starts a watcher to track if there is a new version
    56  // of the API that we want to upgrade to
    57  func (u *UpgraderAPI) WatchAPIVersion(args params.Entities) (params.NotifyWatchResults, error) {
    58  	result := params.NotifyWatchResults{
    59  		Results: make([]params.NotifyWatchResult, len(args.Entities)),
    60  	}
    61  	for i, agent := range args.Entities {
    62  		err := common.ErrPerm
    63  		if u.authorizer.AuthOwner(agent.Tag) {
    64  			watch := u.st.WatchForEnvironConfigChanges()
    65  			// Consume the initial event. Technically, API
    66  			// calls to Watch 'transmit' the initial event
    67  			// in the Watch response. But NotifyWatchers
    68  			// have no state to transmit.
    69  			if _, ok := <-watch.Changes(); ok {
    70  				result.Results[i].NotifyWatcherId = u.resources.Register(watch)
    71  				err = nil
    72  			} else {
    73  				err = watcher.MustErr(watch)
    74  			}
    75  		}
    76  		result.Results[i].Error = common.ServerError(err)
    77  	}
    78  	return result, nil
    79  }
    80  
    81  func (u *UpgraderAPI) getGlobalAgentVersion() (version.Number, *config.Config, error) {
    82  	// Get the Agent Version requested in the Environment Config
    83  	cfg, err := u.st.EnvironConfig()
    84  	if err != nil {
    85  		return version.Number{}, nil, err
    86  	}
    87  	agentVersion, ok := cfg.AgentVersion()
    88  	if !ok {
    89  		return version.Number{}, nil, errors.New("agent version not set in environment config")
    90  	}
    91  	return agentVersion, cfg, nil
    92  }
    93  
    94  // DesiredVersion reports the Agent Version that we want that agent to be running
    95  func (u *UpgraderAPI) DesiredVersion(args params.Entities) (params.VersionResults, error) {
    96  	results := make([]params.VersionResult, len(args.Entities))
    97  	if len(args.Entities) == 0 {
    98  		return params.VersionResults{}, nil
    99  	}
   100  	agentVersion, _, err := u.getGlobalAgentVersion()
   101  	if err != nil {
   102  		return params.VersionResults{}, common.ServerError(err)
   103  	}
   104  	for i, entity := range args.Entities {
   105  		err := common.ErrPerm
   106  		if u.authorizer.AuthOwner(entity.Tag) {
   107  			results[i].Version = &agentVersion
   108  			err = nil
   109  		}
   110  		results[i].Error = common.ServerError(err)
   111  	}
   112  	return params.VersionResults{results}, nil
   113  }