fix: now attempt to bind to the zot server socket to check if the server is running (#3703)

Signed-off-by: Andrei Aaron <andreifdaaron@gmail.com>
This commit is contained in:
Andrei Aaron
2026-01-15 20:02:15 +02:00
committed by GitHub
parent 7c9064574d
commit d33c1e3b22
2 changed files with 51 additions and 16 deletions
+9 -13
View File
@@ -4,7 +4,6 @@ import (
"context"
"fmt"
"net"
"net/http"
"os"
"os/signal"
"syscall"
@@ -208,27 +207,24 @@ func newVerifyFeatureRetentionCmd(conf *config.Config) *cobra.Command {
// checkServerRunning checks if a Zot server is already running on the configured address/port.
func checkServerRunning(conf *config.Config, logger zlog.Logger) error {
req, err := http.NewRequestWithContext(context.Background(),
http.MethodGet,
fmt.Sprintf("http://%s/v2", net.JoinHostPort(conf.HTTP.Address, conf.HTTP.Port)),
nil)
addr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(conf.HTTP.Address, conf.HTTP.Port))
if err != nil {
msg := "failed to create http request"
msg := "failed to resolve TCP address"
logger.Error().Err(err).Msg(msg)
return fmt.Errorf("%s: %w", msg, err)
}
response, err := http.DefaultClient.Do(req)
if err == nil {
response.Body.Close()
logger.Warn().Err(zerr.ErrServerIsRunning).
Msg("server is running, in order to perform the verify-feature retention command the server should be shut down")
listener, err := net.ListenTCP("tcp", addr)
if err != nil {
msg := fmt.Sprintf("failed to bind to %s (server may be running or address unavailable)", addr.String())
logger.Error().Err(err).Msg(msg)
return zerr.ErrServerIsRunning
return fmt.Errorf("%s: %w", msg, err)
}
return nil
// Binding succeeded, server is not running
return listener.Close()
}
// isRemoteCacheEnabled checks if the remote cache is enabled for the global and subpaths storage configs.
+42 -3
View File
@@ -154,15 +154,54 @@ func TestRetentionCheckNegative(t *testing.T) {
os.Args = []string{"cli_test", "verify-feature", "retention", "-l", logFile, "-t", "30s", configFile}
err := cli.NewServerRootCmd().Execute()
So(err, ShouldNotBeNil)
So(err, ShouldEqual, zerr.ErrServerIsRunning)
// Check that error indicates binding failure (server is running)
So(err.Error(), ShouldContainSubstring, "failed to bind")
// Verify warning messages are logged to the log file
// Verify warning and error messages are logged to the log file
logContent, err := os.ReadFile(logFile)
So(err, ShouldBeNil)
So(string(logContent), ShouldContainSubstring,
"local storage detected - the zot server must be stopped to access the storage database")
So(string(logContent), ShouldContainSubstring,
"server is running, in order to perform the verify-feature retention command the server should be shut down")
"failed to bind")
})
Convey("invalid address format", t, func(c C) {
testDir := t.TempDir()
logFile := MakeTempFilePath(t, "retention-check.log")
port := GetFreePort()
// Use an invalid IPv6 address format that will pass LoadConfiguration
// but fail net.ResolveTCPAddr immediately (syntax error, no DNS lookup)
content := fmt.Sprintf(`{
"distSpecVersion": "1.1.1",
"storage": {
"rootDirectory": "%s",
"gc": true
},
"http": {
"address": "[invalid:ipv6",
"port": "%s"
},
"log": {
"level": "debug"
}
}`, testDir, port)
configFile := MakeTempFileWithContent(t, "zot-config.json", content)
os.Args = []string{"cli_test", "verify-feature", "retention", "-l", logFile, "-t", "30s", configFile}
err := cli.NewServerRootCmd().Execute()
So(err, ShouldNotBeNil)
// Check that error indicates TCP address resolution failure
So(err.Error(), ShouldContainSubstring, "failed to resolve TCP address")
// Verify error message is logged to the log file
logContent, err := os.ReadFile(logFile)
So(err, ShouldBeNil)
So(string(logContent), ShouldContainSubstring,
"local storage detected - the zot server must be stopped to access the storage database")
So(string(logContent), ShouldContainSubstring,
"failed to resolve TCP address")
})
Convey("invalid log-file flag", t, func(c C) {