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 }