xolo-server 1.0.1 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/data/client/xolo +182 -82
- data/lib/xolo/core/base_classes/title.rb +261 -20
- data/lib/xolo/core/base_classes/version.rb +53 -8
- 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 +170 -0
- data/lib/xolo/server/helpers/client_data.rb +91 -61
- 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 +395 -383
- data/lib/xolo/server/mixins/title_ted_access.rb +29 -3
- data/lib/xolo/server/mixins/version_jamf_access.rb +185 -159
- 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 +30 -17
- data/lib/xolo/server/routes/uploads.rb +0 -14
- data/lib/xolo/server/routes/versions.rb +22 -17
- data/lib/xolo/server/routes.rb +9 -0
- data/lib/xolo/server/title.rb +107 -78
- data/lib/xolo/server/tmp_overrides.rb +38 -0
- data/lib/xolo/server/version.rb +193 -15
- data/lib/xolo/server.rb +12 -0
- metadata +8 -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,18 @@ module Xolo
|
|
|
187
177
|
delete_jamf_uninstall_policy
|
|
188
178
|
delete_jamf_manual_install_released_policy
|
|
189
179
|
delete_jamf_uninstall_script
|
|
190
|
-
|
|
180
|
+
sleep 5
|
|
181
|
+
|
|
182
|
+
# must delete this group before the patch title
|
|
183
|
+
# since the group criteria references the patch title
|
|
191
184
|
delete_jamf_installed_group
|
|
192
|
-
|
|
185
|
+
sleep 5
|
|
186
|
+
|
|
193
187
|
delete_jamf_patch_title
|
|
188
|
+
|
|
189
|
+
# static group deleted last,
|
|
190
|
+
# was used in scopes for patch and normal policies
|
|
191
|
+
delete_jamf_frozen_group
|
|
194
192
|
end
|
|
195
193
|
|
|
196
194
|
# If any title changes require updates to existing versions in
|
|
@@ -211,8 +209,6 @@ module Xolo
|
|
|
211
209
|
vers_obj.update_release_groups(ttl_obj: self) if changes_for_update&.key? :release_groups
|
|
212
210
|
vers_obj.update_excluded_groups(ttl_obj: self) if changes_for_update&.key? :excluded_groups
|
|
213
211
|
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
212
|
end
|
|
217
213
|
end
|
|
218
214
|
|
|
@@ -271,12 +267,13 @@ module Xolo
|
|
|
271
267
|
######################
|
|
272
268
|
def patch_report(vers: nil)
|
|
273
269
|
vers = Xolo::Server::Helpers::JamfPro::PATCH_REPORT_UNKNOWN_VERSION if vers == Xolo::UNKNOWN
|
|
274
|
-
vers &&= CGI.escape vers.to_s
|
|
275
270
|
|
|
276
271
|
page_size = Xolo::Server::Helpers::JamfPro::PATCH_REPORT_JPAPI_PAGE_SIZE
|
|
277
272
|
page = 0
|
|
278
|
-
paged_rsrc = "#{patch_report_rsrc}?page=#{page}&page-size=#{page_size}"
|
|
279
|
-
|
|
273
|
+
paged_rsrc = +"#{patch_report_rsrc}?page=#{page}&page-size=#{page_size}"
|
|
274
|
+
|
|
275
|
+
filter = vers ? jp_api_filter_string_for_version(vers) : nil
|
|
276
|
+
paged_rsrc << filter if filter
|
|
280
277
|
|
|
281
278
|
report = []
|
|
282
279
|
loop do
|
|
@@ -287,7 +284,7 @@ module Xolo
|
|
|
287
284
|
report += data
|
|
288
285
|
page += 1
|
|
289
286
|
paged_rsrc = "#{patch_report_rsrc}?page=#{page}&page-size=#{page_size}"
|
|
290
|
-
paged_rsrc <<
|
|
287
|
+
paged_rsrc << filter if filter
|
|
291
288
|
end
|
|
292
289
|
|
|
293
290
|
# log_debug "REPORT: #{report}"
|
|
@@ -300,118 +297,25 @@ module Xolo
|
|
|
300
297
|
report
|
|
301
298
|
end
|
|
302
299
|
|
|
303
|
-
|
|
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.
|
|
300
|
+
# given a version, return a patch report filter
|
|
301
|
+
# with it properly quoted and URL escaped
|
|
315
302
|
#
|
|
316
|
-
#
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
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)
|
|
303
|
+
# e.g. this string: 7.1.5 (84650)
|
|
304
|
+
# becomes: version=="7.1.5 (84650)"
|
|
305
|
+
# becomes: version%3D%3D%227.1.5+%2884650%29%22
|
|
306
|
+
# becomes: &filter=version%3D%3D%227.1.5+%2884650%29%22
|
|
343
307
|
#
|
|
344
|
-
#
|
|
308
|
+
# Use CGI.escape because it encodes all special cars, like parens,
|
|
309
|
+
# which we want here, rather than URI::Parser.new.escape
|
|
310
|
+
# which is meant to parse whole URLs leaving URL functional characters.
|
|
345
311
|
#
|
|
346
|
-
# @
|
|
312
|
+
# @param vers [String] the version the filter for
|
|
313
|
+
# @return [String] the quoted and escaped filter string
|
|
347
314
|
################################
|
|
348
|
-
def
|
|
349
|
-
|
|
350
|
-
|
|
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}"
|
|
315
|
+
def jp_api_filter_string_for_version(vers)
|
|
316
|
+
raw_fiter_query = "version==\"#{vers}\""
|
|
317
|
+
escaped_filter_query = CGI.escape raw_fiter_query
|
|
318
|
+
"&filter=#{escaped_filter_query}"
|
|
415
319
|
end
|
|
416
320
|
|
|
417
321
|
####### The Patch Ext Attribute
|
|
@@ -432,6 +336,8 @@ module Xolo
|
|
|
432
336
|
# @return [Boolean]
|
|
433
337
|
#########################
|
|
434
338
|
def need_to_accept_jamf_patch_ea?
|
|
339
|
+
return unless managed?
|
|
340
|
+
|
|
435
341
|
@need_to_accept_jamf_patch_ea
|
|
436
342
|
end
|
|
437
343
|
|
|
@@ -457,16 +363,22 @@ module Xolo
|
|
|
457
363
|
# @return [void]
|
|
458
364
|
############################
|
|
459
365
|
def accept_jamf_patch_ea
|
|
460
|
-
|
|
366
|
+
# give the server a moment to catch up with the new EA before we check on it
|
|
367
|
+
log_debug "Jamf: Checking if we need to accept the version-script EA for title '#{title}'"
|
|
368
|
+
sleep 5
|
|
369
|
+
|
|
370
|
+
awating_acceptance = jamf_patch_ea_awaiting_acceptance?
|
|
461
371
|
|
|
462
|
-
# return with warning if we aren't auto-accepting
|
|
463
|
-
|
|
464
|
-
msg = "Jamf: IMPORTANT:
|
|
465
|
-
progress msg
|
|
372
|
+
# return with warning if we aren't auto-accepting, or for all subscribed titles
|
|
373
|
+
if awating_acceptance && (subscribed? || !Xolo::Server.config.jamf_auto_accept_xolo_eas)
|
|
374
|
+
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."
|
|
375
|
+
progress msg, log: :warn, alert: true
|
|
466
376
|
log_debug 'Admin informed about accepting EA/version-script manually'
|
|
467
377
|
return
|
|
468
378
|
end
|
|
469
379
|
|
|
380
|
+
return unless need_to_accept_jamf_patch_ea?
|
|
381
|
+
|
|
470
382
|
# this is true if the Jamf server already knows it needs to be accepted
|
|
471
383
|
# so just do it now
|
|
472
384
|
if jamf_patch_ea_awaiting_acceptance?
|
|
@@ -607,6 +519,8 @@ module Xolo
|
|
|
607
519
|
end
|
|
608
520
|
|
|
609
521
|
# API call to accept the version-script EA in Jamf Pro
|
|
522
|
+
# This never happens for subscribed titles
|
|
523
|
+
#
|
|
610
524
|
# TODO: when this gets implemented in ruby-jss, use that implementation
|
|
611
525
|
#
|
|
612
526
|
# @return [void]
|
|
@@ -640,7 +554,7 @@ module Xolo
|
|
|
640
554
|
######################
|
|
641
555
|
def jamf_patch_ea_url
|
|
642
556
|
return @jamf_patch_ea_url if @jamf_patch_ea_url
|
|
643
|
-
return unless version_script
|
|
557
|
+
return unless version_script || (subscribed? && jamf_patch_ea_data)
|
|
644
558
|
|
|
645
559
|
@jamf_patch_ea_url = "#{jamf_patch_title_url}?tab=extension"
|
|
646
560
|
end
|
|
@@ -786,7 +700,10 @@ module Xolo
|
|
|
786
700
|
pol.add_script jamf_uninstall_script_name
|
|
787
701
|
pol.set_trigger_event :checkin, false
|
|
788
702
|
pol.set_trigger_event :custom, jamf_uninstall_policy_name
|
|
789
|
-
pol.scope.add_target(:computer_group, jamf_installed_group_name)
|
|
703
|
+
# pol.scope.add_target(:computer_group, jamf_installed_group_name)
|
|
704
|
+
# all targets, cus jamf doesn't like some policies with scoped
|
|
705
|
+
# smart groups using 'latest version'
|
|
706
|
+
pol.scope.set_all_targets
|
|
790
707
|
pol.scope.set_exclusions :computer_groups, [valid_forced_exclusion_group_name] if valid_forced_exclusion_group_name
|
|
791
708
|
pol.frequency = :ongoing
|
|
792
709
|
pol.enable
|
|
@@ -804,7 +721,6 @@ module Xolo
|
|
|
804
721
|
end
|
|
805
722
|
|
|
806
723
|
# delete the policy first if it exists
|
|
807
|
-
|
|
808
724
|
#########################
|
|
809
725
|
def delete_jamf_uninstall_policy
|
|
810
726
|
return unless jamf_uninstall_policy_exist?
|
|
@@ -861,9 +777,9 @@ module Xolo
|
|
|
861
777
|
)
|
|
862
778
|
@jamf_installed_group.save
|
|
863
779
|
configure_jamf_installed_group
|
|
864
|
-
|
|
865
|
-
sleep 10
|
|
780
|
+
|
|
866
781
|
end
|
|
782
|
+
|
|
867
783
|
@jamf_installed_group
|
|
868
784
|
end
|
|
869
785
|
|
|
@@ -876,75 +792,34 @@ module Xolo
|
|
|
876
792
|
|
|
877
793
|
jamf_installed_group.criteria = Jamf::Criteriable::Criteria.new(jamf_installed_group_criteria)
|
|
878
794
|
jamf_installed_group.save
|
|
795
|
+
log_debug 'Jamf: Sleeping 30 secs to let Jamf server see changes to Installed smart group.'
|
|
796
|
+
sleep 30
|
|
879
797
|
end
|
|
880
798
|
|
|
881
799
|
# The criteria for the smart group in Jamf that contains all Macs
|
|
882
800
|
# with any version of this title installed
|
|
883
801
|
#
|
|
884
|
-
#
|
|
885
|
-
#
|
|
802
|
+
# We use the "Patch Reporting: #{display_name}" criterion so that we don't
|
|
803
|
+
# care whether the title uses a version-script or app data.
|
|
886
804
|
#
|
|
887
805
|
# @return [Array<Jamf::Criteriable::Criterion>]
|
|
888
806
|
###################################
|
|
889
807
|
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]
|
|
808
|
+
[
|
|
809
|
+
Jamf::Criteriable::Criterion.new(
|
|
810
|
+
and_or: :and,
|
|
811
|
+
name: "Patch Reporting: #{display_name}",
|
|
812
|
+
search_type: 'less than or equal',
|
|
813
|
+
value: 'Latest Version'
|
|
814
|
+
),
|
|
815
|
+
|
|
816
|
+
Jamf::Criteriable::Criterion.new(
|
|
817
|
+
and_or: :or,
|
|
818
|
+
name: "Patch Reporting: #{display_name}",
|
|
819
|
+
search_type: 'is',
|
|
820
|
+
value: 'Unknown Version'
|
|
821
|
+
)
|
|
822
|
+
]
|
|
948
823
|
end
|
|
949
824
|
|
|
950
825
|
# Delete the 'installed' smart group
|
|
@@ -1239,14 +1114,15 @@ module Xolo
|
|
|
1239
1114
|
#
|
|
1240
1115
|
# @return [Jamf::PatchSource] The Jamf Patch Source
|
|
1241
1116
|
#########################
|
|
1242
|
-
def
|
|
1243
|
-
@
|
|
1117
|
+
def jamf_managed_patch_source
|
|
1118
|
+
@jamf_managed_patch_source ||=
|
|
1244
1119
|
Jamf::PatchSource.fetch(name: Xolo::Server.config.ted_patch_source, cnx: jamf_cnx)
|
|
1245
1120
|
end
|
|
1246
1121
|
|
|
1247
1122
|
# The titles available from the Title Editor via its
|
|
1248
|
-
# Jamf Patch Source.
|
|
1249
|
-
# in the Title Editor
|
|
1123
|
+
# Jamf Patch Source.
|
|
1124
|
+
# These are titles have have been enabled in the Title Editor
|
|
1125
|
+
# but have not yet been activated in Jamf Patch.
|
|
1250
1126
|
#
|
|
1251
1127
|
# available_titles returns a Hash for each available title, with these keys:
|
|
1252
1128
|
#
|
|
@@ -1266,93 +1142,79 @@ module Xolo
|
|
|
1266
1142
|
#
|
|
1267
1143
|
# @return [Array<String>] info about the available titles
|
|
1268
1144
|
#########################
|
|
1269
|
-
def
|
|
1145
|
+
def jamf_available_managed_titles
|
|
1270
1146
|
# Don't cache this in an instance var, it changes during the
|
|
1271
1147
|
# life of our title instance
|
|
1272
|
-
#
|
|
1148
|
+
# jamf_managed_patch_source.available_titles.map { |t| t[:name_id] }
|
|
1273
1149
|
# Also NOTE: "available" means not only enabled
|
|
1274
1150
|
# in the title editor, but also not already active in jamf.
|
|
1275
1151
|
# So any given title will either be here or in
|
|
1276
|
-
#
|
|
1277
|
-
|
|
1152
|
+
# jamf_active_managed_titles, but never both.
|
|
1153
|
+
jamf_managed_patch_source.available_name_ids
|
|
1278
1154
|
end
|
|
1279
1155
|
|
|
1280
1156
|
# @return [Boolean] Is this xolo title available in Jamf?
|
|
1281
1157
|
########################
|
|
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
|
|
1158
|
+
def jamf_managed_title_available?
|
|
1159
|
+
jamf_available_managed_titles.include? title
|
|
1303
1160
|
end
|
|
1304
1161
|
|
|
1305
1162
|
# @return [Boolean] Is this xolo title currently active in Jamf?
|
|
1306
1163
|
########################
|
|
1307
|
-
def
|
|
1308
|
-
|
|
1164
|
+
def jamf_title_active?
|
|
1165
|
+
!jamf_patch_title_id.pix_empty?
|
|
1166
|
+
# if subscribed?
|
|
1167
|
+
# jamf_active_subscribed_titles(refresh: true).key? title
|
|
1168
|
+
# else
|
|
1169
|
+
# jamf_active_managed_titles(refresh: true).key? title
|
|
1170
|
+
# end
|
|
1309
1171
|
end
|
|
1310
1172
|
|
|
1311
|
-
# The
|
|
1312
|
-
#
|
|
1173
|
+
# The managed titles active in Jamf Patch Management from the Title Editor
|
|
1174
|
+
# A hash keyed by the title, with values of the jamf patch title id
|
|
1313
1175
|
#
|
|
1314
|
-
# @return [Integer
|
|
1176
|
+
# @return [Hash {String => Integer}] The managed xolo titles that are active in Jamf Patch Management
|
|
1177
|
+
# and their Jamf::PatchTitle id
|
|
1315
1178
|
########################
|
|
1316
|
-
def
|
|
1317
|
-
@
|
|
1318
|
-
|
|
1179
|
+
def jamf_active_managed_titles(refresh: false)
|
|
1180
|
+
@jamf_active_managed_titles = nil if refresh
|
|
1181
|
+
return @jamf_active_managed_titles if @jamf_active_managed_titles
|
|
1319
1182
|
|
|
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
|
|
1183
|
+
@jamf_active_managed_titles = {}
|
|
1184
|
+
all_patch_titles = Jamf::PatchTitle.all(cnx: jamf_cnx)
|
|
1337
1185
|
|
|
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
|
|
1186
|
+
active_from_ted = all_patch_titles.select do |t|
|
|
1187
|
+
# log_debug "Jamf: Checking if active patch title '#{t[:name]}' with id #{t[:id]} is from the Title Editor's patch source"
|
|
1188
|
+
t[:source_id] == jamf_managed_patch_source.id
|
|
1344
1189
|
end
|
|
1345
1190
|
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1191
|
+
managed_titles = server_app_instance.managed_title_objects.select(&:managed?).map(&:title)
|
|
1192
|
+
|
|
1193
|
+
active_from_ted.each do |t|
|
|
1194
|
+
@jamf_active_managed_titles[t[:name_id]] = t[:id] if managed_titles.include? t[:name_id]
|
|
1350
1195
|
end
|
|
1196
|
+
@jamf_active_managed_titles
|
|
1197
|
+
end
|
|
1351
1198
|
|
|
1352
|
-
|
|
1353
|
-
|
|
1199
|
+
# @return [Hash {String => Integer}] The subscribed xolo titles that are active in Jamf Patch Management
|
|
1200
|
+
# and their Jamf::PatchTitle id
|
|
1201
|
+
########################
|
|
1202
|
+
def jamf_active_subscribed_titles(refresh: false)
|
|
1203
|
+
@jamf_active_subscribed_titles = nil if refresh
|
|
1204
|
+
return @jamf_active_subscribed_titles if @jamf_active_subscribed_titles
|
|
1354
1205
|
|
|
1355
|
-
|
|
1206
|
+
@jamf_active_subscribed_titles = {}
|
|
1207
|
+
|
|
1208
|
+
all_active_patchtitles = Jamf::PatchTitle.all :refresh, cnx: jamf_cnx
|
|
1209
|
+
|
|
1210
|
+
server_app_instance.subscribed_title_objects.each do |st|
|
|
1211
|
+
next unless all_active_patchtitles.any? do |pt|
|
|
1212
|
+
pt[:source_id] == st.jamf_patch_source_id && pt[:name_id] == st.title_id
|
|
1213
|
+
end
|
|
1214
|
+
|
|
1215
|
+
@jamf_active_subscribed_titles[st.title] = pt[:id]
|
|
1216
|
+
end
|
|
1217
|
+
@jamf_active_subscribed_titles
|
|
1356
1218
|
end
|
|
1357
1219
|
|
|
1358
1220
|
# Create or fetch the patch title object for this xolo title.
|
|
@@ -1365,52 +1227,118 @@ module Xolo
|
|
|
1365
1227
|
@jamf_patch_title = nil if refresh
|
|
1366
1228
|
return @jamf_patch_title if @jamf_patch_title
|
|
1367
1229
|
|
|
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
|
|
1230
|
+
# wait up to 60secs for a managed title to become available.
|
|
1231
|
+
# subscribed titles are already available
|
|
1232
|
+
wait_for_managed_title_to_become_available
|
|
1378
1233
|
|
|
1379
|
-
|
|
1234
|
+
# Jamf::PatchTitle object already active, just fetch it
|
|
1235
|
+
if jamf_patch_title_id # jamf_title_active? || subscribed?
|
|
1380
1236
|
@jamf_patch_title = Jamf::PatchTitle.fetch(id: jamf_patch_title_id, cnx: jamf_cnx)
|
|
1381
1237
|
|
|
1238
|
+
# not yet active, so activate/create the Jamf::PatchTitle object
|
|
1382
1239
|
else
|
|
1383
1240
|
return if deleting?
|
|
1384
1241
|
|
|
1385
|
-
|
|
1386
|
-
|
|
1242
|
+
@jamf_patch_title = activate_jamf_patch_title
|
|
1243
|
+
end
|
|
1244
|
+
end
|
|
1245
|
+
|
|
1246
|
+
# activate the patch title in jamf, whatever it's source
|
|
1247
|
+
############################
|
|
1248
|
+
def activate_jamf_patch_title
|
|
1249
|
+
if jamf_title_active?
|
|
1250
|
+
log_debug "Jamf: Title '#{title}' is already active in Jamf Patch"
|
|
1251
|
+
return
|
|
1252
|
+
end
|
|
1253
|
+
|
|
1254
|
+
# patch_source and title_id are required when adding subbed titles
|
|
1255
|
+
# but pre-defined for managed
|
|
1256
|
+
if managed?
|
|
1257
|
+
log_debug "Jamf: Title '#{title}' is managed, so using pre-defined patch source and title_id"
|
|
1258
|
+
log_debug "Jamf: Display Name in managed?: #{display_name}"
|
|
1259
|
+
self.patch_source = Xolo::Server.config.ted_patch_source
|
|
1260
|
+
self.title_id = title
|
|
1261
|
+
log_debug "Jamf: Display Name in managed? after setting patch_source and title_id: #{display_name}"
|
|
1262
|
+
|
|
1263
|
+
# display name is required for managed titles, but will be empty for subbed
|
|
1264
|
+
# so for subbed, we look it up from the patch source
|
|
1265
|
+
else
|
|
1266
|
+
log_debug "Jamf: Title '#{title}' is subscribed, so looking up patch source and title_id from"
|
|
1267
|
+
log_debug "Jamf: Display Name in NOT managed?: #{display_name}"
|
|
1268
|
+
if display_name.pix_empty?
|
|
1269
|
+
self.display_name = Jamf::PatchSource.available_titles(patch_source, cnx: jamf_cnx).select { |t| t[:name_id] == title_id }.first&.dig :app_name
|
|
1270
|
+
end
|
|
1271
|
+
end # if managed
|
|
1272
|
+
|
|
1273
|
+
log_debug "Jamf: class: #{self.class}, display_name: #{display_name}, patch_source: #{patch_source}, title_id: #{title_id}"
|
|
1274
|
+
|
|
1275
|
+
msg = "Jamf: Activating Patch Title '#{display_name}' (#{title}) from the Patch Source '#{patch_source}'"
|
|
1276
|
+
progress msg, log: :info
|
|
1277
|
+
|
|
1278
|
+
jamf_patch_title =
|
|
1279
|
+
Jamf::PatchTitle.create(
|
|
1280
|
+
name: display_name,
|
|
1281
|
+
source: patch_source,
|
|
1282
|
+
name_id: title_id,
|
|
1283
|
+
cnx: jamf_cnx
|
|
1284
|
+
)
|
|
1285
|
+
jamf_patch_title.category = Xolo::Server::JAMF_XOLO_CATEGORY
|
|
1286
|
+
self.jamf_patch_title_id = jamf_patch_title.save
|
|
1287
|
+
log_debug "Activated Jamf Patch Title '#{display_name}' (#{title}) with id #{jamf_patch_title_id}"
|
|
1288
|
+
|
|
1289
|
+
jamf_patch_title
|
|
1290
|
+
end
|
|
1387
1291
|
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
)
|
|
1395
|
-
@jamf_patch_title.category = Xolo::Server::JAMF_XOLO_CATEGORY
|
|
1396
|
-
@jamf_patch_title.save
|
|
1292
|
+
# wait up to 60secs for a managed title to become available to be activated
|
|
1293
|
+
# subscribed titles are already available
|
|
1294
|
+
####################
|
|
1295
|
+
def wait_for_managed_title_to_become_available
|
|
1296
|
+
return unless managed?
|
|
1297
|
+
return if jamf_title_active?
|
|
1397
1298
|
|
|
1299
|
+
counter = 0
|
|
1300
|
+
until jamf_title_active? || jamf_managed_title_available? || counter == 12
|
|
1301
|
+
log_debug "Jamf: Waiting for title '#{display_name}' (#{title}) to become available from the Title Editor"
|
|
1302
|
+
sleep 5
|
|
1303
|
+
counter += 1
|
|
1398
1304
|
end
|
|
1399
|
-
|
|
1305
|
+
|
|
1306
|
+
return if jamf_managed_title_available? || jamf_title_active?
|
|
1307
|
+
|
|
1308
|
+
msg = "Jamf: Title '#{title}' is not yet available to Jamf. Make sure it has at least one version enabled in the Title Editor"
|
|
1309
|
+
log_error msg
|
|
1310
|
+
raise Xolo::NoSuchItemError, msg
|
|
1400
1311
|
end
|
|
1401
1312
|
|
|
1402
1313
|
# Delete the patch title
|
|
1403
1314
|
# NOTE: jamf api user must have 'delete computer ext. attribs' permmissions
|
|
1404
1315
|
##############################
|
|
1405
1316
|
def delete_jamf_patch_title
|
|
1406
|
-
|
|
1317
|
+
log_debug "Jamf: Deleting patch title '#{display_name}' (#{title})"
|
|
1318
|
+
unless jamf_title_active?
|
|
1319
|
+
log_debug "Jamf: Patch title '#{display_name}' (#{title}) is not active in Jamf, nothing to delete"
|
|
1320
|
+
return
|
|
1321
|
+
end
|
|
1322
|
+
|
|
1323
|
+
# # subscribed titles often have name_id's like "1B7"
|
|
1324
|
+
# # whereas managed titles have name_id's that are the same as the title,
|
|
1325
|
+
# # so we have to look up the id differently for subbed vs managed
|
|
1326
|
+
# key = subscribed? ? title_id : title
|
|
1327
|
+
# pt_id = Jamf::PatchTitle.map_all(:id, to: :name_id, cnx: jamf_cnx).invert[key]
|
|
1407
1328
|
|
|
1408
|
-
|
|
1409
|
-
|
|
1329
|
+
# unless pt_id
|
|
1330
|
+
# log_debug "Jamf: Cannot find patch title '#{display_name}' (#{title}) in Jamf, cannot delete"
|
|
1331
|
+
# return
|
|
1332
|
+
# end
|
|
1410
1333
|
|
|
1411
|
-
|
|
1334
|
+
# # 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
|
|
1335
|
+
# unless pt_id.to_s == jamf_patch_title_id.to_s
|
|
1336
|
+
# 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."
|
|
1337
|
+
# end
|
|
1338
|
+
|
|
1339
|
+
msg = "Jamf: Deleting (deactivating) title '#{display_name}' (#{title}}) in Jamf Patch Management"
|
|
1412
1340
|
progress msg, log: :info
|
|
1413
|
-
Jamf::PatchTitle.delete
|
|
1341
|
+
Jamf::PatchTitle.delete jamf_patch_title_id, cnx: jamf_cnx
|
|
1414
1342
|
end
|
|
1415
1343
|
|
|
1416
1344
|
# @return [String] the URL for the Patch Title in Jamf Pro
|
|
@@ -1476,6 +1404,7 @@ module Xolo
|
|
|
1476
1404
|
end
|
|
1477
1405
|
|
|
1478
1406
|
# Configure the settings for the manual_install_released_policy
|
|
1407
|
+
# Be sure to call .save on the policy after this to save the changes.
|
|
1479
1408
|
# @param pol [Jamf::Policy] the policy we are configuring
|
|
1480
1409
|
# @return [void]
|
|
1481
1410
|
###################
|
|
@@ -1490,15 +1419,7 @@ module Xolo
|
|
|
1490
1419
|
# clear any existing packages
|
|
1491
1420
|
pol.package_names.each { |pkg_name| pol.remove_package pkg_name }
|
|
1492
1421
|
|
|
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
|
|
1422
|
+
toggle_jamf_manual_install_released_policy pol
|
|
1502
1423
|
|
|
1503
1424
|
# figure out the exclusions.
|
|
1504
1425
|
#
|
|
@@ -1514,12 +1435,36 @@ module Xolo
|
|
|
1514
1435
|
|
|
1515
1436
|
pol.scope.set_exclusions :computer_groups, excls
|
|
1516
1437
|
|
|
1517
|
-
|
|
1438
|
+
if self_service?
|
|
1439
|
+
add_title_to_self_service(pol)
|
|
1440
|
+
else
|
|
1441
|
+
remove_title_from_self_service(pol)
|
|
1442
|
+
end
|
|
1443
|
+
end
|
|
1518
1444
|
|
|
1519
|
-
|
|
1520
|
-
|
|
1445
|
+
# enable or disable the manual install policy for the current release, depending on
|
|
1446
|
+
# whether or not we have a released version
|
|
1447
|
+
# @param pol [Jamf::Policy] the manual install policy for the current release, which may or may not be saved yet.
|
|
1448
|
+
# return [void]
|
|
1449
|
+
############################
|
|
1450
|
+
def toggle_jamf_manual_install_released_policy(pol, vobj = nil)
|
|
1451
|
+
# remove any current pkg payload
|
|
1452
|
+
pol.package_ids.each { |pid| pol.remove_package pid }
|
|
1453
|
+
|
|
1454
|
+
unless vobj
|
|
1455
|
+
desired_vers = releasing_version || released_version
|
|
1456
|
+
vobj = desired_vers ? version_object(desired_vers) : nil
|
|
1457
|
+
end
|
|
1458
|
+
|
|
1459
|
+
if vobj
|
|
1460
|
+
progress "Jamf: Setting policy #{jamf_manual_install_released_policy_name} to install the package for version '#{vobj.version}'", log: :info
|
|
1461
|
+
pol.add_package vobj.jamf_pkg_id
|
|
1462
|
+
|
|
1463
|
+
progress "Jamf: Enabling policy #{jamf_manual_install_released_policy_name}", log: :info
|
|
1464
|
+
pol.enable
|
|
1521
1465
|
else
|
|
1522
|
-
|
|
1466
|
+
progress "Jamf: Disabling policy #{jamf_manual_install_released_policy_name}, no released version", log: :info
|
|
1467
|
+
pol.disable
|
|
1523
1468
|
end
|
|
1524
1469
|
end
|
|
1525
1470
|
|
|
@@ -1549,111 +1494,178 @@ module Xolo
|
|
|
1549
1494
|
# @return [void]
|
|
1550
1495
|
##################################
|
|
1551
1496
|
def add_title_to_self_service(pol = nil)
|
|
1552
|
-
return unless self_service
|
|
1553
|
-
|
|
1554
1497
|
pol ||= jamf_manual_install_released_policy
|
|
1555
1498
|
|
|
1556
|
-
|
|
1557
|
-
|
|
1499
|
+
unless pol.in_self_service?
|
|
1500
|
+
msg = "Jamf: Adding Manual Install Policy '#{pol.name}' to Self Service."
|
|
1501
|
+
progress msg, log: :info
|
|
1502
|
+
pol.add_to_self_service
|
|
1503
|
+
end
|
|
1558
1504
|
|
|
1559
|
-
pol.add_to_self_service
|
|
1560
1505
|
configure_pol_for_self_service(pol)
|
|
1561
|
-
|
|
1506
|
+
pol.save
|
|
1562
1507
|
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1508
|
+
# loop thru versions to make any SSvc changes
|
|
1509
|
+
version_objects.each do |vobj|
|
|
1510
|
+
ppol = vobj.jamf_patch_policy
|
|
1511
|
+
vobj.configure_patch_pol_for_self_service ppol
|
|
1512
|
+
ppol.save
|
|
1513
|
+
end
|
|
1514
|
+
end
|
|
1568
1515
|
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1516
|
+
# Add the jamf_manual_install_released_policy to self service if needed
|
|
1517
|
+
# @param pol [Jamf::Policy] The jamf_manual_install_released_policy, which may not be saved yet.
|
|
1518
|
+
# @return [void]
|
|
1519
|
+
##################################
|
|
1520
|
+
def remove_title_from_self_service(pol = nil)
|
|
1521
|
+
pol ||= jamf_manual_install_released_policy
|
|
1522
|
+
return unless pol.in_self_service?
|
|
1572
1523
|
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1524
|
+
msg = "Jamf: Removing Manual Install Policy '#{pol.name}' from Self Service."
|
|
1525
|
+
progress msg, log: :info
|
|
1526
|
+
pol.remove_from_self_service
|
|
1576
1527
|
|
|
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
1528
|
pol.save
|
|
1584
1529
|
|
|
1585
|
-
#
|
|
1530
|
+
# loop thru versions to make any SSvc changes
|
|
1531
|
+
version_objects.each do |vobj|
|
|
1532
|
+
progress "Jamf: Removing patch policy for version '#{vobj.version}' of title '#{title}' from Self Service'", log: :info
|
|
1533
|
+
ppol = vobj.jamf_patch_policy
|
|
1534
|
+
ppol.remove_from_self_service
|
|
1535
|
+
ppol.save
|
|
1536
|
+
end
|
|
1586
1537
|
end
|
|
1587
1538
|
|
|
1588
|
-
# Update
|
|
1589
|
-
# TODO: Allow multiple categories, and 'featuring' ?
|
|
1539
|
+
# Update whether or not we are in self service, based on the setting in the title
|
|
1590
1540
|
#
|
|
1591
1541
|
#########################
|
|
1592
|
-
def
|
|
1593
|
-
return unless changes_for_update.key? :self_service_category
|
|
1594
|
-
|
|
1542
|
+
def update_ssvc
|
|
1595
1543
|
pol = jamf_manual_install_released_policy
|
|
1596
|
-
return unless pol
|
|
1597
1544
|
|
|
1598
|
-
|
|
1545
|
+
adding_to_ssvc = changes_for_update.dig :self_service, :new
|
|
1599
1546
|
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
)
|
|
1547
|
+
updating_config = changes_for_update.dig :self_service_category, :new
|
|
1548
|
+
updating_config ||= changes_for_update.dig :description, :new
|
|
1549
|
+
updating_config ||= changes_for_update.dig :display_name, :new
|
|
1604
1550
|
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
pol.save
|
|
1551
|
+
# if adding_to_ssvc is nil, we aren't changing it at all
|
|
1552
|
+
# it must be false to indicate removal.
|
|
1553
|
+
removing_from_ssvc = adding_to_ssvc == false
|
|
1609
1554
|
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
# Update the SSvc Icon for the policies used by this version
|
|
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
|
|
1555
|
+
if adding_to_ssvc
|
|
1556
|
+
add_title_to_self_service(pol)
|
|
1623
1557
|
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
return unless pol
|
|
1558
|
+
elsif updating_config
|
|
1559
|
+
configure_pol_for_self_service(pol)
|
|
1627
1560
|
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1561
|
+
# we should not be in SSvc, remove it, but leave all the settings
|
|
1562
|
+
elsif removing_from_ssvc
|
|
1563
|
+
remove_title_from_self_service(pol)
|
|
1564
|
+
end
|
|
1631
1565
|
|
|
1632
|
-
|
|
1633
|
-
# ssvc - they will need to be updated also
|
|
1566
|
+
pol.save
|
|
1634
1567
|
end
|
|
1635
1568
|
|
|
1636
1569
|
# configure the self-service settings of the manual_install_released_policy
|
|
1570
|
+
# NOTE this doesn't actually add it to self service, just configures the settings
|
|
1571
|
+
# See add_title_to_self_service
|
|
1572
|
+
#
|
|
1637
1573
|
# @param pol [Jamf::Policy] The jamf_manual_install_released_policy, which may not be saved yet.
|
|
1638
1574
|
# @return [void]
|
|
1639
1575
|
############################
|
|
1640
1576
|
def configure_pol_for_self_service(pol = nil)
|
|
1641
1577
|
pol ||= jamf_manual_install_released_policy
|
|
1642
1578
|
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1579
|
+
new_cat = changes_for_update&.dig(:self_service_category, :new) || self_service_category
|
|
1580
|
+
if new_cat
|
|
1581
|
+
progress "Jamf: Setting Self Service category to '#{new_cat}'", log: :debug
|
|
1582
|
+
# clear existing categories, re-add correct one
|
|
1583
|
+
pol.self_service_categories.each { |cat| pol.remove_self_service_category cat }
|
|
1584
|
+
pol.add_self_service_category new_cat if new_cat
|
|
1585
|
+
end
|
|
1586
|
+
|
|
1587
|
+
new_display_name = changes_for_update&.dig(:display_name, :new) || display_name
|
|
1588
|
+
progress "Jamf: Setting Self Service display name to '#{new_display_name}'", log: :debug
|
|
1589
|
+
pol.self_service_display_name = new_display_name
|
|
1590
|
+
|
|
1591
|
+
new_desc = changes_for_update&.dig(:description, :new) || description
|
|
1592
|
+
progress "Jamf: Setting Self Service description to '#{new_desc}'", log: :debug
|
|
1593
|
+
pol.self_service_description = new_desc
|
|
1646
1594
|
|
|
1647
|
-
pol.self_service_description = description
|
|
1648
|
-
pol.self_service_display_name = display_name
|
|
1649
1595
|
pol.self_service_install_button_text = Xolo::Server::Title::SELF_SERVICE_INSTALL_BTN_TEXT
|
|
1650
1596
|
return unless ssvc_icon_file
|
|
1651
1597
|
|
|
1598
|
+
# TODO: Is this needed if we already have a ssvc_icon_id ??
|
|
1599
|
+
progress 'Jamf: Uploading Self Service icon', log: :debug
|
|
1652
1600
|
pol.save # won't do anything unless needed, but has to exist before we can upload icons
|
|
1653
1601
|
pol.upload :icon, ssvc_icon_file
|
|
1602
|
+
# re-fetch the pol to get the icon id
|
|
1654
1603
|
self.ssvc_icon_id = Jamf::Policy.fetch(id: pol.id, cnx: jamf_cnx).icon.id
|
|
1655
1604
|
end
|
|
1656
1605
|
|
|
1606
|
+
# run the autopkg recipe if defined
|
|
1607
|
+
# See Helpers::AutoPkg for more details
|
|
1608
|
+
############################
|
|
1609
|
+
def run_autopkg_recipe
|
|
1610
|
+
server_app_instance.run_autopkg_recipe self
|
|
1611
|
+
end
|
|
1612
|
+
|
|
1613
|
+
# Methods used by subscription stuff
|
|
1614
|
+
##############################
|
|
1615
|
+
|
|
1616
|
+
# Returns an array of known patch versions for this title from Jamf
|
|
1617
|
+
# These are not necessarily in xolo, but they are available from the Patch Source.
|
|
1618
|
+
#
|
|
1619
|
+
# One or more Hashes like this:
|
|
1620
|
+
# {
|
|
1621
|
+
# "version": "143.0.7499.170",
|
|
1622
|
+
# "releaseDate": "2025-12-18T20:31:01Z",
|
|
1623
|
+
# "standalone": true,
|
|
1624
|
+
# "minimumOperatingSystem": "12.0",
|
|
1625
|
+
# "rebootRequired": false,
|
|
1626
|
+
# "killApps": [
|
|
1627
|
+
# {
|
|
1628
|
+
# "appName": "Google Chrome"
|
|
1629
|
+
# }
|
|
1630
|
+
# ],
|
|
1631
|
+
# "absoluteOrderId": "0"
|
|
1632
|
+
# }
|
|
1633
|
+
#
|
|
1634
|
+
# @param version [String, Symbol, nil] If a string, only return info about that version, if :latest,
|
|
1635
|
+
# only the latest version, otherwise all available versions known by the patch source.
|
|
1636
|
+
#
|
|
1637
|
+
# @param refresh [Boolean] re-read the data from the Jamf Pro API
|
|
1638
|
+
#
|
|
1639
|
+
# @return [Array<Hash>] Data about available patch versions for this title
|
|
1640
|
+
################################
|
|
1641
|
+
def patch_versions(version: nil, refresh: false)
|
|
1642
|
+
@patch_versions = nil if refresh
|
|
1643
|
+
@patch_versions ||= []
|
|
1644
|
+
|
|
1645
|
+
if @patch_versions.empty?
|
|
1646
|
+
page = 0
|
|
1647
|
+
loop do
|
|
1648
|
+
jpapi_path = "#{Xolo::Server::JPAPI_PATCH_TITLE_ENDPOINT}/#{jamf_patch_title_id}/definitions?page=#{page}&page-size=1000&sort=absoluteOrderId%3Aasc"
|
|
1649
|
+
log_debug "Jamf: Fetching patch versions for title '#{title}' from Jamf API endpoint '#{jpapi_path}'"
|
|
1650
|
+
|
|
1651
|
+
data = jamf_cnx.jp_get jpapi_path
|
|
1652
|
+
break if data[:results].empty?
|
|
1653
|
+
|
|
1654
|
+
@patch_versions += data[:results]
|
|
1655
|
+
page += 1
|
|
1656
|
+
end # loop
|
|
1657
|
+
end # if
|
|
1658
|
+
|
|
1659
|
+
case version
|
|
1660
|
+
when nil
|
|
1661
|
+
@patch_versions
|
|
1662
|
+
when :latest
|
|
1663
|
+
@patch_versions.select { |p| p[:absoluteOrderId] == '0' }
|
|
1664
|
+
else
|
|
1665
|
+
@patch_versions.select { |p| p[:version] == version }
|
|
1666
|
+
end # case
|
|
1667
|
+
end # patch_versions
|
|
1668
|
+
|
|
1657
1669
|
end # TitleJamfPro
|
|
1658
1670
|
|
|
1659
1671
|
end # Mixins
|