ruby-jss 1.5.1 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ruby-jss might be problematic. Click here for more details.

Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +26 -0
  3. data/lib/jamf.rb +8 -13
  4. data/lib/jamf/api/{abstract_classes → base_classes}/collection_resource.rb +6 -5
  5. data/lib/jamf/api/{abstract_classes → base_classes}/json_object.rb +4 -20
  6. data/lib/jamf/api/{abstract_classes → base_classes}/prestage.rb +1 -1
  7. data/lib/jamf/api/{abstract_classes → base_classes}/resource.rb +6 -2
  8. data/lib/jamf/api/{abstract_classes → base_classes}/singleton_resource.rb +3 -2
  9. data/lib/jamf/api/json_objects/device_enrollment_sync_status.rb +1 -1
  10. data/lib/jamf/api/json_objects/md_prestage_name.rb +1 -1
  11. data/lib/jamf/api/json_objects/md_prestage_names.rb +2 -2
  12. data/lib/jamf/api/json_objects/prestage_assignment.rb +2 -2
  13. data/lib/jamf/api/mixins/{abstract.rb → base_class.rb} +34 -16
  14. data/lib/jamf/api/resources/collection_resources/building.rb +0 -4
  15. data/lib/jamf/api/resources/collection_resources/category.rb +0 -1
  16. data/lib/jamf/api/resources/collection_resources/computer_prestage.rb +1 -1
  17. data/lib/jamf/api/resources/collection_resources/department.rb +0 -2
  18. data/lib/jamf/api/resources/collection_resources/mobile_device_prestage.rb +1 -1
  19. data/lib/jamf/version.rb +1 -1
  20. data/lib/jss/api_connection.rb +1 -36
  21. data/lib/jss/api_object/computer.rb +13 -0
  22. data/lib/jss/api_object/configuration_profile.rb +28 -3
  23. data/lib/jss/api_object/policy.rb +105 -25
  24. data/lib/jss/api_object/scopable/scope.rb +31 -30
  25. data/lib/jss/utility.rb +142 -37
  26. data/lib/jss/version.rb +1 -1
  27. metadata +8 -41
  28. data/lib/jamf/api/abstract_classes/advanced_search.rb +0 -86
  29. data/lib/jamf/api/abstract_classes/generic_reference.rb +0 -153
  30. data/lib/jamf/api/abstract_classes/prestage_skip_setup_items.rb +0 -147
  31. data/lib/jamf/api/json_objects/account_prefs.rb +0 -79
  32. data/lib/jamf/api/json_objects/android_details.rb +0 -139
  33. data/lib/jamf/api/json_objects/appletv_details.rb +0 -110
  34. data/lib/jamf/api/json_objects/attachment.rb +0 -68
  35. data/lib/jamf/api/json_objects/cellular_network.rb +0 -151
  36. data/lib/jamf/api/json_objects/computer_prestage_skip_setup_items.rb +0 -80
  37. data/lib/jamf/api/json_objects/criterion.rb +0 -152
  38. data/lib/jamf/api/json_objects/extension_attribute_value.rb +0 -128
  39. data/lib/jamf/api/json_objects/installed_application.rb +0 -59
  40. data/lib/jamf/api/json_objects/installed_certificate.rb +0 -53
  41. data/lib/jamf/api/json_objects/installed_configuration_profile.rb +0 -67
  42. data/lib/jamf/api/json_objects/installed_ebook.rb +0 -58
  43. data/lib/jamf/api/json_objects/installed_provisioning_profile.rb +0 -59
  44. data/lib/jamf/api/json_objects/ios_details.rb +0 -244
  45. data/lib/jamf/api/json_objects/location.rb +0 -95
  46. data/lib/jamf/api/json_objects/mobile_device_details.rb +0 -219
  47. data/lib/jamf/api/json_objects/mobile_device_security.rb +0 -101
  48. data/lib/jamf/api/json_objects/purchasing_data.rb +0 -125
  49. data/lib/jamf/api/mixins/locatable.rb +0 -124
  50. data/lib/jamf/api/mixins/referable.rb +0 -92
  51. data/lib/jamf/api/resources/collection_resources/account.rb +0 -163
  52. data/lib/jamf/api/resources/collection_resources/advanced_mobile_device_search.rb +0 -52
  53. data/lib/jamf/api/resources/collection_resources/advanced_user_search.rb +0 -52
  54. data/lib/jamf/api/resources/collection_resources/computer.rb +0 -49
  55. data/lib/jamf/api/resources/collection_resources/extension_attribute.rb +0 -45
  56. data/lib/jamf/api/resources/collection_resources/mobile_device.rb +0 -315
  57. data/lib/jamf/api/resources/collection_resources/site.rb +0 -77
  58. data/lib/jamf/api/resources/singleton_resources/authorization.rb +0 -88
  59. data/lib/jamf/api/resources/singleton_resources/client_checkin_settings.rb +0 -139
  60. data/lib/jamf/api/resources/singleton_resources/reenrollment_settings.rb +0 -95
