Internal Change

PiperOrigin-RevId: 514604210
This commit is contained in:
Zach Koopmans
2023-03-06 20:20:47 -08:00
committed by gVisor bot
parent bdb4a4c5ea
commit 63ca40b1c2
2 changed files with 173 additions and 12 deletions
+63
View File
@@ -713,3 +713,66 @@ func TestBundleValidate(t *testing.T) {
})
}
}
func TestToContinerdConfigTOML(t *testing.T) {
header := `binary_name = "%s"
root = "%s"
`
opt := ContainerdConfigOptions{
BinaryPath: "/path/to/runsc",
RootPath: "/path/to/root",
}
header = fmt.Sprintf(header, opt.BinaryPath, opt.RootPath)
for _, tc := range []struct {
name string
bundle Bundle
want string
createError error
}{
{
name: "empty bundle",
want: header,
},
{
name: "valid flag bundle",
bundle: Bundle(map[string]string{"debug": "true"}),
want: func() string {
flagStr := "[runsc_config]\n debug = \"true\"\n"
return strings.Join([]string{header, flagStr}, "")
}(),
},
{
name: "invalid flag bundle",
bundle: Bundle(map[string]string{"not-a-real-flag": "true"}),
createError: fmt.Errorf("unknown flag \"not-a-real-flag\""),
},
} {
t.Run(tc.name, func(t *testing.T) {
cfg, err := NewFromBundle(tc.bundle)
if tc.createError != nil {
if err == nil {
t.Fatalf("got no error, but expected one")
}
if !strings.Contains(err.Error(), tc.createError.Error()) {
t.Fatalf("mismatch error: got: %q want: %q", err.Error(), tc.createError.Error())
}
return
}
if err != nil {
t.Fatalf("NewFromBundle failed: %v", err)
}
toml, err := cfg.ToContainerdConfigTOML(opt)
if err != nil {
t.Fatalf("ToContainerdConfigTOML failed: %v", err)
}
if diff := cmp.Diff(tc.want, toml); diff != "" {
t.Fatalf("mismatch strings: %s", diff)
}
})
}
}
+110 -12
View File
@@ -15,12 +15,15 @@
package config
import (
"bytes"
"fmt"
"os"
"path/filepath"
"reflect"
"sort"
"strconv"
"strings"
"text/template"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/refs"
@@ -198,13 +201,109 @@ func NewFromFlags(flagSet *flag.FlagSet) (*Config, error) {
return conf, nil
}
// ToFlags returns a slice of flags that correspond to the given Config.
func (c *Config) ToFlags() []string {
var rv []string
// Construct a temporary set for default plumbing.
// NewFromBundle makes a new config from a Bundle.
func NewFromBundle(bundle Bundle) (*Config, error) {
if err := bundle.Validate(); err != nil {
return nil, err
}
flagSet := flag.NewFlagSet("tmp", flag.ContinueOnError)
RegisterFlags(flagSet)
conf := &Config{explicitlySet: map[string]struct{}{}}
obj := reflect.ValueOf(conf).Elem()
st := obj.Type()
for i := 0; i < st.NumField(); i++ {
f := st.Field(i)
name, ok := f.Tag.Lookup("flag")
if !ok {
continue
}
fl := flagSet.Lookup(name)
if fl == nil {
return nil, fmt.Errorf("flag %q not found", name)
}
val, ok := bundle[name]
if !ok {
continue
}
if err := flagSet.Set(name, val); err != nil {
return nil, fmt.Errorf("error setting flag %s=%q: %w", name, val, err)
}
conf.Override(flagSet, name, val, true)
conf.explicitlySet[name] = struct{}{}
}
return conf, nil
}
// ToFlags returns a slice of flags that correspond to the given Config.
func (c *Config) ToFlags() []string {
flagSet := flag.NewFlagSet("tmp", flag.ContinueOnError)
RegisterFlags(flagSet)
var rv []string
keyVals := c.keyVals(flagSet, false /*onlyIfSet*/)
for name, val := range keyVals {
rv = append(rv, fmt.Sprintf("--%s=%s", name, val))
}
// Construct a temporary set for default plumbing.
return rv
}
// KeyVal is a key value pair. It is used so ToContainerdConfigTOML returns
// predictable ordering for runsc flags.
type KeyVal struct {
Key string
Val string
}
// ContainerdConfigOptions contains arguments for ToContainerdConfigTOML.
type ContainerdConfigOptions struct {
BinaryPath string
RootPath string
Options map[string]string
RunscFlags []KeyVal
}
// ToContainerdConfigTOML turns a given config into a format for a k8s containerd config.toml file.
// See: https://gvisor.dev/docs/user_guide/containerd/quick_start/
func (c *Config) ToContainerdConfigTOML(opts ContainerdConfigOptions) (string, error) {
flagSet := flag.NewFlagSet("tmp", flag.ContinueOnError)
RegisterFlags(flagSet)
keyVals := c.keyVals(flagSet, true /*onlyIfSet*/)
keys := []string{}
for k := range keyVals {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
opts.RunscFlags = append(opts.RunscFlags, KeyVal{k, keyVals[k]})
}
const temp = `{{if .BinaryPath}}binary_name = "{{.BinaryPath}}"{{end}}
{{if .RootPath}}root = "{{.RootPath}}"{{end}}
{{if .Options}}{{ range $key, $value := .Options}}{{$key}} = "{{$value}}"
{{end}}{{end}}{{if .RunscFlags}}[runsc_config]
{{ range $fl:= .RunscFlags}} {{$fl.Key}} = "{{$fl.Val}}"
{{end}}{{end}}`
t := template.New("temp")
t, err := t.Parse(temp)
if err != nil {
return "", err
}
var buf bytes.Buffer
if err := t.Execute(&buf, opts); err != nil {
return "", err
}
return buf.String(), nil
}
func (c *Config) keyVals(flagSet *flag.FlagSet, onlyIfSet bool) map[string]string {
keyVals := make(map[string]string)
obj := reflect.ValueOf(c).Elem()
st := obj.Type()
@@ -217,11 +316,11 @@ func (c *Config) ToFlags() []string {
}
val := getVal(obj.Field(i))
flag := flagSet.Lookup(name)
if flag == nil {
fl := flagSet.Lookup(name)
if fl == nil {
panic(fmt.Sprintf("Flag %q not found", name))
}
if val == flag.DefValue {
if val == fl.DefValue || onlyIfSet {
// If this config wasn't populated from a FlagSet, don't plumb through default flags.
if c.explicitlySet == nil {
continue
@@ -232,9 +331,9 @@ func (c *Config) ToFlags() []string {
continue
}
}
rv = append(rv, fmt.Sprintf("--%s=%s", flag.Name, val))
keyVals[fl.Name] = val
}
return rv
return keyVals
}
// Override writes a new value to a flag.
@@ -277,7 +376,7 @@ func (c *Config) isOverrideAllowed(name string, value string) error {
if c.AllowFlagOverride {
return nil
}
// If the global override flag is not enabled, check if individual flag is
// If the global override flag is not enabled, check if the individual flag is
// safe to apply.
if allow, ok := overrideAllowlist[name]; ok {
if allow.check != nil {
@@ -311,7 +410,6 @@ func (c *Config) ApplyBundles(flagSet *flag.FlagSet, bundleNames ...BundleName)
valueToBundleName[val] = bundleName
}
}
// Check for conflicting flag values between the bundles.
for flagName, valueToBundleName := range flagToValueToBundleName {
if len(valueToBundleName) == 1 {