Class: Jamf::JPackage

Inherits:
OAPISchemas::Package show all
Extended by:
Filterable
Includes:
ChangeLog, CollectionResource
Defined in:
lib/jamf/api/jamf_pro/api_objects/j_package.rb

Overview

A Package in the Jamf Pro API

Constant Summary collapse

SEARCH_RESULT_OBJECT =

The OAPI object class we get back from a ‘list’ query to get the whole collection, or a subset of it. It contains a :results key which is an array of data for objects of the parent class.

Jamf::OAPISchemas::PackagesSearchResults
POST_OBJECT =

The OAPI object class we send with a POST request to make a new member of the collection in Jamf. This is usually the same as the parent class.

Jamf::OAPISchemas::Package
PUT_OBJECT =

The OAPI object class we send with a PUT request to change an object in Jamf by specifying all its values. Most updates happen this way, and this is usually the same as the parent class

Jamf::OAPISchemas::Package
LIST_PATH =

The path for GETting the list of all objects in the collection, possibly filtered, sorted, and/or paged REQUIRED for all collection resources

GET_PATH, POST_PATH, PUT_PATH, PATCH_PATH, and DELETE_PATH are automatically assumed from the LIST_PATH if they follow the standards:

  • GET_PATH = “#LIST_PATH/id”

    • fetch an object from the collection

  • POST_PATH = LIST_PATH

    • create a new object in the collection

  • PUT_PATH = “#LIST_PATH/id”

    • update an object passing all its values back. Most objects use this or PATCH but not both

  • PATCH_PATH = “#LIST_PATH/id”

    • update an object passing some of its values back Most objects use this or PUT but not both

  • DELETE_PATH = “#LIST_PATH/id”

    • delete an object from the collection

If those paths differ from the standards, the constants must be defined here

'v1/packages'
ALT_IDENTIFIERS =

Identifiers not marked in the superclass’s OAPI_PROPERTIES constant which usually only identifies ‘:id’

%i[packageName fileName].freeze
OBJECT_NAME_ATTR =

If the object does not have a ‘name’ attribute, this is the attribute that holds its name. Used to allow referencing objects by ‘name’, creates a alias of the attribute called “name” and “name=”, and allows the use of “name:” as an identifier in the .fetch, .valid_id and similar methods.

:packageName
FILTER_KEYS =

Must define this when extending Filterable

%i[
  id fileName packageName categoryId info notes manifestFileName cloudTransferStatus
].freeze
UPLOAD_ENDPOINT =

the suffix for the REST resource for uploading a package

'upload'
DEFAULT_CATEGORY_ID =

Defaults for some required values

'-1'
DEFAULT_PRIORITY =
10
DEFAULT_FUT =
false
DEFAULT_REBOOT_REQUIRED =
false
DEFAULT_OS_INSTALL =
false
DEFAULT_SUPPRESS_UPDATES =
false
DEFAULT_SUPPRESS_FROM_DOCK =
false
DEFAULT_SUPPRESS_EULA =
false
DEFAULT_SUPPRESS_REGISTRATION =
false
CHECKSUM_HASH_TYPE_MD5 =

The hashType value in the API or manifests for md5

'MD5'
CHECKSUM_HASH_TYPE_SHA256 =

The hashType value in the API for sha256 - IF it exists?

'SHA_256'
CHECKSUM_HASH_TYPE_SHA256_MDM_DEPLOY =

The hashType value in MDM deploy manifests for sha256

'SHA256'
CHECKSUM_HASH_TYPE_SHA512 =

The hashType value in the API for sha512

'SHA_512'
CHECKSUM_HASH_TYPES =

Mapping of the hash types to the maching Digest modules See calculate_checksum

{
  CHECKSUM_HASH_TYPE_MD5 => Digest::MD5,
  CHECKSUM_HASH_TYPE_SHA256 => Digest::SHA256,
  CHECKSUM_HASH_TYPE_SHA512 => Digest::SHA512
}.freeze
DEFAULT_CHECKSUM_HASH_TYPE =
CHECKSUM_HASH_TYPE_SHA512
MANIFEST_FILENAME_DEFAULT_SUFFIX =

if no manifest filename is provided, this suffix will be appended to the fileName, with spaces converted to dashes.

'-manifest.plist'
MANIFEST_BUNDLE_ID_PREFIX =

If no manifest bundle identifier is provided, this will be used before the packageName.

