Skip to content

Commit a57412a

Browse files
committed
Add AdditionalGIDs field to ContainerEdits
This change adds an AdditionalGIDs field to the ContainerEdits structure. This allows CDI spec producers to associate a group ID with the container's user to allow access to, for example, device nodes with specific permissions. Signed-off-by: Evan Lezar <[email protected]>
1 parent 7b12d28 commit a57412a

File tree

6 files changed

+115
-8
lines changed

6 files changed

+115
-8
lines changed

SPEC.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ Released versions of the spec are available as Git tags.
2727
| v0.4.0 | | Added `type` field to Mount specification |
2828
| v0.5.0 | | Add `HostPath` to `DeviceNodes` |
2929
| v0.6.0 | | Add `Annotations` field to `Spec` and `Device` specifications |
30-
| | | Allow dots (`.`) in name segment of `Kind` field |
30+
| | | Allow dots (`.`) in name segment of `Kind` field |
31+
| v0.7.0 | | Add `AdditionalGIDs` to `ContainerEdits` |
3132

3233
*Note*: The initial release of a **spec** with version `v0.x.0` will be tagged as
3334
`v0.x.0` with subsequent changes to the API applicable to this version tagged as `v0.x.y`.
@@ -82,7 +83,7 @@ The keywords "must", "must not", "required", "shall", "shall not", "should", "sh
8283

