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

     1  // Copyright 2018 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package upgradeseries
     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/cmd/jujud/agent/engine"
    15  	"github.com/juju/juju/service"
    16  )
    17  
    18  // ManifoldConfig holds the information necessary for the dependency engine to
    19  // to run an upgrade-series worker.
    20  type ManifoldConfig struct {
    21  	AgentName     string
    22  	APICallerName string
    23  
    24  	Logger    Logger
    25  	NewFacade func(base.APICaller, names.Tag) Facade
    26  	NewWorker func(Config) (worker.Worker, error)
    27  }
    28  
    29  // Validate validates the manifold configuration.
    30  func (config ManifoldConfig) Validate() error {
    31  	if config.Logger == nil {
    32  		return errors.NotValidf("nil Logger")
    33  	}
    34  	if config.NewWorker == nil {
    35  		return errors.NotValidf("nil NewWorker function")
    36  	}
    37  	if config.NewFacade == nil {
    38  		return errors.NotValidf("nil NewFacade function")
    39  	}
    40  	return nil
    41  }
    42  
    43  // Manifold returns a dependency manifold that runs an upgrade-series worker,
    44  // using the resource names defined in the supplied config.
    45  func Manifold(config ManifoldConfig) dependency.Manifold {
    46  	typedConfig := engine.AgentAPIManifoldConfig{
    47  		AgentName:     config.AgentName,
    48  		APICallerName: config.APICallerName,
    49  	}
    50  	return engine.AgentAPIManifold(typedConfig, config.newWorker)
    51  }
    52  
    53  // newWorker wraps NewWorker for use in a engine.AgentAPIManifold.
    54  func (config ManifoldConfig) newWorker(a agent.Agent, apiCaller base.APICaller) (worker.Worker, error) {
    55  	if err := config.Validate(); err != nil {
    56  		return nil, errors.Trace(err)
    57  	}
    58  
    59  	// Ensure that we have a machine tag.
    60  	agentCfg := a.CurrentConfig()
    61  	tag, ok := agentCfg.Tag().(names.MachineTag)
    62  	if !ok {
    63  		return nil, errors.Errorf("expected a machine tag, got %v", tag)
    64  	}
    65  
    66  	// Partially apply the upgrader factory function so we only need to request
    67  	// using the getter for the to/from OS series.
    68  	newUpgrader := func(currentSeries, targetSeries string) (Upgrader, error) {
    69  		return NewUpgrader(currentSeries, targetSeries, service.NewServiceManagerWithDefaults(), config.Logger)
    70  	}
    71  
    72  	cfg := Config{
    73  		Logger:          config.Logger,
    74  		Facade:          config.NewFacade(apiCaller, tag),
    75  		UnitDiscovery:   &datadirAgents{agentCfg.DataDir()},
    76  		UpgraderFactory: newUpgrader,
    77  	}
    78  
    79  	w, err := config.NewWorker(cfg)
    80  	return w, errors.Annotate(err, "starting machine upgrade series worker")
    81  }
    82  
    83  type datadirAgents struct {
    84  	datadir string
    85  }
    86  
    87  // Units returns the unit tags of the deployed units on the machine.
    88  // This method uses the service.FindAgents method by looking for matching
    89  // names in the data directory. Calling an API method would be an alternative
    90  // except the current upgrader facade doesn't support the Units method.
    91  func (d *datadirAgents) Units() ([]names.UnitTag, error) {
    92  	_, units, _, err := service.FindAgents(d.datadir)
    93  	if err != nil {
    94  		return nil, errors.Annotate(err, "finding deployed units")
    95  	}
    96  	var result []names.UnitTag
    97  	for _, name := range units {
    98  		// We know that this string parses correctly and is a unit tag
    99  		// from the FindAgents function.
   100  		tag, _ := names.ParseTag(name)
   101  		result = append(result, tag.(names.UnitTag))
   102  	}
   103  	return result, nil
   104  }