Class: Jamf::PatchTitle
- Includes:
- Categorizable, Creatable, Sitable, Updatable
- Defined in:
- lib/jamf/api/classic/api_objects/patch_title.rb,
lib/jamf/api/classic/api_objects/patch_title/version.rb
Overview
An active Patch Software Title in the JSS.
This class provides access to titles that have been added to Jamf Pro via a PatchInternalSource or a PatchExternalSource, and the versions contained therein.
Patch versions for the title are available in the #versions read-only attribute, a Hash of versions keyed by the version string. The values are Jamf::PatchTitle::Version objects.
When creating/activating new Patch Titles, with .make, a unique name:, a source: and a name_id: must be provided - the source must be the name or id of an existing PatchSource, and the name_id must be offered by that source. Once created, the source_id and name_id cannot be changed.
When fetching titles, they can be fetched by id:, source_name_id:, or both source: and name_id:
WARNING: While they can be fetched by name, beware: the JSS does not enforce unique names of titles even thought ruby-jss does. If there are duplicates of the name you fetch, which one you get is undefined.
Use the patch_report class or instance method, or PatchTitle::Version.patch_report, to retrieve a report of computers with a specific version of the title installed, or :all, :latest, or :unknown versions. Reports called on the class or an instance default to :all versions, and are slower to retrieve than a specific version,
Defined Under Namespace
Classes: Version
Constant Summary collapse
- USE_XML_WORKAROUND =
TODO: remove this and adjust parsing when jamf fixes the JSON Data map for PatchTitle XML data parsing cuz Borked JSON
{ patch_software_title: { id: -1, name: Jamf::BLANK, name_id: Jamf::BLANK, source_id: -1, notifications: { email_notification: nil, web_notification: nil }, category: { id: -1, name: Jamf::BLANK }, site: { id: -1, name: Jamf::BLANK }, versions: [ { software_version: Jamf::BLANK, package: { id: -1, name: Jamf::BLANK } } ] } }.freeze
- PATCH_REPORT_DATA_MAP =
TODO: remove this and adjust parsing when jamf fixes the JSON Data map for PatchReport XML data parsing cuz Borked JSON
{ patch_report: { name: Jamf::BLANK, patch_software_title_id: -1, total_computers: 0, total_versions: 0, versions: [ { software_version: Jamf::BLANK, computers: [ { id: -1, name: Jamf::BLANK, mac_address: Jamf::BLANK, alt_mac_address: Jamf::BLANK, serial_number: Jamf::BLANK } ] } ] } }.freeze
- RSRC_BASE =
The base for REST resources of this class
'patchsoftwaretitles'.freeze
- RSRC_LIST_KEY =
the hash key used for the JSON list output of all objects in the JSS
:patch_software_titles
- RSRC_OBJECT_KEY =
The hash key used for the JSON object output. It’s also used in various error messages
:patch_software_title
- NON_UNIQUE_NAMES =
true
- OBJECT_HISTORY_OBJECT_TYPE =
the object type for this object in the object history table. See APIObject#add_object_history_entry TODO: comfirm this in 10.4
604
- SITE_SUBSET =
:top
- CATEGORY_SUBSET =
Where is the Category in the API JSON?
:top
- CATEGORY_DATA_TYPE =
How is the category stored in the API data?
Hash
- LATEST_VERSION_ID =
when fetching a specific version, this is a valid version
'Latest'.freeze
- UNKNOWN_VERSION_ID =
when fetching a specific version, this is a valid version
'Unknown'.freeze
- REPORTS_RSRC_BASE =
'patchreports/patchsoftwaretitleid'.freeze
Instance Attribute Summary collapse
-
#email_notification ⇒ Boolean
(also: #email_notification?)
Are new patches announced by email?.
-
#name_id ⇒ String
readonly
The ‘name_id’ for this patch title.
-
#need_to_update ⇒ Boolean
included
from Updatable
readonly
Do we have unsaved changes?.
-
#source_id ⇒ Integer
readonly
The id of the patch source from which we get patches for this title.
-
#source_name_id ⇒ String
readonly
The source_id and name_id joined by ‘-’, a unique identifier.
-
#web_notification ⇒ Boolean
(also: #web_notification?)
Are new patches announced in the JSS web ui?.
Class Method Summary collapse
-
.all(refresh = false, source_id: nil, api: nil, cnx: Jamf.cnx) ⇒ Object
The same as @see APIObject.all but also takes an optional source_id: parameter, which limites the results to patch titles with the specified source_id.
-
.all_ids(refresh = false, source_id: nil, api: nil, cnx: Jamf.cnx) ⇒ Object
The same as @see APIObject.all_ids but also takes an optional source_id: parameter, which limites the results to patch titles with the specified source_id.
-
.all_names(refresh = false, source_id: nil, api: nil, cnx: Jamf.cnx) ⇒ Object
The same as @see APIObject.all_names but also takes an optional source_id: parameter, which limites the results to patch titles with the specified source_id.
-
.all_source_ids(refresh = false, api: nil, cnx: Jamf.cnx) ⇒ Array<Integer>
Returns an Array of unique source_ids used by active Patches.
-
.all_source_name_ids(refresh = false, api: nil, cnx: Jamf.cnx) ⇒ Array<String>
All ‘source_name_id’ values for active patches.
-
.fetch(identifier = nil, **params) ⇒ Object
Patch titles only have an id-based GET resource in the API.
-
.patch_report(title, version: :all, api: nil, cnx: Jamf.cnx) ⇒ Hash
Get a patch report for a softwaretitle, without fetching an instance.
-
.valid_id(ident, refresh = false, api: nil, cnx: Jamf.cnx) ⇒ Object
Override the APIObject.valid_id, since patch sources are so non-standard Accept id, source_name_id, or name.
Instance Method Summary collapse
-
#category=(new_cat) ⇒ void
included
from Categorizable
Change the category of this object.
-
#category_assigned? ⇒ Boolean
(also: #categorized?)
included
from Categorizable
Does this object have a category assigned?.
-
#category_id ⇒ Integer
included
from Categorizable
The id of the category for this object.
-
#category_name ⇒ String
(also: #category)
included
from Categorizable
The name of the category for this object.
-
#category_object ⇒ Jamf::Category
included
from Categorizable
The Jamf::Category instance for this object’s category.
-
#changed_pkg_for_version(version) ⇒ Object
this is called by Jamf::PatchTitle::Version#package= to update @changed_pkgs which is used by #rest_xml to change the package assigned to a patch version in this title.
-
#clone(new_name, api: nil, cnx: nil) ⇒ APIObject
included
from Creatable
make a clone of this API object, with a new name.
-
#create ⇒ Object
wrapper to fetch versions after creating.
-
#evaluate_new_category(new_cat) ⇒ Array<String, Integer>
included
from Categorizable
Given a category name or id, return the name and id TODO: use APIObject.exist? and/or APIObject.valid_id.
-
#initialize(**args) ⇒ PatchTitle
constructor
A new instance of PatchTitle.
-
#name=(newname) ⇒ void
included
from Updatable
Change the name of this item Remember to #update to push changes to the server.
-
#patch_report(vers = :all) ⇒ Object
(also: #version_report, #report)
Get a patch report for this title.
-
#pretty_print_instance_variables ⇒ Array
Remove the various cached data from the instance_variables used to create pretty-print (pp) output.
-
#site=(new_site) ⇒ void
included
from Sitable
Change the site of this object.
-
#site_assigned? ⇒ Boolean
included
from Sitable
Does this object have a site assigned?.
-
#site_id ⇒ Integer
included
from Sitable
The id of the site for this object.
-
#site_name ⇒ String
(also: #site)
included
from Sitable
The name of the site for this object.
-
#site_object ⇒ Jamf::Site
included
from Sitable
The Jamf::Site instance for this object’s site.
-
#unset_category ⇒ void
included
from Categorizable
Set the category to nothing.
-
#unset_site ⇒ void
included
from Sitable
Set the site to nothing.
-
#update ⇒ Object
wrapper to clear @changed_pkgs after updating.
-
#versions ⇒ Hash{String => Jamf::PatchTitle::Version}
The Jamf::PatchVersions fetched for this title, keyed by version string.
-
#versions_with_packages ⇒ Hash
Subset of @versions, containing those which have packages assigned.
Constructor Details
#initialize(**args) ⇒ PatchTitle
Returns a new instance of PatchTitle.
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 431 |
# File 'lib/jamf/api/classic/api_objects/patch_title.rb', line 397 def initialize(**args) super if in_jss @name_id = @init_data[:name_id] @source_id = @init_data[:source_id] else # source: and source_id: are considered the same, source_id: wins @init_data[:source_id] ||= @init_data[:source] raise Jamf::MissingDataError, 'source: and name_id: must be provided' unless @init_data[:name_id] && @init_data[:source_id] @source_id = Jamf::PatchSource.valid_id(@init_data[:source_id], cnx: @cnx) raise Jamf::NoSuchItemError, "No Patch Sources match '#{@init_data[:source]}'" unless source_id @name_id = @init_data[:name_id] valid_name_id = Jamf::PatchSource.available_name_ids(@source_id, cnx: @cnx).include? @name_id raise Jamf::NoSuchItemError, "source #{@init_data[:source]} doesn't offer name_id '#{@init_data[:name_id]}'" unless valid_name_id end @source_name_id = "#{@source_id}-#{@name_id}" @init_data[:notifications] ||= {} notifs = @init_data[:notifications] @web_notification = notifs[:web_notification].nil? ? false : notifs[:web_notification] @email_notification = notifs[:email_notification].nil? ? false : notifs[:email_notification] @versions = {} @init_data[:versions] ||= [] @init_data[:versions].each do |vers| @versions[vers[:software_version]] = Jamf::PatchTitle::Version.new(self, vers) end # each do vers @changed_pkgs = [] end |
Instance Attribute Details
#email_notification ⇒ Boolean Also known as: email_notification?
Returns Are new patches announced by email?.
394 395 396 |
# File 'lib/jamf/api/classic/api_objects/patch_title.rb', line 394 def email_notification @email_notification end |
#name_id ⇒ String (readonly)
Returns the ‘name_id’ for this patch title. name_id is a unique identfier provided by the patch source.
380 381 382 |
# File 'lib/jamf/api/classic/api_objects/patch_title.rb', line 380 def name_id @name_id end |
#need_to_update ⇒ Boolean (readonly) Originally defined in module Updatable
Returns do we have unsaved changes?.
#source_id ⇒ Integer (readonly)
Returns the id of the patch source from which we get patches for this title.
384 385 386 |
# File 'lib/jamf/api/classic/api_objects/patch_title.rb', line 384 def source_id @source_id end |
#source_name_id ⇒ String (readonly)
Returns the source_id and name_id joined by ‘-’, a unique identifier.
387 388 389 |
# File 'lib/jamf/api/classic/api_objects/patch_title.rb', line 387 def source_name_id @source_name_id end |
#web_notification ⇒ Boolean Also known as: web_notification?
Returns Are new patches announced in the JSS web ui?.
390 391 392 |
# File 'lib/jamf/api/classic/api_objects/patch_title.rb', line 390 def web_notification @web_notification end |
Class Method Details
.all(refresh = false, source_id: nil, api: nil, cnx: Jamf.cnx) ⇒ Object
The same as @see APIObject.all but also takes an optional source_id: parameter, which limites the results to patch titles with the specified source_id.
Also - since the combined source_id and name_id are unique, create an identifier key ‘:source_name_id’ by joining them with ‘-’
JAMF BUG: More broken json - the id is coming as a string. so here we turn it into an integer manually :-( Ditto for source_id
173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/jamf/api/classic/api_objects/patch_title.rb', line 173 def self.all(refresh = false, source_id: nil, api: nil, cnx: Jamf.cnx) cnx = api if api data = super refresh, cnx: cnx data.each do |info| info[:id] = info[:id].to_i info[:source_name_id] = "#{info[:source_id]}-#{info[:name_id]}" info[:source_id] = info[:source_id].to_i end return data unless source_id data.select { |p| p[:source_id] == source_id } end |
.all_ids(refresh = false, source_id: nil, api: nil, cnx: Jamf.cnx) ⇒ Object
The same as @see APIObject.all_ids but also takes an optional source_id: parameter, which limites the results to patch titles with the specified source_id.
201 202 203 204 205 |
# File 'lib/jamf/api/classic/api_objects/patch_title.rb', line 201 def self.all_ids(refresh = false, source_id: nil, api: nil, cnx: Jamf.cnx) cnx = api if api all(refresh, source_id: source_id, cnx: cnx).map { |i| i[:id] } end |
.all_names(refresh = false, source_id: nil, api: nil, cnx: Jamf.cnx) ⇒ Object
The same as @see APIObject.all_names but also takes an optional source_id: parameter, which limites the results to patch titles with the specified source_id.
191 192 193 194 195 |
# File 'lib/jamf/api/classic/api_objects/patch_title.rb', line 191 def self.all_names(refresh = false, source_id: nil, api: nil, cnx: Jamf.cnx) cnx = api if api all(refresh, source_id: source_id, cnx: cnx).map { |i| i[:name] } end |
.all_source_ids(refresh = false, api: nil, cnx: Jamf.cnx) ⇒ Array<Integer>
Returns an Array of unique source_ids used by active Patches
e.g. if there are patches that come from one internal source and two external sources this might return [1,3,4].
Regardless of how many patches come from each source, the source id appears only once in this array.
222 223 224 225 226 |
# File 'lib/jamf/api/classic/api_objects/patch_title.rb', line 222 def self.all_source_ids(refresh = false, api: nil, cnx: Jamf.cnx) cnx = api if api all(refresh, cnx: cnx).map { |i| i[:source_id] }.sort.uniq end |
.all_source_name_ids(refresh = false, api: nil, cnx: Jamf.cnx) ⇒ Array<String>
Returns all ‘source_name_id’ values for active patches.
230 231 232 233 234 |
# File 'lib/jamf/api/classic/api_objects/patch_title.rb', line 230 def self.all_source_name_ids(refresh = false, api: nil, cnx: Jamf.cnx) cnx = api if api all(refresh, cnx: cnx).map { |i| i[:source_name_id] } end |
.fetch(identifier = nil, **params) ⇒ Object
Patch titles only have an id-based GET resource in the API. so all other lookup values have to be converted to ID before the call to super
NOTE: The only truely unique identifiers are id and source_name_id
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 |
# File 'lib/jamf/api/classic/api_objects/patch_title.rb', line 318 def self.fetch(identifier = nil, **params) # default connection if unspecified cnx = params.delete :cnx cnx ||= params.delete :api # backward compatibility, deprecated cnx ||= Jamf.cnx # source: and source_id: are considered the same, source_id: wins params[:source_id] ||= params[:source] # if given a source name in params[:source_id] this converts it to an id if params[:source_id] params[:source_id] = Jamf::PatchInternalSource.valid_id(params[:source_id], cnx: cnx) params[:source_id] ||= Jamf::PatchExternalSource.valid_id(params[:source_id], cnx: cnx) end id = if identifier valid_id identifier, cnx: cnx elsif params[:id] all_ids(cnx: cnx).include?(params[:id]) ? params[:id] : nil elsif params[:source_name_id] # TODO: make 'map_all' work with :source_name_id # map_all(:source_name_id, to: :id, cnx: cnx)[params[:source_name_id]] map_all(:id, to: :source_name_id, cnx: cnx).invert[params[:source_name_id]] # WARNING: name_id may not be unique elsif params[:name_id] # TODO: make 'map_all' work with :source_name_id # map_all(:source_name_id, to: :id, cnx: cnx)[params[:source_name_id]] map_all(:id, to: :name_id, cnx: cnx).invert[params[:name_id]] # WARNING: name_id may not be unique elsif params[:name] # map_all_ids_to(:name, cnx: cnx).invert[params[:name]] map_all(:name, to: :id, cnx: cnx)[params[:name]] end raise Jamf::NoSuchItemError, "No matching #{name} found" unless id super id: id, cnx: cnx end |
.patch_report(title, version: :all, api: nil, cnx: Jamf.cnx) ⇒ Hash
Get a patch report for a softwaretitle, without fetching an instance. Defaults to reporting all versions. Specifiying a version will be faster.
The Hash returned has 3 keys:
- :total_comptuters [Integer] total computers found for the requested version(s)
- :total versions [Integer] How many versions does this title have?
Always 1 if you report a specific version
- :versions [Hash {String => Array<Hash>}] Keys are the version(s) requested
values are Arrays of Hashes, one per computer with the keyed version
installed. Computer Hashes have identifiers as keys.
PatchTitle#patch_report calls this method, as does PatchTitle::Version.patch_report.
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 |
# File 'lib/jamf/api/classic/api_objects/patch_title.rb', line 262 def self.patch_report(title, version: :all, api: nil, cnx: Jamf.cnx) cnx = api if api title_id = valid_id title, cnx: cnx raise Jamf::NoSuchItemError, "No PatchTitle matches '#{title}'" unless title_id rsrc = patch_report_rsrc title_id, version # TODO: remove this and adjust parsing when jamf fixes the JSON raw_report = XMLWorkaround.data_via_xml(rsrc, PATCH_REPORT_DATA_MAP, cnx)[:patch_report] report = {} report[:total_computers] = raw_report[:total_computers] report[:total_versions] = raw_report[:total_versions] if raw_report[:versions].is_a? Hash vs = raw_report[:versions][:version][:software_version].to_s comps = raw_report[:versions][:version][:computers] comps = [] if comps.empty? report[:versions] = { vs => comps } return report end report[:versions] = {} raw_report[:versions].each do |v| report[:versions][v[:software_version].to_s] = v[:computers].empty? ? [] : v[:computers] end report end |
.valid_id(ident, refresh = false, api: nil, cnx: Jamf.cnx) ⇒ Object
Override the APIObject.valid_id, since patch sources are so non-standard Accept id, source_name_id, or name. Note name may not be unique, and if not, ymmv
366 367 368 369 370 371 372 373 |
# File 'lib/jamf/api/classic/api_objects/patch_title.rb', line 366 def self.valid_id(ident, refresh = false, api: nil, cnx: Jamf.cnx) cnx = api if api id = all_ids(refresh, cnx: cnx).include?(ident) ? ident : nil id ||= map_all(:id, to: :source_name_id).invert[ident] id ||= map_all(:id, to: :name).invert[ident] id end |
Instance Method Details
#category=(new_cat) ⇒ void Originally defined in module Categorizable
This method returns an undefined value.
Change the category of this object. Any of the NON_CATEGORIES values will unset the category
#category_assigned? ⇒ Boolean Also known as: categorized? Originally defined in module Categorizable
Does this object have a category assigned?
#category_id ⇒ Integer Originally defined in module Categorizable
The id of the category for this object.
#category_name ⇒ String Also known as: category Originally defined in module Categorizable
The name of the category for this object. For backward compatibility, this is aliased to just ‘category’
#category_object ⇒ Jamf::Category Originally defined in module Categorizable
The Jamf::Category instance for this object’s category
#changed_pkg_for_version(version) ⇒ Object
this is called by Jamf::PatchTitle::Version#package= to update @changed_pkgs which is used by #rest_xml to change the package assigned to a patch version in this title.
479 480 481 482 |
# File 'lib/jamf/api/classic/api_objects/patch_title.rb', line 479 def changed_pkg_for_version(version) @changed_pkgs << version @need_to_update = true end |
#clone(new_name, api: nil, cnx: nil) ⇒ APIObject Originally defined in module Creatable
make a clone of this API object, with a new name. The class must be creatable
#create ⇒ Object
wrapper to fetch versions after creating
485 486 487 |
# File 'lib/jamf/api/classic/api_objects/patch_title.rb', line 485 def create super end |
#evaluate_new_category(new_cat) ⇒ Array<String, Integer> Originally defined in module Categorizable
Given a category name or id, return the name and id TODO: use APIObject.exist? and/or APIObject.valid_id
#name=(newname) ⇒ void Originally defined in module Updatable
This method returns an undefined value.
Change the name of this item Remember to #update to push changes to the server.
#patch_report(vers = :all) ⇒ Object Also known as: version_report, report
Get a patch report for this title.
See the class method Jamf::PatchTitle.patch_report
500 501 502 |
# File 'lib/jamf/api/classic/api_objects/patch_title.rb', line 500 def patch_report(vers = :all) Jamf::PatchTitle.patch_report id, version: vers, cnx: @cnx end |
#pretty_print_instance_variables ⇒ Array
Remove the various cached data from the instance_variables used to create pretty-print (pp) output.
512 513 514 515 516 |
# File 'lib/jamf/api/classic/api_objects/patch_title.rb', line 512 def pretty_print_instance_variables vars = super vars.delete :@versions vars end |
#site=(new_site) ⇒ void Originally defined in module Sitable
This method returns an undefined value.
Change the site of this object. Any of the NON_SITES values will unset the site
#site_assigned? ⇒ Boolean Originally defined in module Sitable
Does this object have a site assigned?
#site_id ⇒ Integer Originally defined in module Sitable
The id of the site for this object.
#site_name ⇒ String Also known as: site Originally defined in module Sitable
The name of the site for this object. For backward compatibility, this is aliased to just ‘site’
#site_object ⇒ Jamf::Site Originally defined in module Sitable
The Jamf::Site instance for this object’s site
#unset_category ⇒ void Originally defined in module Categorizable
This method returns an undefined value.
Set the category to nothing
#unset_site ⇒ void Originally defined in module Sitable
This method returns an undefined value.
Set the site to nothing
#update ⇒ Object
wrapper to clear @changed_pkgs after updating
490 491 492 493 494 |
# File 'lib/jamf/api/classic/api_objects/patch_title.rb', line 490 def update response = super @changed_pkgs.clear response end |
#versions ⇒ Hash{String => Jamf::PatchTitle::Version}
Returns The Jamf::PatchVersions fetched for this title, keyed by version string.
435 436 437 438 439 440 441 |
# File 'lib/jamf/api/classic/api_objects/patch_title.rb', line 435 def versions return @versions unless in_jss return @versions unless @versions.empty? # if we are in jss, and versions is empty, re-fetch them @versions = self.class.fetch(id: id).versions end |
#versions_with_packages ⇒ Hash
Returns Subset of @versions, containing those which have packages assigned.
446 447 448 |
# File 'lib/jamf/api/classic/api_objects/patch_title.rb', line 446 def versions_with_packages versions.select { |_ver_string, vers| vers.package_assigned? } end |