ruby-jss 1.5.1 → 1.5.2

Sign up to get free protection for your applications and to get access to all the features.

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]