Skip to content

Commit 611fcb0

Browse files
authored
feat: add sync overrun option to sync windows (#25361) (#25510)
Signed-off-by: Vilius Puškunalis <47086537+puskunalis@users.noreply.github.com>
1 parent 9c8ae9a commit 611fcb0

29 files changed

Lines changed: 2416 additions & 913 deletions

assets/swagger.json

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/argocd/commands/app.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,7 @@ func printAppSummaryTable(app *argoappv1.Application, appURL string, windows *ar
693693
}
694694

695695
if deny || !deny && !allow && inactiveAllows {
696-
s, err := windows.CanSync(true)
696+
s, err := windows.CanSync(true, nil)
697697
if err == nil && s {
698698
status = "Manual Allowed"
699699
} else {

cmd/argocd/commands/projectwindows.go

Lines changed: 88 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -42,25 +42,22 @@ argocd proj windows list <project-name>`,
4242
}
4343
roleCommand.AddCommand(NewProjectWindowsDisableManualSyncCommand(clientOpts))
4444
roleCommand.AddCommand(NewProjectWindowsEnableManualSyncCommand(clientOpts))
45+
roleCommand.AddCommand(NewProjectWindowsDisableSyncOverrunCommand(clientOpts))
46+
roleCommand.AddCommand(NewProjectWindowsEnableSyncOverrunCommand(clientOpts))
4547
roleCommand.AddCommand(NewProjectWindowsAddWindowCommand(clientOpts))
4648
roleCommand.AddCommand(NewProjectWindowsDeleteCommand(clientOpts))
4749
roleCommand.AddCommand(NewProjectWindowsListCommand(clientOpts))
4850
roleCommand.AddCommand(NewProjectWindowsUpdateCommand(clientOpts))
4951
return roleCommand
5052
}
5153

52-
// NewProjectWindowsDisableManualSyncCommand returns a new instance of an `argocd proj windows disable-manual-sync` command
53-
func NewProjectWindowsDisableManualSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
54-
command := &cobra.Command{
55-
Use: "disable-manual-sync PROJECT ID",
56-
Short: "Disable manual sync for a sync window",
57-
Long: "Disable manual sync for a sync window. Requires ID which can be found by running \"argocd proj windows list PROJECT\"",
58-
Example: `
59-
#Disable manual sync for a sync window for the Project
60-
argocd proj windows disable-manual-sync PROJECT ID
61-
62-
#Disabling manual sync for a windows set on the default project with Id 0
63-
argocd proj windows disable-manual-sync default 0`,
54+
// newProjectWindowsToggleCommand creates a command for toggling a boolean field on a sync window
55+
func newProjectWindowsToggleCommand(clientOpts *argocdclient.ClientOptions, use, short, long, example string, updateFn func(*v1alpha1.SyncWindow)) *cobra.Command {
56+
return &cobra.Command{
57+
Use: use,
58+
Short: short,
59+
Long: long,
60+
Example: example,
6461
Run: func(c *cobra.Command, args []string) {
6562
ctx := c.Context()
6663

@@ -79,26 +76,51 @@ argocd proj windows disable-manual-sync default 0`,
7976
proj, err := projIf.Get(ctx, &projectpkg.ProjectQuery{Name: projName})
8077
errors.CheckError(err)
8178

79+
found := false
8280
for i, window := range proj.Spec.SyncWindows {
8381
if id == i {
84-
window.ManualSync = false
82+
updateFn(window)
83+
found = true
84+
break
8585
}
8686
}
87+
if !found {
88+
errors.CheckError(fmt.Errorf("window with id '%d' not found", id))
89+
}
8790

8891
_, err = projIf.Update(ctx, &projectpkg.ProjectUpdateRequest{Project: proj})
8992
errors.CheckError(err)
9093
},
9194
}
92-
return command
95+
}
96+
97+
// NewProjectWindowsDisableManualSyncCommand returns a new instance of an `argocd proj windows disable-manual-sync` command
98+
func NewProjectWindowsDisableManualSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
99+
return newProjectWindowsToggleCommand(
100+
clientOpts,
101+
"disable-manual-sync PROJECT ID",
102+
"Disable manual sync for a sync window",
103+
"Disable manual sync for a sync window. Requires ID which can be found by running \"argocd proj windows list PROJECT\"",
104+
`
105+
#Disable manual sync for a sync window for the Project
106+
argocd proj windows disable-manual-sync PROJECT ID
107+
108+
#Disabling manual sync for a windows set on the default project with Id 0
109+
argocd proj windows disable-manual-sync default 0`,
110+
func(window *v1alpha1.SyncWindow) {
111+
window.ManualSync = false
112+
},
113+
)
93114
}
94115

