xolo-admin 2.2.4 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c2b0f21f5f3a7a55117054a2fe5cd35e7e702debd3909669f969e009b603cbbe
4
- data.tar.gz: 27f012b50a0986d7a06854f5cef89af6b549efe7a22b30faf3601418be3dc56d
3
+ metadata.gz: 9c667de0cc034e593ed21097a61d356497d18be62c6efa84d681459138457e5c
4
+ data.tar.gz: 28c33bd6e5eeb50864a7faca5342381a7929354c7eb052d62e6efa377c14ef08
5
5
  SHA512:
6
- metadata.gz: 854b8cf91c614184a51b2753931135dbb91d697965b5531859d886d96e554fcfb33c60abc141c47bb0748a4150cec8fa0d357a4cbfb4dbf44625b439229adf9a
7
- data.tar.gz: bbcbf4275c621a79829d365b0a4d0bd4ac09775516efb924fbb4bd8f1f9039c17e0b1d8c2ce22293793ffbb83696e86b385cdd57fa2c41c6f706080c69bd1b2e
6
+ metadata.gz: 1af30205a20f66da58d657c716a2de2d6fe7da54f3745add8b68df80929ab2e6aa8dd72a68e1e2d72a009e03c6c48c276f1bd9fbaa3d6b18ba92fe5d7c21dbbc
7
+ data.tar.gz: 1ac20c8dee5bc4aedab29c39aa405788edf80f43cf1de8843e960220cf4024436ca2ed2f26e9b41e8a76203f5a76de2cdf5b9dedb8234ce1cc7c9b3510d7a069
data/data/client/xolo CHANGED
@@ -27,6 +27,9 @@ zmodload zsh/zutil
27
27
  ###############################
28
28
  ###############################
29
29
 
30
+ # just in case
31
+ export PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/libexec:$PATH"
32
+
30
33
  # Needed for the UTF-8 chars in the lsreg output
31
34
  export LANG="en_US.UTF-8"
32
35
  export LC_ALL="en_US.UTF-8"
@@ -94,6 +97,7 @@ be_verbose=
94
97
  debugging_on=
95
98
  no_versions=
96
99
  show_xolo_version=
100
+ do_recon=
97
101
 
98
102
  # arguments
99
103
  command=
@@ -152,7 +156,9 @@ Options:
152
156
  policies, etc, from test xolo server, not the production server.
153
157
  Setting the XOLO_TEST_MODE env. variable does the same thing.
154
158
  -r, --recon: With 'install' or 'uninstall' run a 'jamf recon' after the
155
- operation completes successfully.
159
+ operation completes successfully. With 'update', run a 'jamf recon'
160
+ before the checkin. NOTE: With update, the whole process may take
161
+ many minutes.
156
162
  -n, --no-versions: With the 'list-titles' and 'list-installed' commands,
157
163
  do not show the versions available, or the version
158
164
  installed, respectively.
@@ -187,6 +193,9 @@ Commands:
187
193
     every time this computer checks in with Jamf Pro.
188
194
  Note: this just runs the 'jamf policy' command, which will execute any pending
189
195
  Jamf policies triggered by "recurring check-in".
196
+ If --recon is given, a Jamf recon will run first, followed by a 1 minute pause
197
+ for Jamf to process the data before doing the check-in. This helps the Mac to see
198
+ very recently-released versions as patch updates.
190
199
 
191
200
  refresh, r
192
201
  Update xolo's information about current titles and versions.
@@ -356,42 +365,43 @@ function debug() {
356
365
  debugging_on && echo "DEBUG: $*" 1>&2
357
366
  }
358
367
 
359
- # Gather all installed bundle ids and installed versions from lsreg
368
+ # Gather all installed bundle ids and installed versions from system_profiler
360
369
  # store them in an associative array in $installed_apps.
361
370
  # keys are bundle ids, values are app name & installed version
362
371
  # separated by a semicolon
363
372
  # e.g. 'com.apple.Safari => Safari.app;14.0.3'
364
373
  ###############################
365
374
  function get_installed_apps() {
375
+ # debug "PATH is $PATH"
366
376
  debug "Getting all installed .apps on this Mac..."
367
377
  local app_name
368
378
  local app_bundle_id
369
379
  local app_vers
380
+ local app_plist
370
381
 
371
- # loop thru lsreg output
372
- "$LSREG" -dump Bundle | while IFS= read -r line ; do
373
- # a line if ------ starts a new record
374
- if [[ "$line" =~ '^-+$' ]] ; then
375
- unset app_name
376
- unset app_bundle_id
377
- unset app_vers
378
- continue
379
- fi
382
+ json_app_data=$(/usr/sbin/system_profiler -json SPApplicationsDataType )
383
+
384
+ apps_to_look_at=$(echo "$json_app_data" | grep '"path"' | cut -d'"' -f4 | grep -v '^/System/')
385
+
386
+ for app_path in ${(f)apps_to_look_at} ; do
387
+ app_name=$(/usr/bin/basename "$app_path")
388
+ app_plist="$app_path/Contents/Info.plist"
389
+
390
+ if [[ -f "$app_plist" ]] ; then
391
+ app_bundle_id=$(/usr/bin/plutil -extract CFBundleIdentifier raw "$app_plist" 2>/dev/null)
380
392
 
381
- # $MATCH is the whole matched string, $match is the array of captures
382
- # NOTE this only works if the path is listed before the CFBundleIdentifier
383
- # which seems to be the case in the lsreg output
384
- [[ "$line" =~ '^path:[[:space:]]+/.*/(.+\.app) \(' ]] && app_name=$match[1]
385
- [[ "$line" =~ '^[[:space:]]+CFBundleIdentifier = \"(.+)\";' ]] && app_bundle_id=$match[1]
386
- [[ "$line" =~ '^[[:space:]]+CFBundleShortVersionString = \"(.+)\";' ]] && app_vers=$match[1]
393
+ app_vers=$(/usr/bin/plutil -extract CFBundleShortVersionString raw "$app_plist" 2>/dev/null)
394
+
395
+ # Use CFBundleVersion if no CFBundleShortVersionString
396
+ [[ -z "$app_vers" ]] && \
397
+ app_vers=$(/usr/bin/plutil -extract CFBundleVersion raw "$app_plist" 2>/dev/null)
387
398
 
388
- if [[ -n "$app_name" && -n "$app_bundle_id" && -n "$app_vers" ]] ; then
389
399
  installed_apps[$app_bundle_id]="$app_name;$app_vers"
390
- unset app_name
391
- unset app_bundle_id
392
- unset app_vers
400
+ else
401
+ debug "App Path '$app_path' has no Info.plist"
393
402
  fi
394
403
  done
404
+
395
405
  # installed_apps is now an associative array with bundle ids as keys and app names as values
396
406
 
397
407
  # print the installed apps - this is a long list
@@ -402,8 +412,70 @@ function get_installed_apps() {
402
412
  done
403
413
  fi
404
414
 
415
+ # debug "PATH is $PATH"
405
416
  } # end installed_apps
406
417
 
418
+ ########################################
419
+ ########################################
420
+ ########################################
421
+ ########################################
422
+ ########################################
423
+ ########################################
424
+ # Gather all installed bundle ids and installed versions from lsreg
425
+ # store them in an associative array in $installed_apps.
426
+ # keys are bundle ids, values are app name & installed version
427
+ # separated by a semicolon
428
+ # e.g. 'com.apple.Safari => Safari.app;14.0.3'
429
+ ###############################
430
+ # function get_installed_apps() {
431
+ # debug "Getting all installed .apps on this Mac..."
432
+ # local app_name
433
+ # local app_bundle_id
434
+ # local app_vers
435
+
436
+ # # loop thru lsreg output
437
+ # "$LSREG" -dump Bundle | while IFS= read -r line ; do
438
+ # # a line if ------ starts a new record
439
+ # if [[ "$line" =~ '^-+$' ]] ; then
440
+ # unset app_name
441
+ # unset app_bundle_id
442
+ # unset app_vers
443
+ # continue
444
+ # fi
445
+
446
+ # # $MATCH is the whole matched string, $match is the array of captures
447
+ # # NOTE this only works if the path is listed before the CFBundleIdentifier
448
+ # # which seems to be the case in the lsreg output
449
+ # [[ "$line" =~ '^path:[[:space:]]+/.*/(.+\.app) \(' ]] && app_name=$match[1]
450
+ # [[ "$line" =~ '^[[:space:]]+CFBundleIdentifier = \"(.+)\";' ]] && app_bundle_id=$match[1]
451
+ # [[ "$line" =~ '^[[:space:]]+CFBundleShortVersionString = \"(.+)\";' ]] && app_vers=$match[1]
452
+
453
+ # if [[ -n "$app_name" && -n "$app_bundle_id" && -n "$app_vers" ]] ; then
454
+ # installed_apps[$app_bundle_id]="$app_name;$app_vers"
455
+ # unset app_name
456
+ # unset app_bundle_id
457
+ # unset app_vers
458
+ # fi
459
+ # done
460
+ # # installed_apps is now an associative array with bundle ids as keys and app names as values
461
+
462
+ # # print the installed apps - this is a long list
463
+ # if debugging_on ; then
464
+ # debug "All installed .apps on this Mac:"
465
+ # for bundle app in ${(kv)installed_apps}; do
466
+ # debug "'$bundle' -> '$app'"
467
+ # done
468
+ # fi
469
+
470
+ # } # end installed_apps
471
+ ########################################
472
+ ########################################
473
+ ########################################
474
+ ########################################
475
+ ########################################
476
+ ########################################
477
+ ########################################
478
+
407
479
  # Extract data from the client-data.json file
408
480
  #
409
481
  # TODO: Once we only support macOS 15 (Sequoia) and higher, we
@@ -463,7 +535,7 @@ function all_xolo_titles() {
463
535
  read -r -d '' jscode <<ENDJAVASCRIPT
464
536
  result = Object.keys(parsed_data.titles).join('\n');
465
537
  ENDJAVASCRIPT
466
- extract_json_data "$jscode" | sort
538
+ extract_json_data "$jscode" | /usr/bin/sort
467
539
  }
468
540
 
469
541
  # Outputs all known titles, one per line, with versions and statuses
@@ -969,6 +1041,12 @@ function run_recon() {
969
1041
  function update() {
970
1042
  say "Updating installed titles, or installing newly scoped ones..."
971
1043
 
1044
+ if [[ -n "$do_recon" ]] ; then
1045
+ run_recon
1046
+ say "Pausing to let Jamf Pro process recon data..."
1047
+ sleep 60
1048
+ fi
1049
+
972
1050
  debug "Running jamf policy..."
973
1051
  if be_verbose ; then
974
1052
  $JAMF policy -verbose
@@ -1020,12 +1098,15 @@ function list_installed_titles() {
1020
1098
  local ttl
1021
1099
  local app_data
1022
1100
 
1023
-
1024
1101
  verbose "Locating installed titles..."
1025
1102
 
1026
1103
  # populate the installed_apps associative array
1027
1104
  get_installed_apps
1028
1105
 
1106
+ # gather output here, display it at the end
1107
+ # rather than interspersed with debug lines
1108
+ installed_titles_report=""
1109
+
1029
1110
  while IFS= read -r ttl; do
1030
1111
  app_data=$(app_data_for_title $ttl)
1031
1112
 
@@ -1036,6 +1117,8 @@ function list_installed_titles() {
1036
1117
  display_title_if_installed_by_version_script $ttl
1037
1118
  fi
1038
1119
  done <<<"$(all_xolo_titles)"
1120
+
1121
+ say "$installed_titles_report"
1039
1122
  return 0
1040
1123
  }
1041
1124
 
@@ -1075,9 +1158,9 @@ function display_title_if_installed_by_app_data() {
1075
1158
  [[ "$inst_app_name" == "$app_name" ]] || return
1076
1159
 
1077
1160
  if [[ -n "$no_versions" ]] ; then
1078
- echo $ttl
1161
+ installed_titles_report="$installed_titles_report\n$ttl"
1079
1162
  else
1080
- echo "$ttl ($inst_app_vers)"
1163
+ installed_titles_report="$installed_titles_report\n$ttl ($inst_app_vers)"
1081
1164
  fi
1082
1165
  }
1083
1166
 
@@ -1114,9 +1197,9 @@ function display_title_if_installed_by_version_script() {
1114
1197
  [[ -n "$app_vers" ]] || return
1115
1198
 
1116
1199
  if [[ -n "$no_versions" ]] ; then
1117
- echo $ttl
1200
+ installed_titles_report="$installed_titles_report\n$ttl"
1118
1201
  else
1119
- echo "$ttl ($app_vers)"
1202
+ installed_titles_report="$installed_titles_report\n$ttl ($inst_app_vers)"
1120
1203
  fi
1121
1204
  }
1122
1205
 
@@ -158,6 +158,7 @@ module Xolo
158
158
  FREEZE_TITLE_CMD = 'freeze'
159
159
  THAW_TITLE_CMD = 'thaw'
160
160
  LIST_FROZEN_CMD = 'list-frozen'
161
+ RERUN_AUTOPKG_RECIPE_CMD = 'rerun-autopkg-recipe'
161
162
 
162
163
  LIST_VERSIONS_CMD = 'list-versions'
163
164
  ADD_VERSION_CMD = 'add-version'
@@ -382,6 +383,10 @@ module Xolo
382
383
  }
383
384
  }.freeze
384
385
 
386
+ DEPLOY_RELEASED = 'released'
387
+ DEPLOY_LATEST = 'latest'
388
+ DEPLOY_SPECIAL_VERSIONS = [DEPLOY_RELEASED, DEPLOY_LATEST].freeze
389
+
385
390
  DEPLOY_VERSION_OPTIONS = {
386
391
  groups: {
387
392
  label: 'Computer group whose computers will be targeted',
@@ -518,17 +523,6 @@ module Xolo
518
523
  confirmation: true
519
524
  },
520
525
 
521
- # SUBSCRIBE_CMD => {
522
- # desc: 'Subscribe to a software title from a Patch Source defined in Jamf Pro',
523
- # display: "#{SUBSCRIBE_CMD} title",
524
- # opts: Xolo::Admin::Title.subscribe_cli_opts,
525
- # walkthru_header: "Subscribing to Xolo Title '#{TARGET_TITLE_PLACEHOLDER}'",
526
- # target: :title,
527
- # process_method: :subscribe_title,
528
- # streamed_response: true,
529
- # confirmation: true
530
- # },
531
-
532
526
  EDIT_TITLE_CMD => {
533
527
  desc: 'Edit an exising software title',
534
528
  display: "#{EDIT_TITLE_CMD} title",
@@ -605,6 +599,19 @@ module Xolo
605
599
  process_method: :list_versions
606
600
  },
607
601
 
602
+ RERUN_AUTOPKG_RECIPE_CMD => {
603
+ desc: 'Run the AutoPkg recipe for this title again, and re-upload the new pkg.',
604
+ display: "#{RERUN_AUTOPKG_RECIPE_CMD} title",
605
+ long_desc: <<~ENDLONG,
606
+ The recipe will be run immediately, and the resulting .pkg will be re-uploaded for the latest version of the title.
607
+ ENDLONG
608
+ opts: {},
609
+ target: :title,
610
+ process_method: :rerun_autopkg_recipe,
611
+ streamed_response: true,
612
+ confirmation: true
613
+ },
614
+
608
615
  ADD_VERSION_CMD => {
609
616
  desc: 'Add a new version to a title, making it available for piloting',
610
617
  display: "#{ADD_VERSION_CMD} title version",
@@ -667,6 +674,8 @@ module Xolo
667
674
  Computers in any excluded-groups for the target will be removed from the list of targets
668
675
  before the MDM command is sent.
669
676
 
677
+ You can use the words '#{DEPLOY_RELEASED}' or '#{DEPLOY_LATEST}' as the version, or a specific one.
678
+
670
679
  Computers can be specified by name, serial number, or Jamf ID. Groups can be specified by
671
680
  name.
672
681
 
@@ -513,6 +513,24 @@ module Xolo
513
513
  handle_processing_error e
514
514
  end
515
515
 
516
+ # Re run the autopkg recipe
517
+ ################################
518
+ def rerun_autopkg_recipe
519
+ return unless confirmed? "Re-run the AutoPkg recipe for '#{cli_cmd.title}' and re-upload the new pkg"
520
+
521
+ title = Xolo::Admin::Title.fetch cli_cmd.title, server_cnx
522
+
523
+ response_data = title.rerun_autopkg_recipe server_cnx
524
+
525
+ show_debug "response_data: #{response_data}"
526
+
527
+ display_progress response_data[:progress_stream_url_path]
528
+
529
+ speak "Recipe is running for '#{cli_cmd.title}'. Upload to distribution points will happen soon."
530
+ rescue StandardError => e
531
+ handle_processing_error e
532
+ end
533
+
516
534
  # List all versions of a title in Xolo
517
535
  #
518
536
  # @return [void]
@@ -648,7 +666,23 @@ module Xolo
648
666
  # @return [void]
649
667
  ###############################
650
668
  def deploy_version
651
- return unless confirmed? "Deploy Version '#{cli_cmd.version}' of Title '#{cli_cmd.title}' via MDM?"
669
+ # If version is 'latest' or 'released', figure out the actual version to deploy
670
+ if Xolo::Admin::Options::DEPLOY_SPECIAL_VERSIONS.include? cli_cmd.version
671
+ title = Xolo::Admin::Title.fetch cli_cmd.title, server_cnx
672
+ vers_display =
673
+ case cli_cmd.version
674
+ when Xolo::Admin::Options::DEPLOY_RELEASED
675
+ cli_cmd.version = title.released_version
676
+ "#{cli_cmd.version} (#{Xolo::Admin::Options::DEPLOY_RELEASED})"
677
+ when Xolo::Admin::Options::DEPLOY_LATEST
678
+ cli_cmd.version = title.version_order.first
679
+ "#{cli_cmd.version} (#{Xolo::Admin::Options::DEPLOY_LATEST})"
680
+ else
681
+ cli_cmd.version
682
+ end
683
+ end
684
+
685
+ return unless confirmed? "Deploy Version '#{vers_display}' of Title '#{cli_cmd.title}' via MDM?"
652
686
 
653
687
  unless json? || quiet?
654
688
  puts "Deploying Version '#{cli_cmd.version}' of Title '#{cli_cmd.title}' to computers: #{ARGV.join(', ')}"
@@ -216,6 +216,15 @@ module Xolo
216
216
  resp.body
217
217
  end
218
218
 
219
+ # Rerun the autopkg recipe for this title
220
+ # @param cnx [Faraday::Connection] The connection to use, must be logged in already
221
+ # @return [Hash] the response data
222
+ #########################
223
+ def rerun_autopkg_recipe(_nx = cnx)
224
+ resp = cnx.post "#{SERVER_ROUTE}/#{title}/rerun_autopkg_recipe", {}
225
+ resp.body
226
+ end
227
+
219
228
  # Fetch the frozen computers for this title
220
229
  # @param cnx [Faraday::Connection] The connection to use, must be logged in already
221
230
  # @return [Hash{String => String}] computer name => user name
@@ -12,7 +12,7 @@ module Xolo
12
12
 
13
13
  module Version
14
14
 
15
- VERSION = '2.2.4'.freeze
15
+ VERSION = '2.4.0'.freeze
16
16
 
17
17
  end
18
18
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xolo-admin
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.4
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Lasell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-08-24 00:00:00.000000000 Z
11
+ date: 2026-09-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday