daemon.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. package main
  2. import (
  3. "context"
  4. "crypto/tls"
  5. "fmt"
  6. "os"
  7. "path/filepath"
  8. "runtime"
  9. "strings"
  10. "time"
  11. "github.com/docker/distribution/uuid"
  12. "github.com/docker/docker/api"
  13. apiserver "github.com/docker/docker/api/server"
  14. buildbackend "github.com/docker/docker/api/server/backend/build"
  15. "github.com/docker/docker/api/server/middleware"
  16. "github.com/docker/docker/api/server/router"
  17. "github.com/docker/docker/api/server/router/build"
  18. checkpointrouter "github.com/docker/docker/api/server/router/checkpoint"
  19. "github.com/docker/docker/api/server/router/container"
  20. distributionrouter "github.com/docker/docker/api/server/router/distribution"
  21. "github.com/docker/docker/api/server/router/image"
  22. "github.com/docker/docker/api/server/router/network"
  23. pluginrouter "github.com/docker/docker/api/server/router/plugin"
  24. sessionrouter "github.com/docker/docker/api/server/router/session"
  25. swarmrouter "github.com/docker/docker/api/server/router/swarm"
  26. systemrouter "github.com/docker/docker/api/server/router/system"
  27. "github.com/docker/docker/api/server/router/volume"
  28. buildkit "github.com/docker/docker/builder/builder-next"
  29. "github.com/docker/docker/builder/dockerfile"
  30. "github.com/docker/docker/builder/fscache"
  31. "github.com/docker/docker/cli/debug"
  32. "github.com/docker/docker/daemon"
  33. "github.com/docker/docker/daemon/cluster"
  34. "github.com/docker/docker/daemon/config"
  35. "github.com/docker/docker/daemon/listeners"
  36. "github.com/docker/docker/dockerversion"
  37. "github.com/docker/docker/libcontainerd"
  38. dopts "github.com/docker/docker/opts"
  39. "github.com/docker/docker/pkg/authorization"
  40. "github.com/docker/docker/pkg/jsonmessage"
  41. "github.com/docker/docker/pkg/pidfile"
  42. "github.com/docker/docker/pkg/plugingetter"
  43. "github.com/docker/docker/pkg/signal"
  44. "github.com/docker/docker/pkg/system"
  45. "github.com/docker/docker/plugin"
  46. "github.com/docker/docker/registry"
  47. "github.com/docker/docker/runconfig"
  48. "github.com/docker/go-connections/tlsconfig"
  49. swarmapi "github.com/docker/swarmkit/api"
  50. "github.com/moby/buildkit/session"
  51. "github.com/pkg/errors"
  52. "github.com/sirupsen/logrus"
  53. "github.com/spf13/pflag"
  54. )
  55. // DaemonCli represents the daemon CLI.
  56. type DaemonCli struct {
  57. *config.Config
  58. configFile *string
  59. flags *pflag.FlagSet
  60. api *apiserver.Server
  61. d *daemon.Daemon
  62. authzMiddleware *authorization.Middleware // authzMiddleware enables to dynamically reload the authorization plugins
  63. }
  64. // NewDaemonCli returns a daemon CLI
  65. func NewDaemonCli() *DaemonCli {
  66. return &DaemonCli{}
  67. }
  68. func (cli *DaemonCli) start(opts *daemonOptions) (err error) {
  69. stopc := make(chan bool)
  70. defer close(stopc)
  71. // warn from uuid package when running the daemon
  72. uuid.Loggerf = logrus.Warnf
  73. opts.SetDefaultOptions(opts.flags)
  74. if cli.Config, err = loadDaemonCliConfig(opts); err != nil {
  75. return err
  76. }
  77. cli.configFile = &opts.configFile
  78. cli.flags = opts.flags
  79. if cli.Config.Debug {
  80. debug.Enable()
  81. }
  82. if cli.Config.Experimental {
  83. logrus.Warn("Running experimental build")
  84. }
  85. logrus.SetFormatter(&logrus.TextFormatter{
  86. TimestampFormat: jsonmessage.RFC3339NanoFixed,
  87. DisableColors: cli.Config.RawLogs,
  88. FullTimestamp: true,
  89. })
  90. system.InitLCOW(cli.Config.Experimental)
  91. if err := setDefaultUmask(); err != nil {
  92. return fmt.Errorf("Failed to set umask: %v", err)
  93. }
  94. // Create the daemon root before we create ANY other files (PID, or migrate keys)
  95. // to ensure the appropriate ACL is set (particularly relevant on Windows)
  96. if err := daemon.CreateDaemonRoot(cli.Config); err != nil {
  97. return err
  98. }
  99. if cli.Pidfile != "" {
  100. pf, err := pidfile.New(cli.Pidfile)
  101. if err != nil {
  102. return fmt.Errorf("Error starting daemon: %v", err)
  103. }
  104. defer func() {
  105. if err := pf.Remove(); err != nil {
  106. logrus.Error(err)
  107. }
  108. }()
  109. }
  110. serverConfig, err := newAPIServerConfig(cli)
  111. if err != nil {
  112. return fmt.Errorf("Failed to create API server: %v", err)
  113. }
  114. cli.api = apiserver.New(serverConfig)
  115. hosts, err := loadListeners(cli, serverConfig)
  116. if err != nil {
  117. return fmt.Errorf("Failed to load listeners: %v", err)
  118. }
  119. registryService, err := registry.NewService(cli.Config.ServiceOptions)
  120. if err != nil {
  121. return err
  122. }
  123. rOpts, err := cli.getRemoteOptions()
  124. if err != nil {
  125. return fmt.Errorf("Failed to generate containerd options: %v", err)
  126. }
  127. containerdRemote, err := libcontainerd.New(filepath.Join(cli.Config.Root, "containerd"), filepath.Join(cli.Config.ExecRoot, "containerd"), rOpts...)
  128. if err != nil {
  129. return err
  130. }
  131. signal.Trap(func() {
  132. cli.stop()
  133. <-stopc // wait for daemonCli.start() to return
  134. }, logrus.StandardLogger())
  135. // Notify that the API is active, but before daemon is set up.
  136. preNotifySystem()
  137. pluginStore := plugin.NewStore()
  138. if err := cli.initMiddlewares(cli.api, serverConfig, pluginStore); err != nil {
  139. logrus.Fatalf("Error creating middlewares: %v", err)
  140. }
  141. d, err := daemon.NewDaemon(cli.Config, registryService, containerdRemote, pluginStore)
  142. if err != nil {
  143. return fmt.Errorf("Error starting daemon: %v", err)
  144. }
  145. d.StoreHosts(hosts)
  146. // validate after NewDaemon has restored enabled plugins. Dont change order.
  147. if err := validateAuthzPlugins(cli.Config.AuthorizationPlugins, pluginStore); err != nil {
  148. return fmt.Errorf("Error validating authorization plugin: %v", err)
  149. }
  150. // TODO: move into startMetricsServer()
  151. if cli.Config.MetricsAddress != "" {
  152. if !d.HasExperimental() {
  153. return fmt.Errorf("metrics-addr is only supported when experimental is enabled")
  154. }
  155. if err := startMetricsServer(cli.Config.MetricsAddress); err != nil {
  156. return err
  157. }
  158. }
  159. c, err := createAndStartCluster(cli, d)
  160. if err != nil {
  161. logrus.Fatalf("Error starting cluster component: %v", err)
  162. }
  163. // Restart all autostart containers which has a swarm endpoint
  164. // and is not yet running now that we have successfully
  165. // initialized the cluster.
  166. d.RestartSwarmContainers()
  167. logrus.Info("Daemon has completed initialization")
  168. cli.d = d
  169. routerOptions, err := newRouterOptions(cli.Config, d)
  170. if err != nil {
  171. return err
  172. }
  173. routerOptions.api = cli.api
  174. routerOptions.cluster = c
  175. initRouter(routerOptions)
  176. // process cluster change notifications
  177. watchCtx, cancel := context.WithCancel(context.Background())
  178. defer cancel()
  179. go d.ProcessClusterNotifications(watchCtx, c.GetWatchStream())
  180. cli.setupConfigReloadTrap()
  181. // The serve API routine never exits unless an error occurs
  182. // We need to start it as a goroutine and wait on it so
  183. // daemon doesn't exit
  184. serveAPIWait := make(chan error)
  185. go cli.api.Wait(serveAPIWait)
  186. // after the daemon is done setting up we can notify systemd api
  187. notifySystem()
  188. // Daemon is fully initialized and handling API traffic
  189. // Wait for serve API to complete
  190. errAPI := <-serveAPIWait
  191. c.Cleanup()
  192. shutdownDaemon(d)
  193. containerdRemote.Cleanup()
  194. if errAPI != nil {
  195. return fmt.Errorf("Shutting down due to ServeAPI error: %v", errAPI)
  196. }
  197. return nil
  198. }
  199. type routerOptions struct {
  200. sessionManager *session.Manager
  201. buildBackend *buildbackend.Backend
  202. buildCache *fscache.FSCache // legacy
  203. buildkit *buildkit.Builder
  204. daemon *daemon.Daemon
  205. api *apiserver.Server
  206. cluster *cluster.Cluster
  207. }
  208. func newRouterOptions(config *config.Config, daemon *daemon.Daemon) (routerOptions, error) {
  209. opts := routerOptions{}
  210. sm, err := session.NewManager()
  211. if err != nil {
  212. return opts, errors.Wrap(err, "failed to create sessionmanager")
  213. }
  214. builderStateDir := filepath.Join(config.Root, "builder")
  215. buildCache, err := fscache.NewFSCache(fscache.Opt{
  216. Backend: fscache.NewNaiveCacheBackend(builderStateDir),
  217. Root: builderStateDir,
  218. GCPolicy: fscache.GCPolicy{ // TODO: expose this in config
  219. MaxSize: 1024 * 1024 * 512, // 512MB
  220. MaxKeepDuration: 7 * 24 * time.Hour, // 1 week
  221. },
  222. })
  223. if err != nil {
  224. return opts, errors.Wrap(err, "failed to create fscache")
  225. }
  226. manager, err := dockerfile.NewBuildManager(daemon.BuilderBackend(), sm, buildCache, daemon.IDMappings())
  227. if err != nil {
  228. return opts, err
  229. }
  230. buildkit, err := buildkit.New(buildkit.Opt{
  231. SessionManager: sm,
  232. Root: filepath.Join(config.Root, "buildkit"),
  233. Dist: daemon.DistributionServices(),
  234. })
  235. if err != nil {
  236. return opts, err
  237. }
  238. bb, err := buildbackend.NewBackend(daemon.ImageService(), manager, buildCache, buildkit)
  239. if err != nil {
  240. return opts, errors.Wrap(err, "failed to create buildmanager")
  241. }
  242. return routerOptions{
  243. sessionManager: sm,
  244. buildBackend: bb,
  245. buildCache: buildCache,
  246. buildkit: buildkit,
  247. daemon: daemon,
  248. }, nil
  249. }
  250. func (cli *DaemonCli) reloadConfig() {
  251. reload := func(c *config.Config) {
  252. // Revalidate and reload the authorization plugins
  253. if err := validateAuthzPlugins(c.AuthorizationPlugins, cli.d.PluginStore); err != nil {
  254. logrus.Fatalf("Error validating authorization plugin: %v", err)
  255. return
  256. }
  257. cli.authzMiddleware.SetPlugins(c.AuthorizationPlugins)
  258. // The namespaces com.docker.*, io.docker.*, org.dockerproject.* have been documented
  259. // to be reserved for Docker's internal use, but this was never enforced. Allowing
  260. // configured labels to use these namespaces are deprecated for 18.05.
  261. //
  262. // The following will check the usage of such labels, and report a warning for deprecation.
  263. //
  264. // TODO: At the next stable release, the validation should be folded into the other
  265. // configuration validation functions and an error will be returned instead, and this
  266. // block should be deleted.
  267. if err := config.ValidateReservedNamespaceLabels(c.Labels); err != nil {
  268. logrus.Warnf("Configured labels using reserved namespaces is deprecated: %s", err)
  269. }
  270. if err := cli.d.Reload(c); err != nil {
  271. logrus.Errorf("Error reconfiguring the daemon: %v", err)
  272. return
  273. }
  274. if c.IsValueSet("debug") {
  275. debugEnabled := debug.IsEnabled()
  276. switch {
  277. case debugEnabled && !c.Debug: // disable debug
  278. debug.Disable()
  279. case c.Debug && !debugEnabled: // enable debug
  280. debug.Enable()
  281. }
  282. }
  283. }
  284. if err := config.Reload(*cli.configFile, cli.flags, reload); err != nil {
  285. logrus.Error(err)
  286. }
  287. }
  288. func (cli *DaemonCli) stop() {
  289. cli.api.Close()
  290. }
  291. // shutdownDaemon just wraps daemon.Shutdown() to handle a timeout in case
  292. // d.Shutdown() is waiting too long to kill container or worst it's
  293. // blocked there
  294. func shutdownDaemon(d *daemon.Daemon) {
  295. shutdownTimeout := d.ShutdownTimeout()
  296. ch := make(chan struct{})
  297. go func() {
  298. d.Shutdown()
  299. close(ch)
  300. }()
  301. if shutdownTimeout < 0 {
  302. <-ch
  303. logrus.Debug("Clean shutdown succeeded")
  304. return
  305. }
  306. select {
  307. case <-ch:
  308. logrus.Debug("Clean shutdown succeeded")
  309. case <-time.After(time.Duration(shutdownTimeout) * time.Second):
  310. logrus.Error("Force shutdown daemon")
  311. }
  312. }
  313. func loadDaemonCliConfig(opts *daemonOptions) (*config.Config, error) {
  314. conf := opts.daemonConfig
  315. flags := opts.flags
  316. conf.Debug = opts.Debug
  317. conf.Hosts = opts.Hosts
  318. conf.LogLevel = opts.LogLevel
  319. conf.TLS = opts.TLS
  320. conf.TLSVerify = opts.TLSVerify
  321. conf.CommonTLSOptions = config.CommonTLSOptions{}
  322. if opts.TLSOptions != nil {
  323. conf.CommonTLSOptions.CAFile = opts.TLSOptions.CAFile
  324. conf.CommonTLSOptions.CertFile = opts.TLSOptions.CertFile
  325. conf.CommonTLSOptions.KeyFile = opts.TLSOptions.KeyFile
  326. }
  327. if conf.TrustKeyPath == "" {
  328. conf.TrustKeyPath = filepath.Join(
  329. getDaemonConfDir(conf.Root),
  330. defaultTrustKeyFile)
  331. }
  332. if flags.Changed("graph") && flags.Changed("data-root") {
  333. return nil, fmt.Errorf(`cannot specify both "--graph" and "--data-root" option`)
  334. }
  335. if opts.configFile != "" {
  336. c, err := config.MergeDaemonConfigurations(conf, flags, opts.configFile)
  337. if err != nil {
  338. if flags.Changed("config-file") || !os.IsNotExist(err) {
  339. return nil, fmt.Errorf("unable to configure the Docker daemon with file %s: %v", opts.configFile, err)
  340. }
  341. }
  342. // the merged configuration can be nil if the config file didn't exist.
  343. // leave the current configuration as it is if when that happens.
  344. if c != nil {
  345. conf = c
  346. }
  347. }
  348. if err := config.Validate(conf); err != nil {
  349. return nil, err
  350. }
  351. if runtime.GOOS != "windows" {
  352. if flags.Changed("disable-legacy-registry") {
  353. // TODO: Remove this error after 3 release cycles (18.03)
  354. return nil, errors.New("ERROR: The '--disable-legacy-registry' flag has been removed. Interacting with legacy (v1) registries is no longer supported")
  355. }
  356. if !conf.V2Only {
  357. // TODO: Remove this error after 3 release cycles (18.03)
  358. return nil, errors.New("ERROR: The 'disable-legacy-registry' configuration option has been removed. Interacting with legacy (v1) registries is no longer supported")
  359. }
  360. }
  361. if flags.Changed("graph") {
  362. logrus.Warnf(`The "-g / --graph" flag is deprecated. Please use "--data-root" instead`)
  363. }
  364. // Check if duplicate label-keys with different values are found
  365. newLabels, err := config.GetConflictFreeLabels(conf.Labels)
  366. if err != nil {
  367. return nil, err
  368. }
  369. // The namespaces com.docker.*, io.docker.*, org.dockerproject.* have been documented
  370. // to be reserved for Docker's internal use, but this was never enforced. Allowing
  371. // configured labels to use these namespaces are deprecated for 18.05.
  372. //
  373. // The following will check the usage of such labels, and report a warning for deprecation.
  374. //
  375. // TODO: At the next stable release, the validation should be folded into the other
  376. // configuration validation functions and an error will be returned instead, and this
  377. // block should be deleted.
  378. if err := config.ValidateReservedNamespaceLabels(newLabels); err != nil {
  379. logrus.Warnf("Configured labels using reserved namespaces is deprecated: %s", err)
  380. }
  381. conf.Labels = newLabels
  382. // Regardless of whether the user sets it to true or false, if they
  383. // specify TLSVerify at all then we need to turn on TLS
  384. if conf.IsValueSet(FlagTLSVerify) {
  385. conf.TLS = true
  386. }
  387. // ensure that the log level is the one set after merging configurations
  388. setLogLevel(conf.LogLevel)
  389. return conf, nil
  390. }
  391. func initRouter(opts routerOptions) {
  392. decoder := runconfig.ContainerDecoder{}
  393. routers := []router.Router{
  394. // we need to add the checkpoint router before the container router or the DELETE gets masked
  395. checkpointrouter.NewRouter(opts.daemon, decoder),
  396. container.NewRouter(opts.daemon, decoder),
  397. image.NewRouter(opts.daemon.ImageService()),
  398. systemrouter.NewRouter(opts.daemon, opts.cluster, opts.buildCache, opts.buildkit),
  399. volume.NewRouter(opts.daemon.VolumesService()),
  400. build.NewRouter(opts.buildBackend, opts.daemon),
  401. sessionrouter.NewRouter(opts.sessionManager),
  402. swarmrouter.NewRouter(opts.cluster),
  403. pluginrouter.NewRouter(opts.daemon.PluginManager()),
  404. distributionrouter.NewRouter(opts.daemon.ImageService()),
  405. }
  406. if opts.daemon.NetworkControllerEnabled() {
  407. routers = append(routers, network.NewRouter(opts.daemon, opts.cluster))
  408. }
  409. if opts.daemon.HasExperimental() {
  410. for _, r := range routers {
  411. for _, route := range r.Routes() {
  412. if experimental, ok := route.(router.ExperimentalRoute); ok {
  413. experimental.Enable()
  414. }
  415. }
  416. }
  417. }
  418. opts.api.InitRouter(routers...)
  419. }
  420. // TODO: remove this from cli and return the authzMiddleware
  421. func (cli *DaemonCli) initMiddlewares(s *apiserver.Server, cfg *apiserver.Config, pluginStore plugingetter.PluginGetter) error {
  422. v := cfg.Version
  423. exp := middleware.NewExperimentalMiddleware(cli.Config.Experimental)
  424. s.UseMiddleware(exp)
  425. vm := middleware.NewVersionMiddleware(v, api.DefaultVersion, api.MinVersion)
  426. s.UseMiddleware(vm)
  427. if cfg.CorsHeaders != "" {
  428. c := middleware.NewCORSMiddleware(cfg.CorsHeaders)
  429. s.UseMiddleware(c)
  430. }
  431. cli.authzMiddleware = authorization.NewMiddleware(cli.Config.AuthorizationPlugins, pluginStore)
  432. cli.Config.AuthzMiddleware = cli.authzMiddleware
  433. s.UseMiddleware(cli.authzMiddleware)
  434. return nil
  435. }
  436. func (cli *DaemonCli) getRemoteOptions() ([]libcontainerd.RemoteOption, error) {
  437. opts := []libcontainerd.RemoteOption{}
  438. pOpts, err := cli.getPlatformRemoteOptions()
  439. if err != nil {
  440. return nil, err
  441. }
  442. opts = append(opts, pOpts...)
  443. return opts, nil
  444. }
  445. func newAPIServerConfig(cli *DaemonCli) (*apiserver.Config, error) {
  446. serverConfig := &apiserver.Config{
  447. Logging: true,
  448. SocketGroup: cli.Config.SocketGroup,
  449. Version: dockerversion.Version,
  450. CorsHeaders: cli.Config.CorsHeaders,
  451. }
  452. if cli.Config.TLS {
  453. tlsOptions := tlsconfig.Options{
  454. CAFile: cli.Config.CommonTLSOptions.CAFile,
  455. CertFile: cli.Config.CommonTLSOptions.CertFile,
  456. KeyFile: cli.Config.CommonTLSOptions.KeyFile,
  457. ExclusiveRootPools: true,
  458. }
  459. if cli.Config.TLSVerify {
  460. // server requires and verifies client's certificate
  461. tlsOptions.ClientAuth = tls.RequireAndVerifyClientCert
  462. }
  463. tlsConfig, err := tlsconfig.Server(tlsOptions)
  464. if err != nil {
  465. return nil, err
  466. }
  467. serverConfig.TLSConfig = tlsConfig
  468. }
  469. if len(cli.Config.Hosts) == 0 {
  470. cli.Config.Hosts = make([]string, 1)
  471. }
  472. return serverConfig, nil
  473. }
  474. func loadListeners(cli *DaemonCli, serverConfig *apiserver.Config) ([]string, error) {
  475. var hosts []string
  476. for i := 0; i < len(cli.Config.Hosts); i++ {
  477. var err error
  478. if cli.Config.Hosts[i], err = dopts.ParseHost(cli.Config.TLS, cli.Config.Hosts[i]); err != nil {
  479. return nil, fmt.Errorf("error parsing -H %s : %v", cli.Config.Hosts[i], err)
  480. }
  481. protoAddr := cli.Config.Hosts[i]
  482. protoAddrParts := strings.SplitN(protoAddr, "://", 2)
  483. if len(protoAddrParts) != 2 {
  484. return nil, fmt.Errorf("bad format %s, expected PROTO://ADDR", protoAddr)
  485. }
  486. proto := protoAddrParts[0]
  487. addr := protoAddrParts[1]
  488. // It's a bad idea to bind to TCP without tlsverify.
  489. if proto == "tcp" && (serverConfig.TLSConfig == nil || serverConfig.TLSConfig.ClientAuth != tls.RequireAndVerifyClientCert) {
  490. logrus.Warn("[!] DON'T BIND ON ANY IP ADDRESS WITHOUT setting --tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING [!]")
  491. }
  492. ls, err := listeners.Init(proto, addr, serverConfig.SocketGroup, serverConfig.TLSConfig)
  493. if err != nil {
  494. return nil, err
  495. }
  496. ls = wrapListeners(proto, ls)
  497. // If we're binding to a TCP port, make sure that a container doesn't try to use it.
  498. if proto == "tcp" {
  499. if err := allocateDaemonPort(addr); err != nil {
  500. return nil, err
  501. }
  502. }
  503. logrus.Debugf("Listener created for HTTP on %s (%s)", proto, addr)
  504. hosts = append(hosts, protoAddrParts[1])
  505. cli.api.Accept(addr, ls...)
  506. }
  507. return hosts, nil
  508. }
  509. func createAndStartCluster(cli *DaemonCli, d *daemon.Daemon) (*cluster.Cluster, error) {
  510. name, _ := os.Hostname()
  511. // Use a buffered channel to pass changes from store watch API to daemon
  512. // A buffer allows store watch API and daemon processing to not wait for each other
  513. watchStream := make(chan *swarmapi.WatchMessage, 32)
  514. c, err := cluster.New(cluster.Config{
  515. Root: cli.Config.Root,
  516. Name: name,
  517. Backend: d,
  518. VolumeBackend: d.VolumesService(),
  519. ImageBackend: d.ImageService(),
  520. PluginBackend: d.PluginManager(),
  521. NetworkSubnetsProvider: d,
  522. DefaultAdvertiseAddr: cli.Config.SwarmDefaultAdvertiseAddr,
  523. RaftHeartbeatTick: cli.Config.SwarmRaftHeartbeatTick,
  524. RaftElectionTick: cli.Config.SwarmRaftElectionTick,
  525. RuntimeRoot: cli.getSwarmRunRoot(),
  526. WatchStream: watchStream,
  527. })
  528. if err != nil {
  529. return nil, err
  530. }
  531. d.SetCluster(c)
  532. err = c.Start()
  533. return c, err
  534. }
  535. // validates that the plugins requested with the --authorization-plugin flag are valid AuthzDriver
  536. // plugins present on the host and available to the daemon
  537. func validateAuthzPlugins(requestedPlugins []string, pg plugingetter.PluginGetter) error {
  538. for _, reqPlugin := range requestedPlugins {
  539. if _, err := pg.Get(reqPlugin, authorization.AuthZApiImplements, plugingetter.Lookup); err != nil {
  540. return err
  541. }
  542. }
  543. return nil
  544. }