xolo-server 2.2.2 → 2.2.4
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/lib/xolo/core/base_classes/configuration.rb +1 -1
- data/lib/xolo/core/base_classes/server_object.rb +1 -4
- data/lib/xolo/core/base_classes/title.rb +14 -6
- data/lib/xolo/core/base_classes/version.rb +4 -4
- data/lib/xolo/core/version.rb +1 -1
- data/lib/xolo/server/helpers/client_data.rb +10 -1
- data/lib/xolo/server/helpers/file_transfers.rb +2 -0
- data/lib/xolo/server/helpers/maintenance.rb +19 -2
- data/lib/xolo/server/helpers/progress_streaming.rb +19 -5
- data/lib/xolo/server/helpers/subscriptions.rb +6 -0
- data/lib/xolo/server/helpers/title_editor.rb +71 -0
- data/lib/xolo/server/mixins/title_jamf_access.rb +3 -1
- data/lib/xolo/server/mixins/title_ted_access.rb +46 -6
- data/lib/xolo/server/mixins/version_jamf_access.rb +64 -33
- data/lib/xolo/server/mixins/version_ted_access.rb +6 -39
- data/lib/xolo/server/routes/titles.rb +0 -4
- data/lib/xolo/server/routes/versions.rb +3 -2
- data/lib/xolo/server/title.rb +1 -0
- data/lib/xolo/server/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: 0af0f8b82fade2b7a8d3c65dedf4146e00e9adba56b7c553506a072b4942fcdb
|
|
4
|
+
data.tar.gz: f351cb8a10515a30b851490f77b64067f9485783a5ea0522c0ddf739f5a2ea25
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9575c70693bbc8acf6abfb662e7d535a416dcb1bf32dfa69614194017011247ebcf8e4552f987952d484e30bca490100de0e311942eb9c18cf0bb2d7129ccb31
|
|
7
|
+
data.tar.gz: 1a3ce31608e7fe9d62fe86465a8c8c686c6caec1d44062f2fce899e8e6ccc56ee353adf4b84ac834b8aa500d30c1a9bbe7e222400742609a1df3856131b87432
|
|
@@ -33,7 +33,7 @@ module Xolo
|
|
|
33
33
|
# Instance method #conf_file [Pathname]
|
|
34
34
|
# The full expanded absolute path to the config yaml file.
|
|
35
35
|
#
|
|
36
|
-
# Constant KEYS [Hash{Symbol: Hash}]
|
|
36
|
+
# Constant KEYS [Hash {Symbol: Hash}]
|
|
37
37
|
# The keys of this Hash are the keys that may be found in the yaml file.
|
|
38
38
|
# The Hash values here define the value in the YAML file, with these keys:
|
|
39
39
|
#
|
|
@@ -14,12 +14,9 @@ module Xolo
|
|
|
14
14
|
|
|
15
15
|
module BaseClasses
|
|
16
16
|
|
|
17
|
-
# The base class for dealing with Titles and Versions/Patches in the
|
|
18
|
-
# Xolo Server, Admin, and Client modules.
|
|
19
|
-
#
|
|
20
17
|
# The base class for "xolo objects stored on the xolo server", i.e.
|
|
21
18
|
# Titles and Versions/Patches - whether they are being used on the server,
|
|
22
|
-
#
|
|
19
|
+
# or in xadm.
|
|
23
20
|
#
|
|
24
21
|
# This class holds stuff common to all no matter where or how they are used.
|
|
25
22
|
#
|
|
@@ -15,12 +15,12 @@ module Xolo
|
|
|
15
15
|
module BaseClasses
|
|
16
16
|
|
|
17
17
|
# The base class for dealing with Titles in the
|
|
18
|
-
# Xolo Server
|
|
18
|
+
# Xolo Server & Admin modules.
|
|
19
19
|
#
|
|
20
20
|
# This class holds the common aspects of Xolo Titles as used
|
|
21
|
-
# on the Xolo server
|
|
22
|
-
#
|
|
23
|
-
# exchange.
|
|
21
|
+
# on the Xolo server and in the Xolo Admin CLI app 'xadm'
|
|
22
|
+
# and the 'xolo' client app (as JSON data).
|
|
23
|
+
# - most importately it defines which data they exchange.
|
|
24
24
|
#
|
|
25
25
|
############################
|
|
26
26
|
class Title < Xolo::Core::BaseClasses::ServerObject
|
|
@@ -43,7 +43,7 @@ module Xolo
|
|
|
43
43
|
#
|
|
44
44
|
# This hash defines the common attributes of all Xolo titles - which should
|
|
45
45
|
# be available in all subclasses, both on the server, in xadm, and via the
|
|
46
|
-
# client.
|
|
46
|
+
# client (as JSON data).
|
|
47
47
|
#
|
|
48
48
|
# Each of those subclasses might define (and store or calculate) other
|
|
49
49
|
# attributes as needed.
|
|
@@ -759,7 +759,7 @@ module Xolo
|
|
|
759
759
|
|
|
760
760
|
By default this is false, Patch Policies for versions will be set to 'Install Automatically'.
|
|
761
761
|
|
|
762
|
-
If set to true, Patch Policies for versions will be set to 'Make Available in Self Service' and the version will appear in the Updates section when available. The update won't happen until the user clicks a button, or the 7-day deadline passes. Notifications will be displayed daily.
|
|
762
|
+
If set to true, Patch Policies for versions will be set to 'Make Available in Self Service' and the version will appear in the Updates section when available. The update won't happen until the user clicks a button, or the 7-day deadline passes. Notifications will be displayed daily. For these titles, 'xolo update' will not apply the update, but 'xolo install <title>' will update/install the current release.
|
|
763
763
|
|
|
764
764
|
When installing automatically, or the deadline passes, the update will happen at the checkin after the next recon. If the version has any KillApps, the user will be prompted to quit them, with a grace period of 15 minutes before the update starts.
|
|
765
765
|
|
|
@@ -966,6 +966,14 @@ module Xolo
|
|
|
966
966
|
version_order&.first
|
|
967
967
|
end
|
|
968
968
|
|
|
969
|
+
# Does a given version exist for this title?
|
|
970
|
+
# @param vers [String] the version in question
|
|
971
|
+
# @return [Boolean]
|
|
972
|
+
#######################
|
|
973
|
+
def version_exist?(vers)
|
|
974
|
+
version_order.include? vers
|
|
975
|
+
end
|
|
976
|
+
|
|
969
977
|
# Is this a managed title?
|
|
970
978
|
# @return [Boolean]
|
|
971
979
|
#######################
|
|
@@ -15,12 +15,12 @@ module Xolo
|
|
|
15
15
|
module BaseClasses
|
|
16
16
|
|
|
17
17
|
# The base class for dealing with Versions/Patches in the
|
|
18
|
-
# Xolo Server
|
|
18
|
+
# Xolo Server & Admin modules.
|
|
19
19
|
#
|
|
20
20
|
# This class holds the common aspects of Xolo Versinos as used
|
|
21
|
-
# on the Xolo server
|
|
22
|
-
#
|
|
23
|
-
# exchange.
|
|
21
|
+
# on the Xolo server and in the Xolo Admin CLI app 'xadm'
|
|
22
|
+
# and the 'xolo' client app (as JSON data).
|
|
23
|
+
# - most importately it defines which data they exchange.
|
|
24
24
|
#
|
|
25
25
|
############################
|
|
26
26
|
class Version < Xolo::Core::BaseClasses::ServerObject
|
data/lib/xolo/core/version.rb
CHANGED
|
@@ -160,15 +160,24 @@ module Xolo
|
|
|
160
160
|
#
|
|
161
161
|
# This process is protected by a mutex to prevent multiple updates at the same time.
|
|
162
162
|
#
|
|
163
|
+
# @param post_maint [Boolean] Are we being called at the end of the run_maint method?
|
|
164
|
+
#
|
|
163
165
|
# @return [void]
|
|
164
166
|
#####################
|
|
165
|
-
def update_client_data
|
|
167
|
+
def update_client_data(post_maint: false)
|
|
166
168
|
# don't do anything if we are in developer/test mode
|
|
167
169
|
if Xolo::Server.config.developer_mode?
|
|
168
170
|
log_debug 'Jamf: Skipping client-data update in developer mode'
|
|
169
171
|
return
|
|
170
172
|
end
|
|
171
173
|
|
|
174
|
+
# don't do anything if maintenance is running,
|
|
175
|
+
# the main process will call this method once at the end
|
|
176
|
+
if Xolo::Server::Helpers::Maintenance.maint_running? && !post_maint
|
|
177
|
+
log_debug 'Jamf: Skipping client-data update while maintenance is running'
|
|
178
|
+
return
|
|
179
|
+
end
|
|
180
|
+
|
|
172
181
|
log_info 'Jamf: Updating client-data package'
|
|
173
182
|
|
|
174
183
|
# TODO: Use Concurrent Ruby instead of Mutex
|
|
@@ -124,6 +124,8 @@ module Xolo
|
|
|
124
124
|
pkg_src = Pathname.new pkg_src
|
|
125
125
|
orig_filename ||= pkg_src.basename.to_s
|
|
126
126
|
|
|
127
|
+
log_debug "Starting process_and_upload_to_jamf for #{title}, #{version}, pkg src: #{pkg_src}, orig filename: #{orig_filename}"
|
|
128
|
+
|
|
127
129
|
version = instantiate_version(title: title, version: version) if version.is_a?(String)
|
|
128
130
|
|
|
129
131
|
staged_pkg = prep_pkg_for_upload(version, pkg_src)
|
|
@@ -123,6 +123,12 @@ module Xolo
|
|
|
123
123
|
@last_maint = time
|
|
124
124
|
end
|
|
125
125
|
|
|
126
|
+
# @return [Time] Is maintenance running right now? true if the mutex is locked
|
|
127
|
+
######################################
|
|
128
|
+
def self.maint_running?
|
|
129
|
+
maint_mutex.locked?
|
|
130
|
+
end
|
|
131
|
+
|
|
126
132
|
# post to the server to start the maint process
|
|
127
133
|
# This is done so that the maint can run in the context of a request,
|
|
128
134
|
# having access to Title and Version instantiation.
|
|
@@ -136,12 +142,14 @@ module Xolo
|
|
|
136
142
|
return
|
|
137
143
|
end
|
|
138
144
|
|
|
145
|
+
now = Time.now
|
|
146
|
+
|
|
139
147
|
# only run the maintenance if it's during the MAINT_HOUR
|
|
140
148
|
# and the last one was more than MAINT_MAX_FREQ_SECS ago
|
|
141
149
|
if force
|
|
142
150
|
Xolo::Server.logger.info 'Maint: Starting now due to force'
|
|
143
151
|
|
|
144
|
-
elsif
|
|
152
|
+
elsif now.hour == MAINT_HOUR && (now - last_maint) > MAINT_MAX_FREQ_SECS
|
|
145
153
|
Xolo::Server.logger.info 'Maint: Starting nightly run now'
|
|
146
154
|
|
|
147
155
|
else
|
|
@@ -179,19 +187,25 @@ module Xolo
|
|
|
179
187
|
return
|
|
180
188
|
end
|
|
181
189
|
mutex.lock
|
|
190
|
+
|
|
182
191
|
log_info 'Maint: starting'
|
|
183
192
|
|
|
184
193
|
# instantiate all the titles once now, rather than in all the task methods
|
|
185
|
-
title_objects_for_maint =
|
|
194
|
+
title_objects_for_maint = all_title_objects refresh: true
|
|
186
195
|
|
|
187
196
|
# add new maintenance tasks/methods here
|
|
197
|
+
######
|
|
188
198
|
accept_title_editor_eas title_objects_for_maint
|
|
189
199
|
auto_release_versions title_objects_for_maint
|
|
190
200
|
cleanup_versions title_objects_for_maint
|
|
191
201
|
notify_admins_of_unreleased_pilots title_objects_for_maint
|
|
192
202
|
|
|
203
|
+
# make note of the time.
|
|
193
204
|
Xolo::Server::Helpers::Maintenance.last_maint = Time.now
|
|
194
205
|
log_info 'Maint: complete'
|
|
206
|
+
|
|
207
|
+
log_debug 'Maint: running update_client_data after all tasks'
|
|
208
|
+
update_client_data post_maint: true
|
|
195
209
|
ensure
|
|
196
210
|
mutex&.unlock
|
|
197
211
|
end
|
|
@@ -279,6 +293,9 @@ module Xolo
|
|
|
279
293
|
title_obj.release vobj_to_release.version
|
|
280
294
|
|
|
281
295
|
log_info "Maint: Auto-released version '#{vobj_to_release.version}' of '#{title}' which came out #{vobj_to_release.creation_date}", alert: true
|
|
296
|
+
|
|
297
|
+
# pause for server to catch up
|
|
298
|
+
sleep 60
|
|
282
299
|
end # each title
|
|
283
300
|
|
|
284
301
|
log_debug 'Maint: Done auto-releasing'
|
|
@@ -172,13 +172,17 @@ module Xolo
|
|
|
172
172
|
# @return [void]
|
|
173
173
|
#############################
|
|
174
174
|
def stream_progress(stream_file:, stream:)
|
|
175
|
-
log_debug "About to tail: usr/bin/tail -f -c +1 #{Shellwords.escape stream_file.to_s}"
|
|
175
|
+
# log_debug "About to tail: usr/bin/tail -f -c +1 #{Shellwords.escape stream_file.to_s}"
|
|
176
|
+
log_debug "About to stream file: #{Shellwords.escape stream_file.to_s}"
|
|
177
|
+
|
|
178
|
+
# a moment for the file to exist..
|
|
179
|
+
until stream_file.readable?
|
|
180
|
+
log_debug 'Waiting for stream file to be readable'
|
|
181
|
+
sleep 2
|
|
182
|
+
end
|
|
176
183
|
|
|
177
184
|
begin
|
|
178
185
|
File.open(stream_file, 'r') do |file|
|
|
179
|
-
# Go straight to the end of the file if you only want new lines
|
|
180
|
-
file.seek(0, IO::SEEK_END)
|
|
181
|
-
|
|
182
186
|
heartbeat_counter = 0
|
|
183
187
|
loop do
|
|
184
188
|
# Check if the stream was closed by the user
|
|
@@ -187,10 +191,16 @@ module Xolo
|
|
|
187
191
|
# Try to read the next line
|
|
188
192
|
# This won't block but will return nil if no line is ready
|
|
189
193
|
if line = file.gets
|
|
190
|
-
|
|
194
|
+
# log_debug "STREAMING: line is: '#{line}'"
|
|
195
|
+
|
|
196
|
+
if line.chomp == Xolo::Server::PROGRESS_COMPLETE
|
|
197
|
+
stream.close
|
|
198
|
+
break
|
|
199
|
+
end
|
|
191
200
|
|
|
192
201
|
# Send the line to the browser immediately
|
|
193
202
|
stream << line
|
|
203
|
+
|
|
194
204
|
else
|
|
195
205
|
# If no new line, sleep for a fraction of a second
|
|
196
206
|
# This saves your computer's CPU from working too hard
|
|
@@ -205,8 +215,12 @@ module Xolo
|
|
|
205
215
|
end # file open
|
|
206
216
|
rescue IOError, Errno::ECONNRESET
|
|
207
217
|
nil
|
|
218
|
+
ensure
|
|
219
|
+
stream.close unless stream.closed?
|
|
208
220
|
end # begin
|
|
209
221
|
|
|
222
|
+
# the old way, using tail
|
|
223
|
+
######
|
|
210
224
|
# stdin, stdouterr, wait_thr = Open3.popen2e("/usr/bin/tail -f -c +1 #{Shellwords.escape stream_file.to_s}")
|
|
211
225
|
# stdin.close
|
|
212
226
|
|
|
@@ -75,6 +75,11 @@ module Xolo
|
|
|
75
75
|
subscribed_title = subscribed_title_objects.select { |tobj| tobj.jamf_patch_title_id.to_i == title_id.to_i }.first
|
|
76
76
|
|
|
77
77
|
if subscribed_title
|
|
78
|
+
if subscribed_title.version_exist? new_version
|
|
79
|
+
log_info "Incoming Subscribed version '#{new_version}' of title '#{subscribed_title.title}' (#{subscribed_title.display_name}) already exists, nothing to do."
|
|
80
|
+
return
|
|
81
|
+
end
|
|
82
|
+
|
|
78
83
|
msg = +"New version '#{new_version}' is available for subscribed title '#{subscribed_title.title}' (#{subscribed_title.display_name})."
|
|
79
84
|
|
|
80
85
|
msg << " Running autopkg recipe '#{subscribed_title.autopkg_recipe}'." if subscribed_title.autopkg_enabled?
|
|
@@ -91,6 +96,7 @@ module Xolo
|
|
|
91
96
|
rescue => e
|
|
92
97
|
msg = "Error processing PatchSoftwareTitleUpdated webhook event: #{e.class}: #{e}"
|
|
93
98
|
log_error msg
|
|
99
|
+
e.backtrace.each { |l| log_error "..#{l}" }
|
|
94
100
|
raise e, msg
|
|
95
101
|
end # thread
|
|
96
102
|
end
|
|
@@ -50,6 +50,77 @@ module Xolo
|
|
|
50
50
|
Xolo.verbose_include includer, self
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
+
# Module Methods
|
|
54
|
+
# These must be called using Xolo::Server::Helpers::TitleEditor.<method>
|
|
55
|
+
###############################
|
|
56
|
+
##############################
|
|
57
|
+
|
|
58
|
+
# Given a Windoo::Patch object, and an
|
|
59
|
+
# app_name: & app_bundle_id: or an ea_name:
|
|
60
|
+
# Set the component criteria for the patch to
|
|
61
|
+
# be based either on the app data, or ea
|
|
62
|
+
#
|
|
63
|
+
# @param patch [Windoo::Patch] the patch to set
|
|
64
|
+
#
|
|
65
|
+
# @param title [String] the title for this patch
|
|
66
|
+
# @param app_name [String] the name of the app to use in app-based requirements,
|
|
67
|
+
# must be used with app_bundle_id, cannot be used with ea_name
|
|
68
|
+
#
|
|
69
|
+
# @param app_bundle_id [String] the bundle id of the app to use in app-based requirements
|
|
70
|
+
# must be used with app_name, cannot be used with ea_name
|
|
71
|
+
#
|
|
72
|
+
# @param ea_name [String] the name of the EA to use in EA-based requirements (the ted_ea_key)
|
|
73
|
+
# Cannot be used with app_name or app_bundle_id
|
|
74
|
+
#
|
|
75
|
+
# @return [void]
|
|
76
|
+
################################
|
|
77
|
+
def self.set_patch_component_criteria(ted_patch, app_name: nil, app_bundle_id: nil, ea_name: nil)
|
|
78
|
+
# delete any already there and make a new one
|
|
79
|
+
ted_patch.delete_component
|
|
80
|
+
ted_patch.add_component name: ted_patch.container.id, version: ted_patch.version
|
|
81
|
+
|
|
82
|
+
comp = ted_patch.component
|
|
83
|
+
|
|
84
|
+
if ea_name
|
|
85
|
+
set_ea_component(comp, ea_name, ted_patch.version)
|
|
86
|
+
else
|
|
87
|
+
set_app_component(comp, app_name, app_bundle_id, ted_patch.version)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# @return [void]
|
|
92
|
+
##############################
|
|
93
|
+
def self.set_ea_component(comp, ea_name, version)
|
|
94
|
+
comp.criteria.add_criterion(
|
|
95
|
+
type: 'extensionAttribute',
|
|
96
|
+
name: ea_name,
|
|
97
|
+
operator: 'is',
|
|
98
|
+
value: version
|
|
99
|
+
)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# @return [void]
|
|
103
|
+
##############################
|
|
104
|
+
def self.set_app_component(comp, app_name, app_bundle_id, version)
|
|
105
|
+
comp.criteria.add_criterion(
|
|
106
|
+
name: 'Application Title',
|
|
107
|
+
operator: 'is',
|
|
108
|
+
value: app_name
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
comp.criteria.add_criterion(
|
|
112
|
+
name: 'Application Bundle ID',
|
|
113
|
+
operator: 'is',
|
|
114
|
+
value: app_bundle_id
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
comp.criteria.add_criterion(
|
|
118
|
+
name: 'Application Version',
|
|
119
|
+
operator: 'is',
|
|
120
|
+
value: version
|
|
121
|
+
)
|
|
122
|
+
end
|
|
123
|
+
|
|
53
124
|
# Instance methods
|
|
54
125
|
#
|
|
55
126
|
# These are available directly in sinatra routes and views
|
|
@@ -1716,7 +1716,9 @@ module Xolo
|
|
|
1716
1716
|
def add_title_to_self_service(pol = nil)
|
|
1717
1717
|
pol ||= jamf_manual_install_released_policy
|
|
1718
1718
|
|
|
1719
|
-
|
|
1719
|
+
if pol.in_self_service?
|
|
1720
|
+
progress "Jamf: Manual Install Policy '#{pol.name}' already in Self Service."
|
|
1721
|
+
else
|
|
1720
1722
|
msg = "Jamf: Adding Manual Install Policy '#{pol.name}' to Self Service."
|
|
1721
1723
|
progress msg, log: :info
|
|
1722
1724
|
pol.add_to_self_service
|
|
@@ -119,7 +119,10 @@ module Xolo
|
|
|
119
119
|
|
|
120
120
|
# the capabilites
|
|
121
121
|
stub_patch.capabilities.add_criterion(
|
|
122
|
-
name
|
|
122
|
+
# Use the title as the name, so it matches all the future versions/patches
|
|
123
|
+
# avoiding a warning message in the TEd gui.
|
|
124
|
+
# name: Xolo::Server::Version::STUB_PATCH_CAPABILITY_CRITERION_NAME,
|
|
125
|
+
name: title,
|
|
123
126
|
operator: Xolo::Server::Version::STUB_PATCH_CAPABILITY_CRITERION_OPERATOR,
|
|
124
127
|
value: Xolo::Server::Version::STUB_PATCH_CAPABILITY_CRITERION_VALUE
|
|
125
128
|
)
|
|
@@ -424,17 +427,36 @@ module Xolo
|
|
|
424
427
|
# update the patch compotent criteria for all versions
|
|
425
428
|
# to match changes in the title requirements
|
|
426
429
|
#
|
|
430
|
+
# NOTE: we do all versions in the title editor, not just the ones known to
|
|
431
|
+
# xolo.
|
|
432
|
+
#
|
|
433
|
+
#
|
|
427
434
|
# @return [void]
|
|
428
435
|
##############################
|
|
429
436
|
def set_ted_patch_component_criteria_after_update(app_name: nil, app_bundle_id: nil, ea_name: nil)
|
|
430
|
-
|
|
431
|
-
|
|
437
|
+
ted_title.patches.each do |ted_patch|
|
|
438
|
+
Xolo::Server::Helpers::TitleEditor.set_patch_component_criteria(
|
|
439
|
+
ted_patch,
|
|
432
440
|
app_name: app_name,
|
|
433
441
|
app_bundle_id: app_bundle_id,
|
|
434
442
|
ea_name: ea_name
|
|
435
443
|
)
|
|
436
|
-
|
|
437
|
-
|
|
444
|
+
# ensure its enabled
|
|
445
|
+
ted_patch.enable
|
|
446
|
+
end # ted_title.patches.each
|
|
447
|
+
|
|
448
|
+
# # this only dealt with versions currently known to xolo
|
|
449
|
+
# # but the title editor keeps all versions ever known
|
|
450
|
+
# # even if deleted from xolo.
|
|
451
|
+
#
|
|
452
|
+
# version_objects.each do |vers_obj|
|
|
453
|
+
# vers_obj.set_ted_patch_component_criteria(
|
|
454
|
+
# app_name: app_name,
|
|
455
|
+
# app_bundle_id: app_bundle_id,
|
|
456
|
+
# ea_name: ea_name
|
|
457
|
+
# )
|
|
458
|
+
# vers_obj.enable_ted_patch
|
|
459
|
+
# end
|
|
438
460
|
end
|
|
439
461
|
|
|
440
462
|
# Enable the title in the title editor when at least one patch is enabled
|
|
@@ -538,18 +560,36 @@ module Xolo
|
|
|
538
560
|
version_objects.each do |vobj|
|
|
539
561
|
vobj.repair_ted_patch
|
|
540
562
|
end
|
|
563
|
+
|
|
564
|
+
# also update the component criteria for patches not known to xolo anymore.
|
|
565
|
+
ted_title.patches.each do |ted_patch|
|
|
566
|
+
# we've already done the known version objects, above
|
|
567
|
+
next if version_order.include? ted_patch.version
|
|
568
|
+
|
|
569
|
+
Xolo::Server::Helpers::TitleEditor.set_patch_component_criteria(
|
|
570
|
+
ted_patch,
|
|
571
|
+
app_name: app_name,
|
|
572
|
+
app_bundle_id: app_bundle_id,
|
|
573
|
+
ea_name: ted_ea_key
|
|
574
|
+
)
|
|
575
|
+
ted_patch.enable
|
|
576
|
+
end
|
|
541
577
|
end
|
|
542
578
|
|
|
543
579
|
ted_title.enable unless ted_title(refresh: true).enabled?
|
|
544
580
|
end
|
|
545
581
|
|
|
546
582
|
# Re-enable all patches in the title editor
|
|
583
|
+
# not just those known to xolo
|
|
584
|
+
#
|
|
547
585
|
# @return [void]
|
|
548
586
|
###########################
|
|
549
587
|
def reenable_all_ted_patches
|
|
550
588
|
# re-enable all patches, after any change, which might have disabled them
|
|
551
589
|
progress "Title Editor: Re-enabling all patches for '#{title}'", log: :info
|
|
552
|
-
|
|
590
|
+
|
|
591
|
+
# version_objects.each { |vobj| vobj.enable_ted_patch }
|
|
592
|
+
ted_title.patches.each { |ted_patch| ted_patch.enable }
|
|
553
593
|
end
|
|
554
594
|
|
|
555
595
|
end # TitleEditorTitle
|
|
@@ -438,8 +438,10 @@ module Xolo
|
|
|
438
438
|
end
|
|
439
439
|
|
|
440
440
|
# Delete the package for this version from Jamf Pro.
|
|
441
|
-
# Package deletion
|
|
441
|
+
# Package deletion in some versions of Jamf Pro takes a long time,
|
|
442
|
+
# especially when you have a lot of pkgs. so we do it in a threadpool
|
|
442
443
|
# and tell the admin to check the Alert Tool for completion
|
|
444
|
+
#
|
|
443
445
|
# (if we have an alert tool in place) or to wait at least 5 min before
|
|
444
446
|
# re-adding the same version.
|
|
445
447
|
#
|
|
@@ -452,16 +454,8 @@ module Xolo
|
|
|
452
454
|
msg = "Jamf: Starting deletion of Package '#{jamf_pkg_name}' id #{jamf_pkg_id} at #{Time.now.strftime '%F %T'}"
|
|
453
455
|
progress msg, log: :info
|
|
454
456
|
|
|
455
|
-
warning =
|
|
456
|
-
warning
|
|
457
|
-
if Xolo::Server.config.alert_tool
|
|
458
|
-
'check your Xolo alerts for completion, which can take up to 5 minutes,'
|
|
459
|
-
else
|
|
460
|
-
'wait at least 5 minutes'
|
|
461
|
-
end
|
|
462
|
-
warning << ' before re-adding this version.'
|
|
463
|
-
|
|
464
|
-
progress warning, log: nil
|
|
457
|
+
warning = "IMPORTANT: Package deletion can be slow. If you plan to re-add this version, '#{version}', please\nwait at least 5 minutes before doing so."
|
|
458
|
+
progress warning
|
|
465
459
|
|
|
466
460
|
self.class.pkg_deletion_pool.post do
|
|
467
461
|
start = Time.now
|
|
@@ -470,7 +464,7 @@ module Xolo
|
|
|
470
464
|
Jamf::JPackage.delete pkg_id, cnx: jamf_cnx
|
|
471
465
|
finish = Time.now
|
|
472
466
|
duration = (finish - start).to_i.pix_humanize_secs
|
|
473
|
-
log_info "Jamf: Deleted Package '#{jamf_pkg_name}' id #{jamf_pkg_id} in #{duration}"
|
|
467
|
+
log_info "Jamf: Deleted Package '#{jamf_pkg_name}' id #{jamf_pkg_id} in #{duration}"
|
|
474
468
|
rescue => e
|
|
475
469
|
log_error "Package Deletion thread: #{e.class}: #{e}"
|
|
476
470
|
e.backtrace.each { |l| log_error "..#{l}" }
|
|
@@ -887,14 +881,19 @@ module Xolo
|
|
|
887
881
|
|
|
888
882
|
configure_jamf_patch_policy(ppol)
|
|
889
883
|
|
|
890
|
-
# This is always false to start
|
|
891
|
-
# a rollback is being done
|
|
884
|
+
# This is always false to start, which is why we set it here in the create method
|
|
885
|
+
# will be set to true as needed if a rollback is being done
|
|
892
886
|
ppol.allow_downgrade = false
|
|
893
887
|
|
|
894
888
|
ppol.save
|
|
895
889
|
|
|
896
890
|
# refetch it rather than using the one we just created
|
|
897
|
-
Jamf::PatchPolicy.fetch(name: jamf_patch_policy_name, cnx: jamf_cnx)
|
|
891
|
+
ppol = Jamf::PatchPolicy.fetch(name: jamf_patch_policy_name, cnx: jamf_cnx)
|
|
892
|
+
|
|
893
|
+
# set the ssvc icon, must happen after the policy is saved
|
|
894
|
+
set_patch_policy_ssvc_icon ppol
|
|
895
|
+
|
|
896
|
+
ppol
|
|
898
897
|
end
|
|
899
898
|
|
|
900
899
|
# repair the patch policy only
|
|
@@ -908,6 +907,9 @@ module Xolo
|
|
|
908
907
|
configure_jamf_patch_policy(ppol)
|
|
909
908
|
|
|
910
909
|
ppol.save
|
|
910
|
+
|
|
911
|
+
# set the ssvc icon, must happen after the policy is saved
|
|
912
|
+
set_patch_policy_ssvc_icon ppol
|
|
911
913
|
end
|
|
912
914
|
|
|
913
915
|
# update the :patch_unknown for the patch policy
|
|
@@ -939,14 +941,22 @@ module Xolo
|
|
|
939
941
|
# explicit false
|
|
940
942
|
ppol.patch_unknown = patch_unknown ? true : false
|
|
941
943
|
|
|
944
|
+
# Patch Pol. Scope Targets:
|
|
942
945
|
# when first creating a patch policy, its status is always
|
|
943
946
|
# 'pilot' so the scope targets are the pilot groups, if any.
|
|
947
|
+
#
|
|
944
948
|
# When the version is released, the patch policy will be
|
|
945
|
-
# rescoped to all
|
|
946
|
-
|
|
949
|
+
# rescoped to all computers (limited by eligibility)
|
|
950
|
+
#
|
|
951
|
+
# Any other state should have no scope targets
|
|
952
|
+
if pilot? || creating?
|
|
947
953
|
set_policy_pilot_groups ppol
|
|
948
|
-
|
|
954
|
+
elsif released? || releasing?
|
|
955
|
+
log_debug "Setting Patch Policy Scope for Version '#{version}' of Title '#{title}' to all comptuers, for release"
|
|
949
956
|
ppol.scope.set_all_targets
|
|
957
|
+
else
|
|
958
|
+
log_debug "Setting Patch Policy Scope for Version '#{version}' of Title '#{title}' to no targets: not in pilot or released"
|
|
959
|
+
ppol.scope.set_targets :computer_groups, []
|
|
950
960
|
end
|
|
951
961
|
|
|
952
962
|
# exclusions are for always
|
|
@@ -974,10 +984,24 @@ module Xolo
|
|
|
974
984
|
ppol = jamf_patch_policy
|
|
975
985
|
configure_patch_pol_deployment ttl_obj: ttl_obj, ppol: ppol
|
|
976
986
|
ppol.save
|
|
987
|
+
# set the ssvc icon, must happen after the policy is saved
|
|
988
|
+
set_patch_policy_ssvc_icon ppol
|
|
989
|
+
end
|
|
990
|
+
|
|
991
|
+
# @return [Boolean] should this version use ssvc updates?
|
|
992
|
+
##################
|
|
993
|
+
def use_ssvc_updates?(ttl_obj = nil)
|
|
994
|
+
ttl_obj ||= title_object
|
|
995
|
+
|
|
996
|
+
if ttl_obj.changes_for_update&.dig :self_service_updates
|
|
997
|
+
ttl_obj.changes_for_update[:self_service_updates][:new]
|
|
998
|
+
else
|
|
999
|
+
ttl_obj.self_service_updates
|
|
1000
|
+
end
|
|
977
1001
|
end
|
|
978
1002
|
|
|
979
1003
|
# Configure the patch policy for self service or automatic deployment
|
|
980
|
-
# NOTE:
|
|
1004
|
+
# NOTE: this does not save changes to the policy - the caller must
|
|
981
1005
|
# @param ppol [Jamf::PatchPolicy] The patch policy to configure
|
|
982
1006
|
# @return [void]
|
|
983
1007
|
# ###############################
|
|
@@ -985,13 +1009,6 @@ module Xolo
|
|
|
985
1009
|
ppol ||= jamf_patch_policy
|
|
986
1010
|
ttl_obj ||= title_object
|
|
987
1011
|
|
|
988
|
-
use_ssvc_updates =
|
|
989
|
-
if ttl_obj.changes_for_update&.dig :self_service_updates
|
|
990
|
-
ttl_obj.changes_for_update[:self_service_updates][:new]
|
|
991
|
-
else
|
|
992
|
-
ttl_obj.self_service_updates
|
|
993
|
-
end
|
|
994
|
-
|
|
995
1012
|
# always set the grace period regardless of deployment type
|
|
996
1013
|
progress "Jamf: Configuring Patch Policy grace period for version '#{version}' of title '#{title}' ", log: :info
|
|
997
1014
|
ppol.grace_period = PATCH_POL_GRACE_PERIOD_MINUTES
|
|
@@ -999,7 +1016,7 @@ module Xolo
|
|
|
999
1016
|
ppol.grace_period_message = PATCH_POL_GRACE_PERIOD_MSG
|
|
1000
1017
|
|
|
1001
1018
|
# Self Service deployment
|
|
1002
|
-
if use_ssvc_updates
|
|
1019
|
+
if use_ssvc_updates?
|
|
1003
1020
|
progress "Jamf: Configuring Patch Policy for version '#{version}' of title '#{title}' for Self Service", log: :info
|
|
1004
1021
|
|
|
1005
1022
|
ppol.add_to_self_service
|
|
@@ -1016,10 +1033,6 @@ module Xolo
|
|
|
1016
1033
|
ppol.self_service_reminder_frequency = PATCH_POL_SSVC_REMINDER_FREQ_HRS
|
|
1017
1034
|
ppol.deadline = PATCH_POL_SSVC_DEADLINE_DAYS
|
|
1018
1035
|
|
|
1019
|
-
return unless title_object.ssvc_icon_id
|
|
1020
|
-
|
|
1021
|
-
set_patch_policy_ssvc_icon ppol, title_object.ssvc_icon_id
|
|
1022
|
-
|
|
1023
1036
|
# Automatic deployment
|
|
1024
1037
|
else
|
|
1025
1038
|
progress "Jamf: Configuring Patch Policy for version '#{version}' of title '#{title}' for automatic deployment", log: :info
|
|
@@ -1039,7 +1052,23 @@ module Xolo
|
|
|
1039
1052
|
# @param icon_id [Integer, String] The id of the existing icon to use.
|
|
1040
1053
|
# @return [Void]
|
|
1041
1054
|
##########################
|
|
1042
|
-
def set_patch_policy_ssvc_icon(ppol
|
|
1055
|
+
def set_patch_policy_ssvc_icon(ppol)
|
|
1056
|
+
return unless use_ssvc_updates?
|
|
1057
|
+
|
|
1058
|
+
if title_object.ssvc_icon_id
|
|
1059
|
+
icon_id = title_object.ssvc_icon_id
|
|
1060
|
+
log_debug "Jamf: ssvc_icon_id from title object is: #{icon_id}"
|
|
1061
|
+
else
|
|
1062
|
+
icon_id = title_object.jamf_manual_install_released_policy.self_service_icon.id
|
|
1063
|
+
log_debug "Jamf: ssvc_icon_id from manual install policy is: #{icon_id}"
|
|
1064
|
+
|
|
1065
|
+
end
|
|
1066
|
+
|
|
1067
|
+
if icon_id.pix_empty?
|
|
1068
|
+
log_debug 'Jamf: could not find ssvc icon id, not setting icon for patch policy.'
|
|
1069
|
+
return
|
|
1070
|
+
end
|
|
1071
|
+
|
|
1043
1072
|
# this str can't be frozen for now
|
|
1044
1073
|
icon_xml = +<<~ENDXML
|
|
1045
1074
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
@@ -1053,9 +1082,11 @@ module Xolo
|
|
|
1053
1082
|
ENDXML
|
|
1054
1083
|
|
|
1055
1084
|
log_debug "Jamf: Adding existing SSvc icon to patch policy for version '#{version}' of title '#{title}'"
|
|
1085
|
+
|
|
1056
1086
|
# TODO: in ruby-jss, update c_put and related methods to
|
|
1057
1087
|
# use unfrozen dups of strings for #gsub
|
|
1058
|
-
|
|
1088
|
+
|
|
1089
|
+
jamf_cnx.c_put "patchpolicies/id/#{ppol.id}", icon_xml
|
|
1059
1090
|
end
|
|
1060
1091
|
|
|
1061
1092
|
# @return [String] the URL for the Jamf Pro Patch Policy that updates to this version
|
|
@@ -253,12 +253,12 @@ module Xolo
|
|
|
253
253
|
msg = "Title Editor: Setting #{type}-based component criteria for Patch '#{version}' of SoftwareTitle '#{title}'"
|
|
254
254
|
progress msg, log: :info
|
|
255
255
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
256
|
+
Xolo::Server::Helpers::TitleEditor.set_patch_component_criteria(
|
|
257
|
+
ted_patch,
|
|
258
|
+
app_name: app_name,
|
|
259
|
+
app_bundle_id: app_bundle_id,
|
|
260
|
+
ea_name: ea_name
|
|
261
|
+
)
|
|
262
262
|
end
|
|
263
263
|
|
|
264
264
|
# get the param values for patch component criteria from the title object,
|
|
@@ -287,39 +287,6 @@ module Xolo
|
|
|
287
287
|
[app_name, app_bundle_id, ea_name]
|
|
288
288
|
end
|
|
289
289
|
|
|
290
|
-
# @return [void]
|
|
291
|
-
##############################
|
|
292
|
-
def set_ea_component(comp, ea_name)
|
|
293
|
-
comp.criteria.add_criterion(
|
|
294
|
-
type: 'extensionAttribute',
|
|
295
|
-
name: ea_name,
|
|
296
|
-
operator: 'is',
|
|
297
|
-
value: version
|
|
298
|
-
)
|
|
299
|
-
end
|
|
300
|
-
|
|
301
|
-
# @return [void]
|
|
302
|
-
##############################
|
|
303
|
-
def set_app_component(comp, app_name, app_bundle_id)
|
|
304
|
-
comp.criteria.add_criterion(
|
|
305
|
-
name: 'Application Title',
|
|
306
|
-
operator: 'is',
|
|
307
|
-
value: app_name
|
|
308
|
-
)
|
|
309
|
-
|
|
310
|
-
comp.criteria.add_criterion(
|
|
311
|
-
name: 'Application Bundle ID',
|
|
312
|
-
operator: 'is',
|
|
313
|
-
value: app_bundle_id
|
|
314
|
-
)
|
|
315
|
-
|
|
316
|
-
comp.criteria.add_criterion(
|
|
317
|
-
name: 'Application Version',
|
|
318
|
-
operator: 'is',
|
|
319
|
-
value: version
|
|
320
|
-
)
|
|
321
|
-
end
|
|
322
|
-
|
|
323
290
|
# For a patch to be enabled in the Title Editor, it needs at least a component criterion
|
|
324
291
|
# and one capability. Xolo enforces those when the patch is created, so from the title
|
|
325
292
|
# editor's view it should be OK from the start.
|
|
@@ -144,8 +144,6 @@ module Xolo
|
|
|
144
144
|
|
|
145
145
|
with_streaming do
|
|
146
146
|
title.repair repair_versions: do_versions
|
|
147
|
-
# moved to title.repair
|
|
148
|
-
# update_client_data
|
|
149
147
|
end
|
|
150
148
|
end
|
|
151
149
|
|
|
@@ -159,8 +157,6 @@ module Xolo
|
|
|
159
157
|
|
|
160
158
|
with_streaming do
|
|
161
159
|
title.delete
|
|
162
|
-
# moved to title.delete
|
|
163
|
-
# update_client_data
|
|
164
160
|
end
|
|
165
161
|
end
|
|
166
162
|
|
|
@@ -127,8 +127,6 @@ module Xolo
|
|
|
127
127
|
|
|
128
128
|
with_streaming do
|
|
129
129
|
vers.update new_data
|
|
130
|
-
# moved to vers.update
|
|
131
|
-
# update_client_data
|
|
132
130
|
end
|
|
133
131
|
end
|
|
134
132
|
|
|
@@ -160,7 +158,10 @@ module Xolo
|
|
|
160
158
|
# param with the uploaded file must be :file
|
|
161
159
|
######################
|
|
162
160
|
post '/titles/:title/versions/:version/pkg' do
|
|
161
|
+
@pkg_upload_happening = true
|
|
162
|
+
log_debug "Starting POST to upload pkg for #{params[:title]}, #{params[:version]}"
|
|
163
163
|
process_and_upload_uploaded_pkg
|
|
164
|
+
@pkg_upload_happening = false
|
|
164
165
|
body({ result: :uploaded })
|
|
165
166
|
end
|
|
166
167
|
|
data/lib/xolo/server/title.rb
CHANGED
|
@@ -1130,6 +1130,7 @@ module Xolo
|
|
|
1130
1130
|
repair_ted_title
|
|
1131
1131
|
set_subscribed_display_name_and_publisher
|
|
1132
1132
|
repair_jamf_title_objects
|
|
1133
|
+
self.ssvc_icon_id = jamf_manual_install_released_policy.self_service_icon.id
|
|
1133
1134
|
save_local_data
|
|
1134
1135
|
return unless repair_versions
|
|
1135
1136
|
|
data/lib/xolo/server/version.rb
CHANGED
|
@@ -85,7 +85,7 @@ module Xolo
|
|
|
85
85
|
STUB_PATCH_CAPABILITY_CRITERION_VALUE = '10.0'
|
|
86
86
|
|
|
87
87
|
# machines that have this version installed
|
|
88
|
-
STUB_PATCH_COMPONENT_NAME = 'Xolo Stub'
|
|
88
|
+
# STUB_PATCH_COMPONENT_NAME = 'Xolo Stub'
|
|
89
89
|
STUB_PATCH_COMPONENT_CRITERION_NAME = 'Application Title'
|
|
90
90
|
STUB_PATCH_COMPONENT_CRITERION_OPERATOR = 'is'
|
|
91
91
|
STUB_PATCH_COMPONENT_CRITERION_VALUE = 'XoloStub-DoesNotExist.app'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: xolo-server
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.2.
|
|
4
|
+
version: 2.2.4
|
|
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-
|
|
11
|
+
date: 2026-08-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|