github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/api/controller/remoterelations/remoterelations.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package remoterelations 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/names/v5" 9 "gopkg.in/macaroon.v2" 10 11 "github.com/juju/juju/api" 12 "github.com/juju/juju/api/base" 13 apiwatcher "github.com/juju/juju/api/watcher" 14 apiservererrors "github.com/juju/juju/apiserver/errors" 15 "github.com/juju/juju/core/crossmodel" 16 "github.com/juju/juju/core/status" 17 "github.com/juju/juju/core/watcher" 18 "github.com/juju/juju/rpc/params" 19 ) 20 21 const remoteRelationsFacade = "RemoteRelations" 22 23 // Client provides access to the remoterelations api facade. 24 type Client struct { 25 facade base.FacadeCaller 26 } 27 28 // NewClient creates a new client-side RemoteRelations facade. 29 func NewClient(caller base.APICaller) *Client { 30 facadeCaller := base.NewFacadeCaller(caller, remoteRelationsFacade) 31 return &Client{facadeCaller} 32 } 33 34 // ImportRemoteEntity adds an entity to the remote entities collection 35 // with the specified opaque token. 36 func (c *Client) ImportRemoteEntity(entity names.Tag, token string) error { 37 args := params.RemoteEntityTokenArgs{Args: []params.RemoteEntityTokenArg{ 38 {Tag: entity.String(), Token: token}}, 39 } 40 var results params.ErrorResults 41 err := c.facade.FacadeCall("ImportRemoteEntities", args, &results) 42 if err != nil { 43 return errors.Trace(err) 44 } 45 if len(results.Results) != 1 { 46 return errors.Errorf("expected 1 result, got %d", len(results.Results)) 47 } 48 result := results.Results[0] 49 if result.Error != nil { 50 return errors.Trace(result.Error) 51 } 52 return nil 53 } 54 55 // ExportEntities allocates unique, remote entity IDs for the given entities in the local model. 56 func (c *Client) ExportEntities(tags []names.Tag) ([]params.TokenResult, error) { 57 args := params.Entities{Entities: make([]params.Entity, len(tags))} 58 for i, tag := range tags { 59 args.Entities[i].Tag = tag.String() 60 } 61 var results params.TokenResults 62 err := c.facade.FacadeCall("ExportEntities", args, &results) 63 if err != nil { 64 return nil, errors.Trace(err) 65 } 66 if len(results.Results) != len(tags) { 67 return nil, errors.Errorf("expected %d result(s), got %d", len(tags), len(results.Results)) 68 } 69 return results.Results, nil 70 } 71 72 // GetToken returns the token associated with the entity with the given tag for the specified model. 73 func (c *Client) GetToken(tag names.Tag) (string, error) { 74 args := params.GetTokenArgs{Args: []params.GetTokenArg{ 75 {Tag: tag.String()}}, 76 } 77 var results params.StringResults 78 err := c.facade.FacadeCall("GetTokens", args, &results) 79 if err != nil { 80 return "", errors.Trace(err) 81 } 82 if len(results.Results) != 1 { 83 return "", errors.Errorf("expected 1 result, got %d", len(results.Results)) 84 } 85 result := results.Results[0] 86 if result.Error != nil { 87 if params.IsCodeNotFound(result.Error) { 88 return "", errors.NotFoundf("token for %v", tag) 89 } 90 return "", errors.Trace(result.Error) 91 } 92 return result.Result, nil 93 } 94 95 // SaveMacaroon saves the macaroon for the entity. 96 func (c *Client) SaveMacaroon(entity names.Tag, mac *macaroon.Macaroon) error { 97 args := params.EntityMacaroonArgs{Args: []params.EntityMacaroonArg{ 98 {Tag: entity.String(), Macaroon: mac}}, 99 } 100 var results params.ErrorResults 101 err := c.facade.FacadeCall("SaveMacaroons", args, &results) 102 if err != nil { 103 return errors.Trace(err) 104 } 105 if len(results.Results) != 1 { 106 return errors.Errorf("expected 1 result, got %d", len(results.Results)) 107 } 108 result := results.Results[0] 109 if result.Error != nil { 110 return errors.Trace(result.Error) 111 } 112 return nil 113 } 114 115 // Relations returns information about the cross-model relations with the specified keys 116 // in the local model. 117 func (c *Client) Relations(keys []string) ([]params.RemoteRelationResult, error) { 118 args := params.Entities{Entities: make([]params.Entity, len(keys))} 119 for i, key := range keys { 120 args.Entities[i].Tag = names.NewRelationTag(key).String() 121 } 122 var results params.RemoteRelationResults 123 err := c.facade.FacadeCall("Relations", args, &results) 124 if err != nil { 125 return nil, errors.Trace(err) 126 } 127 if len(results.Results) != len(keys) { 128 return nil, errors.Errorf("expected %d result(s), got %d", len(keys), len(results.Results)) 129 } 130 return results.Results, nil 131 } 132 133 // RemoteApplications returns the current state of the remote applications with 134 // the specified names in the local model. 135 func (c *Client) RemoteApplications(applications []string) ([]params.RemoteApplicationResult, error) { 136 args := params.Entities{Entities: make([]params.Entity, len(applications))} 137 for i, applicationName := range applications { 138 args.Entities[i].Tag = names.NewApplicationTag(applicationName).String() 139 } 140 var results params.RemoteApplicationResults 141 err := c.facade.FacadeCall("RemoteApplications", args, &results) 142 if err != nil { 143 return nil, errors.Trace(err) 144 } 145 if len(results.Results) != len(applications) { 146 return nil, errors.Errorf("expected %d result(s), got %d", len(applications), len(results.Results)) 147 } 148 return results.Results, nil 149 } 150 151 // WatchRemoteApplications returns a strings watcher that notifies of the addition, 152 // removal, and lifecycle changes of remote applications in the model. 153 func (c *Client) WatchRemoteApplications() (watcher.StringsWatcher, error) { 154 var result params.StringsWatchResult 155 err := c.facade.FacadeCall("WatchRemoteApplications", nil, &result) 156 if err != nil { 157 return nil, errors.Trace(err) 158 } 159 if result.Error != nil { 160 return nil, result.Error 161 } 162 w := apiwatcher.NewStringsWatcher(c.facade.RawAPICaller(), result) 163 return w, nil 164 } 165 166 // WatchRemoteApplicationRelations returns remote relations watchers that delivers 167 // changes according to the addition, removal, and lifecycle changes of 168 // relations that the specified remote application is involved in; and also 169 // according to the entering, departing, and change of unit settings in 170 // those relations. 171 func (c *Client) WatchRemoteApplicationRelations(application string) (watcher.StringsWatcher, error) { 172 if !names.IsValidApplication(application) { 173 return nil, errors.NotValidf("application name %q", application) 174 } 175 applicationTag := names.NewApplicationTag(application) 176 args := params.Entities{ 177 Entities: []params.Entity{{Tag: applicationTag.String()}}, 178 } 179 180 var results params.StringsWatchResults 181 err := c.facade.FacadeCall("WatchRemoteApplicationRelations", args, &results) 182 if err != nil { 183 return nil, errors.Trace(err) 184 } 185 if len(results.Results) != 1 { 186 return nil, errors.Errorf("expected 1 result, got %d", len(results.Results)) 187 } 188 result := results.Results[0] 189 if result.Error != nil { 190 return nil, result.Error 191 } 192 w := apiwatcher.NewStringsWatcher(c.facade.RawAPICaller(), result) 193 return w, nil 194 } 195 196 // WatchLocalRelationChanges returns a watcher that emits 197 // fully-expanded changes (suitable for shipping over to a different 198 // controller) to the local units in the relation with the given key. 199 func (c *Client) WatchLocalRelationChanges(relationKey string) (apiwatcher.RemoteRelationWatcher, error) { 200 if !names.IsValidRelation(relationKey) { 201 return nil, errors.NotValidf("relation key %q", relationKey) 202 } 203 relationTag := names.NewRelationTag(relationKey) 204 args := params.Entities{ 205 Entities: []params.Entity{{Tag: relationTag.String()}}, 206 } 207 var results params.RemoteRelationWatchResults 208 err := c.facade.FacadeCall("WatchLocalRelationChanges", args, &results) 209 if err != nil { 210 return nil, errors.Trace(err) 211 } 212 if len(results.Results) != 1 { 213 return nil, errors.Errorf("expected 1 result, got %d", len(results.Results)) 214 } 215 result := results.Results[0] 216 if result.Error != nil { 217 return nil, result.Error 218 } 219 w := apiwatcher.NewRemoteRelationWatcher(c.facade.RawAPICaller(), result) 220 return w, nil 221 } 222 223 // WatchRemoteRelations returns a strings watcher that notifies of the addition, 224 // removal, and lifecycle changes of remote relations in the model. 225 func (c *Client) WatchRemoteRelations() (watcher.StringsWatcher, error) { 226 var result params.StringsWatchResult 227 err := c.facade.FacadeCall("WatchRemoteRelations", nil, &result) 228 if err != nil { 229 return nil, errors.Trace(err) 230 } 231 if result.Error != nil { 232 return nil, result.Error 233 } 234 w := apiwatcher.NewStringsWatcher(c.facade.RawAPICaller(), result) 235 return w, nil 236 } 237 238 // ConsumeRemoteRelationChange consumes a change to settings originating 239 // from the remote/offering side of a relation. 240 func (c *Client) ConsumeRemoteRelationChange(change params.RemoteRelationChangeEvent) error { 241 args := params.RemoteRelationsChanges{ 242 Changes: []params.RemoteRelationChangeEvent{change}, 243 } 244 var results params.ErrorResults 245 err := c.facade.FacadeCall("ConsumeRemoteRelationChanges", args, &results) 246 if err != nil { 247 return errors.Trace(err) 248 } 249 return results.OneError() 250 } 251 252 // ControllerAPIInfoForModel retrieves the controller API info for the specified model. 253 func (c *Client) ControllerAPIInfoForModel(modelUUID string) (*api.Info, error) { 254 modelTag := names.NewModelTag(modelUUID) 255 args := params.Entities{Entities: []params.Entity{{Tag: modelTag.String()}}} 256 var results params.ControllerAPIInfoResults 257 err := c.facade.FacadeCall("ControllerAPIInfoForModels", args, &results) 258 if err != nil { 259 return nil, errors.Trace(err) 260 } 261 if len(results.Results) != 1 { 262 return nil, errors.Errorf("expected 1 result, got %d", len(results.Results)) 263 } 264 result := results.Results[0] 265 if result.Error != nil { 266 return nil, apiservererrors.RestoreError(result.Error) 267 } 268 return &api.Info{ 269 Addrs: result.Addresses, 270 CACert: result.CACert, 271 ModelTag: modelTag, 272 }, nil 273 } 274 275 // SetRemoteApplicationStatus sets the status for the specified remote application. 276 func (c *Client) SetRemoteApplicationStatus(applicationName string, status status.Status, message string) error { 277 args := params.SetStatus{Entities: []params.EntityStatusArgs{ 278 {Tag: names.NewApplicationTag(applicationName).String(), Status: status.String(), Info: message}, 279 }} 280 var results params.ErrorResults 281 err := c.facade.FacadeCall("SetRemoteApplicationsStatus", args, &results) 282 if err != nil { 283 return errors.Trace(err) 284 } 285 return results.OneError() 286 } 287 288 // UpdateControllerForModel ensures that there is an external controller record 289 // for the input info, associated with the input model ID. 290 func (c *Client) UpdateControllerForModel(controller crossmodel.ControllerInfo, modelUUID string) error { 291 args := params.UpdateControllersForModelsParams{Changes: []params.UpdateControllerForModel{{ 292 ModelTag: names.NewModelTag(modelUUID).String(), 293 Info: params.ExternalControllerInfo{ 294 ControllerTag: controller.ControllerTag.String(), 295 Alias: controller.Alias, 296 Addrs: controller.Addrs, 297 CACert: controller.CACert, 298 }, 299 }}} 300 301 var results params.ErrorResults 302 err := c.facade.FacadeCall("UpdateControllersForModels", args, &results) 303 if err != nil { 304 return errors.Trace(err) 305 } 306 307 if len(results.Results) != 1 { 308 return errors.Errorf("expected 1 result, got %d", len(results.Results)) 309 } 310 311 result := results.Results[0] 312 if result.Error != nil { 313 return result.Error 314 } 315 return nil 316 } 317 318 // ConsumeRemoteSecretChanges updates the local model with secret revision changes 319 // originating from the remote/offering model. 320 func (c *Client) ConsumeRemoteSecretChanges(changes []watcher.SecretRevisionChange) error { 321 if len(changes) == 0 { 322 return nil 323 } 324 args := params.LatestSecretRevisionChanges{ 325 Changes: make([]params.SecretRevisionChange, len(changes)), 326 } 327 for i, c := range changes { 328 args.Changes[i] = params.SecretRevisionChange{ 329 URI: c.URI.String(), 330 Revision: c.Revision, 331 } 332 } 333 var results params.ErrorResults 334 err := c.facade.FacadeCall("ConsumeRemoteSecretChanges", args, &results) 335 if err != nil { 336 return errors.Trace(err) 337 } 338 return results.Combine() 339 }