Diff
1diff --git a/cmd/soft/serve/server.go b/cmd/soft/serve/server.go
2index 69d5db5a8fcf40c3c1f09786599303a61cb47c65..76e55f581234203600edebb4f7b7bcb5d1d155f7 100644
3--- a/cmd/soft/serve/server.go
4+++ b/cmd/soft/serve/server.go
5@@ -93,34 +93,51 @@ func NewServer(ctx context.Context) (*Server, error) {
6 // Start starts the SSH server.
7 func (s *Server) Start() error {
8 errg, _ := errgroup.WithContext(s.ctx)
9- errg.Go(func() error {
10- s.logger.Print("Starting Git daemon", "addr", s.Config.Git.ListenAddr)
11- if err := s.GitDaemon.ListenAndServe(); !errors.Is(err, daemon.ErrServerClosed) {
12- return err
13- }
14- return nil
15- })
16- errg.Go(func() error {
17- s.logger.Print("Starting HTTP server", "addr", s.Config.HTTP.ListenAddr)
18- if err := s.HTTPServer.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
19- return err
20- }
21- return nil
22- })
23- errg.Go(func() error {
24- s.logger.Print("Starting SSH server", "addr", s.Config.SSH.ListenAddr)
25- if err := s.SSHServer.ListenAndServe(); !errors.Is(err, ssh.ErrServerClosed) {
26- return err
27- }
28- return nil
29- })
30- errg.Go(func() error {
31- s.logger.Print("Starting Stats server", "addr", s.Config.Stats.ListenAddr)
32- if err := s.StatsServer.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
33- return err
34- }
35- return nil
36- })
37+
38+ // optionally start the SSH server
39+ if s.Config.SSH.Enabled {
40+ errg.Go(func() error {
41+ s.logger.Print("Starting SSH server", "addr", s.Config.SSH.ListenAddr)
42+ if err := s.SSHServer.ListenAndServe(); !errors.Is(err, ssh.ErrServerClosed) {
43+ return err
44+ }
45+ return nil
46+ })
47+ }
48+
49+ // optionally start the git daemon
50+ if s.Config.Git.Enabled {
51+ errg.Go(func() error {
52+ s.logger.Print("Starting Git daemon", "addr", s.Config.Git.ListenAddr)
53+ if err := s.GitDaemon.ListenAndServe(); !errors.Is(err, daemon.ErrServerClosed) {
54+ return err
55+ }
56+ return nil
57+ })
58+ }
59+
60+ // optionally start the HTTP server
61+ if s.Config.HTTP.Enabled {
62+ errg.Go(func() error {
63+ s.logger.Print("Starting HTTP server", "addr", s.Config.HTTP.ListenAddr)
64+ if err := s.HTTPServer.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
65+ return err
66+ }
67+ return nil
68+ })
69+ }
70+
71+ // optionally start the Stats server
72+ if s.Config.Stats.Enabled {
73+ errg.Go(func() error {
74+ s.logger.Print("Starting Stats server", "addr", s.Config.Stats.ListenAddr)
75+ if err := s.StatsServer.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
76+ return err
77+ }
78+ return nil
79+ })
80+ }
81+
82 errg.Go(func() error {
83 s.Cron.Start()
84 return nil
85diff --git a/pkg/config/config.go b/pkg/config/config.go
86index 2b650984c2d401f12c579fa702f32c7828ae5841..9d8395d4546720580e51bb2afc31925a54b2000a 100644
87--- a/pkg/config/config.go
88+++ b/pkg/config/config.go
89@@ -18,6 +18,9 @@ var binPath = "soft"
90
91 // SSHConfig is the configuration for the SSH server.
92 type SSHConfig struct {
93+ // Enabled toggles the SSH server on/off
94+ Enabled bool `env:"ENABLED" yaml:"enabled"`
95+
96 // ListenAddr is the address on which the SSH server will listen.
97 ListenAddr string `env:"LISTEN_ADDR" yaml:"listen_addr"`
98
99@@ -39,6 +42,9 @@ type SSHConfig struct {
100
101 // GitConfig is the Git daemon configuration for the server.
102 type GitConfig struct {
103+ // Enabled toggles the Git daemon on/off
104+ Enabled bool `env:"ENABLED" yaml:"enabled"`
105+
106 // ListenAddr is the address on which the Git daemon will listen.
107 ListenAddr string `env:"LISTEN_ADDR" yaml:"listen_addr"`
108
109@@ -57,6 +63,9 @@ type GitConfig struct {
110
111 // HTTPConfig is the HTTP configuration for the server.
112 type HTTPConfig struct {
113+ // Enabled toggles the HTTP server on/off
114+ Enabled bool `env:"ENABLED" yaml:"enabled"`
115+
116 // ListenAddr is the address on which the HTTP server will listen.
117 ListenAddr string `env:"LISTEN_ADDR" yaml:"listen_addr"`
118
119@@ -72,6 +81,9 @@ type HTTPConfig struct {
120
121 // StatsConfig is the configuration for the stats server.
122 type StatsConfig struct {
123+ // Enabled toggles the Stats server on/off
124+ Enabled bool `env:"ENABLED" yaml:"enabled"`
125+
126 // ListenAddr is the address on which the stats server will listen.
127 ListenAddr string `env:"LISTEN_ADDR" yaml:"listen_addr"`
128 }
129@@ -165,21 +177,25 @@ func (c *Config) Environ() []string {
130 fmt.Sprintf("SOFT_SERVE_DATA_PATH=%s", c.DataPath),
131 fmt.Sprintf("SOFT_SERVE_NAME=%s", c.Name),
132 fmt.Sprintf("SOFT_SERVE_INITIAL_ADMIN_KEYS=%s", strings.Join(c.InitialAdminKeys, "\n")),
133+ fmt.Sprintf("SOFT_SERVE_SSH_ENABLED=%t", c.SSH.Enabled),
134 fmt.Sprintf("SOFT_SERVE_SSH_LISTEN_ADDR=%s", c.SSH.ListenAddr),
135 fmt.Sprintf("SOFT_SERVE_SSH_PUBLIC_URL=%s", c.SSH.PublicURL),
136 fmt.Sprintf("SOFT_SERVE_SSH_KEY_PATH=%s", c.SSH.KeyPath),
137 fmt.Sprintf("SOFT_SERVE_SSH_CLIENT_KEY_PATH=%s", c.SSH.ClientKeyPath),
138 fmt.Sprintf("SOFT_SERVE_SSH_MAX_TIMEOUT=%d", c.SSH.MaxTimeout),
139 fmt.Sprintf("SOFT_SERVE_SSH_IDLE_TIMEOUT=%d", c.SSH.IdleTimeout),
140+ fmt.Sprintf("SOFT_SERVE_GIT_ENABLED=%t", c.Git.Enabled),
141 fmt.Sprintf("SOFT_SERVE_GIT_LISTEN_ADDR=%s", c.Git.ListenAddr),
142 fmt.Sprintf("SOFT_SERVE_GIT_PUBLIC_URL=%s", c.Git.PublicURL),
143 fmt.Sprintf("SOFT_SERVE_GIT_MAX_TIMEOUT=%d", c.Git.MaxTimeout),
144 fmt.Sprintf("SOFT_SERVE_GIT_IDLE_TIMEOUT=%d", c.Git.IdleTimeout),
145 fmt.Sprintf("SOFT_SERVE_GIT_MAX_CONNECTIONS=%d", c.Git.MaxConnections),
146+ fmt.Sprintf("SOFT_SERVE_HTTP_ENABLED=%t", c.HTTP.Enabled),
147 fmt.Sprintf("SOFT_SERVE_HTTP_LISTEN_ADDR=%s", c.HTTP.ListenAddr),
148 fmt.Sprintf("SOFT_SERVE_HTTP_TLS_KEY_PATH=%s", c.HTTP.TLSKeyPath),
149 fmt.Sprintf("SOFT_SERVE_HTTP_TLS_CERT_PATH=%s", c.HTTP.TLSCertPath),
150 fmt.Sprintf("SOFT_SERVE_HTTP_PUBLIC_URL=%s", c.HTTP.PublicURL),
151+ fmt.Sprintf("SOFT_SERVE_STATS_ENABLED=%t", c.Stats.Enabled),
152 fmt.Sprintf("SOFT_SERVE_STATS_LISTEN_ADDR=%s", c.Stats.ListenAddr),
153 fmt.Sprintf("SOFT_SERVE_LOG_FORMAT=%s", c.Log.Format),
154 fmt.Sprintf("SOFT_SERVE_LOG_TIME_FORMAT=%s", c.Log.TimeFormat),
155@@ -318,6 +334,7 @@ func DefaultConfig() *Config {
156 Name: "Soft Serve",
157 DataPath: DefaultDataPath(),
158 SSH: SSHConfig{
159+ Enabled: true,
160 ListenAddr: ":23231",
161 PublicURL: "ssh://localhost:23231",
162 KeyPath: filepath.Join("ssh", "soft_serve_host_ed25519"),
163@@ -326,6 +343,7 @@ func DefaultConfig() *Config {
164 IdleTimeout: 10 * 60, // 10 minutes
165 },
166 Git: GitConfig{
167+ Enabled: true,
168 ListenAddr: ":9418",
169 PublicURL: "git://localhost",
170 MaxTimeout: 0,
171@@ -333,10 +351,12 @@ func DefaultConfig() *Config {
172 MaxConnections: 32,
173 },
174 HTTP: HTTPConfig{
175+ Enabled: true,
176 ListenAddr: ":23232",
177 PublicURL: "http://localhost:23232",
178 },
179 Stats: StatsConfig{
180+ Enabled: true,
181 ListenAddr: "localhost:23233",
182 },
183 Log: LogConfig{
184diff --git a/testscript/script_test.go b/testscript/script_test.go
185index 564372808f2e8f6b7eacc86a33f348a48428e070..8f3a6af43497752cae064723faf0ccc1da02c8b1 100644
186--- a/testscript/script_test.go
187+++ b/testscript/script_test.go
188@@ -79,20 +79,21 @@ func TestScript(t *testing.T) {
189 UpdateScripts: *update,
190 RequireExplicitExec: true,
191 Cmds: map[string]func(ts *testscript.TestScript, neg bool, args []string){
192- "soft": cmdSoft("admin", admin1.Signer()),
193- "usoft": cmdSoft("user1", user1.Signer()),
194- "git": cmdGit(admin1Key),
195- "ugit": cmdGit(user1Key),
196- "curl": cmdCurl,
197- "mkfile": cmdMkfile,
198- "envfile": cmdEnvfile,
199- "readfile": cmdReadfile,
200- "dos2unix": cmdDos2Unix,
201- "new-webhook": cmdNewWebhook,
202- "ensureserverrunning": cmdEnsureServerRunning,
203- "stopserver": cmdStopserver,
204- "ui": cmdUI(admin1.Signer()),
205- "uui": cmdUI(user1.Signer()),
206+ "soft": cmdSoft("admin", admin1.Signer()),
207+ "usoft": cmdSoft("user1", user1.Signer()),
208+ "git": cmdGit(admin1Key),
209+ "ugit": cmdGit(user1Key),
210+ "curl": cmdCurl,
211+ "mkfile": cmdMkfile,
212+ "envfile": cmdEnvfile,
213+ "readfile": cmdReadfile,
214+ "dos2unix": cmdDos2Unix,
215+ "new-webhook": cmdNewWebhook,
216+ "ensureserverrunning": cmdEnsureServerRunning,
217+ "ensureservernotrunning": cmdEnsureServerNotRunning,
218+ "stopserver": cmdStopserver,
219+ "ui": cmdUI(admin1.Signer()),
220+ "uui": cmdUI(user1.Signer()),
221 },
222 Setup: func(e *testscript.Env) error {
223 // Add binPath to PATH
224@@ -112,6 +113,8 @@ func TestScript(t *testing.T) {
225 e.Setenv("DATA_PATH", data)
226 e.Setenv("SSH_PORT", fmt.Sprintf("%d", sshPort))
227 e.Setenv("HTTP_PORT", fmt.Sprintf("%d", httpPort))
228+ e.Setenv("STATS_PORT", fmt.Sprintf("%d", statsPort))
229+ e.Setenv("GIT_PORT", fmt.Sprintf("%d", gitPort))
230 e.Setenv("ADMIN1_AUTHORIZED_KEY", admin1.AuthorizedKey())
231 e.Setenv("ADMIN2_AUTHORIZED_KEY", admin2.AuthorizedKey())
232 e.Setenv("USER1_AUTHORIZED_KEY", user1.AuthorizedKey())
233@@ -496,6 +499,32 @@ func cmdEnsureServerRunning(ts *testscript.TestScript, neg bool, args []string)
234 }
235 }
236
237+func cmdEnsureServerNotRunning(ts *testscript.TestScript, neg bool, args []string) {
238+ if len(args) < 1 {
239+ ts.Fatalf("Must supply a TCP port of one of the services to connect to. " +
240+ "These are set as env vars as they are randomized. " +
241+ "Example usage: \"cmdensureservernotrunning SSH_PORT\"\n" +
242+ "Valid values for the env var: SSH_PORT|HTTP_PORT|GIT_PORT|STATS_PORT")
243+ }
244+
245+ port := ts.Getenv(args[0])
246+
247+ // verify that the server is not up
248+ addr := net.JoinHostPort("localhost", port)
249+ for {
250+ conn, _ := net.DialTimeout(
251+ "tcp",
252+ addr,
253+ time.Second,
254+ )
255+ if conn != nil {
256+ ts.Fatalf("server is running on port %s while it should not be running", port)
257+ conn.Close()
258+ }
259+ break
260+ }
261+}
262+
263 func cmdStopserver(ts *testscript.TestScript, neg bool, args []string) {
264 // stop the server
265 resp, err := http.DefaultClient.Head(fmt.Sprintf("%s/__stop", ts.Getenv("SOFT_SERVE_HTTP_PUBLIC_URL")))
266diff --git a/testscript/testdata/config-servers-git_disabled.txtar b/testscript/testdata/config-servers-git_disabled.txtar
267new file mode 100644
268index 0000000000000000000000000000000000000000..7fe34eda1e28c3430ac7214ca6b16ef0867d23fb
269--- /dev/null
270+++ b/testscript/testdata/config-servers-git_disabled.txtar
271@@ -0,0 +1,18 @@
272+# vi: set ft=conf
273+
274+# disable git listening
275+env SOFT_SERVE_SSH_ENABLED=true
276+env SOFT_SERVE_GIT_ENABLED=false
277+env SOFT_SERVE_HTTP_ENABLED=true
278+env SOFT_SERVE_STATS_ENABLED=true
279+
280+# start soft serve
281+exec soft serve --sync-hooks &
282+
283+# wait for the ssh + other servers to come up
284+ensureserverrunning SSH_PORT
285+ensureserverrunning HTTP_PORT
286+ensureserverrunning STATS_PORT
287+
288+# ensure that the disabled server is not running
289+ensureservernotrunning GIT_PORT
290diff --git a/testscript/testdata/config-servers-http_disabled.txtar b/testscript/testdata/config-servers-http_disabled.txtar
291new file mode 100644
292index 0000000000000000000000000000000000000000..7eee3ed5d52673a4f2b3d1ebb57c36a4f0f7d06b
293--- /dev/null
294+++ b/testscript/testdata/config-servers-http_disabled.txtar
295@@ -0,0 +1,19 @@
296+# vi: set ft=conf
297+
298+# disable http listening
299+env SOFT_SERVE_SSH_ENABLED=true
300+env SOFT_SERVE_GIT_ENABLED=true
301+env SOFT_SERVE_HTTP_ENABLED=false
302+env SOFT_SERVE_STATS_ENABLED=true
303+
304+# start soft serve
305+exec soft serve --sync-hooks &
306+
307+# wait for the ssh + other servers to come up
308+ensureserverrunning SSH_PORT
309+ensureserverrunning GIT_PORT
310+ensureserverrunning STATS_PORT
311+
312+# ensure that the disabled server is not running
313+ensureservernotrunning HTTP_PORT
314+
315diff --git a/testscript/testdata/config-servers-ssh_disabled.txtar b/testscript/testdata/config-servers-ssh_disabled.txtar
316new file mode 100644
317index 0000000000000000000000000000000000000000..30b7492deae79d7688409341d4db256b7a603b38
318--- /dev/null
319+++ b/testscript/testdata/config-servers-ssh_disabled.txtar
320@@ -0,0 +1,18 @@
321+# vi: set ft=conf
322+
323+# disable ssh listening
324+env SOFT_SERVE_SSH_ENABLED=false
325+env SOFT_SERVE_GIT_ENABLED=true
326+env SOFT_SERVE_HTTP_ENABLED=true
327+env SOFT_SERVE_STATS_ENABLED=true
328+
329+# start soft serve
330+exec soft serve --sync-hooks &
331+
332+# wait for the git + other servers to come up
333+ensureserverrunning GIT_PORT
334+ensureserverrunning HTTP_PORT
335+ensureserverrunning STATS_PORT
336+
337+# ensure that the disabled server is not running
338+ensureservernotrunning SSH_PORT
339diff --git a/testscript/testdata/config-servers-stats_disabled.txtar b/testscript/testdata/config-servers-stats_disabled.txtar
340new file mode 100644
341index 0000000000000000000000000000000000000000..2b8031752933733274760701411eb587c176e3c0
342--- /dev/null
343+++ b/testscript/testdata/config-servers-stats_disabled.txtar
344@@ -0,0 +1,18 @@
345+# vi: set ft=conf
346+
347+# disable stats listening
348+env SOFT_SERVE_SSH_ENABLED=true
349+env SOFT_SERVE_GIT_ENABLED=true
350+env SOFT_SERVE_HTTP_ENABLED=true
351+env SOFT_SERVE_STATS_ENABLED=false
352+
353+# start soft serve
354+exec soft serve --sync-hooks &
355+
356+# wait for the ssh + other servers to come up
357+ensureserverrunning SSH_PORT
358+ensureserverrunning GIT_PORT
359+ensureserverrunning HTTP_PORT
360+
361+# ensure that the disabled server is not running
362+ensureservernotrunning STATS_PORT