xolo-server 2.2.0 → 2.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 84bf8381f9806f22096c6404f36e62cb49d418384cf8a9cd722bbb4afbfc60d1
4
- data.tar.gz: 22e325e7e124104589c946006531cad9e5ab3b8db047b8403e66d5bb83166d0f
3
+ metadata.gz: 6b12ee4495ec1ef8ad6ff15963a47b8c5c960fbfc66c447355d9205a821945d5
4
+ data.tar.gz: b5223966d5f2d32298cbd74fceb3bc9bd86377249f05cf7ff0cdcee7d892a0ef
5
5
  SHA512:
6
- metadata.gz: 8dde7e538db3e32619b7828057e7671c8eef1460a60df222f63754624d98093b66b6badf78b8834ef4517343b0464e965471cd1bbb841ec66886b20d5ca98d0a
7
- data.tar.gz: 738fdb9b8c7cd66cb82c1efe39cbc00aafa011a0adc6b4936f6a2fcaadf1733f64fa88a2648a8a7d8639d4866203328be8ce8baee86103d9982e83b4cf144841
6
+ metadata.gz: 6891dc7666891af24efb6c3b2842154dedc0fb94652203ac7cdbce21b2f5cbf38e69dbbd54630f7c5c4f5dabdc3b717ade26c26ce1fcfbb94fc318669a2704c7
7
+ data.tar.gz: faf5eb9e5a6ce4e63989070bece99e9916fe44fe14a40d6e25a04a16ddeabd5d45641cf6cce380827fa0d06901bccfc345a99ea5983b2f2509223eaf816467b6
@@ -759,7 +759,7 @@ module Xolo
759
759
 
760
760
  By default this is false, Patch Policies for versions will be set to 'Install Automatically'.
761
761
 
762
- If set to true, Patch Policies for versions will be set to 'Make Available in Self Service' and the version will appear in the Updates section when available. The update won't happen until the user clicks a button, or the 7-day deadline passes. Notifications will be displayed daily.
762
+ If set to true, Patch Policies for versions will be set to 'Make Available in Self Service' and the version will appear in the Updates section when available. The update won't happen until the user clicks a button, or the 7-day deadline passes. Notifications will be displayed daily. For these titles, 'xolo update' will not apply the update, but 'xolo install <title>' will update/install the current release.
763
763
 
764
764
  When installing automatically, or the deadline passes, the update will happen at the checkin after the next recon. If the version has any KillApps, the user will be prompted to quit them, with a grace period of 15 minutes before the update starts.
765
765
 
@@ -12,7 +12,7 @@ module Xolo
12
12
 
13
13
  module Version
14
14
 
15
- VERSION = '2.2.0'.freeze
15
+ VERSION = '2.2.3'.freeze
16
16
 
17
17
  end
18
18
 
@@ -160,15 +160,24 @@ module Xolo
160
160
  #
161
161
  # This process is protected by a mutex to prevent multiple updates at the same time.
162
162
  #
163
+ # @param post_maint [Boolean] Are we being called at the end of the run_maint method?
164
+ #
163
165
  # @return [void]
164
166
  #####################
165
- def update_client_data
167
+ def update_client_data(post_maint: false)
166
168
  # don't do anything if we are in developer/test mode
167
169
  if Xolo::Server.config.developer_mode?
168
170
  log_debug 'Jamf: Skipping client-data update in developer mode'
169
171
  return
170
172
  end
171
173
 
174
+ # don't do anything if maintenance is running,
175
+ # the main process will call this method once at the end
176
+ if Xolo::Server::Helpers::Maintenance.maint_running? && !post_maint
177
+ log_debug 'Jamf: Skipping client-data update while maintenance is running'
178
+ return
179
+ end
180
+
172
181
  log_info 'Jamf: Updating client-data package'
173
182
 
174
183
  # TODO: Use Concurrent Ruby instead of Mutex
@@ -13,9 +13,10 @@ module Xolo
13
13
  module Helpers
14
14
 
15
15
  # Nightly maintenance tasks
16
- # - accept TEd EAs
16
+ # - accept lingering TEd EAs, if configured to
17
17
  # - autorelease versions
18
18
  # - clean up old versions
19
+ # - notify title maintainers of old unreleased pilots
19
20
  #
20
21
  # Also, alerts will be posted, and Emails will be sent to the
21
22
  # admins who added versions that have been in pilot for more than
@@ -32,8 +33,24 @@ module Xolo
32
33
  # Constants
33
34
  #####################################
34
35
 
36
+ # TODO: ? use the next 3 values as defaults, and
37
+ # set them in the server config
38
+
39
+ # how often does our maint timer check to see if it should run maintenance?
40
+ # Slightly less than an hour means there will always be at least one check every
41
+ # hour, sometimes two.
42
+ MAINT_CHECK_INTERVAL = 3500
43
+ # MAINT_CHECK_INTERVAL = 600
44
+
35
45
  # At what hour should the nightly maintenance run?
36
46
  MAINT_HOUR = 2
47
+ # MAINT_HOUR = 10
48
+
49
+ # Maint won't run unless the last run was at least this many
50
+ # seconds ago.
51
+ # 23 hrs ago means that even if we check twice within the
52
+ # MAINT_HOUR, only the first one will run.
53
+ MAINT_MAX_FREQ_SECS = 23 * 3600
37
54
 
38
55
  # the route we POST to, to start the nightly process.
39
56
  TIMED_MAINT_TRIGGER_ROUTE = '/maint/maint-internal'
@@ -84,9 +101,10 @@ module Xolo
84
101
  return @maint_timer_task if @maint_timer_task
85
102
 
86
103
  @maint_timer_task =
87
- Concurrent::TimerTask.new(execution_interval: 3600) { post_to_start_maint }
104
+ Concurrent::TimerTask.new(execution_interval: MAINT_CHECK_INTERVAL) { post_to_start_maint }
105
+
106
+ Xolo::Server.logger.info "Created Concurrent::TimerTask for nightly maintenance. Will check every #{MAINT_CHECK_INTERVAL} secs, and run during the hour of: #{MAINT_HOUR}"
88
107
 
89
- Xolo::Server.logger.info 'Created Concurrent::TimerTask for nightly maintenance.'
90
108
  @maint_timer_task
91
109
  end
92
110
 
@@ -105,6 +123,12 @@ module Xolo
105
123
  @last_maint = time
106
124
  end
107
125
 
126
+ # @return [Time] Is maintenance running right now? true if the mutex is locked
127
+ ######################################
128
+ def self.maint_running?
129
+ maint_mutex.locked?
130
+ end
131
+
108
132
  # post to the server to start the maint process
109
133
  # This is done so that the maint can run in the context of a request,
110
134
  # having access to Title and Version instantiation.
@@ -118,10 +142,20 @@ module Xolo
118
142
  return
119
143
  end
120
144
 
121
- # only run the maintenance if it's between 2am and 3am
122
- # and the last one was more than 23 hrs ago
123
- last_maint_hrs_ago = (Time.now - last_maint) / 3600
124
- return unless force || (Time.now.hour == MAINT_HOUR && last_maint_hrs_ago > 23)
145
+ now = Time.now
146
+
147
+ # only run the maintenance if it's during the MAINT_HOUR
148
+ # and the last one was more than MAINT_MAX_FREQ_SECS ago
149
+ if force
150
+ Xolo::Server.logger.info 'Maint: Starting now due to force'
151
+
152
+ elsif now.hour == MAINT_HOUR && (now - last_maint) > MAINT_MAX_FREQ_SECS
153
+ Xolo::Server.logger.info 'Maint: Starting nightly run now'
154
+
155
+ else
156
+ Xolo::Server.logger.info "Maint: Not starting, it isn't time"
157
+ return
158
+ end
125
159
 
126
160
  uri = URI.parse "https://#{Xolo::Server::Helpers::Auth::IPV4_LOOPBACK}#{TIMED_MAINT_TRIGGER_ROUTE}"
127
161
  https = Net::HTTP.new(uri.host, uri.port)
@@ -153,14 +187,25 @@ module Xolo
153
187
  return
154
188
  end
155
189
  mutex.lock
190
+
156
191
  log_info 'Maint: starting'
157
192
 
193
+ # instantiate all the titles once now, rather than in all the task methods
194
+ title_objects_for_maint = all_title_objects refresh: true
195
+
158
196
  # add new maintenance tasks/methods here
159
- accept_title_editor_eas
160
- auto_release_versions
161
- cleanup_versions
197
+ ######
198
+ accept_title_editor_eas title_objects_for_maint
199
+ auto_release_versions title_objects_for_maint
200
+ cleanup_versions title_objects_for_maint
201
+ notify_admins_of_unreleased_pilots title_objects_for_maint
162
202
 
203
+ # make note of the time.
204
+ Xolo::Server::Helpers::Maintenance.last_maint = Time.now
163
205
  log_info 'Maint: complete'
206
+
207
+ log_debug 'Maint: running update_client_data after all tasks'
208
+ update_client_data post_maint: true
164
209
  ensure
165
210
  mutex&.unlock
166
211
  end
@@ -169,17 +214,16 @@ module Xolo
169
214
  # and auto accept them if we need to
