xolo-server 2.1.0 → 2.2.2
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 +4 -4
- data/data/client/xolo +16 -4
- data/data/com.pixar.xoloserver.plist +9 -2
- data/lib/xolo/core/base_classes/title.rb +113 -13
- data/lib/xolo/core/base_classes/version.rb +5 -6
- data/lib/xolo/core/exceptions.rb +3 -1
- data/lib/xolo/core/version.rb +1 -1
- data/lib/xolo/server/app.rb +1 -1
- data/lib/xolo/server/configuration.rb +4 -4
- data/lib/xolo/server/helpers/auth.rb +3 -3
- data/lib/xolo/server/helpers/maintenance.rb +194 -90
- data/lib/xolo/server/helpers/progress_streaming.rb +43 -10
- data/lib/xolo/server/mixins/title_jamf_access.rb +269 -51
- data/lib/xolo/server/mixins/version_jamf_access.rb +83 -34
- data/lib/xolo/server/routes/maint.rb +16 -15
- data/lib/xolo/server/routes/titles.rb +3 -0
- data/lib/xolo/server/routes.rb +1 -1
- data/lib/xolo/server/title.rb +28 -5
- data/lib/xolo/server/version.rb +71 -28
- metadata +2 -2
|
@@ -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,
|
|
@@ -80,29 +81,29 @@ module Xolo
|
|
|
80
81
|
body state
|
|
81
82
|
end
|
|
82
83
|
|
|
83
|
-
# run the
|
|
84
|
+
# run the maint process from the internal timer task
|
|
84
85
|
# The before filter will ensure the request came from the server itself.
|
|
85
86
|
# with a valid internal auth token.
|
|
86
87
|
################
|
|
87
|
-
post '/maint/
|
|
88
|
-
log_info 'Starting internal
|
|
89
|
-
session[:admin] = 'Automated
|
|
88
|
+
post '/maint/maint-internal' do
|
|
89
|
+
log_info 'Starting internal maint'
|
|
90
|
+
session[:admin] = 'Automated Maintenance'
|
|
90
91
|
|
|
91
|
-
thr = Thread.new {
|
|
92
|
-
thr.name = 'Internal
|
|
93
|
-
result = { result: 'Internal
|
|
92
|
+
thr = Thread.new { run_maint }
|
|
93
|
+
thr.name = 'Internal Maintenance Thread'
|
|
94
|
+
result = { result: 'Internal Maintenance Underway' }
|
|
94
95
|
body result
|
|
95
96
|
end
|
|
96
97
|
|
|
97
|
-
# run the
|
|
98
|
+
# run the maintenance process manually from a server admin via xadm
|
|
98
99
|
################
|
|
99
|
-
post '/maint/
|
|
100
|
-
log_info "Starting manual server
|
|
100
|
+
post '/maint/maint-start' do
|
|
101
|
+
log_info "Starting manual server maintenance by #{session[:admin]}"
|
|
101
102
|
|
|
102
|
-
session[:admin] = "
|
|
103
|
-
thr = Thread.new {
|
|
104
|
-
thr.name = 'Manual
|
|
105
|
-
result = { result: 'Manual
|
|
103
|
+
session[:admin] = "Maintenance by #{session[:admin]}"
|
|
104
|
+
thr = Thread.new { run_maint }
|
|
105
|
+
thr.name = 'Manual Maintenance Thread'
|
|
106
|
+
result = { result: 'Manual Maintenance Underway' }
|
|
106
107
|
body result
|
|
107
108
|
end
|
|
108
109
|
|
|
@@ -146,7 +147,7 @@ module Xolo
|
|
|
146
147
|
# Shutdown the server gracefully
|
|
147
148
|
# stop accepting new requests
|
|
148
149
|
# wait for all queues and threads to finish, including:
|
|
149
|
-
# the
|
|
150
|
+
# the maintenance timer task & mutex
|
|
150
151
|
# the log rotation timer task & mutex
|
|
151
152
|
# the pkg deletion pool
|
|
152
153
|
# the object locks
|
|
@@ -263,6 +263,9 @@ module Xolo
|
|
|
263
263
|
if title.jamf_title_active?
|
|
264
264
|
data[:jamf_patch_title_url] = title.jamf_patch_title_url unless title.jamf_patch_title_id.pix_empty?
|
|
265
265
|
data[:jamf_patch_ea_url] = title.jamf_patch_ea_url if title.version_script
|
|
266
|
+
|
|
267
|
+
data[:jamf_target_groups_exclusion_group_url] = title.jamf_target_groups_exclusion_group_url if title.jamf_target_groups_exclusion_group_exist?
|
|
268
|
+
|
|
266
269
|
end
|
|
267
270
|
|
|
268
271
|
body data
|
data/lib/xolo/server/routes.rb
CHANGED
|
@@ -127,7 +127,7 @@ module Xolo
|
|
|
127
127
|
@no_json = true
|
|
128
128
|
stream_file = Pathname.new params[:stream_file]
|
|
129
129
|
|
|
130
|
-
stream do |stream_out|
|
|
130
|
+
stream :keep_open do |stream_out|
|
|
131
131
|
stream_progress(stream_file: stream_file, stream: stream_out)
|
|
132
132
|
rescue => e
|
|
133
133
|
stream_out << "ERROR DURING PROGRESS STREAM: #{e.class}: #{e}"
|
data/lib/xolo/server/title.rb
CHANGED
|
@@ -77,6 +77,7 @@ module Xolo
|
|
|
77
77
|
JAMF_MANUAL_INSTALL_RELEASED_POL_SUFFIX = 'install'
|
|
78
78
|
JAMF_UNINSTALL_SUFFIX = 'uninstall'
|
|
79
79
|
JAMF_EXPIRE_SUFFIX = 'expire'
|
|
80
|
+
JAMF_TGT_GRP_EXCL_GRP_NAME_SUFFIX = 'target-group-exclusions'
|
|
80
81
|
|
|
81
82
|
# the expire policy will run this client command,
|
|
82
83
|
# appending the title
|
|
@@ -257,6 +258,20 @@ module Xolo
|
|
|
257
258
|
# @return [String] the name of the smart group
|
|
258
259
|
attr_reader :jamf_frozen_group_name
|
|
259
260
|
|
|
261
|
+
# If a title has 'target_groups', they act as the opposite of
|
|
262
|
+
# excluded groups - macs NOT in the target groups can't see the title.
|
|
263
|
+
#
|
|
264
|
+
# We implement this by maintaining a smart group
|
|
265
|
+
# named 'xolo-<title>-target-group-exclusions', which has the criteria:
|
|
266
|
+
# computerGroup...not a member of...<target-group>
|
|
267
|
+
# ANDed together for each target-group
|
|
268
|
+
# and then we use that smart group as an exclusion.
|
|
269
|
+
#
|
|
270
|
+
# This is the name of that smart group.
|
|
271
|
+
#
|
|
272
|
+
# @return [String] the name of the smart group
|
|
273
|
+
attr_reader :jamf_target_groups_exclusion_group_name
|
|
274
|
+
|
|
260
275
|
# The name of the policy that does initial manual or self-service
|
|
261
276
|
# installs of the currently-released version of this title.
|
|
262
277
|
# It will be named 'xolo-<title>-install'
|
|
@@ -354,6 +369,7 @@ module Xolo
|
|
|
354
369
|
@jamf_obj_name_pfx = "#{jamf_obj_name_pfx_base}#{data_hash[:title]}"
|
|
355
370
|
@jamf_installed_group_name = "#{jamf_obj_name_pfx}-#{JAMF_INSTALLED_GROUP_NAME_SUFFIX}"
|
|
356
371
|
@jamf_frozen_group_name = "#{jamf_obj_name_pfx}-#{JAMF_FROZEN_GROUP_NAME_SUFFIX}"
|
|
372
|
+
@jamf_target_groups_exclusion_group_name = "#{jamf_obj_name_pfx}-#{JAMF_TGT_GRP_EXCL_GRP_NAME_SUFFIX}"
|
|
357
373
|
|
|
358
374
|
@jamf_manual_install_released_policy_name = "#{jamf_obj_name_pfx}-#{JAMF_MANUAL_INSTALL_RELEASED_POL_SUFFIX}"
|
|
359
375
|
|
|
@@ -419,7 +435,7 @@ module Xolo
|
|
|
419
435
|
def jamf_patch_title_id
|
|
420
436
|
return @jamf_patch_title_id if @jamf_patch_title_id
|
|
421
437
|
|
|
422
|
-
log_debug "Getting jamf_patch_title_id for title '#{title}'"
|
|
438
|
+
log_debug "Jamf: Getting jamf_patch_title_id for title '#{title}'"
|
|
423
439
|
|
|
424
440
|
self.jamf_patch_title_id =
|
|
425
441
|
if managed?
|
|
@@ -615,7 +631,7 @@ module Xolo
|
|
|
615
631
|
end
|
|
616
632
|
|
|
617
633
|
# @return [Array<Xolo::Server::Version>] An array of all current version objects
|
|
618
|
-
# NOTE: This might not be wise if hundreds of versions, but automated
|
|
634
|
+
# NOTE: This might not be wise if hundreds of versions, but automated maintenance should
|
|
619
635
|
# help with that.
|
|
620
636
|
########################
|
|
621
637
|
def version_objects(refresh: false)
|
|
@@ -973,10 +989,16 @@ module Xolo
|
|
|
973
989
|
"Version '#{version_to_release}' of title '#{title}' is already released"
|
|
974
990
|
end
|
|
975
991
|
|
|
976
|
-
|
|
992
|
+
unless versions.include? version_to_release
|
|
993
|
+
raise Xolo::NoSuchItemError,
|
|
994
|
+
"No version '#{version_to_release}' for title '#{title}'"
|
|
995
|
+
end
|
|
996
|
+
|
|
997
|
+
jamf_patch_title(refresh: true)
|
|
998
|
+
return if jamf_patch_title.versions.key?(version_to_release)
|
|
977
999
|
|
|
978
|
-
raise Xolo::
|
|
979
|
-
"
|
|
1000
|
+
raise Xolo::TooSoonError,
|
|
1001
|
+
"Version '#{version_to_release}' of title '#{title}' is not yet visible to Jamf Pro. Please wait at least 10 minutes after adding it before releasing it. An alert notification will be sent when it is ready."
|
|
980
1002
|
end
|
|
981
1003
|
|
|
982
1004
|
# Update all versions when releasing one
|
|
@@ -1106,6 +1128,7 @@ module Xolo
|
|
|
1106
1128
|
|
|
1107
1129
|
progress "Starting repair of title '#{title}'"
|
|
1108
1130
|
repair_ted_title
|
|
1131
|
+
set_subscribed_display_name_and_publisher
|
|
1109
1132
|
repair_jamf_title_objects
|
|
1110
1133
|
save_local_data
|
|
1111
1134
|
return unless repair_versions
|
data/lib/xolo/server/version.rb
CHANGED
|
@@ -234,14 +234,38 @@ module Xolo
|
|
|
234
234
|
def self.add_version_via_subscription(title_object:, new_version:)
|
|
235
235
|
title_object.log_info "Adding new version '#{new_version}' for subscribed title '#{title_object.title}'"
|
|
236
236
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
unless
|
|
237
|
+
vobj_data = new_subscribed_version_data(title_object: title_object, new_version: new_version)
|
|
238
|
+
|
|
239
|
+
unless vobj_data
|
|
240
240
|
msg = "Could not get patch version data from JPAPI for version '#{new_version}' of subscribed title '#{title_object.title}'. Cannot create new version in Xolo without this data. Aborting."
|
|
241
241
|
title_object.log_error msg, alert: true
|
|
242
242
|
return
|
|
243
243
|
end
|
|
244
244
|
|
|
245
|
+
# instantiate the version object
|
|
246
|
+
title_object.log_debug "Instantiating version via subscription '#{new_version}' of title '#{title_object.title}' (#{title_object.class}) with data: #{vobj_data}"
|
|
247
|
+
|
|
248
|
+
vobj = title_object.server_app_instance.instantiate_version(
|
|
249
|
+
title: title_object,
|
|
250
|
+
version: new_version,
|
|
251
|
+
**vobj_data
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
# create it in xolo
|
|
255
|
+
vobj.create
|
|
256
|
+
|
|
257
|
+
# tell someone
|
|
258
|
+
send_alerts_about_new_subscribed_version(title_object: title_object, vobj: vobj)
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# Gather the data needed to create a new xolo version from a subscription
|
|
262
|
+
# @return [Hash] the data needed to create the version object
|
|
263
|
+
################
|
|
264
|
+
def self.new_subscribed_version_data(title_object:, new_version:)
|
|
265
|
+
patch_version_data = title_object.patch_versions(version: new_version).first
|
|
266
|
+
# return nil if not found - will send error alert
|
|
267
|
+
return unless patch_version_data
|
|
268
|
+
|
|
245
269
|
title_object.log_debug "Got patch version data from JPAPI for version '#{new_version}': #{patch_version_data}"
|
|
246
270
|
|
|
247
271
|
# put the data into a hash for creating a new version object
|
|
@@ -269,34 +293,47 @@ module Xolo
|
|
|
269
293
|
end
|
|
270
294
|
end
|
|
271
295
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
vobj = title_object.server_app_instance.instantiate_version(
|
|
276
|
-
title: title_object,
|
|
277
|
-
version: new_version,
|
|
278
|
-
**vobj_data
|
|
279
|
-
)
|
|
280
|
-
|
|
281
|
-
# create it in xolo
|
|
282
|
-
vobj.create
|
|
283
|
-
|
|
284
|
-
# moved to vobj.create:
|
|
285
|
-
# vobj.server_app_instance.update_client_data
|
|
296
|
+
vobj_data
|
|
297
|
+
end
|
|
286
298
|
|
|
287
|
-
|
|
288
|
-
|
|
299
|
+
# Handle alerts for newly-created subscribed version
|
|
300
|
+
##################
|
|
301
|
+
def self.send_alerts_about_new_subscribed_version(title_object:, vobj:)
|
|
302
|
+
title = title_object.title
|
|
303
|
+
new_version = vobj.version
|
|
304
|
+
|
|
305
|
+
# if here, and auto_release_delay is zero, release it immediately
|
|
306
|
+
if title_object.autopkg_enabled?
|
|
307
|
+
|
|
308
|
+
auto_release_delay = title_object.auto_release_delay.to_i
|
|
309
|
+
|
|
310
|
+
# is auto_release_delay an integer?
|
|
311
|
+
if title_object.auto_release_delay&.pix_integer? && !auto_release_delay.negative?
|
|
312
|
+
how_soon =
|
|
313
|
+
if auto_release_delay.zero?
|
|
314
|
+
'tonight'
|
|
315
|
+
elsif auto_release_delay == 1
|
|
316
|
+
'tomorrow night'
|
|
317
|
+
else
|
|
318
|
+
"in #{auto_release_delayy} days"
|
|
319
|
+
end
|
|
320
|
+
msg = "New pilot for subscribed title '#{title}', version '#{new_version}' has been created in Xolo via subscription.\nIt will be released during nightly maintenance #{how_soon}"
|
|
321
|
+
|
|
322
|
+
# nil, empty, 'none', or negative = no auto release
|
|
323
|
+
else
|
|
324
|
+
msg = "ACTION REQUIRED: New pilot for subscribed title '#{title}', version '#{new_version}' has been created in Xolo via subscription.\nRequires manual release."
|
|
325
|
+
end
|
|
289
326
|
|
|
290
327
|
# if not autopkg enabled, we need to tell someone to upload a pkg for this new version
|
|
291
|
-
|
|
328
|
+
else
|
|
292
329
|
# update general alert msg
|
|
293
|
-
msg = "#{
|
|
330
|
+
msg = "ACTION REQUIRED: New pilot for subscribed title '#{title}', version '#{new_version}' has been created in Xolo via subscription.\nPlease upload a .pkg for it ASAP using this command:\n xadm edit-version #{title} #{new_version} --pkg-to-upload /path/to/installer.pkg"
|
|
294
331
|
|
|
295
332
|
# email to title contact
|
|
296
333
|
vobj.server_app_instance.send_email to: title_object.contact_email, subject: 'Need manual upload of xolo pkg', msg: msg
|
|
297
334
|
end # if title_object.autopkg_enabled?
|
|
298
335
|
|
|
299
|
-
# send
|
|
336
|
+
# send alert
|
|
300
337
|
vobj.log_info msg, alert: true
|
|
301
338
|
end
|
|
302
339
|
|
|
@@ -488,6 +525,7 @@ module Xolo
|
|
|
488
525
|
# this title.
|
|
489
526
|
#
|
|
490
527
|
# Excluded groups are defined in the title, applying to all versions, and may be augmented by:
|
|
528
|
+
# - A smart group of computers NOT in the target_groups, if any target groups are defined.
|
|
491
529
|
# - Xolo::Server.config.forced_exclusion, a group excluded from ALL of xolo, defined
|
|
492
530
|
# in the server config.
|
|
493
531
|
# - The title's jamf_frozen_group_name, if it exists, containing computers that have been
|
|
@@ -506,14 +544,17 @@ module Xolo
|
|
|
506
544
|
return @excluded_groups_to_use if @excluded_groups_to_use
|
|
507
545
|
|
|
508
546
|
ttl_obj ||= title_object
|
|
509
|
-
# get the excluded groups from the title
|
|
510
|
-
# Use .dup so we don't modify the original
|
|
511
|
-
@excluded_groups_to_use = ttl_obj.changes_for_update&.key?(:excluded_groups) ? ttl_obj.changes_for_update[:excluded_groups][:new].dup : ttl_obj.excluded_groups.dup
|
|
512
547
|
|
|
513
548
|
# always exclude the frozen static group
|
|
514
549
|
# calling ttl_obj.jamf_frozen_group will create the group if needed
|
|
515
|
-
@excluded_groups_to_use
|
|
516
|
-
log_debug "
|
|
550
|
+
@excluded_groups_to_use = [ttl_obj.jamf_frozen_group.name]
|
|
551
|
+
log_debug "Added '#{ttl_obj.jamf_frozen_group_name}' to @excluded_groups_to_use"
|
|
552
|
+
|
|
553
|
+
# get the excluded groups from the title
|
|
554
|
+
@excluded_groups_to_use += ttl_obj.changes_for_update&.key?(:excluded_groups) ? ttl_obj.changes_for_update[:excluded_groups][:new] : ttl_obj.excluded_groups
|
|
555
|
+
|
|
556
|
+
# add the jamf_target_groups_exclusion_group - it must have been created before now
|
|
557
|
+
@excluded_groups_to_use << ttl_obj.jamf_target_groups_exclusion_group_name if ttl_obj.use_jamf_target_groups_exclusion_group?
|
|
517
558
|
|
|
518
559
|
# always exclude Xolo::Server.config.forced_exclusion if defined
|
|
519
560
|
@excluded_groups_to_use << valid_forced_exclusion_group_name if valid_forced_exclusion_group_name
|
|
@@ -858,6 +899,7 @@ module Xolo
|
|
|
858
899
|
msg = "Jamf: Version '#{version}': Setting scope targets of patch policy to all eligible computers"
|
|
859
900
|
progress msg, log: :info
|
|
860
901
|
ppol = jamf_patch_policy
|
|
902
|
+
ppol.enable
|
|
861
903
|
ppol.scope.set_all_targets
|
|
862
904
|
|
|
863
905
|
# if rollback, make sure the patch policy is set to 'allow downgrade'
|
|
@@ -1017,7 +1059,8 @@ module Xolo
|
|
|
1017
1059
|
log_change msg: 'Version Deleted'
|
|
1018
1060
|
|
|
1019
1061
|
progress "Version '#{version}' of Title '#{title}' has been deleted from Xolo.", log: :info
|
|
1020
|
-
|
|
1062
|
+
|
|
1063
|
+
server_app_instance.update_client_data unless deleting_title
|
|
1021
1064
|
ensure
|
|
1022
1065
|
unlock
|
|
1023
1066
|
end
|
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.
|
|
4
|
+
version: 2.2.2
|
|
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-
|
|
11
|
+
date: 2026-08-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|