Module: Xolo::Server::Mixins::VersionJamfAccess

Included in:
Version
Defined in:
lib/xolo/server/mixins/version_jamf_access.rb

Overview

This is mixed in to Xolo::Server::Version to define Version-related access to the Jamf Pro server

Constant Summary collapse

JAMF_SMART_GROUP_NAME_INSTALLED_SFX =

The group of macs with this version installed is named the full prefix plus this suffix.

'installed'
JAMF_POLICY_NAME_MANUAL_INSTALL_SFX =

The policy that does initial installs on-demand (via ‘xolo install <title> <version’) is named the full prefix plus this suffix.

'manual-install'
JAMF_POLICY_NAME_AUTO_INSTALL_SFX =

The policy that does auto-installs is named the full prefix plus this suffix. The scope is changed as needed when a version’s status changes

'auto-install'
JAMF_POLICY_NAME_AUTO_REINSTALL_SFX =

The policy that does auto-re-installs is named the full prefix plus this suffix. The scope is changed as needed when a version’s status changes

'auto-reinstall'

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.extended(extender) ⇒ Object

when this module is extended



165
166
167
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 165

def self.extended(extender)
  Xolo.verbose_extend extender, self
end

.included(includer) ⇒ Object

when this module is included



160
161
162
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 160

def self.included(includer)
  Xolo.verbose_include includer, self
end

Instance Method Details

#activate_managed_patch_version_in_jamfvoid

This method returns an undefined value.

Wait until the version is visible from the title editor then assign the pkg to it in Jamf Patch, and create the patch policy.

Do this in a thread so the xadm user doesn’t wait up to ?? minutes.



1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 1258

def activate_managed_patch_version_in_jamf
  # don't do this if there's already one running for this instance
  if @activate_patch_version_thread&.alive?
    log_debug "Jamf: activate_patch_version_thread already running. Caller: #{caller_locations.first}"
    return
  end

  msg = "Jamf: Will assign Jamf pkg '#{jamf_pkg_name}' and create the patch policy when this version becomes visible to Jamf Pro from the Title Editor."
  progress msg, log: :debug

  @activate_patch_version_thread = Thread.new do
    log_debug "Jamf: Starting activate_patch_version_thread waiting for version #{version} of title #{title} to become visible from the title editor"

    start_time = Time.now
    max_time = start_time + Xolo::Server::MAX_JAMF_WAIT_FOR_TITLE_EDITOR
    start_time = start_time.strftime '%F %T'

    did_it = false

    while Time.now < max_time
      sleep 15
      log_debug "Jamf: checking for version #{version} of title #{title} to become visible from the title editor since #{start_time}"

      # check for the existence of the jamf_patch_title every time, since it might have gone away
      # if the title was deleted while this was happening.
      next unless title_object.jamf_patch_title(refresh: true) && title_object.jamf_patch_title.versions.key?(version)

      did_it = true
      break
    end

    if did_it
      activate_patch_version_in_jamf
      msg = "Jamf: Version '#{version}' of title '#{title}' is now visible in Jamf Pro. Package assigned and Patch policy created."
      log_info msg, alert: true
    else
      msg = "Jamf: ERROR: Version '#{version}' of title '#{title}' has not become visible from the Title Editor in over #{Xolo::Server::MAX_JAMF_WAIT_FOR_TITLE_EDITOR} seconds. The package has not been assigned, and no patch policy was created."
      log_error msg, alert: true
    end
  end # thread
  @activate_patch_version_thread.name = "activate_patch_version_thread-#{title}-#{version}"
end

#activate_patch_version_in_jamfvoid

This method returns an undefined value.

Assign the package for this version to the Jamf::PatchTitle::Version in Jamf and create the patch policy for this version.



1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 1315

def activate_patch_version_in_jamf
  log_debug "Jamf: Activating patch version in Jamf for version '#{version}' of title '#{title}'"

  # create the Jamf::JPackage object if needed
  jamf_package
  title_object.jamf_patch_title(refresh: true)
  sleep 3

  assign_pkg_to_patch_in_jamf
  # give jamf a moment to catch up and refresh the patch title
  # so we see the pkg has been assigned
  sleep 2
  title_object.jamf_patch_title(refresh: true)

  create_jamf_patch_policy
end

#activate_subscribed_patch_version_in_jamfObject

Patches for subscribed titles are already visible in Jamf Patch Management So we just need to assign the pkg to the patch version, and create the patch policy.



1304
1305
1306
1307
1308
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 1304

def activate_subscribed_patch_version_in_jamf
  msg = "Jamf: Assigning package and creating patch policy for version '#{version}' of subscribed title '#{title}'"
  log_info msg
  activate_patch_version_in_jamf
end

#assign_pkg_to_patch_in_jamfvoid

This method returns an undefined value.

Assign the Package to the Jamf::PatchTitle::Version for this Xolo version. This ‘activates’ the version in Jamf Patch, and must happen before patch policies can be created

Jamf::PatchTitle::Version objects are contained in the matching Jamf::PatchTitle, and to make or save changes, we have to fetch the title, update the version, and save the title.

NOTE: This can’t happen until Jamf see’s the version in the title editor otherwise you’ll get an error. The methods that call this should ensure the version is visible.



1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 1346

def assign_pkg_to_patch_in_jamf
  patch_vers_obj = jamf_patch_version

  if patch_vers_obj.nil? && repairing?
    msg = "Jamf: Cant re-assign package '#{jamf_pkg_name}' to patch version '#{version}' of title '#{title}' at this time. If there are problems with it, try 'repair' again later."
    progress msg, log: :info
    return
  end

  progress "Jamf: Assigning package '#{jamf_pkg_name}' to patch version '#{version}' of title '#{title}'", log: :info

  log_debug "Jamf: jamf_patch_version is: #{patch_vers_obj}"

  patch_vers_obj.package = jamf_pkg_name
  log_debug "Jamf: jamf_patch_version after assignment is: #{patch_vers_obj}"

  title_object.jamf_patch_title.save
  log_debug 'Jamf: Saved jamf_patch_title after assigning package to version.'
end

#configure_jamf_auto_install_policy(pol = nil) ⇒ Object

Configure the given policy as the auto-install policy for this version

Parameters:

  • pol (Jamf::Policy) (defaults to: nil)

    the policy to configure



542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 542

def configure_jamf_auto_install_policy(pol = nil)
  pol ||= jamf_auto_install_policy

  pol.category = Xolo::Server::JAMF_XOLO_CATEGORY
  pol.set_trigger_event :checkin, true
  pol.set_trigger_event :custom, Xolo::BLANK
  pol.frequency = :once_per_computer
  pol.retry_event = :checkin
  pol.retry_attempts = 5
  pol.recon = false

  pol.package_names.each { |pkg_name| pol.remove_package pkg_name }
  pol.add_package jamf_pkg_name

  # exclusions are for always
  set_policy_exclusions pol

  # set the scope targets based on status
  if pilot?
    set_policy_pilot_groups pol
  else
    set_policy_release_groups pol
  end

  # enable or disable based on status
  if pilot? || released? || releasing?
    pol.enable
  else
    pol.disable
  end
