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 }