func NewRPCClientDriver(rawDriverData []byte, driverName string) (*RPCClientDriver, error) { mcnName := "" p, err := localbinary.NewPlugin(driverName) if err != nil { return nil, err } go func() { if err := p.Serve(); err != nil { // TODO: Is this best approach? log.Warn(err) return } }() addr, err := p.Address() if err != nil { return nil, fmt.Errorf("Error attempting to get plugin server address for RPC: %s", err) } rpcclient, err := rpc.DialHTTP("tcp", addr) if err != nil { return nil, err } c := &RPCClientDriver{ Client: NewInternalClient(rpcclient), heartbeatDoneCh: make(chan bool), } go func(c *RPCClientDriver) { for { select { case <-c.heartbeatDoneCh: return default: if err := c.Client.Call("RPCServerDriver.Heartbeat", struct{}{}, nil); err != nil { log.Warnf("Error attempting heartbeat call to plugin server: %s", err) c.Close() return } time.Sleep(heartbeatInterval) } } }(c) var serverVersion int if err := c.Client.Call("RPCServerDriver.GetVersion", struct{}{}, &serverVersion); err != nil { return nil, err } if serverVersion != version.APIVersion { return nil, fmt.Errorf("Driver binary uses an incompatible API version (%d)", serverVersion) } log.Debug("Using API Version ", serverVersion) if err := c.SetConfigRaw(rawDriverData); err != nil { return nil, err } mcnName = c.GetMachineName() p.MachineName = mcnName c.Client.MachineName = mcnName c.plugin = p return c, nil }
func (f *DefaultRPCClientDriverFactory) NewRPCClientDriver(driverName string, rawDriver []byte) (*RPCClientDriver, error) { mcnName := "" p, err := localbinary.NewPlugin(driverName) if err != nil { return nil, err } go func() { if err := p.Serve(); err != nil { // TODO: Is this best approach? log.Warn(err) return } }() addr, err := p.Address() if err != nil { return nil, fmt.Errorf("Error attempting to get plugin server address for RPC: %s", err) } rpcclient, err := rpc.DialHTTP("tcp", addr) if err != nil { return nil, err } c := &RPCClientDriver{ Client: NewInternalClient(rpcclient), heartbeatDoneCh: make(chan bool), } f.openedDriversLock.Lock() f.openedDrivers = append(f.openedDrivers, c) f.openedDriversLock.Unlock() var serverVersion int if err := c.Client.Call(GetVersionMethod, struct{}{}, &serverVersion); err != nil { // this is the first call we make to the server. We try to play nice with old pre 0.5.1 client, // by gracefully trying old RPCServiceName, we do this only once, and keep the result for future calls. log.Debugf(err.Error()) log.Debugf("Client (%s) with %s does not work, re-attempting with %s", c.Client.MachineName, RPCServiceNameV1, RPCServiceNameV0) c.Client.switchToV0() if err := c.Client.Call(GetVersionMethod, struct{}{}, &serverVersion); err != nil { return nil, err } } if serverVersion != version.APIVersion { return nil, fmt.Errorf("Driver binary uses an incompatible API version (%d)", serverVersion) } log.Debug("Using API Version ", serverVersion) go func(c *RPCClientDriver) { for { select { case <-c.heartbeatDoneCh: return case <-time.After(heartbeatInterval): if err := c.Client.Call(HeartbeatMethod, struct{}{}, nil); err != nil { log.Warnf("Error attempting heartbeat call to plugin server: %s", err) } } } }(c) if err := c.SetConfigRaw(rawDriver); err != nil { return nil, err } mcnName = c.GetMachineName() p.MachineName = mcnName c.Client.MachineName = mcnName c.plugin = p return c, nil }