github.com/phobos182/packer@v0.2.3-0.20130819023704-c84d2aeffc68/packer/plugin/plugin.go (about) 1 // The plugin package provides the functionality to both expose a Packer 2 // plugin binary and to connect to an existing Packer plugin binary. 3 // 4 // Packer supports plugins in the form of self-contained external static 5 // Go binaries. These binaries behave in a certain way (enforced by this 6 // package) and are connected to in a certain way (also enforced by this 7 // package). 8 package plugin 9 10 import ( 11 "errors" 12 "fmt" 13 "github.com/mitchellh/packer/packer" 14 packrpc "github.com/mitchellh/packer/packer/rpc" 15 "log" 16 "net" 17 "net/rpc" 18 "os" 19 "os/signal" 20 "runtime" 21 "strconv" 22 ) 23 24 const MagicCookieKey = "PACKER_PLUGIN_MAGIC_COOKIE" 25 const MagicCookieValue = "d602bf8f470bc67ca7faa0386276bbdd4330efaf76d1a219cb4d6991ca9872b2" 26 27 // This serves a single RPC connection on the given RPC server on 28 // a random port. 29 func serve(server *rpc.Server) (err error) { 30 if os.Getenv(MagicCookieKey) != MagicCookieValue { 31 return errors.New("Please do not execute plugins directly. Packer will execute these for you.") 32 } 33 34 // If there is no explicit number of Go threads to use, then set it 35 if os.Getenv("GOMAXPROCS") == "" { 36 runtime.GOMAXPROCS(runtime.NumCPU()) 37 } 38 39 minPort, err := strconv.ParseInt(os.Getenv("PACKER_PLUGIN_MIN_PORT"), 10, 32) 40 if err != nil { 41 return 42 } 43 44 maxPort, err := strconv.ParseInt(os.Getenv("PACKER_PLUGIN_MAX_PORT"), 10, 32) 45 if err != nil { 46 return 47 } 48 49 log.Printf("Plugin minimum port: %d\n", minPort) 50 log.Printf("Plugin maximum port: %d\n", maxPort) 51 52 // Set the RPC port range 53 packrpc.PortRange(int(minPort), int(maxPort)) 54 55 var address string 56 var listener net.Listener 57 for port := minPort; port <= maxPort; port++ { 58 address = fmt.Sprintf("127.0.0.1:%d", port) 59 listener, err = net.Listen("tcp", address) 60 if err != nil { 61 err = nil 62 continue 63 } 64 65 break 66 } 67 68 defer listener.Close() 69 70 // Output the address to stdout 71 log.Printf("Plugin address: %s\n", address) 72 fmt.Println(address) 73 os.Stdout.Sync() 74 75 // Accept a connection 76 log.Println("Waiting for connection...") 77 conn, err := listener.Accept() 78 if err != nil { 79 log.Printf("Error accepting connection: %s\n", err.Error()) 80 return 81 } 82 83 // Serve a single connection 84 log.Println("Serving a plugin connection...") 85 server.ServeConn(conn) 86 return 87 } 88 89 // Registers a signal handler to "swallow" interrupts so that the 90 // plugin isn't killed. The main host Packer process is responsible 91 // for killing the plugins when interrupted. 92 func swallowInterrupts() { 93 ch := make(chan os.Signal, 1) 94 signal.Notify(ch, os.Interrupt) 95 96 go func() { 97 <-ch 98 log.Println("Received interrupt signal. Ignoring.") 99 }() 100 } 101 102 // Serves a builder from a plugin. 103 func ServeBuilder(builder packer.Builder) { 104 log.Println("Preparing to serve a builder plugin...") 105 106 server := rpc.NewServer() 107 packrpc.RegisterBuilder(server, builder) 108 109 swallowInterrupts() 110 if err := serve(server); err != nil { 111 log.Printf("ERROR: %s", err) 112 os.Exit(1) 113 } 114 } 115 116 // Serves a command from a plugin. 117 func ServeCommand(command packer.Command) { 118 log.Println("Preparing to serve a command plugin...") 119 120 server := rpc.NewServer() 121 packrpc.RegisterCommand(server, command) 122 123 swallowInterrupts() 124 if err := serve(server); err != nil { 125 log.Printf("ERROR: %s", err) 126 os.Exit(1) 127 } 128 } 129 130 // Serves a hook from a plugin. 131 func ServeHook(hook packer.Hook) { 132 log.Println("Preparing to serve a hook plugin...") 133 134 server := rpc.NewServer() 135 packrpc.RegisterHook(server, hook) 136 137 swallowInterrupts() 138 if err := serve(server); err != nil { 139 log.Printf("ERROR: %s", err) 140 os.Exit(1) 141 } 142 } 143 144 // Serves a post-processor from a plugin. 145 func ServePostProcessor(p packer.PostProcessor) { 146 log.Println("Preparing to serve a post-processor plugin...") 147 148 server := rpc.NewServer() 149 packrpc.RegisterPostProcessor(server, p) 150 151 swallowInterrupts() 152 if err := serve(server); err != nil { 153 log.Printf("ERROR: %s", err) 154 os.Exit(1) 155 } 156 } 157 158 // Serves a provisioner from a plugin. 159 func ServeProvisioner(p packer.Provisioner) { 160 log.Println("Preparing to serve a provisioner plugin...") 161 162 server := rpc.NewServer() 163 packrpc.RegisterProvisioner(server, p) 164 165 swallowInterrupts() 166 if err := serve(server); err != nil { 167 log.Printf("ERROR: %s", err) 168 os.Exit(1) 169 } 170 }