xolo-admin 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.
@@ -26,7 +26,7 @@ module Xolo
26
26
  # Routes for server admins
27
27
 
28
28
  SERVER_STATUS_ROUTE = '/maint/state'
29
- SERVER_CLENUP_ROUTE = '/maint/cleanup'
29
+ SERVER_CLEANUP_ROUTE = '/maint/cleanup'
30
30
  SERVER_ROTATE_LOGS_ROUTE = '/maint/rotate-logs'
31
31
  SERVER_UPDATE_CLIENT_DATA_ROUTE = '/maint/update-client-data'
32
32
  SERVER_LOG_LEVEL_ROUTE = '/maint/set-log-level'
@@ -72,6 +72,14 @@ module Xolo
72
72
  puts msg unless quiet?
73
73
  end
74
74
 
75
+ # TODO: Use this everywhere in admin
76
+ ##########################
77
+ def show_debug(msg)
78
+ return unless debug?
79
+
80
+ puts "DEBUG: #{msg}"
81
+ end
82
+
75
83
  # Search for a title in Xolo
76
84
  # Looks for the search string (case insensitive) in these attributes:
77
85
  # - title
@@ -234,19 +242,30 @@ module Xolo
234
242
 
235
243
  new_title = Xolo::Admin::Title.new opts_to_process
236
244
 
245
+ # TMP TESTING
246
+ # puts 'DEBUG: opts_to_process:'
247
+ # opts_to_process.to_h.each do |k, v|
248
+ # puts " #{k}: #{v}"
249
+ # end
250
+ # return
251
+
237
252
  response_data = new_title.add(server_cnx)
238
253
 
239
254
  if debug?
240
255
  puts "DEBUG: response_data: #{response_data}"
241
256
  puts
242
257
  end
243
-
244
- display_progress response_data[:progress_stream_url_path]
258
+ if response_data[:progress_stream_url_path]
259
+ display_progress response_data[:progress_stream_url_path]
260
+ else
261
+ puts '# No progress stream URL returned'
262
+ return
263
+ end
245
264
 
246
265
  # Upload the ssvc icon, if any?
247
266
  upload_ssvc_icon new_title
248
267
 
249
- speak "Title '#{cli_cmd.title}' has been added to Xolo.\nAdd at least one version to enable piloting and deployment"
268
+ speak "Title '#{cli_cmd.title}' has been added to Xolo.\nEnsure there's at least one version to enable piloting and deployment"
250
269
  rescue StandardError => e
251
270
  handle_processing_error e
252
271
  end
@@ -307,9 +326,26 @@ module Xolo
307
326
  def upload_ssvc_icon(title)
308
327
  return unless title.self_service_icon.is_a? Pathname
309
328
 
329
+ speak 'Pausing to let jamf server catch up before uploading self-service icon...'
330
+ sleep 30
310
331
  speak "Uploading self-service icon #{title.self_service_icon.basename}, #{title.self_service_icon.pix_humanize_size} to Xolo."
311
332
 
312
- title.upload_self_service_icon(upload_cnx)
333
+ wait_for_title_timer = 0
334
+ begin
335
+ title.upload_self_service_icon(upload_cnx)
336
+ rescue Xolo::ConnectionError => e
337
+ speak "Error uploading self-service icon: #{e.message}, trying again in 5 secs"
338
+ # If we get a 404, it might be because the title isn't fully created yet.
339
+ # Wait a bit and try again, up to a certain number of seconds.
340
+ if wait_for_title_timer < 90
341
+ sleep 5
342
+ wait_for_title_timer += 5
343
+ retry
344
+ else
345
+ msg = "Failed to upload icon for Title '#{title}' after retrying for #{wait_for_title_timer} seconds."
346
+ raise Xolo::NoSuchItemError, msg
347
+ end # if
348
+ end # begin
313
349
 
314
350
  speak 'Self-service icon uploaded. Will be added to Self Service policies as needed'
315
351
  rescue StandardError => e
