Add a passthrough directory feature. (#76)

This is only compiled in when a `dev` build tag is specified (see #75)
for safety. Attempting to use the flag without that tag at build time
will fail. However, it is always available within the codebase itself so
that tests can be written against this functionality in a programmatic
way.

Manual testing was performed; no plans to add automated ones as this
isn't production-necessary nor exported functionality.
This commit is contained in:
Jeff Mitchell authored and GitHub committed 2020-05-21 16:12:31 -04:00
1 parent 9fd86faf15
commit 374a3991a2
7 files changed
+88 -30

No files matched your search

+16 -13
View File
@@ -21,6 +21,8 @@ import (
var _ cli.Command = (*Command)(nil)
var _ cli.CommandAutocomplete = (*Command)(nil)
var devOnlyControllerFlags = func(*Command, *base.FlagSet) {}
type Command struct {
*base.Server
@@ -37,12 +39,13 @@ type Command struct {
flagConfig string
flagLogLevel string
flagLogFormat string
flagCombineLogs bool
flagDev bool
flagDevAdminPassword string
flagDevControllerAPIListenAddr string
flagDevControllerClusterListenAddr string
flagDevOrgId string
flagCombineLogs bool
flagDevPassthroughDirectory string
}
func (c *Command) Synopsis() string {
@@ -106,19 +109,17 @@ func (c *Command) Flags() *base.FlagSets {
})
f.StringVar(&base.StringVar{
Name: "dev-org-id",
Target: &c.flagDevOrgId,
Default: "",
EnvVar: "WATCHTWER_DEV_ORG_ID",
Name: "dev-org-id",
Target: &c.flagDevOrgId,
EnvVar: "WATCHTWER_DEV_ORG_ID",
Usage: "Auto-created organization ID. This only applies when running in \"dev\" " +
"mode.",
})
f.StringVar(&base.StringVar{
Name: "dev-admin-password",
Target: &c.flagDevAdminPassword,
Default: "",
EnvVar: "WATCHTWER_DEV_ADMIN_PASSWORD",
Name: "dev-admin-password",
Target: &c.flagDevAdminPassword,
EnvVar: "WATCHTWER_DEV_ADMIN_PASSWORD",
Usage: "Initial admin password. This only applies when running in \"dev\" " +
"mode.",
})
@@ -138,12 +139,13 @@ func (c *Command) Flags() *base.FlagSets {
})
f.BoolVar(&base.BoolVar{
Name: "combine-logs",
Target: &c.flagCombineLogs,
Default: false,
Usage: "If set, both startup information and logs will be sent to stdout. If not set (the default), startup information will go to stdout and logs will be sent to stderr.",
Name: "combine-logs",
Target: &c.flagCombineLogs,
Usage: "If set, both startup information and logs will be sent to stdout. If not set (the default), startup information will go to stdout and logs will be sent to stderr.",
})
devOnlyControllerFlags(c, f)
return set
}
@@ -315,6 +317,7 @@ func (c *Command) ParseFlagsAndConfig(args []string) int {
if c.flagDevOrgId != "" {
c.Config.DefaultOrgId = c.flagDevOrgId
}
c.Config.PassthroughDirectory = c.flagDevPassthroughDirectory
for _, l := range c.Config.Listeners {
if len(l.Purpose) != 1 {
@@ -0,0 +1,18 @@
// +build dev
package controller
import "github.com/hashicorp/watchtower/internal/cmd/base"
func init() {
devOnlyControllerFlags = addDevOnlyControllerFlags
}
func addDevOnlyControllerFlags(c *Command, f *base.FlagSet) {
f.StringVar(&base.StringVar{
Name: "dev-passthrough-directory",
Target: &c.flagDevPassthroughDirectory,
EnvVar: "WATCHTOWER_DEV_PASSTHROUGH_DIRECTORY",
Usage: "Enables a passthrough directory in the webserver at /passthrough",
})
}
+16 -13
View File
@@ -17,6 +17,8 @@ import (
var _ cli.Command = (*Command)(nil)
var _ cli.CommandAutocomplete = (*Command)(nil)
var devOnlyControllerFlags = func(*Command, *base.FlagSet) {}
type Command struct {
*base.Server
@@ -30,12 +32,13 @@ type Command struct {
flagConfig string
flagLogLevel string
flagLogFormat string
flagCombineLogs bool
flagDev bool
flagDevAdminPassword string
flagDevOrgId string
flagDevControllerAPIListenAddr string
flagDevControllerClusterListenAddr string
flagCombineLogs bool
flagDevPassthroughDirectory string
}
func (c *Command) Synopsis() string {
@@ -82,19 +85,17 @@ func (c *Command) Flags() *base.FlagSets {
f = set.NewFlagSet("Dev Options")
f.StringVar(&base.StringVar{
Name: "dev-org-id",
Target: &c.flagDevOrgId,
Default: "",
EnvVar: "WATCHTWER_DEV_ORG_ID",
Name: "dev-org-id",
Target: &c.flagDevOrgId,
EnvVar: "WATCHTWER_DEV_ORG_ID",
Usage: "Auto-created organization ID. This only applies when running in \"dev\" " +
"mode.",
})
f.StringVar(&base.StringVar{
Name: "dev-admin-password",
Target: &c.flagDevAdminPassword,
Default: "",
EnvVar: "WATCHTWER_DEV_ADMIN_PASSWORD",
Name: "dev-admin-password",
Target: &c.flagDevAdminPassword,
EnvVar: "WATCHTWER_DEV_ADMIN_PASSWORD",
Usage: "Initial admin password. This only applies when running in \"dev\" " +
"mode.",
})
@@ -114,12 +115,13 @@ func (c *Command) Flags() *base.FlagSets {
})
f.BoolVar(&base.BoolVar{
Name: "combine-logs",
Target: &c.flagCombineLogs,
Default: false,
Usage: "If set, both startup information and logs will be sent to stdout. If not set (the default), startup information will go to stdout and logs will be sent to stderr.",
Name: "combine-logs",
Target: &c.flagCombineLogs,
Usage: "If set, both startup information and logs will be sent to stdout. If not set (the default), startup information will go to stdout and logs will be sent to stderr.",
})
devOnlyControllerFlags(c, f)
return set
}
@@ -153,6 +155,7 @@ func (c *Command) Run(args []string) int {
if c.flagDevOrgId != "" {
devConfig.DefaultOrgId = c.flagDevOrgId
}
devConfig.PassthroughDirectory = c.flagDevPassthroughDirectory
for _, l := range devConfig.Listeners {
if len(l.Purpose) != 1 {
+18
View File
@@ -0,0 +1,18 @@
// +build dev
package dev
import "github.com/hashicorp/watchtower/internal/cmd/base"
func init() {
devOnlyControllerFlags = addDevOnlyControllerFlags
}
func addDevOnlyControllerFlags(c *Command, f *base.FlagSet) {
f.StringVar(&base.StringVar{
Name: "dev-passthrough-directory",
Target: &c.flagDevPassthroughDirectory,
EnvVar: "WATCHTOWER_DEV_PASSTHROUGH_DIRECTORY",
Usage: "Enables a passthrough directory in the webserver at /passthrough",
})
}
+3 -2
View File
@@ -65,8 +65,9 @@ listener "tcp" {
type Config struct {
*configutil.SharedConfig `hcl:"-"`
DevController bool `hcl:"-"`
DefaultOrgId string `hcl:"default_org_id"`
DevController bool `hcl:"-"`
DefaultOrgId string `hcl:"default_org_id"`
PassthroughDirectory string `hcl:"-"`
}
// DevWorker is a Config that is used for dev mode of Watchtower
+2 -2
View File
@@ -9,6 +9,6 @@ import (
type Config struct {
*base.Server
RawConfig *config.Config
BaseContext context.Context
RawConfig *config.Config
BaseContext context.Context
}
+15
View File
@@ -5,6 +5,7 @@ import (
"encoding/json"
"net/http"
"path"
"path/filepath"
"strings"
"time"
@@ -30,6 +31,20 @@ func (c *Controller) handler(props HandlerProperties) http.Handler {
// Create the muxer to handle the actual endpoints
mux := http.NewServeMux()
if c.conf.RawConfig.PassthroughDirectory != "" {
// Panic may not be ideal but this is never a production call and it'll
// panic on startup. We could also just change the function to return
// an error.
abs, err := filepath.Abs(c.conf.RawConfig.PassthroughDirectory)
if err != nil {
panic(err)
}
c.logger.Warn("serving passthrough files at /passthrough", "path", abs)
fs := http.FileServer(http.Dir(abs))
prefixHandler := http.StripPrefix("/passthrough/", fs)
mux.Handle("/passthrough/", prefixHandler)
}
mux.Handle("/v1/", handleGrpcGateway(c))
corsWrappedHandler := wrapHandlerWithCors(mux, props)