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  }