diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index d25355364..0fe0f2080 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -141,22 +141,24 @@ jobs: - name: Write out basic config run: | - cat << EOF > test.cfg + cat << EOF > test.yaml --- - - local-only: + version: 2 + local-only: + local: true - - control-service: - service: control + control-services: + - service: control filename: /tmp/receptor.sock - - work-command: - worktype: cat + work-commands: + - worktype: cat command: cat EOF - name: Run receptor (and wait a few seconds for it to boot) run: | - podman run --name receptor -d -v $PWD/test.cfg:/etc/receptor/receptor.conf:Z localhost/receptor + podman run --name receptor -d -v $PWD/test.yaml:/etc/receptor/receptor.yaml:Z localhost/receptor sleep 3 podman logs receptor diff --git a/.golangci.yml b/.golangci.yml index 492a94488..327c017d5 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -56,6 +56,7 @@ linters-settings: allow: - "$gostd" - "github.com/ansible/receptor/internal/version" + - "github.com/ansible/receptor/cmd" - "github.com/ansible/receptor/pkg" - "github.com/creack/pty" - "github.com/fsnotify/fsnotify" @@ -70,6 +71,8 @@ linters-settings: - "github.com/rogpeppe/go-internal/lockedfile" - "github.com/songgao/water" - "github.com/vishvananda/netlink" + - "github.com/spf13/viper" + - "github.com/spf13/cobra" - "k8s.io/api/core" - "k8s.io/apimachinery/pkg" - "k8s.io/client-go" diff --git a/Makefile b/Makefile index bee7b90d8..53ed8485c 100644 --- a/Makefile +++ b/Makefile @@ -117,10 +117,6 @@ build-all: ./cmd/receptor-cl && \ $(GO) build \ example/*.go && \ - $(GO) build \ - -o receptor \ - --tags no_backends,no_services,no_tls_config \ - ./cmd/receptor-cl && \ $(GO) build \ -o receptor \ -ldflags "-X 'github.com/ansible/receptor/internal/version.Version=$(VERSION)'" \ diff --git a/cmd/config.go b/cmd/config.go new file mode 100644 index 000000000..df371a1dc --- /dev/null +++ b/cmd/config.go @@ -0,0 +1,217 @@ +package cmd + +import ( + "fmt" + "os" + "reflect" + + "github.com/ansible/receptor/pkg/backends" + "github.com/ansible/receptor/pkg/certificates" + "github.com/ansible/receptor/pkg/controlsvc" + "github.com/ansible/receptor/pkg/logger" + "github.com/ansible/receptor/pkg/netceptor" + "github.com/ansible/receptor/pkg/services" + "github.com/ansible/receptor/pkg/types" + "github.com/ansible/receptor/pkg/workceptor" + "github.com/ghjm/cmdline" + "github.com/spf13/viper" +) + +type Initer interface { + Init() error +} + +type Preparer interface { + Prepare() error +} + +type Runer interface { + Run() error +} + +type ReceptorConfig struct { + // Used pointer structs to apply defaults to config + Node *types.NodeCfg + Trace logger.TraceCfg + LocalOnly backends.NullBackendCfg `mapstructure:"local-only"` + LogLevel *logger.LoglevelCfg `mapstructure:"log-level"` + ControlServices []*controlsvc.CmdlineConfigUnix `mapstructure:"control-services"` + TCPPeers []*backends.TCPDialerCfg `mapstructure:"tcp-peers"` + UDPPeers []*backends.UDPDialerCfg `mapstructure:"udp-peers"` + WSPeers []*backends.WebsocketDialerCfg `mapstructure:"ws-peers"` + TCPListeners []*backends.TCPListenerCfg `mapstructure:"tcp-listeners"` + UDPListeners []*backends.UDPListenerCfg `mapstructure:"udp-listeners"` + WSListeners []*backends.WebsocketListenerCfg `mapstructure:"ws-listeners"` + TLSClients []netceptor.TLSClientConfig `mapstructure:"tls-clients"` + TLSServer []netceptor.TLSServerConfig `mapstructure:"tls-servers"` + WorkCommands []workceptor.CommandWorkerCfg `mapstructure:"work-commands"` + WorkKubernetes []*workceptor.KubeWorkerCfg `mapstructure:"work-kubernetes"` + WorkSigning workceptor.SigningKeyPrivateCfg `mapstructure:"work-signing"` + WorkVerification workceptor.VerifyingKeyPublicCfg `mapstructure:"work-verification"` + IPRouters []services.IPRouterCfg + TCPClients []services.TCPProxyOutboundCfg `mapstructure:"tcp-clients"` + TCPServers []services.TCPProxyInboundCfg `mapstructure:"tcp-servers"` + UDPClients []services.TCPProxyInboundCfg `mapstructure:"udp-clients"` + UDPServers []services.TCPProxyInboundCfg `mapstructure:"udp-servers"` + UnixSocketClients []services.UnixProxyOutboundCfg `mapstructure:"unix-socket-clients"` + UnixSocketServers []services.UnixProxyInboundCfg `mapstructure:"unix-socket-servers"` +} + +type CertificatesConfig struct { + InitCA certificates.InitCAConfig `mapstructure:"cert-init"` + MakeReq []certificates.MakeReqConfig `mapstructure:"cert-makereqs"` + SignReq []certificates.SignReqConfig `mapstructure:"cert-signreqs"` +} + +func PrintPhaseErrorMessage(configName string, phase string, err error) { + fmt.Printf("ERROR: %s for %s on %s phase\n", err, configName, phase) +} + +func ParseConfigs(configFile string) (*ReceptorConfig, *CertificatesConfig, error) { + if configFile == "" && viper.ConfigFileUsed() == "" { + fmt.Fprintln(os.Stderr, "Could not locate config file (default is $HOME/receptor.yaml)") + os.Exit(1) + } + var receptorConfig ReceptorConfig + var certifcatesConfig CertificatesConfig + err := viper.Unmarshal(&receptorConfig) + if err != nil { + return nil, nil, err + } + + err = viper.Unmarshal(&certifcatesConfig) + if err != nil { + return nil, nil, err + } + + return &receptorConfig, &certifcatesConfig, nil +} + +func isConfigEmpty(v reflect.Value) bool { + isEmpty := true + for i := 0; i < v.NumField(); i++ { + if reflect.Value.IsZero(v.Field(i)) { + continue + } + isEmpty = false + } + + return isEmpty +} + +func RunConfigV2(v reflect.Value) { + phases := []string{"Init", "Prepare", "Run"} + + for _, phase := range phases { + for i := 0; i < v.NumField(); i++ { + if reflect.Value.IsZero(v.Field(i)) { + continue + } + + switch v.Field(i).Kind() { + case reflect.Slice: + for j := 0; j < v.Field(i).Len(); j++ { + RunPhases(phase, v.Field(i).Index(j)) + } + default: + RunPhases(phase, v.Field(i)) + } + } + } +} + +// RunPhases runs the appropriate function (Init, Prepare, Run) on a command. +func RunPhases(phase string, v reflect.Value) { + cmd := v.Interface() + var err error + + if phase == "Init" { + switch c := cmd.(type) { + case Initer: + err = c.Init() + if err != nil { + PrintPhaseErrorMessage(v.Type().Name(), phase, err) + } + default: + } + } + if phase == "Prepare" { + switch c := cmd.(type) { + case Preparer: + err = c.Prepare() + if err != nil { + PrintPhaseErrorMessage(v.Type().Name(), phase, err) + } + default: + } + } + if phase == "Run" { + switch c := cmd.(type) { + case Runer: + err = c.Run() + if err != nil { + PrintPhaseErrorMessage(v.Type().Name(), phase, err) + } + default: + } + } +} + +func RunConfigV1() { + cl := cmdline.NewCmdline() + cl.AddConfigType("node", "Specifies the node configuration of this instance", types.NodeCfg{}, cmdline.Required, cmdline.Singleton) + cl.AddConfigType("local-only", "Runs a self-contained node with no backend", backends.NullBackendCfg{}, cmdline.Singleton) + + // Add registered config types from imported modules + for _, appName := range []string{ + "receptor-version", + "receptor-logging", + "receptor-tls", + "receptor-certificates", + "receptor-control-service", + "receptor-command-service", + "receptor-ip-router", + "receptor-proxies", + "receptor-backends", + "receptor-workers", + } { + cl.AddRegisteredConfigTypes(appName) + } + + osArgs := os.Args[1:] + + err := cl.ParseAndRun(osArgs, []string{"Init", "Prepare", "Run"}, cmdline.ShowHelpIfNoArgs) + if err != nil { + fmt.Printf("Error: %s\n", err) + os.Exit(1) + } + if cl.WhatRan() != "" { + // We ran an exclusive command, so we aren't starting any back-ends + os.Exit(0) + } + + configPath := "" + for i, arg := range osArgs { + if arg == "--config" || arg == "-c" { + if len(osArgs) > i+1 { + configPath = osArgs[i+1] + } + + break + } + } + + // only allow reloading if a configuration file was provided. If ReloadCL is + // not set, then the control service reload command will fail + if configPath != "" { + // create closure with the passed in args to be ran during a reload + reloadParseAndRun := func(toRun []string) error { + return cl.ParseAndRun(osArgs, toRun) + } + err = controlsvc.InitReload(configPath, reloadParseAndRun) + if err != nil { + fmt.Printf("Error: %s\n", err) + os.Exit(1) + } + } +} diff --git a/cmd/defaults.go b/cmd/defaults.go new file mode 100644 index 000000000..93d568c02 --- /dev/null +++ b/cmd/defaults.go @@ -0,0 +1,130 @@ +package cmd + +import "github.com/ansible/receptor/pkg/types" + +func SetTCPListenerDefaults(config *ReceptorConfig) { + for _, listener := range config.TCPListeners { + if listener.Cost == 0 { + listener.Cost = 1.0 + } + if listener.BindAddr == "" { + listener.BindAddr = "0.0.0.0" + } + } +} + +func SetUDPListenerDefaults(config *ReceptorConfig) { + for _, listener := range config.UDPListeners { + if listener.Cost == 0 { + listener.Cost = 1.0 + } + if listener.BindAddr == "" { + listener.BindAddr = "0.0.0.0" + } + } +} + +func SetWSListenerDefaults(config *ReceptorConfig) { + for _, listener := range config.WSListeners { + if listener.Cost == 0 { + listener.Cost = 1.0 + } + if listener.BindAddr == "" { + listener.BindAddr = "0.0.0.0" + } + if listener.Path == "" { + listener.BindAddr = "/" + } + } +} + +func SetUDPPeerDefaults(config *ReceptorConfig) { + for _, peer := range config.TCPPeers { + if peer.Cost == 0 { + peer.Cost = 1.0 + } + + if !peer.Redial { + peer.Redial = true + } + } +} + +func SetTCPPeerDefaults(config *ReceptorConfig) { + for _, peer := range config.TCPPeers { + if peer.Cost == 0 { + peer.Cost = 1.0 + } + + if !peer.Redial { + peer.Redial = true + } + } +} + +func SetWSPeerDefaults(config *ReceptorConfig) { + for _, peer := range config.WSPeers { + if peer.Cost == 0 { + peer.Cost = 1.0 + } + + if !peer.Redial { + peer.Redial = true + } + } +} + +func SetCmdlineUnixDefaults(config *ReceptorConfig) { + for _, service := range config.ControlServices { + if service.Permissions == 0 { + service.Permissions = 0o600 + } + + if service.Service == "" { + service.Service = "control" + } + } +} + +func SetLogLevelDefaults(config *ReceptorConfig) { + if config.LogLevel == nil { + return + } + if config.LogLevel.Level == "" { + config.LogLevel.Level = "error" + } +} + +func SetNodeDefaults(config *ReceptorConfig) { + if config.Node == nil { + config.Node = &types.NodeCfg{} + } + if config.Node.DataDir == "" { + config.Node.DataDir = "/tmp/receptor" + } +} + +func SetKubeWorkerDefaults(config *ReceptorConfig) { + for _, worker := range config.WorkKubernetes { + if worker.AuthMethod == "" { + worker.AuthMethod = "incluster" + } + + if worker.StreamMethod == "" { + worker.StreamMethod = "logger" + } + } +} + +func SetConfigDefaults(config *ReceptorConfig) { + SetTCPListenerDefaults(config) + SetUDPListenerDefaults(config) + SetWSListenerDefaults(config) + SetTCPPeerDefaults(config) + SetUDPPeerDefaults(config) + SetWSPeerDefaults(config) + SetCmdlineUnixDefaults(config) + SetLogLevelDefaults(config) + SetNodeDefaults(config) + SetKubeWorkerDefaults(config) +} diff --git a/cmd/receptor-cl/receptor.go b/cmd/receptor-cl/receptor.go index aceb7cc42..3be3fa12b 100644 --- a/cmd/receptor-cl/receptor.go +++ b/cmd/receptor-cl/receptor.go @@ -1,106 +1,41 @@ package main import ( - "context" - "crypto/tls" "fmt" "os" - "sync" + "github.com/ansible/receptor/cmd" _ "github.com/ansible/receptor/internal/version" _ "github.com/ansible/receptor/pkg/backends" _ "github.com/ansible/receptor/pkg/certificates" - "github.com/ansible/receptor/pkg/controlsvc" "github.com/ansible/receptor/pkg/netceptor" _ "github.com/ansible/receptor/pkg/services" - "github.com/ansible/receptor/pkg/types" - "github.com/ghjm/cmdline" ) -type nullBackendCfg struct{} - -// make the nullBackendCfg object be usable as a do-nothing Backend. -func (cfg nullBackendCfg) Start(_ context.Context, _ *sync.WaitGroup) (chan netceptor.BackendSession, error) { - return make(chan netceptor.BackendSession), nil -} - -// Run runs the action, in this case adding a null backend to keep the wait group alive. -func (cfg nullBackendCfg) Run() error { - err := netceptor.MainInstance.AddBackend(&nullBackendCfg{}) - if err != nil { - return err - } - - return nil -} - -func (cfg *nullBackendCfg) GetAddr() string { - return "" -} - -func (cfg *nullBackendCfg) GetTLS() *tls.Config { - return nil -} - -func (cfg nullBackendCfg) Reload() error { - return cfg.Run() -} - func main() { - cl := cmdline.NewCmdline() - cl.AddConfigType("node", "Specifies the node configuration of this instance", types.NodeCfg{}, cmdline.Required, cmdline.Singleton) - cl.AddConfigType("local-only", "Runs a self-contained node with no backend", nullBackendCfg{}, cmdline.Singleton) - - // Add registered config types from imported modules - for _, appName := range []string{ - "receptor-version", - "receptor-logging", - "receptor-tls", - "receptor-certificates", - "receptor-control-service", - "receptor-command-service", - "receptor-ip-router", - "receptor-proxies", - "receptor-backends", - "receptor-workers", - } { - cl.AddRegisteredConfigTypes(appName) - } - - osArgs := os.Args[1:] + var legacy bool + newArgs := []string{} + for _, arg := range os.Args { + if arg == "--legacy" { + legacy = true - err := cl.ParseAndRun(osArgs, []string{"Init", "Prepare", "Run"}, cmdline.ShowHelpIfNoArgs) - if err != nil { - fmt.Printf("Error: %s\n", err) - os.Exit(1) - } - if cl.WhatRan() != "" { - // We ran an exclusive command, so we aren't starting any back-ends - os.Exit(0) + continue + } + newArgs = append(newArgs, arg) } - configPath := "" - for i, arg := range osArgs { - if arg == "--config" || arg == "-c" { - if len(osArgs) > i+1 { - configPath = osArgs[i+1] - } + os.Args = newArgs - break - } + if !legacy { + cmd.Execute() + } else { + fmt.Println("Running old cli/config") + cmd.RunConfigV1() } - // only allow reloading if a configuration file was provided. If ReloadCL is - // not set, then the control service reload command will fail - if configPath != "" { - // create closure with the passed in args to be ran during a reload - reloadParseAndRun := func(toRun []string) error { - return cl.ParseAndRun(osArgs, toRun) - } - err = controlsvc.InitReload(configPath, reloadParseAndRun) - if err != nil { - fmt.Printf("Error: %s\n", err) - os.Exit(1) + for _, arg := range os.Args { + if arg == "--help" { + os.Exit(0) } } diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 000000000..400ffe08e --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,85 @@ +package cmd + +import ( + "fmt" + "os" + "reflect" + + receptorVersion "github.com/ansible/receptor/internal/version" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var ( + cfgFile string + version bool +) + +// rootCmd represents the base command when called without any subcommands. +var rootCmd = &cobra.Command{ + Use: "receptor", + Short: "Run a receptor instance.", + Long: ` + Receptor is an overlay network intended to ease the distribution of work across a large and dispersed collection of workers. + Receptor nodes establish peer-to-peer connections with each other via existing networks. + Once connected, the receptor mesh provides datagram (UDP-like) and stream (TCP-like) capabilities to applications, as well as robust unit-of-work handling with resiliency against transient network failures.`, + Run: func(cmd *cobra.Command, args []string) { + if version { + fmt.Println(receptorVersion.Version) + os.Exit(0) + } + receptorConfig, certifcatesConfig, err := ParseConfigs(cfgFile) + if err != nil { + fmt.Printf("unable to decode into struct, %v", err) + os.Exit(1) + } + + isEmptyReceptorConfig := isConfigEmpty(reflect.ValueOf(*receptorConfig)) + + RunConfigV2(reflect.ValueOf(*certifcatesConfig)) + if isEmptyReceptorConfig { + fmt.Println("empty receptor config, skipping...") + os.Exit(0) + } + + SetConfigDefaults(receptorConfig) + RunConfigV2(reflect.ValueOf(*receptorConfig)) + }, +} + +func Execute() { + err := rootCmd.Execute() + if err != nil { + os.Exit(1) + } +} + +func init() { + cobra.OnInitialize(initConfig) + + rootCmd.Flags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/receptor.yaml)") + rootCmd.Flags().BoolVar(&version, "version", false, "Show the Receptor version") +} + +var FindMe = true + +// initConfig reads in config file and ENV variables if set. +func initConfig() { + if cfgFile != "" { + viper.SetConfigFile(cfgFile) + } else { + home, err := os.UserHomeDir() + cobra.CheckErr(err) + + viper.AddConfigPath(home) + viper.SetConfigType("yaml") + viper.SetConfigName("receptor") + } + + viper.AutomaticEnv() + + err := viper.ReadInConfig() + if err == nil { + fmt.Fprintln(os.Stdout, "Using config file:", viper.ConfigFileUsed()) + } +} diff --git a/docs/source/developer_guide.rst b/docs/source/developer_guide.rst index 7650f2e90..b4e1c80e0 100644 --- a/docs/source/developer_guide.rst +++ b/docs/source/developer_guide.rst @@ -98,8 +98,8 @@ As an example, in tcp.go .. code-block:: yaml - - tcp-peer: - address: localhost:2222 + tcp-peers: + - address: localhost:2222 ``RegisterConfigTypeForApp`` tells the cmdline parser that "tcp-peer" is mapped to the ``TCPDialerCfg{}`` structure. diff --git a/docs/source/getting_started_guide/creating_a_basic_network.rst b/docs/source/getting_started_guide/creating_a_basic_network.rst index a6be11249..c3daef241 100644 --- a/docs/source/getting_started_guide/creating_a_basic_network.rst +++ b/docs/source/getting_started_guide/creating_a_basic_network.rst @@ -6,13 +6,13 @@ Creating a basic 3-node network ############################### In this section, we will create a three-node network. -The three nodes are: foo, bar, and mal. +The three nodes are: foo, bar, and baz. -`foo -> bar <- mal` +`foo -> bar <- baz` -foo and mal are directly connected to bar with TCP connections. +foo and baz are directly connected to bar with TCP connections. -foo can reach mal by sending network packets through bar. +foo can reach baz by sending network packets through bar. *********************** Receptor configurations @@ -25,18 +25,19 @@ Receptor configurations .. code-block:: yaml --- - - node: - id: foo + version: 2 + node: + id: foo - - control-service: - service: control + control-services: + - service: control filename: /tmp/foo.sock - - tcp-peer: - address: localhost:2222 - redial: true + tcp-peers: + - address: localhost:2222 - - log-level: debug + log-level: + level: debug ... @@ -45,37 +46,40 @@ Receptor configurations .. code-block:: yaml --- - - node: - id: bar + version: 2 + node: + id: bar - - control-service: - service: control + control-services: + - service: control filename: /tmp/bar.sock - - tcp-listener: - port: 2222 + tcp-listeners: + - port: 2222 - - log-level: debug + log-level: + level: debug ... -``mal.yml`` +``baz.yml`` .. code-block:: yaml --- - - node: - id: mal + version: 2 + node: + id: baz - - control-service: - service: control - filename: /tmp/mal.sock + control-services: + - service: control + filename: /tmp/baz.sock - - tcp-peer: - address: localhost:2222 - redial: true + tcp-peers: + - address: localhost:2222 - - log-level: debug + log-level: + level: debug - work-command: workType: echo @@ -97,7 +101,7 @@ Receptor configurations .. code-block:: bash - ./receptor --config mal.yml + ./receptor --config baz.yml .. seealso:: diff --git a/docs/source/getting_started_guide/index.rst b/docs/source/getting_started_guide/index.rst index 30017aa72..65165a26c 100644 --- a/docs/source/getting_started_guide/index.rst +++ b/docs/source/getting_started_guide/index.rst @@ -2,12 +2,9 @@ Getting started with Receptor ############################# -Receptor is an overlay network intended to ease the distribution of work across -a large and dispersed collection of workers. Receptor nodes establish peer-to- -peer connections with each other via existing networks. Once connected, the re- -ceptor mesh provides datagram (UDP-like) and stream (TCP-like) capabilities to -applications, as well as robust unit-of-work handling with resiliency against -transient network failures. +Receptor is an overlay network that distributes work across large and dispersed collections of worker nodes. +Receptor nodes establish peer-to-peer connections through existing networks. +Once connected, the Receptor mesh provides datagram (UDP-like) and stream (TCP-like) capabilities to applications, as well as robust unit-of-work handling with resiliency against transient network failures. .. image:: mesh.png diff --git a/docs/source/user_guide/basic_usage.rst b/docs/source/user_guide/basic_usage.rst index 7ef340a1e..26ceab468 100644 --- a/docs/source/user_guide/basic_usage.rst +++ b/docs/source/user_guide/basic_usage.rst @@ -5,22 +5,21 @@ Using Receptor :local: -Configuring Receptor with the CLI ------------------------------------ - -Run the following command in a terminal to start a node called `foo`, - -.. code-block:: bash - - receptor --node id=foo --local-only --log-level Debug - -The log shows the receptor node started successfully - -``INFO 2021/07/22 22:40:36 Initialization complete`` - -Supported log levels, in increasing verbosity, are ``Error``, ``Warning``, ``Info`` and ``Debug``. The default level is ``Info``. - -Note: stop the receptor process with ``ctrl-c`` +Using the Receptor CLI +---------------------- + +.. list-table:: Persistent Flags + :header-rows: 1 + :widths: auto + + * - Action + - Description + * - ``--config `` + - Loads configuration options from a YAML file. + * - ``--version`` + - Display the Receptor version. + * - ``--help`` + - Display this help .. _configuring_receptor_with_a_config_file: @@ -32,13 +31,15 @@ Receptor can be configured on the command-line, exemplified above, or via a yaml .. code-block:: yaml --- - - node: - id: foo + version: 2 + node: + id: foo - - local-only + local-only: + local: true - - log-level: - level: Debug + log-level: + level: Debug Start receptor using the config file diff --git a/docs/source/user_guide/configuration_options.rst b/docs/source/user_guide/configuration_options.rst index 90693f580..3e64bc50b 100644 --- a/docs/source/user_guide/configuration_options.rst +++ b/docs/source/user_guide/configuration_options.rst @@ -2,78 +2,48 @@ Receptor Configuration Options ============================== ---------------------- -Receptor command line ---------------------- +^^^^^^^^^^^^^^^^ +Control Services +^^^^^^^^^^^^^^^^ -Command line arguments use the following syntax: ``receptor [-- [= ...] ...]`` - -The possible options for ```` are listed below. Parameters for actions are listed in their own section. - ----------------- -Persistent Flags ----------------- - -.. list-table:: Persistent Flags - :header-rows: 1 - :widths: auto - - * - Action - - Description - * - ``--bash-completion`` - - Generates a completion script for the Bash shell. - * - ``--config `` - - Loads additional configuration options from a YAML file. - * - ``--control-service`` - - Runs a control service. - * - ``--help`` - - Show this help - * - ``--local-only`` - - Runs a self-contained node with no backend. - * - ``--log-level`` - - Specifies the verbosity level for command output. - * - ``--node`` - - Specifies the node configuration of this instance. This parameter is required. - * - ``--trace`` - - Enables packet tracing output. - * - ``--version`` - - Display the Receptor version. - -^^^^^^^^^^^^^^^ -Bash completion -^^^^^^^^^^^^^^^ - -To add Receptor auto-completion to the bash session: ``. <(receptor --bash-completion)`` - -^^^^^^^^^^^^^^^ -Control Service -^^^^^^^^^^^^^^^ - -.. list-table:: Control Service +.. list-table:: Control Service (List item) :header-rows: 1 :widths: auto * - Parameter - - Description - - Default value - * - ``filename=`` + - Description + - Default value + - Type + * - ``filename`` - Specifies the filename of a local Unix socket to bind to the service. - No default value. - * - ``permissions=`` + - string + * - ``permissions`` - Socket file permissions - 0600 - * - ``service=`` + - int + * - ``service`` - Receptor service name to listen on - control - * - ``tls=`` + - string + * - ``tls`` - Name of TLS server config for the Receptor listener - No default value. - * - ``tcplisten=`` + - string + * - ``tcplisten`` - Local TCP port or host:port to bind to the control service - No default value. - * - ``tcptls=`` + - string + * - ``tcptls`` - Name of TLS server config for the TCP listener - No default value. + - string + +.. code-block:: yaml + + control-services: + - service: foo + filename: /tmp/foo.sock ^^^^^^^^^ Log level @@ -86,9 +56,16 @@ Log level * - Parameter - Description - Default value - * - ``level=`` + - Type + * - ``level`` - Log level: Error, Warning, Info or Debug - Error + - string + +.. code-block:: yaml + + log-level: + level: debug ^^^^ Node @@ -101,162 +78,187 @@ Node * - Parameter - Description - Default value - * - ``id=`` + - Type + * - ``id`` - Node ID - local hostname - * - ``datadir=`` + - string + * - ``datadir`` - Directory in which to store node data - /tmp/receptor - * - ``firewallrules=`` + - string + * - ``firewallrules`` - Firewall Rules. See :ref:`firewall_rules` for syntax - No default value. - * - ``maxidleconnectiontimeout=`` + - JSON + * - ``maxidleconnectiontimeout`` - Max duration with no traffic before a backend connection is timed out and refreshed - No default value. + - string + + +.. code-block:: yaml + + node: + id: foo ------------------------------------------ Configure resources used by other commands ------------------------------------------ -.. list-table:: Configure resources used by other commands - :header-rows: 1 - :widths: auto - - * - Action - - Description - * - ``--tls-client`` - - Define a TLS client configuration - * - ``--tls-server`` - - Define a TLS server configuration - -^^^^^^^^^^ -TLS Client -^^^^^^^^^^ +^^^^^^^^^^^ +TLS Clients +^^^^^^^^^^^ -.. list-table:: TLS Client +.. list-table:: TLS Client (List item) :header-rows: 1 :widths: auto * - Parameter - Description - Default value - * - ``cert=`` + - Type + * - ``cert`` - Client certificate filename (required) - No default value. - * - ``insecureskipverify=`` + - string + * - ``insecureskipverify`` - Accept any server cert - false - * - ``key=`` + - bool + * - ``key`` - Client private key filename (required) - No default value. - * - ``mintls13=`` + - string + * - ``mintls13`` - Set minimum TLS version to 1.3. Otherwise the minimum is 1.2 - false - * - ``name=`` + - bool + * - ``name`` - Name of this TLS client configuration (required) - No default value. - * - ``pinnedservercert=<[]string (may be repeated)>`` + - string + * - ``pinnedservercert`` - Pinned fingerprint of required server certificate - No default value. - * - ``rootcas=`` + - list of string + * - ``rootcas`` - Root CA bundle to use instead of system trust - No default value. - * - ``skipreceptornamescheck=`` + - string + * - ``skipreceptornamescheck`` - if true, skip verifying ReceptorNames OIDs in certificate at startup - No default value. + - bool -^^^^^^^^^^ -TLS Server -^^^^^^^^^^ +.. code-block:: yaml + + tls-clients: + - name: tlsclient + cert: /tmp/certs/foo.crt + key: /tmp/certs/key.crt -.. list-table:: TLS Server +^^^^^^^^^^^ +TLS Servers +^^^^^^^^^^^ + +.. list-table:: TLS Server (List item) :header-rows: 1 :widths: auto * - Parameter - Description - Default value - * - ``cert=`` + - Type + * - ``cert`` - Server certificate filename (required) - No default value. - * - ``clientcas=`` + - string + * - ``clientcas`` - Filename of CA bundle to verify client certs with - No default value. - * - ``key=`` + - string + * - ``key`` - Server private key filename (required) - No default value. - * - ``mintls13=`` + - string + * - ``mintls13`` - Set minimum TLS version to 1.3. Otherwise the minimum is 1.2 - false - * - ``name=`` + - bool + * - ``name`` - Name of this TLS server configuration (required) - No default value. - * - ``pinnedclientcert=<[]string (may be repeated)>`` + - string + * - ``pinnedclientcert`` - Pinned fingerprint of required client certificate - No default value. - * - ``requireclientcert=`` + - list of string + * - ``requireclientcert`` - Require client certificates - false - * - ``skipreceptornamescheck=`` + - bool + * - ``skipreceptornamescheck`` - Skip verifying ReceptorNames OIDs in certificate at startup - false + - bool ----------------------------------------------------------------------- -Commands to configure back-ends, which connect Receptor nodes together ----------------------------------------------------------------------- +.. code-block:: yaml -.. list-table:: Control Service - :header-rows: 1 - :widths: auto + tls-servers: + - name: tlsserver + cert: /tmp/certs/foo.crt + key: /tmp/certs/key.crt - * - Action - - Description - * - ``--tcp-listener`` - - Run a backend listener on a TCP port - * - ``--tcp-peer`` - - Make an outbound backend connection to a TCP peer - * - ``--udp-listener`` - - Run a backend listener on a UDP port - * - ``--udp-peer`` - - Make an outbound backend connection to a UDP peer - * - ``--ws-listener`` - - Run an http server that accepts websocket connections - * - ``--ws-peer`` - - Connect outbound to a websocket peer +---------------------------------------------------------------------- +Options to configure back-ends, which connect Receptor nodes together +---------------------------------------------------------------------- -^^^^^^^^^^^^ -TCP listener -^^^^^^^^^^^^ +^^^^^^^^^^^^^ +TCP listeners +^^^^^^^^^^^^^ -.. list-table:: TCP Listener +.. list-table:: TCP Listener (List item) :header-rows: 1 :widths: auto * - Parameter - Description - Default value - * - ``allowedpeers=<[]string (may be repeated)>`` + - Type + * - ``allowedpeers`` - Peer node IDs to allow via this connection - No default value. - * - ``bindaddr=`` + - list of string + * - ``bindaddr`` - Local address to bind to - 0.0.0.0 - * - ``cost=`` + - string + * - ``cost`` - Connection cost (weight) - 1.0 - * - ``nodecost=`` + - float64 + * - ``nodecost`` - Per-node costs - No default value. - * - ``port=`` + - float64 + * - ``port`` - Local TCP port to listen on (required) - No default value. - * - ``tls=`` + - int + * - ``tls`` - Name of TLS server config - No default value. + - string -^^^^^^^^ -TCP Peer -^^^^^^^^ +.. code-block:: yaml + + tcp-listeners: + - port: 2223 + +^^^^^^^^^ +TCP Peers +^^^^^^^^^ .. list-table:: TCP Peer :header-rows: 1 @@ -265,54 +267,77 @@ TCP Peer * - Parameter - Description - Default value - * - ``address=`` + - Type + * - ``address`` - Remote address (Host:Port) to connect to (required) - No default value. - * - ``allowedpeers=<[]string (may be repeated)>`` + - string + * - ``allowedpeers`` - Peer node IDs to allow via this connection - No default value. - * - ``cost=`` + - list of string + * - ``cost`` - Connection cost (weight) - 1.0 - * - ``redial=`` + - float64 + * - ``redial`` - Keep redialing on lost connection - true - * - ``tls=`` + - bool + * - ``tls`` - Name of TLS client configuration - No default value. + - string + +.. code-block:: yaml + + tcp-peers: + - address: localhost:2223 -^^^^^^^^^^^^ -UDP Listener -^^^^^^^^^^^^ -.. list-table:: UDP Listener +^^^^^^^^^^^^^ +UDP Listeners +^^^^^^^^^^^^^ + +.. list-table:: UDP Listener (List item) :header-rows: 1 :widths: auto * - Parameter - Description - Default value - * - ``allowedpeers=<[]string (may be repeated)>`` + - Type + * - ``allowedpeers`` - Peer node IDs to allow via this connection - No default value. - * - ``bindaddr=`` + - list of string + * - ``bindaddr`` - Local address to bind to - 0.0.0.0 - * - ``cost=`` + - string + * - ``cost`` - Connection cost (weight) - 1.0 - * - ``nodecost=`` + - float64 + * - ``nodecost`` - Per-node costs - No default value. - * - ``port=`` + - float64 + * - ``port`` - Local UDP port to listen on (required) - No default value. + - int -^^^^^^^^ -UDP Peer -^^^^^^^^ +.. code-block:: yaml -.. list-table:: UDP Peer + udp-listeners: + - port: 2223 + +^^^^^^^^^ +UDP Peers +^^^^^^^^^ + +.. list-table:: UDP Peer (List item) :header-rows: 1 :widths: auto @@ -332,9 +357,14 @@ UDP Peer - Keep redialing on lost connection - true -^^^^^^^^^^^^^^^^^^ -Websocket Listener -^^^^^^^^^^^^^^^^^^ +.. code-block:: yaml + + udp-peers: + - address: localhost:2223 + +^^^^^^^^^^^^^^^^^^^ +Websocket Listeners +^^^^^^^^^^^^^^^^^^^ .. list-table:: Websocket Listener :header-rows: 1 @@ -343,322 +373,378 @@ Websocket Listener * - Parameter - Description - Default value - * - ``allowedpeers=<[]string (may be repeated)>`` + - Type + * - ``allowedpeers`` - Peer node IDs to allow via this connection - No default value. - * - ``bindaddr=`` + - list of string + * - ``bindaddr`` - Local address to bind to - 0.0.0.0 - * - ``cost=`` + - string + * - ``cost`` - Connection cost (weight) - 1.0 - * - ``nodecost=`` + - float64 + * - ``nodecost`` - Per-node costs - No default value. - * - ``path=`` + - float64 + * - ``path`` - URI path to the websocket server - \/ - * - ``port=`` + - string + * - ``port`` - Local TCP port to run http server on (required) - No default value. - * - ``tls=`` + - int + * - ``tls`` - Name of TLS server configuration - No default value. + - string + +.. code-block:: yaml -^^^^^^^^^^^^^^ -Websocket Peer -^^^^^^^^^^^^^^ + ws-listeners: + - port: 27198 + +^^^^^^^^^^^^^^^ +Websocket Peers +^^^^^^^^^^^^^^^ -.. list-table:: Websocket Peer +.. list-table:: Websocket Peer (List item) :header-rows: 1 :widths: auto * - Parameter - Description - Default value - * - ``address=`` + - Type + * - ``address`` - URL to connect to (required) - No default value. - * - ``allowedpeers=<[]string (may be repeated)>`` + - string + * - ``allowedpeers`` - Peer node IDs to allow via this connection - No default value. - * - ``cost=`` + - list of string + * - ``cost`` - Connection cost (weight) - 1.0 - * - ``extraheader=`` + - float64 + * - ``extraheader`` - Sends extra HTTP header on initial connection - No default value. - * - ``redial=`` + - string + * - ``redial`` - Keep redialing on lost connection - true - * - ``tls=`` + - bool + * - ``tls`` - Name of TLS client config - No default value. + - string + +.. code-block:: yaml + + ws-peers: + - address: ws://localhost:27198 ------------------------------------------------------- Configure services that run on top of the Receptor mesh ------------------------------------------------------- -.. list-table:: Configure services that run on top of the Receptor mesh - :header-rows: 1 - :widths: auto - - * - Action - - Description - * - ``--command-service`` - - Run an interactive command via a Receptor service - * - ``--ip-router`` - - Run an IP router using a tun interface - * - ``--tcp-client`` - - Listen on a Receptor service and forward via TCP - * - ``--tcp-server`` - - Listen for TCP and forward via Receptor - * - ``--udp-client`` - - Listen on a Receptor service and forward via UDP - * - ``--udp-server`` - - Listen for UDP and forward via Receptor - * - ``--unix-socket-client`` - - Listen via Receptor and forward to a Unix socket - * - ``--unix-socket-server`` - - Listen on a Unix socket and forward via Receptor - -^^^^^^^^^^^^^^^ -Command Service -^^^^^^^^^^^^^^^ - -.. list-table:: Command Service - :header-rows: 1 - :widths: auto - - * - Parameter - - Description - - Default value - * - ``command=`` - - Command to execute on a connection (required) - - No default value. - * - ``service=`` - - Receptor service name to bind to (required) - - No default value. - * - ``tls=`` - - Name of TLS server config - - No default value. - -^^^^^^^^^ -IP Router -^^^^^^^^^ +^^^^^^^^^^ +IP Routers +^^^^^^^^^^ -.. list-table:: IP Router +.. list-table:: IP Router (List item) :header-rows: 1 :widths: auto * - Parameter - Description - Default value - * - ``interface=`` + - Type + * - ``interface`` - Name of the local tun interface - No default value. - * - ``localnet=`` + - string + * - ``localnet`` - Local /30 CIDR address (required) - No default value. - * - ``networkname=`` + - string + * - ``networkname`` - Name of this network and service. (required) - No default value. - * - ``routes=`` + - string + * - ``routes`` - Comma separated list of CIDR subnets to advertise - No default value. + - string -^^^^^^^^^^ -TCP Client -^^^^^^^^^^ +.. code-block:: yaml + + ip-routers: + - networkname: hello + localnet: abc + +^^^^^^^^^^^ +TCP Clients +^^^^^^^^^^^ -.. list-table:: TCP Client +.. list-table:: TCP Client (List item) :header-rows: 1 :widths: auto * - Parameter - Description - Default value - * - ``address=`` + * - ``address`` - Address for outbound TCP connection (required) - No default value. - * - ``service=`` + * - ``service`` - Receptor service name to bind to (required) - No default value. - * - ``tlsserver=`` + * - ``tlsserver`` - Name of TLS server config for the Receptor service - No default value. - * - ``tlsclient=`` + * - ``tlsclient`` - Name of TLS client config for the TCP connection - No default value. -^^^^^^^^^^ -TCP Server -^^^^^^^^^^ +.. code-block:: yaml + + tcp-clients: + - address: localhost:2223 + service: foo -.. list-table:: TCP Server +^^^^^^^^^^^ +TCP Servers +^^^^^^^^^^^ + +.. list-table:: TCP Server (List item) :header-rows: 1 :widths: auto * - Parameter - Description - Default value - * - ``bindaddr=`` + - Type + * - ``bindaddr`` - Address to bind TCP listener to - 0.0.0.0 - * - ``port=`` + - string + * - ``port`` - Local TCP port to bind to (required) - No default value. - * - ``remotenode=`` + - int + * - ``remotenode`` - Receptor node to connect to (required) - No default value. - * - ``remoteservice=`` + - string + * - ``remoteservice`` - Receptor service name to connect to (required) - No default value. - * - ``tlsserver=`` + - string + * - ``tlsserver`` - Name of TLS server config for the TCP listener - No default value. - * - ``tlsclient=`` + - string + * - ``tlsclient`` - Name of TLS client config for the Receptor connection - No default value. + - string + +.. code-block:: yaml + + tcp-servers: + - port: 2223 + remotenode: foo + remoteservice: foo -^^^^^^^^^^ -UDP Client -^^^^^^^^^^ -.. list-table:: UDP Client +^^^^^^^^^^^ +UDP Clients +^^^^^^^^^^^ + +.. list-table:: UDP Client (List item) :header-rows: 1 :widths: auto * - Parameter - Description - Default value - * - ``address=`` + - Type + * - ``address`` - Address for outbound UDP connection (required) - No default value. - * - ``service=`` + - string + * - ``service`` - Receptor service name to bind to (required) - No default value. + - string -^^^^^^^^^^ -UDP Server -^^^^^^^^^^ +.. code-block:: yaml -.. list-table:: UDP Server + udp-clients: + - address: localhost:2223 + service: foo + + +^^^^^^^^^^^ +UDP Servers +^^^^^^^^^^^ + +.. list-table:: UDP Server (List item) :header-rows: 1 :widths: auto * - Parameter - Description - Default value - * - ``bindaddr=`` + - Type + * - ``bindaddr`` - Address to bind UDP listener to - 0.0.0.0 - * - ``port=`` + - string + * - ``port`` - Local UDP port to bind to (required) - No default value. - * - ``remotenode=`` + - int + * - ``remotenode`` - Receptor node to connect to (required) - No default value. - * - ``remoteservice=`` + - string + * - ``remoteservice`` - Receptor service name to connect to (required) - No default value. + - string + +.. code-block:: yaml -^^^^^^^^^^^^^^^^^^ -Unix Socket Client -^^^^^^^^^^^^^^^^^^ + udp-servers: + - address: 2223 + remotenode: foo + remoteservice: foo -.. list-table:: Unix Socket Client + +^^^^^^^^^^^^^^^^^^^ +Unix Socket Clients +^^^^^^^^^^^^^^^^^^^ + +.. list-table:: Unix Socket Client (List item) :header-rows: 1 :widths: auto * - Parameter - Description - Default value - * - ``filename=`` + - Type + * - ``filename`` - Socket filename, which must already exist (required) - No default value. - * - ``service=`` + - string + * - ``service`` - Receptor service name to bind to (required) - No default value. - * - ``tls=`` + - string + * - ``tls`` - Name of TLS server config for the Receptor connection - No default value. + - string + +.. code-block:: yaml + + unix-socket-clients: + - filename: /tmp/foo.sock + service: foo + -^^^^^^^^^^^^^^^^^^ -Unix Socket Server -^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^ +Unix Socket Servers +^^^^^^^^^^^^^^^^^^^ -.. list-table:: Unix Socket Server +.. list-table:: Unix Socket Server (List item) :header-rows: 1 :widths: auto * - Parameter - Description - Default value - * - ``filename=`` + - Type + * - ``filename`` - Socket filename, which will be overwritten (required) - No default value. - * - ``permissions=`` + - string + * - ``permissions`` - Socket file permissions - 0600 - * - ``remotenode=`` + - int + * - ``remotenode`` - Receptor node to connect to (required) - No default value. - * - ``remoteservice=`` + - string + * - ``remoteservice`` - Receptor service name to connect to (required) - No default value. - * - ``tls=`` + - string + * - ``tls`` - Name of TLS client config for the Receptor connection - No default value. + - string + +.. code-block:: yaml + + unix-socket-servers: + - filename: /tmp/foo.sock + remotenode: foo + remoteservice: foo + -------------------------------------------- Configure workers that process units of work -------------------------------------------- -.. list-table:: Configure workers that process units of work - :header-rows: 1 - :widths: auto - - * - Action - - Description - * - ``--work-command`` - - Run a worker using an external command - * - ``--work-kubernetes`` - - Run a worker using Kubernetes - * - ``--work-python`` - - Run a worker using a Python plugin - [DEPRECATION WARNING] This option is not currently being used. This feature will be removed from receptor in a future release - * - ``--work-signing`` - - Private key to sign work submissions - * - ``--work-verification`` - - Public key to verify work submissions - -^^^^^^^^^^^^ -Work Command -^^^^^^^^^^^^ +^^^^^^^^^^^^^ +Work Commands +^^^^^^^^^^^^^ -.. list-table:: Work Command +.. list-table:: Work Command (List item) :header-rows: 1 :widths: auto * - Parameter - Description - Default value - * - ``allowruntimeparams=`` + - Type + * - ``allowruntimeparams`` - Allow users to add more parameters - false - * - ``command=`` + - bool + * - ``command`` - Command to run to process units of work (required) - No default value. - * - ``params=`` + - string + * - ``params`` - Command-line parameters - No default value. - * - ``verifysignature=`` + - string + * - ``verifysignature`` - Verify a signed work submission - false - * - ``worktype=`` + - bool + * - ``worktype`` - Name for this worker type (required) - No default value. + - string + +.. code-block:: yaml + + work-commands: + - command: cat + worktype: cat + ^^^^^^^^^^^^^^^ Work Kubernetes @@ -671,75 +757,72 @@ Work Kubernetes * - Parameter - Description - Default value - * - ``allowruntimeauth=`` + - Type + * - ``allowruntimeauth`` - Allow passing API parameters at runtime - false - * - ``allowruntimecommand=`` + - bool + * - ``allowruntimecommand`` - Allow specifying image & command at runtime - false - * - ``allowruntimeparams=`` + - bool + * - ``allowruntimeparams`` - Allow adding command parameters at runtime - false - * - ``allowruntimepod=`` + - bool + * - ``allowruntimepod`` - Allow passing Pod at runtime - false - * - ``authmethod=`` + - bool + * - ``authmethod`` - One of: kubeconfig, incluster - incluster - * - ``command=`` + - string + * - ``command`` - Command to run in the container (overrides entrypoint) - No default value. - * - ``deletepodonrestart=`` + - string + * - ``deletepodonrestart`` - On restart, delete the pod if in pending state - true - * - ``image=`` + - bool + * - ``image`` - Container image to use for the worker pod - No default value. - * - ``kubeconfig=`` + - string + * - ``kubeconfig`` - Kubeconfig filename (for authmethod=kubeconfig) - No default value. - * - ``namespace=`` + - string + * - ``namespace`` - Kubernetes namespace to create pods in - No default value. - * - ``params=`` + - string + * - ``params`` - Command-line parameters to pass to the entrypoint - No default value. - * - ``pod=`` + - string + * - ``pod`` - Pod definition filename, in json or yaml format - No default value. - * - ``streammethod=`` + - string + * - ``streammethod`` - Method for connecting to worker pods: logger or tcp - logger - * - ``verifysignature=`` + - string + * - ``verifysignature`` - Verify a signed work submission - false - * - ``worktype=`` + - bool + * - ``worktype`` - Name for this worker type (required) - No default value. + - string -^^^^^^^^^^^ -Work Python -^^^^^^^^^^^ +.. code-block:: yaml -.. list-table:: Work Python [DEPRECATION WARNING] This option is not currently being used. This feature will be removed from receptor in a future release - :header-rows: 1 - :widths: auto - - * - Parameter - - Description - - Default value - * - ``config=`` - - Plugin-specific configuration - - No default value. - * - ``function=`` - - Receptor-exported function to call (required) - - No default value. - * - ``plugin=`` - - Python module name of the worker plugin (required) - - No default value. - * - ``worktype=`` - - Name for this worker type (required) - - No default value. + work-kubernetes: + - worktype: cat ^^^^^^^^^^^^ Work Signing @@ -752,12 +835,22 @@ Work Signing * - Parameter - Description - Default value - * - ``privatekey=`` + - Type + * - ``privatekey`` - Private key to sign work submissions - No default value. - * - ``tokenexpiration=`` + - string + * - ``tokenexpiration`` - Expiration of the signed json web token, e.g. 3h or 3h30m - No default value. + - string + +.. code-block:: yaml + + work-signing: + privatekey: /tmp/signworkprivate.pem + tokenexpiration: 30m + ^^^^^^^^^^^^^^^^^ Work Verification @@ -770,27 +863,22 @@ Work Verification * - Parameter - Description - Default value - * - ``publickey=`` + - Type + * - ``publickey`` - Public key to verify signed work submissions - No default value. + - string + +.. code-block:: yaml + + work-verification: + publickey: /tmp/signworkpublic.pem + ----------------------------------------------------- Generate certificates and run a certificate authority ----------------------------------------------------- -.. list-table:: Generate certificates and run a certificate authority - :header-rows: 1 - :widths: auto - - * - Action - - Description - * - ``--cert-init`` - - Initialize PKI CA - * - ``--cert-makereq`` - - Create certificate request - * - ``--cert-signreq`` - - Sign request and produce certificate - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Certificate Authority Initialization ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -802,60 +890,92 @@ Certificate Authority Initialization * - Parameter - Description - Default value - * - ``bits=`` + - Type + * - ``bits`` - Bit length of the encryption keys of the certificate (required) - No default value. - * - ``commonname=`` + - int + * - ``commonname`` - Common name to assign to the certificate (required) - No default value. - * - ``notafter=`` + - string + * - ``notafter`` - Expiration (NotAfter) date/time, in RFC3339 format - No default value. - * - ``notbefore=`` + - string + * - ``notbefore`` - Effective (NotBefore) date/time, in RFC3339 format - No default value. - * - ``outcert=`` + - string + * - ``outcert`` - File to save the CA certificate to (required) - No default value. - * - ``outkey=`` + - string + * - ``outkey`` - File to save the CA private key to (required) - No default value. + - string + +.. code-block:: yaml -^^^^^^^^^^^^^^^^^^^^^^^^^^ -Create Certificate Request -^^^^^^^^^^^^^^^^^^^^^^^^^^ + cert-init: + commonname: test CA + bits: 2048 + outcert: /tmp/certs/ca.crt + outkey: /tmp/certs/ca.key -.. list-table:: Create Certificate Request + +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Create Certificate Requests +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. list-table:: Create Certificate Request (List item) :header-rows: 1 :widths: auto * - Parameter - Description - Default value - * - ``bits=`` + - Type + * - ``bits`` - Bit length of the encryption keys of the certificate - No default value. - * - ``commonname=`` + - int + * - ``commonname`` - Common name to assign to the certificate (required) - No default value. - * - ``dnsname=<[]string (may be repeated)>`` + - string + * - ``dnsname`` - DNS names to add to the certificate - No default value. - * - ``inkey=`` + - list of string + * - ``inkey`` - Private key to use for the request - No default value. - * - ``ipaddress=<[]string (may be repeated)>`` + - string + * - ``ipaddress`` - IP addresses to add to the certificate - No default value. - * - ``nodeid=<[]string (may be repeated)>`` + - list of string + * - ``nodeid`` - Receptor node IDs to add to the certificate - No default value. - * - ``outreq=`` + - list of string + * - ``outreq`` - File to save the certificate request to (required) - No default value. - * - ``outkey=`` + - string + * - ``outkey`` - File to save the private key to (new key will be generated) - No default value. + - string + +.. code-block:: yaml + + cert-makereqs: + - address: localhost:2223 + service: foo + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Sign Request and Produce Certificate @@ -868,24 +988,39 @@ Sign Request and Produce Certificate * - Parameter - Description - Default value - * - ``cacert=`` + - Type + * - ``cacert`` - CA certificate PEM filename (required) - No default value. - * - ``cakey=`` + - string + * - ``cakey`` - CA private key PEM filename (required) - No default value. - * - ``notafter=`` + - string + * - ``notafter`` - Expiration (NotAfter) date/time, in RFC3339 format - No default value. - * - ``notbefore=`` + - string + * - ``notbefore`` - Effective (NotBefore) date/time, in RFC3339 format - No default value. - * - ``outcert=`` + - string + * - ``outcert`` - File to save the signed certificate to (required) - No default value. - * - ``req=`` + - string + * - ``req`` - Certificate Request PEM filename (required) - No default value. - * - ``verify=`` + - string + * - ``verify`` - If true, do not prompt the user for verification - False + - bool + +.. code-block:: yaml + + tcp-clients: + - address: localhost:2223 + service: foo + diff --git a/docs/source/user_guide/connecting_nodes.rst b/docs/source/user_guide/connecting_nodes.rst index 41cb75944..675a8963f 100644 --- a/docs/source/user_guide/connecting_nodes.rst +++ b/docs/source/user_guide/connecting_nodes.rst @@ -7,7 +7,10 @@ Connecting nodes :local: -Connect nodes via receptor backends. TCP, UDP, and websockets are currently supported. For example, ``tcp-peer`` can be used to connect to another node's ``tcp-listener``, and ``ws-peer`` can be used to connect to another node's ``ws-listener``. +Connect nodes through Receptor backends. +TCP, UDP, and websockets are currently supported. +For example, you can connect one Receptor node to another using the ``tcp-peers`` and ``tcp-listeners`` configuration options. +Similarly you can connect Receptor nodes using the ``ws-peers`` and ``ws-listeners`` configuration options. .. image:: mesh.png :alt: Connected nodes as netceptor peers @@ -17,42 +20,45 @@ foo.yml .. code-block:: yaml --- - - node: - id: foo + version: 2 + node: + id: foo - - log-level: - level: Debug + log-level: + level: Debug - - tcp-listener: - port: 2222 + tcp-listeners: + - port: 2222 bar.yml .. code-block:: yaml --- - - node: - id: bar + version: 2 + node: + id: bar - - log-level: - level: Debug + log-level: + level: Debug - - tcp-peer: - address: localhost:2222 + tcp-peers: + - address: localhost:2222 fish.yml .. code-block:: yaml --- - - node: - id: fish + version: 2 + node: + id: fish - - log-level: - level: Debug + log-level: + level: Debug - - tcp-peer: - address: localhost:2222 + tcp-peers: + - address: localhost:2222 If we start the backends for each of these configurations, this will form a three-node mesh. Notice `bar` and `fish` are not directly connected to each other. However, the mesh allows traffic from `bar` to pass through `foo` to reach `fish`, as if `bar` and `fish` were directly connected. @@ -99,21 +105,22 @@ in foo.yml .. code-block:: yaml - - tcp-listener: - port: 2222 + tcp-listeners: + - port: 2222 cost: 1.0 nodecost: - bar: 1.6 - fish: 2.0 + bar: 1.6 + fish: 2.0 This means packets sent to `fish` have a cost of 2.0, whereas packets sent to `bar` have a cost of 1.6. If `haz` joined the mesh, it would get a cost of 1.0 since it's not in the nodecost map. -The costs on the two ends of the connection must match. For example, the ``tcp-peer`` on `fish` must have a cost of 2.0, otherwise the connection will be refused. +The costs on both ends of the connection must match. +For example, the ``tcp-peers`` configuration on ``fish`` must have a cost of ``2.0``, otherwise the connection will be refused. in fish.yml .. code-block:: yaml - - tcp-peer: - address: localhost:2222 + tcp-peers: + - address: localhost:2222 cost: 2.0 diff --git a/docs/source/user_guide/edge_networks.rst b/docs/source/user_guide/edge_networks.rst index e9b1437d6..8cad0f7d9 100644 --- a/docs/source/user_guide/edge_networks.rst +++ b/docs/source/user_guide/edge_networks.rst @@ -36,38 +36,45 @@ foo.yml .. code-block:: yaml --- - - node: - id: foo - maxidleconnectiontimeout: 60s - - log-level: - level: Debug - - tcp-listener: - port: 2222 + version: 2 + node: + id: foo + maxidleconnectiontimeout: 60s + + log-level: + level: Debug + + tcp-listeners: + - port: 2222 bar.yml .. code-block:: yaml --- - - node: - id: bar - maxidleconnectiontimeout: 60s - - log-level: - level: Debug - - tcp-peer: - address: localhost:2222 + node: + id: bar + maxidleconnectiontimeout: 60s + + log-level: + level: Debug + + tcp-peers: + - address: localhost:2222 fish.yml .. code-block:: yaml --- - - node: - id: fish - maxidleconnectiontimeout: 60s - - log-level: - level: Debug - - tcp-peer: - address: localhost:2222 + node: + id: fish + maxidleconnectiontimeout: 60s + + log-level: + level: Debug + + tcp-peers: + - address: localhost:2222 *Note* - All Receptor nodes in the mesh must define a `maxidleconnectiontimeout` value, if this value is consumed on ANY node. The effective `maxidleconnectiontimeout` value is the minumum value between all the nodes in the mesh. diff --git a/docs/source/user_guide/firewall.rst b/docs/source/user_guide/firewall.rst index cc0db89de..fb7853bb9 100644 --- a/docs/source/user_guide/firewall.rst +++ b/docs/source/user_guide/firewall.rst @@ -15,7 +15,6 @@ Firewall rules are added under the ``node`` entry in a Receptor configuration fi .. code-block:: yaml # Accepts everything - --- node: firewallrules: - action: "accept" @@ -23,7 +22,6 @@ Firewall rules are added under the ``node`` entry in a Receptor configuration fi .. code-block:: yaml # Drops traffic from `foo` to `bar`'s control service - --- node: firewallrules: - action: "drop" @@ -34,7 +32,6 @@ Firewall rules are added under the ``node`` entry in a Receptor configuration fi .. code-block:: yaml # Rejects traffic originating from nodes like abcb, adfb, etc - --- node: firewallrules: - action: "reject" @@ -43,7 +40,6 @@ Firewall rules are added under the ``node`` entry in a Receptor configuration fi .. code-block:: yaml # Rejects traffic destined for nodes like abcb, AdfB, etc - --- node: firewallrules: - action: "reject" diff --git a/docs/source/user_guide/interacting_with_nodes.rst b/docs/source/user_guide/interacting_with_nodes.rst index 32a28e680..273d616fa 100644 --- a/docs/source/user_guide/interacting_with_nodes.rst +++ b/docs/source/user_guide/interacting_with_nodes.rst @@ -16,17 +16,18 @@ foo.yml .. code-block:: yaml --- - - node: - id: foo + version: 2 + node: + id: foo - - log-level: - level: Debug + log-level: + level: debug - - tcp-listener: - port: 2222 + tcp-listeners: + - port: 2222 - - control-service: - service: control + control-services: + - service: control filename: /tmp/foo.sock bar.yml @@ -34,17 +35,18 @@ bar.yml .. code-block:: yaml --- - - node: - id: bar + version: 2 + node: + id: bar - - log-level: - level: Debug + log-level: + level: debug - - tcp-peer: - address: localhost:2222 + tcp-peers: + - address: localhost:2222 - - control-service: - service: control + control-services: + - service: control If ``filename`` is set, receptor will create a unix domain socket. Use receptorctl to interact with the running receptor node via this domain socket (using "--socket"). The control service on `bar` does not have a ``filename`` set, but can be connected to using the "connect" command, as shown in the :ref:`connect_to_csv` section. @@ -188,12 +190,12 @@ Any action items related to receptor backend connections can be reloaded, withou .. code-block:: text - tcp-peer - tcp-listener - ws-peer - ws-listener - udp-peer - udp-listener + tcp-peers + tcp-listeners + ws-peers + ws-listeners + udp-peers + udp-listeners local-only Changes can include modifying, adding, or removing these items from the configuration file. diff --git a/docs/source/user_guide/k8s.rst b/docs/source/user_guide/k8s.rst index 71c0cf26e..f91962f0b 100644 --- a/docs/source/user_guide/k8s.rst +++ b/docs/source/user_guide/k8s.rst @@ -11,21 +11,22 @@ foo.yml .. code-block:: yaml --- - - node: - id: foo + version: 2 + node: + id: foo - - log-level: - level: Debug + log-level: + level: Debug - - tcp-listener: - port: 2222 + tcp-listeners: + port: 2222 - - control-service: - service: control + control-services: + - service: control filename: /tmp/foo.sock - - work-kubernetes: - worktype: kubeit + work-kubernetes: + - worktype: kubeit authmethod: kubeconfig allowruntimeauth: true allowruntimepod: true @@ -34,7 +35,7 @@ foo.yml kubeitpod.yml .. note:: - You may need to set ``tcp-listener``, ``tcp-peer``, or ``local-only`` before you can start the control service. See https://github.com/ansible/receptor/issues/518 + You might need to set ``tcp-listeners``, ``tcp-peers``, or ``local-only`` before you can start the control service. See https://github.com/ansible/receptor/issues/518 .. code-block:: yaml diff --git a/docs/source/user_guide/tls.rst b/docs/source/user_guide/tls.rst index 2fb215cf5..596873c24 100644 --- a/docs/source/user_guide/tls.rst +++ b/docs/source/user_guide/tls.rst @@ -10,65 +10,67 @@ mesh connections. Configuring TLS --------------- -Add ``tls-server`` and ``tls-client`` definitions to Receptor config files. +Add ``tls-servers`` and ``tls-clients`` definitions to Receptor configuration files. ``foo.yml`` .. code-block:: yaml --- - - node: - id: foo + version: 2 + node: + id: foo - - log-level: - level: Debug + log-level: + level: Debug - - tls-server: - name: myserver + tls-servers: + - name: myserver cert: /full/path/foo.crt key: /full/path/foo.key requireclientcert: true clientcas: /full/path/ca.crt - - tcp-listener: - port: 2222 + tcp-listeners: + - port: 2222 tls: myserver -Defining ``tls-server`` takes no effect, but it can be referenced elsewhere in the Receptor config file. -In the preceding configuration snippet, ``tls`` in the ``tcp-listener`` is set to use ``myserver``. -In general, ``tls-server`` should be referenced anywhere Receptor is expecting an incoming connection, such as ``*-listener`` backends or on the ``control-service``. -Similarly, ``tls-client`` should be referenced anywhere Receptor is expecting to make an outgoing connection, i.e. ``*-peer`` backends or in ``receptorctl`` (the command-line client for Receptor). +Defining ``tls-servers`` has no effect, but it can be referenced elsewhere in the Receptor configuration file. +In the preceding configuration snippet, ``tls`` in the ``tcp-listeners`` is set to use ``myserver``. +In general, ``tls-servers`` should be referenced anywhere Receptor is expecting an incoming connection, such as ``*-listeners`` backends or on the ``control-services``. +Similarly, ``tls-clients`` should be referenced anywhere Receptor is expecting to make an outgoing connection, such as ``*-peers`` backends or in ``receptorctl`` (the command-line client for Receptor). ``bar.yml`` .. code-block:: yaml --- - - node: - id: bar + version: 2 + node: + id: bar - - log-level: - level: Debug + log-level: + level: Debug - - tls-client: - name: myclient + tls-clients: + - name: myclient rootcas: /full/path/ca.crt insecureskipverify: false cert: /full/path/bar.crt key: /full/path/bar.key - - tcp-peer: - address: localhost:2222 + tcp-peers: + - address: localhost:2222 tls: myclient -``myclient`` is referenced in ``tcp-peer``. Once started, `foo` and `bar` will authenticate each other, and the connection will be fully encrypted. +``myclient`` is referenced in ``tcp-peers``. Once started, `foo` and `bar` will authenticate each other, and the connection will be fully encrypted. Generating certs ----------------- Receptor supports X.509 compliant certificates and provides a built-in tool to generate valid certificates. -Running Receptor with the ``cert-init``, ``cert-makereq``, and ``cert-signreq`` actions creates certificate authorities, make requests, and sign requests. +Running and configuring Receptor with the ``cert-init``, ``cert-makereqs``, and ``cert-signreqs`` properties creates certificate authorities, make requests, and sign requests. ``makecerts.sh`` @@ -83,7 +85,7 @@ Running Receptor with the ``cert-init``, ``cert-makereq``, and ``cert-signreq`` done The preceding script will create a CA, and for each node ``foo`` and ``bar``, create a certificate request and sign it with the CA. -These certificates and keys can then create ``tls-server`` and ``tls-client`` definitions in the Receptor config files. +These certificates and keys can then create ``tls-servers`` and ``tls-clients`` definitions in the Receptor configuration files. Pinned certificates -------------------- @@ -95,11 +97,12 @@ pinning for this purpose. Here is an example of a pinned certificate configurat .. code-block:: yaml --- - - node: - id: foo + version: 2 + node: + id: foo - - tls-server: - name: myserver + tls-servers: + - name: myserver cert: /full/path/foo.crt key: /full/path/foo.key requireclientcert: true @@ -107,8 +110,8 @@ pinning for this purpose. Here is an example of a pinned certificate configurat pinnedclientcert: - E6:9B:98:A7:A5:DB:17:D6:E4:2C:DE:76:45:42:A8:79:A3:0A:C5:6D:10:42:7A:6A:C4:54:57:83:F1:0F:E2:95 - - tcp-listener: - port: 2222 + tcp-listeners: + - port: 2222 tls: myserver Certificate pinning is an added requirement, and does not eliminate the need to meet other stated requirements. In the above example, the client certificate must both be signed by a CA in the `ca.crt` bundle, and also have the listed fingerprint. Multiple fingerprints may be specified, in which case a certificate matching any one of them will be accepted. @@ -144,22 +147,23 @@ The default behavior for this option is `false` which means that the certificate .. code-block:: yaml --- - - node: - id: bar + version: 2 + node: + id: bar - - log-level: - level: Debug + log-level: + level: Debug - - tls-client: - name: myclient + tls-clients: + - name: myclient rootcas: /full/path/ca.crt insecureskipverify: false cert: /full/path/bar.crt key: /full/path/bar.key skipreceptornamescheck: true - - tls-server: - name: myserver + tls-servers: + - name: myserver cert: /full/path/foo.crt key: /full/path/foo.key requireclientcert: true @@ -168,6 +172,6 @@ The default behavior for this option is `false` which means that the certificate - E6:9B:98:A7:A5:DB:17:D6:E4:2C:DE:76:45:42:A8:79:A3:0A:C5:6D:10:42:7A:6A:C4:54:57:83:F1:0F:E2:95 skipreceptornamescheck: true - - tcp-peer: - address: localhost:2222 + tcp-peers: + - address: localhost:2222 tls: myclient diff --git a/docs/source/user_guide/workceptor.rst b/docs/source/user_guide/workceptor.rst index 93bc4a23d..401954109 100644 --- a/docs/source/user_guide/workceptor.rst +++ b/docs/source/user_guide/workceptor.rst @@ -6,28 +6,29 @@ Workceptor Workceptor is a component of receptor that handles units of work. -``work-command`` defines a type of work that can run on the node. +``work-commands`` defines a type of work that can run on the node. foo.yml .. code-block:: yaml --- - - node: - id: foo + version: 2 + node: + id: foo - - log-level: - level: Debug + log-level: + level: Debug - - tcp-listener: - port: 2222 + tcp-listeners: + - port: 2222 - - control-service: - service: control + control-services: + - service: control filename: /tmp/foo.sock - - work-command: - workType: echoint + work-commands: + - workType: echoint command: bash params: "-c \"for i in {1..5}; do echo $i; sleep 1; done\"" @@ -36,25 +37,24 @@ bar.yml .. code-block:: yaml --- - - node: - id: bar + version: 2 + node: + id: bar - - log-level: - level: Debug + log-level: + level: Debug - - tcp-peer: - address: localhost:2222 + tcp-peer: + address: localhost:2222 - - control-service: - service: control + control-services: + - service: control - - work-command: - worktype: echoint + work-commands: + - worktype: echoint command: bash params: "-c \"for i in {1..10}; do echo $i; sleep 1; done\"" - - - work-command: - workType: echopayload + - workType: echopayload command: bash params: "-c \"while read -r line; do echo ${line^^}; sleep 3; done\"" @@ -72,7 +72,7 @@ Configuring work commands Local work ----------- -Start the work by connecting to the ``control-service`` and issuing a "work submit" command +Start the work by connecting to the ``control-services`` and issuing a "work submit" command .. code-block:: bash @@ -133,8 +133,7 @@ in `bar.yml` .. code-block:: yaml - - work-command: - workType: echopayload + - workType: echopayload command: bash params: "-c \"while read -r line; do echo ${line^^}; sleep 5; done\"" @@ -161,8 +160,8 @@ Work commands can be configured to allow parameters to be passed to commands whe .. code-block:: yaml - - work-command: - workType: listcontents + work-commands: + - workType: listcontents command: ls allowruntimeparams: true @@ -271,11 +270,10 @@ in `bar.yml` .. code-block:: yaml # PKIX - - work-verification: - publickey: /full/path/signworkpublic.pem + work-verification: + publickey: /full/path/signworkpublic.pem - - work-command: - workType: echopayload + - workType: echopayload command: bash params: "-c \"while read -r line; do echo ${line^^}; sleep 5; done\"" verifysignature: true @@ -285,9 +283,9 @@ in `foo.yml` .. code-block:: yaml # PKCS1 - - work-signing: - privatekey: /full/path/signworkprivate.pem - tokenexpiration: 30m + work-signing: + privatekey: /full/path/signworkprivate.pem + tokenexpiration: 30m Tokenexpiration determines how long a the signature is valid for. This expiration directly corresponds to the "expiresAt" field in the generated JSON web token. Valid units include "h" and "m", e.g. 1h30m for one hour and 30 minutes. diff --git a/go.mod b/go.mod index ad3c5d9b1..f7d6ae984 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,8 @@ require ( github.com/quic-go/quic-go v0.40.1 github.com/rogpeppe/go-internal v1.12.0 github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 + github.com/spf13/cobra v1.8.0 + github.com/spf13/viper v1.18.2 github.com/vishvananda/netlink v1.1.0 go.uber.org/goleak v1.3.0 go.uber.org/mock v0.4.0 @@ -30,7 +32,7 @@ require ( ) require ( - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/go-logr/logr v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect @@ -42,32 +44,46 @@ require ( github.com/google/gnostic-models v0.6.8 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20231229205709-960ae82b1e42 // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/uuid v1.4.0 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect github.com/imdario/mergo v0.3.15 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moby/spdystream v0.2.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/onsi/ginkgo/v2 v2.13.2 // indirect + github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/quic-go/qtls-go1-20 v0.4.1 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.6.0 // indirect github.com/vishvananda/netns v0.0.4 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/oauth2 v0.15.0 // indirect golang.org/x/crypto v0.25.0 // indirect golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect golang.org/x/mod v0.17.0 // indirect - golang.org/x/oauth2 v0.10.0 // indirect golang.org/x/sys v0.22.0 // indirect golang.org/x/term v0.22.0 // indirect golang.org/x/text v0.16.0 // indirect - golang.org/x/time v0.3.0 // indirect + golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/klog/v2 v2.110.1 // indirect k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect diff --git a/go.sum b/go.sum index 9cc1a513c..819e1017e 100644 --- a/go.sum +++ b/go.sum @@ -1,17 +1,21 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/ghjm/cmdline v0.1.2 h1:XhhlCLSPx4qYf+eNDNzge3lBtymw5ZbWMnJfOFbuL6k= @@ -47,13 +51,17 @@ github.com/google/pprof v0.0.0-20231229205709-960ae82b1e42 h1:dHLYa5D8/Ta0aLR2Xc github.com/google/pprof v0.0.0-20231229205709-960ae82b1e42/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -69,8 +77,12 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= @@ -90,10 +102,13 @@ github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= +github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= +github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prep/socketpair v0.0.0-20171228153254-c2c6a7f821c2 h1:vzKDZ0uNPcOdITzZT5d4Tn2YOalCMqIhYzVNq/oRjlw= github.com/prep/socketpair v0.0.0-20171228153254-c2c6a7f821c2/go.mod h1:E/IaW35yb7xPACTLciISfz5w+jqPwmnXwDdmilSl/Nc= github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs= @@ -102,10 +117,25 @@ github.com/quic-go/quic-go v0.40.1 h1:X3AGzUNFs0jVuO3esAGnTfvdgvL4fq655WaOi1snv1 github.com/quic-go/quic-go v0.40.1/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 h1:TG/diQgUe0pntT/2D9tmUCz4VNwm9MfrtPr0SU2qSX8= github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= +github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -116,6 +146,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= @@ -124,10 +156,14 @@ github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZla github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -146,10 +182,10 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= +golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= -golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= -golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -174,8 +210,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -196,6 +232,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/internal/version/version.go b/internal/version/version.go index 977257b63..1ea9d9cb7 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/ghjm/cmdline" + "github.com/spf13/viper" ) // Version is receptor app version. @@ -24,6 +25,10 @@ func (cfg cmdlineCfg) Run() error { } func init() { + version := viper.GetInt("version") + if version > 1 { + return + } cmdline.RegisterConfigTypeForApp("receptor-version", "version", "Displays the Receptor version.", cmdlineCfg{}, cmdline.Exclusive) } diff --git a/packaging/container/Dockerfile b/packaging/container/Dockerfile index bc45d0a2c..036f82b2f 100644 --- a/packaging/container/Dockerfile +++ b/packaging/container/Dockerfile @@ -19,7 +19,7 @@ LABEL version="${VERSION}" COPY receptorctl-${VERSION}-py3-none-any.whl /tmp COPY receptor_python_worker-${VERSION}-py3-none-any.whl /tmp -COPY receptor.conf /etc/receptor/receptor.conf +COPY receptor.yaml /etc/receptor/receptor.yaml RUN dnf -y update && \ dnf -y install python3.12-pip && \ @@ -36,4 +36,4 @@ ENV RECEPTORCTL_SOCKET=/tmp/receptor.sock EXPOSE 7323 ENTRYPOINT ["/usr/local/bin/dumb-init", "--"] -CMD ["/usr/bin/receptor", "-c", "/etc/receptor/receptor.conf"] +CMD ["/usr/bin/receptor", "--config", "/etc/receptor/receptor.yaml"] diff --git a/packaging/container/receptor.conf b/packaging/container/receptor.conf deleted file mode 100644 index 66e812e94..000000000 --- a/packaging/container/receptor.conf +++ /dev/null @@ -1,7 +0,0 @@ ---- -- control-service: - service: control - filename: /tmp/receptor.sock - -- tcp-listener: - port: 7323 diff --git a/packaging/container/receptor.yaml b/packaging/container/receptor.yaml new file mode 100644 index 000000000..075b25f65 --- /dev/null +++ b/packaging/container/receptor.yaml @@ -0,0 +1,8 @@ +--- +version: 2 +control-services: + - service: control + filename: /tmp/receptor.sock + +tcp-listeners: + - port: 7323 diff --git a/packaging/tc-image/Dockerfile b/packaging/tc-image/Dockerfile index b1e2d460d..bdae6d265 100644 --- a/packaging/tc-image/Dockerfile +++ b/packaging/tc-image/Dockerfile @@ -3,4 +3,4 @@ FROM receptor:latest RUN dnf install tc -y ENTRYPOINT ["/bin/bash"] -CMD ["-c", "/usr/bin/receptor --config /etc/receptor/receptor.conf > /etc/receptor/stdout 2> /etc/receptor/stderr"] +CMD ["-c", "/usr/bin/receptor --legacy --config /etc/receptor/receptor.conf > /etc/receptor/stdout 2> /etc/receptor/stderr"] diff --git a/pkg/backends/null.go b/pkg/backends/null.go new file mode 100644 index 000000000..2461aa4a6 --- /dev/null +++ b/pkg/backends/null.go @@ -0,0 +1,40 @@ +package backends + +import ( + "context" + "crypto/tls" + "sync" + + "github.com/ansible/receptor/pkg/netceptor" +) + +type NullBackendCfg struct { + Local bool +} + +// make the nullBackendCfg object be usable as a do-nothing Backend. +func (cfg NullBackendCfg) Start(_ context.Context, _ *sync.WaitGroup) (chan netceptor.BackendSession, error) { + return make(chan netceptor.BackendSession), nil +} + +// Run runs the action, in this case adding a null backend to keep the wait group alive. +func (cfg NullBackendCfg) Run() error { + err := netceptor.MainInstance.AddBackend(&NullBackendCfg{}) + if err != nil { + return err + } + + return nil +} + +func (cfg *NullBackendCfg) GetAddr() string { + return "" +} + +func (cfg *NullBackendCfg) GetTLS() *tls.Config { + return nil +} + +func (cfg NullBackendCfg) Reload() error { + return cfg.Run() +} diff --git a/pkg/backends/tcp.go b/pkg/backends/tcp.go index e4c66b444..397b743c4 100644 --- a/pkg/backends/tcp.go +++ b/pkg/backends/tcp.go @@ -1,6 +1,3 @@ -//go:build !no_tcp_backend && !no_backends -// +build !no_tcp_backend,!no_backends - package backends import ( @@ -17,6 +14,7 @@ import ( "github.com/ansible/receptor/pkg/netceptor" "github.com/ansible/receptor/pkg/utils" "github.com/ghjm/cmdline" + "github.com/spf13/viper" ) // TCPDialer implements Backend for outbound TCP. @@ -367,6 +365,10 @@ func (cfg TCPListenerCfg) Reload() error { } func init() { + version := viper.GetInt("version") + if version > 1 { + return + } cmdline.RegisterConfigTypeForApp("receptor-backends", "tcp-listener", "Run a backend listener on a TCP port", TCPListenerCfg{}, cmdline.Section(backendSection)) cmdline.RegisterConfigTypeForApp("receptor-backends", diff --git a/pkg/backends/udp.go b/pkg/backends/udp.go index 779949f88..5ec07b043 100644 --- a/pkg/backends/udp.go +++ b/pkg/backends/udp.go @@ -1,6 +1,3 @@ -//go:build !no_udp_backend && !no_backends -// +build !no_udp_backend,!no_backends - package backends import ( @@ -15,6 +12,7 @@ import ( "github.com/ansible/receptor/pkg/netceptor" "github.com/ansible/receptor/pkg/utils" "github.com/ghjm/cmdline" + "github.com/spf13/viper" ) // UDPMaxPacketLen is the maximum size of a message that can be sent over UDP. @@ -353,7 +351,7 @@ func (cfg UDPListenerCfg) Run() error { } // udpDialerCfg is the cmdline configuration object for a UDP listener. -type udpDialerCfg struct { +type UDPDialerCfg struct { Address string `description:"Host:Port to connect to" barevalue:"yes" required:"yes"` Redial bool `description:"Keep redialing on lost connection" default:"true"` Cost float64 `description:"Connection cost (weight)" default:"1.0"` @@ -361,7 +359,7 @@ type udpDialerCfg struct { } // Prepare verifies the parameters are correct. -func (cfg udpDialerCfg) Prepare() error { +func (cfg UDPDialerCfg) Prepare() error { if cfg.Cost <= 0.0 { return fmt.Errorf("connection cost must be positive") } @@ -370,7 +368,7 @@ func (cfg udpDialerCfg) Prepare() error { } // Run runs the action. -func (cfg udpDialerCfg) Run() error { +func (cfg UDPDialerCfg) Run() error { netceptor.MainInstance.Logger.Debug("Running UDP peer connection %s\n", cfg.Address) b, err := NewUDPDialer(cfg.Address, cfg.Redial, netceptor.MainInstance.Logger) if err != nil { @@ -390,7 +388,7 @@ func (cfg udpDialerCfg) Run() error { return nil } -func (cfg udpDialerCfg) PreReload() error { +func (cfg UDPDialerCfg) PreReload() error { return cfg.Prepare() } @@ -398,7 +396,7 @@ func (cfg UDPListenerCfg) PreReload() error { return cfg.Prepare() } -func (cfg udpDialerCfg) Reload() error { +func (cfg UDPDialerCfg) Reload() error { return cfg.Run() } @@ -407,8 +405,12 @@ func (cfg UDPListenerCfg) Reload() error { } func init() { + version := viper.GetInt("version") + if version > 1 { + return + } cmdline.RegisterConfigTypeForApp("receptor-backends", "UDP-listener", "Run a backend listener on a UDP port", UDPListenerCfg{}, cmdline.Section(backendSection)) cmdline.RegisterConfigTypeForApp("receptor-backends", - "UDP-peer", "Make an outbound backend connection to a UDP peer", udpDialerCfg{}, cmdline.Section(backendSection)) + "UDP-peer", "Make an outbound backend connection to a UDP peer", UDPDialerCfg{}, cmdline.Section(backendSection)) } diff --git a/pkg/backends/websockets.go b/pkg/backends/websockets.go index 3c26aa348..74b6dc7a9 100644 --- a/pkg/backends/websockets.go +++ b/pkg/backends/websockets.go @@ -1,6 +1,3 @@ -//go:build !no_websocket_backend && !no_backends -// +build !no_websocket_backend,!no_backends - package backends import ( @@ -18,6 +15,7 @@ import ( "github.com/ansible/receptor/pkg/netceptor" "github.com/ghjm/cmdline" "github.com/gorilla/websocket" + "github.com/spf13/viper" ) // WebsocketDialer implements Backend for outbound Websocket. @@ -435,7 +433,7 @@ func (cfg WebsocketListenerCfg) Run() error { } // websocketDialerCfg is the cmdline configuration object for a Websocket listener. -type websocketDialerCfg struct { +type WebsocketDialerCfg struct { Address string `description:"URL to connect to" barevalue:"yes" required:"yes"` Redial bool `description:"Keep redialing on lost connection" default:"true"` ExtraHeader string `description:"Sends extra HTTP header on initial connection"` @@ -445,7 +443,7 @@ type websocketDialerCfg struct { } // Prepare verifies that we are reasonably ready to go. -func (cfg websocketDialerCfg) Prepare() error { +func (cfg WebsocketDialerCfg) Prepare() error { if cfg.Cost <= 0.0 { return fmt.Errorf("connection cost must be positive") } @@ -460,7 +458,7 @@ func (cfg websocketDialerCfg) Prepare() error { } // Run runs the action. -func (cfg websocketDialerCfg) Run() error { +func (cfg WebsocketDialerCfg) Run() error { netceptor.MainInstance.Logger.Debug("Running Websocket peer connection %s\n", cfg.Address) u, err := url.Parse(cfg.Address) if err != nil { @@ -490,7 +488,7 @@ func (cfg websocketDialerCfg) Run() error { return nil } -func (cfg websocketDialerCfg) PreReload() error { +func (cfg WebsocketDialerCfg) PreReload() error { return cfg.Prepare() } @@ -498,7 +496,7 @@ func (cfg WebsocketListenerCfg) PreReload() error { return cfg.Prepare() } -func (cfg websocketDialerCfg) Reload() error { +func (cfg WebsocketDialerCfg) Reload() error { return cfg.Run() } @@ -507,8 +505,12 @@ func (cfg WebsocketListenerCfg) Reload() error { } func init() { + version := viper.GetInt("version") + if version > 1 { + return + } cmdline.RegisterConfigTypeForApp("receptor-backends", "ws-listener", "Run an http server that accepts websocket connections", WebsocketListenerCfg{}, cmdline.Section(backendSection)) cmdline.RegisterConfigTypeForApp("receptor-backends", - "ws-peer", "Connect outbound to a websocket peer", websocketDialerCfg{}, cmdline.Section(backendSection)) + "ws-peer", "Connect outbound to a websocket peer", WebsocketDialerCfg{}, cmdline.Section(backendSection)) } diff --git a/pkg/certificates/cli.go b/pkg/certificates/cli.go index aa1245643..bb1f3a873 100644 --- a/pkg/certificates/cli.go +++ b/pkg/certificates/cli.go @@ -12,6 +12,7 @@ import ( "time" "github.com/ghjm/cmdline" + "github.com/spf13/viper" ) // Oser is the function calls interfaces for mocking os. @@ -36,7 +37,7 @@ func InitCA(opts *CertOptions, certOut, keyOut string, osWrapper Oser) error { return err } -type initCA struct { +type InitCAConfig struct { CommonName string `description:"Common name to assign to the certificate" required:"Yes"` Bits int `description:"Bit length of the encryption keys of the certificate" required:"Yes"` NotBefore string `description:"Effective (NotBefore) date/time, in RFC3339 format"` @@ -45,7 +46,7 @@ type initCA struct { OutKey string `description:"File to save the CA private key to" required:"Yes"` } -func (ica initCA) Run() (err error) { +func (ica InitCAConfig) Run() (err error) { opts := &CertOptions{ CommonName: ica.CommonName, Bits: ica.Bits, @@ -113,7 +114,7 @@ func MakeReq(opts *CertOptions, keyIn, keyOut, reqOut string, osWrapper Oser) er return nil } -type makeReq struct { +type MakeReqConfig struct { CommonName string `description:"Common name to assign to the certificate" required:"Yes"` Bits int `description:"Bit length of the encryption keys of the certificate"` DNSName []string `description:"DNS names to add to the certificate"` @@ -124,7 +125,7 @@ type makeReq struct { OutKey string `description:"File to save the private key to (new key will be generated)"` } -func (mr makeReq) Prepare() error { +func (mr MakeReqConfig) Prepare() error { if mr.InKey == "" && mr.OutKey == "" { return fmt.Errorf("must provide either InKey or OutKey") } @@ -141,7 +142,7 @@ func (mr makeReq) Prepare() error { return nil } -func (mr makeReq) Run() error { +func (mr MakeReqConfig) Run() error { opts := &CertOptions{ CommonName: mr.CommonName, Bits: mr.Bits, @@ -227,7 +228,7 @@ func SignReq(opts *CertOptions, caCrtPath, caKeyPath, reqPath, certOut string, v return SaveToPEMFile(certOut, []interface{}{cert}, &OsWrapper{}) } -type signReq struct { +type SignReqConfig struct { Req string `description:"Certificate Request PEM filename" required:"Yes"` CACert string `description:"CA certificate PEM filename" required:"Yes"` CAKey string `description:"CA private key PEM filename" required:"Yes"` @@ -237,7 +238,7 @@ type signReq struct { Verify bool `description:"If true, do not prompt the user for verification" default:"False"` } -func (sr signReq) Run() error { +func (sr SignReqConfig) Run() error { opts := &CertOptions{} if sr.NotBefore != "" { t, err := time.Parse(time.RFC3339, sr.NotBefore) @@ -258,10 +259,14 @@ func (sr signReq) Run() error { } func init() { + version := viper.GetInt("version") + if version > 1 { + return + } cmdline.RegisterConfigTypeForApp("receptor-certificates", - "cert-init", "Initialize PKI CA", initCA{}, cmdline.Exclusive, cmdline.Section(certSection)) + "cert-init", "Initialize PKI CA", InitCAConfig{}, cmdline.Exclusive, cmdline.Section(certSection)) cmdline.RegisterConfigTypeForApp("receptor-certificates", - "cert-makereq", "Create certificate request", makeReq{}, cmdline.Exclusive, cmdline.Section(certSection)) + "cert-makereq", "Create certificate request", MakeReqConfig{}, cmdline.Exclusive, cmdline.Section(certSection)) cmdline.RegisterConfigTypeForApp("receptor-certificates", - "cert-signreq", "Sign request and produce certificate", signReq{}, cmdline.Exclusive, cmdline.Section(certSection)) + "cert-signreq", "Sign request and produce certificate", SignReqConfig{}, cmdline.Exclusive, cmdline.Section(certSection)) } diff --git a/pkg/controlsvc/controlsvc.go b/pkg/controlsvc/controlsvc.go index 4853c3bbf..0c2015afd 100644 --- a/pkg/controlsvc/controlsvc.go +++ b/pkg/controlsvc/controlsvc.go @@ -22,6 +22,7 @@ import ( "github.com/ansible/receptor/pkg/netceptor" "github.com/ansible/receptor/pkg/utils" "github.com/ghjm/cmdline" + "github.com/spf13/viper" ) const ( @@ -489,7 +490,7 @@ type cmdlineConfigWindows struct { } // cmdlineConfigUnix is the cmdline configuration object for a control service on Unix. -type cmdlineConfigUnix struct { +type CmdlineConfigUnix struct { Service string `description:"Receptor service name to listen on" default:"control"` Filename string `description:"Specifies the filename of a local Unix socket to bind to the service."` Permissions int `description:"Socket file permissions" default:"0600"` @@ -499,7 +500,7 @@ type cmdlineConfigUnix struct { } // Run runs the action. -func (cfg cmdlineConfigUnix) Run() error { +func (cfg CmdlineConfigUnix) Run() error { if cfg.TLS != "" && cfg.TCPListen != "" && cfg.TCPTLS == "" { netceptor.MainInstance.Logger.Warning("Control service %s has TLS configured on the Receptor listener but not the TCP listener.", cfg.Service) } @@ -525,7 +526,7 @@ func (cfg cmdlineConfigUnix) Run() error { // Run runs the action. func (cfg cmdlineConfigWindows) Run() error { - return cmdlineConfigUnix{ + return CmdlineConfigUnix{ Service: cfg.Service, TLS: cfg.TLS, TCPListen: cfg.TCPListen, @@ -534,11 +535,15 @@ func (cfg cmdlineConfigWindows) Run() error { } func init() { + version := viper.GetInt("version") + if version > 1 { + return + } if runtime.GOOS == "windows" { cmdline.RegisterConfigTypeForApp("receptor-control-service", "control-service", "Runs a control service", cmdlineConfigWindows{}) } else { cmdline.RegisterConfigTypeForApp("receptor-control-service", - "control-service", "Runs a control service", cmdlineConfigUnix{}) + "control-service", "Runs a control service", CmdlineConfigUnix{}) } } diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 18c680a03..3f5d52d7b 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -9,6 +9,7 @@ import ( "sync" "github.com/ghjm/cmdline" + "github.com/spf13/viper" ) var ( @@ -262,11 +263,11 @@ func (rl *ReceptorLogger) LogLevelToName(logLevel int) (string, error) { return "", err } -type loglevelCfg struct { +type LoglevelCfg struct { Level string `description:"Log level: Error, Warning, Info or Debug" barevalue:"yes" default:"error"` } -func (cfg loglevelCfg) Init() error { +func (cfg LoglevelCfg) Init() error { var err error val, err := GetLogLevelByName(cfg.Level) if err != nil { @@ -277,20 +278,24 @@ func (cfg loglevelCfg) Init() error { return nil } -type traceCfg struct{} +type TraceCfg struct{} -func (cfg traceCfg) Prepare() error { +func (cfg TraceCfg) Prepare() error { return nil } func init() { + version := viper.GetInt("version") + if version > 1 { + return + } logLevel = InfoLevel showTrace = false log.SetOutput(os.Stdout) log.SetFlags(log.Ldate | log.Ltime) cmdline.RegisterConfigTypeForApp("receptor-logging", - "log-level", "Specifies the verbosity level for command output", loglevelCfg{}, cmdline.Singleton) + "log-level", "Specifies the verbosity level for command output", LoglevelCfg{}, cmdline.Singleton) cmdline.RegisterConfigTypeForApp("receptor-logging", - "trace", "Enables packet tracing output", traceCfg{}, cmdline.Singleton) + "trace", "Enables packet tracing output", TraceCfg{}, cmdline.Singleton) } diff --git a/pkg/netceptor/tlsconfig.go b/pkg/netceptor/tlsconfig.go index 5f0bfe116..e1c4e11ae 100644 --- a/pkg/netceptor/tlsconfig.go +++ b/pkg/netceptor/tlsconfig.go @@ -1,6 +1,3 @@ -//go:build !no_tls_config -// +build !no_tls_config - package netceptor import ( @@ -14,6 +11,7 @@ import ( "github.com/ansible/receptor/pkg/utils" "github.com/ghjm/cmdline" + "github.com/spf13/viper" ) // ************************************************************************** @@ -239,6 +237,10 @@ func (cfg TLSClientConfig) Prepare() error { } func init() { + version := viper.GetInt("version") + if version > 1 { + return + } cmdline.RegisterConfigTypeForApp("receptor-tls", "tls-server", "Define a TLS server configuration", TLSServerConfig{}, cmdline.Section(configSection)) cmdline.RegisterConfigTypeForApp("receptor-tls", diff --git a/pkg/services/command.go b/pkg/services/command.go index df20e8e59..49096c5b4 100644 --- a/pkg/services/command.go +++ b/pkg/services/command.go @@ -1,5 +1,5 @@ -//go:build !windows && !no_command_service && !windows && !no_services -// +build !windows,!no_command_service,!windows,!no_services +//go:build !windows +// +build !windows package services @@ -14,6 +14,7 @@ import ( "github.com/creack/pty" "github.com/ghjm/cmdline" "github.com/google/shlex" + "github.com/spf13/viper" ) func runCommand(qc net.Conn, command string, logger *logger.ReceptorLogger) error { @@ -59,14 +60,14 @@ func CommandService(s *netceptor.Netceptor, service string, tlscfg *tls.Config, } // commandSvcCfg is the cmdline configuration object for a command service. -type commandSvcCfg struct { +type CommandSvcCfg struct { Service string `required:"true" description:"Receptor service name to bind to"` Command string `required:"true" description:"Command to execute on a connection"` TLS string `description:"Name of TLS server config"` } // Run runs the action. -func (cfg commandSvcCfg) Run() error { +func (cfg CommandSvcCfg) Run() error { netceptor.MainInstance.Logger.Info("Running command service %s\n", cfg) tlscfg, err := netceptor.MainInstance.GetServerTLSConfig(cfg.TLS) if err != nil { @@ -78,6 +79,10 @@ func (cfg commandSvcCfg) Run() error { } func init() { + version := viper.GetInt("version") + if version > 1 { + return + } cmdline.RegisterConfigTypeForApp("receptor-command-service", - "command-service", "Run an interactive command via a Receptor service", commandSvcCfg{}, cmdline.Section(servicesSection)) + "command-service", "Run an interactive command via a Receptor service", CommandSvcCfg{}, cmdline.Section(servicesSection)) } diff --git a/pkg/services/ip_router.go b/pkg/services/ip_router.go index b3926a123..2410eade4 100644 --- a/pkg/services/ip_router.go +++ b/pkg/services/ip_router.go @@ -1,5 +1,5 @@ -//go:build linux && !no_ip_router && linux && !no_services -// +build linux,!no_ip_router,linux,!no_services +//go:build linux +// +build linux package services @@ -16,6 +16,7 @@ import ( "github.com/ansible/receptor/pkg/utils" "github.com/ghjm/cmdline" "github.com/songgao/water" + "github.com/spf13/viper" "github.com/vishvananda/netlink" "golang.org/x/net/ipv4" "golang.org/x/net/ipv6" @@ -359,16 +360,8 @@ func (ipr *IPRouterService) run() error { return nil } -// ipRouterCfg is the cmdline configuration object for an IP router. -type ipRouterCfg struct { - NetworkName string `required:"true" description:"Name of this network and service."` - Interface string `description:"Name of the local tun interface"` - LocalNet string `required:"true" description:"Local /30 CIDR address"` - Routes string `description:"Comma separated list of CIDR subnets to advertise"` -} - // Run runs the action. -func (cfg ipRouterCfg) Run() error { +func (cfg IPRouterCfg) Run() error { netceptor.MainInstance.Logger.Debug("Running tun router service %s\n", cfg) _, err := NewIPRouter(netceptor.MainInstance, cfg.NetworkName, cfg.Interface, cfg.LocalNet, cfg.Routes) if err != nil { @@ -379,6 +372,10 @@ func (cfg ipRouterCfg) Run() error { } func init() { + version := viper.GetInt("version") + if version > 1 { + return + } cmdline.RegisterConfigTypeForApp("receptor-ip-router", - "ip-router", "Run an IP router using a tun interface", ipRouterCfg{}, cmdline.Section(servicesSection)) + "ip-router", "Run an IP router using a tun interface", IPRouterCfg{}, cmdline.Section(servicesSection)) } diff --git a/pkg/services/ip_router_cfg.go b/pkg/services/ip_router_cfg.go new file mode 100644 index 000000000..c4206f2e2 --- /dev/null +++ b/pkg/services/ip_router_cfg.go @@ -0,0 +1,9 @@ +package services + +// ipRouterCfg is the cmdline configuration object for an IP router. +type IPRouterCfg struct { + NetworkName string `required:"true" description:"Name of this network and service."` + Interface string `description:"Name of the local tun interface"` + LocalNet string `required:"true" description:"Local /30 CIDR address"` + Routes string `description:"Comma separated list of CIDR subnets to advertise"` +} diff --git a/pkg/services/tcp_proxy.go b/pkg/services/tcp_proxy.go index e6080e21b..5d73c3b7e 100644 --- a/pkg/services/tcp_proxy.go +++ b/pkg/services/tcp_proxy.go @@ -1,6 +1,3 @@ -//go:build !no_proxies && !no_services -// +build !no_proxies,!no_services - package services import ( @@ -12,6 +9,7 @@ import ( "github.com/ansible/receptor/pkg/netceptor" "github.com/ansible/receptor/pkg/utils" "github.com/ghjm/cmdline" + "github.com/spf13/viper" ) // TCPProxyServiceInbound listens on a TCP port and forwards the connection over the Receptor network. @@ -84,7 +82,7 @@ func TCPProxyServiceOutbound(s *netceptor.Netceptor, service string, tlsServer * } // tcpProxyInboundCfg is the cmdline configuration object for a TCP inbound proxy. -type tcpProxyInboundCfg struct { +type TCPProxyInboundCfg struct { Port int `required:"true" description:"Local TCP port to bind to"` BindAddr string `description:"Address to bind TCP listener to" default:"0.0.0.0"` RemoteNode string `required:"true" description:"Receptor node to connect to"` @@ -94,7 +92,7 @@ type tcpProxyInboundCfg struct { } // Run runs the action. -func (cfg tcpProxyInboundCfg) Run() error { +func (cfg TCPProxyInboundCfg) Run() error { netceptor.MainInstance.Logger.Debug("Running TCP inbound proxy service %v\n", cfg) tlsClientCfg, err := netceptor.MainInstance.GetClientTLSConfig(cfg.TLSClient, cfg.RemoteNode, netceptor.ExpectedHostnameTypeReceptor) if err != nil { @@ -110,7 +108,7 @@ func (cfg tcpProxyInboundCfg) Run() error { } // tcpProxyOutboundCfg is the cmdline configuration object for a TCP outbound proxy. -type tcpProxyOutboundCfg struct { +type TCPProxyOutboundCfg struct { Service string `required:"true" description:"Receptor service name to bind to"` Address string `required:"true" description:"Address for outbound TCP connection"` TLSServer string `description:"Name of TLS server config for the Receptor service"` @@ -118,7 +116,7 @@ type tcpProxyOutboundCfg struct { } // Run runs the action. -func (cfg tcpProxyOutboundCfg) Run() error { +func (cfg TCPProxyOutboundCfg) Run() error { netceptor.MainInstance.Logger.Debug("Running TCP inbound proxy service %s\n", cfg) TLSServerConfig, err := netceptor.MainInstance.GetServerTLSConfig(cfg.TLSServer) if err != nil { @@ -137,8 +135,12 @@ func (cfg tcpProxyOutboundCfg) Run() error { } func init() { + version := viper.GetInt("version") + if version > 1 { + return + } cmdline.RegisterConfigTypeForApp("receptor-proxies", - "tcp-server", "Listen for TCP and forward via Receptor", tcpProxyInboundCfg{}, cmdline.Section(servicesSection)) + "tcp-server", "Listen for TCP and forward via Receptor", TCPProxyInboundCfg{}, cmdline.Section(servicesSection)) cmdline.RegisterConfigTypeForApp("receptor-proxies", - "tcp-client", "Listen on a Receptor service and forward via TCP", tcpProxyOutboundCfg{}, cmdline.Section(servicesSection)) + "tcp-client", "Listen on a Receptor service and forward via TCP", TCPProxyOutboundCfg{}, cmdline.Section(servicesSection)) } diff --git a/pkg/services/udp_proxy.go b/pkg/services/udp_proxy.go index 399b06076..1a9b05094 100644 --- a/pkg/services/udp_proxy.go +++ b/pkg/services/udp_proxy.go @@ -1,6 +1,3 @@ -//go:build !no_proxies && !no_services -// +build !no_proxies,!no_services - package services import ( @@ -11,6 +8,7 @@ import ( "github.com/ansible/receptor/pkg/netceptor" "github.com/ansible/receptor/pkg/utils" "github.com/ghjm/cmdline" + "github.com/spf13/viper" ) // UDPProxyServiceInbound listens on a UDP port and forwards packets to a remote Receptor service. @@ -174,7 +172,7 @@ func runUDPToNetceptorOutbound(uc *net.UDPConn, pc netceptor.PacketConner, addr } // udpProxyInboundCfg is the cmdline configuration object for a UDP inbound proxy. -type udpProxyInboundCfg struct { +type UDPProxyInboundCfg struct { Port int `required:"true" description:"Local UDP port to bind to"` BindAddr string `description:"Address to bind UDP listener to" default:"0.0.0.0"` RemoteNode string `required:"true" description:"Receptor node to connect to"` @@ -182,28 +180,32 @@ type udpProxyInboundCfg struct { } // Run runs the action. -func (cfg udpProxyInboundCfg) Run() error { +func (cfg UDPProxyInboundCfg) Run() error { netceptor.MainInstance.Logger.Debug("Running UDP inbound proxy service %v\n", cfg) return UDPProxyServiceInbound(netceptor.MainInstance, cfg.BindAddr, cfg.Port, cfg.RemoteNode, cfg.RemoteService) } // udpProxyOutboundCfg is the cmdline configuration object for a UDP outbound proxy. -type udpProxyOutboundCfg struct { +type UDPProxyOutboundCfg struct { Service string `required:"true" description:"Receptor service name to bind to"` Address string `required:"true" description:"Address for outbound UDP connection"` } // Run runs the action. -func (cfg udpProxyOutboundCfg) Run() error { +func (cfg UDPProxyOutboundCfg) Run() error { netceptor.MainInstance.Logger.Debug("Running UDP outbound proxy service %s\n", cfg) return UDPProxyServiceOutbound(netceptor.MainInstance, cfg.Service, cfg.Address) } func init() { + version := viper.GetInt("version") + if version > 1 { + return + } cmdline.RegisterConfigTypeForApp("receptor-proxies", - "udp-server", "Listen for UDP and forward via Receptor", udpProxyInboundCfg{}, cmdline.Section(servicesSection)) + "udp-server", "Listen for UDP and forward via Receptor", UDPProxyInboundCfg{}, cmdline.Section(servicesSection)) cmdline.RegisterConfigTypeForApp("receptor-proxies", - "udp-client", "Listen on a Receptor service and forward via UDP", udpProxyOutboundCfg{}, cmdline.Section(servicesSection)) + "udp-client", "Listen on a Receptor service and forward via UDP", UDPProxyOutboundCfg{}, cmdline.Section(servicesSection)) } diff --git a/pkg/services/unix_proxy.go b/pkg/services/unix_proxy.go index e197ee8be..de56b25e6 100644 --- a/pkg/services/unix_proxy.go +++ b/pkg/services/unix_proxy.go @@ -1,6 +1,3 @@ -//go:build !no_proxies && !no_services -// +build !no_proxies,!no_services - package services import ( @@ -13,6 +10,7 @@ import ( "github.com/ansible/receptor/pkg/netceptor" "github.com/ansible/receptor/pkg/utils" "github.com/ghjm/cmdline" + "github.com/spf13/viper" ) // UnixProxyServiceInbound listens on a Unix socket and forwards connections over the Receptor network. @@ -78,7 +76,7 @@ func UnixProxyServiceOutbound(s *netceptor.Netceptor, service string, tlscfg *tl } // unixProxyInboundCfg is the cmdline configuration object for a Unix socket inbound proxy. -type unixProxyInboundCfg struct { +type UnixProxyInboundCfg struct { Filename string `required:"true" description:"Socket filename, which will be overwritten"` Permissions int `description:"Socket file permissions" default:"0600"` RemoteNode string `required:"true" description:"Receptor node to connect to"` @@ -87,7 +85,7 @@ type unixProxyInboundCfg struct { } // Run runs the action. -func (cfg unixProxyInboundCfg) Run() error { +func (cfg UnixProxyInboundCfg) Run() error { netceptor.MainInstance.Logger.Debug("Running Unix socket inbound proxy service %v\n", cfg) tlscfg, err := netceptor.MainInstance.GetClientTLSConfig(cfg.TLS, cfg.RemoteNode, netceptor.ExpectedHostnameTypeReceptor) if err != nil { @@ -99,14 +97,14 @@ func (cfg unixProxyInboundCfg) Run() error { } // unixProxyOutboundCfg is the cmdline configuration object for a Unix socket outbound proxy. -type unixProxyOutboundCfg struct { +type UnixProxyOutboundCfg struct { Service string `required:"true" description:"Receptor service name to bind to"` Filename string `required:"true" description:"Socket filename, which must already exist"` TLS string `description:"Name of TLS server config for the Receptor connection"` } // Run runs the action. -func (cfg unixProxyOutboundCfg) Run() error { +func (cfg UnixProxyOutboundCfg) Run() error { netceptor.MainInstance.Logger.Debug("Running Unix socket inbound proxy service %s\n", cfg) tlscfg, err := netceptor.MainInstance.GetServerTLSConfig(cfg.TLS) if err != nil { @@ -117,10 +115,14 @@ func (cfg unixProxyOutboundCfg) Run() error { } func init() { + version := viper.GetInt("version") + if version > 1 { + return + } if runtime.GOOS != "windows" { cmdline.RegisterConfigTypeForApp("receptor-proxies", - "unix-socket-server", "Listen on a Unix socket and forward via Receptor", unixProxyInboundCfg{}, cmdline.Section(servicesSection)) + "unix-socket-server", "Listen on a Unix socket and forward via Receptor", UnixProxyInboundCfg{}, cmdline.Section(servicesSection)) cmdline.RegisterConfigTypeForApp("receptor-proxies", - "unix-socket-client", "Listen via Receptor and forward to a Unix socket", unixProxyOutboundCfg{}, cmdline.Section(servicesSection)) + "unix-socket-client", "Listen via Receptor and forward to a Unix socket", UnixProxyOutboundCfg{}, cmdline.Section(servicesSection)) } } diff --git a/pkg/types/main.go b/pkg/types/main.go index f2d1e0713..2dfa923aa 100644 --- a/pkg/types/main.go +++ b/pkg/types/main.go @@ -12,10 +12,14 @@ import ( ) type NodeCfg struct { - ID string `description:"Node ID. Defaults to local hostname." barevalue:"yes"` - DataDir string `description:"Directory in which to store node data" default:"/tmp/receptor"` - FirewallRules []netceptor.FirewallRuleData `description:"Firewall Rules (see documentation for syntax)"` - MaxIdleConnectionTimeout string `description:"Max duration with no traffic before a backend connection is timed out and refreshed."` + ID string `description:"Node ID. Defaults to the local hostname." barevalue:"yes"` + DataDir string `description:"Directory in which to store node data." default:"/tmp/receptor"` + FirewallRules []netceptor.FirewallRuleData `description:"Firewall rules, see documentation for syntax."` + MaxIdleConnectionTimeout string `description:"Maximum duration with no traffic before a backend connection is timed out and refreshed."` + ReceptorKubeSupportReconnect string + ReceptorKubeClientsetQPS string + ReceptorKubeClientsetBurst string + ReceptorKubeClientsetRateLimiter string } func (cfg NodeCfg) Init() error { diff --git a/pkg/workceptor/command.go b/pkg/workceptor/command.go index fa9394490..ed98d2eca 100644 --- a/pkg/workceptor/command.go +++ b/pkg/workceptor/command.go @@ -18,6 +18,7 @@ import ( "github.com/ghjm/cmdline" "github.com/google/shlex" + "github.com/spf13/viper" ) type BaseWorkUnitForWorkUnit interface { @@ -268,7 +269,7 @@ func (cw *commandUnit) Start() error { receptorBin = "receptor" } - cmd := exec.Command(receptorBin, "--node", "id=worker", + cmd := exec.Command(receptorBin, "--legacy", "--node", "id=worker", "--log-level", levelName, "--command-runner", fmt.Sprintf("command=%s", cw.command), @@ -482,6 +483,10 @@ func (cfg VerifyingKeyPublicCfg) PrepareVerifyingKeyPublicCfg() error { } func init() { + version := viper.GetInt("version") + if version > 1 { + return + } cmdline.RegisterConfigTypeForApp("receptor-workers", "work-signing", "Private key to sign work submissions", SigningKeyPrivateCfg{}, cmdline.Singleton, cmdline.Section(workersSection)) cmdline.RegisterConfigTypeForApp("receptor-workers", diff --git a/pkg/workceptor/kubernetes.go b/pkg/workceptor/kubernetes.go index 35464a3e5..67e4ae461 100644 --- a/pkg/workceptor/kubernetes.go +++ b/pkg/workceptor/kubernetes.go @@ -19,6 +19,7 @@ import ( "github.com/ghjm/cmdline" "github.com/google/shlex" + "github.com/spf13/viper" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -910,7 +911,18 @@ func ShouldUseReconnect(kw *KubeUnit) bool { // accepted values: "enabled", "disabled", "auto". The default is "enabled" // all invalid values will assume to be "disabled" - env, ok := os.LookupEnv("RECEPTOR_KUBE_SUPPORT_RECONNECT") + version := viper.GetInt("version") + var env string + ok := false + switch version { + case 2: + env = viper.GetString("node.ReceptorKubeSupportReconnect") + if env != "" { + ok = true + } + default: + env, ok = os.LookupEnv("RECEPTOR_KUBE_SUPPORT_RECONNECT") + } if ok { switch env { case "enabled": @@ -1200,7 +1212,18 @@ func (kw *KubeUnit) connectToKube() error { // RECEPTOR_KUBE_CLIENTSET_QPS // default: 100 - envQPS, ok := os.LookupEnv("RECEPTOR_KUBE_CLIENTSET_QPS") + version := viper.GetInt("version") + var envQPS string + ok := false + switch version { + case 2: + envQPS = viper.GetString("node.ReceptorKubeClientsetQPS") + if envQPS != "" { + ok = true + } + default: + envQPS, ok = os.LookupEnv("RECEPTOR_KUBE_CLIENTSET_QPS") + } if ok { qps, err := strconv.Atoi(envQPS) if err != nil { @@ -1216,7 +1239,16 @@ func (kw *KubeUnit) connectToKube() error { // RECEPTOR_KUBE_CLIENTSET_BURST // default: 10 x QPS - envBurst, ok := os.LookupEnv("RECEPTOR_KUBE_CLIENTSET_BURST") + var envBurst string + switch version { + case 2: + envBurst = viper.GetString("node.ReceptorKubeClientsetBurst") + if envBurst != "" { + ok = true + } + default: + envBurst, ok = os.LookupEnv("RECEPTOR_KUBE_CLIENTSET_BURST") + } if ok { burst, err := strconv.Atoi(envBurst) if err != nil { @@ -1232,7 +1264,16 @@ func (kw *KubeUnit) connectToKube() error { // RECEPTOR_KUBE_CLIENTSET_RATE_LIMITER // default: tokenbucket // options: never, always, tokenbucket - envRateLimiter, ok := os.LookupEnv("RECEPTOR_KUBE_CLIENTSET_RATE_LIMITER") + var envRateLimiter string + switch version { + case 2: + envRateLimiter = viper.GetString("node.ReceptorKubeClientsetRateLimiter") + if envRateLimiter != "" { + ok = true + } + default: + envRateLimiter, ok = os.LookupEnv("RECEPTOR_KUBE_CLIENTSET_RATE_LIMITER") + } if ok { switch envRateLimiter { case "never": @@ -1577,6 +1618,10 @@ func (cfg KubeWorkerCfg) Run() error { } func init() { + version := viper.GetInt("version") + if version > 1 { + return + } cmdline.RegisterConfigTypeForApp("receptor-workers", "work-kubernetes", "Run a worker using Kubernetes", KubeWorkerCfg{}, cmdline.Section(workersSection)) } diff --git a/pkg/workceptor/python.go b/pkg/workceptor/python.go index 05279bfdc..acd0fed3b 100644 --- a/pkg/workceptor/python.go +++ b/pkg/workceptor/python.go @@ -10,6 +10,7 @@ import ( "os/exec" "github.com/ghjm/cmdline" + "github.com/spf13/viper" ) // pythonUnit implements the WorkUnit interface. @@ -44,7 +45,7 @@ func (pw *pythonUnit) Start() error { // ************************************************************************** // workPythonCfg is the cmdline configuration object for a Python worker plugin. -type workPythonCfg struct { +type WorkPythonCfg struct { WorkType string `required:"true" description:"Name for this worker type"` Plugin string `required:"true" description:"Python module name of the worker plugin"` Function string `required:"true" description:"Receptor-exported function to call"` @@ -52,7 +53,7 @@ type workPythonCfg struct { } // NewWorker is a factory to produce worker instances. -func (cfg workPythonCfg) NewWorker(_ BaseWorkUnitForWorkUnit, w *Workceptor, unitID string, workType string) WorkUnit { +func (cfg WorkPythonCfg) NewWorker(_ BaseWorkUnitForWorkUnit, w *Workceptor, unitID string, workType string) WorkUnit { cw := &pythonUnit{ commandUnit: commandUnit{ BaseWorkUnitForWorkUnit: &BaseWorkUnit{ @@ -71,7 +72,7 @@ func (cfg workPythonCfg) NewWorker(_ BaseWorkUnitForWorkUnit, w *Workceptor, uni } // Run runs the action. -func (cfg workPythonCfg) Run() error { +func (cfg WorkPythonCfg) Run() error { err := MainInstance.RegisterWorker(cfg.WorkType, cfg.NewWorker, false) errWithDeprecation := errors.Join(err, errors.New("[DEPRECATION WARNING] This option is not currently being used. This feature will be removed from receptor in a future release")) @@ -80,6 +81,10 @@ func (cfg workPythonCfg) Run() error { } func init() { + version := viper.GetInt("version") + if version > 1 { + return + } cmdline.RegisterConfigTypeForApp("receptor-workers", - "work-python", "Run a worker using a Python plugin\n[DEPRECATION WARNING] This option is not currently being used. This feature will be removed from receptor in a future release.", workPythonCfg{}, cmdline.Section(workersSection)) + "work-python", "Run a worker using a Python plugin\n[DEPRECATION WARNING] This option is not currently being used. This feature will be removed from receptor in a future release.", WorkPythonCfg{}, cmdline.Section(workersSection)) } diff --git a/receptorctl/tests/conftest.py b/receptorctl/tests/conftest.py index bc1811364..64cce93db 100644 --- a/receptorctl/tests/conftest.py +++ b/receptorctl/tests/conftest.py @@ -266,7 +266,7 @@ def start_nodes(receptor_mesh, receptor_nodes, receptor_bin_path): ) receptor_nodes.nodes.append( subprocess.Popen( - [receptor_bin_path, "-c", config_file], + [receptor_bin_path, "--legacy", "-c", config_file], stdout=receptor_nodes.log_files[i], stderr=receptor_nodes.log_files[i], ) @@ -335,6 +335,7 @@ def receptor_mesh_access_control( @pytest.fixture(scope="function") def receptor_control_args(receptor_mesh): args = { + "--legacy": None, "--socket": f"{receptor_mesh.get_mesh_tmp_dir()}/{receptor_mesh.socket_file_name}", "--config": None, "--tls": None, diff --git a/tests/functional/cli/cli_test.go b/tests/functional/cli/cli_test.go index 5763c5795..0e7a243d8 100644 --- a/tests/functional/cli/cli_test.go +++ b/tests/functional/cli/cli_test.go @@ -28,7 +28,7 @@ func ConfirmListening(pid int, proto string) (bool, error) { func TestHelp(t *testing.T) { t.Parallel() - cmd := exec.Command("receptor", "--help") + cmd := exec.Command("receptor", "--legacy", "--help") if err := cmd.Run(); err != nil { t.Fatal(err) } @@ -50,7 +50,7 @@ func TestListeners(t *testing.T) { t.Run(listener, func(t *testing.T) { t.Parallel() receptorStdOut := bytes.Buffer{} - cmd := exec.Command("receptor", "--node", "id=test", listener, "port=0") + cmd := exec.Command("receptor", "--legacy", "--node", "id=test", listener, "port=0") cmd.Stdout = &receptorStdOut err := cmd.Start() if err != nil { @@ -98,7 +98,7 @@ func TestSSLListeners(t *testing.T) { if err != nil { t.Fatal(err) } - cmd := exec.Command("receptor", "--node", "id=test", "--tls-server", "name=server-tls", fmt.Sprintf("cert=%s", crt), fmt.Sprintf("key=%s", key), listener, fmt.Sprintf("port=%d", port), "tls=server-tls") + cmd := exec.Command("receptor", "--legacy", "--node", "id=test", "--tls-server", "name=server-tls", fmt.Sprintf("cert=%s", crt), fmt.Sprintf("key=%s", key), listener, fmt.Sprintf("port=%d", port), "tls=server-tls") cmd.Stdout = &receptorStdOut err = cmd.Start() if err != nil { @@ -143,7 +143,7 @@ func TestNegativeCost(t *testing.T) { t.Run(listener, func(t *testing.T) { t.Parallel() receptorStdOut := bytes.Buffer{} - cmd := exec.Command("receptor", "--node", "id=test", listener, "port=0", "cost=-1") + cmd := exec.Command("receptor", "--legacy", "--node", "id=test", listener, "port=0", "cost=-1") cmd.Stdout = &receptorStdOut err := cmd.Start() if err != nil { @@ -185,7 +185,7 @@ func TestCostMap(t *testing.T) { t.Run(costMapCopy, func(t *testing.T) { t.Parallel() receptorStdOut := bytes.Buffer{} - cmd := exec.Command("receptor", "--node", "id=test", listener, "port=0", fmt.Sprintf("nodecost=%s", costMapCopy)) + cmd := exec.Command("receptor", "--legacy", "--node", "id=test", listener, "port=0", fmt.Sprintf("nodecost=%s", costMapCopy)) cmd.Stdout = &receptorStdOut err := cmd.Start() if err != nil { @@ -235,7 +235,7 @@ func TestCosts(t *testing.T) { t.Run(costCopy, func(t *testing.T) { t.Parallel() receptorStdOut := bytes.Buffer{} - cmd := exec.Command("receptor", "--node", "id=test", listener, "port=0", fmt.Sprintf("cost=%s", costCopy)) + cmd := exec.Command("receptor", "--legacy", "--node", "id=test", listener, "port=0", fmt.Sprintf("cost=%s", costCopy)) cmd.Stdout = &receptorStdOut err := cmd.Start() if err != nil {