Class: Jamf::Resource Abstract

Inherits:
JSONObject show all
Extended by:
BaseClass
Defined in:
lib/jamf/api/base_classes/resource.rb

Overview

This class is abstract.

Jamf::Resource represents a thing directly accessible in the API. It will contain one or more API endpoints.

A resource has a base URI path in the API used for interacting with the resource and directly-related sub-resources.

For example, the device-reenrollment settings are a resource at the url path

> …/uapi/v1/reenrollment

and the related sub-resource for the change history of the reenrollment settings is at

> …/uapi/v1/reenrollment/history

All resources based at …/uapi/v1/reenrollment are encapsulated in the class ReEnrollmentSettings, a descendent of Jamf::Resource

There are two types of resources: Singletons and Collections.

**Singleton resources** have only one instance available in the API, and they cannot be create or deleted, only fetched and usually updated, tho some cant be updated either, e.g. Jamf::AppStoreCountryCodes. The device-reenrollment settings mentioned above are an example of a Singleton resource. When the resource is fetched from the API, it is cached, and (usually) future fetching will return the same instance. See SingletonResource for details.

**Collection resources** have more than one resource within them, and those can (usually) be created and deleted as well as fetched and updated. The entire collection (or a part of it) can also be fetched as an Array. When the whole collection is fetched, the result is cached for future use. See CollectionResource for details.

# Instantiating Resources

For all subclasses of Jamf::Resource, using the ruby standard .new class method to instantiate an object will raise an exception. We do this to avoid the ambiguity of the word 'new' in this context.

Normally in ruby, .new means 'make a new instance of this class in memory'. But with Jamf Resoureces, when making a new instance in memory, we might be making an instance of a resource that already exists in Jamf Pro, or perhaps making an instance of a 'new' thing that we want to create in Jamf Pro, but doesn't exist there at the moment.

While we could look at the parameters passed to decide which of those two things we're doing, (and require specific parameters for each action), that doesn't change the fact that a human reading the line:

a_building = Jamf::Building.new name: 'Main Building'

sounds like we want to create a new building in the JSS, when in fact we're just retrieving one that's already there.

To make the code more readable and totally clear, .new is not allowed for making instances of Jamf::Resources. Instead, use the class method .fetch to retrieve existing resources, like so:

a_building = Jamf::Building.fetch name: 'Main Building'

This makes it clear what the code is doing, and when you get the error that there's no building with that name, the error makes sense, which it wouldn't if you were creating a new building in the JSS.

Likewise, to make a new one in Jamf Pro, use .create, as in:

a_building = Jamf::Building.create name: 'Main Building'

This makes it obvious that we're creating a new building in the JSS

In both cases, the instance method #save is used to send your changes to the API. If the resource already exists, the changes will be applied to the server with #save. If it doesn't yet exist, it will be created by #save.

# Subclassing

### Required Constant: RSRC_VERSION

The version of the resource model supported by ruby-jss for this class.

Every resource in the Jamf Pro API has a version as part of its URL path. For example, in the full resource URL:

https://your.jamf.server:port/uapi/v1/reenrollment

the resource version is `v1`. At any given time, the API may have many versions of a resource available - v2 might be released with new values available or deprecated values removed, but v1 remains and is unchanged.

Each subclass of Jamf::Resource must define RSRC_VERSION as a String, e.g. 'v1', which defines the version supported by the subclass.

As new versions are released by Jamf, when the changes are implemented in ruby-jss, the RSRC_VERSION is updated.

## Required Constant: OBJECT_MODEL

This is required of all JSONObject subclasses. Refer to that documentation for full details about implementing the OBJECT_MODEL constant.

## Required Constant: RSRC_PATH

This is the URI path to the resource, relative to the API base and version ('uapi/vX/').

Examples:

