Browse code

Net dial to the plugin socket during enable.

When a plugin fails to start, we still incorrectly mark it as enabled.
This change verifies that we can dial to the plugin socket to confirm that
the plugin is functional and only then mark the plugin as enabled. Also,
dont delete the plugin on install, if only the enable fails.

Signed-off-by: Anusha Ragunathan <anusha.ragunathan@docker.com>

Anusha Ragunathan authored on 2017/02/25 08:35:10
Showing 2 changed files
... ...
@@ -60,8 +60,8 @@ func (cli *Client) PluginInstall(ctx context.Context, name string, options types
60 60
 			return
61 61
 		}
62 62
 
63
-		err = cli.PluginEnable(ctx, name, types.PluginEnableOptions{Timeout: 0})
64
-		pw.CloseWithError(err)
63
+		enableErr := cli.PluginEnable(ctx, name, types.PluginEnableOptions{Timeout: 0})
64
+		pw.CloseWithError(enableErr)
65 65
 	}()
66 66
 	return pr, nil
67 67
 }
... ...
@@ -5,6 +5,7 @@ package plugin
5 5
 import (
6 6
 	"encoding/json"
7 7
 	"fmt"
8
+	"net"
8 9
 	"os"
9 10
 	"path/filepath"
10 11
 	"syscall"
... ...
@@ -77,7 +78,8 @@ func (pm *Manager) enable(p *v2.Plugin, c *controller, force bool) error {
77 77
 }
78 78
 
79 79
 func (pm *Manager) pluginPostStart(p *v2.Plugin, c *controller) error {
80
-	client, err := plugins.NewClientWithTimeout("unix://"+filepath.Join(pm.config.ExecRoot, p.GetID(), p.GetSocket()), nil, c.timeoutInSecs)
80
+	sockAddr := filepath.Join(pm.config.ExecRoot, p.GetID(), p.GetSocket())
81
+	client, err := plugins.NewClientWithTimeout("unix://"+sockAddr, nil, c.timeoutInSecs)
81 82
 	if err != nil {
82 83
 		c.restart = false
83 84
 		shutdownPlugin(p, c, pm.containerdClient)
... ...
@@ -85,6 +87,27 @@ func (pm *Manager) pluginPostStart(p *v2.Plugin, c *controller) error {
85 85
 	}
86 86
 
87 87
 	p.SetPClient(client)
88
+
89
+	maxRetries := 3
90
+	var retries int
91
+	for {
92
+		time.Sleep(3 * time.Second)
93
+		retries++
94
+
95
+		if retries > maxRetries {
96
+			logrus.Debugf("error net dialing plugin: %v", err)
97
+			c.restart = false
98
+			shutdownPlugin(p, c, pm.containerdClient)
99
+			return err
100
+		}
101
+
102
+		// net dial into the unix socket to see if someone's listening.
103
+		conn, err := net.Dial("unix", sockAddr)
104
+		if err == nil {
105
+			conn.Close()
106
+			break
107
+		}
108
+	}
88 109
 	pm.config.Store.SetState(p, true)
89 110
 	pm.config.Store.CallHandler(p)
90 111