github.com/mikesimons/terraform@v0.6.13-0.20160304043642-f11448c69214/rpc/client.go (about) 1 package rpc 2 3 import ( 4 "io" 5 "net" 6 "net/rpc" 7 8 "github.com/hashicorp/terraform/terraform" 9 "github.com/hashicorp/yamux" 10 ) 11 12 // Client connects to a Server in order to request plugin implementations 13 // for Terraform. 14 type Client struct { 15 broker *muxBroker 16 control *rpc.Client 17 } 18 19 // Dial opens a connection to a Terraform RPC server and returns a client. 20 func Dial(network, address string) (*Client, error) { 21 conn, err := net.Dial(network, address) 22 if err != nil { 23 return nil, err 24 } 25 26 if tcpConn, ok := conn.(*net.TCPConn); ok { 27 // Make sure to set keep alive so that the connection doesn't die 28 tcpConn.SetKeepAlive(true) 29 } 30 31 return NewClient(conn) 32 } 33 34 // NewClient creates a client from an already-open connection-like value. 35 // Dial is typically used instead. 36 func NewClient(conn io.ReadWriteCloser) (*Client, error) { 37 // Create the yamux client so we can multiplex 38 mux, err := yamux.Client(conn, nil) 39 if err != nil { 40 conn.Close() 41 return nil, err 42 } 43 44 // Connect to the control stream. 45 control, err := mux.Open() 46 if err != nil { 47 mux.Close() 48 return nil, err 49 } 50 51 // Create the broker and start it up 52 broker := newMuxBroker(mux) 53 go broker.Run() 54 55 // Build the client using our broker and control channel. 56 return &Client{ 57 broker: broker, 58 control: rpc.NewClient(control), 59 }, nil 60 } 61 62 // Close closes the connection. The client is no longer usable after this 63 // is called. 64 func (c *Client) Close() error { 65 if err := c.control.Close(); err != nil { 66 return err 67 } 68 69 return c.broker.Close() 70 } 71 72 func (c *Client) ResourceProvider() (terraform.ResourceProvider, error) { 73 var id uint32 74 if err := c.control.Call( 75 "Dispenser.ResourceProvider", new(interface{}), &id); err != nil { 76 return nil, err 77 } 78 79 conn, err := c.broker.Dial(id) 80 if err != nil { 81 return nil, err 82 } 83 84 return &ResourceProvider{ 85 Broker: c.broker, 86 Client: rpc.NewClient(conn), 87 Name: "ResourceProvider", 88 }, nil 89 } 90 91 func (c *Client) ResourceProvisioner() (terraform.ResourceProvisioner, error) { 92 var id uint32 93 if err := c.control.Call( 94 "Dispenser.ResourceProvisioner", new(interface{}), &id); err != nil { 95 return nil, err 96 } 97 98 conn, err := c.broker.Dial(id) 99 if err != nil { 100 return nil, err 101 } 102 103 return &ResourceProvisioner{ 104 Broker: c.broker, 105 Client: rpc.NewClient(conn), 106 Name: "ResourceProvisioner", 107 }, nil 108 }