Class: Jamf::Group

Inherits:
APIObject show all
Includes:
Creatable, Criteriable, Sitable, Updatable
Defined in:
lib/jamf/api/classic/base_classes/group.rb

Overview

This is the parent class of the smart/static group objects in the JSS namely, ComputerGroup, MobileDeviceGroup, and UserGroup

It provides methods for working with the membership of static groups and, by including Criteriable, the criteria for smart groups.

When changing the criteria of a smart group, use the #criteria attribute, which is a Criteria instance.

Subclasses must define these constants:

  • MEMBER_CLASS: the ruby-jss class to which the group members belong (e.g. Jamf::MobileDevice)

  • ADD_MEMBERS_ELEMENT: the XML element tag for adding members to the group wuth a PUT call to the API, e.g. ‘computer_additions’

  • REMOVE_MEMBERS_ELEMENT: the XML element tag for removing members from the group wuth a PUT call to the API, e.g. ‘computer_deletions’

Direct Known Subclasses

ComputerGroup, MobileDeviceGroup, UserGroup

Constant Summary collapse

GROUP_TYPES =

the types of groups allowed for creation

%i[smart static].freeze
SITE_SUBSET =

Where is the Site data in the API JSON?

:top
ID_XML_TAG =

the ‘id’ xml element tag

'id'.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(**args) ⇒ Group

When creating a new group in the JSS, you must call .make with a :type key and a value of :smart or :static, as well as a :name

Raises:

See Also:



209
210
211
212
213
214
215
216
217
218
# File 'lib/jamf/api/classic/base_classes/group.rb', line 209

def initialize(**args)
  raise Jamf::InvalidDataError, 'New group creation must specify a :type of :smart or :static' if args[:id] == :new && !(GROUP_TYPES.include? args[:type])

  super

  @is_smart = @init_data[:is_smart] || (args[:type] == :smart)

  @members =
    @init_data[self.class::MEMBER_CLASS::RSRC_LIST_KEY] || []
end

Instance Attribute Details

#criteriaJamf::Criteriable::Criteria Originally defined in module Criteriable

Returns the criteria for the instance into which we’re mixed.

Returns:

#is_smartBoolean (readonly) Also known as: smart?

Returns is this a smart group.

Returns:

  • (Boolean)

    is this a smart group



193
194
195
# File 'lib/jamf/api/classic/base_classes/group.rb', line 193

def is_smart
  @is_smart
end

#membersArray<Hash>

Each hash contains the identifiers for a member of the group, those being:

  • :id, :name, and possibly :udid, :serial_number, :mac_address, :alt_mac_address, and :wifi_mac_address

Returns:

See Also:



190
191
192
# File 'lib/jamf/api/classic/base_classes/group.rb', line 190

def members
  @members
end

#need_to_updateBoolean (readonly) Originally defined in module Updatable

Returns do we have unsaved changes?.

Returns:

  • (Boolean)

    do we have unsaved changes?

#notify_on_changeBoolean (readonly) Also known as: notify_on_change?, notify?

Returns does this group send notifications when it changes?.

Returns:

  • (Boolean)

    does this group send notifications when it changes?



197
198
199
# File 'lib/jamf/api/classic/base_classes/group.rb', line 197

def notify_on_change
  @notify_on_change
end

Class Method Details

.all_smart(refresh = false, api: nil, cnx: Jamf.cnx) ⇒ Object

Returns an Array of all the smart groups.



61
62
63
64
65
# File 'lib/jamf/api/classic/base_classes/group.rb', line 61

def self.all_smart(refresh = false, api: nil, cnx: Jamf.cnx)
  cnx = api if api

  all(refresh, cnx: cnx).select { |g| g[:is_smart] }
end

.all_static(refresh = false, api: nil, cnx: Jamf.cnx) ⇒ Object

Returns an Array of all the static groups.



70
71
72
73
74
# File 'lib/jamf/api/classic/base_classes/group.rb', line 70

