github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/common/crossmodel/state.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package crossmodel 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/names/v5" 9 10 "github.com/juju/juju/core/crossmodel" 11 "github.com/juju/juju/state" 12 ) 13 14 // GetBackend wraps a State to provide a Backend interface implementation. 15 func GetBackend(st *state.State) stateShim { 16 model, err := st.Model() 17 if err != nil { 18 logger.Errorf("called GetBackend on a State with no Model.") 19 return stateShim{} 20 } 21 return stateShim{State: st, Model: model} 22 } 23 24 // TODO - CAAS(ericclaudejones): This should contain state alone, model will be 25 // removed once all relevant methods are moved from state to model. 26 type stateShim struct { 27 *state.State 28 *state.Model 29 } 30 31 func (st stateShim) KeyRelation(key string) (Relation, error) { 32 r, err := st.State.KeyRelation(key) 33 if err != nil { 34 return nil, errors.Trace(err) 35 } 36 return relationShim{r, st.State}, nil 37 } 38 39 func (st stateShim) OfferConnectionForRelation(relationKey string) (OfferConnection, error) { 40 return st.State.OfferConnectionForRelation(relationKey) 41 } 42 43 // ControllerTag returns the tag of the controller in which we are operating. 44 // This is a temporary transitional step. Eventually code using 45 // crossmodel.Backend will only need to be passed a state.Model. 46 func (st stateShim) ControllerTag() names.ControllerTag { 47 return st.Model.ControllerTag() 48 } 49 50 // ModelTag returns the tag of the model in which we are operating. 51 // This is a temporary transitional step. 52 func (st stateShim) ModelTag() names.ModelTag { 53 return st.Model.ModelTag() 54 } 55 56 type applicationShim struct { 57 *state.Application 58 } 59 60 func (a applicationShim) Charm() (ch Charm, force bool, err error) { 61 return a.Application.Charm() 62 } 63 64 func (a applicationShim) EndpointBindings() (Bindings, error) { 65 return a.Application.EndpointBindings() 66 } 67 68 func (a applicationShim) AllUnits() ([]Unit, error) { 69 all, err := a.Application.AllUnits() 70 if err != nil { 71 return nil, err 72 } 73 result := make([]Unit, len(all)) 74 for i, u := range all { 75 result[i] = u 76 } 77 return result, nil 78 } 79 80 func (st stateShim) Application(name string) (Application, error) { 81 a, err := st.State.Application(name) 82 if err != nil { 83 return nil, errors.Trace(err) 84 } 85 return applicationShim{a}, nil 86 } 87 88 type remoteApplicationShim struct { 89 *state.RemoteApplication 90 } 91 92 func (a remoteApplicationShim) DestroyOperation(force bool) state.ModelOperation { 93 return a.RemoteApplication.DestroyOperation(force) 94 } 95 96 func (st stateShim) RemoteApplication(name string) (RemoteApplication, error) { 97 a, err := st.State.RemoteApplication(name) 98 if err != nil { 99 return nil, errors.Trace(err) 100 } 101 return &remoteApplicationShim{a}, nil 102 } 103 104 func (st stateShim) AddRelation(eps ...state.Endpoint) (Relation, error) { 105 r, err := st.State.AddRelation(eps...) 106 if err != nil { 107 return nil, errors.Trace(err) 108 } 109 return relationShim{r, st.State}, nil 110 } 111 112 func (st stateShim) EndpointsRelation(eps ...state.Endpoint) (Relation, error) { 113 r, err := st.State.EndpointsRelation(eps...) 114 if err != nil { 115 return nil, errors.Trace(err) 116 } 117 return relationShim{r, st.State}, nil 118 } 119 120 func (st stateShim) AddRemoteApplication(args state.AddRemoteApplicationParams) (RemoteApplication, error) { 121 a, err := st.State.AddRemoteApplication(args) 122 if err != nil { 123 return nil, errors.Trace(err) 124 } 125 return remoteApplicationShim{a}, nil 126 } 127 128 func (st stateShim) OfferUUIDForRelation(key string) (string, error) { 129 oc, err := st.State.OfferConnectionForRelation(key) 130 if err != nil { 131 return "", errors.Trace(err) 132 } 133 return oc.OfferUUID(), nil 134 } 135 136 func (st stateShim) GetRemoteEntity(token string) (names.Tag, error) { 137 r := st.State.RemoteEntities() 138 return r.GetRemoteEntity(token) 139 } 140 141 func (st stateShim) GetToken(entity names.Tag) (string, error) { 142 r := st.State.RemoteEntities() 143 return r.GetToken(entity) 144 } 145 146 func (st stateShim) ExportLocalEntity(entity names.Tag) (string, error) { 147 r := st.State.RemoteEntities() 148 return r.ExportLocalEntity(entity) 149 } 150 151 func (st stateShim) ImportRemoteEntity(entity names.Tag, token string) error { 152 r := st.State.RemoteEntities() 153 return r.ImportRemoteEntity(entity, token) 154 } 155 156 func (st stateShim) ApplicationOfferForUUID(offerUUID string) (*crossmodel.ApplicationOffer, error) { 157 return state.NewApplicationOffers(st.State).ApplicationOfferForUUID(offerUUID) 158 } 159 160 func (s stateShim) SaveIngressNetworks(relationKey string, cidrs []string) (state.RelationNetworks, error) { 161 api := state.NewRelationIngressNetworks(s.State) 162 return api.Save(relationKey, false, cidrs) 163 } 164 165 func (s stateShim) IngressNetworks(relationKey string) (state.RelationNetworks, error) { 166 api := state.NewRelationIngressNetworks(s.State) 167 return api.Networks(relationKey) 168 } 169 170 type relationShim struct { 171 *state.Relation 172 st *state.State 173 } 174 175 func (r relationShim) RemoteUnit(unitId string) (RelationUnit, error) { 176 ru, err := r.Relation.RemoteUnit(unitId) 177 if err != nil { 178 return nil, errors.Trace(err) 179 } 180 return relationUnitShim{ru}, nil 181 } 182 183 func (r relationShim) AllRemoteUnits(appName string) ([]RelationUnit, error) { 184 all, err := r.Relation.AllRemoteUnits(appName) 185 if err != nil { 186 return nil, errors.Trace(err) 187 } 188 result := make([]RelationUnit, len(all)) 189 for i, ru := range all { 190 result[i] = relationUnitShim{ru} 191 } 192 return result, nil 193 } 194 195 func (r relationShim) Unit(unitId string) (RelationUnit, error) { 196 unit, err := r.st.Unit(unitId) 197 if err != nil { 198 return nil, errors.Trace(err) 199 } 200 ru, err := r.Relation.Unit(unit) 201 if err != nil { 202 return nil, errors.Trace(err) 203 } 204 return relationUnitShim{ru}, nil 205 } 206 207 func (r relationShim) ReplaceApplicationSettings(appName string, values map[string]interface{}) error { 208 currentSettings, err := r.ApplicationSettings(appName) 209 if err != nil { 210 return errors.Trace(err) 211 } 212 // This is a replace rather than an update so make the update 213 // remove any settings missing from the new values. 214 for key := range currentSettings { 215 if _, found := values[key]; !found { 216 values[key] = "" 217 } 218 } 219 // We're replicating changes from another controller so we need to 220 // trust them that the leadership was managed correctly - we can't 221 // check it here. 222 return errors.Trace(r.UpdateApplicationSettings(appName, &successfulToken{}, values)) 223 } 224 225 type successfulToken struct{} 226 227 // Check is all of the lease.Token interface. 228 func (t successfulToken) Check() error { 229 return nil 230 } 231 232 type relationUnitShim struct { 233 *state.RelationUnit 234 } 235 236 func (r relationUnitShim) Settings() (map[string]interface{}, error) { 237 settings, err := r.RelationUnit.Settings() 238 if err != nil { 239 return nil, errors.Trace(err) 240 } 241 return settings.Map(), nil 242 } 243 244 func (r relationUnitShim) ReplaceSettings(s map[string]interface{}) error { 245 settings, err := r.RelationUnit.Settings() 246 if err != nil { 247 return errors.Trace(err) 248 } 249 settings.Update(s) 250 for _, key := range settings.Keys() { 251 if _, ok := s[key]; ok { 252 continue 253 } 254 settings.Delete(key) 255 } 256 _, err = settings.Write() 257 return errors.Trace(err) 258 }