introduce working dir pipe mgr

This commit is contained in:
Boshi Lian 2019-01-04 11:40:39 +00:00
parent 7e9f9300d4
commit 650023f363
7 changed files with 133 additions and 97 deletions

7
Gopkg.lock generated
View file

@ -14,10 +14,11 @@
revision = "d32a9ef172a1ec91efdf3ce26b240c946285bfe7"
[[projects]]
branch = "ignore_unknown_ini"
name = "github.com/jessevdk/go-flags"
packages = ["."]
revision = "c6ca198ec95c841fdb89fc0de7496fed11ab854e"
version = "v1.4.0"
revision = "f0dfbc82957e3db331cb27732d270e275614b005"
source = "https://github.com/tg123/go-flags"
[[projects]]
name = "github.com/jinzhu/gorm"
@ -65,6 +66,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "52065920d52958f5461e7df92a92483c9eb78c9bb4b504e0bc82e68e38cfb191"
inputs-digest = "534da9de5467ab2fd3960701473a3fd7da82684491b7b65f21644b0a6b7147f5"
solver-name = "gps-cdcl"
solver-version = 1

View file

@ -30,5 +30,6 @@
name = "github.com/jinzhu/gorm"
[[constraint]]
version = "v1.4.0"
branch = "ignore_unknown_ini"
name = "github.com/jessevdk/go-flags"
source = "https://github.com/tg123/go-flags"

View file

