github.com/kikitux/packer@v0.10.1-0.20160322154024-6237df566f9f/common/step_http_server.go (about)

     1  package common
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/mitchellh/multistep"
     6  	"github.com/mitchellh/packer/packer"
     7  	"log"
     8  	"math/rand"
     9  	"net"
    10  	"net/http"
    11  )
    12  
    13  // This step creates and runs the HTTP server that is serving files from the
    14  // directory specified by the 'http_directory` configuration parameter in the
    15  // template.
    16  //
    17  // Uses:
    18  //   ui     packer.Ui
    19  //
    20  // Produces:
    21  //   http_port int - The port the HTTP server started on.
    22  type StepHTTPServer struct {
    23  	HTTPDir     string
    24  	HTTPPortMin uint
    25  	HTTPPortMax uint
    26  
    27  	l net.Listener
    28  }
    29  
    30  func (s *StepHTTPServer) Run(state multistep.StateBag) multistep.StepAction {
    31  	ui := state.Get("ui").(packer.Ui)
    32  
    33  	var httpPort uint = 0
    34  	if s.HTTPDir == "" {
    35  		state.Put("http_port", httpPort)
    36  		return multistep.ActionContinue
    37  	}
    38  
    39  	// Find an available TCP port for our HTTP server
    40  	var httpAddr string
    41  	portRange := int(s.HTTPPortMax - s.HTTPPortMin)
    42  	for {
    43  		var err error
    44  		var offset uint = 0
    45  
    46  		if portRange > 0 {
    47  			// Intn will panic if portRange == 0, so we do a check.
    48  			offset = uint(rand.Intn(portRange))
    49  		}
    50  
    51  		httpPort = offset + s.HTTPPortMin
    52  		httpAddr = fmt.Sprintf("0.0.0.0:%d", httpPort)
    53  		log.Printf("Trying port: %d", httpPort)
    54  		s.l, err = net.Listen("tcp", httpAddr)
    55  		if err == nil {
    56  			break
    57  		}
    58  	}
    59  
    60  	ui.Say(fmt.Sprintf("Starting HTTP server on port %d", httpPort))
    61  
    62  	// Start the HTTP server and run it in the background
    63  	fileServer := http.FileServer(http.Dir(s.HTTPDir))
    64  	server := &http.Server{Addr: httpAddr, Handler: fileServer}
    65  	go server.Serve(s.l)
    66  
    67  	// Save the address into the state so it can be accessed in the future
    68  	state.Put("http_port", httpPort)
    69  
    70  	return multistep.ActionContinue
    71  }
    72  
    73  func (s *StepHTTPServer) Cleanup(multistep.StateBag) {
    74  	if s.l != nil {
    75  		// Close the listener so that the HTTP server stops
    76  		s.l.Close()
    77  	}
    78  }