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