@@ -1046,6 +1046,19 @@ module JSS
1046
1046
  @need_to_update = true
1047
1047
  end
1048
1048
 
1049
+ # flush the logs for this computer in a given policy
1050
+ # @see JSS::Policy.flush_logs
1051
+ #
1052
+ def flush_policy_logs(policy, older_than: 0, period: :days)
1053
+ JSS::Policy.flush_logs(
1054
+ policy,
1055
+ older_than: older_than,
1056
+ period: period,
1057
+ computers: [@id],
1058
+ api: @api
1059
+ )
1060
+ end
1061
+
1049
1062
  def barcode1=(new_val)
1050
1063
  new_val = new_val.strip
1051
1064
  return nil if @barcode1 == new_val
@@ -55,6 +55,11 @@ module JSS
55
55
  # which DISTRIBUTION_METHODS means we're in self service?
56
56
  SELF_SERVICE_DIST_METHOD = 'Make Available in Self Service'.freeze
57
57
 
58
+ # when a change is made, which in-scope machines should get
59
+ # the changed profile?
60
+ REDEPLOY_NEWLY_ASSIGNED = 'Newly Assigned'.freeze
61
+ REDEPLOY_ALL = 'All'.freeze
62
+
58
63
  # Our SelfService deploys profiles
59
64
  SELF_SERVICE_PAYLOAD = :profile
60
65
 
@@ -76,7 +81,11 @@ module JSS
76
81
  # @return [String] the uuid of this profile. NOT Updatable
77
82
  attr_reader :uuid
78
83
 
79
- # @return [Boolean] Should this profile be redeployed when an inventory update happens?
84
+ # @return [String] When a change is made to the profile, which scoped machines
85
+ # should get the changes? This will always contain REDEPLOY_NEWLY_ASSIGNED
86
+ # when fetched, but can be set to REDEPLOY_ALL via the redeploy_to_all:
87
+ # parameter to #update & #save. After the update is complete, it reverts
88
+ # to REDEPLOY_NEWLY_ASSIGNED
80
89
  attr_reader :redeploy_on_update
81
90
 
82
91
  # @return [String] the plist containing the payloads for this profile. NOT Updatable
@@ -154,11 +163,27 @@ module JSS
154
163
  end
155
164
 
156
165
  # clear flag after updating
157
- def update
158
- super
166
+ def update(redeploy_to_all: false)
167
+ @redeploy_on_update = redeploy_to_all ? REDEPLOY_ALL : REDEPLOY_NEWLY_ASSIGNED
168
+ super()
169
+ # always reset to newly assigned
170
+ @redeploy_on_update = REDEPLOY_NEWLY_ASSIGNED
159
171
  @update_payloads = nil
160
172
  end
161
173
 
174
+ # wrapper with param
175
+ def save(redeploy_to_all: false)
176
+ if @in_jss
177
+ raise JSS::UnsupportedError, 'Updating this object in the JSS is currently not supported by ruby-jss' unless updatable?
178
+
179
+ update redeploy_to_all: redeploy_to_all
180
+ else
181
+ raise JSS::UnsupportedError, 'Creating this object in the JSS is currently not supported by ruby-jss' unless creatable?
182
+
183
+ create
184
+ end
185
+ end
186
+
162
187
  # Private Instance Methods
163
188
  ###################################
164
189
  private
@@ -263,14 +263,14 @@ module JSS
263
263
  }.freeze
264
264
 
265
265
  LOG_FLUSH_INTERVAL_PERIODS = {
266
- day: 'Day',
267
- days: 'Day',
268
- week: 'Week',
269
- weeks: 'Week',
270
- month: 'Month',
271
- months: 'Month',
272
- year: 'Year',
273
- years: 'Year'
266
+ day: 'Days',
267
+ days: 'Days',
268
+ week: 'Weeks',
269
+ weeks: 'Weeks',
270
+ month: 'Months',
271
+ months: 'Months',
272
+ year: 'Years',
273
+ years: 'Years'
274
274
  }.freeze
275
275
 
276
276
  # the object type for this object in
@@ -287,6 +287,83 @@ module JSS
287
287
  # How is the category stored in the API data?
288
288
  CATEGORY_DATA_TYPE = Hash
289
289
 
