github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/apiserver/upgrader/unitupgrader.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  	"github.com/juju/names"
     8  
     9  	"github.com/juju/juju/apiserver/common"
    10  	"github.com/juju/juju/apiserver/params"
    11  	"github.com/juju/juju/state"
    12  	"github.com/juju/juju/state/watcher"
    13  	"github.com/juju/juju/version"
    14  )
    15  
    16  // UnitUpgraderAPI provides access to the UnitUpgrader API facade.
    17  type UnitUpgraderAPI struct {
    18  	*common.ToolsSetter
    19  
    20  	st         *state.State
    21  	resources  *common.Resources
    22  	authorizer common.Authorizer
    23  }
    24  
    25  // NewUnitUpgraderAPI creates a new server-side UnitUpgraderAPI facade.
    26  func NewUnitUpgraderAPI(
    27  	st *state.State,
    28  	resources *common.Resources,
    29  	authorizer common.Authorizer,
    30  ) (*UnitUpgraderAPI, error) {
    31  	if !authorizer.AuthUnitAgent() {
    32  		return nil, common.ErrPerm
    33  	}
    34  
    35  	getCanWrite := func() (common.AuthFunc, error) {
    36  		return authorizer.AuthOwner, nil
    37  	}
    38  	return &UnitUpgraderAPI{
    39  		ToolsSetter: common.NewToolsSetter(st, getCanWrite),
    40  		st:          st,
    41  		resources:   resources,
    42  		authorizer:  authorizer,
    43  	}, nil
    44  }
    45  
    46  func (u *UnitUpgraderAPI) watchAssignedMachine(unitTag names.Tag) (string, error) {
    47  	machine, err := u.getAssignedMachine(unitTag)
    48  	if err != nil {
    49  		return "", err
    50  	}
    51  	watch := machine.Watch()
    52  	// Consume the initial event. Technically, API
    53  	// calls to Watch 'transmit' the initial event
    54  	// in the Watch response. But NotifyWatchers
    55  	// have no state to transmit.
    56  	if _, ok := <-watch.Changes(); ok {
    57  		return u.resources.Register(watch), nil
    58  	}
    59  	return "", watcher.EnsureErr(watch)
    60  }
    61  
    62  // WatchAPIVersion starts a watcher to track if there is a new version
    63  // of the API that we want to upgrade to. The watcher tracks changes to
    64  // the unit's assigned machine since that's where the required agent version is stored.
    65  func (u *UnitUpgraderAPI) WatchAPIVersion(args params.Entities) (params.NotifyWatchResults, error) {
    66  	result := params.NotifyWatchResults{
    67  		Results: make([]params.NotifyWatchResult, len(args.Entities)),
    68  	}
    69  	for i, agent := range args.Entities {
    70  		tag, err := names.ParseTag(agent.Tag)
    71  		if err != nil {
    72  			result.Results[i].Error = common.ServerError(common.ErrPerm)
    73  			continue
    74  		}
    75  		err = common.ErrPerm
    76  		if u.authorizer.AuthOwner(tag) {
    77  			var watcherId string
    78  			watcherId, err = u.watchAssignedMachine(tag)
    79  			if err == nil {
    80  				result.Results[i].NotifyWatcherId = watcherId
    81  			}
    82  		}
    83  		result.Results[i].Error = common.ServerError(err)
    84  	}
    85  	return result, nil
    86  }
    87  
    88  // DesiredVersion reports the Agent Version that we want that unit to be running.
    89  // The desired version is what the unit's assigned machine is running.
    90  func (u *UnitUpgraderAPI) DesiredVersion(args params.Entities) (params.VersionResults, error) {
    91  	result := make([]params.VersionResult, len(args.Entities))
    92  	for i, entity := range args.Entities {
    93  		tag, err := names.ParseTag(entity.Tag)
    94  		if err != nil {
    95  			result[i].Error = common.ServerError(common.ErrPerm)
    96  			continue
    97  		}
    98  		err = common.ErrPerm
    99  		if u.authorizer.AuthOwner(tag) {
   100  			result[i].Version, err = u.getMachineToolsVersion(tag)
   101  		}
   102  		result[i].Error = common.ServerError(err)
   103  	}
   104  	return params.VersionResults{Results: result}, nil
   105  }
   106  
   107  // Tools finds the tools necessary for the given agents.
   108  func (u *UnitUpgraderAPI) Tools(args params.Entities) (params.ToolsResults, error) {
   109  	result := params.ToolsResults{
   110  		Results: make([]params.ToolsResult, len(args.Entities)),
   111  	}
   112  	for i, entity := range args.Entities {
   113  		result.Results[i].Error = common.ServerError(common.ErrPerm)
   114  		tag, err := names.ParseTag(entity.Tag)
   115  		if err != nil {
   116  			continue
   117  		}
   118  		if u.authorizer.AuthOwner(tag) {
   119  			result.Results[i] = u.getMachineTools(tag)
   120  		}
   121  	}
   122  	return result, nil
   123  }
   124  
   125  func (u *UnitUpgraderAPI) getAssignedMachine(tag names.Tag) (*state.Machine, error) {
   126  	// Check that we really have a unit tag.
   127  	switch tag := tag.(type) {
   128  	case names.UnitTag:
   129  		unit, err := u.st.Unit(tag.Id())
   130  		if err != nil {
   131  			return nil, common.ErrPerm
   132  		}
   133  		id, err := unit.AssignedMachineId()
   134  		if err != nil {
   135  			return nil, err
   136  		}
   137  		return u.st.Machine(id)
   138  	default:
   139  		return nil, common.ErrPerm
   140  	}
   141  }
   142  
   143  func (u *UnitUpgraderAPI) getMachineTools(tag names.Tag) params.ToolsResult {
   144  	var result params.ToolsResult
   145  	machine, err := u.getAssignedMachine(tag)
   146  	if err != nil {
   147  		result.Error = common.ServerError(err)
   148  		return result
   149  	}
   150  	machineTools, err := machine.AgentTools()
   151  	if err != nil {
   152  		result.Error = common.ServerError(err)
   153  		return result
   154  	}
   155  	result.Tools = machineTools
   156  	return result
   157  }
   158  
   159  func (u *UnitUpgraderAPI) getMachineToolsVersion(tag names.Tag) (*version.Number, error) {
   160  	machine, err := u.getAssignedMachine(tag)
   161  	if err != nil {
   162  		return nil, err
   163  	}
   164  	machineTools, err := machine.AgentTools()
   165  	if err != nil {
   166  		return nil, err
   167  	}
   168  	return &machineTools.Version.Number, nil
   169  }