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.
- checksums.yaml +4 -4
- data/CHANGES.md +26 -0
- data/lib/jamf.rb +8 -13
- data/lib/jamf/api/{abstract_classes → base_classes}/collection_resource.rb +6 -5
- data/lib/jamf/api/{abstract_classes → base_classes}/json_object.rb +4 -20
- data/lib/jamf/api/{abstract_classes → base_classes}/prestage.rb +1 -1
- data/lib/jamf/api/{abstract_classes → base_classes}/resource.rb +6 -2
- data/lib/jamf/api/{abstract_classes → base_classes}/singleton_resource.rb +3 -2
- data/lib/jamf/api/json_objects/device_enrollment_sync_status.rb +1 -1
- data/lib/jamf/api/json_objects/md_prestage_name.rb +1 -1
- data/lib/jamf/api/json_objects/md_prestage_names.rb +2 -2
- data/lib/jamf/api/json_objects/prestage_assignment.rb +2 -2
- data/lib/jamf/api/mixins/{abstract.rb → base_class.rb} +34 -16
- data/lib/jamf/api/resources/collection_resources/building.rb +0 -4
- data/lib/jamf/api/resources/collection_resources/category.rb +0 -1
- data/lib/jamf/api/resources/collection_resources/computer_prestage.rb +1 -1
- data/lib/jamf/api/resources/collection_resources/department.rb +0 -2
- data/lib/jamf/api/resources/collection_resources/mobile_device_prestage.rb +1 -1
- data/lib/jamf/version.rb +1 -1
- data/lib/jss/api_connection.rb +1 -36
- data/lib/jss/api_object/computer.rb +13 -0
- data/lib/jss/api_object/configuration_profile.rb +28 -3
- data/lib/jss/api_object/policy.rb +105 -25
- data/lib/jss/api_object/scopable/scope.rb +31 -30
- data/lib/jss/utility.rb +142 -37
- data/lib/jss/version.rb +1 -1
- metadata +8 -41
- data/lib/jamf/api/abstract_classes/advanced_search.rb +0 -86
- data/lib/jamf/api/abstract_classes/generic_reference.rb +0 -153
- data/lib/jamf/api/abstract_classes/prestage_skip_setup_items.rb +0 -147
- data/lib/jamf/api/json_objects/account_prefs.rb +0 -79
- data/lib/jamf/api/json_objects/android_details.rb +0 -139
- data/lib/jamf/api/json_objects/appletv_details.rb +0 -110
- data/lib/jamf/api/json_objects/attachment.rb +0 -68
- data/lib/jamf/api/json_objects/cellular_network.rb +0 -151
- data/lib/jamf/api/json_objects/computer_prestage_skip_setup_items.rb +0 -80
- data/lib/jamf/api/json_objects/criterion.rb +0 -152
- data/lib/jamf/api/json_objects/extension_attribute_value.rb +0 -128
- data/lib/jamf/api/json_objects/installed_application.rb +0 -59
- data/lib/jamf/api/json_objects/installed_certificate.rb +0 -53
- data/lib/jamf/api/json_objects/installed_configuration_profile.rb +0 -67
- data/lib/jamf/api/json_objects/installed_ebook.rb +0 -58
- data/lib/jamf/api/json_objects/installed_provisioning_profile.rb +0 -59
- data/lib/jamf/api/json_objects/ios_details.rb +0 -244
- data/lib/jamf/api/json_objects/location.rb +0 -95
- data/lib/jamf/api/json_objects/mobile_device_details.rb +0 -219
- data/lib/jamf/api/json_objects/mobile_device_security.rb +0 -101
- data/lib/jamf/api/json_objects/purchasing_data.rb +0 -125
- data/lib/jamf/api/mixins/locatable.rb +0 -124
- data/lib/jamf/api/mixins/referable.rb +0 -92
- data/lib/jamf/api/resources/collection_resources/account.rb +0 -163
- data/lib/jamf/api/resources/collection_resources/advanced_mobile_device_search.rb +0 -52
- data/lib/jamf/api/resources/collection_resources/advanced_user_search.rb +0 -52
- data/lib/jamf/api/resources/collection_resources/computer.rb +0 -49
- data/lib/jamf/api/resources/collection_resources/extension_attribute.rb +0 -45
- data/lib/jamf/api/resources/collection_resources/mobile_device.rb +0 -315
- data/lib/jamf/api/resources/collection_resources/site.rb +0 -77
- data/lib/jamf/api/resources/singleton_resources/authorization.rb +0 -88
- data/lib/jamf/api/resources/singleton_resources/client_checkin_settings.rb +0 -139
- 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 [
|
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
|
-
|
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: '
|
267
|
-
days: '
|
268
|
-
week: '
|
269
|
-
weeks: '
|
270
|
-
month: '
|
271
|
-
months: '
|
272
|
-
year: '
|
273
|
-
years: '
|
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
|
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
|
-
#
|
1801
|
+
# NOTE: Currently the API doesn't have a way to flush only failed policies.
|
1722
1802
|
#
|
1723
|
-
#
|
1724
|
-
#
|
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
|
-
|
1736
|
-
|
1737
|
-
|
1738
|
-
|
1739
|
-
|
1740
|
-
|
1741
|
-
|
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
|
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]
|
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
|
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]
|
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]
|
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
|
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]
|
502
|
+
return unless @targets[key]&.include?(item_id)
|
503
503
|
|
504
504
|
@targets[key].delete item_id
|
505
|
-
@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]
|
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
|
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]
|
564
|
+
return nil if @limitations[key]&.include?(item_id)
|
565
565
|
|
566
|
-
if @exclusions[key]
|
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
|
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]
|
591
|
+
return unless @limitations[key]&.include?(item_id)
|
592
592
|
|
593
593
|
@limitations[key].delete item_id
|
594
|
-
@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
|
-
|
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
|
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]
|
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]
|
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]
|
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
|
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]
|
677
|
+
return unless @exclusions[key]&.include?(item_id)
|
676
678
|
|
677
679
|
@exclusions[key].delete item_id
|
678
|
-
@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
|
data/lib/jss/utility.rb
CHANGED
@@ -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
|
-
#
|
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
|
-
#
|
36
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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.
|
44
|
-
# # ["10.
|
45
|
-
# # "10.
|
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.
|
48
|
-
# # "
|
49
|
-
# # "
|
110
|
+
# # "10.16.x",
|
111
|
+
# # "11.x",
|
112
|
+
# # "12.x",
|
50
113
|
# # ...
|
51
|
-
# # "
|
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
|
-
|
121
|
+
major, minor, maint = min_os.split('.')
|
59
122
|
maint = 'x' if maint.nil? || maint == '0'
|
60
123
|
|
61
|
-
|
62
|
-
|
63
|
-
|
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
|
-
#
|
66
|
-
|
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
|
-
|
69
|
-
(
|
70
|
-
ok_oses <<
|
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
|
75
|
-
|
76
|
-
|
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:
|
432
|
-
revision:
|
433
|
-
maint:
|
434
|
-
patch:
|
435
|
-
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
|
598
|
+
@devmode = setting == :on
|
493
599
|
end
|
494
600
|
|
495
|
-
|
496
601
|
# is devmode currently on?
|
497
602
|
#
|
498
603
|
# @return [Boolean]
|