cmd/packet: Use IPXEScriptURL instead of passing script via Userdata

Using the userdat to pass the iPXE script precludes us from passing
actual userdata to the instance. Instead pass a URL to the iPXE script.
The script is expected to be a <base-url>/<name>-packet.ipxe.

When starting a server also serve the iPXE script from memory (not
the file system). The http server needed extending to differentiate
between the serving files and the iPXE script and ServeMux is used
to differentiate based on path.

A subsequent commit will provide an option to write the iPXE script
to disk.

Signed-off-by: Rolf Neugebauer <rolf.neugebauer@docker.com>
This commit is contained in:
Rolf Neugebauer 2018-01-09 15:35:23 +00:00
parent 8ae4f5bc86
commit 2431dd9950

View File

@ -56,7 +56,7 @@ func runPacket(args []string) {
fmt.Printf("Options:\n\n")
flags.PrintDefaults()
}
baseURLFlag := flags.String("base-url", "", "Base URL that the kernel and initrd are served from (or "+packetBaseURL+")")
baseURLFlag := flags.String("base-url", "", "Base URL that the kernel, initrd and iPXE script are served from (or "+packetBaseURL+")")
zoneFlag := flags.String("zone", packetDefaultZone, "Packet Zone (or "+packetZoneVar+")")
machineFlag := flags.String("machine", packetDefaultMachine, "Packet Machine Type (or "+packetMachineVar+")")
apiKeyFlag := flags.String("api-key", "", "Packet API key (or "+packetAPIKeyVar+")")
@ -80,7 +80,7 @@ func runPacket(args []string) {
url := getStringValue(packetBaseURL, *baseURLFlag, "")
if url == "" {
log.Fatal("Need to specify a value for --base-url where the images are hosted. This URL should contain <url>/%s-kernel and <url>/%s-initrd.img")
log.Fatal("Need to specify a value for --base-url where the images are hosted. This URL should contain <url>/%s-kernel, <url>/%s-initrd.img and <url>/%s-packet.ipxe")
}
facility := getStringValue(packetZoneVar, *zoneFlag, "")
plan := getStringValue(packetMachineVar, *machineFlag, defaultMachine)
@ -101,19 +101,31 @@ func runPacket(args []string) {
log.Fatalf("Combination of keep=%t and console=%t makes little sense", *keepFlag, *consoleFlag)
}
// Read kernel command line
var cmdline string
if c, err := ioutil.ReadFile(prefix + "-cmdline"); err != nil {
log.Fatalf("Cannot open cmdline file: %v", err)
} else {
cmdline = string(c)
}
ipxeScriptName := fmt.Sprintf("%s-packet.ipxe", name)
// Serve files with a local http server
var httpServer *http.Server
if *serveFlag != "" {
// Read kernel command line
var cmdline string
if c, err := ioutil.ReadFile(prefix + "-cmdline"); err != nil {
log.Fatalf("Cannot open cmdline file: %v", err)
} else {
cmdline = string(c)
}
ipxeScript := packetIPXEScript(name, url, cmdline, packetMachineToArch(*machineFlag))
log.Debugf("Using iPXE script:\n%s\n", ipxeScript)
// Two handlers, one for the iPXE script and one for the kernel/initrd files
mux := http.NewServeMux()
mux.HandleFunc(fmt.Sprintf("/%s", ipxeScriptName),
func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, ipxeScript)
})
fs := serveFiles{[]string{fmt.Sprintf("%s-kernel", name), fmt.Sprintf("%s-initrd.img", name)}}
httpServer = &http.Server{Addr: *serveFlag, Handler: http.FileServer(fs)}
mux.Handle("/", http.FileServer(fs))
httpServer = &http.Server{Addr: *serveFlag, Handler: mux}
go func() {
log.Debugf("Listening on http://%s\n", *serveFlag)
if err := httpServer.ListenAndServe(); err != nil {
@ -122,16 +134,19 @@ func runPacket(args []string) {
}()
}
userData := packetIPXEScript(name, url, cmdline, packetMachineToArch(*machineFlag))
log.Debugf("Using userData of:\n%s\n", userData)
// Make sure the URL works
// Make sure the URLs work
ipxeURL := fmt.Sprintf("%s/%s", url, ipxeScriptName)
initrdURL := fmt.Sprintf("%s/%s-initrd.img", url, name)
kernelURL := fmt.Sprintf("%s/%s-kernel", url, name)
log.Infof("Validating URls: %s %s", initrdURL, kernelURL)
log.Infof("Validating URL: %s", ipxeURL)
if err := validateHTTPURL(ipxeURL); err != nil {
log.Fatalf("Invalid iPXE URL %s: %v", ipxeURL, err)
}
log.Infof("Validating URL: %s", kernelURL)
if err := validateHTTPURL(kernelURL); err != nil {
log.Fatalf("Invalid kernel URL %s: %v", kernelURL, err)
}
log.Infof("Validating URL: %s", initrdURL)
if err := validateHTTPURL(initrdURL); err != nil {
log.Fatalf("Invalid initrd URL %s: %v", initrdURL, err)
}
@ -153,11 +168,11 @@ func runPacket(args []string) {
log.Debugf("%s\n", string(b))
req := packngo.DeviceUpdateRequest{
Hostname: hostname,
UserData: userData,
Locked: dev.Locked,
Tags: dev.Tags,
AlwaysPXE: *alwaysPXE,
Hostname: hostname,
Locked: dev.Locked,
Tags: dev.Tags,
IPXEScriptURL: ipxeURL,
AlwaysPXE: *alwaysPXE,
}
dev, _, err = client.Devices.Update(*deviceFlag, &req)
if err != nil {
@ -169,15 +184,15 @@ func runPacket(args []string) {
} else {
// Create a new device
req := packngo.DeviceCreateRequest{
Hostname: hostname,
Plan: plan,
Facility: facility,
OS: osType,
BillingCycle: billing,
ProjectID: projectID,
UserData: userData,
Tags: tags,
AlwaysPXE: *alwaysPXE,
Hostname: hostname,
Plan: plan,
Facility: facility,
OS: osType,
BillingCycle: billing,
ProjectID: projectID,
Tags: tags,
IPXEScriptURL: ipxeURL,
AlwaysPXE: *alwaysPXE,
}
dev, _, err = client.Devices.Create(&req)
if err != nil {