290
+ # Class Methods
291
+ ######################
292
+
293
+ # Flush logs for a given policy older than some number of days, weeks,
294
+ # months or years, possibly limited to one or more computers.
295
+ #
296
+ # With no parameters, flushes all logs for the policy for all computers.
297
+ #
298
+ # NOTE: Currently the API doesn't have a way to flush only failed policies.
299
+ #
300
+ # WARNING: Log flushing can take a long time, and the API call doesnt return
301
+ # until its finished. The connection timeout will be temporarily raised to
302
+ # 30 minutes, unless it's already higher.
303
+ #
304
+ # @param policy[Integer,String] The id or name of the policy to flush
305
+ #
306
+ # @param older_than[Integer] 0, 1, 2, 3, or 6
307
+ #
308
+ # @param period[Symbol] :days, :weeks, :months, or :years
309
+ #
310
+ # @param computers[Array<Integer,String>] Identifiers of the target computers
311
+ # either ids, names, SNs, macaddrs, or UDIDs. If omitted, flushes logs for
312
+ # all computers
313
+ #
314
+ # @param api [JSS::APIConnection] the API connection to use.
315
+ #
316
+ # @return [void]
317
+ #
318
+ def self.flush_logs(policy, older_than: 0, period: :days, computers: [], api: JSS.api)
319
+ orig_timeout = api.cnx.options.timeout
320
+ pol_id = valid_id policy
321
+ raise JSS::NoSuchItemError, "No Policy identified by '#{policy}'." unless pol_id
322
+
323
+ older_than = LOG_FLUSH_INTERVAL_INTEGERS[older_than]
324
+ raise JSS::InvalidDataError, "older_than must be one of these integers: #{LOG_FLUSH_INTERVAL_INTEGERS.keys.join ', '}" unless older_than
325
+
326
+ period = LOG_FLUSH_INTERVAL_PERIODS[period]
327
+ raise JSS::InvalidDataError, "period must be one of these symbols: :#{LOG_FLUSH_INTERVAL_PERIODS.keys.join ', :'}" unless period
328
+
329
+ computers = [computers] unless computers.is_a? Array
330
+
331
+ # log flushes can be really slow
332
+ api.timeout = 1800 unless orig_timeout > 1800
333
+
334
+ return api.delete_rsrc "#{LOG_FLUSH_RSRC}/policy/id/#{pol_id}/interval/#{older_than}+#{period}" if computers.empty?
335
+
336
+ flush_logs_for_specific_computers pol_id, older_than, period, computers, api
337
+ ensure
338
+ api.timeout = orig_timeout
339
+ end
340
+
341
+ # use an XML body in a DELETE request to flush logs for
342
+ # a list of computers - used by the flush_logs class method
343
+ def self.flush_logs_for_specific_computers(pol_id, older_than, period, computers, api)
344
+ # build the xml body for a DELETE request
345
+ xml_doc = REXML::Document.new JSS::APIConnection::XML_HEADER
346
+ lf = xml_doc.add_element 'logflush'
347
+ lf.add_element('log').text = 'policy'
348
+ lf.add_element('log_id').text = pol_id.to_s
349
+ lf.add_element('interval').text = "#{older_than} #{period}"
350
+ comps_elem = lf.add_element 'computers'
351
+ computers.each do |c|
352
+ id = JSS::Computer.valid_id c
353
+ next unless id
354
+
355
+ ce = comps_elem.add_element 'computer'
356
+ ce.add_element('id').text = id.to_s
357
+ end
358
+
359
+ # Do a DELETE request with a body.
360
+ api.cnx.delete(LOG_FLUSH_RSRC) do |req|
361
+ req.headers[JSS::APIConnection::HTTP_CONTENT_TYPE_HEADER] = JSS::APIConnection::MIME_XML
362
+ req.body = xml_doc.to_s
363
+ end
364
+ end
365
+ private_class_method :flush_logs_for_specific_computers
366
+
290
367
  # Attributes
291
368
  ######################
292
369
 
@@ -1715,34 +1792,37 @@ module JSS
1715
1792
  end
1716
1793
  alias execute run
1717
1794
 
1718
- # Flush all policy logs for this policy older than
1719
- # some number of days, weeks, months or years.
1795
+ # Flush logs for this policy older than
1796
+ # some number of days, weeks, months or years, possibly limited to
1797
+ # one or more computers
1798
+ #
1799
+ # With no parameters, flushes all logs for all computers
1720
1800
  #
1721
- # With no parameters, flushes all logs
1801
+ # NOTE: Currently the API doesn't have a way to flush only failed policies.
1722
1802
  #
1723
- # NOTE: Currently the API doesn't have a way to
1724
- # flush only failed policies.
1803
+ # WARNING: Log flushing can take a long time, and the API call doesnt return
1804
+ # until its finished. The connection timeout will be temporarily raised to
1805
+ # 30 minutes, unless it's already higher.
1725
1806
  #
1726
1807
  # @param older_than[Integer] 0, 1, 2, 3, or 6
1727
1808
  #
1728
1809
  # @param period[Symbol] :days, :weeks, :months, or :years
1729
1810
  #
1811
+ # @param computers[Array<Integer,String>] Identifiers of the target computers
1812
+ # either ids, names, SNs, macaddrs, or UDIDs
1813
+ #
1730
1814
  # @return [void]
1731
1815
  #
1732
- def flush_logs(older_than: 0, period: :days)
1816
+ def flush_logs(older_than: 0, period: :days, computers: [])
1733
1817
  raise JSS::NoSuchItemError, "Policy doesn't exist in the JSS. Use #create first." unless @in_jss
1734
1818
 
1735
- unless LOG_FLUSH_INTERVAL_INTEGERS.key?(older_than)
1736
- raise JSS::InvalidDataError, "older_than must be one of these integers: #{LOG_FLUSH_INTERVAL_INTEGERS.keys.join ', '}"
1737
- end
1738
-
1739
- unless LOG_FLUSH_INTERVAL_PERIODS.key?(period)
1740
- raise JSS::InvalidDataError, "period must be one of these symbols: :#{LOG_FLUSH_INTERVAL_PERIODS.keys.join ', :'}"
1741
- end
1742
-
1743
- interval = "#{LOG_FLUSH_INTERVAL_INTEGERS[older_than]}+#{LOG_FLUSH_INTERVAL_PERIODS[period]}"
1744
-
1745
- @api.delete_rsrc "#{LOG_FLUSH_RSRC}/policy/id/#{@id}/interval/#{interval}"
1819
+ JSS::Policy.flush_logs(
1820
+ @id,
1821
+ older_than: older_than,
1822
+ period: period,
1823
+ computers: computers,
1824
+ api: @api
1825
+ )
1746
1826
  end
1747
1827
 
1748
1828
  # Private Instance Methods
@@ -224,6 +224,7 @@ module JSS
224
224
  # A reference to the object that contains this Scope
225
225
  #
226
226
  # For telling it when a change is made and an update needed
227
+ # and for accessing its api connection
227
228
  attr_accessor :container
228
229
 
229
230
  # @return [Boolean] should we expect a potential 409 Conflict
@@ -246,7 +247,6 @@ module JSS
246
247
  attr_reader :all_targets
247
248
  alias all_targets? all_targets
248
249
 
249
-
250
250
  # The items which form the base scope of included targets
251
251
  #
252
252
  # This is the group of targets to which the limitations and exclusions apply.
@@ -408,7 +408,7 @@ module JSS
408
408
  @exclusions = {}
409
409
  @exclusion_keys.each { |k| @exclusions[k] = [] }
410
410
  end
411
- @container.should_update if @container
411
+ @container&.should_update
412
412
  end
413
413
 
414
414
  # Replace a list of item names for as targets in this scope.
@@ -436,7 +436,7 @@ module JSS
436
436
  list.map! do |ident|
437
437
  item_id = validate_item(:target, key, ident)
438
438
 
439
- if @exclusions[key] && @exclusions[key].include?(item_id)
439
+ if @exclusions[key]&.include?(item_id)
440
440
  raise JSS::AlreadyExistsError, \
441
441
  "Can't set #{key} target to '#{ident}' because it's already an explicit exclusion."
442
442
  end
@@ -448,7 +448,7 @@ module JSS
448
448
 
449
449
  @targets[key] = list
450
450
  @all_targets = false
451
- @container.should_update if @container
451
+ @container&.should_update
452
452
  end # sinclude_in_scope
453
453
  alias set_target set_targets
454
454
  alias set_inclusion set_targets
@@ -474,13 +474,13 @@ module JSS
474
474
  def add_target(key, item)
475
475
  key = pluralize_key(key)
476
476
  item_id = validate_item(:target, key, item)
477
- return if @targets[key] && @exclusions[key].include?(item_id)
477
+ return if @targets[key]&.include?(item_id)
478
478
 
479
- raise JSS::AlreadyExistsError, "Can't set #{key} target to '#{item}' because it's already an explicit exclusion." if @exclusions[key] && @exclusions[key].include?(item_id)
479
+ raise JSS::AlreadyExistsError, "Can't set #{key} target to '#{item}' because it's already an explicit exclusion." if @exclusions[key]&.include?(item_id)
480
480
 
481
481
  @targets[key] << item_id
482
482
  @all_targets = false
483
- @container.should_update if @container
483
+ @container&.should_update
484
484
  end
485
485
  alias add_inclusion add_target
486
486
 
@@ -499,10 +499,10 @@ module JSS
499
499
  key = pluralize_key(key)
500
500
  item_id = validate_item :target, key, item, error_if_not_found: false
501
501
  return unless item_id
502
- return unless @targets[key] && @exclusions[key].include?(item_id)
502
+ return unless @targets[key]&.include?(item_id)
503
503
 
504
504
  @targets[key].delete item_id
505
- @container.should_update if @container
505
+ @container&.should_update
506
506
  end
507
507
  alias remove_inclusion remove_target
508
508
 
@@ -529,7 +529,7 @@ module JSS
529
529
  # check the idents
530
530
  list.map! do |ident|
531
531
  item_id = validate_item(:limitation, key, ident)
532
- if @exclusions[key] && @exclusions[key].include?(item_id)
532
+ if @exclusions[key]&.include?(item_id)
533
533
  raise JSS::AlreadyExistsError, "Can't set #{key} limitation for '#{name}' because it's already an explicit exclusion."
534
534
  end
535
535
 
@@ -539,7 +539,7 @@ module JSS
539
539
  return nil if list.sort == @limitations[key].sort
