Skip to content

Commit 02bf394

Browse files
committed
feat: show RootlessKit version in nerdctl version output
When running in rootless mode, nerdctl version now includes the RootlessKit version as a server component, matching the format used by docker version. This helps users quickly verify which RootlessKit version is in use without running rootlesskit --version separately. The version is only shown when rootless mode is active (i.e. when rootlessutil.IsRootless() is true). If rootlesskit is not found on PATH or its output cannot be parsed, a warning is logged and the component is shown without a version string. Fixes #4936 Signed-off-by: Aaron <aaroniofjm@gmail.com>
1 parent 1eab5e6 commit 02bf394

2 files changed

Lines changed: 53 additions & 0 deletions

File tree

pkg/infoutil/infoutil.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"github.com/containerd/nerdctl/v2/pkg/buildkitutil"
3636
"github.com/containerd/nerdctl/v2/pkg/inspecttypes/dockercompat"
3737
"github.com/containerd/nerdctl/v2/pkg/inspecttypes/native"
38+
"github.com/containerd/nerdctl/v2/pkg/rootlessutil"
3839
"github.com/containerd/nerdctl/v2/pkg/version"
3940
)
4041

@@ -142,6 +143,9 @@ func ServerVersion(ctx context.Context, client *containerd.Client) (*dockercompa
142143
runcVersion(),
143144
},
144145
}
146+
if rootlessutil.IsRootless() {
147+
v.Components = append(v.Components, rootlessKitVersion())
148+
}
145149
return v, nil
146150
}
147151

@@ -233,6 +237,32 @@ func parseRuncVersion(runcVersionStdout []byte) (*dockercompat.ComponentVersion,
233237
}
234238

235239
// getMobySysInfo returns the moby system info for the given cgroup manager
240+
241+
func rootlessKitVersion() dockercompat.ComponentVersion {
242+
stdout, err := exec.Command("rootlesskit", "--version").Output()
243+
if err != nil {
244+
log.L.WithError(err).Warnf("unable to determine RootlessKit version")
245+
return dockercompat.ComponentVersion{Name: "rootlesskit"}
246+
}
247+
v, err := parseRootlessKitVersion(stdout)
248+
if err != nil {
249+
log.L.Warn(err)
250+
return dockercompat.ComponentVersion{Name: "rootlesskit"}
251+
}
252+
return *v
253+
}
254+
255+
func parseRootlessKitVersion(stdout []byte) (*dockercompat.ComponentVersion, error) {
256+
// Expected format: "rootlesskit version 2.0.0" or "rootlesskit version 2.3.1+dev"
257+
fields := strings.Fields(strings.TrimSpace(string(stdout)))
258+
if len(fields) < 3 || fields[0] != "rootlesskit" {
259+
return nil, fmt.Errorf("unable to parse RootlessKit version, got: %s", string(stdout))
260+
}
261+
return &dockercompat.ComponentVersion{
262+
Name: "rootlesskit",
263+
Version: fields[2],
264+
}, nil
265+
}
236266
func getMobySysInfo(cgroupManager string) *sysinfo.SysInfo {
237267
var info dockercompat.Info
238268
info.CgroupVersion = CgroupsVersion()

pkg/infoutil/infoutil_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,26 @@ libseccomp: 2.5.1`: {
8383
}
8484
}
8585
}
86+
87+
func TestParseRootlessKitVersion(t *testing.T) {
88+
testCases := map[string]*dockercompat.ComponentVersion{
89+
"rootlesskit version 2.3.1\n": {
90+
Name: "rootlesskit",
91+
Version: "2.3.1",
92+
},
93+
"rootlesskit version 2.0.0+dev\n": {
94+
Name: "rootlesskit",
95+
Version: "2.0.0+dev",
96+
},
97+
"unexpected output": nil,
98+
}
99+
for s, expected := range testCases {
100+
got, err := parseRootlessKitVersion([]byte(s))
101+
if expected != nil {
102+
assert.NilError(t, err)
103+
assert.DeepEqual(t, expected, got)
104+
} else {
105+
assert.Assert(t, err != nil)
106+
}
107+
}
108+
}

0 commit comments

Comments
 (0)