8384
```
8485
{
85-
"cdiVersion": "0.6.0",
86+
"cdiVersion": "0.7.0",
8687
"kind": "<name>",
8788
8889
// This field contains a set of key-value pairs that may be used to provide
@@ -149,6 +150,11 @@ The keywords "must", "must not", "required", "shall", "shall not", "should", "sh
149150
"env": [ "<envName>=<envValue>"], (optional)
150151
"timeout": <int> (optional)
151152
}
153+
],
154+
// Additional GIDs to add to the container process.
155+
// Note that a value of 0 is ignored.
156+
additionalGIDs: [ (optional)
157+
<uint32>
152158
]
153159
}
154160
]
@@ -220,6 +226,7 @@ The `containerEdits` field has the following definition:
220226
* `args` (array of strings, OPTIONAL) with the same semantics as IEEE Std 1003.1-2008 execv's argv.
221227
* `env` (array of strings, OPTIONAL) with the same semantics as IEEE Std 1003.1-2008's environ.
222228
* `timeout` (int, OPTIONAL) is the number of seconds before aborting the hook. If set, timeout MUST be greater than zero. If not set container runtime will wait for the hook to return.
229+
* `additionalGids` (array of uint32s, OPTIONAL) A list of additional group IDs to add with the container process. These values are added to the `user.additionalGids` field in the OCI runtime specification. Values of 0 are ignored.
223230

224231
## Error Handling
225232
* Kind requested is not present in any CDI file.

pkg/cdi/container-edits.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,13 @@ func (e *ContainerEdits) Apply(spec *oci.Spec) error {
144144
}
145145
}
146146

147+
for _, additionalGID := range e.AdditionalGIDs {
148+
if additionalGID == 0 {
149+
continue
150+
}
151+
specgen.AddProcessAdditionalGid(additionalGID)
152+
}
153+
147154
return nil
148155
}
149156

@@ -192,6 +199,7 @@ func (e *ContainerEdits) Append(o *ContainerEdits) *ContainerEdits {
192199
e.DeviceNodes = append(e.DeviceNodes, o.DeviceNodes...)
193200
e.Hooks = append(e.Hooks, o.Hooks...)
194201
e.Mounts = append(e.Mounts, o.Mounts...)
202+
e.AdditionalGIDs = append(e.AdditionalGIDs, o.AdditionalGIDs...)
195203

196204
return e
197205
}
@@ -202,7 +210,7 @@ func (e *ContainerEdits) isEmpty() bool {
202210
if e == nil {
203211
return false
204212
}
205-
return len(e.Env)+len(e.DeviceNodes)+len(e.Hooks)+len(e.Mounts) == 0
213+
return len(e.Env)+len(e.DeviceNodes)+len(e.Hooks)+len(e.Mounts)+len(e.AdditionalGIDs) == 0
206214
}
207215

208216
// ValidateEnv validates the given environment variables.

pkg/cdi/container-edits_test.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,42 @@ func TestApplyContainerEdits(t *testing.T) {
467467
},
468468
},
469469
},
470+
{
471+
name: "additional GIDs are applied",
472+
spec: &oci.Spec{},
473+
edits: &cdi.ContainerEdits{
474+
AdditionalGIDs: []uint32{4, 5, 6},
475+
},
476+
result: &oci.Spec{
477+
Process: &oci.Process{
478+
User: oci.User{
479+
AdditionalGids: []uint32{4, 5, 6},
480+
},
481+
},
482+
},
483+
},
484+
{
485+
name: "duplicate GIDs are ignored",
486+
spec: &oci.Spec{},
487+
edits: &cdi.ContainerEdits{
488+
AdditionalGIDs: []uint32{4, 5, 6, 5, 6, 4},
489+
},
490+
result: &oci.Spec{
491+
Process: &oci.Process{
492+
User: oci.User{
493+
AdditionalGids: []uint32{4, 5, 6},
494+
},
495+
},
496+
},
497+
},
498+
{
499+
name: "additional GID 0 is skipped",
500+
spec: &oci.Spec{},
501+
edits: &cdi.ContainerEdits{
502+
AdditionalGIDs: []uint32{0},
503+
},
504+
result: &oci.Spec{},
505+
},
470506
} {
471507
t.Run(tc.name, func(t *testing.T) {
472508
edits := ContainerEdits{tc.edits}
@@ -612,6 +648,36 @@ func TestAppend(t *testing.T) {
612648
},
613649
},
614650
},
651+
{
652+
name: "merge additional GIDs does not deduplicate",
653+
dst: &ContainerEdits{
654+
ContainerEdits: &cdi.ContainerEdits{
655+
AdditionalGIDs: []uint32{5},
656+
},
657+
},
658+
src: []*ContainerEdits{
659+
{
660+
ContainerEdits: &cdi.ContainerEdits{
661+
AdditionalGIDs: []uint32{0},
662+
},
663+
},
664+
{
665+
ContainerEdits: &cdi.ContainerEdits{
666+
AdditionalGIDs: []uint32{5},
667+
},
668+
},
669+
{
670+
ContainerEdits: &cdi.ContainerEdits{
671+
AdditionalGIDs: []uint32{6, 7, 6},
672+
},
673+
},
674+
},
675+
result: &ContainerEdits{
676+
ContainerEdits: &cdi.ContainerEdits{
677+
AdditionalGIDs: []uint32{5, 0, 5, 6, 7, 6},
678+
},
679+
},
680+
},
615681
} {
616682
t.Run(tc.name, func(t *testing.T) {
617683
dst := tc.dst

pkg/cdi/version.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const (
3939
v040 version = "v0.4.0"
4040
v050 version = "v0.5.0"
4141
v060 version = "v0.6.0"
42+
v070 version = "v0.7.0"
4243

4344
// vEarliest is the earliest supported version of the CDI specification
4445
vEarliest version = v030
@@ -54,6 +55,7 @@ var validSpecVersions = requiredVersionMap{
5455
v040: requiresV040,
5556
v050: requiresV050,
5657
v060: requiresV060,
58+
v070: requiresV070,
5759
}
5860

5961
// MinimumRequiredVersion determines the minimum spec version for the input spec.
@@ -118,6 +120,23 @@ func (r requiredVersionMap) requiredVersion(spec *cdi.Spec) version {
118120
return minVersion
119121
}
120122

123+
// requiresV070 returns true if the spec uses v0.7.0 features
124+
func requiresV070(spec *cdi.Spec) bool {
125+
// The v0.7.0 spec allows additional GIDs to be specified at a spec level.
126+
if len(spec.ContainerEdits.AdditionalGIDs) > 0 {
127+
return true
128+
}
129+
130+
for _, d := range spec.Devices {
131+
// The v0.7.0 spec allows additional GIDs to be specified at a device level.
132+
if len(d.ContainerEdits.AdditionalGIDs) > 0 {
133+
return true
134+
}
135+
}
136+
137+
return false
138+
}
139+
121140
// requiresV060 returns true if the spec uses v0.6.0 features
122141
func requiresV060(spec *cdi.Spec) bool {
123142
// The v0.6.0 spec allows annotations to be specified at a spec level

schema/defs.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,12 @@
134134
"items": {
135135
"$ref": "#/definitions/Hook"
136136
}
137+
},
138+
"additionalGids": {
139+
"type": "array",
140+
"items": {
141+
"$ref": "#/definitions/uint32"
142+
}
137143
}
138144
}
139145
},

specs-go/config.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package specs
33
import "os"
44

55
// CurrentVersion is the current version of the Spec.
6-
const CurrentVersion = "0.6.0"
6+
const CurrentVersion = "0.7.0"
77

88
// Spec is the base configuration for CDI
99
type Spec struct {
@@ -25,10 +25,11 @@ type Device struct {
2525

2626
// ContainerEdits are edits a container runtime must make to the OCI spec to expose the device.
2727
type ContainerEdits struct {
28-
Env []string `json:"env,omitempty"`
29-
DeviceNodes []*DeviceNode `json:"deviceNodes,omitempty"`
30-
Hooks []*Hook `json:"hooks,omitempty"`
31-
Mounts []*Mount `json:"mounts,omitempty"`
28+
Env []string `json:"env,omitempty"`
29+
DeviceNodes []*DeviceNode `json:"deviceNodes,omitempty"`
30+
Hooks []*Hook `json:"hooks,omitempty"`
31+
Mounts []*Mount `json:"mounts,omitempty"`
32+
AdditionalGIDs []uint32 `json:"additionalGids,omitempty"`
3233
}
3334

3435
// DeviceNode represents a device node that needs to be added to the OCI spec.

0 commit comments

Comments
 (0)