Skip to content

Commit

Permalink
feature: add support for base dir
Browse files Browse the repository at this point in the history
BaseDir allows one to serve files that are stored on the host machine.
  • Loading branch information
OGKevin committed May 22, 2021
1 parent 8b141d3 commit c2acb3a
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 10 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,14 @@ mounts:
# When true, the proxy path defined above gets a suffix to the Path prefix appended to it.
proxyAppendSuffix: true

- path: /subdir
# When true, all paths starting with this prefix use this mount.
pathIsPrefix: true
# Provides a path on the host to find the files.
# So that BasePath: /tftpboot path: /subdir and client requests: /tfptboot/subdir/file.x the path on the host
# becomes /tfptboot/subdir/file.x
baseDir: /tftpboot

- path: /install.ipxe
# The templating context provides access to: .LocalIP, .RemoteIP, .HttpBaseUrl and .Manifest.
# Sprig functions are available: masterminds.github.io/sprig
Expand Down
20 changes: 16 additions & 4 deletions httpd/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@ package httpd
import (
"bytes"
_ "embed"
mfest "github.com/DSpeichert/netbootd/manifest"
"github.com/DSpeichert/netbootd/static"
"github.com/Masterminds/sprig"
"io"
"net"
"net/http"
"net/http/httputil"
"net/url"
"os"
"strings"
"text/template"
"time"

mfest "github.com/DSpeichert/netbootd/manifest"
"github.com/DSpeichert/netbootd/static"
"github.com/Masterminds/sprig"
)

type Handler struct {
Expand Down Expand Up @@ -129,8 +131,18 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
rp.ServeHTTP(w, r)
return
} else if mount.BaseDir != "" {
f, err := os.Open(mount.BaseDir + r.URL.Path)
if err != nil {
h.server.logger.Error().
Err(err).
Msg("Could not get file from BaseDir")
http.Error(w, err.Error(), http.StatusInternalServerError)
}
http.ServeContent(w, r, r.URL.Path, time.Time{}, f)
return
} else {
// mount has neither .Path nor .Proxy defined
// mount has neither .Path, .Proxy nor .BaseDir defined
h.server.logger.Error().
Str("path", r.RequestURI).
Str("client", raddr.String()).
Expand Down
33 changes: 31 additions & 2 deletions manifest/io.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,20 @@ package manifest

import (
"encoding/json"
"fmt"
"path/filepath"
"strings"

"gopkg.in/yaml.v2"
)

func ManifestFromJson(content []byte) (manifest Manifest, err error) {
err = json.Unmarshal(content, &manifest)
return
if err != nil {
return manifest, err
}

return manifest, manifest.Validate()
}

func (m *Manifest) ToJson() ([]byte, error) {
Expand All @@ -16,7 +24,28 @@ func (m *Manifest) ToJson() ([]byte, error) {

func ManifestFromYaml(content []byte) (manifest Manifest, err error) {
err = yaml.Unmarshal(content, &manifest)
return
if err != nil {
return manifest, err
}

return manifest, manifest.Validate()
}

func (m Manifest) Validate() error {
for i, mount := range m.Mounts {
if mount.BaseDir != "" {
if !filepath.IsAbs(mount.BaseDir) {
return fmt.Errorf("BaseDir needs to be absolute path")
}
if !strings.HasSuffix(mount.BaseDir, "/") {
mount.BaseDir = mount.BaseDir + "/"
}

m.Mounts[i] = mount
}
}

return nil
}

func (m *Manifest) ToYaml() ([]byte, error) {
Expand Down
5 changes: 5 additions & 0 deletions manifest/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ type Mount struct {
// Provides content template (passed through template/text) to serve.
// Mutually exclusive with Proxy option.
Content string

// Provides a path on the host to find the files.
// So that BasePath: /tftpboot path: /subdir and client requests: /tfptboot/subdir/file.x the path on the host
// becomes /tfptboot/subdir/file.x
BaseDir string `yaml:"baseDir"`
}

func (m Mount) ProxyDirector() (func(req *http.Request), error) {
Expand Down
43 changes: 39 additions & 4 deletions tftpd/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ import (
_ "embed"
"errors"
"fmt"
mfest "github.com/DSpeichert/netbootd/manifest"
"github.com/DSpeichert/netbootd/static"
"github.com/Masterminds/sprig"
"github.com/pin/tftp"
"io"
"net/http"
"net/url"
"os"
"strings"
"text/template"

mfest "github.com/DSpeichert/netbootd/manifest"
"github.com/DSpeichert/netbootd/static"
"github.com/Masterminds/sprig"
"github.com/pin/tftp"
)

func (server *Server) tftpReadHandler(filename string, rf io.ReaderFrom) error {
Expand Down Expand Up @@ -156,6 +158,39 @@ func (server *Server) tftpReadHandler(filename string, rf io.ReaderFrom) error {
return err
}

server.logger.Info().
Err(err).
Str("path", filename).
Str("client", raddr.IP.String()).
Int64("sent", n).
Msg("transfer finished")
} else if mount.BaseDir != "" {
f, err := os.Open(mount.BaseDir + filename)
if err != nil {
server.logger.Error().
Err(err).
Msg("Could not get file from BaseDir")

return err
}

stat, err := f.Stat()
if err != nil {
server.logger.Error().
Err(err).
Msg("Could not get file host file stats")
return err
}

rf.(tftp.OutgoingTransfer).SetSize(int64(stat.Size()))

n, err := rf.ReadFrom(f)
if err != nil {
server.logger.Error().
Msgf("ReadFrom failed: %v", err)
return err
}

server.logger.Info().
Err(err).
Str("path", filename).
Expand Down

0 comments on commit c2acb3a

Please sign in to comment.