jss-api 0.5.8 → 0.6.1

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.
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