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  }