95116
// NewProjectWindowsEnableManualSyncCommand returns a new instance of an `argocd proj windows enable-manual-sync` command
96117
func NewProjectWindowsEnableManualSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
97-
command := &cobra.Command{
98-
Use: "enable-manual-sync PROJECT ID",
99-
Short: "Enable manual sync for a sync window",
100-
Long: "Enable manual sync for a sync window. Requires ID which can be found by running \"argocd proj windows list PROJECT\"",
101-
Example: `
118+
return newProjectWindowsToggleCommand(
119+
clientOpts,
120+
"enable-manual-sync PROJECT ID",
121+
"Enable manual sync for a sync window",
122+
"Enable manual sync for a sync window. Requires ID which can be found by running \"argocd proj windows list PROJECT\"",
123+
`
102124
#Enabling manual sync for a general case
103125
argocd proj windows enable-manual-sync PROJECT ID
104126
@@ -107,35 +129,48 @@ argocd proj windows enable-manual-sync default 2
107129
108130
#Enabling manual sync with a custom message
109131
argocd proj windows enable-manual-sync my-app-project --message "Manual sync initiated by admin`,
110-
Run: func(c *cobra.Command, args []string) {
111-
ctx := c.Context()
112-
113-
if len(args) != 2 {
114-
c.HelpFunc()(c, args)
115-
os.Exit(1)
116-
}
117-
118-
projName := args[0]
119-
id, err := strconv.Atoi(args[1])
120-
errors.CheckError(err)
121-
122-
conn, projIf := headless.NewClientOrDie(clientOpts, c).NewProjectClientOrDie()
123-
defer utilio.Close(conn)
124-
125-
proj, err := projIf.Get(ctx, &projectpkg.ProjectQuery{Name: projName})
126-
errors.CheckError(err)
132+
func(window *v1alpha1.SyncWindow) {
133+
window.ManualSync = true
134+
},
135+
)
136+
}
127137

128-
for i, window := range proj.Spec.SyncWindows {
129-
if id == i {
130-
window.ManualSync = true
131-
}
132-
}
138+
// NewProjectWindowsDisableSyncOverrunCommand returns a new instance of an `argocd proj windows disable-sync-overrun` command
139+
func NewProjectWindowsDisableSyncOverrunCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
140+
return newProjectWindowsToggleCommand(
141+
clientOpts,
142+
"disable-sync-overrun PROJECT ID",
143+
"Disable sync overrun for a sync window",
144+
"Disable sync overrun for a sync window. Requires ID which can be found by running \"argocd proj windows list PROJECT\"",
145+
`
146+
#Disable sync overrun for a sync window for the Project
147+
argocd proj windows disable-sync-overrun PROJECT ID
148+
149+
#Disabling sync overrun for a window set on the default project with Id 0
150+
argocd proj windows disable-sync-overrun default 0`,
151+
func(window *v1alpha1.SyncWindow) {
152+
window.SyncOverrun = false
153+
},
154+
)
155+
}
133156

134-
_, err = projIf.Update(ctx, &projectpkg.ProjectUpdateRequest{Project: proj})
135-
errors.CheckError(err)
157+
// NewProjectWindowsEnableSyncOverrunCommand returns a new instance of an `argocd proj windows enable-sync-overrun` command
158+
func NewProjectWindowsEnableSyncOverrunCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
159+
return newProjectWindowsToggleCommand(
160+
clientOpts,
161+
"enable-sync-overrun PROJECT ID",
162+
"Enable sync overrun for a sync window",
163+
"Enable sync overrun for a sync window. When enabled on a deny window, syncs that started before the deny window will be allowed to continue. When enabled on an allow window, syncs that started during the allow window can continue after the window ends. Requires ID which can be found by running \"argocd proj windows list PROJECT\"",
164+
`
165+
#Enable sync overrun for a sync window
166+
argocd proj windows enable-sync-overrun PROJECT ID
167+
168+
#Enabling sync overrun for a window set on the default project with Id 2
169+
argocd proj windows enable-sync-overrun default 2`,
170+
func(window *v1alpha1.SyncWindow) {
171+
window.SyncOverrun = true
136172
},
137-
}
138-
return command
173+
)
139174
}
140175

