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  }