From 06f638e2212afad84c80ac045916122d11e67cf6 Mon Sep 17 00:00:00 2001 From: John Schnake Date: Fri, 27 Sep 2019 14:33:59 -0500 Subject: [PATCH] Allow the --plugin flag to specify a directory of plugins (#911) If someone specifies `sonobuoy run|gen --plugin X` then X ought to be allowed to be either a single plugin file or a directory of plugins. To avoid dropping errors intentionally or processing lots of unnecessary files, when processing a directory, we only consider *.yaml files. We also do not recurse deeper into the directory. Fixes #906 Signed-off-by: John Schnake --- cmd/sonobuoy/app/gen.go | 2 +- cmd/sonobuoy/app/gen_test.go | 222 ++++++++++++------ cmd/sonobuoy/app/pluginList.go | 49 +++- cmd/sonobuoy/app/pluginList_test.go | 12 +- cmd/sonobuoy/app/testdata/sonobuoy.conf | 6 - .../app/testdata/testPluginDir/plugin1.yaml | 14 ++ .../app/testdata/testPluginDir/plugin2.yaml | 14 ++ .../testdata/testPluginDir/pluginNotYAML.ext | 14 ++ 8 files changed, 243 insertions(+), 90 deletions(-) delete mode 100644 cmd/sonobuoy/app/testdata/sonobuoy.conf create mode 100644 cmd/sonobuoy/app/testdata/testPluginDir/plugin1.yaml create mode 100644 cmd/sonobuoy/app/testdata/testPluginDir/plugin2.yaml create mode 100644 cmd/sonobuoy/app/testdata/testPluginDir/pluginNotYAML.ext diff --git a/cmd/sonobuoy/app/gen.go b/cmd/sonobuoy/app/gen.go index f6771be79..f83aefd03 100644 --- a/cmd/sonobuoy/app/gen.go +++ b/cmd/sonobuoy/app/gen.go @@ -104,7 +104,7 @@ func (g *genFlags) Config() (*client.GenConfig, error) { // the Enabled and Disabled modes of rbacmode don't need the client, so kubeclient can be nil. // if kubeclient is needed, ErrRBACNoClient will be returned and that error can be reported back up. - rbacEnabled, err := genflags.rbacMode.Enabled(kubeclient) + rbacEnabled, err := g.rbacMode.Enabled(kubeclient) if err != nil { if errors.Cause(err) == ErrRBACNoClient { return nil, errors.Wrap(err, kubeError.Error()) diff --git a/cmd/sonobuoy/app/gen_test.go b/cmd/sonobuoy/app/gen_test.go index 248efc984..cfb57b37c 100644 --- a/cmd/sonobuoy/app/gen_test.go +++ b/cmd/sonobuoy/app/gen_test.go @@ -14,6 +14,8 @@ limitations under the License. package app import ( + "io/ioutil" + "os" "reflect" "strings" "testing" @@ -22,6 +24,10 @@ import ( "github.com/heptio/sonobuoy/pkg/client" "github.com/heptio/sonobuoy/pkg/config" "github.com/heptio/sonobuoy/pkg/plugin" + "github.com/heptio/sonobuoy/pkg/plugin/manifest" + + "github.com/kylelemons/godebug/pretty" + v1 "k8s.io/api/core/v1" ) const ( @@ -85,19 +91,30 @@ func TestResolveConformanceImage(t *testing.T) { func TestResolveConfig(t *testing.T) { defaultPluginSearchPath := config.New().PluginSearchPath defaultAggr := plugin.AggregationConfig{TimeoutSeconds: 10800} + dynamicConfigFileName := "*determinedAtRuntime*" tcs := []struct { - name string - input *genFlags + name string + + // CLI input to parse. + input string + + // Not every field of this will be tested at this time. expected *config.Config - cliInput string + + // If specified, will write the config to a temp file then append + // the `--config=tmpfile` to the input. This way we can keep the config files + // small and with the test rather than in a testdata file. + configFileContents string + + // TODO(jschnake): This test previously was just testing the config.Config + // and only certain fields. We may consider expanding this to testing the entire + // genConfig object but for now I am expanding this just to ensure proper plugin loading. + expectedGenConfigPlugins *client.GenConfig }{ { - name: "NonDisruptiveConformance mode when supplied config is nil (nothing interesting happens)", - input: &genFlags{ - mode: client.NonDisruptiveConformance, - sonobuoyConfig: SonobuoyConfig{}, - }, + name: "NonDisruptiveConformance mode when supplied config is nil (nothing interesting happens)", + input: "", expected: &config.Config{ Namespace: "sonobuoy", WorkerImage: "gcr.io/heptio-images/sonobuoy:" + buildinfo.Version, @@ -110,19 +127,13 @@ func TestResolveConfig(t *testing.T) { Aggregation: defaultAggr, Resources: config.DefaultResources, }, - }, { - name: "Quick mode and a non-nil supplied config", - input: &genFlags{ - mode: client.Quick, - sonobuoyConfig: SonobuoyConfig{ - Config: config.Config{ - Aggregation: plugin.AggregationConfig{ - BindAddress: "10.0.0.1", - }, - }, - raw: rawInput, - }, + expectedGenConfigPlugins: &client.GenConfig{ + DynamicPlugins: []string{"e2e", "systemd-logs"}, }, + }, { + name: "Quick mode and a non-nil supplied config", + input: "--mode quick --config=" + dynamicConfigFileName, + configFileContents: `{"Server":{"bindaddress":"10.0.0.1"}}`, expected: &config.Config{ Namespace: "sonobuoy", WorkerImage: "gcr.io/heptio-images/sonobuoy:" + buildinfo.Version, @@ -138,19 +149,13 @@ func TestResolveConfig(t *testing.T) { PluginSearchPath: defaultPluginSearchPath, Resources: config.DefaultResources, }, - }, { - name: "NonDisruptiveConformance mode with plugin selection specified", - input: &genFlags{ - mode: client.NonDisruptiveConformance, - sonobuoyConfig: SonobuoyConfig{ - Config: config.Config{ - PluginSelections: []plugin.Selection{ - {Name: "systemd-logs"}, - }, - }, - raw: "not empty", - }, + expectedGenConfigPlugins: &client.GenConfig{ + DynamicPlugins: []string{"e2e"}, }, + }, { + name: "NonDisruptiveConformance mode with plugin selection specified", + input: "--plugin systemd-logs --config=" + dynamicConfigFileName, + configFileContents: `{"Plugins":[{"name":"systemd-logs"}]}`, expected: &config.Config{ Namespace: "sonobuoy", WorkerImage: "gcr.io/heptio-images/sonobuoy:" + buildinfo.Version, @@ -166,14 +171,13 @@ func TestResolveConfig(t *testing.T) { }, Resources: config.DefaultResources, }, - }, { - name: "Flags should override the config settings when set", - input: &genFlags{ - sonobuoyConfig: SonobuoyConfig{ - Config: config.Config{Namespace: "configNS"}, - }, + expectedGenConfigPlugins: &client.GenConfig{ + DynamicPlugins: []string{"systemd-logs"}, }, - cliInput: "--namespace=flagNS --sonobuoy-image=flagImage --image-pull-policy=Always --timeout 100", + }, { + name: "NS flag prioritized over config value", + configFileContents: `{"Namespace":"configNS","WorkerImage":"configImage","ImagePullPolicy":"IfNotPresent","Server":{"timeoutseconds":999}}`, + input: "--namespace=flagNS --sonobuoy-image=flagImage --image-pull-policy=Always --timeout 100 --config=" + dynamicConfigFileName, expected: &config.Config{ Namespace: "flagNS", WorkerImage: "flagImage", @@ -186,14 +190,17 @@ func TestResolveConfig(t *testing.T) { Aggregation: plugin.AggregationConfig{TimeoutSeconds: 100}, Resources: config.DefaultResources, }, + expectedGenConfigPlugins: &client.GenConfig{ + DynamicPlugins: []string{"e2e", "systemd-logs"}, + }, }, { - name: "Flags shouldn't override the config settings unless set", - input: &genFlags{}, - cliInput: "--sonobuoy-image=flagImage --config testdata/sonobuoy.conf", + name: "Worker image and pull policy flags prioritized over config values", + input: "--sonobuoy-image=flagImage --image-pull-policy=Always --config " + dynamicConfigFileName, + configFileContents: `{"Namespace":"configNS","WorkerImage":"configImage","ImagePullPolicy":"Never","Server":{"timeoutseconds":500}}`, expected: &config.Config{ Namespace: "configNS", WorkerImage: "flagImage", - ImagePullPolicy: "Never", + ImagePullPolicy: "Always", PluginSelections: []plugin.Selection{ {Name: "e2e"}, {Name: "systemd-logs"}, @@ -202,10 +209,13 @@ func TestResolveConfig(t *testing.T) { Aggregation: plugin.AggregationConfig{TimeoutSeconds: 500}, Resources: config.DefaultResources, }, + expectedGenConfigPlugins: &client.GenConfig{ + DynamicPlugins: []string{"e2e", "systemd-logs"}, + }, }, { - name: "Flags shouldn't override the config settings unless set", - input: &genFlags{}, - cliInput: "--config testdata/sonobuoy.conf", + name: "Default flag values dont override config values", + input: "--config " + dynamicConfigFileName, + configFileContents: `{"Namespace":"configNS","WorkerImage":"configImage","ImagePullPolicy":"Never","Server":{"timeoutseconds":500}}`, expected: &config.Config{ Namespace: "configNS", WorkerImage: "configImage", @@ -218,10 +228,12 @@ func TestResolveConfig(t *testing.T) { Aggregation: plugin.AggregationConfig{TimeoutSeconds: 500}, Resources: config.DefaultResources, }, + expectedGenConfigPlugins: &client.GenConfig{ + DynamicPlugins: []string{"e2e", "systemd-logs"}, + }, }, { - name: "Manually specified plugins should result in empty selection", - input: &genFlags{}, - cliInput: "--plugin e2e", + name: "Manually specified plugins should result in empty selection", + input: "--plugin e2e", expected: &config.Config{ Namespace: "sonobuoy", WorkerImage: "gcr.io/heptio-images/sonobuoy:" + buildinfo.Version, @@ -231,10 +243,12 @@ func TestResolveConfig(t *testing.T) { Aggregation: defaultAggr, Resources: config.DefaultResources, }, + expectedGenConfigPlugins: &client.GenConfig{ + DynamicPlugins: []string{"e2e"}, + }, }, { - name: "Empty, non-nil resources and plugins should be preserved", - input: &genFlags{}, - cliInput: "--config testdata/emptyQueryAndPlugins.conf", + name: "Empty, non-nil resources and plugins should be preserved", + input: "--config testdata/emptyQueryAndPlugins.conf", expected: &config.Config{ Namespace: "sonobuoy", WorkerImage: "gcr.io/heptio-images/sonobuoy:" + buildinfo.Version, @@ -244,44 +258,110 @@ func TestResolveConfig(t *testing.T) { PluginSelections: []plugin.Selection{}, Resources: []string{}, }, + expectedGenConfigPlugins: &client.GenConfig{}, + }, { + name: "Plugins can be loaded by directory", + input: "--plugin testdata/testPluginDir", + expected: &config.Config{ + Namespace: "sonobuoy", + WorkerImage: "gcr.io/heptio-images/sonobuoy:" + buildinfo.Version, + ImagePullPolicy: "IfNotPresent", + PluginSelections: nil, + PluginSearchPath: defaultPluginSearchPath, + Aggregation: defaultAggr, + Resources: config.DefaultResources, + }, + expectedGenConfigPlugins: &client.GenConfig{ + StaticPlugins: []*manifest.Manifest{ + {SonobuoyConfig: manifest.SonobuoyConfig{Driver: "Job", PluginName: "plugin1", SkipCleanup: false, ResultFormat: "raw"}, Spec: manifest.Container{Container: v1.Container{Name: "plugin", Image: "foo/bar:v1", Command: []string{"./run.sh"}, VolumeMounts: []v1.VolumeMount{{ReadOnly: false, Name: "results", MountPath: plugin.ResultsDir}}}}}, + {SonobuoyConfig: manifest.SonobuoyConfig{Driver: "Job", PluginName: "plugin2", SkipCleanup: false, ResultFormat: "raw"}, Spec: manifest.Container{Container: v1.Container{Name: "plugin", Image: "foo/bar:v2", Command: []string{"./run.sh"}, VolumeMounts: []v1.VolumeMount{{ReadOnly: false, Name: "results", MountPath: plugin.ResultsDir}}}}}, + }, + }, + }, { + name: "Plugins loaded by directory and by name", + input: "--plugin e2e --plugin testdata/testPluginDir --plugin testdata/testPluginDir/pluginNotYAML.ext", + expected: &config.Config{ + Namespace: "sonobuoy", + WorkerImage: "gcr.io/heptio-images/sonobuoy:" + buildinfo.Version, + ImagePullPolicy: "IfNotPresent", + PluginSelections: nil, + PluginSearchPath: defaultPluginSearchPath, + Aggregation: defaultAggr, + Resources: config.DefaultResources, + }, + expectedGenConfigPlugins: &client.GenConfig{ + StaticPlugins: []*manifest.Manifest{ + {SonobuoyConfig: manifest.SonobuoyConfig{Driver: "Job", PluginName: "plugin1", SkipCleanup: false, ResultFormat: "raw"}, Spec: manifest.Container{Container: v1.Container{Name: "plugin", Image: "foo/bar:v1", Command: []string{"./run.sh"}, VolumeMounts: []v1.VolumeMount{{ReadOnly: false, Name: "results", MountPath: plugin.ResultsDir}}}}}, + {SonobuoyConfig: manifest.SonobuoyConfig{Driver: "Job", PluginName: "plugin2", SkipCleanup: false, ResultFormat: "raw"}, Spec: manifest.Container{Container: v1.Container{Name: "plugin", Image: "foo/bar:v2", Command: []string{"./run.sh"}, VolumeMounts: []v1.VolumeMount{{ReadOnly: false, Name: "results", MountPath: plugin.ResultsDir}}}}}, + {SonobuoyConfig: manifest.SonobuoyConfig{Driver: "Job", PluginName: "plugin3", SkipCleanup: false, ResultFormat: "raw"}, Spec: manifest.Container{Container: v1.Container{Name: "plugin", Image: "foo/bar:v3", Command: []string{"./run.sh"}, VolumeMounts: []v1.VolumeMount{{ReadOnly: false, Name: "results", MountPath: plugin.ResultsDir}}}}}, + }, + DynamicPlugins: []string{"e2e"}, + }, }, } for _, tc := range tcs { t.Run(tc.name, func(t *testing.T) { - // Simulate parsing of input via CLI. Making this optional to avoid complicating - // setup for other tests which just explicitly set the values. - if len(tc.cliInput) > 0 { - fs := GenFlagSet(tc.input, EnabledRBACMode) - if err := fs.Parse(strings.Split(tc.cliInput, " ")); err != nil { - t.Fatalf("Failed to parse CLI input %q: %v", tc.cliInput, err) + // Write and load a config file + if len(tc.configFileContents) > 0 { + tmpFile, err := ioutil.TempFile("", "") + if err != nil { + t.Fatalf("Failed to create temp file for test: %v", err) } + defer os.Remove(tmpFile.Name()) + err = ioutil.WriteFile(tmpFile.Name(), []byte(tc.configFileContents), 0666) + if err != nil { + t.Fatalf("Failed to write temp config file for test: %v", err) + } + tc.input = strings.Replace(tc.input, dynamicConfigFileName, tmpFile.Name(), -1) + } + + // Simulate parsing of input via CLI. + gflagset := &genFlags{} + fs := GenFlagSet(gflagset, EnabledRBACMode) + if err := fs.Parse(strings.Split(tc.input, " ")); err != nil { + t.Fatalf("Failed to parse CLI input %q: %v", tc.input, err) } - conf := tc.input.resolveConfig() + // Manually set KubeConformanceImage for all tests so that it does not error due to having 'auto' image + // without a real cluster to target for version info + gflagset.kubeConformanceImage = "testOnly" + + genConfig, err := gflagset.Config() + if err != nil { + t.Fatalf("Failed to generate GenConfig: %v", err) + } + + if genConfig.Config.Namespace != tc.expected.Namespace { + t.Errorf("Expected namespace %v but got %v", tc.expected.Namespace, genConfig.Config.Namespace) + } + + if genConfig.Config.WorkerImage != tc.expected.WorkerImage { + t.Errorf("Expected worker image %v but got %v", tc.expected.WorkerImage, genConfig.Config.WorkerImage) + } - if conf.Namespace != tc.expected.Namespace { - t.Errorf("Expected namespace %v but got %v", tc.expected.Namespace, conf.Namespace) + if genConfig.Config.ImagePullPolicy != tc.expected.ImagePullPolicy { + t.Errorf("Expected image pull policy %v but got %v", tc.expected.ImagePullPolicy, genConfig.Config.ImagePullPolicy) } - if conf.WorkerImage != tc.expected.WorkerImage { - t.Errorf("Expected worker image %v but got %v", tc.expected.WorkerImage, conf.WorkerImage) + if genConfig.Config.Aggregation.TimeoutSeconds != tc.expected.Aggregation.TimeoutSeconds { + t.Errorf("Expected timeout %v but got %v", tc.expected.Aggregation.TimeoutSeconds, genConfig.Config.Aggregation.TimeoutSeconds) } - if conf.ImagePullPolicy != tc.expected.ImagePullPolicy { - t.Errorf("Expected image pull policy %v but got %v", tc.expected.ImagePullPolicy, conf.ImagePullPolicy) + if !reflect.DeepEqual(genConfig.Config.PluginSelections, tc.expected.PluginSelections) { + t.Errorf("expected PluginSelections %v but got %v", tc.expected.PluginSelections, genConfig.Config.PluginSelections) } - if conf.Aggregation.TimeoutSeconds != tc.expected.Aggregation.TimeoutSeconds { - t.Errorf("Expected timeout %v but got %v", tc.expected.Aggregation.TimeoutSeconds, conf.Aggregation.TimeoutSeconds) + if !reflect.DeepEqual(genConfig.Config.Resources, tc.expected.Resources) { + t.Errorf("expected resources %v but got %v", tc.expected.Resources, genConfig.Config.Resources) } - if !reflect.DeepEqual(conf.PluginSelections, tc.expected.PluginSelections) { - t.Errorf("expected PluginSelections %v but got %v", tc.expected.PluginSelections, conf.PluginSelections) + if diff := pretty.Compare(genConfig.StaticPlugins, tc.expectedGenConfigPlugins.StaticPlugins); diff != "" { + t.Errorf("expected static plugins to match but got diff:\n%s\n", diff) } - if !reflect.DeepEqual(conf.Resources, tc.expected.Resources) { - t.Errorf("expected resources %v but got %v", tc.expected.Resources, conf.Resources) + if diff := pretty.Compare(genConfig.DynamicPlugins, tc.expectedGenConfigPlugins.DynamicPlugins); diff != "" { + t.Errorf("expected dynamic plugins to match but got diff:\n%s\n", diff) } }) } diff --git a/cmd/sonobuoy/app/pluginList.go b/cmd/sonobuoy/app/pluginList.go index 13516901d..63cf91ba2 100644 --- a/cmd/sonobuoy/app/pluginList.go +++ b/cmd/sonobuoy/app/pluginList.go @@ -18,6 +18,8 @@ package app import ( "io/ioutil" + "os" + "path/filepath" "strings" "github.com/heptio/sonobuoy/pkg/plugin/manifest" @@ -41,6 +43,7 @@ type pluginList struct { const ( pluginE2E = "e2e" pluginSystemdLogs = "systemd-logs" + fileExtensionYAML = ".yaml" ) // Make sure pluginList implements Value properly @@ -71,19 +74,53 @@ func (p *pluginList) Set(str string) error { case pluginSystemdLogs: p.DynamicPlugins = append(p.DynamicPlugins, str) default: - b, err := ioutil.ReadFile(str) + finfo, err := os.Stat(str) if err != nil { - return errors.Wrapf(err, "unable to read file '%v'", str) + return errors.Wrapf(err, "unable to stat %q", str) } - newPlugin, err := loadManifest(b) - if err != nil { - return errors.Wrapf(err, "failed to load plugin file '%v'", str) + if finfo.IsDir() { + return p.loadPluginsDir(str) } + return p.loadSinglePlugin(str) + } + + return nil +} + +// loadPluginsDir loads every plugin in the given directory. It does not traverse recursively +// into the directory. A plugin must have the '.yaml' extension to be considered. +// It returns the first error encountered and stops processing. +func (p *pluginList) loadPluginsDir(dirpath string) error { + files, err := ioutil.ReadDir(dirpath) + if err != nil { + return errors.Wrapf(err, "failed to read directory %q", dirpath) + } + + for _, file := range files { + if !file.IsDir() && strings.HasSuffix(file.Name(), fileExtensionYAML) { + if err := p.loadSinglePlugin(filepath.Join(dirpath, file.Name())); err != nil { + return errors.Wrapf(err, "failed to load plugin in file %q", file.Name()) + } + } + } + + return nil +} + +// loadSinglePlugin loads a single plugin located at the given path. +func (p *pluginList) loadSinglePlugin(filepath string) error { + b, err := ioutil.ReadFile(filepath) + if err != nil { + return errors.Wrapf(err, "unable to read file %q", filepath) + } - p.StaticPlugins = append(p.StaticPlugins, newPlugin) + newPlugin, err := loadManifest(b) + if err != nil { + return errors.Wrapf(err, "failed to load plugin file %q", filepath) } + p.StaticPlugins = append(p.StaticPlugins, newPlugin) return nil } diff --git a/cmd/sonobuoy/app/pluginList_test.go b/cmd/sonobuoy/app/pluginList_test.go index 744062eb0..ecf06aa76 100644 --- a/cmd/sonobuoy/app/pluginList_test.go +++ b/cmd/sonobuoy/app/pluginList_test.go @@ -33,15 +33,15 @@ func TestSetPluginList(t *testing.T) { }{ { desc: "empty filename", - expectErr: `unable to read file '': open : no such file or directory`, + expectErr: `unable to stat "": stat : no such file or directory`, }, { desc: "file does not exist", input: "no-file", - expectErr: `unable to read file 'no-file': open no-file: no such file or directory`, + expectErr: `unable to stat "no-file": stat no-file: no such file or directory`, }, { desc: "bad manifest", input: "testdata/badmanifest.yaml", - expectErr: `failed to load plugin file 'testdata/badmanifest.yaml': couldn't decode yaml for plugin definition: couldn't get version/kind; json parse error: json: cannot unmarshal string into Go value of type struct { APIVersion string "json:\"apiVersion,omitempty\""; Kind string "json:\"kind,omitempty\"" }`, + expectErr: `failed to load plugin file "testdata/badmanifest.yaml": couldn't decode yaml for plugin definition: couldn't get version/kind; json parse error: json: cannot unmarshal string into Go value of type struct { APIVersion string "json:\"apiVersion,omitempty\""; Kind string "json:\"kind,omitempty\"" }`, }, { desc: "loading e2e", input: "e2e", @@ -57,17 +57,17 @@ func TestSetPluginList(t *testing.T) { input: "testdata/goodmanifest.yaml", list: pluginList{}, expect: pluginList{StaticPlugins: []*manifest.Manifest{ - &manifest.Manifest{SonobuoyConfig: manifest.SonobuoyConfig{PluginName: "test"}}, + {SonobuoyConfig: manifest.SonobuoyConfig{PluginName: "test"}}, }}, }, { desc: "dynamic and static", input: "e2e", list: pluginList{StaticPlugins: []*manifest.Manifest{ - &manifest.Manifest{SonobuoyConfig: manifest.SonobuoyConfig{PluginName: "test"}}, + {SonobuoyConfig: manifest.SonobuoyConfig{PluginName: "test"}}, }}, expect: pluginList{ StaticPlugins: []*manifest.Manifest{ - &manifest.Manifest{SonobuoyConfig: manifest.SonobuoyConfig{PluginName: "test"}}, + {SonobuoyConfig: manifest.SonobuoyConfig{PluginName: "test"}}, }, DynamicPlugins: []string{"e2e"}, }, diff --git a/cmd/sonobuoy/app/testdata/sonobuoy.conf b/cmd/sonobuoy/app/testdata/sonobuoy.conf deleted file mode 100644 index dfd5e49ca..000000000 --- a/cmd/sonobuoy/app/testdata/sonobuoy.conf +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Namespace":"configNS", - "WorkerImage":"configImage", - "ImagePullPolicy":"Never", - "Server":{"timeoutseconds":500} -} \ No newline at end of file diff --git a/cmd/sonobuoy/app/testdata/testPluginDir/plugin1.yaml b/cmd/sonobuoy/app/testdata/testPluginDir/plugin1.yaml new file mode 100644 index 000000000..8d0ec33c2 --- /dev/null +++ b/cmd/sonobuoy/app/testdata/testPluginDir/plugin1.yaml @@ -0,0 +1,14 @@ +sonobuoy-config: + driver: Job + plugin-name: plugin1 + result-format: raw +spec: + command: + - ./run.sh + image: foo/bar:v1 + name: plugin + resources: {} + volumeMounts: + - mountPath: /tmp/results + name: results + diff --git a/cmd/sonobuoy/app/testdata/testPluginDir/plugin2.yaml b/cmd/sonobuoy/app/testdata/testPluginDir/plugin2.yaml new file mode 100644 index 000000000..c59ff8da6 --- /dev/null +++ b/cmd/sonobuoy/app/testdata/testPluginDir/plugin2.yaml @@ -0,0 +1,14 @@ +sonobuoy-config: + driver: Job + plugin-name: plugin2 + result-format: raw +spec: + command: + - ./run.sh + image: foo/bar:v2 + name: plugin + resources: {} + volumeMounts: + - mountPath: /tmp/results + name: results + diff --git a/cmd/sonobuoy/app/testdata/testPluginDir/pluginNotYAML.ext b/cmd/sonobuoy/app/testdata/testPluginDir/pluginNotYAML.ext new file mode 100644 index 000000000..2ef4965fd --- /dev/null +++ b/cmd/sonobuoy/app/testdata/testPluginDir/pluginNotYAML.ext @@ -0,0 +1,14 @@ +sonobuoy-config: + driver: Job + plugin-name: plugin3 + result-format: raw +spec: + command: + - ./run.sh + image: foo/bar:v3 + name: plugin + resources: {} + volumeMounts: + - mountPath: /tmp/results + name: results +