Skip to content

Commit

Permalink
fix: libpod API perf issue due to using /info instead of /_ping (#40) (
Browse files Browse the repository at this point in the history
…#41)

* test: log list-network timing for Docker, podman
* perf: don't use /info libpod endpoint for API version detection, as it is very slow
* fix: use _ping endpoint for libpod API version detection
* chore: refactoring
* fix: podmannet test failing on Ubuntu 22.04LTS
---------

Signed-off-by: thediveo <[email protected]>
  • Loading branch information
thediveo authored Jan 18, 2024
1 parent dbef597 commit 3a412b6
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 45 deletions.
13 changes: 13 additions & 0 deletions decorator/podmannet/_test/pind/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,17 @@ RUN dnf -y install \
dnf clean all && \
rm -rf /var/cache /var/log/dnf* /var/log/yum.* && \
systemctl enable podman.socket
RUN echo $'[containers]\n\
netns="host"\n\
userns="host"\n\
ipcns="host"\n\
utsns="host"\n\
cgroupns="host"\n\
cgroups="disabled"\n\
log_driver = "k8s-file"\n\
[engine]\n\
cgroup_manager = "cgroupfs"\n\
events_logger="file"\n\
runtime="crun"\n\
' > /etc/containers/containers.conf
CMD [ "/usr/sbin/init" ]
34 changes: 15 additions & 19 deletions decorator/podmannet/libpodclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@ func (c *Client) Close() error {
// this seems to be version-independent, but still needs any version in its
// endpoint path.
func (c *Client) apiPath(apipath string) string {
if c.libpodVersion == "" {
if apipath == "/_ping" {
// use only for initial libpod info (API version) retrieval; please note
// that all libpod API endpoints are versioned, there are not
// that all libpod API endpoints are versioned, there are no
// un-versioned endpoints like the Docker API does.
return path.Join("/v0/libpod", apipath)
return apipath
}
return path.Join("/v"+c.libpodVersion+"/libpod", apipath)
}
Expand Down Expand Up @@ -121,24 +121,20 @@ func ensureReaderClosed(resp *http.Response) {
resp.Body.Close()
}

// essentialLibpodInformation grabs just the API version information from the
// JSON salad returned by a “/vX/libpod/info” endpoint.
type essentialLibpodInformation struct {
Version struct {
APIVersion string // major.minor.patch, without "v" prefix
} `json:"version"`
}

// info returns the “essential” libpod information, that is, the libpod API
// version.
func (c *Client) info(ctx context.Context) (essentialLibpodInformation, error) {
resp, err := c.get(ctx, "/info")
var info essentialLibpodInformation
// ping the /_ping API endpoint (which is unversioned) and return the value of
// the “Libpod-Api-Version” header that came back from this endpoint, or an
// empty string. The libpod API version is in semver format, without any “v”
// prefix.
//
// Use the returned API version to set Client.libpodVersion so that following
// libpod endpoint calls are properly versioned.
func (c *Client) ping(ctx context.Context) (libpodAPIVersion string) {
resp, err := c.get(ctx, "/_ping")
defer ensureReaderClosed(resp)
if err != nil {
return info, err
return ""
}
err = json.NewDecoder(resp.Body).Decode(&info)
return info, err
return resp.Header.Get("Libpod-Api-Version")
}

// NetworkResource grabs just the few things from a podman network we're
Expand Down
8 changes: 1 addition & 7 deletions decorator/podmannet/podmannet.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,7 @@ func makePodmanNetworks(ctx context.Context, engine *model.ContainerEngine, alln
engine.API, err.Error())
return
}
info, err := libpodclient.info(ctx)
if err != nil {
log.Warnf("cannot discover podman-managed networks from API %s, reason: %s",
engine.API, err.Error())
return
}
libpodclient.libpodVersion = info.Version.APIVersion
libpodclient.libpodVersion = libpodclient.ping(ctx)
networks, _ := libpodclient.networkList(ctx)
_ = libpodclient.Close()
netnsid, _ := ops.NamespacePath(fmt.Sprintf("/proc/%d/ns/net", engine.PID)).ID()
Expand Down
36 changes: 18 additions & 18 deletions decorator/podmannet/podmannet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ import (
"github.com/ory/dockertest/v3"
"github.com/ory/dockertest/v3/docker"
"github.com/siemens/ghostwire/v2/internal/discover"
"github.com/siemens/ghostwire/v2/network"
"github.com/siemens/turtlefinder"
"github.com/thediveo/lxkns/model"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gleak"
. "github.com/thediveo/fdooze"
"github.com/thediveo/lxkns/model"
. "github.com/thediveo/success"
)

Expand All @@ -29,8 +30,8 @@ const (
pindName = "ghostwire-pind"
pindImageName = "siemens/ghostwire-pind"

spinupTimeout = 10 * time.Second
spinupPolling = 500 * time.Millisecond
nifDiscoveryTimeout = 5 * time.Second
nifDiscoveryPolling = 250 * time.Millisecond

goroutinesUnwindTimeout = 2 * time.Second
goroutinesUnwindPolling = 250 * time.Millisecond
Expand Down Expand Up @@ -92,9 +93,9 @@ var _ = Describe("turtle finder", Ordered, Serial, func() {
Repository: pindImageName,
Privileged: true,
Mounts: []string{
"/var", // well, this actually is an unnamed volume
"/var/lib/containers", // well, this actually is an unnamed volume
},
Tty: true,
Tty: false,
}, func(hc *docker.HostConfig) {
hc.Init = false
hc.Tmpfs = map[string]string{
Expand Down Expand Up @@ -138,7 +139,11 @@ var _ = Describe("turtle finder", Ordered, Serial, func() {

By("running a canary container connected to the default 'podman' network")
Expect(pindCntr.Exec([]string{
"podman", "run", "-d", "-it", "--rm", "--name", "canary", "busybox",
"podman", "run", "-d", "--rm",
"--name", "canary",
"--net", "podman", /* WHAT?? otherwise doesn't connect the container??? */
"busybox",
"/bin/sh", "-c", "while true; do sleep 1; done",
}, dockertest.ExecOptions{
StdOut: GinkgoWriter,
StdErr: GinkgoWriter,
Expand Down Expand Up @@ -172,25 +177,20 @@ var _ = Describe("turtle finder", Ordered, Serial, func() {
defer cizer.Close()

By("running a full Ghostwire discovery that should pick up the podman networks")
allnetns, lxknsdisco := discover.Discover(ctx, cizer, nil)
Expect(lxknsdisco.Processes).To(HaveKey(model.PIDType(pindCntr.Container.State.Pid)))
pindNetnsID := lxknsdisco.Processes[model.PIDType(pindCntr.Container.State.Pid)].
Namespaces[model.NetNS].ID()
Expect(pindNetnsID).NotTo(BeZero())
Expect(allnetns).To(HaveKey(pindNetnsID))
pindNetns := allnetns[pindNetnsID]
// We expect the following network interfaces to be present inside our
// podman-in-docker container:
// - eth0 ... a.k.a. the "mcwielahm" network
// - podman0 ... a.k.a. the "podman" network
Expect(pindNetns.Nifs).To(ContainElements(
Eventually(ctx, func() map[int]network.Interface {
allnetns, lxknsdisco := discover.Discover(ctx, cizer, nil)
pindNetnsID := lxknsdisco.Processes[model.PIDType(pindCntr.Container.State.Pid)].
Namespaces[model.NetNS].ID()
return allnetns[pindNetnsID].Nifs
}).Within(nifDiscoveryPolling).ProbeEvery(nifDiscoveryPolling).Should(ContainElements(
HaveField("Nif()", And(
HaveField("Name", "eth0"),
HaveField("Alias", "mcwielahm"))),
HaveField("Nif()", And(
HaveField("Name", "podman0"),
HaveField("Alias", "podman"))),
))

})

})
2 changes: 1 addition & 1 deletion defs_version.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 3a412b6

Please sign in to comment.