ruby-jss 1.0.2 → 1.0.3b1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of ruby-jss might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGES.md +11 -0
- data/bin/cgrouper +3 -3
- data/lib/jss/api_connection.rb +2 -1
- data/lib/jss/api_object/computer.rb +20 -12
- data/lib/jss/api_object/ldap_server.rb +249 -444
- data/lib/jss/api_object/package.rb +390 -342
- data/lib/jss/api_object/self_servable/icon.rb +5 -1
- data/lib/jss/client.rb +30 -1
- data/lib/jss/client/management_action.rb +1 -1
- data/lib/jss/composer.rb +1 -1
- data/lib/jss/version.rb +1 -1
- metadata +17 -17
@@ -1,95 +1,85 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
###
|
27
|
-
module JSS
|
28
|
-
|
29
|
-
### Module Constants
|
30
|
-
#####################################
|
31
|
-
|
32
|
-
### Module Variables
|
33
|
-
#####################################
|
1
|
+
# Copyright 2018 Pixar
|
2
|
+
|
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
|
+
#
|
34
25
|
|
35
|
-
|
36
|
-
#####################################
|
26
|
+
module JSS
|
37
27
|
|
38
|
-
|
28
|
+
# Classes
|
39
29
|
#####################################
|
40
30
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
31
|
+
# A Package in the JSS
|
32
|
+
#
|
33
|
+
# Also the API provides no access to the package's
|
34
|
+
# file list (index), so indexing must be done separately (usually via Casper Admin)
|
35
|
+
#
|
46
36
|
class Package < JSS::APIObject
|
47
37
|
|
48
|
-
|
38
|
+
# Mix-Ins
|
49
39
|
#####################################
|
50
40
|
|
51
41
|
include JSS::Categorizable
|
52
42
|
include JSS::Creatable
|
53
43
|
include JSS::Updatable
|
54
44
|
|
55
|
-
|
45
|
+
# Class Methods
|
56
46
|
#####################################
|
57
47
|
|
58
|
-
|
48
|
+
# Class Constants
|
59
49
|
#####################################
|
60
50
|
|
61
|
-
|
51
|
+
# The base for REST resources of this class
|
62
52
|
RSRC_BASE = 'packages'.freeze
|
63
53
|
|
64
|
-
|
54
|
+
# the hash key used for the JSON list output of all objects in the JSS
|
65
55
|
RSRC_LIST_KEY = :packages
|
66
56
|
|
67
|
-
|
68
|
-
|
57
|
+
# The hash key used for the JSON object output.
|
58
|
+
# It's also used in various error messages
|
69
59
|
RSRC_OBJECT_KEY = :package
|
70
60
|
|
71
|
-
|
72
|
-
VALID_DATA_KEYS = [
|
61
|
+
# these keys, as well as :id and :name, are present in valid API JSON data for this class
|
62
|
+
VALID_DATA_KEYS = %i[fill_existing_users fill_user_template reboot_required].freeze
|
73
63
|
|
74
|
-
|
64
|
+
# The pkg storage folder on the distribution point
|
75
65
|
DIST_POINT_PKGS_FOLDER = 'Packages'.freeze
|
76
66
|
|
77
|
-
|
78
|
-
CPU_TYPES = %w
|
67
|
+
# The possible values for cpu_type (required_processor) in a JSS package
|
68
|
+
CPU_TYPES = %w[None x86 ppc].freeze
|
79
69
|
|
80
|
-
|
70
|
+
# the possible priorities
|
81
71
|
PRIORITIES = (1..20)
|
82
72
|
|
83
|
-
|
73
|
+
# the default priority, since one is needed for making new pkgs
|
84
74
|
DEFAULT_PRIORITY = 10
|
85
75
|
|
86
|
-
|
76
|
+
# by default, no processor requirement
|
87
77
|
DEFAULT_PROCESSOR = 'None'.freeze
|
88
78
|
|
89
|
-
|
79
|
+
# When we shouldn't install anything (e.g. switch w/package)
|
90
80
|
DO_NOT_INSTALL = 'Do Not Install'.freeze
|
91
81
|
|
92
|
-
|
82
|
+
# The table in the database for this object
|
93
83
|
DB_TABLE = 'packages'.freeze
|
94
84
|
|
95
85
|
# the object type for this object in
|
@@ -103,67 +93,126 @@ module JSS
|
|
103
93
|
# How is the category stored in the API data?
|
104
94
|
CATEGORY_DATA_TYPE = String
|
105
95
|
|
106
|
-
|
107
|
-
### Class Variables
|
96
|
+
# Class Methods
|
108
97
|
#####################################
|
109
98
|
|
110
|
-
|
111
|
-
|
99
|
+
# An array of all dist-point filenames used by all JSS packages
|
100
|
+
#
|
101
|
+
# Slow cuz we have to instantiate every pkg
|
102
|
+
#
|
103
|
+
# @param api[JSS::APIConnection] an API connection to use
|
104
|
+
# Defaults to the corrently active API. See {JSS::APIConnection}
|
105
|
+
#
|
106
|
+
# @return [Array<String>] The current file names
|
107
|
+
#
|
108
|
+
def self.all_filenames(api: JSS.api)
|
109
|
+
pkgs_in_use = []
|
110
|
+
all_ids.each { |pkg_id| pkgs_in_use << fetch(id: pkg_id, api: api).filename }
|
111
|
+
pkgs_in_use.compact
|
112
|
+
end
|
113
|
+
|
114
|
+
# An array of String filenames for all files DIST_POINT_PKGS_FOLDER
|
115
|
+
# that aren't used by a JSS::Package
|
116
|
+
#
|
117
|
+
# Slow cuz we have to instantiate every pkg
|
118
|
+
#
|
119
|
+
# @param ro_pw[String] the password for the readonly account
|
120
|
+
# on the master Distribution Point,
|
121
|
+
#
|
122
|
+
# @param unmount[Boolean] whether or not ot unount the
|
123
|
+
# distribution point when finished.
|
124
|
+
#
|
125
|
+
# @param api[JSS::APIConnection] an API connection to use
|
126
|
+
# Defaults to the corrently active API. See {JSS::APIConnection}
|
127
|
+
#
|
128
|
+
# @return [Array<String>] The orphaned files
|
129
|
+
#
|
130
|
+
def self.orphaned_files(ro_pw, unmount = true, api: JSS.api)
|
131
|
+
mdp = JSS::DistributionPoint.master_distribution_point api: api
|
132
|
+
pkgs_dir = mdp.mount(ro_pw, :ro) + DIST_POINT_PKGS_FOLDER
|
133
|
+
files_on_mdp = pkgs_dir.children.map { |f| f.basename.to_s }
|
134
|
+
mdp.unmount if unmount
|
135
|
+
files_on_mdp - all_filenames(api: api)
|
136
|
+
end
|
112
137
|
|
113
|
-
|
138
|
+
# An array of String filenames for all filenames in any
|
139
|
+
# JSS::Package that don't exist on DIST_POINT_PKGS_FOLDER
|
140
|
+
#
|
141
|
+
# Slow cuz we have to instantiate every pkg
|
142
|
+
#
|
143
|
+
# @param ro_pw[String] the password for the readonly account
|
144
|
+
# on the master Distribution Point,
|
145
|
+
#
|
146
|
+
# @param unmount[Boolean] whether or not ot unount the
|
147
|
+
# distribution point when finished.
|
148
|
+
#
|
149
|
+
# @param api[JSS::APIConnection] an API connection to use
|
150
|
+
# Defaults to the corrently active API. See {JSS::APIConnection}
|
151
|
+
#
|
152
|
+
# @return [Array<String>] The orphaned files
|
153
|
+
#
|
154
|
+
def self.missing_files(ro_pw, unmount = true, api: JSS.api)
|
155
|
+
mdp = JSS::DistributionPoint.master_distribution_point api: api
|
156
|
+
pkgs_dir = mdp.mount(ro_pw, :ro) + DIST_POINT_PKGS_FOLDER
|
157
|
+
files_on_mdp = pkgs_dir.children.map { |f| f.basename.to_s }
|
158
|
+
mdp.unmount if unmount
|
159
|
+
all_filenames(api: api) - files_on_mdp
|
160
|
+
end
|
161
|
+
|
162
|
+
# Attributes
|
114
163
|
#####################################
|
115
164
|
|
116
|
-
|
165
|
+
# @return [String] the filename of the .pkg, .mpkg, or .dmg on the Casper server
|
117
166
|
attr_reader :filename
|
118
167
|
|
119
|
-
|
168
|
+
# @return [Pathname] the local receipt when this pkg is installed
|
120
169
|
attr_reader :receipt
|
121
170
|
|
122
|
-
|
171
|
+
# @return [Boolean] does this item 'Fill Existing Users' when jamf installs it?
|
123
172
|
attr_reader :fill_existing_users
|
124
173
|
|
125
|
-
|
174
|
+
# @return [Boolean] does this pkg also get install in the OS user homedir template
|
126
175
|
attr_reader :fill_user_template
|
127
176
|
|
128
|
-
|
177
|
+
# @return [Boolean] does this item require a reboot after installation?
|
129
178
|
attr_reader :reboot_required
|
130
179
|
|
131
|
-
|
180
|
+
# @return [Array<String>] the OS versions this can be installed onto. For all minor versions, the format is 10.5.x
|
132
181
|
attr_reader :os_requirements
|
133
182
|
|
134
|
-
|
183
|
+
# @return [String] limit installation to these architectures: 'x86', 'ppc', 'None'
|
135
184
|
attr_reader :required_processor
|
136
185
|
|
137
|
-
|
186
|
+
# @return [String] the name of a pkg to install (or "Do Not Install") when this pkg can't be installed
|
138
187
|
attr_reader :switch_with_package
|
139
188
|
|
140
|
-
|
189
|
+
# @return [Boolean] can this item be uninstalled? Some, e.g. OS Updates, can't
|
141
190
|
attr_reader :allow_uninstalled
|
142
191
|
|
143
|
-
|
192
|
+
# @return [String] the info field for this pkg - stores d3's basename & swupdate values
|
144
193
|
attr_reader :info
|
145
194
|
|
146
|
-
|
195
|
+
# @return [String] the notes field for this pkg
|
147
196
|
attr_reader :notes
|
148
197
|
|
149
|
-
|
198
|
+
# @return [Boolean] only install this pkg if it's available in the commandline softwareupdate.
|
150
199
|
attr_reader :install_if_reported_available
|
151
200
|
|
152
|
-
|
201
|
+
# @return [Boolean] should this pkg be installed on the boot volume during imaging
|
153
202
|
attr_reader :boot_volume_required
|
154
203
|
|
155
|
-
|
204
|
+
# @return [Integer] Priority to use for deploying or uninstalling the package
|
156
205
|
attr_reader :priority
|
157
206
|
|
158
|
-
|
207
|
+
# @return [Boolean] does this pkg cause a notification to be sent on self-heal?
|
159
208
|
attr_reader :send_notification
|
160
209
|
|
161
|
-
|
162
|
-
|
210
|
+
# @see JSS::APIObject#initialize
|
211
|
+
#
|
163
212
|
def initialize(args = {})
|
164
213
|
super
|
165
214
|
|
166
|
-
|
215
|
+
# now we have pkg_data with something in it, so fill out the instance vars
|
167
216
|
@allow_uninstalled = @init_data[:allow_uninstalled]
|
168
217
|
@boot_volume_required = @init_data[:boot_volume_required]
|
169
218
|
@filename = @init_data[:filename] || @init_data[:name]
|
@@ -186,21 +235,21 @@ module JSS
|
|
186
235
|
@receipt = @filename ? (JSS::Client::RECEIPTS_FOLDER + @filename.to_s.sub(/.zip$/, '')) : nil
|
187
236
|
end # init
|
188
237
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
238
|
+
# Change the 'allow to be uninstalled' field in the JSS
|
239
|
+
# NOTE The package must be indexed before this works. Right now, that means
|
240
|
+
# using CasperAdmin.app
|
241
|
+
#
|
242
|
+
# @param new_val[Boolean]
|
243
|
+
#
|
244
|
+
# @return [void]
|
245
|
+
#
|
197
246
|
def allow_uninstalled=(new_val)
|
198
247
|
return nil if new_val == @allow_uninstalled
|
199
248
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
249
|
+
# removable? defaults to false
|
250
|
+
# even though we usually want to be able to ununstall things, it would be
|
251
|
+
# dangerous to do on things like OS updates, so it must be turned on explicitly.
|
252
|
+
# packages must be indexed with Casper Admin in order to be uninstalled.
|
204
253
|
new_val = false if new_val.to_s.empty?
|
205
254
|
raise JSS::InvalidDataError, "allow_uninstalled must be boolean 'true' or 'false'" unless JSS::TRUE_FALSE.include? new_val
|
206
255
|
|
@@ -208,12 +257,12 @@ module JSS
|
|
208
257
|
@need_to_update = true
|
209
258
|
end
|
210
259
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
260
|
+
# Change the boot volume required field in the JSS
|
261
|
+
#
|
262
|
+
# @param new_val[Boolean]
|
263
|
+
#
|
264
|
+
# @return [void]
|
265
|
+
#
|
217
266
|
def boot_volume_required=(new_val)
|
218
267
|
return nil if new_val == @boot_volume_required
|
219
268
|
new_val = false if new_val.to_s.empty?
|
@@ -222,28 +271,28 @@ module JSS
|
|
222
271
|
@need_to_update = true
|
223
272
|
end
|
224
273
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
274
|
+
# Change the package filename.
|
275
|
+
# Setting it to nil or empty will make it match the display name
|
276
|
+
#
|
277
|
+
# @param new_val[String]
|
278
|
+
#
|
279
|
+
# @return [void]
|
280
|
+
#
|
232
281
|
def filename=(new_val)
|
233
282
|
new_val = nil if new_val == ''
|
234
283
|
new_val ||= @name
|
235
284
|
return nil if new_val == @filename
|
236
|
-
|
285
|
+
warn 'WARNING: you must change the filename on the master Distribution Point. See JSS::Package.update_master_filename.' if @in_jss
|
237
286
|
@filename = new_val
|
238
287
|
@need_to_update = true
|
239
288
|
end
|
240
289
|
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
290
|
+
# Change the Fill Existing Users value
|
291
|
+
#
|
292
|
+
# @param new_val[Boolean]
|
293
|
+
#
|
294
|
+
# @return [void]
|
295
|
+
#
|
247
296
|
def fill_existing_users=(new_val)
|
248
297
|
return nil if new_val == @fill_existing_users
|
249
298
|
new_val = false if new_val.to_s.empty?
|
@@ -252,12 +301,12 @@ module JSS
|
|
252
301
|
@need_to_update = true
|
253
302
|
end
|
254
303
|
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
304
|
+
# Change the fill_user_template value
|
305
|
+
#
|
306
|
+
# @param new_val[Boolean]
|
307
|
+
#
|
308
|
+
# @return [void]
|
309
|
+
#
|
261
310
|
def fill_user_template=(new_val)
|
262
311
|
return nil if new_val == @fill_user_template
|
263
312
|
new_val = false if new_val.to_s.empty?
|
@@ -266,26 +315,26 @@ module JSS
|
|
266
315
|
@need_to_update = true
|
267
316
|
end
|
268
317
|
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
318
|
+
# Change the info field in the JSS.
|
319
|
+
#
|
320
|
+
# @param new_val[String]
|
321
|
+
#
|
322
|
+
# @return [void]
|
323
|
+
#
|
275
324
|
def info=(new_val)
|
276
325
|
return nil if new_val == @info
|
277
|
-
|
326
|
+
# line breaks should be \r
|
278
327
|
new_val = new_val.to_s.tr("\n", "\r")
|
279
328
|
@info = new_val
|
280
329
|
@need_to_update = true
|
281
330
|
end
|
282
331
|
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
332
|
+
# Change the if_in_swupdate field in the JSS
|
333
|
+
#
|
334
|
+
# @param new_val[Boolean]
|
335
|
+
#
|
336
|
+
# @return [void]
|
337
|
+
#
|
289
338
|
def install_if_reported_available=(new_val)
|
290
339
|
return nil if new_val == @install_if_reported_available
|
291
340
|
new_val = false if new_val.to_s.empty?
|
@@ -294,37 +343,37 @@ module JSS
|
|
294
343
|
@need_to_update = true
|
295
344
|
end
|
296
345
|
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
346
|
+
# Change the notes field in the JSS.NewLines are converted \r.
|
347
|
+
#
|
348
|
+
# @param new_val[String]
|
349
|
+
#
|
350
|
+
# @return [void]
|
351
|
+
#
|
303
352
|
def notes=(new_val)
|
304
353
|
return nil if new_val == @notes
|
305
|
-
|
354
|
+
# line breaks should be \r
|
306
355
|
new_val = new_val.to_s.tr("\n", "\r")
|
307
356
|
@notes = new_val
|
308
357
|
@need_to_update = true
|
309
358
|
end
|
310
359
|
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
360
|
+
# Change the os_requirements field in the JSS
|
361
|
+
# E.g. 10.5, 10.5.3, 10.6.x
|
362
|
+
#
|
363
|
+
# @param new_val[String,Array] comma-separated string, or array of os versions
|
364
|
+
#
|
365
|
+
# @return [void]
|
366
|
+
#
|
367
|
+
# Extra feature: Minumum OS's can now be specified as a
|
368
|
+
# string using the notation ">=10.6.7".
|
369
|
+
#
|
370
|
+
# @see JSS.expand_min_os
|
371
|
+
#
|
323
372
|
def os_requirements=(new_val)
|
324
|
-
|
373
|
+
# nil should be an empty array
|
325
374
|
new_val = [] if new_val.to_s.empty?
|
326
375
|
|
327
|
-
|
376
|
+
# if any value starts with >=, expand it
|
328
377
|
case new_val
|
329
378
|
when String
|
330
379
|
new_val = JSS.expand_min_os(new_val) if new_val =~ /^>=/
|
@@ -335,30 +384,30 @@ module JSS
|
|
335
384
|
else
|
336
385
|
raise JSS::InvalidDataError, 'os_requirements must be a String or an Array of strings'
|
337
386
|
end
|
338
|
-
|
387
|
+
# get the array version
|
339
388
|
@os_requirements = JSS.to_s_and_a(new_val)[:arrayform]
|
340
389
|
@need_to_update = true
|
341
390
|
end
|
342
391
|
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
392
|
+
# Is a given OS OK for this package based on its
|
393
|
+
# @os_requirements?
|
394
|
+
#
|
395
|
+
# @param os[String] the os to check, defaults to
|
396
|
+
# the os of the current machine.
|
397
|
+
#
|
398
|
+
# @return [Boolean] can this pkg be installed with the os
|
399
|
+
# given?
|
400
|
+
#
|
352
401
|
def os_ok?(os = nil)
|
353
402
|
JSS.os_ok? @os_requirements, os
|
354
403
|
end
|
355
404
|
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
405
|
+
# Change the priority field in the JSS
|
406
|
+
#
|
407
|
+
# @param new_val[Integer] one of PRIORITIES
|
408
|
+
#
|
409
|
+
# @return [void]
|
410
|
+
#
|
362
411
|
def priority=(new_val)
|
363
412
|
return nil if new_val == @priority
|
364
413
|
new_val = DEFAULT_PRIORITY if new_val.to_s.empty?
|
@@ -367,12 +416,12 @@ module JSS
|
|
367
416
|
@need_to_update = true
|
368
417
|
end
|
369
418
|
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
419
|
+
# Change the reboot-required field in the JSS
|
420
|
+
#
|
421
|
+
# @param new_val[Boolean]
|
422
|
+
#
|
423
|
+
# @return [void]
|
424
|
+
#
|
376
425
|
def reboot_required=(new_val)
|
377
426
|
return nil if new_val == @reboot_required
|
378
427
|
new_val = false if new_val.to_s.empty?
|
@@ -381,12 +430,12 @@ module JSS
|
|
381
430
|
@need_to_update = true
|
382
431
|
end
|
383
432
|
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
433
|
+
# Change the required processor field in the JSS
|
434
|
+
#
|
435
|
+
# @param new_val[String] one of {CPU_TYPES}
|
436
|
+
#
|
437
|
+
# @return [void]
|
438
|
+
#
|
390
439
|
def required_processor=(new_val)
|
391
440
|
return nil if new_val == @required_processor
|
392
441
|
|
@@ -397,25 +446,25 @@ module JSS
|
|
397
446
|
@need_to_update = true
|
398
447
|
end
|
399
448
|
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
449
|
+
# Is a given processor OK for this package based on its
|
450
|
+
# @required_processor?
|
451
|
+
#
|
452
|
+
# @param processor[String] the processor to check, defaults to
|
453
|
+
# the processor of the current machine.
|
454
|
+
#
|
455
|
+
# @return [Boolean] can this pkg be installed with the processor
|
456
|
+
# given?
|
457
|
+
#
|
409
458
|
def processor_ok?(processor = nil)
|
410
459
|
JSS.processor_ok? @required_processor, processor
|
411
460
|
end
|
412
461
|
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
462
|
+
# Change the notify field in the JSS
|
463
|
+
#
|
464
|
+
# @param new_val[Boolean]
|
465
|
+
#
|
466
|
+
# @return [void]
|
467
|
+
#
|
419
468
|
def send_notification=(new_val)
|
420
469
|
return nil if new_val == @send_notification
|
421
470
|
new_val = false if new_val.to_s.empty?
|
@@ -424,12 +473,12 @@ module JSS
|
|
424
473
|
@need_to_update = true
|
425
474
|
end
|
426
475
|
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
476
|
+
# Change which pkg should be installed if this one can't.
|
477
|
+
#
|
478
|
+
# @param new_val[String] the name of an existing package or "Do Not Install"
|
479
|
+
#
|
480
|
+
# @return [void]
|
481
|
+
#
|
433
482
|
def switch_with_package=(new_val)
|
434
483
|
return nil if new_val == @switch_with_package
|
435
484
|
new_val = nil if new_val.to_s.empty?
|
@@ -441,34 +490,34 @@ module JSS
|
|
441
490
|
@need_to_update = true
|
442
491
|
end
|
443
492
|
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
493
|
+
# Is this packaged installed on the current machine (via casper)?
|
494
|
+
# We just look for the receipt, which is the @filename less any possible .zip extension.
|
495
|
+
#
|
496
|
+
# @return [Boolean]
|
497
|
+
#
|
449
498
|
def installed?
|
450
499
|
@receipt.file?
|
451
500
|
end
|
452
501
|
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
502
|
+
# Upload a locally-readable file to the master distribution point.
|
503
|
+
# If the file is a directory (like a bundle .pk/.mpkg) it will be zipped before
|
504
|
+
# uploading and the @filename will be adjusted accordingly by adding a .zip extension
|
505
|
+
#
|
506
|
+
# The name of the local file doesn't matter, the file on the dist. point will
|
507
|
+
# use the @filename (possibly with .zip)
|
508
|
+
#
|
509
|
+
# If you'll be uploading several files you can specify unmount as false, and do it manually when all
|
510
|
+
# are finished with JSS::DistributionPoint.master_distribution_point.unmount
|
511
|
+
#
|
512
|
+
# @param local_file_path[String,Pathname] the local path to the file to be uploaded
|
513
|
+
#
|
514
|
+
# @param rw_pw[String,Symbol] the password for the read/write account on the master Distribution Point,
|
515
|
+
# or :prompt, or :stdin# where # is the line of stdin containing the password See {JSS::DistributionPoint#mount}
|
516
|
+
#
|
517
|
+
# @param unmount[Boolean] whether or not ot unount the distribution point when finished.
|
518
|
+
#
|
519
|
+
# @return [void]
|
520
|
+
#
|
472
521
|
def upload_master_file(local_file_path, rw_pw, unmount = true)
|
473
522
|
raise JSS::NoSuchItemError, 'Please create this package in the JSS before uploading it.' unless @in_jss
|
474
523
|
|
@@ -478,15 +527,15 @@ module JSS
|
|
478
527
|
local_path = Pathname.new local_file_path
|
479
528
|
raise JSS::NoSuchItemError, "Local file '#{@local_file}' doesn't exist" unless local_path.exist?
|
480
529
|
|
481
|
-
|
530
|
+
# should we zip it?
|
482
531
|
if local_path.directory?
|
483
532
|
begin
|
484
|
-
|
533
|
+
# go to the same dir as the local file
|
485
534
|
wd = Dir.pwd
|
486
535
|
Dir.chdir local_path.parent
|
487
536
|
|
488
|
-
|
489
|
-
|
537
|
+
# the contents of the zip file have to have the same name as the zip file itself (minus the .zip)
|
538
|
+
# so temporarily rename the source
|
490
539
|
local_path_to_upload = local_path.parent + @filename
|
491
540
|
local_path.rename local_path_to_upload unless local_path_to_upload == local_path
|
492
541
|
|
@@ -496,15 +545,14 @@ module JSS
|
|
496
545
|
zipfile = zipdir + (local_path_to_upload.basename.to_s + '.zip')
|
497
546
|
|
498
547
|
raise 'There was a problem zipping the pkg bundle' unless system "/usr/bin/zip -qr '#{zipfile}' '#{local_path_to_upload}'"
|
499
|
-
|
500
548
|
ensure
|
501
|
-
|
549
|
+
# rename the source to the original name
|
502
550
|
local_path_to_upload.rename local_path if local_path_to_upload.exist? && local_path_to_upload != local_path
|
503
|
-
|
551
|
+
# go back where we started
|
504
552
|
Dir.chdir wd
|
505
553
|
end # begin
|
506
554
|
|
507
|
-
|
555
|
+
# update our info
|
508
556
|
local_path = zipfile
|
509
557
|
destination = destination.to_s + '.zip'
|
510
558
|
@filename = zipfile.basename.to_s
|
@@ -517,19 +565,19 @@ module JSS
|
|
517
565
|
mdp.unmount if unmount
|
518
566
|
end # upload
|
519
567
|
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
568
|
+
# Change the name of a package file on the master distribution point.
|
569
|
+
#
|
570
|
+
# @param new_file_name[String]
|
571
|
+
#
|
572
|
+
# @param old_file_name[default: @filename, String]
|
573
|
+
#
|
574
|
+
# @param unmount[Boolean] whether or not ot unount the distribution point when finished.
|
575
|
+
#
|
576
|
+
# @param rw_pw[String,Symbol] the password for the read/write account on the master Distribution Point,
|
577
|
+
# or :prompt, or :stdin# where # is the line of stdin containing the password See {JSS::DistributionPoint#mount}
|
578
|
+
#
|
579
|
+
# @return [nil]
|
580
|
+
#
|
533
581
|
def update_master_filename(old_file_name, new_file_name, rw_pw, unmount = true)
|
534
582
|
raise JSS::NoSuchItemError, "#{old_file_name} does not exist in the jss." unless @in_jss
|
535
583
|
mdp = JSS::DistributionPoint.master_distribution_point api: @api
|
@@ -539,7 +587,7 @@ module JSS
|
|
539
587
|
old_file.exist?
|
540
588
|
|
541
589
|
new_file = pkgs_dir + new_file_name
|
542
|
-
|
590
|
+
# use the extension of the original file.
|
543
591
|
new_file = pkgs_dir + (new_file_name + old_file.extname) if new_file.extname.empty?
|
544
592
|
|
545
593
|
old_file.rename new_file
|
@@ -547,18 +595,18 @@ module JSS
|
|
547
595
|
nil
|
548
596
|
end # update_master_filename
|
549
597
|
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
598
|
+
# Delete the filename from the master distribution point, if it exists.
|
599
|
+
#
|
600
|
+
# If you'll be uploading several files you can specify unmount as false, and do it manually when all
|
601
|
+
# are finished.
|
602
|
+
#
|
603
|
+
# @param rw_pw[String] the password for the read/write account on the master Distribution Point
|
604
|
+
# or :prompt, or :stdin# where # is the line of stdin containing the password. See {JSS::DistributionPoint#mount}
|
605
|
+
#
|
606
|
+
# @param unmount[Boolean] whether or not ot unount the distribution point when finished.
|
607
|
+
#
|
608
|
+
# @return [Boolean] was the file deleted?
|
609
|
+
#
|
562
610
|
def delete_master_file(rw_pw, unmount = true)
|
563
611
|
mdp = JSS::DistributionPoint.master_distribution_point api: @api
|
564
612
|
file = mdp.mount(rw_pw, :rw) + "#{DIST_POINT_PKGS_FOLDER}/#{@filename}"
|
@@ -572,61 +620,61 @@ module JSS
|
|
572
620
|
did_it
|
573
621
|
end # delete master file
|
574
622
|
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
623
|
+
# Delete this package from the JSS, optionally
|
624
|
+
# deleting the master dist point file also.
|
625
|
+
#
|
626
|
+
# @param delete_file[Boolean] should the master dist point file be deleted?
|
627
|
+
#
|
628
|
+
# @param rw_pw[String] the password for the read/write account on the master Distribution Point
|
629
|
+
# or :prompt, or :stdin# where # is the line of stdin containing the password. See {JSS::DistributionPoint#mount}
|
630
|
+
#
|
631
|
+
# @param unmount[Boolean] whether or not ot unount the distribution point when finished.
|
632
|
+
#
|
585
633
|
def delete(delete_file: false, rw_pw: nil, unmount: true)
|
586
634
|
super()
|
587
635
|
delete_master_file(rw_pw, unmount) if delete_file
|
588
636
|
end
|
589
637
|
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
638
|
+
# Install this package via the jamf binary 'install' command from the
|
639
|
+
# distribution point for this machine.
|
640
|
+
# See {JSS::DistributionPoint.my_distribution_point}
|
641
|
+
#
|
642
|
+
# @note This code must be run as root to install packages
|
643
|
+
#
|
644
|
+
# The read-only or http passwd for the dist. point must be provided,
|
645
|
+
# except for non-authenticated http downloads)
|
646
|
+
#
|
647
|
+
# @param args[Hash] the arguments for installation
|
648
|
+
#
|
649
|
+
# @option args :ro_pw[String] the read-only or http password for the
|
650
|
+
# distribution point for the local machine
|
651
|
+
# (http will be used if available, and may not need a pw)
|
652
|
+
#
|
653
|
+
# @option args :target[String,Pathname] The drive on which to install
|
654
|
+
# the package, defaults to '/'
|
655
|
+
#
|
656
|
+
# @option args :verbose [Boolean] be verbose to stdout, defaults to false
|
657
|
+
#
|
658
|
+
# @option args :feu[Boolean] fill existing users, defaults to false
|
659
|
+
#
|
660
|
+
# @option args :fut[Boolean] fill user template, defaults to false
|
661
|
+
#
|
662
|
+
# @option args :unmount[Boolean] unmount the distribution point when
|
663
|
+
# finished?(if we mounted it), defaults to false
|
664
|
+
#
|
665
|
+
# @option args :no_http[Boolean] don't use http downloads even if they
|
666
|
+
# are enabled for the dist. point.
|
667
|
+
#
|
668
|
+
# @option args :alt_download_url [String] Use this url for an http
|
669
|
+
# download, regardless of distribution point settings. This can be used
|
670
|
+
# to access Cloud Distribution Points if the fileshare isn't available.
|
671
|
+
# The URL should already be ur
|
672
|
+
# The package filename will be removed or appended as needed.
|
673
|
+
#
|
674
|
+
# @return [Boolean] did the jamf install succeed?
|
675
|
+
#
|
676
|
+
# @todo deal with cert-based https authentication in dist points
|
677
|
+
#
|
630
678
|
def install(args = {})
|
631
679
|
raise JSS::UnsupportedError, 'You must have root privileges to install packages' unless JSS.superuser?
|
632
680
|
|
@@ -656,7 +704,7 @@ module JSS
|
|
656
704
|
else
|
657
705
|
mdp = JSS::DistributionPoint.my_distribution_point api: @api
|
658
706
|
|
659
|
-
|
707
|
+
# how do we access our dist. point? with http?
|
660
708
|
if mdp.http_downloads_enabled && !(args[:no_http])
|
661
709
|
using_http = true
|
662
710
|
src_path = mdp.http_url
|
@@ -682,14 +730,14 @@ module JSS
|
|
682
730
|
src_path += @filename.to_s unless no_filename_in_url
|
683
731
|
end
|
684
732
|
|
685
|
-
|
733
|
+
# are we doing "fill existing users" or "fill user template"?
|
686
734
|
do_feu = args[:feu] ? '-feu' : ''
|
687
735
|
do_fut = args[:fut] ? '-fut' : ''
|
688
736
|
|
689
|
-
|
737
|
+
# the install args for jamf
|
690
738
|
command_args = "-package '#{@filename}' -path '#{src_path}' -target '#{args[:target]}' #{do_feu} #{do_fut} -showProgress -verbose"
|
691
739
|
|
692
|
-
|
740
|
+
# run it via a client cmd
|
693
741
|
install_out = JSS::Client.run_jamf :install, command_args, args[:verbose]
|
694
742
|
|
695
743
|
install_out =~ %r{<exitCode>(\d+)</exitCode>}
|
@@ -703,22 +751,22 @@ module JSS
|
|
703
751
|
install_exit.zero? ? true : false
|
704
752
|
end
|
705
753
|
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
754
|
+
# Uninstall this pkg via the jamf command.
|
755
|
+
#
|
756
|
+
# @param args[Hash] the arguments for installation
|
757
|
+
#
|
758
|
+
# @option args :target[String,Pathname] The drive from which to uninstall the package, defaults to '/'
|
759
|
+
#
|
760
|
+
# @option args :verbose[Boolean] be verbose to stdout, defaults to false
|
761
|
+
#
|
762
|
+
# @option args :feu[Boolean] fill existing users, defaults to false
|
763
|
+
#
|
764
|
+
# @option args :fut[Boolean] fill user template, defaults to false
|
765
|
+
#
|
766
|
+
# @return [Process::Status] the result of the 'jamf uninstall' command
|
767
|
+
#
|
768
|
+
# @note This code must be run as root to uninstall packages
|
769
|
+
#
|
722
770
|
def uninstall(args = {})
|
723
771
|
unless removable?
|
724
772
|
raise JSS::UnsupportedError, \
|
@@ -727,23 +775,23 @@ module JSS
|
|
727
775
|
raise JSS::UnsupportedError, 'You must have root privileges to uninstall packages' unless JSS.superuser?
|
728
776
|
args[:target] ||= '/'
|
729
777
|
|
730
|
-
|
778
|
+
# are we doing "fill existing users" or "fill user template"?
|
731
779
|
do_feu = args[:feu] ? '-feu' : ''
|
732
780
|
do_fut = args[:fut] ? '-fut' : ''
|
733
781
|
|
734
|
-
|
782
|
+
# use jamf binary to uninstall the pkg
|
735
783
|
jamf_opts = "-target '#{args[:target]}' -id '#{@id}' #{do_feu} #{do_fut}"
|
736
784
|
|
737
|
-
|
785
|
+
# run it via a client
|
738
786
|
JSS::Client.run_jamf 'uninstall', jamf_opts, args[:verbose]
|
739
787
|
|
740
788
|
$CHILD_STATUS
|
741
789
|
end
|
742
790
|
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
791
|
+
# What type of package is this?
|
792
|
+
#
|
793
|
+
# @return [Symbol] :pkg or :dmg or:unknown
|
794
|
+
#
|
747
795
|
def type
|
748
796
|
case @filename
|
749
797
|
when /\.m?pkg(\.zip)?$/ then :pkg
|
@@ -752,7 +800,7 @@ module JSS
|
|
752
800
|
end
|
753
801
|
end
|
754
802
|
|
755
|
-
|
803
|
+
# Aliases
|
756
804
|
################################
|
757
805
|
|
758
806
|
# aliases under their methods seem to confuse the YARD documenter, so I'm putting them all here.
|
@@ -782,14 +830,14 @@ module JSS
|
|
782
830
|
alias cpu_type= required_processor=
|
783
831
|
alias notify= send_notification=
|
784
832
|
|
785
|
-
|
833
|
+
# Private Instance Methods
|
786
834
|
################################
|
787
835
|
|
788
836
|
private
|
789
837
|
|
790
|
-
|
791
|
-
|
792
|
-
|
838
|
+
# Return the REST XML for this pkg, with the current values,
|
839
|
+
# for saving or updating
|
840
|
+
#
|
793
841
|
def rest_xml
|
794
842
|
doc = REXML::Document.new APIConnection::XML_HEADER
|
795
843
|
pkg = doc.add_element 'package'
|