'com.pixar.ruby-jss.'
MANIFEST_BUNDLE_VERSION_DEFAULT =

if no manifest bundle version is provided, this will be used.

'0'
MANIFEST_CHUNK_SIZE =

Not doing chunking by default in generated manifests, but if we do, we’ll use this

1024 * 1024 * 10
MANIFEST_PLIST_TEMPLATE =

10MB

{
  items: [
    {
      assets: [
        {
          'kind' => 'software-package',
          'sha256s' => [],
          'url' => 'url-goes-here'
        } # end hash
      ], # end assets array,
      metadata: {
        'kind' => 'software',
        'bundle-identifier' => "#{MANIFEST_BUNDLE_ID_PREFIX}example",
        'bundle-version' => MANIFEST_BUNDLE_VERSION_DEFAULT,
        'title' => 'title',
        'sizeInBytes' => 1,
        'sha256-whole' => 'sha256-goes-here'
      } # end metadata
    } # end hash
  ] # end items array
}.freeze
DEPLOYMENT_ENDPOINT =

The endpoint for deploying a package via MDM see developer.jamf.com/jamf-pro/reference/post_v1-deploy-package

'/v1/deploy-package?verbose=true'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(**data) ⇒ JPackage

Make an instance. Data comes from the API

Parameters:

  • data (Hash)

    the data for constructing a new object.



325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
# File 'lib/jamf/api/jamf_pro/api_objects/j_package.rb', line 325

def initialize(**data)
  super

  # set defaults for some required values
  #
  # check for explicit nils, since if these are boolean false
  # we don't want to change them.

  self.categoryId = DEFAULT_CATEGORY_ID if categoryId.nil?
  self.priority = DEFAULT_PRIORITY if priority.nil?
  self.fillUserTemplate = DEFAULT_FUT if fillUserTemplate.nil?
  self.rebootRequired = DEFAULT_REBOOT_REQUIRED if rebootRequired.nil?
  self.osInstall = DEFAULT_OS_INSTALL if osInstall.nil?
  self.suppressUpdates = DEFAULT_SUPPRESS_UPDATES if suppressUpdates.nil?
  self.suppressFromDock = DEFAULT_SUPPRESS_FROM_DOCK if suppressFromDock.nil?
  self.suppressEula = DEFAULT_SUPPRESS_EULA if suppressEula.nil?
  self.suppressRegistration = DEFAULT_SUPPRESS_REGISTRATION if suppressRegistration.nil?

  @checksum =
    case hashType
    when CHECKSUM_HASH_TYPE_MD5
      md5 || hashValue
    when CHECKSUM_HASH_TYPE_SHA256
      sha256 || hashValue
    when CHECKSUM_HASH_TYPE_SHA512
      hashValue
    end
end

Instance Attribute Details

#checksumString (readonly)

Checksums

Packages in Jamf Pro can have a checksum in either MD5 or SHA512, or possibly SHA256 - none of our 1500 pkgs have 256, but given the existence of the sha256 attribute in the API data, I’m assuming it existed at some point, and behaves like md5 (read on)

In all cases, the hashType attribute indicates the type of checksum, as a string, one of ‘MD5’, ‘SHA_256’, or ‘SHA_512’.

In the case of md5 and sha256, the actual digest value (the checksum) is in the ‘md5’ or ‘sha256’ attribute. In the case of sha512, the digest is in the ‘hashValue’ attribute. In anycase, the digest value will also be stored in the checksum attribute

NOTE: This is the checksum used when installing via a Policy. The checksum(s) used when deploying via MDM is stored in the manifest.

Returns:

  • (String)

    the checksum of the package, either an MD5, SHA256, or SHA512 digest of the package file.



284
285
286
# File 'lib/jamf/api/jamf_pro/api_objects/j_package.rb', line 284

def checksum
  @checksum
end

#cnxJamf::Connection (readonly) Originally defined in module JPAPIResource

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

Returns:

  • (Jamf::Connection)

    the API connection thru which we deal with this resource.

#delete_pathString (readonly) Originally defined in module CollectionResource

Returns The path for deleting a this item from the collection in the JPAPI.

Returns:

  • (String)

    The path for deleting a this item from the collection in the JPAPI

#deploy_responseHash (readonly)

The response body of the last mdm-deploy of this package. see #deploy_via_mdm

