github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/state/apiserver/provisioner/provisioner.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package provisioner
     5  
     6  import (
     7  	"launchpad.net/juju-core/constraints"
     8  	"launchpad.net/juju-core/instance"
     9  	"launchpad.net/juju-core/names"
    10  	"launchpad.net/juju-core/state"
    11  	"launchpad.net/juju-core/state/api/params"
    12  	"launchpad.net/juju-core/state/apiserver/common"
    13  	"launchpad.net/juju-core/state/watcher"
    14  )
    15  
    16  // ProvisionerAPI provides access to the Provisioner API facade.
    17  type ProvisionerAPI struct {
    18  	*common.Remover
    19  	*common.StatusSetter
    20  	*common.DeadEnsurer
    21  	*common.PasswordChanger
    22  	*common.LifeGetter
    23  	*common.StateAddresser
    24  	*common.APIAddresser
    25  	*common.ToolsGetter
    26  	*common.EnvironWatcher
    27  	*common.EnvironMachinesWatcher
    28  	*common.InstanceIdGetter
    29  
    30  	st          *state.State
    31  	resources   *common.Resources
    32  	authorizer  common.Authorizer
    33  	getAuthFunc common.GetAuthFunc
    34  }
    35  
    36  // NewProvisionerAPI creates a new server-side ProvisionerAPI facade.
    37  func NewProvisionerAPI(
    38  	st *state.State,
    39  	resources *common.Resources,
    40  	authorizer common.Authorizer,
    41  ) (*ProvisionerAPI, error) {
    42  	if !authorizer.AuthMachineAgent() && !authorizer.AuthEnvironManager() {
    43  		return nil, common.ErrPerm
    44  	}
    45  	getAuthFunc := func() (common.AuthFunc, error) {
    46  		isEnvironManager := authorizer.AuthEnvironManager()
    47  		isMachineAgent := authorizer.AuthMachineAgent()
    48  		authEntityTag := authorizer.GetAuthTag()
    49  
    50  		return func(tag string) bool {
    51  			if isMachineAgent && tag == authEntityTag {
    52  				// A machine agent can always access its own machine.
    53  				return true
    54  			}
    55  			_, id, err := names.ParseTag(tag, names.MachineTagKind)
    56  			if err != nil {
    57  				return false
    58  			}
    59  			parentId := state.ParentId(id)
    60  			if parentId == "" {
    61  				// All top-level machines are accessible by the
    62  				// environment manager.
    63  				return isEnvironManager
    64  			}
    65  			// All containers with the authenticated machine as a
    66  			// parent are accessible by it.
    67  			return isMachineAgent && names.MachineTag(parentId) == authEntityTag
    68  		}, nil
    69  	}
    70  	// Both provisioner types can watch the environment.
    71  	getCanWatch := common.AuthAlways(true)
    72  	// Only the environment provisioner can read secrets.
    73  	getCanReadSecrets := common.AuthAlways(authorizer.AuthEnvironManager())
    74  	return &ProvisionerAPI{
    75  		Remover:                common.NewRemover(st, false, getAuthFunc),
    76  		StatusSetter:           common.NewStatusSetter(st, getAuthFunc),
    77  		DeadEnsurer:            common.NewDeadEnsurer(st, getAuthFunc),
    78  		PasswordChanger:        common.NewPasswordChanger(st, getAuthFunc),
    79  		LifeGetter:             common.NewLifeGetter(st, getAuthFunc),
    80  		StateAddresser:         common.NewStateAddresser(st),
    81  		APIAddresser:           common.NewAPIAddresser(st),
    82  		ToolsGetter:            common.NewToolsGetter(st, getAuthFunc),
    83  		EnvironWatcher:         common.NewEnvironWatcher(st, resources, getCanWatch, getCanReadSecrets),
    84  		EnvironMachinesWatcher: common.NewEnvironMachinesWatcher(st, resources, getCanReadSecrets),
    85  		InstanceIdGetter:       common.NewInstanceIdGetter(st, getAuthFunc),
    86  		st:                     st,
    87  		resources:              resources,
    88  		authorizer:             authorizer,
    89  		getAuthFunc:            getAuthFunc,
    90  	}, nil
    91  }
    92  
    93  func (p *ProvisionerAPI) getMachine(canAccess common.AuthFunc, tag string) (*state.Machine, error) {
    94  	if !canAccess(tag) {
    95  		return nil, common.ErrPerm
    96  	}
    97  	entity, err := p.st.FindEntity(tag)
    98  	if err != nil {
    99  		return nil, err
   100  	}
   101  	// The authorization function guarantees that the tag represents a
   102  	// machine.
   103  	return entity.(*state.Machine), nil
   104  }
   105  
   106  func (p *ProvisionerAPI) watchOneMachineContainers(arg params.WatchContainer) (params.StringsWatchResult, error) {
   107  	nothing := params.StringsWatchResult{}
   108  	canAccess, err := p.getAuthFunc()
   109  	if err != nil {
   110  		return nothing, err
   111  	}
   112  	if !canAccess(arg.MachineTag) {
   113  		return nothing, common.ErrPerm
   114  	}
   115  	_, id, err := names.ParseTag(arg.MachineTag, names.MachineTagKind)
   116  	if err != nil {
   117  		return nothing, err
   118  	}
   119  	machine, err := p.st.Machine(id)
   120  	if err != nil {
   121  		return nothing, err
   122  	}
   123  	var watch state.StringsWatcher
   124  	if arg.ContainerType != "" {
   125  		watch = machine.WatchContainers(instance.ContainerType(arg.ContainerType))
   126  	} else {
   127  		watch = machine.WatchAllContainers()
   128  	}
   129  	// Consume the initial event and forward it to the result.
   130  	if changes, ok := <-watch.Changes(); ok {
   131  		return params.StringsWatchResult{
   132  			StringsWatcherId: p.resources.Register(watch),
   133  			Changes:          changes,
   134  		}, nil
   135  	}
   136  	return nothing, watcher.MustErr(watch)
   137  }
   138  
   139  // WatchContainers starts a StringsWatcher to watch containers deployed to
   140  // any machine passed in args.
   141  func (p *ProvisionerAPI) WatchContainers(args params.WatchContainers) (params.StringsWatchResults, error) {
   142  	result := params.StringsWatchResults{
   143  		Results: make([]params.StringsWatchResult, len(args.Params)),
   144  	}
   145  	for i, arg := range args.Params {
   146  		watcherResult, err := p.watchOneMachineContainers(arg)
   147  		result.Results[i] = watcherResult
   148  		result.Results[i].Error = common.ServerError(err)
   149  	}
   150  	return result, nil
   151  }
   152  
   153  // WatchAllContainers starts a StringsWatcher to watch all containers deployed to
   154  // any machine passed in args.
   155  func (p *ProvisionerAPI) WatchAllContainers(args params.WatchContainers) (params.StringsWatchResults, error) {
   156  	return p.WatchContainers(args)
   157  }
   158  
   159  // SetSupportedContainers updates the list of containers supported by the machines passed in args.
   160  func (p *ProvisionerAPI) SetSupportedContainers(
   161  	args params.MachineContainersParams) (params.ErrorResults, error) {
   162  
   163  	result := params.ErrorResults{
   164  		Results: make([]params.ErrorResult, len(args.Params)),
   165  	}
   166  	for i, arg := range args.Params {
   167  		canAccess, err := p.getAuthFunc()
   168  		if err != nil {
   169  			return result, err
   170  		}
   171  		machine, err := p.getMachine(canAccess, arg.MachineTag)
   172  		if err != nil {
   173  			result.Results[i].Error = common.ServerError(err)
   174  			continue
   175  		}
   176  		if len(arg.ContainerTypes) == 0 {
   177  			err = machine.SupportsNoContainers()
   178  		} else {
   179  			err = machine.SetSupportedContainers(arg.ContainerTypes)
   180  		}
   181  		if err != nil {
   182  			result.Results[i].Error = common.ServerError(err)
   183  		}
   184  	}
   185  	return result, nil
   186  }
   187  
   188  // ContainerConfig returns information from the environment config that are
   189  // needed for container cloud-init.
   190  func (p *ProvisionerAPI) ContainerConfig() (params.ContainerConfig, error) {
   191  	result := params.ContainerConfig{}
   192  	config, err := p.st.EnvironConfig()
   193  	if err != nil {
   194  		return result, err
   195  	}
   196  	result.ProviderType = config.Type()
   197  	result.AuthorizedKeys = config.AuthorizedKeys()
   198  	result.SSLHostnameVerification = config.SSLHostnameVerification()
   199  	result.Proxy = config.ProxySettings()
   200  	result.AptProxy = config.AptProxySettings()
   201  	return result, nil
   202  }
   203  
   204  // Status returns the status of each given machine entity.
   205  func (p *ProvisionerAPI) Status(args params.Entities) (params.StatusResults, error) {
   206  	result := params.StatusResults{
   207  		Results: make([]params.StatusResult, len(args.Entities)),
   208  	}
   209  	canAccess, err := p.getAuthFunc()
   210  	if err != nil {
   211  		return result, err
   212  	}
   213  	for i, entity := range args.Entities {
   214  		machine, err := p.getMachine(canAccess, entity.Tag)
   215  		if err == nil {
   216  			r := &result.Results[i]
   217  			r.Status, r.Info, _, err = machine.Status()
   218  		}
   219  		result.Results[i].Error = common.ServerError(err)
   220  	}
   221  	return result, nil
   222  }
   223  
   224  // Series returns the deployed series for each given machine entity.
   225  func (p *ProvisionerAPI) Series(args params.Entities) (params.StringResults, error) {
   226  	result := params.StringResults{
   227  		Results: make([]params.StringResult, len(args.Entities)),
   228  	}
   229  	canAccess, err := p.getAuthFunc()
   230  	if err != nil {
   231  		return result, err
   232  	}
   233  	for i, entity := range args.Entities {
   234  		machine, err := p.getMachine(canAccess, entity.Tag)
   235  		if err == nil {
   236  			result.Results[i].Result = machine.Series()
   237  		}
   238  		result.Results[i].Error = common.ServerError(err)
   239  	}
   240  	return result, nil
   241  }
   242  
   243  // Constraints returns the constraints for each given machine entity.
   244  func (p *ProvisionerAPI) Constraints(args params.Entities) (params.ConstraintsResults, error) {
   245  	result := params.ConstraintsResults{
   246  		Results: make([]params.ConstraintsResult, len(args.Entities)),
   247  	}
   248  	canAccess, err := p.getAuthFunc()
   249  	if err != nil {
   250  		return result, err
   251  	}
   252  	for i, entity := range args.Entities {
   253  		machine, err := p.getMachine(canAccess, entity.Tag)
   254  		if err == nil {
   255  			var cons constraints.Value
   256  			cons, err = machine.Constraints()
   257  			if err == nil {
   258  				result.Results[i].Constraints = cons
   259  			}
   260  		}
   261  		result.Results[i].Error = common.ServerError(err)
   262  	}
   263  	return result, nil
   264  }
   265  
   266  // SetProvisioned sets the provider specific machine id, nonce and
   267  // metadata for each given machine. Once set, the instance id cannot
   268  // be changed.
   269  func (p *ProvisionerAPI) SetProvisioned(args params.SetProvisioned) (params.ErrorResults, error) {
   270  	result := params.ErrorResults{
   271  		Results: make([]params.ErrorResult, len(args.Machines)),
   272  	}
   273  	canAccess, err := p.getAuthFunc()
   274  	if err != nil {
   275  		return result, err
   276  	}
   277  	for i, arg := range args.Machines {
   278  		machine, err := p.getMachine(canAccess, arg.Tag)
   279  		if err == nil {
   280  			err = machine.SetProvisioned(arg.InstanceId, arg.Nonce, arg.Characteristics)
   281  		}
   282  		result.Results[i].Error = common.ServerError(err)
   283  	}
   284  	return result, nil
   285  }