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 }