mirror of
https://github.com/project-zot/zot.git
synced 2024-12-16 21:56:37 -05:00
report listening port when chosen by kernel (#770)
Based off of the PR by @thesayyn https://github.com/project-zot/zot/pull/720 Signed-off-by: Ramkumar Chinchani <rchincha@cisco.com>
This commit is contained in:
parent
d68bbf6743
commit
f3faae0e09
5 changed files with 133 additions and 0 deletions
|
@ -55,4 +55,5 @@ var (
|
||||||
ErrSyncSignature = errors.New("sync: couldn't get upstream notary/cosign signatures")
|
ErrSyncSignature = errors.New("sync: couldn't get upstream notary/cosign signatures")
|
||||||
ErrImageLintAnnotations = errors.New("routes: lint checks failed")
|
ErrImageLintAnnotations = errors.New("routes: lint checks failed")
|
||||||
ErrParsingAuthHeader = errors.New("auth: failed parsing authorization header")
|
ErrParsingAuthHeader = errors.New("auth: failed parsing authorization header")
|
||||||
|
ErrBadType = errors.New("core: invalid type")
|
||||||
)
|
)
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
goSync "sync"
|
goSync "sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
@ -41,6 +42,8 @@ type Controller struct {
|
||||||
Server *http.Server
|
Server *http.Server
|
||||||
Metrics monitoring.MetricServer
|
Metrics monitoring.MetricServer
|
||||||
wgShutDown *goSync.WaitGroup // use it to gracefully shutdown goroutines
|
wgShutDown *goSync.WaitGroup // use it to gracefully shutdown goroutines
|
||||||
|
// runtime params
|
||||||
|
chosenPort int // kernel-chosen port
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewController(config *config.Config) *Controller {
|
func NewController(config *config.Config) *Controller {
|
||||||
|
@ -103,6 +106,10 @@ func DumpRuntimeParams(log log.Logger) {
|
||||||
evt.Msg("runtime params")
|
evt.Msg("runtime params")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Controller) GetPort() int {
|
||||||
|
return c.chosenPort
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Controller) Run(reloadCtx context.Context) error {
|
func (c *Controller) Run(reloadCtx context.Context) error {
|
||||||
// print the current configuration, but strip secrets
|
// print the current configuration, but strip secrets
|
||||||
c.Log.Info().Interface("params", c.Config.Sanitize()).Msg("configuration settings")
|
c.Log.Info().Interface("params", c.Config.Sanitize()).Msg("configuration settings")
|
||||||
|
@ -171,6 +178,25 @@ func (c *Controller) Run(reloadCtx context.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.Config.HTTP.Port == "0" || c.Config.HTTP.Port == "" {
|
||||||
|
chosenAddr, ok := listener.Addr().(*net.TCPAddr)
|
||||||
|
if !ok {
|
||||||
|
c.Log.Error().Str("port", c.Config.HTTP.Port).Msg("invalid addr type")
|
||||||
|
|
||||||
|
return errors.ErrBadType
|
||||||
|
}
|
||||||
|
|
||||||
|
c.chosenPort = chosenAddr.Port
|
||||||
|
|
||||||
|
c.Log.Info().Int("port", chosenAddr.Port).IPAddr("address", chosenAddr.IP).Msg(
|
||||||
|
"port is unspecified, listening on kernel chosen port",
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
chosenPort, _ := strconv.ParseInt(c.Config.HTTP.Port, 10, 64)
|
||||||
|
|
||||||
|
c.chosenPort = int(chosenPort)
|
||||||
|
}
|
||||||
|
|
||||||
if c.Config.HTTP.TLS != nil && c.Config.HTTP.TLS.Key != "" && c.Config.HTTP.TLS.Cert != "" {
|
if c.Config.HTTP.TLS != nil && c.Config.HTTP.TLS.Key != "" && c.Config.HTTP.TLS.Cert != "" {
|
||||||
server.TLSConfig = &tls.Config{
|
server.TLSConfig = &tls.Config{
|
||||||
CipherSuites: []uint16{
|
CipherSuites: []uint16{
|
||||||
|
|
|
@ -143,6 +143,55 @@ func TestRunAlreadyRunningServer(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAutoPortSelection(t *testing.T) {
|
||||||
|
Convey("Run server with specifying a port", t, func() {
|
||||||
|
conf := config.New()
|
||||||
|
conf.HTTP.Port = "0"
|
||||||
|
|
||||||
|
logFile, err := os.CreateTemp("", "zot-log*.txt")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
conf.Log.Output = logFile.Name()
|
||||||
|
defer os.Remove(logFile.Name()) // clean up
|
||||||
|
|
||||||
|
ctlr := api.NewController(conf)
|
||||||
|
ctlr.Config.Storage.RootDirectory = t.TempDir()
|
||||||
|
|
||||||
|
go startServer(ctlr)
|
||||||
|
time.Sleep(1000 * time.Millisecond)
|
||||||
|
defer stopServer(ctlr)
|
||||||
|
|
||||||
|
file, err := os.Open(logFile.Name())
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
|
||||||
|
var contents bytes.Buffer
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
if time.Since(start) < time.Second*30 {
|
||||||
|
t.Logf("Exhausted: Controller did not print the expected log within 30 seconds")
|
||||||
|
}
|
||||||
|
text := scanner.Text()
|
||||||
|
contents.WriteString(text)
|
||||||
|
if strings.Contains(text, "Port unspecified") {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
t.Logf(scanner.Text())
|
||||||
|
}
|
||||||
|
So(scanner.Err(), ShouldBeNil)
|
||||||
|
So(contents.String(), ShouldContainSubstring,
|
||||||
|
"port is unspecified, listening on kernel chosen port",
|
||||||
|
)
|
||||||
|
So(contents.String(), ShouldContainSubstring, "\"address\":\"127.0.0.1\"")
|
||||||
|
So(contents.String(), ShouldContainSubstring, "\"port\":")
|
||||||
|
|
||||||
|
So(ctlr.GetPort(), ShouldBeGreaterThan, 0)
|
||||||
|
So(ctlr.GetPort(), ShouldBeLessThan, 65536)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestObjectStorageController(t *testing.T) {
|
func TestObjectStorageController(t *testing.T) {
|
||||||
skipIt(t)
|
skipIt(t)
|
||||||
Convey("Negative make a new object storage controller", t, func() {
|
Convey("Negative make a new object storage controller", t, func() {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -232,6 +233,10 @@ func validateStorageConfig(cfg *config.Config) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateConfiguration(config *config.Config) error {
|
func validateConfiguration(config *config.Config) error {
|
||||||
|
if err := validateHTTP(config); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if err := validateGC(config); err != nil {
|
if err := validateGC(config); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -514,6 +519,21 @@ func validateLDAP(config *config.Config) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateHTTP(config *config.Config) error {
|
||||||
|
if config.HTTP.Port != "" {
|
||||||
|
port, err := strconv.ParseInt(config.HTTP.Port, 10, 64)
|
||||||
|
if err != nil || (port < 0 || port > 65535) {
|
||||||
|
log.Error().Str("port", config.HTTP.Port).Msg("invalid port")
|
||||||
|
|
||||||
|
return errors.ErrBadConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("HTTP port %d\n", port)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func validateGC(config *config.Config) error {
|
func validateGC(config *config.Config) error {
|
||||||
// enforce GC params
|
// enforce GC params
|
||||||
if config.Storage.GCDelay < 0 {
|
if config.Storage.GCDelay < 0 {
|
||||||
|
|
|
@ -540,6 +540,43 @@ func TestLoadConfig(t *testing.T) {
|
||||||
err = cli.LoadConfiguration(config, tmpfile.Name())
|
err = cli.LoadConfiguration(config, tmpfile.Name())
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Convey("Test HTTP port", t, func() {
|
||||||
|
config := config.New()
|
||||||
|
tmpfile, err := os.CreateTemp("", "zot-test*.json")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
defer os.Remove(tmpfile.Name())
|
||||||
|
|
||||||
|
content := []byte(`{"storage":{"rootDirectory":"/tmp/zot",
|
||||||
|
"subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true"},
|
||||||
|
"/b": {"rootDirectory": "/zot-a","dedupe":"true"}}},
|
||||||
|
"http":{"address":"127.0.0.1","port":"8080","realm":"zot",
|
||||||
|
"auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`)
|
||||||
|
err = os.WriteFile(tmpfile.Name(), content, 0o0600)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
err = cli.LoadConfiguration(config, tmpfile.Name())
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
content = []byte(`{"storage":{"rootDirectory":"/tmp/zot",
|
||||||
|
"subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true"},
|
||||||
|
"/b": {"rootDirectory": "/zot-a","dedupe":"true"}}},
|
||||||
|
"http":{"address":"127.0.0.1","port":"-1","realm":"zot",
|
||||||
|
"auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`)
|
||||||
|
err = os.WriteFile(tmpfile.Name(), content, 0o0600)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
err = cli.LoadConfiguration(config, tmpfile.Name())
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
|
||||||
|
content = []byte(`{"storage":{"rootDirectory":"/tmp/zot",
|
||||||
|
"subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true"},
|
||||||
|
"/b": {"rootDirectory": "/zot-a","dedupe":"true"}}},
|
||||||
|
"http":{"address":"127.0.0.1","port":"65536","realm":"zot",
|
||||||
|
"auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`)
|
||||||
|
err = os.WriteFile(tmpfile.Name(), content, 0o0600)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
err = cli.LoadConfiguration(config, tmpfile.Name())
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGC(t *testing.T) {
|
func TestGC(t *testing.T) {
|
||||||
|
|
Loading…
Reference in a new issue