Module: Jamf::ManagedSoftwareUpdates

Defined in:
lib/jamf/api/jamf_pro/api_objects/managed_software_updates.rb,
lib/jamf/api/jamf_pro/api_objects/managed_software_updates/plan.rb

Overview

This module provides access to the Managed Software Updates endpoints of the Jamf Pro API.

Sending managed software updates is done by creating a “plan” for one or more devices, or a group of devices, either computers or mobile devices. Plans are created with the ManagedSoftwareUpdates.send_managed_sw_update module method, which takes the target devices or group, the update action, the version type, and other optional parameters such as specific version, build version.

Once created/sent, Plans, identified by their planUuid, can be retrieved with the Jamf::ManagedSoftwareUpdate::Plan class which encapsulates the details of the plan, including the latest status of the update from the Jamf Pro server.

You can also retrieve the status of any computer or group from the MDM server/Client Machines via the Jamf::ManagedSoftwareUpdates.status method, which returns an array of Status objects for the devices or group members you specify.

TODO: We will integrate the ManagedSoftwareUpdate::Plan class into Jamf::Computer, Jamf::MobileDevice, Jamf::ComputerGroup, and Jamf::MobileDeviceGroup (and/or their JP API versions) as both a class method and an instance method, so that you can send updates directly from those classes and instances.

We will probably not add support for the “feature-toggle” endpoints, since eventually this ‘feature’ will be the only way to do these updates, and that such toggling is better done in the web app.

Defined Under Namespace

Classes: Plan

Constant Summary collapse

MANAGED_SW_UPDATES_PATH =

API PATHS

'v1/managed-software-updates'
AVAILABLE_VERSIONS_PATH =
"#{MANAGED_SW_UPDATES_PATH}/available-updates"
DEVICE_POST_PATH =
"#{MANAGED_SW_UPDATES_PATH}/plans"
GROUP_POST_PATH =
"#{MANAGED_SW_UPDATES_PATH}/plans/group"
STATUS_PATH =
"#{MANAGED_SW_UPDATES_PATH}/update-statuses"
COMPUTER_STATUS_PATH =
"#{STATUS_PATH}/computers"
COMPUTER_GROUP_STATUS_PATH =
"#{STATUS_PATH}/computer-groups"
MOBILE_DEVICE_STATUS_PATH =
"#{STATUS_PATH}/mobile-devices"
MOBILE_DEVICE_GROUP_STATUS_PATH =
"#{STATUS_PATH}/mobile-device-groups"
STATUS_FILTER_KEYS =
%i[
  osUpdatesStatusId device.deviceId device.objectType downloaded downloadPercentComplete productKey status deferralsRemaining maxDeferrals nextScheduledInstall created updated
].freeze
DEVICE_TYPES =
Jamf::OAPISchemas::PlanDevicePost::OBJECT_TYPE_OPTIONS
GROUP_TYPES =
Jamf::OAPISchemas::PlanGroupPost::OBJECT_TYPE_OPTIONS
UPDATE_ACTIONS =
Jamf::OAPISchemas::PlanConfigurationPost::UPDATE_ACTION_OPTIONS
VERSION_TYPES =
Jamf::OAPISchemas::PlanConfigurationPost::VERSION_TYPE_OPTIONS

Class Method Summary collapse

Class Method Details

.available_os_updates(cnx: Jamf.cnx) ⇒ Hash {Symbol => Array<String>}

get the list of available OS versions for macOS and/or iOS/iPadOS

Parameters:

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

    the connection to use, defaults to Jamf.cnx

Returns:



93
94
95
# File 'lib/jamf/api/jamf_pro/api_objects/managed_software_updates.rb', line 93

def self.available_os_updates(cnx: Jamf.cnx)
  cnx.jp_get(AVAILABLE_VERSIONS_PATH)[:availableUpdates]
end

.send_managed_sw_update(targetType:, updateAction:, versionType:, deviceIds: nil, groupId: nil, cnx: Jamf.cnx, **opts) ⇒ Hash {String => String}

Send an MDM/DDM OS update command to one or more target devices or a group

TODO: Integrate this into Jamf::Computer, Jamf::MobileDevice, Jamf::ComputerGroup, and Jamf::MobileDeviceGroup as both a class method and an instance method.

of the device to force update by. NOTE: This operation requires Declarative Device Management and is only available for Jamf Cloud customers.

Parameters:

  • deviceIds (String, Integer, Array<String, Integer>) (defaults to: nil)

    Required if no groupId is given. The Jamf ID for the device targets, may be integers or integer-strings.

  • groupId (String, Integer) (defaults to: nil)

    Requied if no deviceIds are given. The Jamf ID for the group target, may be integer or integer-string.

  • targetType (Symbol, String)

    Required. The type of device or group. For devices, one of :computer, :mobile_device, :apple_tv. For groups, one of :computer_group, :mobile_device_group.

  • updateAction (Symbol, String)

    Required. One of :download_only, :download_install, :download_install_allow_deferral, :download_install_restart, :download_install_schedule.

  • versionType (Symbol, String)

    Required. One of :latest_major, :latest_minor, :latest_any, :specific_version, :custom_version

  • specificVersion (String)

    Optional. Indicates the specific version to update to. Only available when the versionType is set to specific_version or custom_version

  • buildVersion (String)

    Optional. Indicates the build version to update to. Only available when the version type is set to custom version.

  • maxDeferrals (Integer)

    Required when the provided updateAction is :download_install_allow_deferral. Not applicable to all updateActions.

  • forceInstallLocalDateTime (Time, Jamf::Timestamp, String)

    Optional. The local date and time

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

    The API connection to use. Defaults to Jamf.cnx

