github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/libnetwork/drivers/remote/driver.go (about)

     1  package remote
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  
     7  	"github.com/docker/docker/libnetwork/datastore"
     8  	"github.com/docker/docker/libnetwork/discoverapi"
     9  	"github.com/docker/docker/libnetwork/driverapi"
    10  	"github.com/docker/docker/libnetwork/drivers/remote/api"
    11  	"github.com/docker/docker/libnetwork/types"
    12  	"github.com/docker/docker/pkg/plugingetter"
    13  	"github.com/docker/docker/pkg/plugins"
    14  	"github.com/pkg/errors"
    15  	"github.com/sirupsen/logrus"
    16  )
    17  
    18  type driver struct {
    19  	endpoint    *plugins.Client
    20  	networkType string
    21  }
    22  
    23  type maybeError interface {
    24  	GetError() string
    25  }
    26  
    27  func newDriver(name string, client *plugins.Client) driverapi.Driver {
    28  	return &driver{networkType: name, endpoint: client}
    29  }
    30  
    31  // Init makes sure a remote driver is registered when a network driver
    32  // plugin is activated.
    33  func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
    34  	newPluginHandler := func(name string, client *plugins.Client) {
    35  		// negotiate driver capability with client
    36  		d := newDriver(name, client)
    37  		c, err := d.(*driver).getCapabilities()
    38  		if err != nil {
    39  			logrus.Errorf("error getting capability for %s due to %v", name, err)
    40  			return
    41  		}
    42  		if err = dc.RegisterDriver(name, d, *c); err != nil {
    43  			logrus.Errorf("error registering driver for %s due to %v", name, err)
    44  		}
    45  	}
    46  
    47  	// Unit test code is unaware of a true PluginStore. So we fall back to v1 plugins.
    48  	handleFunc := plugins.Handle
    49  	if pg := dc.GetPluginGetter(); pg != nil {
    50  		handleFunc = pg.Handle
    51  		activePlugins := pg.GetAllManagedPluginsByCap(driverapi.NetworkPluginEndpointType)
    52  		for _, ap := range activePlugins {
    53  			client, err := getPluginClient(ap)
    54  			if err != nil {
    55  				return err
    56  			}
    57  			newPluginHandler(ap.Name(), client)
    58  		}
    59  	}
    60  	handleFunc(driverapi.NetworkPluginEndpointType, newPluginHandler)
    61  
    62  	return nil
    63  }
    64  
    65  func getPluginClient(p plugingetter.CompatPlugin) (*plugins.Client, error) {
    66  	if v1, ok := p.(plugingetter.PluginWithV1Client); ok {
    67  		return v1.Client(), nil
    68  	}
    69  
    70  	pa, ok := p.(plugingetter.PluginAddr)
    71  	if !ok {
    72  		return nil, errors.Errorf("unknown plugin type %T", p)
    73  	}
    74  
    75  	if pa.Protocol() != plugins.ProtocolSchemeHTTPV1 {
    76  		return nil, errors.Errorf("unsupported plugin protocol %s", pa.Protocol())
    77  	}
    78  
    79  	addr := pa.Addr()
    80  	client, err := plugins.NewClientWithTimeout(addr.Network()+"://"+addr.String(), nil, pa.Timeout())
    81  	if err != nil {
    82  		return nil, errors.Wrap(err, "error creating plugin client")
    83  	}
    84  	return client, nil
    85  }
    86  
    87  // Get capability from client
    88  func (d *driver) getCapabilities() (*driverapi.Capability, error) {
    89  	var capResp api.GetCapabilityResponse
    90  	if err := d.call("GetCapabilities", nil, &capResp); err != nil {
    91  		return nil, err
    92  	}
    93  
    94  	c := &driverapi.Capability{}
    95  	switch capResp.Scope {
    96  	case "global":
    97  		c.DataScope = datastore.GlobalScope
    98  	case "local":
    99  		c.DataScope = datastore.LocalScope
   100  	default:
   101  		return nil, fmt.Errorf("invalid capability: expecting 'local' or 'global', got %s", capResp.Scope)
   102  	}
   103  
   104  	switch capResp.ConnectivityScope {
   105  	case "global":
   106  		c.ConnectivityScope = datastore.GlobalScope
   107  	case "local":
   108  		c.ConnectivityScope = datastore.LocalScope
   109  	case "":
   110  		c.ConnectivityScope = c.DataScope
   111  	default:
   112  		return nil, fmt.Errorf("invalid capability: expecting 'local' or 'global', got %s", capResp.Scope)
   113  	}
   114  
   115  	return c, nil
   116  }
   117  
   118  // Config is not implemented for remote drivers, since it is assumed
   119  // to be supplied to the remote process out-of-band (e.g., as command
   120  // line arguments).
   121  func (d *driver) Config(option map[string]interface{}) error {
   122  	return &driverapi.ErrNotImplemented{}
   123  }
   124  
   125  func (d *driver) call(methodName string, arg interface{}, retVal maybeError) error {
   126  	method := driverapi.NetworkPluginEndpointType + "." + methodName
   127  	err := d.endpoint.Call(method, arg, retVal)
   128  	if err != nil {
   129  		return err
   130  	}
   131  	if e := retVal.GetError(); e != "" {
   132  		return fmt.Errorf("remote: %s", e)
   133  	}
   134  	return nil
   135  }
   136  
   137  func (d *driver) NetworkAllocate(id string, options map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) {
   138  	create := &api.AllocateNetworkRequest{
   139  		NetworkID: id,
   140  		Options:   options,
   141  		IPv4Data:  ipV4Data,
   142  		IPv6Data:  ipV6Data,
   143  	}
   144  	retVal := api.AllocateNetworkResponse{}
   145  	err := d.call("AllocateNetwork", create, &retVal)
   146  	return retVal.Options, err
   147  }
   148  
   149  func (d *driver) NetworkFree(id string) error {
   150  	fr := &api.FreeNetworkRequest{NetworkID: id}
   151  	return d.call("FreeNetwork", fr, &api.FreeNetworkResponse{})
   152  }
   153  
   154  func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
   155  }
   156  
   157  func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) {
   158  	return "", nil
   159  }
   160  
   161  func (d *driver) CreateNetwork(id string, options map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
   162  	create := &api.CreateNetworkRequest{
   163  		NetworkID: id,
   164  		Options:   options,
   165  		IPv4Data:  ipV4Data,
   166  		IPv6Data:  ipV6Data,
   167  	}
   168  	return d.call("CreateNetwork", create, &api.CreateNetworkResponse{})
   169  }
   170  
   171  func (d *driver) DeleteNetwork(nid string) error {
   172  	delete := &api.DeleteNetworkRequest{NetworkID: nid}
   173  	return d.call("DeleteNetwork", delete, &api.DeleteNetworkResponse{})
   174  }
   175  
   176  func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
   177  	if ifInfo == nil {
   178  		return errors.New("must not be called with nil InterfaceInfo")
   179  	}
   180  
   181  	reqIface := &api.EndpointInterface{}
   182  	if ifInfo.Address() != nil {
   183  		reqIface.Address = ifInfo.Address().String()
   184  	}
   185  	if ifInfo.AddressIPv6() != nil {
   186  		reqIface.AddressIPv6 = ifInfo.AddressIPv6().String()
   187  	}
   188  	if ifInfo.MacAddress() != nil {
   189  		reqIface.MacAddress = ifInfo.MacAddress().String()
   190  	}
   191  
   192  	create := &api.CreateEndpointRequest{
   193  		NetworkID:  nid,
   194  		EndpointID: eid,
   195  		Interface:  reqIface,
   196  		Options:    epOptions,
   197  	}
   198  	var res api.CreateEndpointResponse
   199  	if err := d.call("CreateEndpoint", create, &res); err != nil {
   200  		return err
   201  	}
   202  
   203  	inIface, err := parseInterface(res)
   204  	if err != nil {
   205  		return err
   206  	}
   207  	if inIface == nil {
   208  		// Remote driver did not set any field
   209  		return nil
   210  	}
   211  
   212  	if inIface.MacAddress != nil {
   213  		if err := ifInfo.SetMacAddress(inIface.MacAddress); err != nil {
   214  			return errorWithRollback(fmt.Sprintf("driver modified interface MAC address: %v", err), d.DeleteEndpoint(nid, eid))
   215  		}
   216  	}
   217  	if inIface.Address != nil {
   218  		if err := ifInfo.SetIPAddress(inIface.Address); err != nil {
   219  			return errorWithRollback(fmt.Sprintf("driver modified interface address: %v", err), d.DeleteEndpoint(nid, eid))
   220  		}
   221  	}
   222  	if inIface.AddressIPv6 != nil {
   223  		if err := ifInfo.SetIPAddress(inIface.AddressIPv6); err != nil {
   224  			return errorWithRollback(fmt.Sprintf("driver modified interface address: %v", err), d.DeleteEndpoint(nid, eid))
   225  		}
   226  	}
   227  
   228  	return nil
   229  }
   230  
   231  func errorWithRollback(msg string, err error) error {
   232  	rollback := "rolled back"
   233  	if err != nil {
   234  		rollback = "failed to roll back: " + err.Error()
   235  	}
   236  	return fmt.Errorf("%s; %s", msg, rollback)
   237  }
   238  
   239  func (d *driver) DeleteEndpoint(nid, eid string) error {
   240  	delete := &api.DeleteEndpointRequest{
   241  		NetworkID:  nid,
   242  		EndpointID: eid,
   243  	}
   244  	return d.call("DeleteEndpoint", delete, &api.DeleteEndpointResponse{})
   245  }
   246  
   247  func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
   248  	info := &api.EndpointInfoRequest{
   249  		NetworkID:  nid,
   250  		EndpointID: eid,
   251  	}
   252  	var res api.EndpointInfoResponse
   253  	if err := d.call("EndpointOperInfo", info, &res); err != nil {
   254  		return nil, err
   255  	}
   256  	return res.Value, nil
   257  }
   258  
   259  // Join method is invoked when a Sandbox is attached to an endpoint.
   260  func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
   261  	join := &api.JoinRequest{
   262  		NetworkID:  nid,
   263  		EndpointID: eid,
   264  		SandboxKey: sboxKey,
   265  		Options:    options,
   266  	}
   267  	var (
   268  		res api.JoinResponse
   269  		err error
   270  	)
   271  	if err = d.call("Join", join, &res); err != nil {
   272  		return err
   273  	}
   274  
   275  	ifaceName := res.InterfaceName
   276  	if iface := jinfo.InterfaceName(); iface != nil && ifaceName != nil {
   277  		if err := iface.SetNames(ifaceName.SrcName, ifaceName.DstPrefix); err != nil {
   278  			return errorWithRollback(fmt.Sprintf("failed to set interface name: %s", err), d.Leave(nid, eid))
   279  		}
   280  	}
   281  
   282  	var addr net.IP
   283  	if res.Gateway != "" {
   284  		if addr = net.ParseIP(res.Gateway); addr == nil {
   285  			return fmt.Errorf(`unable to parse Gateway "%s"`, res.Gateway)
   286  		}
   287  		if jinfo.SetGateway(addr) != nil {
   288  			return errorWithRollback(fmt.Sprintf("failed to set gateway: %v", addr), d.Leave(nid, eid))
   289  		}
   290  	}
   291  	if res.GatewayIPv6 != "" {
   292  		if addr = net.ParseIP(res.GatewayIPv6); addr == nil {
   293  			return fmt.Errorf(`unable to parse GatewayIPv6 "%s"`, res.GatewayIPv6)
   294  		}
   295  		if jinfo.SetGatewayIPv6(addr) != nil {
   296  			return errorWithRollback(fmt.Sprintf("failed to set gateway IPv6: %v", addr), d.Leave(nid, eid))
   297  		}
   298  	}
   299  	if len(res.StaticRoutes) > 0 {
   300  		routes, err := parseStaticRoutes(res)
   301  		if err != nil {
   302  			return err
   303  		}
   304  		for _, route := range routes {
   305  			if jinfo.AddStaticRoute(route.Destination, route.RouteType, route.NextHop) != nil {
   306  				return errorWithRollback(fmt.Sprintf("failed to set static route: %v", route), d.Leave(nid, eid))
   307  			}
   308  		}
   309  	}
   310  	if res.DisableGatewayService {
   311  		jinfo.DisableGatewayService()
   312  	}
   313  	return nil
   314  }
   315  
   316  // Leave method is invoked when a Sandbox detaches from an endpoint.
   317  func (d *driver) Leave(nid, eid string) error {
   318  	leave := &api.LeaveRequest{
   319  		NetworkID:  nid,
   320  		EndpointID: eid,
   321  	}
   322  	return d.call("Leave", leave, &api.LeaveResponse{})
   323  }
   324  
   325  // ProgramExternalConnectivity is invoked to program the rules to allow external connectivity for the endpoint.
   326  func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
   327  	data := &api.ProgramExternalConnectivityRequest{
   328  		NetworkID:  nid,
   329  		EndpointID: eid,
   330  		Options:    options,
   331  	}
   332  	err := d.call("ProgramExternalConnectivity", data, &api.ProgramExternalConnectivityResponse{})
   333  	if err != nil && plugins.IsNotFound(err) {
   334  		// It is not mandatory yet to support this method
   335  		return nil
   336  	}
   337  	return err
   338  }
   339  
   340  // RevokeExternalConnectivity method is invoked to remove any external connectivity programming related to the endpoint.
   341  func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
   342  	data := &api.RevokeExternalConnectivityRequest{
   343  		NetworkID:  nid,
   344  		EndpointID: eid,
   345  	}
   346  	err := d.call("RevokeExternalConnectivity", data, &api.RevokeExternalConnectivityResponse{})
   347  	if err != nil && plugins.IsNotFound(err) {
   348  		// It is not mandatory yet to support this method
   349  		return nil
   350  	}
   351  	return err
   352  }
   353  
   354  func (d *driver) Type() string {
   355  	return d.networkType
   356  }
   357  
   358  func (d *driver) IsBuiltIn() bool {
   359  	return false
   360  }
   361  
   362  // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
   363  func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
   364  	if dType != discoverapi.NodeDiscovery {
   365  		return nil
   366  	}
   367  	notif := &api.DiscoveryNotification{
   368  		DiscoveryType: dType,
   369  		DiscoveryData: data,
   370  	}
   371  	return d.call("DiscoverNew", notif, &api.DiscoveryResponse{})
   372  }
   373  
   374  // DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
   375  func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
   376  	if dType != discoverapi.NodeDiscovery {
   377  		return nil
   378  	}
   379  	notif := &api.DiscoveryNotification{
   380  		DiscoveryType: dType,
   381  		DiscoveryData: data,
   382  	}
   383  	return d.call("DiscoverDelete", notif, &api.DiscoveryResponse{})
   384  }
   385  
   386  func parseStaticRoutes(r api.JoinResponse) ([]*types.StaticRoute, error) {
   387  	var routes = make([]*types.StaticRoute, len(r.StaticRoutes))
   388  	for i, inRoute := range r.StaticRoutes {
   389  		var err error
   390  		outRoute := &types.StaticRoute{RouteType: inRoute.RouteType}
   391  
   392  		if inRoute.Destination != "" {
   393  			if outRoute.Destination, err = types.ParseCIDR(inRoute.Destination); err != nil {
   394  				return nil, err
   395  			}
   396  		}
   397  
   398  		if inRoute.NextHop != "" {
   399  			outRoute.NextHop = net.ParseIP(inRoute.NextHop)
   400  			if outRoute.NextHop == nil {
   401  				return nil, fmt.Errorf("failed to parse nexthop IP %s", inRoute.NextHop)
   402  			}
   403  		}
   404  
   405  		routes[i] = outRoute
   406  	}
   407  	return routes, nil
   408  }
   409  
   410  // parseInterfaces validates all the parameters of an Interface and returns them.
   411  func parseInterface(r api.CreateEndpointResponse) (*api.Interface, error) {
   412  	var outIf *api.Interface
   413  
   414  	inIf := r.Interface
   415  	if inIf != nil {
   416  		var err error
   417  		outIf = &api.Interface{}
   418  		if inIf.Address != "" {
   419  			if outIf.Address, err = types.ParseCIDR(inIf.Address); err != nil {
   420  				return nil, err
   421  			}
   422  		}
   423  		if inIf.AddressIPv6 != "" {
   424  			if outIf.AddressIPv6, err = types.ParseCIDR(inIf.AddressIPv6); err != nil {
   425  				return nil, err
   426  			}
   427  		}
   428  		if inIf.MacAddress != "" {
   429  			if outIf.MacAddress, err = net.ParseMAC(inIf.MacAddress); err != nil {
   430  				return nil, err
   431  			}
   432  		}
   433  	}
   434  
   435  	return outIf, nil
   436  }