ruby-jss 1.2.10 → 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.
- checksums.yaml +4 -4
- data/CHANGES.md +208 -1
- data/lib/jamf.rb +18 -16
- data/lib/jamf/api/base_classes/collection_resource.rb +613 -0
- data/lib/jamf/api/{abstract_classes → base_classes}/json_object.rb +110 -102
- data/lib/jamf/api/{abstract_classes → base_classes}/prestage.rb +56 -31
- data/lib/jamf/api/{abstract_classes → base_classes}/resource.rb +10 -6
- data/lib/jamf/api/{abstract_classes → base_classes}/singleton_resource.rb +4 -3
- data/lib/jamf/api/connection.rb +20 -12
- data/lib/jamf/api/connection/api_error.rb +8 -8
- data/lib/jamf/api/connection/token.rb +36 -15
- data/lib/jamf/api/json_objects/device_enrollment_device.rb +14 -7
- data/lib/jamf/api/json_objects/{location.rb → device_enrollment_device_sync_state.rb} +27 -41
- data/lib/jamf/api/json_objects/device_enrollment_sync_status.rb +1 -1
- data/lib/jamf/api/json_objects/{attachment.rb → locale.rb} +14 -23
- 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/md_prestage_skip_setup_items.rb +50 -1
- data/lib/jamf/api/json_objects/prestage_assignment.rb +2 -2
- data/lib/jamf/api/json_objects/prestage_location.rb +3 -3
- data/lib/jamf/api/json_objects/prestage_purchasing_data.rb +7 -7
- data/lib/jamf/api/json_objects/prestage_scope.rb +1 -1
- data/lib/jamf/api/{resources/collection_resources → json_objects}/time_zone.rb +9 -23
- data/lib/jamf/api/mixins/{abstract.rb → base_class.rb} +34 -16
- data/lib/jamf/api/mixins/bulk_deletable.rb +27 -6
- data/lib/jamf/api/mixins/change_log.rb +201 -51
- data/lib/jamf/api/{resources/collection_resources/extension_attribute.rb → mixins/filterable.rb} +20 -14
- data/lib/jamf/api/mixins/pageable.rb +208 -0
- data/lib/jamf/api/{json_objects/installed_application.rb → mixins/sortable.rb} +33 -33
- data/lib/jamf/api/resources/collection_resources/building.rb +16 -9
- data/lib/jamf/api/resources/collection_resources/category.rb +5 -4
- data/lib/jamf/api/resources/collection_resources/computer_prestage.rb +12 -5
- data/lib/jamf/api/resources/collection_resources/department.rb +1 -3
- data/lib/jamf/api/resources/collection_resources/device_enrollment.rb +13 -13
- data/lib/jamf/api/resources/collection_resources/inventory_preload_record.rb +11 -3
- data/lib/jamf/api/resources/collection_resources/mobile_device_prestage.rb +25 -23
- data/lib/jamf/api/resources/collection_resources/script.rb +61 -25
- data/lib/jamf/api/resources/singleton_resources/app_store_country_codes.rb +15 -5
- data/lib/jamf/api/resources/singleton_resources/locales.rb +155 -0
- data/lib/jamf/api/resources/singleton_resources/time_zones.rb +213 -0
- data/lib/jamf/configuration.rb +7 -9
- data/lib/jamf/ruby_extensions.rb +1 -0
- data/lib/jamf/ruby_extensions/array.rb +1 -1
- data/lib/jamf/ruby_extensions/array/utils.rb +3 -3
- data/lib/jamf/{api/resources/collection_resources/computer.rb → ruby_extensions/dig.rb} +22 -19
- data/lib/jamf/validate.rb +63 -24
- data/lib/jamf/version.rb +1 -1
- data/lib/jss.rb +4 -1
- data/lib/jss/api_connection.rb +111 -433
- data/lib/jss/api_object.rb +16 -13
- data/lib/jss/api_object/advanced_search.rb +27 -26
- data/lib/jss/api_object/app_store_country_codes.rb +298 -0
- data/lib/jss/api_object/categorizable.rb +1 -1
- data/lib/jss/api_object/computer.rb +13 -0
- data/lib/jss/api_object/configuration_profile.rb +60 -4
- data/lib/jss/api_object/directory_binding.rb +273 -0
- data/lib/jss/api_object/directory_binding_type.rb +96 -0
- data/lib/jss/api_object/directory_binding_type/active_directory.rb +539 -0
- data/lib/jss/api_object/directory_binding_type/admitmac.rb +594 -0
- data/lib/jss/api_object/directory_binding_type/centrify.rb +226 -0
- data/lib/jss/api_object/directory_binding_type/open_directory.rb +178 -0
- data/lib/jss/api_object/directory_binding_type/powerbroker_identity_services.rb +73 -0
- data/lib/jss/api_object/disk_encryption_configurations.rb +114 -0
- data/lib/jss/api_object/distribution_point.rb +97 -37
- data/lib/jss/api_object/dock_item.rb +143 -0
- data/lib/jss/api_object/ebook.rb +1 -2
- data/lib/jss/api_object/extendable.rb +1 -1
- data/lib/jss/api_object/extension_attribute.rb +4 -3
- data/lib/jss/api_object/group.rb +33 -2
- data/lib/jss/api_object/mac_application.rb +107 -8
- data/lib/jss/api_object/mobile_device_application.rb +12 -0
- data/lib/jss/api_object/network_segment.rb +195 -70
- data/lib/jss/api_object/package.rb +105 -40
- data/lib/jss/api_object/patch_source.rb +10 -9
- data/lib/jss/api_object/policy.rb +596 -32
- data/lib/jss/api_object/printer.rb +446 -0
- data/lib/jss/api_object/scopable.rb +10 -15
- data/lib/jss/api_object/scopable/scope.rb +371 -55
- data/lib/jss/api_object/self_servable.rb +17 -9
- data/lib/jss/api_object/uploadable.rb +1 -1
- data/lib/jss/api_object/user.rb +42 -1
- data/lib/jss/api_object/vpp_account.rb +209 -0
- data/lib/jss/api_object/vppable.rb +169 -13
- data/lib/jss/composer.rb +1 -1
- data/lib/jss/exceptions.rb +3 -0
- data/lib/jss/server.rb +15 -0
- data/lib/jss/utility.rb +143 -52
- data/lib/jss/validate.rb +53 -10
- data/lib/jss/version.rb +1 -1
- metadata +56 -61
- data/lib/jamf/api/abstract_classes/advanced_search.rb +0 -86
- data/lib/jamf/api/abstract_classes/collection_resource.rb +0 -433
- data/lib/jamf/api/abstract_classes/generic_reference.rb +0 -145
- data/lib/jamf/api/abstract_classes/prestage_skip_setup_items.rb +0 -126
- 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/cellular_network.rb +0 -151
- data/lib/jamf/api/json_objects/computer_prestage_skip_setup_items.rb +0 -67
- 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_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/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/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
|
@@ -41,17 +41,21 @@ module JSS
|
|
|
41
41
|
# This class provides methods for adding, removing, or fully replacing the
|
|
42
42
|
# various items in scope's realms: targets, limitations, and exclusions.
|
|
43
43
|
#
|
|
44
|
-
#
|
|
44
|
+
# This class also provides a way to see if a machine will be included in
|
|
45
|
+
# this scope.
|
|
46
|
+
#
|
|
47
|
+
# IMPORTANT - Users & User Groups in Targets and Exclusions:
|
|
48
|
+
#
|
|
45
49
|
# The classic API has bugs regarding the use of Users, UserGroups,
|
|
46
50
|
# LDAP/Local Users, & LDAP User Groups in scopes. Here's a discussion
|
|
47
51
|
# of those bugs and how ruby-jss handles them.
|
|
48
52
|
#
|
|
49
53
|
# Targets/Inclusions
|
|
50
|
-
# - 'Users' can only be JSS::Users - No LDAP
|
|
54
|
+
# - 'Users' in the Scope UI can only be JSS::Users - No LDAP
|
|
51
55
|
# - BUG: They do not appear in API data (XML or JSON) and are
|
|
52
56
|
# NOT SUPPORTED in ruby-jss.
|
|
53
57
|
# - You must use the Web UI to work with them in a Scope.
|
|
54
|
-
# - 'User Groups' can only be JSS::UserGroups - No LDAP
|
|
58
|
+
# - 'User Groups' in the Scope UI can only be JSS::UserGroups - No LDAP
|
|
55
59
|
# - BUG: They do not appear in API data (XML or JSON) and are
|
|
56
60
|
# NOT SUPPORTED in ruby-jss.
|
|
57
61
|
# - You must use the Web UI to work with them in a Scope.
|
|
@@ -70,11 +74,11 @@ module JSS
|
|
|
70
74
|
# scope=>limitations=>user_groups
|
|
71
75
|
#
|
|
72
76
|
# Exclusions, combines the behavior of Inclusions & Limitations
|
|
73
|
-
# - 'Users' can only be JSS::Users - No LDAP
|
|
77
|
+
# - 'Users' in the Scope UI can only be JSS::Users - No LDAP
|
|
74
78
|
# - BUG: They do not appear in API data (XML or JSON) and are
|
|
75
79
|
# NOT SUPPORTED in ruby-jss.
|
|
76
80
|
# - You must use the Web UI to work with them in a Scope.
|
|
77
|
-
# - 'User Groups' can only be JSS::UserGroups - No LDAP
|
|
81
|
+
# - 'User Groups' in the Scope UI can only be JSS::UserGroups - No LDAP
|
|
78
82
|
# - BUG: They do not appear in API data (XML or JSON) and are
|
|
79
83
|
# NOT SUPPORTED in ruby-jss.
|
|
80
84
|
# - You must use the Web UI to work with them in a Scope.
|
|
@@ -220,62 +224,70 @@ module JSS
|
|
|
220
224
|
# A reference to the object that contains this Scope
|
|
221
225
|
#
|
|
222
226
|
# For telling it when a change is made and an update needed
|
|
227
|
+
# and for accessing its api connection
|
|
223
228
|
attr_accessor :container
|
|
224
229
|
|
|
225
230
|
# @return [Boolean] should we expect a potential 409 Conflict
|
|
226
231
|
# if we can't connect to LDAP servers for verification?
|
|
227
232
|
attr_accessor :unable_to_verify_ldap_entries
|
|
228
233
|
|
|
229
|
-
# what type of target is this scope for? Computers or
|
|
234
|
+
# what type of target is this scope for? Computers or MobileDevices?
|
|
230
235
|
attr_reader :target_class
|
|
231
236
|
|
|
232
|
-
#
|
|
233
|
-
|
|
234
|
-
# The items which form the base scope of included targets
|
|
235
|
-
#
|
|
236
|
-
# This is the group of targets to which the limitations and exclusions apply.
|
|
237
|
-
# they keys are:
|
|
238
|
-
# - :targets
|
|
239
|
-
# - :target_groups
|
|
240
|
-
# - :departments
|
|
241
|
-
# - :buildings
|
|
242
|
-
# and the values are Arrays of names of those things.
|
|
243
|
-
#
|
|
244
|
-
attr_reader :inclusions
|
|
237
|
+
# what type of target group is this scope for? ComputerGroups or MobileDeviceGroups?
|
|
238
|
+
attr_reader :group_class
|
|
245
239
|
|
|
246
240
|
# @return [Boolean]
|
|
247
241
|
#
|
|
248
242
|
# Does this scope cover all targets?
|
|
249
243
|
#
|
|
250
|
-
# If this is true, the @
|
|
244
|
+
# If this is true, the @targets Hash is ignored, and all
|
|
251
245
|
# targets in the JSS form the base scope.
|
|
252
246
|
#
|
|
253
247
|
attr_reader :all_targets
|
|
248
|
+
alias all_targets? all_targets
|
|
254
249
|
|
|
255
|
-
#
|
|
250
|
+
# The items which form the base scope of included targets
|
|
256
251
|
#
|
|
257
|
-
#
|
|
252
|
+
# This is the group of targets to which the limitations and exclusions apply.
|
|
253
|
+
# they keys are:
|
|
254
|
+
# - :computers or :mobile_devices (which are directly targeted)
|
|
255
|
+
# - :direct_targets - a synonym for :mobile_devices or :computers
|
|
256
|
+
# - :computer_groups or :mobile_device_groups (which target all of their memebers)
|
|
257
|
+
# - :group_targets - a synonym for :computer_groups or :mobile_device_groups
|
|
258
|
+
# - :departments
|
|
259
|
+
# - :buildings
|
|
260
|
+
# and the values are Arrays of names of those things.
|
|
258
261
|
#
|
|
259
|
-
#
|
|
262
|
+
# @return [Hash{Symbol: Array<Integer>}]
|
|
263
|
+
attr_reader :targets
|
|
264
|
+
# backward compatibility
|
|
265
|
+
alias inclusions targets
|
|
266
|
+
|
|
267
|
+
# The items in these arrays are the limitations applied to targets in the @targets .
|
|
268
|
+
#
|
|
269
|
+
# The arrays of ids are:
|
|
260
270
|
# - :network_segments
|
|
261
|
-
# - :
|
|
271
|
+
# - :jamf_ldap_users
|
|
262
272
|
# - :user_groups
|
|
263
273
|
#
|
|
274
|
+
# @return [Hash{Symbol: Array<Integer, String>}]
|
|
264
275
|
attr_reader :limitations
|
|
265
276
|
|
|
266
|
-
# @
|
|
277
|
+
# The items in these arrays are the exclusions applied to targets in the @targets .
|
|
267
278
|
#
|
|
268
|
-
# The
|
|
269
|
-
#
|
|
270
|
-
#
|
|
271
|
-
# - :
|
|
272
|
-
# - :
|
|
279
|
+
# The arrays of ids are:
|
|
280
|
+
# - :computers or :mobile_devices (which are directly excluded)
|
|
281
|
+
# - :direct_exclusions - a synonym for :mobile_devices or :computers
|
|
282
|
+
# - :computer_groups or :mobile_device_groups (which exclude all of their memebers)
|
|
283
|
+
# - :group_exclusions - a synonym for :computer_groups or :mobile_device_groups
|
|
273
284
|
# - :departments
|
|
274
285
|
# - :buildings
|
|
275
286
|
# - :network_segments
|
|
276
287
|
# - :users
|
|
277
288
|
# - :user_groups
|
|
278
289
|
#
|
|
290
|
+
# @return [Hash{Symbol: Array<Integer, String>}]
|
|
279
291
|
attr_reader :exclusions
|
|
280
292
|
|
|
281
293
|
# Public Instance Methods
|
|
@@ -299,7 +311,7 @@ module JSS
|
|
|
299
311
|
@group_key = TARGETS_AND_GROUPS[@target_key]
|
|
300
312
|
@group_class = SCOPING_CLASSES[@group_key]
|
|
301
313
|
|
|
302
|
-
@
|
|
314
|
+
@target_keys = [@target_key, @group_key] + INCLUSIONS
|
|
303
315
|
@exclusion_keys = [@target_key, @group_key] + EXCLUSIONS
|
|
304
316
|
|
|
305
317
|
@all_key = "all_#{target_key}".to_sym
|
|
@@ -307,11 +319,13 @@ module JSS
|
|
|
307
319
|
|
|
308
320
|
# Everything gets mapped from an Array of Hashes to
|
|
309
321
|
# an Array of ids
|
|
310
|
-
@
|
|
311
|
-
@
|
|
322
|
+
@targets = {}
|
|
323
|
+
@target_keys.each do |k|
|
|
312
324
|
raw_scope[k] ||= []
|
|
313
|
-
@
|
|
314
|
-
|
|
325
|
+
@targets[k] = raw_scope[k].compact.map { |n| n[:id].to_i }
|
|
326
|
+
@targets[:direct_targets] = @targets[k] if k == @target_key
|
|
327
|
+
@targets[:group_targets] = @targets[k] if k == @group_key
|
|
328
|
+
end # @target_keys.each do |k|
|
|
315
329
|
|
|
316
330
|
# the :users key from the API is what we call :jamf_ldap_users
|
|
317
331
|
# and the :user_groups key from the API we call :ldap_user_groups
|
|
@@ -365,6 +379,8 @@ module JSS
|
|
|
365
379
|
api_data = raw_scope[:exclusions][k]
|
|
366
380
|
api_data ||= []
|
|
367
381
|
@exclusions[k] = api_data.compact.map { |n| n[:id].to_i }
|
|
382
|
+
@exclusions[:direct_exclusions] = @exclusions[k] if k == @target_key
|
|
383
|
+
@exclusions[:group_exclusions] = @exclusions[k] if k == @group_key
|
|
368
384
|
end # if ...elsif... else
|
|
369
385
|
end # @exclusion_keys.each
|
|
370
386
|
end # if raw_scope[:exclusions]
|
|
@@ -382,8 +398,8 @@ module JSS
|
|
|
382
398
|
# @return [void]
|
|
383
399
|
#
|
|
384
400
|
def include_all(clear = false)
|
|
385
|
-
@
|
|
386
|
-
@
|
|
401
|
+
@targets = {}
|
|
402
|
+
@target_keys.each { |k| @targets[k] = [] }
|
|
387
403
|
@all_targets = true
|
|
388
404
|
if clear
|
|
389
405
|
@limitations = {}
|
|
@@ -428,9 +444,9 @@ module JSS
|
|
|
428
444
|
item_id
|
|
429
445
|
end # each
|
|
430
446
|
|
|
431
|
-
return nil if list.sort == @
|
|
447
|
+
return nil if list.sort == @targets[key].sort
|
|
432
448
|
|
|
433
|
-
@
|
|
449
|
+
@targets[key] = list
|
|
434
450
|
@all_targets = false
|
|
435
451
|
@container&.should_update
|
|
436
452
|
end # sinclude_in_scope
|
|
@@ -458,11 +474,11 @@ module JSS
|
|
|
458
474
|
def add_target(key, item)
|
|
459
475
|
key = pluralize_key(key)
|
|
460
476
|
item_id = validate_item(:target, key, item)
|
|
461
|
-
return if @
|
|
477
|
+
return if @targets[key]&.include?(item_id)
|
|
462
478
|
|
|
463
479
|
raise JSS::AlreadyExistsError, "Can't set #{key} target to '#{item}' because it's already an explicit exclusion." if @exclusions[key]&.include?(item_id)
|
|
464
480
|
|
|
465
|
-
@
|
|
481
|
+
@targets[key] << item_id
|
|
466
482
|
@all_targets = false
|
|
467
483
|
@container&.should_update
|
|
468
484
|
end
|
|
@@ -483,9 +499,9 @@ module JSS
|
|
|
483
499
|
key = pluralize_key(key)
|
|
484
500
|
item_id = validate_item :target, key, item, error_if_not_found: false
|
|
485
501
|
return unless item_id
|
|
486
|
-
return unless @
|
|
502
|
+
return unless @targets[key]&.include?(item_id)
|
|
487
503
|
|
|
488
|
-
@
|
|
504
|
+
@targets[key].delete item_id
|
|
489
505
|
@container&.should_update
|
|
490
506
|
end
|
|
491
507
|
alias remove_inclusion remove_target
|
|
@@ -600,10 +616,12 @@ module JSS
|
|
|
600
616
|
list.map! do |ident|
|
|
601
617
|
item_id = validate_item(:exclusion, key, ident)
|
|
602
618
|
case key
|
|
603
|
-
when *@
|
|
604
|
-
|
|
619
|
+
when *@target_keys
|
|
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
|
|
605
623
|
when *LIMITATIONS
|
|
606
|
-
if @limitations[key]
|
|
624
|
+
if @limitations[key] && @exclusions[key].include?(item_id)
|
|
607
625
|
raise JSS::AlreadyExistsError, "Can't exclude #{key} '#{ident}' because it's already an explicit limitation."
|
|
608
626
|
end
|
|
609
627
|
end
|
|
@@ -634,7 +652,7 @@ module JSS
|
|
|
634
652
|
item_id = validate_item(:exclusion, key, item)
|
|
635
653
|
return if @exclusions[key]&.include?(item_id)
|
|
636
654
|
|
|
637
|
-
raise JSS::AlreadyExistsError, "Can't exclude #{key} scope to '#{item}' because it's already explicitly included." if @
|
|
655
|
+
raise JSS::AlreadyExistsError, "Can't exclude #{key} scope to '#{item}' because it's already explicitly included." if @targets[key]&.include?(item)
|
|
638
656
|
|
|
639
657
|
raise JSS::AlreadyExistsError, "Can't exclude #{key} '#{item}' because it's already an explicit limitation." if @limitations[key]&.include?(item)
|
|
640
658
|
|
|
@@ -672,7 +690,8 @@ module JSS
|
|
|
672
690
|
scope = REXML::Element.new 'scope'
|
|
673
691
|
scope.add_element(@all_key.to_s).text = @all_targets
|
|
674
692
|
|
|
675
|
-
@
|
|
693
|
+
@target_keys.each do |klass|
|
|
694
|
+
list = @targets[klass]
|
|
676
695
|
list.compact!
|
|
677
696
|
list.delete 0
|
|
678
697
|
list_as_hashes = list.map { |i| { id: i } }
|
|
@@ -702,7 +721,8 @@ module JSS
|
|
|
702
721
|
end
|
|
703
722
|
|
|
704
723
|
exclusions = scope.add_element('exclusions')
|
|
705
|
-
@
|
|
724
|
+
@exclusion_keys.each do |klass|
|
|
725
|
+
list = @exclusions[klass]
|
|
706
726
|
list.compact!
|
|
707
727
|
list.delete 0
|
|
708
728
|
if klass == :jamf_ldap_users
|
|
@@ -737,9 +757,59 @@ module JSS
|
|
|
737
757
|
vars
|
|
738
758
|
end
|
|
739
759
|
|
|
740
|
-
#
|
|
760
|
+
# Return a hash of id => name for all machines in the target class
|
|
761
|
+
# that are within this scope.
|
|
762
|
+
#
|
|
763
|
+
# WARNING: This must instantiate all machines in the target class.
|
|
764
|
+
# It will still be slow, at least the first time for each target class.
|
|
765
|
+
# On the upside, the instantiated machines will be cached, so generating
|
|
766
|
+
# this list for other scopes with the same target class will be much
|
|
767
|
+
# much faster.
|
|
768
|
+
# In tests, 1600 Computers took about 7 minutes the first time,
|
|
769
|
+
# but less than 1 second after caching.
|
|
770
|
+
#
|
|
771
|
+
# See also the warning for #in_scope?
|
|
772
|
+
#
|
|
773
|
+
# @return [Hash{Integer => String}]
|
|
774
|
+
#
|
|
775
|
+
################
|
|
776
|
+
def scoped_machines
|
|
777
|
+
scoped_machines = {}
|
|
778
|
+
@target_class.all_objects(api: container.api).each do |machine|
|
|
779
|
+
scoped_machines[machine.id] = machine.name if in_scope? machine
|
|
780
|
+
end
|
|
781
|
+
scoped_machines
|
|
782
|
+
end
|
|
783
|
+
|
|
784
|
+
# is a given machine is in this scope?
|
|
785
|
+
#
|
|
786
|
+
# For a parameter you may pass either an instantiated
|
|
787
|
+
# JSS::MobileDevice or JSS::Computer, or an identifier for one.
|
|
788
|
+
# If an identifier is passed, it is not instantiated, but an API
|
|
789
|
+
# request is made for just the required subsets of data, thus
|
|
790
|
+
# speeding things up a bit when calling this method many times.
|
|
791
|
+
#
|
|
792
|
+
# WARNING: For scopes that include Jamf Users and Jamf User Groups
|
|
793
|
+
# as targets or exclusions, this method may return an incorrect value.
|
|
794
|
+
# See the discussion in the documentation for the Scopable::Scope class
|
|
795
|
+
# under 'IMPORTANT - Users & User Groups in Targets and Exclusions'
|
|
796
|
+
#
|
|
797
|
+
# NOTE: currently in-range iBeacons are transient, and are not reported
|
|
798
|
+
# to the JSS as inventory data. As such they are ignored in this result.
|
|
799
|
+
# If a scope contains iBeacon limitations or exclusions, it is up to
|
|
800
|
+
# the user to be aware of that when evaluating the meaning of this result.
|
|
801
|
+
#
|
|
802
|
+
# @param machine[Integer, String, JSS::MobileDevice, JSS::Computer]
|
|
803
|
+
# Either an identifier for the machine, or an instantiated object
|
|
804
|
+
#
|
|
805
|
+
# @return [Boolean]
|
|
806
|
+
#
|
|
807
|
+
##############
|
|
808
|
+
def in_scope?(machine)
|
|
809
|
+
machine_data = fetch_machine_data machine
|
|
741
810
|
|
|
742
|
-
|
|
811
|
+
a_target?(machine_data) && within_limitations?(machine_data) && !excluded?(machine_data)
|
|
812
|
+
end
|
|
743
813
|
|
|
744
814
|
# Private Instance Methods
|
|
745
815
|
#####################################
|
|
@@ -765,7 +835,7 @@ module JSS
|
|
|
765
835
|
# which keys allowed depends on how the item is used...
|
|
766
836
|
possible_keys =
|
|
767
837
|
case realm
|
|
768
|
-
when :target then @
|
|
838
|
+
when :target then @target_keys
|
|
769
839
|
when :limitation then LIMITATIONS
|
|
770
840
|
when :exclusion then @exclusion_keys
|
|
771
841
|
else
|
|
@@ -781,15 +851,15 @@ module JSS
|
|
|
781
851
|
|
|
782
852
|
# id will be a string
|
|
783
853
|
if key == :jamf_ldap_users
|
|
784
|
-
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)
|
|
785
855
|
|
|
786
856
|
# id will be a string
|
|
787
857
|
elsif key == :ldap_user_groups
|
|
788
|
-
id = ident if JSS::LDAPServer.group_in_ldap? ident
|
|
858
|
+
id = ident if JSS::LDAPServer.group_in_ldap? ident, api: container.api
|
|
789
859
|
|
|
790
860
|
# id will be an integer
|
|
791
861
|
else
|
|
792
|
-
id = SCOPING_CLASSES[key].valid_id ident
|
|
862
|
+
id = SCOPING_CLASSES[key].valid_id ident, api: container.api
|
|
793
863
|
end
|
|
794
864
|
|
|
795
865
|
raise JSS::NoSuchItemError, "No existing #{key} matching '#{ident}'" if error_if_not_found && id.nil?
|
|
@@ -809,6 +879,252 @@ module JSS
|
|
|
809
879
|
end
|
|
810
880
|
end
|
|
811
881
|
|
|
882
|
+
# The data used by the methods that figure out if a machine is
|
|
883
|
+
# in this scope, a Hash of Hashes. the sub hashes are:
|
|
884
|
+
#
|
|
885
|
+
# general: the 'general' subset
|
|
886
|
+
# location: the 'location' subset
|
|
887
|
+
# group_ids: an Array of the group ids to which the machine belongs.
|
|
888
|
+
#
|
|
889
|
+
# @param machine[Integer, String, JSS::MobileDevice, JSS::Computer]
|
|
890
|
+
# Either an identifier for the machine, or an instantiated object
|
|
891
|
+
#
|
|
892
|
+
# @return
|
|
893
|
+
#
|
|
894
|
+
def fetch_machine_data(machine)
|
|
895
|
+
case machine
|
|
896
|
+
when JSS::Computer
|
|
897
|
+
raise JSS::InvalidDataError, "Targets of this scope must be #{@target_class}" unless @target_class == JSS::Computer
|
|
898
|
+
|
|
899
|
+
general = machine.init_data[:general]
|
|
900
|
+
location = machine.init_data[:location]
|
|
901
|
+
group_ids = group_ids machine.computer_groups
|
|
902
|
+
|
|
903
|
+
# put in standardize place for easier use
|
|
904
|
+
# MDevs already have this at general[:managed]
|
|
905
|
+
general[:managed] = general[:remote_management][:managed]
|
|
906
|
+
|
|
907
|
+
when JSS::MobileDevice
|
|
908
|
+
raise JSS::InvalidDataError, "Targets of this scope must be #{@target_class}" unless @target_class == JSS::MobileDevice
|
|
909
|
+
|
|
910
|
+
general = machine.init_data[:general]
|
|
911
|
+
location = machine.init_data[:location]
|
|
912
|
+
group_ids = group_ids machine.mobile_device_groups
|
|
913
|
+
|
|
914
|
+
else
|
|
915
|
+
general, location, group_ids = fetch_subsets(machine)
|
|
916
|
+
end # case
|
|
917
|
+
|
|
918
|
+
{
|
|
919
|
+
general: general,
|
|
920
|
+
location: location,
|
|
921
|
+
group_ids: group_ids
|
|
922
|
+
}
|
|
923
|
+
end
|
|
924
|
+
|
|
925
|
+
# When we are given an indentifier for a machine,
|
|
926
|
+
# fetch just the subsets of API data we need to
|
|
927
|
+
# determine if the machine is in this scope
|
|
928
|
+
#
|
|
929
|
+
# @param ident[String, Integer]
|
|
930
|
+
#
|
|
931
|
+
# @return [Array] the general, locacation, and parsed group IDs
|
|
932
|
+
#
|
|
933
|
+
def fetch_subsets(ident)
|
|
934
|
+
id = @target_class.valid_id ident, api: container.api
|
|
935
|
+
raise JSS::NoSuchItemError, "No #{@target_class} matching #{machine}" unless id
|
|
936
|
+
|
|
937
|
+
if @target_class == JSS::MobileDevice
|
|
938
|
+
grp_subset = 'MobileDeviceGroups'
|
|
939
|
+
top_key = :mobile_device
|
|
940
|
+
else
|
|
941
|
+
grp_subset = 'GroupsAccounts'
|
|
942
|
+
top_key = :computer
|
|
943
|
+
end
|
|
944
|
+
subset_rsrc = "#{@target_class::RSRC_BASE}/id/#{id}/subset/General&Location&#{grp_subset}"
|
|
945
|
+
data = container.api.get_rsrc(subset_rsrc)[top_key]
|
|
946
|
+
grp_data =
|
|
947
|
+
if @target_class == JSS::MobileDevice
|
|
948
|
+
data[:mobile_device_groups]
|
|
949
|
+
else
|
|
950
|
+
data[:groups_accounts][:computer_group_memberships]
|
|
951
|
+
end
|
|
952
|
+
|
|
953
|
+
[data[:general], data[:location], group_ids(grp_data)]
|
|
954
|
+
end
|
|
955
|
+
|
|
956
|
+
# Given the raw API data for a machines group membership,
|
|
957
|
+
# return an array of the IDs of the groups.
|
|
958
|
+
#
|
|
959
|
+
# @param raw[Array] The API array of the machine's group memberships
|
|
960
|
+
#
|
|
961
|
+
# @return [Array] The ID's of the groups to which the machine belongs.
|
|
962
|
+
#
|
|
963
|
+
def group_ids(raw)
|
|
964
|
+
if @target_class == JSS::MobileDevice
|
|
965
|
+
raw.map { |mdg| mdg[:id] }
|
|
966
|
+
else
|
|
967
|
+
names_to_ids = @group_class.map_all_ids_to(:name).invert
|
|
968
|
+
raw.map { |gn| names_to_ids[gn] }
|
|
969
|
+
end
|
|
970
|
+
end
|
|
971
|
+
|
|
972
|
+
# @param machine_data[Hash] See #fetch_machine_data
|
|
973
|
+
# @return [Boolean]
|
|
974
|
+
################
|
|
975
|
+
def a_target?(machine_data)
|
|
976
|
+
return false unless machine_data[:general][:managed]
|
|
977
|
+
return true if \
|
|
978
|
+
all_targets? || \
|
|
979
|
+
machine_directly_scoped?(machine_data, :target) || \
|
|
980
|
+
machine_in_scope_group?(machine_data, :target) || \
|
|
981
|
+
machine_in_scope_buildings?(machine_data, :target) || \
|
|
982
|
+
machine_in_scope_depts?(machine_data, :target)
|
|
983
|
+
|
|
984
|
+
false
|
|
985
|
+
end
|
|
986
|
+
|
|
987
|
+
# @param machine_data[Hash] See #fetch_machine_data
|
|
988
|
+
# @return [Boolean]
|
|
989
|
+
################
|
|
990
|
+
def within_limitations?(machine_data)
|
|
991
|
+
return false if \
|
|
992
|
+
machine_in_scope_netsegs?(machine_data, :limitation) == false || \
|
|
993
|
+
machine_in_scope_jamf_ldap_users_list?(machine_data, :limitation) == false || \
|
|
994
|
+
machine_in_scope_ldap_usergroup_list?(machine_data, :limitation) == false
|
|
995
|
+
|
|
996
|
+
true
|
|
997
|
+
end
|
|
998
|
+
|
|
999
|
+
# @param machine_data[Hash] See #fetch_machine_data
|
|
1000
|
+
# @return [Boolean]
|
|
1001
|
+
################
|
|
1002
|
+
def excluded?(machine_data)
|
|
1003
|
+
return true if
|
|
1004
|
+
machine_directly_scoped?(machine_data, :exclusion) || \
|
|
1005
|
+
machine_in_scope_group?(machine_data, :exclusion) || \
|
|
1006
|
+
machine_in_scope_buildings?(machine_data, :exclusion) || \
|
|
1007
|
+
machine_in_scope_depts?(machine_data, :exclusion) || \
|
|
1008
|
+
machine_in_scope_netsegs?(machine_data, :exclusion) || \
|
|
1009
|
+
machine_in_scope_jamf_ldap_users_list?(machine_data, :exclusion) || \
|
|
1010
|
+
machine_in_scope_ldap_usergroup_list?(machine_data, :exclusion)
|
|
1011
|
+
|
|
1012
|
+
false
|
|
1013
|
+
end
|
|
1014
|
+
|
|
1015
|
+
# @param machine_data[Hash] See #fetch_machine_data
|
|
1016
|
+
# @param part[Symbol] either :target or :exclusion
|
|
1017
|
+
# @return [Boolean] Is the machine directly spcified in this part of the scope?
|
|
1018
|
+
################
|
|
1019
|
+
def machine_directly_scoped?(machine_data, part)
|
|
1020
|
+
scope_list = part == :target ? @targets[:direct_targets] : @exclusions[:direct_exclusions]
|
|
1021
|
+
scope_list.include? machine_data[:general][:id]
|
|
1022
|
+
end
|
|
1023
|
+
|
|
1024
|
+
# @param machine_data[Hash] See #fetch_machine_data
|
|
1025
|
+
# @param part[Symbol] either :target or :exclusion
|
|
1026
|
+
# @return [Boolean] Is the machine a member of any group listed in this part of the scope?
|
|
1027
|
+
################
|
|
1028
|
+
def machine_in_scope_group?(machine_data, part)
|
|
1029
|
+
scope_list = part == :target ? @targets[:group_targets] : @exclusions[:group_exclusions]
|
|
1030
|
+
# if the list is empty, return nil
|
|
1031
|
+
return if scope_list.empty?
|
|
1032
|
+
|
|
1033
|
+
# if the intersection of the machine's group ids, and those of the scope part
|
|
1034
|
+
# is not empty, then the machine is in at least one of the groups
|
|
1035
|
+
!(machine_data[:group_ids] & scope_list).empty?
|
|
1036
|
+
end
|
|
1037
|
+
|
|
1038
|
+
# @param machine_data[Hash] See #fetch_machine_data
|
|
1039
|
+
# @param part[Symbol] either :target or :exclusion
|
|
1040
|
+
# @return [Boolean] Is the machine in any building listed in this part of the scope?
|
|
1041
|
+
#################
|
|
1042
|
+
def machine_in_scope_buildings?(machine_data, part)
|
|
1043
|
+
scope_list = part == :target ? @targets[:buildings] : @exclusions[:buildings]
|
|
1044
|
+
|
|
1045
|
+
# nil if empty
|
|
1046
|
+
return if scope_list.empty?
|
|
1047
|
+
# false if no building for the machine - it isn't in any dept
|
|
1048
|
+
return false if machine_data[:location][:building].to_s.empty?
|
|
1049
|
+
|
|
1050
|
+
building_id = JSS::Building.map_all_ids_to(:name).invert[machine_data[:location][:building]]
|
|
1051
|
+
scope_list.include? building_id
|
|
1052
|
+
end
|
|
1053
|
+
|
|
1054
|
+
# @param machine_data[Hash] See #fetch_machine_data
|
|
1055
|
+
# @param part[Symbol] either :target or :exclusion
|
|
1056
|
+
# @return [Boolean] Is the machine in any department listed in this part of the scope?
|
|
1057
|
+
#################
|
|
1058
|
+
def machine_in_scope_depts?(machine_data, part)
|
|
1059
|
+
scope_list = part == :target ? @targets[:departments] : @exclusions[:departments]
|
|
1060
|
+
|
|
1061
|
+
# nil if empty
|
|
1062
|
+
return if scope_list.empty?
|
|
1063
|
+
# false if no dept for the machine - it isn't in any dept
|
|
1064
|
+
return false if machine_data[:location][:department].to_s.empty?
|
|
1065
|
+
|
|
1066
|
+
dept_id = JSS::Department.map_all_ids_to(:name).invert[machine_data[:location][:department]]
|
|
1067
|
+
|
|
1068
|
+
scope_list.include? dept_id
|
|
1069
|
+
end
|
|
1070
|
+
|
|
1071
|
+
# @param machine_data[Hash] See #fetch_machine_data
|
|
1072
|
+
# @param part[Symbol] either :limitation or :exclusion
|
|
1073
|
+
# @return [Boolean] Is the machine in any NetworkSegment listed in this part of the scope?
|
|
1074
|
+
##################
|
|
1075
|
+
def machine_in_scope_netsegs?(machine_data, part)
|
|
1076
|
+
scope_list = part == :limitation ? @limitations[:network_segments] : @exclusions[:network_segments]
|
|
1077
|
+
|
|
1078
|
+
# nil if no netsegs in scope part
|
|
1079
|
+
return if scope_list.empty?
|
|
1080
|
+
|
|
1081
|
+
ip = @target_class == JSS::Computer ? machine_data[:general][:last_reported_ip] : machine_data[:general][:ip_address]
|
|
1082
|
+
# false if no ip for machine - it isn't in a any of the segs
|
|
1083
|
+
return false if ip.to_s.empty?
|
|
1084
|
+
|
|
1085
|
+
mach_segs = JSS::NetworkSegment.network_segments_for_ip ip
|
|
1086
|
+
|
|
1087
|
+
# if the intersection is not empty, then the machine is in at least one of the net segs
|
|
1088
|
+
!(mach_segs & scope_list).empty?
|
|
1089
|
+
end
|
|
1090
|
+
|
|
1091
|
+
# @param machine_data[Hash] See #fetch_machine_data
|
|
1092
|
+
# @param part[Symbol] either :limitation or :exclusion
|
|
1093
|
+
# @return [Boolean] Is the user of this machine in the list of jamf/ldap users in this part of the scope?
|
|
1094
|
+
##################
|
|
1095
|
+
def machine_in_scope_jamf_ldap_users_list?(machine_data, part)
|
|
1096
|
+
scope_list = part == :limitation ? @limitations[:jamf_ldap_users] : @exclusions[:jamf_ldap_users]
|
|
1097
|
+
|
|
1098
|
+
# nil if the list is empty
|
|
1099
|
+
return if scope_list.empty?
|
|
1100
|
+
|
|
1101
|
+
scope_list.include? machine_data[:location][:username]
|
|
1102
|
+
end
|
|
1103
|
+
|
|
1104
|
+
# @param machine_data[Hash] See #fetch_machine_data
|
|
1105
|
+
# @param part[Symbol] either :limitation or :exclusion
|
|
1106
|
+
# @return [Boolean] Is the user of this machine a member of any of the LDAP groups in in this part of the scope?
|
|
1107
|
+
##################
|
|
1108
|
+
def machine_in_scope_ldap_usergroup_list?(machine_data, part)
|
|
1109
|
+
scope_list = part == :limitation ? @limitations[:ldap_user_groups] : @exclusions[:ldap_user_groups]
|
|
1110
|
+
|
|
1111
|
+
# nil if the list is empty
|
|
1112
|
+
return if scope_list.empty?
|
|
1113
|
+
|
|
1114
|
+
# loop thru them checking to see if the user is a member
|
|
1115
|
+
scope_list.each do |ldapgroup|
|
|
1116
|
+
server = JSS::LDAPServer.server_for_group ldapgroup
|
|
1117
|
+
# if the group doesn't exist in any LDAP the user isn't a part of it
|
|
1118
|
+
next unless server
|
|
1119
|
+
|
|
1120
|
+
# if the user name is in any group, return true
|
|
1121
|
+
return true if JSS::LDAPServer.check_membership server, machine_data[:location][:username], ldapgroup
|
|
1122
|
+
end
|
|
1123
|
+
|
|
1124
|
+
# if we're here, not in any group
|
|
1125
|
+
false
|
|
1126
|
+
end
|
|
1127
|
+
|
|
812
1128
|
end # class Scope
|
|
813
1129
|
|
|
814
1130
|
end # module Scopable
|