github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/common/controllerconfig.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package common
     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/core/crossmodel"
    12  	"github.com/juju/juju/rpc/params"
    13  )
    14  
    15  // ControllerConfigAPI implements two common methods for use by various
    16  // facades - eg Provisioner and ControllerConfig.
    17  type ControllerConfigAPI struct {
    18  	st ControllerConfigState
    19  }
    20  
    21  // NewStateControllerConfig returns a new NewControllerConfigAPI.
    22  func NewStateControllerConfig(st ControllerConfigState) *ControllerConfigAPI {
    23  	return &ControllerConfigAPI{
    24  		st: st,
    25  	}
    26  }
    27  
    28  // ControllerConfig returns the controller's configuration.
    29  func (s *ControllerConfigAPI) ControllerConfig() (params.ControllerConfigResult, error) {
    30  	result := params.ControllerConfigResult{}
    31  	config, err := s.st.ControllerConfig()
    32  	if err != nil {
    33  		return result, err
    34  	}
    35  	result.Config = params.ControllerConfig(config)
    36  	return result, nil
    37  }
    38  
    39  // ControllerAPIInfoForModels returns the controller api connection details for the specified models.
    40  func (s *ControllerConfigAPI) ControllerAPIInfoForModels(args params.Entities) (params.ControllerAPIInfoResults, error) {
    41  	var result params.ControllerAPIInfoResults
    42  	result.Results = make([]params.ControllerAPIInfoResult, len(args.Entities))
    43  	for i, entity := range args.Entities {
    44  		info, err := s.getModelControllerInfo(entity)
    45  		if err != nil {
    46  			result.Results[i].Error = apiservererrors.ServerError(err)
    47  			continue
    48  		}
    49  		result.Results[i] = info
    50  	}
    51  	return result, nil
    52  }
    53  
    54  // GetModelControllerInfo returns the external controller details for the specified model.
    55  func (s *ControllerConfigAPI) getModelControllerInfo(model params.Entity) (params.ControllerAPIInfoResult, error) {
    56  	modelTag, err := names.ParseModelTag(model.Tag)
    57  	if err != nil {
    58  		return params.ControllerAPIInfoResult{}, errors.Trace(err)
    59  	}
    60  	// First see if the requested model UUID is hosted by this controller.
    61  	modelExists, err := s.st.ModelExists(modelTag.Id())
    62  	if err != nil {
    63  		return params.ControllerAPIInfoResult{}, errors.Trace(err)
    64  	}
    65  	if modelExists {
    66  		addrs, caCert, err := StateControllerInfo(s.st)
    67  		if err != nil {
    68  			return params.ControllerAPIInfoResult{}, errors.Trace(err)
    69  		}
    70  		return params.ControllerAPIInfoResult{
    71  			Addresses: addrs,
    72  			CACert:    caCert,
    73  		}, nil
    74  	}
    75  
    76  	ec := s.st.NewExternalControllers()
    77  	ctrl, err := ec.ControllerForModel(modelTag.Id())
    78  	if err == nil {
    79  		return params.ControllerAPIInfoResult{
    80  			Addresses: ctrl.ControllerInfo().Addrs,
    81  			CACert:    ctrl.ControllerInfo().CACert,
    82  		}, nil
    83  	}
    84  	if !errors.IsNotFound(err) {
    85  		return params.ControllerAPIInfoResult{}, errors.Trace(err)
    86  	}
    87  
    88  	// The model may have been migrated from this controller to another.
    89  	// If so, save the target as an external controller.
    90  	// This will preserve cross-model relation consumers for models that were
    91  	// on the same controller as migrated model, but not for consumers on other
    92  	// controllers.
    93  	// They will have to follow redirects and update their own relation data.
    94  	mig, err := s.st.CompletedMigrationForModel(modelTag.Id())
    95  	if err != nil {
    96  		return params.ControllerAPIInfoResult{}, errors.Trace(err)
    97  	}
    98  	target, err := mig.TargetInfo()
    99  	if err != nil {
   100  		return params.ControllerAPIInfoResult{}, errors.Trace(err)
   101  	}
   102  
   103  	logger.Debugf("found migrated model on another controller, saving the information")
   104  	_, err = ec.Save(crossmodel.ControllerInfo{
   105  		ControllerTag: target.ControllerTag,
   106  		Alias:         target.ControllerAlias,
   107  		Addrs:         target.Addrs,
   108  		CACert:        target.CACert,
   109  	}, modelTag.Id())
   110  	if err != nil {
   111  		return params.ControllerAPIInfoResult{}, errors.Trace(err)
   112  	}
   113  	return params.ControllerAPIInfoResult{
   114  		Addresses: target.Addrs,
   115  		CACert:    target.CACert,
   116  	}, nil
   117  }
   118  
   119  // StateControllerInfo returns the local controller details for the given State.
   120  func StateControllerInfo(st controllerInfoState) (addrs []string, caCert string, _ error) {
   121  	addr, err := apiAddresses(st)
   122  	if err != nil {
   123  		return nil, "", errors.Trace(err)
   124  	}
   125  	controllerConfig, err := st.ControllerConfig()
   126  	if err != nil {
   127  		return nil, "", errors.Trace(err)
   128  	}
   129  	caCert, _ = controllerConfig.CACert()
   130  	return addr, caCert, nil
   131  }