The Wayback Machine - https://web.archive.org/web/20220603144204/https://github.com/google/gvisor/commit/671bd7b0f8971d77309fef5143cf2f92b696e52b
Skip to content
Permalink
Browse files
Don't clobber /etc/docker/config.json on debian updates.
PiperOrigin-RevId: 449537553
  • Loading branch information
zkoopmans authored and gvisor-bot committed May 18, 2022
1 parent 1ccbffc commit 671bd7b0f8971d77309fef5143cf2f92b696e52b
Showing 4 changed files with 401 additions and 45 deletions.
@@ -20,7 +20,7 @@ fi

# Update docker configuration.
if [ -f /etc/docker/daemon.json ]; then
runsc install
runsc install --clobber=false
if systemctl is-active -q docker; then
systemctl reload docker || echo "unable to reload docker; you must do so manually." >&2
fi
@@ -82,6 +82,7 @@ go_test(
"delete_test.go",
"exec_test.go",
"gofer_test.go",
"install_test.go",
"mitigate_test.go",
],
data = [
@@ -22,6 +22,7 @@ import (
"log"
"os"
"path"
"regexp"

"github.com/google/subcommands"
"gvisor.dev/gvisor/pkg/sentry/platform"
@@ -31,10 +32,13 @@ import (

// Install implements subcommands.Command.
type Install struct {
ConfigFile string
Runtime string
Experimental bool
CgroupDriver string
ConfigFile string
Runtime string
Experimental bool
Clobber bool
CgroupDriver string
executablePath string
runtimeArgs []string
}

// Name implements subcommands.Command.Name.
@@ -57,17 +61,18 @@ func (*Install) Usage() string {
func (i *Install) SetFlags(fs *flag.FlagSet) {
fs.StringVar(&i.ConfigFile, "config_file", "/etc/docker/daemon.json", "path to Docker daemon config file")
fs.StringVar(&i.Runtime, "runtime", "runsc", "runtime name")
fs.BoolVar(&i.Experimental, "experimental", false, "enable experimental features")
fs.BoolVar(&i.Experimental, "experimental", false, "enable/disable experimental features")
fs.BoolVar(&i.Clobber, "clobber", true, "clobber existing runtime configuration")
fs.StringVar(&i.CgroupDriver, "cgroupdriver", "", "docker cgroup driver")
}

// Execute implements subcommands.Command.Execute.
func (i *Install) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
// Grab the name and arguments.
runtimeArgs := f.Args()
i.runtimeArgs = f.Args()
testFlags := flag.NewFlagSet("test", flag.ContinueOnError)
config.RegisterFlags(testFlags)
testFlags.Parse(runtimeArgs)
testFlags.Parse(i.runtimeArgs)
conf, err := config.NewFromFlags(testFlags)
if err != nil {
log.Fatalf("invalid runtime arguments: %v", err)
@@ -92,10 +97,34 @@ func (i *Install) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{})
log.Fatalf("Error reading current exectuable: %v", err)
}

i.executablePath = path

installRW := configReaderWriter{
read: defaultReadConfig,
write: defaultWriteConfig,
}

if err := doInstallConfig(i, installRW); err != nil {
log.Fatalf("Install failed: %v", err)
}

// Success.
log.Print("Successfully updated config.")
return subcommands.ExitSuccess
}

func doInstallConfig(i *Install, rw configReaderWriter) error {
// Load the configuration file.
c, err := readConfig(i.ConfigFile)
configBytes, err := rw.read(i.ConfigFile)
if err != nil {
log.Fatalf("Error reading config file %q: %v", i.ConfigFile, err)
return fmt.Errorf("error reading config file %q: %v", i.ConfigFile, err)
}
// Unmarshal the configuration.
c := make(map[string]interface{})
if len(configBytes) > 0 {
if err := json.Unmarshal(configBytes, &c); err != nil {
return err
}
}

// Add the given runtime.
@@ -106,37 +135,64 @@ func (i *Install) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{})
rts = make(map[string]interface{})
c["runtimes"] = rts
}
rts[i.Runtime] = struct {
Path string `json:"path,omitempty"`
RuntimeArgs []string `json:"runtimeArgs,omitempty"`
}{
Path: path,
RuntimeArgs: runtimeArgs,
updateRuntime := func() {
rts[i.Runtime] = struct {
Path string `json:"path,omitempty"`
RuntimeArgs []string `json:"runtimeArgs,omitempty"`
}{
Path: i.executablePath,
RuntimeArgs: i.runtimeArgs,
}
}
_, ok := rts[i.Runtime]
switch {
case !ok:
log.Printf("Runtime %s not found: adding\n", i.Runtime)
updateRuntime()
case i.Clobber:
log.Printf("Clobber is set. Overwriting runtime %s not found: adding\n", i.Runtime)
updateRuntime()
default:
log.Printf("Not overwriting runtime %s\n", i.Runtime)
}

// Set experimental if required.
if i.Experimental {
c["experimental"] = true
}

re := regexp.MustCompile(`^native.cgroupdriver=`)
// Set the cgroupdriver if required.
if i.CgroupDriver != "" {
v, ok := c["exec-opts"]
if ok {
opts := v.([]interface{})
c["exec-opts"] = append(opts, fmt.Sprintf("native.cgroupdriver=%s", i.CgroupDriver))
} else {
if !ok {
c["exec-opts"] = []string{fmt.Sprintf("native.cgroupdriver=%s", i.CgroupDriver)}
} else {
opts := v.([]interface{})
newOpts := []interface{}{}
for _, opt := range opts {
if !i.Clobber {
newOpts = opts
break
}
o, ok := opt.(string)
if !ok {
continue
}

if !re.MatchString(o) {
newOpts = append(newOpts, o)
}
}
c["exec-opts"] = append(newOpts, fmt.Sprintf("native.cgroupdriver=%s", i.CgroupDriver))
}
}

// Write out the runtime.
if err := writeConfig(c, i.ConfigFile); err != nil {
log.Fatalf("Error writing config file %q: %v", i.ConfigFile, err)
if err := rw.write(c, i.ConfigFile); err != nil {
return fmt.Errorf("error writing config file %q: %v", i.ConfigFile, err)
}

// Success.
log.Printf("Added runtime %q with arguments %v to %q.", i.Runtime, runtimeArgs, i.ConfigFile)
return subcommands.ExitSuccess
return nil
}

// Uninstall implements subcommands.Command.
@@ -170,48 +226,61 @@ func (u *Uninstall) SetFlags(fs *flag.FlagSet) {
// Execute implements subcommands.Command.Execute.
func (u *Uninstall) Execute(context.Context, *flag.FlagSet, ...interface{}) subcommands.ExitStatus {
log.Printf("Removing runtime %q from %q.", u.Runtime, u.ConfigFile)
if err := doUninstallConfig(u, configReaderWriter{
read: defaultReadConfig,
write: defaultWriteConfig,
}); err != nil {
log.Fatalf("Uninstall failed: %v", err)
}
return subcommands.ExitSuccess
}

c, err := readConfig(u.ConfigFile)
func doUninstallConfig(u *Uninstall, rw configReaderWriter) error {
configBytes, err := rw.read(u.ConfigFile)
if err != nil {
log.Fatalf("Error reading config file %q: %v", u.ConfigFile, err)
return fmt.Errorf("error reading config file %q: %v", u.ConfigFile, err)
}

// Unmarshal the configuration.
c := make(map[string]interface{})
if len(configBytes) > 0 {
if err := json.Unmarshal(configBytes, &c); err != nil {
return err
}
}

var rts map[string]interface{}
if i, ok := c["runtimes"]; ok {
rts = i.(map[string]interface{})
} else {
log.Fatalf("runtime %q not found", u.Runtime)
return fmt.Errorf("runtime %q not found", u.Runtime)
}
if _, ok := rts[u.Runtime]; !ok {
log.Fatalf("runtime %q not found", u.Runtime)
return fmt.Errorf("runtime %q not found", u.Runtime)
}
delete(rts, u.Runtime)

if err := writeConfig(c, u.ConfigFile); err != nil {
log.Fatalf("Error writing config file %q: %v", u.ConfigFile, err)
if err := rw.write(c, u.ConfigFile); err != nil {
return fmt.Errorf("error writing config file %q: %v", u.ConfigFile, err)
}
return subcommands.ExitSuccess
return nil
}

type configReaderWriter struct {
read func(string) ([]byte, error)
write func(map[string]interface{}, string) error
}

func readConfig(path string) (map[string]interface{}, error) {
func defaultReadConfig(path string) ([]byte, error) {
// Read the configuration data.
configBytes, err := ioutil.ReadFile(path)
if err != nil && !os.IsNotExist(err) {
return nil, err
}

// Unmarshal the configuration.
c := make(map[string]interface{})
if len(configBytes) > 0 {
if err := json.Unmarshal(configBytes, &c); err != nil {
return nil, err
}
}

return c, nil
return configBytes, nil
}

func writeConfig(c map[string]interface{}, filename string) error {
func defaultWriteConfig(c map[string]interface{}, filename string) error {
// Marshal the configuration.
b, err := json.MarshalIndent(c, "", " ")
if err != nil {

0 comments on commit 671bd7b

Please sign in to comment.