ruby-jss 1.0.2 → 1.0.3b1
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.
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'
|