end

#configure_jamf_auto_reinstall_policy(pol) ⇒ Object

Set the proper config for the auto reinstall policy

Parameters:

  • pol (Jamf::Policy)

    the policy to configure



817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 817

def configure_jamf_auto_reinstall_policy(pol)
  # this creates the installed group if it doesn't already exist
  jamf_installed_group

  pol.category = Xolo::Server::JAMF_XOLO_CATEGORY
  pol.set_trigger_event :checkin, true
  pol.set_trigger_event :custom, Xolo::BLANK
  pol.frequency = :once_per_computer
  pol.recon = false
  pol.retry_event = :checkin
  pol.retry_attempts = 5
  pol.scope.set_targets :computer_groups, [jamf_installed_group.name]

  # exclusions are for always
  set_policy_exclusions pol

  pol.package_names.each { |pkg_name| pol.remove_package pkg_name }
  pol.add_package jamf_pkg_name

  # NOTE: this policy is not enabled by default - it will be enabled
  # if/when the pkg for the policy is re-uploaded
  pol.enable if reupload_date.is_a? Time
end

#configure_jamf_installed_group(grp) ⇒ void

This method returns an undefined value.

Set the configuration of the given smart group as needed for the jamf_installed_group

Parameters:

  • grp (Jamf::ComputerGroup)

    the group to configure



734
735
736
737
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 734

def configure_jamf_installed_group(grp)
  progress "Jamf: Setting criteria for smart group '#{grp.name}'", log: :info
  grp.criteria = Jamf::Criteriable::Criteria.new(jamf_installed_group_criteria)
end

#configure_jamf_manual_install_policy(pol) ⇒ Object

Configure the given policy as the manual-install policy for this version

Parameters:

  • pol (Jamf::Policy)

    the policy to configure



638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 638

def configure_jamf_manual_install_policy(pol)
  pol.category = Xolo::Server::JAMF_XOLO_CATEGORY
  pol.set_trigger_event :checkin, false
  pol.set_trigger_event :custom, jamf_manual_install_trigger
  pol.frequency = :ongoing
  pol.recon = false

  pol.package_names.each { |pkg_name| pol.remove_package pkg_name }
  pol.add_package jamf_pkg_name

  set_policy_to_all_targets pol
  set_policy_exclusions pol

  # These policies shouldn't be in ssvc
  # only the title's jamf_manual_install_released_policy is
  pol.remove_from_self_service if pol.in_self_service?
  pol.enable
end

#create_in_jamfObject

Create everything we need in Jamf



181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 181

def create_in_jamf
  # this will create the JPackage object
  jamf_package

  # The
  # - jamf_installed_group
  # - jamf_auto_reinstall_policy
  # aren't needed until there's a pkg re-upload
  # and they will be created then if they doesn't already exist

  # these will create the policies
  jamf_auto_install_policy
  jamf_manual_install_policy

  if subscribed?
    activate_subscribed_patch_version_in_jamf
  else
    activate_managed_patch_version_in_jamf
  end
end

#create_jamf_auto_install_policyJamf::Policy

The auto install policy is triggered by checkin but may have narrow scope targets, or may be targeted to ‘all’ (after release) Before release, the targets are those defined in #pilot_groups_to_use

After release, the targets are changed to those in title_object#release_groups

This policy is never in self service

Returns:

  • (Jamf::Policy)

    the auto install policy for this version



522
523
524
525
526
527
528
529
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 522

def create_jamf_auto_install_policy
  progress "Jamf: Creating Auto Install Policy: #{jamf_auto_install_policy_name}", log: :debug

  @jamf_auto_install_policy = Jamf::Policy.create name: jamf_auto_install_policy_name, cnx: jamf_cnx

  configure_jamf_auto_install_policy
  @jamf_auto_install_policy.save
end

#create_jamf_auto_reinstall_policyJamf::Policy

The auto rionstall policy, for when a pkg is re-uploaded for this version.

Returns:

  • (Jamf::Policy)

    the auto install policy for this version



797
798
799
800
801
802
803
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 797

def create_jamf_auto_reinstall_policy
  progress "Jamf: Creating Auto Re-Install Policy: #{jamf_auto_reinstall_policy_name}", log: :debug
  pol = Jamf::Policy.create name: jamf_auto_reinstall_policy_name, cnx: jamf_cnx
  configure_jamf_auto_reinstall_policy(pol)
  pol.save
  pol
end

#create_jamf_installed_groupJamf::ComputerGroup

Create the smart group of macs with this version installed

Returns:

  • (Jamf::ComputerGroup)

    the smart group.



703
704
705
706
707
708
709
710
711
712
713
714
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 703

def create_jamf_installed_group
  progress "Jamf: Creating smart group '#{jamf_installed_group_name}'", log: :info

  @jamf_installed_group = Jamf::ComputerGroup.create(
    name: jamf_installed_group_name,
    type: :smart,
    cnx: jamf_cnx
  )
  configure_jamf_installed_group @jamf_installed_group
  @jamf_installed_group.save
  @jamf_installed_group
end

#create_jamf_manual_install_policyObject

The manual install policy is always scoped to all computers, with exclusions

The policy has a custom trigger, or can be installed via self service



617
618
619
620
621
622
623
624
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 617

def create_jamf_manual_install_policy
  progress "Jamf: Creating Manual Install Policy: #{jamf_manual_install_policy_name}", log: :info

  pol = Jamf::Policy.create name: jamf_manual_install_policy_name, cnx: jamf_cnx
  configure_jamf_manual_install_policy(pol)
  pol.save
  pol
end

#create_jamf_packageJamf::JPackage

Returns Create the Jamf::JPackage object for this version and return it.

Returns:

  • (Jamf::JPackage)

    Create the Jamf::JPackage object for this version and return it



339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 339

def create_jamf_package
  progress "Jamf: Creating Jamf::JPackage '#{jamf_pkg_name}'", log: :info

  # The filename is temporary, and will be replaced when the file is uploaded
  pkg = Jamf::JPackage.create(
    cnx: jamf_cnx,
    packageName: jamf_pkg_name,
    fileName: "#{jamf_pkg_name}.pkg",
    rebootRequired: reboot,
    notes: jamf_package_notes,
    categoryId: jamf_xolo_category_id,
    osRequirements: ">=#{min_os}"
  )

  # TODO: Implement max_os, either here, or by maintaining a smart group?
  # I really wish jamf would improve how package objects handle
  # OS requirements, building in the concept of min/max

  self.jamf_pkg_id = pkg.save
  # save the data now so the pkg_id is available for immeadiate use, e.g. by pkg upload
  save_local_data
  pkg
