depot3 3.0.15 → 3.0.20
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/CHANGES.md +21 -1
- data/README.md +6 -6
- data/bin/d3 +3 -3
- data/bin/d3admin +257 -293
- data/lib/d3/admin/add.rb +98 -94
- data/lib/d3/admin/interactive.rb +195 -161
- data/lib/d3/admin/options.rb +424 -412
- data/lib/d3/admin/prefs.rb +73 -42
- data/lib/d3/admin/validate.rb +50 -43
- data/lib/d3/client/auth.rb +4 -2
- data/lib/d3/client/class_methods.rb +169 -119
- data/lib/d3/client/receipt.rb +2 -2
- data/lib/d3/database.rb +167 -180
- data/lib/d3/log.rb +2 -3
- data/lib/d3/package/server_actions.rb +2 -3
- data/lib/d3/package/validate.rb +63 -70
- data/lib/d3/version.rb +1 -2
- metadata +2 -2
data/lib/d3/client/auth.rb
CHANGED
@@ -88,7 +88,10 @@ module D3
|
|
88
88
|
# return the desired password, so remove the pipe,
|
89
89
|
# execute it, and return stdout from it.
|
90
90
|
if path.end_with? "|"
|
91
|
-
|
91
|
+
cmd = path.chomp '|'
|
92
|
+
output = `#{cmd} 2>&1`.chomp
|
93
|
+
return output if $CHILD_STATUS.exitstatus.zero?
|
94
|
+
raise D3::PermissionError, "can't get client password for #{pw}: #{output}"
|
92
95
|
end
|
93
96
|
|
94
97
|
file = Pathname.new path
|
@@ -106,4 +109,3 @@ module D3
|
|
106
109
|
|
107
110
|
end # class Client
|
108
111
|
end # module D3
|
109
|
-
|
@@ -22,9 +22,10 @@
|
|
22
22
|
###
|
23
23
|
###
|
24
24
|
|
25
|
-
|
26
25
|
###
|
27
26
|
module D3
|
27
|
+
|
28
|
+
# Client
|
28
29
|
class Client < JSS::Client
|
29
30
|
|
30
31
|
################# Class Methods #################
|
@@ -45,8 +46,7 @@ module D3
|
|
45
46
|
###
|
46
47
|
### @return [void]
|
47
48
|
###
|
48
|
-
def self.install(pkgs, options
|
49
|
-
|
49
|
+
def self.install(pkgs, options)
|
50
50
|
pkgs = [pkgs] if pkgs.is_a? String
|
51
51
|
|
52
52
|
pkgs.each do |pkg_to_search|
|
@@ -58,11 +58,26 @@ module D3
|
|
58
58
|
raise D3::InstallError, "The package for #{desired_pkg.edition} is missing from the JSS" if desired_pkg.missing?
|
59
59
|
|
60
60
|
if options.custom_expiration
|
61
|
-
|
61
|
+
D3.log "Sorry #{desired_pkg.edition} is not expirable. A d3 admin needs to add an expiration path.", :warn if desired_pkg.expiration_paths.empty?
|
62
|
+
break
|
62
63
|
end
|
63
64
|
|
64
65
|
curr_rcpt = D3::Client::Receipt.all[desired_pkg.basename]
|
65
66
|
|
67
|
+
# If we were asked to freeze_on_install and the currently installed is
|
68
|
+
# same edition, freeze it anyway.
|
69
|
+
# Use force to freeze if the currently installed is newer.
|
70
|
+
#
|
71
|
+
if curr_rcpt && curr_rcpt.id >= desired_pkg.id && options.freeze_on_install
|
72
|
+
if options.force || curr_rcpt.id == desired_pkg.id
|
73
|
+
freeze_receipts([curr_rcpt.basename]) unless curr_rcpt.frozen?
|
74
|
+
D3.log "Freezing previously installed #{curr_rcpt.edition}", :warn
|
75
|
+
break
|
76
|
+
end # if options.force elsif curr_rcpt.id == desired_pkg.id
|
77
|
+
D3.log "Cannot freeze previously installed #{curr_rcpt.edition} (#{curr_rcpt.status}) It is newer than #{desired_pkg.edition}. Use --force if needed.", :warn
|
78
|
+
break
|
79
|
+
end
|
80
|
+
|
66
81
|
# many things can be forced
|
67
82
|
# things that are defined in the pkg itself
|
68
83
|
# (exclusions, prohibiting procs, oses, cpus)
|
@@ -76,42 +91,42 @@ module D3
|
|
76
91
|
desired_pkg.check_for_skipped
|
77
92
|
# same or newer?
|
78
93
|
desired_pkg.check_for_newer_version
|
79
|
-
|
80
94
|
end # unless options.force
|
81
95
|
|
82
96
|
if curr_rcpt
|
83
97
|
D3.log("Un-freezing #{curr_rcpt.edition} by installing #{desired_pkg.edition}", :warn) if curr_rcpt.frozen?
|
84
|
-
|
85
|
-
if desired_pkg.id == curr_rcpt.id
|
98
|
+
if desired_pkg.id == curr_rcpt.id
|
86
99
|
D3.log("Re-installing #{desired_pkg.edition}(#{desired_pkg.status})", :warn)
|
87
|
-
elsif
|
100
|
+
elsif desired_pkg.id < curr_rcpt.id
|
88
101
|
D3.log("Rolling back #{curr_rcpt.edition}(#{curr_rcpt.status}) to #{desired_pkg.edition}(#{desired_pkg.status})", :warn)
|
89
102
|
else
|
90
103
|
D3.log("Updating #{curr_rcpt.edition}(#{curr_rcpt.status}) to #{desired_pkg.edition}(#{desired_pkg.status})", :warn)
|
91
104
|
end
|
92
105
|
end # if curr rcpt
|
93
106
|
|
107
|
+
cloud = cloud_dist_point_to_use(pkg: desired_pkg)
|
108
|
+
|
94
109
|
desired_pkg.install(
|
95
|
-
:
|
96
|
-
:
|
97
|
-
:
|
98
|
-
:
|
99
|
-
:
|
100
|
-
:
|
110
|
+
force: options.force,
|
111
|
+
admin: get_admin(desired_pkg, options),
|
112
|
+
puppywalk: options.puppies,
|
113
|
+
expiration: options.custom_expiration,
|
114
|
+
verbose: options.verbose,
|
115
|
+
alt_download_url: cloud
|
101
116
|
)
|
102
117
|
|
103
|
-
|
118
|
+
freeze_receipts([desired_pkg.basename]) if options.freeze_on_install
|
104
119
|
|
105
120
|
D3.log "Finished installing #{desired_pkg.edition}(#{desired_pkg.status})", :info
|
106
121
|
|
107
122
|
rescue JSS::MissingDataError, JSS::NoSuchItemError, JSS::InvalidDataError, D3::InstallError
|
108
|
-
D3.log "Skipping installation of #{pkg_to_search}: #{
|
123
|
+
D3.log "Skipping installation of #{pkg_to_search}: #{$ERROR_INFO}", :error
|
109
124
|
D3.log_backtrace
|
110
125
|
rescue D3::PreInstallError
|
111
|
-
D3.log "There was an error with the pre-install script for #{desired_pkg.edition}: #{
|
126
|
+
D3.log "There was an error with the pre-install script for #{desired_pkg.edition}: #{$ERROR_INFO}", :error
|
112
127
|
D3.log_backtrace
|
113
128
|
rescue D3::PostInstallError
|
114
|
-
D3.log "There was an error with the post-install script for #{desired_pkg.edition}: #{
|
129
|
+
D3.log "There was an error with the post-install script for #{desired_pkg.edition}: #{$ERROR_INFO} NOTE: it was installed, but may have problems.", :error
|
115
130
|
D3.log_backtrace
|
116
131
|
end # begin
|
117
132
|
end # args.each
|
@@ -136,13 +151,12 @@ module D3
|
|
136
151
|
D3.log "Finished uninstalling #{rcpt.edition}.", :info
|
137
152
|
|
138
153
|
rescue JSS::MissingDataError, D3::UninstallError, JSS::InvalidDataError
|
139
|
-
D3.log "Skipping uninstall of #{rcpt_to_remove}: #{
|
154
|
+
D3.log "Skipping uninstall of #{rcpt_to_remove}: #{$ERROR_INFO}", :error
|
140
155
|
D3.log_backtrace
|
141
156
|
next
|
142
157
|
end # begin
|
143
158
|
end # rcpts.each
|
144
|
-
|
145
|
-
end #uninstall_manual
|
159
|
+
end # uninstall_manual
|
146
160
|
|
147
161
|
### Return a valid, possibly-default, admin name for
|
148
162
|
### installing a package. Since the admin name is stored in
|
@@ -154,10 +168,9 @@ module D3
|
|
154
168
|
### @return [String] a valid admin name to use for the install
|
155
169
|
###
|
156
170
|
def self.get_admin(pkg_to_install, options)
|
157
|
-
|
158
171
|
# is this puppy already in the queue? If so,
|
159
172
|
# the queue has our admin_name
|
160
|
-
if options.puppies
|
173
|
+
if options.puppies && D3::PUPPY_Q.q[pkg_to_install.basename]
|
161
174
|
|
162
175
|
admin = D3::PUPPY_Q.q[pkg_to_install.basename].admin
|
163
176
|
admin ||= D3::DFT_PUPPY_ADMIN
|
@@ -171,7 +184,7 @@ module D3
|
|
171
184
|
|
172
185
|
end # if @options.puppies
|
173
186
|
|
174
|
-
|
187
|
+
admin
|
175
188
|
end # get admin name
|
176
189
|
|
177
190
|
### Remove one or more puppies from the puppy queue
|
@@ -180,9 +193,9 @@ module D3
|
|
180
193
|
###
|
181
194
|
### @return [void]
|
182
195
|
###
|
183
|
-
def self.dequeue_puppies
|
196
|
+
def self.dequeue_puppies(puppies)
|
184
197
|
puppies = [puppies] if puppies.is_a? String
|
185
|
-
puppies = D3::PUPPY_Q.pups if puppies.include?
|
198
|
+
puppies = D3::PUPPY_Q.pups if puppies.include? 'all'
|
186
199
|
puppies.each do |pup|
|
187
200
|
unless the_puppy = D3::PUPPY_Q.q[pup]
|
188
201
|
D3.log "No pkg for basename '#{pup}' in the puppy queue.", :warn
|
@@ -192,7 +205,7 @@ module D3
|
|
192
205
|
D3.log "Removing '#{the_puppy.edition}' from the puppy queue.", :warn
|
193
206
|
D3::PUPPY_Q - the_puppy
|
194
207
|
rescue
|
195
|
-
D3.log
|
208
|
+
D3.log "Couldn't remove #{the_puppy.edition} from the puppy queue: #{$ERROR_INFO}", :error
|
196
209
|
end # begin
|
197
210
|
end
|
198
211
|
end
|
@@ -203,9 +216,9 @@ module D3
|
|
203
216
|
###
|
204
217
|
### @return [void]
|
205
218
|
###
|
206
|
-
def self.sync
|
219
|
+
def self.sync(options = OpenStruct.new)
|
207
220
|
D3::Client.set_env :sync
|
208
|
-
D3.log
|
221
|
+
D3.log 'Starting sync', :warn
|
209
222
|
|
210
223
|
begin
|
211
224
|
# update rcpts
|
@@ -233,7 +246,7 @@ module D3
|
|
233
246
|
# updates)
|
234
247
|
clean_missing_receipts
|
235
248
|
|
236
|
-
D3.log
|
249
|
+
D3.log 'Finished sync', :warn
|
237
250
|
ensure
|
238
251
|
D3::Client.unset_env :sync
|
239
252
|
end
|
@@ -253,8 +266,7 @@ module D3
|
|
253
266
|
### @return [void]
|
254
267
|
###
|
255
268
|
def self.update_rcpts
|
256
|
-
D3.log
|
257
|
-
need_saving = false
|
269
|
+
D3.log 'Updating receipts', :warn
|
258
270
|
|
259
271
|
D3::Client::Receipt.all.each do |basename, rcpt|
|
260
272
|
pkgdata = D3::Package.find_package rcpt.edition, :hash
|
@@ -317,7 +329,7 @@ module D3
|
|
317
329
|
need_update = true
|
318
330
|
end # if
|
319
331
|
|
320
|
-
if (rcpt.expiration != pkgdata[:expiration].to_i)
|
332
|
+
if (rcpt.expiration != pkgdata[:expiration].to_i) && !rcpt.custom_expiration
|
321
333
|
rcpt.expiration = pkgdata[:expiration].to_i
|
322
334
|
D3.log "Updating expiration for #{rcpt.edition}", :info
|
323
335
|
need_update = true
|
@@ -336,7 +348,6 @@ module D3
|
|
336
348
|
need_update = true
|
337
349
|
end # if
|
338
350
|
|
339
|
-
|
340
351
|
rcpt.update if need_update
|
341
352
|
end # each do basename, rcpt
|
342
353
|
end # update_rcpts
|
@@ -347,7 +358,7 @@ module D3
|
|
347
358
|
### @return [void]
|
348
359
|
###
|
349
360
|
def self.clean_doghouse
|
350
|
-
D3.log
|
361
|
+
D3.log 'Checking for invalid puppies in the queue', :warn
|
351
362
|
D3::PUPPY_Q.pending_puppies.each do |basename, pup|
|
352
363
|
unless D3::Package.all_ids.include? pup.id
|
353
364
|
D3.log "Removing #{pup.edition} from puppy queue: no longer in d3", :info
|
@@ -356,7 +367,7 @@ module D3
|
|
356
367
|
end
|
357
368
|
if D3::Package.missing_data.keys.include? pup.id
|
358
369
|
D3.log "Removing #{pup.edition} from puppy queue: status is 'missing'", :info
|
359
|
-
D3::PUPPY_Q -pup
|
370
|
+
D3::PUPPY_Q - pup
|
360
371
|
end
|
361
372
|
end
|
362
373
|
end
|
@@ -367,13 +378,13 @@ module D3
|
|
367
378
|
###
|
368
379
|
### @return [void]
|
369
380
|
###
|
370
|
-
def self.do_auto_installs
|
381
|
+
def self.do_auto_installs(options)
|
371
382
|
verbose = options.verbose
|
372
|
-
force =
|
373
|
-
D3.log
|
383
|
+
force = options.force || D3.forced?
|
384
|
+
D3.log 'Checking for new packages to auto-install', :warn
|
374
385
|
D3::Client.set_env :auto_install
|
375
386
|
begin # for ensure below
|
376
|
-
|
387
|
+
D3::Client::Receipt.basenames :refresh
|
377
388
|
|
378
389
|
# loop through the groups for this machine
|
379
390
|
auto_groups = D3::Client.computer_groups.dup
|
@@ -382,12 +393,11 @@ module D3
|
|
382
393
|
# this is the intersection of all pkg ids that get auto-installed
|
383
394
|
# for the group, and all live pkg ids...
|
384
395
|
# meaning this machine should have these pkg ids.
|
385
|
-
live_ids_for_group = (
|
396
|
+
live_ids_for_group = (D3::Package.live_data.keys & D3::Package.auto_install_ids_for_group(group))
|
386
397
|
|
387
398
|
live_ids_for_group.each do |live_id|
|
388
|
-
|
389
399
|
# skip those not available
|
390
|
-
next unless
|
400
|
+
next unless available_pkg_ids.include? live_id
|
391
401
|
|
392
402
|
auto_install_basename = D3::Package.live_data[live_id][:basename]
|
393
403
|
|
@@ -395,7 +405,7 @@ module D3
|
|
395
405
|
# the update_installed_pkgs method during sync.
|
396
406
|
next if D3::Client::Receipt.all.keys.include? auto_install_basename
|
397
407
|
|
398
|
-
new_pkg = D3::Package.new :
|
408
|
+
new_pkg = D3::Package.new id: live_id
|
399
409
|
|
400
410
|
if new_pkg.reboot?
|
401
411
|
queued_id = puppy_in_queue new_pkg.basename
|
@@ -407,24 +417,25 @@ module D3
|
|
407
417
|
|
408
418
|
begin
|
409
419
|
D3.log "Auto-installing #{new_pkg.basename} for group '#{group}'", :info
|
420
|
+
cloud = cloud_dist_point_to_use(pkg: new_pkg)
|
410
421
|
new_pkg.install(
|
411
|
-
:
|
412
|
-
:
|
413
|
-
:
|
414
|
-
:
|
415
|
-
:
|
422
|
+
admin: D3::AUTO_INSTALL_ADMIN,
|
423
|
+
verbose: verbose,
|
424
|
+
force: force,
|
425
|
+
puppywalk: options.puppies,
|
426
|
+
alt_download_url: cloud
|
416
427
|
)
|
417
428
|
D3.log "Auto-installed #{new_pkg.basename}", :warn
|
418
429
|
rescue JSS::MissingDataError, JSS::InvalidDataError, D3::InstallError
|
419
|
-
D3.log "Skipping auto-install of #{new_pkg.edition}: #{
|
430
|
+
D3.log "Skipping auto-install of #{new_pkg.edition}: #{$ERROR_INFO}", :error
|
420
431
|
D3.log_backtrace
|
421
432
|
rescue D3::PreInstallError
|
422
|
-
D3.log "There was an error with the pre-install script for #{new_pkg.edition}: #{
|
433
|
+
D3.log "There was an error with the pre-install script for #{new_pkg.edition}: #{$ERROR_INFO}", :error
|
423
434
|
D3.log_backtrace
|
424
435
|
rescue D3::PostInstallError
|
425
|
-
D3.log "There was an error with the post-install script for #{new_pkg.edition}: #{
|
436
|
+
D3.log "There was an error with the post-install script for #{new_pkg.edition}: #{$ERROR_INFO} NOTE: #{new_pkg.edition} was installed, but may not work.", :error
|
426
437
|
D3.log_backtrace
|
427
|
-
end #begin
|
438
|
+
end # begin
|
428
439
|
end # live_ids_for_group.each do |live_id|
|
429
440
|
end # each group
|
430
441
|
ensure
|
@@ -436,8 +447,8 @@ module D3
|
|
436
447
|
###
|
437
448
|
###
|
438
449
|
def self.clean_missing_receipts
|
439
|
-
D3.log
|
440
|
-
D3::Client::Receipt.all.values.select{|r| r.status == :missing}.each do |mrcpt|
|
450
|
+
D3.log 'Checking for receipts no longer in d3', :warn
|
451
|
+
D3::Client::Receipt.all.values.select { |r| r.status == :missing }.each do |mrcpt|
|
441
452
|
D3.log "Removing receipt for missing edition #{mrcpt.edition}", :info
|
442
453
|
D3::Client::Receipt.remove_receipt mrcpt.basename
|
443
454
|
D3.log "Removed receipt for missing edition #{mrcpt.edition}", :info
|
@@ -451,10 +462,10 @@ module D3
|
|
451
462
|
###
|
452
463
|
### @return [void]
|
453
464
|
###
|
454
|
-
def self.update_installed_pkgs
|
465
|
+
def self.update_installed_pkgs(options)
|
455
466
|
verbose = options.verbose
|
456
|
-
force =
|
457
|
-
D3.log
|
467
|
+
force = options.force || D3.forced?
|
468
|
+
D3.log 'Checking for updates to installed packages', :warn
|
458
469
|
D3::Client.set_env :auto_update
|
459
470
|
begin # see ensure below
|
460
471
|
|
@@ -463,7 +474,6 @@ module D3
|
|
463
474
|
|
464
475
|
# loop through the install pkgs
|
465
476
|
D3::Client::Receipt.all.values.each do |rcpt|
|
466
|
-
|
467
477
|
# is there a live pkg for this basename?
|
468
478
|
if live_basenames_to_ids[rcpt.basename]
|
469
479
|
live_id = live_basenames_to_ids[rcpt.basename]
|
@@ -501,7 +511,7 @@ module D3
|
|
501
511
|
if live_pkg_data[:reboot]
|
502
512
|
queued_id = puppy_in_queue(live_pkg_data[:basename])
|
503
513
|
if queued_id && queued_id >= live_pkg_data[:id]
|
504
|
-
D3.log "Skipping auto-update of puppy-queue item #{
|
514
|
+
D3.log "Skipping auto-update of puppy-queue item #{live_pkg_data[:edition]}, there's a newer one in the queue already", :info
|
505
515
|
next
|
506
516
|
end # if queued_id && queued_id >= live_pkg.id
|
507
517
|
end # if live_pkg.reboot?
|
@@ -517,26 +527,27 @@ module D3
|
|
517
527
|
expiration = rcpt.custom_expiration ? rcpt.expiration : nil
|
518
528
|
|
519
529
|
# heres the pkg
|
520
|
-
live_pkg = D3::Package.new :
|
530
|
+
live_pkg = D3::Package.new id: live_basenames_to_ids[rcpt.basename]
|
521
531
|
|
522
532
|
begin
|
533
|
+
cloud = cloud_dist_point_to_use(pkg: live_pkg)
|
523
534
|
live_pkg.install(
|
524
|
-
:
|
525
|
-
:
|
526
|
-
:
|
527
|
-
:
|
528
|
-
:
|
529
|
-
:
|
530
|
-
|
535
|
+
admin: rcpt.admin,
|
536
|
+
expiration: expiration,
|
537
|
+
verbose: verbose,
|
538
|
+
force: force,
|
539
|
+
puppywalk: options.puppies,
|
540
|
+
alt_download_url: cloud
|
541
|
+
)
|
531
542
|
D3.log "Done updating #{rcpt.edition} (#{rcpt.status}) to #{live_pkg.edition} (#{live_pkg.status})", :info
|
532
543
|
rescue JSS::MissingDataError, JSS::InvalidDataError, D3::InstallError
|
533
|
-
D3.log "Skipping update of #{rcpt.edition} to #{live_pkg.edition}: #{
|
544
|
+
D3.log "Skipping update of #{rcpt.edition} to #{live_pkg.edition}: #{$ERROR_INFO}", :error
|
534
545
|
D3.log_backtrace
|
535
546
|
rescue D3::PreInstallError
|
536
|
-
D3.log "There was an error with the pre-install script for #{live_pkg.edition}: #{
|
547
|
+
D3.log "There was an error with the pre-install script for #{live_pkg.edition}: #{$ERROR_INFO}", :error
|
537
548
|
D3.log_backtrace
|
538
549
|
rescue D3::PostInstallError
|
539
|
-
D3.log "There was an error with the post-install script for #{live_pkg.edition}: #{
|
550
|
+
D3.log "There was an error with the post-install script for #{live_pkg.edition}: #{$ERROR_INFO} NOTE: #{live_pkg.edition} was installed, but may not work.", :error
|
540
551
|
D3.log_backtrace
|
541
552
|
end # begin
|
542
553
|
end # D3::Client::Receipt.all.values.each
|
@@ -551,7 +562,7 @@ module D3
|
|
551
562
|
###
|
552
563
|
### @return [void]
|
553
564
|
###
|
554
|
-
def self.freeze_receipts
|
565
|
+
def self.freeze_receipts(basenames)
|
555
566
|
basenames.each do |bn|
|
556
567
|
rcpt = D3::Client::Receipt.all[bn]
|
557
568
|
next unless rcpt
|
@@ -571,7 +582,7 @@ module D3
|
|
571
582
|
###
|
572
583
|
### @return [void]
|
573
584
|
###
|
574
|
-
def self.thaw_receipts
|
585
|
+
def self.thaw_receipts(basenames)
|
575
586
|
basenames.each do |bn|
|
576
587
|
rcpt = D3::Client::Receipt.all[bn]
|
577
588
|
next unless rcpt
|
@@ -591,11 +602,11 @@ module D3
|
|
591
602
|
###
|
592
603
|
### @return [void]
|
593
604
|
###
|
594
|
-
def self.forget_receipts
|
605
|
+
def self.forget_receipts(basenames)
|
595
606
|
basenames.each do |bn|
|
596
607
|
rcpt = D3::Client::Receipt.all[bn]
|
597
608
|
next unless rcpt
|
598
|
-
rcpt.apple_pkg_ids.each{|ar| system "/usr/sbin/pkgutil --forget '#{ar}'" }
|
609
|
+
rcpt.apple_pkg_ids.each { |ar| system "/usr/sbin/pkgutil --forget '#{ar}'" }
|
599
610
|
D3::Client::Receipt.remove_receipt bn
|
600
611
|
D3.log "Receipt for #{rcpt.edition} has been forgotten", :warn
|
601
612
|
end
|
@@ -604,22 +615,23 @@ module D3
|
|
604
615
|
### Do any pending puppy installs right now, because we're
|
605
616
|
### syncing and --puppies option was given
|
606
617
|
###
|
607
|
-
def self.do_puppy_queue_installs_from_sync
|
618
|
+
def self.do_puppy_queue_installs_from_sync(options)
|
608
619
|
return unless options.puppies
|
609
|
-
return if
|
610
|
-
D3.log
|
620
|
+
return if D3::PUPPY_Q.q.empty?
|
621
|
+
D3.log 'Installing all pkgs from puppy-queue during sync with --puppies', :info
|
611
622
|
D3::PUPPY_Q.q.each do |basename, puppy|
|
612
623
|
begin
|
613
624
|
D3.log "Installing #{puppy.edition} from puppy-queue during sync with --puppies", :debug
|
614
|
-
new_pkg = D3::Package.new :
|
625
|
+
new_pkg = D3::Package.new id: puppy.id
|
626
|
+
cloud = cloud_dist_point_to_use(pkg: new_pkg)
|
615
627
|
new_pkg.install(
|
616
|
-
:
|
617
|
-
:
|
618
|
-
:
|
619
|
-
:
|
620
|
-
:
|
621
|
-
:
|
622
|
-
|
628
|
+
admin: puppy.admin,
|
629
|
+
verbose: options.verbose,
|
630
|
+
force: puppy.force,
|
631
|
+
puppywalk: true,
|
632
|
+
expiration: puppy.expiration,
|
633
|
+
alt_download_url: cloud
|
634
|
+
)
|
623
635
|
|
624
636
|
D3::PUPPY_Q - puppy
|
625
637
|
rescue JSS::NoSuchItemError
|
@@ -627,13 +639,13 @@ module D3
|
|
627
639
|
D3.log_backtrace
|
628
640
|
D3::PUPPY_Q - puppy
|
629
641
|
rescue JSS::MissingDataError, JSS::InvalidDataError, D3::InstallError
|
630
|
-
D3.log "Skipping install of #{new_pkg.edition} from queue: #{
|
642
|
+
D3.log "Skipping install of #{new_pkg.edition} from queue: #{$ERROR_INFO}", :error
|
631
643
|
D3.log_backtrace
|
632
644
|
rescue D3::PreInstallError
|
633
|
-
D3.log "There was an error with the pre-install script for #{new_pkg.edition}: #{
|
645
|
+
D3.log "There was an error with the pre-install script for #{new_pkg.edition}: #{$ERROR_INFO}", :error
|
634
646
|
D3.log_backtrace
|
635
647
|
rescue D3::PostInstallError
|
636
|
-
D3.log "There was an error with the post-install script for #{new_pkg.edition}: #{
|
648
|
+
D3.log "There was an error with the post-install script for #{new_pkg.edition}: #{$ERROR_INFO} NOTE: #{new_pkg.edition} was installed, but may not work.", :error
|
637
649
|
D3.log_backtrace
|
638
650
|
D3::PUPPY_Q - puppy
|
639
651
|
end # begin
|
@@ -669,7 +681,7 @@ module D3
|
|
669
681
|
###
|
670
682
|
def self.do_expirations (verbose = false, force = D3.forced?)
|
671
683
|
@@editions_expired = []
|
672
|
-
D3.log
|
684
|
+
D3.log 'Starting expiration check', :warn
|
673
685
|
|
674
686
|
D3::Client::Receipt.all.values.each do |rcpt|
|
675
687
|
begin
|
@@ -677,14 +689,14 @@ module D3
|
|
677
689
|
expired_edition = rcpt.expire verbose, force
|
678
690
|
@@editions_expired << expired_edition if expired_edition
|
679
691
|
rescue
|
680
|
-
D3.log "There was an error expiring #{rcpt.edition}: #{
|
692
|
+
D3.log "There was an error expiring #{rcpt.edition}: #{$ERROR_INFO}", :error
|
681
693
|
D3.log_backtrace
|
682
694
|
end
|
683
695
|
end
|
684
696
|
|
685
697
|
return true if @@editions_expired.empty?
|
686
698
|
|
687
|
-
D3::Client.set_env :finished_expirations, @@editions_expired.join(
|
699
|
+
D3::Client.set_env :finished_expirations, @@editions_expired.join(' ')
|
688
700
|
|
689
701
|
if policy = D3::CONFIG.client_expiration_policy
|
690
702
|
D3.run_policy policy, :expiration, verbose
|
@@ -701,11 +713,11 @@ module D3
|
|
701
713
|
###
|
702
714
|
### @return [Array<Integer>]
|
703
715
|
###
|
704
|
-
def self.available_pkg_ids
|
716
|
+
def self.available_pkg_ids(refresh = false)
|
705
717
|
@@available_pkg_ids = nil if refresh
|
706
718
|
return @@available_pkg_ids if @@available_pkg_ids
|
707
719
|
|
708
|
-
|
720
|
+
computer_groups(:refresh) if refresh
|
709
721
|
|
710
722
|
my_cpu = `/usr/bin/uname -p`
|
711
723
|
my_os = `/usr/bin/sw_vers -productVersion`.chomp
|
@@ -715,7 +727,7 @@ module D3
|
|
715
727
|
D3::Package.package_data.values.each do |pkg|
|
716
728
|
next unless JSS.os_ok? pkg[:oses], my_os
|
717
729
|
next unless JSS.processor_ok? pkg[:required_processor], my_cpu
|
718
|
-
@@available_pkg_ids << pkg[:id] if (pkg[:excluded_groups] &
|
730
|
+
@@available_pkg_ids << pkg[:id] if (pkg[:excluded_groups] & computer_groups).empty?
|
719
731
|
end # do pkg
|
720
732
|
@@available_pkg_ids
|
721
733
|
end
|
@@ -726,10 +738,10 @@ module D3
|
|
726
738
|
###
|
727
739
|
### @return [Array<String>] the JSS groups to which this machine belongs
|
728
740
|
###
|
729
|
-
def self.computer_groups
|
741
|
+
def self.computer_groups(refresh = false)
|
730
742
|
@@computer_groups = nil if refresh
|
731
743
|
return @@computer_groups if @@computer_groups
|
732
|
-
@@computer_groups = JSS::Computer.new(:
|
744
|
+
@@computer_groups = JSS::Computer.new(udid: JSS::Client.udid).computer_groups
|
733
745
|
end
|
734
746
|
|
735
747
|
### The cloud dist point to use for installs
|
@@ -743,29 +755,61 @@ module D3
|
|
743
755
|
### @return [String, nil] The download url for the cloud dist point,
|
744
756
|
### if we should use one, or nil.
|
745
757
|
###
|
746
|
-
def self.cloud_dist_point_to_use(refresh = false)
|
758
|
+
def self.cloud_dist_point_to_use(refresh = false, pkg: nil)
|
759
|
+
byebug
|
760
|
+
raise 'You must provide a pkg' unless pkg.is_a? D3::Package
|
761
|
+
|
747
762
|
@@cloud_dist_url == :unknown if refresh
|
748
|
-
return @@cloud_dist_url unless @@cloud_dist_url == :unknown
|
749
763
|
|
750
764
|
mdp = JSS::DistributionPoint.my_distribution_point
|
751
765
|
|
766
|
+
# Should we try a cloud distribution point if the primary is unavailable ?
|
752
767
|
unless D3::CONFIG.client_try_cloud_distpoint
|
753
768
|
D3.log "Config is not to try cloud, using only Distribution Point '#{mdp.name}'", :info
|
754
|
-
return @@cloud_dist_url =
|
769
|
+
return @@cloud_dist_url = nil
|
755
770
|
end
|
756
771
|
|
757
|
-
|
772
|
+
# Can we reach the primary distribution point? Return nil if true.
|
773
|
+
if mdp.reachable_for_download?(get_ro_pass(:http)) || mdp.reachable_for_download?(get_ro_pass(:dist))
|
758
774
|
D3.log "Distribution Point '#{mdp.name}' is reachable, no need for cloud", :info
|
759
|
-
return @@cloud_dist_url =
|
775
|
+
return @@cloud_dist_url = nil
|
760
776
|
end
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
D3.log
|
777
|
+
|
778
|
+
# Get the cloud distribution point defined in the JSS
|
779
|
+
cloud_url = cloud_distribution_point_url
|
780
|
+
unless cloud_url
|
781
|
+
D3.log 'No cloud distribution URL found.', :info
|
782
|
+
return @@cloud_dist_url = nil
|
766
783
|
end
|
784
|
+
# Make sure the package is available on the cloud distribution point
|
785
|
+
pkg_available = validate_pkg_in_cloud(cloud_url, pkg) if cloud_url
|
786
|
+
unless pkg_available
|
787
|
+
D3.log "#{pkg.edition} is not available in the cloud", :info
|
788
|
+
return @@cloud_dist_url = nil
|
789
|
+
end
|
790
|
+
|
767
791
|
@@cloud_dist_url = cloud_url
|
768
|
-
end
|
792
|
+
end # self.cloud_dist_point_to_use
|
793
|
+
|
794
|
+
# given a cloud url and a D3::Package
|
795
|
+
# is the pkg available at that url?
|
796
|
+
#
|
797
|
+
# @return [Boolean]
|
798
|
+
#
|
799
|
+
def self.validate_pkg_in_cloud(url, pkg)
|
800
|
+
full_url = "#{url}/#{pkg.filename}"
|
801
|
+
dummy_install_target = Pathname.new('/Volumes/' + Time.now.asctime)
|
802
|
+
jamf_cmd = "#{JSS::Client::JAMF_BINARY} install -package #{Shellwords.escape pkg.filename} -path #{Shellwords.escape full_url} -target #{Shellwords.escape dummy_install_target}/ -showProgress -verbose"
|
803
|
+
Open3.popen2e(jamf_cmd) do |_stdin, stdout_err, wait_thr|
|
804
|
+
stdout_err.each do |line|
|
805
|
+
if /^\d*+\.\d*+% / =~ line
|
806
|
+
Process.kill('KILL', wait_thr.pid)
|
807
|
+
return true
|
808
|
+
end # end if /^\d*+\.\d*+% / =~ line
|
809
|
+
end # end stdout_err.each do |line|
|
810
|
+
return false
|
811
|
+
end # end Open3.popen2e(jamf_cmd) do |_stdin, stdout_err, wait_thr|
|
812
|
+
end # def self.validate_pkg_in_cloud pkg
|
769
813
|
|
770
814
|
### Is a Cloud Distribution Point available for pkg downloads?
|
771
815
|
### If so, return the url for downloading pkg files
|
@@ -774,12 +818,12 @@ module D3
|
|
774
818
|
### @return [String, nil]
|
775
819
|
###
|
776
820
|
def self.cloud_distribution_point_url
|
777
|
-
result = JSS::DB_CNX.db.query
|
821
|
+
result = JSS::DB_CNX.db.query 'SELECT download_url, cdn_url FROM cloud_distribution_point'
|
778
822
|
urls = result.fetch
|
779
823
|
result.free
|
780
824
|
return nil if urls.nil?
|
781
|
-
return nil if urls[0].empty?
|
782
|
-
|
825
|
+
return nil if urls[0].empty? || urls[1].empty?
|
826
|
+
urls[0].empty? ? urls[1] : urls[0]
|
783
827
|
end
|
784
828
|
|
785
829
|
### Given a basename, is any edition of it in the puppy queue?
|
@@ -789,26 +833,32 @@ module D3
|
|
789
833
|
###
|
790
834
|
### @return [Integer, nil] The id of the queued package for the basename, if any
|
791
835
|
###
|
792
|
-
def self.puppy_in_queue
|
836
|
+
def self.puppy_in_queue(basename)
|
793
837
|
pup = D3::PUPPY_Q.queue[basename]
|
794
838
|
return nil unless pup
|
795
|
-
|
839
|
+
pup.id
|
796
840
|
end # basename in puppy queue
|
797
841
|
|
798
|
-
|
799
842
|
### get the executable path of the current foreground GUI app. NOTE, if you
|
800
843
|
### have fast user switching on, or multi-user screensharing,
|
801
844
|
### this only gets the one currenly using the physical console
|
802
845
|
###
|
803
|
-
### @return [Pathname] the path to the executable of the current foreground app
|
846
|
+
### @return [Pathname, nil] the path to the executable of the current foreground app, nil if none
|
804
847
|
###
|
805
848
|
def self.foreground_executable_path
|
806
|
-
lsai =
|
807
|
-
ls_app_id =
|
849
|
+
lsai = '/usr/bin/lsappinfo'
|
850
|
+
ls_app_id = `#{lsai} front`.chomp
|
851
|
+
return nil if ls_app_id == '[ NULL ] '
|
808
852
|
|
809
853
|
raw = `#{lsai} info -only executablepath '#{ls_app_id}'`.chomp
|
810
|
-
|
811
|
-
|
854
|
+
return nil if raw.empty?
|
855
|
+
|
856
|
+
path = raw.split(/=\s*"/).last
|
857
|
+
return nil unless path
|
858
|
+
path.chomp!('"')
|
859
|
+
path.empty? ? nil : Pathname.new(path)
|
812
860
|
end
|
861
|
+
|
813
862
|
end # class
|
863
|
+
|
814
864
|
end # module D3
|