@@ -478,6 +514,7 @@ module Xolo
478
514
  opts_to_process.title = cli_cmd.title
479
515
  opts_to_process.version = cli_cmd.version
480
516
 
517
+ title_obj = Xolo::Admin::Title.fetch cli_cmd.title, server_cnx
481
518
  new_vers = Xolo::Admin::Version.new opts_to_process
482
519
  response_data = new_vers.add(server_cnx)
483
520
 
@@ -489,7 +526,8 @@ module Xolo
489
526
  display_progress response_data[:progress_stream_url_path]
490
527
 
491
528
  # Upload the pkg, if any?
492
- upload_pkg(new_vers)
529
+ upload_pkg(new_vers) unless title_obj.autopkg_enabled?
530
+
493
531
  speak 'It can take up to 15 minutes for the version to be available via Jamf and Self Service.'
494
532
  rescue StandardError => e
495
533
  handle_processing_error e
@@ -510,6 +548,8 @@ module Xolo
510
548
  def upload_pkg(version)
511
549
  return unless version.pkg_to_upload.is_a? Pathname
512
550
 
551
+ # TODO: deal with autopkg pkgs, should we be able to do this?
552
+
513
553
  speak "Uploading #{version.pkg_to_upload.basename}, #{version.pkg_to_upload.pix_humanize_size} to Xolo"
514
554
  # start the upload in a thread
515
555
  upload_thr = Thread.new { version.upload_pkg(upload_cnx) }
@@ -941,7 +981,7 @@ module Xolo
941
981
  def server_cleanup
942
982
  return unless confirmed? 'Run the Xolo Server cleanup process'
943
983
 
944
- result = server_cnx.post(SERVER_CLENUP_ROUTE).body
984
+ result = server_cnx.post(SERVER_CLEANUP_ROUTE).body
945
985
  puts result[:result]
946
986
  rescue StandardError => e
947
987
  handle_processing_error e
@@ -1036,6 +1076,35 @@ module Xolo
1036
1076
  list_in_cols header, jamf_computer_group_names.sort_by(&:downcase)
1037
1077
  end
1038
1078
 
1079
+ # List Available titles for subscription
1080
+ #
1081
+ # @return [void]
1082
+ #############################
1083
+ def list_available_titles
1084
+ data = jamf_available_titles.sort_by { |t| t[:app_name].downcase }
1085
+ data.map! do |t|
1086
+ {
1087
+ display_name: t[:app_name],
1088
+ publisher: t[:publisher],
1089
+ patch_source: t[:source_name],
1090
+ title_id: t[:name_id],
1091
+ current_version: t[:current_version],
1092
+ last_modified: t[:last_modified]
1093
+ }
1094
+ end
1095
+
1096
+ if json?
1097
+ puts JSON.pretty_generate(data)
1098
+ return
1099
+ end
1100
+
1101
+ title = 'Titles Available for Subscription'
1102
+ header = %w[DisplayName Publisher PatchSource TitleID]
1103
+ lines = data.map { |t| [t[:display_name], t[:publisher], t[:patch_source], t[:title_id]] }
1104
+
1105
+ show_text generate_report(lines, header_row: header, title: title)
1106
+ end
1107
+
1039
1108
  # List all the SSVC categories in jamf pro
1040
1109
  #
1041
1110
  # @return [void]
@@ -85,7 +85,7 @@ module Xolo
85
85
  ###################
86
86
  def progress_history
87
87
  progress_history_file.pix_touch
88
- history = YAML.load progress_history_file.read
88
+ history = YAML.safe_load progress_history_file.read, permitted_classes: [Symbol, Time]
89
89
  history ||= {}
90
90
 
91
91
  now = Time.now
@@ -43,10 +43,17 @@ module Xolo
43
43
  #############################
44
44
 
45
45
  # @return [Hash{Symbol: Hash}] The ATTRIBUTES that are available as CLI & walkthru options
46
+ ##############################
46
47
  def self.cli_opts
