github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/worker/firewaller/manifold.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package firewaller 5 6 import ( 7 stdcontext "context" 8 9 "github.com/juju/errors" 10 "github.com/juju/worker/v3" 11 "github.com/juju/worker/v3/dependency" 12 13 "github.com/juju/juju/agent" 14 "github.com/juju/juju/api" 15 "github.com/juju/juju/api/base" 16 "github.com/juju/juju/api/controller/remoterelations" 17 "github.com/juju/juju/environs" 18 "github.com/juju/juju/environs/config" 19 "github.com/juju/juju/environs/models" 20 "github.com/juju/juju/worker/apicaller" 21 "github.com/juju/juju/worker/common" 22 ) 23 24 // logger is here to stop the desire of creating a package level logger. 25 // Don't do this, instead use the one passed as manifold config. 26 type logger interface{} 27 28 var _ logger = struct{}{} 29 30 // Logger represents the methods used by the worker to log details. 31 type Logger interface { 32 Tracef(string, ...interface{}) 33 Debugf(string, ...interface{}) 34 Warningf(string, ...interface{}) 35 Infof(string, ...interface{}) 36 Errorf(string, ...interface{}) 37 } 38 39 // ManifoldConfig describes the resources used by the firewaller worker. 40 type ManifoldConfig struct { 41 AgentName string 42 APICallerName string 43 EnvironName string 44 Logger Logger 45 46 NewControllerConnection apicaller.NewExternalControllerConnectionFunc 47 NewRemoteRelationsFacade func(base.APICaller) *remoterelations.Client 48 NewFirewallerFacade func(base.APICaller) (FirewallerAPI, error) 49 NewFirewallerWorker func(Config) (worker.Worker, error) 50 NewCredentialValidatorFacade func(base.APICaller) (common.CredentialAPI, error) 51 } 52 53 // Manifold returns a Manifold that encapsulates the firewaller worker. 54 func Manifold(cfg ManifoldConfig) dependency.Manifold { 55 return dependency.Manifold{ 56 Inputs: []string{ 57 cfg.AgentName, 58 cfg.APICallerName, 59 cfg.EnvironName, 60 }, 61 Start: cfg.start, 62 } 63 } 64 65 // Validate is called by start to check for bad configuration. 66 func (cfg ManifoldConfig) Validate() error { 67 if cfg.AgentName == "" { 68 return errors.NotValidf("empty AgentName") 69 } 70 if cfg.APICallerName == "" { 71 return errors.NotValidf("empty APICallerName") 72 } 73 if cfg.EnvironName == "" { 74 return errors.NotValidf("empty EnvironName") 75 } 76 if cfg.Logger == nil { 77 return errors.NotValidf("nil Logger") 78 } 79 if cfg.NewControllerConnection == nil { 80 return errors.NotValidf("nil NewControllerConnection") 81 } 82 if cfg.NewRemoteRelationsFacade == nil { 83 return errors.NotValidf("nil NewRemoteRelationsFacade") 84 } 85 if cfg.NewFirewallerFacade == nil { 86 return errors.NotValidf("nil NewFirewallerFacade") 87 } 88 if cfg.NewFirewallerWorker == nil { 89 return errors.NotValidf("nil NewFirewallerWorker") 90 } 91 if cfg.NewCredentialValidatorFacade == nil { 92 return errors.NotValidf("nil NewCredentialValidatorFacade") 93 } 94 return nil 95 } 96 97 // start is a StartFunc for a Worker manifold. 98 func (cfg ManifoldConfig) start(context dependency.Context) (worker.Worker, error) { 99 if err := cfg.Validate(); err != nil { 100 return nil, errors.Trace(err) 101 } 102 103 var agent agent.Agent 104 if err := context.Get(cfg.AgentName, &agent); err != nil { 105 return nil, errors.Trace(err) 106 } 107 var apiConn api.Connection 108 if err := context.Get(cfg.APICallerName, &apiConn); err != nil { 109 return nil, errors.Trace(err) 110 } 111 112 var environ environs.Environ 113 if err := context.Get(cfg.EnvironName, &environ); err != nil { 114 return nil, errors.Trace(err) 115 } 116 117 // Check if the env supports global firewalling. If the 118 // configured mode is instance, we can ignore fwEnv being a 119 // nil value, as it won't be used. 120 fwEnv, fwEnvOK := environ.(environs.Firewaller) 121 122 modelFw, _ := environ.(models.ModelFirewaller) 123 124 mode := environ.Config().FirewallMode() 125 if mode == config.FwNone { 126 cfg.Logger.Infof("stopping firewaller (not required)") 127 return nil, dependency.ErrUninstall 128 } else if mode == config.FwGlobal { 129 if !fwEnvOK { 130 cfg.Logger.Infof("Firewall global mode set on provider with no support. stopping firewaller") 131 return nil, dependency.ErrUninstall 132 } 133 } 134 135 firewallerAPI, err := cfg.NewFirewallerFacade(apiConn) 136 if err != nil { 137 return nil, errors.Trace(err) 138 } 139 140 credentialAPI, err := cfg.NewCredentialValidatorFacade(apiConn) 141 if err != nil { 142 return nil, errors.Trace(err) 143 } 144 145 // Check if the env supports IPV6 CIDRs for firewall ingress rules. 146 var envIPV6CIDRSupport bool 147 if featQuerier, ok := environ.(environs.FirewallFeatureQuerier); ok { 148 var err error 149 cloudCtx := common.NewCloudCallContextFunc(credentialAPI)(stdcontext.Background()) 150 if envIPV6CIDRSupport, err = featQuerier.SupportsRulesWithIPV6CIDRs(cloudCtx); err != nil { 151 return nil, errors.Trace(err) 152 } 153 } 154 155 w, err := cfg.NewFirewallerWorker(Config{ 156 ModelUUID: agent.CurrentConfig().Model().Id(), 157 RemoteRelationsApi: cfg.NewRemoteRelationsFacade(apiConn), 158 FirewallerAPI: firewallerAPI, 159 EnvironFirewaller: fwEnv, 160 EnvironModelFirewaller: modelFw, 161 EnvironInstances: environ, 162 EnvironIPV6CIDRSupport: envIPV6CIDRSupport, 163 Mode: mode, 164 NewCrossModelFacadeFunc: crossmodelFirewallerFacadeFunc(cfg.NewControllerConnection), 165 CredentialAPI: credentialAPI, 166 Logger: cfg.Logger, 167 }) 168 if err != nil { 169 return nil, errors.Trace(err) 170 } 171 return w, nil 172 }