def self.all_static(refresh = false, api: nil, cnx: Jamf.cnx)
  cnx = api if api

  all(refresh, cnx: cnx).reject { |g| g[:is_smart] }
end

.change_membership(group, add_members: [], remove_members: [], api: nil, cnx: Jamf.cnx) ⇒ void

This method returns an undefined value.

Immediatly add and/or remove members in a static group without instantiating it first. Uses the <x_additions> and <x_deletions> XML elements available when sending a PUT request to the API.

Parameters:

  • group (String, Integer)

    The name or id of the group being changed

  • add_members (String, Integer, Array<String, Integer>) (defaults to: [])

    valid identifier(s) for members to add

  • remove_members (String, Integer, Array<String, Integer>) (defaults to: [])

    valid identifier(s) for members to remove

  • cnx (Jamf::Connection) (defaults to: Jamf.cnx)

    The API connetion to use, uses the default connection if not specified

Raises:



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/jamf/api/classic/base_classes/group.rb', line 93

def self.change_membership(group, add_members: [], remove_members: [], api: nil, cnx: Jamf.cnx)
  cnx = api if api

  raise Jamf::NoSuchItemError, "No #{self} matching '#{group}'" unless (group_id = valid_id group, cnx: cnx)
  raise Jamf::UnsupportedError, "Not a static group, can't change membership" if map_all(:id, to: :is_smart, cnx: cnx)[group_id]

  add_members = [add_members].flatten
  remove_members = [remove_members].flatten
  return if add_members.empty? && remove_members.empty?

  # we must know the current group membership, because the API
  # will raise a conflict error if we try to remove a member
  # that isn't in the group (which is kinda lame - it should just
  # ignore this, like it does when we add a member that's already
  # in the group.)
  # Its even more lame because we have to instantiate the group
  # and part of the point of this class method is to avoid that.
  current_member_ids = fetch(id: group_id, cnx: cnx).member_ids

  # nil if no changes to be made
  xml_doc = change_membership_xml add_members, remove_members, current_member_ids
  return unless xml_doc

  cnx.c_put "#{self::RSRC_BASE}/id/#{group_id}", xml_doc.to_s
end

Instance Method Details

#add_member(mem) ⇒ void

This method returns an undefined value.

Add a member, by name or id

Parameters:

  • m (Integer, String)

    the id or name of the member to add

Raises:



399
400
401
402
403
404
# File 'lib/jamf/api/classic/base_classes/group.rb', line 399

def add_member(mem)
  raise UnsupportedError, "Smart group members can't be changed." if smart?

  @members << check_member(mem)
  @need_to_update = true
end

#change_membership(add_members: [], remove_members: []) ⇒ void

This method returns an undefined value.

Immediatly add and/or remove members in this static group

IMPORTANT: This method changes the group in the JSS immediately,

there is no need to call #update/#save

Parameters:

  • add_members (String, Integer, Array<String, Integer>) (defaults to: [])

    valid identifier(s) for members to add

  • remove_members (String, Integer, Array<String, Integer>) (defaults to: [])

    valid identifier(s) for members to remove

  • cnx (Jamf::Connection)

    The API connetion to use, uses the default connection if not specified



457
458
459
460
# File 'lib/jamf/api/classic/base_classes/group.rb', line 457

def change_membership(add_members: [], remove_members: [])
  self.class.change_membership(@id, add_members: add_members, remove_members: remove_members, cnx: @cnx)
  refresh_members
end

#clearvoid

This method returns an undefined value.

Remove all members

Raises:



433
434
435
436
437
438
439
# File 'lib/jamf/api/classic/base_classes/group.rb', line 433

def clear
  raise InvalidDataError, "Smart group members can't be changed." if @is_smart
  return if @members.empty?

  @members.clear
  @need_to_update = true
end

#clone(new_name, api: nil, cnx: nil) ⇒ APIObject Originally defined in module Creatable

make a clone of this API object, with a new name. The class must be creatable

Parameters:

  • name (String)

    the name for the new object

  • cnx (Jamf::Connection) (defaults to: nil)

    the API in which to create the object Defaults to the API used to instantiate this object

Returns:

  • (APIObject)

    An unsaved clone of this APIObject with the given name

Raises:

#create(calculate_members: true, retries: 10) ⇒ Object

Parameters:

  • calculate_members (Boolan) (defaults to: true)

    should the local membership list be re-read from the API after the group is created?

  • retries (Integer) (defaults to: 10)

    If calculate_members is true, refetching the group to re-read the membership can happen too fast, the JSS won’t know it exists yet and will throw a NoSuchItem error. If that happens, try again this many times with a 1 second pause between attempts.

Raises:

See Also:

  • Creatable#create


233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/jamf/api/classic/base_classes/group.rb', line 233

def create(calculate_members: true, retries: 10)
  raise Jamf::MissingDataError, 'No criteria specified for smart group' if @is_smart && !@criteria

  super()

  if calculate_members
    tries = 0
    while tries < retries
      begin
        refresh_members
        break
      rescue
        sleep 1
        tries += 1
      end # begin
    end # while
  end # if calc members

  @id
end

#criteria=(new_criteria) ⇒ Object

Apply a new set of criteria to a smart group

Parameters:

  • new_criteria (Jamf::Criteria)

    the new criteria for the smart group

Raises:



293
294
295
296
297
# File 'lib/jamf/api/classic/base_classes/group.rb', line 293

def criteria=(new_criteria)
  raise InvalidDataError, 'Only smart groups have criteria.' unless @is_smart

  super
end

#deleteObject

See Also:



281
282
283
284
285
286
287
# File 'lib/jamf/api/classic/base_classes/group.rb', line 281

def delete
  super
  @is_smart = nil
  @criteria = nil
  @site = nil
  @members = []
end

#make_smart(**params) ⇒ void Also known as: set_smart

This method returns an undefined value.

Change static group to smart group

Parameters:

  • args (Hash)

    the options and settings use for switching the computer group from static group to smart group



306
307
308
309
310
311
312
313
314
315
# File 'lib/jamf/api/classic/base_classes/group.rb', line 306

def make_smart(**params)
  return if @is_smart

  params[:criteria] = [] if params[:criteria].nil?

  params[:criteria]

  @is_smart = true
  @need_to_update = true
end

#make_static(**params) ⇒ void Also known as: set_static

This method returns an undefined value.

Change smart group to static group

Parameters:

  • args (Hash)

    the options and settings use for switching the computer group from smart group to static group



326
327
328
329
330
331
332
333
334
# File 'lib/jamf/api/classic/base_classes/group.rb', line 326

def make_static(**params)
  return unless @is_smart

  preserve_members = params.include? :preserve_members

  @is_smart = false

  clear unless preserve_members
end

#member_idsArray<Integer>

Returns the ids of the group members.

Returns:

  • (Array<Integer>)

    the ids of the group members



361
362
363
# File 'lib/jamf/api/classic/base_classes/group.rb', line 361

def member_ids
  @members.map { |m| m[:id] }
end

#member_namesArray<String>

Returns the names of the group members.

Returns:



355
356
357
# File 'lib/jamf/api/classic/base_classes/group.rb', line 355

def member_names
  @members.map { |m| m[:name] }
end

#name=(newname) ⇒ void Originally defined in module Updatable

This method returns an undefined value.

Change the name of this item Remember to #update to push changes to the server.

Parameters:

  • newname (String)

    the new name

Raises:

#parse_criteriavoid Originally defined in module Criteriable

This method returns an undefined value.

During initialization, convert the @init_data Hash into a Jamf::Criteriable::Criteria instance stored in @criteria

Classes mixing in this module must call this in #initialize

#refresh_membersArray<Hash>

Refresh the membership from the API

