xolo-server 1.0.0 → 2.0.2
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/README.md +42 -4
- data/bin/xoloserver +3 -0
- data/data/client/xolo +1233 -0
- data/lib/optimist_with_insert_blanks.rb +1216 -0
- data/lib/xolo/core/base_classes/configuration.rb +238 -0
- data/lib/xolo/core/base_classes/server_object.rb +112 -0
- data/lib/xolo/core/base_classes/title.rb +884 -0
- data/lib/xolo/core/base_classes/version.rb +641 -0
- data/lib/xolo/core/constants.rb +85 -0
- data/lib/xolo/core/exceptions.rb +52 -0
- data/lib/xolo/core/json_wrappers.rb +43 -0
- data/lib/xolo/core/loading.rb +59 -0
- data/lib/xolo/core/output.rb +292 -0
- data/lib/xolo/core/security_cmd.rb +128 -0
- data/lib/xolo/core/version.rb +21 -0
- data/lib/xolo/core.rb +47 -0
- data/lib/xolo/server/app.rb +7 -0
- data/lib/xolo/server/configuration.rb +243 -38
- data/lib/xolo/server/constants.rb +10 -0
- data/lib/xolo/server/helpers/auth.rb +19 -2
- data/lib/xolo/server/helpers/autopkg.rb +157 -0
- data/lib/xolo/server/helpers/client_data.rb +90 -60
- data/lib/xolo/server/helpers/file_transfers.rb +412 -82
- data/lib/xolo/server/helpers/jamf_pro.rb +31 -7
- data/lib/xolo/server/helpers/log.rb +2 -0
- data/lib/xolo/server/helpers/maintenance.rb +1 -0
- data/lib/xolo/server/helpers/notification.rb +4 -3
- data/lib/xolo/server/helpers/pkg_signing.rb +16 -12
- data/lib/xolo/server/helpers/progress_streaming.rb +9 -12
- data/lib/xolo/server/helpers/subscriptions.rb +119 -0
- data/lib/xolo/server/helpers/titles.rb +27 -3
- data/lib/xolo/server/helpers/versions.rb +23 -11
- data/lib/xolo/server/mixins/changelog.rb +9 -16
- data/lib/xolo/server/mixins/title_jamf_access.rb +375 -390
- data/lib/xolo/server/mixins/title_ted_access.rb +50 -8
- data/lib/xolo/server/mixins/version_jamf_access.rb +118 -129
- data/lib/xolo/server/mixins/version_ted_access.rb +34 -4
- data/lib/xolo/server/object_locks.rb +2 -1
- data/lib/xolo/server/routes/auth.rb +2 -2
- data/lib/xolo/server/routes/jamf_pro.rb +11 -1
- data/lib/xolo/server/routes/maint.rb +2 -1
- data/lib/xolo/server/routes/subscriptions.rb +126 -0
- data/lib/xolo/server/routes/title_editor.rb +1 -1
- data/lib/xolo/server/routes/titles.rb +26 -11
- data/lib/xolo/server/routes/uploads.rb +0 -14
- data/lib/xolo/server/routes/versions.rb +14 -13
- data/lib/xolo/server/routes.rb +15 -23
- data/lib/xolo/server/title.rb +100 -77
- data/lib/xolo/server/version.rb +178 -18
- data/lib/xolo/server.rb +8 -0
- metadata +20 -11
data/lib/xolo/server/title.rb
CHANGED
|
@@ -72,38 +72,11 @@ module Xolo
|
|
|
72
72
|
# on the xolo server.
|
|
73
73
|
UNINSTALL_SCRIPT_FILENAME = 'uninstall-script'
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
# The key is this value as a prefix on the title
|
|
81
|
-
# so for title 'foobar', it is 'xolo-foobar'
|
|
82
|
-
# That value is also used as the display name
|
|
83
|
-
TITLE_EDITOR_EA_KEY_PREFIX = Xolo::Server::JAMF_OBJECT_NAME_PFX
|
|
84
|
-
|
|
85
|
-
# The EA from the title editor, which is used in Jamf Patch
|
|
86
|
-
# cannot, unfortunately, be used as a criterion in normal
|
|
87
|
-
# smart groups or advanced searches.
|
|
88
|
-
# Since we need a smart group containing all macs with any
|
|
89
|
-
# version of the title installed, we need a second copy of the
|
|
90
|
-
# EA as a 'normal' EA.
|
|
91
|
-
#
|
|
92
|
-
# (That group is used as an exclusion to any auto-install initial-
|
|
93
|
-
# install policies, so that those policies don't stomp on the matching
|
|
94
|
-
# Patch Policies)
|
|
95
|
-
#
|
|
96
|
-
# The 'duplicate' EA is named the same as the Titled Editor key
|
|
97
|
-
# (see TITLE_EDITOR_EA_KEY_PREFIX) with this suffix added.
|
|
98
|
-
# So for the Title Editor key 'xolo-<title>', we'll also have
|
|
99
|
-
# a matching normal EA called 'xolo-<title>-installed-version'
|
|
100
|
-
JAMF_NORMAL_EA_NAME_SUFFIX = '-installed-version'
|
|
101
|
-
|
|
102
|
-
JAMF_INSTALLED_GROUP_NAME_SUFFIX = '-installed'
|
|
103
|
-
JAMF_FROZEN_GROUP_NAME_SUFFIX = '-frozen'
|
|
104
|
-
|
|
105
|
-
JAMF_UNINSTALL_SUFFIX = '-uninstall'
|
|
106
|
-
JAMF_EXPIRE_SUFFIX = '-expire'
|
|
75
|
+
JAMF_INSTALLED_GROUP_NAME_SUFFIX = 'installed'
|
|
76
|
+
JAMF_FROZEN_GROUP_NAME_SUFFIX = 'frozen'
|
|
77
|
+
JAMF_MANUAL_INSTALL_RELEASED_POL_SUFFIX = 'install'
|
|
78
|
+
JAMF_UNINSTALL_SUFFIX = 'uninstall'
|
|
79
|
+
JAMF_EXPIRE_SUFFIX = 'expire'
|
|
107
80
|
|
|
108
81
|
# the expire policy will run this client command,
|
|
109
82
|
# appending the title
|
|
@@ -164,20 +137,6 @@ module Xolo
|
|
|
164
137
|
title_dirs.map(&:basename).map(&:to_s)
|
|
165
138
|
end
|
|
166
139
|
|
|
167
|
-
# @return [String] The key and display name of a version script stored
|
|
168
|
-
# in the title editor as the ExtAttr for a given title
|
|
169
|
-
#####################
|
|
170
|
-
def self.ted_ea_key(title)
|
|
171
|
-
"#{TITLE_EDITOR_EA_KEY_PREFIX}#{title}"
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
# @return [String] The display name of a version script as a normal
|
|
175
|
-
# EA in Jamf, which can be used in Smart Groups and Adv Searches.
|
|
176
|
-
#####################
|
|
177
|
-
def self.jamf_normal_ea_name(title)
|
|
178
|
-
"#{ted_ea_key(title)}#{JAMF_NORMAL_EA_NAME_SUFFIX}"
|
|
179
|
-
end
|
|
180
|
-
|
|
181
140
|
# The title dir for a given title on the server,
|
|
182
141
|
# which may or may not exist.
|
|
183
142
|
#
|
|
@@ -228,7 +187,8 @@ module Xolo
|
|
|
228
187
|
# for the given title
|
|
229
188
|
#
|
|
230
189
|
# NOTE: All instantiation should happen using the #instantiate_title method
|
|
231
|
-
# in the server app instance
|
|
190
|
+
# in the server app instance, or related methods like all_title_objects.
|
|
191
|
+
# Please don't call this method directly
|
|
232
192
|
#
|
|
233
193
|
# @pararm title [String] the title we care about
|
|
234
194
|
# @return [Xolo::Server::Title] load an existing title
|
|
@@ -239,6 +199,10 @@ module Xolo
|
|
|
239
199
|
new parse_json(title_data_file(title).read)
|
|
240
200
|
end
|
|
241
201
|
|
|
202
|
+
# Does this title exist in the title editor.
|
|
203
|
+
# WARNING: Being in the title editor doesn't necessarily mean that this title
|
|
204
|
+
# is managed
|
|
205
|
+
#
|
|
242
206
|
# @param title [String] the title we are looking for
|
|
243
207
|
# @pararm cnx [Windoo::Connection] The Title Editor connection to use
|
|
244
208
|
# @return [Boolean] Does the given title exist in the Title Editor?
|
|
@@ -325,9 +289,6 @@ module Xolo
|
|
|
325
289
|
# @return [Xolo::Server::App] our Sinatra server app
|
|
326
290
|
attr_accessor :server_app_instance
|
|
327
291
|
|
|
328
|
-
# @return [Integer] The Windoo::SoftwareTitle#softwareTitleId
|
|
329
|
-
attr_accessor :ted_id_number
|
|
330
|
-
|
|
331
292
|
# when applying updates, the new data from xadm is stored
|
|
332
293
|
# here so it can be accessed by update-methods
|
|
333
294
|
# and compared to the current instance values
|
|
@@ -363,6 +324,13 @@ module Xolo
|
|
|
363
324
|
# version being released
|
|
364
325
|
attr_accessor :releasing_version
|
|
365
326
|
|
|
327
|
+
# @return [String] The jamf ID of the patch source for this title
|
|
328
|
+
# if the title is subscribed. Managed titles are all in the Title Editor source.
|
|
329
|
+
attr_accessor :jamf_patch_source_id
|
|
330
|
+
|
|
331
|
+
# @return [String] The prefix for all jamf objects for this title, which is 'xolo-<title>' or 'xolotest-<title>' for test server
|
|
332
|
+
attr_reader :jamf_obj_name_pfx
|
|
333
|
+
|
|
366
334
|
# version_order is defined in ATTRIBUTES
|
|
367
335
|
alias versions version_order
|
|
368
336
|
|
|
@@ -376,19 +344,24 @@ module Xolo
|
|
|
376
344
|
def initialize(data_hash)
|
|
377
345
|
super
|
|
378
346
|
|
|
379
|
-
|
|
380
|
-
|
|
347
|
+
# ted_id_number and jamf_patch_title_id are now defined in parent classes ATTRIBUTES so are set by super
|
|
348
|
+
|
|
381
349
|
@version_order ||= []
|
|
350
|
+
|
|
382
351
|
@new_data_for_update = {}
|
|
383
352
|
@changes_for_update = {}
|
|
384
|
-
@jamf_installed_group_name = "#{Xolo::Server::JAMF_OBJECT_NAME_PFX}#{data_hash[:title]}#{JAMF_INSTALLED_GROUP_NAME_SUFFIX}"
|
|
385
|
-
@jamf_frozen_group_name = "#{Xolo::Server::JAMF_OBJECT_NAME_PFX}#{data_hash[:title]}#{JAMF_FROZEN_GROUP_NAME_SUFFIX}"
|
|
386
353
|
|
|
387
|
-
@
|
|
354
|
+
@jamf_obj_name_pfx = "#{jamf_obj_name_pfx_base}#{data_hash[:title]}"
|
|
355
|
+
@jamf_installed_group_name = "#{jamf_obj_name_pfx}-#{JAMF_INSTALLED_GROUP_NAME_SUFFIX}"
|
|
356
|
+
@jamf_frozen_group_name = "#{jamf_obj_name_pfx}-#{JAMF_FROZEN_GROUP_NAME_SUFFIX}"
|
|
357
|
+
|
|
358
|
+
@jamf_manual_install_released_policy_name = "#{jamf_obj_name_pfx}-#{JAMF_MANUAL_INSTALL_RELEASED_POL_SUFFIX}"
|
|
359
|
+
|
|
360
|
+
@jamf_uninstall_script_name = "#{jamf_obj_name_pfx}-#{JAMF_UNINSTALL_SUFFIX}"
|
|
361
|
+
@jamf_uninstall_policy_name = "#{jamf_obj_name_pfx}-#{JAMF_UNINSTALL_SUFFIX}"
|
|
362
|
+
@jamf_expire_policy_name = "#{jamf_obj_name_pfx}-#{JAMF_EXPIRE_SUFFIX}"
|
|
388
363
|
|
|
389
|
-
|
|
390
|
-
@jamf_uninstall_policy_name = "#{Xolo::Server::JAMF_OBJECT_NAME_PFX}#{data_hash[:title]}#{JAMF_UNINSTALL_SUFFIX}"
|
|
391
|
-
@jamf_expire_policy_name = "#{Xolo::Server::JAMF_OBJECT_NAME_PFX}#{data_hash[:title]}#{JAMF_EXPIRE_SUFFIX}"
|
|
364
|
+
# DO NOT USE jamf_cnx here, it comes from the server app instance, which is not set until after initialization.
|
|
392
365
|
end
|
|
393
366
|
|
|
394
367
|
# Instance Methods
|
|
@@ -402,10 +375,12 @@ module Xolo
|
|
|
402
375
|
# @session ||= {}
|
|
403
376
|
end
|
|
404
377
|
|
|
378
|
+
# This can be manually set earlier in the request handling to use a non-standard
|
|
379
|
+
# admin username
|
|
405
380
|
# @return [String]
|
|
406
381
|
###################
|
|
407
382
|
def admin
|
|
408
|
-
session[:admin]
|
|
383
|
+
@admin ||= session[:admin]
|
|
409
384
|
end
|
|
410
385
|
|
|
411
386
|
# @return [Boolean] Are we creating this title?
|
|
@@ -438,6 +413,22 @@ module Xolo
|
|
|
438
413
|
current_action == :releasing
|
|
439
414
|
end
|
|
440
415
|
|
|
416
|
+
# TODO: Remove this when everything has been repaired for v2
|
|
417
|
+
# and all json files know this value
|
|
418
|
+
#######################
|
|
419
|
+
def jamf_patch_title_id
|
|
420
|
+
return @jamf_patch_title_id if @jamf_patch_title_id
|
|
421
|
+
|
|
422
|
+
log_debug "Getting jamf_patch_title_id for title '#{title}'"
|
|
423
|
+
|
|
424
|
+
self.jamf_patch_title_id =
|
|
425
|
+
if managed?
|
|
426
|
+
jamf_active_managed_titles[title]
|
|
427
|
+
else
|
|
428
|
+
jamf_active_subscribed_titles[title]
|
|
429
|
+
end
|
|
430
|
+
end
|
|
431
|
+
|
|
441
432
|
# Append a message to the progress stream file,
|
|
442
433
|
# optionally sending it also to the log
|
|
443
434
|
#
|
|
@@ -448,8 +439,8 @@ module Xolo
|
|
|
448
439
|
#
|
|
449
440
|
# @return [void]
|
|
450
441
|
###################
|
|
451
|
-
def progress(msg, log: :debug)
|
|
452
|
-
server_app_instance.progress msg, log: log
|
|
442
|
+
def progress(msg, log: :debug, alert: false)
|
|
443
|
+
server_app_instance.progress msg, log: log, alert: alert
|
|
453
444
|
end
|
|
454
445
|
|
|
455
446
|
# @return [Windoo::Connection] a single Title Editor connection to use for
|
|
@@ -589,13 +580,6 @@ module Xolo
|
|
|
589
580
|
template_file.read
|
|
590
581
|
end
|
|
591
582
|
|
|
592
|
-
# @return [String] The display name of a version script as a normal
|
|
593
|
-
# EA in Jamf, which can be used in Smart Groups and Adv Searches.
|
|
594
|
-
#####################
|
|
595
|
-
def jamf_normal_ea_name
|
|
596
|
-
@jamf_normal_ea_name ||= self.class.jamf_normal_ea_name title
|
|
597
|
-
end
|
|
598
|
-
|
|
599
583
|
# prepend a new version to the version_order
|
|
600
584
|
#
|
|
601
585
|
# @param version [String] the version to prepend
|
|
@@ -603,11 +587,8 @@ module Xolo
|
|
|
603
587
|
# @return [void]
|
|
604
588
|
########################
|
|
605
589
|
def prepend_version(version)
|
|
606
|
-
lock
|
|
607
590
|
version_order.unshift version
|
|
608
591
|
save_local_data
|
|
609
|
-
ensure
|
|
610
|
-
unlock
|
|
611
592
|
end
|
|
612
593
|
|
|
613
594
|
# remove a version from the version_order
|
|
@@ -670,8 +651,13 @@ module Xolo
|
|
|
670
651
|
self.created_by = admin
|
|
671
652
|
log_debug "creation_date: #{creation_date}, created_by: #{created_by}"
|
|
672
653
|
|
|
654
|
+
log_debug "TitleData at #create: #{to_h}"
|
|
655
|
+
|
|
673
656
|
# this will create the title as needed in the Title Editor
|
|
657
|
+
log_debug "Display Name before creating in ted: #{display_name}"
|
|
674
658
|
create_title_in_ted
|
|
659
|
+
|
|
660
|
+
log_debug "Display Name before creating in jamf: #{display_name}"
|
|
675
661
|
create_title_in_jamf
|
|
676
662
|
|
|
677
663
|
# save to file last, because saving to TitleEd and Jamf will
|
|
@@ -679,6 +665,16 @@ module Xolo
|
|
|
679
665
|
progress 'Saving title data to Xolo server'
|
|
680
666
|
save_local_data
|
|
681
667
|
|
|
668
|
+
if subscribed?
|
|
669
|
+
# create version for latest available
|
|
670
|
+
# - either autopkg or notification to upload.
|
|
671
|
+
# See also Helpers::Subscriptions.process_patch_title_updated_webhook
|
|
672
|
+
Xolo::Server::Version.add_version_via_subscription(
|
|
673
|
+
title_object: self,
|
|
674
|
+
new_version: patch_versions(version: :latest)[0][:version]
|
|
675
|
+
)
|
|
676
|
+
end # if subscribed
|
|
677
|
+
|
|
682
678
|
log_change msg: 'Title Created'
|
|
683
679
|
|
|
684
680
|
# ssvc icon is uploaded in a separate process, and the
|
|
@@ -776,6 +772,9 @@ module Xolo
|
|
|
776
772
|
# @return [void]
|
|
777
773
|
##########################
|
|
778
774
|
def save_local_data
|
|
775
|
+
# If we don't have a patch source id yet, get it now
|
|
776
|
+
self.jamf_patch_source_id ||= Jamf::PatchSource.valid_id(patch_source, cnx: jamf_cnx) if patch_source
|
|
777
|
+
|
|
779
778
|
# create the dirs for the title
|
|
780
779
|
title_dir.mkpath
|
|
781
780
|
vdir = title_dir + Xolo::Server::Version::VERSIONS_DIRNAME
|
|
@@ -838,6 +837,17 @@ module Xolo
|
|
|
838
837
|
self.uninstall_script &&= Xolo::ITEM_UPLOADED
|
|
839
838
|
end
|
|
840
839
|
|
|
840
|
+
# Is AutoPkg integration enabled for the server and title?
|
|
841
|
+
# This overrides the method in core title, which just checks for the presence of the recipe and dir.
|
|
842
|
+
###############################
|
|
843
|
+
def autopkg_enabled?
|
|
844
|
+
return @autopkg_enabled if defined?(@autopkg_enabled)
|
|
845
|
+
|
|
846
|
+
@autopkg_enabled = server_app_instance.autopkg_enabled? && \
|
|
847
|
+
autopkg_recipe && \
|
|
848
|
+
autopkg_dir
|
|
849
|
+
end
|
|
850
|
+
|
|
841
851
|
# are we uninstallable?
|
|
842
852
|
#
|
|
843
853
|
# @return [Boolean]
|
|
@@ -908,10 +918,10 @@ module Xolo
|
|
|
908
918
|
version_objects.reverse.each do |vers|
|
|
909
919
|
# vers might be nil if it was already deleted
|
|
910
920
|
# e.g. a prev. attempt to delete the title failed partway through
|
|
911
|
-
vers&.delete update_title: false
|
|
921
|
+
vers&.delete update_title: false, deleting_title: true
|
|
912
922
|
end
|
|
913
923
|
|
|
914
|
-
delete_title_from_ted
|
|
924
|
+
delete_title_from_ted unless subscribed?
|
|
915
925
|
|
|
916
926
|
delete_title_from_jamf
|
|
917
927
|
|
|
@@ -940,6 +950,9 @@ module Xolo
|
|
|
940
950
|
|
|
941
951
|
update_versions_for_release version_to_release
|
|
942
952
|
|
|
953
|
+
# the jamf 'manual install released' policy for the new release
|
|
954
|
+
# is updated in the release_version method below
|
|
955
|
+
|
|
943
956
|
# update the title
|
|
944
957
|
self.released_version = version_to_release
|
|
945
958
|
save_local_data
|
|
@@ -1008,8 +1021,14 @@ module Xolo
|
|
|
1008
1021
|
progress msg, log: :info
|
|
1009
1022
|
|
|
1010
1023
|
pol = jamf_manual_install_released_policy
|
|
1011
|
-
|
|
1012
|
-
|
|
1024
|
+
toggle_jamf_manual_install_released_policy pol, vobj
|
|
1025
|
+
|
|
1026
|
+
if self_service?
|
|
1027
|
+
add_title_to_self_service(pol)
|
|
1028
|
+
else
|
|
1029
|
+
remove_title_from_self_service(pol)
|
|
1030
|
+
end
|
|
1031
|
+
|
|
1013
1032
|
pol.save
|
|
1014
1033
|
end
|
|
1015
1034
|
|
|
@@ -1058,7 +1077,6 @@ module Xolo
|
|
|
1058
1077
|
#
|
|
1059
1078
|
# Then look at the various Jamf objects pertaining to this title, and ensure they are correct
|
|
1060
1079
|
# - Accept Patch EA
|
|
1061
|
-
# - Normal EA 'xolo-<title>-installed-version'
|
|
1062
1080
|
# - title-installed smart group 'xolo-<title>-installed'
|
|
1063
1081
|
# - frozen static group 'xolo-<title>-frozen'
|
|
1064
1082
|
# - manual/SSvc install-current-release policy 'xolo-<title>-install'
|
|
@@ -1085,6 +1103,7 @@ module Xolo
|
|
|
1085
1103
|
progress "Starting repair of title '#{title}'"
|
|
1086
1104
|
repair_ted_title
|
|
1087
1105
|
repair_jamf_title_objects
|
|
1106
|
+
save_local_data
|
|
1088
1107
|
return unless repair_versions
|
|
1089
1108
|
|
|
1090
1109
|
version_objects.each do |vobj|
|
|
@@ -1114,7 +1133,7 @@ module Xolo
|
|
|
1114
1133
|
|
|
1115
1134
|
exp = Time.now + Xolo::Server::ObjectLocks::OBJECT_LOCK_LIMIT
|
|
1116
1135
|
Xolo::Server.object_locks[title][:expires] = exp
|
|
1117
|
-
log_debug "Locked title '#{title}' for updates until #{exp}"
|
|
1136
|
+
log_debug "Locked title '#{title}' for updates until #{exp}, by method #{caller_locations.first.label}"
|
|
1118
1137
|
end
|
|
1119
1138
|
|
|
1120
1139
|
# Unlock this v for updates
|
|
@@ -1131,7 +1150,11 @@ module Xolo
|
|
|
1131
1150
|
###########################
|
|
1132
1151
|
def to_h
|
|
1133
1152
|
hash = super
|
|
1153
|
+
|
|
1154
|
+
# TODO: remove these after 'repairing' everything for v2
|
|
1134
1155
|
hash[:ted_id_number] = ted_id_number
|
|
1156
|
+
hash[:jamf_patch_title_id] = jamf_patch_title_id
|
|
1157
|
+
|
|
1135
1158
|
hash[:ssvc_icon_id] = ssvc_icon_id
|
|
1136
1159
|
hash
|
|
1137
1160
|
end
|
data/lib/xolo/server/version.rb
CHANGED
|
@@ -223,12 +223,86 @@ module Xolo
|
|
|
223
223
|
}
|
|
224
224
|
end
|
|
225
225
|
|
|
226
|
+
# add a new version in response to a patch title update webhook event.
|
|
227
|
+
# This doesn't upload a pkg - it just creates the version in Xolo, and then
|
|
228
|
+
# someone can upload a pkg to it via xadm or autopkg will do it if configured.
|
|
229
|
+
#
|
|
230
|
+
# @param title_object [Xolo::Server::Title] the title object for the subscribed title
|
|
231
|
+
# @param new_version [String] the new version to add
|
|
232
|
+
# @return [void]
|
|
233
|
+
######################
|
|
234
|
+
def self.add_version_via_subscription(title_object:, new_version:)
|
|
235
|
+
title_object.log_info "Adding new version '#{new_version}' for subscribed title '#{title_object.title}'"
|
|
236
|
+
|
|
237
|
+
# get more details about this version from the JPAPI
|
|
238
|
+
patch_version_data = title_object.patch_versions(version: new_version).first
|
|
239
|
+
unless patch_version_data
|
|
240
|
+
msg = "Could not get patch version data from JPAPI for version '#{new_version}' of subscribed title '#{title_object.title}'. Cannot create new version in Xolo without this data. Aborting."
|
|
241
|
+
title_object.log_error msg, alert: true
|
|
242
|
+
return
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
title_object.log_debug "Got patch version data from JPAPI for version '#{new_version}': #{patch_version_data}"
|
|
246
|
+
|
|
247
|
+
# put the data into a hash for creating a new version object
|
|
248
|
+
vobj_data = {
|
|
249
|
+
publish_date: Time.parse(patch_version_data[:releaseDate]),
|
|
250
|
+
standalone: patch_version_data[:standalone],
|
|
251
|
+
min_os: patch_version_data[:minimumOperatingSystem],
|
|
252
|
+
reboot: patch_version_data[:rebootRequired],
|
|
253
|
+
killapps: []
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
# Killapps for subscribed titles? The API only shows app names without the .app, e.g.
|
|
257
|
+
# "killApps": [
|
|
258
|
+
# {
|
|
259
|
+
# "appName": "ChrislTestHelper"
|
|
260
|
+
# },
|
|
261
|
+
# {
|
|
262
|
+
# "appName": "Chrisl Test"
|
|
263
|
+
# }
|
|
264
|
+
# ]
|
|
265
|
+
# Since we don't manage them, we'll just record them in the data like this...
|
|
266
|
+
unless patch_version_data[:killApps].pix_empty?
|
|
267
|
+
patch_version_data[:killApps].each do |ka|
|
|
268
|
+
vobj_data[:killapps] << "#{ka[:appName]}.app;unknown.from.subscription"
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# instantiate the version object
|
|
273
|
+
title_object.log_debug "Instantiating version via subscription '#{new_version}' of title '#{title_object.title}' (#{title_object.class}) with data: #{vobj_data}"
|
|
274
|
+
|
|
275
|
+
vobj = title_object.server_app_instance.instantiate_version(
|
|
276
|
+
title: title_object,
|
|
277
|
+
version: new_version,
|
|
278
|
+
**vobj_data
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
# create it in xolo
|
|
282
|
+
vobj.create
|
|
283
|
+
|
|
284
|
+
# tell someone
|
|
285
|
+
msg = "ACTION REQUIRED: New pilot version '#{new_version}' for subscribed title '#{title_object.title}' has been created in Xolo via subscription."
|
|
286
|
+
|
|
287
|
+
# if not autopkg enabled, we need to tell someone to upload a pkg for this new version
|
|
288
|
+
unless title_object.autopkg_enabled?
|
|
289
|
+
# update general alert msg
|
|
290
|
+
msg = "#{msg}\nPlease upload a .pkg for it ASAP using this command:\n xadm edit-version #{title_object.title} #{new_version} --pkg-to-upload /path/to/installer.pkg"
|
|
291
|
+
|
|
292
|
+
# email to title contact
|
|
293
|
+
vobj.server_app_instance.send_email to: title_object.contact_email, subject: 'Need manual upload of xolo pkg', msg: msg
|
|
294
|
+
end # if title_object.autopkg_enabled?
|
|
295
|
+
|
|
296
|
+
# send general alert
|
|
297
|
+
vobj.log_info msg, alert: true
|
|
298
|
+
end
|
|
299
|
+
|
|
226
300
|
# Attributes
|
|
227
301
|
######################
|
|
228
302
|
######################
|
|
229
303
|
|
|
230
304
|
# The instance of Xolo::Server::App that instantiated this
|
|
231
|
-
#
|
|
305
|
+
# version object. This is how we access things that are available in routes
|
|
232
306
|
# and helpers, like the single Jamf and TEd
|
|
233
307
|
# connections for this App instance.
|
|
234
308
|
attr_accessor :server_app_instance
|
|
@@ -297,6 +371,9 @@ module Xolo
|
|
|
297
371
|
# one of :creating, :updating, :deleting
|
|
298
372
|
attr_accessor :current_action
|
|
299
373
|
|
|
374
|
+
# @return [Boolean] is the pkg being processed now from an autopkg recipe?
|
|
375
|
+
attr_accessor :pkg_is_from_autopkg
|
|
376
|
+
|
|
300
377
|
# Constructor
|
|
301
378
|
######################
|
|
302
379
|
######################
|
|
@@ -314,15 +391,15 @@ module Xolo
|
|
|
314
391
|
@jamf_pkg_id ||= data_hash[:jamf_pkg_id]
|
|
315
392
|
|
|
316
393
|
# and these can be generated now
|
|
317
|
-
@jamf_obj_name_pfx = "#{
|
|
394
|
+
@jamf_obj_name_pfx = "#{jamf_obj_name_pfx_base}#{title}-#{version}"
|
|
318
395
|
|
|
319
396
|
@jamf_pkg_name ||= @jamf_obj_name_pfx
|
|
320
397
|
|
|
321
|
-
@jamf_installed_group_name = "#{jamf_obj_name_pfx}
|
|
398
|
+
@jamf_installed_group_name = "#{jamf_obj_name_pfx}-#{JAMF_SMART_GROUP_NAME_INSTALLED_SFX}"
|
|
322
399
|
|
|
323
|
-
@jamf_auto_install_policy_name = "#{jamf_obj_name_pfx}
|
|
324
|
-
@jamf_manual_install_policy_name = "#{jamf_obj_name_pfx}
|
|
325
|
-
@jamf_auto_reinstall_policy_name = "#{jamf_obj_name_pfx}
|
|
400
|
+
@jamf_auto_install_policy_name = "#{jamf_obj_name_pfx}-#{JAMF_POLICY_NAME_AUTO_INSTALL_SFX}"
|
|
401
|
+
@jamf_manual_install_policy_name = "#{jamf_obj_name_pfx}-#{JAMF_POLICY_NAME_MANUAL_INSTALL_SFX}"
|
|
402
|
+
@jamf_auto_reinstall_policy_name = "#{jamf_obj_name_pfx}-#{JAMF_POLICY_NAME_AUTO_REINSTALL_SFX}"
|
|
326
403
|
|
|
327
404
|
@jamf_patch_policy_name = @jamf_obj_name_pfx
|
|
328
405
|
|
|
@@ -391,7 +468,17 @@ module Xolo
|
|
|
391
468
|
def pilot_groups_to_use
|
|
392
469
|
return @pilot_groups_to_use if @pilot_groups_to_use
|
|
393
470
|
|
|
471
|
+
# any defined in the version override any in the title
|
|
394
472
|
@pilot_groups_to_use = changes_for_update&.key?(:pilot_groups) ? changes_for_update[:pilot_groups][:new] : pilot_groups
|
|
473
|
+
return @pilot_groups_to_use unless @pilot_groups_to_use.empty?
|
|
474
|
+
|
|
475
|
+
# if none defined in the version, look in the title
|
|
476
|
+
@pilot_groups_to_use =
|
|
477
|
+
if title_object.changes_for_update&.key?(:pilot_groups)
|
|
478
|
+
title_object.changes_for_update[:pilot_groups][:new]
|
|
479
|
+
else
|
|
480
|
+
title_object.pilot_groups
|
|
481
|
+
end
|
|
395
482
|
end
|
|
396
483
|
|
|
397
484
|
# The scope excluded groups to use in policies and patch policies for all versions of
|
|
@@ -456,10 +543,12 @@ module Xolo
|
|
|
456
543
|
# @session ||= {}
|
|
457
544
|
end
|
|
458
545
|
|
|
546
|
+
# This can be manually set earlier in the request handling to use a non-standard
|
|
547
|
+
# admin username
|
|
459
548
|
# @return [String]
|
|
460
549
|
###################
|
|
461
550
|
def admin
|
|
462
|
-
session[:admin]
|
|
551
|
+
@admin ||= session[:admin]
|
|
463
552
|
end
|
|
464
553
|
|
|
465
554
|
# Append a message to the progress stream file,
|
|
@@ -472,8 +561,8 @@ module Xolo
|
|
|
472
561
|
#
|
|
473
562
|
# @return [void]
|
|
474
563
|
###################
|
|
475
|
-
def progress(msg, log: :debug)
|
|
476
|
-
server_app_instance.progress msg, log: log
|
|
564
|
+
def progress(msg, log: :debug, alert: false)
|
|
565
|
+
server_app_instance.progress msg, log: log, alert: alert
|
|
477
566
|
end
|
|
478
567
|
|
|
479
568
|
# This might have been set already if we were instantiated via our title
|
|
@@ -559,9 +648,7 @@ module Xolo
|
|
|
559
648
|
progress 'Saving version data to Xolo server'
|
|
560
649
|
save_local_data
|
|
561
650
|
|
|
562
|
-
create_patch_in_ted
|
|
563
|
-
enable_ted_patch
|
|
564
|
-
title_object.enable_ted_title
|
|
651
|
+
create_patch_in_ted unless subscribed?
|
|
565
652
|
|
|
566
653
|
create_in_jamf
|
|
567
654
|
|
|
@@ -578,10 +665,68 @@ module Xolo
|
|
|
578
665
|
log_change msg: 'Version Created'
|
|
579
666
|
|
|
580
667
|
progress "Version '#{version}' of Title '#{title}' has been created in Xolo.", log: :info
|
|
668
|
+
|
|
669
|
+
# all done unless we need to get a pkg via autopkg
|
|
670
|
+
# pkg upload from xadm will happen in a separate process,
|
|
671
|
+
# so we don't want to do it here in the create method
|
|
672
|
+
|
|
673
|
+
# do we have an uploaded pkg?
|
|
674
|
+
if pkg_to_upload.to_s.start_with? '/'
|
|
675
|
+
progress "Pkg will be uploaded to xolo via xadm shortly, from path '#{pkg_to_upload}'", log: :info
|
|
676
|
+
|
|
677
|
+
# if we have an autopkg recipe and dir, get the .pkg and upload it to Jamf
|
|
678
|
+
elsif title_object.autopkg_enabled?
|
|
679
|
+
handle_autopkg_during_create
|
|
680
|
+
|
|
681
|
+
# otherwise tell someone we need a .pkg
|
|
682
|
+
else
|
|
683
|
+
msg = "No --pkg-to-upload given for version '#{version}' of title #{title}, and no autopkg recipe enabled. Please upload a pkg via xadm or enable autopkg for this title."
|
|
684
|
+
|
|
685
|
+
# no alert when subscribed because a better alert mesg is sent from add_version_via_subscription
|
|
686
|
+
subscribed? ? progress(msg, log: :warn) : progress(msg, log: :warn, alert: true)
|
|
687
|
+
end
|
|
581
688
|
ensure
|
|
582
689
|
unlock
|
|
583
690
|
end
|
|
584
691
|
|
|
692
|
+
# Do autopkg stuff during creation
|
|
693
|
+
#
|
|
694
|
+
############################
|
|
695
|
+
def handle_autopkg_during_create
|
|
696
|
+
return unless title_object.autopkg_enabled?
|
|
697
|
+
|
|
698
|
+
pkg_src = title_object.run_autopkg_recipe
|
|
699
|
+
|
|
700
|
+
if pkg_src.nil?
|
|
701
|
+
msg = 'AutoPkg recipe is enabled for this title, but no pkg was found after running the recipe. Please check the AutoPkg recipe and the server log for details.'
|
|
702
|
+
progress msg, log: :warn, alert: true
|
|
703
|
+
return
|
|
704
|
+
end
|
|
705
|
+
|
|
706
|
+
oldest_allowed = Time.now - 1200 # 20 minutes ago
|
|
707
|
+
if pkg_src.mtime < oldest_allowed
|
|
708
|
+
msg = "AutoPkg recipe is enabled for this title, and a pkg was found after running the recipe, but it was last modified at #{pkg_src.mtime}, which is more than 20 minutes ago. To avoid accidentally uploading an old pkg, the server will not upload this pkg. Please check the AutoPkg recipe and the server log for details."
|
|
709
|
+
progress msg, log: :warn, alert: true
|
|
710
|
+
return
|
|
711
|
+
end
|
|
712
|
+
|
|
713
|
+
# this lets future code know that the pkg we're working with came from autopkg
|
|
714
|
+
self.pkg_is_from_autopkg = true
|
|
715
|
+
|
|
716
|
+
# Upload the pkg to Jamf, and associate it with this version
|
|
717
|
+
server_app_instance.process_and_upload_autopkg_pkg(title, self, pkg_src)
|
|
718
|
+
end
|
|
719
|
+
|
|
720
|
+
# Is this version part of a subscribed title?
|
|
721
|
+
def subscribed?
|
|
722
|
+
title_object.subscribed?
|
|
723
|
+
end
|
|
724
|
+
|
|
725
|
+
# or a managed title?
|
|
726
|
+
def managed?
|
|
727
|
+
!subscribed?
|
|
728
|
+
end
|
|
729
|
+
|
|
585
730
|
# Update a this version, updating to the
|
|
586
731
|
# local filesystem, Jamf Pro, and the Title Editor as needed
|
|
587
732
|
#
|
|
@@ -608,7 +753,6 @@ module Xolo
|
|
|
608
753
|
|
|
609
754
|
# update ted before jamf
|
|
610
755
|
update_patch_in_ted
|
|
611
|
-
enable_ted_patch
|
|
612
756
|
update_version_in_jamf
|
|
613
757
|
update_local_instance_values
|
|
614
758
|
save_local_data
|
|
@@ -669,13 +813,16 @@ module Xolo
|
|
|
669
813
|
progress "Fixing original upload date: #{new_date}, by: #{new_by}", log: :debug
|
|
670
814
|
self.upload_date = new_date
|
|
671
815
|
self.uploaded_by = new_by
|
|
672
|
-
|
|
816
|
+
|
|
673
817
|
end
|
|
818
|
+
save_local_data
|
|
674
819
|
ensure
|
|
675
820
|
unlock
|
|
676
821
|
end
|
|
677
822
|
|
|
678
823
|
# Release this version, possibly rolling back from a previously newer version
|
|
824
|
+
# This should only be called by the title. The initial 'release' action starts in the title,
|
|
825
|
+
# and then calls this method on the version to do the version-specific release steps.
|
|
679
826
|
#
|
|
680
827
|
# @param rollback [Boolean] If true, this version is being released as a rollback
|
|
681
828
|
#
|
|
@@ -689,6 +836,7 @@ module Xolo
|
|
|
689
836
|
progress msg, log: :info
|
|
690
837
|
pol = jamf_auto_install_policy
|
|
691
838
|
set_policy_release_groups pol
|
|
839
|
+
pol.enable
|
|
692
840
|
pol.save
|
|
693
841
|
|
|
694
842
|
# set scope targets of patch policy to all (in patch pols, 'all' means 'all eligible')
|
|
@@ -825,15 +973,25 @@ module Xolo
|
|
|
825
973
|
# know the version is gone. Set this to false when the title itself
|
|
826
974
|
# is being deleted and calling this method.
|
|
827
975
|
#
|
|
976
|
+
# @param deleting_title [Boolean] Is the title itself being deleted?
|
|
977
|
+
#
|
|
828
978
|
# @return [void]
|
|
829
979
|
##########################
|
|
830
|
-
def delete(update_title: true)
|
|
980
|
+
def delete(update_title: true, deleting_title: false)
|
|
831
981
|
lock
|
|
832
982
|
@current_action = :deleting
|
|
833
983
|
|
|
834
|
-
delete_patch_from_ted
|
|
835
984
|
delete_version_from_jamf
|
|
836
985
|
|
|
986
|
+
# NOTE: we no longer delete the patch from the Title Editor
|
|
987
|
+
# unless the whole title is being deleted, because
|
|
988
|
+
# patches may be needed for reporting purposes.
|
|
989
|
+
# When the title is deleted, the title's delete method
|
|
990
|
+
# will delete all patches for all versions.
|
|
991
|
+
# If other situations arise where we need to delete
|
|
992
|
+
# ted patches individually, set deleting_title to true.
|
|
993
|
+
delete_patch_from_ted if deleting_title && managed?
|
|
994
|
+
|
|
837
995
|
# remove from the title's list of versions
|
|
838
996
|
progress 'Deleting version from title data on the Xolo server', log: :debug
|
|
839
997
|
title_object.remove_version(version) if update_title
|
|
@@ -860,14 +1018,16 @@ module Xolo
|
|
|
860
1018
|
raise Xolo::ServerError, 'Server is shutting down' if Xolo::Server.shutting_down?
|
|
861
1019
|
|
|
862
1020
|
while locked?
|
|
863
|
-
|
|
1021
|
+
if (Time.now.to_i % 5).zero?
|
|
1022
|
+
log_debug "Method #{caller_locations.first.label} is waiting for update lock on Version '#{version}' of title '#{title}'..."
|
|
1023
|
+
end
|
|
864
1024
|
sleep 0.33
|
|
865
1025
|
end
|
|
866
1026
|
Xolo::Server.object_locks[title] ||= { versions: {} }
|
|
867
1027
|
|
|
868
1028
|
exp = Time.now + Xolo::Server::ObjectLocks::OBJECT_LOCK_LIMIT
|
|
869
1029
|
Xolo::Server.object_locks[title][:versions][version] = exp
|
|
870
|
-
log_debug "Locked version '#{version}' of title '#{title}' for updates until #{exp}"
|
|
1030
|
+
log_debug "Locked version '#{version}' of title '#{title}' for updates until #{exp}, by method #{caller_locations.first.label}"
|
|
871
1031
|
end
|
|
872
1032
|
|
|
873
1033
|
# Unlock this version for updates
|
data/lib/xolo/server.rb
CHANGED
|
@@ -27,6 +27,7 @@ require 'base64'
|
|
|
27
27
|
require 'resolv'
|
|
28
28
|
require 'shellwords'
|
|
29
29
|
require 'net/smtp'
|
|
30
|
+
require 'etc'
|
|
30
31
|
|
|
31
32
|
# Gems
|
|
32
33
|
######
|
|
@@ -102,6 +103,11 @@ module Xolo
|
|
|
102
103
|
##############################
|
|
103
104
|
##############################
|
|
104
105
|
|
|
106
|
+
################
|
|
107
|
+
def self.test_server?
|
|
108
|
+
Xolo::Server.config.test_server
|
|
109
|
+
end
|
|
110
|
+
|
|
105
111
|
################
|
|
106
112
|
def self.start_time
|
|
107
113
|
@start_time
|
|
@@ -194,6 +200,8 @@ require 'xolo/server/helpers/versions'
|
|
|
194
200
|
require 'xolo/server/helpers/client_data'
|
|
195
201
|
require 'xolo/server/helpers/file_transfers'
|
|
196
202
|
require 'xolo/server/helpers/maintenance'
|
|
203
|
+
require 'xolo/server/helpers/subscriptions'
|
|
204
|
+
require 'xolo/server/helpers/autopkg'
|
|
197
205
|
|
|
198
206
|
require 'xolo/server/configuration'
|
|
199
207
|
|