github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/worker/instancemutater/manifold.go (about)

     1  // Copyright 2019 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package instancemutater
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/names/v5"
     9  	"github.com/juju/worker/v3"
    10  	"github.com/juju/worker/v3/dependency"
    11  
    12  	"github.com/juju/juju/agent"
    13  	"github.com/juju/juju/api/base"
    14  	"github.com/juju/juju/environs"
    15  )
    16  
    17  //go:generate go run go.uber.org/mock/mockgen -package mocks -destination mocks/worker_mock.go github.com/juju/worker/v3 Worker
    18  //go:generate go run go.uber.org/mock/mockgen -package mocks -destination mocks/dependency_mock.go github.com/juju/worker/v3/dependency Context
    19  //go:generate go run go.uber.org/mock/mockgen -package mocks -destination mocks/environs_mock.go github.com/juju/juju/environs Environ,LXDProfiler,InstanceBroker
    20  //go:generate go run go.uber.org/mock/mockgen -package mocks -destination mocks/base_mock.go github.com/juju/juju/api/base APICaller
    21  //go:generate go run go.uber.org/mock/mockgen -package mocks -destination mocks/agent_mock.go github.com/juju/juju/agent Agent,Config
    22  
    23  // ModelManifoldConfig describes the resources used by the instancemuter worker.
    24  type ModelManifoldConfig struct {
    25  	APICallerName string
    26  	EnvironName   string
    27  	AgentName     string
    28  
    29  	Logger    Logger
    30  	NewWorker func(Config) (worker.Worker, error)
    31  	NewClient func(base.APICaller) InstanceMutaterAPI
    32  }
    33  
    34  // Validate validates the manifold configuration.
    35  func (config ModelManifoldConfig) Validate() error {
    36  	if config.Logger == nil {
    37  		return errors.NotValidf("nil Logger")
    38  	}
    39  	if config.NewWorker == nil {
    40  		return errors.NotValidf("nil NewWorker")
    41  	}
    42  	if config.NewClient == nil {
    43  		return errors.NotValidf("nil NewClient")
    44  	}
    45  	if config.AgentName == "" {
    46  		return errors.NotValidf("empty AgentName")
    47  	}
    48  	if config.EnvironName == "" {
    49  		return errors.NotValidf("empty EnvironName")
    50  	}
    51  	if config.APICallerName == "" {
    52  		return errors.NotValidf("empty APICallerName")
    53  	}
    54  	return nil
    55  }
    56  
    57  func (config ModelManifoldConfig) newWorker(environ environs.Environ, apiCaller base.APICaller, agent agent.Agent) (worker.Worker, error) {
    58  	if err := config.Validate(); err != nil {
    59  		return nil, errors.Trace(err)
    60  	}
    61  	// If we don't have a LXDProfiler, we should uninstall the worker as quickly
    62  	// as possible.
    63  	broker, ok := environ.(environs.LXDProfiler)
    64  	if !ok {
    65  		// If we don't have an LXDProfiler broker, there is no need to
    66  		// run this worker.
    67  		config.Logger.Debugf("Uninstalling worker because the broker is not a LXDProfiler %T", environ)
    68  		return nil, dependency.ErrUninstall
    69  	}
    70  	facade := config.NewClient(apiCaller)
    71  	agentConfig := agent.CurrentConfig()
    72  	cfg := Config{
    73  		Logger:      config.Logger,
    74  		Facade:      facade,
    75  		Broker:      broker,
    76  		AgentConfig: agentConfig,
    77  		Tag:         agentConfig.Tag(),
    78  	}
    79  
    80  	w, err := config.NewWorker(cfg)
    81  	if err != nil {
    82  		return nil, errors.Annotate(err, "cannot start model instance-mutater worker")
    83  	}
    84  	return w, nil
    85  }
    86  
    87  // ModelManifold returns a Manifold that encapsulates the instancemutater worker.
    88  func ModelManifold(config ModelManifoldConfig) dependency.Manifold {
    89  	typedConfig := EnvironAPIConfig{
    90  		EnvironName:   config.EnvironName,
    91  		APICallerName: config.APICallerName,
    92  		AgentName:     config.AgentName,
    93  	}
    94  	return EnvironAPIManifold(typedConfig, config.newWorker)
    95  }
    96  
    97  // EnvironAPIConfig represents a typed manifold starter func, that handles
    98  // getting resources from the configuration.
    99  type EnvironAPIConfig struct {
   100  	EnvironName   string
   101  	APICallerName string
   102  	AgentName     string
   103  }
   104  
   105  // EnvironAPIStartFunc encapsulates creation of a worker based on the environ
   106  // and APICaller.
   107  type EnvironAPIStartFunc func(environs.Environ, base.APICaller, agent.Agent) (worker.Worker, error)
   108  
   109  // EnvironAPIManifold returns a dependency.Manifold that calls the supplied
   110  // start func with the API and envrion resources defined in the config
   111  // (once those resources are present).
   112  func EnvironAPIManifold(config EnvironAPIConfig, start EnvironAPIStartFunc) dependency.Manifold {
   113  	return dependency.Manifold{
   114  		Inputs: []string{
   115  			config.AgentName,
   116  			config.APICallerName,
   117  			config.EnvironName,
   118  		},
   119  		Start: func(context dependency.Context) (worker.Worker, error) {
   120  			var agent agent.Agent
   121  			if err := context.Get(config.AgentName, &agent); err != nil {
   122  				return nil, errors.Trace(err)
   123  			}
   124  			var environ environs.Environ
   125  			if err := context.Get(config.EnvironName, &environ); err != nil {
   126  				return nil, errors.Trace(err)
   127  			}
   128  			var apiCaller base.APICaller
   129  			if err := context.Get(config.APICallerName, &apiCaller); err != nil {
   130  				return nil, errors.Trace(err)
   131  			}
   132  			return start(environ, apiCaller, agent)
   133  		},
   134  	}
   135  }
   136  
   137  // MachineManifoldConfig describes the resources used by the instancemuter worker.
   138  type MachineManifoldConfig struct {
   139  	APICallerName string
   140  	BrokerName    string
   141  	AgentName     string
   142  
   143  	Logger    Logger
   144  	NewWorker func(Config) (worker.Worker, error)
   145  	NewClient func(base.APICaller) InstanceMutaterAPI
   146  }
   147  
   148  // Validate validates the manifold configuration.
   149  func (config MachineManifoldConfig) Validate() error {
   150  	if config.Logger == nil {
   151  		return errors.NotValidf("nil Logger")
   152  	}
   153  	if config.NewWorker == nil {
   154  		return errors.NotValidf("nil NewWorker")
   155  	}
   156  	if config.NewClient == nil {
   157  		return errors.NotValidf("nil NewClient")
   158  	}
   159  	if config.AgentName == "" {
   160  		return errors.NotValidf("empty AgentName")
   161  	}
   162  	if config.BrokerName == "" {
   163  		return errors.NotValidf("empty BrokerName")
   164  	}
   165  	if config.APICallerName == "" {
   166  		return errors.NotValidf("empty APICallerName")
   167  	}
   168  	return nil
   169  }
   170  
   171  func (config MachineManifoldConfig) newWorker(instanceBroker environs.InstanceBroker, apiCaller base.APICaller, agent agent.Agent) (worker.Worker, error) {
   172  	if err := config.Validate(); err != nil {
   173  		return nil, errors.Trace(err)
   174  	}
   175  	// If we don't have a LXDProfiler, we should uninstall the worker as quickly
   176  	// as possible.
   177  	broker, ok := instanceBroker.(environs.LXDProfiler)
   178  	if !ok {
   179  		// If we don't have an LXDProfiler broker, there is no need to
   180  		// run this worker.
   181  		config.Logger.Debugf("Uninstalling worker because the broker is not a LXDProfiler %T", instanceBroker)
   182  		return nil, dependency.ErrUninstall
   183  	}
   184  	agentConfig := agent.CurrentConfig()
   185  	tag := agentConfig.Tag()
   186  	if _, ok := tag.(names.MachineTag); !ok {
   187  		config.Logger.Warningf("cannot start a ContainerWorker on a %q, not starting", tag.Kind())
   188  		return nil, dependency.ErrUninstall
   189  	}
   190  	facade := config.NewClient(apiCaller)
   191  	cfg := Config{
   192  		Logger:      config.Logger,
   193  		Facade:      facade,
   194  		Broker:      broker,
   195  		AgentConfig: agentConfig,
   196  		Tag:         tag,
   197  	}
   198  
   199  	w, err := config.NewWorker(cfg)
   200  	if err != nil {
   201  		return nil, errors.Annotate(err, "cannot start machine instancemutater worker")
   202  	}
   203  	return w, nil
   204  }
   205  
   206  // MachineManifold returns a Manifold that encapsulates the instancemutater worker.
   207  func MachineManifold(config MachineManifoldConfig) dependency.Manifold {
   208  	typedConfig := BrokerAPIConfig{
   209  		BrokerName:    config.BrokerName,
   210  		APICallerName: config.APICallerName,
   211  		AgentName:     config.AgentName,
   212  	}
   213  	return BrokerAPIManifold(typedConfig, config.newWorker)
   214  }
   215  
   216  // BrokerAPIConfig represents a typed manifold starter func, that handles
   217  // getting resources from the configuration.
   218  type BrokerAPIConfig struct {
   219  	BrokerName    string
   220  	APICallerName string
   221  	AgentName     string
   222  }
   223  
   224  // BrokerAPIStartFunc encapsulates creation of a worker based on the environ
   225  // and APICaller.
   226  type BrokerAPIStartFunc func(environs.InstanceBroker, base.APICaller, agent.Agent) (worker.Worker, error)
   227  
   228  // BrokerAPIManifold returns a dependency.Manifold that calls the supplied
   229  // start func with the API and envrion resources defined in the config
   230  // (once those resources are present).
   231  func BrokerAPIManifold(config BrokerAPIConfig, start BrokerAPIStartFunc) dependency.Manifold {
   232  	return dependency.Manifold{
   233  		Inputs: []string{
   234  			config.AgentName,
   235  			config.APICallerName,
   236  			config.BrokerName,
   237  		},
   238  		Start: func(context dependency.Context) (worker.Worker, error) {
   239  			var agent agent.Agent
   240  			if err := context.Get(config.AgentName, &agent); err != nil {
   241  				return nil, errors.Trace(err)
   242  			}
   243  			var broker environs.InstanceBroker
   244  			if err := context.Get(config.BrokerName, &broker); err != nil {
   245  				return nil, errors.Trace(err)
   246  			}
   247  			var apiCaller base.APICaller
   248  			if err := context.Get(config.APICallerName, &apiCaller); err != nil {
   249  				return nil, errors.Trace(err)
   250  			}
   251  			return start(broker, apiCaller, agent)
   252  		},
   253  	}
   254  }