This commit brings in Remote driver integrated with the newly introduced
Plugin framework as a Docker Package.
The Plugin framework is designed as a Package and has no runtime
dependancy on Docker platform. It stands on its own and is a good
candidate for getting the remote drivers hooked to libnetwork
Signed-off-by: Madhu Venugopal <madhu@docker.com>
| ... | ... |
@@ -48,6 +48,7 @@ package libnetwork |
| 48 | 48 |
import ( |
| 49 | 49 |
"sync" |
| 50 | 50 |
|
| 51 |
+ "github.com/docker/docker/pkg/plugins" |
|
| 51 | 52 |
"github.com/docker/docker/pkg/stringid" |
| 52 | 53 |
"github.com/docker/libnetwork/driverapi" |
| 53 | 54 |
"github.com/docker/libnetwork/sandbox" |
| ... | ... |
@@ -140,7 +141,11 @@ func (c *controller) NewNetwork(networkType, name string, options ...NetworkOpti |
| 140 | 140 |
d, ok := c.drivers[networkType] |
| 141 | 141 |
c.Unlock() |
| 142 | 142 |
if !ok {
|
| 143 |
- return nil, ErrInvalidNetworkDriver |
|
| 143 |
+ var err error |
|
| 144 |
+ d, err = c.loadDriver(networkType) |
|
| 145 |
+ if err != nil {
|
|
| 146 |
+ return nil, err |
|
| 147 |
+ } |
|
| 144 | 148 |
} |
| 145 | 149 |
|
| 146 | 150 |
// Check if a network already exists with the specified network name |
| ... | ... |
@@ -275,3 +280,19 @@ func (c *controller) sandboxGet(key string) sandbox.Sandbox {
|
| 275 | 275 |
|
| 276 | 276 |
return sData.sandbox |
| 277 | 277 |
} |
| 278 |
+ |
|
| 279 |
+func (c *controller) loadDriver(networkType string) (driverapi.Driver, error) {
|
|
| 280 |
+ // Plugins pkg performs lazy loading of plugins that acts as remote drivers. |
|
| 281 |
+ // As per the design, this Get call will result in remote driver discovery if there is a corresponding plugin available. |
|
| 282 |
+ _, err := plugins.Get(networkType, driverapi.NetworkPluginEndpointType) |
|
| 283 |
+ if err != nil {
|
|
| 284 |
+ return nil, err |
|
| 285 |
+ } |
|
| 286 |
+ c.Lock() |
|
| 287 |
+ defer c.Unlock() |
|
| 288 |
+ d, ok := c.drivers[networkType] |
|
| 289 |
+ if !ok {
|
|
| 290 |
+ return nil, ErrInvalidNetworkDriver |
|
| 291 |
+ } |
|
| 292 |
+ return d, nil |
|
| 293 |
+} |
| ... | ... |
@@ -19,6 +19,9 @@ var ( |
| 19 | 19 |
ErrNotImplemented = errors.New("The API is not implemented yet")
|
| 20 | 20 |
) |
| 21 | 21 |
|
| 22 |
+// NetworkPluginEndpointType represents the Endpoint Type used by Plugin system |
|
| 23 |
+const NetworkPluginEndpointType = "NetworkDriver" |
|
| 24 |
+ |
|
| 22 | 25 |
// Driver is an interface that every plugin driver needs to implement. |
| 23 | 26 |
type Driver interface {
|
| 24 | 27 |
// Push driver specific config to the driver |
| ... | ... |
@@ -3,6 +3,8 @@ package remote |
| 3 | 3 |
import ( |
| 4 | 4 |
"errors" |
| 5 | 5 |
|
| 6 |
+ log "github.com/Sirupsen/logrus" |
|
| 7 |
+ "github.com/docker/docker/pkg/plugins" |
|
| 6 | 8 |
"github.com/docker/libnetwork/driverapi" |
| 7 | 9 |
"github.com/docker/libnetwork/sandbox" |
| 8 | 10 |
"github.com/docker/libnetwork/types" |
| ... | ... |
@@ -10,13 +12,22 @@ import ( |
| 10 | 10 |
|
| 11 | 11 |
var errNoCallback = errors.New("No Callback handler registered with Driver")
|
| 12 | 12 |
|
| 13 |
-const remoteNetworkType = "remote" |
|
| 14 |
- |
|
| 15 | 13 |
type driver struct {
|
| 14 |
+ endpoint *plugins.Client |
|
| 15 |
+ networkType string |
|
| 16 | 16 |
} |
| 17 | 17 |
|
| 18 | 18 |
// Init does the necessary work to register remote drivers |
| 19 | 19 |
func Init(dc driverapi.DriverCallback) error {
|
| 20 |
+ plugins.Handle(driverapi.NetworkPluginEndpointType, func(name string, client *plugins.Client) {
|
|
| 21 |
+ |
|
| 22 |
+ // TODO : Handhake with the Remote Plugin goes here |
|
| 23 |
+ |
|
| 24 |
+ newDriver := &driver{networkType: name, endpoint: client}
|
|
| 25 |
+ if err := dc.RegisterDriver(name, newDriver); err != nil {
|
|
| 26 |
+ log.Errorf("Error registering Driver for %s due to %v", name, err)
|
|
| 27 |
+ } |
|
| 28 |
+ }) |
|
| 20 | 29 |
return nil |
| 21 | 30 |
} |
| 22 | 31 |
|
| ... | ... |
@@ -55,5 +66,5 @@ func (d *driver) Leave(nid, eid types.UUID, options map[string]interface{}) erro
|
| 55 | 55 |
} |
| 56 | 56 |
|
| 57 | 57 |
func (d *driver) Type() string {
|
| 58 |
- return remoteNetworkType |
|
| 58 |
+ return d.networkType |
|
| 59 | 59 |
} |
| ... | ... |
@@ -6,6 +6,8 @@ import ( |
| 6 | 6 |
"fmt" |
| 7 | 7 |
"io/ioutil" |
| 8 | 8 |
"net" |
| 9 |
+ "net/http" |
|
| 10 |
+ "net/http/httptest" |
|
| 9 | 11 |
"os" |
| 10 | 12 |
"runtime" |
| 11 | 13 |
"strconv" |
| ... | ... |
@@ -13,8 +15,10 @@ import ( |
| 13 | 13 |
"testing" |
| 14 | 14 |
|
| 15 | 15 |
log "github.com/Sirupsen/logrus" |
| 16 |
+ "github.com/docker/docker/pkg/plugins" |
|
| 16 | 17 |
"github.com/docker/docker/pkg/reexec" |
| 17 | 18 |
"github.com/docker/libnetwork" |
| 19 |
+ "github.com/docker/libnetwork/driverapi" |
|
| 18 | 20 |
"github.com/docker/libnetwork/netlabel" |
| 19 | 21 |
"github.com/docker/libnetwork/netutils" |
| 20 | 22 |
"github.com/docker/libnetwork/options" |
| ... | ... |
@@ -226,7 +230,7 @@ func TestUnknownDriver(t *testing.T) {
|
| 226 | 226 |
} |
| 227 | 227 |
} |
| 228 | 228 |
|
| 229 |
-func TestNilDriver(t *testing.T) {
|
|
| 229 |
+func TestNilRemoteDriver(t *testing.T) {
|
|
| 230 | 230 |
controller, err := libnetwork.New() |
| 231 | 231 |
if err != nil {
|
| 232 | 232 |
t.Fatal(err) |
| ... | ... |
@@ -238,24 +242,7 @@ func TestNilDriver(t *testing.T) {
|
| 238 | 238 |
t.Fatal("Expected to fail. But instead succeeded")
|
| 239 | 239 |
} |
| 240 | 240 |
|
| 241 |
- if err != libnetwork.ErrInvalidNetworkDriver {
|
|
| 242 |
- t.Fatalf("Did not fail with expected error. Actual error: %v", err)
|
|
| 243 |
- } |
|
| 244 |
-} |
|
| 245 |
- |
|
| 246 |
-func TestNoInitDriver(t *testing.T) {
|
|
| 247 |
- controller, err := libnetwork.New() |
|
| 248 |
- if err != nil {
|
|
| 249 |
- t.Fatal(err) |
|
| 250 |
- } |
|
| 251 |
- |
|
| 252 |
- _, err = controller.NewNetwork("ppp", "dummy",
|
|
| 253 |
- libnetwork.NetworkOptionGeneric(getEmptyGenericOption())) |
|
| 254 |
- if err == nil {
|
|
| 255 |
- t.Fatal("Expected to fail. But instead succeeded")
|
|
| 256 |
- } |
|
| 257 |
- |
|
| 258 |
- if err != libnetwork.ErrInvalidNetworkDriver {
|
|
| 241 |
+ if err != plugins.ErrNotFound {
|
|
| 259 | 242 |
t.Fatalf("Did not fail with expected error. Actual error: %v", err)
|
| 260 | 243 |
} |
| 261 | 244 |
} |
| ... | ... |
@@ -1134,6 +1121,102 @@ func TestResolvConf(t *testing.T) {
|
| 1134 | 1134 |
} |
| 1135 | 1135 |
} |
| 1136 | 1136 |
|
| 1137 |
+func TestInvalidRemoteDriver(t *testing.T) {
|
|
| 1138 |
+ if !netutils.IsRunningInContainer() {
|
|
| 1139 |
+ t.Skip("Skipping test when not running inside a Container")
|
|
| 1140 |
+ } |
|
| 1141 |
+ |
|
| 1142 |
+ mux := http.NewServeMux() |
|
| 1143 |
+ server := httptest.NewServer(mux) |
|
| 1144 |
+ if server == nil {
|
|
| 1145 |
+ t.Fatal("Failed to start a HTTP Server")
|
|
| 1146 |
+ } |
|
| 1147 |
+ defer server.Close() |
|
| 1148 |
+ |
|
| 1149 |
+ type pluginRequest struct {
|
|
| 1150 |
+ name string |
|
| 1151 |
+ } |
|
| 1152 |
+ |
|
| 1153 |
+ mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
|
|
| 1154 |
+ w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
|
| 1155 |
+ fmt.Fprintln(w, `{"Implements": ["InvalidDriver"]}`)
|
|
| 1156 |
+ }) |
|
| 1157 |
+ |
|
| 1158 |
+ if err := os.MkdirAll("/usr/share/docker/plugins", 0755); err != nil {
|
|
| 1159 |
+ t.Fatal(err) |
|
| 1160 |
+ } |
|
| 1161 |
+ defer func() {
|
|
| 1162 |
+ if err := os.RemoveAll("/usr/share/docker/plugins"); err != nil {
|
|
| 1163 |
+ t.Fatal(err) |
|
| 1164 |
+ } |
|
| 1165 |
+ }() |
|
| 1166 |
+ |
|
| 1167 |
+ if err := ioutil.WriteFile("/usr/share/docker/plugins/invalid-network-driver.spec", []byte(server.URL), 0644); err != nil {
|
|
| 1168 |
+ t.Fatal(err) |
|
| 1169 |
+ } |
|
| 1170 |
+ |
|
| 1171 |
+ controller, err := libnetwork.New() |
|
| 1172 |
+ if err != nil {
|
|
| 1173 |
+ t.Fatal(err) |
|
| 1174 |
+ } |
|
| 1175 |
+ |
|
| 1176 |
+ _, err = controller.NewNetwork("invalid-network-driver", "dummy",
|
|
| 1177 |
+ libnetwork.NetworkOptionGeneric(getEmptyGenericOption())) |
|
| 1178 |
+ if err == nil {
|
|
| 1179 |
+ t.Fatal("Expected to fail. But instead succeeded")
|
|
| 1180 |
+ } |
|
| 1181 |
+ |
|
| 1182 |
+ if err != plugins.ErrNotImplements {
|
|
| 1183 |
+ t.Fatalf("Did not fail with expected error. Actual error: %v", err)
|
|
| 1184 |
+ } |
|
| 1185 |
+} |
|
| 1186 |
+ |
|
| 1187 |
+func TestValidRemoteDriver(t *testing.T) {
|
|
| 1188 |
+ if !netutils.IsRunningInContainer() {
|
|
| 1189 |
+ t.Skip("Skipping test when not running inside a Container")
|
|
| 1190 |
+ } |
|
| 1191 |
+ |
|
| 1192 |
+ mux := http.NewServeMux() |
|
| 1193 |
+ server := httptest.NewServer(mux) |
|
| 1194 |
+ if server == nil {
|
|
| 1195 |
+ t.Fatal("Failed to start a HTTP Server")
|
|
| 1196 |
+ } |
|
| 1197 |
+ defer server.Close() |
|
| 1198 |
+ |
|
| 1199 |
+ type pluginRequest struct {
|
|
| 1200 |
+ name string |
|
| 1201 |
+ } |
|
| 1202 |
+ |
|
| 1203 |
+ mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
|
|
| 1204 |
+ w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
|
| 1205 |
+ fmt.Fprintf(w, `{"Implements": ["%s"]}`, driverapi.NetworkPluginEndpointType)
|
|
| 1206 |
+ }) |
|
| 1207 |
+ |
|
| 1208 |
+ if err := os.MkdirAll("/usr/share/docker/plugins", 0755); err != nil {
|
|
| 1209 |
+ t.Fatal(err) |
|
| 1210 |
+ } |
|
| 1211 |
+ defer func() {
|
|
| 1212 |
+ if err := os.RemoveAll("/usr/share/docker/plugins"); err != nil {
|
|
| 1213 |
+ t.Fatal(err) |
|
| 1214 |
+ } |
|
| 1215 |
+ }() |
|
| 1216 |
+ |
|
| 1217 |
+ if err := ioutil.WriteFile("/usr/share/docker/plugins/valid-network-driver.spec", []byte(server.URL), 0644); err != nil {
|
|
| 1218 |
+ t.Fatal(err) |
|
| 1219 |
+ } |
|
| 1220 |
+ |
|
| 1221 |
+ controller, err := libnetwork.New() |
|
| 1222 |
+ if err != nil {
|
|
| 1223 |
+ t.Fatal(err) |
|
| 1224 |
+ } |
|
| 1225 |
+ |
|
| 1226 |
+ _, err = controller.NewNetwork("valid-network-driver", "dummy",
|
|
| 1227 |
+ libnetwork.NetworkOptionGeneric(getEmptyGenericOption())) |
|
| 1228 |
+ if err != nil && err != driverapi.ErrNotImplemented {
|
|
| 1229 |
+ t.Fatal(err) |
|
| 1230 |
+ } |
|
| 1231 |
+} |
|
| 1232 |
+ |
|
| 1137 | 1233 |
var ( |
| 1138 | 1234 |
once sync.Once |
| 1139 | 1235 |
ctrlr libnetwork.NetworkController |