Repository: moby/moby (language: go)

Issue:
`docker info`: expose runtime features ("rro" mount mode , etc.)
### Description

Follow-up to:
- https://github.com/moby/moby/pull/45278


`docker info --format=json` should print runtime-specific features such as the availability of the `rro` mount mode.

Not sure if we should expose the entire OCI runtime `*features.Features` struct into `docker info --format=json`, or just expose its small subset:
https://github.com/moby/moby/blob/591c98cdbee73d36fe27abdb4456f8d70b8e549d/daemon/runtime_unix.go#L226-L236


Discussion / hints:

Fix patch:
diff --git a/api/server/router/system/system_routes.go b/api/server/router/system/system_routes.go
index 613b04322f9d5..ab91247d7ee75 100644
--- a/api/server/router/system/system_routes.go
+++ b/api/server/router/system/system_routes.go
@@ -91,6 +91,12 @@ func (s *systemRouter) getInfo(ctx context.Context, w http.ResponseWriter, r *ht
 				info.OperatingSystem = "<unknown>"
 			}
 		}
+		if versions.LessThan(version, "1.44") {
+			for k, rt := range info.Runtimes {
+				// Status field introduced inl API v1.44.
+				info.Runtimes[k] = system.RuntimeWithStatus{Runtime: rt.Runtime}
+			}
+		}
 		if versions.GreaterThanOrEqualTo(version, "1.42") {
 			info.KernelMemory = false
 		}
diff --git a/api/swagger.yaml b/api/swagger.yaml
index a24cc758d2991..8bc11103b2870 100644
--- a/api/swagger.yaml
+++ b/api/swagger.yaml
@@ -5618,6 +5618,28 @@ definitions:
         items:
           type: "string"
         example: ["--debug", "--systemd-cgroup=false"]
+      status:
+        description: |
+          Information specific to the runtime.
+
+          While this API specification does not define data provided by runtimes,
+          the following well-known properties may be provided by runtimes:
+
+          `org.opencontainers.runtime-spec.features`: features structure as defined
+          in the [OCI Runtime Specification](https://github.com/opencontainers/runtime-spec/blob/main/features.md),
+          in a JSON string representation.
+
+          <p><br /></p>
+
+          > **Note**: The information returned in this field, including the
+          > formatting of values and labels, should not be considered stable,
+          > and may change without notice.
+        type: "object"
+        x-nullable: true
+        additionalProperties:
+          type: "string"
+        example:
+          "org.opencontainers.runtime-spec.features": "{\"ociVersionMin\":\"1.0.0\",\"ociVersionMax\":\"1.1.0\",\"...\":\"...\"}"
 
   Commit:
     description: |
diff --git a/api/types/system/info.go b/api/types/system/info.go
index 09dbbd0926346..89d4a0098e366 100644
--- a/api/types/system/info.go
+++ b/api/types/system/info.go
@@ -58,7 +58,7 @@ type Info struct {
 	Labels             []string
 	ExperimentalBuild  bool
 	ServerVersion      string
-	Runtimes           map[string]Runtime
+	Runtimes           map[string]RuntimeWithStatus
 	DefaultRuntime     string
 	Swarm              swarm.Info
 	// LiveRestoreEnabled determines whether containers should be kept
diff --git a/api/types/system/runtime.go b/api/types/system/runtime.go
index 83433acf92c10..d077295a0d317 100644
--- a/api/types/system/runtime.go
+++ b/api/types/system/runtime.go
@@ -12,3 +12,9 @@ type Runtime struct {
 	Type    string                 `json:"runtimeType,omitempty"`
 	Options map[string]interface{} `json:"options,omitempty"`
 }
+
+// RuntimeWithStatus extends [Runtime] to hold [RuntimeStatus].
+type RuntimeWithStatus struct {
+	Runtime
+	Status map[string]string `json:"status,omitempty"`
+}
diff --git a/daemon/info_unix.go b/daemon/info_unix.go
index 57c6601c057b2..cd7f55faac06f 100644
--- a/daemon/info_unix.go
+++ b/daemon/info_unix.go
@@ -4,6 +4,7 @@ package daemon // import "github.com/docker/docker/daemon"
 
 import (
 	"context"
+	"encoding/json"
 	"fmt"
 	"os"
 	"os/exec"
@@ -43,14 +44,22 @@ func (daemon *Daemon) fillPlatformInfo(ctx context.Context, v *system.Info, sysI
 		v.CPUSet = sysInfo.Cpuset
 		v.PidsLimit = sysInfo.PidsLimit
 	}
-	v.Runtimes = make(map[string]system.Runtime)
+	v.Runtimes = make(map[string]system.RuntimeWithStatus)
 	for n, p := range stockRuntimes() {
-		v.Runtimes[n] = system.Runtime{Path: p}
+		v.Runtimes[n] = system.RuntimeWithStatus{
+			Runtime: system.Runtime{
+				Path: p,
+			},
+			Status: daemon.runtimeStatus(ctx, cfg, n),
+		}
 	}
 	for n, r := range cfg.Config.Runtimes {
-		v.Runtimes[n] = system.Runtime{
-			Path: r.Path,
-			Args: append([]string(nil), r.Args...),
+		v.Runtimes[n] = system.RuntimeWithStatus{
+			Runtime: system.Runtime{
+				Path: r.Path,
+				Args: append([]string(nil), r.Args...),
+			},
+			Status: daemon.runtimeStatus(ctx, cfg, n),
 		}
 	}
 	v.DefaultRuntime = cfg.Runtimes.Default
@@ -486,3 +495,24 @@ func populateInitVersion(ctx context.Context, cfg *configStore, v *types.Version
 	})
 	return nil
 }
+
+// ociRuntimeFeaturesKey is the "well-known" used for including the
+// OCI runtime spec "features" struct.
+//
+// see https://github.com/opencontainers/runtime-spec/blob/main/features.md
+const ociRuntimeFeaturesKey = "org.opencontainers.runtime-spec.features"
+
+func (daemon *Daemon) runtimeStatus(ctx context.Context, cfg *configStore, runtimeName string) map[string]string {
+	m := make(map[string]string)
+	if runtimeName == "" {
+		runtimeName = cfg.Runtimes.Default
+	}
+	if features := cfg.Runtimes.Features(runtimeName); features != nil {
+		if j, err := json.Marshal(features); err == nil {
+			m[ociRuntimeFeaturesKey] = string(j)
+		} else {
+			log.G(ctx).WithFields(log.Fields{"error": err, "runtime": runtimeName}).Warn("Failed to call json.Marshal for the OCI features struct of runtime")
+		}
+	}
+	return m
+}
diff --git a/docs/api/version-history.md b/docs/api/version-history.md
index f1a0bc2a64e0c..4dcff253f2725 100644
--- a/docs/api/version-history.md
+++ b/docs/api/version-history.md
@@ -67,6 +67,7 @@ keywords: "API, Docker, rcli, REST, documentation"
   requests is now deprecated. You should instead use the field `TaskTemplate.Networks`.
 * The `Container` and `ContainerConfig` fields in the `GET /images/{name}/json`
   response are deprecated and will no longer be included in API v1.45.
+* `GET /info` now includes `status` properties in `Runtimes`.
 
 ## v1.43 API changes
 


Test patch: