Module: JSS::Extendable

Included in:
Computer, MobileDevice, User
Defined in:
lib/jss/api_object/extendable.rb,
lib/jss.rb

Overview

A mix-in module for handling extension attribute data for objects in the JSS.

This module provides standardized ways to deal with Extension Attribute data in objects that gather that data (Computers, MobileDevices, and Users). For working with the Extension Attributes themselves, see ExtensionAttribute and its subclasses.

API objects that have Extension Attribute data return it in an Array of Hashes, one for each defined ExtensionAttribute for the class; i.e. a Computer's Array has one Hash for each ComputerExtensionAttribute defined in the JSS.

The Hash keys are:

  • :id => the ExtAttr id

  • :name => the ExtAttr name

  • :type => the data type of the ExtAttr value

  • :value => the value for the ExtAttr for this object as of the last report.

Classes including this module must define the constant EXT_ATTRIB_CLASS specifying which ExtensionAttribute subclass defines the relevant extension attributes. For Example, Computer sets this:

EXT_ATTRIB_CLASS = JSS::ComputerExtensionAttribute

Parsing also populates @ext_attrs which is a Hash of name => value for each EA.

When updating or creating, those classes must add the REXML output of #ext_attr_xml to their rest_xml output.

Constant Summary collapse

EXTENDABLE =

Constants

true
NUMERIC_TYPES =

ExtensionAttributes refer to the numeric data type as “Integer” but the ext. attr values that come with extendable objects refer to that data type as “Number”. Here's an array with both, so we can work with ether more easily.

%w[Number Integer].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#ext_attrsHash (readonly)


81
82
83
# File 'lib/jss/api_object/extendable.rb', line 81

def ext_attrs
  @ext_attrs
end

#extension_attributesArray<Hash> (readonly)


78
79
80
# File 'lib/jss/api_object/extendable.rb', line 78

def extension_attributes
  @extension_attributes
end

Instance Method Details

#ext_attr_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.

TODO: make this (and all XML amending) method take the in-progress XML doc and add (or not) the EA xml to it. See how Sitable#add_site_to_xml works, as called from Computer.rest_xml


191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/jss/api_object/extendable.rb', line 191

def ext_attr_xml
  @changed_eas ||= []
  eaxml = REXML::Element.new('extension_attributes')
  @extension_attributes.each do |ea|
    next unless @changed_eas.include? ea[:name]
    ea_el = eaxml.add_element('extension_attribute')
    ea_el.add_element('name').text = ea[:name]

    if ea[:type] == 'Date'
      begin
        ea_el.add_element('value').text = ea[:value].to_jss_date
      rescue
        ea_el.add_element('value').text = ea[:value].to_s
      end
    else
      ea_el.add_element('value').text = ea[:value].to_s
    end # if
  end # each do ea

  eaxml
end

#parse_ext_attrsvoid

This method returns an undefined value.

Populate @extension_attributes (the Array of Hashes that comes from the API) and @ext_attr_names, which is a Hash mapping the EA names to their values. This is called during initialization for all objects that mix in this module


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
118
# File 'lib/jss/api_object/extendable.rb', line 93

def parse_ext_attrs
  @extension_attributes = @init_data[:extension_attributes]
  @extension_attributes ||= []
  @ext_attrs = {}

  @extension_attributes.each do |ea|
    case ea[:type]

    when 'Date'
      begin # if there's random non-date data, the parse will fail
        ea[:value] = JSS.parse_datetime ea[:value]
      rescue
        true
      end

    when *NUMERIC_TYPES
      ea[:value] = ea[:value].to_i unless ea[:value].to_s.empty?
    end # case

    @ext_attrs[ea[:name]] = ea[:value]
  end # each do ea

  # remember changes as they happen so
  # we only send changes back to the server.
  @changed_eas = []
end

#set_ext_attr(name, value) ⇒ void

This method returns an undefined value.

Set the value of an extension attribute

If the extension attribute is defined as a popup menu, the value must be one of the defined popup choices, or an empty string

If the ext. attrib. is defined with a data type of Integer, the value must be an Integer.

If the ext. attrib. is defined with a data type of Date, the value will be converted to a Time

Note that while the Jamf Pro Web interface does not allow editing the values of Extension Attributes populated by Scripts or LDAP, the API does allow it. Bear in mind however that those values will be reset again at the next recon.


139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/jss/api_object/extendable.rb', line 139

def set_ext_attr(name, value)
  # this will raise an exception if the name doesn't exist
  ea_def = self.class::EXT_ATTRIB_CLASS.fetch name: name, api: api

  if ea_def.input_type == 'Pop-up Menu' && (!ea_def.popup_choices.include? value.to_s)
    raise JSS::UnsupportedError, "The value for #{name} must be one of: '#{ea_def.popup_choices.join("' '")}'"
  end

  unless value == JSS::BLANK
    case ea_def.data_type
    when 'Date'
      value = JSS.parse_datetime value

    when *NUMERIC_TYPES
      raise JSS::InvalidDataError, "The value for #{name} must be an integer" unless value.is_a? Integer

    end # case
  end # unless blank

  been_set = false
  @extension_attributes.each do |ea|
    next unless ea[:name] == name
    ea[:value] = value
    been_set = true
  end
  unless been_set
    @extension_attributes << { id: ea_def.id, name: name, type: ea_def.data_type, value: value }
  end

  @ext_attrs[name] = value
  @changed_eas << name
  @need_to_update = true
end

#unsaved_eas?Boolean

are there any changes in the EAs needing to be saved?


177
178
179
# File 'lib/jss/api_object/extendable.rb', line 177

def unsaved_eas?
  @need_to_update && @changed_eas && !@changed_eas.empty?
end