jss-api 0.6.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/lib/jss-api.rb +1 -191
  2. metadata +16 -146
  3. data/.yardopts +0 -7
  4. data/CHANGES.md +0 -88
  5. data/LICENSE.txt +0 -174
  6. data/README.md +0 -396
  7. data/THANKS.md +0 -6
  8. data/bin/cgrouper +0 -485
  9. data/bin/subnet-update +0 -400
  10. data/lib/jss-api/api_connection.rb +0 -400
  11. data/lib/jss-api/api_object.rb +0 -616
  12. data/lib/jss-api/api_object/advanced_search.rb +0 -389
  13. data/lib/jss-api/api_object/advanced_search/advanced_computer_search.rb +0 -95
  14. data/lib/jss-api/api_object/advanced_search/advanced_mobile_device_search.rb +0 -96
  15. data/lib/jss-api/api_object/advanced_search/advanced_user_search.rb +0 -95
  16. data/lib/jss-api/api_object/building.rb +0 -92
  17. data/lib/jss-api/api_object/category.rb +0 -147
  18. data/lib/jss-api/api_object/computer.rb +0 -852
  19. data/lib/jss-api/api_object/creatable.rb +0 -98
  20. data/lib/jss-api/api_object/criteriable.rb +0 -189
  21. data/lib/jss-api/api_object/criteriable/criteria.rb +0 -231
  22. data/lib/jss-api/api_object/criteriable/criterion.rb +0 -228
  23. data/lib/jss-api/api_object/department.rb +0 -93
  24. data/lib/jss-api/api_object/distribution_point.rb +0 -560
  25. data/lib/jss-api/api_object/extendable.rb +0 -221
  26. data/lib/jss-api/api_object/extension_attribute.rb +0 -457
  27. data/lib/jss-api/api_object/extension_attribute/computer_extension_attribute.rb +0 -362
  28. data/lib/jss-api/api_object/extension_attribute/mobile_device_extension_attribute.rb +0 -189
  29. data/lib/jss-api/api_object/extension_attribute/user_extension_attribute.rb +0 -117
  30. data/lib/jss-api/api_object/group.rb +0 -380
  31. data/lib/jss-api/api_object/group/computer_group.rb +0 -124
  32. data/lib/jss-api/api_object/group/mobile_device_group.rb +0 -139
  33. data/lib/jss-api/api_object/group/user_group.rb +0 -139
  34. data/lib/jss-api/api_object/ldap_server.rb +0 -535
  35. data/lib/jss-api/api_object/locatable.rb +0 -286
  36. data/lib/jss-api/api_object/matchable.rb +0 -97
  37. data/lib/jss-api/api_object/mobile_device.rb +0 -556
  38. data/lib/jss-api/api_object/netboot_server.rb +0 -148
  39. data/lib/jss-api/api_object/network_segment.rb +0 -414
  40. data/lib/jss-api/api_object/osx_configuration_profile.rb +0 -261
  41. data/lib/jss-api/api_object/package.rb +0 -812
  42. data/lib/jss-api/api_object/peripheral.rb +0 -335
  43. data/lib/jss-api/api_object/peripheral_type.rb +0 -295
  44. data/lib/jss-api/api_object/policy.rb +0 -898
  45. data/lib/jss-api/api_object/purchasable.rb +0 -316
  46. data/lib/jss-api/api_object/removable_macaddr.rb +0 -98
  47. data/lib/jss-api/api_object/scopable.rb +0 -136
  48. data/lib/jss-api/api_object/scopable/scope.rb +0 -621
  49. data/lib/jss-api/api_object/script.rb +0 -631
  50. data/lib/jss-api/api_object/self_servable.rb +0 -355
  51. data/lib/jss-api/api_object/site.rb +0 -93
  52. data/lib/jss-api/api_object/software_update_server.rb +0 -109
  53. data/lib/jss-api/api_object/updatable.rb +0 -117
  54. data/lib/jss-api/api_object/uploadable.rb +0 -138
  55. data/lib/jss-api/api_object/user.rb +0 -272
  56. data/lib/jss-api/client.rb +0 -504
  57. data/lib/jss-api/compatibility.rb +0 -66
  58. data/lib/jss-api/composer.rb +0 -171
  59. data/lib/jss-api/configuration.rb +0 -306
  60. data/lib/jss-api/db_connection.rb +0 -298
  61. data/lib/jss-api/exceptions.rb +0 -95
  62. data/lib/jss-api/ruby_extensions.rb +0 -35
  63. data/lib/jss-api/ruby_extensions/filetest.rb +0 -43
  64. data/lib/jss-api/ruby_extensions/hash.rb +0 -79
  65. data/lib/jss-api/ruby_extensions/ipaddr.rb +0 -91
  66. data/lib/jss-api/ruby_extensions/pathname.rb +0 -77
  67. data/lib/jss-api/ruby_extensions/string.rb +0 -59
  68. data/lib/jss-api/ruby_extensions/time.rb +0 -63
  69. data/lib/jss-api/server.rb +0 -108
  70. data/lib/jss-api/utility.rb +0 -416
  71. data/lib/jss-api/version.rb +0 -31
