depot3 0.0.0a1 → 3.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +55 -1
- data/bin/d3 +323 -0
- data/bin/d3admin +1011 -0
- data/bin/d3helper +354 -0
- data/bin/puppytime +334 -0
- data/data/d3/com.pixar.d3.RepoMan.plist +23 -0
- data/data/d3/d3.conf.example +507 -0
- data/data/d3/d3RepoMan.app/Contents/Frameworks/libswiftAppKit.dylib +0 -0
- data/data/d3/d3RepoMan.app/Contents/Frameworks/libswiftCore.dylib +0 -0
- data/data/d3/d3RepoMan.app/Contents/Frameworks/libswiftCoreData.dylib +0 -0
- data/data/d3/d3RepoMan.app/Contents/Frameworks/libswiftCoreGraphics.dylib +0 -0
- data/data/d3/d3RepoMan.app/Contents/Frameworks/libswiftCoreImage.dylib +0 -0
- data/data/d3/d3RepoMan.app/Contents/Frameworks/libswiftDarwin.dylib +0 -0
- data/data/d3/d3RepoMan.app/Contents/Frameworks/libswiftDispatch.dylib +0 -0
- data/data/d3/d3RepoMan.app/Contents/Frameworks/libswiftFoundation.dylib +0 -0
- data/data/d3/d3RepoMan.app/Contents/Frameworks/libswiftObjectiveC.dylib +0 -0
- data/data/d3/d3RepoMan.app/Contents/Info.plist +56 -0
- data/data/d3/d3RepoMan.app/Contents/MacOS/d3RepoMan +0 -0
- data/data/d3/d3RepoMan.app/Contents/PkgInfo +1 -0
- data/data/d3/d3RepoMan.app/Contents/Resources/Base.lproj/MainMenu.nib +0 -0
- data/data/d3/d3RepoMan.app/Contents/Resources/last-foreground-times-template.plist +5 -0
- data/data/d3/d3RepoMan.app/Contents/_CodeSignature/CodeResources +214 -0
- data/data/d3/puppytime/ImageLicenses.txt +165 -0
- data/data/d3/puppytime/notification_image +1 -0
- data/data/d3/puppytime/opt_out_image +1 -0
- data/data/d3/puppytime/slideshow/2008-07-11_White_German_Shepherd_pup_chilling_at_the_Coker_Arboretum.jpg +0 -0
- data/data/d3/puppytime/slideshow/2009-04-21_APBT_pup_on_deck.jpg +0 -0
- data/data/d3/puppytime/slideshow/A_puppy_Yorkie.jpg +0 -0
- data/data/d3/puppytime/slideshow/Alert_Pug_Puppy.jpg +0 -0
- data/data/d3/puppytime/slideshow/Australian_Cattle_Dog_puppies_04.JPG +0 -0
- data/data/d3/puppytime/slideshow/Beagle_puppy_Cadet.jpg +0 -0
- data/data/d3/puppytime/slideshow/Bernese_Mountain_Dog.jpg +0 -0
- data/data/d3/puppytime/slideshow/Bloodhound_Puppy.jpg +0 -0
- data/data/d3/puppytime/slideshow/Boston_terrier_with_toy.jpg +0 -0
- data/data/d3/puppytime/slideshow/Boxer_puppy_fawn_portrai.jpg +0 -0
- data/data/d3/puppytime/slideshow/Caracal_kitten.jpg +0 -0
- data/data/d3/puppytime/slideshow/Chihuahua_&_Doberman_Pup.jpg +0 -0
- data/data/d3/puppytime/slideshow/Cuccioli_di_Margot_a_35_gg_Basenjis.jpg +0 -0
- data/data/d3/puppytime/slideshow/Dalmatian_puppy_03.jpg +0 -0
- data/data/d3/puppytime/slideshow/GoldenRetrieverPuppyDaisyParker.JPG +0 -0
- data/data/d3/puppytime/slideshow/Green_eyed_beige_Chihuahua.jpg +0 -0
- data/data/d3/puppytime/slideshow/Let_Sleeping_Dogs_Lie.jpg +0 -0
- data/data/d3/puppytime/slideshow/Meatball_-_French_Bulldog_Puppy.jpg +0 -0
- data/data/d3/puppytime/slideshow/Oola_-_9_weeks.jpg +0 -0
- data/data/d3/puppytime/slideshow/Pancho0008.JPG +0 -0
- data/data/d3/puppytime/slideshow/Pomeranian_orange-sable_Coco.jpg +0 -0
- data/data/d3/puppytime/slideshow/Pug_puppy_001.jpg +0 -0
- data/data/d3/puppytime/slideshow/Puggle_puppy_6_weeks.JPG +0 -0
- data/data/d3/puppytime/slideshow/Puli_kan.jpg +0 -0
- data/data/d3/puppytime/slideshow/Puppy_French_Bulldog.jpg +0 -0
- data/data/d3/puppytime/slideshow/Rocco_the_Bulldog.jpg +0 -0
- data/data/d3/puppytime/slideshow/Rottweiler_Face.jpg +0 -0
- data/data/d3/puppytime/slideshow/Saint_Bernard_puppy.jpg +0 -0
- data/data/d3/puppytime/slideshow/Scottish_froment.jpg +0 -0
- data/data/d3/puppytime/slideshow/Shar_pei_puppy_(age_2_months).jpg +0 -0
- data/data/d3/puppytime/slideshow/Shiba-Inu_beim_Spielen_im_Schnee.JPG +0 -0
- data/data/d3/puppytime/slideshow/Smooth-coat_Border_Collie_puppy..jpg +0 -0
- data/data/d3/puppytime/slideshow/Smooth_Dachshund_puppies.jpg +0 -0
- data/data/d3/puppytime/slideshow/Snow_dog.jpg +0 -0
- data/data/d3/puppytime/slideshow/Taylor_the_Pembroke_Welsh_Corgi.png +0 -0
- data/data/d3/puppytime/slideshow/Weim_Pups_001.jpg +0 -0
- data/data/d3/puppytime/slideshow/Westie_pups.jpg +0 -0
- data/data/d3/puppytime/slideshow/Yellow_Labrador_puppies_(4165737325).jpg +0 -0
- data/lib/d3/admin/add.rb +451 -0
- data/lib/d3/admin/auth.rb +470 -0
- data/lib/d3/admin/edit.rb +297 -0
- data/lib/d3/admin/help.rb +396 -0
- data/lib/d3/admin/interactive.rb +972 -0
- data/lib/d3/admin/options.rb +454 -0
- data/lib/d3/admin/prefs.rb +204 -0
- data/lib/d3/admin/report.rb +727 -0
- data/lib/d3/admin/state.rb +42 -0
- data/lib/d3/admin/validate.rb +413 -0
- data/lib/d3/admin.rb +42 -0
- data/lib/d3/basename.rb +217 -0
- data/lib/d3/client/auth.rb +108 -0
- data/lib/d3/client/class_methods.rb +766 -0
- data/lib/d3/client/class_variables.rb +47 -0
- data/lib/d3/client/cli.rb +187 -0
- data/lib/d3/client/environment.rb +134 -0
- data/lib/d3/client/help.rb +110 -0
- data/lib/d3/client/lists.rb +314 -0
- data/lib/d3/client/receipt.rb +1173 -0
- data/lib/d3/client.rb +45 -0
- data/lib/d3/configuration.rb +319 -0
- data/lib/d3/constants.rb +60 -0
- data/lib/d3/database.rb +488 -0
- data/lib/d3/exceptions.rb +44 -0
- data/lib/d3/log.rb +271 -0
- data/lib/d3/package/aliases.rb +80 -0
- data/lib/d3/package/attributes.rb +97 -0
- data/lib/d3/package/class_methods.rb +817 -0
- data/lib/d3/package/class_variables.rb +46 -0
- data/lib/d3/package/client_actions.rb +293 -0
- data/lib/d3/package/constants.rb +58 -0
- data/lib/d3/package/constructor.rb +191 -0
- data/lib/d3/package/getters.rb +164 -0
- data/lib/d3/package/mixins.rb +39 -0
- data/lib/d3/package/private_methods.rb +227 -0
- data/lib/d3/package/questions.rb +95 -0
- data/lib/d3/package/server_actions.rb +683 -0
- data/lib/d3/package/setters.rb +326 -0
- data/lib/d3/package/validate.rb +448 -0
- data/lib/d3/package.rb +51 -0
- data/lib/d3/puppytime/pending_puppy.rb +108 -0
- data/lib/d3/puppytime/puppy_queue.rb +274 -0
- data/lib/d3/puppytime.rb +68 -0
- data/lib/d3/state.rb +105 -0
- data/lib/d3/utility.rb +325 -0
- data/lib/d3/version.rb +1 -1
- metadata +162 -9
data/bin/d3helper
ADDED
@@ -0,0 +1,354 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
### Copyright 2016 Pixar
|
3
|
+
###
|
4
|
+
### Licensed under the Apache License, Version 2.0 (the "Apache License")
|
5
|
+
### with the following modification; you may not use this file except in
|
6
|
+
### compliance with the Apache License and the following modification to it:
|
7
|
+
### Section 6. Trademarks. is deleted and replaced with:
|
8
|
+
###
|
9
|
+
### 6. Trademarks. This License does not grant permission to use the trade
|
10
|
+
### names, trademarks, service marks, or product names of the Licensor
|
11
|
+
### and its affiliates, except as required to comply with Section 4(c) of
|
12
|
+
### the License and to reproduce the content of the NOTICE file.
|
13
|
+
###
|
14
|
+
### You may obtain a copy of the Apache License at
|
15
|
+
###
|
16
|
+
### http://www.apache.org/licenses/LICENSE-2.0
|
17
|
+
###
|
18
|
+
### Unless required by applicable law or agreed to in writing, software
|
19
|
+
### distributed under the Apache License with the above modification is
|
20
|
+
### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
21
|
+
### KIND, either express or implied. See the Apache License for the specific
|
22
|
+
### language governing permissions and limitations under the Apache License.
|
23
|
+
###
|
24
|
+
###
|
25
|
+
|
26
|
+
######################################
|
27
|
+
# == Synopsis
|
28
|
+
# d3helper [action]
|
29
|
+
#
|
30
|
+
# d3helper: perform various helper tasks for d3
|
31
|
+
#
|
32
|
+
# Copyright Pixar Animation Studios
|
33
|
+
#
|
34
|
+
# Author: Chris Lasell chrisl@pixar.com
|
35
|
+
#
|
36
|
+
#
|
37
|
+
######################################
|
38
|
+
|
39
|
+
|
40
|
+
############
|
41
|
+
# Modules, Libraries, etc
|
42
|
+
############
|
43
|
+
# Load libraries
|
44
|
+
require 'd3'
|
45
|
+
|
46
|
+
############
|
47
|
+
# The App Object
|
48
|
+
############
|
49
|
+
|
50
|
+
class App
|
51
|
+
|
52
|
+
############################################
|
53
|
+
### Constants - paths, settings, and other values used throughout
|
54
|
+
|
55
|
+
ACTIONS = {
|
56
|
+
"--display-puppy-notification" => :display_puppy_notification,
|
57
|
+
"--rcpts-for-ea" => :rcpts_for_ea,
|
58
|
+
"--puppyq-for-ea" => :puppyq_for_ea,
|
59
|
+
"--import-casper-receipts" => :import_receipts,
|
60
|
+
"--help" => :help,
|
61
|
+
"--version" => :show_version
|
62
|
+
}
|
63
|
+
|
64
|
+
USAGE = "#{File.basename(__FILE__)} [--help] [action]\nwhere action is one of: #{ACTIONS.keys.join(', ')}"
|
65
|
+
|
66
|
+
|
67
|
+
attr_reader :debug
|
68
|
+
|
69
|
+
############################################
|
70
|
+
### Setup
|
71
|
+
### Initialization should only be used to set variables
|
72
|
+
### and set up the infrasctructure. No actual processing/error checking
|
73
|
+
### until the run method is called.
|
74
|
+
###
|
75
|
+
def initialize(args)
|
76
|
+
opts = GetoptLong.new(
|
77
|
+
[ '--help', '-h', '-H', GetoptLong::NO_ARGUMENT ],
|
78
|
+
[ '--debug', '-d', GetoptLong::NO_ARGUMENT ],
|
79
|
+
[ '--import-casper-receipts', GetoptLong::NO_ARGUMENT ],
|
80
|
+
[ '--display-puppy-notification', GetoptLong::NO_ARGUMENT ],
|
81
|
+
[ '--rcpts-for-ea', GetoptLong::NO_ARGUMENT ],
|
82
|
+
[ '--puppyq-for-ea', GetoptLong::NO_ARGUMENT ],
|
83
|
+
[ '--version', '-v', GetoptLong::NO_ARGUMENT ],
|
84
|
+
[ '--configure', GetoptLong::NO_ARGUMENT ]
|
85
|
+
)
|
86
|
+
|
87
|
+
opts.each do |opt, arg|
|
88
|
+
case opt
|
89
|
+
when '--help'
|
90
|
+
@action = ACTIONS[opt]
|
91
|
+
when '--version'
|
92
|
+
@action = ACTIONS[opt]
|
93
|
+
when '--debug'
|
94
|
+
@debug = true
|
95
|
+
when '--import-casper-receipts'
|
96
|
+
@action = ACTIONS[opt]
|
97
|
+
when '--display-puppy-notification'
|
98
|
+
@action = ACTIONS[opt]
|
99
|
+
when '--rcpts-for-ea'
|
100
|
+
@action = ACTIONS[opt]
|
101
|
+
when '--puppyq-for-ea'
|
102
|
+
@action = ACTIONS[opt]
|
103
|
+
when '--configure'
|
104
|
+
@action = ACTIONS[opt]
|
105
|
+
end # case
|
106
|
+
end # opts.each
|
107
|
+
|
108
|
+
unless @action
|
109
|
+
puts USAGE
|
110
|
+
exit 1
|
111
|
+
end
|
112
|
+
|
113
|
+
D3::LOG.progname = File.basename(__FILE__)
|
114
|
+
end # init
|
115
|
+
|
116
|
+
############################################
|
117
|
+
### Run
|
118
|
+
def run
|
119
|
+
if @action == :help or @action == :show_version
|
120
|
+
self.send @action
|
121
|
+
return
|
122
|
+
end
|
123
|
+
|
124
|
+
# Must be root to do these things
|
125
|
+
raise D3::PermissionError, "Only root can use this program" unless JSS.superuser?
|
126
|
+
|
127
|
+
# connect to the server servernames are defined in JSS::CONFIG
|
128
|
+
D3::Client.connect
|
129
|
+
|
130
|
+
# do something
|
131
|
+
self.send @action
|
132
|
+
|
133
|
+
end # run
|
134
|
+
|
135
|
+
############################################
|
136
|
+
### Instance Methods
|
137
|
+
|
138
|
+
############
|
139
|
+
# spew out help
|
140
|
+
def help
|
141
|
+
|
142
|
+
puts <<-USAGEBLURB
|
143
|
+
#{USAGE}
|
144
|
+
|
145
|
+
--display-puppy-notification Tell users that puppies need walking.
|
146
|
+
--import-casper-receipts Import local Casper package receipts into
|
147
|
+
d3 receipts. Can be run repeatedly to
|
148
|
+
import for packages new to d3.
|
149
|
+
--rcpts-for-ea Generate Extension Attribute data about
|
150
|
+
the d3 receipts on this machine.
|
151
|
+
--help, -h, -H Show this help.
|
152
|
+
|
153
|
+
USAGEBLURB
|
154
|
+
|
155
|
+
end # show_help
|
156
|
+
|
157
|
+
|
158
|
+
def show_version
|
159
|
+
puts <<-ENDVERS
|
160
|
+
D3 module version: #{D3::VERSION}
|
161
|
+
JSS module version: #{JSS::VERSION}
|
162
|
+
ENDVERS
|
163
|
+
end
|
164
|
+
|
165
|
+
###
|
166
|
+
def display_puppy_notification
|
167
|
+
puppy_notification_env = D3::Client::ENV_STATES[:puppytime_notification]
|
168
|
+
|
169
|
+
pending_puppy_names = ENV[puppy_notification_env]
|
170
|
+
pending_puppy_names ||= "(No Puppies to walk! why are you seeing this?)"
|
171
|
+
|
172
|
+
description = "Please log out ASAP for software installs and updates.
|
173
|
+
Watch a parade of cute puppies while these items are installed:
|
174
|
+
#{pending_puppy_names}"
|
175
|
+
|
176
|
+
image_path = D3::CONFIG.puppy_notify_image_path ? Pathname.new(D3::CONFIG.puppy_notify_image_path) : nil
|
177
|
+
|
178
|
+
image_path = D3::PuppyTime::DFT_NOTIFY_IMAGE unless image_path && image_path.file?
|
179
|
+
|
180
|
+
# fork off the jamf helper, then detach it so the policy running this doesn't
|
181
|
+
# hang aound
|
182
|
+
alert_pid = Process.fork do
|
183
|
+
JSS::Client.jamf_helper( :hud, :lock_hud => true,
|
184
|
+
:window_position => :ur,
|
185
|
+
:title => "The puppies await you",
|
186
|
+
:align_heading => :center,
|
187
|
+
:heading => "It's PuppyTime!",
|
188
|
+
:description => description,
|
189
|
+
:align_description => :left,
|
190
|
+
:icon => image_path.to_s,
|
191
|
+
:icon_size => 300,
|
192
|
+
:button1 => "OK",
|
193
|
+
:default_button => 1
|
194
|
+
)
|
195
|
+
end # fork
|
196
|
+
Process.detach(alert_pid)
|
197
|
+
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
### output a JSON string with miminal data about the receipts on this machine
|
202
|
+
### wrapped in a <result> tag, to be used in the CONFIG.report_receipts_ext_attr_name
|
203
|
+
### extension attribute
|
204
|
+
###
|
205
|
+
def rcpts_for_ea
|
206
|
+
begin
|
207
|
+
ea_data = {}
|
208
|
+
D3::Client::Receipt.all.values.each { |r|
|
209
|
+
this_r = {}
|
210
|
+
this_r[:version] = r.version
|
211
|
+
this_r[:revision] = r.revision
|
212
|
+
this_r[:status] = r.status
|
213
|
+
this_r[:installed_at] = r.installed_at
|
214
|
+
this_r[:admin] = r.admin
|
215
|
+
this_r[:frozen] = r.frozen?
|
216
|
+
this_r[:manual] = r.manually_installed
|
217
|
+
this_r[:custom_expiration] = r.custom_expiration
|
218
|
+
this_r[:last_usage] = r.last_usage
|
219
|
+
ea_data[r.basename] = this_r
|
220
|
+
} # D3::Client::Receipt.all.values do |r|
|
221
|
+
|
222
|
+
res = JSON.dump ea_data
|
223
|
+
rescue
|
224
|
+
res = "ERROR:#{$!}:#{$@.first}"
|
225
|
+
end
|
226
|
+
puts "<result>#{res}</result>"
|
227
|
+
end
|
228
|
+
|
229
|
+
|
230
|
+
### output a JSON string with data about the pending puppytime (logout)
|
231
|
+
### installs on this machine wrapped in a <result> tag, to be used in the
|
232
|
+
### CONFIG.report_puppyq_ext_attr_name extension attribute
|
233
|
+
###
|
234
|
+
### The data is a hash of hashes, first keys are basenames
|
235
|
+
### second keys are
|
236
|
+
### :version
|
237
|
+
### :revision
|
238
|
+
### :status
|
239
|
+
### :queued_at (Time)
|
240
|
+
### :admin
|
241
|
+
### :custom_expiration
|
242
|
+
###
|
243
|
+
### @return [void]
|
244
|
+
###
|
245
|
+
def puppyq_for_ea
|
246
|
+
begin
|
247
|
+
ea_data = {}
|
248
|
+
D3::PUPPY_Q.queue.values.each { |pup|
|
249
|
+
this_pup = {}
|
250
|
+
this_pup[:version] = pup.version
|
251
|
+
this_pup[:revision] = pup.revision
|
252
|
+
this_pup[:status] = pup.status
|
253
|
+
this_pup[:queued_at] = pup.queued_at
|
254
|
+
this_pup[:admin] = pup.admin
|
255
|
+
this_pup[:custom_expiration] = pup.custom_expiration
|
256
|
+
ea_data[pup.basename] = this_pup
|
257
|
+
} # D3::Client::Receipt.all.values do |r|
|
258
|
+
|
259
|
+
res = JSON.dump ea_data
|
260
|
+
rescue
|
261
|
+
res = "ERROR:#{$!}:#{$@.first}"
|
262
|
+
end
|
263
|
+
puts "<result>#{res}</result>"
|
264
|
+
end
|
265
|
+
|
266
|
+
|
267
|
+
###
|
268
|
+
def import_receipts
|
269
|
+
|
270
|
+
D3.log "Importing Casper Receipts for packages in d3", :warn
|
271
|
+
|
272
|
+
# this gets us a hash of jss package filenames -> pkg ids
|
273
|
+
d3_pkg_filenames = D3::Package.all_filenames.invert
|
274
|
+
|
275
|
+
# this is an array of current d3 receipt ids
|
276
|
+
d3_rcpt_ids = D3::Client::Receipt.all.values.map{|r| r.id}
|
277
|
+
|
278
|
+
now = Time.now
|
279
|
+
|
280
|
+
JSS::Client.receipts.each do |jss_rcpt|
|
281
|
+
|
282
|
+
|
283
|
+
# jss_rcpt is a Pathname object, the rcpt name is the paths basename
|
284
|
+
jss_rcpt_name = jss_rcpt.basename.to_s
|
285
|
+
|
286
|
+
# do we have a match?
|
287
|
+
pkg_id = d3_pkg_filenames[jss_rcpt_name]
|
288
|
+
# if not, the filename might end with .zip, but the rcpt name doesnt
|
289
|
+
pkg_id ||= d3_pkg_filenames[jss_rcpt_name + ".zip"]
|
290
|
+
# if still not, this jss recipt doesn't point to a d3 package.
|
291
|
+
next unless pkg_id
|
292
|
+
|
293
|
+
# If we're here, the jss receipt might need to be imported, unless its
|
294
|
+
# already been imported
|
295
|
+
next if d3_rcpt_ids.include? pkg_id
|
296
|
+
|
297
|
+
# If we're here, we need to import the receipt, so get the matching D3
|
298
|
+
# package and make a receipt from it.
|
299
|
+
D3.log "Importing Casper Receipt #{jss_rcpt_name}", :warn
|
300
|
+
begin
|
301
|
+
d3_pkg = D3::Package.new id: pkg_id
|
302
|
+
|
303
|
+
# do we already have a rcpt for the package's basename? if so,
|
304
|
+
# delete it - we can only have on rcpt per basename
|
305
|
+
|
306
|
+
if D3::Client::Receipt.all(:refresh).keys.include? d3_pkg.basename
|
307
|
+
D3.log "Deleting previous d3 receipt for basename #{d3_pkg.basename}", :warn
|
308
|
+
D3::Client::Receipt.all[d3_pkg.basename].delete
|
309
|
+
end
|
310
|
+
|
311
|
+
d3_rcpt = D3::Client::Receipt.new(
|
312
|
+
:basename => d3_pkg.basename,
|
313
|
+
:version => d3_pkg.version,
|
314
|
+
:revision => d3_pkg.revision,
|
315
|
+
:admin => D3::AUTO_INSTALL_ADMIN,
|
316
|
+
:id => d3_pkg.id,
|
317
|
+
:status => d3_pkg.status ,
|
318
|
+
:jamf_rcpt_file => jss_rcpt,
|
319
|
+
:apple_pkg_ids => nil,
|
320
|
+
:installed_at => jss_rcpt.mtime,
|
321
|
+
:removable => d3_pkg.removable,
|
322
|
+
:expiration => d3_pkg.expiration,
|
323
|
+
:expiration_path => d3_pkg.expiration_path,
|
324
|
+
:prohibiting_process => d3_pkg.prohibiting_process,
|
325
|
+
:pre_remove_script_id => d3_pkg.pre_remove_script_id,
|
326
|
+
:post_remove_script_id => d3_pkg.post_remove_script_id
|
327
|
+
)
|
328
|
+
D3::Client::Receipt.add_receipt d3_rcpt, :replace
|
329
|
+
D3.log "Done. Imported Casper Receipt #{jss_rcpt_name}", :warn
|
330
|
+
rescue
|
331
|
+
D3.log "ERROR importing Casper Receipt #{jss_rcpt_name}: #{$!}", :error
|
332
|
+
end
|
333
|
+
|
334
|
+
D3.log "Done importing Casper Receipts for packages in d3", :warn
|
335
|
+
|
336
|
+
end #JSS::Client.receipts.each do |jss_rcpt|
|
337
|
+
end #import_receipts
|
338
|
+
|
339
|
+
end # class App
|
340
|
+
|
341
|
+
|
342
|
+
############
|
343
|
+
# Go
|
344
|
+
############
|
345
|
+
begin
|
346
|
+
app = nil
|
347
|
+
app = App.new(ARGV)
|
348
|
+
app.run
|
349
|
+
exit 0
|
350
|
+
rescue
|
351
|
+
$stderr.puts "An error occurred: #{$!}"
|
352
|
+
$stderr.puts $@ if D3::CONFIG.log_level == :debug or (app and app.debug)
|
353
|
+
exit 1
|
354
|
+
end # begin
|
data/bin/puppytime
ADDED
@@ -0,0 +1,334 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
### Copyright 2016 Pixar
|
3
|
+
###
|
4
|
+
### Licensed under the Apache License, Version 2.0 (the "Apache License")
|
5
|
+
### with the following modification; you may not use this file except in
|
6
|
+
### compliance with the Apache License and the following modification to it:
|
7
|
+
### Section 6. Trademarks. is deleted and replaced with:
|
8
|
+
###
|
9
|
+
### 6. Trademarks. This License does not grant permission to use the trade
|
10
|
+
### names, trademarks, service marks, or product names of the Licensor
|
11
|
+
### and its affiliates, except as required to comply with Section 4(c) of
|
12
|
+
### the License and to reproduce the content of the NOTICE file.
|
13
|
+
###
|
14
|
+
### You may obtain a copy of the Apache License at
|
15
|
+
###
|
16
|
+
### http://www.apache.org/licenses/LICENSE-2.0
|
17
|
+
###
|
18
|
+
### Unless required by applicable law or agreed to in writing, software
|
19
|
+
### distributed under the Apache License with the above modification is
|
20
|
+
### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
21
|
+
### KIND, either express or implied. See the Apache License for the specific
|
22
|
+
### language governing permissions and limitations under the Apache License.
|
23
|
+
###
|
24
|
+
###
|
25
|
+
|
26
|
+
|
27
|
+
# PuppyTime! Install all d3 packages listed in the puppy-queue while displaying
|
28
|
+
# a slideshow.
|
29
|
+
#
|
30
|
+
# The default images are of cute puppies, but they can be customized.
|
31
|
+
# See http://some/url/ for details.
|
32
|
+
#
|
33
|
+
# If there are no items in the queue, the script exits immediately.
|
34
|
+
#
|
35
|
+
# This script is intended to be executed at logout. This is best accomplished
|
36
|
+
# with a Casper policy triggered at logout. The policy can either run this script
|
37
|
+
# as a Casper script (in which case you need to add it to the JSS) or
|
38
|
+
# can call it locally using the "execute command" field of the
|
39
|
+
# "files and processes" section of the policy
|
40
|
+
#
|
41
|
+
# This script also expects a policy to be defined in
|
42
|
+
# D3::CONFIG.puppy_reboot_policy, which can contain policy name, custom-trigger
|
43
|
+
# or JSS id number.
|
44
|
+
#
|
45
|
+
# That policy may do any other actions after installing the packages in the
|
46
|
+
# queue, but before the reboot. It shouldn't to too much, however, since the
|
47
|
+
# system may be in an unstable state after the installs. The policy itself
|
48
|
+
# *must* do the actual reboot.
|
49
|
+
#
|
50
|
+
# If the D3::CONFIG.puppy_reboot_policy is not defined, or doesn't exist exist
|
51
|
+
# in the JSS, this script will reboot with 'shutdown -r now'
|
52
|
+
#
|
53
|
+
#
|
54
|
+
require 'd3'
|
55
|
+
require 'ostruct'
|
56
|
+
|
57
|
+
class App
|
58
|
+
|
59
|
+
VERSION = "3.0.0"
|
60
|
+
|
61
|
+
# app attributes
|
62
|
+
attr_reader :slideshow_pid
|
63
|
+
|
64
|
+
# Set up
|
65
|
+
def initialize(args)
|
66
|
+
|
67
|
+
@show_version = (args.include? "--version") || (args.include? "-v")
|
68
|
+
|
69
|
+
# debugging?
|
70
|
+
if args.include? "--debug"
|
71
|
+
@debug = true
|
72
|
+
D3::LOG.level = :debug
|
73
|
+
D3::Client.set_env :debug
|
74
|
+
args.delete_if{|f| f == "--debug" }
|
75
|
+
end
|
76
|
+
|
77
|
+
# These come from the JAMF binary and how it runs scripts
|
78
|
+
# the first arg is the target drive
|
79
|
+
# the second arg is the computer name
|
80
|
+
# the third arg is always the user.
|
81
|
+
@target_drive = args[0]
|
82
|
+
@comp_name = args[1]
|
83
|
+
@user = args[2]
|
84
|
+
|
85
|
+
|
86
|
+
# use config values or defaults
|
87
|
+
@optout_text = D3::CONFIG.puppy_optout_text || D3::PuppyTime::DFT_OPTOUT_TEXT
|
88
|
+
|
89
|
+
@optout_image_path = Pathname.new(D3::CONFIG.puppy_optout_image_path || D3::PuppyTime::DFT_OPTOUT_IMAGE)
|
90
|
+
|
91
|
+
@optout_seconds = D3::CONFIG.puppy_optout_seconds || D3::PuppyTime::DFT_OPTOUT_SECS
|
92
|
+
|
93
|
+
@slideshow_folder_path = Pathname.new(D3::CONFIG.puppy_slideshow_folder_path || D3::PuppyTime::DFT_SLIDESHOW_DIR)
|
94
|
+
|
95
|
+
@image_size = D3::CONFIG.puppy_image_size || D3::PuppyTime::DFT_IMG_SIZE
|
96
|
+
|
97
|
+
@title = D3::CONFIG.puppy_title || D3::PuppyTime::DFT_TITLE
|
98
|
+
|
99
|
+
@display_secs = D3::CONFIG.puppy_display_secs || D3::PuppyTime::DFT_DISPLAY_SECS
|
100
|
+
|
101
|
+
@show_captions = D3::CONFIG.puppy_display_captions
|
102
|
+
|
103
|
+
@dft_caption = D3::PuppyTime::DFT_CAPTION || D3::PuppyTime::DFT_CAPTION
|
104
|
+
|
105
|
+
# paths must exist, or use defaults
|
106
|
+
@optout_image_path = D3::PuppyTime::DFT_OPTOUT_IMAGE unless @optout_image_path.file?
|
107
|
+
@slideshow_folder_path = D3::PuppyTime::DFT_SLIDESHOW_DIR unless @slideshow_folder_path.directory?
|
108
|
+
|
109
|
+
|
110
|
+
end # init
|
111
|
+
|
112
|
+
### walk them puppies!
|
113
|
+
def run
|
114
|
+
|
115
|
+
if @show_version
|
116
|
+
show_version
|
117
|
+
return
|
118
|
+
end
|
119
|
+
|
120
|
+
D3.log "Starting PuppyTime", :warn
|
121
|
+
|
122
|
+
# show the opt-out window
|
123
|
+
button_clicked = JSS::Client.jamf_helper( :hud,
|
124
|
+
:lock_hud => true,
|
125
|
+
:title => @title,
|
126
|
+
:heading => "It's PuppyTime!",
|
127
|
+
:align_heading => D3::PuppyTime::CAPTION_POSITION,
|
128
|
+
:description => @optout_text,
|
129
|
+
:align_description => D3::PuppyTime::TEXT_POSITION,
|
130
|
+
:icon => @optout_image_path.to_s,
|
131
|
+
:icon_size => @image_size,
|
132
|
+
:button1 => "OK",
|
133
|
+
:button2 => "Cancel",
|
134
|
+
:default_button => 1,
|
135
|
+
:cancel_button => 2,
|
136
|
+
:timeout => @optout_seconds,
|
137
|
+
:countdown => true,
|
138
|
+
:align_countdown => D3::PuppyTime::COUNTDOWN_POSITION
|
139
|
+
)
|
140
|
+
|
141
|
+
# TODO test if we need #startlaunchd
|
142
|
+
|
143
|
+
# did the user cancel in time?
|
144
|
+
if button_clicked == 2
|
145
|
+
D3.log "User cancelled puppytime.", :warn
|
146
|
+
return true
|
147
|
+
end
|
148
|
+
|
149
|
+
D3::Client.connect
|
150
|
+
|
151
|
+
# start the slideshow
|
152
|
+
# this sets up @write_to_slideshow as our end of the pipe to
|
153
|
+
# update the text on the slideshow
|
154
|
+
show_puppies
|
155
|
+
|
156
|
+
# now loop through the puppy queue, installing
|
157
|
+
# each one with a call to d3 itself
|
158
|
+
D3::PUPPY_Q.queue.each do |pupname,pup|
|
159
|
+
|
160
|
+
# make sure the pkg exists
|
161
|
+
unless D3::Package.all_editions.include? pup.edition
|
162
|
+
D3::PUPPY_Q - pup
|
163
|
+
D3.log "Removed invalid puppy #{pup.edition} from the queue.", :info
|
164
|
+
next
|
165
|
+
end
|
166
|
+
|
167
|
+
write_to_slideshow "Installing: #{pup.edition}"
|
168
|
+
pup.install
|
169
|
+
|
170
|
+
end # D3::PUPPY_Q.queue.each
|
171
|
+
|
172
|
+
write_to_slideshow "All Done with installs!\nThis computer will reboot in a moment.\nThanks for playing!"
|
173
|
+
sleep @display_secs
|
174
|
+
|
175
|
+
# end the slideshow
|
176
|
+
stop_puppies
|
177
|
+
D3.log "Puppies have been walked, rebooting.", :warn
|
178
|
+
do_reboot
|
179
|
+
|
180
|
+
end # run
|
181
|
+
|
182
|
+
|
183
|
+
def show_version
|
184
|
+
puts <<-ENDVERS
|
185
|
+
D3 module version: #{D3::VERSION}
|
186
|
+
JSS module version: #{JSS::VERSION}
|
187
|
+
ENDVERS
|
188
|
+
end
|
189
|
+
|
190
|
+
### Update the slideshow with a new message
|
191
|
+
###
|
192
|
+
### @param message[String] the new message to display
|
193
|
+
###
|
194
|
+
### @return [void]
|
195
|
+
###
|
196
|
+
def write_to_slideshow (message)
|
197
|
+
@write_to_slideshow.puts message if @write_to_slideshow
|
198
|
+
end
|
199
|
+
|
200
|
+
### Start the puppy slideshow!
|
201
|
+
### This forks off a process to show the puppy pics while we
|
202
|
+
### do the installs. It just loops indefinitely through all
|
203
|
+
### the puppy pics.
|
204
|
+
### It returns the PID of the subprocess
|
205
|
+
### which we'll kill when we're done with the installs
|
206
|
+
###
|
207
|
+
### @return [Integer] the pid of the slideshow process
|
208
|
+
###
|
209
|
+
def show_puppies
|
210
|
+
|
211
|
+
# these pipe-ends will be duplicated in the forked child.
|
212
|
+
# we'll use the write_to_slideshow end to send the text of the latest
|
213
|
+
# thing we're installing.
|
214
|
+
#
|
215
|
+
# The forked child will use the read_from_main_process end to get that text from us
|
216
|
+
@read_from_main_process, @write_to_slideshow = IO.pipe
|
217
|
+
|
218
|
+
@slideshow_pid = Process.fork do
|
219
|
+
|
220
|
+
# the slideshow doesn't use this end of the pipe
|
221
|
+
@write_to_slideshow.close
|
222
|
+
|
223
|
+
# collect all the slideshow images and shuffle them into a random order
|
224
|
+
image_paths = @slideshow_folder_path.children.shuffle
|
225
|
+
|
226
|
+
# Start with this window description
|
227
|
+
description = "Preparing Installers."
|
228
|
+
|
229
|
+
while true do
|
230
|
+
image_paths.each do |slide_img|
|
231
|
+
|
232
|
+
caption = @show_captions ? slide_img.basename.to_s.chomp(slide_img.extname) : @dft_caption
|
233
|
+
|
234
|
+
# Read a new description, if one was sent, up to 3000 chars
|
235
|
+
begin
|
236
|
+
raw_read = @read_from_main_process.read_nonblock 3000
|
237
|
+
description = raw_read.lines.first.chomp
|
238
|
+
rescue
|
239
|
+
# this catches the error when read_from_main_process has nothing to give us
|
240
|
+
end
|
241
|
+
|
242
|
+
# Show this puppy
|
243
|
+
JSS::Client.jamf_helper( :hud,
|
244
|
+
:lock_hud => true,
|
245
|
+
:title => @title,
|
246
|
+
:heading => caption,
|
247
|
+
:align_heading => D3::PuppyTime::CAPTION_POSITION,
|
248
|
+
:description => description,
|
249
|
+
:align_description => D3::PuppyTime::TEXT_POSITION,
|
250
|
+
:icon => slide_img,
|
251
|
+
:icon_size => @image_size,
|
252
|
+
:timeout => @display_secs
|
253
|
+
)
|
254
|
+
end # each slide_img
|
255
|
+
end # while true
|
256
|
+
|
257
|
+
# the slideshow is done reading if we get here.
|
258
|
+
@read_from_main_process.close
|
259
|
+
|
260
|
+
end # fork
|
261
|
+
|
262
|
+
# the main process doesn't use this end of the pipe
|
263
|
+
@read_from_main_process.close
|
264
|
+
|
265
|
+
return @slideshow_pid
|
266
|
+
end #show_puppies
|
267
|
+
|
268
|
+
### Stop the puppy slideshow
|
269
|
+
###
|
270
|
+
### @return [void]
|
271
|
+
###
|
272
|
+
def stop_puppies
|
273
|
+
return if @puppies_stopped
|
274
|
+
@write_to_slideshow.close if @write_to_slideshow
|
275
|
+
Process.kill("TERM", @slideshow_pid) if @slideshow_pid
|
276
|
+
@slideshow_pid = nil
|
277
|
+
@puppies_stopped = true
|
278
|
+
end
|
279
|
+
|
280
|
+
### Reboot the machine
|
281
|
+
### If a reboot policy is defined and exists, use it
|
282
|
+
### and expect it to do the reboot.
|
283
|
+
### otherwise use 'shutdown -r now'
|
284
|
+
###
|
285
|
+
### @return [void]
|
286
|
+
###
|
287
|
+
def do_reboot
|
288
|
+
|
289
|
+
# get the policy name or id from the d3 config
|
290
|
+
policy = D3::CONFIG.puppy_reboot_policy
|
291
|
+
|
292
|
+
unless policy
|
293
|
+
D3.log "No puppy reboot policy in configuration, using 'shutdown -r now'", :debug
|
294
|
+
system "/sbin/shutdown -r now"
|
295
|
+
return
|
296
|
+
end
|
297
|
+
unless D3.run_policy policy, :puppy_reboot, :verbose
|
298
|
+
D3.log "Invalid reboot policy '#{policy_config}' in configuration, using 'shutdown -r now'.", :warn
|
299
|
+
system "/sbin/shutdown -r now"
|
300
|
+
end
|
301
|
+
end # do reboot
|
302
|
+
|
303
|
+
end # class App
|
304
|
+
|
305
|
+
############
|
306
|
+
begin
|
307
|
+
# exit asap if there are not puppies in the queue
|
308
|
+
exit 0 if D3::PUPPY_Q.pups.empty?
|
309
|
+
|
310
|
+
D3::LOG.progname = "puppytime"
|
311
|
+
D3::Client.set_env :puppytime
|
312
|
+
|
313
|
+
if app = App.new(ARGV)
|
314
|
+
app.run
|
315
|
+
# make sure we don't leave zombie puppies running around.
|
316
|
+
Process.wait if app.respond_to? :slideshow_pid and app.slideshow_pid
|
317
|
+
end
|
318
|
+
|
319
|
+
rescue
|
320
|
+
if defined?(app)
|
321
|
+
app.write_to_slideshow "*** AN ERROR OCCURED ***\nStopping puppies for now" if app.respond_to? :write_to_slideshow
|
322
|
+
app.stop_puppies if app.respond_to? :stop_puppies
|
323
|
+
end
|
324
|
+
# handle exceptions not handled elsewhere
|
325
|
+
D3.log "#{$!.class}: #{$!}", :fatal
|
326
|
+
D3.log_backtrace
|
327
|
+
puts $@
|
328
|
+
exit 12
|
329
|
+
ensure
|
330
|
+
if JSS::API.connected?
|
331
|
+
JSS::DistributionPoint.my_distribution_point.unmount if JSS::DistributionPoint.my_distribution_point.mounted?
|
332
|
+
D3::Client.disconnect
|
333
|
+
end # if
|
334
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
3
|
+
<!--
|
4
|
+
This should be installed as a top-level launch agent, in /Library/LaunchAgents.
|
5
|
+
It should have owner:group 'root:wheel' and permissions 0644
|
6
|
+
It will be launched automatically when each user logs in, and will record
|
7
|
+
timestamps for applications coming to the foreground into a plist in
|
8
|
+
/Library/Application Support/d3/Usage/
|
9
|
+
-->
|
10
|
+
<plist version="1.0">
|
11
|
+
<dict>
|
12
|
+
<key>Label</key>
|
13
|
+
<string>com.pixar.d3.RepoMan</string>
|
14
|
+
<key>ProgramArguments</key>
|
15
|
+
<array>
|
16
|
+
<string>/Library/Application Support/d3/d3RepoMan.app/Contents/MacOS/d3RepoMan</string>
|
17
|
+
</array>
|
18
|
+
<key>RunAtLoad</key>
|
19
|
+
<true/>
|
20
|
+
<key>KeepAlive</key>
|
21
|
+
<true/>
|
22
|
+
</dict>
|
23
|
+
</plist>
|