github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/migrations/externalcontrollers.go (about)

     1  // Copyright 2019 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package migrations
     5  
     6  import (
     7  	"github.com/juju/description/v5"
     8  	"github.com/juju/errors"
     9  	"github.com/juju/names/v5"
    10  )
    11  
    12  // MigrationExternalController represents a state.ExternalController
    13  // Point of use interface to enable better encapsulation.
    14  type MigrationExternalController interface {
    15  	// ID holds the controller ID from the external controller
    16  	ID() string
    17  
    18  	// Alias holds an alias (human friendly) name for the controller.
    19  	Alias() string
    20  
    21  	// Addrs holds the host:port values for the external
    22  	// controller's API server.
    23  	Addrs() []string
    24  
    25  	// CACert holds the certificate to validate the external
    26  	// controller's target API server's TLS certificate.
    27  	CACert() string
    28  
    29  	// Models holds model UUIDs hosted on this controller.
    30  	Models() []string
    31  }
    32  
    33  // AllExternalControllerSource defines an in-place usage for reading all the
    34  // external controllers.
    35  type AllExternalControllerSource interface {
    36  	ControllerForModel(string) (MigrationExternalController, error)
    37  }
    38  
    39  // ExternalControllerSource composes all the interfaces to create a external
    40  // controllers.
    41  type ExternalControllerSource interface {
    42  	AllExternalControllerSource
    43  	AllRemoteApplicationSource
    44  }
    45  
    46  // ExternalControllerModel defines an in-place usage for adding a
    47  // external controller to a model.
    48  type ExternalControllerModel interface {
    49  	AddExternalController(description.ExternalControllerArgs) description.ExternalController
    50  }
    51  
    52  // ExportExternalControllers describes a way to execute a migration for
    53  // exporting external controller s.
    54  type ExportExternalControllers struct{}
    55  
    56  // Execute the migration of the external controllers using typed interfaces, to
    57  // ensure we don't loose any type safety.
    58  // This doesn't conform to an interface because go doesn't have generics, but
    59  // when this does arrive this would be an excellent place to use them.
    60  func (m ExportExternalControllers) Execute(src ExternalControllerSource, dst ExternalControllerModel) error {
    61  	// If there are not remote applications, then no external controllers will
    62  	// be exported. We should understand if that's ever going to be an issue?
    63  	remoteApplications, err := src.AllRemoteApplications()
    64  	if err != nil {
    65  		return errors.Trace(err)
    66  	}
    67  
    68  	// Iterate over the source model UUIDs, to gather up all the related
    69  	// external controllers. Store them in a map to create a unique set of
    70  	// source model UUIDs, that way we don't request multiple versions of the
    71  	// same external controller.
    72  	sourceModelUUIDs := make(map[string]struct{})
    73  	for _, remoteApp := range remoteApplications {
    74  		sourceModelUUIDs[remoteApp.SourceModel().Id()] = struct{}{}
    75  	}
    76  
    77  	controllers := make(map[string]MigrationExternalController)
    78  	for modelUUID := range sourceModelUUIDs {
    79  		externalController, err := src.ControllerForModel(modelUUID)
    80  		if err != nil {
    81  			// This can occur when attempting to export a remote application
    82  			// where there is a external controller, yet the controller doesn't
    83  			// exist.
    84  			// This generally only happens whilst keeping backwards
    85  			// compatibility, whilst remote applications aren't exported or
    86  			// imported correctly.
    87  			// TODO (stickupkid): This should be removed when we support CMR
    88  			// migrations without a feature flag.
    89  			if errors.IsNotFound(err) {
    90  				continue
    91  			}
    92  			return errors.Trace(err)
    93  		}
    94  		controllers[externalController.ID()] = externalController
    95  	}
    96  
    97  	for _, controller := range controllers {
    98  		m.addExternalController(dst, controller)
    99  	}
   100  	return nil
   101  }
   102  
   103  func (m ExportExternalControllers) addExternalController(dst ExternalControllerModel, ctrl MigrationExternalController) {
   104  	_ = dst.AddExternalController(description.ExternalControllerArgs{
   105  		Tag:    names.NewControllerTag(ctrl.ID()),
   106  		Addrs:  ctrl.Addrs(),
   107  		Alias:  ctrl.Alias(),
   108  		CACert: ctrl.CACert(),
   109  		Models: ctrl.Models(),
   110  	})
   111  }