github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/apiserver/undertaker/undertaker.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package undertaker
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"gopkg.in/juju/names.v2"
     9  
    10  	"github.com/juju/juju/apiserver/common"
    11  	"github.com/juju/juju/apiserver/facade"
    12  	"github.com/juju/juju/apiserver/params"
    13  	"github.com/juju/juju/state"
    14  	"github.com/juju/juju/state/watcher"
    15  )
    16  
    17  func init() {
    18  	common.RegisterStandardFacade("Undertaker", 1, NewUndertakerAPI)
    19  }
    20  
    21  // UndertakerAPI implements the API used by the model undertaker worker.
    22  type UndertakerAPI struct {
    23  	st        State
    24  	resources facade.Resources
    25  	*common.StatusSetter
    26  }
    27  
    28  // NewUndertakerAPI creates a new instance of the undertaker API.
    29  func NewUndertakerAPI(st *state.State, resources facade.Resources, authorizer facade.Authorizer) (*UndertakerAPI, error) {
    30  	return newUndertakerAPI(&stateShim{st}, resources, authorizer)
    31  }
    32  
    33  func newUndertakerAPI(st State, resources facade.Resources, authorizer facade.Authorizer) (*UndertakerAPI, error) {
    34  	if !authorizer.AuthMachineAgent() || !authorizer.AuthModelManager() {
    35  		return nil, common.ErrPerm
    36  	}
    37  	model, err := st.Model()
    38  	if err != nil {
    39  		return nil, errors.Trace(err)
    40  	}
    41  	getCanModifyModel := func() (common.AuthFunc, error) {
    42  		return func(tag names.Tag) bool {
    43  			if st.IsController() {
    44  				return true
    45  			}
    46  			// Only the agent's model can be modified.
    47  			modelTag, ok := tag.(names.ModelTag)
    48  			if !ok {
    49  				return false
    50  			}
    51  			return modelTag.Id() == model.UUID()
    52  		}, nil
    53  	}
    54  	return &UndertakerAPI{
    55  		st:           st,
    56  		resources:    resources,
    57  		StatusSetter: common.NewStatusSetter(st, getCanModifyModel),
    58  	}, nil
    59  }
    60  
    61  // ModelInfo returns information on the model needed by the undertaker worker.
    62  func (u *UndertakerAPI) ModelInfo() (params.UndertakerModelInfoResult, error) {
    63  	result := params.UndertakerModelInfoResult{}
    64  	env, err := u.st.Model()
    65  
    66  	if err != nil {
    67  		return result, errors.Trace(err)
    68  	}
    69  
    70  	result.Result = params.UndertakerModelInfo{
    71  		UUID:       env.UUID(),
    72  		GlobalName: env.Owner().String() + "/" + env.Name(),
    73  		Name:       env.Name(),
    74  		IsSystem:   u.st.IsController(),
    75  		Life:       params.Life(env.Life().String()),
    76  	}
    77  
    78  	return result, nil
    79  }
    80  
    81  // ProcessDyingModel checks if a dying environment has any machines or services.
    82  // If there are none, the environment's life is changed from dying to dead.
    83  func (u *UndertakerAPI) ProcessDyingModel() error {
    84  	return u.st.ProcessDyingModel()
    85  }
    86  
    87  // RemoveModel removes any records of this model from Juju.
    88  func (u *UndertakerAPI) RemoveModel() error {
    89  	return u.st.RemoveAllModelDocs()
    90  }
    91  
    92  func (u *UndertakerAPI) environResourceWatcher() params.NotifyWatchResult {
    93  	var nothing params.NotifyWatchResult
    94  	machines, err := u.st.AllMachines()
    95  	if err != nil {
    96  		nothing.Error = common.ServerError(err)
    97  		return nothing
    98  	}
    99  	services, err := u.st.AllApplications()
   100  	if err != nil {
   101  		nothing.Error = common.ServerError(err)
   102  		return nothing
   103  	}
   104  	var watchers []state.NotifyWatcher
   105  	for _, machine := range machines {
   106  		watchers = append(watchers, machine.Watch())
   107  	}
   108  	for _, service := range services {
   109  		watchers = append(watchers, service.Watch())
   110  	}
   111  
   112  	watch := common.NewMultiNotifyWatcher(watchers...)
   113  
   114  	if _, ok := <-watch.Changes(); ok {
   115  		return params.NotifyWatchResult{
   116  			NotifyWatcherId: u.resources.Register(watch),
   117  		}
   118  	}
   119  	nothing.Error = common.ServerError(watcher.EnsureErr(watch))
   120  	return nothing
   121  }
   122  
   123  // WatchModelResources creates watchers for changes to the lifecycle of an
   124  // model's machines and services.
   125  func (u *UndertakerAPI) WatchModelResources() params.NotifyWatchResults {
   126  	return params.NotifyWatchResults{
   127  		Results: []params.NotifyWatchResult{
   128  			u.environResourceWatcher(),
   129  		},
   130  	}
   131  }
   132  
   133  // ModelConfig returns the model's configuration.
   134  func (u *UndertakerAPI) ModelConfig() (params.ModelConfigResult, error) {
   135  	result := params.ModelConfigResult{}
   136  
   137  	config, err := u.st.ModelConfig()
   138  	if err != nil {
   139  		return result, err
   140  	}
   141  	allAttrs := config.AllAttrs()
   142  	result.Config = allAttrs
   143  	return result, nil
   144  }