V2 Fix support for tcp://[::]<port> connections

* Fix support for socket activation, on remote and service

$ systemd-socket-activate -l 8083 --fdname=podman bin/podman system service --log-level=debug --time=30
$ bin/podman-remote --remote=tcp://[::]:8083 image ls

Or, use the podman.{socket,service} unit files

$ bin/podman-remote --remote=unix:///run/podman/podman.sock image ls

Signed-off-by: Jhon Honce <jhonce@redhat.com>
This commit is contained in:
Jhon Honce
2020-04-17 16:27:17 -07:00
parent aa97cb5f42
commit 4e0326241b
5 changed files with 27 additions and 28 deletions

View File

@ -57,7 +57,7 @@ func service(cmd *cobra.Command, args []string) error {
if err != nil { if err != nil {
return err return err
} }
logrus.Infof("using API endpoint: \"%s\"", apiURI) logrus.Infof("using API endpoint: '%s'", apiURI)
opts := entities.ServiceOptions{ opts := entities.ServiceOptions{
URI: apiURI, URI: apiURI,
@ -75,7 +75,6 @@ func service(cmd *cobra.Command, args []string) error {
} }
func resolveApiURI(_url []string) (string, error) { func resolveApiURI(_url []string) (string, error) {
// When determining _*THE*_ listening endpoint -- // When determining _*THE*_ listening endpoint --
// 1) User input wins always // 1) User input wins always
// 2) systemd socket activation // 2) systemd socket activation
@ -83,14 +82,15 @@ func resolveApiURI(_url []string) (string, error) {
// 4) if varlink -- adapter.DefaultVarlinkAddress // 4) if varlink -- adapter.DefaultVarlinkAddress
// 5) lastly adapter.DefaultAPIAddress // 5) lastly adapter.DefaultAPIAddress
if _url == nil { if len(_url) == 0 {
if v, found := os.LookupEnv("PODMAN_SOCKET"); found { if v, found := os.LookupEnv("PODMAN_SOCKET"); found {
logrus.Debugf("PODMAN_SOCKET='%s' used to determine API endpoint", v)
_url = []string{v} _url = []string{v}
} }
} }
switch { switch {
case len(_url) > 0: case len(_url) > 0 && _url[0] != "":
return _url[0], nil return _url[0], nil
case systemd.SocketActivated(): case systemd.SocketActivated():
logrus.Info("using systemd socket activation to determine API endpoint") logrus.Info("using systemd socket activation to determine API endpoint")

View File

@ -51,7 +51,7 @@ func NewServerWithSettings(runtime *libpod.Runtime, duration time.Duration, list
func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Listener) (*APIServer, error) { func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Listener) (*APIServer, error) {
// If listener not provided try socket activation protocol // If listener not provided try socket activation protocol
if listener == nil { if listener == nil {
if _, found := os.LookupEnv("LISTEN_FDS"); !found { if _, found := os.LookupEnv("LISTEN_PID"); !found {
return nil, errors.Errorf("Cannot create API Server, no listener provided and socket activation protocol is not active.") return nil, errors.Errorf("Cannot create API Server, no listener provided and socket activation protocol is not active.")
} }
@ -125,7 +125,7 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li
if err != nil { if err != nil {
methods = []string{"<N/A>"} methods = []string{"<N/A>"}
} }
logrus.Debugf("Methods: %s Path: %s", strings.Join(methods, ", "), path) logrus.Debugf("Methods: %6s Path: %s", strings.Join(methods, ", "), path)
return nil return nil
}) })
} }
@ -179,6 +179,7 @@ func (s *APIServer) Shutdown() error {
} }
// Gracefully shutdown server, duration of wait same as idle window // Gracefully shutdown server, duration of wait same as idle window
// TODO: Should we really wait the idle window for shutdown?
ctx, cancel := context.WithTimeout(context.Background(), s.idleTracker.Duration) ctx, cancel := context.WithTimeout(context.Background(), s.idleTracker.Duration)
defer cancel() defer cancel()
go func() { go func() {

View File

@ -126,7 +126,7 @@ func tcpClient(_url *url.URL) (*http.Client, error) {
return &http.Client{ return &http.Client{
Transport: &http.Transport{ Transport: &http.Transport{
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) { DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return net.Dial("tcp", _url.Path) return net.Dial("tcp", _url.Host)
}, },
DisableCompression: true, DisableCompression: true,
}, },

View File

@ -35,7 +35,7 @@ func (ic *ContainerEngine) Info(ctx context.Context) (*define.Info, error) {
func (ic *ContainerEngine) RestService(_ context.Context, opts entities.ServiceOptions) error { func (ic *ContainerEngine) RestService(_ context.Context, opts entities.ServiceOptions) error {
var ( var (
listener net.Listener listener *net.Listener
err error err error
) )
@ -45,13 +45,14 @@ func (ic *ContainerEngine) RestService(_ context.Context, opts entities.ServiceO
return errors.Errorf("%s is an invalid socket destination", opts.URI) return errors.Errorf("%s is an invalid socket destination", opts.URI)
} }
address := strings.Join(fields[1:], ":") address := strings.Join(fields[1:], ":")
listener, err = net.Listen(fields[0], address) l, err := net.Listen(fields[0], address)
if err != nil { if err != nil {
return errors.Wrapf(err, "unable to create socket %s", opts.URI) return errors.Wrapf(err, "unable to create socket %s", opts.URI)
} }
listener = &l
} }
server, err := api.NewServerWithSettings(ic.Libpod, opts.Timeout, &listener) server, err := api.NewServerWithSettings(ic.Libpod, opts.Timeout, listener)
if err != nil { if err != nil {
return err return err
} }
@ -62,7 +63,9 @@ func (ic *ContainerEngine) RestService(_ context.Context, opts entities.ServiceO
}() }()
err = server.Serve() err = server.Serve()
_ = listener.Close() if listener != nil {
_ = (*listener).Close()
}
return err return err
} }

View File

@ -3,38 +3,33 @@ package systemd
import ( import (
"os" "os"
"strconv" "strconv"
"strings"
) )
// SocketActivated determine if podman is running under the socket activation protocol // SocketActivated determine if podman is running under the socket activation protocol
// Criteria is based on the expectations of "github.com/coreos/go-systemd/v22/activation"
func SocketActivated() bool { func SocketActivated() bool {
pid, pid_found := os.LookupEnv("LISTEN_PID") pid, found := os.LookupEnv("LISTEN_PID")
fds, fds_found := os.LookupEnv("LISTEN_FDS") if !found {
fdnames, fdnames_found := os.LookupEnv("LISTEN_FDNAMES")
if !(pid_found && fds_found && fdnames_found) {
return false return false
} }
p, err := strconv.Atoi(pid) p, err := strconv.Atoi(pid)
if err != nil || p != os.Getpid() { if err != nil || p != os.Getpid() {
return false return false
} }
fds, found := os.LookupEnv("LISTEN_FDS")
if !found {
return false
}
nfds, err := strconv.Atoi(fds) nfds, err := strconv.Atoi(fds)
if err != nil || nfds < 1 { if err != nil || nfds == 0 {
return false return false
} }
// First available file descriptor is always 3. // "github.com/coreos/go-systemd/v22/activation" will use and validate this variable's
if nfds > 1 { // value. We're just providing a fast fail
names := strings.Split(fdnames, ":") if _, found = os.LookupEnv("LISTEN_FDNAMES"); !found {
for _, n := range names { return false
if strings.Contains(n, "podman") {
return true
} }
}
}
return true return true
} }