Returns:



466
467
468
# File 'lib/jamf/api/classic/base_classes/group.rb', line 466

def refresh_members
  @members = @cnx.c_get(@rest_rsrc)[self.class::RSRC_OBJECT_KEY][self.class::MEMBER_CLASS::RSRC_LIST_KEY]
end

#remove_member(mem) ⇒ void

This method returns an undefined value.

Remove a member by id, or name

Parameters:

  • m (Integer, String)

    an identifier for the item to remove

Raises:



412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
# File 'lib/jamf/api/classic/base_classes/group.rb', line 412

def remove_member(mem)
  raise UnsupportedError, "Smart group members can't be changed." if smart?

  # See if we have the identifier in the @members array of hashes
  id_to_remove = @members.select { |mm| mm.values.include? mem }.first&.dig :id

  # But the members hash might not have SN, macaddr, etc, and never has udid, so
  # look at the MEMBER_CLASS if needed
  id_to_remove ||= self.class::MEMBER_CLASS.valid_id mem

  # nothing to do if that id isn't one of our members
  return unless id_to_remove && member_ids.include?(id_to_remove)

  @members.delete_if { |h| h[:id] == id_to_remove } # { |k, v| k == :id && v == id_to_remove }
  @need_to_update = true
end

#save(**params) ⇒ Object

Wrapper/alias for both create and update



263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# File 'lib/jamf/api/classic/base_classes/group.rb', line 263

def save(**params)
  params[:calculate_members] = true if params[:calculate_members].nil?
  params[:retries] = 10 if params[:retries].nil?
  params[:refresh] = true if params[:refresh].nil?

  if @in_jss
    raise Jamf::UnsupportedError, 'Updating this object in the JSS is currently not supported by ruby-jss' unless updatable?

    update refresh: params[:refresh]
  else
    raise Jamf::UnsupportedError, 'Creating this object in the JSS is currently not supported by ruby-jss' unless creatable?

    create calculate_members: params[:calculate_members], retries: params[:retries]
  end
end

#should_updatevoid Originally defined in module Criteriable

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.

This method returns an undefined value.

Allow our Criteria to tell us when there’s been a change that needs to be updated.

#site=(new_site) ⇒ void Originally defined in module Sitable

This method returns an undefined value.

Change the site of this object. Any of the NON_SITES values will unset the site

Parameters:

  • new_site (Integer, String)

    The new site

Raises:

#site_assigned?Boolean Originally defined in module Sitable

Does this object have a site assigned?

Returns:

  • (Boolean)

    Does this object have a site assigned?

#site_idInteger Originally defined in module Sitable

The id of the site for this object.

Returns:

  • (Integer)

    The id of the site for this object.

#site_nameString Also known as: site Originally defined in module Sitable

The name of the site for this object. For backward compatibility, this is aliased to just ‘site’

Returns:

  • (String)

    The name of the site for this object.

#site_objectJamf::Site Originally defined in module Sitable

The Jamf::Site instance for this object’s site

Returns:

  • (Jamf::Site)

    The Jamf::Site instance for this object’s site

#sizeInteger Also known as: count

How many members of the group?

Returns:

  • (Integer)

    the number of members of the group



342
343
344
# File 'lib/jamf/api/classic/base_classes/group.rb', line 342

def size
  @members.count
end

#static?Boolean Also known as: is_static

Returns Is this a static group?.

Returns:

  • (Boolean)

    Is this a static group?



348
349
350
# File 'lib/jamf/api/classic/base_classes/group.rb', line 348

def static?
  !smart?
end

#unset_sitevoid Originally defined in module Sitable

This method returns an undefined value.

Set the site to nothing

#update(refresh: true) ⇒ Object

See Also:

  • Updatable#update


256
257
258
259
260
# File 'lib/jamf/api/classic/base_classes/group.rb', line 256

def update(refresh: true)
  super()
  refresh_members if refresh
  @id
end