@@ -1,400 +0,0 @@
1
- #!/usr/bin/ruby
2
-
3
- ### Copyright 2016 Pixar
4
- ###
5
- ### Licensed under the Apache License, Version 2.0 (the "Apache License")
6
- ### with the following modification; you may not use this file except in
7
- ### compliance with the Apache License and the following modification to it:
8
- ### Section 6. Trademarks. is deleted and replaced with:
9
- ###
10
- ### 6. Trademarks. This License does not grant permission to use the trade
11
- ### names, trademarks, service marks, or product names of the Licensor
12
- ### and its affiliates, except as required to comply with Section 4(c) of
13
- ### the License and to reproduce the content of the NOTICE file.
14
- ###
15
- ### You may obtain a copy of the Apache License at
16
- ###
17
- ### http://www.apache.org/licenses/LICENSE-2.0
18
- ###
19
- ### Unless required by applicable law or agreed to in writing, software
20
- ### distributed under the Apache License with the above modification is
21
- ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
22
- ### KIND, either express or implied. See the Apache License for the specific
23
- ### language governing permissions and limitations under the Apache License.
24
-
25
- ##############################
26
- # == Synopsis
27
- # Add, remove, or change the Network Segments in the JSS based on data from an input file
28
- # in CSV, tab, or other delimited format.
29
- #
30
- # == Usage
31
- # subnet-update [-t | -d delimiter] [-h] file
32
- #
33
- #
34
- # == Author
35
- # Chris Lasell <chrisl@pixar.com>
36
- #
37
- # == Copyright
38
- # Copyright (c) 2014 Pixar Animation Studios
39
-
40
- ##############################
41
- # Libraries
42
- require 'jss-api'
43
- require 'getoptlong'
44
-
45
- ##############################
46
- # The app object
47
- class App
48
-
49
- ##############################
50
- # Constants
51
-
52
- USAGE = "Usage: #{File.basename($0)} [-d delim] [--header] [-c col1,col2,col3 ] [-m manual-prefix] [--help] /path/to/file"
53
-
54
- POTENTIAL_COLUMNS = [:name, :starting, :ending, :cidr]
55
-
56
- # Whenever we process a file, we store it here. The next time we
57
- # run, if the input file is identical to this, we exit witout doing anything.
58
- DEFAULT_CACHE_FILE = Pathname.new("~/.last_subnet_update").expand_path
59
-
60
- DEFAULT_DELIMITER = "\t"
61
- DEFAULT_COLUMNS = [:name, :starting, :ending]
62
- DEFAULT_MANUAL_PREFIX = "Manual-"
63
-
64
-
65
- attr_reader :debug
66
-
67
- ###############
68
- # set up
69
- def initialize(args)
70
-
71
- # set defaults
72
- @debug = false
73
-
74
- @delim = DEFAULT_DELIMITER
75
- @header = false
76
- @columns = DEFAULT_COLUMNS
77
- @cache_file = DEFAULT_CACHE_FILE
78
- @manual_prefix = DEFAULT_MANUAL_PREFIX
79
-
80
-
81
- #define the cli opts
82
- cli_opts = GetoptLong.new(
83
- [ '--help', '-H', GetoptLong::NO_ARGUMENT ],
84
- [ '--delimiter', '--delim', '-d', GetoptLong::REQUIRED_ARGUMENT],
85
- [ '--header', '-h', GetoptLong::NO_ARGUMENT],
86
- [ '--columns', '-c', GetoptLong::OPTIONAL_ARGUMENT],
87
- [ '--manual-prefix', '-m', GetoptLong::OPTIONAL_ARGUMENT],
88
- [ '--cache', GetoptLong::REQUIRED_ARGUMENT ],
89
- [ '--debug', GetoptLong::NO_ARGUMENT],
90
- [ '--server', '-S', GetoptLong::OPTIONAL_ARGUMENT],
91
- [ '--port', '-P', GetoptLong::OPTIONAL_ARGUMENT],
92
- [ '--user', '-U', GetoptLong::OPTIONAL_ARGUMENT],
93
- [ '--no-verify-cert', '-V', GetoptLong::NO_ARGUMENT],
94
- [ '--timeout', '-T', GetoptLong::OPTIONAL_ARGUMENT]
95
- )
96
-
97
- # parse the cli opts
98
- cli_opts.each do |opt, arg|
99
- case opt
100
- when '--help' then show_help
101
- when '--delimiter' then @delim = arg
102
- when '--header' then @header = true
103
- when '--columns' then @columns = arg.split(',').map{|c| c.to_sym}
104
- when '--manual-prefix' then @manual_prefix = arg
105
- when '--cache' then @cache_file = Pathname.new arg
106
- when '--debug' then @debug = true
107
- when '--server'
108
- @server = arg
109
-
110
- when '--port'
111
- @port = arg
112
-
113
- when '--user'
114
- @user = arg
115
-
116
- when '--no-verify-cert'
117
- @verify_cert = false
118
-
119
- when '--timeout'
120
- @timeout = arg
121
-
122
- end # case
123
- end # each opt arg
124
-
125
-
126
- @columns = nil if @columns and @columns.empty?
127
-
128
- @file = args.shift
129
-
130
-
131
- end # init
132
-
133
- ###############
134
- # Go!
135
- def run
136
-
137
- unless @file
138
- puts "No input file specified."
139
- puts USAGE
140
- return
141
- end
142
-
143
- @file = Pathname.new @file
144
-
145
- unless parse_file
146
- puts "File hasn't changed since last time, no changes to make!"
147
- return
148
- end
149
-
150
- # use any config settings defined....
151
- @user ||= JSS::CONFIG.api_username
152
- @server ||= JSS::CONFIG.api_server_name
153
- @getpass = $stdin.tty? ? :prompt : :stdin
154
-
155
- raise JSS::MissingDataError, "No JSS Username provided or found in the JSS gem config." unless @user
156
- raise JSS::MissingDataError, "No JSS Server provided or found in the JSS gem config." unless @server
157
-
158
- JSS::API.connect( :server => @server,
159
- :port => @port,
160
- :verify_cert => @verify_cert,
161
- :user => @user,
162
- :pw => @getpass,
163
- :stdin_line => 1,
164
- :timeout => @timeout
165
- )
166
-
167
- update_network_segments
168
-
169
- end # run
170
-
171
- #####################################
172
- ###
173
- ### Show Help
174
- ###
175
- def show_help
176
- puts <<-FULLHELP
177
- Update the JSS Network Segments from a delimited file of subnet information.
178
-
179
- #{USAGE}
180
-
181
- Options:
182
- -d, --delimiter - The field delimiter in the file, defaults to tab.
183
- -c, --columns [col1,col2,col3]
184
- - The column order in file, must include 'name', 'starting',
185
- and either 'ending' or 'cidr'
186
- -h, --header - The first line of the file is a header line,
187
- possibly defining the columns
188
- -m, --manual-prefix - Network Segment names in the JSS with this prefix are ignored.
189
- Defaults to 'Manual-'
190
- --cache /path/.. - Where read/save the input data for comparison between runs.
191
- Defaults to ~/.last_subnet_update
192
- -S, --server srvr - specify the JSS API server name
193
- -P, --port portnum - specify the JSS API port
194
- -U, --user username - specify the JSS API user
195
- -V, --no-verify-cert - Allow self-signed, unverified SSL certificate
196
- -T, --timeout secs - specify the JSS API timeout
197
- -H, --help - show this help
198
- --debug - show the ruby backtrace when errors occur
199
-
200
- This program parses the input file line by line (possibly accounting for a header line).
201
- Each line defines the name and IP-range of a subnet/network segment.
202
-
203
- - If a segment doesn't exist in the JSS, it is created.
204
- - If a segment's range has changed, it is updated in the JSS.
205
- - If a JSS segment doesn't exist in the file, it is deleted from the JSS
206
- unless its name starts with the --manual-prefix
207
-
208
- Input File:
209
- - The file must contain three columns, separated by the --delimiter,
210
- with these names, in any order:
211
- - 'name' (the network segment name)
212
- - 'starting' (the starting IP address of the network segment)
213
- - EITHER of:
214
- - 'ending' (the ending IP address of the network segment)
215
- - 'cidr' (the network range of the segment as a CIDR bitmask, e.g. '24')
216
- Notes:
217
- - The --columns option is a comma-separted list of the three
218
- column names aboveindicating the column-order in the file.
219
-
220
- - If --columns are not provided, and --header is specified, the first line
221
- is assumed to contain the column names, separated by the delimiter
222
-
223
- - If --header is provided with --columns, the first line of the file is ignored.
224
-
225
- - The raw data from the file is cached and compared to the input file at
226
- the next run. If the data is identical, no JSS connection is made.
227
-
228
- - If no API settings are provided, they will be read from /etc/jss_gem.conf
229
- and ~/.jss_gem.conf. See the JSS Gem docs for details.
230
-
231
- - The password for the connection will be read from STDIN or prompted if needed
232
-
233
- FULLHELP
234
- exit 0
235
- end
236
-
237
- ########################
238
- # parse the incoming data file.
239
- # If the file hasn't changed from the last time we processed it
240
- # then return false
241
- # otherwise parse it into @parsed_data and return true
242
- # @parsed_data is an array of hashes, each with :name, :starting, and :ending
243
- #
244
- def parse_file
245
-
246
- raise "'#{@file}' is not readable, or not a regular file" unless @file.readable? and @file.file?
247
-
248
- # read in the file
249
- @raw_data = @file.read
250
-
251
- # compare it to the one we used last time
252
- if @cache_file.readable?
253
- return false if @raw_data == @cache_file.read
254
- end
255
-
256
- # split the data into an array by newlines
257
- lines = @raw_data.split "\n"
258
-
259
- # remove the first line if its a header, and parse it into the columns
260
- # if needed
261
- if @header
262
- header = lines.shift
263
- @columns ||= header.split(/\s*#{@delim}\s*/).map{|c| c.to_sym}
264
- end
265
-
266
- # check some state
267
- raise "Columns must include 'name' and 'starting'" unless @columns.include?(:name) and @columns.include?(:starting)
268
- raise "Columns must include either 'ending' or 'cidr'" unless @columns.include?(:ending) or @columns.include?(:cidr)
269
-
270
- @use_cidr = @columns.include? :cidr
271
-
272
-
273
- # which columns are which in the file?
274
- name = @columns.index :name
275
- starting = @columns.index :starting
276
- ending = @use_cidr ? @columns.index(:cidr) : @columns.index(:ending)
277
-
278
- # split each line and convert it into a hash
279
- @parsed_data = lines.map do |line|
280
-
281
- parts = line.split(@delim).map{|f| f.strip }
282
-
283
- unless parts[name] and parts[starting] and parts[ending]
284
- puts "Skipping invalid line: #{line}"
285
- next
286
- end
287
-
288
-
289
- {:name => parts[name], :starting => parts[starting], :ending => parts[ending]}
290
- end
291
-
292
- # parsed data is now an array of hashes
293
- return true
294
- end
295
-
296
- #############################################
297
- #############################################
298
- # Update the JSS Network Segments from GIT_NETBLOCKS_URL, q.v.
299
- def update_network_segments
300
-
301
- # CREATE any that are in the parsed data but not yet in the JSS,
302
- # and UPDATE any that exist but have modified ranges.
303
- # While looping through, make a hash of JSS::NetworkSegment objects, keyed by their name.
304
- segs_from_data = {}
305
-
306
- @parsed_data.each do |pd|
307
-
308
- # skip anthing with the manual prefix
309
- next if pd[:name].start_with? @manual_prefix
310
-
311
- ender = @use_cidr ? :cidr : :ending_address
312
-
313
- begin
314
- this_seg = JSS::NetworkSegment.new(:id => :new, :name => pd[:name], :starting_address => pd[:starting], ender => pd[:ending])
315
-
316
- # If the new netsegment should have other settings (dist. point, netboot server, etc...)
317
- # here's where you should apply those settings.
318
-
319
- this_seg.create
320
- puts "Added Network Segment '#{this_seg.name}' to the JSS"
321
-
322
- # it already exists, so see if it needs any changes
323
- rescue JSS::AlreadyExistsError
324
-
325
- # there's already one with this name, so just grab it.
326
- this_seg = JSS::NetworkSegment.new( :name => pd[:name])
327
-
328
- # does the startng addres need to be changed?
329
- needs_update = this_seg.starting_address.to_s != pd[:starting].to_s
330
-
331
- # even if we don't need to update the starting, we might need to update
332
- # the ending...
333
- unless needs_update
334
- if @use_cidr
335
- needs_update = this_seg.cidr.to_i != pd[:ending].to_i
336
- else
337
- needs_update = this_seg.ending_address.to_s != pd[:ending].to_s
338
- end # if @use_cidr
339
- end #unless needs update
340
-
341
- # did we decide we need an update?
342
- if needs_update
343
- this_seg.starting_address = pd[:starting]
344
- if @use_cidr
345
- this_seg.cidr = pd[:ending].to_i
346
- else
347
- this_seg.ending_address = pd[:ending]
348
- end # if @use_cidr
349
- this_seg.update
350
- puts "Updated IP range for Network Segment '#{this_seg.name}'"
351
-
352
- else # doesn't need update
353
- puts "Network Segment '#{this_seg.name}' doesn't have any changes."
354
- end # if needs update
355
-
356
- # rescue other errors
357
- rescue
358
- raise "There was an error with NetworkSegment #{pd[:name]}: #{$!}"
359
- end # begin
360
-
361
- segs_from_data[this_seg.name] = this_seg
362
- end
363
-
364
-
365
- # DELETE those in jss, but not in parsed data,
366
- # unless the name starts with @manual_prefix
367
- JSS::NetworkSegment.map_all_ids_to(:name).each do |id,name|
368
-
369
- next if name.start_with? @manual_prefix
370
-
371
- unless segs_from_data.keys.include? name
372
- JSS::NetworkSegment.new(:id => id).delete
373
- puts "Deleted Network Segment '#{name}' from the JSS"
374
- end # unless
375
-
376
- end # jss_uids.each seg
377
-
378
- # save the data into a file for comparison next time
379
- @cache_file.jss_save @raw_data
380
-
381
- # all done
382
- return true
383
- end # update_network_segments
384
-
385
- end # app
386
-
387
- ##############################
388
- # create the app and go
389
- begin
390
- app = App.new(ARGV)
391
- app.run
392
- rescue
393
- # handle exceptions not handled elsewhere
394
- puts "An error occurred: #{$!}"
395
- puts "Backtrace:" if app.debug
396
- puts $@ if app.debug
397
-
398
- ensure
399
-
400
- end
@@ -1,400 +0,0 @@
1
- ### Copyright 2016 Pixar
2
- ###
3
- ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
- ### with the following modification; you may not use this file except in
5
- ### compliance with the Apache License and the following modification to it:
6
- ### Section 6. Trademarks. is deleted and replaced with:
7
- ###
8
- ### 6. Trademarks. This License does not grant permission to use the trade
9
- ### names, trademarks, service marks, or product names of the Licensor
10
- ### and its affiliates, except as required to comply with Section 4(c) of
11
- ### the License and to reproduce the content of the NOTICE file.
12
- ###
13
- ### You may obtain a copy of the Apache License at
14
- ###
15
- ### http://www.apache.org/licenses/LICENSE-2.0
16
- ###
17
- ### Unless required by applicable law or agreed to in writing, software
18
- ### distributed under the Apache License with the above modification is
19
- ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
- ### KIND, either express or implied. See the Apache License for the specific
21
- ### language governing permissions and limitations under the Apache License.
22
- ###
23
- ###
24
-
25
- ###
26
- module JSS
27
-
28
- #####################################
29
- ### Constants
30
- #####################################
31
-
32
- #####################################
33
- ### Module Variables
34
- #####################################
35
-
36
- #####################################
37
- ### Module Methods
38
- #####################################
39
-
40
- #####################################
41
- ### Module Classes
42
- #####################################
43
-
44
- ###
45
- ### An API connection to the JSS.
46
- ###
47
- ### This is a singleton class, only one can exist at a time.
48
- ### Its one instance is created automatically when the module loads, but it
49
- ### isn't connected to anything at that time.
50
- ###
51
- ### Use it via the {JSS::API} constant to call the #connect
52
- ### method, and the {#get_rsrc}, {#put_rsrc}, {#post_rsrc}, & {#delete_rsrc}
53
- ### methods, q.v. below.
54
- ###
55
- ### To access the underlying RestClient::Resource instance,
56
- ### use JSS::API.cnx
57
- ###
58
- class APIConnection
59
- include Singleton
60
-
61
- #####################################
62
- ### Class Constants
63
- #####################################
64
-
65
- ### The base API path in the jss URL
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
-
76
- ### The Default port
77
- HTTP_PORT = 9006
78
-
79
- ### The SSL port
80
- SSL_PORT = 8443
81
-
82
- ### The top line of an XML doc for submitting data via API
83
- XML_HEADER = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>'
84
-
85
- ### Default timeouts in seconds
86
- DFT_OPEN_TIMEOUT = 60
87
- DFT_TIMEOUT = 60
88
-
89
- ### The Default SSL Version
90
- DFT_SSL_VERSION = 'TLSv1'
91
-
92
- #####################################
93
- ### Attributes
94
- #####################################
95
-
96
- ### @return [String] the username who's connected to the JSS API
97
- attr_reader :jss_user
98
-
99
- ### @return [RestClient::Resource] the underlying connection resource
100
- attr_reader :cnx
101
-
102
- ### @return [Boolean] are we connected right now?
103
- attr_reader :connected
104
-
105
- ### @return [JSS::Server] the details of the JSS to which we're connected.
106
- attr_reader :server
107
-
108
- ### @return [String] the hostname of the JSS to which we're connected.
109
- attr_reader :server_host
110
-
111
- #####################################
112
- ### Constructor
113
- #####################################
114
-
115
- ###
116
- ### To connect, use JSS::APIConnection.instance.connect
117
- ### or a shortcut, JSS::API.connect
118
- ###
119
- def initialize ()
120
- @connected = false
121
- end # init
122
-
123
- #####################################
124
- ### Class Methods
125
- #####################################
126
-
127
- ###
128
- ### Connect to the JSS API.
129
- ###
130
- ### @param args[Hash] the keyed arguments for connection.
131
- ###
132
- ### @option args :server[String] the hostname of the JSS API server, required if not defined in JSS::CONFIG
133
- ###
134
- ### @option args :port[Integer] the port number to connect with, defaults to 8443
135
- ###
136
- ### @option args :use_ssl[Boolean] should the connection be made over SSL? Defaults to true.
137
- ###
138
- ### @option args :verify_cert[Boolean] should HTTPS SSL certificates be verified. Defaults to true.
139
- ### If your connection raises RestClient::SSLCertificateNotVerified, and you don't care about the
140
- ### validity of the SSL cert. just set this explicitly to false.
141
- ###
142
- ### @option args :user[String] a JSS user who has API privs, required if not defined in JSS::CONFIG
143
- ###
144
- ### @option args :pw[String,Symbol] Required, the password for that user, or :prompt, or :stdin
145
- ### If :prompt, the user is promted on the commandline to enter the password for the :user.
146
- ### If :stdin#, the password is read from a line of std in represented by the digit at #,
147
- ### so :stdin3 reads the passwd from the third line of standard input. defaults to line 1,
148
- ### if no digit is supplied. see {JSS.stdin}
149
- ###
150
- ### @option args :open_timeout[Integer] the number of seconds to wait for an initial response, defaults to 60
151
- ###
152
- ### @option args :timeout[Integer] the number of seconds before an API call times out, defaults to 60
153
- ###
154
- ### @return [true]
155
- ###
156
- def connect (args = {})
157
-
158
- # the server, if not specified, might come from a couple places.
159
- # see #hostname
160
- args[:server] ||= hostname
161
-
162
- # settings from config if they aren't in the args
163
- args[:server] ||= JSS::CONFIG.api_server_name
164
- args[:port] ||= JSS::CONFIG.api_server_port
165
- args[:user] ||= JSS::CONFIG.api_username
166
- args[:timeout] ||= JSS::CONFIG.api_timeout
167
- args[:open_timeout] ||= JSS::CONFIG.api_timeout_open
168
- args[:ssl_version] ||= JSS::CONFIG.api_ssl_version
169
-
170
- # if verify cert given was NOT in the args....
171
- if args[:verify_cert].nil?
172
- # set it from the prefs
173
- args[:verify_cert] = JSS::CONFIG.api_verify_cert
174
- end
175
-
176
- # settings from client jamf plist if needed
177
- args[:port] ||= JSS::Client.jss_port
178
-
179
- # default settings if needed
180
- args[:port] ||= SSL_PORT
181
- args[:timeout] ||= DFT_TIMEOUT
182
- args[:open_timeout] ||= DFT_OPEN_TIMEOUT
183
-
184
- # As of Casper 9.61 we can't use SSL, must use TLS, since SSLv3 was susceptible to poodles.
185
- # NOTE - this requires rest-client v 1.7.0 or higher
186
- # which requires mime-types 2.0 or higher, which requires ruby 1.9.2 or higher!
187
- # That means that support for ruby 1.8.7 stops with Casper 9.6
188
- args[:ssl_version] ||= DFT_SSL_VERSION
189
-
190
-
191
- # must have server, user, and pw
192
- raise JSS::MissingDataError, "No JSS :server specified, or in configuration." unless args[:server]
193
- raise JSS::MissingDataError, "No JSS :user specified, or in configuration." unless args[:user]
194
- raise JSS::MissingDataError, "Missing :pw for user '#{args[:user]}'" unless args[:pw]
195
-
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
-
204
-
205
- # prep the args for passing to RestClient::Resource
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
208
-
209
- args[:password] = if args[:pw] == :prompt
210
- JSS.prompt_for_password "Enter the password for JSS user #{args[:user]}@#{args[:server]}:"
211
- elsif args[:pw].is_a?(Symbol) and args[:pw].to_s.start_with?('stdin')
212
- args[:pw].to_s =~ /^stdin(\d+)$/
213
- line = $1
214
- line ||= 1
215
- JSS.stdin line
216
- else
217
- args[:pw]
218
- end
219
-
220
- # heres our connection
221
- @cnx = RestClient::Resource.new("#{@rest_url}", args)
222
-
223
- @jss_user = args[:user]
224
- @server_host = args[:server]
225
- @connected = true
226
- @server = JSS::Server.new
227
-
228
- if @server.version < JSS.parse_jss_version(JSS::MINIMUM_SERVER_VERSION)[:version]
229
- raise JSS::UnsupportedError, "Your JSS Server version, #{@server.raw_version}, is to low. Must be #{JSS::MINIMUM_SERVER_VERSION} or higher."
230
- end
231
-
232
- return @connected ? @server_host : nil
233
- end # connect
234
-
235
- ###
236
- ### Reset the response timeout for the rest connection
237
- ###
238
- ### @param timeout[Integer] the new timeout in seconds
239
- ###
240
- ### @return [void]
241
- ###
242
- def timeout= (timeout)
243
- @cnx.options[:timeout] = timeout
244
- end
245
-
246
- ###
247
- ### Reset the open-connection timeout for the rest connection
248
- ###
249
- ### @param timeout[Integer] the new timeout in seconds
250
- ###
251
- ### @return [void]
252
- ###
253
- def open_timeout= (timeout)
254
- @cnx.options[:open_timeout] = timeout
255
- end
256
-
257
-
258
- ###
259
- ### With a REST connection, there isn't any real "connection" to disconnect from
260
- ### So to disconnect, we just unset all our credentials.
261
- ###
262
- ### @return [void]
263
- ###
264
- def disconnect
265
- @jss_user = nil
266
- @rest_url = nil
267
- @server_host = nil
268
- @cnx = nil
269
- @connected = false
270
- end # disconnect
271
-
272
- ###
273
- ### Get an arbitrary JSS resource
274
- ###
275
- ### The first argument is the resource to get (the part of the API url
276
- ### after the 'JSSResource/' )
277
- ###
278
- ### By default we get the data in JSON, and parse it
279
- ### into a ruby data structure (arrays, hashes, strings, etc)
280
- ### with symbolized Hash keys.
281
- ###
282
- ### @param rsrc[String] the resource to get
283
- ### (the part of the API url after the 'JSSResource/' )
284
- ###
285
- ### @param format[Symbol] either ;json or :xml
286
- ### If the second argument is :xml, the XML data is returned as a String.
287
- ###
288
- ### @return [Hash,String] the result of the get
289
- ###
290
- def get_rsrc (rsrc, format = :json)
291
- raise JSS::InvalidConnectionError, "Not Connected. Use JSS::API.connect first." unless @connected
292
- rsrc = URI::encode rsrc
293
- data = @cnx[rsrc].get(:accept => format)
294
- return JSON.parse(data, :symbolize_names => true) if format == :json
295
- data
296
- end
297
-
298
- ###
299
- ### Change an existing JSS resource
300
- ###
301
- ### @param rsrc[String] the API resource being changed, the URL part after 'JSSResource/'
302
- ###
303
- ### @param xml[String] the xml specifying the changes.
304
- ###
305
- ### @return [String] the xml response from the server.
306
- ###
307
- def put_rsrc(rsrc,xml)
308
- raise JSS::InvalidConnectionError, "Not Connected. Use JSS::API.connect first." unless @connected
309
-
310
- ### convert CRs & to &#13;
311
- xml.gsub!(/\r/, '&#13;')
312
-
313
- ### send the data
314
- @cnx[rsrc].put(xml, :content_type => 'text/xml')
315
- end
316
-
317
- ###
318
- ### Create a new JSS resource
319
- ###
320
- ### @param rsrc[String] the API resource being created, the URL part after 'JSSResource/'
321
- ###
322
- ### @param xml[String] the xml specifying the new object.
323
- ###
324
- ### @return [String] the xml response from the server.
325
- ###
326
- def post_rsrc(rsrc,xml)
327
- raise JSS::InvalidConnectionError, "Not Connected. Use JSS::API.connect first." unless @connected
328
-
329
- ### convert CRs & to &#13;
330
- xml.gsub!(/\r/, '&#13;')
331
-
332
- ### send the data
333
- @cnx[rsrc].post xml, :content_type => 'text/xml', :accept => :json
334
- end #post_rsrc
335
-
336
- ### Delete a resource from the JSS
337
- ###
338
- ### @param rsrc[String] the resource to create, the URL part after 'JSSResource/'
339
- ###
340
- ### @return [String] the xml response from the server.
341
- ###
342
- def delete_rsrc(rsrc)
343
- raise JSS::InvalidConnectionError, "Not Connected. Use JSS::API.connect first." unless @connected
344
- raise MissingDataError, "Missing :rsrc" if rsrc.nil?
345
-
346
- ### delete the resource
347
- @cnx[rsrc].delete
348
-
349
- end #delete_rsrc
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
-
390
- ### aliases
391
- alias connected? connected
392
-
393
-
394
- end # class JSSAPIConnection
395
-
396
- ### The single instance of the APIConnection
397
- API = APIConnection.instance
398
-
399
-
400
- end # module