From e556b08857a84da90171f5172fc6615bd9850120 Mon Sep 17 00:00:00 2001 From: Pratik Jagrut Date: Tue, 17 Oct 2023 13:01:59 +0530 Subject: [PATCH] test: add unit tests for tarian-pod-agent --- cmd/tarian-pod-agent/cmd/flags/flags_test.go | 55 +++++++++ cmd/tarian-pod-agent/cmd/register.go | 36 +++--- cmd/tarian-pod-agent/cmd/register_test.go | 123 +++++++++++++++++++ cmd/tarian-pod-agent/cmd/root.go | 2 +- cmd/tarian-pod-agent/cmd/root_test.go | 36 ++++++ cmd/tarian-pod-agent/cmd/threat_scan.go | 59 +++------ cmd/tarian-pod-agent/cmd/threat_scan_test.go | 88 +++++++++++++ cmd/tarian-pod-agent/cmd/util.go | 44 +++++++ cmd/tarian-pod-agent/cmd/util_test.go | 66 ++++++++++ cmd/tarian-pod-agent/cmd/version.go | 6 +- cmd/tarianctl/cmd/flags/flags_test.go | 3 +- pkg/podagent/fake_podagent.go | 121 ++++++++++++++++++ pkg/podagent/interface.go | 43 +++++++ pkg/podagent/podagent.go | 25 +++- test/e2e/e2e_helper.go | 2 +- 15 files changed, 638 insertions(+), 71 deletions(-) create mode 100644 cmd/tarian-pod-agent/cmd/flags/flags_test.go create mode 100644 cmd/tarian-pod-agent/cmd/register_test.go create mode 100644 cmd/tarian-pod-agent/cmd/root_test.go create mode 100644 cmd/tarian-pod-agent/cmd/threat_scan_test.go create mode 100644 cmd/tarian-pod-agent/cmd/util.go create mode 100644 cmd/tarian-pod-agent/cmd/util_test.go create mode 100644 pkg/podagent/fake_podagent.go create mode 100644 pkg/podagent/interface.go diff --git a/cmd/tarian-pod-agent/cmd/flags/flags_test.go b/cmd/tarian-pod-agent/cmd/flags/flags_test.go new file mode 100644 index 00000000..d85ef37a --- /dev/null +++ b/cmd/tarian-pod-agent/cmd/flags/flags_test.go @@ -0,0 +1,55 @@ +package flags + +import ( + "testing" + + "github.com/spf13/pflag" + "github.com/stretchr/testify/assert" +) + +func TestSetGlobalFlags(t *testing.T) { + // Create a FlagSet for testing + fs := pflag.NewFlagSet("test", pflag.ExitOnError) + + // Initialize global flags + globalFlags := SetGlobalFlags(fs) + + // Test default values + assert.Equal(t, "info", globalFlags.LogLevel) + assert.Equal(t, "text", globalFlags.LogFormatter) +} + +func TestValidateGlobalFlags(t *testing.T) { + tests := []struct { + name string + globalFlags *GlobalFlags + expectedError string + }{ + { + name: "Valid Flags", + globalFlags: &GlobalFlags{LogLevel: "info", LogFormatter: "text"}, + expectedError: "", + }, + { + name: "Invalid LogLevel", + globalFlags: &GlobalFlags{LogLevel: "invalid", LogFormatter: "text"}, + expectedError: "invalid log level: invalid", + }, + { + name: "Invalid LogFormatter", + globalFlags: &GlobalFlags{LogLevel: "info", LogFormatter: "invalid"}, + expectedError: "invalid log formatter: invalid", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.globalFlags.ValidateGlobalFlags() + if tt.expectedError == "" { + assert.NoError(t, err) + } else { + assert.EqualError(t, err, tt.expectedError) + } + }) + } +} diff --git a/cmd/tarian-pod-agent/cmd/register.go b/cmd/tarian-pod-agent/cmd/register.go index 1eedf50b..54ff871c 100644 --- a/cmd/tarian-pod-agent/cmd/register.go +++ b/cmd/tarian-pod-agent/cmd/register.go @@ -1,6 +1,7 @@ package cmd import ( + "fmt" "os" "os/signal" "strings" @@ -29,6 +30,8 @@ type registerCommand struct { registerFilePaths string registerFileIgnorePaths string fileValidationInterval time.Duration + + podAgent podagent.Agent } func newRegisterCommand(globalFlag *flags.GlobalFlags) *cobra.Command { @@ -61,13 +64,14 @@ func newRegisterCommand(globalFlag *flags.GlobalFlags) *cobra.Command { func (c *registerCommand) runRegisterCommand(cmd *cobra.Command, args []string) error { c.logger.Info("tarian-pod-agent is running in register mode") addr := c.host + ":" + c.port - agent := podagent.NewPodAgent(c.logger, addr) + if c.podAgent == nil { + c.podAgent = podagent.NewPodAgent(c.logger, addr) + } if c.podLabelsFile != "" { - podLabels, err := readLabelsFromFile(c.podLabelsFile) - + podLabels, err := readLabelsFromFile(c.logger, c.podLabelsFile) if err != nil { - c.logger.WithError(err).Error("failed reading pod-labels-file") + return fmt.Errorf("failed reading pod-labels-file: %w", err) } // delete pod-template-hash @@ -82,24 +86,24 @@ func (c *registerCommand) runRegisterCommand(cmd *cobra.Command, args []string) } } - agent.SetPodLabels(podLabels) + c.podAgent.SetPodLabels(podLabels) } if c.podName != "" { - agent.SetPodName(c.podName) + c.podAgent.SetPodName(c.podName) } else { hostname, err := os.Hostname() if err == nil { - agent.SetPodName(hostname) + c.podAgent.SetPodName(hostname) } } if c.podUID != "" { - agent.SetpodUID(c.podUID) + c.podAgent.SetPodUID(c.podUID) } if c.namespace != "" { - agent.SetNamespace(c.namespace) + c.podAgent.SetNamespace(c.namespace) } registerRules := strings.Split(c.registerRules, ",") @@ -107,10 +111,10 @@ func (c *registerCommand) runRegisterCommand(cmd *cobra.Command, args []string) switch strings.TrimSpace(rule) { case "files": c.logger.Warn("enabled auto register for files") - agent.EnableRegisterFiles() + c.podAgent.EnableRegisterFiles() case "all": c.logger.Info("enabled auto register for all rules") - agent.EnableRegisterFiles() + c.podAgent.EnableRegisterFiles() } } @@ -119,16 +123,16 @@ func (c *registerCommand) runRegisterCommand(cmd *cobra.Command, args []string) for _, path := range registerFilePathsArg { registerFilePaths = append(registerFilePaths, strings.TrimSpace(path)) } - agent.SetRegisterFilePaths(registerFilePaths) + c.podAgent.SetRegisterFilePaths(registerFilePaths) registerFileIgnorePathsArg := strings.Split(c.registerFileIgnorePaths, ",") registerFileIgnorePaths := []string{} for _, path := range registerFileIgnorePathsArg { registerFileIgnorePaths = append(registerFileIgnorePaths, strings.TrimSpace(path)) } - agent.SetRegisterFileIgnorePaths(registerFileIgnorePaths) + c.podAgent.SetRegisterFileIgnorePaths(registerFileIgnorePaths) - agent.SetFileValidationInterval(c.fileValidationInterval) + c.podAgent.SetFileValidationInterval(c.fileValidationInterval) sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM) @@ -137,10 +141,10 @@ func (c *registerCommand) runRegisterCommand(cmd *cobra.Command, args []string) sig := <-sigCh c.logger.WithField("signal", sig).Info("got sigterm signal, attempting graceful shutdown") - agent.GracefulStop() + c.podAgent.GracefulStop() }() - agent.RunRegister() + c.podAgent.RunRegister() c.logger.Info("tarian-pod-agent shutdown gracefully") return nil } diff --git a/cmd/tarian-pod-agent/cmd/register_test.go b/cmd/tarian-pod-agent/cmd/register_test.go new file mode 100644 index 00000000..f5162a11 --- /dev/null +++ b/cmd/tarian-pod-agent/cmd/register_test.go @@ -0,0 +1,123 @@ +package cmd + +import ( + "os" + "testing" + + "github.com/kube-tarian/tarian/cmd/tarian-pod-agent/cmd/flags" + "github.com/kube-tarian/tarian/pkg/log" + "github.com/kube-tarian/tarian/pkg/podagent" + utesting "github.com/kube-tarian/tarian/pkg/testing" + "github.com/spf13/cobra" + "github.com/stretchr/testify/assert" +) + +func TestRegisterCommandRun(t *testing.T) { + logger := log.GetLogger() + file := createTestLabelsFile(t, true) + defer os.Remove(file.Name()) + tests := []struct { + name string + expectedErr string + expectedLog string + + podLabelsFile string + + podAgent podagent.Agent + }{ + { + name: "Run Register mode Successfully", + podAgent: podagent.NewFakePodAgent(logger), + expectedLog: "tarian-pod-agent is running in register mode", + }, + { + name: "Run Register mode with a empty Labels File", + podAgent: podagent.NewFakePodAgent(logger), + expectedErr: "no labels found in file", + podLabelsFile: file.Name(), + }, + { + name: "Run register mode with Invalid Labels File", + expectedErr: "failed to open file", + podLabelsFile: "nonexistent_labels.txt", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cmd := ®isterCommand{ + logger: logger, + podLabelsFile: tt.podLabelsFile, + podAgent: tt.podAgent, + } + + logOutput := []byte{} + cmd.logger.Out = &utesting.LogOutputWriter{Output: &logOutput} + log.MiniLogFormat() + + err := cmd.runRegisterCommand(nil, nil) + + if tt.expectedErr != "" { + assert.Contains(t, err.Error(), tt.expectedErr) + } else { + if !assert.NoError(t, err) { + assert.FailNow(t, "error not expected") + } + } + + if tt.expectedLog != "" { + assert.Contains(t, utesting.CleanLog(string(logOutput)), utesting.CleanLog(tt.expectedLog)) + } + }) + } +} + +func TestNewRegisterModeCommand(t *testing.T) { + globalFlags := &flags.GlobalFlags{} + cmd := newRegisterCommand(globalFlags) + + assert.NotNil(t, cmd) + assert.IsType(t, &cobra.Command{}, cmd) + + assert.Equal(t, "register", cmd.Use) + assert.Equal(t, "Register the pod to the Tarian server", cmd.Short) + + testFlags(t, cmd) +} + +func testFlags(t *testing.T, cmd *cobra.Command) { + assert.Equal(t, defaultClusterAgentHost, cmd.Flags().Lookup("host").DefValue) + err := cmd.Flags().Set("host", "localhost") + assert.NoError(t, err) + assert.Equal(t, "localhost", cmd.Flags().Lookup("host").Value.String()) + + assert.Equal(t, defaultClusterAgentPort, cmd.Flags().Lookup("port").DefValue) + err = cmd.Flags().Set("port", "50053") + assert.NoError(t, err) + assert.Equal(t, "50053", cmd.Flags().Lookup("port").Value.String()) + + assert.Equal(t, "", cmd.Flags().Lookup("pod-labels-file").DefValue) + err = cmd.Flags().Set("pod-labels-file", "test_labels.txt") + assert.NoError(t, err) + assert.Equal(t, "test_labels.txt", cmd.Flags().Lookup("pod-labels-file").Value.String()) + + assert.Equal(t, "", cmd.Flags().Lookup("pod-name").DefValue) + err = cmd.Flags().Set("pod-name", "test_pod") + assert.NoError(t, err) + assert.Equal(t, "test_pod", cmd.Flags().Lookup("pod-name").Value.String()) + + assert.Equal(t, "", cmd.Flags().Lookup("pod-uid").DefValue) + err = cmd.Flags().Set("pod-uid", "test_pod_uid") + assert.NoError(t, err) + assert.Equal(t, "test_pod_uid", cmd.Flags().Lookup("pod-uid").Value.String()) + + assert.Equal(t, "", cmd.Flags().Lookup("namespace").DefValue) + err = cmd.Flags().Set("namespace", "test_namespace") + assert.NoError(t, err) + assert.Equal(t, "test_namespace", cmd.Flags().Lookup("namespace").Value.String()) + + assert.Equal(t, "3s", cmd.Flags().Lookup("file-validation-interval").DefValue) + err = cmd.Flags().Set("file-validation-interval", "5s") + assert.NoError(t, err) + assert.Equal(t, "5s", cmd.Flags().Lookup("file-validation-interval").Value.String()) +} diff --git a/cmd/tarian-pod-agent/cmd/root.go b/cmd/tarian-pod-agent/cmd/root.go index 2e4fca48..1879b62d 100644 --- a/cmd/tarian-pod-agent/cmd/root.go +++ b/cmd/tarian-pod-agent/cmd/root.go @@ -14,7 +14,7 @@ var globalFlags *flags.GlobalFlags func newRootCommand(logger *logrus.Logger) *cobra.Command { var rootCmd = &cobra.Command{ - Use: "Tarian Pod Agent", + Use: "tarian-pod-agent", Short: "The Tarian pod agent is the component which runs as a sidecar to monitor your main container.", Version: version.GetVersion(), SilenceUsage: true, diff --git a/cmd/tarian-pod-agent/cmd/root_test.go b/cmd/tarian-pod-agent/cmd/root_test.go new file mode 100644 index 00000000..28b095ee --- /dev/null +++ b/cmd/tarian-pod-agent/cmd/root_test.go @@ -0,0 +1,36 @@ +package cmd + +import ( + "bytes" + "io" + "testing" + + "github.com/kube-tarian/tarian/pkg/log" + "github.com/stretchr/testify/assert" +) + +func TestPodAgentRootCommand(t *testing.T) { + t.Run("TestRootCommandVersion", func(t *testing.T) { + stdout := new(bytes.Buffer) + + err := runRootCommand(stdout, []string{"version"}) + if assert.NoError(t, err) { + out, _ := io.ReadAll(stdout) + assert.Contains(t, string(out), "tarian pod agent version:") + } + }) + + t.Run("TestRootCommandInvalidSubcommand", func(t *testing.T) { + stdout := new(bytes.Buffer) + err := runRootCommand(stdout, []string{"invalidStderr-subcommand"}) + assert.EqualError(t, err, `unknown command "invalidStderr-subcommand" for "tarian-pod-agent"`) + }) +} + +func runRootCommand(output *bytes.Buffer, args []string) error { + logger := log.GetLogger() + logger.SetOutput(output) + rootCmd := buildRootCommand(logger) + rootCmd.SetArgs(args) + return rootCmd.Execute() +} diff --git a/cmd/tarian-pod-agent/cmd/threat_scan.go b/cmd/tarian-pod-agent/cmd/threat_scan.go index c9fab7f2..5c98a8ed 100644 --- a/cmd/tarian-pod-agent/cmd/threat_scan.go +++ b/cmd/tarian-pod-agent/cmd/threat_scan.go @@ -1,11 +1,9 @@ package cmd import ( - "bufio" "fmt" "os" "os/signal" - "strings" "syscall" "time" @@ -32,6 +30,8 @@ type threatScanCommand struct { podUID string namespace string fileValidationInterval time.Duration + + podAgent podagent.Agent } func newThreatScanCommand(globalFlag *flags.GlobalFlags) *cobra.Command { @@ -60,12 +60,14 @@ func newThreatScanCommand(globalFlag *flags.GlobalFlags) *cobra.Command { func (c *threatScanCommand) run(_ *cobra.Command, args []string) error { c.logger.Info("tarian-pod-agent is running in threat-scan mode") addr := c.host + ":" + c.port - agent := podagent.NewPodAgent(c.logger, addr) - if c.podLabelsFile != "" { - podLabels, err := readLabelsFromFile(c.podLabelsFile) + if c.podAgent == nil { + c.podAgent = podagent.NewPodAgent(c.logger, addr) + } + if c.podLabelsFile != "" { + podLabels, err := readLabelsFromFile(c.logger, c.podLabelsFile) if err != nil { - c.logger.WithError(err).Error("failed reading pod-labels-file") + return fmt.Errorf("failed reading pod-labels-file: %w", err) } // delete pod-template-hash @@ -80,27 +82,27 @@ func (c *threatScanCommand) run(_ *cobra.Command, args []string) error { } } - agent.SetPodLabels(podLabels) + c.podAgent.SetPodLabels(podLabels) } if c.podName != "" { - agent.SetPodName(c.podName) + c.podAgent.SetPodName(c.podName) } else { hostname, err := os.Hostname() if err == nil { - agent.SetPodName(hostname) + c.podAgent.SetPodName(hostname) } } if c.podUID != "" { - agent.SetpodUID(c.podUID) + c.podAgent.SetPodUID(c.podUID) } if c.namespace != "" { - agent.SetNamespace(c.namespace) + c.podAgent.SetNamespace(c.namespace) } - agent.SetFileValidationInterval(c.fileValidationInterval) + c.podAgent.SetFileValidationInterval(c.fileValidationInterval) sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM) @@ -108,39 +110,10 @@ func (c *threatScanCommand) run(_ *cobra.Command, args []string) error { go func() { sig := <-sigCh c.logger.WithField("signal", sig).Info("got sigterm signal, attempting graceful shutdown") - agent.GracefulStop() + c.podAgent.GracefulStop() }() - agent.RunThreatScan() + c.podAgent.RunThreatScan() c.logger.Info("tarian-pod-agent shutdown gracefully") return nil } - -func readLabelsFromFile(path string) ([]*tarianpb.Label, error) { - labels := []*tarianpb.Label{} - - file, err := os.Open(path) - if err != nil { - return nil, fmt.Errorf("failed to open file: %w", err) - } - defer file.Close() - - scanner := bufio.NewScanner(file) - scanner.Split(bufio.ScanLines) - - for scanner.Scan() { - line := scanner.Text() - idx := strings.Index(line, "=") - - if idx < 0 { - continue - } - - key := line[:idx] - value := strings.Trim(line[idx+1:], "\"") - - labels = append(labels, &tarianpb.Label{Key: key, Value: value}) - } - - return labels, nil -} diff --git a/cmd/tarian-pod-agent/cmd/threat_scan_test.go b/cmd/tarian-pod-agent/cmd/threat_scan_test.go new file mode 100644 index 00000000..cea9f8f1 --- /dev/null +++ b/cmd/tarian-pod-agent/cmd/threat_scan_test.go @@ -0,0 +1,88 @@ +package cmd + +import ( + "os" + "testing" + "time" + + "github.com/kube-tarian/tarian/cmd/tarian-pod-agent/cmd/flags" + "github.com/kube-tarian/tarian/pkg/log" + "github.com/kube-tarian/tarian/pkg/podagent" + utesting "github.com/kube-tarian/tarian/pkg/testing" + "github.com/spf13/cobra" + "github.com/stretchr/testify/assert" +) + +func TestThreatScanRunCommand(t *testing.T) { + logger := log.GetLogger() + file := createTestLabelsFile(t, true) + defer os.Remove(file.Name()) + tests := []struct { + name string + expectedErr string + expectedLog string + + podLabelsFile string + fileValidationInterval time.Duration + + podAgent podagent.Agent + }{ + { + name: "Run Threat Scan Successfully", + podAgent: podagent.NewFakePodAgent(logger), + expectedLog: "tarian-pod-agent is running in threat-scan mode SetPodName SetFileValidationInterval RunThreatScan tarian-pod-agent shutdown gracefully", + }, + { + name: "Run Threat Scan with a empty Labels File", + podAgent: podagent.NewFakePodAgent(logger), + expectedErr: "no labels found in file", + podLabelsFile: file.Name(), + }, + { + name: "Run Threat Scan with Invalid Labels File", + expectedErr: "failed to open file", + podLabelsFile: "nonexistent_labels.txt", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cmd := &threatScanCommand{ + logger: logger, + podLabelsFile: tt.podLabelsFile, + podAgent: tt.podAgent, + fileValidationInterval: tt.fileValidationInterval, + } + + logOutput := []byte{} + cmd.logger.Out = &utesting.LogOutputWriter{Output: &logOutput} + log.MiniLogFormat() + + err := cmd.run(nil, nil) + + if tt.expectedErr != "" { + assert.Contains(t, err.Error(), tt.expectedErr) + } else { + if !assert.NoError(t, err) { + assert.FailNow(t, "error not expected") + } + } + + if tt.expectedLog != "" { + assert.Contains(t, utesting.CleanLog(string(logOutput)), utesting.CleanLog(tt.expectedLog)) + } + }) + } +} + +func TestNewThreatScanCommand(t *testing.T) { + globalFlags := &flags.GlobalFlags{} + cmd := newThreatScanCommand(globalFlags) + + assert.NotNil(t, cmd) + assert.IsType(t, &cobra.Command{}, cmd) + + assert.Equal(t, "threat-scan", cmd.Use) + assert.Equal(t, "Scan the container image for vulnerabilities", cmd.Short) + testFlags(t, cmd) +} diff --git a/cmd/tarian-pod-agent/cmd/util.go b/cmd/tarian-pod-agent/cmd/util.go new file mode 100644 index 00000000..ece15553 --- /dev/null +++ b/cmd/tarian-pod-agent/cmd/util.go @@ -0,0 +1,44 @@ +package cmd + +import ( + "bufio" + "fmt" + "os" + "strings" + + "github.com/kube-tarian/tarian/pkg/tarianpb" + "github.com/sirupsen/logrus" +) + +func readLabelsFromFile(logger *logrus.Logger, path string) ([]*tarianpb.Label, error) { + labels := []*tarianpb.Label{} + + file, err := os.Open(path) + if err != nil { + return nil, fmt.Errorf("failed to open file: %w", err) + } + defer file.Close() + + scanner := bufio.NewScanner(file) + scanner.Split(bufio.ScanLines) + + for scanner.Scan() { + line := scanner.Text() + idx := strings.Index(line, "=") + + if idx < 0 { + continue + } + + key := line[:idx] + value := strings.Trim(line[idx+1:], "\"") + logger.Debugf("Read label from file: %s=%s", key, value) + + labels = append(labels, &tarianpb.Label{Key: key, Value: value}) + } + + if len(labels) == 0 { + return nil, fmt.Errorf("no labels found in file") + } + return labels, nil +} diff --git a/cmd/tarian-pod-agent/cmd/util_test.go b/cmd/tarian-pod-agent/cmd/util_test.go new file mode 100644 index 00000000..e5797b41 --- /dev/null +++ b/cmd/tarian-pod-agent/cmd/util_test.go @@ -0,0 +1,66 @@ +package cmd + +import ( + "os" + "testing" + + "github.com/kube-tarian/tarian/pkg/log" + "github.com/kube-tarian/tarian/pkg/tarianpb" + "github.com/stretchr/testify/assert" +) + +func TestReadLabelsFromFile(t *testing.T) { + file := createTestLabelsFile(t, false) + defer os.Remove(file.Name()) + tests := []struct { + name string + fileName string + expectedErr string + expectedLabels []*tarianpb.Label + }{ + { + name: "Valid Labels File", + fileName: file.Name(), + expectedLabels: []*tarianpb.Label{ + {Key: "key1", Value: "value1"}, + {Key: "key2", Value: "value2"}, + {Key: "key3", Value: "value3"}, + }, + }, + { + name: "Invalid Labels File", + fileName: "nonexistent_labels.txt", + expectedErr: "failed to open file", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + labels, err := readLabelsFromFile(log.GetLogger(), tt.fileName) + + if tt.expectedErr != "" { + assert.Contains(t, err.Error(), tt.expectedErr) + } else { + assert.NoError(t, err) + assert.Len(t, labels, len(tt.expectedLabels)) + + for i, expectedLabel := range tt.expectedLabels { + assert.Equal(t, expectedLabel.Key, labels[i].Key) + assert.Equal(t, expectedLabel.Value, labels[i].Value) + } + } + }) + } +} + +func createTestLabelsFile(t *testing.T, empty bool) *os.File { + file, _ := os.CreateTemp("", "test_labels_*.txt") + if !empty { + content := []byte("key1=\"value1\"\nkey2=\"value2\"\nkey3=\"value3\"\n") + _, err := file.Write(content) + assert.NoError(t, err) + err = file.Close() + assert.NoError(t, err) + } + return file +} diff --git a/cmd/tarian-pod-agent/cmd/version.go b/cmd/tarian-pod-agent/cmd/version.go index 96cf58fe..fe0d935e 100644 --- a/cmd/tarian-pod-agent/cmd/version.go +++ b/cmd/tarian-pod-agent/cmd/version.go @@ -1,9 +1,8 @@ package cmd import ( - "fmt" - version "github.com/kube-tarian/tarian/cmd" + "github.com/kube-tarian/tarian/pkg/log" "github.com/spf13/cobra" ) @@ -12,6 +11,7 @@ var versionCmd = &cobra.Command{ Args: cobra.NoArgs, Short: "Prints version of tarian-pod-agent", Run: func(cmd *cobra.Command, args []string) { - fmt.Printf("tarian pod agent version: %s\n", version.GetVersion()) + logger := log.GetLogger() + logger.Infof("tarian pod agent version: %s\n", version.GetVersion()) }, } diff --git a/cmd/tarianctl/cmd/flags/flags_test.go b/cmd/tarianctl/cmd/flags/flags_test.go index 844ea508..04a58631 100644 --- a/cmd/tarianctl/cmd/flags/flags_test.go +++ b/cmd/tarianctl/cmd/flags/flags_test.go @@ -4,6 +4,7 @@ import ( "os" "testing" + "github.com/kube-tarian/tarian/pkg/log" "github.com/spf13/pflag" "github.com/stretchr/testify/assert" ) @@ -97,7 +98,7 @@ func TestGetFlagValuesFromEnvVar(t *testing.T) { // Create global flags and load values from environment variables globalFlags := &GlobalFlags{} - globalFlags.GetFlagValuesFromEnvVar() + globalFlags.GetFlagValuesFromEnvVar(log.GetLogger()) // Check if the value was correctly loaded from the environment variable assert.Equal(t, tarianServerEnvVarValue, globalFlags.ServerAddr) diff --git a/pkg/podagent/fake_podagent.go b/pkg/podagent/fake_podagent.go new file mode 100644 index 00000000..145909af --- /dev/null +++ b/pkg/podagent/fake_podagent.go @@ -0,0 +1,121 @@ +package podagent + +import ( + "time" + + "github.com/kube-tarian/tarian/pkg/tarianpb" + "github.com/sirupsen/logrus" +) + +type fakePodAgent struct { + logger *logrus.Logger +} + +// NewFakePodAgent returns a fake pod agent. +func NewFakePodAgent(logger *logrus.Logger) Agent { + return &fakePodAgent{ + logger: logger, + } +} + +// Dial implements Agent. +func (f *fakePodAgent) Dial() { + f.logger.Info("Dial") +} + +// EnableRegisterFiles implements Agent. +func (f *fakePodAgent) EnableRegisterFiles() { + f.logger.Info("EnableRegisterFiles") +} + +// GetConstraints implements Agent. +func (f *fakePodAgent) GetConstraints() []*tarianpb.Constraint { + var regex = "regex-1" + var hash = "hash-1" + values := []*tarianpb.Constraint{ + { + + Kind: "FakeKind", + Namespace: "test-ns1", + Name: "constraint-1", + Selector: &tarianpb.Selector{ + MatchLabels: []*tarianpb.MatchLabel{ + {Key: "key1", Value: "value1"}, + }, + }, + AllowedProcesses: []*tarianpb.AllowedProcessRule{ + {Regex: ®ex}, + }, + AllowedFiles: []*tarianpb.AllowedFileRule{ + {Name: "file-1", Sha256Sum: &hash}, + }, + }, + } + f.logger.Info(values) + return values +} + +// GracefulStop implements Agent. +func (f *fakePodAgent) GracefulStop() { + f.logger.Info("GracefulStop") +} + +// ReportViolatedFilesToClusterAgent implements Agent. +func (f *fakePodAgent) ReportViolatedFilesToClusterAgent(violatedFiles map[string]*violatedFile) { + f.logger.Info("ReportViolatedFilesToClusterAgent") +} + +// RunRegister implements Agent. +func (f *fakePodAgent) RunRegister() { + f.logger.Info("RunRegister") +} + +// RunThreatScan implements Agent. +func (f *fakePodAgent) RunThreatScan() { + f.logger.Info("RunThreatScan") +} + +// SetConstraints implements Agent. +func (f *fakePodAgent) SetConstraints(constraints []*tarianpb.Constraint) { + f.logger.Info("SetConstraints") +} + +// SetFileValidationInterval implements Agent. +func (f *fakePodAgent) SetFileValidationInterval(t time.Duration) { + f.logger.Info("SetFileValidationInterval") +} + +// SetNamespace implements Agent. +func (f *fakePodAgent) SetNamespace(namespace string) { + f.logger.Info("SetNamespace") +} + +// SetPodLabels implements Agent. +func (f *fakePodAgent) SetPodLabels(labels []*tarianpb.Label) { + f.logger.Info("SetPodLabels") +} + +// SetPodName implements Agent. +func (f *fakePodAgent) SetPodName(name string) { + f.logger.Info("SetPodName") +} + +// SetPodUID implements Agent. +func (f *fakePodAgent) SetPodUID(uid string) { + f.logger.Info("SetPodUID") +} + +// SetRegisterFileIgnorePaths implements Agent. +func (f *fakePodAgent) SetRegisterFileIgnorePaths(paths []string) { + f.logger.Info("SetRegisterFileIgnorePaths") +} + +// SetRegisterFilePaths implements Agent. +func (f *fakePodAgent) SetRegisterFilePaths(paths []string) { + f.logger.Info("SetRegisterFilePaths") +} + +// SyncConstraints implements Agent. +func (f *fakePodAgent) SyncConstraints() { + f.logger.Info("SyncConstraints") +} diff --git a/pkg/podagent/interface.go b/pkg/podagent/interface.go new file mode 100644 index 00000000..b7f33d76 --- /dev/null +++ b/pkg/podagent/interface.go @@ -0,0 +1,43 @@ +package podagent + +import ( + "time" + + "github.com/kube-tarian/tarian/pkg/tarianpb" +) + +// Agent is the interface that wraps the basic methods for a pod agent. +type Agent interface { + // SetPodLabels sets the pod labels for the agent. + SetPodLabels(labels []*tarianpb.Label) + // SetPodName sets the pod name for the agent. + SetPodName(name string) + // SetPodUID sets the pod UID for the agent. + SetPodUID(uid string) + // SetNamespace sets the namespace for the agent. + SetNamespace(namespace string) + // SetFileValidationInterval sets the interval for file validation. + SetFileValidationInterval(t time.Duration) + // EnableRegisterFiles enables the agent to register files. + EnableRegisterFiles() + // SetRegisterFilePaths sets the paths to register. + SetRegisterFilePaths(paths []string) + // SetRegisterFileIgnorePaths sets the paths to ignore while registering. + SetRegisterFileIgnorePaths(paths []string) + // Dial establishes a connection to the cluster agent. + Dial() + // GracefulStop stops the agent gracefully. + GracefulStop() + // RunThreatScan starts the threat scan loop. + RunThreatScan() + // RunRegister starts the registration loop. + RunRegister() + // SetConstraints sets the constraints for the agent. + SetConstraints(constraints []*tarianpb.Constraint) + // GetConstraints returns the constraints for the agent. + GetConstraints() []*tarianpb.Constraint + // SyncConstraints retrieves and synchronizes constraints from the cluster agent. + SyncConstraints() + // ReportViolatedFilesToClusterAgent reports violated files to the cluster agent. + ReportViolatedFilesToClusterAgent(violatedFiles map[string]*violatedFile) +} diff --git a/pkg/podagent/podagent.go b/pkg/podagent/podagent.go index 52e5307c..39127b88 100644 --- a/pkg/podagent/podagent.go +++ b/pkg/podagent/podagent.go @@ -54,7 +54,7 @@ type PodAgent struct { // // Returns: // - *PodAgent: A new instance of the PodAgent. -func NewPodAgent(logger *logrus.Logger, clusterAgentAddress string) *PodAgent { +func NewPodAgent(logger *logrus.Logger, clusterAgentAddress string) Agent { ctx, cancel := context.WithCancel(context.Background()) return &PodAgent{ @@ -72,6 +72,7 @@ func NewPodAgent(logger *logrus.Logger, clusterAgentAddress string) *PodAgent { // - labels: The labels to set for the pod. func (p *PodAgent) SetPodLabels(labels []*tarianpb.Label) { p.podLabels = labels + p.logger.Debug("pod label(s) set to: ", p.podLabels) } // SetPodName sets the name of the pod. @@ -80,14 +81,16 @@ func (p *PodAgent) SetPodLabels(labels []*tarianpb.Label) { // - name: The name of the pod. func (p *PodAgent) SetPodName(name string) { p.podName = name + p.logger.Debug("pod name set to: ", p.podName) } -// SetpodUID sets the UID of the pod. +// SetPodUID sets the UID of the pod. // // Parameters: // - uid: The UID of the pod. -func (p *PodAgent) SetpodUID(uid string) { +func (p *PodAgent) SetPodUID(uid string) { p.podUID = uid + p.logger.Debug("pod UID set to: ", p.podUID) } // SetNamespace sets the namespace of the pod. @@ -96,6 +99,7 @@ func (p *PodAgent) SetpodUID(uid string) { // - namespace: The namespace of the pod. func (p *PodAgent) SetNamespace(namespace string) { p.namespace = namespace + p.logger.Debug("pod namespace set to: ", p.namespace) } // SetFileValidationInterval sets the interval for file validation. @@ -104,11 +108,13 @@ func (p *PodAgent) SetNamespace(namespace string) { // - t: The duration for file validation interval. func (p *PodAgent) SetFileValidationInterval(t time.Duration) { p.fileValidationInterval = t + p.logger.Debug("file validation interval set to: ", p.fileValidationInterval) } // EnableRegisterFiles enables file registration. func (p *PodAgent) EnableRegisterFiles() { p.enableRegisterFiles = true + p.logger.Debug("file registration enabled") } // SetRegisterFilePaths sets the file paths to register. @@ -117,6 +123,7 @@ func (p *PodAgent) EnableRegisterFiles() { // - paths: The file paths to register. func (p *PodAgent) SetRegisterFilePaths(paths []string) { p.registerFilePaths = paths + p.logger.Debug("file paths to register set to: ", p.registerFilePaths) } // SetRegisterFileIgnorePaths sets the file paths to ignore during registration. @@ -125,22 +132,24 @@ func (p *PodAgent) SetRegisterFilePaths(paths []string) { // - paths: The file paths to ignore during registration. func (p *PodAgent) SetRegisterFileIgnorePaths(paths []string) { p.registerFileIgnorePaths = paths + p.logger.Debug("file paths to ignore during registration set to: ", p.registerFileIgnorePaths) } // Dial establishes a connection to the cluster agent. func (p *PodAgent) Dial() { + p.logger.Debug("establishing a connection to the cluster agent.....") var err error p.grpcConn, err = grpc.Dial(p.clusterAgentAddress, grpc.WithTransportCredentials(insecure.NewCredentials())) - p.configClient = tarianpb.NewConfigClient(p.grpcConn) - p.eventClient = tarianpb.NewEventClient(p.grpcConn) - if err != nil { p.logger.WithError(err).Fatal("couldn't connect to the cluster agent") } + p.configClient = tarianpb.NewConfigClient(p.grpcConn) + p.eventClient = tarianpb.NewEventClient(p.grpcConn) } // GracefulStop stops the PodAgent gracefully. func (p *PodAgent) GracefulStop() { + p.logger.Debug("gracefully stopping the pod agent") p.cancelFunc() if p.grpcConn != nil { @@ -150,6 +159,7 @@ func (p *PodAgent) GracefulStop() { // RunThreatScan starts the threat scan loop. func (p *PodAgent) RunThreatScan() { + p.logger.Info("starting threat scan....") p.Dial() defer p.grpcConn.Close() @@ -171,6 +181,7 @@ func (p *PodAgent) RunThreatScan() { // RunRegister starts the registration loop. func (p *PodAgent) RunRegister() { + p.logger.Info("starting file registration....") p.Dial() defer p.grpcConn.Close() @@ -202,6 +213,7 @@ func (p *PodAgent) SetConstraints(constraints []*tarianpb.Constraint) { defer p.constraintsLock.Unlock() p.constraints = constraints + p.logger.Debugf("constraints %v set", p.constraints) } // GetConstraints retrieves the constraints for the pod. @@ -226,6 +238,7 @@ func (p *PodAgent) loopSyncConstraints(ctx context.Context) error { // SyncConstraints retrieves and synchronizes constraints from the cluster agent. func (p *PodAgent) SyncConstraints() { + p.logger.Debug("syncing constraints from the cluster agent") ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) r, err := p.configClient.GetConstraints(ctx, &tarianpb.GetConstraintsRequest{Namespace: p.namespace, Labels: p.podLabels}) diff --git a/test/e2e/e2e_helper.go b/test/e2e/e2e_helper.go index 4b98c35b..8a6c3b7f 100644 --- a/test/e2e/e2e_helper.go +++ b/test/e2e/e2e_helper.go @@ -32,7 +32,7 @@ const ( type TestHelper struct { server *grpc.Server // The gRPC server used for testing. clusterAgent clusteragent.Agent // The ClusterAgent for cluster management. - podAgent *podagent.PodAgent // The PodAgent for managing pods. + podAgent podagent.Agent // The PodAgent for managing pods. t *testing.T // The testing.T instance for reporting test failures. dgraphConfig dgraphstore.DgraphConfig // Configuration for Dgraph database. dg dgraphstore.Client // The Dgraph client.