summaryrefslogtreecommitdiffhomepage
path: root/runsc/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'runsc/cmd')
-rw-r--r--runsc/cmd/BUILD3
-rw-r--r--runsc/cmd/capability_test.go4
-rw-r--r--runsc/cmd/install.go210
3 files changed, 215 insertions, 2 deletions
diff --git a/runsc/cmd/BUILD b/runsc/cmd/BUILD
index 5223b9972..250845ad7 100644
--- a/runsc/cmd/BUILD
+++ b/runsc/cmd/BUILD
@@ -19,6 +19,7 @@ go_library(
"exec.go",
"gofer.go",
"help.go",
+ "install.go",
"kill.go",
"list.go",
"path.go",
@@ -81,7 +82,7 @@ go_test(
"//runsc/boot",
"//runsc/container",
"//runsc/specutils",
- "//runsc/test/testutil",
+ "//runsc/testutil",
"@com_github_google_go-cmp//cmp:go_default_library",
"@com_github_google_go-cmp//cmp/cmpopts:go_default_library",
"@com_github_opencontainers_runtime-spec//specs-go:go_default_library",
diff --git a/runsc/cmd/capability_test.go b/runsc/cmd/capability_test.go
index 3ae25a257..0c27f7313 100644
--- a/runsc/cmd/capability_test.go
+++ b/runsc/cmd/capability_test.go
@@ -15,6 +15,7 @@
package cmd
import (
+ "flag"
"fmt"
"os"
"testing"
@@ -25,7 +26,7 @@ import (
"gvisor.dev/gvisor/runsc/boot"
"gvisor.dev/gvisor/runsc/container"
"gvisor.dev/gvisor/runsc/specutils"
- "gvisor.dev/gvisor/runsc/test/testutil"
+ "gvisor.dev/gvisor/runsc/testutil"
)
func init() {
@@ -121,6 +122,7 @@ func TestCapabilities(t *testing.T) {
}
func TestMain(m *testing.M) {
+ flag.Parse()
specutils.MaybeRunAsRoot()
os.Exit(m.Run())
}
diff --git a/runsc/cmd/install.go b/runsc/cmd/install.go
new file mode 100644
index 000000000..441c1db0d
--- /dev/null
+++ b/runsc/cmd/install.go
@@ -0,0 +1,210 @@
+// Copyright 2019 The gVisor Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cmd
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+ "path"
+
+ "flag"
+ "github.com/google/subcommands"
+)
+
+// Install implements subcommands.Command.
+type Install struct {
+ ConfigFile string
+ Runtime string
+ Experimental bool
+}
+
+// Name implements subcommands.Command.Name.
+func (*Install) Name() string {
+ return "install"
+}
+
+// Synopsis implements subcommands.Command.Synopsis.
+func (*Install) Synopsis() string {
+ return "adds a runtime to docker daemon configuration"
+}
+
+// Usage implements subcommands.Command.Usage.
+func (*Install) Usage() string {
+ return `install [flags] <name> [-- [args...]] -- if provided, args are passed to the runtime
+`
+}
+
+// SetFlags implements subcommands.Command.SetFlags.
+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")
+}
+
+// Execute implements subcommands.Command.Execute.
+func (i *Install) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) subcommands.ExitStatus {
+ // Grab the name and arguments.
+ runtimeArgs := f.Args()
+
+ // Extract the executable.
+ path, err := os.Executable()
+ if err != nil {
+ log.Fatalf("Error reading current exectuable: %v", err)
+ }
+
+ // Load the configuration file.
+ c, err := readConfig(i.ConfigFile)
+ if err != nil {
+ log.Fatalf("Error reading config file %q: %v", i.ConfigFile, err)
+ }
+
+ // Add the given runtime.
+ var rts map[string]interface{}
+ if i, ok := c["runtimes"]; ok {
+ rts = i.(map[string]interface{})
+ } else {
+ 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,
+ }
+
+ // Set experimental if required.
+ if i.Experimental {
+ c["experimental"] = true
+ }
+
+ // Write out the runtime.
+ if err := writeConfig(c, i.ConfigFile); err != nil {
+ log.Fatalf("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
+}
+
+// Uninstall implements subcommands.Command.
+type Uninstall struct {
+ ConfigFile string
+ Runtime string
+}
+
+// Name implements subcommands.Command.Name.
+func (*Uninstall) Name() string {
+ return "uninstall"
+}
+
+// Synopsis implements subcommands.Command.Synopsis.
+func (*Uninstall) Synopsis() string {
+ return "removes a runtime from docker daemon configuration"
+}
+
+// Usage implements subcommands.Command.Usage.
+func (*Uninstall) Usage() string {
+ return `uninstall [flags] <name>
+`
+}
+
+// SetFlags implements subcommands.Command.SetFlags.
+func (u *Uninstall) SetFlags(fs *flag.FlagSet) {
+ fs.StringVar(&u.ConfigFile, "config_file", "/etc/docker/daemon.json", "path to Docker daemon config file")
+ fs.StringVar(&u.Runtime, "runtime", "runsc", "runtime name")
+}
+
+// Execute implements subcommands.Command.Execute.
+func (u *Uninstall) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) subcommands.ExitStatus {
+ log.Printf("Removing runtime %q from %q.", u.Runtime, u.ConfigFile)
+
+ c, err := readConfig(u.ConfigFile)
+ if err != nil {
+ log.Fatalf("Error reading config file %q: %v", u.ConfigFile, 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)
+ }
+ if _, ok := rts[u.Runtime]; !ok {
+ log.Fatalf("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)
+ }
+ return subcommands.ExitSuccess
+}
+
+func readConfig(path string) (map[string]interface{}, 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
+}
+
+func writeConfig(c map[string]interface{}, filename string) error {
+ // Marshal the configuration.
+ b, err := json.MarshalIndent(c, "", " ")
+ if err != nil {
+ return err
+ }
+
+ // Copy the old configuration.
+ old, err := ioutil.ReadFile(filename)
+ if err != nil {
+ if !os.IsNotExist(err) {
+ return fmt.Errorf("error reading config file %q: %v", filename, err)
+ }
+ } else {
+ if err := ioutil.WriteFile(filename+"~", old, 0644); err != nil {
+ return fmt.Errorf("error backing up config file %q: %v", filename, err)
+ }
+ }
+
+ // Make the necessary directories.
+ if err := os.MkdirAll(path.Dir(filename), 0755); err != nil {
+ return fmt.Errorf("error creating config directory for %q: %v", filename, err)
+ }
+
+ // Write the new configuration.
+ if err := ioutil.WriteFile(filename, b, 0644); err != nil {
+ return fmt.Errorf("error writing config file %q: %v", filename, err)
+ }
+
+ return nil
+}