540
540
 
541
541
  @limitations[key] = list
542
- @container.should_update if @container
542
+ @container&.should_update
543
543
  end # set_limitation
544
544
  alias set_limitations set_limitation
545
545
 
@@ -561,14 +561,14 @@ module JSS
561
561
  def add_limitation(key, item)
562
562
  key = pluralize_key(key)
563
563
  item_id = validate_item(:limitation, key, item)
564
- return nil if @limitations[key] && @exclusions[key].include?(item_id)
564
+ return nil if @limitations[key]&.include?(item_id)
565
565
 
566
- if @exclusions[key] && @exclusions[key].include?(item_id)
566
+ if @exclusions[key]&.include?(item_id)
567
567
  raise JSS::AlreadyExistsError, "Can't set #{key} limitation for '#{name}' because it's already an explicit exclusion."
568
568
  end
569
569
 
570
570
  @limitations[key] << item_id
571
- @container.should_update if @container
571
+ @container&.should_update
572
572
  end
573
573
 
574
574
  # Remove a single item for limiting this scope.
@@ -588,10 +588,10 @@ module JSS
588
588
  key = pluralize_key(key)
589
589
  item_id = validate_item :limitation, key, item, error_if_not_found: false
590
590
  return unless item_id
591
- return unless @limitations[key] && @exclusions[key].include?(item_id)
591
+ return unless @limitations[key]&.include?(item_id)
592
592
 
593
593
  @limitations[key].delete item_id
594
- @container.should_update if @container
594
+ @container&.should_update
595
595
  end ###
596
596
 
597
597
  # Replace an exclusion list for this scope
@@ -617,7 +617,9 @@ module JSS
617
617
  item_id = validate_item(:exclusion, key, ident)
618
618
  case key
619
619
  when *@target_keys
620
- raise JSS::AlreadyExistsError, "Can't exclude #{key} '#{ident}' because it's already explicitly included." if @targets[key] && @exclusions[key].include?(item_id)
620
+ if @targets[key] && @exclusions[key].include?(item_id)
621
+ raise JSS::AlreadyExistsError, "Can't exclude #{key} '#{ident}' because it's already explicitly included."
622
+ end
621
623
  when *LIMITATIONS
622
624
  if @limitations[key] && @exclusions[key].include?(item_id)
623
625
  raise JSS::AlreadyExistsError, "Can't exclude #{key} '#{ident}' because it's already an explicit limitation."
@@ -629,7 +631,7 @@ module JSS
629
631
  return nil if list.sort == @exclusions[key].sort
630
632
 
631
633
  @exclusions[key] = list
632
- @container.should_update if @container
634
+ @container&.should_update
633
635
  end # limit scope
634
636
 
635
637
  # Add a single item for exclusions of this scope.
@@ -648,14 +650,14 @@ module JSS
648
650
  def add_exclusion(key, item)
649
651
  key = pluralize_key(key)
650
652
  item_id = validate_item(:exclusion, key, item)
651
- return if @exclusions[key] && @exclusions[key].include?(item_id)
653
+ return if @exclusions[key]&.include?(item_id)
652
654
 
653
- raise JSS::AlreadyExistsError, "Can't exclude #{key} scope to '#{item}' because it's already explicitly included." if @targets[key] && @targets[key].include?(item)
655
+ raise JSS::AlreadyExistsError, "Can't exclude #{key} scope to '#{item}' because it's already explicitly included." if @targets[key]&.include?(item)
654
656
 
655
- raise JSS::AlreadyExistsError, "Can't exclude #{key} '#{item}' because it's already an explicit limitation." if @limitations[key] && @limitations[key].include?(item)
657
+ raise JSS::AlreadyExistsError, "Can't exclude #{key} '#{item}' because it's already an explicit limitation." if @limitations[key]&.include?(item)
656
658
 
657
659
  @exclusions[key] << item_id
658
- @container.should_update if @container
660
+ @container&.should_update
659
661
  end
660
662
 
661
663
  # Remove a single item for exclusions of this scope
@@ -672,10 +674,10 @@ module JSS
672
674
  def remove_exclusion(key, item)
673
675
  key = pluralize_key(key)
674
676
  item_id = validate_item :exclusion, key, item, error_if_not_found: false
675
- return unless @exclusions[key] && @exclusions[key].include?(item_id)
677
+ return unless @exclusions[key]&.include?(item_id)
676
678
 
677
679
  @exclusions[key].delete item_id
678
- @container.should_update if @container
680
+ @container&.should_update
679
681
  end
680
682
 
681
683
  # @api private
@@ -773,7 +775,7 @@ module JSS
773
775
  ################
774
776
  def scoped_machines
775
777
  scoped_machines = {}
776
- @target_class.all_objects.each do |machine|
778
+ @target_class.all_objects(api: container.api).each do |machine|
777
779
  scoped_machines[machine.id] = machine.name if in_scope? machine
778
780
  end
