Class: Jamf::APIObject
- Includes:
- Comparable
- Defined in:
- lib/jamf/api/classic/base_classes/api_object.rb
Overview
This class is the parent to all JSS API objects. It provides standard methods and constants that apply to all API resouces.
See the README.md file for general info about using subclasses of Jamf::APIObject
Subclassing
Initilize / Constructor
All subclasses must call ‘super` in their initialize method, which will call the method defined here in APIObject. Not only does this retrieve the data from the API, it parses the raw JSON data into a Hash, & stores it in In general, subclasses should do any class-specific argument checking before calling super, and then afterwards use the contents of @init_data to populate any class-specific attributes. Populating @id, @name, @rest_rsrc, and @in_jss are handled here.
This class also handles parsing @init_data for any mixed-in modules, e.g. Scopable, Categorizable or Extendable. See those modules for any requirements they have when including them.
Object Creation
If a subclass should be able to be created in the JSS be sure to include Creatable
The constructor should verify any extra required data in the args
See Creatable for more details.
Object Modification
If a subclass should be modifiable in the JSS, include Updatable, q.v. for details.
Object Deletion
All subclasses can be deleted in the JSS.
Required Constants
Subclasses must provide certain constants in order to correctly interpret API data and communicate with the API:
RSRC_BASE [String]
The base for REST resources of this class
e.g. ‘computergroups’ in
https://casper.mycompany.com:8443/JSSResource/computergroups/id/12
RSRC_LIST_KEY [Symbol]
When GETting the RSRC_BASE for a subclass, an Array of Hashes is returned with one Hash of basic info for each object of that type in the JSS. All objects have their JSS id and name in that Hash, some have other data as well. This Array is used for a variety of purposes when using ruby-jss, since it gives you basic info about all objects, without having to fetch each one individually.
Here’s the top of the output from the ‘computergroups’ RSRC_BASE:
{:computer_groups=>
[{:id=>1020, :name=>"config-no-turnstile", :is_smart=>true},
{:id=>1357, :name=>"10.8 Laptops", :is_smart=>true},
{:id=>1094, :name=>"wifi_cert-expired", :is_smart=>true},
{:id=>1144, :name=>"mytestgroup", :is_smart=>false},
...
Notice that the Array we want is embedded in a one-item Hash, and the key in that Hash for the desired Array is the Symbol :computer_groups.
That symbol is the value needed in the RSRC_LIST_KEY constant.
The ‘.all_ids’, ‘.all_names’ and other ‘.all_*’ class methods use the list-resource Array to extract other Arrays of the desired values - which can be used to check for existance without retrieving an entire object, among other uses.
RSRC_OBJECT_KEY [Symbol]
The one-item Hash key used for individual JSON object output. It’s also used in various error messages
As with the list-resource output mentioned above, when GETting a specific object resource, there’s an extra layer of encapsulation in a one-item Hash. Here’s the top of the JSON for a single computer group fetched from ‘…computergroups/id/1043’
{:computer_group=>
{:id=>1043,
:name=>"tmp-no-d3",
:is_smart=>false,
:site=>{:id=>-1, :name=>"None"},
:criteria=>[],
:computers=>[
...
The data for the group itself is the inner Hash.
The RSRC_OBJECT_KEY in this case is set to :computer_group - the key in the top-level, one-item Hash that we need to get the real Hash about the object.
Optional Constants
OTHER_LOOKUP_KEYS
Fetching individual objects from the API is usuallly done via the object’s unique JSS id, via a resrouce URL like so:
...JSSResource/<RSRC_BASE>/id/<idnumber>
Most objects can also be looked-up by name, because the API also has and endpoint ..JSSResource/<RSRC_BASE>/name/<name> (See NON_UNIQUE_NAMES below)
Some objects, like Computers and MobileDevices, have other values that serve as unique identifiers and can also be used as ‘lookup keys’ for fetching individual objects. When this is the case, those values always appear in the objects list-resource data (See RSRC_LIST_KEY above).
For example, here’s a summary-hash for a single MobileDevice from the list-resource ‘…JSSResource/mobiledevices’, which you might get in the Array returned by Jamf::MobileDevice.all:
{
:id=>3964,
:name=>"Bear",
:device_name=>"Bear",
:udid=>"XXX",
:serial_number=>"YYY2244MM60",
:phone_number=>"510-555-1212",
:wifi_mac_address=>"00:00:00:00:00:00",
:managed=>true,
:supervised=>false,
:model=>"iPad Pro (9.7-inch Cellular)",
:model_identifier=>"iPad6,4",
:modelDisplay=>"iPad Pro (9.7-inch Cellular)",
:model_display=>"iPad Pro (9.7-inch Cellular)",
:username=>"fred"
}
For MobileDevices, serial_number, udid, and wifi_mac_address are also all unique identifiers for an individual device, and can be used to fetch them.
To specify other identifiers for an APIObject subclass, create the constant OTHER_LOOKUP_KEYS containing a Hash of Hashes, like so:
OTHER_LOOKUP_KEYS = {
serial_number: {
aliases: [:serialnumber, :sn],
fetch_rsrc_key: :serialnumber
},
udid: {
fetch_rsrc_key: :udid
},
wifi_mac_address: {
aliases: [:macaddress, :macaddr],
fetch_rsrc_key: :macaddress
}
}.freeze
The keys in OTHER_LOOKUP_KEYS are the keys in a summary-hash data from .all that hold a unique identifier. Each value is a Hash with one or two keys:
- aliases: [Array<Symbol>]
Aliases for that identifier, i.e. abbreviations or spelling variants.
These aliases can be used in fetching, and they also have
matching `.all_<aliase>s` methods.
If no aliases are needed, don't specify anything, as with the udid:
in the example above
- fetch_rsrc_key: [Symbol]
Often a unique identifier can be used to build a URL for fetching (or
updating or deleteing) an object with that value, rather than with id.
For example, while the MobileDevice in the example data above would
normally be fetched at the resource 'JSSResource/mobiledevices/id/3964'
it can also be fetched at
'JSSResource/mobiledevices/serialnumber/YYY2244MM60'.
Since the URL is built using 'serialnumber', the symbol :serialnumber
is used as the fetch_rsrc_key.
Setting a fetch_rsrc_key: for one of the OTHER_LOOKUP_KEYS tells ruby-jss
that such a URL is available, and fetching by that lookup key will be
faster when using that URL.
If a fetch_rsrc_key is not set, fetching will be slower, since the fetch
method must first refresh the list of all available objects to find the
id to use for building the resource URL.
This is also true when fetching without specifying which lookup key to
use, e.g. `.fetch 'foo'` vs. `.fetch sn: 'foo'`
The OTHER_LOOKUP_KEYS, if defined, are merged with the DEFAULT_LOOKUP_KEYS defined below via the APIObject.lookup_keys class method, They are used for:
-
creating list-methods: For each lookup key, a class method ‘.all_<key>s` is created automatically, e.g. `.all_serial_numbers`. The aliases are used to make alises of those methods, e.g. `.all_sns`
-
finding valid ids: The APIObject.valid_id class method looks at the known lookup keys to find an object’s id.
-
fetching: When an indentifier is given to ‘.fetch`, the fetch_rsrc_key is used to build the resource URL for fetching the object. If there is no fetch_rsrc_key, the lookup_keys and aliases are used to find the matching id, which is used to build the URL.
When no identifier is specified, .fetch uses .valid_id, described above.
NON_UNIQUE_NAMES
Some JSS objects, like Computers and MobileDevices, do not treat names as unique in the JSS, but they can still be used for fetching objects. The API itself will return data for a non-unique name lookup, but there’s no way to guarantee which object you get back.
In those subclasses, set NON_UNIQUE_NAMES to any value, and a Jamf::AmbiguousError exception will be raised when trying to fetch by name and the name isn’t unique.
Because of the extra processing, the check for this state will only happen when NON_UNIQUE_NAMES is set. If not set at all, the check doesn’t happen and if multiple objects have the same name, which one is returned is undefined.
When that’s the case, fetching explicitly by name, or when fetching with a plain search term that matches a non-unique name, will raise a Jamf::AmbiguousError exception,when the name isn’t unique. If that happens, you’ll have to use some other identifier to fetch the desired object.
Note: Fetching, finding valid id, and name collisions are case-insensitive.
Direct Known Subclasses
Account, AdvancedSearch, Building, Category, Computer, ComputerInvitation, ConfigurationProfile, Department, DirectoryBinding, DiskEncryptionConfiguration, DistributionPoint, DockItem, Ebook, ExtensionAttribute, Group, IBeacon, LdapServer, MacApplication, MobileDevice, MobileDeviceApplication, NetBootServer, NetworkSegment, Package, PatchPolicy, PatchSource, PatchTitle, Peripheral, PeripheralType, Policy, Printer, RemovableMacAddress, RestrictedSoftware, Script, Site, SoftwareUpdateServer, User, VPPAccount, WebHook
Constant Summary collapse
- API_SOURCE =
which API do APIObjects come from? The JPAPI equivalent is in Jamf::JPAPIResource
:classic- OK_INSTANTIATORS =
‘.new’ can only be called from these methods:
['make', 'create', 'fetch', 'block in fetch'].freeze
- DEFAULT_LOOKUP_KEYS =
See the discussion of ‘Lookup Keys’ in the comments/docs for Jamf::APIObject
{ id: { fetch_rsrc_key: :id }, name: { fetch_rsrc_key: :name } }.freeze
- OBJECT_HISTORY_TABLE =
This table holds the object history for JSS objects. Object history is not available via the API, only MySQL.
'object_history'.freeze
Instance Attribute Summary collapse
-
#cnx ⇒ Jamf::Connection
(also: #api)
readonly
The API connection thru which we deal with this object.
-
#id ⇒ Integer
readonly
The JSS id number.
-
#in_jss ⇒ Boolean
(also: #in_jss?)
readonly
Is it in the JSS?.
-
#init_data ⇒ Object
readonly
The parsed JSON data retrieved from the API when this object was fetched.
-
#name ⇒ String
readonly
The name.
-
#rest_rsrc ⇒ String
readonly
The Rest resource for API access (the part after “JSSResource/” ).
Class Method Summary collapse
-
.all(refresh = false, api: nil, cnx: Jamf.cnx) ⇒ Array<Hash{:name=>String, :id=> Integer}>
Return an Array of Hashes for all objects of this subclass in the JSS.
-
.all_objects(refresh = false, api: nil, cnx: Jamf.cnx) ⇒ Array<APIObject>
Return an Array of Jamf::APIObject subclass instances e.g when called on Jamf::Package, return a hash of Jamf::Package instancesa for every package in the JSS.
-
.create(**args) ⇒ APIObject
Make a ruby instance of a not-yet-existing APIObject.
-
.define_identifier_list_methods ⇒ Object
Loop through the defined lookup keys and make .all_<key>s methods for each one, with alises as needed.
-
.delete(victims, refresh = true, api: nil, cnx: Jamf.cnx) ⇒ Array<Integer>
Delete one or more API objects by jss_id without instantiating them.
-
.duplicate_names(refresh = false, api: nil, cnx: Jamf.cnx) ⇒ Hash {String => Integer}
Name => number of occurances.
-
.exist?(identifier, refresh = false, api: nil, cnx: Jamf.cnx) ⇒ Boolean
Return true or false if an object of this subclass with the given Identifier exists on the server.
-
.fetch(searchterm = nil, **args) ⇒ APIObject
Retrieve an object from the API and return an instance of this APIObject subclass.
-
.fetch_rsrc_key(lookup_key) ⇒ Symbol?
Given a lookup key, or an alias of one, return the matching fetch_rsrc_key for building a fetch/GET resource URL, or nil if no fetch_rsrc_key is defined.
-
.get_name(a_thing) ⇒ String
Some API objects contain references to other API objects.
-
.get_raw(id, format: :json, as_string: false, api: nil, cnx: Jamf.cnx) ⇒ Hash, ...
Fetch the mostly- or fully-raw JSON or XML data for an object of this subclass.
-
.id_for_identifier(key, val, refresh = false, api: nil, cnx: Jamf.cnx) ⇒ Integer?
Return the id of the object of this subclass with the given lookup key == a given identifier.
-
.lookup_keys(no_aliases: false, fetch_rsrc_keys: false) ⇒ Hash {Symbol: Symbol}, Array<Symbol>
What are all the lookup keys available for this class, with all their aliases (or optionally not) or with their fetch_rsrc_keys.
-
.make(**args) ⇒ Object
deprecated
Deprecated.
use .create instead
-
.map_all(ident, to:, cnx: Jamf.cnx, refresh: false, cached_list: nil) ⇒ Hash {Symbol: Object}
A Hash of all members of this collection where the keys are some identifier and values are any other attribute.
-
.map_all_ids_to(other_key, refresh = false, cached_list: nil, api: nil, cnx: Jamf.cnx) ⇒ Hash{Integer => Oject}
Return a hash of all objects of this subclass in the JSS where the key is the id, and the value is some other key in the data items returned by the Jamf::APIObject.all.
-
.new(**args) ⇒ Object
Disallow direct use of ruby’s .new class method for creating instances.
-
.post_raw(xml, api: nil, cnx: Jamf.cnx) ⇒ REXML::Document
POST some raw XML to the API for a given id in this subclass.
-
.put_raw(id, xml, api: nil, cnx: Jamf.cnx) ⇒ REXML::Document
PUT some raw XML to the API for a given id in this subclass.
-
.real_lookup_key(key) ⇒ Symbol
get the real lookup key frm a given alias.
-
.valid_id(identifier = nil, refresh = false, api: nil, cnx: Jamf.cnx, **ident_and_val) ⇒ Integer?
Return the id of the object of this subclass with the given identifier.
-
.validate_not_metaclass(klass) ⇒ Object
Can’t use APIObject directly.
-
.xml_list(array, content = :name) ⇒ REXML::Element
Convert an Array of Hashes of API object data to a REXML element.
Instance Method Summary collapse
-
#<=>(other) ⇒ Object
COMPARABLE APIobjects are == if all of their lookup key values are the same.
-
#add_object_history_entry(user: nil, notes: nil, details: nil) ⇒ void
Make an entry in this object’s Object History.
-
#categorizable? ⇒ Boolean
See Categorizable.
-
#creatable? ⇒ Boolean
See Creatable.
-
#create ⇒ Object
@deprecated, use #save.
-
#criterable? ⇒ Boolean
See Criteriable.
-
#delete ⇒ void
Delete this item from the JSS.
-
#extendable? ⇒ Boolean
See extendable.
- #idents_combined ⇒ Object
-
#initialize(**args) ⇒ APIObject
constructor
The args hash must include :id, :name, or :data.
-
#locatable? ⇒ Boolean
See Locatable.
-
#matchable? ⇒ Boolean
See Matchable.
-
#object_history ⇒ Array<Hash>
the object history for this object, an array of hashes one per history entry, in order of creation.
-
#ppx ⇒ void
Print the rest_xml value of the object to stdout, with indentation.
-
#pretty_print_instance_variables ⇒ Array
Remove the init_data and api object from the instance_variables used to create pretty-print (pp) output.
-
#purchasable? ⇒ Boolean
See Purchasable.
-
#save ⇒ Integer
Either Create or Update this object in the JSS.
-
#scopable? ⇒ Boolean
See Scopable.
-
#self_servable? ⇒ Boolean
See SelfServable.
-
#sitable? ⇒ Boolean
See Sitable.
-
#to_s ⇒ String
A meaningful string representation of this object.
-
#updatable? ⇒ Boolean
See Updatable.
-
#update ⇒ Object
@deprecated, use #save.
-
#uploadable? ⇒ Boolean
See Uploadable.
-
#vppable? ⇒ Boolean
See VPPable.
Constructor Details
#initialize(**args) ⇒ APIObject
The args hash must include :id, :name, or :data.
-
:id or :name will be looked up via the API
-
if the subclass includes Jamf::Creatable, :id can be :new, to create a new object in the JSS. and :name is required
-
-
:data must be the JSON output of a separate Connection query (a Hash of valid object data)
Some subclasses can accept other options, by pasing their keys in a final Array
1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1261 def initialize(**args) @cnx = args[:cnx] @cnx ||= args[:api] @cnx ||= Jamf.cnx # we're making a new one in the JSS if args[:id] == :new validate_init_for_creation(args) setup_object_for_creation(args) @need_to_update = true # we're instantiating an existing one in the jss else @init_data = look_up_object_data(args) @need_to_update = false end ## end arg parsing parse_init_data end |
Instance Attribute Details
#cnx ⇒ Jamf::Connection (readonly) Also known as: api
Returns the API connection thru which we deal with this object.
1215 1216 1217 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1215 def cnx @cnx end |
#id ⇒ Integer (readonly)
Returns the JSS id number.
1224 1225 1226 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1224 def id @id end |
#in_jss ⇒ Boolean (readonly) Also known as: in_jss?
Returns is it in the JSS?.
1230 1231 1232 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1230 def in_jss @in_jss end |
#init_data ⇒ Object (readonly)
Returns the parsed JSON data retrieved from the API when this object was fetched.
1221 1222 1223 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1221 def init_data @init_data end |
#name ⇒ String (readonly)
Returns the name.
1227 1228 1229 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1227 def name @name end |
#rest_rsrc ⇒ String (readonly)
Returns the Rest resource for API access (the part after “JSSResource/” ).
1233 1234 1235 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1233 def rest_rsrc @rest_rsrc end |
Class Method Details
.all(refresh = false, api: nil, cnx: Jamf.cnx) ⇒ Array<Hash{:name=>String, :id=> Integer}>
Return an Array of Hashes for all objects of this subclass in the JSS.
This method is only valid in subclasses of Jamf::APIObject, and is the parsed JSON output of an API query for the resource defined in the subclass’s RSRC_BASE
e.g. for Jamf::Computer, with the RSRC_BASE of :computers, This method retuens the output of the ‘JSSResource/computers’ resource, which is a list of all computers in the JSS.
Each item in the Array is a Hash with at least two keys, :id and :name. The class methods .all_ids and .all_names provide easier access to those dataas mapped Arrays.
Some API classes provide other keys in each Hash, e.g. :udid (for computers and mobile devices) or :is_smart (for groups).
For those keys that are listed in a subclass’s lookup_keys method, there are matching methods ‘.all_(key)s` which return an array just of those values, from the values of this hash. For example, `.all_udids` will use the .all array to return an array of just udids, if the subclass defines :udid in its OTHER_LOOKUP_KEYS (See ’Lookup Keys’ in the class comments/docs above)
Subclasses should provide appropriate .all_xxx class methods for accessing any other other values as Arrays, e.g. Jamf::Computer.all_managed
– Caching
The results of the first call to .all for each subclass is cached in the .c_object_list_cache of the given Connection and that cache is used for all future calls, so as to not requery the server every time.
To force requerying to get updated data, provided a truthy argument. I usually use :refresh, so that it’s obvious what I’m doing, but true, 1, or anything besides false or nil will work.
The various methods that use the output of this method also take the refresh parameter which will be passed here as needed.
– Alternate API connections
To query an APIConnection other than the currently active one, provide one via the cnx: named parameter.
492 493 494 495 496 497 498 499 500 501 502 503 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 492 def self.all(refresh = false, api: nil, cnx: Jamf.cnx) cnx = api if api (self) cache = cnx.c_object_list_cache cache_key = self::RSRC_LIST_KEY cnx.flushcache(cache_key) if refresh return cache[cache_key] if cache[cache_key] cache[cache_key] = cnx.c_get(self::RSRC_BASE)[cache_key] end |
.all_objects(refresh = false, api: nil, cnx: Jamf.cnx) ⇒ Array<APIObject>
Return an Array of Jamf::APIObject subclass instances e.g when called on Jamf::Package, return a hash of Jamf::Package instancesa for every package in the JSS.
WARNING: This may be slow as it has to look up each object individually! use it wisely.
632 633 634 635 636 637 638 639 640 641 642 643 644 645 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 632 def self.all_objects(refresh = false, api: nil, cnx: Jamf.cnx) cnx = api if api objects_cache_key ||= "#{self::RSRC_LIST_KEY}_objects".to_sym api_cache = cnx.c_object_list_cache api_cache[objects_cache_key] = nil if refresh return api_cache[objects_cache_key] if api_cache[objects_cache_key] all_result = all(refresh, cnx: cnx) api_cache[objects_cache_key] = all_result.map do |o| fetch id: o[:id], cnx: cnx, refresh: false end end |
.create(**args) ⇒ APIObject
Make a ruby instance of a not-yet-existing APIObject.
This is how to create new objects in the JSS. A name: must be provided, and different subclasses can take other named parameters.
For retrieving existing objects in the JSS, use fetch
After calling this you’ll have a local instance, which will be created in the JSS when you call #create on it. see #create
1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1121 def self.create(**args) (self) unless constants.include?(:CREATABLE) raise Jamf::UnsupportedError, "Creating #{self::RSRC_LIST_KEY} isn't yet supported. Please use other Casper workflows." end raise ArgumentError, "Use '#{self.class}.fetch id: xx' to retrieve existing JSS objects" if args[:id] args[:cnx] ||= args[:api] # deprecated args[:cnx] ||= Jamf.cnx args[:id] = :new new(**args) end |
.define_identifier_list_methods ⇒ Object
Loop through the defined lookup keys and make .all_<key>s methods for each one, with alises as needed.
This is called automatically when subclasses are loaded by zeitwerk
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 279 def self.define_identifier_list_methods Jamf.load_msg "Defining list-methods for APIObject subclass #{self}" lookup_keys.each do |als, key| meth_name = key.to_s.end_with?('s') ? "all_#{key}es" : "all_#{key}s" if als == key # the all_ method - skip if defined in the class next if singleton_methods.include? meth_name.to_sym define_singleton_method meth_name do |refresh = false, cached_list: nil, api: nil, cnx: Jamf.cnx| cnx = api if api list = cached_list || all(refresh, cnx: cnx) list.map { |i| i[key] } end Jamf.load_msg "Defined method #{self}##{meth_name}" else # an alias - skip if defined in the class als_name = als.to_s.end_with?('s') ? "all_#{als}es" : "all_#{als}s" next if singleton_methods.include? als_name.to_sym define_singleton_method als_name do |refresh = false, api: nil, cnx: Jamf.cnx| cnx = api if api send meth_name, refresh, cnx: cnx end Jamf.load_msg "Defined alias '#{als_name}' of #{self}##{meth_name}" end # if end # lookup_keys.each true end |
.delete(victims, refresh = true, api: nil, cnx: Jamf.cnx) ⇒ Array<Integer>
Delete one or more API objects by jss_id without instantiating them. Non-existent id’s are skipped and an array of skipped ids is returned.
If an Array is provided, it is passed through #uniq! before being processed.
1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1173 def self.delete(victims, refresh = true, api: nil, cnx: Jamf.cnx) cnx = api if api (self) raise Jamf::InvalidDataError, 'Parameter must be an Integer ID or an Array of them' unless victims.is_a?(Integer) || victims.is_a?(Array) case victims when Integer victims = [victims] when Array victims.uniq! end skipped = [] current_ids = all_ids refresh, cnx: cnx victims.each do |vid| if current_ids.include? vid cnx.c_delete "#{self::RSRC_BASE}/id/#{vid}" else skipped << vid end # if current_ids include vid end # each victim # clear any cached all-lists or id-maps for this class # so they'll re-cache as needed cnx.flushcache self::RSRC_LIST_KEY # all :refresh, cnx: cnx skipped end |
.duplicate_names(refresh = false, api: nil, cnx: Jamf.cnx) ⇒ Hash {String => Integer}
Returns name => number of occurances.
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 507 def self.duplicate_names(refresh = false, api: nil, cnx: Jamf.cnx) cnx = api if api return {} unless defined? self::NON_UNIQUE_NAMES dups = {} all(refresh, cnx: cnx).each do |obj| if dups[obj[:name]] dups[obj[:name]] += 1 else dups[obj[:name]] = 1 end # if end # all(refresh, cnx: cnx).each dups.delete_if { |_k, v| v == 1 } dups end |
.exist?(identifier, refresh = false, api: nil, cnx: Jamf.cnx) ⇒ Boolean
Return true or false if an object of this subclass with the given Identifier exists on the server
one of the available lookup_keys
813 814 815 816 817 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 813 def self.exist?(identifier, refresh = false, api: nil, cnx: Jamf.cnx) cnx = api if api !valid_id(identifier, refresh, cnx: cnx).nil? end |
.fetch(searchterm = nil, **args) ⇒ APIObject
Retrieve an object from the API and return an instance of this APIObject subclass.
Fetching is faster when specifying a lookup key, and that key has a fetch_rsrc_key defined in its OTHER_LOOKUP_KEYS constant, as in the second example above.
When no lookup key is given, as in the first example above, or when that key doesn’t have a defined fetch_rsrc_key, ruby-jss uses the currently cached list resource data to find the id matching the value given, and that id is used to fetch the object. (see ‘List Resources and Lookup Keys’ in the APIObject comments/docs above)
Since that cached list data may be out of date, you can provide the param ‘refrsh: true`, to reload the list from the server. This will cause the fetch to be slower still, so use with caution.
For creating new objects in the JSS, use make
943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 943 def self.fetch(searchterm = nil, **args) (self) # which connection? cnx = args.delete :cnx cnx ||= args.delete :api # backward compatibility, deprecated cnx ||= Jamf.cnx # refresh the .all list if needed if args.delete(:refresh) || searchterm == :random all(:refresh, cnx: cnx) just_refreshed = true else just_refreshed = false end # a random object? if searchterm == :random || args[:random] rnd_thing = all(cnx: cnx).sample raise Jamf::NoSuchItemError, "No #{self::RSRC_LIST_KEY} found" unless rnd_thing return new id: rnd_thing[:id], cnx: cnx end # get the lookup key and value, if given fetch_key, fetch_val = args.to_a.first fetch_rsrc_key = fetch_rsrc_key(fetch_key) # names should raise an error if more than one exists, # so we always have to do id_for_identifier, which will do so. if fetch_rsrc_key == :name id = id_for_identifier fetch_key, fetch_val, !just_refreshed, cnx: cnx fetch_rsrc = id ? "#{self::RSRC_BASE}/name/#{CGI.escape fetch_val.to_s}" : nil # if the fetch rsrc key exists, it can be used directly in an endpoint path # so, use it directly, rather than looking up the id first. elsif fetch_rsrc_key fetch_rsrc = "#{self::RSRC_BASE}/#{fetch_rsrc_key}/#{CGI.escape fetch_val.to_s}" # it has an OTHER_LOOKUP_KEY but that key doesn't have a fetch_rsrc # so we look in the .map_all_ids_to_* hash for it. elsif fetch_key id = id_for_identifier fetch_key, fetch_val, !just_refreshed, cnx: cnx fetch_rsrc = id ? "#{self::RSRC_BASE}/id/#{id}" : nil # no fetch key was given in the args, so try a search term elsif searchterm id = valid_id searchterm, cnx: cnx fetch_rsrc = id ? "#{self::RSRC_BASE}/id/#{id}" : nil else raise ArgumentError, 'Missing searchterm or fetch key' end new fetch_rsrc: fetch_rsrc, cnx: cnx end |
.fetch_rsrc_key(lookup_key) ⇒ Symbol?
Given a lookup key, or an alias of one, return the matching fetch_rsrc_key for building a fetch/GET resource URL, or nil if no fetch_rsrc_key is defined.
See OTHER_LOOKUP_KEYS in the APIObject class comments/docs above for details.
400 401 402 403 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 400 def self.fetch_rsrc_key(lookup_key) parse_lookup_keys unless @fetch_rsrc_keys @fetch_rsrc_keys[lookup_key] end |
.get_name(a_thing) ⇒ String
Some API objects contain references to other API objects. Usually those references are a Hash containing the :id and :name of the target. Sometimes, however the reference is just the name of the target.
A Script has a property :category, which comes from the API as a String, the name of the category for that script. e.g. “GoodStuff”
A Policy also has a property :category, but it comes from the API as a Hash with both the name and id, e.g. {:id => 8, :name => “GoodStuff”}
When that reference is to a single thing (like the category to which something belongs) APIObject subclasses usually store only the name, and use the name when returning data to the API.
When an object references a list of related objects (like the computers assigned to a user) that list will be and Array of Hashes as above, with both the :id and :name
This method is just a handy way to extract the name regardless of how it comes from the API. Most APIObject subclasses use it in their #initialize method
890 891 892 893 894 895 896 897 898 899 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 890 def self.get_name(a_thing) case a_thing when String a_thing when Hash a_thing[:name] when nil nil end end |
.get_raw(id, format: :json, as_string: false, api: nil, cnx: Jamf.cnx) ⇒ Hash, ...
Fetch the mostly- or fully-raw JSON or XML data for an object of this subclass.
By default, returns the JSON data parsed into a Hash.
When format: is anything but :json, returns the XML data parsed into a REXML::Document
When as_string: is truthy, returns an unparsed JSON String (or XML String if format: is not :json) as it comes directly from the API.
When fetching raw JSON, the returned Hash will have its keys symbolized.
This can be substantialy faster than instantiating, especially when you don’t need all the ruby goodness of a full instance, but just want a few values for an object that aren’t available in the ‘all` data
This is really just a wrapper around Connection.c_get that automatically fills in the RSRC::BASE value for you.
1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1032 def self.get_raw(id, format: :json, as_string: false, api: nil, cnx: Jamf.cnx) cnx = api if api (self) rsrc = "#{self::RSRC_BASE}/id/#{id}" data = cnx.c_get rsrc, format, raw_json: as_string return data if format == :json || as_string REXML::Document.new(**data) end |
.id_for_identifier(key, val, refresh = false, api: nil, cnx: Jamf.cnx) ⇒ Integer?
Return the id of the object of this subclass with the given lookup key == a given identifier.
Return nil if no object has that value in that key
Raises a Jamf::Ambiguous error if there’s more than one matching value for any key, which might be true of names for Computers and Devices
This is similar to .valid_id, except only one key is searched
779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 779 def self.id_for_identifier(key, val, refresh = false, api: nil, cnx: Jamf.cnx) cnx = api if api # refresh if needed all(refresh, cnx: cnx) if refresh # get the real key if an alias was used key = real_lookup_key key # do id's expicitly, they are integers return all_ids(cnx: cnx).include?(val) ? val : nil if key == :id mapped_ids = map_all_ids_to key, cnx: cnx matches = mapped_ids.select { |_id, map_val| val.casecmp? map_val } raise Jamf::AmbiguousError, "Key #{key}: value '#{val}' is not unique for #{self}" if matches.size > 1 return nil if matches.size.zero? matches.keys.first end |
.lookup_keys(no_aliases: false, fetch_rsrc_keys: false) ⇒ Hash {Symbol: Symbol}, Array<Symbol>
What are all the lookup keys available for this class, with all their aliases (or optionally not) or with their fetch_rsrc_keys
This method combines the DEFAULT_LOOOKUP_KEYS defined above, with the optional OTHER_LOOKUP_KEYS from a subclass (See ‘Lookup Keys’ in the class comments/docs above)
The hash returned flattens and inverts the two source hashes, so that all possible lookup keys (the keys and their aliases) are hash keys and the non-aliased lookup key is the value.
For example, when
OTHER_LOOKUP_KEYS = {
serial_number: { aliases: [:serialnumber, :sn], fetch_rsrc_key: :serialnumber },
udid: { fetch_rsrc_key: :udid },
wifi_mac_address: { aliases: [:macaddress, :macaddr], fetch_rsrc_key: :macaddress }
}
It is combined with DEFAULT_LOOKUP_KEYS to produce:
{
id: :id,
name: :name,
serial_number: :serial_number,
serialnumber: :serial_number,
sn: :serial_number,
udid: :udid,
wifi_mac_address: :wifi_mac_address,
macaddress: :wifi_mac_address,
macaddr: :wifi_mac_address
}
If the optional parameter no_aliases: is truthy, only the real keynames are returned in an array, so the above would become
[:id, :name, :serial_number, :udid, :wifi_mac_address]
385 386 387 388 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 385 def self.lookup_keys(no_aliases: false, fetch_rsrc_keys: false) parse_lookup_keys unless @lookup_keys no_aliases ? @lookup_keys.values.uniq : @lookup_keys end |
.make(**args) ⇒ Object
use .create instead
backward compatability
1136 1137 1138 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1136 def self.make(**args) create(**args) end |
.map_all(ident, to:, cnx: Jamf.cnx, refresh: false, cached_list: nil) ⇒ Hash {Symbol: Object}
A Hash of all members of this collection where the keys are some identifier and values are any other attribute.
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 541 def self.map_all(ident, to:, cnx: Jamf.cnx, refresh: false, cached_list: nil) orig_ident = ident ident = lookup_keys[ident] raise Jamf::InvalidDataError, "No identifier :#{orig_ident} for class #{self}" unless ident list = cached_list || all(refresh, cnx: cnx) mapped = list.map do |i| [ i[ident], i[to] ] end # do i mapped.to_h end |
.map_all_ids_to(other_key, refresh = false, cached_list: nil, api: nil, cnx: Jamf.cnx) ⇒ Hash{Integer => Oject}
Return a hash of all objects of this subclass in the JSS where the key is the id, and the value is some other key in the data items returned by the Jamf::APIObject.all.
If the other key doesn’t exist in the API summary data from .all (eg :udid for Jamf::Department) the values will be nil.
Use this method to map ID numbers to other identifiers returned by the API list resources. Invert its result to map the other identfier to ids.
These hashes are cached separately from the .all data, and when the refresh parameter is truthy, both will be refreshed.
WARNING: Some values in the output of .all are not guaranteed to be unique in Jamf Pro. This is fine in the direct output of this method, each id will be the key for some value and many ids might have the same value. However if you invert that hash, the values become keys, and the ids become the values, and there can be only one id per each new key. Which id becomes associated with a value is undefined, and data about the others is lost. This is especially important if you ‘.map_all_ids_to :name`, since, for some objects, names are not unique.
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 598 def self.map_all_ids_to(other_key, refresh = false, cached_list: nil, api: nil, cnx: Jamf.cnx) cnx = api if api map_all :id, to: other_key, refresh: refresh, cnx: cnx, cached_list: cached_list # # we will accept any key, it'll just return nil if not in the # # .all hashes. However if we're given an alias of a lookup key # # we need to convert it to its real name. # other_key = lookup_keys[other_key] if lookup_keys[other_key] # # cache_key = "#{self::RSRC_LIST_KEY}_map_#{other_key}".to_sym # cache = cnx.c_object_list_cache # cache[cache_key] = nil if refresh # return cache[cache_key] if cache[cache_key] # # map = {} # all(refresh, cnx: cnx).each { |i| map[i[:id]] = i[other_key] } # cache[cache_key] = map end |
.new(**args) ⇒ Object
Disallow direct use of ruby’s .new class method for creating instances. Require use of .fetch or .make
1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1142 def self.new(**args) (self) # calling_method = caller_locations(1..1).first.label # # Temp workaround for ruby 3.4 until I figure out the best way to deal with # the new behavior of caller_locations. `label` used to return just the method name # e.g. `fetch` but now it returns, e.g. `Jamf::APIObject.fetch` # See https://docs.ruby-lang.org/en/3.4/Thread/Backtrace/Location.html # and investigate the `base_label` method calling_method = caller_locations(1..1).first.label.to_s.split('.').last raise Jamf::UnsupportedError, 'Use .fetch or .create to instantiate APIObject classes' unless OK_INSTANTIATORS.include? calling_method super end |
.post_raw(xml, api: nil, cnx: Jamf.cnx) ⇒ REXML::Document
POST some raw XML to the API for a given id in this subclass.
WARNING: You must create or acquire the XML to be sent, and no validation will be performed on it. It must be a String, or something that returns an XML string with #to_s, such as a REXML::Document, or a REXML::Element.
This probably isn’t as much of a speed gain as get_raw or put_raw, as opposed to instantiating a ruby object, but might still be useful.
This is really just a wrapper around Connection.c_post that automatically fills in the RSRC::BASE value for you.
1093 1094 1095 1096 1097 1098 1099 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1093 def self.post_raw(xml, api: nil, cnx: Jamf.cnx) cnx = api if api (self) rsrc = "#{self::RSRC_BASE}/id/-1" REXML::Document.new(cnx.c_post(rsrc, xml.to_s)) end |
.put_raw(id, xml, api: nil, cnx: Jamf.cnx) ⇒ REXML::Document
PUT some raw XML to the API for a given id in this subclass.
WARNING: You must create or acquire the XML to be sent, and no validation will be performed on it. It must be a String, or something that returns an XML string with #to_s, such as a REXML::Document, or a REXML::Element.
In some cases, where you’re making simple changes to simple XML, this can be faster than fetching a full instance and the re-saving it.
This is really just a wrapper around Connection.c_put that automatically fills in the RSRC::BASE value for you.
1065 1066 1067 1068 1069 1070 1071 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1065 def self.put_raw(id, xml, api: nil, cnx: Jamf.cnx) cnx = api if api (self) rsrc = "#{self::RSRC_BASE}/id/#{id}" REXML::Document.new(cnx.c_put(rsrc, xml.to_s)) end |
.real_lookup_key(key) ⇒ Symbol
get the real lookup key frm a given alias
433 434 435 436 437 438 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 433 def self.real_lookup_key(key) real_key = lookup_keys[key] raise ArgumentError, "Unknown lookup key '#{key}' for #{self}" unless real_key real_key end |
.valid_id(identifier = nil, refresh = false, api: nil, cnx: Jamf.cnx, **ident_and_val) ⇒ Integer?
Return the id of the object of this subclass with the given identifier.
Return nil if no object has an identifier that matches.
For all objects the ‘name’ is an identifier. Some objects have more, e.g. udid, mac_address & serial_number. Matches are case-insensitive.
NOTE: while name is an identifier, for Computers and MobileDevices, it need not be unique in Jamf. If name is matched, which one gets returned is undefined. In short - dont’ use names here unless you know they are unique.
NOTE: Integers passed in as strings, e.g. ‘12345’ will be converted to integers and return the matching integer id if it exists.
This means that if you have names that might match ‘12345’ and you use
valid_id '12345'
you will get back the id 12345, if such an id exists, even if it is not the object with the name ‘12345’
To explicitly look for ‘12345’ as a name, use:
valid_id name: '12345'
See the ident_and_val param below.
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/base_classes/api_object.rb', line 693 def self.valid_id(identifier = nil, refresh = false, api: nil, cnx: Jamf.cnx, **ident_and_val) cnx = api if api # refresh the cache if needed all(refresh, cnx: cnx) if refresh # Were we given an explict identifier key, like name: or id:? # If so, just look for that. unless ident_and_val.empty? # only the first k/v pair of the ident_and_val hash is used key = ident_and_val.keys.first val = ident_and_val[key] # if we are explicitly looking for an id, ensure we use an integer # even if we were given an integer in a string. if key == :id val = val.to_i if val.is_a?(String) && val.j_integer? return all_ids(cnx: cnx).include?(val) ? val : nil end # map the identifiers to ids, and return the id if there's # a case-insensitive matching identifire map_all(key, to: :id).each do |ident_val, id| return id if ident_val.to_s.casecmp? val.to_s end nil end # If we are here, we need to seach all available identifier keys # Start by looking for it as an id. # it its a valid integer id, return it return identifier if all_ids(cnx: cnx).include? identifier # if its a valid integer-in-a-string id, return it if identifier.is_a?(String) && identifier.j_integer? int_id = identifier.to_i return int_id if all_ids(cnx: cnx).include? int_id end # Now go through all the other identifier keys keys_to_check = lookup_keys(no_aliases: true) keys_to_check.delete :id # we've already checked :id # loop thru looking for a match keys_to_check.each do |key| mapped_ids = map_all_ids_to key, cnx: cnx matches = mapped_ids.select { |_id, ident| ident.casecmp? identifier } # If exactly one match, return the id return matches.keys.first if matches.size == 1 end nil end |
.validate_not_metaclass(klass) ⇒ Object
Can’t use APIObject directly.
1206 1207 1208 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1206 def self.(klass) raise Jamf::UnsupportedError, 'Jamf::APIObject is a metaclass. Do not use it directly' if klass == Jamf::APIObject end |
.xml_list(array, content = :name) ⇒ REXML::Element
Convert an Array of Hashes of API object data to a REXML element.
Given an Array of Hashes of items in the subclass where each Hash has at least an :id or a :name key, (as what comes from the .all class method) return a REXML <classes> element with one <class> element per Hash member.
861 862 863 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 861 def self.xml_list(array, content = :name) JSS.item_list_to_rexml_list self::RSRC_LIST_KEY, self::RSRC_OBJECT_KEY, array, content end |
Instance Method Details
#<=>(other) ⇒ Object
COMPARABLE APIobjects are == if all of their lookup key values are the same
262 263 264 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 262 def <=>(other) idents_combined <=> other.idents_combined end |
#add_object_history_entry(user: nil, notes: nil, details: nil) ⇒ void
This method returns an undefined value.
Make an entry in this object’s Object History. For this to work, the APIObject subclass must define OBJECT_HISTORY_OBJECT_TYPE, an integer indicating the object type in the OBJECT_HISTORY_TABLE in the database (e.g. for computers, the object type is 1)
NOTE: Object history is not available via the Classic API,
so access is only available through direct MySQL
connections
Also: the ‘details’ column in the table shows up in the
'notes' column of the Web UI. and the 'object_description'
column of the table shows up in the 'details' column of
the UI, under the 'details' .
The params below reflect the UI, not the table.
1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1472 def add_object_history_entry(user: nil, notes: nil, details: nil) validate_object_history_available raise Jamf::MissingDataError, 'A user: must be provided to make the entry' unless user raise Jamf::MissingDataError, 'notes: must be provided to make the entry' unless notes user = "'#{Mysql.quote user.to_s}'" notes = "'#{Mysql.quote notes.to_s}'" obj_type = self.class::OBJECT_HISTORY_OBJECT_TYPE field_list = 'object_type, object_id, username, details, timestamp_epoch' value_list = "#{obj_type}, #{@id}, #{user}, #{notes}, #{Time.now.to_jss_epoch}" if details field_list << ', object_description' value_list << ", '#{Mysql.quote details.to_s}'" end # if details q = "INSERT INTO #{OBJECT_HISTORY_TABLE} (#{field_list}) VALUES (#{value_list})" Jamf::DB_CNX.db.query q end |
#categorizable? ⇒ Boolean
Returns See Categorizable.
1342 1343 1344 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1342 def categorizable? defined? self.class::CATEGORIZABLE end |
#creatable? ⇒ Boolean
Returns See Creatable.
1332 1333 1334 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1332 def creatable? defined? self.class::CREATABLE end |
#create ⇒ Object
@deprecated, use #save
1312 1313 1314 1315 1316 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1312 def create raise Jamf::UnsupportedError, 'Creating this object in the JSS is currently not supported by ruby-jss' unless creatable? create_in_jamf end |
#criterable? ⇒ Boolean
Returns See Criteriable.
1357 1358 1359 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1357 def criterable? defined? self.class::CRITERIABLE end |
#delete ⇒ void
This method returns an undefined value.
Delete this item from the JSS.
one or more objects by id without needing to instantiate
Subclasses may want to redefine this method, first calling super, then setting other attributes to nil, false, empty, etc..
1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1407 def delete return unless @in_jss @cnx.c_delete @rest_rsrc @rest_rsrc = "#{self.class::RSRC_BASE}/name/#{CGI.escape @name.to_s}" @id = nil @in_jss = false @need_to_update = false # clear any cached all-lists or id-maps for this class # so they'll re-cache as needed @cnx.flushcache self.class::RSRC_LIST_KEY # self.class.all :refresh, cnx: @cnx :deleted end |
#extendable? ⇒ Boolean
Returns See extendable.
1367 1368 1369 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1367 def extendable? defined? self.class::EXTENDABLE end |
#idents_combined ⇒ Object
266 267 268 269 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 266 def idents_combined my_keys = self.class.lookup_keys.values.uniq my_keys.map { |k| send(k).to_s }.sort.join end |
#locatable? ⇒ Boolean
Returns See Locatable.
1377 1378 1379 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1377 def locatable? defined? self.class::LOCATABLE end |
#matchable? ⇒ Boolean
Returns See Matchable.
1372 1373 1374 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1372 def matchable? defined? self.class::MATCHABLE end |
#object_history ⇒ Array<Hash>
the object history for this object, an array of hashes one per history entry, in order of creation. Each hash contains:
user: String, the username that created the entry
notes: String, the notes for the entry
date: Time, the for the entry
details: String or nil, any details provided for the entry
1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1509 def object_history validate_object_history_available q = "SELECT username, details, timestamp_epoch, object_description FROM #{OBJECT_HISTORY_TABLE} WHERE object_type = #{self.class::OBJECT_HISTORY_OBJECT_TYPE} AND object_id = #{@id} ORDER BY object_history_id ASC" result = Jamf::DB_CNX.db.query q history = [] result.each do |entry| history << { user: entry[0], notes: entry[1], date: JSS.epoch_to_time(entry[2]), details: entry[3] } end # each do entry history end |
#ppx ⇒ void
This method returns an undefined value.
Print the rest_xml value of the object to stdout, with indentation. Useful for debugging.
1536 1537 1538 1539 1540 1541 1542 1543 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1536 def ppx return nil unless creatable? || updatable? formatter = REXML::Formatters::Pretty.new(2) formatter.compact = true formatter.write(REXML::Document.new(rest_xml), $stdout) puts end |
#pretty_print_instance_variables ⇒ Array
Remove the init_data and api object from the instance_variables used to create pretty-print (pp) output.
1439 1440 1441 1442 1443 1444 1445 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1439 def pretty_print_instance_variables vars = instance_variables.sort vars.delete :@cnx vars.delete :@init_data vars.delete :@main_subset vars end |
#purchasable? ⇒ Boolean
Returns See Purchasable.
1382 1383 1384 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1382 def purchasable? defined? self.class::PURCHASABLE end |
#save ⇒ Integer
Either Create or Update this object in the JSS
If this item is creatable or updatable, then create it if needed, or update it if it already exists.
1303 1304 1305 1306 1307 1308 1309 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1303 def save if @in_jss update else create end end |
#scopable? ⇒ Boolean
Returns See Scopable.
1387 1388 1389 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1387 def scopable? defined? self.class::SCOPABLE end |
#self_servable? ⇒ Boolean
Returns See SelfServable.
1352 1353 1354 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1352 def self_servable? defined? self.class::SELF_SERVABLE end |
#sitable? ⇒ Boolean
Returns See Sitable.
1362 1363 1364 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1362 def sitable? defined? self.class::SITABLE end |
#to_s ⇒ String
A meaningful string representation of this object
1429 1430 1431 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1429 def to_s "#{self.class}@#{cnx.host}, id: #{@id}" end |
#updatable? ⇒ Boolean
Returns See Updatable.
1337 1338 1339 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1337 def updatable? defined? self.class::UPDATABLE end |
#update ⇒ Object
@deprecated, use #save
1319 1320 1321 1322 1323 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1319 def update raise Jamf::UnsupportedError, 'Updating this object in the JSS is currently not supported by ruby-jss' unless updatable? update_in_jamf end |
#uploadable? ⇒ Boolean
Returns See Uploadable.
1392 1393 1394 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1392 def uploadable? defined? self.class::UPLOADABLE end |
#vppable? ⇒ Boolean
Returns See VPPable.
1347 1348 1349 |
# File 'lib/jamf/api/classic/base_classes/api_object.rb', line 1347 def vppable? defined? self.class::VPPABLE end |