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.
Files changed (68) hide show
  1. data/CHANGES.md +55 -7
  2. data/README.md +2 -1
  3. data/bin/cgrouper +1 -1
  4. data/bin/subnet-update +1 -1
  5. data/lib/jss-api.rb +2 -363
  6. data/lib/jss-api/api_connection.rb +78 -15
  7. data/lib/jss-api/api_object.rb +1 -1
  8. data/lib/jss-api/api_object/advanced_search.rb +1 -1
  9. data/lib/jss-api/api_object/advanced_search/advanced_computer_search.rb +1 -1
  10. data/lib/jss-api/api_object/advanced_search/advanced_mobile_device_search.rb +1 -1
  11. data/lib/jss-api/api_object/advanced_search/advanced_user_search.rb +1 -1
  12. data/lib/jss-api/api_object/building.rb +1 -1
  13. data/lib/jss-api/api_object/category.rb +1 -1
  14. data/lib/jss-api/api_object/computer.rb +1 -1
  15. data/lib/jss-api/api_object/creatable.rb +1 -1
  16. data/lib/jss-api/api_object/criteriable.rb +1 -1
  17. data/lib/jss-api/api_object/criteriable/criteria.rb +1 -1
  18. data/lib/jss-api/api_object/criteriable/criterion.rb +1 -1
  19. data/lib/jss-api/api_object/department.rb +1 -1
  20. data/lib/jss-api/api_object/distribution_point.rb +92 -22
  21. data/lib/jss-api/api_object/extendable.rb +1 -1
  22. data/lib/jss-api/api_object/extension_attribute.rb +1 -1
  23. data/lib/jss-api/api_object/extension_attribute/computer_extension_attribute.rb +1 -1
  24. data/lib/jss-api/api_object/extension_attribute/mobile_device_extension_attribute.rb +1 -1
  25. data/lib/jss-api/api_object/extension_attribute/user_extension_attribute.rb +1 -1
  26. data/lib/jss-api/api_object/group.rb +1 -1
  27. data/lib/jss-api/api_object/group/computer_group.rb +1 -1
  28. data/lib/jss-api/api_object/group/mobile_device_group.rb +1 -1
  29. data/lib/jss-api/api_object/group/user_group.rb +1 -1
  30. data/lib/jss-api/api_object/ldap_server.rb +1 -1
  31. data/lib/jss-api/api_object/locatable.rb +1 -1
  32. data/lib/jss-api/api_object/matchable.rb +1 -1
  33. data/lib/jss-api/api_object/mobile_device.rb +1 -1
  34. data/lib/jss-api/api_object/netboot_server.rb +1 -1
  35. data/lib/jss-api/api_object/network_segment.rb +1 -1
  36. data/lib/jss-api/api_object/osx_configuration_profile.rb +1 -1
  37. data/lib/jss-api/api_object/package.rb +117 -64
  38. data/lib/jss-api/api_object/peripheral.rb +1 -1
  39. data/lib/jss-api/api_object/peripheral_type.rb +1 -1
  40. data/lib/jss-api/api_object/policy.rb +1 -1
  41. data/lib/jss-api/api_object/purchasable.rb +1 -1
  42. data/lib/jss-api/api_object/removable_macaddr.rb +1 -1
  43. data/lib/jss-api/api_object/scopable.rb +1 -1
  44. data/lib/jss-api/api_object/scopable/scope.rb +1 -1
  45. data/lib/jss-api/api_object/script.rb +1 -1
  46. data/lib/jss-api/api_object/self_servable.rb +1 -1
  47. data/lib/jss-api/api_object/site.rb +1 -1
  48. data/lib/jss-api/api_object/software_update_server.rb +1 -1
  49. data/lib/jss-api/api_object/updatable.rb +1 -1
  50. data/lib/jss-api/api_object/uploadable.rb +1 -1
  51. data/lib/jss-api/api_object/user.rb +1 -1
  52. data/lib/jss-api/client.rb +22 -21
  53. data/lib/jss-api/compatibility.rb +1 -1
  54. data/lib/jss-api/composer.rb +2 -2
  55. data/lib/jss-api/configuration.rb +1 -1
  56. data/lib/jss-api/db_connection.rb +63 -12
  57. data/lib/jss-api/exceptions.rb +1 -1
  58. data/lib/jss-api/ruby_extensions.rb +1 -1
  59. data/lib/jss-api/ruby_extensions/filetest.rb +1 -1
  60. data/lib/jss-api/ruby_extensions/hash.rb +1 -1
  61. data/lib/jss-api/ruby_extensions/ipaddr.rb +1 -1
  62. data/lib/jss-api/ruby_extensions/pathname.rb +1 -1
  63. data/lib/jss-api/ruby_extensions/string.rb +17 -1
  64. data/lib/jss-api/ruby_extensions/time.rb +1 -1
  65. data/lib/jss-api/server.rb +1 -1
  66. data/lib/jss-api/utility.rb +416 -0
  67. data/lib/jss-api/version.rb +8 -8
  68. metadata +3 -2
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
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
- RSRC = "JSSResource"
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 or not?
177
- ssl = SSL_PORT == args[:port].to_i ? "s" : ''
178
- @rest_url = URI::encode "http#{ssl}://#{args[:server]}:#{args[:port]}/#{RSRC}"
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 nil (unset) or non-false, then we will verify
182
- args[:verify_ssl] = (args[:verify_cert].nil? or args[:verify_cert]) ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
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 true
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
 
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
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
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
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
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
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
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
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
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
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
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
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
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
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
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
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
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
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
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
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
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
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
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
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
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
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
@@ -1,25 +1,25 @@
1
- ### Copyright 2014 Pixar
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 digit at #,
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 (or anything else) = read-write
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 = :ro1)
431
+ def mount(pw = nil, access = :ro)
363
432
  return @mountpoint if mounted?
364
- access = :rw unless access == :ro
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
- #if system "#{@mnt_cmd} -o '#{MOUNT_OPTIONS}' '#{@mount_url}' '#{@mountpoint}'"
397
- if system @mnt_cmd.to_s, *['-o', MOUNT_OPTIONS, @mount_url, @mountpoint.to_s]
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, "There was a problem mounting #{@ip_address}"
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