Class: Xolo::Server::Version
- Inherits:
-
Core::BaseClasses::Version
- Object
- Core::BaseClasses::Version
- Xolo::Server::Version
- Includes:
- Comparable, Helpers::JamfPro, Helpers::Log, Helpers::Notification, Helpers::TitleEditor, Mixins::Changelog, Mixins::VersionJamfAccess, Mixins::VersionTedAccess
- Defined in:
- lib/xolo/server/version.rb
Overview
Xolo Version/Patch as used on the Xolo Server
The code in this file mostly deals with the data on the Xolo server itself, and general methods for manipulating the version.
Code for interacting with the Title Editor and Jamf Pro are in the helpers and mixins.
NOTE be sure to only instantiate these using the server’s ‘instantiate_version’ method, or else they might not have all the correct innards
Constant Summary collapse
- VERSIONS_DIRNAME =
On the server, xolo versions are represented by JSON files in the ‘versions’ directory of the title directory
So a title ‘foobar’ would have a directory
(Xolo::Server::DATA_DIR)/titles/foobar/
In there will be a ‘versions’ dir containing json files for each version of the title.
'versions'
- JAMF_PKG_NOTES_VERS_PH =
'XOLO-VERSION-HERE'
- JAMF_PKG_NOTES_TITLE_PH =
'XOLO-TITLE-HERE'
- JAMF_PKG_NOTES_PREFIX =
The ‘Notes’ of a jamf pkg are the Xolo Title Description, with this prepended
<<~ENDNOTES This package is maintained by 'xolo', to install version '#{JAMF_PKG_NOTES_VERS_PH}' of title '#{JAMF_PKG_NOTES_TITLE_PH}'. The description in Xolo is: ENDNOTES
- MAX_PKG_DELETION_THREADS =
10
- STUB_PATCH_VERSION =
STUB PATCH
We create a fake ‘stub’ patch with all ted titles so that we can activate the title before any real version is added and also accept any EA/version_script, either manually or automatically
This version should never be available to any mac, and needs no patch policies or packages.
It should also never be deleted until the title itself is deleted.
'0.0.0x0'
- STUB_PATCH_CAPABILITY_CRITERION_NAME =
machines that can install this version
'Operating System Version'
- STUB_PATCH_CAPABILITY_CRITERION_OPERATOR =
'less than or equal'
- STUB_PATCH_CAPABILITY_CRITERION_VALUE =
'10.0'
- STUB_PATCH_COMPONENT_NAME =
machines that have this version installed
'Xolo Stub'
- STUB_PATCH_COMPONENT_CRITERION_NAME =
'Application Title'
- STUB_PATCH_COMPONENT_CRITERION_OPERATOR =
'is'
- STUB_PATCH_COMPONENT_CRITERION_VALUE =
'XoloStub-DoesNotExist.app'
Constants included from Mixins::VersionJamfAccess
Mixins::VersionJamfAccess::JAMF_AUTO_REINSTALL_WAIT_SECS, Mixins::VersionJamfAccess::JAMF_POLICY_NAME_AUTO_INSTALL_SFX, Mixins::VersionJamfAccess::JAMF_POLICY_NAME_AUTO_REINSTALL_SFX, Mixins::VersionJamfAccess::JAMF_POLICY_NAME_MANUAL_INSTALL_SFX, Mixins::VersionJamfAccess::JAMF_SMART_GROUP_NAME_INSTALLED_SFX
Constants included from Mixins::Changelog
Mixins::Changelog::TITLE_CHANGELOG_FILENAME
Constants included from Helpers::Notification
Helpers::Notification::ALERT_TOOL_EMAIL_PREFIX, Helpers::Notification::DFT_EMAIL_FROM
Constants included from Helpers::JamfPro
Helpers::JamfPro::PATCH_REPORT_JPAPI_PAGE_SIZE, Helpers::JamfPro::PATCH_REPORT_UNKNOWN_VERSION
Instance Attribute Summary collapse
-
#changes_for_update ⇒ Hash
readonly
Also when applying updates, this will hold the changes being made: the differences between tne current attributs and the new_data_for_update We’ll figure this out at the start of the update and can use it later to 1) avoid doing things we don’t need to 2) log the changes in the change log at the very end.
-
#current_action ⇒ Symbol
The current action being taken on this title one of :creating, :updating, :deleting.
-
#jamf_auto_install_policy_name ⇒ Object
readonly
Jamf auto-install policies are named this.
-
#jamf_auto_reinstall_policy_name ⇒ Object
readonly
Jamf auto re-install policies are named this.
-
#jamf_installed_group_name ⇒ String
readonly
For each version there will be a smart group containing all macs that have that version of the title installed.
-
#jamf_manual_install_policy_name ⇒ Object
(also: #jamf_manual_install_trigger)
readonly
Jamf manual install policies are named this.
-
#jamf_obj_name_pfx ⇒ Object
readonly
Jamf object names start with this.
-
#jamf_patch_policy_name ⇒ Object
readonly
Jamf Patch Policy is named this.
-
#jamf_pkg_id ⇒ Object
readonly
The Jamf Package object has this jamf id.
-
#new_data_for_update ⇒ Object
readonly
when applying updates, the new data is stored here so it can be accessed by update-methods and compared to the current instanace values both for updating the title, and the versions.
-
#server_app_instance ⇒ Object
The instance of Xolo::Server::App that instantiated this title object.
-
#ted_id_number ⇒ Object
The Windoo::Patch#patchId.
-
#title_object(refresh: false) ⇒ Xolo::Server::Title
This might have been set already if we were instantiated via our title.
Class Method Summary collapse
-
.all_versions(title) ⇒ Array<String>
A list of all known versions for a title, just the basenames of all the version files with the extension removed.
-
.data_dir(title, version) ⇒ Pathname
The the local directory containing various files specific to the given version of a title.
-
.data_file(title, version) ⇒ Pathname
The the local JSON file containing the current values for the given version of a title.
-
.in_ted?(patch_id, cnx:) ⇒ Boolean
Does the given patch exist in the Title Editor?.
-
.load(title, version) ⇒ Xolo::Server::Title
Instantiate from the local JSON file containing the current values for the given version of a title.
-
.locked?(title, version) ⇒ Boolean
Is a version locked for updates?.
-
.manifest_file(title, version) ⇒ Pathname
The the local xml plist file containing the .pkg manifest for the given version of a title.
-
.pkg_deletion_pool ⇒ Queue
The package-deletion thread pool.
-
.pkg_deletion_pool_info ⇒ Hash
info about the current pkg deletion pool state, for the /state route.
-
.version_dir(title) ⇒ Pathname
The directory containing subdirectories for each version of a title.
-
.version_dirs(title) ⇒ Array<Pathname>
All version directories for a title.
Instance Method Summary collapse
-
#<=>(other) ⇒ Object
version comparison.
- #admin ⇒ String
-
#create ⇒ void
Save a new version, adding to the local filesystem, Jamf Pro, and the Title Editor as needed This should be running in the context of #with_streaming.
-
#creating? ⇒ Boolean
Are we creating this version?.
-
#data_dir ⇒ Pathname
The data directory for this version.
-
#data_file ⇒ Pathname
The JSON data file for this version.
-
#delete(update_title: true) ⇒ void
Delete the version.
-
#deleting? ⇒ Boolean
Are we deleting this version?.
-
#deprecate ⇒ void
deprecate this version.
-
#excluded_groups_to_use(ttl_obj: nil) ⇒ Array<String>
The scope excluded groups to use in policies and patch policies for all versions of this title.
-
#initialize(data_hash) ⇒ Version
constructor
NOTE: be sure to only instantiate these using the servers ‘instantiate_version’ method, or else they might not have all the correct innards.
-
#jamf_cnx(refresh: false) ⇒ Jamf::Connection
A single Jamf Pro API connection to use for the life of this instance.
-
#lock ⇒ Object
Lock this version for updates.
-
#locked? ⇒ Boolean
Is this version locked for updates?.
-
#manifest_file ⇒ Pathname
The manifest plist file for this version.
-
#order_index ⇒ Integer
The index of this version in the title’s reversed version_order array.
-
#pilot_groups_to_use ⇒ Array<String>
The scope target groups to use in policies and patch policies during pilot This is defined in each version, and inherited when new versions are created.
-
#progress(msg, log: :debug) ⇒ void
Append a message to the progress stream file, optionally sending it also to the log.
-
#release(rollback:) ⇒ void
Release this version, possibly rolling back from a previously newer version.
-
#release_groups_to_use(ttl_obj: nil) ⇒ Array<String>
The scope target groups to use in policies and patch policies when the version is released This is defined in the title and applies to all versions.
-
#releasing? ⇒ Boolean
Are we releasing this version?.
-
#repair ⇒ Object
Repair this version.
-
#repairing? ⇒ Boolean
Are we repairing this version?.
-
#reset_to_pilot ⇒ void
Reset this version to ‘pilot’ status, since we are rolling back to a previous version.
-
#save_local_data ⇒ void
Save our current data out to our JSON data file This overwrites the existing data.
- #session ⇒ Hash
-
#skip ⇒ void
skip this version.
-
#ted_cnx ⇒ Windoo::Connection
A single Title Editor connection to use for the life of this instance.
-
#ted_patch(refresh: false) ⇒ Windoo::Patch
TODO: maybe pass in an appropriate Windoo::SoftwareTitle, so we don’t have to use refresh all the time to re-fetch, if we just re-fetched from elsewhere?.
-
#ted_title(refresh: false) ⇒ Windoo::SoftwareTitle
The Windoo::SoftwareTitle object that represents this version’s title in the title editor.
-
#to_h ⇒ Object
Add more data to our hash.
-
#unlock ⇒ Object
Unlock this version for updates.
-
#update(new_data) ⇒ void
Update a this version, updating to the local filesystem, Jamf Pro, and the Title Editor as needed.
-
#update_local_instance_values ⇒ void
Update our instance attributes with any new data before saving the changes back out to the file system.
-
#updating? ⇒ Boolean
Are we updating this version?.
Methods included from Mixins::VersionTedAccess
#create_patch_in_ted, #delete_patch_from_ted, #enable_ted_patch, #get_patch_component_criteria_params, included, #repair_ted_patch, #set_app_component, #set_ea_component, #set_patch_capabilites, #set_patch_killapps, #set_ted_patch_component_criteria, #ted_patch_url, #update_patch_in_ted
Methods included from Mixins::VersionJamfAccess
#activate_patch_version_in_jamf, #assign_pkg_to_patch_in_jamf, #configure_jamf_auto_install_policy, #configure_jamf_auto_reinstall_policy, #configure_jamf_installed_group, #configure_jamf_manual_install_policy, #create_in_jamf, #create_jamf_auto_install_policy, #create_jamf_auto_reinstall_policy, #create_jamf_installed_group, #create_jamf_manual_install_policy, #create_jamf_package, #create_jamf_patch_policy, #delete_jamf_package, #delete_version_from_jamf, #deploy_via_mdm, #disable_policies_for_deprecation_or_skipping, #expand_groups_for_deploy, extended, included, #jamf_auto_install_policy, #jamf_auto_install_policy_exist?, #jamf_auto_install_policy_url, #jamf_auto_reinstall_policy, #jamf_auto_reinstall_policy_exist?, #jamf_auto_reinstall_policy_url, #jamf_gui_url, #jamf_installed_group, #jamf_installed_group_criteria, #jamf_installed_group_exist?, #jamf_installed_group_url, #jamf_manual_install_policy, #jamf_manual_install_policy_exist?, #jamf_manual_install_policy_url, #jamf_package, #jamf_package_notes, #jamf_package_url, #jamf_patch_policy, #jamf_patch_policy_exist?, #jamf_patch_policy_url, #jamf_patch_version, #patch_report, #remove_exclusions_from_deploy, #remove_invalid_computers_for_deploy, #repair_jamf_auto_install_policy, #repair_jamf_auto_reinstall_policy, #repair_jamf_installed_group, #repair_jamf_manual_install_policy, #repair_jamf_package, #repair_jamf_patch_policy, #repair_jamf_version_objects, #reset_policies_to_pilot, #set_policy_exclusions, #set_policy_pilot_groups, #set_policy_release_groups, #set_policy_to_all_targets, #update_excluded_groups, #update_jamf_package_notes, #update_jamf_pkg_min_os, #update_jamf_pkg_reboot, #update_pilot_groups, #update_release_groups, #update_version_in_jamf, #wait_to_enable_reinstall_policy
Methods included from Mixins::Changelog
#backup_changelog, backup_file_dir, #changelog, #changelog_backup_file, #changelog_file, #changelog_lock, changelog_locks, #delete_changelog, #hostname_from_ip, included, #log_change, #log_update_changes, #note_changes_for_update_and_log
Methods included from Helpers::Notification
#email_from, included, #send_alert, #send_email, #send_email_alert, #server_fqdn, #server_name
Methods included from Helpers::Log
included, #log_debug, #log_error, #log_fatal, #log_info, #log_unknown, #log_warn, #logger, #session_svr_obj_id
Methods included from Helpers::TitleEditor
Methods included from Helpers::JamfPro
extended, included, #jamf_gui_url, #jamf_xolo_category_id, #valid_forced_exclusion_group_name
Constructor Details
#initialize(data_hash) ⇒ Version
NOTE: be sure to only instantiate these using the servers ‘instantiate_version’ method, or else they might not have all the correct innards
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
# File 'lib/xolo/server/version.rb', line 307 def initialize(data_hash) super # These attrs aren't defined in the ATTRIBUTES # and/or are not stored in the on-disk json file @ted_id_number ||= data_hash[:ted_id_number] @jamf_pkg_id ||= data_hash[:jamf_pkg_id] # and these can be generated now @jamf_obj_name_pfx = "#{Xolo::Server::JAMF_OBJECT_NAME_PFX}#{title}-#{version}" @jamf_pkg_name ||= @jamf_obj_name_pfx @jamf_installed_group_name = "#{jamf_obj_name_pfx}#{JAMF_SMART_GROUP_NAME_INSTALLED_SFX}" @jamf_auto_install_policy_name = "#{jamf_obj_name_pfx}#{JAMF_POLICY_NAME_AUTO_INSTALL_SFX}" @jamf_manual_install_policy_name = "#{jamf_obj_name_pfx}#{JAMF_POLICY_NAME_MANUAL_INSTALL_SFX}" @jamf_auto_reinstall_policy_name = "#{jamf_obj_name_pfx}#{JAMF_POLICY_NAME_AUTO_REINSTALL_SFX}" @jamf_patch_policy_name = @jamf_obj_name_pfx # we set @jamf_pkg_file when a pkg is uploaded # since we don't know until then if its a .pkg or .zip # It will be stored in the local data and reloaded as needed end |
Instance Attribute Details
#changes_for_update ⇒ Hash (readonly)
Also when applying updates, this will hold the changes being made: the differences between tne current attributs and the new_data_for_update We’ll figure this out at the start of the update and can use it later to 1) avoid doing things we don’t need to 2) log the changes in the change log at the very end
This is a Hash with keys of the attribute names that have changed the values are Hashes with keys of :old and :new e.g. { pilot_groups: { old: [‘foo’], new: [‘bar’] } }
294 295 296 |
# File 'lib/xolo/server/version.rb', line 294 def changes_for_update @changes_for_update end |
#current_action ⇒ Symbol
Returns The current action being taken on this title one of :creating, :updating, :deleting.
298 299 300 |
# File 'lib/xolo/server/version.rb', line 298 def current_action @current_action end |
#jamf_auto_install_policy_name ⇒ Object (readonly)
Jamf auto-install policies are named this
259 260 261 |
# File 'lib/xolo/server/version.rb', line 259 def jamf_auto_install_policy_name @jamf_auto_install_policy_name end |
#jamf_auto_reinstall_policy_name ⇒ Object (readonly)
Jamf auto re-install policies are named this
265 266 267 |
# File 'lib/xolo/server/version.rb', line 265 def jamf_auto_reinstall_policy_name @jamf_auto_reinstall_policy_name end |
#jamf_installed_group_name ⇒ String (readonly)
For each version there will be a smart group containing all macs that have that version of the title installed. The smart group will be named ‘xolo-<title>-<version>-installed’
It will be used as the target for the auto-reinstall
256 257 258 |
# File 'lib/xolo/server/version.rb', line 256 def jamf_installed_group_name @jamf_installed_group_name end |
#jamf_manual_install_policy_name ⇒ Object (readonly) Also known as: jamf_manual_install_trigger
Jamf manual install policies are named this
262 263 264 |
# File 'lib/xolo/server/version.rb', line 262 def jamf_manual_install_policy_name @jamf_manual_install_policy_name end |
#jamf_obj_name_pfx ⇒ Object (readonly)
Jamf object names start with this
247 248 249 |
# File 'lib/xolo/server/version.rb', line 247 def jamf_obj_name_pfx @jamf_obj_name_pfx end |
#jamf_patch_policy_name ⇒ Object (readonly)
Jamf Patch Policy is named this
271 272 273 |
# File 'lib/xolo/server/version.rb', line 271 def jamf_patch_policy_name @jamf_patch_policy_name end |
#jamf_pkg_id ⇒ Object (readonly)
The Jamf Package object has this jamf id
274 275 276 |
# File 'lib/xolo/server/version.rb', line 274 def jamf_pkg_id @jamf_pkg_id end |
#new_data_for_update ⇒ Object (readonly)
when applying updates, the new data is stored here so it can be accessed by update-methods and compared to the current instanace values both for updating the title, and the versions
280 281 282 |
# File 'lib/xolo/server/version.rb', line 280 def new_data_for_update @new_data_for_update end |
#server_app_instance ⇒ Object
The instance of Xolo::Server::App that instantiated this title object. This is how we access things that are available in routes and helpers, like the single Jamf and TEd connections for this App instance.
234 235 236 |
# File 'lib/xolo/server/version.rb', line 234 def server_app_instance @server_app_instance end |
#ted_id_number ⇒ Object
The Windoo::Patch#patchId
244 245 246 |
# File 'lib/xolo/server/version.rb', line 244 def ted_id_number @ted_id_number end |
#title_object(refresh: false) ⇒ Xolo::Server::Title
This might have been set already if we were instantiated via our title
482 483 484 485 |
# File 'lib/xolo/server/version.rb', line 482 def title_object(refresh: false) @title_object = nil if refresh @title_object ||= server_app_instance.instantiate_title title end |
Class Method Details
.all_versions(title) ⇒ Array<String>
Returns A list of all known versions for a title, just the basenames of all the version files with the extension removed.
117 118 119 |
# File 'lib/xolo/server/version.rb', line 117 def self.all_versions(title) version_dirs(title).map { |c| c.basename.to_s } end |
.data_dir(title, version) ⇒ Pathname
The the local directory containing various files specific to the given version of a title
130 131 132 |
# File 'lib/xolo/server/version.rb', line 130 def self.data_dir(title, version) version_dir(title) + version end |
.data_file(title, version) ⇒ Pathname
The the local JSON file containing the current values for the given version of a title
143 144 145 |
# File 'lib/xolo/server/version.rb', line 143 def self.data_file(title, version) data_dir(title, version) + "#{version}.json" end |
.in_ted?(patch_id, cnx:) ⇒ Boolean
Returns Does the given patch exist in the Title Editor?.
182 183 184 |
# File 'lib/xolo/server/version.rb', line 182 def self.in_ted?(patch_id, cnx:) Windoo::Patch.all_ids(cnx: cnx).include? patch_id end |
.load(title, version) ⇒ Xolo::Server::Title
Instantiate from the local JSON file containing the current values for the given version of a title
NOTE: All instantiation should happen using the #instantiate_version method in the server app instance. Please don’t call this method directly
173 174 175 176 |
# File 'lib/xolo/server/version.rb', line 173 def self.load(title, version) Xolo::Server.logger.debug "Loading version '#{version}' of title '#{title}' from file" new parse_json(data_file(title, version).read) end |
.locked?(title, version) ⇒ Boolean
Is a version locked for updates?
188 189 190 191 |
# File 'lib/xolo/server/version.rb', line 188 def self.locked?(title, version) curr_lock = Xolo::Server.object_locks.dig title, :versions, version curr_lock && curr_lock > Time.now end |
.manifest_file(title, version) ⇒ Pathname
The the local xml plist file containing the .pkg manifest for the given version of a title
156 157 158 |
# File 'lib/xolo/server/version.rb', line 156 def self.manifest_file(title, version) data_dir(title, version) + "#{version}.manifest.plist" end |
.pkg_deletion_pool ⇒ Queue
The package-deletion thread pool
the auto_terminate is false to prevents the threads from being daemonized, and running after the main thread exits. This is important because launchd jobs should never do that.
See ruby-concurrency.github.io/concurrent-ruby/master/file.thread_pools.html
202 203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/xolo/server/version.rb', line 202 def self.pkg_deletion_pool @pkg_deletion_pool ||= Concurrent::ThreadPoolExecutor.new( name: 'package-deletion', min_threads: 1, # start with 1 thread max_threads: MAX_PKG_DELETION_THREADS, # create at most 10 threads max_queue: 0, # no limit auto_terminate: false, # see method comments above idletime: 60 # seconds thread can remain idle before it is reclaimed, default is 60 # fallback_policy: :abort # the default is :abort, which will raise a # Concurrent::RejectedExecutionError exception and discard the task ) end |
.pkg_deletion_pool_info ⇒ Hash
info about the current pkg deletion pool state, for the /state route
219 220 221 222 223 224 |
# File 'lib/xolo/server/version.rb', line 219 def self.pkg_deletion_pool_info { threads: pkg_deletion_pool.length, queued_tasks: pkg_deletion_pool.queue_length } end |
.version_dir(title) ⇒ Pathname
Returns The directory containing subdirectories for each version of a title. They contain JSON and other files for the versions.
101 102 103 |
# File 'lib/xolo/server/version.rb', line 101 def self.version_dir(title) Xolo::Server::Title.title_dir(title) + VERSIONS_DIRNAME end |
.version_dirs(title) ⇒ Array<Pathname>
Returns All version directories for a title.
108 109 110 111 |
# File 'lib/xolo/server/version.rb', line 108 def self.version_dirs(title) vdir = version_dir(title) vdir.directory? ? vdir.children : [] end |
Instance Method Details
#<=>(other) ⇒ Object
version comparison
341 342 343 344 345 346 |
# File 'lib/xolo/server/version.rb', line 341 def <=>(other) raise Xolo::InvalidDataError, 'Cannot compare with other classes' unless other.is_a? Xolo::Server::Version raise Xolo::InvalidDataError, 'Cannot compare versions of different titles' unless other.title == title order_index <=> other.order_index end |
#admin ⇒ String
461 462 463 |
# File 'lib/xolo/server/version.rb', line 461 def admin session[:admin] end |
#create ⇒ void
This method returns an undefined value.
Save a new version, adding to the local filesystem, Jamf Pro, and the Title Editor as needed This should be running in the context of #with_streaming
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 |
# File 'lib/xolo/server/version.rb', line 548 def create lock @current_action = :creating self.creation_date = Time.now self.created_by = admin self.status = STATUS_PENDING log_debug "creation_date: #{creation_date}, created_by: #{created_by}" # save to file here so that we have something to delete if # the next couple steps fail progress 'Saving version data to Xolo server' save_local_data create_patch_in_ted enable_ted_patch title_object.enable_ted_title create_in_jamf self.status = STATUS_PILOT # save to file again now, because saving to TitleEd and Jamf will # add some data save_local_data # prepend our version to the version_order array of the title progress "Updating title version_order, prepending '#{version}'", log: :info title_object.prepend_version(version) log_change msg: 'Version Created' progress "Version '#{version}' of Title '#{title}' has been created in Xolo.", log: :info ensure unlock end |
#creating? ⇒ Boolean
Returns Are we creating this version?.
358 359 360 |
# File 'lib/xolo/server/version.rb', line 358 def creating? current_action == :creating end |
#data_dir ⇒ Pathname
The data directory for this version
504 505 506 |
# File 'lib/xolo/server/version.rb', line 504 def data_dir self.class.data_dir title, version end |
#data_file ⇒ Pathname
The JSON data file for this version
511 512 513 |
# File 'lib/xolo/server/version.rb', line 511 def data_file self.class.data_file title, version end |
#delete(update_title: true) ⇒ void
This method returns an undefined value.
Delete the version
830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 |
# File 'lib/xolo/server/version.rb', line 830 def delete(update_title: true) lock @current_action = :deleting delete_patch_from_ted delete_version_from_jamf # remove from the title's list of versions progress 'Deleting version from title data on the Xolo server', log: :debug title_object.remove_version(version) if update_title # delete the local data progress 'Deleting version data from the Xolo server', log: :info data_dir.rmtree log_change msg: 'Version Deleted' progress "Version '#{version}' of Title '#{title}' has been deleted from Xolo.", log: :info ensure unlock end |
#deleting? ⇒ Boolean
Returns Are we deleting this version?.
376 377 378 |
# File 'lib/xolo/server/version.rb', line 376 def deleting? current_action == :deleting end |
#deprecate ⇒ void
This method returns an undefined value.
deprecate this version
726 727 728 729 730 731 732 733 734 735 736 737 738 |
# File 'lib/xolo/server/version.rb', line 726 def deprecate lock progress "Deprecating older released version '#{version}'" disable_policies_for_deprecation_or_skipping :deprecated self.status = STATUS_DEPRECATED self.deprecation_date = Time.now self.deprecated_by = admin log_change msg: 'Version Deprecated' save_local_data ensure unlock end |
#excluded_groups_to_use(ttl_obj: nil) ⇒ Array<String>
The scope excluded groups to use in policies and patch policies for all versions of this title.
Excluded groups are defined in the title, applying to all versions, and may be augmented by:
-
Xolo::Server.config.forced_exclusion, a group excluded from ALL of xolo, defined in the server config.
-
The title’s jamf_frozen_group_name, if it exists, containing computers that have been ‘frozen’ to a single version.
For initial install policies, the smart group of macs with any version installed (jamf_installed_group_name) “xolo-<title>-installed” is also excluded, because otherwise the initial-install policies would stomp on the patch policies.
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 |
# File 'lib/xolo/server/version.rb', line 415 def excluded_groups_to_use(ttl_obj: nil) return @excluded_groups_to_use if @excluded_groups_to_use ttl_obj ||= title_object # get the excluded groups from the title # Use .dup so we don't modify the original @excluded_groups_to_use = ttl_obj.changes_for_update&.key?(:excluded_groups) ? ttl_obj.changes_for_update[:excluded_groups][:new].dup : ttl_obj.excluded_groups.dup # always exclude the frozen static group # calling ttl_obj.jamf_frozen_group will create the group if needed @excluded_groups_to_use << ttl_obj.jamf_frozen_group.name log_debug "Appended '#{ttl_obj.jamf_frozen_group_name}' to @excluded_groups_to_use" # always exclude Xolo::Server.config.forced_exclusion if defined @excluded_groups_to_use << valid_forced_exclusion_group_name if valid_forced_exclusion_group_name @excluded_groups_to_use.uniq! log_debug "Excluded groups to use: #{@excluded_groups_to_use.join ', '}" @excluded_groups_to_use end |
#jamf_cnx(refresh: false) ⇒ Jamf::Connection
Returns a single Jamf Pro API connection to use for the life of this instance.
497 498 499 |
# File 'lib/xolo/server/version.rb', line 497 def jamf_cnx(refresh: false) server_app_instance.jamf_cnx refresh: refresh end |
#lock ⇒ Object
Lock this version for updates
859 860 861 862 863 864 865 866 867 868 869 870 871 |
# File 'lib/xolo/server/version.rb', line 859 def lock raise Xolo::ServerError, 'Server is shutting down' if Xolo::Server.shutting_down? while locked? log_debug "Waiting for update lock on Version '#{version}' of title '#{title}'..." if (Time.now.to_i % 5).zero? sleep 0.33 end Xolo::Server.object_locks[title] ||= { versions: {} } exp = Time.now + Xolo::Server::ObjectLocks::OBJECT_LOCK_LIMIT Xolo::Server.object_locks[title][:versions][version] = exp log_debug "Locked version '#{version}' of title '#{title}' for updates until #{exp}" end |
#locked? ⇒ Boolean
Is this version locked for updates?
853 854 855 |
# File 'lib/xolo/server/version.rb', line 853 def locked? self.class.locked?(title, version) end |
#manifest_file ⇒ Pathname
The manifest plist file for this version
518 519 520 |
# File 'lib/xolo/server/version.rb', line 518 def manifest_file self.class.manifest_file title, version end |
#order_index ⇒ Integer
Returns The index of this version in the title’s reversed version_order array. We reverse it because the version_order array holds the newest versions first, so the index of the newest version is 0, the next newest is 1, etc - we need the opposite of that.
352 353 354 |
# File 'lib/xolo/server/version.rb', line 352 def order_index title_object.version_order.reverse.index version end |
#pilot_groups_to_use ⇒ Array<String>
The scope target groups to use in policies and patch policies during pilot This is defined in each version, and inherited when new versions are created.
391 392 393 394 395 |
# File 'lib/xolo/server/version.rb', line 391 def pilot_groups_to_use return @pilot_groups_to_use if @pilot_groups_to_use @pilot_groups_to_use = changes_for_update&.key?(:pilot_groups) ? changes_for_update[:pilot_groups][:new] : pilot_groups end |
#progress(msg, log: :debug) ⇒ void
This method returns an undefined value.
Append a message to the progress stream file, optionally sending it also to the log
475 476 477 |
# File 'lib/xolo/server/version.rb', line 475 def progress(msg, log: :debug) server_app_instance.progress msg, log: log end |
#release(rollback:) ⇒ void
This method returns an undefined value.
Release this version, possibly rolling back from a previously newer version
684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 |
# File 'lib/xolo/server/version.rb', line 684 def release(rollback:) lock @current_action = :releasing # set scope targets of auto-install policy to release-groups msg = "Jamf: Version '#{version}': Setting scope targets of auto-install policy to release_groups: #{release_groups_to_use.join(', ')}" progress msg, log: :info pol = jamf_auto_install_policy set_policy_release_groups pol pol.save # set scope targets of patch policy to all (in patch pols, 'all' means 'all eligible') msg = "Jamf: Version '#{version}': Setting scope targets of patch policy to all eligible computers" progress msg, log: :info ppol = jamf_patch_policy ppol.scope.set_all_targets # if rollback, make sure the patch policy is set to 'allow downgrade' if rollback msg = "Jamf: Version '#{version}': Setting patch policy to allow downgrade" progress msg, log: :info ppol.allow_downgrade = true else ppol.allow_downgrade = false end ppol.save # change status to 'released' self.status = STATUS_RELEASED self.release_date = Time.now self.released_by = admin chg_msg = rollback ? 'Version Released - Rolled Back' : 'Version Released' log_change msg: chg_msg save_local_data ensure unlock end |
#release_groups_to_use(ttl_obj: nil) ⇒ Array<String>
The scope target groups to use in policies and patch policies when the version is released This is defined in the title and applies to all versions.
445 446 447 448 449 450 |
# File 'lib/xolo/server/version.rb', line 445 def release_groups_to_use(ttl_obj: nil) return @release_groups_to_use if @release_groups_to_use ttl_obj ||= title_object @release_groups_to_use = ttl_obj.changes_for_update&.key?(:release_groups) ? ttl_obj.changes_for_update[:release_groups][:new] : ttl_obj.release_groups end |
#releasing? ⇒ Boolean
Returns Are we releasing this version?.
382 383 384 |
# File 'lib/xolo/server/version.rb', line 382 def releasing? current_action == :releasing end |
#repair ⇒ Object
Repair this version. Look at the Title Editor patch object, and ensure it’s correct based on the local data file.
- version order
- min os
- max os
- standalone
- reboot
- release date
- killapps
- component criteria
- component name '<title>'
- capability criteria
- enabled
Then look at the various Jamf objects pertaining to this version, and ensure they are correct
- package object 'xolo-<title>-<version>'
- filename 'xolo-<title>-<version>.pkg'
- description
- os limitations
- auto install policy 'xolo-<title>-<version>-auto-install'
- manual install policy 'xolo-<title>-<version>-manual-install'
- patch policy 'xolo-<title>-<version>'
Then look at the xolo metadata, and fix whatever is needed
651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 |
# File 'lib/xolo/server/version.rb', line 651 def repair lock @current_action = :repairing log_change msg: "Repairing version '#{version}'" progress "Starting repair of version '#{version}' of title '#{title}'", log: :debug repair_ted_patch repair_jamf_version_objects # If there's a reupload, but no original, make the orig the same as the re unless upload_date if reupload_date && reuploaded_by new_date = reupload_date new_by = reuploaded_by else new_date = Time.parse '2025-02-15' new_by = 'buzzlightyear' end progress "Fixing original upload date: #{new_date}, by: #{new_by}", log: :debug self.upload_date = new_date self.uploaded_by = new_by save_local_data end ensure unlock end |
#repairing? ⇒ Boolean
Returns Are we repairing this version?.
370 371 372 |
# File 'lib/xolo/server/version.rb', line 370 def repairing? current_action == :repairing end |
#reset_to_pilot ⇒ void
This method returns an undefined value.
Reset this version to ‘pilot’ status, since we are rolling back to a previous version
762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 |
# File 'lib/xolo/server/version.rb', line 762 def reset_to_pilot return if status == STATUS_PILOT lock progress "Resetting version '#{version}' to pilot status due to rollback of an older version" reset_policies_to_pilot self.status = STATUS_PILOT self.skipped_date = nil self.skipped_by = nil self.deprecation_date = nil self.deprecated_by = nil log_change msg: 'Version Reset to Pilot' save_local_data ensure unlock end |
#save_local_data ⇒ void
This method returns an undefined value.
Save our current data out to our JSON data file This overwrites the existing data.
810 811 812 813 814 815 816 817 818 819 820 |
# File 'lib/xolo/server/version.rb', line 810 def save_local_data data_dir.mkpath self.modification_date = Time.now self.modified_by = admin log_debug "Version '#{version}' of Title '#{title}' noting modification by #{modified_by}" file = data_file log_debug "Saving local version data to: #{file}" file.pix_atomic_write to_json end |
#session ⇒ Hash
454 455 456 457 |
# File 'lib/xolo/server/version.rb', line 454 def session server_app_instance&.session || {} # @session ||= {} end |
#skip ⇒ void
This method returns an undefined value.
skip this version
744 745 746 747 748 749 750 751 752 753 754 755 |
# File 'lib/xolo/server/version.rb', line 744 def skip lock progress "Skipping unreleased version '#{version}'" disable_policies_for_deprecation_or_skipping :skipped self.status = STATUS_SKIPPED self.skipped_date = Time.now self.skipped_by = admin log_change msg: 'Version Skipped' save_local_data ensure unlock end |
#ted_cnx ⇒ Windoo::Connection
Returns a single Title Editor connection to use for the life of this instance.
490 491 492 |
# File 'lib/xolo/server/version.rb', line 490 def ted_cnx server_app_instance.ted_cnx end |
#ted_patch(refresh: false) ⇒ Windoo::Patch
TODO: maybe pass in an appropriate Windoo::SoftwareTitle, so we don’t have to use refresh all the time to re-fetch, if we just re-fetched from elsewhere?
529 530 531 532 |
# File 'lib/xolo/server/version.rb', line 529 def ted_patch(refresh: false) @ted_patch = nil if refresh @ted_patch ||= ted_title(refresh: refresh).patches.patch(version) end |
#ted_title(refresh: false) ⇒ Windoo::SoftwareTitle
Returns The Windoo::SoftwareTitle object that represents this version’s title in the title editor.
537 538 539 540 |
# File 'lib/xolo/server/version.rb', line 537 def ted_title(refresh: false) @ted_title = nil if refresh @ted_title ||= Windoo::SoftwareTitle.fetch id: title, cnx: ted_cnx end |
#to_h ⇒ Object
Add more data to our hash
885 886 887 888 889 890 891 892 893 894 895 896 |
# File 'lib/xolo/server/version.rb', line 885 def to_h hash = super # These attrs aren't defined in the ATTRIBUTES # but we want them in the hash and/or JSON hash[:jamf_pkg_id] = jamf_pkg_id hash[:ted_id_number] = ted_id_number hash[:pilot_groups_to_use] = pilot_groups_to_use hash[:release_groups_to_use] = release_groups_to_use hash.sort.to_h end |
#unlock ⇒ Object
Unlock this version for updates
875 876 877 878 879 880 881 |
# File 'lib/xolo/server/version.rb', line 875 def unlock curr_lock = Xolo::Server.object_locks.dig title, :versions, version return unless curr_lock Xolo::Server.object_locks[title][:versions].delete version log_debug "Unlocked version '#{version}' of title '#{title}' for updates" end |
#update(new_data) ⇒ void
This method returns an undefined value.
Update a this version, updating to the local filesystem, Jamf Pro, and the Title Editor as needed
591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 |
# File 'lib/xolo/server/version.rb', line 591 def update(new_data) lock @current_action = :updating @new_data_for_update = new_data @changes_for_update = note_changes_for_update_and_log if @changes_for_update.pix_empty? progress 'No changes to make', log: :info return end log_info "Updating version '#{version}' of title '#{title}' for admin '#{admin}'" # changelog - log the changes now, and # if there is an error, we'll log that too # saying the above changes were not completed and to # look at the server log for details. log_update_changes # update ted before jamf update_patch_in_ted enable_ted_patch update_version_in_jamf update_local_instance_values save_local_data # new pkg uploads happen in a separate process rescue => e log_change msg: "ERROR: The update failed and the changes didn't all go through!\n#{e.class}: #{e.}\nSee server log for details." # re-raise for proper error handling in the server app raise ensure unlock end |
#update_local_instance_values ⇒ void
This method returns an undefined value.
Update our instance attributes with any new data before saving the changes back out to the file system
783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 |
# File 'lib/xolo/server/version.rb', line 783 def update_local_instance_values # update instance data with new data before writing out to the filesystem. # Do this last so that the instance values can be compared to # new_data_for_update in the steps above. # Also, those steps might have updated some server-specific attributes # which will be saved to the file system as well. ATTRIBUTES.each do |attr, deets| # make sure these are updated elsewhere if needed, # e.g. modification data. next if deets[:read_only] next unless deets[:cli] new_val = new_data_for_update[attr] old_val = send(attr) next if new_val == old_val log_debug "Updating Xolo Version attribute '#{attr}': '#{old_val}' -> '#{new_val}'" send "#{attr}=", new_val end # update any other server-specific attributes here... end |
#updating? ⇒ Boolean
Returns Are we updating this version?.
364 365 366 |
# File 'lib/xolo/server/version.rb', line 364 def updating? current_action == :updating end |