rescue => e
  msg = "Jamf: Failed to create Jamf::JPackage '#{jamf_pkg_name}': #{e.class}: #{e}"
  log_error msg
  raise Xolo::ServerError, msg
end

#create_jamf_patch_policyJamf::PatchPolicy

Returns The xolo patch policy for this version.

Returns:

  • (Jamf::PatchPolicy)

    The xolo patch policy for this version



879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 879

def create_jamf_patch_policy
  progress "Jamf: Creating Patch Policy for Version '#{version}' of Title '#{title}'.", log: :info

  # TODO: decide how many patch policies - see comments at top
  # Probably one: for pilots initially and then rescoped to all for release
  #
  # TODO: How to set these, and should they be settable
  # at the Xolo::Title or  Xolo::Version level?
  #
  # allow downgrade? No, to start with.
  # When a version is released, IF we are rolling back, then this will be set.
  # This is to be set only on the current release and only when it was a rollback.
  #
  # patch_unknown_versions... yes?
  #
  # if not in ssvc:
  # - grace period?
  # - update warning Message and Subject
  #
  # if in ssvc:
  # - any way to use existing icon?
  # - use title desc... do we want a version desc??
  # - notifications?  Message and Subject? SSvc only, Notif Ctr?
  # - deadline and grace period message and subbject

  ppol = Jamf::PatchPolicy.create(
    cnx: jamf_cnx,
    name: jamf_patch_policy_name,
    patch_title: title_object.jamf_patch_title.id,
    target_version: version
  )

  # when first creating a patch policy, its status is always
  # 'pilot' so the scope targets are the pilot groups, if any.
  # When the version is released, the patch policy will be
  # rescoped to all targets (limited by eligibility)
  set_policy_pilot_groups ppol

  # exclusions are for always
  set_policy_exclusions ppol

  # This will be set to true as needed if
  # a rollback is being done
  ppol.allow_downgrade = false

  # This should default to false, so that
  # we don't accidentally downgrade non-xolo test installs,
  # or server-pushed updates (like with commvault or cisco VPN)
  ppol.patch_unknown = patch_unknown ? true : false

  ppol.enable

  ppol.save

  # refetch it rather than using the one we just created
  Jamf::PatchPolicy.fetch(name: jamf_patch_policy_name, cnx: jamf_cnx)
end

#delete_jamf_packagevoid

This method returns an undefined value.

Delete the package for this version from Jamf Pro. Package deletion takes a long time, so we do it in a threadpool and tell the admin to check the Alert Tool for completion (if we have an alert tool in place) or to wait at least 5 min before re-adding the same version.



449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 449

def delete_jamf_package
  pkg_id = jamf_pkg_id || Jamf::JPackage.valid_id(packageName: jamf_pkg_name, cnx: jamf_cnx)
  return unless pkg_id

  msg = "Jamf: Starting deletion of Package '#{jamf_pkg_name}' id #{jamf_pkg_id} at #{Time.now.strftime '%F %T'}"
  progress msg, log: :info

  warning = +"IMPORTANT: Package deletion can be slow. If you plan to re-add this version, '#{version}', please\n  "
  warning <<
    if Xolo::Server.config.alert_tool
      'check your Xolo alerts for completion, which can take up to 5 minutes,'
    else
      'wait at least 5 minutes'
    end
  warning << ' before re-adding this version.'

  progress warning, log: nil

  self.class.pkg_deletion_pool.post do
    start = Time.now
    log_info "Jamf: Started threadpool deletion of Package '#{jamf_pkg_name}' id #{jamf_pkg_id} at #{start}"
    jamf_cnx.timeout = 3600
    Jamf::JPackage.delete pkg_id, cnx: jamf_cnx
    finish = Time.now
    duration = (finish - start).to_i.pix_humanize_secs
    log_info "Jamf: Deleted Package '#{jamf_pkg_name}' id #{jamf_pkg_id} in #{duration}", alert: true
  rescue => e
    log_error "Package Deletion thread: #{e.class}: #{e}"
    e.backtrace.each { |l| log_error "..#{l}" }
  end
end

#delete_version_from_jamfvoid

This method returns an undefined value.

Delete an entire version from Jamf Pro This includes the package, the manual install policy, the auto install policy, and the patch policy.



252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 252

def delete_version_from_jamf
  log_debug "Deleting Version '#{version}' from Jamf"

  # The Policies
  pols = [
    jamf_manual_install_policy,
    jamf_auto_install_policy,
    jamf_auto_reinstall_policy,
    jamf_patch_policy
  ]
  pols.each do |pol|
    next unless pol

    progress "Jamf: Deleting #{pol.class} '#{pol.name}'", log: :info
    pol.delete
  end

  # The Installed Group
  if jamf_installed_group
    progress "Jamf: Deleting #{jamf_installed_group.class} '#{jamf_installed_group.name}'", log: :info
    jamf_installed_group.delete
  end

  # Delete package object
  # This is slow and it blocks, so do it in a thread and update progress every
  # 15 secs
  delete_jamf_package

  # The code below is used when we want real-time progress updates to xadm
  # while deletion is happening. It's slow, so we're not using it now.

  # msg = "Jamf: Starting deletion of Package '#{jamf_pkg_name}' id #{jamf_pkg_id} at #{Time.now.strftime '%F %T'}..."
  # progress msg, log: :debug

  # # do this in another thread, so we can report the progress while its happening
  # pkg_del_thr = Thread.new { Jamf::JPackage.fetch(packageName: jamf_pkg_name, cnx: jamf_cnx).delete }
  # pkg_del_thr.name = "package-deletion-thread-#{session[:xolo_id]}"
  # sleep 15
  # while pkg_del_thr.alive?
  #   progress "... #{Time.now.strftime '%F %T'} still deleting, this is slow, sorry."
  #   sleep 15
  # end

  # msg = "Jamf: Deleted Package '#{jamf_pkg_name}' id #{jamf_pkg_id} at  #{Time.now.strftime '%F %T'}"
  # progress msg, log: :debug
end

#deploy_via_mdm(targets) ⇒ Hash

Install this version on a one or more computers via MDM.

Parameters:

  • targets (Hash)

    With the following keys

    • computers: [Array<String, Integer>] The computer identifiers to install on. Identifiers are either serial numbers, names, or Jamf IDs.

    • groups: [Array<String, Integer>] The names or ids of computer groups to install on.

Returns:

  • (Hash)

    The results of the install with the following keys

    • removals: [Array<Hash>] { device: <String>, group: <InteStringger>, reason: <String> }

    • queuedCommands: [Array<Hash>] { device: <String>, commandUuid: <String> }

    • errors: [Array<Hash>] { device: <String>, group: <Integer>, reason: <String> }



