Skip to content

Commit 0131f73

Browse files
bennyyang11NoaheCampbelldependabot[bot]
committed
Cron job clean (#1862)
* created roadmap and yaml claude agent * Update roadmap.md * chore(deps): bump sigstore/cosign-installer from 3.9.2 to 3.10.0 (#1857) Bumps [sigstore/cosign-installer](https://github.com/sigstore/cosign-installer) from 3.9.2 to 3.10.0. - [Release notes](https://github.com/sigstore/cosign-installer/releases) - [Commits](sigstore/cosign-installer@v3.9.2...v3.10.0) --- updated-dependencies: - dependency-name: sigstore/cosign-installer dependency-version: 3.10.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump the security group with 2 updates (#1858) Bumps the security group with 2 updates: [github.com/vmware-tanzu/velero](https://github.com/vmware-tanzu/velero) and [helm.sh/helm/v3](https://github.com/helm/helm). Updates `github.com/vmware-tanzu/velero` from 1.16.2 to 1.17.0 - [Release notes](https://github.com/vmware-tanzu/velero/releases) - [Changelog](https://github.com/vmware-tanzu/velero/blob/main/CHANGELOG.md) - [Commits](velero-io/velero@v1.16.2...v1.17.0) Updates `helm.sh/helm/v3` from 3.18.6 to 3.19.0 - [Release notes](https://github.com/helm/helm/releases) - [Commits](helm/helm@v3.18.6...v3.19.0) --- updated-dependencies: - dependency-name: github.com/vmware-tanzu/velero dependency-version: 1.17.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: security - dependency-name: helm.sh/helm/v3 dependency-version: 3.19.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: security ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump helm.sh/helm/v3 from 3.18.6 to 3.19.0 in /examples/sdk/helm-template in the security group (#1859) chore(deps): bump helm.sh/helm/v3 Bumps the security group in /examples/sdk/helm-template with 1 update: [helm.sh/helm/v3](https://github.com/helm/helm). Updates `helm.sh/helm/v3` from 3.18.6 to 3.19.0 - [Release notes](https://github.com/helm/helm/releases) - [Commits](helm/helm@v3.18.6...v3.19.0) --- updated-dependencies: - dependency-name: helm.sh/helm/v3 dependency-version: 3.19.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: security ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Add cron job support bundle scheduler Complete implementation with K8s integration: - pkg/schedule/job.go: Job management and persistence - pkg/schedule/daemon.go: Real-time scheduler daemon - pkg/schedule/cli.go: CLI commands (create, list, delete, daemon) - pkg/schedule/schedule_test.go: Comprehensive unit tests - cmd/troubleshoot/cli/root.go: CLI integration * fixing bugbot * Fix all bugbot errors: auto-update stability, job cooldown timing, and daemon execution * Deleting Agent * removed unused flags * fixing auto-upload * fixing markdown files * namespace not required flag for auto collectors to work * loosened cron job validation * writes logs to logfile * fix: resolve autoFromEnv variable scoping issue for CI - Ensure autoFromEnv variable and its usage are in correct scope - Fix build errors: declared and not used / undefined variable - All functionality preserved and tested locally - Force add to override gitignore --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Noah Campbell <noah.edward.campbell@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1 parent eaaace5 commit 0131f73

10 files changed

Lines changed: 3310 additions & 14 deletions

File tree

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,10 @@ sbom/
4848
# Ignore generated support bundles
4949
*.tar.gz
5050
!testdata/supportbundle/*.tar.gz
51+
52+
# Ignore built binaries
53+
troubleshoot
54+
troubleshoot-test
55+
cmd/troubleshoot/troubleshoot
56+
cmd/*/troubleshoot
57+
support-bundle

Cron-Job-Support-Bundles-PRD.md

Lines changed: 1695 additions & 0 deletions
Large diffs are not rendered by default.

cmd/troubleshoot/cli/root.go

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,21 +43,25 @@ If no arguments are provided, specs are automatically loaded from the cluster by
4343
}
4444

4545
// Auto-update support-bundle unless disabled by flag or env
46-
envAuto := os.Getenv("TROUBLESHOOT_AUTO_UPDATE")
47-
autoFromEnv := true
48-
if envAuto != "" {
49-
if strings.EqualFold(envAuto, "0") || strings.EqualFold(envAuto, "false") {
50-
autoFromEnv = false
46+
// Only run auto-update for the root support-bundle command, not subcommands
47+
if cmd.Name() == "support-bundle" && !cmd.HasParent() {
48+
envAuto := os.Getenv("TROUBLESHOOT_AUTO_UPDATE")
49+
autoFromEnv := true
50+
if envAuto != "" {
51+
if strings.EqualFold(envAuto, "0") || strings.EqualFold(envAuto, "false") {
52+
autoFromEnv = false
53+
}
5154
}
52-
}
53-
if v.GetBool("auto-update") && autoFromEnv {
54-
exe, err := os.Executable()
55-
if err == nil {
56-
_ = updater.CheckAndUpdate(cmd.Context(), updater.Options{
57-
BinaryName: "support-bundle",
58-
CurrentPath: exe,
59-
Printf: func(f string, a ...interface{}) { fmt.Fprintf(os.Stderr, f, a...) },
60-
})
55+
56+
if v.GetBool("auto-update") && autoFromEnv {
57+
exe, err := os.Executable()
58+
if err == nil {
59+
_ = updater.CheckAndUpdate(cmd.Context(), updater.Options{
60+
BinaryName: "support-bundle",
61+
CurrentPath: exe,
62+
Printf: func(f string, a ...interface{}) { fmt.Fprintf(os.Stderr, f, a...) },
63+
})
64+
}
6165
}
6266
}
6367
},
@@ -103,11 +107,13 @@ If no arguments are provided, specs are automatically loaded from the cluster by
103107
cmd.AddCommand(Analyze())
104108
cmd.AddCommand(Redact())
105109
cmd.AddCommand(Diff())
110+
cmd.AddCommand(Schedule())
106111
cmd.AddCommand(UploadCmd())
107112
cmd.AddCommand(util.VersionCmd())
108113

109114
cmd.Flags().StringSlice("redactors", []string{}, "names of the additional redactors to use")
110115
cmd.Flags().Bool("redact", true, "enable/disable default redactions")
116+
111117
cmd.Flags().Bool("interactive", true, "enable/disable interactive mode")
112118
cmd.Flags().Bool("collect-without-permissions", true, "always generate a support bundle, even if it some require additional permissions")
113119
cmd.Flags().StringSliceP("selector", "l", []string{"troubleshoot.sh/kind=support-bundle"}, "selector to filter on for loading additional support bundle specs found in secrets within the cluster")

cmd/troubleshoot/cli/schedule.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package cli
2+
3+
import (
4+
"github.com/replicatedhq/troubleshoot/pkg/schedule"
5+
"github.com/spf13/cobra"
6+
)
7+
8+
// Schedule returns the schedule command for managing scheduled support bundle jobs
9+
func Schedule() *cobra.Command {
10+
return schedule.CLI()
11+
}

pkg/schedule/cli.go

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
package schedule
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"text/tabwriter"
7+
8+
"github.com/spf13/cobra"
9+
)
10+
11+
// CLI creates the schedule command
12+
func CLI() *cobra.Command {
13+
cmd := &cobra.Command{
14+
Use: "schedule",
15+
Short: "Manage scheduled support bundle jobs",
16+
Long: `Create and manage scheduled support bundle collection jobs.
17+
18+
This allows customers to schedule support bundle collection to run automatically
19+
at specified times using standard cron syntax.`,
20+
}
21+
22+
cmd.AddCommand(
23+
createCommand(),
24+
listCommand(),
25+
deleteCommand(),
26+
daemonCommand(),
27+
)
28+
29+
return cmd
30+
}
31+
32+
// createCommand creates the create subcommand
33+
func createCommand() *cobra.Command {
34+
cmd := &cobra.Command{
35+
Use: "create [job-name] --cron [schedule] [--namespace ns]",
36+
Short: "Create a scheduled support bundle job",
37+
Long: `Create a new scheduled job to automatically collect support bundles.
38+
39+
Examples:
40+
# Daily at 2 AM
41+
support-bundle schedule create daily-check --cron "0 2 * * *" --namespace production
42+
43+
# Every 6 hours with auto-discovery and auto-upload to vendor portal
44+
support-bundle schedule create frequent --cron "0 */6 * * *" --namespace app --auto --upload enabled`,
45+
Args: cobra.ExactArgs(1),
46+
RunE: func(cmd *cobra.Command, args []string) error {
47+
cronSchedule, _ := cmd.Flags().GetString("cron")
48+
namespace, _ := cmd.Flags().GetString("namespace")
49+
auto, _ := cmd.Flags().GetBool("auto")
50+
upload, _ := cmd.Flags().GetString("upload")
51+
52+
if cronSchedule == "" {
53+
return fmt.Errorf("--cron is required")
54+
}
55+
56+
manager, err := NewManager()
57+
if err != nil {
58+
return err
59+
}
60+
job, err := manager.CreateJob(args[0], cronSchedule, namespace, auto, upload)
61+
if err != nil {
62+
return err
63+
}
64+
65+
fmt.Printf("✓ Created scheduled job '%s' (ID: %s)\n", job.Name, job.ID)
66+
fmt.Printf(" Schedule: %s\n", job.Schedule)
67+
fmt.Printf(" Namespace: %s\n", job.Namespace)
68+
if auto {
69+
fmt.Printf(" Auto-discovery: enabled\n")
70+
}
71+
if upload != "" {
72+
fmt.Printf(" Auto-upload: enabled (uploads to vendor portal)\n")
73+
}
74+
75+
fmt.Printf("\n💡 To activate, start the daemon:\n")
76+
fmt.Printf(" support-bundle schedule daemon start\n")
77+
78+
return nil
79+
},
80+
}
81+
82+
cmd.Flags().StringP("cron", "c", "", "Cron expression (required)")
83+
cmd.Flags().StringP("namespace", "n", "", "Kubernetes namespace (optional)")
84+
cmd.Flags().Bool("auto", false, "Enable auto-discovery")
85+
cmd.Flags().String("upload", "", "Enable auto-upload to vendor portal (any non-empty value enables auto-upload)")
86+
cmd.MarkFlagRequired("cron")
87+
88+
return cmd
89+
}
90+
91+
// listCommand creates the list subcommand
92+
func listCommand() *cobra.Command {
93+
return &cobra.Command{
94+
Use: "list",
95+
Short: "List all scheduled jobs",
96+
RunE: func(cmd *cobra.Command, args []string) error {
97+
manager, err := NewManager()
98+
if err != nil {
99+
return err
100+
}
101+
jobs, err := manager.ListJobs()
102+
if err != nil {
103+
return err
104+
}
105+
106+
if len(jobs) == 0 {
107+
fmt.Println("No scheduled jobs found")
108+
return nil
109+
}
110+
111+
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
112+
fmt.Fprintln(w, "NAME\tSCHEDULE\tNAMESPACE\tAUTO\tAUTO-UPLOAD\tRUNS")
113+
114+
for _, job := range jobs {
115+
upload := "none"
116+
if job.Upload != "" {
117+
upload = "enabled"
118+
}
119+
fmt.Fprintf(w, "%s\t%s\t%s\t%t\t%s\t%d\n",
120+
job.Name, job.Schedule, job.Namespace, job.Auto, upload, job.RunCount)
121+
}
122+
123+
return w.Flush()
124+
},
125+
}
126+
}
127+
128+
// deleteCommand creates the delete subcommand
129+
func deleteCommand() *cobra.Command {
130+
return &cobra.Command{
131+
Use: "delete [job-name]",
132+
Short: "Delete a scheduled job",
133+
Args: cobra.ExactArgs(1),
134+
RunE: func(cmd *cobra.Command, args []string) error {
135+
manager, err := NewManager()
136+
if err != nil {
137+
return err
138+
}
139+
140+
if err := manager.DeleteJob(args[0]); err != nil {
141+
return err
142+
}
143+
144+
fmt.Printf("✓ Deleted job: %s\n", args[0])
145+
return nil
146+
},
147+
}
148+
}
149+
150+
// daemonCommand creates the daemon subcommand
151+
func daemonCommand() *cobra.Command {
152+
cmd := &cobra.Command{
153+
Use: "daemon",
154+
Short: "Manage scheduler daemon",
155+
}
156+
157+
start := &cobra.Command{
158+
Use: "start",
159+
Short: "Start the scheduler daemon",
160+
Long: "Start the daemon to automatically execute scheduled jobs",
161+
RunE: func(cmd *cobra.Command, args []string) error {
162+
daemon, err := NewDaemon()
163+
if err != nil {
164+
return err
165+
}
166+
return daemon.Start()
167+
},
168+
}
169+
170+
cmd.AddCommand(start)
171+
return cmd
172+
}

0 commit comments

Comments
 (0)