Report correct RemoteURI

Rather than assuming a filesystem path, the API service URI is recorded
in the libpod runtime configuration and then reported as requested.

Note: All schemes other than "unix" are hard-coded to report URI exists.

Fixes #12023

Signed-off-by: Jhon Honce <jhonce@redhat.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
Daniel J Walsh 2022-04-27 15:48:04 -04:00
parent b1e9ea38e5
commit 5fa6f686db
No known key found for this signature in database
GPG key ID: A2DF901DABE2C028
10 changed files with 92 additions and 96 deletions

View file

@ -4,17 +4,18 @@
package system
import (
"context"
"fmt"
"net"
"net/url"
"os"
"path/filepath"
"github.com/containers/podman/v4/cmd/podman/registry"
api "github.com/containers/podman/v4/pkg/api/server"
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/containers/podman/v4/pkg/domain/infra"
"github.com/containers/podman/v4/pkg/servicereaper"
"github.com/containers/podman/v4/pkg/util"
"github.com/coreos/go-systemd/v22/activation"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/pflag"
@ -27,7 +28,26 @@ func restService(flags *pflag.FlagSet, cfg *entities.PodmanConfig, opts entities
err error
)
if opts.URI != "" {
libpodRuntime, err := infra.GetRuntime(registry.Context(), flags, cfg)
if err != nil {
return err
}
if opts.URI == "" {
if _, found := os.LookupEnv("LISTEN_PID"); !found {
return errors.New("no service URI provided and socket activation protocol is not active")
}
listeners, err := activation.Listeners()
if err != nil {
return fmt.Errorf("cannot retrieve file descriptors from systemd: %w", err)
}
if len(listeners) != 1 {
return fmt.Errorf("wrong number of file descriptors for socket activation protocol (%d != 1)", len(listeners))
}
listener = listeners[0]
libpodRuntime.SetRemoteURI(listeners[0].Addr().String())
} else {
uri, err := url.Parse(opts.URI)
if err != nil {
return errors.Errorf("%s is an invalid socket destination", opts.URI)
@ -39,7 +59,6 @@ func restService(flags *pflag.FlagSet, cfg *entities.PodmanConfig, opts entities
if err != nil {
return err
}
util.SetSocketPath(path)
if os.Getenv("LISTEN_FDS") != "" {
// If it is activated by systemd, use the first LISTEN_FD (3)
// instead of opening the socket file.
@ -67,6 +86,7 @@ func restService(flags *pflag.FlagSet, cfg *entities.PodmanConfig, opts entities
default:
logrus.Debugf("Attempting API Service endpoint scheme %q", uri.Scheme)
}
libpodRuntime.SetRemoteURI(uri.String())
}
// Close stdin, so shortnames will not prompt
@ -78,15 +98,10 @@ func restService(flags *pflag.FlagSet, cfg *entities.PodmanConfig, opts entities
if err := unix.Dup2(int(devNullfile.Fd()), int(os.Stdin.Fd())); err != nil {
return err
}
rt, err := infra.GetRuntime(context.Background(), flags, cfg)
if err != nil {
return err
}
servicereaper.Start()
infra.StartWatcher(rt)
server, err := api.NewServerWithSettings(rt, listener, opts)
infra.StartWatcher(libpodRuntime)
server, err := api.NewServerWithSettings(libpodRuntime, listener, opts)
if err != nil {
return err
}

View file

@ -1158,7 +1158,7 @@ func (r *Runtime) getVolumePlugin(name string) (*plugin.VolumePlugin, error) {
return plugin.GetVolumePlugin(name, pluginPath)
}
// GetSecretsStoreageDir returns the directory that the secrets manager should take
// GetSecretsStorageDir returns the directory that the secrets manager should take
func (r *Runtime) GetSecretsStorageDir() string {
return filepath.Join(r.store.GraphRoot(), "secrets")
}
@ -1206,7 +1206,17 @@ func (r *Runtime) Network() nettypes.ContainerNetwork {
return r.network
}
// Network returns the network interface which is used by the runtime
// GetDefaultNetworkName returns the network interface which is used by the runtime
func (r *Runtime) GetDefaultNetworkName() string {
return r.config.Network.DefaultNetwork
}
// RemoteURI returns the API server URI
func (r *Runtime) RemoteURI() string {
return r.config.Engine.RemoteURI
}
// SetRemoteURI records the API server URI
func (r *Runtime) SetRemoteURI(uri string) {
r.config.Engine.RemoteURI = uri
}

View file

@ -20,7 +20,6 @@ import (
"github.com/containers/podman/v4/pkg/api/server/idle"
"github.com/containers/podman/v4/pkg/api/types"
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/coreos/go-systemd/v22/activation"
"github.com/coreos/go-systemd/v22/daemon"
"github.com/gorilla/mux"
"github.com/gorilla/schema"
@ -65,25 +64,7 @@ func NewServerWithSettings(runtime *libpod.Runtime, listener net.Listener, opts
}
func newServer(runtime *libpod.Runtime, listener net.Listener, opts entities.ServiceOptions) (*APIServer, error) {
// If listener not provided try socket activation protocol
if listener == nil {
if _, found := os.LookupEnv("LISTEN_PID"); !found {
return nil, fmt.Errorf("no service listener provided and socket activation protocol is not active")
}
listeners, err := activation.Listeners()
if err != nil {
return nil, fmt.Errorf("cannot retrieve file descriptors from systemd: %w", err)
}
if len(listeners) != 1 {
return nil, fmt.Errorf("wrong number of file descriptors for socket activation protocol (%d != 1)", len(listeners))
}
listener = listeners[0]
// note that activation.Listeners() return nil when it cannot listen on the fd (i.e. udp connection)
if listener == nil {
return nil, fmt.Errorf("unexpected fd received from systemd: cannot listen on it")
}
}
logrus.Infof("API service listening on %q. URI: %q", listener.Addr(), runtime.RemoteURI())
if opts.CorsHeaders == "" {
logrus.Debug("CORS Headers were not set")
} else {

View file

@ -6,6 +6,7 @@ import (
"net/url"
"os"
"os/exec"
"path/filepath"
"github.com/containers/common/pkg/cgroups"
"github.com/containers/common/pkg/config"
@ -27,27 +28,40 @@ func (ic *ContainerEngine) Info(ctx context.Context) (*define.Info, error) {
if err != nil {
return nil, err
}
info.Host.RemoteSocket = &define.RemoteSocket{Path: ic.Libpod.RemoteURI()}
socketPath, err := util.SocketPath()
// `podman system connection add` invokes podman via ssh to fill in connection string. Here
// we are reporting the default systemd activation socket path as we cannot know if a future
// service may be run with another URI.
if ic.Libpod.RemoteURI() == "" {
xdg := "/run"
if path, err := util.GetRuntimeDir(); err != nil {
// Info is as good as we can guess...
return info, err
} else if path != "" {
xdg = path
}
uri := url.URL{
Scheme: "unix",
Path: filepath.Join(xdg, "podman", "podman.sock"),
}
ic.Libpod.SetRemoteURI(uri.String())
info.Host.RemoteSocket.Path = uri.Path
}
uri, err := url.Parse(ic.Libpod.RemoteURI())
if err != nil {
return nil, err
}
rs := define.RemoteSocket{
Path: socketPath,
Exists: false,
if uri.Scheme == "unix" {
_, err := os.Stat(uri.Path)
info.Host.RemoteSocket.Exists = err == nil
} else {
info.Host.RemoteSocket.Exists = true
}
// Check if the socket exists
if fi, err := os.Stat(socketPath); err == nil {
if fi.Mode()&os.ModeSocket != 0 {
rs.Exists = true
}
}
// TODO
// it was suggested future versions of this could perform
// a ping on the socket for greater confidence the socket is
// actually active.
info.Host.RemoteSocket = &rs
return info, err
}

View file

@ -731,29 +731,6 @@ func IDtoolsToRuntimeSpec(idMaps []idtools.IDMap) (convertedIDMap []specs.LinuxI
return convertedIDMap
}
var socketPath string
func SetSocketPath(path string) {
socketPath = path
}
func SocketPath() (string, error) {
if socketPath != "" {
return socketPath, nil
}
xdg, err := GetRuntimeDir()
if err != nil {
return "", err
}
if len(xdg) == 0 {
// If no xdg is returned, assume root socket
xdg = "/run"
}
// Glue the socket path together
return filepath.Join(xdg, "podman", "podman.sock"), nil
}
func LookupUser(name string) (*user.User, error) {
// Assume UID look up first, if it fails lookup by username
if u, err := user.LookupId(name); err == nil {

View file

@ -119,33 +119,31 @@ var _ = Describe("Podman Info", func() {
Expect(string(out)).To(Equal(expect))
})
It("podman info check RemoteSocket", func() {
It("check RemoteSocket ", func() {
session := podmanTest.Podman([]string{"info", "--format", "{{.Host.RemoteSocket.Path}}"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.OutputToString()).To(MatchRegexp("/run/.*podman.*sock"))
if IsRemote() {
session = podmanTest.Podman([]string{"info", "--format", "{{.Host.RemoteSocket.Exists}}"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.OutputToString()).To(ContainSubstring("true"))
}
})
It("verify ServiceIsRemote", func() {
session := podmanTest.Podman([]string{"info", "--format", "{{.Host.ServiceIsRemote}}"})
session = podmanTest.Podman([]string{"info", "--format", "{{.Host.ServiceIsRemote}}"})
session.WaitWithDefaultTimeout()
Expect(session).To(Exit(0))
Expect(session).Should(Exit(0))
if podmanTest.RemoteTest {
Expect(session.OutputToString()).To(ContainSubstring("true"))
Expect(session.OutputToString()).To(Equal("true"))
} else {
Expect(session.OutputToString()).To(ContainSubstring("false"))
Expect(session.OutputToString()).To(Equal("false"))
}
session = podmanTest.Podman([]string{"info", "--format", "{{.Host.RemoteSocket.Exists}}"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
if IsRemote() {
Expect(session.OutputToString()).To(ContainSubstring("true"))
}
})
It("Podman info must contain cgroupControllers with ReleventControllers", func() {
It("Podman info must contain cgroupControllers with RelevantControllers", func() {
SkipIfRootless("Hard to tell which controllers are going to be enabled for rootless")
SkipIfRootlessCgroupsV1("Disable cgroups not supported on cgroupv1 for rootless users")
session := podmanTest.Podman([]string{"info", "--format", "{{.Host.CgroupControllers}}"})

View file

@ -3180,8 +3180,10 @@ invalid kube kind
Expect(ls).Should(Exit(0))
Expect(ls.OutputToStringArray()).To(HaveLen(1))
containerLen := podmanTest.Podman([]string{"pod", "inspect", pod.Name, "--format", "'{{len .Containers}}'"})
containerLen := podmanTest.Podman([]string{"pod", "inspect", pod.Name, "--format", "{{len .Containers}}"})
containerLen.WaitWithDefaultTimeout()
Expect(containerLen).Should(Exit(0))
Expect(containerLen.OutputToString()).To(Equal("2"))
ctr01Name := "ctr01"
ctr02Name := "ctr02"
@ -3199,7 +3201,7 @@ invalid kube kind
replace.WaitWithDefaultTimeout()
Expect(replace).Should(Exit(0))
newContainerLen := podmanTest.Podman([]string{"pod", "inspect", newPod.Name, "--format", "'{{len .Containers}}'"})
newContainerLen := podmanTest.Podman([]string{"pod", "inspect", newPod.Name, "--format", "{{len .Containers}}"})
newContainerLen.WaitWithDefaultTimeout()
Expect(newContainerLen).Should(Exit(0))
Expect(newContainerLen.OutputToString()).NotTo(Equal(containerLen.OutputToString()))

View file

@ -247,7 +247,7 @@ var _ = Describe("podman system connection", func() {
// podman-remote commands will be executed by ginkgo directly.
SkipIfContainerized("sshd is not available when running in a container")
SkipIfRemote("connection heuristic requires both podman and podman-remote binaries")
SkipIfNotRootless("FIXME: setup ssh keys when root")
SkipIfNotRootless(fmt.Sprintf("FIXME: setup ssh keys when root. uid(%d) euid(%d)", os.Getuid(), os.Geteuid()))
SkipIfSystemdNotRunning("cannot test connection heuristic if systemd is not running")
SkipIfNotActive("sshd", "cannot test connection heuristic if sshd is not running")
})

View file

@ -20,7 +20,7 @@ var _ = Describe("podman system service", func() {
// The timeout used to for the service to respond. As shown in #12167,
// this may take some time on machines under high load.
var timeout = 20
var timeout = 30
BeforeEach(func() {
tempdir, err := CreateTempDirInTempDir()

View file

@ -99,10 +99,9 @@ $c2[ ]\+tcp://localhost:54321[ ]\+true" \
_SERVICE_PID=$!
wait_for_port localhost $_SERVICE_PORT
# FIXME: #12023, RemoteSocket is always /run/something
# run_podman info --format '{{.Host.RemoteSocket.Path}}'
# is "$output" "tcp:localhost:$_SERVICE_PORT" \
# "podman info works, and talks to the correct server"
_run_podman_remote info --format '{{.Host.RemoteSocket.Path}}'
is "$output" "tcp:localhost:$_SERVICE_PORT" \
"podman info works, and talks to the correct server"
_run_podman_remote info --format '{{.Store.GraphRoot}}'
is "$output" "${PODMAN_TMPDIR}/root" \