mirror of
https://github.com/moby/moby.git
synced 2026-01-11 18:51:37 +00:00
NRI: add daemon.json/command line options
Signed-off-by: Rob Murray <rob.murray@docker.com>
This commit is contained in:
94
daemon/pkg/opts/nri_opts.go
Normal file
94
daemon/pkg/opts/nri_opts.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package opts
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type NRIOpts struct {
|
||||
Enable bool `json:"enable,omitempty"`
|
||||
PluginPath string `json:"plugin-path,omitempty"`
|
||||
PluginConfigPath string `json:"plugin-config-path,omitempty"`
|
||||
SocketPath string `json:"socket-path,omitempty"`
|
||||
}
|
||||
|
||||
func (c *NRIOpts) UnmarshalJSON(raw []byte) error {
|
||||
dec := json.NewDecoder(bytes.NewReader(raw))
|
||||
dec.DisallowUnknownFields()
|
||||
type nc *NRIOpts // prevent recursion
|
||||
if err := dec.Decode(nc(c)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NamedNRIOpts is a NamedOption and flags.Value for NRI configuration parsing.
|
||||
type NamedNRIOpts struct {
|
||||
Val *NRIOpts
|
||||
}
|
||||
|
||||
func NewNamedNRIOptsRef(val *NRIOpts) *NamedNRIOpts {
|
||||
return &NamedNRIOpts{Val: val}
|
||||
}
|
||||
|
||||
func (p *NamedNRIOpts) Set(value string) error {
|
||||
csvReader := csv.NewReader(strings.NewReader(value))
|
||||
fields, err := csvReader.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, field := range fields {
|
||||
key, val, _ := strings.Cut(field, "=")
|
||||
switch key {
|
||||
case "enable":
|
||||
// Assume "enable=true" if no value given, so that "--nri enable" works.
|
||||
if val == "" {
|
||||
val = "true"
|
||||
}
|
||||
en, err := strconv.ParseBool(val)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid value for NRI enable %q: %w", val, err)
|
||||
}
|
||||
p.Val.Enable = en
|
||||
case "plugin-path":
|
||||
p.Val.PluginPath = val
|
||||
case "plugin-config-path":
|
||||
p.Val.PluginConfigPath = val
|
||||
case "socket-path":
|
||||
p.Val.SocketPath = val
|
||||
default:
|
||||
return fmt.Errorf("unexpected key '%s' in '%s'", key, field)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Type returns the type of this option
|
||||
func (p *NamedNRIOpts) Type() string {
|
||||
return "nri-opts"
|
||||
}
|
||||
|
||||
// String returns a string repr of this option
|
||||
func (p *NamedNRIOpts) String() string {
|
||||
vals := []string{fmt.Sprintf("enable=%v", p.Val.Enable)}
|
||||
if p.Val.PluginPath != "" {
|
||||
vals = append(vals, "plugin-path="+p.Val.PluginPath)
|
||||
}
|
||||
if p.Val.PluginConfigPath != "" {
|
||||
vals = append(vals, "plugin-config-path="+p.Val.PluginConfigPath)
|
||||
}
|
||||
if p.Val.SocketPath != "" {
|
||||
vals = append(vals, "socket-path="+p.Val.SocketPath)
|
||||
}
|
||||
return strings.Join(vals, ",")
|
||||
}
|
||||
|
||||
// Name returns the flag name of this option
|
||||
func (p *NamedNRIOpts) Name() string {
|
||||
return "nri-opts"
|
||||
}
|
||||
117
daemon/pkg/opts/nri_opts_test.go
Normal file
117
daemon/pkg/opts/nri_opts_test.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package opts
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestNRIOptsJSON(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
json string
|
||||
expErr string
|
||||
expNRI NRIOpts
|
||||
}{
|
||||
{
|
||||
name: "no config",
|
||||
expNRI: NRIOpts{},
|
||||
},
|
||||
{
|
||||
name: "json enable",
|
||||
json: `{"enable": true}`,
|
||||
expNRI: NRIOpts{
|
||||
Enable: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "json enable with paths",
|
||||
json: `{"enable": true, "plugin-path": "/foo", "plugin-config-path": "/bar", "socket-path": "/baz"}`,
|
||||
expNRI: NRIOpts{
|
||||
Enable: true,
|
||||
PluginPath: "/foo",
|
||||
PluginConfigPath: "/bar",
|
||||
SocketPath: "/baz",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "json unknown field",
|
||||
json: `{"foo": "bar"}`,
|
||||
expErr: "unknown field \"foo\"",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
var nc NRIOpts
|
||||
if tc.json != "" {
|
||||
err := nc.UnmarshalJSON([]byte(tc.json))
|
||||
if tc.expErr != "" {
|
||||
assert.Check(t, is.ErrorContains(err, tc.expErr))
|
||||
return
|
||||
}
|
||||
assert.Check(t, err)
|
||||
}
|
||||
assert.Check(t, is.Equal(nc, tc.expNRI))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNRIOptsCmd(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
cmd string
|
||||
expErr string
|
||||
expNRI NRIOpts
|
||||
expString string
|
||||
}{
|
||||
{
|
||||
name: "cmd enable",
|
||||
cmd: "enable=true",
|
||||
expNRI: NRIOpts{
|
||||
Enable: true,
|
||||
},
|
||||
expString: "enable=true",
|
||||
},
|
||||
{
|
||||
name: "cmd enable with paths",
|
||||
cmd: "enable=true,plugin-path=/foo,plugin-config-path=/bar,socket-path=/baz",
|
||||
expNRI: NRIOpts{
|
||||
Enable: true,
|
||||
PluginPath: "/foo",
|
||||
PluginConfigPath: "/bar",
|
||||
SocketPath: "/baz",
|
||||
},
|
||||
expString: "enable=true,plugin-path=/foo,plugin-config-path=/bar,socket-path=/baz",
|
||||
},
|
||||
{
|
||||
// "--nri-opts enable"
|
||||
name: "cmd enable no value",
|
||||
cmd: `enable`,
|
||||
expNRI: NRIOpts{
|
||||
Enable: true,
|
||||
},
|
||||
expString: "enable=true",
|
||||
},
|
||||
{
|
||||
name: "cmd unknown field",
|
||||
cmd: `foo=bar`,
|
||||
expErr: "unexpected key 'foo' in 'foo=bar'",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
var nc NRIOpts
|
||||
nriOpt := NewNamedNRIOptsRef(&nc)
|
||||
err := nriOpt.Set(tc.cmd)
|
||||
if tc.expErr != "" {
|
||||
assert.Check(t, is.ErrorContains(err, tc.expErr))
|
||||
return
|
||||
}
|
||||
assert.Check(t, err)
|
||||
assert.Check(t, is.Equal(nriOpt.String(), tc.expString))
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user