github.com/andresvia/terraform@v0.6.15-0.20160412045437-d51c75946785/rpc/server.go (about)

     1  package rpc
     2  
     3  import (
     4  	"io"
     5  	"log"
     6  	"net"
     7  	"net/rpc"
     8  
     9  	"github.com/hashicorp/terraform/terraform"
    10  	"github.com/hashicorp/yamux"
    11  )
    12  
    13  // Server listens for network connections and then dispenses interface
    14  // implementations for Terraform over net/rpc.
    15  type Server struct {
    16  	ProviderFunc    ProviderFunc
    17  	ProvisionerFunc ProvisionerFunc
    18  }
    19  
    20  // ProviderFunc creates terraform.ResourceProviders when they're requested
    21  // from the server.
    22  type ProviderFunc func() terraform.ResourceProvider
    23  
    24  // ProvisionerFunc creates terraform.ResourceProvisioners when they're requested
    25  // from the server.
    26  type ProvisionerFunc func() terraform.ResourceProvisioner
    27  
    28  // Accept accepts connections on a listener and serves requests for
    29  // each incoming connection. Accept blocks; the caller typically invokes
    30  // it in a go statement.
    31  func (s *Server) Accept(lis net.Listener) {
    32  	for {
    33  		conn, err := lis.Accept()
    34  		if err != nil {
    35  			log.Printf("[ERR] plugin server: %s", err)
    36  			return
    37  		}
    38  
    39  		go s.ServeConn(conn)
    40  	}
    41  }
    42  
    43  // ServeConn runs a single connection.
    44  //
    45  // ServeConn blocks, serving the connection until the client hangs up.
    46  func (s *Server) ServeConn(conn io.ReadWriteCloser) {
    47  	// First create the yamux server to wrap this connection
    48  	mux, err := yamux.Server(conn, nil)
    49  	if err != nil {
    50  		conn.Close()
    51  		log.Printf("[ERR] plugin: %s", err)
    52  		return
    53  	}
    54  
    55  	// Accept the control connection
    56  	control, err := mux.Accept()
    57  	if err != nil {
    58  		mux.Close()
    59  		log.Printf("[ERR] plugin: %s", err)
    60  		return
    61  	}
    62  
    63  	// Create the broker and start it up
    64  	broker := newMuxBroker(mux)
    65  	go broker.Run()
    66  
    67  	// Use the control connection to build the dispenser and serve the
    68  	// connection.
    69  	server := rpc.NewServer()
    70  	server.RegisterName("Dispenser", &dispenseServer{
    71  		ProviderFunc:    s.ProviderFunc,
    72  		ProvisionerFunc: s.ProvisionerFunc,
    73  
    74  		broker: broker,
    75  	})
    76  	server.ServeConn(control)
    77  }
    78  
    79  // dispenseServer dispenses variousinterface implementations for Terraform.
    80  type dispenseServer struct {
    81  	ProviderFunc    ProviderFunc
    82  	ProvisionerFunc ProvisionerFunc
    83  
    84  	broker *muxBroker
    85  }
    86  
    87  func (d *dispenseServer) ResourceProvider(
    88  	args interface{}, response *uint32) error {
    89  	id := d.broker.NextId()
    90  	*response = id
    91  
    92  	go func() {
    93  		conn, err := d.broker.Accept(id)
    94  		if err != nil {
    95  			log.Printf("[ERR] Plugin dispense: %s", err)
    96  			return
    97  		}
    98  
    99  		serve(conn, "ResourceProvider", &ResourceProviderServer{
   100  			Broker:   d.broker,
   101  			Provider: d.ProviderFunc(),
   102  		})
   103  	}()
   104  
   105  	return nil
   106  }
   107  
   108  func (d *dispenseServer) ResourceProvisioner(
   109  	args interface{}, response *uint32) error {
   110  	id := d.broker.NextId()
   111  	*response = id
   112  
   113  	go func() {
   114  		conn, err := d.broker.Accept(id)
   115  		if err != nil {
   116  			log.Printf("[ERR] Plugin dispense: %s", err)
   117  			return
   118  		}
   119  
   120  		serve(conn, "ResourceProvisioner", &ResourceProvisionerServer{
   121  			Broker:      d.broker,
   122  			Provisioner: d.ProvisionerFunc(),
   123  		})
   124  	}()
   125  
   126  	return nil
   127  }
   128  
   129  func acceptAndServe(mux *muxBroker, id uint32, n string, v interface{}) {
   130  	conn, err := mux.Accept(id)
   131  	if err != nil {
   132  		log.Printf("[ERR] Plugin acceptAndServe: %s", err)
   133  		return
   134  	}
   135  
   136  	serve(conn, n, v)
   137  }
   138  
   139  func serve(conn io.ReadWriteCloser, name string, v interface{}) {
   140  	server := rpc.NewServer()
   141  	if err := server.RegisterName(name, v); err != nil {
   142  		log.Printf("[ERR] Plugin dispense: %s", err)
   143  		return
   144  	}
   145  
   146  	server.ServeConn(conn)
   147  }