{
  "queuedCommands": [
    {
      "device": 1,
      "commandUuid": "aaaaaaaa-3f1e-4b3a-a5b3-ca0cd7430937"
    }
  ],
  "errors": [
    {
      "device": 2,
      "group": 3,
      "reason": "Device does not support the InstallEnterpriseApplication command"
    }
  ]
}

Returns:

  • (Hash)

    the response body of the last mdm-deploy of this package



316
317
318
# File 'lib/jamf/api/jamf_pro/api_objects/j_package.rb', line 316

def deploy_response
  @deploy_response
end

#get_pathString (readonly) Originally defined in module JPAPIResource

Returns The path for fetching this thing from the JPAPI

this gets set in the constructor in the CollectionResource or SingletonResource mixins.

Returns:

  • (String)

    The path for fetching this thing from the JPAPI

    this gets set in the constructor in the CollectionResource or SingletonResource mixins

#post_pathString (readonly) Originally defined in module CollectionResource

Returns The path for creating a new item in the collection in the JPAPI.

Returns:

  • (String)

    The path for creating a new item in the collection in the JPAPI

#update_pathString (readonly) Originally defined in module JPAPIResource

Returns The path for updating this thing from the JPAPI

this gets set in the constructor in the CollectionResource or SingletonResource mixins

We use ‘update_path’ because some items are updated via a PUT_PATH and others via a PATCH_PATH. When this gets set, it will contain the appropriate one.

Returns:

  • (String)

    The path for updating this thing from the JPAPI

    this gets set in the constructor in the CollectionResource or SingletonResource mixins

    We use ‘update_path’ because some items are updated via a PUT_PATH and others via a PATCH_PATH. When this gets set, it will contain the appropriate one.

#upload_responseHash (readonly)

The response body of the last upload of this package, with a timestamp added. Looks like:

{
  :id=>"10392",
  :href=>"https://casper-int.pixar.com:8443/api/v1/packages/10392/upload/10392"
  :time=>2025-09-01 12:00:00 -0700
}

see #upload

Returns:

  • (Hash)

    the response body of the last upload of this package



295
296
297
# File 'lib/jamf/api/jamf_pro/api_objects/j_package.rb', line 295

def upload_response
  @upload_response
end

Class Method Details

.calculate_checksum(filepath, type = DEFAULT_CHECKSUM_HASH_TYPE) ⇒ String

Given a file path, and hash type, generate the checksum for an arbitrary file.

Parameters:

  • filepath (String, Pathname)

    The file to checksum

  • type (String) (defaults to: DEFAULT_CHECKSUM_HASH_TYPE)

    One of the keys of CHECKSUM_HASH_TYPES, either CHECKSUM_HASH_TYPE_MD5 or CHECKSUM_HASH_TYPE_SHA512

Returns:

  • (String)

    The checksum of the file

Raises:

  • (ArgumentError)


211
212
213
214
215
# File 'lib/jamf/api/jamf_pro/api_objects/j_package.rb', line 211

def self.calculate_checksum(filepath, type = DEFAULT_CHECKSUM_HASH_TYPE)
  raise ArgumentError, 'Unknown checksum hash type' unless CHECKSUM_HASH_TYPES.key? type

  CHECKSUM_HASH_TYPES[type].file(filepath).hexdigest
end

.default_manifest_base_urlString

Getter for the default base URL for package manifests. This will be the one set for the class for this ruby session, or the one set in the Jamf.config.package_manifest_base_url seealso default_manifest_base_url=

Returns:

  • (String)

    the default base URL for building manifests



257
258
259
# File 'lib/jamf/api/jamf_pro/api_objects/j_package.rb', line 257

def self.default_manifest_base_url
  @default_manifest_url || Jamf.config.package_manifest_base_url
end

.default_manifest_base_url=(url) ⇒ void

This method returns an undefined value.

Setter for a default base URL for package manifests. Manifests are required for packages deployed via enrollment prestages or via the InstallEnterpriseApplication MDM command.

When generating a manifest for a package, you must provide a URL from which the package can be downloaded. This is usually from your Cloud Distribution Point, but can be some other https web server.

If Jamf.config.package_manifest_base_url is defined (see Configuration) then that will be used as the default. Otherwise, or if you wish to override the config, the value set here will be used as the default for generating manifests for all Jamf::JPackage objects in this ruby session.

Setting this in the config or here means you don’t have to provide a base URL each time when calling #generate_manifest or #upload, however you can still provide one at that time to override any default.

Normally, the package’s fileName is appended to this URL to generate the full download URL. E.g. for a package with a fileName ‘my-app.pkg’, with the base URL of ‘my-cdp.myorg.com’, the download URL in the manifest would be ‘my-cdp.myorg.com/my-app.pkg

See #generate_manifest for more info.

Parameters:

  • url (String)

    the default base URL for building manifests, overrides any value in the config.



246
247
248
# File 'lib/jamf/api/jamf_pro/api_objects/j_package.rb', line 246

def self.default_manifest_base_url=(url)
  @default_manifest_url = url.to_s
end

.filter_keysObject Originally defined in module Filterable

Instance Method Details

#add_change_log_note(note) ⇒ Object Originally defined in module ChangeLog

Instance Methods

wrappers for the class methods, which pass the id and cnx should work on Singleton Resources since @id will be nil but @cnx will be set.

#change_log(sort: nil, filter: nil) ⇒ Object Originally defined in module ChangeLog

#change_log_countObject Originally defined in module ChangeLog

#change_log_pager(page_size: Jamf::Pager::DEFAULT_PAGE_SIZE, sort: nil, filter: nil) ⇒ Object Originally defined in module ChangeLog

#checksum_valid?(filepath) ⇒ Boolean

Returns Does the checksum of the file match the checksum in the object? nil if there is no checksum in the object.

Parameters:

  • filepath (String, Pathname)

    the path to a local copy of the package file

Returns:

  • (Boolean)

    Does the checksum of the file match the checksum in the object? nil if there is no checksum in the object.



415
416
417
418
419
# File 'lib/jamf/api/jamf_pro/api_objects/j_package.rb', line 415

def checksum_valid?(filepath)
  return unless checksum

  self.class.calculate_checksum(filepath, hashType) == checksum
end

#default_manifestFileNameString

Returns A default if none is set explicitly.

Returns:

  • (String)

    A default if none is set explicitly



423
424
425
# File 'lib/jamf/api/jamf_pro/api_objects/j_package.rb', line 423

def default_manifestFileName
  "#{fileName.gsub(' ', '-')}#{MANIFEST_FILENAME_DEFAULT_SUFFIX}"
end

#deleteObject Originally defined in module CollectionResource

#deploy_via_mdm(computer_ids: nil, group_id: nil, managed: false) ⇒ Hash

Deploy this package to computers or a group via MDM.

REQUIREMENTS:

  • The package must have a manifest with specific data. See #manifest= and #generate_manifest for details.

  • The .pkg file must be a product archive (.pkg) built with Xcode or productbuild. (it must contain a ‘Distribution’ file, usually generated by those tools) Simple ‘component’ packages built with pkgbuild are not supported.

  • The .pkg file must be signed with a trusted signing certificate

This will send an MDM InstallEnterpriseApplication command to install the package to one or more computers, and/or the members of a single computer group.

Parameters:

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

    The ids of the computers to deploy to

  • group_id (Integer) (defaults to: nil)

    The id of the computer group to deploy to

  • managed (Boolean) (defaults to: false)

    Should the installed package be managed by Jamf Pro? Defaults to false. This seems to be for App Store apps only??

Returns:

  • (Hash)

    the response from the server. see #deploy_response

Raises:

  • (ArgumentError)


789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
# File 'lib/jamf/api/jamf_pro/api_objects/j_package.rb', line 789

def deploy_via_mdm(computer_ids: nil, group_id: nil, managed: false)
  raise ArgumentError, 'No computer_ids or group_id provided' unless computer_ids || group_id
  raise Jamf::MissingDataError, 'No manifest set for this package' if manifest.to_s.empty?
  raise Jamf::NoSuchItemError, 'This package has no id, it must be saved in Jamf Pro before uploading' unless exist?

  # convert the full manifest to a ruby hash
  parsed_manifest = manifest_hash

  # manifest data for the MDMDeploy command, which is a hash.
  # hopefully some day Jamf will just use the manifest for the pkg
  mdm_manifest = {}
  mdm_manifest['url'] = manifest_url_for_deployment(parsed_manifest)
  mdm_manifest['hash'], mdm_manifest['hashType'] = manifest_checksum_for_deployment(parsed_manifest)
  mdm_manifest['bundleId'] = manifest_bundle_identifier_for_deployment(parsed_manifest)
  mdm_manifest['bundleVersion'] = manifest_bundle_version_for_deployment(parsed_manifest)
  mdm_manifest['title'] = manifest_title_for_deployment(parsed_manifest)
  mdm_manifest['sizeInBytes'] = manifest_size_for_deployment(parsed_manifest)

  set_optional_mdm_manifest_values(parsed_manifest, mdm_manifest)

  # make sure the computers are in an array
  computer_ids = [computer_ids].flatten.compact.uniq

  # make the payload
  payload = {
    manifest: mdm_manifest,
    installAsManaged: managed,
    devices: computer_ids
  }
  payload[:groupId] = group_id.to_s if group_id

  # send the command
  @deploy_response = cnx.post(DEPLOYMENT_ENDPOINT, payload)
end

#exist?Boolean Originally defined in module CollectionResource

Returns:

  • (Boolean)

#generate_manifest(filepath, **opts) ⇒ void

This method returns an undefined value.

Generate a manifest plist (xml) for this package from a local .pkg file, and update the #manifest and #manifestFileName attributes

Afterwards, you will need to call #save on the object to save the new values to the server.

See also #manifest= for setting the manifest from a file or string.

The download URL used in the manifest will be the default for the class (if you have set one) usually with the fileName appended. The class default may come from the ruby-jss config, or be set directly on the class, see JPackage.default_manifest_base_url=

Unless set explicitly afterward using #manifestFileName= the manifest filename will be the fileName of the Package object, with spaces converted to dashes, followed by MANIFEST_FILENAME_DEFAULT_SUFFIX. e.g. my-app.pkg-manifest.plist

By default, this method is invoked when uploading the pkg file using #upload and the opts will be passed from that method to this one. When invoked from #upload, the new values will be saved to the Jamf Pro server automatically.

The manifests generated by this method are suitable for use in MDM deployments.

If you don’t provide a bundle_identifier, it will be generated from the packageName, prefixed with ‘com.pixar.ruby-jss.’ and with spaces converted to dashes.

If you don’t provide a bundle_version, it will be ‘0’

Parameters:

  • filepath (String, Pathname)

    the path to a local copy of the package file for which this manifest is being generated. This MUST match the one uploaded to the server, as it is used to calculate the checksums in the manifest.

  • opts (Hash)

    a hash of keyword arguments

Options Hash (**opts):

  • append_filename_to_url (Boolean)

    should the fileName be appended to the URL, defaults to true. If false, the url given must be the full URL to download the individual package file.

  • chunk_size (Integer)

    the size of each chunk in the manifest, in bytes. If omitted, the whole file will be checksummed at once and downloads will not be chunked. A common chunk size is 10MB, or 1024 * 1024 * 10. NOTE: Not all distribution points support chunked downloads.

  • bundle_identifier (String, Symbol)

    The bundle identifier of the package, Should match that in the .pkg itself. Defaults to ‘com.pixar.ruby-jss.packageName’ where packageName is the packageName with whitespace converted to dashes.

  • bundle_version (String)

    the version of the package. Defaults to ‘0’

  • subtitle (String)

    a subtitle for the package, optional

  • full_size_image_url (String)

    optional, used during MDM deployment

  • display_image_url (String)

    optional, used during MDM deployment



556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
# File 'lib/jamf/api/jamf_pro/api_objects/j_package.rb', line 556

def generate_manifest(filepath, **opts)
  # make sure the file exists
  file = Pathname.new(filepath)
  validate_local_file(file)

  filesize = file.size

  # make the manifest
  new_manifest = MANIFEST_PLIST_TEMPLATE.dup

  url = build_manifest_url opts[:url], append_filename: opts[:append_filename_to_url]

  new_manifest[:items][0][:assets][0]['url'] = url.to_s

  # get the checksum(s)
  calculate_manifest_checksums(file, new_manifest, chunk_size: opts[:chunk_size])

  append_manifest_image('full-size-image', opts[:full_size_image_url], new_manifest) if opts[:full_size_image_url]

  append_manifest_image('display-image', opts[:display_image_url], new_manifest) if opts[:display_image_url]

  new_manifest[:items][0][:metadata]['title'] = packageName
  new_manifest[:items][0][:metadata]['subtitle'] = opts[:subtitle] if opts[:subtitle]
  new_manifest[:items][0][:metadata]['sizeInBytes'] = filesize
  new_manifest[:items][0][:metadata]['bundle-identifier'] =
    (opts[:bundle_identifier] || "#{MANIFEST_BUNDLE_ID_PREFIX}#{packageName.gsub(/\s+/, '-')}")
  new_manifest[:items][0][:metadata]['bundle-version'] = opts[:bundle_version] if opts[:bundle_version]

  plist = CFPropertyList::List.new
  plist.value = CFPropertyList.guess(new_manifest)
  self.manifest = plist.to_str(CFPropertyList::List::FORMAT_XML, formatted: true)

  self.manifestFileName = default_manifestFileName
end

#history_pathObject Originally defined in module ChangeLog

#manifest=(new_manifest) ⇒ void

This method returns an undefined value.

Set the manifest from a local file or a String containing an XML plist. If from a file, the manifestFileName attribute is set to the filename

To automatically generate a manifest plist for this package from a locally-readable .pkg file, use #generate_manifest

All manifests require a valid URL for downloading the .pkg file when installing on a client.

No validation of the manifest is done here.

DEPLOYING VIA MDM:

When using this method, if you want to be able to deploy the package using deploy_via_mdm, the manifest MUST include a metadata dictionary with at least the following keys:

- 'kind' = 'software'
- 'bundle-identifier' that preferably matches the bundle identifier of the pkg
- 'bundle-version' = that preferably matches the version of the pkg
- 'title' = the name of the pkg or what it installs
- 'sizeInBytes' = the size of the .pkg in bytes

as well as one of these non-standard keys:

- 'sha256-whole' = the SHA256 digest of the whole file, regardless of chunking data in the 'assets' array

OR

- 'md5-whole' = the MD5 digest of the whole file, regardless of chunking data in the 'assets' array

The non-standard keys are because the Jamf Pro API endpoint for deploying via MDM requires a whole-file checksum even if the file is chunked in the manifest.

See the MANIFEST_PLIST_TEMPLATE constant for an example of the data structure (as a ruby hash, not a plist)

Parameters:

  • new_manifest (String, Pathname)

    the manifest plist data or path to a local file



462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
# File 'lib/jamf/api/jamf_pro/api_objects/j_package.rb', line 462

def manifest=(new_manifest)
  # if its a string but not an xml plist, assume its a path
  new_manifest = Pathname.new(new_manifest) if new_manifest.is_a?(String) && !new_manifest.start_with?('<?xml')
  orig_manifest = manifest

  new_xml =
    if new_manifest.is_a? Pathname
      new_manifest.read

    elsif new_manifest.is_a? String
      new_manifest

    else
      raise ArgumentError, 'Argument must be a Pathname, or a String containing a path or an XML plist'
    end

  @manifest = new_xml
  note_unsaved_change :manifest, orig_manifest
end

#manifest_hashHash

return the manifest as a ruby hash converted from the plist IMPORTANT: all hash keys are strings, not symbols

Returns:

  • (Hash)

    the manifest as a ruby hash



487
488
489
490
491
# File 'lib/jamf/api/jamf_pro/api_objects/j_package.rb', line 487

def manifest_hash
  return if manifest.to_s.empty?

  CFPropertyList.native_types(CFPropertyList::List.new(data: manifest).value)
end

#osRequirements=(new_val) ⇒ void

This method returns an undefined value.

Change the os_requirements field in the JSS E.g. 10.5, 10.5.3, 10.6.x

Extra feature: Minumum OS’s can now be specified as a string using the notation “>=10.6.7”.

Parameters:

  • new_val (String, Array<String>)

    comma-separated string, or array of os versions

See Also:

  • Jamf.expand_min_os


376
377
378
379
380
381
382
383
384
385
386
# File 'lib/jamf/api/jamf_pro/api_objects/j_package.rb', line 376

def osRequirements=(new_val)
  # make sure we have an array
  new_val = [new_val].flatten.compact.uniq.map(&:to_s)
  new_val.map! do |vers|
    vers.start_with?('>=') ? Jamf.expand_min_os(vers) : vers
  end

  orig_osRequirements = osRequirements
  @osRequirements = new_val.join(', ')
  note_unsaved_change :osRequirements, orig_osRequirements
end

#pretty_print_instance_variablesArray Originally defined in module JPAPIResource

Remove large cached items from the instance_variables used to create pretty-print (pp) output.

Returns:

  • (Array)

    the desired instance_variables

#recalculate_checksum(filepath) ⇒ String

Recalculate the checksum of the package file from a given filepath, and update the object’s checksum and hashValue attributes.

NOTE: This updates the checksum used when installing via a Policy. The checksum(s) used when deploying via MDM is stored in the manifest.

You will need to call #save on the object to save the new checksum to the server.

New checksums are always SHA512

Parameters:

  • filepath (String, Pathname)

    the path to a local copy of the package file

Returns:

  • (String)

    The new checksum of the package file



402
403
404
405
406
407
408
409
# File 'lib/jamf/api/jamf_pro/api_objects/j_package.rb', line 402

def recalculate_checksum(filepath)
  # update the checksum
  @checksum = self.class.calculate_checksum(filepath, DEFAULT_CHECKSUM_HASH_TYPE)
  self.hashType = DEFAULT_CHECKSUM_HASH_TYPE
  self.sha256 = nil
  self.md5 = nil
  self.hashValue = @checksum
end

#receiptPathname

Returns the local receipt when this pkg is installed by a policy.

Returns:

  • (Pathname)

    the local receipt when this pkg is installed by a policy



359
360
361
362
# File 'lib/jamf/api/jamf_pro/api_objects/j_package.rb', line 359

def receipt
  # the receipt is the filename with any .zip extension removed.
  fileName ? (Jamf::Client::RECEIPTS_FOLDER + fileName.to_s.sub(/.zip$/, '')) : nil
end

#saveObject Originally defined in module JPAPIResource

TODO: error handling

#to_sString Originally defined in module CollectionResource

A meaningful string representation of this object

Returns:

#upload(filepath, **opts) ⇒ void

This method returns an undefined value.

Upload a package file to Jamf Pro.

WARNING: This will automatically call #save, saving any pending changes to the Jamf Pro server!

This uses the Jamf Pro API to upload the file via the package/upload endpoint. If you don’t use an appropriate primary distribution point, this may not work. Also, that endpoint may not upload to any other distribution points.

The fileName attribute of the JPackage object will be updated to the local filename. If that filename is in use by some other package, you’ll get an error:

Field: fileName, Error: DUPLICATE_FIELD duplicate name

This will automatically call #save at least once, and possibly twice. First, in order to ensure the correct fileName in Jamf based on the file being uploaded, and second, in order to update the checksum and manifest in Jamf Pro, if needed. *** Any other outstanding changes will also be saved!

After uploading, the response from the server is in the #upload_response attribute, with a timestamp added to the data from the API.

Parameters:

  • filepath (String, Pathname)

    the path to the package file to upload

  • opts (Hash)

    a hash of keyword arguments

Options Hash (**opts):

  • :update_checksum (Boolean)

    update the checksum of the package in Jamf Pro. Defaults to true. All new checksums are SHA_512. WARNING: If you set this to false, the checksum in the object will not be updated and installs may fail. Be sure to set it to the correct value yourself.

  • :update_manifest (Boolean)

    update the manifest of the package in Jamf Pro Defaults to true. WARNING: If you set this to false, the manifest in the object will not be updated and PreStage & MDM deployments may fail. Be sure to set it to the correct value using #generate_manifest or #manifest= yourself.

  • append_filename_to_url (Boolean)

    See #generate_manifest

  • chunk_size (Integer)

    See #generate_manifest

  • bundle_identifier (String)

    See #generate_manifest

  • bundle_version (String)

    See #generate_manifest

  • subtitle (String)

    See #generate_manifest

  • full_size_image_url (String)

    See #generate_manifest

  • display_image_url (String)

    See #generate_manifest



737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
# File 'lib/jamf/api/jamf_pro/api_objects/j_package.rb', line 737

def upload(filepath, **opts)
  file = Pathname.new(filepath)
  validate_local_file(file)

  # update the filename if needed
  # must happen before the upload so it matches the file being uploaded
  self.fileName = file.basename.to_s

  # We must save the checksum and manifest to the server before uploading
  # the file, because otherwise jamf will likely overwrite the manifest
  # after it uploads to the primary distribution point.

  # recalulate the checksum unless told no to
  # NOTE: It appears that the checksum will always be recaluclated by
  # the Jamf Pro server, as MD5. If you really want our default SHA512,
  # then do this again later, manually.
  recalculate_checksum(file) unless opts[:update_checksum] == false

  # generate a manifest using the new file
  generate_manifest(file, **opts) unless opts[:update_manifest] == false

  # save the new fileName, checksum and manifest
  save

  # upload the file
  @upload_response = cnx.jp_upload("#{get_path}/#{UPLOAD_ENDPOINT}", file)
  @upload_response[:time] = Time.now
  @upload_response
end