Allow pod init config to be used with runsc trace create

As convenience allow a pod init config file to be used to create
a trace session. It's common to want to use the same configuration
for pod init and trace create, but the config file formats are
different. This change allows both formats to be used with
`runsc trace create`.

Updates #4805

PiperOrigin-RevId: 454075022
This commit is contained in:
Fabricio Voznika
2022-06-09 20:43:45 -07:00
committed by gVisor bot
parent cbbcf93443
commit 1dad561c8b
4 changed files with 129 additions and 9 deletions
+1
View File
@@ -55,6 +55,7 @@ func LoadInitConfig(path string) (*InitConfig, error) {
func loadInitConfig(reader io.Reader) (*InitConfig, error) {
decoder := json.NewDecoder(reader)
decoder.DisallowUnknownFields()
init := &InitConfig{}
if err := decoder.Decode(init); err != nil {
return nil, err
+14 -1
View File
@@ -1,4 +1,4 @@
load("//tools:defs.bzl", "go_library")
load("//tools:defs.bzl", "go_library", "go_test")
package(licenses = ["notice"])
@@ -18,6 +18,7 @@ go_library(
deps = [
"//pkg/log",
"//pkg/sentry/seccheck",
"//runsc/boot",
"//runsc/cmd/util",
"//runsc/config",
"//runsc/container",
@@ -25,3 +26,15 @@ go_library(
"@com_github_google_subcommands//:go_default_library",
],
)
go_test(
name = "trace_test",
size = "small",
srcs = ["create_test.go"],
library = ":trace",
deps = [
"//pkg/sentry/seccheck",
"//pkg/test/testutil",
"//runsc/boot",
],
)
+35 -8
View File
@@ -17,10 +17,13 @@ package trace
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/google/subcommands"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/sentry/seccheck"
"gvisor.dev/gvisor/runsc/boot"
"gvisor.dev/gvisor/runsc/cmd/util"
"gvisor.dev/gvisor/runsc/config"
"gvisor.dev/gvisor/runsc/container"
@@ -66,15 +69,9 @@ func (l *create) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}
return util.Errorf("missing path to configuration file, please set --config=[path]")
}
file, err := os.Open(l.config)
sessionConfig, err := decodeTraceConfig(l.config)
if err != nil {
return util.Errorf(err.Error())
}
defer file.Close()
decoder := json.NewDecoder(file)
sessionConfig := &seccheck.SessionConfig{}
if err := decoder.Decode(sessionConfig); err != nil {
return util.Errorf("invalid configuration file: %v", err)
return util.Errorf("loading config file: %v", err)
}
id := f.Arg(0)
@@ -95,3 +92,33 @@ func (l *create) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}
return subcommands.ExitSuccess
}
func decodeTraceConfig(path string) (*seccheck.SessionConfig, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
decoder := json.NewDecoder(file)
decoder.DisallowUnknownFields()
sessionConfig := &seccheck.SessionConfig{}
err = decoder.Decode(sessionConfig)
if err == nil {
// Success, we're done.
return sessionConfig, nil
}
// If file cannot be decoded as a SessionConfig, try with InitConfig as
// convenience in case the caller wants to reuse a trace session from
// InitConfig file.
log.Debugf("Config file is not a seccheck.SessionConfig, try with boot.InitConfig instead: %v", err)
if _, err := file.Seek(0, 0); err != nil {
return nil, err
}
initConfig := &boot.InitConfig{}
if err := decoder.Decode(initConfig); err != nil {
return nil, fmt.Errorf("invalid configuration file: %w", err)
}
return &initConfig.TraceSession, nil
}
+79
View File
@@ -0,0 +1,79 @@
// Copyright 2022 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 trace
import (
"encoding/json"
"os"
"reflect"
"strings"
"testing"
"gvisor.dev/gvisor/pkg/sentry/seccheck"
"gvisor.dev/gvisor/pkg/test/testutil"
"gvisor.dev/gvisor/runsc/boot"
)
func TestConfigFile(t *testing.T) {
testCfg := seccheck.SessionConfig{
Name: "Default",
Points: []seccheck.PointConfig{
{Name: "point-1"},
},
Sinks: []seccheck.SinkConfig{{Name: "sink-1"}},
}
for _, tc := range []struct {
name string
json interface{}
want seccheck.SessionConfig
err string
}{
{
name: "SessionConfig",
json: testCfg,
want: testCfg,
},
{
name: "InitConfig",
json: boot.InitConfig{TraceSession: testCfg},
want: testCfg,
},
} {
t.Run(tc.name, func(t *testing.T) {
tmp, err := os.CreateTemp(testutil.TmpDir(), "trace-create")
if err != nil {
t.Fatal(err)
}
defer tmp.Close()
encoder := json.NewEncoder(tmp)
if err := encoder.Encode(tc.json); err != nil {
t.Fatal(err)
}
config, err := decodeTraceConfig(tmp.Name())
if len(tc.err) == 0 {
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(&tc.want, config) {
t.Errorf("loaded trace session is different, want: %+v, got: %+v", &tc.want, config)
}
} else if err == nil || !strings.Contains(err.Error(), tc.err) {
t.Errorf("unexpected error, want: %q, got: %v", tc.err, err)
}
})
}
}