github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/apiserver/manifold.go (about)

     1  // Copyright 2017 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package apiserver
     5  
     6  import (
     7  	"net/http"
     8  
     9  	"github.com/juju/clock"
    10  	"github.com/juju/errors"
    11  	"github.com/juju/pubsub"
    12  	"github.com/prometheus/client_golang/prometheus"
    13  	"gopkg.in/juju/worker.v1"
    14  	"gopkg.in/juju/worker.v1/dependency"
    15  
    16  	"github.com/juju/juju/agent"
    17  	"github.com/juju/juju/apiserver"
    18  	"github.com/juju/juju/apiserver/apiserverhttp"
    19  	"github.com/juju/juju/apiserver/httpcontext"
    20  	"github.com/juju/juju/core/auditlog"
    21  	"github.com/juju/juju/core/cache"
    22  	"github.com/juju/juju/core/lease"
    23  	"github.com/juju/juju/core/presence"
    24  	"github.com/juju/juju/state"
    25  	"github.com/juju/juju/worker/common"
    26  	"github.com/juju/juju/worker/gate"
    27  	workerstate "github.com/juju/juju/worker/state"
    28  )
    29  
    30  // ManifoldConfig holds the information necessary to run an apiserver
    31  // worker in a dependency.Engine.
    32  type ManifoldConfig struct {
    33  	AgentName              string
    34  	AuthenticatorName      string
    35  	ClockName              string
    36  	ModelCacheName         string
    37  	MuxName                string
    38  	RestoreStatusName      string
    39  	StateName              string
    40  	UpgradeGateName        string
    41  	AuditConfigUpdaterName string
    42  	LeaseManagerName       string
    43  	RaftTransportName      string
    44  
    45  	PrometheusRegisterer              prometheus.Registerer
    46  	RegisterIntrospectionHTTPHandlers func(func(path string, _ http.Handler))
    47  	Hub                               *pubsub.StructuredHub
    48  	Presence                          presence.Recorder
    49  
    50  	NewWorker           func(Config) (worker.Worker, error)
    51  	NewMetricsCollector func() *apiserver.Collector
    52  }
    53  
    54  // Validate validates the manifold configuration.
    55  func (config ManifoldConfig) Validate() error {
    56  	if config.AgentName == "" {
    57  		return errors.NotValidf("empty AgentName")
    58  	}
    59  	if config.AuthenticatorName == "" {
    60  		return errors.NotValidf("empty AuthenticatorName")
    61  	}
    62  	if config.ClockName == "" {
    63  		return errors.NotValidf("empty ClockName")
    64  	}
    65  	if config.ModelCacheName == "" {
    66  		return errors.NotValidf("empty ModelCacheName")
    67  	}
    68  	if config.MuxName == "" {
    69  		return errors.NotValidf("empty MuxName")
    70  	}
    71  	if config.RestoreStatusName == "" {
    72  		return errors.NotValidf("empty RestoreStatusName")
    73  	}
    74  	if config.StateName == "" {
    75  		return errors.NotValidf("empty StateName")
    76  	}
    77  	if config.UpgradeGateName == "" {
    78  		return errors.NotValidf("empty UpgradeGateName")
    79  	}
    80  	if config.AuditConfigUpdaterName == "" {
    81  		return errors.NotValidf("empty AuditConfigUpdaterName")
    82  	}
    83  	if config.LeaseManagerName == "" {
    84  		return errors.NotValidf("empty LeaseManagerName")
    85  	}
    86  	if config.RaftTransportName == "" {
    87  		return errors.NotValidf("empty RaftTransportName")
    88  	}
    89  	if config.PrometheusRegisterer == nil {
    90  		return errors.NotValidf("nil PrometheusRegisterer")
    91  	}
    92  	if config.RegisterIntrospectionHTTPHandlers == nil {
    93  		return errors.NotValidf("nil RegisterIntrospectionHTTPHandlers")
    94  	}
    95  	if config.Hub == nil {
    96  		return errors.NotValidf("nil Hub")
    97  	}
    98  	if config.Presence == nil {
    99  		return errors.NotValidf("nil Presence")
   100  	}
   101  	if config.NewWorker == nil {
   102  		return errors.NotValidf("nil NewWorker")
   103  	}
   104  	if config.NewMetricsCollector == nil {
   105  		return errors.NotValidf("nil NewMetricsCollector")
   106  	}
   107  	return nil
   108  }
   109  
   110  // Manifold returns a dependency.Manifold that will run an apiserver
   111  // worker. The manifold outputs an *apiserverhttp.Mux, for other workers
   112  // to register handlers against.
   113  func Manifold(config ManifoldConfig) dependency.Manifold {
   114  	return dependency.Manifold{
   115  		Inputs: []string{
   116  			config.AgentName,
   117  			config.AuthenticatorName,
   118  			config.ClockName,
   119  			config.ModelCacheName,
   120  			config.MuxName,
   121  			config.RestoreStatusName,
   122  			config.StateName,
   123  			config.UpgradeGateName,
   124  			config.AuditConfigUpdaterName,
   125  			config.LeaseManagerName,
   126  			config.RaftTransportName,
   127  		},
   128  		Start: config.start,
   129  	}
   130  }
   131  
   132  // start is a method on ManifoldConfig because it's more readable than a closure.
   133  func (config ManifoldConfig) start(context dependency.Context) (worker.Worker, error) {
   134  	if err := config.Validate(); err != nil {
   135  		return nil, errors.Trace(err)
   136  	}
   137  
   138  	var agent agent.Agent
   139  	if err := context.Get(config.AgentName, &agent); err != nil {
   140  		return nil, errors.Trace(err)
   141  	}
   142  
   143  	var clock clock.Clock
   144  	if err := context.Get(config.ClockName, &clock); err != nil {
   145  		return nil, errors.Trace(err)
   146  	}
   147  
   148  	var mux *apiserverhttp.Mux
   149  	if err := context.Get(config.MuxName, &mux); err != nil {
   150  		return nil, errors.Trace(err)
   151  	}
   152  
   153  	var authenticator httpcontext.LocalMacaroonAuthenticator
   154  	if err := context.Get(config.AuthenticatorName, &authenticator); err != nil {
   155  		return nil, errors.Trace(err)
   156  	}
   157  
   158  	var restoreStatus func() state.RestoreStatus
   159  	if err := context.Get(config.RestoreStatusName, &restoreStatus); err != nil {
   160  		return nil, errors.Trace(err)
   161  	}
   162  
   163  	var stTracker workerstate.StateTracker
   164  	if err := context.Get(config.StateName, &stTracker); err != nil {
   165  		return nil, errors.Trace(err)
   166  	}
   167  
   168  	var controller *cache.Controller
   169  	if err := context.Get(config.ModelCacheName, &controller); err != nil {
   170  		return nil, errors.Trace(err)
   171  	}
   172  
   173  	var upgradeLock gate.Waiter
   174  	if err := context.Get(config.UpgradeGateName, &upgradeLock); err != nil {
   175  		return nil, errors.Trace(err)
   176  	}
   177  
   178  	var getAuditConfig func() auditlog.Config
   179  	if err := context.Get(config.AuditConfigUpdaterName, &getAuditConfig); err != nil {
   180  		return nil, errors.Trace(err)
   181  	}
   182  
   183  	var leaseManager lease.Manager
   184  	if err := context.Get(config.LeaseManagerName, &leaseManager); err != nil {
   185  		return nil, errors.Trace(err)
   186  	}
   187  
   188  	// We don't need anything from the raft-transport but we need to
   189  	// tie the lifetime of this worker to it - otherwise http-server
   190  	// will hang waiting for this to release the mux.
   191  	if err := context.Get(config.RaftTransportName, nil); err != nil {
   192  		return nil, errors.Trace(err)
   193  	}
   194  
   195  	// Get the state pool after grabbing dependencies so we don't need
   196  	// to remember to call Done on it if they're not running yet.
   197  	statePool, err := stTracker.Use()
   198  	if err != nil {
   199  		return nil, errors.Trace(err)
   200  	}
   201  
   202  	// Register the metrics collector against the prometheus register.
   203  	metricsCollector := config.NewMetricsCollector()
   204  	if err := config.PrometheusRegisterer.Register(metricsCollector); err != nil {
   205  		return nil, errors.Trace(err)
   206  	}
   207  
   208  	w, err := config.NewWorker(Config{
   209  		AgentConfig:                       agent.CurrentConfig(),
   210  		Clock:                             clock,
   211  		Mux:                               mux,
   212  		StatePool:                         statePool,
   213  		Controller:                        controller,
   214  		LeaseManager:                      leaseManager,
   215  		RegisterIntrospectionHTTPHandlers: config.RegisterIntrospectionHTTPHandlers,
   216  		RestoreStatus:                     restoreStatus,
   217  		UpgradeComplete:                   upgradeLock.IsUnlocked,
   218  		Hub:                               config.Hub,
   219  		Presence:                          config.Presence,
   220  		Authenticator:                     authenticator,
   221  		GetAuditConfig:                    getAuditConfig,
   222  		NewServer:                         newServerShim,
   223  		MetricsCollector:                  metricsCollector,
   224  	})
   225  	if err != nil {
   226  		stTracker.Done()
   227  		return nil, errors.Trace(err)
   228  	}
   229  	mux.AddClient()
   230  	return common.NewCleanupWorker(w, func() {
   231  		mux.ClientDone()
   232  		stTracker.Done()
   233  
   234  		// clean up the metrics for the worker, so the next time a worker is
   235  		// created we can safely register the metrics again.
   236  		config.PrometheusRegisterer.Unregister(metricsCollector)
   237  	}), nil
   238  }