Returns:



135
136
137
138
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
172
173
174
175
176
177
178
179
180
181
# File 'lib/jamf/api/jamf_pro/api_objects/managed_software_updates.rb', line 135

def self.send_managed_sw_update(targetType:, updateAction:, versionType:, deviceIds: nil, groupId: nil, cnx: Jamf.cnx, **opts)
  deviceIds, groupId, targetType = validate_targets(targetType: targetType, deviceIds: deviceIds, groupId: groupId)

  # Ensure we have a valid update action
  updateAction = validate_update_action(updateAction)

  # Ensure we have a valid version type
  versionType = validate_version_type(versionType)

  # Build the request body, starting with the common config
  request_body = {
    config: {
      updateAction: updateAction,
      versionType: versionType
    }
  }

  request_body[:config][:specificVersion] = opts[:specificVersion] if opts[:specificVersion]
  request_body[:config][:buildVersion] = opts[:buildVersion] if opts[:buildVersion]
  request_body[:config][:maxDeferrals] = opts[:maxDeferrals] if opts[:maxDeferrals]
  if opts[:forceInstallLocalDateTime]
    time = Time.parse opts[:forceInstallLocalDateTime] unless opts[:forceInstallLocalDateTime].is_a? Time
    request_body[:config][:forceInstallLocalDateTime] = time.strftime('%FT%T')
  end

  # Add the target information
  if deviceIds
    request_body[:devices] = deviceIds.map { |id| { deviceId: id, objectType: targetType } }
    post_path = DEVICE_POST_PATH
  else
    request_body[:group] = {
      groupId: groupId,
      objectType: targetType
    }
    post_path = GROUP_POST_PATH
  end

  response = cnx.jp_post(post_path, request_body)
  parsed_response = Jamf::OAPISchemas::ManagedSoftwareUpdatePlanPostResponse.new response

  result = {}
  parsed_response.plans.each do |plan|
    result[plan.device.deviceId] = plan.planId
  end

  result
end

.status(type: nil, id: nil, filter: nil, cnx: Jamf.cnx) ⇒ Array<Jamf::OAPISchemas::ManagedSoftwareUpdateStatus>

Retrieve one or more ManagedSoftwareUpdateStatuses objects for a device, group members, or the result of an arbitrary filter on all Status objects.

TODO: Integrate this into Jamf::Computer, Jamf::MobileDevice, Jamf::ComputerGroup, and Jamf::MobileDeviceGroup as both a class method and an instance method.

Parameters:

  • type (Symbol) (defaults to: nil)

    Required unless using a filter. One of :computer, :mobile_device, :mobile_device_group, :computer_group.

  • id (Integer, String) (defaults to: nil)

    Required unless using a filter. The Jamf ID of the device or group

  • filter (String) (defaults to: nil)

    Required unless providing type: and id:. An RSQL filter string to apply to the collection of Status objects. Available filter keys are: osUpdatesStatusId device.deviceId device.objectType downloaded downloadPercentComplete productKey status deferralsRemaining maxDeferrals nextScheduledInstall created updated

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

    The API connection to use. Defaults to Jamf.cnx

Returns:

Raises:

  • (ArgumentError)


205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/jamf/api/jamf_pro/api_objects/managed_software_updates.rb', line 205

def self.status(type: nil, id: nil, filter: nil, cnx: Jamf.cnx)
  raise ArgumentError, 'Must provide either type and id, or a filter' if (type || id) && filter
  raise ArgumentError, 'Must provide both type and id if using either' if (type || id) && !(type && id)

  get_path =
    case type
    when :computer
      "#{COMPUTER_STATUS_PATH}/#{id}"
    when :mobile_device
      "#{MOBILE_DEVICE_STATUS_PATH}/#{id}"
    when :computer_group
      "#{COMPUTER_GROUP_STATUS_PATH}/#{id}"
    when :mobile_device_group
      "#{MOBILE_DEVICE_GROUP_STATUS_PATH}/#{id}"
    else
      unless type.nil?
        raise ArgumentError,
              "Invalid type: #{type}, must be one of: #{%i[computer mobile_device computer_group mobile_device_group].join ', '}"
      end
      raise ArgumentError, 'filter required if not using type and id' unless filter

      "#{STATUS_PATH}/?filter=#{CGI.escape filter}"
    end

  Jamf::OAPISchemas::ManagedSoftwareUpdateStatuses.new(cnx.jp_get(get_path)).results
end