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