Detailed changes
@@ -93,34 +93,51 @@ func NewServer(ctx context.Context) (*Server, error) {
// Start starts the SSH server.
func (s *Server) Start() error {
errg, _ := errgroup.WithContext(s.ctx)
- errg.Go(func() error {
- s.logger.Print("Starting Git daemon", "addr", s.Config.Git.ListenAddr)
- if err := s.GitDaemon.ListenAndServe(); !errors.Is(err, daemon.ErrServerClosed) {
- return err
- }
- return nil
- })
- errg.Go(func() error {
- s.logger.Print("Starting HTTP server", "addr", s.Config.HTTP.ListenAddr)
- if err := s.HTTPServer.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
- return err
- }
- return nil
- })
- errg.Go(func() error {
- s.logger.Print("Starting SSH server", "addr", s.Config.SSH.ListenAddr)
- if err := s.SSHServer.ListenAndServe(); !errors.Is(err, ssh.ErrServerClosed) {
- return err
- }
- return nil
- })
- errg.Go(func() error {
- s.logger.Print("Starting Stats server", "addr", s.Config.Stats.ListenAddr)
- if err := s.StatsServer.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
- return err
- }
- return nil
- })
+
+ // optionally start the SSH server
+ if s.Config.SSH.Enabled {
+ errg.Go(func() error {
+ s.logger.Print("Starting SSH server", "addr", s.Config.SSH.ListenAddr)
+ if err := s.SSHServer.ListenAndServe(); !errors.Is(err, ssh.ErrServerClosed) {
+ return err
+ }
+ return nil
+ })
+ }
+
+ // optionally start the git daemon
+ if s.Config.Git.Enabled {
+ errg.Go(func() error {
+ s.logger.Print("Starting Git daemon", "addr", s.Config.Git.ListenAddr)
+ if err := s.GitDaemon.ListenAndServe(); !errors.Is(err, daemon.ErrServerClosed) {
+ return err
+ }
+ return nil
+ })
+ }
+
+ // optionally start the HTTP server
+ if s.Config.HTTP.Enabled {
+ errg.Go(func() error {
+ s.logger.Print("Starting HTTP server", "addr", s.Config.HTTP.ListenAddr)
+ if err := s.HTTPServer.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
+ return err
+ }
+ return nil
+ })
+ }
+
+ // optionally start the Stats server
+ if s.Config.Stats.Enabled {
+ errg.Go(func() error {
+ s.logger.Print("Starting Stats server", "addr", s.Config.Stats.ListenAddr)
+ if err := s.StatsServer.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
+ return err
+ }
+ return nil
+ })
+ }
+
errg.Go(func() error {
s.Cron.Start()
return nil
@@ -18,6 +18,9 @@ var binPath = "soft"
// SSHConfig is the configuration for the SSH server.
type SSHConfig struct {
+ // Enabled toggles the SSH server on/off
+ Enabled bool `env:"ENABLED" yaml:"enabled"`
+
// ListenAddr is the address on which the SSH server will listen.
ListenAddr string `env:"LISTEN_ADDR" yaml:"listen_addr"`
@@ -39,6 +42,9 @@ type SSHConfig struct {
// GitConfig is the Git daemon configuration for the server.
type GitConfig struct {
+ // Enabled toggles the Git daemon on/off
+ Enabled bool `env:"ENABLED" yaml:"enabled"`
+
// ListenAddr is the address on which the Git daemon will listen.
ListenAddr string `env:"LISTEN_ADDR" yaml:"listen_addr"`
@@ -57,6 +63,9 @@ type GitConfig struct {
// HTTPConfig is the HTTP configuration for the server.
type HTTPConfig struct {
+ // Enabled toggles the HTTP server on/off
+ Enabled bool `env:"ENABLED" yaml:"enabled"`
+
// ListenAddr is the address on which the HTTP server will listen.
ListenAddr string `env:"LISTEN_ADDR" yaml:"listen_addr"`
@@ -72,6 +81,9 @@ type HTTPConfig struct {
// StatsConfig is the configuration for the stats server.
type StatsConfig struct {
+ // Enabled toggles the Stats server on/off
+ Enabled bool `env:"ENABLED" yaml:"enabled"`
+
// ListenAddr is the address on which the stats server will listen.
ListenAddr string `env:"LISTEN_ADDR" yaml:"listen_addr"`
}
@@ -165,21 +177,25 @@ func (c *Config) Environ() []string {
fmt.Sprintf("SOFT_SERVE_DATA_PATH=%s", c.DataPath),
fmt.Sprintf("SOFT_SERVE_NAME=%s", c.Name),
fmt.Sprintf("SOFT_SERVE_INITIAL_ADMIN_KEYS=%s", strings.Join(c.InitialAdminKeys, "\n")),
+ fmt.Sprintf("SOFT_SERVE_SSH_ENABLED=%t", c.SSH.Enabled),
fmt.Sprintf("SOFT_SERVE_SSH_LISTEN_ADDR=%s", c.SSH.ListenAddr),
fmt.Sprintf("SOFT_SERVE_SSH_PUBLIC_URL=%s", c.SSH.PublicURL),
fmt.Sprintf("SOFT_SERVE_SSH_KEY_PATH=%s", c.SSH.KeyPath),
fmt.Sprintf("SOFT_SERVE_SSH_CLIENT_KEY_PATH=%s", c.SSH.ClientKeyPath),
fmt.Sprintf("SOFT_SERVE_SSH_MAX_TIMEOUT=%d", c.SSH.MaxTimeout),
fmt.Sprintf("SOFT_SERVE_SSH_IDLE_TIMEOUT=%d", c.SSH.IdleTimeout),
+ fmt.Sprintf("SOFT_SERVE_GIT_ENABLED=%t", c.Git.Enabled),
fmt.Sprintf("SOFT_SERVE_GIT_LISTEN_ADDR=%s", c.Git.ListenAddr),
fmt.Sprintf("SOFT_SERVE_GIT_PUBLIC_URL=%s", c.Git.PublicURL),
fmt.Sprintf("SOFT_SERVE_GIT_MAX_TIMEOUT=%d", c.Git.MaxTimeout),
fmt.Sprintf("SOFT_SERVE_GIT_IDLE_TIMEOUT=%d", c.Git.IdleTimeout),
fmt.Sprintf("SOFT_SERVE_GIT_MAX_CONNECTIONS=%d", c.Git.MaxConnections),
+ fmt.Sprintf("SOFT_SERVE_HTTP_ENABLED=%t", c.HTTP.Enabled),
fmt.Sprintf("SOFT_SERVE_HTTP_LISTEN_ADDR=%s", c.HTTP.ListenAddr),
fmt.Sprintf("SOFT_SERVE_HTTP_TLS_KEY_PATH=%s", c.HTTP.TLSKeyPath),
fmt.Sprintf("SOFT_SERVE_HTTP_TLS_CERT_PATH=%s", c.HTTP.TLSCertPath),
fmt.Sprintf("SOFT_SERVE_HTTP_PUBLIC_URL=%s", c.HTTP.PublicURL),
+ fmt.Sprintf("SOFT_SERVE_STATS_ENABLED=%t", c.Stats.Enabled),
fmt.Sprintf("SOFT_SERVE_STATS_LISTEN_ADDR=%s", c.Stats.ListenAddr),
fmt.Sprintf("SOFT_SERVE_LOG_FORMAT=%s", c.Log.Format),
fmt.Sprintf("SOFT_SERVE_LOG_TIME_FORMAT=%s", c.Log.TimeFormat),
@@ -318,6 +334,7 @@ func DefaultConfig() *Config {
Name: "Soft Serve",
DataPath: DefaultDataPath(),
SSH: SSHConfig{
+ Enabled: true,
ListenAddr: ":23231",
PublicURL: "ssh://localhost:23231",
KeyPath: filepath.Join("ssh", "soft_serve_host_ed25519"),
@@ -326,6 +343,7 @@ func DefaultConfig() *Config {
IdleTimeout: 10 * 60, // 10 minutes
},
Git: GitConfig{
+ Enabled: true,
ListenAddr: ":9418",
PublicURL: "git://localhost",
MaxTimeout: 0,
@@ -333,10 +351,12 @@ func DefaultConfig() *Config {
MaxConnections: 32,
},
HTTP: HTTPConfig{
+ Enabled: true,
ListenAddr: ":23232",
PublicURL: "http://localhost:23232",
},
Stats: StatsConfig{
+ Enabled: true,
ListenAddr: "localhost:23233",
},
Log: LogConfig{
@@ -79,20 +79,21 @@ func TestScript(t *testing.T) {
UpdateScripts: *update,
RequireExplicitExec: true,
Cmds: map[string]func(ts *testscript.TestScript, neg bool, args []string){
- "soft": cmdSoft("admin", admin1.Signer()),
- "usoft": cmdSoft("user1", user1.Signer()),
- "git": cmdGit(admin1Key),
- "ugit": cmdGit(user1Key),
- "curl": cmdCurl,
- "mkfile": cmdMkfile,
- "envfile": cmdEnvfile,
- "readfile": cmdReadfile,
- "dos2unix": cmdDos2Unix,
- "new-webhook": cmdNewWebhook,
- "ensureserverrunning": cmdEnsureServerRunning,
- "stopserver": cmdStopserver,
- "ui": cmdUI(admin1.Signer()),
- "uui": cmdUI(user1.Signer()),
+ "soft": cmdSoft("admin", admin1.Signer()),
+ "usoft": cmdSoft("user1", user1.Signer()),
+ "git": cmdGit(admin1Key),
+ "ugit": cmdGit(user1Key),
+ "curl": cmdCurl,
+ "mkfile": cmdMkfile,
+ "envfile": cmdEnvfile,
+ "readfile": cmdReadfile,
+ "dos2unix": cmdDos2Unix,
+ "new-webhook": cmdNewWebhook,
+ "ensureserverrunning": cmdEnsureServerRunning,
+ "ensureservernotrunning": cmdEnsureServerNotRunning,
+ "stopserver": cmdStopserver,
+ "ui": cmdUI(admin1.Signer()),
+ "uui": cmdUI(user1.Signer()),
},
Setup: func(e *testscript.Env) error {
// Add binPath to PATH
@@ -112,6 +113,8 @@ func TestScript(t *testing.T) {
e.Setenv("DATA_PATH", data)
e.Setenv("SSH_PORT", fmt.Sprintf("%d", sshPort))
e.Setenv("HTTP_PORT", fmt.Sprintf("%d", httpPort))
+ e.Setenv("STATS_PORT", fmt.Sprintf("%d", statsPort))
+ e.Setenv("GIT_PORT", fmt.Sprintf("%d", gitPort))
e.Setenv("ADMIN1_AUTHORIZED_KEY", admin1.AuthorizedKey())
e.Setenv("ADMIN2_AUTHORIZED_KEY", admin2.AuthorizedKey())
e.Setenv("USER1_AUTHORIZED_KEY", user1.AuthorizedKey())
@@ -496,6 +499,32 @@ func cmdEnsureServerRunning(ts *testscript.TestScript, neg bool, args []string)
}
}
+func cmdEnsureServerNotRunning(ts *testscript.TestScript, neg bool, args []string) {
+ if len(args) < 1 {
+ ts.Fatalf("Must supply a TCP port of one of the services to connect to. " +
+ "These are set as env vars as they are randomized. " +
+ "Example usage: \"cmdensureservernotrunning SSH_PORT\"\n" +
+ "Valid values for the env var: SSH_PORT|HTTP_PORT|GIT_PORT|STATS_PORT")
+ }
+
+ port := ts.Getenv(args[0])
+
+ // verify that the server is not up
+ addr := net.JoinHostPort("localhost", port)
+ for {
+ conn, _ := net.DialTimeout(
+ "tcp",
+ addr,
+ time.Second,
+ )
+ if conn != nil {
+ ts.Fatalf("server is running on port %s while it should not be running", port)
+ conn.Close()
+ }
+ break
+ }
+}
+
func cmdStopserver(ts *testscript.TestScript, neg bool, args []string) {
// stop the server
resp, err := http.DefaultClient.Head(fmt.Sprintf("%s/__stop", ts.Getenv("SOFT_SERVE_HTTP_PUBLIC_URL")))
@@ -0,0 +1,18 @@
+# vi: set ft=conf
+
+# disable git listening
+env SOFT_SERVE_SSH_ENABLED=true
+env SOFT_SERVE_GIT_ENABLED=false
+env SOFT_SERVE_HTTP_ENABLED=true
+env SOFT_SERVE_STATS_ENABLED=true
+
+# start soft serve
+exec soft serve --sync-hooks &
+
+# wait for the ssh + other servers to come up
+ensureserverrunning SSH_PORT
+ensureserverrunning HTTP_PORT
+ensureserverrunning STATS_PORT
+
+# ensure that the disabled server is not running
+ensureservernotrunning GIT_PORT
@@ -0,0 +1,19 @@
+# vi: set ft=conf
+
+# disable http listening
+env SOFT_SERVE_SSH_ENABLED=true
+env SOFT_SERVE_GIT_ENABLED=true
+env SOFT_SERVE_HTTP_ENABLED=false
+env SOFT_SERVE_STATS_ENABLED=true
+
+# start soft serve
+exec soft serve --sync-hooks &
+
+# wait for the ssh + other servers to come up
+ensureserverrunning SSH_PORT
+ensureserverrunning GIT_PORT
+ensureserverrunning STATS_PORT
+
+# ensure that the disabled server is not running
+ensureservernotrunning HTTP_PORT
+
@@ -0,0 +1,18 @@
+# vi: set ft=conf
+
+# disable ssh listening
+env SOFT_SERVE_SSH_ENABLED=false
+env SOFT_SERVE_GIT_ENABLED=true
+env SOFT_SERVE_HTTP_ENABLED=true
+env SOFT_SERVE_STATS_ENABLED=true
+
+# start soft serve
+exec soft serve --sync-hooks &
+
+# wait for the git + other servers to come up
+ensureserverrunning GIT_PORT
+ensureserverrunning HTTP_PORT
+ensureserverrunning STATS_PORT
+
+# ensure that the disabled server is not running
+ensureservernotrunning SSH_PORT
@@ -0,0 +1,18 @@
+# vi: set ft=conf
+
+# disable stats listening
+env SOFT_SERVE_SSH_ENABLED=true
+env SOFT_SERVE_GIT_ENABLED=true
+env SOFT_SERVE_HTTP_ENABLED=true
+env SOFT_SERVE_STATS_ENABLED=false
+
+# start soft serve
+exec soft serve --sync-hooks &
+
+# wait for the ssh + other servers to come up
+ensureserverrunning SSH_PORT
+ensureserverrunning GIT_PORT
+ensureserverrunning HTTP_PORT
+
+# ensure that the disabled server is not running
+ensureservernotrunning STATS_PORT