779
781
  scoped_machines
@@ -809,7 +811,6 @@ module JSS
809
811
  a_target?(machine_data) && within_limitations?(machine_data) && !excluded?(machine_data)
810
812
  end
811
813
 
812
-
813
814
  # Private Instance Methods
814
815
  #####################################
815
816
  private
@@ -850,15 +851,15 @@ module JSS
850
851
 
851
852
  # id will be a string
852
853
  if key == :jamf_ldap_users
853
- id = ident if JSS::User.all_names(:refresh).include?(ident) || JSS::LDAPServer.user_in_ldap?(ident)
854
+ id = ident if JSS::User.all_names(:refresh, api: container.api).include?(ident) || JSS::LDAPServer.user_in_ldap?(ident)
854
855
 
855
856
  # id will be a string
856
857
  elsif key == :ldap_user_groups
857
- id = ident if JSS::LDAPServer.group_in_ldap? ident
858
+ id = ident if JSS::LDAPServer.group_in_ldap? ident, api: container.api
858
859
 
859
860
  # id will be an integer
860
861
  else
861
- id = SCOPING_CLASSES[key].valid_id ident
862
+ id = SCOPING_CLASSES[key].valid_id ident, api: container.api
862
863
  end
863
864
 
864
865
  raise JSS::NoSuchItemError, "No existing #{key} matching '#{ident}'" if error_if_not_found && id.nil?
@@ -930,7 +931,7 @@ module JSS
930
931
  # @return [Array] the general, locacation, and parsed group IDs
931
932
  #
932
933
  def fetch_subsets(ident)
933
- id = @target_class.valid_id ident
934
+ id = @target_class.valid_id ident, api: container.api
934
935
  raise JSS::NoSuchItemError, "No #{@target_class} matching #{machine}" unless id
935
936
 
936
937
  if @target_class == JSS::MobileDevice
@@ -23,59 +23,157 @@
23
23
  #
24
24
  #
25
25
 
26
- #
27
26
  module JSS
28
27
 
29
28
  # A collection of useful utility methods. Mostly for
30
29
  # converting values between formats, parsing data, and
31
30
  # user interaction.
32
31
 
33
- # Converts an OS Version into an Array of higher OS versions.
32
+ # Hash of 'minor' => 'maint'
33
+ # The maximum maint release for macOS 10.minor.maint
34
+ # e.g the highest release of 10.6 was 10.6.8, the highest release of
35
+ # 10.15 was 10.15.7
36
+ #
37
+ # 12 is the default for the current OS and higher
38
+ # (and hoping apple doesn't release 10.16.13)
39
+ OS_TEN_MAXS = {
40
+ 2 => 8,
41
+ 3 => 9,
42
+ 4 => 11,
43
+ 5 => 8,
44
+ 6 => 8,
45
+ 7 => 5,
46
+ 8 => 5,
47
+ 9 => 5,
48
+ 10 => 5,
49
+ 11 => 6,
50
+ 12 => 6,
51
+ 13 => 6,
52
+ 14 => 6,
53
+ 15 => 7,
54
+ 16 => 12
55
+ }
56
+
57
+ # Hash of 'major' => 'minor'
58
+ # The maximum minor release for macOS major.minor
59
+ # e.g. the highest release of 11 is 11.12
60
+ #
61
+ # 12 is the default for the current OS and higher
62
+ # (and hoping apple doesn't release 11.13)
63
+ MAC_OS_MAXS = {
64
+ 11 => 12,
65
+ 12 => 12,
66
+ 13 => 12,
67
+ 14 => 12,
68
+ 15 => 12,
69
+ 16 => 12,
70
+ 17 => 12,
71
+ 18 => 12,
72
+ 19 => 12,
73
+ 20 => 12
74
+ }
75
+
76
+ # Converts an OS Version into an Array of equal or higher OS versions, up to
77
+ # some non-existant max, hopefully far in the future, currently 20.12
78
+ #
79
+ # This array can then be joined with commas and used as the value of the
80
+ # os_requirements for Packages and Scripts.
81
+ #
82
+ # It's unlikely that this method, as written, will still be in use by
83
+ # the release of macOS 20.12, but currently thats the upper limit.
84
+ #
85
+ # Hopefully well before then JAMF will implement a "minimum OS" in Jamf Pro
86
+ # itself, then we could avoid the inherant limitations in using a method like
87
+ # this.
34
88
  #
35
- # It's unlikely that this library will still be in use as-is by the release of OS X 10.30.
36
- # Hopefully well before then JAMF will implement a "minimum OS" in the JSS itself.
89
+ # When the highest maint. release of an OS version is not known, because its
90
+ # the currently released OS version or higher, then this method assumes '12'
91
+ # e.g. '10.16.12', '11.12', '12.12', etc.
37
92
  #
38
- # @param min_os [String] the mimimum OS version to expand, e.g. ">=10.6.7" or "10.6.7"
93
+ # Apple has never released more than 11 updates to a version of macOS
94
+ # (that being 10.4), so hopefully 12 is enough
39
95
  #
