Module: Xolo::Server::Mixins::TitleJamfAccess
- Included in:
- Title
- Defined in:
- lib/xolo/server/mixins/title_jamf_access.rb
Overview
This is mixed in to Xolo::Server::Title to define Title-related access to the Jamf Pro server
Class Method Summary collapse
-
.included(includer) ⇒ Object
when this module is included.
Instance Method Summary collapse
-
#accept_jamf_patch_ea ⇒ void
This method should only be called when we expect to need to accept the EA - not only when we first activate a title with a version script, but when the version_script has changed, or been added, replacing app_name and app_bundle_id.
-
#accept_jamf_patch_ea_via_api ⇒ void
API call to accept the version-script EA in Jamf Pro This never happens for subscribed titles.
-
#activate_jamf_patch_title ⇒ Object
activate the patch title in jamf, whatever it’s source.
-
#add_title_to_self_service(pol = nil) ⇒ void
Add the jamf_manual_install_released_policy to self service if needed.
-
#auto_accept_patch_ea_in_thread ⇒ Object
Wait for up to an hour for Jamf to notice that our TEd EA needs to be accepted, and then do it.
-
#configure_jamf_expire_policy ⇒ Object
Configure the expiration policy.
-
#configure_jamf_installed_group ⇒ void
Set the configuration of jamf_installed_group.
-
#configure_jamf_manual_install_released_policy(pol) ⇒ void
Configure the settings for the manual_install_released_policy Be sure to call .save on the policy after this to save the changes.
-
#configure_jamf_uninstall_policy(pol = nil) ⇒ Object
Configure the uninstall policy.
-
#configure_jamf_uninstall_script ⇒ void
Configure the uninstall script in jamf with our uninstall_script contents.
-
#configure_pol_for_self_service(pol = nil) ⇒ void
configure the self-service settings of the manual_install_released_policy NOTE this doesn’t actually add it to self service, just configures the settings See add_title_to_self_service.
-
#create_jamf_manual_install_released_policy ⇒ Object
The manual install policy for the current release is always scoped to all computers, with exclusions.
-
#create_title_in_jamf ⇒ void
Create title-level things in jamf when creating a title.
- #delete_jamf_expire_policy ⇒ Object
-
#delete_jamf_frozen_group ⇒ void
Delete the ‘frozen’ static group.
-
#delete_jamf_installed_group ⇒ void
Delete the ‘installed’ smart group.
- #delete_jamf_manual_install_released_policy ⇒ Object
-
#delete_jamf_patch_title ⇒ Object
Delete the patch title NOTE: jamf api user must have ‘delete computer ext.
-
#delete_jamf_uninstall_policy ⇒ Object
delete the policy first if it exists.
- #delete_jamf_uninstall_script ⇒ Object
- #delete_lingering_policies_for_title ⇒ Object
-
#delete_title_from_jamf ⇒ Object
Delete an entire title from Jamf Pro alway delete policies first, then scripts, then groups, then EAs, then the patch title.
-
#freeze_computers(computers:) ⇒ Object
freeze some computers see #freeze_or_thaw_computers.
-
#freeze_or_thaw_computers(action:, computers:) ⇒ Hash
Freeze or thaw an array of computers for a title.
-
#frozen_computers ⇒ Hash{String => String}
Return the members of the ‘frozen’ static group for a title.
-
#jamf_active_managed_titles(refresh: false) ⇒ Hash {String => Integer}
The managed titles active in Jamf Patch Management from the Title Editor A hash keyed by the title, with values of the jamf patch title id.
-
#jamf_active_subscribed_titles(refresh: false) ⇒ Hash {String => Integer}
The subscribed xolo titles that are active in Jamf Patch Management and their Jamf::PatchTitle id.
-
#jamf_available_managed_titles ⇒ Array<String>
The titles available from the Title Editor via its Jamf Patch Source.
-
#jamf_expire_policy ⇒ Jamf::Policy
Create or fetch the policy that expires a title.
-
#jamf_expire_policy_exist? ⇒ Boolean
Does the jamf_expire_policy exist?.
-
#jamf_expire_policy_url ⇒ String
The URL for the uninstall policy in Jamf Pro.
-
#jamf_frozen_group ⇒ Jamf::ComputerGroup?
Create or fetch static in jamf that contains macs with this title ‘frozen’ If we are deleting and it doesn’t exist, return nil.
-
#jamf_frozen_group_exist? ⇒ Boolean
Does the jamf_frozen_group exist?.
-
#jamf_frozen_group_url ⇒ String
The URL for the Frozen static group in Jamf Pro.
-
#jamf_gui_url ⇒ String
The start of the Jamf Pro URL for GUI/WebApp access.
-
#jamf_installed_group ⇒ Jamf::ComputerGroup?
Create or fetch he smartgroup in jamf that contains all macs with any version of this title installed.
-
#jamf_installed_group_criteria ⇒ Array<Jamf::Criteriable::Criterion>
The criteria for the smart group in Jamf that contains all Macs with any version of this title installed.
-
#jamf_installed_group_exist? ⇒ Boolean
Does the jamf_installed_group exist?.
-
#jamf_installed_group_url ⇒ String
The URL for the Frozen statig group in Jamf Pro.
-
#jamf_managed_patch_source ⇒ Jamf::PatchSource
The Jamf Patch Source that is connected to the Title Editor This must be manually configured in the Jamf server and the Xolo server.
-
#jamf_managed_title_available? ⇒ Boolean
Is this xolo title available in Jamf?.
-
#jamf_manual_install_released_policy ⇒ Jamf::Policy
Create or fetch the manual install policy for the currently released version.
-
#jamf_manual_install_released_policy_exist? ⇒ Boolean
Does the jamf_manual_install_released_policy exist?.
-
#jamf_manual_install_released_policy_url ⇒ String
The URL for the manual install policy in Jamf Pro.
-
#jamf_patch_ea_awaiting_acceptance? ⇒ Boolean
Does the Jamf Title currently need its EA to be accepted, according to Jamf Pro?.
-
#jamf_patch_ea_contents ⇒ String?
the script contents of the Jamf Patch EA that comes from our version_script.
-
#jamf_patch_ea_data ⇒ Hash
The version_script as a Jamf Extension Attribute, once the title as been activated in Jamf.
-
#jamf_patch_ea_matches_version_script? ⇒ Boolean?
Does the EA for this title in Jamf match the version script we know about?.
-
#jamf_patch_ea_url ⇒ String
The URL for the Patch EA in Jamf Pro.
-
#jamf_patch_title(refresh: false) ⇒ Jamf::PatchTitle?
Create or fetch the patch title object for this xolo title.
-
#jamf_patch_title_url ⇒ String
The URL for the Patch Title in Jamf Pro.
-
#jamf_title_active? ⇒ Boolean
Is this xolo title currently active in Jamf?.
-
#jamf_uninstall_policy ⇒ Jamf::Policy
Create or fetch the policy that runs the jamf uninstall script.
-
#jamf_uninstall_policy_exist? ⇒ Boolean
Does the jamf_uninstall_policy exist?.
-
#jamf_uninstall_policy_url ⇒ String
The URL for the uninstall policy in Jamf Pro.
-
#jamf_uninstall_script ⇒ Jamf::Script
Create or fetch the script that uninstalls this title from a Mac.
-
#jamf_uninstall_script_exist? ⇒ Boolean
Does the uninstall script exist in jamf?.
-
#jamf_uninstall_script_url ⇒ String
The URL for the uninstall script in Jamf Pro.
-
#need_to_accept_jamf_patch_ea? ⇒ Boolean
Do we need to accept the patch ea in jamf?.
-
#need_to_delete_jamf_uninstall_script? ⇒ Boolean
do we need to delete the uninstall script stuff in jamf?.
-
#need_to_update_description? ⇒ Boolean
do we need to update the description? True if our incoming changes include :description.
-
#need_to_update_expiration? ⇒ Boolean
do we need to create or delete the expire policy? True if our incoming changes include :expiration.
-
#need_to_update_jamf_uninstall_script? ⇒ Boolean
do we need to update the uninstall scriptin jamf? true if our incoming changes include :uninstall_script OR :uninstall_ids and the new value of at least one of them is not empty.
-
#patch_report(vers: nil) ⇒ Arrah<Hash>
Get the patch report for this title.
-
#patch_versions(version: nil, refresh: false) ⇒ Array<Hash>
Returns an array of known patch versions for this title from Jamf These are not necessarily in xolo, but they are available from the Patch Source.
-
#remove_title_from_self_service(pol = nil) ⇒ void
Add the jamf_manual_install_released_policy to self service if needed.
-
#repair_frozen_group ⇒ Object
repair the frozen group.
-
#repair_jamf_expire_policy ⇒ Object
repair the expire policy in jamf.
-
#repair_jamf_manual_install_released_policy ⇒ Object
repair the jamf_manual_install_released_policy - the policy that installs whatever is the current release.
-
#repair_jamf_title_objects ⇒ Object
Repair this title in Jamf Pro - TODO: activate title in patch mgmt - TODO: Accept Patch EA - title-installed smart group ‘xolo-<title>-installed’ - frozen static group ‘xolo-<title>-frozen’ - manual/SSvc install-current-release policy ‘xolo-<title>-install’ - trigger ‘xolo-<title>-install’ - ssvc icon - ssvc category - description - if uninstallable - uninstall script ‘xolo-<title>-uninstall’ - uninstall policy ‘xolo-<title>-uninstall’ - if expirable - expire policy ‘xolo-<title>-expire’ - trigger ‘xolo-<title>-expire’.
-
#repair_jamf_uninstall_policy ⇒ Object
repair the uninstall script and policy in jamf.
-
#repair_jamf_uninstall_script ⇒ Object
repair the uninstall script and policy in jamf.
-
#run_autopkg_recipe ⇒ Object
run the autopkg recipe if defined See Helpers::AutoPkg for more details.
-
#thaw_computers(computers:) ⇒ Object
thaw some computers see #freeze_or_thaw_computers.
-
#toggle_jamf_manual_install_released_policy(pol, vobj = nil) ⇒ Object
enable or disable the manual install policy for the current release, depending on whether or not we have a released version return [void].
-
#update_description_in_jamf ⇒ void
Update the description in Jamfy places it appears At the moment, this is only the manual install policy if its in self service.
-
#update_ssvc ⇒ Object
Update whether or not we are in self service, based on the setting in the title.
-
#update_title_in_jamf ⇒ void
Apply any changes to Jamf as needed Mostly this just sets flags indicating what needs to be updated in the various version-related things in jamf - policies, self service, etc.
-
#update_versions_for_title_changes_in_jamf ⇒ void
If any title changes require updates to existing versions in Jamf, this loops thru the versions and applies them.
-
#wait_for_managed_title_to_become_available ⇒ Object
wait up to 60secs for a managed title to become available to be activated subscribed titles are already available.
Class Method Details
.included(includer) ⇒ Object
when this module is included
37 38 39 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 37 def self.included(includer) Xolo.verbose_include includer, self end |
Instance Method Details
#accept_jamf_patch_ea ⇒ void
This method returns an undefined value.
This method should only be called when we expect to need to accept the EA - not only when we first activate a title with a version script, but when the version_script has changed, or been added, replacing app_name and app_bundle_id.
If the EA needs acceptance when this method starts, we accept it and we’re done.
If not (there is no EA, or it’s already accepted) then we spin off a thread that waits up to an hour for Jamf to notice the change from the Title Editor and require re-acceptance.
As soon as we see that Jamf shows accepted: false, we’ll accept it and be done.
If we make it for an hour and never see the expected need for acceptance, we log it and send an alert about it.
TODO: when this is implemented in ruby-jss, use the implementation
NOTE: PATCHing the ea of the title requires CRUD privs for computer ext attrs
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 357 def accept_jamf_patch_ea # give the server a moment to catch up with the new EA before we check on it log_debug "Jamf: Checking if we need to accept the version-script EA for title '#{title}'" sleep 5 awating_acceptance = jamf_patch_ea_awaiting_acceptance? # return with warning if we aren't auto-accepting, or for all subscribed titles if awating_acceptance && (subscribed? || !Xolo::Server.config.jamf_auto_accept_xolo_eas) 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." progress msg, log: :warn, alert: true log_debug 'Admin informed about accepting EA/version-script manually' return end return unless need_to_accept_jamf_patch_ea? # this is true if the Jamf server already knows it needs to be accepted # so just do it now if jamf_patch_ea_awaiting_acceptance? progress "Jamf: Auto-accepting use of version-script ExtensionAttribute '#{ted_ea_key}'", log: :info accept_jamf_patch_ea_via_api return end # If not, we are here because we expect it will need acceptance soon # So we call this method to wait for Jamf to notice that, # checking in the background for up to an hour. auto_accept_patch_ea_in_thread end |
#accept_jamf_patch_ea_via_api ⇒ void
This method returns an undefined value.
API call to accept the version-script EA in Jamf Pro This never happens for subscribed titles
TODO: when this gets implemented in ruby-jss, use that implementation
520 521 522 523 524 525 526 527 528 529 530 531 532 533 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 520 def accept_jamf_patch_ea_via_api patchdata = <<~ENDPATCHDATA { "extensionAttributes": [ { "accepted": true, "eaId": "#{ted_ea_key}" } ] } ENDPATCHDATA jamf_cnx.jp_patch "v2/patch-software-title-configurations/#{jamf_patch_title_id}", patchdata log_debug "Jamf: Auto-accepted ExtensionAttribute '#{ted_ea_key}'" end |
#activate_jamf_patch_title ⇒ Object
activate the patch title in jamf, whatever it’s source
1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1240 def activate_jamf_patch_title if jamf_title_active? log_debug "Jamf: Title '#{title}' is already active in Jamf Patch" return end # patch_source and title_id are required when adding subbed titles # but pre-defined for managed if managed? log_debug "Jamf: Title '#{title}' is managed, so using pre-defined patch source and title_id" log_debug "Jamf: Display Name in managed?: #{display_name}" self.patch_source = Xolo::Server.config.ted_patch_source self.title_id = title log_debug "Jamf: Display Name in managed? after setting patch_source and title_id: #{display_name}" # display name is required for managed titles, but will be empty for subbed # so for subbed, we look it up from the patch source else log_debug "Jamf: Title '#{title}' is subscribed, so looking up patch source and title_id from" log_debug "Jamf: Display Name in NOT managed?: #{display_name}" if display_name.pix_empty? self.display_name = Jamf::PatchSource.available_titles(patch_source, cnx: jamf_cnx).select { |t| t[:name_id] == title_id }.first&.dig :app_name end end # if managed log_debug "Jamf: class: #{self.class}, display_name: #{display_name}, patch_source: #{patch_source}, title_id: #{title_id}" msg = "Jamf: Activating Patch Title '#{display_name}' (#{title}) from the Patch Source '#{patch_source}'" progress msg, log: :info jamf_patch_title = Jamf::PatchTitle.create( name: display_name, source: patch_source, name_id: title_id, cnx: jamf_cnx ) jamf_patch_title.category = Xolo::Server::JAMF_XOLO_CATEGORY self.jamf_patch_title_id = jamf_patch_title.save log_debug "Activated Jamf Patch Title '#{display_name}' (#{title}) with id #{jamf_patch_title_id}" jamf_patch_title end |
#add_title_to_self_service(pol = nil) ⇒ void
This method returns an undefined value.
Add the jamf_manual_install_released_policy to self service if needed
1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1488 def add_title_to_self_service(pol = nil) pol ||= jamf_manual_install_released_policy unless pol.in_self_service? msg = "Jamf: Adding Manual Install Policy '#{pol.name}' to Self Service." progress msg, log: :info pol.add_to_self_service end configure_pol_for_self_service(pol) pol.save end |
#auto_accept_patch_ea_in_thread ⇒ Object
Wait for up to an hour for Jamf to notice that our TEd EA needs to be accepted, and then do it
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 391 def auto_accept_patch_ea_in_thread # don't do this if there's already one running for this instance if @auto_accept_ea_thread&.alive? log_debug "Jamf: auto_accept_ea_thread already running. Caller: #{caller_locations.first}" return end progress "Jamf: version-script ExtAttr for this title '#{ted_ea_key}' will be auto-accepted when Jamf sees the changes in the Title Editor" @auto_accept_ea_thread = Thread.new do log_debug "Jamf: Starting auto_accept_ea_thread for #{title}" start_time = Time.now max_time = start_time + Xolo::Server::MAX_JAMF_WAIT_FOR_TITLE_EDITOR start_time = start_time.strftime '%F %T' did_it = false while Time.now < max_time sleep 30 # refresh our jamf connection cuz it might expire if this takes a while, esp if using # an APIClient jamf_cnx(refresh: true) if jamf_cnx.token.secs_remaining < 90 log_debug "Jamf: checking for expected (re)acceptance of version-script ExtensionAttribute '#{ted_ea_key}' since #{start_time}" next unless jamf_patch_ea_awaiting_acceptance? accept_jamf_patch_ea_via_api log_info "Jamf: Auto-accepted use of version-script ExtensionAttribute '#{ted_ea_key}'" did_it = true break end # while unless did_it msg = "Jamf: Expected to (re)accept version-script ExtensionAttribute '#{ted_ea_key}', but Jamf hasn't seen the change in over #{Xolo::Server::MAX_JAMF_WAIT_FOR_TITLE_EDITOR} secs. Please investigate." log_error msg, alert: true end end # thread @auto_accept_ea_thread.name = "auto_accept_ea_thread for #{title}" end |
#configure_jamf_expire_policy ⇒ Object
Configure the expiration policy
1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1054 def configure_jamf_expire_policy pol = jamf_expire_policy pol.category = Xolo::Server::JAMF_XOLO_CATEGORY pol.run_command = "#{Xolo::Server::Title::CLIENT_EXPIRE_COMMAND} #{title}" pol.set_trigger_event :checkin, true pol.set_trigger_event :custom, jamf_expire_policy_name pol.scope.add_target(:computer_group, jamf_installed_group_name) pol.scope.set_exclusions :computer_groups, [valid_forced_exclusion_group_name] if valid_forced_exclusion_group_name pol.frequency = :daily pol.enable pol.save end |
#configure_jamf_installed_group ⇒ void
This method returns an undefined value.
Set the configuration of jamf_installed_group
782 783 784 785 786 787 788 789 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 782 def configure_jamf_installed_group progress "Jamf: Configuring smart group '#{jamf_installed_group_name}'", log: :info jamf_installed_group.criteria = Jamf::Criteriable::Criteria.new(jamf_installed_group_criteria) jamf_installed_group.save log_debug 'Jamf: Sleeping 30 secs to let Jamf server see changes to Installed smart group.' sleep 30 end |
#configure_jamf_manual_install_released_policy(pol) ⇒ void
This method returns an undefined value.
Configure the settings for the manual_install_released_policy Be sure to call .save on the policy after this to save the changes.
1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1403 def configure_jamf_manual_install_released_policy(pol) pol.category = Xolo::Server::JAMF_XOLO_CATEGORY pol.set_trigger_event :checkin, false pol.set_trigger_event :custom, jamf_manual_install_released_policy_name pol.frequency = :ongoing pol.recon = false pol.scope.set_all_targets # clear any existing packages pol.package_names.each { |pkg_name| pol.remove_package pkg_name } toggle_jamf_manual_install_released_policy pol # figure out the exclusions. # # explicit exlusions for the title excls = changes_for_update&.key?(:excluded_groups) ? changes_for_update[:excluded_groups][:new].dup : excluded_groups.dup excls ||= [] # plus the frozen group excls << jamf_frozen_group_name # plus any forced group from the server config excls << valid_forced_exclusion_group_name if valid_forced_exclusion_group_name # NOTE: we do not exclude existing installs, so that manual re-installs can be a thing. log_debug "Setting exclusions for manual install policy for current release: #{excls}" pol.scope.set_exclusions :computer_groups, excls if self_service? add_title_to_self_service(pol) else remove_title_from_self_service(pol) end end |
#configure_jamf_uninstall_policy(pol = nil) ⇒ Object
Configure the uninstall policy
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 688 def configure_jamf_uninstall_policy(pol = nil) progress "Jamf: Configuring uninstall policy '#{jamf_uninstall_policy_name}'", log: :info pol ||= jamf_uninstall_policy pol.category = Xolo::Server::JAMF_XOLO_CATEGORY pol.add_script jamf_uninstall_script_name pol.set_trigger_event :checkin, false pol.set_trigger_event :custom, jamf_uninstall_policy_name # pol.scope.add_target(:computer_group, jamf_installed_group_name) # all targets, cus jamf doesn't like some policies with scoped # smart groups using 'latest version' pol.scope.set_all_targets pol.scope.set_exclusions :computer_groups, [valid_forced_exclusion_group_name] if valid_forced_exclusion_group_name pol.frequency = :ongoing pol.enable pol.save end |
#configure_jamf_uninstall_script ⇒ void
This method returns an undefined value.
Configure the uninstall script in jamf with our uninstall_script contents
590 591 592 593 594 595 596 597 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 590 def configure_jamf_uninstall_script # if we don't have an uninstall script, nothing to do, it will be deleted elsewhere return unless uninstall_script_contents progress "Jamf: Congfiguring the uninstall script '#{jamf_uninstall_script_name}'", log: :info jamf_uninstall_script.code = uninstall_script_contents jamf_uninstall_script.save end |
#configure_pol_for_self_service(pol = nil) ⇒ void
This method returns an undefined value.
configure the self-service settings of the manual_install_released_policy NOTE this doesn’t actually add it to self service, just configures the settings See add_title_to_self_service
1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1555 def configure_pol_for_self_service(pol = nil) pol ||= jamf_manual_install_released_policy new_cat = changes_for_update&.dig(:self_service_category, :new) || self_service_category if new_cat progress "Jamf: Setting Self Service category to '#{new_cat}'", log: :debug # clear existing categories, re-add correct one pol.self_service_categories.each { |cat| pol.remove_self_service_category cat } pol.add_self_service_category new_cat if new_cat end new_display_name = changes_for_update&.dig(:self_service_display_name, :new) || display_name progress "Jamf: Setting Self Service display name to '#{new_display_name}'", log: :debug pol.self_service_display_name = new_display_name new_desc = changes_for_update&.dig(:self_service_description, :new) || description progress "Jamf: Setting Self Service description to '#{new_desc}'", log: :debug pol.self_service_description = new_desc pol. = Xolo::Server::Title::SELF_SERVICE_INSTALL_BTN_TEXT return unless ssvc_icon_file progress 'Jamf: Uploading Self Service icon', log: :debug pol.save # won't do anything unless needed, but has to exist before we can upload icons pol.upload :icon, ssvc_icon_file # re-fetch the pol to get the icon id self.ssvc_icon_id = Jamf::Policy.fetch(id: pol.id, cnx: jamf_cnx).icon.id end |
#create_jamf_manual_install_released_policy ⇒ Object
The manual install policy for the current release is always scoped to all
computers, with exclusions
The policy has a custom trigger, or can be installed via self service if desired
1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1387 def create_jamf_manual_install_released_policy msg = "Jamf: Creating manual install policy for current release: '#{jamf_manual_install_released_policy_name}'" progress msg, log: :info pol = Jamf::Policy.create name: jamf_manual_install_released_policy_name, cnx: jamf_cnx configure_jamf_manual_install_released_policy(pol) pol.save pol end |
#create_title_in_jamf ⇒ void
This method returns an undefined value.
Create title-level things in jamf when creating a title.
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 62 def create_title_in_jamf log_debug "Display Name in create_title_in_jamf: #{display_name}" # create/activate the Jamf::PatchTitle # this notes the jamf id of the PatchTitle # and sets the display name if needed for subbed titles jamf_patch_title # This creates the installed group # must happen after activating the title in jamf jamf_installed_group if uninstall_script || !uninstall_ids.pix_empty? configure_jamf_uninstall_script # this creates the policy to use the script # must happen after the uninstall script is created jamf_uninstall_policy # this creates the expire policy if needed jamf_expire_policy if expiration && !expire_paths.pix_empty? end # Create the static group that will contain computers where this title is 'frozen' # Just calling this will create it if it doesn't exist. jamf_frozen_group # This either notifies, or does it # TODO: EAs for subscribed titles can change at any time and need # re-accepted - Notifications must happen. accept_jamf_patch_ea end |
#delete_jamf_expire_policy ⇒ Object
1068 1069 1070 1071 1072 1073 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1068 def delete_jamf_expire_policy return unless jamf_expire_policy_exist? progress "Jamf: Deleting expiration policy '#{jamf_expire_policy_name}'", log: :info jamf_expire_policy.delete end |
#delete_jamf_frozen_group ⇒ void
This method returns an undefined value.
Delete the ‘frozen’ static group
1001 1002 1003 1004 1005 1006 1007 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1001 def delete_jamf_frozen_group grp_id = Jamf::ComputerGroup.valid_id jamf_frozen_group_name, cnx: jamf_cnx return unless grp_id progress "Jamf: Deleting static group '#{jamf_frozen_group_name}'", log: :info Jamf::ComputerGroup.delete grp_id, cnx: jamf_cnx end |
#delete_jamf_installed_group ⇒ void
This method returns an undefined value.
Delete the ‘installed’ smart group
820 821 822 823 824 825 826 827 828 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 820 def delete_jamf_installed_group return unless jamf_installed_group_exist? progress "Jamf: Deleting smart group '#{jamf_installed_group_name}'", log: :info jamf_installed_group.delete # give the server time to see the deletion log_debug 'Sleeping to let server see deletion of smart group' sleep 10 end |
#delete_jamf_manual_install_released_policy ⇒ Object
1476 1477 1478 1479 1480 1481 1482 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1476 def delete_jamf_manual_install_released_policy return unless jamf_manual_install_released_policy_exist? msg = "Jamf: Deleting the manual/Self Service install policy for the current release '#{jamf_manual_install_released_policy_name}'" progress msg, log: :info jamf_manual_install_released_policy.delete end |
#delete_jamf_patch_title ⇒ Object
Delete the patch title NOTE: jamf api user must have ‘delete computer ext. attribs’ permmissions
1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1308 def delete_jamf_patch_title log_debug "Jamf: Deleting patch title '#{display_name}' (#{title})" unless jamf_title_active? log_debug "Jamf: Patch title '#{display_name}' (#{title}) is not active in Jamf, nothing to delete" return end # # subscribed titles often have name_id's like "1B7" # # whereas managed titles have name_id's that are the same as the title, # # so we have to look up the id differently for subbed vs managed # key = subscribed? ? title_id : title # pt_id = Jamf::PatchTitle.map_all(:id, to: :name_id, cnx: jamf_cnx).invert[key] # unless pt_id # log_debug "Jamf: Cannot find patch title '#{display_name}' (#{title}) in Jamf, cannot delete" # return # end # # 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 # unless pt_id.to_s == jamf_patch_title_id.to_s # 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." # end msg = "Jamf: Deleting (deactivating) title '#{display_name}' (#{title}}) in Jamf Patch Management" progress msg, log: :info Jamf::PatchTitle.delete jamf_patch_title_id, cnx: jamf_cnx end |
#delete_jamf_uninstall_policy ⇒ Object
delete the policy first if it exists
717 718 719 720 721 722 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 717 def delete_jamf_uninstall_policy return unless jamf_uninstall_policy_exist? progress "Jamf: Deleting uninstall policy '#{jamf_uninstall_policy_name}'", log: :info jamf_uninstall_policy.delete end |
#delete_jamf_uninstall_script ⇒ Object
618 619 620 621 622 623 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 618 def delete_jamf_uninstall_script return unless jamf_uninstall_script_exist? progress "Jamf: Deleting uninstall script '#{jamf_uninstall_script_name}'", log: :info jamf_uninstall_script.delete end |
#delete_lingering_policies_for_title ⇒ Object
196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 196 def delete_lingering_policies_for_title Jamf::Policy.all_names(:refresh, cnx: jamf_cnx).each do |polname| next unless polname.start_with? jamf_obj_name_pfx polid = Jamf::Policy.valid_id(polname, cnx: jamf_cnx) next unless polid progress "Jamf: Deleting lingering policy #{polname}, possibly from a failed version action.", log: :info Jamf::Policy.delete(polid, cnx: jamf_cnx) end end |
#delete_title_from_jamf ⇒ Object
Delete an entire title from Jamf Pro alway delete policies first, then scripts, then groups, then EAs, then the patch title
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 174 def delete_title_from_jamf # ORDER MATTERS delete_jamf_expire_policy delete_jamf_uninstall_policy delete_jamf_manual_install_released_policy delete_jamf_uninstall_script delete_lingering_policies_for_title sleep 5 # must delete this group before the patch title # since the group criteria references the patch title delete_jamf_installed_group sleep 5 delete_jamf_patch_title # static group deleted last, # was used in scopes for patch and normal policies delete_jamf_frozen_group end |
#freeze_computers(computers:) ⇒ Object
freeze some computers see #freeze_or_thaw_computers
919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 919 def freeze_computers(computers:) result = {} freezes_to_log = [] comp_names = Jamf::Computer.all_names cnx: jamf_cnx grp_members = jamf_frozen_group.member_names computers.each do |comp| if grp_members.include? comp log_info "Not freezing computer '#{comp}' for title '#{title}', already frozen" result[comp] = "#{Xolo::ERROR}: Already frozen" elsif comp_names.include? comp log_info "Freezing computer '#{comp}' for title '#{title}'" jamf_frozen_group.add_member comp result[comp] = Xolo::OK freezes_to_log << comp else log_debug "Cannot freeze computer '#{comp}' for title '#{title}', no such computer" result[comp] = "#{Xolo::ERROR}: No computer with that name" end # if comp_names.include end # computers.each [result, freezes_to_log] end |
#freeze_or_thaw_computers(action:, computers:) ⇒ Hash
Freeze or thaw an array of computers for a title
887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 887 def freeze_or_thaw_computers(action:, computers:) return unless %i[freeze thaw].include? action # convert to an array if it's a single string computers = [computers].flatten result, changes_to_log = if action == :thaw thaw_computers(computers: computers) else freeze_computers(computers: computers) end # if action == jamf_frozen_group.save unless changes_to_log.empty? action_msg = if action == :freeze "Froze computers: #{changes_to_log.join(', ')}" else "Thawed computers: #{changes_to_log.join(', ')}" end log_change msg: action_msg end result end |
#frozen_computers ⇒ Hash{String => String}
Return the members of the ‘frozen’ static group for a title
979 980 981 982 983 984 985 986 987 988 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 979 def frozen_computers members = {} comps = jamf_frozen_group.member_names comps_to_users = Jamf::Computer.map_all :name, to: :username, cnx: jamf_cnx comps.each { |comp| members[comp] = comps_to_users[comp] || 'unknown' } members end |
#jamf_active_managed_titles(refresh: false) ⇒ Hash {String => Integer}
The managed titles active in Jamf Patch Management from the Title Editor A hash keyed by the title, with values of the jamf patch title id
1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1171 def jamf_active_managed_titles(refresh: false) @jamf_active_managed_titles = nil if refresh return @jamf_active_managed_titles if @jamf_active_managed_titles @jamf_active_managed_titles = {} all_patch_titles = Jamf::PatchTitle.all(cnx: jamf_cnx) active_from_ted = all_patch_titles.select do |t| # log_debug "Jamf: Checking if active patch title '#{t[:name]}' with id #{t[:id]} is from the Title Editor's patch source" t[:source_id] == jamf_managed_patch_source.id end managed_titles = server_app_instance.managed_title_objects.select(&:managed?).map(&:title) active_from_ted.each do |t| @jamf_active_managed_titles[t[:name_id]] = t[:id] if managed_titles.include? t[:name_id] end @jamf_active_managed_titles end |
#jamf_active_subscribed_titles(refresh: false) ⇒ Hash {String => Integer}
Returns The subscribed xolo titles that are active in Jamf Patch Management and their Jamf::PatchTitle id.
1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1194 def jamf_active_subscribed_titles(refresh: false) @jamf_active_subscribed_titles = nil if refresh return @jamf_active_subscribed_titles if @jamf_active_subscribed_titles @jamf_active_subscribed_titles = {} all_active_patchtitles = Jamf::PatchTitle.all :refresh, cnx: jamf_cnx server_app_instance.subscribed_title_objects.each do |st| next unless all_active_patchtitles.any? do |pt| pt[:source_id] == st.jamf_patch_source_id && pt[:name_id] == st.title_id end @jamf_active_subscribed_titles[st.title] = pt[:id] end @jamf_active_subscribed_titles end |
#jamf_available_managed_titles ⇒ Array<String>
The titles available from the Title Editor via its Jamf Patch Source. These are titles have have been enabled in the Title Editor but have not yet been activated in Jamf Patch.
available_titles returns a Hash for each available title, with these keys:
name_id: [String] The Xolo 'title' or the Title Editor 'id'
current_version: [String] NOTE: This
may be a version that is in 'pilot' from Xolo's POV, but
from the TEd's POV, it has been made available to Jamf.
publisher: [String]
last_modified: [Time]
app_name: [String] The Xolo 'display_name'
but we map it to just the name_id
1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1137 def jamf_available_managed_titles # Don't cache this in an instance var, it changes during the # life of our title instance # jamf_managed_patch_source.available_titles.map { |t| t[:name_id] } # Also NOTE: "available" means not only enabled # in the title editor, but also not already active in jamf. # So any given title will either be here or in # jamf_active_managed_titles, but never both. jamf_managed_patch_source.available_name_ids end |
#jamf_expire_policy ⇒ Jamf::Policy
Create or fetch the policy that expires a title
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1034 def jamf_expire_policy return @jamf_expire_policy if @jamf_expire_policy if jamf_expire_policy_exist? @jamf_expire_policy = Jamf::Policy.fetch name: jamf_expire_policy_name, cnx: jamf_cnx else return if deleting? progress "Jamf: Creating Expiration policy: '#{jamf_expire_policy_name}'", log: :info @jamf_expire_policy = Jamf::Policy.create name: jamf_expire_policy_name, cnx: jamf_cnx configure_jamf_expire_policy end @jamf_expire_policy end |
#jamf_expire_policy_exist? ⇒ Boolean
Returns Does the jamf_expire_policy exist?.
1026 1027 1028 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1026 def jamf_expire_policy_exist? Jamf::Policy.all_names(:refresh, cnx: jamf_cnx).include? jamf_expire_policy_name end |
#jamf_expire_policy_url ⇒ String
Returns the URL for the uninstall policy in Jamf Pro.
1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1089 def jamf_expire_policy_url return @jamf_expire_policy_url if @jamf_expire_policy_url return unless uninstallable? return unless expiration pol_id = Jamf::Policy.valid_id jamf_expire_policy_name, cnx: jamf_cnx return unless pol_id @jamf_expire_policy_url = "#{jamf_gui_url}/policies.html?id=#{pol_id}&o=r" end |
#jamf_frozen_group ⇒ Jamf::ComputerGroup?
Create or fetch static in jamf that contains macs with this title ‘frozen’ If we are deleting and it doesn’t exist, return nil. There really isn’t any configuration or repairing to do, it’s just a static group.
857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 857 def jamf_frozen_group return @jamf_frozen_group if @jamf_frozen_group if jamf_frozen_group_exist? @jamf_frozen_group = Jamf::ComputerGroup.fetch name: jamf_frozen_group_name, cnx: jamf_cnx else return if deleting? progress "Jamf: Creating static group '#{jamf_frozen_group_name}' with no members at the moment", log: :info @jamf_frozen_group = Jamf::ComputerGroup.create( name: jamf_frozen_group_name, type: :static, cnx: jamf_cnx ) @jamf_frozen_group.save end @jamf_frozen_group end |
#jamf_frozen_group_exist? ⇒ Boolean
Returns Does the jamf_frozen_group exist?.
847 848 849 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 847 def jamf_frozen_group_exist? Jamf::ComputerGroup.all_names(:refresh, cnx: jamf_cnx).include? jamf_frozen_group_name end |
#jamf_frozen_group_url ⇒ String
Returns the URL for the Frozen static group in Jamf Pro.
1011 1012 1013 1014 1015 1016 1017 1018 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1011 def jamf_frozen_group_url return @jamf_frozen_group_url if @jamf_frozen_group_url gr_id = Jamf::ComputerGroup.valid_id jamf_frozen_group_name, cnx: jamf_cnx return unless gr_id @jamf_frozen_group_url = "#{jamf_gui_url}/staticComputerGroups.html?id=#{gr_id}&o=r" end |
#jamf_gui_url ⇒ String
Returns The start of the Jamf Pro URL for GUI/WebApp access.
54 55 56 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 54 def jamf_gui_url server_app_instance.jamf_gui_url end |
#jamf_installed_group ⇒ Jamf::ComputerGroup?
Create or fetch he smartgroup in jamf that contains all macs with any version of this title installed. If we are deleting and it doesn’t exist, return nil.
752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 752 def jamf_installed_group return @jamf_installed_group if @jamf_installed_group if jamf_installed_group_exist? @jamf_installed_group = Jamf::ComputerGroup.fetch( name: jamf_installed_group_name, cnx: jamf_cnx ) else return if deleting? progress "Jamf: Creating smart group '#{jamf_installed_group_name}'", log: :info @jamf_installed_group = Jamf::ComputerGroup.create( name: jamf_installed_group_name, type: :smart, cnx: jamf_cnx ) @jamf_installed_group.save configure_jamf_installed_group end @jamf_installed_group end |
#jamf_installed_group_criteria ⇒ Array<Jamf::Criteriable::Criterion>
The criteria for the smart group in Jamf that contains all Macs with any version of this title installed
We use the “Patch Reporting: #display_name” criterion so that we don’t care whether the title uses a version-script or app data.
799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 799 def jamf_installed_group_criteria [ Jamf::Criteriable::Criterion.new( and_or: :and, name: "Patch Reporting: #{display_name}", search_type: 'less than or equal', value: 'Latest Version' ), Jamf::Criteriable::Criterion.new( and_or: :or, name: "Patch Reporting: #{display_name}", search_type: 'is', value: 'Unknown Version' ) ] end |
#jamf_installed_group_exist? ⇒ Boolean
Returns Does the jamf_installed_group exist?.
742 743 744 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 742 def jamf_installed_group_exist? Jamf::ComputerGroup.all_names(:refresh, cnx: jamf_cnx).include? jamf_installed_group_name end |
#jamf_installed_group_url ⇒ String
Returns the URL for the Frozen statig group in Jamf Pro.
832 833 834 835 836 837 838 839 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 832 def jamf_installed_group_url return @jamf_installed_group_url if @jamf_installed_group_url gr_id = Jamf::ComputerGroup.valid_id jamf_installed_group_name, cnx: jamf_cnx return unless gr_id @jamf_installed_group_url = "#{jamf_gui_url}/smartComputerGroups.html?id=#{gr_id}&o=r" end |
#jamf_managed_patch_source ⇒ Jamf::PatchSource
The Jamf Patch Source that is connected to the Title Editor This must be manually configured in the Jamf server and the Xolo server
1109 1110 1111 1112 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1109 def jamf_managed_patch_source @jamf_managed_patch_source ||= Jamf::PatchSource.fetch(name: Xolo::Server.config.ted_patch_source, cnx: jamf_cnx) end |
#jamf_managed_title_available? ⇒ Boolean
Returns Is this xolo title available in Jamf?.
1150 1151 1152 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1150 def jamf_managed_title_available? jamf_available_managed_titles.include? title end |
#jamf_manual_install_released_policy ⇒ Jamf::Policy
Create or fetch the manual install policy for the currently released version. If we are deleting and it doesn’t exist, return nil. Also return nil if we have no version released
1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1358 def jamf_manual_install_released_policy @jamf_manual_install_released_policy ||= if jamf_manual_install_released_policy_exist? Jamf::Policy.fetch(name: jamf_manual_install_released_policy_name, cnx: jamf_cnx) else return if deleting? create_jamf_manual_install_released_policy end end |
#jamf_manual_install_released_policy_exist? ⇒ Boolean
Returns Does the jamf_manual_install_released_policy exist?.
1348 1349 1350 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1348 def jamf_manual_install_released_policy_exist? Jamf::Policy.all_names(:refresh, cnx: jamf_cnx).include? jamf_manual_install_released_policy_name end |
#jamf_manual_install_released_policy_url ⇒ String
Returns the URL for the manual install policy in Jamf Pro.
1371 1372 1373 1374 1375 1376 1377 1378 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1371 def jamf_manual_install_released_policy_url return @jamf_manual_install_released_policy_url if @jamf_manual_install_released_policy_url pol_id = Jamf::Policy.valid_id jamf_manual_install_released_policy_name, cnx: jamf_cnx return unless pol_id @jamf_manual_install_released_policy_url = "#{jamf_gui_url}/policies.html?id=#{pol_id}&o=r" end |
#jamf_patch_ea_awaiting_acceptance? ⇒ Boolean
Does the Jamf Title currently need its EA to be accepted, according to Jamf Pro?
NOTE: Jamf might not see the need for this immediately, so we set and use them to determine if we should wait for this to become true.
440 441 442 443 444 445 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 440 def jamf_patch_ea_awaiting_acceptance? ead = jamf_patch_ea_data return unless ead !ead[:accepted] end |
#jamf_patch_ea_contents ⇒ String?
the script contents of the Jamf Patch EA that comes from our version_script
538 539 540 541 542 543 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 538 def jamf_patch_ea_contents jea_data = jamf_patch_ea_data return unless jea_data && jea_data[:scriptContents] Base64.decode64 jea_data[:scriptContents] end |
#jamf_patch_ea_data ⇒ Hash
The version_script as a Jamf Extension Attribute, once the title as been activated in Jamf.
This is a hash of data returned from the JP API endpoint:
"v2/patch-software-title-configurations/#{jamf_patch_title_id}/extension-attributes"
which has these keys:
:accepted [Boolean] has it been accepted for the title?
:eaId [String] the 'key' of the EA from the title editor
:displayName [String] the displayname from the title editor, for titles
maintained by xolo, it's the same as the eaId
:scriptContent [String] the Base64-encoded script of the EA.
TODO: when this gets implemented in ruby-jss, use that implementation and return the patch title ea object.
NOTE: The title must be activated in Jamf before accessing this.
NOTE: We fetch this hash every time this method is called, since we may
be waiting for jamf to notice that the EA has changed in the Title Editor
and needs re-acceptance
NOTE: While Jamf Patch allows for multiple EAs per title, the Title Editor only
allows for one. So even tho the data comes back in an array, we only care about
the first (and only) value.
507 508 509 510 511 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 507 def jamf_patch_ea_data return unless jamf_patch_title_id jamf_cnx.jp_get("v2/patch-software-title-configurations/#{jamf_patch_title_id}/extension-attributes").first end |
#jamf_patch_ea_matches_version_script? ⇒ Boolean?
Does the EA for this title in Jamf match the version script we know about?
If we don’t have a version script, then we don’t really care what Jamf has at the moment, Jamf’s should go away once it catches up with the title editor.
But if we do have one, and Jamf has something different, we’ll need to accept it, if configured to do so automatically.
This method just tells us the current situation about our version script vs the Jamf Patch EA.
463 464 465 466 467 468 469 470 471 472 473 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 463 def jamf_patch_ea_matches_version_script? # our current version script - nil if we currently don't have one our_version_script = version_script_contents # we don't have one, so if Jamf does at the moment, it'll go away soon # when jamf catches up with the title editor. return unless our_version_script # does jamf's script match ours? our_version_script.chomp == jamf_patch_ea_contents.chomp end |
#jamf_patch_ea_url ⇒ String
Returns the URL for the Patch EA in Jamf Pro.
547 548 549 550 551 552 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 547 def jamf_patch_ea_url return @jamf_patch_ea_url if @jamf_patch_ea_url return unless version_script || (subscribed? && jamf_patch_ea_data) @jamf_patch_ea_url = "#{jamf_patch_title_url}?tab=extension" end |
#jamf_patch_title(refresh: false) ⇒ Jamf::PatchTitle?
Create or fetch the patch title object for this xolo title. If we are deleting and it doesn’t exist, return nil.
1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1218 def jamf_patch_title(refresh: false) @jamf_patch_title = nil if refresh return @jamf_patch_title if @jamf_patch_title # wait up to 60secs for a managed title to become available. # subscribed titles are already available wait_for_managed_title_to_become_available # Jamf::PatchTitle object already active, just fetch it if jamf_patch_title_id # jamf_title_active? || subscribed? @jamf_patch_title = Jamf::PatchTitle.fetch(id: jamf_patch_title_id, cnx: jamf_cnx) # not yet active, so activate/create the Jamf::PatchTitle object else return if deleting? @jamf_patch_title = activate_jamf_patch_title end end |
#jamf_patch_title_url ⇒ String
Returns the URL for the Patch Title in Jamf Pro.
1338 1339 1340 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1338 def jamf_patch_title_url @jamf_patch_title_url ||= "#{jamf_gui_url}/view/computers/patch/#{jamf_patch_title_id}" end |
#jamf_title_active? ⇒ Boolean
Returns Is this xolo title currently active in Jamf?.
1156 1157 1158 1159 1160 1161 1162 1163 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1156 def jamf_title_active? !jamf_patch_title_id.pix_empty? # if subscribed? # jamf_active_subscribed_titles(refresh: true).key? title # else # jamf_active_managed_titles(refresh: true).key? title # end end |
#jamf_uninstall_policy ⇒ Jamf::Policy
Create or fetch the policy that runs the jamf uninstall script
669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 669 def jamf_uninstall_policy return @jamf_uninstall_policy if @jamf_uninstall_policy if jamf_uninstall_policy_exist? @jamf_uninstall_policy = Jamf::Policy.fetch name: jamf_uninstall_policy_name, cnx: jamf_cnx else return if deleting? progress "Jamf: Creating Uninstall policy: '#{jamf_uninstall_policy_name}'", log: :info @jamf_uninstall_policy = Jamf::Policy.create name: jamf_uninstall_policy_name, cnx: jamf_cnx configure_jamf_uninstall_policy(jamf_uninstall_policy) end @jamf_uninstall_policy end |
#jamf_uninstall_policy_exist? ⇒ Boolean
Returns Does the jamf_uninstall_policy exist?.
661 662 663 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 661 def jamf_uninstall_policy_exist? Jamf::Policy.all_names(:refresh, cnx: jamf_cnx).include? jamf_uninstall_policy_name end |
#jamf_uninstall_policy_url ⇒ String
Returns the URL for the uninstall policy in Jamf Pro.
726 727 728 729 730 731 732 733 734 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 726 def jamf_uninstall_policy_url return @jamf_uninstall_policy_url if @jamf_uninstall_policy_url return unless uninstallable? pol_id = Jamf::Policy.valid_id jamf_uninstall_policy_name, cnx: jamf_cnx return unless pol_id @jamf_uninstall_policy_url = "#{jamf_gui_url}/policies.html?id=#{pol_id}&o=r" end |
#jamf_uninstall_script ⇒ Jamf::Script
Create or fetch the script that uninstalls this title from a Mac
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 568 def jamf_uninstall_script return @jamf_uninstall_script if @jamf_uninstall_script if jamf_uninstall_script_exist? @jamf_uninstall_script = Jamf::Script.fetch name: jamf_uninstall_script_name, cnx: jamf_cnx else return if deleting? progress "Jamf: Creating Uninstall script '#{jamf_uninstall_script_name}'", log: :info @jamf_uninstall_script = Jamf::Script.create( name: jamf_uninstall_script_name, cnx: jamf_cnx ) @jamf_uninstall_script.save end @jamf_uninstall_script end |
#jamf_uninstall_script_exist? ⇒ Boolean
Returns Does the uninstall script exist in jamf?.
560 561 562 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 560 def jamf_uninstall_script_exist? Jamf::Script.all_names(:refresh, cnx: jamf_cnx).include? jamf_uninstall_script_name end |
#jamf_uninstall_script_url ⇒ String
Returns the URL for the uninstall script in Jamf Pro.
645 646 647 648 649 650 651 652 653 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 645 def jamf_uninstall_script_url return @jamf_uninstall_script_url if @jamf_uninstall_script_url return unless uninstallable? scr_id = Jamf::Script.valid_id jamf_uninstall_script_name, cnx: jamf_cnx return unless scr_id @jamf_uninstall_script_url = "#{jamf_gui_url}/view/settings/computer-management/scripts/#{scr_id}?tab=script" end |
#need_to_accept_jamf_patch_ea? ⇒ Boolean
Do we need to accept the patch ea in jamf?
True if
-
title activation, and version_script
-
any time version_script changes
-
any time we switch from bundle data to version_script
-
Title#create_ted_ea
-
Title#update_ted_ea
330 331 332 333 334 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 330 def need_to_accept_jamf_patch_ea? return unless managed? @need_to_accept_jamf_patch_ea end |
#need_to_delete_jamf_uninstall_script? ⇒ Boolean
do we need to delete the uninstall script stuff in jamf?
639 640 641 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 639 def need_to_delete_jamf_uninstall_script? uninstall_script_contents.pix_empty? end |
#need_to_update_description? ⇒ Boolean
do we need to update the description? True if our incoming changes include :description
257 258 259 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 257 def need_to_update_description? changes_for_update.key?(:description) end |
#need_to_update_expiration? ⇒ Boolean
do we need to create or delete the expire policy? True if our incoming changes include :expiration
Ignore the expire paths - even when disabling expiration they can stay there, they won’t mean anything.
269 270 271 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 269 def need_to_update_expiration? changes_for_update.key?(:expiration) end |
#need_to_update_jamf_uninstall_script? ⇒ Boolean
do we need to update the uninstall scriptin jamf? true if our incoming changes include :uninstall_script OR :uninstall_ids and the new value of at least one of them is not empty
(in which case we’ll delete it)
607 608 609 610 611 612 613 614 615 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 607 def need_to_update_jamf_uninstall_script? if changes_for_update.key?(:uninstall_script) !changes_for_update[:uninstall_script][:new].pix_empty? elsif changes_for_update.key?(:uninstall_ids) !changes_for_update[:uninstall_ids][:new].pix_empty? else false end end |
#patch_report(vers: nil) ⇒ Arrah<Hash>
Get the patch report for this title. It’s the JPAPI report data with each hash having a frozen: key added
TODO: rework this when all the paging stuff is handled by ruby-jss
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 282 def patch_report(vers: nil) vers = Xolo::Server::Helpers::JamfPro::PATCH_REPORT_UNKNOWN_VERSION if vers == Xolo::UNKNOWN vers &&= CGI.escape vers.to_s page_size = Xolo::Server::Helpers::JamfPro::PATCH_REPORT_JPAPI_PAGE_SIZE page = 0 paged_rsrc = "#{patch_report_rsrc}?page=#{page}&page-size=#{page_size}" paged_rsrc << "&filter=version%3D%3D#{vers}" if vers report = [] loop do data = jamf_cnx.jp_get(paged_rsrc)[:results] log_debug "GOT #{paged_rsrc} >>> results size: #{data.size}" break if data.empty? report += data page += 1 paged_rsrc = "#{patch_report_rsrc}?page=#{page}&page-size=#{page_size}" paged_rsrc << "&filter=version%3D%3D#{vers}" if vers end # log_debug "REPORT: #{report}" frozen_comps = frozen_computers.keys report.each do |h| h[:frozen] = frozen_comps.include? h[:computerName] h[:version] = Xolo::UNKNOWN if h[:version] == Xolo::Server::Helpers::JamfPro::PATCH_REPORT_UNKNOWN_VERSION end report end |
#patch_versions(version: nil, refresh: false) ⇒ Array<Hash>
Returns an array of known patch versions for this title from Jamf These are not necessarily in xolo, but they are available from the Patch Source.
One or more Hashes like this:
{
"version": "143.0.7499.170",
"releaseDate": "2025-12-18T20:31:01Z",
"standalone": true,
"minimumOperatingSystem": "12.0",
"rebootRequired": false,
"killApps": [
{
"appName": "Google Chrome"
}
],
"absoluteOrderId": "0"
}
1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1619 def patch_versions(version: nil, refresh: false) @patch_versions = nil if refresh @patch_versions ||= [] if @patch_versions.empty? page = 0 loop do jpapi_path = "#{Xolo::Server::JPAPI_PATCH_TITLE_ENDPOINT}/#{jamf_patch_title_id}/definitions?page=#{page}&page-size=1000&sort=absoluteOrderId%3Aasc" log_debug "Jamf: Fetching patch versions for title '#{title}' from Jamf API endpoint '#{jpapi_path}'" data = jamf_cnx.jp_get jpapi_path break if data[:results].empty? @patch_versions += data[:results] page += 1 end # loop end # if case version when nil @patch_versions when :latest @patch_versions.select { |p| p[:absoluteOrderId] == '0' } else @patch_versions.select { |p| p[:version] == version } end # case end |
#remove_title_from_self_service(pol = nil) ⇒ void
This method returns an undefined value.
Add the jamf_manual_install_released_policy to self service if needed
1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1505 def remove_title_from_self_service(pol = nil) pol ||= jamf_manual_install_released_policy return unless pol.in_self_service? msg = "Jamf: Removing Manual Install Policy '#{pol.name}' from Self Service." progress msg, log: :info pol.remove_from_self_service pol.save end |
#repair_frozen_group ⇒ Object
repair the frozen group
992 993 994 995 996 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 992 def repair_frozen_group progress 'Jamf: Ensuring frozen static group exists', log: :debug # This creates it if it doesn't exist. Nothing more we can do here. jamf_frozen_group end |
#repair_jamf_expire_policy ⇒ Object
repair the expire policy in jamf
1077 1078 1079 1080 1081 1082 1083 1084 1085 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1077 def repair_jamf_expire_policy if expiration && !expire_paths.pix_empty? progress "Jamf: Repairing expiration policy '#{jamf_expire_policy_name}'" configure_jamf_expire_policy else delete_jamf_expire_policy end end |
#repair_jamf_manual_install_released_policy ⇒ Object
repair the jamf_manual_install_released_policy - the policy that installs whatever is the current release
1466 1467 1468 1469 1470 1471 1472 1473 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1466 def repair_jamf_manual_install_released_policy return unless released_version progress 'Jamf: Repairing the manual/Self Service install policy for the current release' pol = jamf_manual_install_released_policy configure_jamf_manual_install_released_policy(pol) pol.save end |
#repair_jamf_title_objects ⇒ Object
Repair this title in Jamf Pro
-
TODO: activate title in patch mgmt
-
TODO: Accept Patch EA
-
-
title-installed smart group ‘xolo-<title>-installed’
-
frozen static group ‘xolo-<title>-frozen’
-
manual/SSvc install-current-release policy ‘xolo-<title>-install’
-
trigger ‘xolo-<title>-install’
-
ssvc icon
-
ssvc category
-
description
-
-
if uninstallable
-
uninstall script ‘xolo-<title>-uninstall’
-
uninstall policy ‘xolo-<title>-uninstall’
-
if expirable
-
expire policy ‘xolo-<title>-expire’
-
trigger ‘xolo-<title>-expire’
-
-
-
160 161 162 163 164 165 166 167 168 169 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 160 def repair_jamf_title_objects progress "Jamf: Repairing Jamf objects for title '#{title}'", log: :info configure_jamf_installed_group repair_jamf_uninstall_policy repair_jamf_uninstall_script repair_jamf_expire_policy repair_frozen_group repair_jamf_manual_install_released_policy end |
#repair_jamf_uninstall_policy ⇒ Object
repair the uninstall script and policy in jamf
707 708 709 710 711 712 713 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 707 def repair_jamf_uninstall_policy if uninstall_script_contents configure_jamf_uninstall_policy else delete_jamf_uninstall_policy end end |
#repair_jamf_uninstall_script ⇒ Object
repair the uninstall script and policy in jamf
627 628 629 630 631 632 633 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 627 def repair_jamf_uninstall_script if uninstall_script_contents configure_jamf_uninstall_script else delete_jamf_uninstall_script end end |
#run_autopkg_recipe ⇒ Object
run the autopkg recipe if defined See Helpers::AutoPkg for more details
1587 1588 1589 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1587 def run_autopkg_recipe server_app_instance.run_autopkg_recipe self end |
#thaw_computers(computers:) ⇒ Object
thaw some computers see #freeze_or_thaw_computers
947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 947 def thaw_computers(computers:) result = {} thaws_to_log = [] if computers.include? Xolo::TARGET_ALL log_info "Thawing all computers for title: '#{title}'" jamf_frozen_group.clear result[Xolo::TARGET_ALL] = Xolo::OK thaws_to_log << Xolo::TARGET_ALL else grp_members = jamf_frozen_group.member_names computers.each do |comp| if grp_members.include? comp jamf_frozen_group.remove_member comp log_info "Thawed computer '#{comp}' for title '#{title}'" result[comp] = Xolo::OK thaws_to_log << comp else log_debug "Cannot thaw computer '#{comp}' for title '#{title}', not frozen" result[comp] = "#{Xolo::ERROR}: Not frozen" end # if grp_members.include? comp end # computers.each end # if computers.include? [result, thaws_to_log] end |
#toggle_jamf_manual_install_released_policy(pol, vobj = nil) ⇒ Object
enable or disable the manual install policy for the current release, depending on whether or not we have a released version return [void]
1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1442 def toggle_jamf_manual_install_released_policy(pol, vobj = nil) # remove any current pkg payload pol.package_ids.each { |pid| pol.remove_package pid } unless vobj desired_vers = releasing_version || released_version vobj = desired_vers ? version_object(desired_vers) : nil end if vobj progress "Jamf: Setting policy #{jamf_manual_install_released_policy_name} to install the package for version '#{vobj.version}'", log: :info pol.add_package vobj.jamf_pkg_id progress "Jamf: Enabling policy #{jamf_manual_install_released_policy_name}", log: :info pol.enable else progress "Jamf: Disabling policy #{jamf_manual_install_released_policy_name}, no released version", log: :info pol.disable end end |
#update_description_in_jamf ⇒ void
This method returns an undefined value.
Update the description in Jamfy places it appears At the moment, this is only the manual install policy if its in self service. The package notes are updated by the versions themselves via the update_versions_for_title_changes_in_jamf method
237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 237 def update_description_in_jamf return unless need_to_update_description? # Update the manual install policy return unless self_service pol = jamf_manual_install_released_policy return unless pol progress "Jamf: Updating Description for Self Service in policy '#{pol.name}'.", log: :info new_desc = changes_for_update[:description][:new] || description pol.self_service_description = new_desc pol.save end |
#update_ssvc ⇒ Object
Update whether or not we are in self service, based on the setting in the title
1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1519 def update_ssvc pol = jamf_manual_install_released_policy adding_to_ssvc = changes_for_update.dig :self_service, :new updating_config = changes_for_update.dig :self_service_category, :new updating_config ||= changes_for_update.dig :description, :new updating_config ||= changes_for_update.dig :display_name, :new # if adding_to_ssvc is nil, we aren't changing it at all # it must be false to indicate removal. removing_from_ssvc = adding_to_ssvc == false if adding_to_ssvc add_title_to_self_service(pol) elsif updating_config configure_pol_for_self_service(pol) # we should not be in SSvc, remove it, but leave all the settings elsif removing_from_ssvc remove_title_from_self_service(pol) end pol.save # TODO: if we decide to use ssvc in patch policies, loop thru versions to make any changes end |
#update_title_in_jamf ⇒ void
This method returns an undefined value.
Apply any changes to Jamf as needed Mostly this just sets flags indicating what needs to be updated in the various version-related things in jamf - policies, self service, etc.
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 100 def update_title_in_jamf # ORDER MATTERS # if the exclusions have changed update the manual install released policy if changes_for_update[:excluded_groups] progress "Jamf: Updating excluded groups for Manual Released Policy '#{jamf_manual_install_released_policy_name}'." configure_jamf_manual_install_released_policy(jamf_manual_install_released_policy) end # Do we need to update (vs delete) the uninstall script? if need_to_update_jamf_uninstall_script? configure_jamf_uninstall_script configure_jamf_uninstall_policy # this creates the policy to use the script, if needed # which needs both the uninstall script and the installed group to exist jamf_uninstall_policy # or delete it if no longer needed elsif need_to_delete_jamf_uninstall_script? delete_jamf_uninstall_policy delete_jamf_uninstall_script end # Do we need to add or delete the expire policy? # NOTE: if the uninstall script was deleted, # expiration won't do anything. if need_to_update_expiration? changes_for_update.dig(:expiration, :new).to_i.positive? ? jamf_expire_policy : delete_jamf_expire_policy end update_description_in_jamf update_ssvc # TODO: deal with icon changes: if changes_for_update&.key? :self_service_icon if jamf_title_active? update_versions_for_title_changes_in_jamf else log_debug "Jamf: Title '#{display_name}' (#{title}) is not yet active to Jamf, nothing to update in versions." end end |
#update_versions_for_title_changes_in_jamf ⇒ void
This method returns an undefined value.
If any title changes require updates to existing versions in Jamf, this loops thru the versions and applies them
This should happen after the incoming changes have been applied to this title instance
Jamf Stuff
-
update any policy scopes
-
update any policy SSvc settings
221 222 223 224 225 226 227 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 221 def update_versions_for_title_changes_in_jamf version_objects.each do |vers_obj| vers_obj.update_release_groups(ttl_obj: self) if changes_for_update&.key? :release_groups vers_obj.update_excluded_groups(ttl_obj: self) if changes_for_update&.key? :excluded_groups vers_obj.update_jamf_package_notes(ttl_obj: self) if need_to_update_description? end end |
#wait_for_managed_title_to_become_available ⇒ Object
wait up to 60secs for a managed title to become available to be activated subscribed titles are already available
1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 |
# File 'lib/xolo/server/mixins/title_jamf_access.rb', line 1287 def wait_for_managed_title_to_become_available return unless managed? return if jamf_title_active? counter = 0 until jamf_title_active? || jamf_managed_title_available? || counter == 12 log_debug "Jamf: Waiting for title '#{display_name}' (#{title}) to become available from the Title Editor" sleep 5 counter += 1 end return if jamf_managed_title_available? || jamf_title_active? msg = "Jamf: Title '#{title}' is not yet available to Jamf. Make sure it has at least one version enabled in the Title Editor" log_error msg raise Xolo::NoSuchItemError, msg end |