170
215
  # @return [void]
171
216
  ######################################
172
- def accept_title_editor_eas
217
+ def accept_title_editor_eas(title_objects)
173
218
  unless Xolo::Server.config.jamf_auto_accept_xolo_eas
174
- log_info 'Maint: The xolo server is not configured to auto-accept Title Editor EAs'
219
+ log_debug 'Maint: The xolo server is not configured to auto-accept Title Editor EAs'
175
220
  return
176
221
  end
177
222
 
178
223
  log_info 'Maint: Looking for Title Editor EAs to auto-accept'
179
224
 
180
- # TODO: Be DRY with this stuff and similar in title_jamf_access.rb
181
- Xolo::Server::Title.all_titles.each do |title|
182
- title_obj = instantiate_title title
225
+ title_objects.each do |title_obj|
226
+ title = title_obj.title
183
227
  next if title_obj.subscribed?
184
228
  next unless title_obj.jamf_patch_ea_awaiting_acceptance?
185
229
 
@@ -195,14 +239,17 @@ module Xolo
195
239
  # Do any pending auto-releases
196
240
  # @return [void]
197
241
  ##############################
198
- def auto_release_versions
242
+ def auto_release_versions(title_objects)
199
243
  log_info 'Maint: Auto-releasing appropriate versions'
200
244
 
201
245
  today = Date.today
202
246
 
203
247
  # Loop thru the titles
204
- Xolo::Server::Title.all_titles.each do |title|
205
- title_obj = instantiate_title title
248
+ title_objects.each do |title_obj|
249
+ title = title_obj.title
250
+
251
+ # nothing to do if its nil or 'none'
252
+ next if title_obj.auto_release_delay.nil? || title_obj.auto_release_delay == Xolo::NONE
206
253
 
207
254
  # title must be subscribed and autopkg
208
255
  # (enforced in xadm)
@@ -214,19 +261,22 @@ module Xolo
214
261
  # NOTE: it is stored as a string because it might be 'none'
215
262
  # TODO: store none as nil, so we don't have to do the pix_integer check??
216
263
  delay = title_obj.auto_release_delay.to_i
217
- next unless title_obj.auto_release_delay.pix_integer? && !delay.negative?
264
+ next unless title_obj.auto_release_delay&.pix_integer? && !delay.negative?
218
265
 
219
266
  # Any version with this creation date should be released now, skip if not
220
267
  # So if the auto_release_delay is 7, its today - 7 days.
221
268
  # if the auto_release_delay is 0, its today - 0 days, aka today
222
269
  creation_date_to_be_released_today = today - delay
223
270
 
224
- # Find the newest pilot version whose creation date is creation_date_to_be_released_today
271
+ # Find the newest pilot version whose creation date is
272
+ # creation_date_to_be_released_today or earlier
225
273
  # That one should be released now.
226
274
  vobj_to_release = nil
275
+
276
+ # version objects are in order of newest to oldest
227
277
  title_obj.version_objects.each do |vobj|
228
278
  next unless vobj.pilot?
229
- next unless vobj.creation_date.to_date == creation_date_to_be_released_today
279
+ next unless vobj.creation_date.to_date <= creation_date_to_be_released_today
230
280
 
231
281
  vobj_to_release = vobj
232
282
  break
@@ -243,6 +293,9 @@ module Xolo
243
293
  title_obj.release vobj_to_release.version
244
294
 
245
295
  log_info "Maint: Auto-released version '#{vobj_to_release.version}' of '#{title}' which came out #{vobj_to_release.creation_date}", alert: true
296
+
297
+ # pause for server to catch up
298
+ sleep 60
246
299
  end # each title
247
300
 
248
301
  log_debug 'Maint: Done auto-releasing'
@@ -251,12 +304,11 @@ module Xolo
251
304
  # Cleanup versions.
252
305
  # @return [void]
253
306
  ################################
254
- def cleanup_versions
255
- log_info 'Maint: cleaning up deprecated and skipped versions'
256
-
257
- Xolo::Server::Title.all_titles.each do |title|
258
- title_obj = instantiate_title title
307
+ def cleanup_versions(title_objects)
308
+ log_info 'Maint: Cleaning up deprecated and skipped versions'
259
309
 
310
+ # Loop thru the titles
311
+ title_objects.each do |title_obj|
260
312
  title_obj.version_objects.each do |version|
261
313
  if version.deprecated?
262
314
  cleanup_deprecated_version version
@@ -264,12 +316,8 @@ module Xolo
264
316
  cleanup_skipped_version version
265
317
  end # case
266
318
  end # each version
