@@ -3,6 +3,7 @@ package rpcdriver
33import (
44 "fmt"
55 "net/rpc"
6+ "time"
67
78 "github.com/docker/machine/libmachine/drivers"
89 "github.com/docker/machine/libmachine/drivers/plugin/localbinary"
@@ -11,8 +12,14 @@ import (
1112 "github.com/docker/machine/libmachine/state"
1213)
1314
15+ var (
16+ heartbeatInterval = 200 * time .Millisecond
17+ )
18+
1419type RpcClientDriver struct {
15- Client * InternalClient
20+ plugin localbinary.DriverPlugin
21+ heartbeatDoneCh chan bool
22+ Client * InternalClient
1623}
1724
1825type RpcCall struct {
@@ -22,36 +29,27 @@ type RpcCall struct {
2229}
2330
2431type InternalClient struct {
25- RpcClient * rpc.Client
26- Calls chan RpcCall
27- CallErrs chan error
32+ MachineName string
33+ RpcClient * rpc.Client
2834}
2935
3036func (ic * InternalClient ) Call (serviceMethod string , args interface {}, reply interface {}) error {
31- ic .Calls <- RpcCall {
32- ServiceMethod : serviceMethod ,
33- Args : args ,
34- Reply : reply ,
37+ if serviceMethod != "RpcServerDriver.Heartbeat" {
38+ log .Debugf ("(%s) Calling %+v" , ic .MachineName , serviceMethod )
3539 }
36-
37- return <- ic .CallErrs
40+ return ic .RpcClient .Call (serviceMethod , args , reply )
3841}
3942
4043func NewInternalClient (rpcclient * rpc.Client ) * InternalClient {
4144 return & InternalClient {
4245 RpcClient : rpcclient ,
43- Calls : make (chan RpcCall ),
44- CallErrs : make (chan error ),
4546 }
4647}
47-
4848func NewRpcClientDriver (rawDriverData []byte , driverName string ) (* RpcClientDriver , error ) {
4949 mcnName := ""
5050
5151 p := localbinary .NewLocalBinaryPlugin (driverName )
5252
53- c := & RpcClientDriver {}
54-
5553 go func () {
5654 if err := p .Serve (); err != nil {
5755 // If we can't safely load the server, best to just
@@ -70,31 +68,24 @@ func NewRpcClientDriver(rawDriverData []byte, driverName string) (*RpcClientDriv
7068 return nil , err
7169 }
7270
73- c .Client = NewInternalClient (rpcclient )
71+ c := & RpcClientDriver {
72+ Client : NewInternalClient (rpcclient ),
73+ heartbeatDoneCh : make (chan bool ),
74+ }
7475
75- go func () {
76+ go func (heartbeatDoneCh <- chan bool ) {
7677 for {
77- call := <- c .Client .Calls
78-
79- log .Debugf ("(%s) Got msg %+v" , mcnName , call )
80-
81- if call .ServiceMethod == "RpcServerDriver.Close" {
82- p .Close ()
83- }
84-
85- c .Client .CallErrs <- c .Client .RpcClient .Call (call .ServiceMethod , call .Args , call .Reply )
86-
87- if call .ServiceMethod == "RpcServerDriver.Close" {
88- // If we're messaging the server to close,
89- // we're not accepting any more RPC calls at
90- // all, so return from this function
91- // (subsequent "requests" to make a call by
92- // sending on the Calls channel will simply
93- // block and never go through)
78+ select {
79+ case <- heartbeatDoneCh :
9480 return
81+ default :
82+ if err := c .Client .Call ("RpcServerDriver.Heartbeat" , struct {}{}, nil ); err != nil {
83+ log .Warnf ("Error attempting heartbeat call to plugin server: %s" , err )
84+ }
85+ time .Sleep (heartbeatInterval )
9586 }
9687 }
97- }()
88+ }(c . heartbeatDoneCh )
9889
9990 var version int
10091 if err := c .Client .Call ("RpcServerDriver.GetVersion" , struct {}{}, & version ); err != nil {
@@ -108,6 +99,8 @@ func NewRpcClientDriver(rawDriverData []byte, driverName string) (*RpcClientDriv
10899
109100 mcnName = c .GetMachineName ()
110101 p .MachineName = mcnName
102+ c .Client .MachineName = mcnName
103+ c .plugin = p
111104
112105 return c , nil
113106}
@@ -121,6 +114,15 @@ func (c *RpcClientDriver) UnmarshalJSON(data []byte) error {
121114}
122115
123116func (c * RpcClientDriver ) Close () error {
117+ c .heartbeatDoneCh <- true
118+ close (c .heartbeatDoneCh )
119+
120+ log .Debug ("Making call to close connection to plugin binary" )
121+
122+ if err := c .plugin .Close (); err != nil {
123+ return err
124+ }
125+
124126 log .Debug ("Making call to close driver server" )
125127
126128 if err := c .Client .Call ("RpcServerDriver.Close" , struct {}{}, nil ); err != nil {
0 commit comments