xolo-server 1.0.0 → 2.0.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/README.md +42 -4
- data/bin/xoloserver +3 -0
- data/data/client/xolo +1233 -0
- data/lib/optimist_with_insert_blanks.rb +1216 -0
- data/lib/xolo/core/base_classes/configuration.rb +238 -0
- data/lib/xolo/core/base_classes/server_object.rb +112 -0
- data/lib/xolo/core/base_classes/title.rb +884 -0
- data/lib/xolo/core/base_classes/version.rb +641 -0
- data/lib/xolo/core/constants.rb +85 -0
- data/lib/xolo/core/exceptions.rb +52 -0
- data/lib/xolo/core/json_wrappers.rb +43 -0
- data/lib/xolo/core/loading.rb +59 -0
- data/lib/xolo/core/output.rb +292 -0
- data/lib/xolo/core/security_cmd.rb +128 -0
- data/lib/xolo/core/version.rb +21 -0
- data/lib/xolo/core.rb +47 -0
- data/lib/xolo/server/app.rb +7 -0
- data/lib/xolo/server/configuration.rb +243 -38
- data/lib/xolo/server/constants.rb +10 -0
- data/lib/xolo/server/helpers/auth.rb +19 -2
- data/lib/xolo/server/helpers/autopkg.rb +157 -0
- data/lib/xolo/server/helpers/client_data.rb +90 -60
- data/lib/xolo/server/helpers/file_transfers.rb +412 -82
- data/lib/xolo/server/helpers/jamf_pro.rb +31 -7
- data/lib/xolo/server/helpers/log.rb +2 -0
- data/lib/xolo/server/helpers/maintenance.rb +1 -0
- data/lib/xolo/server/helpers/notification.rb +4 -3
- data/lib/xolo/server/helpers/pkg_signing.rb +16 -12
- data/lib/xolo/server/helpers/progress_streaming.rb +9 -12
- data/lib/xolo/server/helpers/subscriptions.rb +119 -0
- data/lib/xolo/server/helpers/titles.rb +27 -3
- data/lib/xolo/server/helpers/versions.rb +23 -11
- data/lib/xolo/server/mixins/changelog.rb +9 -16
- data/lib/xolo/server/mixins/title_jamf_access.rb +375 -390
- data/lib/xolo/server/mixins/title_ted_access.rb +50 -8
- data/lib/xolo/server/mixins/version_jamf_access.rb +118 -129
- data/lib/xolo/server/mixins/version_ted_access.rb +34 -4
- data/lib/xolo/server/object_locks.rb +2 -1
- data/lib/xolo/server/routes/auth.rb +2 -2
- data/lib/xolo/server/routes/jamf_pro.rb +11 -1
- data/lib/xolo/server/routes/maint.rb +2 -1
- data/lib/xolo/server/routes/subscriptions.rb +126 -0
- data/lib/xolo/server/routes/title_editor.rb +1 -1
- data/lib/xolo/server/routes/titles.rb +26 -11
- data/lib/xolo/server/routes/uploads.rb +0 -14
- data/lib/xolo/server/routes/versions.rb +14 -13
- data/lib/xolo/server/routes.rb +15 -23
- data/lib/xolo/server/title.rb +100 -77
- data/lib/xolo/server/version.rb +178 -18
- data/lib/xolo/server.rb +8 -0
- metadata +20 -11
|
@@ -60,13 +60,16 @@ module Xolo
|
|
|
60
60
|
# @return [void]
|
|
61
61
|
################################
|
|
62
62
|
def create_title_in_jamf
|
|
63
|
-
|
|
63
|
+
log_debug "Display Name in create_title_in_jamf: #{display_name}"
|
|
64
64
|
|
|
65
|
-
# create the
|
|
66
|
-
|
|
65
|
+
# create/activate the Jamf::PatchTitle
|
|
66
|
+
# this notes the jamf id of the PatchTitle
|
|
67
|
+
# and sets the display name if needed for subbed titles
|
|
68
|
+
jamf_patch_title
|
|
67
69
|
|
|
68
|
-
#
|
|
69
|
-
|
|
70
|
+
# This creates the installed group
|
|
71
|
+
# must happen after activating the title in jamf
|
|
72
|
+
jamf_installed_group
|
|
70
73
|
|
|
71
74
|
if uninstall_script || !uninstall_ids.pix_empty?
|
|
72
75
|
configure_jamf_uninstall_script
|
|
@@ -82,7 +85,10 @@ module Xolo
|
|
|
82
85
|
# Just calling this will create it if it doesn't exist.
|
|
83
86
|
jamf_frozen_group
|
|
84
87
|
|
|
85
|
-
|
|
88
|
+
# This either notifies, or does it
|
|
89
|
+
# TODO: EAs for subscribed titles can change at any time and need
|
|
90
|
+
# re-accepted - Notifications must happen.
|
|
91
|
+
accept_jamf_patch_ea
|
|
86
92
|
end
|
|
87
93
|
|
|
88
94
|
# Apply any changes to Jamf as needed
|
|
@@ -94,14 +100,6 @@ module Xolo
|
|
|
94
100
|
def update_title_in_jamf
|
|
95
101
|
# ORDER MATTERS
|
|
96
102
|
|
|
97
|
-
# do we have a version_script? if so we maintain a 'normal' EA
|
|
98
|
-
# this has to happen before updating the installed_group
|
|
99
|
-
configure_jamf_normal_ea if need_to_update_jamf_normal_ea?
|
|
100
|
-
|
|
101
|
-
# this smart group might use the normal-EA or might use app data
|
|
102
|
-
# If those have changed, we need to update it.
|
|
103
|
-
configure_jamf_installed_group if need_to_update_jamf_installed_group?
|
|
104
|
-
|
|
105
103
|
# if the exclusions have changed update the manual install released policy
|
|
106
104
|
if changes_for_update[:excluded_groups]
|
|
107
105
|
progress "Jamf: Updating excluded groups for Manual Released Policy '#{jamf_manual_install_released_policy_name}'."
|
|
@@ -110,7 +108,6 @@ module Xolo
|
|
|
110
108
|
|
|
111
109
|
# Do we need to update (vs delete) the uninstall script?
|
|
112
110
|
if need_to_update_jamf_uninstall_script?
|
|
113
|
-
|
|
114
111
|
configure_jamf_uninstall_script
|
|
115
112
|
configure_jamf_uninstall_policy
|
|
116
113
|
|
|
@@ -122,7 +119,6 @@ module Xolo
|
|
|
122
119
|
elsif need_to_delete_jamf_uninstall_script?
|
|
123
120
|
delete_jamf_uninstall_policy
|
|
124
121
|
delete_jamf_uninstall_script
|
|
125
|
-
# can't expire without
|
|
126
122
|
end
|
|
127
123
|
|
|
128
124
|
# Do we need to add or delete the expire policy?
|
|
@@ -132,16 +128,11 @@ module Xolo
|
|
|
132
128
|
changes_for_update.dig(:expiration, :new).to_i.positive? ? jamf_expire_policy : delete_jamf_expire_policy
|
|
133
129
|
end
|
|
134
130
|
|
|
135
|
-
# If we don't use a version script anymore, delete the normal EA
|
|
136
|
-
# this has to happen after updating the installed_group
|
|
137
|
-
delete_jamf_normal_ea unless version_script_contents
|
|
138
|
-
|
|
139
131
|
update_description_in_jamf
|
|
140
132
|
update_ssvc
|
|
141
|
-
update_ssvc_category
|
|
142
133
|
# TODO: deal with icon changes: if changes_for_update&.key? :self_service_icon
|
|
143
134
|
|
|
144
|
-
if
|
|
135
|
+
if jamf_title_active?
|
|
145
136
|
update_versions_for_title_changes_in_jamf
|
|
146
137
|
else
|
|
147
138
|
log_debug "Jamf: Title '#{display_name}' (#{title}) is not yet active to Jamf, nothing to update in versions."
|
|
@@ -151,7 +142,6 @@ module Xolo
|
|
|
151
142
|
# Repair this title in Jamf Pro
|
|
152
143
|
# - TODO: activate title in patch mgmt
|
|
153
144
|
# - TODO: Accept Patch EA
|
|
154
|
-
# - Normal EA 'xolo-<title>-installed-version'
|
|
155
145
|
# - title-installed smart group 'xolo-<title>-installed'
|
|
156
146
|
# - frozen static group 'xolo-<title>-frozen'
|
|
157
147
|
# - manual/SSvc install-current-release policy 'xolo-<title>-install'
|
|
@@ -169,7 +159,7 @@ module Xolo
|
|
|
169
159
|
###############################################
|
|
170
160
|
def repair_jamf_title_objects
|
|
171
161
|
progress "Jamf: Repairing Jamf objects for title '#{title}'", log: :info
|
|
172
|
-
|
|
162
|
+
|
|
173
163
|
configure_jamf_installed_group
|
|
174
164
|
repair_jamf_uninstall_policy
|
|
175
165
|
repair_jamf_uninstall_script
|
|
@@ -187,10 +177,32 @@ module Xolo
|
|
|
187
177
|
delete_jamf_uninstall_policy
|
|
188
178
|
delete_jamf_manual_install_released_policy
|
|
189
179
|
delete_jamf_uninstall_script
|
|
190
|
-
|
|
180
|
+
delete_lingering_policies_for_title
|
|
181
|
+
sleep 5
|
|
182
|
+
|
|
183
|
+
# must delete this group before the patch title
|
|
184
|
+
# since the group criteria references the patch title
|
|
191
185
|
delete_jamf_installed_group
|
|
192
|
-
|
|
186
|
+
sleep 5
|
|
187
|
+
|
|
193
188
|
delete_jamf_patch_title
|
|
189
|
+
|
|
190
|
+
# static group deleted last,
|
|
191
|
+
# was used in scopes for patch and normal policies
|
|
192
|
+
delete_jamf_frozen_group
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
################################
|
|
196
|
+
def delete_lingering_policies_for_title
|
|
197
|
+
Jamf::Policy.all_names(:refresh, cnx: jamf_cnx).each do |polname|
|
|
198
|
+
next unless polname.start_with? jamf_obj_name_pfx
|
|
199
|
+
|
|
200
|
+
polid = Jamf::Policy.valid_id(polname, cnx: jamf_cnx)
|
|
201
|
+
next unless polid
|
|
202
|
+
|
|
203
|
+
progress "Jamf: Deleting lingering policy #{polname}, possibly from a failed version action.", log: :info
|
|
204
|
+
Jamf::Policy.delete(polid, cnx: jamf_cnx)
|
|
205
|
+
end
|
|
194
206
|
end
|
|
195
207
|
|
|
196
208
|
# If any title changes require updates to existing versions in
|
|
@@ -211,8 +223,6 @@ module Xolo
|
|
|
211
223
|
vers_obj.update_release_groups(ttl_obj: self) if changes_for_update&.key? :release_groups
|
|
212
224
|
vers_obj.update_excluded_groups(ttl_obj: self) if changes_for_update&.key? :excluded_groups
|
|
213
225
|
vers_obj.update_jamf_package_notes(ttl_obj: self) if need_to_update_description?
|
|
214
|
-
# vers_obj.update_ssvc(ttl_obj: self) if changes_for_update&.key? :self_service
|
|
215
|
-
# vers_obj.update_ssvc_category(ttl_obj: self) if changes_for_update&.key? :self_service_category
|
|
216
226
|
end
|
|
217
227
|
end
|
|
218
228
|
|
|
@@ -300,125 +310,6 @@ module Xolo
|
|
|
300
310
|
report
|
|
301
311
|
end
|
|
302
312
|
|
|
303
|
-
####### The'Normal" Extension Attribute
|
|
304
|
-
###########################################
|
|
305
|
-
###########################################
|
|
306
|
-
|
|
307
|
-
# @return [Boolean] Does the 'normal' EA exist in jamf?
|
|
308
|
-
#########################
|
|
309
|
-
def jamf_normal_ea_exist?
|
|
310
|
-
Jamf::ComputerExtensionAttribute.all_names(:refresh, cnx: jamf_cnx).include? jamf_normal_ea_name
|
|
311
|
-
end
|
|
312
|
-
|
|
313
|
-
# Create or fetch the 'normal' EA in jamf
|
|
314
|
-
# If we are deleting and it doesn't exist, return nil.
|
|
315
|
-
#
|
|
316
|
-
# @return [Jamf::ComputerExtensionAttribute] The 'normal' Jamf ComputerExtensionAttribute for this title
|
|
317
|
-
########################
|
|
318
|
-
def jamf_normal_ea
|
|
319
|
-
return @jamf_normal_ea if @jamf_normal_ea
|
|
320
|
-
|
|
321
|
-
if jamf_normal_ea_exist?
|
|
322
|
-
@jamf_normal_ea = Jamf::ComputerExtensionAttribute.fetch(name: jamf_normal_ea_name, cnx: jamf_cnx)
|
|
323
|
-
|
|
324
|
-
else
|
|
325
|
-
return if deleting?
|
|
326
|
-
|
|
327
|
-
msg = "Jamf: Creating regular extension attribute '#{jamf_normal_ea_name}' for use in smart groups"
|
|
328
|
-
progress msg, log: :info
|
|
329
|
-
|
|
330
|
-
@jamf_normal_ea = Jamf::ComputerExtensionAttribute.create(
|
|
331
|
-
name: jamf_normal_ea_name,
|
|
332
|
-
cnx: jamf_cnx
|
|
333
|
-
)
|
|
334
|
-
@jamf_normal_ea.save
|
|
335
|
-
|
|
336
|
-
end
|
|
337
|
-
@jamf_normal_ea
|
|
338
|
-
end
|
|
339
|
-
|
|
340
|
-
# Configure the 'normal' EA that matches the Patch EA for this title,
|
|
341
|
-
# so that it can be used in smart groups and adv. searches.
|
|
342
|
-
# (Patch EAs aren't available for use in smart group critera)
|
|
343
|
-
#
|
|
344
|
-
# If we have one already but are deleting it, that happens elsewhere
|
|
345
|
-
#
|
|
346
|
-
# @return [void]
|
|
347
|
-
################################
|
|
348
|
-
def configure_jamf_normal_ea
|
|
349
|
-
progress "Jamf: Configuring regular extension attribute '#{jamf_normal_ea_name}'", log: :info
|
|
350
|
-
|
|
351
|
-
jamf_normal_ea.description = "The version of xolo title '#{title}' installed on the machine"
|
|
352
|
-
jamf_normal_ea.data_type = :string
|
|
353
|
-
|
|
354
|
-
# this is our incoming or already-existing EA script
|
|
355
|
-
if version_script_contents.pix_empty?
|
|
356
|
-
# nothing to do if its nil, if we need to delete it, that'll happen later
|
|
357
|
-
else
|
|
358
|
-
jamf_normal_ea.enabled = true
|
|
359
|
-
jamf_normal_ea.input_type = 'script'
|
|
360
|
-
jamf_normal_ea.script = version_script_contents
|
|
361
|
-
end
|
|
362
|
-
|
|
363
|
-
jamf_normal_ea.script = scr
|
|
364
|
-
jamf_normal_ea.save
|
|
365
|
-
end
|
|
366
|
-
|
|
367
|
-
# Repair the 'normal' EA in jamf to match our version_script
|
|
368
|
-
########################
|
|
369
|
-
def repair_jamf_normal_ea
|
|
370
|
-
if version_script_contents.pix_empty?
|
|
371
|
-
delete_jamf_normal_ea
|
|
372
|
-
else
|
|
373
|
-
configure_jamf_normal_ea
|
|
374
|
-
end
|
|
375
|
-
end
|
|
376
|
-
|
|
377
|
-
# Delete the 'normal' computer ext attr matching the Patch EA
|
|
378
|
-
# @return [void]
|
|
379
|
-
######################################
|
|
380
|
-
def delete_jamf_normal_ea
|
|
381
|
-
ea_id = Jamf::ComputerExtensionAttribute.valid_id jamf_normal_ea_name, cnx: jamf_cnx
|
|
382
|
-
return unless ea_id
|
|
383
|
-
|
|
384
|
-
progress "Jamf: Deleting regular extension attribute '#{jamf_normal_ea_name}'", log: :info
|
|
385
|
-
Jamf::ComputerExtensionAttribute.delete ea_id, cnx: jamf_cnx
|
|
386
|
-
end
|
|
387
|
-
|
|
388
|
-
# do we need to update the normal EA in jamf?
|
|
389
|
-
# true if our incoming changes include :version_script
|
|
390
|
-
# and the new value is not empty (in which case we'll delete it)
|
|
391
|
-
#
|
|
392
|
-
# @return [Boolean]
|
|
393
|
-
########################
|
|
394
|
-
def need_to_update_jamf_normal_ea?
|
|
395
|
-
changes_for_update.key?(:version_script) && !changes_for_update[:version_script][:new].pix_empty?
|
|
396
|
-
end
|
|
397
|
-
|
|
398
|
-
# the script contents of the Normal Jamf EA that comes from our version_script
|
|
399
|
-
# @return [String, nil] nil if there is none
|
|
400
|
-
##############################
|
|
401
|
-
def jamf_normal_ea_contents
|
|
402
|
-
return unless jamf_normal_ea_exist?
|
|
403
|
-
|
|
404
|
-
jamf_normal_ea.script
|
|
405
|
-
end
|
|
406
|
-
|
|
407
|
-
# @return [String] the URL for the Normal EA in Jamf Pro
|
|
408
|
-
######################
|
|
409
|
-
def jamf_normal_ea_url
|
|
410
|
-
return @jamf_normal_ea_url if @jamf_normal_ea_url
|
|
411
|
-
return unless version_script
|
|
412
|
-
|
|
413
|
-
ea_id = Jamf::ComputerExtensionAttribute.valid_id jamf_normal_ea_name, cnx: jamf_cnx
|
|
414
|
-
return unless ea_id
|
|
415
|
-
|
|
416
|
-
# Jamf Changed the URL!
|
|
417
|
-
# @jamf_normal_ea_url = "#{jamf_gui_url}/computerExtensionAttributes.html?id=#{ea_id}&o=r"
|
|
418
|
-
|
|
419
|
-
@jamf_normal_ea_url = "#{jamf_gui_url}/view/settings/computer-management/computer-extension-attributes/#{ea_id}"
|
|
420
|
-
end
|
|
421
|
-
|
|
422
313
|
####### The Patch Ext Attribute
|
|
423
314
|
###########################################
|
|
424
315
|
###########################################
|
|
@@ -437,6 +328,8 @@ module Xolo
|
|
|
437
328
|
# @return [Boolean]
|
|
438
329
|
#########################
|
|
439
330
|
def need_to_accept_jamf_patch_ea?
|
|
331
|
+
return unless managed?
|
|
332
|
+
|
|
440
333
|
@need_to_accept_jamf_patch_ea
|
|
441
334
|
end
|
|
442
335
|
|
|
@@ -462,16 +355,22 @@ module Xolo
|
|
|
462
355
|
# @return [void]
|
|
463
356
|
############################
|
|
464
357
|
def accept_jamf_patch_ea
|
|
465
|
-
|
|
358
|
+
# give the server a moment to catch up with the new EA before we check on it
|
|
359
|
+
log_debug "Jamf: Checking if we need to accept the version-script EA for title '#{title}'"
|
|
360
|
+
sleep 5
|
|
361
|
+
|
|
362
|
+
awating_acceptance = jamf_patch_ea_awaiting_acceptance?
|
|
466
363
|
|
|
467
|
-
# return with warning if we aren't auto-accepting
|
|
468
|
-
|
|
469
|
-
msg = "Jamf: IMPORTANT:
|
|
470
|
-
progress msg
|
|
364
|
+
# return with warning if we aren't auto-accepting, or for all subscribed titles
|
|
365
|
+
if awating_acceptance && (subscribed? || !Xolo::Server.config.jamf_auto_accept_xolo_eas)
|
|
366
|
+
msg = "Jamf: IMPORTANT: The Extension Attribute (version-script) for title '#{title}' must be accepted manually in Jamf Pro at #{jamf_patch_ea_url} under the 'Extension Attribute' tab (click 'Edit'). If you cannot do this yourself, please contact your Xolo server admins for assistance. Deployment will not happen until this is done."
|
|
367
|
+
progress msg, log: :warn, alert: true
|
|
471
368
|
log_debug 'Admin informed about accepting EA/version-script manually'
|
|
472
369
|
return
|
|
473
370
|
end
|
|
474
371
|
|
|
372
|
+
return unless need_to_accept_jamf_patch_ea?
|
|
373
|
+
|
|
475
374
|
# this is true if the Jamf server already knows it needs to be accepted
|
|
476
375
|
# so just do it now
|
|
477
376
|
if jamf_patch_ea_awaiting_acceptance?
|
|
@@ -612,6 +511,8 @@ module Xolo
|
|
|
612
511
|
end
|
|
613
512
|
|
|
614
513
|
# API call to accept the version-script EA in Jamf Pro
|
|
514
|
+
# This never happens for subscribed titles
|
|
515
|
+
#
|
|
615
516
|
# TODO: when this gets implemented in ruby-jss, use that implementation
|
|
616
517
|
#
|
|
617
518
|
# @return [void]
|
|
@@ -645,7 +546,7 @@ module Xolo
|
|
|
645
546
|
######################
|
|
646
547
|
def jamf_patch_ea_url
|
|
647
548
|
return @jamf_patch_ea_url if @jamf_patch_ea_url
|
|
648
|
-
return unless version_script
|
|
549
|
+
return unless version_script || (subscribed? && jamf_patch_ea_data)
|
|
649
550
|
|
|
650
551
|
@jamf_patch_ea_url = "#{jamf_patch_title_url}?tab=extension"
|
|
651
552
|
end
|
|
@@ -791,7 +692,10 @@ module Xolo
|
|
|
791
692
|
pol.add_script jamf_uninstall_script_name
|
|
792
693
|
pol.set_trigger_event :checkin, false
|
|
793
694
|
pol.set_trigger_event :custom, jamf_uninstall_policy_name
|
|
794
|
-
pol.scope.add_target(:computer_group, jamf_installed_group_name)
|
|
695
|
+
# pol.scope.add_target(:computer_group, jamf_installed_group_name)
|
|
696
|
+
# all targets, cus jamf doesn't like some policies with scoped
|
|
697
|
+
# smart groups using 'latest version'
|
|
698
|
+
pol.scope.set_all_targets
|
|
795
699
|
pol.scope.set_exclusions :computer_groups, [valid_forced_exclusion_group_name] if valid_forced_exclusion_group_name
|
|
796
700
|
pol.frequency = :ongoing
|
|
797
701
|
pol.enable
|
|
@@ -809,7 +713,6 @@ module Xolo
|
|
|
809
713
|
end
|
|
810
714
|
|
|
811
715
|
# delete the policy first if it exists
|
|
812
|
-
|
|
813
716
|
#########################
|
|
814
717
|
def delete_jamf_uninstall_policy
|
|
815
718
|
return unless jamf_uninstall_policy_exist?
|
|
@@ -866,9 +769,9 @@ module Xolo
|
|
|
866
769
|
)
|
|
867
770
|
@jamf_installed_group.save
|
|
868
771
|
configure_jamf_installed_group
|
|
869
|
-
|
|
870
|
-
sleep 10
|
|
772
|
+
|
|
871
773
|
end
|
|
774
|
+
|
|
872
775
|
@jamf_installed_group
|
|
873
776
|
end
|
|
874
777
|
|
|
@@ -881,75 +784,34 @@ module Xolo
|
|
|
881
784
|
|
|
882
785
|
jamf_installed_group.criteria = Jamf::Criteriable::Criteria.new(jamf_installed_group_criteria)
|
|
883
786
|
jamf_installed_group.save
|
|
787
|
+
log_debug 'Jamf: Sleeping 30 secs to let Jamf server see changes to Installed smart group.'
|
|
788
|
+
sleep 30
|
|
884
789
|
end
|
|
885
790
|
|
|
886
791
|
# The criteria for the smart group in Jamf that contains all Macs
|
|
887
792
|
# with any version of this title installed
|
|
888
793
|
#
|
|
889
|
-
#
|
|
890
|
-
#
|
|
794
|
+
# We use the "Patch Reporting: #{display_name}" criterion so that we don't
|
|
795
|
+
# care whether the title uses a version-script or app data.
|
|
891
796
|
#
|
|
892
797
|
# @return [Array<Jamf::Criteriable::Criterion>]
|
|
893
798
|
###################################
|
|
894
799
|
def jamf_installed_group_criteria
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
)
|
|
911
|
-
]
|
|
912
|
-
|
|
913
|
-
# No version script, so we must be using app data
|
|
914
|
-
else
|
|
915
|
-
aname = changes_for_update.dig(:app_name, :new) || app_name
|
|
916
|
-
abundle = changes_for_update.dig(:app_bundle_id, :new) || app_bundle_id
|
|
917
|
-
|
|
918
|
-
[
|
|
919
|
-
Jamf::Criteriable::Criterion.new(
|
|
920
|
-
and_or: :and,
|
|
921
|
-
name: 'Application Title',
|
|
922
|
-
search_type: 'is',
|
|
923
|
-
value: aname
|
|
924
|
-
),
|
|
925
|
-
|
|
926
|
-
Jamf::Criteriable::Criterion.new(
|
|
927
|
-
and_or: :and,
|
|
928
|
-
name: 'Application Bundle ID',
|
|
929
|
-
search_type: 'is',
|
|
930
|
-
value: abundle
|
|
931
|
-
)
|
|
932
|
-
]
|
|
933
|
-
end
|
|
934
|
-
end
|
|
935
|
-
|
|
936
|
-
# do we need to update the 'installed' smart group?
|
|
937
|
-
# true if our incoming changes include the app_name or app_bundle_id
|
|
938
|
-
#
|
|
939
|
-
# If they changed at all, we need to update no matter what:
|
|
940
|
-
# - if they are now nil, we switched to a version script
|
|
941
|
-
#
|
|
942
|
-
# - if they aren't nil but are different, we need to update
|
|
943
|
-
# the group criteria to reflect that.
|
|
944
|
-
#
|
|
945
|
-
# Changes to the version script, if it was in use before, don't
|
|
946
|
-
# require us to change the smart group
|
|
947
|
-
#
|
|
948
|
-
#
|
|
949
|
-
# @return [Boolean]
|
|
950
|
-
#########################
|
|
951
|
-
def need_to_update_jamf_installed_group?
|
|
952
|
-
changes_for_update[:app_name] || changes_for_update[:app_bundle_id]
|
|
800
|
+
[
|
|
801
|
+
Jamf::Criteriable::Criterion.new(
|
|
802
|
+
and_or: :and,
|
|
803
|
+
name: "Patch Reporting: #{display_name}",
|
|
804
|
+
search_type: 'less than or equal',
|
|
805
|
+
value: 'Latest Version'
|
|
806
|
+
),
|
|
807
|
+
|
|
808
|
+
Jamf::Criteriable::Criterion.new(
|
|
809
|
+
and_or: :or,
|
|
810
|
+
name: "Patch Reporting: #{display_name}",
|
|
811
|
+
search_type: 'is',
|
|
812
|
+
value: 'Unknown Version'
|
|
813
|
+
)
|
|
814
|
+
]
|
|
953
815
|
end
|
|
954
816
|
|
|
955
817
|
# Delete the 'installed' smart group
|
|
@@ -1244,14 +1106,15 @@ module Xolo
|
|
|
1244
1106
|
#
|
|
1245
1107
|
# @return [Jamf::PatchSource] The Jamf Patch Source
|
|
1246
1108
|
#########################
|
|
1247
|
-
def
|
|
1248
|
-
@
|
|
1109
|
+
def jamf_managed_patch_source
|
|
1110
|
+
@jamf_managed_patch_source ||=
|
|
1249
1111
|
Jamf::PatchSource.fetch(name: Xolo::Server.config.ted_patch_source, cnx: jamf_cnx)
|
|
1250
1112
|
end
|
|
1251
1113
|
|
|
1252
1114
|
# The titles available from the Title Editor via its
|
|
1253
|
-
# Jamf Patch Source.
|
|
1254
|
-
# in the Title Editor
|
|
1115
|
+
# Jamf Patch Source.
|
|
1116
|
+
# These are titles have have been enabled in the Title Editor
|
|
1117
|
+
# but have not yet been activated in Jamf Patch.
|
|
1255
1118
|
#
|
|
1256
1119
|
# available_titles returns a Hash for each available title, with these keys:
|
|
1257
1120
|
#
|
|
@@ -1271,93 +1134,79 @@ module Xolo
|
|
|
1271
1134
|
#
|
|
1272
1135
|
# @return [Array<String>] info about the available titles
|
|
1273
1136
|
#########################
|
|
1274
|
-
def
|
|
1137
|
+
def jamf_available_managed_titles
|
|
1275
1138
|
# Don't cache this in an instance var, it changes during the
|
|
1276
1139
|
# life of our title instance
|
|
1277
|
-
#
|
|
1140
|
+
# jamf_managed_patch_source.available_titles.map { |t| t[:name_id] }
|
|
1278
1141
|
# Also NOTE: "available" means not only enabled
|
|
1279
1142
|
# in the title editor, but also not already active in jamf.
|
|
1280
1143
|
# So any given title will either be here or in
|
|
1281
|
-
#
|
|
1282
|
-
|
|
1144
|
+
# jamf_active_managed_titles, but never both.
|
|
1145
|
+
jamf_managed_patch_source.available_name_ids
|
|
1283
1146
|
end
|
|
1284
1147
|
|
|
1285
1148
|
# @return [Boolean] Is this xolo title available in Jamf?
|
|
1286
1149
|
########################
|
|
1287
|
-
def
|
|
1288
|
-
|
|
1289
|
-
end
|
|
1290
|
-
|
|
1291
|
-
# The titles active in Jamf Patch Management from the Title Editor
|
|
1292
|
-
# This takes into account that other Patch Sources may have titles with the
|
|
1293
|
-
# same 'name_id' (the xolo 'title')
|
|
1294
|
-
# A hash keyed by the title, with values of the jamf title id
|
|
1295
|
-
#
|
|
1296
|
-
# @return [Hash {String => Integer}] The xolo titles that are active in Jamf Patch Management
|
|
1297
|
-
########################
|
|
1298
|
-
def jamf_active_ted_titles(refresh: false)
|
|
1299
|
-
@jamf_active_ted_titles = nil if refresh
|
|
1300
|
-
return @jamf_active_ted_titles if @jamf_active_ted_titles
|
|
1301
|
-
|
|
1302
|
-
@jamf_active_ted_titles = {}
|
|
1303
|
-
active_from_ted = Jamf::PatchTitle.all(:refresh, cnx: jamf_cnx).select do |t|
|
|
1304
|
-
t[:source_id] == jamf_ted_patch_source.id
|
|
1305
|
-
end
|
|
1306
|
-
active_from_ted.each { |t| @jamf_active_ted_titles[t[:name_id]] = t[:id] }
|
|
1307
|
-
@jamf_active_ted_titles
|
|
1150
|
+
def jamf_managed_title_available?
|
|
1151
|
+
jamf_available_managed_titles.include? title
|
|
1308
1152
|
end
|
|
1309
1153
|
|
|
1310
1154
|
# @return [Boolean] Is this xolo title currently active in Jamf?
|
|
1311
1155
|
########################
|
|
1312
|
-
def
|
|
1313
|
-
|
|
1156
|
+
def jamf_title_active?
|
|
1157
|
+
!jamf_patch_title_id.pix_empty?
|
|
1158
|
+
# if subscribed?
|
|
1159
|
+
# jamf_active_subscribed_titles(refresh: true).key? title
|
|
1160
|
+
# else
|
|
1161
|
+
# jamf_active_managed_titles(refresh: true).key? title
|
|
1162
|
+
# end
|
|
1314
1163
|
end
|
|
1315
1164
|
|
|
1316
|
-
# The
|
|
1317
|
-
#
|
|
1165
|
+
# The managed titles active in Jamf Patch Management from the Title Editor
|
|
1166
|
+
# A hash keyed by the title, with values of the jamf patch title id
|
|
1318
1167
|
#
|
|
1319
|
-
# @return [Integer
|
|
1168
|
+
# @return [Hash {String => Integer}] The managed xolo titles that are active in Jamf Patch Management
|
|
1169
|
+
# and their Jamf::PatchTitle id
|
|
1320
1170
|
########################
|
|
1321
|
-
def
|
|
1322
|
-
@
|
|
1323
|
-
|
|
1171
|
+
def jamf_active_managed_titles(refresh: false)
|
|
1172
|
+
@jamf_active_managed_titles = nil if refresh
|
|
1173
|
+
return @jamf_active_managed_titles if @jamf_active_managed_titles
|
|
1324
1174
|
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
# This 'subscribes' Jamf to the title in the title editor
|
|
1328
|
-
# It must be enabled in the Title Editor first, meaning
|
|
1329
|
-
# it has at least one requirement, and at least one enabled patch/version.
|
|
1330
|
-
#
|
|
1331
|
-
# The 'stub' patch version should allow this when we create the title.
|
|
1332
|
-
#
|
|
1333
|
-
# Xolo should have enabled it in the Title editor before we
|
|
1334
|
-
# reach this point.
|
|
1335
|
-
#
|
|
1336
|
-
##########################
|
|
1337
|
-
def activate_jamf_patch_title
|
|
1338
|
-
if jamf_ted_title_active?
|
|
1339
|
-
log_debug "Jamf: Title '#{display_name}' (#{title}) is already active in Jamf"
|
|
1340
|
-
return
|
|
1341
|
-
end
|
|
1175
|
+
@jamf_active_managed_titles = {}
|
|
1176
|
+
all_patch_titles = Jamf::PatchTitle.all(cnx: jamf_cnx)
|
|
1342
1177
|
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
log_debug "Jamf: Waiting for title '#{display_name}' (#{title}) to become available from the Title Editor"
|
|
1347
|
-
sleep 5
|
|
1348
|
-
counter += 1
|
|
1178
|
+
active_from_ted = all_patch_titles.select do |t|
|
|
1179
|
+
# log_debug "Jamf: Checking if active patch title '#{t[:name]}' with id #{t[:id]} is from the Title Editor's patch source"
|
|
1180
|
+
t[:source_id] == jamf_managed_patch_source.id
|
|
1349
1181
|
end
|
|
1350
1182
|
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1183
|
+
managed_titles = server_app_instance.managed_title_objects.select(&:managed?).map(&:title)
|
|
1184
|
+
|
|
1185
|
+
active_from_ted.each do |t|
|
|
1186
|
+
@jamf_active_managed_titles[t[:name_id]] = t[:id] if managed_titles.include? t[:name_id]
|
|
1355
1187
|
end
|
|
1188
|
+
@jamf_active_managed_titles
|
|
1189
|
+
end
|
|
1356
1190
|
|
|
1357
|
-
|
|
1358
|
-
|
|
1191
|
+
# @return [Hash {String => Integer}] The subscribed xolo titles that are active in Jamf Patch Management
|
|
1192
|
+
# and their Jamf::PatchTitle id
|
|
1193
|
+
########################
|
|
1194
|
+
def jamf_active_subscribed_titles(refresh: false)
|
|
1195
|
+
@jamf_active_subscribed_titles = nil if refresh
|
|
1196
|
+
return @jamf_active_subscribed_titles if @jamf_active_subscribed_titles
|
|
1359
1197
|
|
|
1360
|
-
|
|
1198
|
+
@jamf_active_subscribed_titles = {}
|
|
1199
|
+
|
|
1200
|
+
all_active_patchtitles = Jamf::PatchTitle.all :refresh, cnx: jamf_cnx
|
|
1201
|
+
|
|
1202
|
+
server_app_instance.subscribed_title_objects.each do |st|
|
|
1203
|
+
next unless all_active_patchtitles.any? do |pt|
|
|
1204
|
+
pt[:source_id] == st.jamf_patch_source_id && pt[:name_id] == st.title_id
|
|
1205
|
+
end
|
|
1206
|
+
|
|
1207
|
+
@jamf_active_subscribed_titles[st.title] = pt[:id]
|
|
1208
|
+
end
|
|
1209
|
+
@jamf_active_subscribed_titles
|
|
1361
1210
|
end
|
|
1362
1211
|
|
|
1363
1212
|
# Create or fetch the patch title object for this xolo title.
|
|
@@ -1370,52 +1219,118 @@ module Xolo
|
|
|
1370
1219
|
@jamf_patch_title = nil if refresh
|
|
1371
1220
|
return @jamf_patch_title if @jamf_patch_title
|
|
1372
1221
|
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
raise Xolo::ServerError,
|
|
1377
|
-
"Jamf: Title '#{title}' is not available in Jamf after waiting #{Xolo::Server::MAX_JAMF_WAIT_FOR_TITLE_EDITOR} seconds"
|
|
1378
|
-
end
|
|
1379
|
-
|
|
1380
|
-
log_debug "Waiting a long time for title '#{title}' to become available from TEd. Checking every 10 secs"
|
|
1381
|
-
sleep 10
|
|
1382
|
-
end
|
|
1222
|
+
# wait up to 60secs for a managed title to become available.
|
|
1223
|
+
# subscribed titles are already available
|
|
1224
|
+
wait_for_managed_title_to_become_available
|
|
1383
1225
|
|
|
1384
|
-
|
|
1226
|
+
# Jamf::PatchTitle object already active, just fetch it
|
|
1227
|
+
if jamf_patch_title_id # jamf_title_active? || subscribed?
|
|
1385
1228
|
@jamf_patch_title = Jamf::PatchTitle.fetch(id: jamf_patch_title_id, cnx: jamf_cnx)
|
|
1386
1229
|
|
|
1230
|
+
# not yet active, so activate/create the Jamf::PatchTitle object
|
|
1387
1231
|
else
|
|
1388
1232
|
return if deleting?
|
|
1389
1233
|
|
|
1390
|
-
|
|
1391
|
-
|
|
1234
|
+
@jamf_patch_title = activate_jamf_patch_title
|
|
1235
|
+
end
|
|
1236
|
+
end
|
|
1392
1237
|
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1238
|
+
# activate the patch title in jamf, whatever it's source
|
|
1239
|
+
############################
|
|
1240
|
+
def activate_jamf_patch_title
|
|
1241
|
+
if jamf_title_active?
|
|
1242
|
+
log_debug "Jamf: Title '#{title}' is already active in Jamf Patch"
|
|
1243
|
+
return
|
|
1244
|
+
end
|
|
1245
|
+
|
|
1246
|
+
# patch_source and title_id are required when adding subbed titles
|
|
1247
|
+
# but pre-defined for managed
|
|
1248
|
+
if managed?
|
|
1249
|
+
log_debug "Jamf: Title '#{title}' is managed, so using pre-defined patch source and title_id"
|
|
1250
|
+
log_debug "Jamf: Display Name in managed?: #{display_name}"
|
|
1251
|
+
self.patch_source = Xolo::Server.config.ted_patch_source
|
|
1252
|
+
self.title_id = title
|
|
1253
|
+
log_debug "Jamf: Display Name in managed? after setting patch_source and title_id: #{display_name}"
|
|
1254
|
+
|
|
1255
|
+
# display name is required for managed titles, but will be empty for subbed
|
|
1256
|
+
# so for subbed, we look it up from the patch source
|
|
1257
|
+
else
|
|
1258
|
+
log_debug "Jamf: Title '#{title}' is subscribed, so looking up patch source and title_id from"
|
|
1259
|
+
log_debug "Jamf: Display Name in NOT managed?: #{display_name}"
|
|
1260
|
+
if display_name.pix_empty?
|
|
1261
|
+
self.display_name = Jamf::PatchSource.available_titles(patch_source, cnx: jamf_cnx).select { |t| t[:name_id] == title_id }.first&.dig :app_name
|
|
1262
|
+
end
|
|
1263
|
+
end # if managed
|
|
1264
|
+
|
|
1265
|
+
log_debug "Jamf: class: #{self.class}, display_name: #{display_name}, patch_source: #{patch_source}, title_id: #{title_id}"
|
|
1266
|
+
|
|
1267
|
+
msg = "Jamf: Activating Patch Title '#{display_name}' (#{title}) from the Patch Source '#{patch_source}'"
|
|
1268
|
+
progress msg, log: :info
|
|
1402
1269
|
|
|
1270
|
+
jamf_patch_title =
|
|
1271
|
+
Jamf::PatchTitle.create(
|
|
1272
|
+
name: display_name,
|
|
1273
|
+
source: patch_source,
|
|
1274
|
+
name_id: title_id,
|
|
1275
|
+
cnx: jamf_cnx
|
|
1276
|
+
)
|
|
1277
|
+
jamf_patch_title.category = Xolo::Server::JAMF_XOLO_CATEGORY
|
|
1278
|
+
self.jamf_patch_title_id = jamf_patch_title.save
|
|
1279
|
+
log_debug "Activated Jamf Patch Title '#{display_name}' (#{title}) with id #{jamf_patch_title_id}"
|
|
1280
|
+
|
|
1281
|
+
jamf_patch_title
|
|
1282
|
+
end
|
|
1283
|
+
|
|
1284
|
+
# wait up to 60secs for a managed title to become available to be activated
|
|
1285
|
+
# subscribed titles are already available
|
|
1286
|
+
####################
|
|
1287
|
+
def wait_for_managed_title_to_become_available
|
|
1288
|
+
return unless managed?
|
|
1289
|
+
return if jamf_title_active?
|
|
1290
|
+
|
|
1291
|
+
counter = 0
|
|
1292
|
+
until jamf_title_active? || jamf_managed_title_available? || counter == 12
|
|
1293
|
+
log_debug "Jamf: Waiting for title '#{display_name}' (#{title}) to become available from the Title Editor"
|
|
1294
|
+
sleep 5
|
|
1295
|
+
counter += 1
|
|
1403
1296
|
end
|
|
1404
|
-
|
|
1297
|
+
|
|
1298
|
+
return if jamf_managed_title_available? || jamf_title_active?
|
|
1299
|
+
|
|
1300
|
+
msg = "Jamf: Title '#{title}' is not yet available to Jamf. Make sure it has at least one version enabled in the Title Editor"
|
|
1301
|
+
log_error msg
|
|
1302
|
+
raise Xolo::NoSuchItemError, msg
|
|
1405
1303
|
end
|
|
1406
1304
|
|
|
1407
1305
|
# Delete the patch title
|
|
1408
1306
|
# NOTE: jamf api user must have 'delete computer ext. attribs' permmissions
|
|
1409
1307
|
##############################
|
|
1410
1308
|
def delete_jamf_patch_title
|
|
1411
|
-
|
|
1309
|
+
log_debug "Jamf: Deleting patch title '#{display_name}' (#{title})"
|
|
1310
|
+
unless jamf_title_active?
|
|
1311
|
+
log_debug "Jamf: Patch title '#{display_name}' (#{title}) is not active in Jamf, nothing to delete"
|
|
1312
|
+
return
|
|
1313
|
+
end
|
|
1412
1314
|
|
|
1413
|
-
|
|
1414
|
-
|
|
1315
|
+
# # subscribed titles often have name_id's like "1B7"
|
|
1316
|
+
# # whereas managed titles have name_id's that are the same as the title,
|
|
1317
|
+
# # so we have to look up the id differently for subbed vs managed
|
|
1318
|
+
# key = subscribed? ? title_id : title
|
|
1319
|
+
# pt_id = Jamf::PatchTitle.map_all(:id, to: :name_id, cnx: jamf_cnx).invert[key]
|
|
1415
1320
|
|
|
1416
|
-
|
|
1321
|
+
# unless pt_id
|
|
1322
|
+
# log_debug "Jamf: Cannot find patch title '#{display_name}' (#{title}) in Jamf, cannot delete"
|
|
1323
|
+
# return
|
|
1324
|
+
# end
|
|
1325
|
+
|
|
1326
|
+
# # the pt_id SHOULD match the jamf_patch_title_id we have stored, but just in case, we'll use the one we looked up here
|
|
1327
|
+
# unless pt_id.to_s == jamf_patch_title_id.to_s
|
|
1328
|
+
# log_warn "Jamf: Stored patch title id #{jamf_patch_title_id} does not match id #{pt_id} looked up for '#{display_name}' (#{title}). We are deleting the stored id."
|
|
1329
|
+
# end
|
|
1330
|
+
|
|
1331
|
+
msg = "Jamf: Deleting (deactivating) title '#{display_name}' (#{title}}) in Jamf Patch Management"
|
|
1417
1332
|
progress msg, log: :info
|
|
1418
|
-
Jamf::PatchTitle.delete
|
|
1333
|
+
Jamf::PatchTitle.delete jamf_patch_title_id, cnx: jamf_cnx
|
|
1419
1334
|
end
|
|
1420
1335
|
|
|
1421
1336
|
# @return [String] the URL for the Patch Title in Jamf Pro
|
|
@@ -1481,6 +1396,7 @@ module Xolo
|
|
|
1481
1396
|
end
|
|
1482
1397
|
|
|
1483
1398
|
# Configure the settings for the manual_install_released_policy
|
|
1399
|
+
# Be sure to call .save on the policy after this to save the changes.
|
|
1484
1400
|
# @param pol [Jamf::Policy] the policy we are configuring
|
|
1485
1401
|
# @return [void]
|
|
1486
1402
|
###################
|
|
@@ -1495,15 +1411,7 @@ module Xolo
|
|
|
1495
1411
|
# clear any existing packages
|
|
1496
1412
|
pol.package_names.each { |pkg_name| pol.remove_package pkg_name }
|
|
1497
1413
|
|
|
1498
|
-
|
|
1499
|
-
desired_vers = releasing_version || released_version
|
|
1500
|
-
if desired_vers
|
|
1501
|
-
rel_vers = version_object(desired_vers)
|
|
1502
|
-
pol.add_package rel_vers.jamf_pkg_id
|
|
1503
|
-
pol.enable
|
|
1504
|
-
else
|
|
1505
|
-
pol.disable
|
|
1506
|
-
end
|
|
1414
|
+
toggle_jamf_manual_install_released_policy pol
|
|
1507
1415
|
|
|
1508
1416
|
# figure out the exclusions.
|
|
1509
1417
|
#
|
|
@@ -1519,12 +1427,36 @@ module Xolo
|
|
|
1519
1427
|
|
|
1520
1428
|
pol.scope.set_exclusions :computer_groups, excls
|
|
1521
1429
|
|
|
1522
|
-
|
|
1430
|
+
if self_service?
|
|
1431
|
+
add_title_to_self_service(pol)
|
|
1432
|
+
else
|
|
1433
|
+
remove_title_from_self_service(pol)
|
|
1434
|
+
end
|
|
1435
|
+
end
|
|
1523
1436
|
|
|
1524
|
-
|
|
1525
|
-
|
|
1437
|
+
# enable or disable the manual install policy for the current release, depending on
|
|
1438
|
+
# whether or not we have a released version
|
|
1439
|
+
# @param pol [Jamf::Policy] the manual install policy for the current release, which may or may not be saved yet.
|
|
1440
|
+
# return [void]
|
|
1441
|
+
############################
|
|
1442
|
+
def toggle_jamf_manual_install_released_policy(pol, vobj = nil)
|
|
1443
|
+
# remove any current pkg payload
|
|
1444
|
+
pol.package_ids.each { |pid| pol.remove_package pid }
|
|
1445
|
+
|
|
1446
|
+
unless vobj
|
|
1447
|
+
desired_vers = releasing_version || released_version
|
|
1448
|
+
vobj = desired_vers ? version_object(desired_vers) : nil
|
|
1449
|
+
end
|
|
1450
|
+
|
|
1451
|
+
if vobj
|
|
1452
|
+
progress "Jamf: Setting policy #{jamf_manual_install_released_policy_name} to install the package for version '#{vobj.version}'", log: :info
|
|
1453
|
+
pol.add_package vobj.jamf_pkg_id
|
|
1454
|
+
|
|
1455
|
+
progress "Jamf: Enabling policy #{jamf_manual_install_released_policy_name}", log: :info
|
|
1456
|
+
pol.enable
|
|
1526
1457
|
else
|
|
1527
|
-
|
|
1458
|
+
progress "Jamf: Disabling policy #{jamf_manual_install_released_policy_name}, no released version", log: :info
|
|
1459
|
+
pol.disable
|
|
1528
1460
|
end
|
|
1529
1461
|
end
|
|
1530
1462
|
|
|
@@ -1554,111 +1486,164 @@ module Xolo
|
|
|
1554
1486
|
# @return [void]
|
|
1555
1487
|
##################################
|
|
1556
1488
|
def add_title_to_self_service(pol = nil)
|
|
1557
|
-
return unless self_service
|
|
1558
|
-
|
|
1559
1489
|
pol ||= jamf_manual_install_released_policy
|
|
1560
1490
|
|
|
1561
|
-
|
|
1562
|
-
|
|
1491
|
+
unless pol.in_self_service?
|
|
1492
|
+
msg = "Jamf: Adding Manual Install Policy '#{pol.name}' to Self Service."
|
|
1493
|
+
progress msg, log: :info
|
|
1494
|
+
pol.add_to_self_service
|
|
1495
|
+
end
|
|
1563
1496
|
|
|
1564
|
-
pol.add_to_self_service
|
|
1565
1497
|
configure_pol_for_self_service(pol)
|
|
1498
|
+
pol.save
|
|
1566
1499
|
end
|
|
1567
1500
|
|
|
1568
|
-
#
|
|
1569
|
-
#
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
pol = jamf_manual_install_released_policy
|
|
1576
|
-
return unless pol
|
|
1501
|
+
# Add the jamf_manual_install_released_policy to self service if needed
|
|
1502
|
+
# @param pol [Jamf::Policy] The jamf_manual_install_released_policy, which may not be saved yet.
|
|
1503
|
+
# @return [void]
|
|
1504
|
+
##################################
|
|
1505
|
+
def remove_title_from_self_service(pol = nil)
|
|
1506
|
+
pol ||= jamf_manual_install_released_policy
|
|
1507
|
+
return unless pol.in_self_service?
|
|
1577
1508
|
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1509
|
+
msg = "Jamf: Removing Manual Install Policy '#{pol.name}' from Self Service."
|
|
1510
|
+
progress msg, log: :info
|
|
1511
|
+
pol.remove_from_self_service
|
|
1581
1512
|
|
|
1582
|
-
# we should not be in SSvc
|
|
1583
|
-
elsif pol.in_self_service?
|
|
1584
|
-
msg = "Jamf: Removing Manual Install Policy '#{pol.name}' from Self Service."
|
|
1585
|
-
progress msg, log: :info
|
|
1586
|
-
pol.remove_from_self_service
|
|
1587
|
-
end
|
|
1588
1513
|
pol.save
|
|
1589
|
-
|
|
1590
|
-
# TODO: if we decide to use ssvc in patch policies, loop thru versions to make any changes
|
|
1591
1514
|
end
|
|
1592
1515
|
|
|
1593
|
-
# Update
|
|
1594
|
-
# TODO: Allow multiple categories, and 'featuring' ?
|
|
1516
|
+
# Update whether or not we are in self service, based on the setting in the title
|
|
1595
1517
|
#
|
|
1596
1518
|
#########################
|
|
1597
|
-
def
|
|
1598
|
-
return unless changes_for_update.key? :self_service_category
|
|
1599
|
-
|
|
1519
|
+
def update_ssvc
|
|
1600
1520
|
pol = jamf_manual_install_released_policy
|
|
1601
|
-
return unless pol
|
|
1602
1521
|
|
|
1603
|
-
|
|
1522
|
+
adding_to_ssvc = changes_for_update.dig :self_service, :new
|
|
1604
1523
|
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
)
|
|
1524
|
+
updating_config = changes_for_update.dig :self_service_category, :new
|
|
1525
|
+
updating_config ||= changes_for_update.dig :description, :new
|
|
1526
|
+
updating_config ||= changes_for_update.dig :display_name, :new
|
|
1609
1527
|
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
pol.save
|
|
1528
|
+
# if adding_to_ssvc is nil, we aren't changing it at all
|
|
1529
|
+
# it must be false to indicate removal.
|
|
1530
|
+
removing_from_ssvc = adding_to_ssvc == false
|
|
1614
1531
|
|
|
1615
|
-
|
|
1616
|
-
|
|
1532
|
+
if adding_to_ssvc
|
|
1533
|
+
add_title_to_self_service(pol)
|
|
1617
1534
|
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
# @param ttl_obj [Xolo::Server::Title] The pre-instantiated title for ths version.
|
|
1621
|
-
# if nil, we'll instantiate it now
|
|
1622
|
-
#
|
|
1623
|
-
# @return [void]
|
|
1624
|
-
###############################
|
|
1625
|
-
def update_ssvc_icon(ttl_obj: nil)
|
|
1626
|
-
ttl_obj ||= title_object
|
|
1627
|
-
# update manual install policy
|
|
1535
|
+
elsif updating_config
|
|
1536
|
+
configure_pol_for_self_service(pol)
|
|
1628
1537
|
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1538
|
+
# we should not be in SSvc, remove it, but leave all the settings
|
|
1539
|
+
elsif removing_from_ssvc
|
|
1540
|
+
remove_title_from_self_service(pol)
|
|
1541
|
+
end
|
|
1632
1542
|
|
|
1633
|
-
pol.
|
|
1634
|
-
progress "Jamf: Updated Icon for Manual Install Policy '#{jamf_manual_install_policy_name}'",
|
|
1635
|
-
log: :debug
|
|
1543
|
+
pol.save
|
|
1636
1544
|
|
|
1637
|
-
# TODO:
|
|
1638
|
-
# ssvc - they will need to be updated also
|
|
1545
|
+
# TODO: if we decide to use ssvc in patch policies, loop thru versions to make any changes
|
|
1639
1546
|
end
|
|
1640
1547
|
|
|
1641
1548
|
# configure the self-service settings of the manual_install_released_policy
|
|
1549
|
+
# NOTE this doesn't actually add it to self service, just configures the settings
|
|
1550
|
+
# See add_title_to_self_service
|
|
1551
|
+
#
|
|
1642
1552
|
# @param pol [Jamf::Policy] The jamf_manual_install_released_policy, which may not be saved yet.
|
|
1643
1553
|
# @return [void]
|
|
1644
1554
|
############################
|
|
1645
1555
|
def configure_pol_for_self_service(pol = nil)
|
|
1646
1556
|
pol ||= jamf_manual_install_released_policy
|
|
1647
1557
|
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1558
|
+
new_cat = changes_for_update&.dig(:self_service_category, :new) || self_service_category
|
|
1559
|
+
if new_cat
|
|
1560
|
+
progress "Jamf: Setting Self Service category to '#{new_cat}'", log: :debug
|
|
1561
|
+
# clear existing categories, re-add correct one
|
|
1562
|
+
pol.self_service_categories.each { |cat| pol.remove_self_service_category cat }
|
|
1563
|
+
pol.add_self_service_category new_cat if new_cat
|
|
1564
|
+
end
|
|
1565
|
+
|
|
1566
|
+
new_display_name = changes_for_update&.dig(:self_service_display_name, :new) || display_name
|
|
1567
|
+
progress "Jamf: Setting Self Service display name to '#{new_display_name}'", log: :debug
|
|
1568
|
+
pol.self_service_display_name = new_display_name
|
|
1569
|
+
|
|
1570
|
+
new_desc = changes_for_update&.dig(:self_service_description, :new) || description
|
|
1571
|
+
progress "Jamf: Setting Self Service description to '#{new_desc}'", log: :debug
|
|
1572
|
+
pol.self_service_description = new_desc
|
|
1651
1573
|
|
|
1652
|
-
pol.self_service_description = description
|
|
1653
|
-
pol.self_service_display_name = display_name
|
|
1654
1574
|
pol.self_service_install_button_text = Xolo::Server::Title::SELF_SERVICE_INSTALL_BTN_TEXT
|
|
1655
1575
|
return unless ssvc_icon_file
|
|
1656
1576
|
|
|
1577
|
+
progress 'Jamf: Uploading Self Service icon', log: :debug
|
|
1657
1578
|
pol.save # won't do anything unless needed, but has to exist before we can upload icons
|
|
1658
1579
|
pol.upload :icon, ssvc_icon_file
|
|
1580
|
+
# re-fetch the pol to get the icon id
|
|
1659
1581
|
self.ssvc_icon_id = Jamf::Policy.fetch(id: pol.id, cnx: jamf_cnx).icon.id
|
|
1660
1582
|
end
|
|
1661
1583
|
|
|
1584
|
+
# run the autopkg recipe if defined
|
|
1585
|
+
# See Helpers::AutoPkg for more details
|
|
1586
|
+
############################
|
|
1587
|
+
def run_autopkg_recipe
|
|
1588
|
+
server_app_instance.run_autopkg_recipe self
|
|
1589
|
+
end
|
|
1590
|
+
|
|
1591
|
+
# Methods used by subscription stuff
|
|
1592
|
+
##############################
|
|
1593
|
+
|
|
1594
|
+
# Returns an array of known patch versions for this title from Jamf
|
|
1595
|
+
# These are not necessarily in xolo, but they are available from the Patch Source.
|
|
1596
|
+
#
|
|
1597
|
+
# One or more Hashes like this:
|
|
1598
|
+
# {
|
|
1599
|
+
# "version": "143.0.7499.170",
|
|
1600
|
+
# "releaseDate": "2025-12-18T20:31:01Z",
|
|
1601
|
+
# "standalone": true,
|
|
1602
|
+
# "minimumOperatingSystem": "12.0",
|
|
1603
|
+
# "rebootRequired": false,
|
|
1604
|
+
# "killApps": [
|
|
1605
|
+
# {
|
|
1606
|
+
# "appName": "Google Chrome"
|
|
1607
|
+
# }
|
|
1608
|
+
# ],
|
|
1609
|
+
# "absoluteOrderId": "0"
|
|
1610
|
+
# }
|
|
1611
|
+
#
|
|
1612
|
+
# @param version [String, Symbol, nil] If a string, only return info about that version, if :latest,
|
|
1613
|
+
# only the latest version, otherwise all available versions known by the patch source.
|
|
1614
|
+
#
|
|
1615
|
+
# @param refresh [Boolean] re-read the data from the Jamf Pro API
|
|
1616
|
+
#
|
|
1617
|
+
# @return [Array<Hash>] Data about available patch versions for this title
|
|
1618
|
+
################################
|
|
1619
|
+
def patch_versions(version: nil, refresh: false)
|
|
1620
|
+
@patch_versions = nil if refresh
|
|
1621
|
+
@patch_versions ||= []
|
|
1622
|
+
|
|
1623
|
+
if @patch_versions.empty?
|
|
1624
|
+
page = 0
|
|
1625
|
+
loop do
|
|
1626
|
+
jpapi_path = "#{Xolo::Server::JPAPI_PATCH_TITLE_ENDPOINT}/#{jamf_patch_title_id}/definitions?page=#{page}&page-size=1000&sort=absoluteOrderId%3Aasc"
|
|
1627
|
+
log_debug "Jamf: Fetching patch versions for title '#{title}' from Jamf API endpoint '#{jpapi_path}'"
|
|
1628
|
+
|
|
1629
|
+
data = jamf_cnx.jp_get jpapi_path
|
|
1630
|
+
break if data[:results].empty?
|
|
1631
|
+
|
|
1632
|
+
@patch_versions += data[:results]
|
|
1633
|
+
page += 1
|
|
1634
|
+
end # loop
|
|
1635
|
+
end # if
|
|
1636
|
+
|
|
1637
|
+
case version
|
|
1638
|
+
when nil
|
|
1639
|
+
@patch_versions
|
|
1640
|
+
when :latest
|
|
1641
|
+
@patch_versions.select { |p| p[:absoluteOrderId] == '0' }
|
|
1642
|
+
else
|
|
1643
|
+
@patch_versions.select { |p| p[:version] == version }
|
|
1644
|
+
end # case
|
|
1645
|
+
end # patch_versions
|
|
1646
|
+
|
|
1662
1647
|
end # TitleJamfPro
|
|
1663
1648
|
|
|
1664
1649
|
end # Mixins
|