github.com/rsyabuta/packer@v1.1.4-0.20180119234903-5ef0c2280f0b/common/step_http_server.go (about)

     1  package common
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"log"
     7  	"math/rand"
     8  	"net"
     9  	"net/http"
    10  	"os"
    11  	"path/filepath"
    12  
    13  	"github.com/hashicorp/packer/packer"
    14  	"github.com/mitchellh/multistep"
    15  )
    16  
    17  // This step creates and runs the HTTP server that is serving files from the
    18  // directory specified by the 'http_directory` configuration parameter in the
    19  // template.
    20  //
    21  // Uses:
    22  //   ui     packer.Ui
    23  //
    24  // Produces:
    25  //   http_port int - The port the HTTP server started on.
    26  type StepHTTPServer struct {
    27  	HTTPDir     string
    28  	HTTPPortMin uint
    29  	HTTPPortMax uint
    30  
    31  	l net.Listener
    32  }
    33  
    34  func (s *StepHTTPServer) Run(state multistep.StateBag) multistep.StepAction {
    35  	ui := state.Get("ui").(packer.Ui)
    36  
    37  	var httpPort uint = 0
    38  	if s.HTTPDir == "" {
    39  		state.Put("http_port", httpPort)
    40  		return multistep.ActionContinue
    41  	}
    42  
    43  	// Find an available TCP port for our HTTP server
    44  	var httpAddr string
    45  	portRange := int(s.HTTPPortMax - s.HTTPPortMin)
    46  	for {
    47  		var err error
    48  		var offset uint = 0
    49  
    50  		if portRange > 0 {
    51  			// Intn will panic if portRange == 0, so we do a check.
    52  			// Intn is from [0, n), so add 1 to make from [0, n]
    53  			offset = uint(rand.Intn(portRange + 1))
    54  		}
    55  
    56  		httpPort = offset + s.HTTPPortMin
    57  		httpAddr = fmt.Sprintf("0.0.0.0:%d", httpPort)
    58  		log.Printf("Trying port: %d", httpPort)
    59  		s.l, err = net.Listen("tcp", httpAddr)
    60  		if err == nil {
    61  			break
    62  		}
    63  	}
    64  
    65  	ui.Say(fmt.Sprintf("Starting HTTP server on port %d", httpPort))
    66  
    67  	// Start the HTTP server and run it in the background
    68  	fileServer := http.FileServer(http.Dir(s.HTTPDir))
    69  	server := &http.Server{Addr: httpAddr, Handler: fileServer}
    70  	go server.Serve(s.l)
    71  
    72  	// Save the address into the state so it can be accessed in the future
    73  	state.Put("http_port", httpPort)
    74  	SetHTTPPort(fmt.Sprintf("%d", httpPort))
    75  
    76  	return multistep.ActionContinue
    77  }
    78  
    79  func httpAddrFilename(suffix string) string {
    80  	uuid := os.Getenv("PACKER_RUN_UUID")
    81  	return filepath.Join(os.TempDir(), fmt.Sprintf("packer-%s-%s", uuid, suffix))
    82  }
    83  
    84  func SetHTTPPort(port string) error {
    85  	return ioutil.WriteFile(httpAddrFilename("port"), []byte(port), 0644)
    86  }
    87  
    88  func SetHTTPIP(ip string) error {
    89  	return ioutil.WriteFile(httpAddrFilename("ip"), []byte(ip), 0644)
    90  }
    91  
    92  func GetHTTPAddr() string {
    93  	ip, err := ioutil.ReadFile(httpAddrFilename("ip"))
    94  	if err != nil {
    95  		return ""
    96  	}
    97  	port, err := ioutil.ReadFile(httpAddrFilename("port"))
    98  	if err != nil {
    99  		return ""
   100  	}
   101  	return fmt.Sprintf("%s:%s", ip, port)
   102  }
   103  
   104  func (s *StepHTTPServer) Cleanup(multistep.StateBag) {
   105  	if s.l != nil {
   106  		// Close the listener so that the HTTP server stops
   107  		s.l.Close()
   108  	}
   109  	os.Remove(httpAddrFilename("port"))
   110  	os.Remove(httpAddrFilename("ip"))
   111  }