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

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package upgradesteps
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/clock"
    10  	"github.com/juju/errors"
    11  	"github.com/juju/names/v5"
    12  	"github.com/juju/retry"
    13  	"github.com/juju/worker/v3"
    14  	"github.com/juju/worker/v3/dependency"
    15  
    16  	"github.com/juju/juju/agent"
    17  	"github.com/juju/juju/api"
    18  	apiagent "github.com/juju/juju/api/agent/agent"
    19  	"github.com/juju/juju/state"
    20  	"github.com/juju/juju/upgrades"
    21  	"github.com/juju/juju/worker/gate"
    22  )
    23  
    24  // ManifoldConfig defines the names of the manifolds on which a
    25  // Manifold will depend.
    26  type ManifoldConfig struct {
    27  	AgentName            string
    28  	APICallerName        string
    29  	UpgradeStepsGateName string
    30  	OpenStateForUpgrade  func() (*state.StatePool, error)
    31  	PreUpgradeSteps      upgrades.PreUpgradeStepsFunc
    32  	NewAgentStatusSetter func(apiConn api.Connection) (StatusSetter, error)
    33  }
    34  
    35  // Manifold returns a dependency manifold that runs an upgrader
    36  // worker, using the resource names defined in the supplied config.
    37  func Manifold(config ManifoldConfig) dependency.Manifold {
    38  	return dependency.Manifold{
    39  		Inputs: []string{
    40  			config.AgentName,
    41  			config.APICallerName,
    42  			config.UpgradeStepsGateName,
    43  		},
    44  		Start: func(context dependency.Context) (worker.Worker, error) {
    45  			// Sanity checks
    46  			if config.OpenStateForUpgrade == nil {
    47  				return nil, errors.New("missing OpenStateForUpgrade in config")
    48  			}
    49  			if config.PreUpgradeSteps == nil {
    50  				return nil, errors.New("missing PreUpgradeSteps in config")
    51  			}
    52  
    53  			// Get the agent.
    54  			var localAgent agent.Agent
    55  			if err := context.Get(config.AgentName, &localAgent); err != nil {
    56  				return nil, errors.Trace(err)
    57  			}
    58  
    59  			// Get API connection.
    60  			// TODO(fwereade): can we make the worker use an
    61  			// APICaller instead? should be able to depend on
    62  			// the Engine to abort us when conn is closed...
    63  			var apiConn api.Connection
    64  			if err := context.Get(config.APICallerName, &apiConn); err != nil {
    65  				return nil, errors.Trace(err)
    66  			}
    67  
    68  			// Get upgradeSteps completed lock.
    69  			var upgradeStepsLock gate.Lock
    70  			if err := context.Get(config.UpgradeStepsGateName, &upgradeStepsLock); err != nil {
    71  				return nil, errors.Trace(err)
    72  			}
    73  
    74  			// Get a component capable of setting machine status
    75  			// to indicate progress to the user.
    76  			statusSetter, err := config.NewAgentStatusSetter(apiConn)
    77  			if err != nil {
    78  				return nil, errors.Trace(err)
    79  			}
    80  			// Application tag for CAAS operator; controller,
    81  			// machine or unit tag for agents.
    82  			agentTag := localAgent.CurrentConfig().Tag()
    83  			isOperator := agentTag.Kind() == names.ApplicationTagKind
    84  
    85  			var isController bool
    86  			if !isOperator {
    87  				isController, err = apiagent.IsController(apiConn, agentTag)
    88  				if err != nil {
    89  					return nil, errors.Trace(err)
    90  				}
    91  			}
    92  			return NewWorker(
    93  				upgradeStepsLock,
    94  				localAgent,
    95  				apiConn,
    96  				isController,
    97  				config.OpenStateForUpgrade,
    98  				config.PreUpgradeSteps,
    99  				retry.CallArgs{
   100  					Clock:    clock.WallClock,
   101  					Delay:    2 * time.Minute,
   102  					Attempts: 5,
   103  				},
   104  				statusSetter,
   105  				isOperator,
   106  			)
   107  		},
   108  	}
   109  }