40
- # @return [Array] Nearly all potential OS versions from the minimum to 10.19.x.
96
+ # Since Big Sur might report itself as either '10.16.x' or '11.x', this method
97
+ # will allow for both possibilities, and the array will contain whatever
98
+ # iterations needed for both version numbers
99
+ #
100
+ # @param min_os [String] the mimimum OS version to expand, e.g. ">=10.9.4" or "11.1"
101
+ #
102
+ # @return [Array] Nearly all potential OS versions from the minimum to 20.12
41
103
  #
42
104
  # @example
43
- # JSS.expand_min_os ">=10.6.7" # => returns this array
44
- # # ["10.6.7",
45
- # # "10.6.8",
105
+ # JSS.expand_min_os ">=10.9.4" # => returns this array
106
+ # # ["10.9.4",
107
+ # # "10.9.5",
108
+ # # "10.10.x"
46
109
  # # ...
47
- # # "10.6.25",
48
- # # "10.7.x",
49
- # # "10.8.x",
110
+ # # "10.16.x",
111
+ # # "11.x",
112
+ # # "12.x",
50
113
  # # ...
51
- # # "10.30.x"]
114
+ # # "20.x"]
52
115
  #
53
116
  #
54
117
  def self.expand_min_os(min_os)
55
118
  min_os = min_os.delete '>='
56
119
 
57
120
  # split the version into major, minor and maintenance release numbers
58
- (maj, min, maint) = min_os.split('.')
121
+ major, minor, maint = min_os.split('.')
59
122
  maint = 'x' if maint.nil? || maint == '0'
60
123
 
61
- # if the maint release number is an "x" just start the list of OK OS's with it
62
- if maint == 'x'
63
- ok_oses = [maj + '.' + min.to_s + '.x']
124
+ ok_oses = []
125
+
126
+ # if major == 11 e.g. big sur, e.g. 10.16,
127
+ # reset major & min so that we get coverage for both
128
+ # 10.16 and 11, since clients may report it as either
129
+ if major == '11'
130
+ major = '10'
131
+ maint = minor
132
+ minor = '16'
133
+ end
134
+
135
+ # Deal with 10.x.x up to 10.16
136
+ if major == '10'
137
+ # if the maint release number is an "x" just start the list of OK OS's with it
138
+ if maint == 'x'
139
+ ok_oses << min_os
140
+
141
+ # otherwise, start with it and explicitly add all maint releases for
142
+ # that maint version. if unknown because its a current or future OS,
143
+ # go as h
144
+ else
145
+ max_maint_for_minor = OS_TEN_MAXS[minor.to_i]
146
+ (maint.to_i..max_maint_for_minor).each do |m|
147
+ ok_oses << "#{major}.#{minor}.#{m}"
148
+ end # each m
149
+ end
150
+
151
+ # now account for all macOS versions starting with 10.
152
+ # up to 10.16.x
153
+ ((minor.to_i + 1)..16).each do |v|
154
+ ok_oses << "#{major}.#{v}.x"
155
+ end # each v
156
+
157
+ # now reset major to 11, so we can continue with BigSur and up
158
+ major = '11'
159
+ minor = minor == '16' ? maint : 'x'
160
+ end # if major == 10
64
161
 
65
- # otherwise, start with it and explicitly add all maint releases up to 15
66
- # (and hope apple doesn't do more than 15 maint releases for an OS)
162
+ # Now deal with Big Sur and higher, macOS 10.16/11
163
+ if minor == 'x'
164
+ ok_oses << "#{major}.#{minor}"
67
165
  else
68
- ok_oses = []
69
- (maint.to_i..25).each do |m|
70
- ok_oses << maj + '.' + min + '.' + m.to_s
166
+ max_minor_for_major = MAC_OS_MAXS[major.to_i]
167
+ (minor.to_i..max_minor_for_major).each do |m|
168
+ ok_oses << "#{major}.#{m}"
71
169
  end # each m
72
- end
170
+ end # if minor == x
73
171
 
74
- # now account for all OS X versions starting with 10.
75
- # up to 10.30.x
76
- ((min.to_i + 1)..30).each do |v|
77
- ok_oses << maj + '.' + v.to_s + '.x'
172
+ # now account for all macOS versions 11 and up
173
+ ((major.to_i + 1)..MAC_OS_MAXS.keys.max).each do |v|
174
+ ok_oses << "#{v}.x"
78
175
  end # each v
176
+
79
177
  ok_oses
80
178
  end
81
179
 
@@ -95,6 +193,7 @@ module JSS
95
193
  #
96
194
  def self.processor_ok?(requirement, processor = nil)
97
195
  return true if requirement.to_s.empty? || requirement =~ /none/i
196
+
98
197
  processor ||= `/usr/bin/uname -p`
99
198
  requirement == (processor.to_s.include?('86') ? 'x86' : 'ppc')
100
199
  end