47
48
  @cli_opts ||= ATTRIBUTES.select { |_k, v| v[:cli] }
48
49
  end
49
50
 
51
+ # @return [Hash{Symbol: Hash}] The ATTRIBUTES that are available as opts for the subscribe command
52
+ ################################
53
+ # def self.subscribe_cli_opts
54
+ # @subscribe_cli_opts ||= ATTRIBUTES.select { |_k, v| v[:cli_subscribe] }
55
+ # end
56
+
50
57
  # @return [Array<String>] The currently known titles names on the server
51
58
  #############################
52
59
  def self.all_titles(cnx)
@@ -77,8 +84,9 @@ module Xolo
77
84
  ####################
78
85
  def self.fetch(title, cnx)
79
86
  resp = cnx.get "#{SERVER_ROUTE}/#{title}"
80
-
81
- new resp.body
87
+ title_obj = new resp.body
88
+ title_obj.cnx = cnx
89
+ title_obj
82
90
  rescue Faraday::ResourceNotFound
83
91
  raise Xolo::NoSuchItemError, "No such title '#{title}'"
84
92
  end
@@ -115,6 +123,8 @@ module Xolo
115
123
  # Attributes
116
124
  ######################
117
125
  ######################
126
+ # the server connection used to fetch this version
127
+ attr_accessor :cnx
118
128
 
119
129
  # Constructor
120
130
  ######################
@@ -139,7 +149,7 @@ module Xolo
139
149
  # @param cnx [Faraday::Connection] The connection to use, must be logged in already
140
150
  # @return [Hash] the response body from the server
141
151
  ####################
142
- def add(cnx)
152
+ def add(cnx = self.cnx)
143
153
  resp = cnx.post SERVER_ROUTE, to_h
144
154
  resp.body
145
155
  end
@@ -148,7 +158,7 @@ module Xolo
148
158
  # @param cnx [Faraday::Connection] The connection to use, must be logged in already
149
159
  # @return [Hash] the response body from the server
150
160
  ####################
151
- def update(cnx)
161
+ def update(cnx = self.cnx)
152
162
  resp = cnx.put "#{SERVER_ROUTE}/#{title}", to_h
153
163
  resp.body
154
164
  end
@@ -158,7 +168,7 @@ module Xolo
158
168
  # @param version [String] the version to release
159
169
  # @return [Hash] the response body from the server
160
170
  ####################
161
- def release(cnx, version:)
171
+ def release(cnx = self.cnx, version:)
162
172
  resp = cnx.patch "#{SERVER_ROUTE}/#{title}/release/#{version}", {}
163
173
  resp.body
164
174
  end
@@ -168,7 +178,7 @@ module Xolo
168
178
  # @param versions [Boolean] if true, repair all versions of this title
169
179
  # @return [Hash] the response body from the server
170
180
  ####################
171
- def repair(cnx, versions: false)
181
+ def repair(cnx = self.cnx, versions: false)
172
182
  resp = cnx.post "#{SERVER_ROUTE}/#{title}/repair", { repair_versions: versions }
173
183
  resp.body
174
184
  end
@@ -177,7 +187,7 @@ module Xolo
177
187
  # @param cnx [Faraday::Connection] The connection to use, must be logged in already
178
188
  # @return [Hash] the response data
179
189
  ####################
180
- def delete(cnx)
190
+ def delete(cnx = self.cnx)
181
191
  self.class.delete title, cnx
182
192
  end
183
193
 
@@ -186,7 +196,7 @@ module Xolo
186
196
  # @param cnx [Faraday::Connection] The connection to use, must be logged in already
187
197
  # @return [Hash] the response data
188
198
  ####################
189
- def freeze(targets, users = false, cnx)
199
+ def freeze(targets, users = false, cnx = self.cnx)
190
200
  data = { targets: targets, users: users }
191
201
  resp = cnx.put "#{SERVER_ROUTE}/#{title}/freeze", data
