github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/agent/deployer/deployer.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package deployer
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"gopkg.in/juju/names.v2"
    10  
    11  	"github.com/juju/juju/apiserver/common"
    12  	"github.com/juju/juju/apiserver/facade"
    13  	"github.com/juju/juju/apiserver/params"
    14  	"github.com/juju/juju/state"
    15  )
    16  
    17  // DeployerAPI provides access to the Deployer API facade.
    18  type DeployerAPI struct {
    19  	*common.Remover
    20  	*common.PasswordChanger
    21  	*common.LifeGetter
    22  	*common.APIAddresser
    23  	*common.UnitsWatcher
    24  	*common.StatusSetter
    25  
    26  	st         *state.State
    27  	resources  facade.Resources
    28  	authorizer facade.Authorizer
    29  }
    30  
    31  // NewDeployerAPI creates a new server-side DeployerAPI facade.
    32  func NewDeployerAPI(
    33  	st *state.State,
    34  	resources facade.Resources,
    35  	authorizer facade.Authorizer,
    36  ) (*DeployerAPI, error) {
    37  	if !authorizer.AuthMachineAgent() {
    38  		return nil, common.ErrPerm
    39  	}
    40  	getAuthFunc := func() (common.AuthFunc, error) {
    41  		// Get all units of the machine and cache them.
    42  		thisMachineTag := authorizer.GetAuthTag()
    43  		units, err := getAllUnits(st, thisMachineTag)
    44  		if err != nil {
    45  			return nil, err
    46  		}
    47  		// Then we just check if the unit is already known.
    48  		return func(tag names.Tag) bool {
    49  			for _, unit := range units {
    50  				// TODO (thumper): remove the names.Tag conversion when gccgo
    51  				// implements concrete-type-to-interface comparison correctly.
    52  				if names.Tag(names.NewUnitTag(unit)) == tag {
    53  					return true
    54  				}
    55  			}
    56  			return false
    57  		}, nil
    58  	}
    59  	getCanWatch := func() (common.AuthFunc, error) {
    60  		return authorizer.AuthOwner, nil
    61  	}
    62  	return &DeployerAPI{
    63  		Remover:         common.NewRemover(st, true, getAuthFunc),
    64  		PasswordChanger: common.NewPasswordChanger(st, getAuthFunc),
    65  		LifeGetter:      common.NewLifeGetter(st, getAuthFunc),
    66  		APIAddresser:    common.NewAPIAddresser(st, resources),
    67  		UnitsWatcher:    common.NewUnitsWatcher(st, resources, getCanWatch),
    68  		StatusSetter:    common.NewStatusSetter(st, getAuthFunc),
    69  		st:              st,
    70  		resources:       resources,
    71  		authorizer:      authorizer,
    72  	}, nil
    73  }
    74  
    75  // ConnectionInfo returns all the address information that the
    76  // deployer task needs in one call.
    77  func (d *DeployerAPI) ConnectionInfo() (result params.DeployerConnectionValues, err error) {
    78  	apiAddrs, err := d.APIAddresses()
    79  	if err != nil {
    80  		return result, err
    81  	}
    82  	result = params.DeployerConnectionValues{
    83  		APIAddresses: apiAddrs.Result,
    84  	}
    85  	return result, err
    86  }
    87  
    88  // SetStatus sets the status of the specified entities.
    89  func (d *DeployerAPI) SetStatus(args params.SetStatus) (params.ErrorResults, error) {
    90  	return d.StatusSetter.SetStatus(args)
    91  }
    92  
    93  // getAllUnits returns a list of all principal and subordinate units
    94  // assigned to the given machine.
    95  func getAllUnits(st *state.State, tag names.Tag) ([]string, error) {
    96  	machine, err := st.Machine(tag.Id())
    97  	if err != nil {
    98  		return nil, err
    99  	}
   100  	// Start a watcher on machine's units, read the initial event and stop it.
   101  	watch := machine.WatchUnits()
   102  	defer watch.Stop()
   103  	if units, ok := <-watch.Changes(); ok {
   104  		return units, nil
   105  	}
   106  	return nil, fmt.Errorf("cannot obtain units of machine %q: %v", tag, watch.Err())
   107  }