@@ -115,6 +214,7 @@ module JSS
115
214
  def self.os_ok?(requirement, os_to_check = nil)
116
215
  return true if requirement.to_s =~ /none/i
117
216
  return true if requirement.to_s == 'n'
217
+
118
218
  requirement = JSS.to_s_and_a(requirement)[:arrayform]
119
219
  return true if requirement.empty?
120
220
 
@@ -187,6 +287,7 @@ module JSS
187
287
  case plist
188
288
  when String
189
289
  return Plist.parse_xml plist if plist.include? '</plist>'
290
+
190
291
  plist = Pathname.new plist
191
292
  when Pathname
192
293
  true
@@ -223,9 +324,7 @@ module JSS
223
324
 
224
325
  # if the UTC offset of the datetime is zero, make a new one with the correct local offset
225
326
  # (which might also be zero if we happen to be in GMT)
226
- if the_dt.offset.zero?
227
- the_dt = DateTime.new(the_dt.year, the_dt.month, the_dt.day, the_dt.hour, the_dt.min, the_dt.sec, JSS::TIME_ZONE_OFFSET)
228
- end
327
+ the_dt = DateTime.new(the_dt.year, the_dt.month, the_dt.day, the_dt.hour, the_dt.min, the_dt.sec, JSS::TIME_ZONE_OFFSET) if the_dt.offset.zero?
229
328
  # now convert it to a Time and return it
230
329
  Time.at the_dt.strftime('%s').to_i, usec
231
330
  end # parse_time
@@ -247,6 +346,7 @@ module JSS
247
346
  #
248
347
  def self.epoch_to_time(epoch)
249
348
  return nil if NIL_DATES.include? epoch
349
+
250
350
  Time.at(epoch.to_i / 1000.0)
251
351
  end # parse_date
252
352
 
@@ -266,6 +366,7 @@ module JSS
266
366
  def self.api_object_class(name)
267
367
  klass = api_object_names[name.downcase.to_sym]
268
368
  raise JSS::InvalidDataError, "Unknown API Object Class: #{name}" unless klass
369
+
269
370
  klass
270
371
  end
271
372
 
@@ -283,11 +384,13 @@ module JSS
283
384
  #
284
385
  def self.api_object_names
285
386
  return @api_object_names if @api_object_names
387
+
286
388
  @api_object_names ||= {}
287
389
  JSS.constants.each do |const|
288
390
  klass = JSS.const_get const
289
391
  next unless klass.is_a? Class
290
392
  next unless klass.ancestors.include? JSS::APIObject
393
+
291
394
  @api_object_names[klass.const_get(:RSRC_LIST_KEY).to_sym] = klass if klass.constants.include? :RSRC_LIST_KEY
292
395
  @api_object_names[klass.const_get(:RSRC_OBJECT_KEY).to_sym] = klass if klass.constants.include? :RSRC_OBJECT_KEY
293
396
  end
@@ -324,6 +427,7 @@ module JSS
324
427
  #
325
428
  def self.array_to_rexml_array(element, list)
326
429
  raise JSS::InvalidDataError, 'Arg. must be an Array.' unless list.is_a? Array
430
+
327
431
  element = element.to_s
328
432
  list.map do |v|
329
433
  e = REXML::Element.new(element)
@@ -350,6 +454,7 @@ module JSS
350
454
  #
351
455
  def self.hash_to_rexml_array(hash)
352
456
  raise InvalidDataError, 'Arg. must be a Hash.' unless hash.is_a? Hash
457
+
353
458
  ary = []
354
459
  hash.each_pair do |k, v|
355
460
  el = REXML::Element.new k.to_s
@@ -428,11 +533,11 @@ module JSS
428
533
 
429
534
  {
430
535
  major: major.to_i,
431
- minor: minor.to_i,
432
- revision: revision.to_i,
433
- maint: revision.to_i,
434
- patch: revision.to_i,
435
- build: build,
536
+ minor: minor.to_i,
537
+ revision: revision.to_i,
538
+ maint: revision.to_i,
539
+ patch: revision.to_i,
540
+ build: build,
436
541
  version: Gem::Version.new("#{major}.#{minor}.#{revision}")
437
542
  }
438
543
  end
@@ -457,6 +562,7 @@ module JSS
457
562
  @stdin_lines ||= ($stdin.tty? ? [] : $stdin.read.lines.map { |l| l.chomp("\n") })
458
563
 
459
564
  return @stdin_lines.join("\n") if line <= 0
565
+
460
566
  idx = line - 1
461
567
  @stdin_lines[idx]
462
568
  end
@@ -489,10 +595,9 @@ module JSS
489
595
  # @return [Boolean] The new state of devmode
490
596
  #
491
597
  def self.devmode(setting)
492
- @devmode = setting == :on ? true : false
598
+ @devmode = setting == :on
493
599
  end
494
600
 
495
-
496
601
  # is devmode currently on?
497
602
  #
498
603
  # @return [Boolean]