diff --git a/cmd/minikube/cmd/config/config.go b/cmd/minikube/cmd/config/config.go index 4af7698da3ab..9fd3685354ce 100644 --- a/cmd/minikube/cmd/config/config.go +++ b/cmd/minikube/cmd/config/config.go @@ -168,6 +168,10 @@ var settings = []Setting{ name: config.Rootless, set: SetBool, }, + { + name: config.MaxAuditEntries, + set: SetInt, + }, } // ConfigCmd represents the config command diff --git a/cmd/minikube/cmd/root.go b/cmd/minikube/cmd/root.go index dea3f0ee5704..e614866728e8 100644 --- a/cmd/minikube/cmd/root.go +++ b/cmd/minikube/cmd/root.go @@ -325,6 +325,7 @@ func setupViper() { viper.SetDefault(config.ReminderWaitPeriodInHours, 24) viper.SetDefault(config.WantNoneDriverWarning, true) viper.SetDefault(config.WantVirtualBoxDriverWarning, true) + viper.SetDefault(config.MaxAuditEntries, 1000) } func addToPath(dir string) { diff --git a/pkg/minikube/audit/audit.go b/pkg/minikube/audit/audit.go index 2f945f7ceeab..8292bb2274d6 100644 --- a/pkg/minikube/audit/audit.go +++ b/pkg/minikube/audit/audit.go @@ -98,6 +98,9 @@ func LogCommandEnd(id string) error { return err } var entriesNeedsToUpdate int + + startIndex := getStartIndex(len(rowSlice)) + rowSlice = rowSlice[startIndex:] for _, v := range rowSlice { if v.id == id { v.endTime = time.Now().Format(constants.TimeFormat) @@ -118,6 +121,15 @@ func LogCommandEnd(id string) error { return nil } +func getStartIndex(entryCount int) int { + maxEntries := viper.GetInt(config.MaxAuditEntries) + startIndex := entryCount - maxEntries + if maxEntries <= 0 || startIndex <= 0 { + return 0 + } + return startIndex +} + // shouldLog returns if the command should be logged. func shouldLog() bool { // in rare chance we get here without a command, don't log diff --git a/pkg/minikube/audit/audit_test.go b/pkg/minikube/audit/audit_test.go index 262ceac82135..3397850bf0e7 100644 --- a/pkg/minikube/audit/audit_test.go +++ b/pkg/minikube/audit/audit_test.go @@ -17,8 +17,11 @@ limitations under the License. package audit import ( + "io" "os" + "os/exec" "os/user" + "strings" "testing" "github.com/spf13/pflag" @@ -27,6 +30,33 @@ import ( ) func TestAudit(t *testing.T) { + var auditFilename string + + t.Run("setup", func(t *testing.T) { + f, err := os.CreateTemp("", "audit.json") + if err != nil { + t.Fatalf("failed creating temporary file: %v", err) + } + auditFilename = f.Name() + + s := `{"data":{"args":"-p mini1","command":"start","endTime":"Wed, 03 Feb 2021 15:33:05 MST","profile":"mini1","startTime":"Wed, 03 Feb 2021 15:30:33 MST","user":"user1"},"datacontenttype":"application/json","id":"9b7593cb-fbec-49e5-a3ce-bdc2d0bfb208","source":"https://minikube.sigs.k8s.io/","specversion":"1.0","type":"io.k8s.si gs.minikube.audit"} +{"data":{"args":"-p mini1","command":"start","endTime":"Wed, 03 Feb 2021 15:33:05 MST","profile":"mini1","startTime":"Wed, 03 Feb 2021 15:30:33 MST","user":"user1"},"datacontenttype":"application/json","id":"9b7593cb-fbec-49e5-a3ce-bdc2d0bfb208","source":"https://minikube.sigs.k8s.io/","specversion":"1.0","type":"io.k8s.si gs.minikube.audit"} +{"data":{"args":"--user user2","command":"logs","endTime":"Tue, 02 Feb 2021 16:46:20 MST","profile":"minikube","startTime":"Tue, 02 Feb 2021 16:46:00 MST","user":"user2"},"datacontenttype":"application/json","id":"fec03227-2484-48b6-880a-88fd010b5efd","source":"https://minikube.sigs.k8s.io/","specversion":"1.0","type":"io.k8s.sigs.minikube.audit"} +{"data":{"args":"-p mini1","command":"start","endTime":"Wed, 03 Feb 2021 15:33:05 MST","profile":"mini1","startTime":"Wed, 03 Feb 2021 15:30:33 MST","user":"user1"},"datacontenttype":"application/json","id":"9b7593cb-fbec-49e5-a3ce-bdc2d0bfb208","source":"https://minikube.sigs.k8s.io/","specversion":"1.0","type":"io.k8s.si gs.minikube.audit"} +{"data":{"args":"--user user2","command":"logs","endTime":"Tue, 02 Feb 2021 16:46:20 MST","profile":"minikube","startTime":"Tue, 02 Feb 2021 16:46:00 MST","user":"user2"},"datacontenttype":"application/json","id":"fec03227-2484-48b6-880a-88fd010b5efd","source":"https://minikube.sigs.k8s.io/","specversion":"1.0","type":"io.k8s.sigs.minikube.audit"} +` + + if _, err := f.WriteString(s); err != nil { + t.Fatalf("failed writing to file: %v", err) + } + if _, err := f.Seek(0, io.SeekStart); err != nil { + t.Fatalf("failed seeking to start of file: %v", err) + } + + currentLogFile = f + viper.Set(config.MaxAuditEntries, 3) + }) + t.Run("username", func(t *testing.T) { u, err := user.Current() if err != nil { @@ -168,7 +198,6 @@ func TestAudit(t *testing.T) { mockArgs(t, test.args) got := isDeletePurge() - if got != test.want { t.Errorf("test.args = %q; isDeletePurge() = %t; want %t", test.args, got, test.want) } @@ -211,11 +240,18 @@ func TestAudit(t *testing.T) { if err != nil { t.Fatal("start failed") } - err = LogCommandEnd(auditID) + if err := LogCommandEnd(auditID); err != nil { + t.Fatal(err) + } + b, err := exec.Command("wc", "-l", auditFilename).Output() if err != nil { t.Fatal(err) } + if !strings.Contains(string(b), "3") { + t.Errorf("MaxAuditEntries did not work, expected 3 lines in the audit log found %s", string(b)) + } + }) t.Run("LogCommandEndNonExistingID", func(t *testing.T) { diff --git a/pkg/minikube/config/config.go b/pkg/minikube/config/config.go index d93352604c33..1f93ce6deff9 100644 --- a/pkg/minikube/config/config.go +++ b/pkg/minikube/config/config.go @@ -54,6 +54,8 @@ const ( AddonListFlag = "addons" // EmbedCerts represents the config for embedding certificates in kubeconfig EmbedCerts = "EmbedCerts" + // MaxAuditEntries is the maximum number of audit entries to retain + MaxAuditEntries = "MaxAuditEntries" ) var (