267
-
268
- notify_admins_of_unreleased_pilots(title_obj)
269
319
  end # each title
270
-
271
- Xolo::Server::Helpers::Maintenance.last_maint = Time.now
272
- log_info 'Maint: versions cleanup complete'
320
+ log_info 'Maint: Version cleanup complete'
273
321
  end
274
322
 
275
323
  # Cleanup a deprecated version.
@@ -284,7 +332,7 @@ module Xolo
284
332
  days_deprecated = (Time.now - version.deprecation_date) / 86_400
285
333
  return unless days_deprecated > deprecated_lifetime_days
286
334
 
287
- log_info "Cleanup: Deleting deprecated version '#{version.version}' of title '#{version.title}'"
335
+ log_info "Maint: Deleting deprecated version '#{version.version}' of title '#{version.title}'"
288
336
  version.delete
289
337
  end
290
338
 
@@ -295,38 +343,50 @@ module Xolo
295
343
  def cleanup_skipped_version(version)
296
344
  return if Xolo::Server.config.keep_skipped_versions
297
345
 
298
- log_info "Cleanup: Deleting skipped version '#{version.version}' of title '#{version.title}'"
346
+ log_info "Maint: Deleting skipped version '#{version.version}' of title '#{version.title}'"
299
347
  version.delete
300
348
  end
301
349
 
302
350
  # Notify the admins about unreleased pilots if needed
303
351
  # @return [void]
304
352
  ################################
305
- def notify_admins_of_unreleased_pilots(title_obj)
306
- return unless Time.now.day == UNRELEASED_PILOTS_NOTIFICATION_DAY
307
- return unless unreleased_pilots_notification_days.positive?
308
- return unless title_obj.latest_version
353
+ def notify_admins_of_unreleased_pilots(title_objects)
354
+ unless Time.now.day == UNRELEASED_PILOTS_NOTIFICATION_DAY
355
+ log_debug 'Maint: Not notifying admins of old pilots, wrong day of the month.'
356
+ return
357
+ end
358
+ unless unreleased_pilots_notification_days&.positive?
359
+ log_debug 'Maint: Not notifying admins of old pilots, unreleased_pilots_notification_days is not a positive integer'
360
+ return
361
+ end
362
+
363
+ log_info 'Maint: Notifying admins about old unreleased pilots'
309
364
 
310
- latest_vers_obj = instantiate_version title: title_obj, version: title_obj.latest_version
311
- return unless latest_vers_obj.pilot?
365
+ title_objects.each do |title_obj|
366
+ next unless title_obj.latest_version
312
367
 
313
- days_in_pilot = ((Time.now - latest_vers_obj.creation_date) / 86_400).to_i
368
+ latest_vers_obj = instantiate_version title: title_obj, version: title_obj.latest_version
369
+ next unless latest_vers_obj.pilot?
314
370
 
315
- return unless days_in_pilot > unreleased_pilots_notification_days
371
+ days_in_pilot = ((Time.now - latest_vers_obj.creation_date) / 86_400).to_i
316
372
 
317
- alert_msg = "Cleanup: Notifying #{title_obj.contact_email} about unreleased pilot '#{latest_vers}' of title '#{title_obj.title}', in pilot for #{days_in_pilot} days"
373
+ next unless days_in_pilot > unreleased_pilots_notification_days
318
374
 
319
- log_info alert_msg
320
- send_alert alert_msg
375
+ alert_msg = "Maint: Notifying #{title_obj.contact_email} about unreleased pilot '#{latest_vers}' of title '#{title_obj.title}', in pilot for #{days_in_pilot} days"
321
376
 
322
- email_msg = <<~MSG
377
+ log_info alert_msg
378
+ send_alert alert_msg
379
+
380
+ email_msg = <<~MSG
323
381
  The newest version '#{latest_vers_obj.version}' of title '#{title_obj.title}' has been in pilot for #{days_in_pilot} days, which makes it seem like it's not going to be released.
324
382
 
325
383
  To reduce clutter, please consider releasing it, deleting it, or deleting the whole title if it's no longer needed.
326
384
 
327
385
  If this is intentional, you can ignore this monthly message.
328
- MSG
329
- send_email to: title_obj.contact_email, subject: 'Unreleased Pilot Notification', msg: email_msg
386
+ MSG
387
+ send_email to: title_obj.contact_email, subject: 'Unreleased Pilot Notification', msg: email_msg
388
+ end # each title
389
+ log_info 'Maint: Done notifying admins about old unreleased pilots'
330
390
  end
331
391
 
332
392
  # how many days can a version be deprecated?
