From 87450b8f8bddb5cc597a761db13271f51abb6630 Mon Sep 17 00:00:00 2001 From: Joshua Arrevillaga <2004jarrevillaga@gmail.com> Date: Thu, 29 May 2025 12:48:17 -0400 Subject: [PATCH] podman buildx inspect support Added support for "podman buildx inspect". The goal was to replicate the default output from "docker buildx inspect" as much as possible but a problem encountered was podman not supporting BuildKit. To replicate the output I resorted to printing the statements with default values but only changed the driver name to use podman instead of docker. Since there was no buildkit, gave it the value of "N/A" to depict it's not supported. For Platforms, I resorted to using the emulated architectures found on your linux system + the host architecture of your local machine or podman server. The bootstrap flag was also added but is considered a NOP since there is no buildkit container to run before running inspect. An extra field was added to the HostInfo struct so when you run "podman info" the emulated architectures will show, this was used so you can grab the information from the podman engine. Fixes #13014 Signed-off-by: Joshua Arrevillaga <2004jarrevillaga@gmail.com> --- cmd/podman/images/buildx_inspect.go | 81 +++++++++++++++++++++++++++++ libpod/define/info.go | 2 + pkg/domain/infra/abi/system.go | 4 ++ test/e2e/buildx_inspect_test.go | 38 ++++++++++++++ 4 files changed, 125 insertions(+) create mode 100644 cmd/podman/images/buildx_inspect.go create mode 100644 test/e2e/buildx_inspect_test.go diff --git a/cmd/podman/images/buildx_inspect.go b/cmd/podman/images/buildx_inspect.go new file mode 100644 index 0000000000..5fe1dab607 --- /dev/null +++ b/cmd/podman/images/buildx_inspect.go @@ -0,0 +1,81 @@ +package images + +import ( + "fmt" + "strings" + + "github.com/containers/podman/v5/cmd/podman/registry" + "github.com/spf13/cobra" +) + +type buildNode struct { + Name string + Endpoint string + Status string + BuildkitVersion string + Platforms []string +} + +type buildxInspectOutput struct { + builderName string + driverName string + Nodes []buildNode +} + +var buildxInspectCmd = &cobra.Command{ + Use: "inspect", + Short: "Inspects build capabilities", + Long: "Displays information about the current builder instance (compatibility with Docker buildx inspect)", + RunE: runBuildxInspect, + Example: `podman buildx inspect + podman buildx inspect --bootstrap`, +} + +func init() { + buildxInspectCmd.Flags().Bool("bootstrap", false, "Currently a No Op for podman") + registry.Commands = append(registry.Commands, registry.CliCommand{ + Command: buildxInspectCmd, + Parent: buildxCmd, + }) +} + +func runBuildxInspect(cmd *cobra.Command, args []string) error { + info, err := registry.ContainerEngine().Info(registry.Context()) + + if err != nil { + return fmt.Errorf("retrieving podman information: %w", err) + } + + nativePlatform := fmt.Sprintf("%s/%s", info.Host.OS, info.Host.Arch) + + // Constants are based on default values for Docker buildx inspect. + defaultNode := buildNode{ + Name: "default", + Endpoint: "default", + Status: "running", + BuildkitVersion: "N/A", + Platforms: []string{nativePlatform}, + } + + defaultNode.Platforms = append(defaultNode.Platforms, info.Host.EmulatedArchitectures...) + + out := buildxInspectOutput{ + builderName: "default", + driverName: "podman", + Nodes: []buildNode{defaultNode}, + } + + fmt.Printf("Name: %s\n", out.builderName) + fmt.Printf("Driver: %s\n", out.driverName) + fmt.Println() + + fmt.Println("Nodes:") + fmt.Printf("Name: %s\n", out.Nodes[0].Name) + fmt.Printf("Endpoint: %s\n", out.Nodes[0].Endpoint) + fmt.Printf("Status: %s\n", out.Nodes[0].Status) + fmt.Printf("Buildkit version: %s\n", out.Nodes[0].BuildkitVersion) + + fmt.Printf("Platforms: %s\n", strings.Join(out.Nodes[0].Platforms, ", ")) + fmt.Println("Labels: ") + return nil +} diff --git a/libpod/define/info.go b/libpod/define/info.go index bc37d81396..967a664c99 100644 --- a/libpod/define/info.go +++ b/libpod/define/info.go @@ -66,6 +66,8 @@ type HostInfo struct { Uptime string `json:"uptime"` Variant string `json:"variant"` Linkmode string `json:"linkmode"` + + EmulatedArchitectures []string `json:"emulatedArchitectures,omitempty"` } // RemoteSocket describes information about the API socket diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go index fd7c32eea9..204c851edc 100644 --- a/pkg/domain/infra/abi/system.go +++ b/pkg/domain/infra/abi/system.go @@ -15,6 +15,7 @@ import ( "github.com/containers/podman/v5/libpod/define" "github.com/containers/podman/v5/pkg/domain/entities" "github.com/containers/podman/v5/pkg/domain/entities/reports" + "github.com/containers/podman/v5/pkg/emulation" "github.com/containers/podman/v5/pkg/util" "github.com/containers/storage" "github.com/containers/storage/pkg/directory" @@ -27,6 +28,9 @@ func (ic *ContainerEngine) Info(ctx context.Context) (*define.Info, error) { if err != nil { return nil, err } + + info.Host.EmulatedArchitectures = emulation.Registered() + info.Host.RemoteSocket = &define.RemoteSocket{Path: ic.Libpod.RemoteURI()} // `podman system connection add` invokes podman via ssh to fill in connection string. Here diff --git a/test/e2e/buildx_inspect_test.go b/test/e2e/buildx_inspect_test.go new file mode 100644 index 0000000000..2ce79861b4 --- /dev/null +++ b/test/e2e/buildx_inspect_test.go @@ -0,0 +1,38 @@ +//go:build linux || freebsd + +package integration + +import ( + "encoding/json" + "regexp" + "strings" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +var _ = Describe("Podman buildx inspect", func() { + It("podman buildx inspect", func() { + session := podmanTest.PodmanExitCleanly("buildx", "inspect") + out := session.OutputToString() + + session_bootstrap := podmanTest.PodmanExitCleanly("buildx", "inspect", "--bootstrap") + out_bootstrap := session_bootstrap.OutputToString() + Expect(out_bootstrap).To(Equal(out), "Output of 'podman buildx inspect' and 'podman buildx inspect --bootstrap' should be the same") + + emuInfo := podmanTest.PodmanExitCleanly("info", "--format", "{{json .Host.EmulatedArchitectures}}") + var emuArchs []string + Expect(json.Unmarshal([]byte(emuInfo.OutputToString()), &emuArchs)).To(Succeed()) + + nativeInfo := podmanTest.PodmanExitCleanly("info", "--format", "{{.Host.OS}}/{{.Host.Arch}}") + nativePlat := strings.TrimSpace(nativeInfo.OutputToString()) + Expect(nativePlat).ToNot(BeEmpty()) + + expected := append(emuArchs, nativePlat) + + for _, p := range expected { + re := regexp.MustCompile(`(?s)Platforms:.*\b` + regexp.QuoteMeta(p) + `\b`) + Expect(out).To(MatchRegexp(re.String()), "missing %q in:\n%s", p, out) + } + }) +})