xolo-server 1.0.1 → 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/data/client/xolo +152 -79
- data/lib/xolo/core/base_classes/title.rb +254 -18
- data/lib/xolo/core/base_classes/version.rb +47 -7
- data/lib/xolo/core/constants.rb +7 -3
- data/lib/xolo/core/security_cmd.rb +128 -0
- data/lib/xolo/core/version.rb +1 -1
- data/lib/xolo/core.rb +1 -0
- data/lib/xolo/server/app.rb +7 -0
- data/lib/xolo/server/configuration.rb +243 -37
- 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 +30 -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 -385
- data/lib/xolo/server/mixins/title_ted_access.rb +29 -3
- data/lib/xolo/server/mixins/version_jamf_access.rb +95 -112
- data/lib/xolo/server/mixins/version_ted_access.rb +25 -0
- 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 +9 -0
- data/lib/xolo/server/title.rb +100 -77
- data/lib/xolo/server/version.rb +177 -15
- data/lib/xolo/server.rb +8 -0
- metadata +7 -9
|
@@ -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,120 +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
|
-
# nothing to do if its nil, if we need to delete it, that'll happen later
|
|
350
|
-
return if version_script_contents.pix_empty?
|
|
351
|
-
|
|
352
|
-
progress "Jamf: Configuring regular extension attribute '#{jamf_normal_ea_name}'", log: :info
|
|
353
|
-
|
|
354
|
-
jamf_normal_ea.description = "The version of xolo title '#{title}' installed on the machine"
|
|
355
|
-
jamf_normal_ea.data_type = 'String'
|
|
356
|
-
jamf_normal_ea.input_type = 'script'
|
|
357
|
-
jamf_normal_ea.enable
|
|
358
|
-
jamf_normal_ea.script = version_script_contents
|
|
359
|
-
jamf_normal_ea.save
|
|
360
|
-
end
|
|
361
|
-
|
|
362
|
-
# Repair the 'normal' EA in jamf to match our version_script
|
|
363
|
-
########################
|
|
364
|
-
def repair_jamf_normal_ea
|
|
365
|
-
if version_script_contents.pix_empty?
|
|
366
|
-
delete_jamf_normal_ea
|
|
367
|
-
else
|
|
368
|
-
configure_jamf_normal_ea
|
|
369
|
-
end
|
|
370
|
-
end
|
|
371
|
-
|
|
372
|
-
# Delete the 'normal' computer ext attr matching the Patch EA
|
|
373
|
-
# @return [void]
|
|
374
|
-
######################################
|
|
375
|
-
def delete_jamf_normal_ea
|
|
376
|
-
ea_id = Jamf::ComputerExtensionAttribute.valid_id jamf_normal_ea_name, cnx: jamf_cnx
|
|
377
|
-
return unless ea_id
|
|
378
|
-
|
|
379
|
-
progress "Jamf: Deleting regular extension attribute '#{jamf_normal_ea_name}'", log: :info
|
|
380
|
-
Jamf::ComputerExtensionAttribute.delete ea_id, cnx: jamf_cnx
|
|
381
|
-
end
|
|
382
|
-
|
|
383
|
-
# do we need to update the normal EA in jamf?
|
|
384
|
-
# true if our incoming changes include :version_script
|
|
385
|
-
# and the new value is not empty (in which case we'll delete it)
|
|
386
|
-
#
|
|
387
|
-
# @return [Boolean]
|
|
388
|
-
########################
|
|
389
|
-
def need_to_update_jamf_normal_ea?
|
|
390
|
-
changes_for_update.key?(:version_script) && !changes_for_update[:version_script][:new].pix_empty?
|
|
391
|
-
end
|
|
392
|
-
|
|
393
|
-
# the script contents of the Normal Jamf EA that comes from our version_script
|
|
394
|
-
# @return [String, nil] nil if there is none
|
|
395
|
-
##############################
|
|
396
|
-
def jamf_normal_ea_contents
|
|
397
|
-
return unless jamf_normal_ea_exist?
|
|
398
|
-
|
|
399
|
-
jamf_normal_ea.script
|
|
400
|
-
end
|
|
401
|
-
|
|
402
|
-
# @return [String] the URL for the Normal EA in Jamf Pro
|
|
403
|
-
######################
|
|
404
|
-
def jamf_normal_ea_url
|
|
405
|
-
return @jamf_normal_ea_url if @jamf_normal_ea_url
|
|
406
|
-
return unless version_script
|
|
407
|
-
|
|
408
|
-
ea_id = Jamf::ComputerExtensionAttribute.valid_id jamf_normal_ea_name, cnx: jamf_cnx
|
|
409
|
-
return unless ea_id
|
|
410
|
-
|
|
411
|
-
# Jamf Changed the URL!
|
|
412
|
-
# @jamf_normal_ea_url = "#{jamf_gui_url}/computerExtensionAttributes.html?id=#{ea_id}&o=r"
|
|
413
|
-
|
|
414
|
-
@jamf_normal_ea_url = "#{jamf_gui_url}/view/settings/computer-management/computer-extension-attributes/#{ea_id}"
|
|
415
|
-
end
|
|
416
|
-
|
|
417
313
|
####### The Patch Ext Attribute
|
|
418
314
|
###########################################
|
|
419
315
|
###########################################
|
|
@@ -432,6 +328,8 @@ module Xolo
|
|
|
432
328
|
# @return [Boolean]
|
|
433
329
|
#########################
|
|
434
330
|
def need_to_accept_jamf_patch_ea?
|
|
331
|
+
return unless managed?
|
|
332
|
+
|
|
435
333
|
@need_to_accept_jamf_patch_ea
|
|
436
334
|
end
|
|
437
335
|
|
|
@@ -457,16 +355,22 @@ module Xolo
|
|
|
457
355
|
# @return [void]
|
|
458
356
|
############################
|
|
459
357
|
def accept_jamf_patch_ea
|
|
460
|
-
|
|
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?
|
|
461
363
|
|
|
462
|
-
# return with warning if we aren't auto-accepting
|
|
463
|
-
|
|
464
|
-
msg = "Jamf: IMPORTANT:
|
|
465
|
-
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
|
|
466
368
|
log_debug 'Admin informed about accepting EA/version-script manually'
|
|
467
369
|
return
|
|
468
370
|
end
|
|
469
371
|
|
|
372
|
+
return unless need_to_accept_jamf_patch_ea?
|
|
373
|
+
|
|
470
374
|
# this is true if the Jamf server already knows it needs to be accepted
|
|
471
375
|
# so just do it now
|
|
472
376
|
if jamf_patch_ea_awaiting_acceptance?
|
|
@@ -607,6 +511,8 @@ module Xolo
|
|
|
607
511
|
end
|
|
608
512
|
|
|
609
513
|
# API call to accept the version-script EA in Jamf Pro
|
|
514
|
+
# This never happens for subscribed titles
|
|
515
|
+
#
|
|
610
516
|
# TODO: when this gets implemented in ruby-jss, use that implementation
|
|
611
517
|
#
|
|
612
518
|
# @return [void]
|
|
@@ -640,7 +546,7 @@ module Xolo
|
|
|
640
546
|
######################
|
|
641
547
|
def jamf_patch_ea_url
|
|
642
548
|
return @jamf_patch_ea_url if @jamf_patch_ea_url
|
|
643
|
-
return unless version_script
|
|
549
|
+
return unless version_script || (subscribed? && jamf_patch_ea_data)
|
|
644
550
|
|
|
645
551
|
@jamf_patch_ea_url = "#{jamf_patch_title_url}?tab=extension"
|
|
646
552
|
end
|
|
@@ -786,7 +692,10 @@ module Xolo
|
|
|
786
692
|
pol.add_script jamf_uninstall_script_name
|
|
787
693
|
pol.set_trigger_event :checkin, false
|
|
788
694
|
pol.set_trigger_event :custom, jamf_uninstall_policy_name
|
|
789
|
-
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
|
|
790
699
|
pol.scope.set_exclusions :computer_groups, [valid_forced_exclusion_group_name] if valid_forced_exclusion_group_name
|
|
791
700
|
pol.frequency = :ongoing
|
|
792
701
|
pol.enable
|
|
@@ -804,7 +713,6 @@ module Xolo
|
|
|
804
713
|
end
|
|
805
714
|
|
|
806
715
|
# delete the policy first if it exists
|
|
807
|
-
|
|
808
716
|
#########################
|
|
809
717
|
def delete_jamf_uninstall_policy
|
|
810
718
|
return unless jamf_uninstall_policy_exist?
|
|
@@ -861,9 +769,9 @@ module Xolo
|
|
|
861
769
|
)
|
|
862
770
|
@jamf_installed_group.save
|
|
863
771
|
configure_jamf_installed_group
|
|
864
|
-
|
|
865
|
-
sleep 10
|
|
772
|
+
|
|
866
773
|
end
|
|
774
|
+
|
|
867
775
|
@jamf_installed_group
|
|
868
776
|
end
|
|
869
777
|
|
|
@@ -876,75 +784,34 @@ module Xolo
|
|
|
876
784
|
|
|
877
785
|
jamf_installed_group.criteria = Jamf::Criteriable::Criteria.new(jamf_installed_group_criteria)
|
|
878
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
|
|
879
789
|
end
|
|
880
790
|
|
|
881
791
|
# The criteria for the smart group in Jamf that contains all Macs
|
|
882
792
|
# with any version of this title installed
|
|
883
793
|
#
|
|
884
|
-
#
|
|
885
|
-
#
|
|
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.
|
|
886
796
|
#
|
|
887
797
|
# @return [Array<Jamf::Criteriable::Criterion>]
|
|
888
798
|
###################################
|
|
889
799
|
def jamf_installed_group_criteria
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
)
|
|
906
|
-
]
|
|
907
|
-
|
|
908
|
-
# No version script, so we must be using app data
|
|
909
|
-
else
|
|
910
|
-
aname = changes_for_update.dig(:app_name, :new) || app_name
|
|
911
|
-
abundle = changes_for_update.dig(:app_bundle_id, :new) || app_bundle_id
|
|
912
|
-
|
|
913
|
-
[
|
|
914
|
-
Jamf::Criteriable::Criterion.new(
|
|
915
|
-
and_or: :and,
|
|
916
|
-
name: 'Application Title',
|
|
917
|
-
search_type: 'is',
|
|
918
|
-
value: aname
|
|
919
|
-
),
|
|
920
|
-
|
|
921
|
-
Jamf::Criteriable::Criterion.new(
|
|
922
|
-
and_or: :and,
|
|
923
|
-
name: 'Application Bundle ID',
|
|
924
|
-
search_type: 'is',
|
|
925
|
-
value: abundle
|
|
926
|
-
)
|
|
927
|
-
]
|
|
928
|
-
end
|
|
929
|
-
end
|
|
930
|
-
|
|
931
|
-
# do we need to update the 'installed' smart group?
|
|
932
|
-
# true if our incoming changes include the app_name or app_bundle_id
|
|
933
|
-
#
|
|
934
|
-
# If they changed at all, we need to update no matter what:
|
|
935
|
-
# - if they are now nil, we switched to a version script
|
|
936
|
-
#
|
|
937
|
-
# - if they aren't nil but are different, we need to update
|
|
938
|
-
# the group criteria to reflect that.
|
|
939
|
-
#
|
|
940
|
-
# Changes to the version script, if it was in use before, don't
|
|
941
|
-
# require us to change the smart group
|
|
942
|
-
#
|
|
943
|
-
#
|
|
944
|
-
# @return [Boolean]
|
|
945
|
-
#########################
|
|
946
|
-
def need_to_update_jamf_installed_group?
|
|
947
|
-
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
|
+
]
|
|
948
815
|
end
|
|
949
816
|
|
|
950
817
|
# Delete the 'installed' smart group
|
|
@@ -1239,14 +1106,15 @@ module Xolo
|
|
|
1239
1106
|
#
|
|
1240
1107
|
# @return [Jamf::PatchSource] The Jamf Patch Source
|
|
1241
1108
|
#########################
|
|
1242
|
-
def
|
|
1243
|
-
@
|
|
1109
|
+
def jamf_managed_patch_source
|
|
1110
|
+
@jamf_managed_patch_source ||=
|
|
1244
1111
|
Jamf::PatchSource.fetch(name: Xolo::Server.config.ted_patch_source, cnx: jamf_cnx)
|
|
1245
1112
|
end
|
|
1246
1113
|
|
|
1247
1114
|
# The titles available from the Title Editor via its
|
|
1248
|
-
# Jamf Patch Source.
|
|
1249
|
-
# 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.
|
|
1250
1118
|
#
|
|
1251
1119
|
# available_titles returns a Hash for each available title, with these keys:
|
|
1252
1120
|
#
|
|
@@ -1266,93 +1134,79 @@ module Xolo
|
|
|
1266
1134
|
#
|
|
1267
1135
|
# @return [Array<String>] info about the available titles
|
|
1268
1136
|
#########################
|
|
1269
|
-
def
|
|
1137
|
+
def jamf_available_managed_titles
|
|
1270
1138
|
# Don't cache this in an instance var, it changes during the
|
|
1271
1139
|
# life of our title instance
|
|
1272
|
-
#
|
|
1140
|
+
# jamf_managed_patch_source.available_titles.map { |t| t[:name_id] }
|
|
1273
1141
|
# Also NOTE: "available" means not only enabled
|
|
1274
1142
|
# in the title editor, but also not already active in jamf.
|
|
1275
1143
|
# So any given title will either be here or in
|
|
1276
|
-
#
|
|
1277
|
-
|
|
1144
|
+
# jamf_active_managed_titles, but never both.
|
|
1145
|
+
jamf_managed_patch_source.available_name_ids
|
|
1278
1146
|
end
|
|
1279
1147
|
|
|
1280
1148
|
# @return [Boolean] Is this xolo title available in Jamf?
|
|
1281
1149
|
########################
|
|
1282
|
-
def
|
|
1283
|
-
|
|
1284
|
-
end
|
|
1285
|
-
|
|
1286
|
-
# The titles active in Jamf Patch Management from the Title Editor
|
|
1287
|
-
# This takes into account that other Patch Sources may have titles with the
|
|
1288
|
-
# same 'name_id' (the xolo 'title')
|
|
1289
|
-
# A hash keyed by the title, with values of the jamf title id
|
|
1290
|
-
#
|
|
1291
|
-
# @return [Hash {String => Integer}] The xolo titles that are active in Jamf Patch Management
|
|
1292
|
-
########################
|
|
1293
|
-
def jamf_active_ted_titles(refresh: false)
|
|
1294
|
-
@jamf_active_ted_titles = nil if refresh
|
|
1295
|
-
return @jamf_active_ted_titles if @jamf_active_ted_titles
|
|
1296
|
-
|
|
1297
|
-
@jamf_active_ted_titles = {}
|
|
1298
|
-
active_from_ted = Jamf::PatchTitle.all(:refresh, cnx: jamf_cnx).select do |t|
|
|
1299
|
-
t[:source_id] == jamf_ted_patch_source.id
|
|
1300
|
-
end
|
|
1301
|
-
active_from_ted.each { |t| @jamf_active_ted_titles[t[:name_id]] = t[:id] }
|
|
1302
|
-
@jamf_active_ted_titles
|
|
1150
|
+
def jamf_managed_title_available?
|
|
1151
|
+
jamf_available_managed_titles.include? title
|
|
1303
1152
|
end
|
|
1304
1153
|
|
|
1305
1154
|
# @return [Boolean] Is this xolo title currently active in Jamf?
|
|
1306
1155
|
########################
|
|
1307
|
-
def
|
|
1308
|
-
|
|
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
|
|
1309
1163
|
end
|
|
1310
1164
|
|
|
1311
|
-
# The
|
|
1312
|
-
#
|
|
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
|
|
1313
1167
|
#
|
|
1314
|
-
# @return [Integer
|
|
1168
|
+
# @return [Hash {String => Integer}] The managed xolo titles that are active in Jamf Patch Management
|
|
1169
|
+
# and their Jamf::PatchTitle id
|
|
1315
1170
|
########################
|
|
1316
|
-
def
|
|
1317
|
-
@
|
|
1318
|
-
|
|
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
|
|
1319
1174
|
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
# This 'subscribes' Jamf to the title in the title editor
|
|
1323
|
-
# It must be enabled in the Title Editor first, meaning
|
|
1324
|
-
# it has at least one requirement, and at least one enabled patch/version.
|
|
1325
|
-
#
|
|
1326
|
-
# The 'stub' patch version should allow this when we create the title.
|
|
1327
|
-
#
|
|
1328
|
-
# Xolo should have enabled it in the Title editor before we
|
|
1329
|
-
# reach this point.
|
|
1330
|
-
#
|
|
1331
|
-
##########################
|
|
1332
|
-
def activate_jamf_patch_title
|
|
1333
|
-
if jamf_ted_title_active?
|
|
1334
|
-
log_debug "Jamf: Title '#{display_name}' (#{title}) is already active in Jamf"
|
|
1335
|
-
return
|
|
1336
|
-
end
|
|
1175
|
+
@jamf_active_managed_titles = {}
|
|
1176
|
+
all_patch_titles = Jamf::PatchTitle.all(cnx: jamf_cnx)
|
|
1337
1177
|
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
log_debug "Jamf: Waiting for title '#{display_name}' (#{title}) to become available from the Title Editor"
|
|
1342
|
-
sleep 5
|
|
1343
|
-
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
|
|
1344
1181
|
end
|
|
1345
1182
|
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
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]
|
|
1350
1187
|
end
|
|
1188
|
+
@jamf_active_managed_titles
|
|
1189
|
+
end
|
|
1351
1190
|
|
|
1352
|
-
|
|
1353
|
-
|
|
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
|
|
1354
1197
|
|
|
1355
|
-
|
|
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
|
|
1356
1210
|
end
|
|
1357
1211
|
|
|
1358
1212
|
# Create or fetch the patch title object for this xolo title.
|
|
@@ -1365,52 +1219,118 @@ module Xolo
|
|
|
1365
1219
|
@jamf_patch_title = nil if refresh
|
|
1366
1220
|
return @jamf_patch_title if @jamf_patch_title
|
|
1367
1221
|
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
raise Xolo::ServerError,
|
|
1372
|
-
"Jamf: Title '#{title}' is not available in Jamf after waiting #{Xolo::Server::MAX_JAMF_WAIT_FOR_TITLE_EDITOR} seconds"
|
|
1373
|
-
end
|
|
1374
|
-
|
|
1375
|
-
log_debug "Waiting a long time for title '#{title}' to become available from TEd. Checking every 10 secs"
|
|
1376
|
-
sleep 10
|
|
1377
|
-
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
|
|
1378
1225
|
|
|
1379
|
-
|
|
1226
|
+
# Jamf::PatchTitle object already active, just fetch it
|
|
1227
|
+
if jamf_patch_title_id # jamf_title_active? || subscribed?
|
|
1380
1228
|
@jamf_patch_title = Jamf::PatchTitle.fetch(id: jamf_patch_title_id, cnx: jamf_cnx)
|
|
1381
1229
|
|
|
1230
|
+
# not yet active, so activate/create the Jamf::PatchTitle object
|
|
1382
1231
|
else
|
|
1383
1232
|
return if deleting?
|
|
1384
1233
|
|
|
1385
|
-
|
|
1386
|
-
|
|
1234
|
+
@jamf_patch_title = activate_jamf_patch_title
|
|
1235
|
+
end
|
|
1236
|
+
end
|
|
1387
1237
|
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
@jamf_patch_title.category = Xolo::Server::JAMF_XOLO_CATEGORY
|
|
1396
|
-
@jamf_patch_title.save
|
|
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
|
|
1397
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
|
|
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
|
|
1398
1296
|
end
|
|
1399
|
-
|
|
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
|
|
1400
1303
|
end
|
|
1401
1304
|
|
|
1402
1305
|
# Delete the patch title
|
|
1403
1306
|
# NOTE: jamf api user must have 'delete computer ext. attribs' permmissions
|
|
1404
1307
|
##############################
|
|
1405
1308
|
def delete_jamf_patch_title
|
|
1406
|
-
|
|
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
|
|
1314
|
+
|
|
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]
|
|
1407
1320
|
|
|
1408
|
-
|
|
1409
|
-
|
|
1321
|
+
# unless pt_id
|
|
1322
|
+
# log_debug "Jamf: Cannot find patch title '#{display_name}' (#{title}) in Jamf, cannot delete"
|
|
1323
|
+
# return
|
|
1324
|
+
# end
|
|
1410
1325
|
|
|
1411
|
-
|
|
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"
|
|
1412
1332
|
progress msg, log: :info
|
|
1413
|
-
Jamf::PatchTitle.delete
|
|
1333
|
+
Jamf::PatchTitle.delete jamf_patch_title_id, cnx: jamf_cnx
|
|
1414
1334
|
end
|
|
1415
1335
|
|
|
1416
1336
|
# @return [String] the URL for the Patch Title in Jamf Pro
|
|
@@ -1476,6 +1396,7 @@ module Xolo
|
|
|
1476
1396
|
end
|
|
1477
1397
|
|
|
1478
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.
|
|
1479
1400
|
# @param pol [Jamf::Policy] the policy we are configuring
|
|
1480
1401
|
# @return [void]
|
|
1481
1402
|
###################
|
|
@@ -1490,15 +1411,7 @@ module Xolo
|
|
|
1490
1411
|
# clear any existing packages
|
|
1491
1412
|
pol.package_names.each { |pkg_name| pol.remove_package pkg_name }
|
|
1492
1413
|
|
|
1493
|
-
|
|
1494
|
-
desired_vers = releasing_version || released_version
|
|
1495
|
-
if desired_vers
|
|
1496
|
-
rel_vers = version_object(desired_vers)
|
|
1497
|
-
pol.add_package rel_vers.jamf_pkg_id
|
|
1498
|
-
pol.enable
|
|
1499
|
-
else
|
|
1500
|
-
pol.disable
|
|
1501
|
-
end
|
|
1414
|
+
toggle_jamf_manual_install_released_policy pol
|
|
1502
1415
|
|
|
1503
1416
|
# figure out the exclusions.
|
|
1504
1417
|
#
|
|
@@ -1514,12 +1427,36 @@ module Xolo
|
|
|
1514
1427
|
|
|
1515
1428
|
pol.scope.set_exclusions :computer_groups, excls
|
|
1516
1429
|
|
|
1517
|
-
|
|
1430
|
+
if self_service?
|
|
1431
|
+
add_title_to_self_service(pol)
|
|
1432
|
+
else
|
|
1433
|
+
remove_title_from_self_service(pol)
|
|
1434
|
+
end
|
|
1435
|
+
end
|
|
1518
1436
|
|
|
1519
|
-
|
|
1520
|
-
|
|
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
|
|
1521
1457
|
else
|
|
1522
|
-
|
|
1458
|
+
progress "Jamf: Disabling policy #{jamf_manual_install_released_policy_name}, no released version", log: :info
|
|
1459
|
+
pol.disable
|
|
1523
1460
|
end
|
|
1524
1461
|
end
|
|
1525
1462
|
|
|
@@ -1549,111 +1486,164 @@ module Xolo
|
|
|
1549
1486
|
# @return [void]
|
|
1550
1487
|
##################################
|
|
1551
1488
|
def add_title_to_self_service(pol = nil)
|
|
1552
|
-
return unless self_service
|
|
1553
|
-
|
|
1554
1489
|
pol ||= jamf_manual_install_released_policy
|
|
1555
1490
|
|
|
1556
|
-
|
|
1557
|
-
|
|
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
|
|
1558
1496
|
|
|
1559
|
-
pol.add_to_self_service
|
|
1560
1497
|
configure_pol_for_self_service(pol)
|
|
1498
|
+
pol.save
|
|
1561
1499
|
end
|
|
1562
1500
|
|
|
1563
|
-
#
|
|
1564
|
-
#
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
pol = jamf_manual_install_released_policy
|
|
1571
|
-
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?
|
|
1572
1508
|
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1509
|
+
msg = "Jamf: Removing Manual Install Policy '#{pol.name}' from Self Service."
|
|
1510
|
+
progress msg, log: :info
|
|
1511
|
+
pol.remove_from_self_service
|
|
1576
1512
|
|
|
1577
|
-
# we should not be in SSvc
|
|
1578
|
-
elsif pol.in_self_service?
|
|
1579
|
-
msg = "Jamf: Removing Manual Install Policy '#{pol.name}' from Self Service."
|
|
1580
|
-
progress msg, log: :info
|
|
1581
|
-
pol.remove_from_self_service
|
|
1582
|
-
end
|
|
1583
1513
|
pol.save
|
|
1584
|
-
|
|
1585
|
-
# TODO: if we decide to use ssvc in patch policies, loop thru versions to make any changes
|
|
1586
1514
|
end
|
|
1587
1515
|
|
|
1588
|
-
# Update
|
|
1589
|
-
# TODO: Allow multiple categories, and 'featuring' ?
|
|
1516
|
+
# Update whether or not we are in self service, based on the setting in the title
|
|
1590
1517
|
#
|
|
1591
1518
|
#########################
|
|
1592
|
-
def
|
|
1593
|
-
return unless changes_for_update.key? :self_service_category
|
|
1594
|
-
|
|
1519
|
+
def update_ssvc
|
|
1595
1520
|
pol = jamf_manual_install_released_policy
|
|
1596
|
-
return unless pol
|
|
1597
1521
|
|
|
1598
|
-
|
|
1522
|
+
adding_to_ssvc = changes_for_update.dig :self_service, :new
|
|
1599
1523
|
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
)
|
|
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
|
|
1604
1527
|
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
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
|
|
1609
1531
|
|
|
1610
|
-
|
|
1611
|
-
|
|
1532
|
+
if adding_to_ssvc
|
|
1533
|
+
add_title_to_self_service(pol)
|
|
1612
1534
|
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
# @param ttl_obj [Xolo::Server::Title] The pre-instantiated title for ths version.
|
|
1616
|
-
# if nil, we'll instantiate it now
|
|
1617
|
-
#
|
|
1618
|
-
# @return [void]
|
|
1619
|
-
###############################
|
|
1620
|
-
def update_ssvc_icon(ttl_obj: nil)
|
|
1621
|
-
ttl_obj ||= title_object
|
|
1622
|
-
# update manual install policy
|
|
1535
|
+
elsif updating_config
|
|
1536
|
+
configure_pol_for_self_service(pol)
|
|
1623
1537
|
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
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
|
|
1627
1542
|
|
|
1628
|
-
pol.
|
|
1629
|
-
progress "Jamf: Updated Icon for Manual Install Policy '#{jamf_manual_install_policy_name}'",
|
|
1630
|
-
log: :debug
|
|
1543
|
+
pol.save
|
|
1631
1544
|
|
|
1632
|
-
# TODO:
|
|
1633
|
-
# 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
|
|
1634
1546
|
end
|
|
1635
1547
|
|
|
1636
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
|
+
#
|
|
1637
1552
|
# @param pol [Jamf::Policy] The jamf_manual_install_released_policy, which may not be saved yet.
|
|
1638
1553
|
# @return [void]
|
|
1639
1554
|
############################
|
|
1640
1555
|
def configure_pol_for_self_service(pol = nil)
|
|
1641
1556
|
pol ||= jamf_manual_install_released_policy
|
|
1642
1557
|
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
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
|
|
1646
1573
|
|
|
1647
|
-
pol.self_service_description = description
|
|
1648
|
-
pol.self_service_display_name = display_name
|
|
1649
1574
|
pol.self_service_install_button_text = Xolo::Server::Title::SELF_SERVICE_INSTALL_BTN_TEXT
|
|
1650
1575
|
return unless ssvc_icon_file
|
|
1651
1576
|
|
|
1577
|
+
progress 'Jamf: Uploading Self Service icon', log: :debug
|
|
1652
1578
|
pol.save # won't do anything unless needed, but has to exist before we can upload icons
|
|
1653
1579
|
pol.upload :icon, ssvc_icon_file
|
|
1580
|
+
# re-fetch the pol to get the icon id
|
|
1654
1581
|
self.ssvc_icon_id = Jamf::Policy.fetch(id: pol.id, cnx: jamf_cnx).icon.id
|
|
1655
1582
|
end
|
|
1656
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
|
+
|
|
1657
1647
|
end # TitleJamfPro
|
|
1658
1648
|
|
|
1659
1649
|
end # Mixins
|