Fix rendering of text flag defaults
This commit is contained in:
parent
af69f1cfba
commit
ca62a37692
@ -47,6 +47,10 @@ type Bootstrap struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New initializes and returns a new Bootstrap file for a new host.
|
// New initializes and returns a new Bootstrap file for a new host.
|
||||||
|
//
|
||||||
|
// TODO in the resulting bootstrap only include this host and hosts which are
|
||||||
|
// necessary for connecting to nebula/garage. Remember to immediately re-poll
|
||||||
|
// garage for the full hosts list during network joining.
|
||||||
func New(
|
func New(
|
||||||
caCreds nebula.CACredentials,
|
caCreds nebula.CACredentials,
|
||||||
adminCreationParams CreationParams,
|
adminCreationParams CreationParams,
|
||||||
|
@ -3,20 +3,37 @@ package main
|
|||||||
import (
|
import (
|
||||||
"encoding"
|
"encoding"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"isle/nebula"
|
||||||
|
"net/netip"
|
||||||
)
|
)
|
||||||
|
|
||||||
type textUnmarshalerFlag struct {
|
type textUnmarshaler[T any] interface {
|
||||||
inner interface {
|
|
||||||
encoding.TextUnmarshaler
|
encoding.TextUnmarshaler
|
||||||
|
*T
|
||||||
|
}
|
||||||
|
|
||||||
|
type textUnmarshalerFlag[T encoding.TextMarshaler, P textUnmarshaler[T]] struct {
|
||||||
|
V T
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *textUnmarshalerFlag[T, P]) Set(v string) error {
|
||||||
|
return P(&(f.V)).UnmarshalText([]byte(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *textUnmarshalerFlag[T, P]) String() string {
|
||||||
|
b, err := f.V.MarshalText()
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("calling MarshalText on %#v: %v", f.V, err))
|
||||||
}
|
}
|
||||||
|
return string(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f textUnmarshalerFlag) Set(v string) error {
|
func (f *textUnmarshalerFlag[T, P]) Type() string { return "string" }
|
||||||
return f.inner.UnmarshalText([]byte(v))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f textUnmarshalerFlag) String() string {
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
return fmt.Sprint(f.inner)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f textUnmarshalerFlag) Type() string { return "string" }
|
type (
|
||||||
|
hostNameFlag = textUnmarshalerFlag[nebula.HostName, *nebula.HostName]
|
||||||
|
ipNetFlag = textUnmarshalerFlag[nebula.IPNet, *nebula.IPNet]
|
||||||
|
ipFlag = textUnmarshalerFlag[netip.Addr, *netip.Addr]
|
||||||
|
)
|
||||||
|
@ -7,8 +7,6 @@ import (
|
|||||||
"isle/bootstrap"
|
"isle/bootstrap"
|
||||||
"isle/daemon"
|
"isle/daemon"
|
||||||
"isle/jsonutil"
|
"isle/jsonutil"
|
||||||
"isle/nebula"
|
|
||||||
"net/netip"
|
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
@ -19,19 +17,17 @@ var subCmdHostsCreate = subCmd{
|
|||||||
do: func(subCmdCtx subCmdCtx) error {
|
do: func(subCmdCtx subCmdCtx) error {
|
||||||
var (
|
var (
|
||||||
flags = subCmdCtx.flagSet(false)
|
flags = subCmdCtx.flagSet(false)
|
||||||
hostName nebula.HostName
|
hostName hostNameFlag
|
||||||
ip netip.Addr
|
ip ipFlag
|
||||||
)
|
)
|
||||||
|
|
||||||
hostNameF := flags.VarPF(
|
hostNameF := flags.VarPF(
|
||||||
textUnmarshalerFlag{&hostName},
|
&hostName,
|
||||||
"hostname", "h",
|
"hostname", "h",
|
||||||
"Name of the host to generate bootstrap.json for",
|
"Name of the host to generate bootstrap.json for",
|
||||||
)
|
)
|
||||||
|
|
||||||
flags.VarP(
|
flags.VarP(&ip, "ip", "i", "IP of the new host. An available IP will be chosen if none is given.")
|
||||||
textUnmarshalerFlag{&ip}, "ip", "i", "IP of the new host",
|
|
||||||
)
|
|
||||||
|
|
||||||
canCreateHosts := flags.Bool(
|
canCreateHosts := flags.Bool(
|
||||||
"can-create-hosts",
|
"can-create-hosts",
|
||||||
@ -53,9 +49,9 @@ var subCmdHostsCreate = subCmd{
|
|||||||
&res,
|
&res,
|
||||||
"CreateHost",
|
"CreateHost",
|
||||||
daemon.CreateHostRequest{
|
daemon.CreateHostRequest{
|
||||||
HostName: hostName,
|
HostName: hostName.V,
|
||||||
Opts: daemon.CreateHostOpts{
|
Opts: daemon.CreateHostOpts{
|
||||||
IP: ip,
|
IP: ip.V,
|
||||||
CanCreateHosts: *canCreateHosts,
|
CanCreateHosts: *canCreateHosts,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -110,11 +106,11 @@ var subCmdHostsRemove = subCmd{
|
|||||||
do: func(subCmdCtx subCmdCtx) error {
|
do: func(subCmdCtx subCmdCtx) error {
|
||||||
var (
|
var (
|
||||||
flags = subCmdCtx.flagSet(false)
|
flags = subCmdCtx.flagSet(false)
|
||||||
hostName nebula.HostName
|
hostName hostNameFlag
|
||||||
)
|
)
|
||||||
|
|
||||||
hostNameF := flags.VarPF(
|
hostNameF := flags.VarPF(
|
||||||
textUnmarshalerFlag{&hostName},
|
&hostName,
|
||||||
"hostname", "h",
|
"hostname", "h",
|
||||||
"Name of the host to remove",
|
"Name of the host to remove",
|
||||||
)
|
)
|
||||||
@ -129,7 +125,7 @@ var subCmdHostsRemove = subCmd{
|
|||||||
|
|
||||||
err := subCmdCtx.daemonRCPClient.Call(
|
err := subCmdCtx.daemonRCPClient.Call(
|
||||||
subCmdCtx.ctx, nil, "RemoveHost", daemon.RemoveHostRequest{
|
subCmdCtx.ctx, nil, "RemoveHost", daemon.RemoveHostRequest{
|
||||||
HostName: hostName,
|
HostName: hostName.V,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -15,11 +15,11 @@ var subCmdNebulaCreateCert = subCmd{
|
|||||||
do: func(subCmdCtx subCmdCtx) error {
|
do: func(subCmdCtx subCmdCtx) error {
|
||||||
var (
|
var (
|
||||||
flags = subCmdCtx.flagSet(false)
|
flags = subCmdCtx.flagSet(false)
|
||||||
hostName nebula.HostName
|
hostName hostNameFlag
|
||||||
)
|
)
|
||||||
|
|
||||||
hostNameF := flags.VarPF(
|
hostNameF := flags.VarPF(
|
||||||
textUnmarshalerFlag{&hostName},
|
&hostName,
|
||||||
"hostname", "h",
|
"hostname", "h",
|
||||||
"Name of the host to generate a certificate for",
|
"Name of the host to generate a certificate for",
|
||||||
)
|
)
|
||||||
@ -53,7 +53,7 @@ var subCmdNebulaCreateCert = subCmd{
|
|||||||
&res,
|
&res,
|
||||||
"CreateNebulaCertificate",
|
"CreateNebulaCertificate",
|
||||||
daemon.CreateNebulaCertificateRequest{
|
daemon.CreateNebulaCertificateRequest{
|
||||||
HostName: hostName,
|
HostName: hostName.V,
|
||||||
HostEncryptingPublicKey: hostPub,
|
HostEncryptingPublicKey: hostPub,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"isle/daemon"
|
"isle/daemon"
|
||||||
"isle/jsonutil"
|
"isle/jsonutil"
|
||||||
|
"log"
|
||||||
)
|
)
|
||||||
|
|
||||||
var subCmdNetworkCreate = subCmd{
|
var subCmdNetworkCreate = subCmd{
|
||||||
@ -14,28 +15,30 @@ var subCmdNetworkCreate = subCmd{
|
|||||||
var (
|
var (
|
||||||
ctx = subCmdCtx.ctx
|
ctx = subCmdCtx.ctx
|
||||||
flags = subCmdCtx.flagSet(false)
|
flags = subCmdCtx.flagSet(false)
|
||||||
req daemon.CreateNetworkRequest
|
|
||||||
|
ipNet ipNetFlag
|
||||||
|
hostName hostNameFlag
|
||||||
)
|
)
|
||||||
|
|
||||||
flags.StringVarP(
|
name := flags.StringP(
|
||||||
&req.Name, "name", "n", "",
|
"name", "n", "",
|
||||||
"Human-readable name to identify the network as.",
|
"Human-readable name to identify the network as.",
|
||||||
)
|
)
|
||||||
|
|
||||||
flags.StringVarP(
|
domain := flags.StringP(
|
||||||
&req.Domain, "domain", "d", "",
|
"domain", "d", "",
|
||||||
"Domain name that should be used as the root domain in the network.",
|
"Domain name that should be used as the root domain in the network.",
|
||||||
)
|
)
|
||||||
|
|
||||||
ipNetF := flags.VarPF(
|
ipNetF := flags.VarPF(
|
||||||
textUnmarshalerFlag{&req.IPNet}, "ip-net", "i",
|
&ipNet, "ip-net", "i",
|
||||||
`An IP subnet, in CIDR form, which will be the overall range of`+
|
`An IP subnet, in CIDR form, which will be the overall range of`+
|
||||||
` possible IPs in the network. The first IP in this network`+
|
` possible IPs in the network. The first IP in this network`+
|
||||||
` range will become this first host's IP.`,
|
` range will become this first host's IP.`,
|
||||||
)
|
)
|
||||||
|
|
||||||
hostNameF := flags.VarPF(
|
hostNameF := flags.VarPF(
|
||||||
textUnmarshalerFlag{&req.HostName},
|
&hostName,
|
||||||
"hostname", "h",
|
"hostname", "h",
|
||||||
"Name of this host, which will be the first host in the network",
|
"Name of this host, which will be the first host in the network",
|
||||||
)
|
)
|
||||||
@ -44,13 +47,23 @@ var subCmdNetworkCreate = subCmd{
|
|||||||
return fmt.Errorf("parsing flags: %w", err)
|
return fmt.Errorf("parsing flags: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.Name == "" ||
|
if *name == "" ||
|
||||||
req.Domain == "" ||
|
*domain == "" ||
|
||||||
!ipNetF.Changed ||
|
!ipNetF.Changed ||
|
||||||
!hostNameF.Changed {
|
!hostNameF.Changed {
|
||||||
return errors.New("--name, --domain, --ip-net, and --hostname are required")
|
return errors.New("--name, --domain, --ip-net, and --hostname are required")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
req := daemon.CreateNetworkRequest{
|
||||||
|
Name: *name,
|
||||||
|
Domain: *domain,
|
||||||
|
IPNet: ipNet.V,
|
||||||
|
HostName: hostName.V,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("req:%+v", req)
|
||||||
|
return nil
|
||||||
|
|
||||||
err := subCmdCtx.daemonRCPClient.Call(ctx, nil, "CreateNetwork", req)
|
err := subCmdCtx.daemonRCPClient.Call(ctx, nil, "CreateNetwork", req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("creating network: %w", err)
|
return fmt.Errorf("creating network: %w", err)
|
||||||
|
@ -48,6 +48,8 @@ func (ctx subCmdCtx) flagSet(withPassthrough bool) *pflag.FlagSet {
|
|||||||
passthroughStr = " [--] [args...]"
|
passthroughStr = " [--] [args...]"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO don't allow -h/--help flag to be set by sub-commands (or better,
|
||||||
|
// somehow check that a flag hasn't been set twice).
|
||||||
fmt.Fprintf(
|
fmt.Fprintf(
|
||||||
os.Stderr, "%s[-h|--help] [%s flags...]%s\n\n",
|
os.Stderr, "%s[-h|--help] [%s flags...]%s\n\n",
|
||||||
ctx.usagePrefix(), ctx.subCmd.name, passthroughStr,
|
ctx.usagePrefix(), ctx.subCmd.name, passthroughStr,
|
||||||
|
@ -32,6 +32,8 @@ type CreateHostOpts struct {
|
|||||||
// CanCreateHosts indicates that the bootstrap produced by CreateHost should
|
// CanCreateHosts indicates that the bootstrap produced by CreateHost should
|
||||||
// give the new host the ability to create new hosts as well.
|
// give the new host the ability to create new hosts as well.
|
||||||
CanCreateHosts bool
|
CanCreateHosts bool
|
||||||
|
|
||||||
|
// TODO add nebula cert tags
|
||||||
}
|
}
|
||||||
|
|
||||||
// Daemon presents all functionality required for client frontends to interact
|
// Daemon presents all functionality required for client frontends to interact
|
||||||
@ -85,6 +87,9 @@ type Daemon interface {
|
|||||||
// existing host, given the public key for that host. This is currently
|
// existing host, given the public key for that host. This is currently
|
||||||
// mostly useful for creating certs for mobile devices.
|
// mostly useful for creating certs for mobile devices.
|
||||||
//
|
//
|
||||||
|
// TODO replace this with CreateHostBootstrap, and the
|
||||||
|
// CreateNebulaCertificate RPC method can just pull cert out of that.
|
||||||
|
//
|
||||||
// Errors:
|
// Errors:
|
||||||
// - ErrHostNotFound
|
// - ErrHostNotFound
|
||||||
CreateNebulaCertificate(
|
CreateNebulaCertificate(
|
||||||
@ -685,6 +690,7 @@ func (d *daemon) CreateHost(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO if the ip is given, check that it's not already in use.
|
||||||
|
|
||||||
caSigningPrivateKey, err := getNebulaCASigningPrivateKey(
|
caSigningPrivateKey, err := getNebulaCASigningPrivateKey(
|
||||||
ctx, d.secretsStore,
|
ctx, d.secretsStore,
|
||||||
|
@ -11,6 +11,11 @@ var hostNameRegexp = regexp.MustCompile(`^[a-z][a-z0-9\-]*$`)
|
|||||||
// lowercase letters, numbers, and hyphens, and must start with a letter.
|
// lowercase letters, numbers, and hyphens, and must start with a letter.
|
||||||
type HostName string
|
type HostName string
|
||||||
|
|
||||||
|
// MarshalText casts the HostName to a byte string and returns it.
|
||||||
|
func (h HostName) MarshalText() ([]byte, error) {
|
||||||
|
return []byte(h), nil
|
||||||
|
}
|
||||||
|
|
||||||
// UnmarshalText parses and validates a HostName from a text string.
|
// UnmarshalText parses and validates a HostName from a text string.
|
||||||
func (h *HostName) UnmarshalText(b []byte) error {
|
func (h *HostName) UnmarshalText(b []byte) error {
|
||||||
if !hostNameRegexp.Match(b) {
|
if !hostNameRegexp.Match(b) {
|
||||||
|
Loading…
Reference in New Issue
Block a user