Skip to content

Commit dd8a82c

Browse files
committed
Add WithValidator option to producer API
Signed-off-by: Evan Lezar <elezar@nvidia.com>
1 parent 07ab0e4 commit dd8a82c

3 files changed

Lines changed: 43 additions & 9 deletions

File tree

pkg/cdi/producer/save.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ import (
3030
cdi "tags.cncf.io/container-device-interface/specs-go"
3131
)
3232

33+
type validator interface {
34+
Validate(*cdi.Spec) error
35+
}
36+
3337
type options struct {
3438
outputFormat string
3539
validator validator
@@ -106,6 +110,10 @@ func Save(raw *cdi.Spec, path string, opts ...Option) error {
106110
func WriteTo(raw *cdi.Spec, w io.Writer, opts ...Option) (int64, error) {
107111
o := populateOptions(opts...)
108112

113+
if err := o.Validate(raw); err != nil {
114+
return 0, fmt.Errorf("spec validation failed: %w", err)
115+
}
116+
109117
data, err := o.marshal(raw)
110118
if err != nil {
111119
return 0, fmt.Errorf("failed to marshal spec: %w", err)
@@ -243,3 +251,21 @@ func (o *options) marshal(v any) ([]byte, error) {
243251
return nil, fmt.Errorf("invalid output format: %q", o.outputFormat)
244252
}
245253
}
254+
255+
// Validate a CDI specification using the supplied options.
256+
// If no validator is specified, validation always succeeds.
257+
func (o *options) Validate(raw *cdi.Spec) error {
258+
if o == nil || o.validator == nil {
259+
return nil
260+
}
261+
return o.validator.Validate(raw)
262+
}
263+
264+
type validatorFunction func(*cdi.Spec) error
265+
266+
func (v validatorFunction) Validate(raw *cdi.Spec) error {
267+
if v == nil {
268+
return nil
269+
}
270+
return v(raw)
271+
}

pkg/cdi/producer/save_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package producer
1818

1919
import (
20+
"fmt"
2021
"os"
2122
"path/filepath"
2223
"testing"
@@ -141,6 +142,21 @@ devices: []
141142
require.EqualValues(t, expectedContents, string(contents))
142143
},
143144
},
145+
{
146+
description: "validator is called before save",
147+
spec: &cdi.Spec{
148+
Version: "v1.1.0",
149+
},
150+
filename: "test.yaml",
151+
options: []Option{
152+
WithValidator(validatorFunction(func(s *cdi.Spec) error { return fmt.Errorf("invalid spec") })),
153+
WithPermissions(os.FileMode(0666)),
154+
},
155+
expectedError: "failed to write Spec file: spec validation failed: invalid spec",
156+
assert: func(t *testing.T, fullpath string) {
157+
require.NoFileExists(t, fullpath)
158+
},
159+
},
144160
}
145161

146162
for _, tc := range testCases {

pkg/cdi/spec.go

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -113,21 +113,13 @@ func newSpec(raw *cdi.Spec, path string, priority int) (*Spec, error) {
113113
// Write the CDI Spec to the file associated with it during instantiation
114114
// by newSpec() or ReadSpec().
115115
func (s *Spec) write(overwrite bool) error {
116-
var (
117-
err error
118-
)
119-
120-
err = validateSpec(s.Spec)
121-
if err != nil {
122-
return err
123-
}
124-
125116
return producer.Save(s.Spec, s.path,
126117
// If we cannot determine the file format as yaml from the extension,
127118
// we assume a json format.
128119
producer.WithOutputFormat("json"),
129120
producer.WithOverwrite(overwrite),
130121
producer.WithPermissions(0),
122+
producer.WithValidatorFunction(validateSpec),
131123
)
132124
}
133125

0 commit comments

Comments
 (0)