1. For SingletonResource class {Jamf::Settings::ReEnrollment}, the URL to
   the resource is:

      https://your.jamf.server:port/uapi/v1/reenrollment

   and that URL is used to GET and PUT data, and as a base for the change
   log data.

   The constant {Jamf::Settings::ReEnrollment::RSRC_PATH} must be
   `'reenrollment'`

2. For CollectionResource class {Jamf::MobileDevice}, the URL to the
   collection Array is:

      https://your.jamf.server:port/uapi/v1/mobile-devices

   and that URL is used to GET lists of mobileDevice data and POST data
   to create a new mobile device.
   It is also the base URL for GET, PATCH, PUT and DELETE for individual
   mobileDevices, and their details and change log data.

   The constant {Jamf::MobileDevice::RSRC_PATH} must be
   `'mobile-devices'`

## Required Constant: RSRC_VERSION

As shown in the examples above, the URL paths for resources have a version number between 'uapi' and the RSRC_PATH

Both SingletonResources and CollectionResources must defing the constant RSRC_VERSION as a string containing that version, e.g. 'v1'

ruby-jss doesn't support the older resource paths that don't have a version in their path.

Direct Known Subclasses

CollectionResource, SingletonResource

Constant Summary collapse

NEW_CALLERS =

These methods are allowed to call .new

['fetch', 'create', 'all', 'cached_all', 'block in all', 'block in cached_all'].freeze
RSRC_PREVIEW_VERSION =

The resource version for previewing new features

'preview'.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

This class inherits a constructor from Jamf::JSONObject

Instance Attribute Details

#cnxJamf::Connection (readonly)

Returns the API connection thru which we deal with this resource.

Returns:

  • (Jamf::Connection)

    the API connection thru which we deal with this resource.



222
223
224
# File 'lib/jamf/api/base_classes/resource.rb', line 222

def cnx
  @cnx
end

#rsrc_pathString (readonly)

Returns the resouce path for this object.

Returns:

  • (String)

    the resouce path for this object



225
226
227
# File 'lib/jamf/api/base_classes/resource.rb', line 225

def rsrc_path
  @rsrc_path
end

Class Method Details

.allocate(*args, &block) ⇒ Object Originally defined in module BaseClass

Can't allocate if base class

.base_class?Boolean Originally defined in module BaseClass

Returns:

  • (Boolean)

.new(data, cnx: Jamf.cnx) ⇒ Object

Disallow direct use of ruby's .new class method for creating instances. Require use of .fetch or .create, or 'all'



210
211
212
213
214
215
# File 'lib/jamf/api/base_classes/resource.rb', line 210

def self.new(data, cnx: Jamf.cnx)
  stop_if_base_class
  calling_method = caller_locations(1..1).first.label
  raise Jamf::UnsupportedError, "Use .fetch, .create, or .all(instantiate:true) to instantiate Jamf::Resources" unless NEW_CALLERS.include? calling_method
  super
end

.preview_pathObject



203
204
205
# File 'lib/jamf/api/base_classes/resource.rb', line 203

def self.preview_path
  "#{RSRC_PREVIEW_VERSION}/#{self::RSRC_PATH}"
end

.rsrc_pathString

the resource path for this resource

Returns:



199
200
201
# File 'lib/jamf/api/base_classes/resource.rb', line 199

def self.rsrc_path
  @rsrc_path ||= "#{self::RSRC_VERSION}/#{self::RSRC_PATH}"
end

.stop_if_base_class(action = DEFAULT_ACTION) ⇒ Object Originally defined in module BaseClass

raise an exception if this class is a base class

Instance Method Details

#saveObject

TODO: error handling



231
232
233
234
235
236
237
238
239
240
# File 'lib/jamf/api/base_classes/resource.rb', line 231

def save
  raise Jamf::UnsupportedError, "#{self.class} objects cannot be changed" unless self.class.mutable?

  return unless unsaved_changes?

  exist? ? update_in_jamf : create_in_jamf
  clear_unsaved_changes

  @id || :saved
end