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  }