xolo-server 1.0.1 → 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/data/client/xolo +152 -79
- data/lib/xolo/core/base_classes/title.rb +254 -18
- data/lib/xolo/core/base_classes/version.rb +47 -7
- data/lib/xolo/core/constants.rb +7 -3
- data/lib/xolo/core/security_cmd.rb +128 -0
- data/lib/xolo/core/version.rb +1 -1
- data/lib/xolo/core.rb +1 -0
- data/lib/xolo/server/app.rb +7 -0
- data/lib/xolo/server/configuration.rb +243 -37
- 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 +30 -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 -385
- data/lib/xolo/server/mixins/title_ted_access.rb +29 -3
- data/lib/xolo/server/mixins/version_jamf_access.rb +95 -112
- data/lib/xolo/server/mixins/version_ted_access.rb +25 -0
- 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 +9 -0
- data/lib/xolo/server/title.rb +100 -77
- data/lib/xolo/server/version.rb +177 -15
- data/lib/xolo/server.rb +8 -0
- metadata +7 -9
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Copyright 2025 Pixar
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the terms set forth in the LICENSE.txt file available at
|
|
4
|
+
# at the root of this project.
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
# frozen_string_literal: true
|
|
8
|
+
|
|
9
|
+
# main module
|
|
10
|
+
module Xolo
|
|
11
|
+
|
|
12
|
+
# Server Module
|
|
13
|
+
module Server
|
|
14
|
+
|
|
15
|
+
module Routes
|
|
16
|
+
|
|
17
|
+
# See comments for Xolo::Server::Helpers::TitleEditor
|
|
18
|
+
#
|
|
19
|
+
module Subscriptions
|
|
20
|
+
|
|
21
|
+
# This is how we 'extend' modules to Sinatra servers
|
|
22
|
+
# for route definitions and similar things
|
|
23
|
+
#
|
|
24
|
+
# (things to be 'included' for use in route and view processing
|
|
25
|
+
# are mixed in by delcaring them to be helpers)
|
|
26
|
+
#
|
|
27
|
+
# We make them extentions here with
|
|
28
|
+
# extend Sinatra::Extension (from sinatra-contrib)
|
|
29
|
+
# and then 'register' them in the server with
|
|
30
|
+
# register Xolo::Server::<Module>
|
|
31
|
+
# Doing it this way allows us to split the code into a logical
|
|
32
|
+
# file structure, without re-opening the Sinatra::Base server app,
|
|
33
|
+
# and let xeitwork do the requiring of those files
|
|
34
|
+
extend Sinatra::Extension
|
|
35
|
+
|
|
36
|
+
# Module methods
|
|
37
|
+
#
|
|
38
|
+
##############################
|
|
39
|
+
##############################
|
|
40
|
+
|
|
41
|
+
# when this module is included
|
|
42
|
+
def self.included(includer)
|
|
43
|
+
Xolo.verbose_include includer, self
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# when this module is extended
|
|
47
|
+
def self.extended(extender)
|
|
48
|
+
Xolo.verbose_extend extender, self
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Routes
|
|
52
|
+
#
|
|
53
|
+
##############################
|
|
54
|
+
##############################
|
|
55
|
+
|
|
56
|
+
# This endpoint receives Jamf Webhook PatchSoftwareTitleUpdated events
|
|
57
|
+
# from the Jamf Pro server, indicating that a subscribed title has a new version available.
|
|
58
|
+
#
|
|
59
|
+
# If the title is subscribed in Xolo, this creates a new xolo version for the title,
|
|
60
|
+
# and either notifies the contact email for the title, or uses autopkg to get an installer.
|
|
61
|
+
#
|
|
62
|
+
# The body will be JSON like this:
|
|
63
|
+
# {
|
|
64
|
+
# "event": {
|
|
65
|
+
# "jssID": integer,
|
|
66
|
+
# "lastUpdate": epoch,
|
|
67
|
+
# "latestVersion": "string",
|
|
68
|
+
# "name": "string",
|
|
69
|
+
# "reportUrls": [
|
|
70
|
+
# "string",
|
|
71
|
+
# "string"
|
|
72
|
+
# ]
|
|
73
|
+
# },
|
|
74
|
+
# "webhook": {
|
|
75
|
+
# "eventTimestamp": epoch,
|
|
76
|
+
# "id": integer,
|
|
77
|
+
# "name": "string",
|
|
78
|
+
# "webhookEvent": "PatchSoftwareTitleUpdated"
|
|
79
|
+
# }
|
|
80
|
+
# }
|
|
81
|
+
#
|
|
82
|
+
# Some real data:
|
|
83
|
+
# {
|
|
84
|
+
# "event": {
|
|
85
|
+
# "jssID": 145,
|
|
86
|
+
# "lastUpdate":1765926131000,
|
|
87
|
+
# "latestVersion": "1.0.3",
|
|
88
|
+
# "name": "Xolo Testing",
|
|
89
|
+
# "reportUrls": [
|
|
90
|
+
# "https://myjamf.mycompany.com:8443//patch.html?id=145&o=r"
|
|
91
|
+
# ]
|
|
92
|
+
# },
|
|
93
|
+
# "webhook": {
|
|
94
|
+
# "eventTimestamp":1765926428322,
|
|
95
|
+
# "id": 4,
|
|
96
|
+
# "name": "PatchSoftwareTitleUpdated",
|
|
97
|
+
# "webhookEvent": "PatchSoftwareTitleUpdated"
|
|
98
|
+
# }
|
|
99
|
+
# }
|
|
100
|
+
#
|
|
101
|
+
# NOTE: The above reportUrls is incorrect on modern Jamf Pro servers.
|
|
102
|
+
# the correct one would be https://myjamf.mycompany.com:8443/view/computers/patch/145?tab=report
|
|
103
|
+
#
|
|
104
|
+
###############
|
|
105
|
+
post '/subscribed-title-updates' do
|
|
106
|
+
session[:admin] = Xolo::Server::WEBHOOK_HANDLER_ADMIN_USERNAME
|
|
107
|
+
request.body.rewind
|
|
108
|
+
|
|
109
|
+
# this happens in a thread so that we can return a 200 response to the
|
|
110
|
+
# webhook immediately, and do the processing asynchronously (which may
|
|
111
|
+
# involve time-consuming tasks like autopkg runs)
|
|
112
|
+
process_patch_title_updated_webhook(request.body.read)
|
|
113
|
+
|
|
114
|
+
# always return 200 to the webhook sender
|
|
115
|
+
status 200
|
|
116
|
+
resp = { status: 200, message: 'Webhook event received' }
|
|
117
|
+
body resp
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
end # Module
|
|
121
|
+
|
|
122
|
+
end # Routes
|
|
123
|
+
|
|
124
|
+
end # Server
|
|
125
|
+
|
|
126
|
+
end # module Xolo
|
|
@@ -18,7 +18,7 @@ module Xolo
|
|
|
18
18
|
#
|
|
19
19
|
module TitleEditor
|
|
20
20
|
|
|
21
|
-
# This is how we '
|
|
21
|
+
# This is how we 'extend' modules to Sinatra servers
|
|
22
22
|
# for route definitions and similar things
|
|
23
23
|
#
|
|
24
24
|
# (things to be 'included' for use in route and view processing
|
|
@@ -16,7 +16,7 @@ module Xolo
|
|
|
16
16
|
|
|
17
17
|
module Titles
|
|
18
18
|
|
|
19
|
-
# This is how we '
|
|
19
|
+
# This is how we 'extend' modules to Sinatra servers
|
|
20
20
|
# for route definitions and similar things
|
|
21
21
|
#
|
|
22
22
|
# (things to be 'included' for use in route and view processing
|
|
@@ -48,11 +48,17 @@ module Xolo
|
|
|
48
48
|
halt_on_existing_title title.title
|
|
49
49
|
|
|
50
50
|
log_info "Admin #{session[:admin]} is creating title '#{title.title}'"
|
|
51
|
+
info = { status: 'created', title: title.title }
|
|
52
|
+
body info
|
|
53
|
+
|
|
51
54
|
with_streaming do
|
|
52
55
|
title.create
|
|
53
|
-
# we don't need to update client data when titles are created
|
|
56
|
+
# we don't need to update client data when managed titles are created
|
|
54
57
|
# because they don't have any versions yet, so there's nothing a
|
|
55
58
|
# client can do with them.
|
|
59
|
+
#
|
|
60
|
+
# However subscribed titles will have their latest version activated
|
|
61
|
+
# will need client data updated
|
|
56
62
|
end
|
|
57
63
|
end
|
|
58
64
|
|
|
@@ -240,13 +246,14 @@ module Xolo
|
|
|
240
246
|
#################################
|
|
241
247
|
get '/titles/:title/urls' do
|
|
242
248
|
log_debug "Admin #{session[:admin]} is fetching GUI URLS for title '#{params[:title]}'"
|
|
249
|
+
|
|
243
250
|
halt_on_missing_title params[:title]
|
|
244
251
|
title = instantiate_title params[:title]
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
252
|
+
|
|
253
|
+
data = {}
|
|
254
|
+
data[:ted_title_url] = title.ted_title_url if title.managed?
|
|
255
|
+
data[:jamf_installed_group_url] = title.jamf_installed_group_url if title.jamf_installed_group_exist?
|
|
256
|
+
data[:jamf_frozen_group_url] = title.jamf_frozen_group_url if title.jamf_frozen_group_exist?
|
|
250
257
|
data[:jamf_manual_install_released_policy_url] = title.jamf_manual_install_released_policy_url if title.jamf_manual_install_released_policy_exist?
|
|
251
258
|
|
|
252
259
|
if title.uninstallable?
|
|
@@ -255,13 +262,11 @@ module Xolo
|
|
|
255
262
|
data[:jamf_expire_policy_url] = title.jamf_expire_policy_url if title.expiration
|
|
256
263
|
end
|
|
257
264
|
|
|
258
|
-
if title.
|
|
259
|
-
data[:jamf_patch_title_url] = title.jamf_patch_title_url unless title.
|
|
265
|
+
if title.jamf_title_active?
|
|
266
|
+
data[:jamf_patch_title_url] = title.jamf_patch_title_url unless title.jamf_patch_title_id.pix_empty?
|
|
260
267
|
data[:jamf_patch_ea_url] = title.jamf_patch_ea_url if title.version_script
|
|
261
268
|
end
|
|
262
269
|
|
|
263
|
-
data[:jamf_normal_ea_url] = title.jamf_normal_ea_url if title.version_script
|
|
264
|
-
|
|
265
270
|
body data
|
|
266
271
|
end
|
|
267
272
|
|
|
@@ -276,6 +281,16 @@ module Xolo
|
|
|
276
281
|
body title.changelog
|
|
277
282
|
end
|
|
278
283
|
|
|
284
|
+
# Does this xolo server support autopkg integration?
|
|
285
|
+
#
|
|
286
|
+
# @return [Array<Hash>] The changelog for a title
|
|
287
|
+
#################################
|
|
288
|
+
get '/titles/autopkg_enabled' do
|
|
289
|
+
log_debug "Admin #{session[:admin]} is checking if autopkg is enabled on this server"
|
|
290
|
+
data = { autopkg_enabled: autopkg_enabled? }
|
|
291
|
+
body data
|
|
292
|
+
end
|
|
293
|
+
|
|
279
294
|
end # Titles
|
|
280
295
|
|
|
281
296
|
end # Routes
|
|
@@ -62,20 +62,6 @@ module Xolo
|
|
|
62
62
|
##############################
|
|
63
63
|
##############################
|
|
64
64
|
|
|
65
|
-
# # param with the uploaded file must be :file
|
|
66
|
-
# ######################
|
|
67
|
-
# post '/upload/ssvc-icon/:title' do
|
|
68
|
-
# process_incoming_ssvc_icon
|
|
69
|
-
# body({ result: :uploaded })
|
|
70
|
-
# end
|
|
71
|
-
|
|
72
|
-
# # param with the uploaded file must be :file
|
|
73
|
-
# ######################
|
|
74
|
-
# post '/upload/pkg/:title/:version' do
|
|
75
|
-
# process_incoming_pkg
|
|
76
|
-
# body({ result: :uploaded })
|
|
77
|
-
# end
|
|
78
|
-
|
|
79
65
|
# param with the uploaded file must be :file
|
|
80
66
|
######################
|
|
81
67
|
post '/upload/test' do
|
|
@@ -16,7 +16,7 @@ module Xolo
|
|
|
16
16
|
|
|
17
17
|
module Versions
|
|
18
18
|
|
|
19
|
-
# This is how we '
|
|
19
|
+
# This is how we 'extend' modules to Sinatra servers
|
|
20
20
|
# for route definitions and similar things
|
|
21
21
|
#
|
|
22
22
|
# (things to be 'included' for use in route and view processing
|
|
@@ -58,9 +58,10 @@ module Xolo
|
|
|
58
58
|
data[:min_os] = default_min_os if data[:min_os].pix_empty?
|
|
59
59
|
|
|
60
60
|
log_debug "Incoming new version data: #{data}"
|
|
61
|
-
log_debug "Incoming new version data: #{data.class}"
|
|
62
61
|
|
|
63
|
-
vers = instantiate_version(data)
|
|
62
|
+
vers = instantiate_version(**data)
|
|
63
|
+
log_debug "Instantiated version object: #{vers.class} - #{vers.title} #{vers.version}"
|
|
64
|
+
|
|
64
65
|
halt_on_existing_version vers.title, vers.version
|
|
65
66
|
|
|
66
67
|
if vers.title_object.jamf_patch_ea_awaiting_acceptance? && !Xolo::Server.config.jamf_auto_accept_xolo_eas
|
|
@@ -89,9 +90,9 @@ module Xolo
|
|
|
89
90
|
|
|
90
91
|
log_debug "Admin #{session[:admin]} is listing all versions for title '#{params[:title]}'"
|
|
91
92
|
# body all_versions(params[:title])
|
|
92
|
-
|
|
93
|
+
vers_objs = all_version_objects(params[:title])
|
|
93
94
|
# log_debug "vers_ins: #{vers_ins}"
|
|
94
|
-
body
|
|
95
|
+
body vers_objs.map(&:to_h)
|
|
95
96
|
end
|
|
96
97
|
|
|
97
98
|
# get all the data for a single version
|
|
@@ -156,7 +157,7 @@ module Xolo
|
|
|
156
157
|
# param with the uploaded file must be :file
|
|
157
158
|
######################
|
|
158
159
|
post '/titles/:title/versions/:version/pkg' do
|
|
159
|
-
|
|
160
|
+
process_and_upload_uploaded_pkg
|
|
160
161
|
body({ result: :uploaded })
|
|
161
162
|
end
|
|
162
163
|
|
|
@@ -239,13 +240,13 @@ module Xolo
|
|
|
239
240
|
|
|
240
241
|
halt_on_missing_version params[:title], params[:version]
|
|
241
242
|
vers = instantiate_version title: params[:title], version: params[:version]
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
243
|
+
|
|
244
|
+
data = {}
|
|
245
|
+
data[:ted_patch_url] = vers.ted_patch_url if vers.managed?
|
|
246
|
+
data[:jamf_auto_install_policy_url] = vers.jamf_auto_install_policy_url if vers.jamf_auto_install_policy_exist?
|
|
247
|
+
data[:jamf_manual_install_policy_url] = vers.jamf_manual_install_policy_url if vers.jamf_manual_install_policy_exist?
|
|
248
|
+
data[:jamf_patch_policy_url] = vers.jamf_patch_policy_url if vers.jamf_patch_policy_exist?
|
|
249
|
+
data[:jamf_package_url] = vers.jamf_package_url if vers.jamf_package_exist?
|
|
249
250
|
data[:jamf_version_installed_group] = vers.jamf_installed_group_url if vers.jamf_installed_group_exist?
|
|
250
251
|
data[:jamf_auto_reinstall_policy_url] = vers.jamf_auto_reinstall_policy_url if vers.jamf_auto_reinstall_policy_exist?
|
|
251
252
|
|
data/lib/xolo/server/routes.rb
CHANGED
|
@@ -49,6 +49,14 @@ module Xolo
|
|
|
49
49
|
log_debug "Checking if request path '#{request.path}' is in INTERNAL_ROUTES"
|
|
50
50
|
break if Xolo::Server::Helpers::Auth::INTERNAL_ROUTES.include?(request.path) && valid_internal_auth_token?
|
|
51
51
|
|
|
52
|
+
# This route is used by Jamf Pro Webhooks to notify Xolo of subscribed title updates
|
|
53
|
+
log_debug "Checking if request path '#{request.path}' is PATCH_TITLE_UPDATED_WEBHOOK_ROUTE"
|
|
54
|
+
if request.path == Xolo::Server::Helpers::Auth::PATCH_TITLE_UPDATED_WEBHOOK_ROUTE
|
|
55
|
+
break if jamf_webhook_auth_token_ok?
|
|
56
|
+
|
|
57
|
+
halt 401, { status: 401, error: 'Valid Bearer Token Required' }
|
|
58
|
+
end
|
|
59
|
+
|
|
52
60
|
# these routes are for server admins only, and require an authenticated session
|
|
53
61
|
log_debug "Checking if request path '#{request.path}' is in SERVER_ADMIN_ROUTES"
|
|
54
62
|
break if Xolo::Server::Helpers::Auth::SERVER_ADMIN_ROUTES.include?(request.path) && valid_server_admin?
|
|
@@ -149,3 +157,4 @@ require 'xolo/server/routes/title_editor'
|
|
|
149
157
|
require 'xolo/server/routes/titles'
|
|
150
158
|
require 'xolo/server/routes/uploads'
|
|
151
159
|
require 'xolo/server/routes/versions'
|
|
160
|
+
require 'xolo/server/routes/subscriptions'
|
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
|