github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/facades/controller/environupgrader/upgrader.go (about)

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