192
202
  resp.body
@@ -197,7 +207,7 @@ module Xolo
197
207
  # @param cnx [Faraday::Connection] The connection to use, must be logged in already
198
208
  # @return [Hash] the response data
199
209
  ####################
200
- def thaw(targets, users = false, cnx)
210
+ def thaw(targets, users = false, cnx = self.cnx)
201
211
  data = { targets: targets, users: users }
202
212
  resp = cnx.put "#{SERVER_ROUTE}/#{title}/thaw", data
203
213
  resp.body
@@ -207,7 +217,7 @@ module Xolo
207
217
  # @param cnx [Faraday::Connection] The connection to use, must be logged in already
208
218
  # @return [Hash{String => String}] computer name => user name
209
219
  ####################
210
- def frozen(cnx)
220
+ def frozen(cnx = self.cnx)
211
221
  resp = cnx.get "#{SERVER_ROUTE}/#{title}/frozen"
212
222
  resp.body
213
223
  end
@@ -216,7 +226,7 @@ module Xolo
216
226
  # @param cnx [Faraday::Connection] The connection to use, must be logged in already
217
227
  # @return [Hash{String => String}] page_name => url
218
228
  ####################
219
- def gui_urls(cnx)
229
+ def gui_urls(cnx = self.cnx)
220
230
  resp = cnx.get "#{SERVER_ROUTE}/#{title}/urls"
221
231
  resp.body
222
232
  end
@@ -227,7 +237,7 @@ module Xolo
227
237
  # @param cnx [Faraday::Connection] The connection to use, must be logged in already
228
238
  # @return [Array<Hash>] The change log for this title
229
239
  ####################
230
- def changelog(cnx)
240
+ def changelog(cnx = self.cnx)
231
241
  resp = cnx.get "#{SERVER_ROUTE}/#{title}/changelog"
232
242
  resp.body
233
243
  end
@@ -248,19 +258,16 @@ module Xolo
248
258
  "Can't upload self service icon '#{self_service_icon}': file doesn't exist or is not readable"
249
259
  end
250
260
 
251
- # upfile = Faraday::UploadIO.new(
252
- # self_service_icon.to_s,
253
- # 'application/octet-stream',
254
- # self_service_icon.basename.to_s
255
- # )
256
-
257
261
  mimetype = `/usr/bin/file --brief --mime-type #{Shellwords.escape self_service_icon.expand_path.to_s}`.chomp
258
262
  upfile = Faraday::Multipart::FilePart.new(self_service_icon.expand_path.to_s, mimetype)
259
263
  content = { file: upfile }
260
- # route = "#{UPLOAD_ICON_ROUTE}/#{title}"
261
- route = "#{SERVER_ROUTE}/#{title}/#{UPLOAD_ICON_ROUTE}"
262
264
 
265
+ route = "#{SERVER_ROUTE}/#{title}/#{UPLOAD_ICON_ROUTE}"
263
266
  upload_cnx.post(route) { |req| req.body = content }
267
+ rescue Xolo::NoSuchItemError
268
+ raise
269
+ rescue StandardError => e
270
+ raise Xolo::ConnectionError, "#{e.class}: #{e.message}"
264
271
  end
265
272
 
266
273
  # Get the patch report data for this title
@@ -269,16 +276,16 @@ module Xolo
269
276
  # @param cnx [Faraday::Connection] The connection to use, must be logged in already
270
277
  # @return [Array<Hash>] Data for each computer with any version of this title installed
271
278
  ##################################
272
- def patch_report_data(cnx)
279
+ def patch_report_data(cnx = self.cnx)
273
280
  resp = cnx.get "#{SERVER_ROUTE}/#{title}/patch_report"
274
281
  resp.body
275
282
  end
276
283
 
277
284
  # Add more data to our hash
278
285
  ###########################
279
- def to_h
280
- super
281
- end
286
+ # def to_h
287
+ # super
288
+ # end
282
289
 
283
290
  end # class Title
284
291