Skip to content

Commit

Permalink
cmd: Add a -serve command to the packet.net backend
Browse files Browse the repository at this point in the history
The -serve command starts a local HTTP server which serves
the kernel and initrd files.  The server can then easily be
made available via ngrok or other means.

Signed-off-by: Rolf Neugebauer <rolf.neugebauer@docker.com>
  • Loading branch information
rn committed Aug 15, 2017
1 parent 33e8afb commit fced67d
Showing 1 changed file with 67 additions and 0 deletions.
67 changes: 67 additions & 0 deletions src/cmd/linuxkit/run_packet.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@ package main

import (
"bufio"
"context"
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"net"
"net/http"
"os"
"os/signal"
"os/user"
"path"
"path/filepath"
"strings"
"time"

"github.com/packethost/packngo"
log "github.com/sirupsen/logrus"
Expand Down Expand Up @@ -60,6 +64,7 @@ func runPacket(args []string) {
hostNameFlag := flags.String("hostname", packetDefaultHostname, "Hostname of new instance (or "+packetHostnameVar+")")
nameFlag := flags.String("img-name", "", "Overrides the prefix used to identify the files. Defaults to [name] (or "+packetNameVar+")")
alwaysPXE := flags.Bool("always-pxe", true, "Reboot from PXE every time.")
serveFlag := flags.String("serve", "", "Serve local files via the http port specified, e.g. ':8080'.")
consoleFlag := flags.Bool("console", true, "Provide interactive access on the console.")
if err := flags.Parse(args); err != nil {
log.Fatal("Unable to parse args")
Expand Down Expand Up @@ -98,6 +103,19 @@ func runPacket(args []string) {
cmdline = string(c)
}

// Serve files with a local http server
var httpServer *http.Server
if *serveFlag != "" {
fs := serveFiles{[]string{fmt.Sprintf("%s-kernel", name), fmt.Sprintf("%s-initrd.img", name)}}
httpServer = &http.Server{Addr: ":8080", Handler: http.FileServer(fs)}
go func() {
log.Infof("Listening on http://%s\n", *serveFlag)
if err := httpServer.ListenAndServe(); err != nil {
log.Infof("http server exited with: %v", err)
}
}()
}

// Build the iPXE script
// Note, we *append* the <prefix>-cmdline. iXPE booting will
// need the first set of "kernel-params" and we don't want to
Expand Down Expand Up @@ -150,6 +168,23 @@ func runPacket(args []string) {
} else {
log.Printf("Machine booting")
log.Printf("Access the console with: ssh %s@%s", d.ID, sshHost)

// if the serve option is present, wait till 'ctrl-c' is hit.
// Otherwise we wouldn't serve the files
if *serveFlag != "" {
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt)
log.Printf("Hit ctrl-c to stop http server")
<-stop
}
}

// Stop the http server before exiting
if *serveFlag != "" {
log.Printf("Shutting down http server...")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
httpServer.Shutdown(ctx)
}
}

Expand Down Expand Up @@ -267,3 +302,35 @@ func sshHostKey(host string) (ssh.PublicKey, error) {
}
return hostKey, nil
}

// This implements a http.FileSystem which only responds to specific files.
type serveFiles struct {
files []string
}

// Open implements the Open method for the serveFiles FileSystem
// implementation.
// It converts both the name from the URL and the files provided in
// the serveFiles structure into cleaned, absolute filesystem path and
// only returns the file if the requested name matches one of the
// files in the list.
func (fs serveFiles) Open(name string) (http.File, error) {
cwd, err := os.Getwd()
if err != nil {
return nil, err
}

name = filepath.Join(cwd, filepath.FromSlash(path.Clean("/"+name)))
for _, fn := range fs.files {
fn = filepath.Join(cwd, filepath.FromSlash(path.Clean("/"+fn)))
if name == fn {
f, err := os.Open(fn)
if err != nil {
return nil, err
}
log.Infof("Serving: %s", fn)
return f, nil
}
}
return nil, fmt.Errorf("File %s not found", name)
}

0 comments on commit fced67d

Please sign in to comment.