Skip to content

Commit bd767ff

Browse files
Merge branch 'dev' of https://github.com/KelvinTegelaar/CIPP-API into dev
2 parents 32c3878 + 835972e commit bd767ff

3 files changed

Lines changed: 68 additions & 48 deletions

File tree

Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-ContainerUpdateCheck.ps1

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@ function Start-ContainerUpdateCheck {
1414
$SettingsTable = Get-CippTable -tablename 'ContainerUpdateSettings'
1515
# Reconcile the stored check result with the running build first — a restart may
1616
# have applied a previously detected update, and this must clear the stale
17-
# "update available" flag even when checks are disabled or not yet due.
17+
# "update available" flag even when checks are disabled or not yet due. Sync also
18+
# resolves defaults for never-saved fields (auto-restart on, hourly, 23:00), so
19+
# only an explicitly saved interval of '0' disables checking.
1820
$Settings = Sync-CippContainerUpdateState
1921

20-
if (-not $Settings -or $Settings.CheckInterval -eq '0' -or [string]::IsNullOrWhiteSpace($Settings.CheckInterval)) {
21-
Write-Information 'Container update check: disabled or not configured'
22+
if (-not $Settings -or $Settings.CheckInterval -eq '0') {
23+
Write-Information 'Container update check: disabled'
2224
return
2325
}
2426

@@ -167,11 +169,6 @@ function Start-ContainerUpdateCheck {
167169
}
168170
}
169171

170-
if ($RemoteBuildDate -is [datetime]) {
171-
if ($RemoteBuildDate.Kind -eq [System.DateTimeKind]::Unspecified) { $RemoteBuildDate = [DateTime]::SpecifyKind($RemoteBuildDate, [System.DateTimeKind]::Utc) }
172-
$RemoteBuildDate = $RemoteBuildDate.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss'Z'")
173-
}
174-
175172
$RunningVersion = $env:APP_VERSION
176173
$UpdateAvailable = $false
177174
if ($RemoteVersion -and $RunningVersion -and $RemoteVersion -ne $RunningVersion) {
@@ -181,9 +178,9 @@ function Start-ContainerUpdateCheck {
181178
$UpdateEntity = @{
182179
PartitionKey = 'Settings'
183180
RowKey = 'UpdateConfig'
184-
AutoUpdate = [string]($Settings.AutoUpdate ?? 'false')
185-
CheckInterval = [string]($Settings.CheckInterval ?? '0')
186-
CheckTime = [string]($Settings.CheckTime ?? '')
181+
AutoUpdate = [string]($Settings.AutoUpdate ?? 'true')
182+
CheckInterval = [string]($Settings.CheckInterval ?? '1h')
183+
CheckTime = [string]($Settings.CheckTime ?? '23')
187184
LastCheck = [string][int64](([DateTimeOffset]::UtcNow).ToUnixTimeSeconds())
188185
UpdateAvailable = [string]$UpdateAvailable
189186
RunningVersion = [string]($RunningVersion ?? '')
Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,70 @@
11
function Sync-CippContainerUpdateState {
22
<#
33
.SYNOPSIS
4-
Reconcile the stored container update-check result with the build that is actually running.
4+
Resolve container update settings and reconcile the stored check result with the running build.
55
66
.DESCRIPTION
7+
Returns the effective container update settings. Fields that have never been saved resolve
8+
to the defaults: auto-restart enabled, check every hour, preferred time 23:00. Explicitly
9+
saved values are respected — including CheckInterval '0' (disabled) and a CheckTime saved
10+
as an empty string, which means "no preferred time"; only a missing field falls back to
11+
the default. Both the Status endpoint and the update-check timer consume this, so the
12+
defaults apply identically to both.
13+
714
The ContainerUpdateSettings table is only written when an update check runs, so after a
815
restart that applied an update the table keeps reporting the previous build's state —
916
"update available" with the old running version — until the next check. This compares the
1017
stored result against the running APP_VERSION/IMAGE_TAG and clears or recomputes the flag
11-
locally, without a registry call. Returns the current settings entity, or $null when no
12-
settings have been saved yet.
18+
locally, without a registry call.
1319
#>
1420
[CmdletBinding()]
1521
param()
1622

1723
$SettingsTable = Get-CippTable -tablename 'ContainerUpdateSettings'
1824
$Settings = Get-CIPPAzDataTableEntity @SettingsTable -Filter "PartitionKey eq 'Settings' and RowKey eq 'UpdateConfig'" | Select-Object -First 1
19-
if (-not $Settings) { return $null }
25+
26+
# Effective schedule settings — defaults apply only to never-saved fields
27+
$AutoUpdate = if ([string]::IsNullOrWhiteSpace([string]$Settings.AutoUpdate)) { 'true' } else { [string]$Settings.AutoUpdate }
28+
$CheckInterval = if ([string]::IsNullOrWhiteSpace([string]$Settings.CheckInterval)) { '1h' } else { [string]$Settings.CheckInterval }
29+
$CheckTime = if ($null -eq $Settings.CheckTime) { '23' } else { [string]$Settings.CheckTime }
2030

2131
$RunningVersion = $env:APP_VERSION
2232
$StoredRunning = [string]($Settings.RunningVersion ?? '')
23-
if (-not $RunningVersion -or -not $StoredRunning -or $StoredRunning -eq $RunningVersion) {
24-
return $Settings
25-
}
26-
27-
# The container restarted onto a different build since the last check.
2833
$StoredRemote = [string]($Settings.RemoteVersion ?? '')
2934
$CheckedTag = [string]($Settings.CheckedTag ?? '')
30-
$RunningTag = $env:IMAGE_TAG
31-
if ($CheckedTag -and $RunningTag -and $CheckedTag -ne $RunningTag) {
32-
# The last check ran against a different channel tag — its result no longer applies.
33-
$UpdateAvailable = $false
34-
} else {
35-
$UpdateAvailable = [bool]($StoredRemote -and $StoredRemote -ne $RunningVersion)
35+
$UpdateAvailable = [string]($Settings.UpdateAvailable ?? 'false')
36+
37+
$NeedsWrite = $false
38+
if ($Settings -and $RunningVersion -and $StoredRunning -and $StoredRunning -ne $RunningVersion) {
39+
# The container restarted onto a different build since the last check.
40+
$RunningTag = $env:IMAGE_TAG
41+
if ($CheckedTag -and $RunningTag -and $CheckedTag -ne $RunningTag) {
42+
# The last check ran against a different channel tag — its result no longer applies.
43+
$UpdateAvailable = 'False'
44+
} else {
45+
$UpdateAvailable = [string][bool]($StoredRemote -and $StoredRemote -ne $RunningVersion)
46+
}
47+
Write-Information "Container update state reconciled: running build changed '$StoredRunning' -> '$RunningVersion', UpdateAvailable=$UpdateAvailable"
48+
$StoredRunning = $RunningVersion
49+
$NeedsWrite = $true
3650
}
3751

3852
$Entity = @{
3953
PartitionKey = 'Settings'
4054
RowKey = 'UpdateConfig'
41-
AutoUpdate = [string]($Settings.AutoUpdate ?? 'false')
42-
CheckInterval = [string]($Settings.CheckInterval ?? '0')
43-
CheckTime = [string]($Settings.CheckTime ?? '')
55+
AutoUpdate = $AutoUpdate
56+
CheckInterval = $CheckInterval
57+
CheckTime = $CheckTime
4458
LastCheck = [string]($Settings.LastCheck ?? '')
45-
UpdateAvailable = [string]$UpdateAvailable
46-
RunningVersion = [string]$RunningVersion
59+
UpdateAvailable = $UpdateAvailable
60+
RunningVersion = $StoredRunning
4761
RemoteVersion = $StoredRemote
4862
RemoteDigest = [string]($Settings.RemoteDigest ?? '')
4963
RemoteBuildDate = [string]($Settings.RemoteBuildDate ?? '')
5064
CheckedTag = $CheckedTag
5165
}
52-
Add-CIPPAzDataTableEntity @SettingsTable -Entity $Entity -Force | Out-Null
53-
Write-Information "Container update state reconciled: running build changed '$StoredRunning' -> '$RunningVersion', UpdateAvailable=$UpdateAvailable"
66+
if ($NeedsWrite) {
67+
Add-CIPPAzDataTableEntity @SettingsTable -Entity $Entity -Force | Out-Null
68+
}
5469
return [pscustomobject]$Entity
5570
}

Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecContainerManagement.ps1

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,6 @@ function Invoke-ExecContainerManagement {
7979
}
8080
}
8181

82-
if ($created -is [datetime]) {
83-
if ($created.Kind -eq [System.DateTimeKind]::Unspecified) { $created = [DateTime]::SpecifyKind($created, [System.DateTimeKind]::Utc) }
84-
$created = $created.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss'Z'")
85-
}
86-
8782
return [pscustomobject]@{
8883
Digest = [string]$digest
8984
Version = [string]$version
@@ -123,11 +118,13 @@ function Invoke-ExecContainerManagement {
123118
# Read update settings and last check result, reconciled against the running
124119
# build — a restart may have applied the previously detected update, which
125120
# would otherwise keep showing "update available" until the next check.
121+
# Sync also resolves defaults for never-saved fields (auto-restart on,
122+
# hourly checks, preferred time 23:00).
126123
$Settings = Sync-CippContainerUpdateState
127124
$UpdateInfo = @{
128-
AutoUpdate = $false
129-
CheckInterval = '0'
130-
CheckTime = $null
125+
AutoUpdate = $true
126+
CheckInterval = '1h'
127+
CheckTime = '23'
131128
LastCheck = $null
132129
UpdateAvailable = $false
133130
RunningVersion = $null
@@ -233,13 +230,16 @@ function Invoke-ExecContainerManagement {
233230
}
234231
$Existing = Get-CIPPAzDataTableEntity @SettingsTable -Filter "PartitionKey eq 'Settings' and RowKey eq 'UpdateConfig'" | Select-Object -First 1
235232
if ($Existing) {
236-
$Entity.AutoUpdate = $Existing.AutoUpdate ?? 'false'
237-
$Entity.CheckInterval = $Existing.CheckInterval ?? '0'
238-
$Entity.CheckTime = $Existing.CheckTime ?? ''
233+
# Carry saved schedule fields forward; never-saved fields materialize
234+
# the defaults (auto-restart on, hourly, 23:00). An empty CheckTime is
235+
# an explicit "no preferred time" and is preserved.
236+
$Entity.AutoUpdate = $Existing.AutoUpdate ?? 'true'
237+
$Entity.CheckInterval = $Existing.CheckInterval ?? '1h'
238+
$Entity.CheckTime = $Existing.CheckTime ?? '23'
239239
}
240240
Add-CIPPAzDataTableEntity @SettingsTable -Entity $Entity -Force | Out-Null
241241

242-
$Settings = Get-CIPPAzDataTableEntity @SettingsTable -Filter "PartitionKey eq 'Settings' and RowKey eq 'UpdateConfig'" | Select-Object -First 1
242+
$Settings = Sync-CippContainerUpdateState
243243
if ($UpdateAvailable -and $Settings.AutoUpdate -eq 'true') {
244244
Write-LogMessage -API $APIName -headers $Headers -message "Auto-update: new container version detected (running: $RunningVersion, remote: $RemoteVersion). Restarting." -sev Info
245245
try { Request-CIPPRestart -Reason 'Auto-update: new container version available' } catch {}
@@ -279,8 +279,16 @@ function Invoke-ExecContainerManagement {
279279
if ($CheckInterval -notin $ValidIntervals) {
280280
throw "Invalid check interval: $CheckInterval. Valid: $($ValidIntervals -join ', ')"
281281
}
282-
if ($CheckTime -and ($CheckTime -lt 0 -or $CheckTime -gt 23)) {
283-
throw "Invalid check time: $CheckTime. Must be 0-23 (UTC hour)."
282+
# CheckTime arrives as a string — validate as [int]. A string comparison
283+
# makes '3' -gt 23 true ('3' > '2' lexicographically), rejecting 03:00-09:00.
284+
if ($null -ne $CheckTime -and "$CheckTime" -ne '') {
285+
$ParsedHour = 0
286+
if (-not [int]::TryParse([string]$CheckTime, [ref]$ParsedHour) -or $ParsedHour -lt 0 -or $ParsedHour -gt 23) {
287+
throw "Invalid check time: $CheckTime. Must be an hour between 0 and 23."
288+
}
289+
$CheckTime = $ParsedHour
290+
} else {
291+
$CheckTime = $null
284292
}
285293

286294
# Read existing settings to preserve check results — the upsert replaces the
@@ -304,7 +312,7 @@ function Invoke-ExecContainerManagement {
304312

305313
$IntervalLabel = if ($CheckInterval -eq '0') { 'disabled' } else { "every $CheckInterval" }
306314
$AutoLabel = if ($AutoUpdate) { 'auto-restart enabled' } else { 'manual restart' }
307-
$TimeLabel = if ($CheckTime -and $CheckInterval -ne '0') { " at ${CheckTime}:00 UTC" } else { '' }
315+
$TimeLabel = if ($null -ne $CheckTime -and $CheckInterval -ne '0') { " at $('{0:d2}' -f $CheckTime):00" } else { '' }
308316
$Result = "Update settings saved. Check interval: ${IntervalLabel}${TimeLabel}, $AutoLabel."
309317
Write-LogMessage -API $APIName -headers $Headers -message $Result -sev Info
310318
$Body = @{ Results = $Result }

0 commit comments

Comments
 (0)