github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/cmd/jujud/agent/unit/manifolds.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package unit
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/utils/voyeur"
    11  
    12  	coreagent "github.com/juju/juju/agent"
    13  	msapi "github.com/juju/juju/api/meterstatus"
    14  	"github.com/juju/juju/worker"
    15  	"github.com/juju/juju/worker/agent"
    16  	"github.com/juju/juju/worker/apiaddressupdater"
    17  	"github.com/juju/juju/worker/apicaller"
    18  	"github.com/juju/juju/worker/apiconfigwatcher"
    19  	"github.com/juju/juju/worker/dependency"
    20  	"github.com/juju/juju/worker/fortress"
    21  	"github.com/juju/juju/worker/leadership"
    22  	"github.com/juju/juju/worker/logger"
    23  	"github.com/juju/juju/worker/logsender"
    24  	"github.com/juju/juju/worker/machinelock"
    25  	"github.com/juju/juju/worker/meterstatus"
    26  	"github.com/juju/juju/worker/metrics/collect"
    27  	"github.com/juju/juju/worker/metrics/sender"
    28  	"github.com/juju/juju/worker/metrics/spool"
    29  	"github.com/juju/juju/worker/migrationminion"
    30  	"github.com/juju/juju/worker/proxyupdater"
    31  	"github.com/juju/juju/worker/retrystrategy"
    32  	"github.com/juju/juju/worker/uniter"
    33  	"github.com/juju/juju/worker/upgrader"
    34  )
    35  
    36  // ManifoldsConfig allows specialisation of the result of Manifolds.
    37  type ManifoldsConfig struct {
    38  
    39  	// Agent contains the agent that will be wrapped and made available to
    40  	// its dependencies via a dependency.Engine.
    41  	Agent coreagent.Agent
    42  
    43  	// LogSource will be read from by the logsender component.
    44  	LogSource logsender.LogRecordCh
    45  
    46  	// LeadershipGuarantee controls the behaviour of the leadership tracker.
    47  	LeadershipGuarantee time.Duration
    48  
    49  	// AgentConfigChanged is set whenever the unit agent's config
    50  	// is updated.
    51  	AgentConfigChanged *voyeur.Value
    52  }
    53  
    54  // Manifolds returns a set of co-configured manifolds covering the various
    55  // responsibilities of a standalone unit agent. It also accepts the logSource
    56  // argument because we haven't figured out how to thread all the logging bits
    57  // through a dependency engine yet.
    58  //
    59  // Thou Shalt Not Use String Literals In This Function. Or Else.
    60  func Manifolds(config ManifoldsConfig) dependency.Manifolds {
    61  
    62  	// connectFilter exists to let us retry api connections immediately
    63  	// on password change, rather than causing the dependency engine to
    64  	// wait for a while.
    65  	connectFilter := func(err error) error {
    66  		cause := errors.Cause(err)
    67  		if cause == apicaller.ErrChangedPassword {
    68  			return dependency.ErrBounce
    69  		} else if cause == apicaller.ErrConnectImpossible {
    70  			return worker.ErrTerminateAgent
    71  		}
    72  		return err
    73  	}
    74  
    75  	return dependency.Manifolds{
    76  
    77  		// The agent manifold references the enclosing agent, and is the
    78  		// foundation stone on which most other manifolds ultimately depend.
    79  		// (Currently, that is "all manifolds", but consider a shared clock.)
    80  		agentName: agent.Manifold(config.Agent),
    81  
    82  		// The machine lock manifold is a thin concurrent wrapper around an
    83  		// FSLock in an agreed location. We expect it to be replaced with an
    84  		// in-memory lock when the unit agent moves into the machine agent.
    85  		machineLockName: machinelock.Manifold(machinelock.ManifoldConfig{
    86  			AgentName: agentName,
    87  		}),
    88  
    89  		// The api-config-watcher manifold monitors the API server
    90  		// addresses in the agent config and bounces when they
    91  		// change. It's required as part of model migrations.
    92  		apiConfigWatcherName: apiconfigwatcher.Manifold(apiconfigwatcher.ManifoldConfig{
    93  			AgentName:          agentName,
    94  			AgentConfigChanged: config.AgentConfigChanged,
    95  		}),
    96  
    97  		// The api caller is a thin concurrent wrapper around a connection
    98  		// to some API server. It's used by many other manifolds, which all
    99  		// select their own desired facades. It will be interesting to see
   100  		// how this works when we consolidate the agents; might be best to
   101  		// handle the auth changes server-side..?
   102  		apiCallerName: apicaller.Manifold(apicaller.ManifoldConfig{
   103  			AgentName:            agentName,
   104  			APIConfigWatcherName: apiConfigWatcherName,
   105  			APIOpen:              apicaller.APIOpen,
   106  			NewConnection:        apicaller.ScaryConnect,
   107  			Filter:               connectFilter,
   108  		}),
   109  
   110  		// The log sender is a leaf worker that sends log messages to some
   111  		// API server, when configured so to do. We should only need one of
   112  		// these in a consolidated agent.
   113  		logSenderName: logsender.Manifold(logsender.ManifoldConfig{
   114  			APICallerName: apiCallerName,
   115  			LogSource:     config.LogSource,
   116  		}),
   117  
   118  		// The upgrader is a leaf worker that returns a specific error type
   119  		// recognised by the unit agent, causing other workers to be stopped
   120  		// and the agent to be restarted running the new tools. We should only
   121  		// need one of these in a consolidated agent, but we'll need to be
   122  		// careful about behavioural differences, and interactions with the
   123  		// upgradesteps worker.
   124  		upgraderName: upgrader.Manifold(upgrader.ManifoldConfig{
   125  			AgentName:     agentName,
   126  			APICallerName: apiCallerName,
   127  		}),
   128  
   129  		migrationFortressName: fortress.Manifold(),
   130  
   131  		// The migration minion handles the agent side aspects of model migrations.
   132  		migrationMinionName: migrationminion.Manifold(migrationminion.ManifoldConfig{
   133  			AgentName:     agentName,
   134  			APICallerName: apiCallerName,
   135  			FortressName:  migrationFortressName,
   136  
   137  			NewFacade: migrationminion.NewFacade,
   138  			NewWorker: migrationminion.NewWorker,
   139  		}),
   140  
   141  		// The logging config updater is a leaf worker that indirectly
   142  		// controls the messages sent via the log sender according to
   143  		// changes in environment config. We should only need one of
   144  		// these in a consolidated agent.
   145  		loggingConfigUpdaterName: logger.Manifold(logger.ManifoldConfig{
   146  			AgentName:     agentName,
   147  			APICallerName: apiCallerName,
   148  		}),
   149  
   150  		// The api address updater is a leaf worker that rewrites agent config
   151  		// as the controller addresses change. We should only need one of
   152  		// these in a consolidated agent.
   153  		apiAddressUpdaterName: apiaddressupdater.Manifold(apiaddressupdater.ManifoldConfig{
   154  			AgentName:     agentName,
   155  			APICallerName: apiCallerName,
   156  		}),
   157  
   158  		// The proxy config updater is a leaf worker that sets http/https/apt/etc
   159  		// proxy settings.
   160  		// TODO(fwereade): timing of this is suspicious. There was superstitious
   161  		// code trying to run this early; if that ever helped, it was only by
   162  		// coincidence. Probably we ought to be making components that might
   163  		// need proxy config into explicit dependencies of the proxy updater...
   164  		proxyConfigUpdaterName: proxyupdater.Manifold(proxyupdater.ManifoldConfig{
   165  			APICallerName: apiCallerName,
   166  		}),
   167  
   168  		// The charmdir resource coordinates whether the charm directory is
   169  		// available or not; after 'start' hook and before 'stop' hook
   170  		// executes, and not during upgrades.
   171  		charmDirName: fortress.Manifold(),
   172  
   173  		// The leadership tracker attempts to secure and retain leadership of
   174  		// the unit's service, and is consulted on such matters by the
   175  		// uniter. As it stannds today, we'll need one per unit in a
   176  		// consolidated agent.
   177  		leadershipTrackerName: leadership.Manifold(leadership.ManifoldConfig{
   178  			AgentName:           agentName,
   179  			APICallerName:       apiCallerName,
   180  			LeadershipGuarantee: config.LeadershipGuarantee,
   181  		}),
   182  
   183  		// HookRetryStrategy uses a retrystrategy worker to get a
   184  		// retry strategy that will be used by the uniter to run its hooks.
   185  		hookRetryStrategyName: retrystrategy.Manifold(retrystrategy.ManifoldConfig{
   186  			AgentName:     agentName,
   187  			APICallerName: apiCallerName,
   188  			NewFacade:     retrystrategy.NewFacade,
   189  			NewWorker:     retrystrategy.NewRetryStrategyWorker,
   190  		}),
   191  
   192  		// The uniter installs charms; manages the unit's presence in its
   193  		// relations; creates suboordinate units; runs all the hooks; sends
   194  		// metrics; etc etc etc. We expect to break it up further in the
   195  		// coming weeks, and to need one per unit in a consolidated agent
   196  		// (and probably one for each component broken out).
   197  		uniterName: uniter.Manifold(uniter.ManifoldConfig{
   198  			AgentName:             agentName,
   199  			APICallerName:         apiCallerName,
   200  			LeadershipTrackerName: leadershipTrackerName,
   201  			MachineLockName:       machineLockName,
   202  			CharmDirName:          charmDirName,
   203  			HookRetryStrategyName: hookRetryStrategyName,
   204  		}),
   205  
   206  		// TODO (mattyw) should be added to machine agent.
   207  		metricSpoolName: spool.Manifold(spool.ManifoldConfig{
   208  			AgentName: agentName,
   209  		}),
   210  
   211  		// The metric collect worker executes the collect-metrics hook in a
   212  		// restricted context that can safely run concurrently with other hooks.
   213  		metricCollectName: collect.Manifold(collect.ManifoldConfig{
   214  			AgentName:       agentName,
   215  			MetricSpoolName: metricSpoolName,
   216  			CharmDirName:    charmDirName,
   217  		}),
   218  
   219  		// The meter status worker executes the meter-status-changed hook when it detects
   220  		// that the meter status has changed.
   221  		meterStatusName: meterstatus.Manifold(meterstatus.ManifoldConfig{
   222  			AgentName:                agentName,
   223  			APICallerName:            apiCallerName,
   224  			MachineLockName:          machineLockName,
   225  			NewHookRunner:            meterstatus.NewHookRunner,
   226  			NewMeterStatusAPIClient:  msapi.NewClient,
   227  			NewConnectedStatusWorker: meterstatus.NewConnectedStatusWorker,
   228  			NewIsolatedStatusWorker:  meterstatus.NewIsolatedStatusWorker,
   229  		}),
   230  
   231  		// The metric sender worker periodically sends accumulated metrics to the controller.
   232  		metricSenderName: sender.Manifold(sender.ManifoldConfig{
   233  			AgentName:       agentName,
   234  			APICallerName:   apiCallerName,
   235  			MetricSpoolName: metricSpoolName,
   236  		}),
   237  	}
   238  }
   239  
   240  const (
   241  	agentName            = "agent"
   242  	machineLockName      = "machine-lock"
   243  	apiConfigWatcherName = "api-config-watcher"
   244  	apiCallerName        = "api-caller"
   245  	logSenderName        = "log-sender"
   246  	upgraderName         = "upgrader"
   247  
   248  	migrationFortressName = "migration-fortress"
   249  	migrationMinionName   = "migration-minion"
   250  
   251  	loggingConfigUpdaterName = "logging-config-updater"
   252  	proxyConfigUpdaterName   = "proxy-config-updater"
   253  	apiAddressUpdaterName    = "api-address-updater"
   254  
   255  	charmDirName          = "charm-dir"
   256  	leadershipTrackerName = "leadership-tracker"
   257  	hookRetryStrategyName = "hook-retry-strategy"
   258  	uniterName            = "uniter"
   259  
   260  	metricSpoolName   = "metric-spool"
   261  	meterStatusName   = "meter-status"
   262  	metricCollectName = "metric-collect"
   263  	metricSenderName  = "metric-sender"
   264  )