141176
// NewProjectWindowsAddWindowCommand returns a new instance of an `argocd proj windows add` command
@@ -148,6 +183,7 @@ func NewProjectWindowsAddWindowCommand(clientOpts *argocdclient.ClientOptions) *
148183
namespaces []string
149184
clusters []string
150185
manualSync bool
186+
syncOverrun bool
151187
timeZone string
152188
andOperator bool
153189
description string
@@ -164,7 +200,7 @@ argocd proj windows add PROJECT \
164200
--applications "*" \
165201
--description "Ticket 123"
166202
167-
#Add a deny sync window with the ability to manually sync.
203+
#Add a deny sync window with the ability to manually sync and sync overrun.
168204
argocd proj windows add PROJECT \
169205
--kind deny \
170206
--schedule "30 10 * * *" \
@@ -173,8 +209,8 @@ argocd proj windows add PROJECT \
173209
--namespaces "default,\\*-prod" \
174210
--clusters "prod,staging" \
175211
--manual-sync \
176-
--description "Ticket 123"
177-
`,
212+
--sync-overrun \
213+
--description "Ticket 123"`,
178214
Run: func(c *cobra.Command, args []string) {
179215
ctx := c.Context()
180216

@@ -189,7 +225,7 @@ argocd proj windows add PROJECT \
189225
proj, err := projIf.Get(ctx, &projectpkg.ProjectQuery{Name: projName})
190226
errors.CheckError(err)
191227

192-
err = proj.Spec.AddWindow(kind, schedule, duration, applications, namespaces, clusters, manualSync, timeZone, andOperator, description)
228+
err = proj.Spec.AddWindow(kind, schedule, duration, applications, namespaces, clusters, manualSync, timeZone, andOperator, description, syncOverrun)
193229
errors.CheckError(err)
194230

195231
_, err = projIf.Update(ctx, &projectpkg.ProjectUpdateRequest{Project: proj})
@@ -203,6 +239,7 @@ argocd proj windows add PROJECT \
203239
command.Flags().StringSliceVar(&namespaces, "namespaces", []string{}, "Namespaces that the schedule will be applied to. Comma separated, wildcards supported (e.g. --namespaces default,\\*-prod)")
204240
command.Flags().StringSliceVar(&clusters, "clusters", []string{}, "Clusters that the schedule will be applied to. Comma separated, wildcards supported (e.g. --clusters prod,staging)")
205241
command.Flags().BoolVar(&manualSync, "manual-sync", false, "Allow manual syncs for both deny and allow windows")
242+
command.Flags().BoolVar(&syncOverrun, "sync-overrun", false, "Allow syncs to continue: for deny windows, syncs that started before the window; for allow windows, syncs that started during the window")
206243
command.Flags().StringVar(&timeZone, "time-zone", "UTC", "Time zone of the sync window")
207244
command.Flags().BoolVar(&andOperator, "use-and-operator", false, "Use AND operator for matching applications, namespaces and clusters instead of the default OR operator")
208245
command.Flags().StringVar(&description, "description", "", `Sync window description`)
@@ -362,7 +399,7 @@ argocd proj windows list test-project`,
362399
func printSyncWindows(proj *v1alpha1.AppProject) {
363400
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
364401
var fmtStr string
365-
headers := []any{"ID", "STATUS", "KIND", "SCHEDULE", "DURATION", "APPLICATIONS", "NAMESPACES", "CLUSTERS", "MANUALSYNC", "TIMEZONE", "USEANDOPERATOR"}
402+
headers := []any{"ID", "STATUS", "KIND", "SCHEDULE", "DURATION", "APPLICATIONS", "NAMESPACES", "CLUSTERS", "MANUALSYNC", "SYNCOVERRUN", "TIMEZONE", "USEANDOPERATOR"}
366403
fmtStr = strings.Repeat("%s\t", len(headers)) + "\n"
367404
fmt.Fprintf(w, fmtStr, headers...)
368405
if proj.Spec.SyncWindows.HasWindows() {
@@ -378,6 +415,7 @@ func printSyncWindows(proj *v1alpha1.AppProject) {
378415
formatListOutput(window.Namespaces),
379416
formatListOutput(window.Clusters),
380417
formatBoolEnabledOutput(window.ManualSync),
418+
formatBoolEnabledOutput(window.SyncOverrun),
381419
window.TimeZone,
382420
formatBoolEnabledOutput(window.UseAndOperator),
383421
}

0 commit comments

Comments
 (0)