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

     1  // Copyright 2017 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package peergrouper
     5  
     6  import (
     7  	"github.com/juju/clock"
     8  	"github.com/juju/errors"
     9  	"github.com/juju/worker/v3"
    10  	"github.com/juju/worker/v3/dependency"
    11  	"github.com/prometheus/client_golang/prometheus"
    12  
    13  	"github.com/juju/juju/agent"
    14  	"github.com/juju/juju/state"
    15  	"github.com/juju/juju/worker/common"
    16  	workerstate "github.com/juju/juju/worker/state"
    17  )
    18  
    19  // ManifoldConfig holds the information necessary to run a peergrouper
    20  // in a dependency.Engine.
    21  type ManifoldConfig struct {
    22  	AgentName          string
    23  	ClockName          string
    24  	ControllerPortName string
    25  	StateName          string
    26  	Hub                Hub
    27  
    28  	PrometheusRegisterer prometheus.Registerer
    29  	NewWorker            func(Config) (worker.Worker, error)
    30  }
    31  
    32  // Validate validates the manifold configuration.
    33  func (config ManifoldConfig) Validate() error {
    34  	if config.AgentName == "" {
    35  		return errors.NotValidf("empty AgentName")
    36  	}
    37  	if config.ClockName == "" {
    38  		return errors.NotValidf("empty ClockName")
    39  	}
    40  	if config.ControllerPortName == "" {
    41  		return errors.NotValidf("empty ControllerPortName")
    42  	}
    43  	if config.StateName == "" {
    44  		return errors.NotValidf("empty StateName")
    45  	}
    46  	if config.Hub == nil {
    47  		return errors.NotValidf("nil Hub")
    48  	}
    49  	if config.PrometheusRegisterer == nil {
    50  		return errors.NotValidf("nil PrometheusRegisterer")
    51  	}
    52  	if config.NewWorker == nil {
    53  		return errors.NotValidf("nil NewWorker")
    54  	}
    55  	return nil
    56  }
    57  
    58  // Manifold returns a dependency.Manifold that will run a peergrouper.
    59  func Manifold(config ManifoldConfig) dependency.Manifold {
    60  	return dependency.Manifold{
    61  		Inputs: []string{
    62  			config.AgentName,
    63  			config.ClockName,
    64  			config.ControllerPortName,
    65  			config.StateName,
    66  		},
    67  		Start: config.start,
    68  	}
    69  }
    70  
    71  // start is a method on ManifoldConfig because it's more readable than a closure.
    72  func (config ManifoldConfig) start(context dependency.Context) (worker.Worker, error) {
    73  	if err := config.Validate(); err != nil {
    74  		return nil, errors.Trace(err)
    75  	}
    76  
    77  	var agent agent.Agent
    78  	if err := context.Get(config.AgentName, &agent); err != nil {
    79  		return nil, errors.Trace(err)
    80  	}
    81  
    82  	var clock clock.Clock
    83  	if err := context.Get(config.ClockName, &clock); err != nil {
    84  		return nil, errors.Trace(err)
    85  	}
    86  
    87  	// Ensure that the controller-port worker is running.
    88  	if err := context.Get(config.ControllerPortName, nil); err != nil {
    89  		return nil, errors.Trace(err)
    90  	}
    91  
    92  	var stTracker workerstate.StateTracker
    93  	if err := context.Get(config.StateName, &stTracker); err != nil {
    94  		return nil, errors.Trace(err)
    95  	}
    96  	statePool, err := stTracker.Use()
    97  	if err != nil {
    98  		return nil, errors.Trace(err)
    99  	}
   100  
   101  	st, err := statePool.SystemState()
   102  	if err != nil {
   103  		return nil, errors.Trace(err)
   104  	}
   105  	mongoSession := st.MongoSession()
   106  	agentConfig := agent.CurrentConfig()
   107  	stateServingInfo, ok := agentConfig.StateServingInfo()
   108  	if !ok {
   109  		_ = stTracker.Done()
   110  		return nil, errors.New("state serving info missing from agent config")
   111  	}
   112  	model, err := st.Model()
   113  	if err != nil {
   114  		_ = stTracker.Done()
   115  		return nil, errors.Trace(err)
   116  	}
   117  	supportsHA := model.Type() != state.ModelTypeCAAS
   118  
   119  	w, err := config.NewWorker(Config{
   120  		State:                StateShim{st},
   121  		MongoSession:         MongoSessionShim{mongoSession},
   122  		APIHostPortsSetter:   &CachingAPIHostPortsSetter{APIHostPortsSetter: st},
   123  		Clock:                clock,
   124  		Hub:                  config.Hub,
   125  		MongoPort:            stateServingInfo.StatePort,
   126  		APIPort:              stateServingInfo.APIPort,
   127  		ControllerAPIPort:    stateServingInfo.ControllerAPIPort,
   128  		SupportsHA:           supportsHA,
   129  		PrometheusRegisterer: config.PrometheusRegisterer,
   130  		// On machine models, the controller id is the same as the machine/agent id.
   131  		// TODO(wallyworld) - revisit when we add HA to k8s.
   132  		ControllerId: agentConfig.Tag().Id,
   133  	})
   134  	if err != nil {
   135  		_ = stTracker.Done()
   136  		return nil, errors.Trace(err)
   137  	}
   138  	return common.NewCleanupWorker(w, func() { _ = stTracker.Done() }), nil
   139  }