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  }