github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/worker/upgradedatabase/manifold.go (about)

     1  // Copyright 2019 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package upgradedatabase
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/retry"
    11  	"github.com/juju/version/v2"
    12  	"github.com/juju/worker/v3"
    13  	"github.com/juju/worker/v3/dependency"
    14  
    15  	"github.com/juju/juju/agent"
    16  	"github.com/juju/juju/state"
    17  	"github.com/juju/juju/upgrades"
    18  	"github.com/juju/juju/worker/gate"
    19  )
    20  
    21  // ManifoldConfig defines the configuration on which this manifold depends.
    22  type ManifoldConfig struct {
    23  	AgentName         string
    24  	UpgradeDBGateName string
    25  	Logger            Logger
    26  	OpenState         func() (*state.StatePool, error)
    27  	Clock             Clock
    28  }
    29  
    30  // Validate returns an error if the manifold config is not valid.
    31  func (cfg ManifoldConfig) Validate() error {
    32  	if cfg.UpgradeDBGateName == "" {
    33  		return errors.NotValidf("empty UpgradeDBGateName")
    34  	}
    35  	if cfg.Logger == nil {
    36  		return errors.NotValidf("nil Logger")
    37  	}
    38  	if cfg.OpenState == nil {
    39  		return errors.NotValidf("nil OpenState function")
    40  	}
    41  	if cfg.Clock == nil {
    42  		return errors.NotValidf("nil Clock")
    43  	}
    44  	return nil
    45  }
    46  
    47  // Manifold returns a dependency manifold that runs a database upgrade worker
    48  // using the resource names defined in the supplied config.
    49  func Manifold(cfg ManifoldConfig) dependency.Manifold {
    50  	return dependency.Manifold{
    51  		Inputs: []string{
    52  			cfg.AgentName,
    53  			cfg.UpgradeDBGateName,
    54  		},
    55  		Start: func(context dependency.Context) (worker.Worker, error) {
    56  			// Get the completed lock.
    57  			var upgradeStepsLock gate.Lock
    58  			if err := context.Get(cfg.UpgradeDBGateName, &upgradeStepsLock); err != nil {
    59  				return nil, errors.Trace(err)
    60  			}
    61  
    62  			// Determine this controller's agent and tag.
    63  			var controllerAgent agent.Agent
    64  			if err := context.Get(cfg.AgentName, &controllerAgent); err != nil {
    65  				return nil, errors.Trace(err)
    66  			}
    67  			tag := controllerAgent.CurrentConfig().Tag()
    68  
    69  			// Wrap the state pool factory to return our implementation.
    70  			openState := func() (Pool, error) {
    71  				p, err := cfg.OpenState()
    72  				if err != nil {
    73  					return nil, errors.Trace(err)
    74  				}
    75  				return &pool{p}, nil
    76  			}
    77  
    78  			// Wrap the upgrade steps execution so that we can generate a context lazily.
    79  			performUpgrade := func(v version.Number, t []upgrades.Target, c func() upgrades.Context) error {
    80  				return errors.Trace(upgrades.PerformStateUpgrade(v, t, c()))
    81  			}
    82  
    83  			workerCfg := Config{
    84  				UpgradeComplete: upgradeStepsLock,
    85  				Tag:             tag,
    86  				Agent:           controllerAgent,
    87  				Logger:          cfg.Logger,
    88  				OpenState:       openState,
    89  				PerformUpgrade:  performUpgrade,
    90  				RetryStrategy:   retry.CallArgs{Clock: cfg.Clock, Delay: 2 * time.Minute, Attempts: 5},
    91  				Clock:           cfg.Clock,
    92  			}
    93  			w, err := NewWorker(workerCfg)
    94  			return w, errors.Annotate(err, "starting database upgrade worker")
    95  		},
    96  	}
    97  }