Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion internal/cmd/discoverworkload/discoverworkload.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type config struct {
KubeconfigPath string
LabelSelector string
FieldSelector string
CompactOutput bool
}

func NewCommand(ctx context.Context) *cobra.Command {
Expand Down Expand Up @@ -73,6 +74,10 @@ func NewCommand(ctx context.Context) *cobra.Command {
go discover.StartNotifier(ctx, logger, 15*time.Second, 30*time.Second)

logger.Info("starting to watch for workloads", "duration", cfg.Timeout)

opts := discover.NewManifestJSONProcessorFnOptions{
CompactOutput: cfg.CompactOutput,
}
err = discover.WatchForWorkloads(
ctx,
logger,
Expand All @@ -82,7 +87,7 @@ func NewCommand(ctx context.Context) *cobra.Command {
FieldSelector: cfg.FieldSelector,
},
k8sclient,
discover.NewManifestJSONProcessorFn(os.Stdout),
discover.NewManifestJSONProcessorFn(os.Stdout, opts),
)
if err != nil {
switch {
Expand All @@ -108,6 +113,7 @@ func NewCommand(ctx context.Context) *cobra.Command {
flags.StringVarP(&cfg.KubeconfigPath, "kubeconfig", "k", clientcmd.RecommendedHomeFile, "The kubeconfig to use for cluster access.")
flags.StringVarP(&cfg.LabelSelector, "selector", "l", "", "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2). Matching objects must satisfy all of the specified label constraints.")
flags.StringVar(&cfg.FieldSelector, "field-selector", "", "Selector (field query) to filter on, supports '=', '==', and '!='.(e.g. --field-selector key1=value1,key2=value2). The server only supports a limited number of field queries per type.")
flags.BoolVarP(&cfg.CompactOutput, "compact", "c", false, "Print JSON in compact format instead of pretty-printed output")

return c
}
Expand Down
15 changes: 13 additions & 2 deletions internal/discover/processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@ import (
"github.com/opdev/discover-workload/discovery"
)

type NewManifestJSONProcessorFnOptions struct {
CompactOutput bool
}

// NewManifestJSONProcessorFn produces a ProcessingFunction that will write a
// Manifest in JSON to out. This Processor finds all images from containers,
// initContainers, and ephemeralContainers.
func NewManifestJSONProcessorFn(out io.Writer) ProcessingFunction {
func NewManifestJSONProcessorFn(out io.Writer, opts NewManifestJSONProcessorFnOptions) ProcessingFunction {
return func(ctx context.Context, source <-chan *corev1.Pod, logger *slog.Logger) error {
m := discovery.Manifest{}

Expand All @@ -41,7 +45,14 @@ func NewManifestJSONProcessorFn(out io.Writer) ProcessingFunction {
return nil
}

manifestJSON, err := json.Marshal(m)
var manifestJSON []byte
var err error
if opts.CompactOutput {
manifestJSON, err = json.Marshal(m)
} else {
manifestJSON, err = json.MarshalIndent(m, "", " ")
}

if err != nil {
logger.Error("unable to convert output manifest to JSON", "errMsg", err)
return err
Expand Down
29 changes: 26 additions & 3 deletions internal/discover/processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/opdev/discover-workload/discovery"
)

func TestManifestInsert(t *testing.T) {
func TestManifestAppend(t *testing.T) {
t.Parallel()
testcases := map[string]struct {
ctx context.Context
Expand Down Expand Up @@ -391,6 +391,7 @@ func TestManifestJSONProcessor(t *testing.T) {
testcases := map[string]struct {
ctx context.Context
input []corev1.Pod
compact bool
expected []byte
}{
"initContainer only": {
Expand All @@ -408,7 +409,26 @@ func TestManifestJSONProcessor(t *testing.T) {
},
},
},
expected: []byte("{\"DiscoveredImages\":[{\"Image\":\"example.com/namespace/image:0.0.1\",\"Containers\":[{\"Name\":\"init-cname\",\"Type\":\"InitContainer\",\"Pod\":{\"Name\":\"init-podname\",\"Namespace\":\"\"}}]}]}\n"),
compact: false,
expected: []byte("{\n \"DiscoveredImages\": [\n {\n \"Image\": \"example.com/namespace/image:0.0.1\",\n \"Containers\": [\n {\n \"Name\": \"init-cname\",\n \"Type\": \"InitContainer\",\n \"Pod\": {\n \"Name\": \"init-podname\",\n \"Namespace\": \"\"\n }\n }\n ]\n }\n ]\n}\n"),
},
"with raw printed JSON": {
ctx: context.TODO(),
input: []corev1.Pod{
{
ObjectMeta: metav1.ObjectMeta{Name: "podname"},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "cname",
Image: "example.com/namespace/image:0.0.1",
},
},
},
},
},
compact: true,
expected: []byte("{\"DiscoveredImages\":[{\"Image\":\"example.com/namespace/image:0.0.1\",\"Containers\":[{\"Name\":\"cname\",\"Type\":\"Container\",\"Pod\":{\"Name\":\"podname\",\"Namespace\":\"\"}}]}]}\n"),
},
}

Expand All @@ -417,7 +437,10 @@ func TestManifestJSONProcessor(t *testing.T) {
t.Run(description, func(t *testing.T) {
t.Parallel()
buffer := bytes.NewBuffer([]byte{})
fn := NewManifestJSONProcessorFn(buffer)
opts := NewManifestJSONProcessorFnOptions{
CompactOutput: tc.compact,
}
fn := NewManifestJSONProcessorFn(buffer, opts)

ch := make(chan *corev1.Pod)

Expand Down