jss-api 0.5.8 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.md +55 -7
- data/README.md +2 -1
- data/bin/cgrouper +1 -1
- data/bin/subnet-update +1 -1
- data/lib/jss-api.rb +2 -363
- data/lib/jss-api/api_connection.rb +78 -15
- data/lib/jss-api/api_object.rb +1 -1
- data/lib/jss-api/api_object/advanced_search.rb +1 -1
- data/lib/jss-api/api_object/advanced_search/advanced_computer_search.rb +1 -1
- data/lib/jss-api/api_object/advanced_search/advanced_mobile_device_search.rb +1 -1
- data/lib/jss-api/api_object/advanced_search/advanced_user_search.rb +1 -1
- data/lib/jss-api/api_object/building.rb +1 -1
- data/lib/jss-api/api_object/category.rb +1 -1
- data/lib/jss-api/api_object/computer.rb +1 -1
- data/lib/jss-api/api_object/creatable.rb +1 -1
- data/lib/jss-api/api_object/criteriable.rb +1 -1
- data/lib/jss-api/api_object/criteriable/criteria.rb +1 -1
- data/lib/jss-api/api_object/criteriable/criterion.rb +1 -1
- data/lib/jss-api/api_object/department.rb +1 -1
- data/lib/jss-api/api_object/distribution_point.rb +92 -22
- data/lib/jss-api/api_object/extendable.rb +1 -1
- data/lib/jss-api/api_object/extension_attribute.rb +1 -1
- data/lib/jss-api/api_object/extension_attribute/computer_extension_attribute.rb +1 -1
- data/lib/jss-api/api_object/extension_attribute/mobile_device_extension_attribute.rb +1 -1
- data/lib/jss-api/api_object/extension_attribute/user_extension_attribute.rb +1 -1
- data/lib/jss-api/api_object/group.rb +1 -1
- data/lib/jss-api/api_object/group/computer_group.rb +1 -1
- data/lib/jss-api/api_object/group/mobile_device_group.rb +1 -1
- data/lib/jss-api/api_object/group/user_group.rb +1 -1
- data/lib/jss-api/api_object/ldap_server.rb +1 -1
- data/lib/jss-api/api_object/locatable.rb +1 -1
- data/lib/jss-api/api_object/matchable.rb +1 -1
- data/lib/jss-api/api_object/mobile_device.rb +1 -1
- data/lib/jss-api/api_object/netboot_server.rb +1 -1
- data/lib/jss-api/api_object/network_segment.rb +1 -1
- data/lib/jss-api/api_object/osx_configuration_profile.rb +1 -1
- data/lib/jss-api/api_object/package.rb +117 -64
- data/lib/jss-api/api_object/peripheral.rb +1 -1
- data/lib/jss-api/api_object/peripheral_type.rb +1 -1
- data/lib/jss-api/api_object/policy.rb +1 -1
- data/lib/jss-api/api_object/purchasable.rb +1 -1
- data/lib/jss-api/api_object/removable_macaddr.rb +1 -1
- data/lib/jss-api/api_object/scopable.rb +1 -1
- data/lib/jss-api/api_object/scopable/scope.rb +1 -1
- data/lib/jss-api/api_object/script.rb +1 -1
- data/lib/jss-api/api_object/self_servable.rb +1 -1
- data/lib/jss-api/api_object/site.rb +1 -1
- data/lib/jss-api/api_object/software_update_server.rb +1 -1
- data/lib/jss-api/api_object/updatable.rb +1 -1
- data/lib/jss-api/api_object/uploadable.rb +1 -1
- data/lib/jss-api/api_object/user.rb +1 -1
- data/lib/jss-api/client.rb +22 -21
- data/lib/jss-api/compatibility.rb +1 -1
- data/lib/jss-api/composer.rb +2 -2
- data/lib/jss-api/configuration.rb +1 -1
- data/lib/jss-api/db_connection.rb +63 -12
- data/lib/jss-api/exceptions.rb +1 -1
- data/lib/jss-api/ruby_extensions.rb +1 -1
- data/lib/jss-api/ruby_extensions/filetest.rb +1 -1
- data/lib/jss-api/ruby_extensions/hash.rb +1 -1
- data/lib/jss-api/ruby_extensions/ipaddr.rb +1 -1
- data/lib/jss-api/ruby_extensions/pathname.rb +1 -1
- data/lib/jss-api/ruby_extensions/string.rb +17 -1
- data/lib/jss-api/ruby_extensions/time.rb +1 -1
- data/lib/jss-api/server.rb +1 -1
- data/lib/jss-api/utility.rb +416 -0
- data/lib/jss-api/version.rb +8 -8
- metadata +3 -2
@@ -1,4 +1,4 @@
|
|
1
|
-
### Copyright
|
1
|
+
### Copyright 2016 Pixar
|
2
2
|
###
|
3
3
|
### Licensed under the Apache License, Version 2.0 (the "Apache License")
|
4
4
|
### with the following modification; you may not use this file except in
|
@@ -63,8 +63,16 @@ module JSS
|
|
63
63
|
#####################################
|
64
64
|
|
65
65
|
### The base API path in the jss URL
|
66
|
-
|
67
|
-
|
66
|
+
RSRC_BASE = "JSSResource"
|
67
|
+
|
68
|
+
### A url path to load to see if there's an API available at a host.
|
69
|
+
### This just loads the API resource docs page
|
70
|
+
TEST_PATH = "api"
|
71
|
+
|
72
|
+
### If the test path loads correctly from a casper server, it'll contain
|
73
|
+
### this text
|
74
|
+
TEST_CONTENT = "<title>JSS REST API Resource Documentation</title>"
|
75
|
+
|
68
76
|
### The Default port
|
69
77
|
HTTP_PORT = 9006
|
70
78
|
|
@@ -97,6 +105,9 @@ module JSS
|
|
97
105
|
### @return [JSS::Server] the details of the JSS to which we're connected.
|
98
106
|
attr_reader :server
|
99
107
|
|
108
|
+
### @return [String] the hostname of the JSS to which we're connected.
|
109
|
+
attr_reader :server_host
|
110
|
+
|
100
111
|
#####################################
|
101
112
|
### Constructor
|
102
113
|
#####################################
|
@@ -122,6 +133,8 @@ module JSS
|
|
122
133
|
###
|
123
134
|
### @option args :port[Integer] the port number to connect with, defaults to 8443
|
124
135
|
###
|
136
|
+
### @option args :use_ssl[Boolean] should the connection be made over SSL? Defaults to true.
|
137
|
+
###
|
125
138
|
### @option args :verify_cert[Boolean] should HTTPS SSL certificates be verified. Defaults to true.
|
126
139
|
### If your connection raises RestClient::SSLCertificateNotVerified, and you don't care about the
|
127
140
|
### validity of the SSL cert. just set this explicitly to false.
|
@@ -141,7 +154,11 @@ module JSS
|
|
141
154
|
### @return [true]
|
142
155
|
###
|
143
156
|
def connect (args = {})
|
144
|
-
|
157
|
+
|
158
|
+
# the server, if not specified, might come from a couple places.
|
159
|
+
# see #hostname
|
160
|
+
args[:server] ||= hostname
|
161
|
+
|
145
162
|
# settings from config if they aren't in the args
|
146
163
|
args[:server] ||= JSS::CONFIG.api_server_name
|
147
164
|
args[:port] ||= JSS::CONFIG.api_server_port
|
@@ -155,7 +172,10 @@ module JSS
|
|
155
172
|
# set it from the prefs
|
156
173
|
args[:verify_cert] = JSS::CONFIG.api_verify_cert
|
157
174
|
end
|
158
|
-
|
175
|
+
|
176
|
+
# settings from client jamf plist if needed
|
177
|
+
args[:port] ||= JSS::Client.jss_port
|
178
|
+
|
159
179
|
# default settings if needed
|
160
180
|
args[:port] ||= SSL_PORT
|
161
181
|
args[:timeout] ||= DFT_TIMEOUT
|
@@ -173,13 +193,18 @@ module JSS
|
|
173
193
|
raise JSS::MissingDataError, "No JSS :user specified, or in configuration." unless args[:user]
|
174
194
|
raise JSS::MissingDataError, "Missing :pw for user '#{args[:user]}'" unless args[:pw]
|
175
195
|
|
176
|
-
# ssl
|
177
|
-
|
178
|
-
|
196
|
+
# we're using ssl if 1) args[:use_ssl] is anything but false
|
197
|
+
# or 2) the port is the default casper ssl port.
|
198
|
+
args[:use_ssl] = (not args[:use_ssl] == false) or (args[:port] == SSL_PORT)
|
199
|
+
|
200
|
+
# and here's the URL
|
201
|
+
ssl = args[:use_ssl] ? "s" : ''
|
202
|
+
@rest_url = URI::encode "http#{ssl}://#{args[:server]}:#{args[:port]}/#{RSRC_BASE}"
|
203
|
+
|
179
204
|
|
180
205
|
# prep the args for passing to RestClient::Resource
|
181
|
-
# if verify_cert is
|
182
|
-
args[:verify_ssl] = (args[:verify_cert]
|
206
|
+
# if verify_cert is anything but false, we will verify
|
207
|
+
args[:verify_ssl] = (args[:verify_cert] == false) ? OpenSSL::SSL::VERIFY_NONE : OpenSSL::SSL::VERIFY_PEER
|
183
208
|
|
184
209
|
args[:password] = if args[:pw] == :prompt
|
185
210
|
JSS.prompt_for_password "Enter the password for JSS user #{args[:user]}@#{args[:server]}:"
|
@@ -192,12 +217,11 @@ module JSS
|
|
192
217
|
args[:pw]
|
193
218
|
end
|
194
219
|
|
195
|
-
|
196
|
-
|
197
220
|
# heres our connection
|
198
221
|
@cnx = RestClient::Resource.new("#{@rest_url}", args)
|
199
222
|
|
200
223
|
@jss_user = args[:user]
|
224
|
+
@server_host = args[:server]
|
201
225
|
@connected = true
|
202
226
|
@server = JSS::Server.new
|
203
227
|
|
@@ -205,7 +229,7 @@ module JSS
|
|
205
229
|
raise JSS::UnsupportedError, "Your JSS Server version, #{@server.raw_version}, is to low. Must be #{JSS::MINIMUM_SERVER_VERSION} or higher."
|
206
230
|
end
|
207
231
|
|
208
|
-
return
|
232
|
+
return @connected ? @server_host : nil
|
209
233
|
end # connect
|
210
234
|
|
211
235
|
###
|
@@ -240,6 +264,7 @@ module JSS
|
|
240
264
|
def disconnect
|
241
265
|
@jss_user = nil
|
242
266
|
@rest_url = nil
|
267
|
+
@server_host = nil
|
243
268
|
@cnx = nil
|
244
269
|
@connected = false
|
245
270
|
end # disconnect
|
@@ -308,7 +333,6 @@ module JSS
|
|
308
333
|
@cnx[rsrc].post xml, :content_type => 'text/xml', :accept => :json
|
309
334
|
end #post_rsrc
|
310
335
|
|
311
|
-
###
|
312
336
|
### Delete a resource from the JSS
|
313
337
|
###
|
314
338
|
### @param rsrc[String] the resource to create, the URL part after 'JSSResource/'
|
@@ -323,7 +347,46 @@ module JSS
|
|
323
347
|
@cnx[rsrc].delete
|
324
348
|
|
325
349
|
end #delete_rsrc
|
326
|
-
|
350
|
+
|
351
|
+
|
352
|
+
### Test that a given hostname & port is a JSS API server
|
353
|
+
###
|
354
|
+
### @param server[String] The hostname to test,
|
355
|
+
###
|
356
|
+
### @param port[Integer] The port to try connecting on
|
357
|
+
###
|
358
|
+
### @return [Boolean] does the server host a JSS API?
|
359
|
+
###
|
360
|
+
def valid_server? (server, port = SSL_PORT)
|
361
|
+
# try ssl first
|
362
|
+
begin
|
363
|
+
return true if open("https://#{server}:#{port}/#{TEST_PATH}", ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE).read.include? TEST_CONTENT
|
364
|
+
rescue
|
365
|
+
# then regular http
|
366
|
+
begin
|
367
|
+
return true if open("http://#{server}:#{port}/#{TEST_PATH}").read.include? TEST_CONTENT
|
368
|
+
rescue
|
369
|
+
# any errors = no API
|
370
|
+
return false
|
371
|
+
end # begin
|
372
|
+
end #begin
|
373
|
+
# if we're here, no API
|
374
|
+
return false
|
375
|
+
end
|
376
|
+
|
377
|
+
### The server to which we are connected, or will
|
378
|
+
### try connecting to if none is specified with the
|
379
|
+
### call to #connect
|
380
|
+
###
|
381
|
+
### @return [String] the hostname of the server
|
382
|
+
###
|
383
|
+
def hostname
|
384
|
+
return @server_host if @server_host
|
385
|
+
srvr = JSS::CONFIG.api_server_name
|
386
|
+
srvr ||= JSS::Client.jss_server
|
387
|
+
return srvr
|
388
|
+
end
|
389
|
+
|
327
390
|
### aliases
|
328
391
|
alias connected? connected
|
329
392
|
|
data/lib/jss-api/api_object.rb
CHANGED
@@ -1,25 +1,25 @@
|
|
1
|
-
### Copyright
|
2
|
-
###
|
1
|
+
### Copyright 2016 Pixar
|
2
|
+
###
|
3
3
|
### Licensed under the Apache License, Version 2.0 (the "Apache License")
|
4
4
|
### with the following modification; you may not use this file except in
|
5
5
|
### compliance with the Apache License and the following modification to it:
|
6
6
|
### Section 6. Trademarks. is deleted and replaced with:
|
7
|
-
###
|
7
|
+
###
|
8
8
|
### 6. Trademarks. This License does not grant permission to use the trade
|
9
9
|
### names, trademarks, service marks, or product names of the Licensor
|
10
10
|
### and its affiliates, except as required to comply with Section 4(c) of
|
11
11
|
### the License and to reproduce the content of the NOTICE file.
|
12
|
-
###
|
12
|
+
###
|
13
13
|
### You may obtain a copy of the Apache License at
|
14
|
-
###
|
14
|
+
###
|
15
15
|
### http://www.apache.org/licenses/LICENSE-2.0
|
16
|
-
###
|
16
|
+
###
|
17
17
|
### Unless required by applicable law or agreed to in writing, software
|
18
18
|
### distributed under the Apache License with the above modification is
|
19
19
|
### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
20
20
|
### KIND, either express or implied. See the Apache License for the specific
|
21
21
|
### language governing permissions and limitations under the Apache License.
|
22
|
-
###
|
22
|
+
###
|
23
23
|
###
|
24
24
|
|
25
25
|
###
|
@@ -120,7 +120,7 @@ module JSS
|
|
120
120
|
when 1
|
121
121
|
self.new :id => self.all_ids[0]
|
122
122
|
else
|
123
|
-
self.new :master
|
123
|
+
self.new :id => :master
|
124
124
|
end
|
125
125
|
end
|
126
126
|
|
@@ -244,7 +244,7 @@ module JSS
|
|
244
244
|
###
|
245
245
|
### You can also do this more easily by calling JSS.master_distribution_point
|
246
246
|
###
|
247
|
-
def initialize(args)
|
247
|
+
def initialize(args = {})
|
248
248
|
|
249
249
|
@init_data = nil
|
250
250
|
|
@@ -343,6 +343,75 @@ module JSS
|
|
343
343
|
sha256 == Digest::SHA2.new(256).update(pw).to_s
|
344
344
|
end
|
345
345
|
|
346
|
+
### Check to see if this dist point is reachable for downloads (read-only)
|
347
|
+
### via either http, if available, or filesharing.
|
348
|
+
###
|
349
|
+
### @param pw[String] the read-only password to use for checking the connection
|
350
|
+
### If http downloads are enabled, and no http password is required
|
351
|
+
### this can be omitted.
|
352
|
+
###
|
353
|
+
### @param check_http[Boolean] should we try the http download first, if enabled?
|
354
|
+
### If you're intentionally using the ro password for filesharing, and want to check
|
355
|
+
### only filesharing, then set this to false.
|
356
|
+
###
|
357
|
+
### @return [FalseClass, Symbol] false if not reachable, otherwise :http or :mountable
|
358
|
+
###
|
359
|
+
def reachable_for_download? (pw = '', check_http = true)
|
360
|
+
pw ||= ''
|
361
|
+
http_checked = ""
|
362
|
+
if check_http && http_downloads_enabled
|
363
|
+
if @username_password_required
|
364
|
+
# we don't check the pw here, because if the connection fails, we'll
|
365
|
+
# drop down below to try the password for mounting.
|
366
|
+
# we'll escape all the chars that aren't unreserved
|
367
|
+
reserved_chars = Regexp.new("[^#{URI::REGEXP::PATTERN::UNRESERVED}]")
|
368
|
+
user_pass = "#{URI.escape @http_username,reserved_chars}:#{URI.escape ro_pw, reserved_chars}@"
|
369
|
+
url = @http_url.sub "://#{@ip_address}", "://#{user_pass}#{@ip_address}"
|
370
|
+
else
|
371
|
+
url = @http_url
|
372
|
+
end
|
373
|
+
|
374
|
+
begin
|
375
|
+
open(url).read
|
376
|
+
return :http
|
377
|
+
rescue
|
378
|
+
http_checked = "http and "
|
379
|
+
end
|
380
|
+
end # if check_http && http_downloads_enabled
|
381
|
+
|
382
|
+
return :mountable if mounted?
|
383
|
+
|
384
|
+
return false unless check_pw :ro , pw
|
385
|
+
|
386
|
+
begin
|
387
|
+
mount pw, :ro
|
388
|
+
return :mountable
|
389
|
+
rescue
|
390
|
+
return false
|
391
|
+
ensure
|
392
|
+
unmount
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
### Check to see if this dist point is reachable for uploads (read-write)
|
397
|
+
### via filesharing.
|
398
|
+
###
|
399
|
+
### @param pw[String] the read-write password to use for checking the connection
|
400
|
+
###
|
401
|
+
### @return [FalseClass, Symbol] false if not reachable, otherwise :mountable
|
402
|
+
###
|
403
|
+
def reachable_for_upload? (pw)
|
404
|
+
return :mountable if mounted?
|
405
|
+
return false unless check_pw :rw , pw
|
406
|
+
begin
|
407
|
+
mount pw, :rw
|
408
|
+
return :mountable
|
409
|
+
rescue
|
410
|
+
return false
|
411
|
+
ensure
|
412
|
+
unmount
|
413
|
+
end
|
414
|
+
end
|
346
415
|
|
347
416
|
|
348
417
|
###
|
@@ -350,19 +419,19 @@ module JSS
|
|
350
419
|
###
|
351
420
|
### @param pw[String,Symbol] the read-only or read-write password for this DistributionPoint
|
352
421
|
### If :prompt, the user is promted on the commandline to enter the password for the :user.
|
353
|
-
### If :stdin#, the password is read from a line of std in represented by the
|
354
|
-
### so :stdin3 reads the passwd from the third line of standard input. defaults to line 2,
|
422
|
+
### If :stdin#, the password is read from a line of std in represented by the digits at #,
|
423
|
+
### so :stdin3 reads the passwd from the third line of standard input. defaults to line 2,
|
355
424
|
### if no digit is supplied. see {JSS.stdin}
|
356
425
|
###
|
357
426
|
### @param access[Symbol] how to mount the DistributionPoint, and which password to expect.
|
358
|
-
### :ro = read-only, :rw
|
427
|
+
### :ro (or anything else) = read-only, :rw = read-write
|
359
428
|
###
|
360
429
|
### @return [Pathname] the mountpoint.
|
361
430
|
###
|
362
|
-
def mount(pw = nil, access = :
|
431
|
+
def mount(pw = nil, access = :ro)
|
363
432
|
return @mountpoint if mounted?
|
364
|
-
access = :
|
365
|
-
|
433
|
+
access = :ro unless access == :rw
|
434
|
+
|
366
435
|
password = if pw == :prompt
|
367
436
|
JSS.prompt_for_password "Enter the password for the #{access} user '#{access == :ro ? @read_only_username : @read_write_username }':"
|
368
437
|
elsif pw.is_a?(Symbol) and pw.to_s.start_with?('stdin')
|
@@ -373,7 +442,7 @@ module JSS
|
|
373
442
|
else
|
374
443
|
pw
|
375
444
|
end
|
376
|
-
|
445
|
+
|
377
446
|
pwok = check_pw(access, password)
|
378
447
|
unless pwok
|
379
448
|
msg = pwok.nil? ? "No #{access} password set in the JSS" : "Incorrect password for #{access} account"
|
@@ -393,13 +462,14 @@ module JSS
|
|
393
462
|
|
394
463
|
@mountpoint.mkpath
|
395
464
|
|
396
|
-
|
397
|
-
if
|
465
|
+
mount_out = `#{@mnt_cmd} -o '#{MOUNT_OPTIONS}' '#{@mount_url}' '#{@mountpoint}' 2>&1`
|
466
|
+
if $?.exitstatus == 0 and @mountpoint.mountpoint?
|
467
|
+
#if system @mnt_cmd.to_s, *['-o', MOUNT_OPTIONS, @mount_url, @mountpoint.to_s]
|
398
468
|
@mounted = access
|
399
469
|
else
|
400
470
|
@mountpoint.rmdir if @mountpoint.directory?
|
401
471
|
@mounted = nil
|
402
|
-
raise JSS::FileServiceError, "
|
472
|
+
raise JSS::FileServiceError, "Can't mount #{@ip_address}: #{mount_out}"
|
403
473
|
end
|
404
474
|
return @mountpoint
|
405
475
|
end # mount
|
@@ -421,7 +491,7 @@ module JSS
|
|
421
491
|
end
|
422
492
|
nil
|
423
493
|
end # unmount
|
424
|
-
|
494
|
+
|
425
495
|
|
426
496
|
###
|
427
497
|
### Is this thing mounted right now?
|
@@ -431,8 +501,8 @@ module JSS
|
|
431
501
|
def mounted?
|
432
502
|
@mountpoint.directory? and @mountpoint.mountpoint?
|
433
503
|
end
|
434
|
-
|
435
|
-
|
504
|
+
|
505
|
+
|
436
506
|
#### aliases
|
437
507
|
alias hostname ip_address
|
438
508
|
alias umount unmount
|