@ -19,15 +19,17 @@ func (s *subCommand) Execute(args []string) error {
return s.callback(args)
}
func addSubCommand(parser *flags.Parser, name, desc string, callback interface{}) {
_, err := parser.AddCommand(name, desc, "", callback)
func addSubCommand(parser *flags.Command, name, desc string, callback interface{}) *flags.Command {
c, err := parser.AddCommand(name, desc, "", callback)
if err != nil {
panic(err)
}
return c
}
func addOpt(parser *flags.Parser, name string, data interface{}) {
func addOpt(parser *flags.Group, name string, data interface{}) {
_, err := parser.AddGroup(name, "", data)
if err != nil {
@ -35,7 +37,7 @@ func addOpt(parser *flags.Parser, name string, data interface{}) {
}
}
func addPlugins(parser *flags.Parser, name string, pluginNames []string, getter func(n string) registry.Plugin) {
func addPlugins(parser *flags.Group, name string, pluginNames []string, getter func(n string) registry.Plugin) {
for _, n := range pluginNames {
p := getter(n)
@ -76,30 +78,41 @@ func populateFromConfig(ini *flags.IniParser, data interface{}, longopt string)
func main() {
parser := flags.NewNamedParser("sshpiperd", flags.Default)
parser.SubcommandsOptional = true
parser.LongDescription = "SSH Piper works as a proxy-like ware, and route connections by username, src ip , etc. Please see <https://github.com/tg123/sshpiper> for more information"
// version
addSubCommand(parser, "version", "show version", &subCommand{func(args []string) error {
showVersion()
return nil
}})
// public config
configFile := &struct {
ConfigFile flags.Filename `long:"config" description:"Config file path. Will be overwriten by arg options and environment variables" default:"/etc/sshpiperd.ini" env:"SSHPIPERD_CONFIG_FILE" no-ini:"true"`
}{}
addOpt(parser.Group, "sshpiperd", configFile)
// dumpini
addSubCommand(parser, "dumpconfig", "dump current config ini to stdout", &subCommand{func(args []string) error {
loadFromConfigFile := func(c *flags.Command) {
parser := flags.NewNamedParser("sshpiperd", flags.IgnoreUnknown)
parser.Command = c
ini := flags.NewIniParser(parser)
ini.Write(os.Stdout, flags.IniIncludeDefaults)
return nil
}})
err := populateFromConfig(ini, configFile, "config")
if err != nil {
fmt.Println(fmt.Sprintf("load config file failed %v", err))
os.Exit(1)
}
}
// version
{
addSubCommand(parser.Command, "version", "show version", &subCommand{func(args []string) error {
showVersion()
return nil
}})
}
// manpage
addSubCommand(parser, "manpage", "write man page to stdout", &subCommand{func(args []string) error {
addSubCommand(parser.Command, "manpage", "write man page to stdout", &subCommand{func(args []string) error {
parser.WriteManPage(os.Stdout)
return nil
}})
// plugins
addSubCommand(parser, "plugins", "list support plugins, e.g. sshpiperd plugis upstream", &subCommand{func(args []string) error {
addSubCommand(parser.Command, "plugins", "list support plugins, e.g. sshpiperd plugis upstream", &subCommand{func(args []string) error {
output := func(all []string) {
for _, p := range all {
@ -126,68 +139,59 @@ func main() {
return nil
}})
// options, for snap only at the moment
addSubCommand(parser, "options", "list all options", &subCommand{func(args []string) error {
for _, g := range parser.Groups() {
for _, o := range g.Options() {
fmt.Println(o.LongName)
}
}
return nil
}})
// generate key tools
addSubCommand(parser, "genkey", "generate a 2048 rsa key to stdout", &subCommand{func(args []string) error {
key, err := sshkey.GenerateKey(sshkey.KEY_RSA, 2048)
if err != nil {
{
addSubCommand(parser.Command, "genkey", "generate a 2048 rsa key to stdout", &subCommand{func(args []string) error {
key, err := sshkey.GenerateKey(sshkey.KEY_RSA, 2048)
if err != nil {
return err
}
out, err := sshkey.MarshalPrivate(key, "")
if err != nil {
return err
}
_, err = fmt.Fprint(os.Stdout, string(out))
return err
}
out, err := sshkey.MarshalPrivate(key, "")
if err != nil {
return err
}
_, err = fmt.Fprint(os.Stdout, string(out))
return err
}})
config := &struct {
piperdConfig
loggerConfig
// need to be shown in help, or will be moved to populate config
ConfigFile flags.Filename `long:"config" description:"Config file path. Will be overwriten by arg options and environment variables" default:"/etc/sshpiperd.ini" env:"SSHPIPERD_CONFIG_FILE" no-ini:"true"`
}{}
addSubCommand(parser, "pipe", "manage pipe on current upstream driver", createPipeMgr(&config.UpstreamDriver))
addOpt(parser, "sshpiperd", config)
addPlugins(parser, "upstream", upstream.All(), func(n string) registry.Plugin { return upstream.Get(n) })
addPlugins(parser, "challenger", challenger.All(), func(n string) registry.Plugin { return challenger.Get(n) })
addPlugins(parser, "auditor", auditor.All(), func(n string) registry.Plugin { return auditor.Get(n) })
// populate by config
ini := flags.NewIniParser(parser)
err := populateFromConfig(ini, config, "config")
if err != nil {
fmt.Println(fmt.Sprintf("load config file failed %v", err))
os.Exit(1)
}})
}
parser.CommandHandler = func(command flags.Commander, args []string) error {
// pipe management
{
config := &struct {
UpstreamDriver string `long:"upstream-driver" description:"Upstream provider driver" default:"workingdir" env:"SSHPIPERD_UPSTREAM_DRIVER" ini-name:"upstream-driver"`
}{}
// no subcommand called, start to serve
if command == nil {
var c *flags.Command
c = addSubCommand(parser.Command, "pipe", "manage pipe on current upstream driver", createPipeMgr(func() (upstream.Provider, error) {
if len(args) > 0 {
return fmt.Errorf("unknown command %v", args)
loadFromConfigFile(c)
if config.UpstreamDriver == "" {
return nil, fmt.Errorf("must provider upstream driver")
}
return upstream.Get(config.UpstreamDriver).(upstream.Provider), nil
}))
addOpt(c.Group, "sshpiperd", config)
addPlugins(c.Group, "upstream", upstream.All(), func(n string) registry.Plugin { return upstream.Get(n) })
}
// daemon command
{
config := &struct {
piperdConfig
loggerConfig
}{}
var c *flags.Command
c = addSubCommand(parser.Command, "daemon", "run in daemon mode, serving traffic", &subCommand{func(args []string) error {
// populate by config
loadFromConfigFile(c)
showVersion()
// dump used configure only
@ -195,7 +199,7 @@ func main() {
fmt.Println()
for _, gk := range []string{"sshpiperd", "upstream." + config.UpstreamDriver, "challenger." + config.ChallengerDriver, "auditor." + config.AuditorDriver} {
g := parser.Group.Find(gk)
g := c.Group.Find(gk)
if g == nil {
continue
}
@ -210,9 +214,45 @@ func main() {
}
return startPiper(&config.piperdConfig, config.createLogger())
}
}})
c.SubcommandsOptional = true
addOpt(c.Group, "sshpiperd", config)
addPlugins(c.Group, "upstream", upstream.All(), func(n string) registry.Plugin { return upstream.Get(n) })
addPlugins(c.Group, "challenger", challenger.All(), func(n string) registry.Plugin { return challenger.Get(n) })
addPlugins(c.Group, "auditor", auditor.All(), func(n string) registry.Plugin { return auditor.Get(n) })
// dumpini for daemon
addSubCommand(c, "dumpconfig", "dump current config for daemon ini to stdout", &subCommand{func(args []string) error {
loadFromConfigFile(c)
parser := flags.NewNamedParser("sshpiperd", flags.Default)
parser.Command = c
ini := flags.NewIniParser(parser)
ini.Write(os.Stdout, flags.IniIncludeDefaults)
return nil
}})
// options, for snap only at the moment
addSubCommand(c, "options", "list all options for daemon mode", &subCommand{func(args []string) error {
var printOpts func(*flags.Group)
printOpts = func(group *flags.Group) {
for _, o := range group.Options() {
fmt.Println(o.LongName)
}
for _, g := range group.Groups() {
printOpts(g)
}
}
printOpts(c.Group)
return nil
}})
return command.Execute(args)
}
parser.Parse()

View file

@ -1,20 +1,10 @@
package main
import (
"fmt"
"github.com/tg123/sshpiper/sshpiperd/upstream"
)
func createPipeMgr(driver *string) interface{} {
load := func() (upstream.Provider, error) {
if *driver == "" {
return nil, fmt.Errorf("must provider upstream driver")
}
return upstream.Get(*driver).(upstream.Provider), nil
}
func createPipeMgr(load func() (upstream.Provider, error)) interface{} {
// pipe management
pipeMgrCmd := struct {
List struct {
@ -23,12 +13,12 @@ func createPipeMgr(driver *string) interface{} {
Add struct {
subCommand
PiperUserName string `long:"piper-username" description:"" required:"true" no-ini:"true"`
PiperUserName string `short:"n" long:"piper-username" description:"" required:"true" no-ini:"true"`
// PiperAuthorizedKeysFile flags.Filename
UpstreamUserName string `long:"upstream-username" description:"mapped user name" no-ini:"true"`
UpstreamHost string `long:"host" description:"upstream sshd host" required:"true" no-ini:"true"`
UpstreamPort uint `long:"port" description:"upstream sshd port" default:"22" no-ini:"true"`
UpstreamHost string `short:"u" long:"host" description:"upstream sshd host" required:"true" no-ini:"true"`
UpstreamPort uint `short:"p" long:"port" description:"upstream sshd port" default:"22" no-ini:"true"`
// UpstreamKeyFile flags.Filename
// UpstreamHostKey
@ -38,7 +28,7 @@ func createPipeMgr(driver *string) interface{} {
Remove struct {
subCommand
Name string `long:"name" required:"true" no-ini:"true"`
Name string `short:"n" long:"piper-username" required:"true" no-ini:"true"`
} `command:"remove" description:"remove a pipe from current upstream"`
}{}

View file

@ -5,7 +5,7 @@ bin=$SNAP/sshpiperd
config=$SNAP_DATA/sshpiperd.ini
args=""
for opt in $($bin options); do
for opt in $($bin daemon options); do
v=$(snapctl get $opt)
if [ "$v" != "" ]; then
@ -27,4 +27,4 @@ for opt in $($bin options); do
done
echo ";DO NOT MODIFY, USE snap set sshpiperd key=val, AUTO GENERATED" $(date) > $config
$bin --config /dev/null $args dumpconfig >> $config
$bin daemon --config /dev/null $args dumpconfig >> $config

View file

@ -14,7 +14,7 @@ parts:
apps:
sshpiperd-daemon:
command: sshpiperd --config $SNAP_DATA/sshpiperd.ini
command: sshpiperd daemon --config $SNAP_DATA/sshpiperd.ini
plugs: [network-bind]
daemon: simple
sshpiperd:

View file

@ -505,7 +505,11 @@ func (i *IniParser) parse(ini *ini) error {
groups := i.matchingGroups(name)
if len(groups) == 0 {
return newErrorf(ErrUnknownGroup, "could not find option group `%s'", name)
if (p.Options & IgnoreUnknown) == None {
return newErrorf(ErrUnknownGroup, "could not find option group `%s'", name)
}
continue
}
for _, inival := range section {