Signed-off-by: Karthik Karanth <karanth.karthik@gmail.com>
| ... | ... |
@@ -123,74 +123,15 @@ func (cli *DaemonCli) start(opts *daemonOptions) (err error) {
|
| 123 | 123 |
}() |
| 124 | 124 |
} |
| 125 | 125 |
|
| 126 |
- // TODO: extract to newApiServerConfig() |
|
| 127 |
- serverConfig := &apiserver.Config{
|
|
| 128 |
- Logging: true, |
|
| 129 |
- SocketGroup: cli.Config.SocketGroup, |
|
| 130 |
- Version: dockerversion.Version, |
|
| 131 |
- CorsHeaders: cli.Config.CorsHeaders, |
|
| 132 |
- } |
|
| 133 |
- |
|
| 134 |
- if cli.Config.TLS {
|
|
| 135 |
- tlsOptions := tlsconfig.Options{
|
|
| 136 |
- CAFile: cli.Config.CommonTLSOptions.CAFile, |
|
| 137 |
- CertFile: cli.Config.CommonTLSOptions.CertFile, |
|
| 138 |
- KeyFile: cli.Config.CommonTLSOptions.KeyFile, |
|
| 139 |
- ExclusiveRootPools: true, |
|
| 140 |
- } |
|
| 141 |
- |
|
| 142 |
- if cli.Config.TLSVerify {
|
|
| 143 |
- // server requires and verifies client's certificate |
|
| 144 |
- tlsOptions.ClientAuth = tls.RequireAndVerifyClientCert |
|
| 145 |
- } |
|
| 146 |
- tlsConfig, err := tlsconfig.Server(tlsOptions) |
|
| 147 |
- if err != nil {
|
|
| 148 |
- return err |
|
| 149 |
- } |
|
| 150 |
- serverConfig.TLSConfig = tlsConfig |
|
| 151 |
- } |
|
| 152 |
- |
|
| 153 |
- if len(cli.Config.Hosts) == 0 {
|
|
| 154 |
- cli.Config.Hosts = make([]string, 1) |
|
| 126 |
+ serverConfig, err := newAPIServerConfig(cli) |
|
| 127 |
+ if err != nil {
|
|
| 128 |
+ return fmt.Errorf("Failed to create API server: %v", err)
|
|
| 155 | 129 |
} |
| 156 |
- |
|
| 157 | 130 |
cli.api = apiserver.New(serverConfig) |
| 158 | 131 |
|
| 159 |
- var hosts []string |
|
| 160 |
- |
|
| 161 |
- for i := 0; i < len(cli.Config.Hosts); i++ {
|
|
| 162 |
- var err error |
|
| 163 |
- if cli.Config.Hosts[i], err = dopts.ParseHost(cli.Config.TLS, cli.Config.Hosts[i]); err != nil {
|
|
| 164 |
- return fmt.Errorf("error parsing -H %s : %v", cli.Config.Hosts[i], err)
|
|
| 165 |
- } |
|
| 166 |
- |
|
| 167 |
- protoAddr := cli.Config.Hosts[i] |
|
| 168 |
- protoAddrParts := strings.SplitN(protoAddr, "://", 2) |
|
| 169 |
- if len(protoAddrParts) != 2 {
|
|
| 170 |
- return fmt.Errorf("bad format %s, expected PROTO://ADDR", protoAddr)
|
|
| 171 |
- } |
|
| 172 |
- |
|
| 173 |
- proto := protoAddrParts[0] |
|
| 174 |
- addr := protoAddrParts[1] |
|
| 175 |
- |
|
| 176 |
- // It's a bad idea to bind to TCP without tlsverify. |
|
| 177 |
- if proto == "tcp" && (serverConfig.TLSConfig == nil || serverConfig.TLSConfig.ClientAuth != tls.RequireAndVerifyClientCert) {
|
|
| 178 |
- logrus.Warn("[!] DON'T BIND ON ANY IP ADDRESS WITHOUT setting --tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING [!]")
|
|
| 179 |
- } |
|
| 180 |
- ls, err := listeners.Init(proto, addr, serverConfig.SocketGroup, serverConfig.TLSConfig) |
|
| 181 |
- if err != nil {
|
|
| 182 |
- return err |
|
| 183 |
- } |
|
| 184 |
- ls = wrapListeners(proto, ls) |
|
| 185 |
- // If we're binding to a TCP port, make sure that a container doesn't try to use it. |
|
| 186 |
- if proto == "tcp" {
|
|
| 187 |
- if err := allocateDaemonPort(addr); err != nil {
|
|
| 188 |
- return err |
|
| 189 |
- } |
|
| 190 |
- } |
|
| 191 |
- logrus.Debugf("Listener created for HTTP on %s (%s)", proto, addr)
|
|
| 192 |
- hosts = append(hosts, protoAddrParts[1]) |
|
| 193 |
- cli.api.Accept(addr, ls...) |
|
| 132 |
+ hosts, err := loadListeners(cli, serverConfig) |
|
| 133 |
+ if err != nil {
|
|
| 134 |
+ return fmt.Errorf("Failed to load listeners: %v", err)
|
|
| 194 | 135 |
} |
| 195 | 136 |
|
| 196 | 137 |
registryService, err := registry.NewService(cli.Config.ServiceOptions) |
| ... | ... |
@@ -200,7 +141,7 @@ func (cli *DaemonCli) start(opts *daemonOptions) (err error) {
|
| 200 | 200 |
|
| 201 | 201 |
rOpts, err := cli.getRemoteOptions() |
| 202 | 202 |
if err != nil {
|
| 203 |
- return fmt.Errorf("Failed to generate containerd options: %s", err)
|
|
| 203 |
+ return fmt.Errorf("Failed to generate containerd options: %v", err)
|
|
| 204 | 204 |
} |
| 205 | 205 |
containerdRemote, err := libcontainerd.New(filepath.Join(cli.Config.Root, "containerd"), filepath.Join(cli.Config.ExecRoot, "containerd"), rOpts...) |
| 206 | 206 |
if err != nil {
|
| ... | ... |
@@ -242,31 +183,7 @@ func (cli *DaemonCli) start(opts *daemonOptions) (err error) {
|
| 242 | 242 |
} |
| 243 | 243 |
} |
| 244 | 244 |
|
| 245 |
- // TODO: createAndStartCluster() |
|
| 246 |
- name, _ := os.Hostname() |
|
| 247 |
- |
|
| 248 |
- // Use a buffered channel to pass changes from store watch API to daemon |
|
| 249 |
- // A buffer allows store watch API and daemon processing to not wait for each other |
|
| 250 |
- watchStream := make(chan *swarmapi.WatchMessage, 32) |
|
| 251 |
- |
|
| 252 |
- c, err := cluster.New(cluster.Config{
|
|
| 253 |
- Root: cli.Config.Root, |
|
| 254 |
- Name: name, |
|
| 255 |
- Backend: d, |
|
| 256 |
- ImageBackend: d.ImageService(), |
|
| 257 |
- PluginBackend: d.PluginManager(), |
|
| 258 |
- NetworkSubnetsProvider: d, |
|
| 259 |
- DefaultAdvertiseAddr: cli.Config.SwarmDefaultAdvertiseAddr, |
|
| 260 |
- RaftHeartbeatTick: cli.Config.SwarmRaftHeartbeatTick, |
|
| 261 |
- RaftElectionTick: cli.Config.SwarmRaftElectionTick, |
|
| 262 |
- RuntimeRoot: cli.getSwarmRunRoot(), |
|
| 263 |
- WatchStream: watchStream, |
|
| 264 |
- }) |
|
| 265 |
- if err != nil {
|
|
| 266 |
- logrus.Fatalf("Error creating cluster component: %v", err)
|
|
| 267 |
- } |
|
| 268 |
- d.SetCluster(c) |
|
| 269 |
- err = c.Start() |
|
| 245 |
+ c, err := createAndStartCluster(cli, d) |
|
| 270 | 246 |
if err != nil {
|
| 271 | 247 |
logrus.Fatalf("Error starting cluster component: %v", err)
|
| 272 | 248 |
} |
| ... | ... |
@@ -292,7 +209,7 @@ func (cli *DaemonCli) start(opts *daemonOptions) (err error) {
|
| 292 | 292 |
// process cluster change notifications |
| 293 | 293 |
watchCtx, cancel := context.WithCancel(context.Background()) |
| 294 | 294 |
defer cancel() |
| 295 |
- go d.ProcessClusterNotifications(watchCtx, watchStream) |
|
| 295 |
+ go d.ProcessClusterNotifications(watchCtx, c.GetWatchStream()) |
|
| 296 | 296 |
|
| 297 | 297 |
cli.setupConfigReloadTrap() |
| 298 | 298 |
|
| ... | ... |
@@ -569,6 +486,109 @@ func (cli *DaemonCli) getRemoteOptions() ([]libcontainerd.RemoteOption, error) {
|
| 569 | 569 |
return opts, nil |
| 570 | 570 |
} |
| 571 | 571 |
|
| 572 |
+func newAPIServerConfig(cli *DaemonCli) (*apiserver.Config, error) {
|
|
| 573 |
+ serverConfig := &apiserver.Config{
|
|
| 574 |
+ Logging: true, |
|
| 575 |
+ SocketGroup: cli.Config.SocketGroup, |
|
| 576 |
+ Version: dockerversion.Version, |
|
| 577 |
+ CorsHeaders: cli.Config.CorsHeaders, |
|
| 578 |
+ } |
|
| 579 |
+ |
|
| 580 |
+ if cli.Config.TLS {
|
|
| 581 |
+ tlsOptions := tlsconfig.Options{
|
|
| 582 |
+ CAFile: cli.Config.CommonTLSOptions.CAFile, |
|
| 583 |
+ CertFile: cli.Config.CommonTLSOptions.CertFile, |
|
| 584 |
+ KeyFile: cli.Config.CommonTLSOptions.KeyFile, |
|
| 585 |
+ ExclusiveRootPools: true, |
|
| 586 |
+ } |
|
| 587 |
+ |
|
| 588 |
+ if cli.Config.TLSVerify {
|
|
| 589 |
+ // server requires and verifies client's certificate |
|
| 590 |
+ tlsOptions.ClientAuth = tls.RequireAndVerifyClientCert |
|
| 591 |
+ } |
|
| 592 |
+ tlsConfig, err := tlsconfig.Server(tlsOptions) |
|
| 593 |
+ if err != nil {
|
|
| 594 |
+ return nil, err |
|
| 595 |
+ } |
|
| 596 |
+ serverConfig.TLSConfig = tlsConfig |
|
| 597 |
+ } |
|
| 598 |
+ |
|
| 599 |
+ if len(cli.Config.Hosts) == 0 {
|
|
| 600 |
+ cli.Config.Hosts = make([]string, 1) |
|
| 601 |
+ } |
|
| 602 |
+ |
|
| 603 |
+ return serverConfig, nil |
|
| 604 |
+} |
|
| 605 |
+ |
|
| 606 |
+func loadListeners(cli *DaemonCli, serverConfig *apiserver.Config) ([]string, error) {
|
|
| 607 |
+ var hosts []string |
|
| 608 |
+ for i := 0; i < len(cli.Config.Hosts); i++ {
|
|
| 609 |
+ var err error |
|
| 610 |
+ if cli.Config.Hosts[i], err = dopts.ParseHost(cli.Config.TLS, cli.Config.Hosts[i]); err != nil {
|
|
| 611 |
+ return nil, fmt.Errorf("error parsing -H %s : %v", cli.Config.Hosts[i], err)
|
|
| 612 |
+ } |
|
| 613 |
+ |
|
| 614 |
+ protoAddr := cli.Config.Hosts[i] |
|
| 615 |
+ protoAddrParts := strings.SplitN(protoAddr, "://", 2) |
|
| 616 |
+ if len(protoAddrParts) != 2 {
|
|
| 617 |
+ return nil, fmt.Errorf("bad format %s, expected PROTO://ADDR", protoAddr)
|
|
| 618 |
+ } |
|
| 619 |
+ |
|
| 620 |
+ proto := protoAddrParts[0] |
|
| 621 |
+ addr := protoAddrParts[1] |
|
| 622 |
+ |
|
| 623 |
+ // It's a bad idea to bind to TCP without tlsverify. |
|
| 624 |
+ if proto == "tcp" && (serverConfig.TLSConfig == nil || serverConfig.TLSConfig.ClientAuth != tls.RequireAndVerifyClientCert) {
|
|
| 625 |
+ logrus.Warn("[!] DON'T BIND ON ANY IP ADDRESS WITHOUT setting --tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING [!]")
|
|
| 626 |
+ } |
|
| 627 |
+ ls, err := listeners.Init(proto, addr, serverConfig.SocketGroup, serverConfig.TLSConfig) |
|
| 628 |
+ if err != nil {
|
|
| 629 |
+ return nil, err |
|
| 630 |
+ } |
|
| 631 |
+ ls = wrapListeners(proto, ls) |
|
| 632 |
+ // If we're binding to a TCP port, make sure that a container doesn't try to use it. |
|
| 633 |
+ if proto == "tcp" {
|
|
| 634 |
+ if err := allocateDaemonPort(addr); err != nil {
|
|
| 635 |
+ return nil, err |
|
| 636 |
+ } |
|
| 637 |
+ } |
|
| 638 |
+ logrus.Debugf("Listener created for HTTP on %s (%s)", proto, addr)
|
|
| 639 |
+ hosts = append(hosts, protoAddrParts[1]) |
|
| 640 |
+ cli.api.Accept(addr, ls...) |
|
| 641 |
+ } |
|
| 642 |
+ |
|
| 643 |
+ return hosts, nil |
|
| 644 |
+} |
|
| 645 |
+ |
|
| 646 |
+func createAndStartCluster(cli *DaemonCli, d *daemon.Daemon) (*cluster.Cluster, error) {
|
|
| 647 |
+ name, _ := os.Hostname() |
|
| 648 |
+ |
|
| 649 |
+ // Use a buffered channel to pass changes from store watch API to daemon |
|
| 650 |
+ // A buffer allows store watch API and daemon processing to not wait for each other |
|
| 651 |
+ watchStream := make(chan *swarmapi.WatchMessage, 32) |
|
| 652 |
+ |
|
| 653 |
+ c, err := cluster.New(cluster.Config{
|
|
| 654 |
+ Root: cli.Config.Root, |
|
| 655 |
+ Name: name, |
|
| 656 |
+ Backend: d, |
|
| 657 |
+ ImageBackend: d.ImageService(), |
|
| 658 |
+ PluginBackend: d.PluginManager(), |
|
| 659 |
+ NetworkSubnetsProvider: d, |
|
| 660 |
+ DefaultAdvertiseAddr: cli.Config.SwarmDefaultAdvertiseAddr, |
|
| 661 |
+ RaftHeartbeatTick: cli.Config.SwarmRaftHeartbeatTick, |
|
| 662 |
+ RaftElectionTick: cli.Config.SwarmRaftElectionTick, |
|
| 663 |
+ RuntimeRoot: cli.getSwarmRunRoot(), |
|
| 664 |
+ WatchStream: watchStream, |
|
| 665 |
+ }) |
|
| 666 |
+ if err != nil {
|
|
| 667 |
+ return nil, err |
|
| 668 |
+ } |
|
| 669 |
+ d.SetCluster(c) |
|
| 670 |
+ err = c.Start() |
|
| 671 |
+ |
|
| 672 |
+ return c, err |
|
| 673 |
+} |
|
| 674 |
+ |
|
| 572 | 675 |
// validates that the plugins requested with the --authorization-plugin flag are valid AuthzDriver |
| 573 | 676 |
// plugins present on the host and available to the daemon |
| 574 | 677 |
func validateAuthzPlugins(requestedPlugins []string, pg plugingetter.PluginGetter) error {
|
| ... | ... |
@@ -305,6 +305,13 @@ func (c *Cluster) GetRemoteAddressList() []string {
|
| 305 | 305 |
return c.getRemoteAddressList() |
| 306 | 306 |
} |
| 307 | 307 |
|
| 308 |
+// GetWatchStream returns the channel to pass changes from store watch API |
|
| 309 |
+func (c *Cluster) GetWatchStream() chan *swarmapi.WatchMessage {
|
|
| 310 |
+ c.mu.RLock() |
|
| 311 |
+ defer c.mu.RUnlock() |
|
| 312 |
+ return c.watchStream |
|
| 313 |
+} |
|
| 314 |
+ |
|
| 308 | 315 |
func (c *Cluster) getRemoteAddressList() []string {
|
| 309 | 316 |
state := c.currentNodeState() |
| 310 | 317 |
if state.swarmNode == nil {
|