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.
- 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]
|