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