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 }