Class: Jamf::Scopable::Scope

Inherits:
Object
  • Object
show all
Defined in:
lib/jamf/api/classic/api_objects/scopable/scope.rb

Overview

This class represents a Scope in the JSS, as can be applied to Scopable objects like Policies, Profiles, etc. Instances of this class are generally used as the value of the @scope attribute of those objects.

Scope data comes from the API as a hash within the overall object data. The main keys of the hash define the included targets of the scope. A sub-hash defines limitations on those inclusions, and another sub-hash defines explicit exclusions.

This class provides methods for adding, removing, or fully replacing the various items in scope's realms: targets, limitations, and exclusions.

This class also provides a way to see if a machine will be included in this scope.

IMPORTANT - Users & User Groups in Targets and Exclusions:

The classic API has bugs regarding the use of Users, UserGroups, LDAP/Local Users, & LDAP User Groups in scopes. Here's a discussion of those bugs and how ruby-jss handles them.

Targets/Inclusions

- 'Users' in the Scope UI can only be Jamf::Users - No LDAP
  - BUG: They do not appear in API data (XML or JSON) and are
    NOT SUPPORTED in ruby-jss.
  - You must use the Web UI to work with them in a Scope.
- 'User Groups' in the Scope UI can only be Jamf::UserGroups - No LDAP
  - BUG: They do not appear in API data (XML or JSON) and are
    NOT SUPPORTED in ruby-jss.
  - You must use the Web UI to work with them in a Scope.

Limitations

- 'LDAP/Local Users' can be any string
  - The Web UI accepts any string, even if no matching Local or LDAP user.
  - The data shows up in API data in scope=>limitations=>users
    by name only (the string provided), no IDs
- 'LDAP User Groups' can only be LDAP groups that actually exist
  - The Web UI won't let you add a group that doesn't exist in ldap
  - The data shows up in API data in scope=>limitations=>user_groups
    by name and LDAP ID (which may be empty)
  - The data ALSO shows up in API data in scope=>limit_to_users=>user_groups
    by name only, no LDAP IDs. ruby-jss ignores this and looks at
    scope=>limitations=>user_groups

Exclusions, combines the behavior of Inclusions & Limitations

- 'Users' in the Scope UI can only be Jamf::Users - No LDAP
  - BUG: They do not appear in API data (XML or JSON) and are
    NOT SUPPORTED in ruby-jss.
  - You must use the Web UI to work with them in a Scope.
- 'User Groups' in the Scope UI can only be Jamf::UserGroups - No LDAP
  - BUG: They do not appear in API data (XML or JSON) and are
    NOT SUPPORTED in ruby-jss.
  - You must use the Web UI to work with them in a Scope.
- 'LDAP/Local Users' can be any string
  - The Web UI accepts any string, even if no matching Local or LDAP user.
  - The data shows up in API data in scope=>exclusions=>users
    by name only (the string provided), no IDs
- 'LDAP User Groups' can only be LDAP groups that actually exist
  - The Web UI won't let you add a group that doesn't exist in ldap
  - The data shows up in API data in scope=>exclusions=>user_groups
    by name and LDAP ID (which may be empty)

How ruby-jss handles this:

 - Methods #set_targets and #add_target will not accept the keys
   :user, :users, :user_group, :user_groups.

 - Method #remove_target will ignore them.

 - Methods #set_limitations, #add_limitation & #remove_limitation will accept:
   - :user, :ldap_user, or :jamf_ldap_user (and their plurals) for working
     with 'LDAP/Local Users'. When setting or adding, the provided
     string(s) must exist as either a Jamf::User or an LDAP user
   - :user_group or :ldap_user_group (and their plurals) for working with
     'LDAP User Groups'. When setting or adding, the provided string
     must exist as a group in LDAP.

 - Methods #set_exclusions, #add_exclusion & #remove_exclusion will accept:
   - :user, :ldap_user, or :jamf_ldap_user (and their plurals) for working
     with 'LDAP/Local Users'. When setting or adding, the provided string(s)
     must exist as either a Jamf::User or an LDAP user.
   - :user_group or :ldap_user_group (and their plurals) for working with
     'LDAP User Groups''. When setting or adding, the provided string
     must exist as a group in LDAP.

Internally in the Scope instance:

- The limitations and exclusions that match the WebUI's 'LDAP/Local Users'
  are in @limitations[:jamf_ldap_users]  and @exclusions[:jamf_ldap_users]

- The  limitations and exclusions that match the WebUI's 'LDAP User Groups'
  are in @limitations[:ldap_user_groups]  and @exclusions[:ldap_user_groups]

See Also:

Constant Summary collapse

SCOPING_CLASSES =

These are the classes that Scopes can use for defining a scope, keyed by appropriate symbols. NOTE: All the user and group ones don't actually refer to Jamf::User or Jamf::UserGroup. See IMPORTANT discussion above.

{
  computers: Jamf::Computer,
  computer: Jamf::Computer,
  computer_groups: Jamf::ComputerGroup,
  computer_group: Jamf::ComputerGroup,
  mobile_devices: Jamf::MobileDevice,
  mobile_device: Jamf::MobileDevice,
  mobile_device_groups: Jamf::MobileDeviceGroup,
  mobile_device_group: Jamf::MobileDeviceGroup,
  buildings: Jamf::Building,
  building: Jamf::Building,
  departments: Jamf::Department,
  department: Jamf::Department,
  network_segments: Jamf::NetworkSegment,
  network_segment: Jamf::NetworkSegment,
  ibeacon: Jamf::IBeacon,
  ibeacons: Jamf::IBeacon,
  user: nil,
  users: nil,
  ldap_user: nil,
  ldap_users: nil,
  jamf_ldap_user: nil,
  jamf_ldap_users: nil,
  user_group: nil,
  user_groups: nil,
  ldap_user_group: nil,
  ldap_user_groups: nil
}.freeze
LDAP_JAMF_USER_KEYS =

These keys always mean :jamf_ldap_users

%i[
  user
  users
  ldap_user
  ldap_users
  jamf_ldap_user
  jamf_ldap_users
].freeze
LDAP_GROUP_KEYS =

These keys always mean :ldap_user_groups

%i[
  user_group
  user_groups
  ldap_user_group
  ldap_user_groups
].freeze
TARGETS_AND_GROUPS =

This hash maps the availble Scope Target keys from SCOPING_CLASSES to their corresponding target group keys from SCOPING_CLASSES.

{ computers: :computer_groups, mobile_devices: :mobile_device_groups }.freeze
ESS =

added to the ends of singular key names if needed, e.g. computer_group => computer_groups

's'.freeze
INCLUSIONS =

These can be part of the base inclusion list of the scope, along with the appropriate target and target group keys

%i[buildings departments].freeze
LIMITATIONS =

These can limit the inclusion list These are the keys that come from the API the :users key from the API is what we call :jamf_ldap_users and the :user_groups key from the API we call :ldap_user_groups See the IMPORTANT discussion above.

%i[
  ibeacons
  network_segments
  jamf_ldap_users
  ldap_user_groups
].freeze
EXCLUSIONS =

any of them can be excluded

INCLUSIONS + LIMITATIONS
DEFAULT_SCOPE =

Here's a default scope as it might come from the API.

{
  all_computers: true,
  all_mobile_devices: true,
  limitations: {},
  exclusions: {}
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(target_key, raw_scope = nil) ⇒ Scope

If raw_scope is empty, a default scope, scoped to all targets, is created, and can be modified as needed.

Parameters:

  • target_key (Symbol)

    the kind of thing we're scoping, one of TARGETS_AND_GROUPS

  • raw_scope (Hash) (defaults to: nil)

    the JSON :scope data from an API query that is scopable, e.g. a Policy.



303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
# File 'lib/jamf/api/classic/api_objects/scopable/scope.rb', line 303

def initialize(target_key, raw_scope = nil)
  raw_scope ||= DEFAULT_SCOPE.dup
  unless TARGETS_AND_GROUPS.key?(target_key)
    raise Jamf::InvalidDataError, "The target class of a Scope must be one of the symbols :#{TARGETS_AND_GROUPS.keys.join(', :')}"
  end

  @target_key = target_key
  @target_class = SCOPING_CLASSES[@target_key]
  @group_key = TARGETS_AND_GROUPS[@target_key]
  @group_class = SCOPING_CLASSES[@group_key]

  @target_keys = [@target_key, @group_key] + INCLUSIONS
  @exclusion_keys = [@target_key, @group_key] + EXCLUSIONS

  @all_key = "all_#{target_key}".to_sym
  @all_targets = raw_scope[@all_key]

  # Everything gets mapped from an Array of Hashes to
  # an Array of ids
  @targets = {}
  @target_keys.each do |k|
    raw_scope[k] ||= []
    @targets[k] = raw_scope[k].compact.map { |n| n[:id].to_i }
    @targets[:direct_targets] = @targets[k] if k == @target_key
    @targets[:group_targets] = @targets[k] if k == @group_key
  end # @target_keys.each do |k|

  # the  :users key from the API is what we call :jamf_ldap_users
  # and the :user_groups key from the API we call :ldap_user_groups
  # See the IMPORTANT discussion above.
  @limitations = {}
  if raw_scope[:limitations]

    LIMITATIONS.each do |k|
      # :jamf_ldap_users comes from :users in the API data
      if k == :jamf_ldap_users
        api_data = raw_scope[:limitations][:users]
        api_data ||= []
        @limitations[k] = api_data.compact.map { |n| n[:name].to_s }

      # :ldap_user_groups comes from :user_groups in the API data
      elsif k == :ldap_user_groups
        api_data = raw_scope[:limitations][:user_groups]
        api_data ||= []
        @limitations[k] = api_data.compact.map { |n| n[:name].to_s }

      # others handled normally.
      else
        api_data = raw_scope[:limitations][k]
        api_data ||= []
        @limitations[k] = api_data.compact.map { |n| n[:id].to_i }
      end
    end # LIMITATIONS.each do |k|
  end # if raw_scope[:limitations]

  # the  :users key from the API is what we call :jamf_ldap_users
  # and the :user_groups key from the API we call :ldap_user_groups
  # See the IMPORTANT discussion above.
  @exclusions = {}
  if raw_scope[:exclusions]

    @exclusion_keys.each do |k|
      # :jamf_ldap_users comes from :users in the API data
      if k == :jamf_ldap_users
        api_data = raw_scope[:exclusions][:users]
        api_data ||= []
        @exclusions[k] = api_data.compact.map { |n| n[:name].to_s }

      # :ldap_user_groups comes from :user_groups in the API data
      elsif k == :ldap_user_groups
        api_data = raw_scope[:exclusions][:user_groups]
        api_data ||= []
        @exclusions[k] = api_data.compact.map { |n| n[:name].to_s }

      # others handled normally.
      else
        api_data = raw_scope[:exclusions][k]
        api_data ||= []
        @exclusions[k] = api_data.compact.map { |n| n[:id].to_i }
        @exclusions[:direct_exclusions] = @exclusions[k] if k == @target_key
        @exclusions[:group_exclusions] = @exclusions[k] if k == @group_key
      end # if ...elsif... else
    end # @exclusion_keys.each
  end # if raw_scope[:exclusions]

  @container = nil
end

Instance Attribute Details

#all_targetsBoolean (readonly) Also known as: all_targets?

Does this scope cover all targets?

If this is true, the @targets Hash is ignored, and all targets in the JSS form the base scope.

Returns:

  • (Boolean)


247
248
249
# File 'lib/jamf/api/classic/api_objects/scopable/scope.rb', line 247

def all_targets
  @all_targets
end

#containerJamf::APIObject subclass

A reference to the object that contains this Scope

For telling it when a change is made and an update needed and for accessing its api connection

Returns:



228
229
230
# File 'lib/jamf/api/classic/api_objects/scopable/scope.rb', line 228

def container
  @container
end

#exclusionsHash{Symbol: Array<Integer, String>} (readonly)

The items in these arrays are the exclusions applied to targets in the @targets .

The arrays of ids are:

  • :computers or :mobile_devices (which are directly excluded)

  • :direct_exclusions - a synonym for :mobile_devices or :computers

  • :computer_groups or :mobile_device_groups (which exclude all of their memebers)

  • :group_exclusions - a synonym for :computer_groups or :mobile_device_groups

  • :departments

  • :buildings

  • :network_segments

  • :users

  • :user_groups

Returns:



291
292
293
# File 'lib/jamf/api/classic/api_objects/scopable/scope.rb', line 291

def exclusions
  @exclusions
end

#group_classObject (readonly)

what type of target group is this scope for? ComputerGroups or MobileDeviceGroups?



238
239
240
# File 'lib/jamf/api/classic/api_objects/scopable/scope.rb', line 238

def group_class
  @group_class
end

#limitationsHash{Symbol: Array<Integer, String>} (readonly)

The items in these arrays are the limitations applied to targets in the @targets .

The arrays of ids are:

  • :network_segments

  • :jamf_ldap_users

  • :user_groups

Returns:



275
276
277
# File 'lib/jamf/api/classic/api_objects/scopable/scope.rb', line 275

def limitations
  @limitations
end

#target_classObject (readonly)

what type of target is this scope for? Computers or MobileDevices?



235
236
237
# File 'lib/jamf/api/classic/api_objects/scopable/scope.rb', line 235

def target_class
  @target_class
end

#targetsHash{Symbol: Array<Integer>} (readonly) Also known as: inclusions

The items which form the base scope of included targets

This is the group of targets to which the limitations and exclusions apply. they keys are:

  • :computers or :mobile_devices (which are directly targeted)

  • :direct_targets - a synonym for :mobile_devices or :computers

  • :computer_groups or :mobile_device_groups (which target all of their memebers)

  • :group_targets - a synonym for :computer_groups or :mobile_device_groups

  • :departments

  • :buildings

and the values are Arrays of names of those things.

Returns:



263
264
265
# File 'lib/jamf/api/classic/api_objects/scopable/scope.rb', line 263

def targets
  @targets
end

#unable_to_verify_ldap_entriesBoolean

Returns should we expect a potential 409 Conflict if we can't connect to LDAP servers for verification?.

Returns:

  • (Boolean)

    should we expect a potential 409 Conflict if we can't connect to LDAP servers for verification?



232
233
234
# File 'lib/jamf/api/classic/api_objects/scopable/scope.rb', line 232

def unable_to_verify_ldap_entries
  @unable_to_verify_ldap_entries
end

Instance Method Details

#add_exclusion(key, item) ⇒ void

This method returns an undefined value.

Add a single item for exclusions of this scope.

The item name will be checked for existence in the JSS, and an exception raised if the item doesn't exist.

Examples:

add_exclusion(:network_segments, "foo")

Parameters:

  • key (Symbol)

    the type of item being added to the exclusions, :computer, :building, etc…

  • item (String, integer)

    a valid identifier of the item being added

Raises:



650
651
652
653
654
655
656
657
658
659
660
661
# File 'lib/jamf/api/classic/api_objects/scopable/scope.rb', line 650

def add_exclusion(key, item)
  key = pluralize_key(key)
  item_id = validate_item(:exclusion, key, item)
  return if @exclusions[key]&.include?(item_id)

  raise Jamf::AlreadyExistsError, "Can't exclude #{key} scope to '#{item}' because it's already explicitly included." if @targets[key]&.include?(item)

  raise Jamf::AlreadyExistsError, "Can't exclude #{key} '#{item}' because it's already an explicit limitation." if @limitations[key]&.include?(item)

  @exclusions[key] << item_id
  @container&.should_update
end

#add_limitation(key, item) ⇒ void

TODO:

handle ldap user/group lookups

This method returns an undefined value.

Add a single item for limiting this scope.

The item name will be checked for existence in the JSS, and an exception raised if the item doesn't exist.

Examples:

add_limitation(:network_segments, "foo")

Parameters:

  • key (Symbol)

    the type of item being added, :computer, :building, etc…

  • item (String, integer)

    a valid identifier of the item being added



561
562
563
564
565
566
567
568
569
570
571
572
# File 'lib/jamf/api/classic/api_objects/scopable/scope.rb', line 561

def add_limitation(key, item)
  key = pluralize_key(key)
  item_id = validate_item(:limitation, key, item)
  return nil if @limitations[key]&.include?(item_id)

  if @exclusions[key]&.include?(item_id)
    raise Jamf::AlreadyExistsError, "Can't set #{key} limitation for '#{name}' because it's already an explicit exclusion."
  end

  @limitations[key] << item_id
  @container&.should_update
end

#add_target(key, item) ⇒ void Also known as: add_inclusion

This method returns an undefined value.

Add a single item as a target in this scope.

The item name will be checked for existence in the JSS, and an exception

raised if the item doesn't exist.

Examples:

add_target(:computers, "mantis")
add_target(:computer_groups, 2342)

Parameters:

  • key (Symbol)

    the key from #SCOPING_CLASSES for the kind of item being added, :computer, :building, etc…

  • item (String, integer)

    a valid identifier of the item being added

Raises:



474
475
476
477
478
479
480
481
482
483
484
# File 'lib/jamf/api/classic/api_objects/scopable/scope.rb', line 474

def add_target(key, item)
  key = pluralize_key(key)
  item_id = validate_item(:target, key, item)
  return if @targets[key]&.include?(item_id)

  raise Jamf::AlreadyExistsError, "Can't set #{key} target to '#{item}' because it's already an explicit exclusion." if @exclusions[key]&.include?(item_id)

  @targets[key] << item_id
  @all_targets = false
  @container&.should_update
end

#in_scope?(machine) ⇒ Boolean

is a given machine is in this scope?

For a parameter you may pass either an instantiated Jamf::MobileDevice or Jamf::Computer, or an identifier for one. If an identifier is passed, it is not instantiated, but an API request is made for just the required subsets of data, thus speeding things up a bit when calling this method many times.

WARNING: For scopes that include Jamf Users and Jamf User Groups as targets or exclusions, this method may return an incorrect value. See the discussion in the documentation for the Scopable::Scope class under 'IMPORTANT - Users & User Groups in Targets and Exclusions'

NOTE: currently in-range iBeacons are transient, and are not reported to the JSS as inventory data. As such they are ignored in this result. If a scope contains iBeacon limitations or exclusions, it is up to the user to be aware of that when evaluating the meaning of this result.

Parameters:

Returns:

  • (Boolean)


808
809
810
811
812
# File 'lib/jamf/api/classic/api_objects/scopable/scope.rb', line 808

def in_scope?(machine)
  machine_data = fetch_machine_data machine

  a_target?(machine_data) && within_limitations?(machine_data) && !excluded?(machine_data)
end

#include_all(clear = false) ⇒ void

This method returns an undefined value.

Set the scope's inclusions to all targets.

By default, the limitations and exclusions remain. If a non-false parameter is provided, they will be removed also.

Parameters:

  • clear (Boolean) (defaults to: false)

    Should the limitations and exclusions be removed also?



400
401
402
403
404
405
406
407
408
409
410
411
412
# File 'lib/jamf/api/classic/api_objects/scopable/scope.rb', line 400

def include_all(clear = false)
  @targets = {}
  @target_keys.each { |k| @targets[k] = [] }
  @all_targets = true
  if clear
    @limitations = {}
    LIMITATIONS.each { |k| @limitations[k] = [] }

    @exclusions = {}
    @exclusion_keys.each { |k| @exclusions[k] = [] }
  end
  @container&.should_update
end

#pretty_print_instance_variablesArray

Remove the init_data and api object from the instance_variables used to create pretty-print (pp) output.

Returns:

  • (Array)

    the desired instance_variables



754
755
756
757
758
# File 'lib/jamf/api/classic/api_objects/scopable/scope.rb', line 754

def pretty_print_instance_variables
  vars = instance_variables.sort
  vars.delete :@container
  vars
end

#remove_exclusion(key, item) ⇒ void

This method returns an undefined value.

Remove a single item for exclusions of this scope

Examples:

remove_exclusion(:network_segments, "foo")

Parameters:

  • key (Symbol)

    the type of item being removed from the excludions, :computer, :building, etc…

  • item (String, integer)

    a valid identifier of the item being removed



674
675
676
677
678
679
680
681
# File 'lib/jamf/api/classic/api_objects/scopable/scope.rb', line 674

def remove_exclusion(key, item)
  key = pluralize_key(key)
  item_id = validate_item :exclusion, key, item, error_if_not_found: false
  return unless @exclusions[key]&.include?(item_id)

  @exclusions[key].delete item_id
  @container&.should_update
end

#remove_limitation(key, item) ⇒ void

TODO:

handle ldap user/group lookups

This method returns an undefined value.

Remove a single item for limiting this scope.

Examples:

remove_limitation(:network_segments, "foo")

Parameters:

  • key (Symbol)

    the type of item being removed, :computer, :building, etc…

  • item (String, integer)

    a valid identifier of the item being removed



587
588
589
590
591
592
593
594
595
# File 'lib/jamf/api/classic/api_objects/scopable/scope.rb', line 587

def remove_limitation(key, item)
  key = pluralize_key(key)
  item_id = validate_item :limitation, key, item, error_if_not_found: false
  return unless item_id
  return unless @limitations[key]&.include?(item_id)

  @limitations[key].delete item_id
  @container&.should_update
end

#remove_target(key, item) ⇒ void Also known as: remove_inclusion

This method returns an undefined value.

Remove a single item as a target for this scope.

Examples:

remove_target(:computer, "mantis")

Parameters:

  • key (Symbol)

    the key from #SCOPING_CLASSES for the kind of item being removed, :computer, :building, etc…

  • item (String, integer)

    a valid identifier of the item being removed



498
499
500
501
502
503
504
505
506
# File 'lib/jamf/api/classic/api_objects/scopable/scope.rb', line 498

def remove_target(key, item)
  key = pluralize_key(key)
  item_id = validate_item :target, key, item, error_if_not_found: false
  return unless item_id
  return unless @targets[key]&.include?(item_id)

  @targets[key].delete item_id
  @container&.should_update
end

#scope_xmlREXML::Element

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Return a REXML Element containing the current state of the Scope for adding into the XML of the container.

Returns:

  • (REXML::Element)


689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
# File 'lib/jamf/api/classic/api_objects/scopable/scope.rb', line 689

def scope_xml
  scope = REXML::Element.new 'scope'
  scope.add_element(@all_key.to_s).text = @all_targets

  @target_keys.each do |klass|
    list = @targets[klass]
    list.compact!
    list.delete 0
    list_as_hashes = list.map { |i| { id: i } }
    scope << SCOPING_CLASSES[klass].xml_list(list_as_hashes, :id)
  end

  limitations = scope.add_element('limitations')
  @limitations.each do |klass, list|
    list.compact!
    list.delete 0
    if klass == :jamf_ldap_users
      users_xml = limitations.add_element 'users'
      list.each do |name|
        user_xml = users_xml.add_element 'user'
        user_xml.add_element('name').text = name
      end
    elsif klass == :ldap_user_groups
      user_groups_xml = limitations.add_element 'user_groups'
      list.each do |name|
        user_group_xml = user_groups_xml.add_element 'user_group'
        user_group_xml.add_element('name').text = name
      end
    else
      list_as_hashes = list.map { |i| { id: i } }
      limitations << SCOPING_CLASSES[klass].xml_list(list_as_hashes, :id)
    end
  end

  exclusions = scope.add_element('exclusions')
  @exclusion_keys.each do |klass|
    list = @exclusions[klass]
    list.compact!
    list.delete 0
    if klass == :jamf_ldap_users
      users_xml = exclusions.add_element 'users'
      list.each do |name|
        user_xml = users_xml.add_element 'user'
        user_xml.add_element('name').text = name
      end
    elsif klass == :ldap_user_groups
      user_groups_xml = exclusions.add_element 'user_groups'
      list.each do |name|
        user_group_xml = user_groups_xml.add_element 'user_group'
        user_group_xml.add_element('name').text = name
      end
    else
      list_as_hashes = list.map { |i| { id: i } }
      exclusions << SCOPING_CLASSES[klass].xml_list(list_as_hashes, :id)
    end
  end
  scope
end

#scoped_machinesHash{Integer => String}

Return a hash of id => name for all machines in the target class that are within this scope.

WARNING: This must instantiate all machines in the target class. It will still be slow, at least the first time for each target class. On the upside, the instantiated machines will be cached, so generating this list for other scopes with the same target class will be much much faster. In tests, 1600 Computers took about 7 minutes the first time, but less than 1 second after caching.

See also the warning for #in_scope?

Returns:



776
777
778
779
780
781
782
# File 'lib/jamf/api/classic/api_objects/scopable/scope.rb', line 776

def scoped_machines
  scoped_machines = {}
  @target_class.all_objects(cnx: container.cnx).each do |machine|
    scoped_machines[machine.id] = machine.name if in_scope? machine
  end
  scoped_machines
end

#set_exclusion(key, list) ⇒ void

This method returns an undefined value.

Replace an exclusion list for this scope

The list must be an Array of names of items of the Class being excluded from the scope Each will be checked for existence in the JSS, and an exception raised if the item doesn't exist.

Examples:

set_exclusion(:network_segments, ['foo','bar'])

Parameters:

  • key (Symbol)

    the type of item being excluded, :computer, :building, etc…

  • list (Array)

    the identifiers of the items being set

Raises:



611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
# File 'lib/jamf/api/classic/api_objects/scopable/scope.rb', line 611

def set_exclusion(key, list)
  key = pluralize_key(key)
  raise Jamf::InvalidDataError, "List must be an Array of #{key} identifiers, it may be empty." unless list.is_a? Array

  # check the idents
  list.map! do |ident|
    item_id = validate_item(:exclusion, key, ident)
    case key
    when *@target_keys
      if @targets[key] && @exclusions[key].include?(item_id)
        raise Jamf::AlreadyExistsError, "Can't exclude #{key} '#{ident}' because it's already explicitly included."
      end
    when *LIMITATIONS
      if @limitations[key] && @exclusions[key].include?(item_id)
        raise Jamf::AlreadyExistsError, "Can't exclude #{key} '#{ident}' because it's already an explicit limitation."
      end
    end
    item_id
  end # each

  return nil if list.sort == @exclusions[key].sort

  @exclusions[key] = list
  @container&.should_update
end

#set_limitation(key, list) ⇒ void Also known as: set_limitations

TODO:

handle ldap user group lookups

This method returns an undefined value.

Replace a limitation list for this scope.

The list must be an Array of names of items of the Class represented by the key. Each will be checked for existence in the JSS, and an exception raised if the item doesn't exist.

Examples:

set_limitation(:network_segments, ['foo',231])

Parameters:

  • key (Symbol)

    the type of items being set as limitations, :network_segments, :users, etc…

  • list (Array)

    the identifiers of the items being set as limitations

Raises:



525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
# File 'lib/jamf/api/classic/api_objects/scopable/scope.rb', line 525

def set_limitation(key, list)
  key = pluralize_key(key)
  raise Jamf::InvalidDataError, "List must be an Array of #{key} identifiers, it may be empty." unless list.is_a? Array

  # check the idents
  list.map! do |ident|
    item_id = validate_item(:limitation, key, ident)
    if @exclusions[key]&.include?(item_id)
      raise Jamf::AlreadyExistsError, "Can't set #{key} limitation for '#{name}' because it's already an explicit exclusion."
    end

    item_id
  end # each

  return nil if list.sort == @limitations[key].sort

  @limitations[key] = list
  @container&.should_update
end

#set_targets(key, list) ⇒ void Also known as: set_target, set_inclusion, set_inclusions

This method returns an undefined value.

Replace a list of item names for as targets in this scope.

The list must be an Array of names of items of the Class represented by the key. Each will be checked for existence in the JSS, and an exception raised if the item doesn't exist.

being included, :computer, :building, etc…

Examples:

set_targets(:computers, ['kimchi','mantis'])

Parameters:

  • key (Symbol)

    the key from #SCOPING_CLASSES for the kind of items

  • list (Array)

    identifiers of the items being added

Raises:



431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
# File 'lib/jamf/api/classic/api_objects/scopable/scope.rb', line 431

def set_targets(key, list)
  key = pluralize_key(key)
  raise Jamf::InvalidDataError, "List must be an Array of #{key} identifiers, it may be empty." unless list.is_a? Array

  # check the idents
  list.map! do |ident|
    item_id = validate_item(:target, key, ident)

    if @exclusions[key]&.include?(item_id)
      raise Jamf::AlreadyExistsError, \
            "Can't set #{key} target to '#{ident}' because it's already an explicit exclusion."
    end

    item_id
  end # each

  return nil if list.sort == @targets[key].sort

  @targets[key] = list
  @all_targets = false
  @container&.should_update
end

#to_sObject



815
816
817
# File 'lib/jamf/api/classic/api_objects/scopable/scope.rb', line 815

def to_s
  "Scope for #{container.class} id #{container.id}"
end