1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 1389

def deploy_via_mdm(targets)
  unless dist_pkg
    raise Xolo::UnsupportedError,
          'MDM deployment is not supported for this version, it is not a Distribution Package.'
  end

  all_targets = targets[:computers] || []
  removals = []

  # expand groups into computers,
  all_targets += expand_groups_for_deploy(targets[:groups], removals) if targets[:groups]

  # remove duplicates
  all_targets.uniq!

  # remove invalid computers, after this all_targets will be valid computer ids
  remove_invalid_computers_for_deploy(all_targets, removals)

  # remove members of excluded groups from the list of targets
  remove_exclusions_from_deploy(all_targets, removals)

  if all_targets.empty?
    log_info "Jamf: No valid computers to deploy to for version '#{version}' of title '#{title}'."
    queued_cmds = []
    deploy_errs = []

  else
    # deploy the package to the computers
    jamf_package.deploy_via_mdm computer_ids: all_targets
    # convert ids to names for the response
    comp_ids_to_names = Jamf::Computer.map_all(:id, to: :name, cnx: jamf_cnx)

    queued_cmds = jamf_package.deploy_response[:queuedCommands].map do |qc|
      { device: comp_ids_to_names[qc[:device]], commandUuid: qc[:commandUuid] }
    end

    deploy_errs = jamf_package.deploy_response[:errors].map do |err|
      { device: comp_ids_to_names[err[:device]], reason: err[:reason] }
    end

    log_info "Jamf: Deployed version '#{version}' of title '#{title}' to #{all_targets.size} computers via MDM"

  end

  removals.each { |r| log_info "Jamf: Removal #{r}" }
  queued_cmds.each { |qc| log_info "Jamf: Queued Command #{qc}" }
  deploy_errs.each { |err| log_info "Jamf: Error #{err}" }

  {
    removals: removals,
    queuedCommands: queued_cmds,
    errors: deploy_errs
  }
end

#disable_policies_for_deprecation_or_skipping(reason) ⇒ void

This method returns an undefined value.

Disable the auto-install and patch policies for this version when it is deprecated or skipped

Leave the manual install policy active, but remove it from self-service

Parameters:

  • reason (Symbol)

    :deprecated or :skipped



1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 1076

def disable_policies_for_deprecation_or_skipping(reason)
  progress "Jamf: Disabling auto-install policy for #{reason} version '#{version}'"
  pol = jamf_auto_install_policy
  pol.disable
  pol.save

  # don't disable the auto-reinstall policy - it may be needed
  # for any re-uploads of the pkg for this version, even if deprecated/skipped

  progress "Jamf: Disabling patch policy for #{reason} version '#{version}'"
  ppol = jamf_patch_policy
  ppol.disable
  # ensure patch policy is NOT set to 'allow downgrade'
  ppol.allow_downgrade = false
  ppol.save
end

#expand_groups_for_deploy(groups, removals) ⇒ Array<Integer>

expand computer groups given for deploy_via_mdm

Parameters:

  • groups (Array<String, Integer>)

    The names or ids of computer groups to install on.

  • removals (Array<Hash>)

    The groups that are not valid, for reporting back to the caller

Returns:

  • (Array<Integer>)

    The ids of the computers in the groups



1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 1451

def expand_groups_for_deploy(groups, removals)
  log_debug "Expanding group targets for MDM deployment of title '#{title}',  version '#{version}'"

  computers = []
  groups.each do |g|
    gid = Jamf::ComputerGroup.valid_id g, cnx: jamf_cnx
    if gid
      jgroup = Jamf::ComputerGroup.fetch id: gid, cnx: jamf_cnx

      if excluded_groups_to_use.include? jgroup.name
        log_debug "Jamf: Group '#{jgroup.name}' is in the excluded groups list. Removing."
        removals << { device: nil, group: g, reason: "Group '#{jgroup.name}' is in the excluded groups list" }
        next
      end
      log_debug "Jamf: Adding computers from group '#{jgroup.name}' to deployment targets"
      computers += jgroup.member_ids
    else
      log_debug "Jamf: Group '#{g}' not found in Jamf Pro. Removing."
      removals << { device: nil, group: g, reason: 'Group not found in Jamf Pro' }
    end
  end
  computers
end

#jamf_auto_install_policyJamf::Policy

Create or fetch the auto install policy for this version If we are deleting and it doesn’t exist, return nil.

Returns:

  • (Jamf::Policy)

    The auto-install-policy for this version, if it exists



496
497
498
499
500
501
502
503
504
505
506
507
508
509
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 496

def jamf_auto_install_policy
  # This is imporant to avoid infinite recursion
  return @jamf_auto_install_policy if @jamf_auto_install_policy

  if jamf_auto_install_policy_exist?
    @jamf_auto_install_policy = Jamf::Policy.fetch(name: jamf_auto_install_policy_name, cnx: jamf_cnx)
  else
    return if deleting?

    # this sets @jamf_auto_install_policy
    create_jamf_auto_install_policy
  end
  @jamf_auto_install_policy
end

#jamf_auto_install_policy_exist?Boolean

Returns does the jamf_auto_install_policy exist?.

Returns:

  • (Boolean)

    does the jamf_auto_install_policy exist?



487
488
489
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 487

def jamf_auto_install_policy_exist?
  Jamf::Policy.all_names(cnx: jamf_cnx).include? jamf_auto_install_policy_name
end

#jamf_auto_install_policy_urlString

Returns the URL for the Jamf Pro Policy that does auto-installs of this version.

Returns:

  • (String)

    the URL for the Jamf Pro Policy that does auto-installs of this version



576
577
578
579
580
581
582
583
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 576

def jamf_auto_install_policy_url
  return @jamf_auto_install_policy_url if @jamf_auto_install_policy_url

  pol_id = Jamf::Policy.valid_id jamf_auto_install_policy_name, cnx: jamf_cnx
  return unless pol_id

  @jamf_auto_install_policy_url = "#{jamf_gui_url}/policies.html?id=#{pol_id}&o=r"
end

#jamf_auto_reinstall_policyJamf::Policy

Create or fetch the auto re-install policy for this version If we are deleting and it doesn’t exist, return nil.

Returns:

  • (Jamf::Policy)

    The auto-install-policy for this version, if it exists



783
784
785
786
787
788
789
790
791
792
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 783

def jamf_auto_reinstall_policy
  @jamf_auto_reinstall_policy ||=
    if jamf_auto_reinstall_policy_exist?
      Jamf::Policy.fetch(name: jamf_auto_reinstall_policy_name, cnx: jamf_cnx)
    else
      return if deleting?

      create_jamf_auto_reinstall_policy
    end
end

#jamf_auto_reinstall_policy_exist?Boolean

Returns does the jamf_auto_reinstall_policy exist?.

Returns:

  • (Boolean)

    does the jamf_auto_reinstall_policy exist?



774
775
776
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 774

def jamf_auto_reinstall_policy_exist?
  Jamf::Policy.all_names(:refresh, cnx: jamf_cnx).include? jamf_auto_reinstall_policy_name
end

#jamf_auto_reinstall_policy_urlString

Returns the URL for the Jamf Pro Policy that does auto reinstalls of this version.

Returns:

  • (String)

    the URL for the Jamf Pro Policy that does auto reinstalls of this version



843
844
845
846
847
848
849
850
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 843

def jamf_auto_reinstall_policy_url
  return @jamf_auto_reinstall_policy_url if @jamf_auto_reinstall_policy_url

  pol_id = Jamf::Policy.valid_id jamf_auto_reinstall_policy_name, cnx: jamf_cnx
  return unless pol_id

  @jamf_auto_reinstall_policy_url = "#{jamf_gui_url}/policies.html?id=#{pol_id}&o=r"
end

#jamf_gui_urlString

Returns The start of the Jamf Pro URL for GUI/WebApp access.

Returns:

  • (String)

    The start of the Jamf Pro URL for GUI/WebApp access



301
302
303
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 301

def jamf_gui_url
  server_app_instance.jamf_gui_url
end

#jamf_installed_groupJamf::ComputerGroup

Create or fetch the smart group of macs with this version installed If we are deleting and it doesn’t exist, return nil

Returns:

  • (Jamf::ComputerGroup)

    the smart group.



683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 683

def jamf_installed_group
  return @jamf_installed_group if @jamf_installed_group

  if jamf_installed_group_exist?
    @jamf_installed_group = Jamf::ComputerGroup.fetch(
      name: jamf_installed_group_name,
      cnx: jamf_cnx
    )
  else
    return if deleting?

    create_jamf_installed_group
  end
  @jamf_installed_group
end

#jamf_installed_group_criteriaArray<Jamf::Criteriable::Criterion>

The criteria for the smart group in Jamf that contains all Macs with this version of this title installed

We use the “Patch Reporting: #Xolo::Server::Mixins::VersionJamfAccess.title_objecttitle_object.display_name” criterion so that we don’t care whether the title uses a version-script or app data.

Returns:

  • (Array<Jamf::Criteriable::Criterion>)


747
748
749
750
751
752
753
754
755
756
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 747

def jamf_installed_group_criteria
  [
    Jamf::Criteriable::Criterion.new(
      and_or: :or,
      name: "Patch Reporting: #{title_object.display_name}",
      search_type: 'is',
      value: version
    )
  ]
end

#jamf_installed_group_exist?Boolean

Returns does the jamf_installed_group exist?.

Returns:

  • (Boolean)

    does the jamf_installed_group exist?



674
675
676
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 674

def jamf_installed_group_exist?
  Jamf::ComputerGroup.all_names(cnx: jamf_cnx).include? jamf_installed_group_name
end

#jamf_installed_group_urlObject



759
760
761
762
763
764
765
766
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 759

def jamf_installed_group_url
  return @jamf_installed_group_url if @jamf_installed_group_url

  gr_id = Jamf::ComputerGroup.valid_id jamf_installed_group_name, cnx: jamf_cnx
  return unless gr_id

  @jamf_installed_group_url = "#{jamf_gui_url}/smartComputerGroups.html?id=#{gr_id}&o=r"
end

#jamf_manual_install_policyJamf::Policy

Create or fetch the manual install policy for this version If we are deleting and it doesn’t exist, return nil.

Returns:

  • (Jamf::Policy)

    The manual-install-policy for this version, if it exists



600
601
602
603
604
605
606
607
608
609
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 600

def jamf_manual_install_policy
  @jamf_manual_install_policy ||=
    if jamf_manual_install_policy_exist?
      Jamf::Policy.fetch(name: jamf_manual_install_policy_name, cnx: jamf_cnx)
    else
      return if deleting?

      create_jamf_manual_install_policy
    end
end

#jamf_manual_install_policy_exist?Boolean

Returns does the jamf_manual_install_policy exist?.

Returns:

  • (Boolean)

    does the jamf_manual_install_policy exist?



591
592
593
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 591

def jamf_manual_install_policy_exist?
  Jamf::Policy.all_names(cnx: jamf_cnx).include? jamf_manual_install_policy_name
end

#jamf_manual_install_policy_urlString

Returns the URL for the Jamf Pro Policy that does manual installs of this version.

Returns:

  • (String)

    the URL for the Jamf Pro Policy that does manual installs of this version



659
660
661
662
663
664
665
666
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 659

def jamf_manual_install_policy_url
  return @jamf_manual_install_policy_url if @jamf_manual_install_policy_url

  pol_id = Jamf::Policy.valid_id jamf_manual_install_policy_name, cnx: jamf_cnx
  return unless pol_id

  @jamf_manual_install_policy_url = "#{jamf_gui_url}/policies.html?id=#{pol_id}&o=r"
end

#jamf_packageJamf::JPackage

Create or fetch the Jamf::JPackage object for this version Returns nil if the package doesn’t exist and we’re deleting

Returns:

  • (Jamf::JPackage)

    the Package object associated with this version



314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 314

def jamf_package
  return @jamf_package if @jamf_package

  id = jamf_pkg_id || Jamf::JPackage.valid_id(name: jamf_pkg_name, cnx: jamf_cnx)
  @jamf_package =
    if id
      log_debug "Jamf: Fetching Jamf::JPackage '#{id}'"
      self.jamf_pkg_id = id # in case we only had the name before, now we have the id, so save it
      save_local_data
      Jamf::JPackage.fetch id: id, cnx: jamf_cnx
    else
      return if deleting?

      create_jamf_package
    end
end

#jamf_package_exist?Boolean

Returns does the jamf_package exist?.

Returns:

  • (Boolean)

    does the jamf_package exist?



333
334
335
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 333

def jamf_package_exist?
  !Jamf::JPackage.valid_id(packageName: jamf_pkg_name, cnx: jamf_cnx).nil?
end

#jamf_package_notes(ttl_obj: nil) ⇒ String

Returns the ‘notes’ text for the Jamf::JPackage object for this version.

Returns:

  • (String)

    the ‘notes’ text for the Jamf::JPackage object for this version



369
370
371
372
373
374
375
376
377
378
379
380
381
382
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 369

def jamf_package_notes(ttl_obj: nil)
  ttl_obj ||= title_object
  pkg_notes = Xolo::Server::Version::JAMF_PKG_NOTES_PREFIX.sub(
    Xolo::Server::Version::JAMF_PKG_NOTES_VERS_PH,
    version
  )
  pkg_notes.sub!(
    Xolo::Server::Version::JAMF_PKG_NOTES_TITLE_PH,
    title
  )
  desc = ttl_obj.changes_for_update.dig(:description, :new) || ttl_obj.description
  pkg_notes << desc
  pkg_notes
end

#jamf_package_urlString

Returns the URL for the Package that installs this version in Jamf Pro.

Returns:

  • (String)

    the URL for the Package that installs this version in Jamf Pro



430
431
432
433
434
435
436
437
438
439
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 430

def jamf_package_url
  return @jamf_package_url if @jamf_package_url
  return unless jamf_pkg_id

  # the old url
  # @jamf_package_url = "#{jamf_gui_url}/packages.html?id=#{jamf_pkg_id}&o=r"

  @jamf_package_url = "#{jamf_gui_url}/view/settings/computer-management/packages/#{jamf_pkg_id}?tab=general"
  # https://casper.pixar.com:8443/view/settings/computer-management/packages/12042?tab=general
end

#jamf_patch_policyJamf::PatchPolicy?

Fetch or create the patch policy for this version If we are deleting and it doesn’t exist, return nil.

Returns:

  • (Jamf::PatchPolicy, nil)

    The patch policy for this version, if it exists



866
867
868
869
870
871
872
873
874
875
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 866

def jamf_patch_policy
  @jamf_patch_policy ||=
    if jamf_patch_policy_exist?
      Jamf::PatchPolicy.fetch(name: jamf_patch_policy_name, cnx: jamf_cnx)
    else
      return if deleting?

      create_jamf_patch_policy
    end
end

#jamf_patch_policy_exist?Boolean

Returns does the jamf_patch_policy exist?.

Returns:

  • (Boolean)

    does the jamf_patch_policy exist?



858
859
860
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 858

def jamf_patch_policy_exist?
  Jamf::PatchPolicy.all_names(:refresh, cnx: jamf_cnx).include? jamf_patch_policy_name
end

#jamf_patch_policy_urlString

Returns the URL for the Jamf Pro Patch Policy that updates to this version.

Returns:

  • (String)

    the URL for the Jamf Pro Patch Policy that updates to this version



972
973
974
975
976
977
978
979
980
981
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 972

def jamf_patch_policy_url
  return @jamf_patch_policy_url if @jamf_patch_policy_url

  title_id = title_object.jamf_patch_title_id

  pol_id = Jamf::PatchPolicy.valid_id jamf_patch_policy_name, cnx: jamf_cnx
  return unless pol_id

  @jamf_manual_install_policy_url = "#{jamf_gui_url}/patchDeployment.html?softwareTitleId=#{title_id}&id=#{pol_id}&o=r"
end

#jamf_patch_versionJamf::PatchTitle::Version

Xolo version

Returns:

  • (Jamf::PatchTitle::Version)

    The Jamf::PatchTitle::Version for this

Raises:



1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 1226

def jamf_patch_version
  return @jamf_patch_version if @jamf_patch_version

  # NOTE: in the line below, use the title_object's call to #jamf_patch_title
  # because that will cache the Jamf::PatchTitle instance, and we need to
  # use it to save changes to its Versions.
  # Using the class method won't cache the instance we will need in the
  # future.
  @jamf_patch_version = title_object.jamf_patch_title.versions[version]
  return @jamf_patch_version if @jamf_patch_version

  if repairing?
    # if we're repairing, and the version isn't visible in Jamf, then
    # jamf polled the title editor in the few moments it was disabled.
    # and jamf will see it again within 5 minutes.
    return nil
  end

  # TODO: wait for it to appear when adding, or re-appear when repairing?
  msg = "Jamf: Version '#{version}' of Title '#{title}' is not visible in Jamf. Is the Patch enabled in the Title Editor?"
  log_error msg
  raise Xolo::NoSuchItemError, msg
end

#patch_reportArrah<Hash>

Get the patch report for this version

Returns:

  • (Arrah<Hash>)

    Data for each computer with this version of this title installed



1369
1370
1371
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 1369

def patch_report
  title_object.patch_report vers: version
end

#remove_exclusions_from_deploy(targets, removals) ⇒ void

This method returns an undefined value.

Remove exclusions from the list of targets for deploy_via_mdm

Parameters:

  • targets (Array<Integer>)

    The ids of computers to install on.

  • removals (Array<Hash>)

    The computers that are not valid, for reporting back to the caller



1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 1503

def remove_exclusions_from_deploy(targets, removals)
  log_debug "Removing excluded computer targets for MDM deployment of title '#{title}',  version '#{version}'"

  excluded_groups_to_use.each do |group|
    gid = Jamf::ComputerGroup.valid_id group, cnx: jamf_cnx
    unless gid
      log_error "Jamf: Excluded group '#{group}' not found in Jamf Pro. Skipping."
      next
    end # unless gid

    jgroup = Jamf::ComputerGroup.fetch id: gid, cnx: jamf_cnx
    jgroup.members.each do |member|
      next unless targets.include? member[:id]

      log_debug "Jamf: Removing computer '#{member[:name]}' (#{member[:id]}) from deployment targets because it is in excluded group '#{group}'"
      targets.delete member[:id]
      removals << { device: member[:name], group: nil, reason: "In excluded group '#{group}'" }
    end
  end # excluded_groups_to_use.each
end

#remove_invalid_computers_for_deploy(targets, removals) ⇒ void

This method returns an undefined value.

remove invalid computers from the list of targets for deploy_via_mdm

Parameters:

  • targets (Array<String, Integer>)

    The names or ids of computers to install on.

  • removals (Array<Hash>)

    The computers that are not valid, for reporting back to the caller



1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 1482

def remove_invalid_computers_for_deploy(targets, removals)
  log_debug "Removing invalid computer targets for MDM deployment of title '#{title}',  version '#{version}'"

  targets.map! do |c|
    id = Jamf::Computer.valid_id c, cnx: jamf_cnx
    if id
      id
    else
      removals << { device: c, group: nil, reason: 'Computer not found in Jamf Pro' }
      nil
    end
  end.compact!
end

#repair_jamf_auto_install_policyObject

repair the auto-install policy only



533
534
535
536
537
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 533

def repair_jamf_auto_install_policy
  progress "Jamf: Repairing Auto Install Policy '#{jamf_auto_install_policy_name}'", log: :info
  configure_jamf_auto_install_policy
  jamf_auto_install_policy.save
end

#repair_jamf_auto_reinstall_policyObject

Reset the configuration of the jamf_installed_group



807
808
809
810
811
812
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 807

def repair_jamf_auto_reinstall_policy
  return unless reupload_date

  progress "Jamf: Repairing Auto Re-Install Policy: #{jamf_auto_reinstall_policy_name}", log: :debug
  configure_jamf_auto_reinstall_policy jamf_auto_reinstall_policy
end

#repair_jamf_installed_groupObject

Reset the configuration of the jamf_installed_group but only if there’s been a re-upload of the pkg



719
720
721
722
723
724
725
726
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 719

def repair_jamf_installed_group
  return unless reupload_date

  progress "Jamf: Repairing smart group '#{jamf_installed_group_name}'", log: :info

  configure_jamf_installed_group jamf_installed_group
  jamf_installed_group.save
end

#repair_jamf_manual_install_policyObject

repair the manual-install policy only



628
629
630
631
632
633
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 628

def repair_jamf_manual_install_policy
  pol = jamf_manual_install_policy
  progress "Jamf: Repairing Manual Install Policy '#{jamf_manual_install_policy_name}'", log: :info
  configure_jamf_manual_install_policy(pol)
  pol.save
end

#repair_jamf_packageObject

repair the package object only



416
417
418
419
420
421
422
423
424
425
426
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 416

def repair_jamf_package
  # If these values are all correct, nothing will be saved
  progress "Jamf: Repairing Package '#{jamf_pkg_name}'", log: :info
  jamf_package.packageName = jamf_pkg_name
  jamf_package.fileName = "#{jamf_pkg_name}.pkg"
  jamf_package.rebootRequired = reboot
  jamf_package.notes = jamf_package_notes
  jamf_package.categoryId = jamf_xolo_category_id
  jamf_package.osRequirements = ">=#{min_os}"
  jamf_package.save
end

#repair_jamf_patch_policyObject

repair the patch policy only



939
940
941
942
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
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 939

def repair_jamf_patch_policy
  progress "Jamf: Repairing Patch Policy '#{jamf_patch_policy_name}'", log: :info
  assign_pkg_to_patch_in_jamf

  ppol = jamf_patch_policy
  ppol.name = jamf_patch_policy_name
  ppol.target_version = version

  # This should default tofalse, so that
  # we don't accidentally downgrade non-xolo test installs,
  # or server-pushed updates (like with commvault or cisco VPN)
  ppol.patch_unknown = patch_unknown ? true : false

  if pilot?
    set_policy_pilot_groups ppol
  else
    ppol.scope.set_all_targets
  end

  # exclusions are for always
  set_policy_exclusions ppol

  if pilot? || released?
    ppol.enable
  else
    ppol.disable
  end

  ppol.save
end

#repair_jamf_version_objectsObject

Validate and fix any Jamf::JPackage objects that related to this version:

  • the package object

  • the installed-group

  • the auto-install policy

  • the manual-install policy

  • the auto-reinstall policy

  • the patch policy



236
237
238
239
240
241
242
243
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 236

def repair_jamf_version_objects
  repair_jamf_package
  repair_jamf_installed_group # wont happen if no reupload_date
  repair_jamf_auto_install_policy
  repair_jamf_manual_install_policy
  repair_jamf_auto_reinstall_policy # wont happen if no reupload_date
  repair_jamf_patch_policy
end

#reset_policies_to_pilotvoid

This method returns an undefined value.

reset all the policies for this version to pilot



1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 1097

def reset_policies_to_pilot
  # set scope targets of auto-install policy to pilot-groups and re-enable
  msg = "Jamf: Version '#{version}': Setting scope targets of auto-install policy to pilot_groups: #{pilot_groups_to_use.join(', ')}"
  progress msg, log: :info

  jamf_auto_install_policy.scope.set_targets :computer_groups, pilot_groups_to_use
  jamf_auto_install_policy.enable
  jamf_auto_install_policy.save

  msg = "Jamf: Version '#{version}': Setting scope targets of patch policy to pilot_groups"
  progress msg, log: :info

  # set scope targets of patch policy to pilot-groups and re-enable
  jamf_patch_policy.scope.set_targets :computer_groups, pilot_groups_to_use
  # ensure patch policy is NOT set to 'allow downgrade'
  jamf_patch_policy.allow_downgrade = false
  jamf_patch_policy.enable
  jamf_patch_policy.save
end

#set_policy_exclusions(pol, ttl_obj: nil) ⇒ Object

set excluded groups in a [patch] policy object’s scope REMEMBER TO SAVE THE POLICY LATER

This applies more nuance to the ‘excluded_groups_to_use’ depending on the policy in question. E.g. manual-install policy should not have the installed-group excluded, to allow re-installs

Parameters:

  • pol (Jamf::Policy, Jamf::PatchPolicy)
  • ttl_obj (Xolo::Server::Title) (defaults to: nil)

    The pre-instantiated title for ths version. if nil, we’ll instantiate it now



1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 1044

def set_policy_exclusions(pol, ttl_obj: nil)
  ttl_obj ||= title_object
  # dup, so when we add the installed group below, we don't
  # keep that for future calls to this method.
  exclusions = excluded_groups_to_use(ttl_obj: ttl_obj).dup
  exclusions ||= []

  # the initial auto-install policies must also exclude any mac with the title
  # already installed
  #
  # But the manual-install policy and the auto-reinstall should never exclude it - so that
  # it can be manually installed or automatically re-installed whenever needed
  if pol.is_a?(Jamf::Policy) && pol.name == jamf_auto_install_policy_name
    # calling ttl_obj.jamf_installed_group will create the group if needed
    exclusions << ttl_obj.jamf_installed_group_name
  end

  log_debug "Jamf: updating exclusions for #{pol.class} '#{pol.name}' to: #{exclusions.join ', '}"

  exclusions.uniq!
  pol.scope.set_exclusions :computer_groups, exclusions
end

#set_policy_pilot_groups(pol) ⇒ void

This method returns an undefined value.

set target groups in a pilot [patch] policy object’s scope REMEMBER TO SAVE THE POLICY LATER

Parameters:

  • pol (Jamf::Policy, Jamf::PatchPolicy)


993
994
995
996
997
998
999
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 993

def set_policy_pilot_groups(pol)
  pilots = pilot_groups_to_use
  pilots ||= []
  log_debug "Jamf: setting pilot scope targets for #{pol.class} '#{pol.name}' to: #{pilots.join ', '}"

  pol.scope.set_targets :computer_groups, pilots
end

#set_policy_release_groups(pol, ttl_obj: nil) ⇒ void

This method returns an undefined value.

set target groups in a non=pilot [patch] policy object’s scope REMEMBER TO SAVE THE POLICY LATER

Parameters:

  • pol (Jamf::Policy, Jamf::PatchPolicy)
  • ttl_obj (Xolo::Server::Title) (defaults to: nil)

    The pre-instantiated title for ths version. if nil, we’ll instantiate it now



1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 1020

def set_policy_release_groups(pol, ttl_obj: nil)
  ttl_obj ||= title_object
  targets = release_groups_to_use(ttl_obj: ttl_obj) || []

  log_debug "Jamf: setting release scope targets for #{pol.class} '#{pol.name}' to: #{targets.join ', '}"

  if targets.include? Xolo::TARGET_ALL
    pol.scope.set_all_targets
  else
    pol.scope.set_targets :computer_groups, targets
  end
end

#set_policy_to_all_targets(pol) ⇒ void

This method returns an undefined value.

Set a policy to be scoped to all targets REMEMBER TO SAVE THE POLICY LATER

Parameters:

  • pol (Jamf::Policy, Jamf::PatchPolicy)


1007
1008
1009
1010
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 1007

def set_policy_to_all_targets(pol)
  log_debug "Jamf: setting scope target for #{pol.class} '#{pol.name}' to all computers"
  pol.scope.set_all_targets
end

#update_excluded_groups(ttl_obj: nil) ⇒ Object

Update all the excluded_groups policy scopes for this version when either the title or version has changed them

Applies regardless of status

Parameters:

  • ttl_obj (Xolo::Server::Title) (defaults to: nil)

    The pre-instantiated title for ths version. if nil, we’ll instantiate it now



1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 1181

def update_excluded_groups(ttl_obj: nil)
  log_debug "Updating Excluded Groups for Version '#{version}' of Title '#{title}'"

  # - update the manual install policy
  pol = jamf_manual_install_policy
  if pol
    progress "Jamf: Updating excluded groups for Manual Install Policy '#{jamf_auto_install_policy_name}'."
    set_policy_exclusions(pol, ttl_obj: ttl_obj)
    pol.save
  end

  # - update the auto install policy
  pol = jamf_auto_install_policy
  if pol
    progress "Jamf: Updating excluded groups for Auto Install Policy '#{jamf_auto_install_policy_name}'."
    set_policy_exclusions(pol, ttl_obj: ttl_obj)
    pol.save
  end

  # - update the auto reinstall policy, but only if it exists
  if jamf_auto_reinstall_policy_exist?
    pol = jamf_auto_reinstall_policy
    if pol
      progress "Jamf: Updating excluded groups for Auto ReInstall Policy '#{jamf_auto_reinstall_policy_name}'."
      set_policy_exclusions(pol, ttl_obj: ttl_obj)
      pol.save
    end
  end

  # - update the patch policy
  pol = jamf_patch_policy
  return unless pol

  progress "Jamf: Updating exccluded groups for Patch Policy '#{jamf_patch_policy_name}'."
  set_policy_exclusions(pol, ttl_obj: ttl_obj)
  pol.save
end

#update_jamf_package_notes(ttl_obj: nil) ⇒ void

This method returns an undefined value.

update the description for the Jamf::JPackage



386
387
388
389
390
391
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 386

def update_jamf_package_notes(ttl_obj: nil)
  ttl_obj ||= title_object
  progress "Jamf: Updating notes for Jamf::JPackage '#{jamf_pkg_name}'", log: :debug
  jamf_package.notes = jamf_package_notes(ttl_obj: ttl_obj)
  jamf_package.save
end

#update_jamf_pkg_min_osvoid

This method returns an undefined value.

update the min_os setting for the Jamf::JPackage



406
407
408
409
410
411
412
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 406

def update_jamf_pkg_min_os
  new_min = changes_for_update&.key?(:min_os) ? changes_for_update[:min_os][:new] : min_os
  progress "Jamf: Updating os_requirement for Jamf::JPackage '#{jamf_pkg_name}' to '#{new_min}'",
           log: :debug
  jamf_package.osRequirements = ">=#{new_min}"
  jamf_package.save
end

#update_jamf_pkg_rebootvoid

This method returns an undefined value.

update the reboot setting for the Jamf::JPackage



396
397
398
399
400
401
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 396

def update_jamf_pkg_reboot
  new_reboot = changes_for_update&.key?(:reboot) ? changes_for_update[:reboot][:new] : reboot
  progress "Jamf: Updating reboot setting for Jamf::JPackage '#{jamf_pkg_name}' to '#{new_reboot}'", log: :debug
  jamf_package.rebootRequired = new_reboot
  jamf_package.save
end

#update_pilot_groupsObject

Update all the pilot_groups policy scopes for this version when either the title or version has changed them

Nothing to do if the version isn’t currently in :pilot status

Parameters:

  • ttl_obj (Xolo::Server::Title)

    The pre-instantiated title for ths version. if nil, we’ll instantiate it now



1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 1125

def update_pilot_groups
  # nothing unless we're in pilot
  return unless status == Xolo::Server::Version::STATUS_PILOT

  # - no changes to the manual install policy: scope-target is all

  # - update the auto install policy
  progress "Jamf: Updating pilot groups for Auto Install Policy '#{jamf_auto_install_policy_name}'."

  pol = jamf_auto_install_policy

  set_policy_pilot_groups(pol)
  pol.save

  # - update the patch policy
  progress "Jamf: Updating pilot groups for Patch Policy '#{jamf_patch_policy_name}'."

  pol = jamf_patch_policy

  set_policy_pilot_groups(pol)
  pol.save
end

#update_release_groups(ttl_obj: nil) ⇒ Object

Update all the release_groups policy scopes for this version when either the title or version has changed them

Nothing to do if the version is currently in pending or pilot status

Parameters:

  • ttl_obj (Xolo::Server::Title) (defaults to: nil)

    The pre-instantiated title for ths version. if nil, we’ll instantiate it now



1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 1156

def update_release_groups(ttl_obj: nil)
  return unless status == Xolo::Server::Version::STATUS_RELEASED

  # - no changes to the manual install policy: scope-target is all

  # - update the auto-install policy
  pol = jamf_auto_install_policy
  return unless pol

  set_policy_release_groups(pol, ttl_obj: ttl_obj)
  pol.save
  progress "Jamf: updated release groups for Auto Install Policy '#{jamf_auto_install_policy_name}'.",
           log: :info

  # - no changes to the patch policy: scope-target is all once released
end

#update_version_in_jamfObject

Apply edits to the Xolo version to Jamf as needed This includes scope changes in policies, changes to pkg ‘reboot’ setting and changes to pkg ‘os_requirements’ Uploading a new .pkg installer happen separately



207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/xolo/server/mixins/version_jamf_access.rb', line 207

def update_version_in_jamf
  update_pilot_groups if changes_for_update&.key? :pilot_groups
  update_release_groups(ttl_obj: title_object) if changes_for_update&.key? :release_groups
  update_excluded_groups(ttl_obj: title_object) if changes_for_update&.key? :excluded_groups

  update_jamf_pkg_reboot if changes_for_update&.key? :reboot
  update_jamf_pkg_min_os if changes_for_update&.key? :min_os

  # TODO: Update the critera for the jamf_installed_group IF
  #
  # - the group exists AND
  # - the title has changed how it determines installed versions, e.g. by adding or
  #   changing a version_script or app_bundle_id
  #   Changing those is very rare, and ill-advised, so we will implement
  #   this later.
  #
  # if jamf_installed_group_exist?
  # end
end