1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #29556 from mavenugo/refcount

Fixing a couple of network plugin life-cycle mgmt issues
This commit is contained in:
Victor Vieux 2017-01-03 11:13:22 -08:00 committed by GitHub
commit 2ef6d80454
24 changed files with 194 additions and 31 deletions

View file

@ -12,8 +12,11 @@ import (
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/network"
clustertypes "github.com/docker/docker/daemon/cluster/provider" clustertypes "github.com/docker/docker/daemon/cluster/provider"
"github.com/docker/docker/pkg/plugingetter"
"github.com/docker/docker/runconfig" "github.com/docker/docker/runconfig"
"github.com/docker/libnetwork" "github.com/docker/libnetwork"
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/ipamapi"
networktypes "github.com/docker/libnetwork/types" networktypes "github.com/docker/libnetwork/types"
"github.com/pkg/errors" "github.com/pkg/errors"
"golang.org/x/net/context" "golang.org/x/net/context"
@ -298,6 +301,10 @@ func (daemon *Daemon) createNetwork(create types.NetworkCreateRequest, id string
return nil, err return nil, err
} }
daemon.pluginRefCount(driver, driverapi.NetworkPluginEndpointType, plugingetter.ACQUIRE)
if create.IPAM != nil {
daemon.pluginRefCount(create.IPAM.Driver, ipamapi.PluginEndpointType, plugingetter.ACQUIRE)
}
daemon.LogNetworkEvent(n, "create") daemon.LogNetworkEvent(n, "create")
return &types.NetworkCreateResponse{ return &types.NetworkCreateResponse{
@ -306,6 +313,29 @@ func (daemon *Daemon) createNetwork(create types.NetworkCreateRequest, id string
}, nil }, nil
} }
func (daemon *Daemon) pluginRefCount(driver, capability string, mode int) {
var builtinDrivers []string
if capability == driverapi.NetworkPluginEndpointType {
builtinDrivers = daemon.netController.BuiltinDrivers()
} else if capability == ipamapi.PluginEndpointType {
builtinDrivers = daemon.netController.BuiltinIPAMDrivers()
}
for _, d := range builtinDrivers {
if d == driver {
return
}
}
if daemon.PluginStore != nil {
_, err := daemon.PluginStore.Get(driver, capability, mode)
if err != nil {
logrus.WithError(err).WithFields(logrus.Fields{"mode": mode, "driver": driver}).Error("Error handling plugin refcount operation")
}
}
}
func getIpamConfig(data []network.IPAMConfig) ([]*libnetwork.IpamConf, []*libnetwork.IpamConf, error) { func getIpamConfig(data []network.IPAMConfig) ([]*libnetwork.IpamConf, []*libnetwork.IpamConf, error) {
ipamV4Cfg := []*libnetwork.IpamConf{} ipamV4Cfg := []*libnetwork.IpamConf{}
ipamV6Cfg := []*libnetwork.IpamConf{} ipamV6Cfg := []*libnetwork.IpamConf{}
@ -420,6 +450,9 @@ func (daemon *Daemon) deleteNetwork(networkID string, dynamic bool) error {
if err := nw.Delete(); err != nil { if err := nw.Delete(); err != nil {
return err return err
} }
daemon.pluginRefCount(nw.Type(), driverapi.NetworkPluginEndpointType, plugingetter.RELEASE)
ipamType, _, _, _ := nw.Info().IpamConfig()
daemon.pluginRefCount(ipamType, ipamapi.PluginEndpointType, plugingetter.RELEASE)
daemon.LogNetworkEvent(nw, "destroy") daemon.LogNetworkEvent(nw, "destroy")
return nil return nil
} }

View file

@ -16,8 +16,10 @@ import (
var ( var (
pluginProcessName = "sample-volume-plugin" pluginProcessName = "sample-volume-plugin"
pName = "tonistiigi/sample-volume-plugin" pName = "tonistiigi/sample-volume-plugin"
npName = "tonistiigi/test-docker-netplugin"
pTag = "latest" pTag = "latest"
pNameWithTag = pName + ":" + pTag pNameWithTag = pName + ":" + pTag
npNameWithTag = npName + ":" + pTag
) )
func (s *DockerSuite) TestPluginBasicOps(c *check.C) { func (s *DockerSuite) TestPluginBasicOps(c *check.C) {
@ -87,6 +89,33 @@ func (s *DockerSuite) TestPluginActive(c *check.C) {
c.Assert(out, checker.Contains, pNameWithTag) c.Assert(out, checker.Contains, pNameWithTag)
} }
func (s *DockerSuite) TestPluginActiveNetwork(c *check.C) {
testRequires(c, DaemonIsLinux, IsAmd64, Network)
out, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", npNameWithTag)
c.Assert(err, checker.IsNil)
out, _, err = dockerCmdWithError("network", "create", "-d", npNameWithTag, "test")
c.Assert(err, checker.IsNil)
nID := strings.TrimSpace(out)
out, _, err = dockerCmdWithError("plugin", "remove", npNameWithTag)
c.Assert(out, checker.Contains, "is in use")
_, _, err = dockerCmdWithError("network", "rm", nID)
c.Assert(err, checker.IsNil)
out, _, err = dockerCmdWithError("plugin", "remove", npNameWithTag)
c.Assert(out, checker.Contains, "is enabled")
_, _, err = dockerCmdWithError("plugin", "disable", npNameWithTag)
c.Assert(err, checker.IsNil)
out, _, err = dockerCmdWithError("plugin", "remove", npNameWithTag)
c.Assert(err, checker.IsNil)
c.Assert(out, checker.Contains, npNameWithTag)
}
func (s *DockerSuite) TestPluginInstallDisable(c *check.C) { func (s *DockerSuite) TestPluginInstallDisable(c *check.C) {
testRequires(c, DaemonIsLinux, IsAmd64, Network) testRequires(c, DaemonIsLinux, IsAmd64, Network)
out, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", "--disable", pName) out, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", "--disable", pName)

View file

@ -499,13 +499,6 @@ func (s *DockerSwarmSuite) TestPsListContainersFilterIsTask(c *check.C) {
const globalNetworkPlugin = "global-network-plugin" const globalNetworkPlugin = "global-network-plugin"
const globalIPAMPlugin = "global-ipam-plugin" const globalIPAMPlugin = "global-ipam-plugin"
func (s *DockerSwarmSuite) SetUpSuite(c *check.C) {
mux := http.NewServeMux()
s.server = httptest.NewServer(mux)
c.Assert(s.server, check.NotNil, check.Commentf("Failed to start an HTTP Server"))
setupRemoteGlobalNetworkPlugin(c, mux, s.server.URL, globalNetworkPlugin, globalIPAMPlugin)
}
func setupRemoteGlobalNetworkPlugin(c *check.C, mux *http.ServeMux, url, netDrv, ipamDrv string) { func setupRemoteGlobalNetworkPlugin(c *check.C, mux *http.ServeMux, url, netDrv, ipamDrv string) {
mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) { mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
@ -675,6 +668,16 @@ func setupRemoteGlobalNetworkPlugin(c *check.C, mux *http.ServeMux, url, netDrv,
} }
func (s *DockerSwarmSuite) TestSwarmNetworkPlugin(c *check.C) { func (s *DockerSwarmSuite) TestSwarmNetworkPlugin(c *check.C) {
mux := http.NewServeMux()
s.server = httptest.NewServer(mux)
c.Assert(s.server, check.NotNil, check.Commentf("Failed to start an HTTP Server"))
setupRemoteGlobalNetworkPlugin(c, mux, s.server.URL, globalNetworkPlugin, globalIPAMPlugin)
defer func() {
s.server.Close()
err := os.RemoveAll("/etc/docker/plugins")
c.Assert(err, checker.IsNil)
}()
d := s.AddDaemon(c, true, true) d := s.AddDaemon(c, true, true)
out, err := d.Cmd("network", "create", "-d", globalNetworkPlugin, "foo") out, err := d.Cmd("network", "create", "-d", globalNetworkPlugin, "foo")

View file

@ -23,7 +23,7 @@ github.com/RackSec/srslog 456df3a81436d29ba874f3590eeeee25d666f8a5
github.com/imdario/mergo 0.2.1 github.com/imdario/mergo 0.2.1
#get libnetwork packages #get libnetwork packages
github.com/docker/libnetwork b908488a139e81cb8c4091cd836745aeb4d813a4 github.com/docker/libnetwork 61f01cdbbda7e32e651198b04889f6d825064fa6
github.com/docker/go-events 18b43f1bc85d9cdd42c05a6cd2d444c7a200a894 github.com/docker/go-events 18b43f1bc85d9cdd42c05a6cd2d444c7a200a894
github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80 github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec

View file

@ -79,6 +79,9 @@ type NetworkController interface {
// BuiltinDrivers returns list of builtin drivers // BuiltinDrivers returns list of builtin drivers
BuiltinDrivers() []string BuiltinDrivers() []string
// BuiltinIPAMDrivers returns list of builtin ipam drivers
BuiltinIPAMDrivers() []string
// Config method returns the bootup configuration for the controller // Config method returns the bootup configuration for the controller
Config() config.Config Config() config.Config
@ -476,12 +479,23 @@ func (c *controller) ID() string {
func (c *controller) BuiltinDrivers() []string { func (c *controller) BuiltinDrivers() []string {
drivers := []string{} drivers := []string{}
for _, i := range getInitializers(c.cfg.Daemon.Experimental) { c.drvRegistry.WalkDrivers(func(name string, driver driverapi.Driver, capability driverapi.Capability) bool {
if i.ntype == "remote" { if driver.IsBuiltIn() {
continue drivers = append(drivers, name)
} }
drivers = append(drivers, i.ntype) return false
} })
return drivers
}
func (c *controller) BuiltinIPAMDrivers() []string {
drivers := []string{}
c.drvRegistry.WalkIPAMs(func(name string, driver ipamapi.Ipam, cap *ipamapi.Capability) bool {
if driver.IsBuiltIn() {
drivers = append(drivers, name)
}
return false
})
return drivers return drivers
} }

View file

@ -74,6 +74,9 @@ type Driver interface {
// Type returns the the type of this driver, the network type this driver manages // Type returns the the type of this driver, the network type this driver manages
Type() string Type() string
// IsBuiltIn returns true if it is a built-in driver
IsBuiltIn() bool
} }
// NetworkInfo provides a go interface for drivers to provide network // NetworkInfo provides a go interface for drivers to provide network

View file

@ -1424,6 +1424,10 @@ func (d *driver) Type() string {
return networkType return networkType
} }
func (d *driver) IsBuiltIn() bool {
return true
}
// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
return nil return nil

View file

@ -86,6 +86,10 @@ func (d *driver) Type() string {
return networkType return networkType
} }
func (d *driver) IsBuiltIn() bool {
return true
}
// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
return nil return nil

View file

@ -84,6 +84,10 @@ func (d *driver) Type() string {
return ipvlanType return ipvlanType
} }
func (d *driver) IsBuiltIn() bool {
return true
}
func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error { func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
return nil return nil
} }

View file

@ -86,6 +86,10 @@ func (d *driver) Type() string {
return macvlanType return macvlanType
} }
func (d *driver) IsBuiltIn() bool {
return true
}
func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error { func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
return nil return nil
} }

View file

@ -86,6 +86,10 @@ func (d *driver) Type() string {
return networkType return networkType
} }
func (d *driver) IsBuiltIn() bool {
return true
}
// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
return nil return nil

View file

@ -211,6 +211,10 @@ func (d *driver) Type() string {
return networkType return networkType
} }
func (d *driver) IsBuiltIn() bool {
return true
}
func validateSelf(node string) error { func validateSelf(node string) error {
advIP := net.ParseIP(node) advIP := net.ParseIP(node)
if advIP == nil { if advIP == nil {

View file

@ -229,6 +229,10 @@ func (d *driver) Type() string {
return networkType return networkType
} }
func (d *driver) IsBuiltIn() bool {
return true
}
// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
return types.NotImplementedErrorf("not implemented") return types.NotImplementedErrorf("not implemented")

View file

@ -29,12 +29,7 @@ func newDriver(name string, client *plugins.Client) driverapi.Driver {
// Init makes sure a remote driver is registered when a network driver // Init makes sure a remote driver is registered when a network driver
// plugin is activated. // plugin is activated.
func Init(dc driverapi.DriverCallback, config map[string]interface{}) error { func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
// Unit test code is unaware of a true PluginStore. So we fall back to v1 plugins. newPluginHandler := func(name string, client *plugins.Client) {
handleFunc := plugins.Handle
if pg := dc.GetPluginGetter(); pg != nil {
handleFunc = pg.Handle
}
handleFunc(driverapi.NetworkPluginEndpointType, func(name string, client *plugins.Client) {
// negotiate driver capability with client // negotiate driver capability with client
d := newDriver(name, client) d := newDriver(name, client)
c, err := d.(*driver).getCapabilities() c, err := d.(*driver).getCapabilities()
@ -45,7 +40,19 @@ func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
if err = dc.RegisterDriver(name, d, *c); err != nil { if err = dc.RegisterDriver(name, d, *c); err != nil {
logrus.Errorf("error registering driver for %s due to %v", name, err) logrus.Errorf("error registering driver for %s due to %v", name, err)
} }
}) }
// Unit test code is unaware of a true PluginStore. So we fall back to v1 plugins.
handleFunc := plugins.Handle
if pg := dc.GetPluginGetter(); pg != nil {
handleFunc = pg.Handle
activePlugins := pg.GetAllManagedPluginsByCap(driverapi.NetworkPluginEndpointType)
for _, ap := range activePlugins {
newPluginHandler(ap.Name(), ap.Client())
}
}
handleFunc(driverapi.NetworkPluginEndpointType, newPluginHandler)
return nil return nil
} }
@ -305,6 +312,10 @@ func (d *driver) Type() string {
return d.networkType return d.networkType
} }
func (d *driver) IsBuiltIn() bool {
return false
}
// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
if dType != discoverapi.NodeDiscovery { if dType != discoverapi.NodeDiscovery {

View file

@ -916,6 +916,10 @@ func (d *driver) Type() string {
return networkType return networkType
} }
func (d *driver) IsBuiltIn() bool {
return true
}
// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
return nil return nil

View file

@ -200,6 +200,10 @@ func (d *driver) Type() string {
return networkType return networkType
} }
func (d *driver) IsBuiltIn() bool {
return true
}
func validateSelf(node string) error { func validateSelf(node string) error {
advIP := net.ParseIP(node) advIP := net.ParseIP(node)
if advIP == nil { if advIP == nil {

View file

@ -176,6 +176,10 @@ func (d *driver) Type() string {
return networkType return networkType
} }
func (d *driver) IsBuiltIn() bool {
return true
}
func validateSelf(node string) error { func validateSelf(node string) error {
advIP := net.ParseIP(node) advIP := net.ParseIP(node)
if advIP == nil { if advIP == nil {

View file

@ -698,6 +698,10 @@ func (d *driver) Type() string {
return d.name return d.name
} }
func (d *driver) IsBuiltIn() bool {
return true
}
// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
return nil return nil

View file

@ -164,10 +164,10 @@ func (r *DrvRegistry) RegisterDriver(ntype string, driver driverapi.Driver, capa
} }
r.Lock() r.Lock()
_, ok := r.drivers[ntype] dd, ok := r.drivers[ntype]
r.Unlock() r.Unlock()
if ok { if ok && dd.driver.IsBuiltIn() {
return driverapi.ErrActiveRegistration(ntype) return driverapi.ErrActiveRegistration(ntype)
} }
@ -192,9 +192,9 @@ func (r *DrvRegistry) registerIpamDriver(name string, driver ipamapi.Ipam, caps
} }
r.Lock() r.Lock()
_, ok := r.ipamDrivers[name] dd, ok := r.ipamDrivers[name]
r.Unlock() r.Unlock()
if ok { if ok && dd.driver.IsBuiltIn() {
return types.ForbiddenErrorf("ipam driver %q already registered", name) return types.ForbiddenErrorf("ipam driver %q already registered", name)
} }

View file

@ -594,3 +594,8 @@ func (a *Allocator) DumpDatabase() string {
return s return s
} }
// IsBuiltIn returns true for builtin drivers
func (a *Allocator) IsBuiltIn() bool {
return true
}

View file

@ -80,6 +80,9 @@ type Ipam interface {
RequestAddress(string, net.IP, map[string]string) (*net.IPNet, map[string]string, error) RequestAddress(string, net.IP, map[string]string) (*net.IPNet, map[string]string, error)
// Release the address from the specified pool ID // Release the address from the specified pool ID
ReleaseAddress(string, net.IP) error ReleaseAddress(string, net.IP) error
//IsBuiltIn returns true if it is a built-in driver.
IsBuiltIn() bool
} }
// Capability represents the requirements and capabilities of the IPAM driver // Capability represents the requirements and capabilities of the IPAM driver

View file

@ -65,6 +65,10 @@ func (a *allocator) DiscoverDelete(dType discoverapi.DiscoveryType, data interfa
return nil return nil
} }
func (a *allocator) IsBuiltIn() bool {
return true
}
// Init registers a remote ipam when its plugin is activated // Init registers a remote ipam when its plugin is activated
func Init(ic ipamapi.Callback, l, g interface{}) error { func Init(ic ipamapi.Callback, l, g interface{}) error {
return ic.RegisterIpamDriver(ipamapi.NullIPAM, &allocator{}) return ic.RegisterIpamDriver(ipamapi.NullIPAM, &allocator{})

View file

@ -31,12 +31,7 @@ func newAllocator(name string, client *plugins.Client) ipamapi.Ipam {
// Init registers a remote ipam when its plugin is activated // Init registers a remote ipam when its plugin is activated
func Init(cb ipamapi.Callback, l, g interface{}) error { func Init(cb ipamapi.Callback, l, g interface{}) error {
// Unit test code is unaware of a true PluginStore. So we fall back to v1 plugins. newPluginHandler := func(name string, client *plugins.Client) {
handleFunc := plugins.Handle
if pg := cb.GetPluginGetter(); pg != nil {
handleFunc = pg.Handle
}
handleFunc(ipamapi.PluginEndpointType, func(name string, client *plugins.Client) {
a := newAllocator(name, client) a := newAllocator(name, client)
if cps, err := a.(*allocator).getCapabilities(); err == nil { if cps, err := a.(*allocator).getCapabilities(); err == nil {
if err := cb.RegisterIpamDriverWithCapabilities(name, a, cps); err != nil { if err := cb.RegisterIpamDriverWithCapabilities(name, a, cps); err != nil {
@ -49,7 +44,18 @@ func Init(cb ipamapi.Callback, l, g interface{}) error {
logrus.Errorf("error registering remote ipam driver %s due to %v", name, err) logrus.Errorf("error registering remote ipam driver %s due to %v", name, err)
} }
} }
}) }
// Unit test code is unaware of a true PluginStore. So we fall back to v1 plugins.
handleFunc := plugins.Handle
if pg := cb.GetPluginGetter(); pg != nil {
handleFunc = pg.Handle
activePlugins := pg.GetAllManagedPluginsByCap(ipamapi.PluginEndpointType)
for _, ap := range activePlugins {
newPluginHandler(ap.Name(), ap.Client())
}
}
handleFunc(ipamapi.PluginEndpointType, newPluginHandler)
return nil return nil
} }
@ -143,3 +149,7 @@ func (a *allocator) DiscoverNew(dType discoverapi.DiscoveryType, data interface{
func (a *allocator) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error { func (a *allocator) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
return nil return nil
} }
func (a *allocator) IsBuiltIn() bool {
return false
}

View file

@ -101,3 +101,7 @@ func (a *allocator) DiscoverNew(dType discoverapi.DiscoveryType, data interface{
func (a *allocator) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error { func (a *allocator) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
return nil return nil
} }
func (a *allocator) IsBuiltIn() bool {
return true
}