@@ -1450,7 +1450,7 @@ module Xolo
1450
1450
  jamf_patch_title.category = Xolo::Server::JAMF_XOLO_CATEGORY
1451
1451
  self.jamf_patch_title_id = jamf_patch_title.save
1452
1452
 
1453
- log_debug "Activated Jamf Patch Title '#{display_name}' (#{title}) with id #{jamf_patch_title_id}"
1453
+ log_debug "Jamf: Activated Jamf Patch Title '#{display_name}' (#{title}) with id #{jamf_patch_title_id}"
1454
1454
 
1455
1455
  jamf_patch_title
1456
1456
  end
@@ -1716,7 +1716,9 @@ module Xolo
1716
1716
  def add_title_to_self_service(pol = nil)
1717
1717
  pol ||= jamf_manual_install_released_policy
1718
1718
 
1719
- unless pol.in_self_service?
1719
+ if pol.in_self_service?
1720
+ progress "Jamf: Manual Install Policy '#{pol.name}' already in Self Service."
1721
+ else
1720
1722
  msg = "Jamf: Adding Manual Install Policy '#{pol.name}' to Self Service."
1721
1723
  progress msg, log: :info
1722
1724
  pol.add_to_self_service
@@ -939,14 +939,22 @@ module Xolo
939
939
  # explicit false
940
940
  ppol.patch_unknown = patch_unknown ? true : false
941
941
 
942
+ # Patch Pol. Scope Targets:
942
943
  # when first creating a patch policy, its status is always
943
944
  # 'pilot' so the scope targets are the pilot groups, if any.
945
+ #
944
946
  # When the version is released, the patch policy will be
945
- # rescoped to all targets (limited by eligibility)
946
- if pilot?
947
+ # rescoped to all computers (limited by eligibility)
948
+ #
949
+ # Any other state should have no scope targets
950
+ if pilot? || creating?
947
951
  set_policy_pilot_groups ppol
948
- else
952
+ elsif released? || releasing?
953
+ log_debug "Setting Patch Policy Scope for Version '#{version}' of Title '#{title}' to all comptuers, for release"
949
954
  ppol.scope.set_all_targets
955
+ else
956
+ log_debug "Setting Patch Policy Scope for Version '#{version}' of Title '#{title}' to no targets: not in pilot or released"
957
+ ppol.scope.set_targets :computer_groups, []
950
958
  end
951
959
 
952
960
  # exclusions are for always
@@ -1016,9 +1024,11 @@ module Xolo
1016
1024
  ppol.self_service_reminder_frequency = PATCH_POL_SSVC_REMINDER_FREQ_HRS
1017
1025
  ppol.deadline = PATCH_POL_SSVC_DEADLINE_DAYS
1018
1026
 
1019
- return unless title_object.ssvc_icon_id
1027
+ icon_id =
1028
+ title_object.ssvc_icon_id || title_object.jamf_manual_install_released_policy.self_service_icon.id
1029
+ return unless icon_id
1020
1030
 
1021
- set_patch_policy_ssvc_icon ppol, title_object.ssvc_icon_id
1031
+ set_patch_policy_ssvc_icon ppol, icon_id
1022
1032
 
1023
1033
  # Automatic deployment
1024
1034
  else
@@ -51,6 +51,7 @@ module Xolo
51
51
  start_time: Xolo::Server.start_time,
52
52
  uptime: uptime_secs.pix_humanize_secs,
53
53
  uptime_secs: uptime_secs,
54
+ last_maint: Xolo::Server::Helpers::Maintenance.last_maint,
54
55
  app_env: Xolo::Server.app_env,
55
56
  test_server: Xolo::Server.test_server?,
56
57
  data_dir: Xolo::Server::DATA_DIR,
@@ -435,7 +435,7 @@ module Xolo
435
435
  def jamf_patch_title_id
436
436
  return @jamf_patch_title_id if @jamf_patch_title_id
437
437
 
438
- log_debug "Getting jamf_patch_title_id for title '#{title}'"
438
+ log_debug "Jamf: Getting jamf_patch_title_id for title '#{title}'"
439
439
 
440
440
  self.jamf_patch_title_id =
441
441
  if managed?
@@ -1130,6 +1130,7 @@ module Xolo
1130
1130
  repair_ted_title
1131
1131
  set_subscribed_display_name_and_publisher
1132
1132
  repair_jamf_title_objects
1133
+ self.ssvc_icon_id = jamf_manual_install_released_policy.self_service_icon.id
1133
1134
  save_local_data
1134
1135
  return unless repair_versions
1135
1136
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xolo-server
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 2.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Lasell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-08-14 00:00:00.000000000 Z
11
+ date: 2026-08-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday