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 +4 -4
- data/data/client/xolo +110 -27
- data/lib/xolo/admin/options.rb +20 -11
- data/lib/xolo/admin/processing.rb +35 -1
- data/lib/xolo/admin/title.rb +9 -0
- data/lib/xolo/core/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9c667de0cc034e593ed21097a61d356497d18be62c6efa84d681459138457e5c
|
|
4
|
+
data.tar.gz: 28c33bd6e5eeb50864a7faca5342381a7929354c7eb052d62e6efa377c14ef08
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
|
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
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
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
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
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
|
-
|
|
391
|
-
|
|
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
|
-
|
|
1161
|
+
installed_titles_report="$installed_titles_report\n$ttl"
|
|
1079
1162
|
else
|
|
1080
|
-
|
|
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
|
-
|
|
1200
|
+
installed_titles_report="$installed_titles_report\n$ttl"
|
|
1118
1201
|
else
|
|
1119
|
-
|
|
1202
|
+
installed_titles_report="$installed_titles_report\n$ttl ($inst_app_vers)"
|
|
1120
1203
|
fi
|
|
1121
1204
|
}
|
|
1122
1205
|
|
data/lib/xolo/admin/options.rb
CHANGED
|
@@ -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
|
-
|
|
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(', ')}"
|
data/lib/xolo/admin/title.rb
CHANGED
|
@@ -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
|
data/lib/xolo/core/version.rb
CHANGED
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.
|
|
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-
|
|
11
|
+
date: 2026-09-21 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|