github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/controller/modelupgrader/modelupgrader.go (about)

     1  // Copyright 2017 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package modelupgrader
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/loggo"
     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/environs"
    15  )
    16  
    17  var logger = loggo.GetLogger("juju.apiserver.modelupgrader")
    18  
    19  type Facade struct {
    20  	backend       Backend
    21  	pool          Pool
    22  	providers     ProviderRegistry
    23  	entityWatcher EntityWatcher
    24  	statusSetter  StatusSetter
    25  }
    26  
    27  // EntityWatcher is an interface that provides a means of watching
    28  // entities.
    29  type EntityWatcher interface {
    30  	Watch(params.Entities) (params.NotifyWatchResults, error)
    31  }
    32  
    33  // ProviderRegistry provides the subset of environs.ProviderRegistry
    34  // that we require.
    35  type ProviderRegistry interface {
    36  	Provider(string) (environs.EnvironProvider, error)
    37  }
    38  
    39  // StatusSetter is an interface that provides a means of setting
    40  // the status of entities.
    41  type StatusSetter interface {
    42  	SetStatus(params.SetStatus) (params.ErrorResults, error)
    43  }
    44  
    45  // NewStateFacade provides the signature required for facade registration.
    46  func NewStateFacade(ctx facade.Context) (*Facade, error) {
    47  	pool := NewPool(ctx.StatePool())
    48  	registry := environs.GlobalProviderRegistry()
    49  	watcher := common.NewAgentEntityWatcher(
    50  		ctx.State(),
    51  		ctx.Resources(),
    52  		common.AuthFuncForTagKind(names.ModelTagKind),
    53  	)
    54  	statusSetter := common.NewStatusSetter(
    55  		ctx.State(),
    56  		common.AuthFuncForTagKind(names.ModelTagKind),
    57  	)
    58  	return NewFacade(ctx.State(), pool, registry, watcher, statusSetter, ctx.Auth())
    59  }
    60  
    61  // NewFacade returns a new Facade using the given Backend and Authorizer.
    62  func NewFacade(
    63  	backend Backend,
    64  	pool Pool,
    65  	providers ProviderRegistry,
    66  	entityWatcher EntityWatcher,
    67  	statusSetter StatusSetter,
    68  	auth facade.Authorizer,
    69  ) (*Facade, error) {
    70  	if !auth.AuthController() {
    71  		return nil, common.ErrPerm
    72  	}
    73  	return &Facade{
    74  		backend:       backend,
    75  		pool:          pool,
    76  		providers:     providers,
    77  		entityWatcher: entityWatcher,
    78  		statusSetter:  statusSetter,
    79  	}, nil
    80  }
    81  
    82  // ModelEnvironVersion returns the current version of the environ corresponding
    83  // to each specified model.
    84  func (f *Facade) ModelEnvironVersion(args params.Entities) (params.IntResults, error) {
    85  	result := params.IntResults{
    86  		Results: make([]params.IntResult, len(args.Entities)),
    87  	}
    88  	for i, arg := range args.Entities {
    89  		v, err := f.modelEnvironVersion(arg)
    90  		if err != nil {
    91  			result.Results[i].Error = common.ServerError(err)
    92  			continue
    93  		}
    94  		result.Results[i].Result = v
    95  	}
    96  	return result, nil
    97  }
    98  
    99  func (f *Facade) modelEnvironVersion(arg params.Entity) (int, error) {
   100  	tag, err := names.ParseModelTag(arg.Tag)
   101  	if err != nil {
   102  		return -1, errors.Trace(err)
   103  	}
   104  	model, release, err := f.pool.GetModel(tag.Id())
   105  	if err != nil {
   106  		return -1, errors.Trace(err)
   107  	}
   108  	defer release()
   109  	return model.EnvironVersion(), nil
   110  }
   111  
   112  // ModelTargetEnvironVersion returns the target version of the environ
   113  // corresponding to each specified model. The target version is the
   114  // environ provider's version.
   115  func (f *Facade) ModelTargetEnvironVersion(args params.Entities) (params.IntResults, error) {
   116  	result := params.IntResults{
   117  		Results: make([]params.IntResult, len(args.Entities)),
   118  	}
   119  	for i, arg := range args.Entities {
   120  		v, err := f.modelTargetEnvironVersion(arg)
   121  		if err != nil {
   122  			result.Results[i].Error = common.ServerError(err)
   123  			continue
   124  		}
   125  		result.Results[i].Result = v
   126  	}
   127  	return result, nil
   128  }
   129  
   130  func (f *Facade) modelTargetEnvironVersion(arg params.Entity) (int, error) {
   131  	tag, err := names.ParseModelTag(arg.Tag)
   132  	if err != nil {
   133  		return -1, errors.Trace(err)
   134  	}
   135  	model, release, err := f.pool.GetModel(tag.Id())
   136  	if err != nil {
   137  		return -1, errors.Trace(err)
   138  	}
   139  	defer release()
   140  	cloud, err := f.backend.Cloud(model.Cloud())
   141  	if err != nil {
   142  		return -1, errors.Trace(err)
   143  	}
   144  	provider, err := f.providers.Provider(cloud.Type)
   145  	if err != nil {
   146  		return -1, errors.Trace(err)
   147  	}
   148  	return provider.Version(), nil
   149  }
   150  
   151  // SetModelEnvironVersion sets the current version of the environ corresponding
   152  // to each specified model.
   153  func (f *Facade) SetModelEnvironVersion(args params.SetModelEnvironVersions) (params.ErrorResults, error) {
   154  	result := params.ErrorResults{
   155  		Results: make([]params.ErrorResult, len(args.Models)),
   156  	}
   157  	for i, arg := range args.Models {
   158  		err := f.setModelEnvironVersion(arg)
   159  		if err != nil {
   160  			result.Results[i].Error = common.ServerError(err)
   161  		}
   162  	}
   163  	return result, nil
   164  }
   165  
   166  func (f *Facade) setModelEnvironVersion(arg params.SetModelEnvironVersion) error {
   167  	tag, err := names.ParseModelTag(arg.ModelTag)
   168  	if err != nil {
   169  		return errors.Trace(err)
   170  	}
   171  	model, release, err := f.pool.GetModel(tag.Id())
   172  	if err != nil {
   173  		return errors.Trace(err)
   174  	}
   175  	defer release()
   176  	return errors.Trace(model.SetEnvironVersion(arg.Version))
   177  }
   178  
   179  // WatchModelEnvironVersion watches for changes to the environ version of the
   180  // specified models.
   181  //
   182  // NOTE(axw) this is currently implemented in terms of state.Model.Watch, so
   183  // the client may be notified of changes unrelated to the environ version.
   184  func (f *Facade) WatchModelEnvironVersion(args params.Entities) (params.NotifyWatchResults, error) {
   185  	return f.entityWatcher.Watch(args)
   186  }
   187  
   188  // SetModelStatus sets the status of each given model.
   189  func (f *Facade) SetModelStatus(args params.SetStatus) (params.ErrorResults, error) {
   190  	return f.statusSetter.SetStatus(args)
   191  }