github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/worker/apiserver/worker.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  	"context"
     8  	"fmt"
     9  	"net/http"
    10  
    11  	"github.com/juju/clock"
    12  	"github.com/juju/errors"
    13  	"github.com/juju/pubsub/v2"
    14  	"github.com/juju/worker/v3"
    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/authentication/jwt"
    20  	"github.com/juju/juju/apiserver/authentication/macaroon"
    21  	jujucontroller "github.com/juju/juju/controller"
    22  	"github.com/juju/juju/core/auditlog"
    23  	"github.com/juju/juju/core/cache"
    24  	coredatabase "github.com/juju/juju/core/database"
    25  	"github.com/juju/juju/core/lease"
    26  	"github.com/juju/juju/core/multiwatcher"
    27  	"github.com/juju/juju/core/presence"
    28  	"github.com/juju/juju/state"
    29  	"github.com/juju/juju/worker/syslogger"
    30  )
    31  
    32  // Config is the configuration required for running an API server worker.
    33  type Config struct {
    34  	AgentConfig                       agent.Config
    35  	Clock                             clock.Clock
    36  	Hub                               *pubsub.StructuredHub
    37  	Presence                          presence.Recorder
    38  	Mux                               *apiserverhttp.Mux
    39  	MultiwatcherFactory               multiwatcher.Factory
    40  	LocalMacaroonAuthenticator        macaroon.LocalMacaroonAuthenticator
    41  	StatePool                         *state.StatePool
    42  	Controller                        *cache.Controller
    43  	LeaseManager                      lease.Manager
    44  	SysLogger                         syslogger.SysLogger
    45  	RegisterIntrospectionHTTPHandlers func(func(path string, _ http.Handler))
    46  	UpgradeComplete                   func() bool
    47  	GetAuditConfig                    func() auditlog.Config
    48  	NewServer                         NewServerFunc
    49  	MetricsCollector                  *apiserver.Collector
    50  	EmbeddedCommand                   apiserver.ExecEmbeddedCommandFunc
    51  	CharmhubHTTPClient                HTTPClient
    52  	// DBGetter supplies sql.DB references on request, for named databases.
    53  	DBGetter coredatabase.DBGetter
    54  }
    55  
    56  type HTTPClient interface {
    57  	Do(*http.Request) (*http.Response, error)
    58  }
    59  
    60  // NewServerFunc is the type of function that will be used
    61  // by the worker to create a new API server.
    62  type NewServerFunc func(apiserver.ServerConfig) (worker.Worker, error)
    63  
    64  // Validate validates the API server configuration.
    65  func (config Config) Validate() error {
    66  	if config.AgentConfig == nil {
    67  		return errors.NotValidf("nil AgentConfig")
    68  	}
    69  	if config.Clock == nil {
    70  		return errors.NotValidf("nil Clock")
    71  	}
    72  	if config.Hub == nil {
    73  		return errors.NotValidf("nil Hub")
    74  	}
    75  	if config.Presence == nil {
    76  		return errors.NotValidf("nil Presence")
    77  	}
    78  	if config.StatePool == nil {
    79  		return errors.NotValidf("nil StatePool")
    80  	}
    81  	if config.Controller == nil {
    82  		return errors.NotValidf("nil Controller")
    83  	}
    84  	if config.Mux == nil {
    85  		return errors.NotValidf("nil Mux")
    86  	}
    87  	if config.MultiwatcherFactory == nil {
    88  		return errors.NotValidf("nil MultiwatcherFactory")
    89  	}
    90  	if config.LocalMacaroonAuthenticator == nil {
    91  		return errors.NotValidf("nil LocalMacaroonAuthenticator")
    92  	}
    93  	if config.LeaseManager == nil {
    94  		return errors.NotValidf("nil LeaseManager")
    95  	}
    96  	if config.RegisterIntrospectionHTTPHandlers == nil {
    97  		return errors.NotValidf("nil RegisterIntrospectionHTTPHandlers")
    98  	}
    99  	if config.SysLogger == nil {
   100  		return errors.NotValidf("nil SysLogger")
   101  	}
   102  	if config.UpgradeComplete == nil {
   103  		return errors.NotValidf("nil UpgradeComplete")
   104  	}
   105  	if config.NewServer == nil {
   106  		return errors.NotValidf("nil NewServer")
   107  	}
   108  	if config.MetricsCollector == nil {
   109  		return errors.NotValidf("nil MetricsCollector")
   110  	}
   111  	if config.CharmhubHTTPClient == nil {
   112  		return errors.NotValidf("nil CharmhubHTTPClient")
   113  	}
   114  	if config.DBGetter == nil {
   115  		return errors.NotValidf("nil DBGetter")
   116  	}
   117  	return nil
   118  }
   119  
   120  // NewWorker returns a new API server worker, with the given configuration.
   121  func NewWorker(config Config) (worker.Worker, error) {
   122  	if err := config.Validate(); err != nil {
   123  		return nil, errors.Trace(err)
   124  	}
   125  
   126  	logSinkConfig, err := getLogSinkConfig(config.AgentConfig)
   127  	if err != nil {
   128  		return nil, errors.Annotate(err, "getting log sink config")
   129  	}
   130  
   131  	systemState, err := config.StatePool.SystemState()
   132  	if err != nil {
   133  		return nil, errors.Trace(err)
   134  	}
   135  	controllerConfig, err := systemState.ControllerConfig()
   136  	if err != nil {
   137  		return nil, errors.Annotate(err, "cannot fetch the controller config")
   138  	}
   139  
   140  	observerFactory, err := newObserverFn(
   141  		config.AgentConfig,
   142  		controllerConfig,
   143  		config.Clock,
   144  		config.Hub,
   145  		config.MetricsCollector,
   146  	)
   147  	if err != nil {
   148  		return nil, errors.Annotate(err, "cannot create RPC observer factory")
   149  	}
   150  
   151  	jwtAuthenticator, err := gatherJWTAuthenticator(controllerConfig)
   152  	if err != nil {
   153  		return nil, fmt.Errorf("gathering authenticators for apiserver: %w", err)
   154  	}
   155  
   156  	serverConfig := apiserver.ServerConfig{
   157  		StatePool:                     config.StatePool,
   158  		Controller:                    config.Controller,
   159  		Clock:                         config.Clock,
   160  		Tag:                           config.AgentConfig.Tag(),
   161  		DataDir:                       config.AgentConfig.DataDir(),
   162  		LogDir:                        config.AgentConfig.LogDir(),
   163  		Hub:                           config.Hub,
   164  		Presence:                      config.Presence,
   165  		MultiwatcherFactory:           config.MultiwatcherFactory,
   166  		Mux:                           config.Mux,
   167  		LocalMacaroonAuthenticator:    config.LocalMacaroonAuthenticator,
   168  		JWTAuthenticator:              jwtAuthenticator,
   169  		UpgradeComplete:               config.UpgradeComplete,
   170  		PublicDNSName:                 controllerConfig.AutocertDNSName(),
   171  		AllowModelAccess:              controllerConfig.AllowModelAccess(),
   172  		NewObserver:                   observerFactory,
   173  		RegisterIntrospectionHandlers: config.RegisterIntrospectionHTTPHandlers,
   174  		MetricsCollector:              config.MetricsCollector,
   175  		LogSinkConfig:                 &logSinkConfig,
   176  		GetAuditConfig:                config.GetAuditConfig,
   177  		LeaseManager:                  config.LeaseManager,
   178  		ExecEmbeddedCommand:           config.EmbeddedCommand,
   179  		SysLogger:                     config.SysLogger,
   180  		CharmhubHTTPClient:            config.CharmhubHTTPClient,
   181  		DBGetter:                      config.DBGetter,
   182  	}
   183  	return config.NewServer(serverConfig)
   184  }
   185  
   186  // gatherJWTAuthenticator is responsible for building up the jwt authenticator
   187  // if this controller has been provisioned to trust external jwt tokens.
   188  func gatherJWTAuthenticator(controllerConfig jujucontroller.Config) (jwt.Authenticator, error) {
   189  	jwtRefreshURL := controllerConfig.LoginTokenRefreshURL()
   190  	if jwtRefreshURL == "" {
   191  		return nil, nil
   192  	}
   193  	jwtAuthenticator := jwt.NewAuthenticator(jwtRefreshURL)
   194  	if err := jwtAuthenticator.RegisterJWKSCache(context.Background()); err != nil {
   195  		return nil, err
   196  	}
   197  	return jwtAuthenticator, nil
   198  }
   199  
   200  func newServerShim(config apiserver.ServerConfig) (worker.Worker, error) {
   201  	return apiserver.NewServer(config)
   202  }
   203  
   204  // NewMetricsCollector returns a new apiserver collector
   205  func NewMetricsCollector() *apiserver.Collector {
   206  	return apiserver.NewMetricsCollector()
   207  }