ruby-jss 0.6.7 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of ruby-jss might be problematic. Click here for more details.

@@ -217,7 +217,7 @@ module JSS
217
217
  ### it'll have to be re-connected before using again
218
218
  ###
219
219
  def disconnect
220
- @mysql.close if @mysql.protocol
220
+ @mysql.close! if @mysql.protocol
221
221
  @server = nil
222
222
  @port = nil
223
223
  @socket = nil
@@ -1,33 +1,33 @@
1
1
  ### Copyright 2017 Pixar
2
2
 
3
- ###
3
+ ###
4
4
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
5
5
  ### with the following modification; you may not use this file except in
6
6
  ### compliance with the Apache License and the following modification to it:
7
7
  ### Section 6. Trademarks. is deleted and replaced with:
8
- ###
8
+ ###
9
9
  ### 6. Trademarks. This License does not grant permission to use the trade
10
10
  ### names, trademarks, service marks, or product names of the Licensor
11
11
  ### and its affiliates, except as required to comply with Section 4(c) of
12
12
  ### the License and to reproduce the content of the NOTICE file.
13
- ###
13
+ ###
14
14
  ### You may obtain a copy of the Apache License at
15
- ###
15
+ ###
16
16
  ### http://www.apache.org/licenses/LICENSE-2.0
17
- ###
17
+ ###
18
18
  ### Unless required by applicable law or agreed to in writing, software
19
19
  ### distributed under the Apache License with the above modification is
20
20
  ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21
21
  ### KIND, either express or implied. See the Apache License for the specific
22
22
  ### language governing permissions and limitations under the Apache License.
23
- ###
23
+ ###
24
24
  ###
25
25
 
26
26
  ############################################
27
27
  ### A few augmentations to IPAddr handling.
28
28
  ###
29
29
  class IPAddr
30
-
30
+
31
31
  ### Convert starting and ending IPv4 IP addresses (either Strings or IPAddrs)
32
32
  ### into a single masked IPv4 IPAddr
33
33
  ###
@@ -43,7 +43,7 @@ class IPAddr
43
43
  def self.jss_masked_v4addr(starting,ending)
44
44
  IPAddr.new "#{starting}/#{self.jss_cidr_from_ends(starting,ending)}"
45
45
  end #self.jss_masked_v4addr(starting,ending)
46
-
46
+
47
47
  ### Given starting and ending IPv4 IP addresses (either Strings or IPAddrs)
48
48
  ### return the CIDR notation routing prefix mask
49
49
  ###
@@ -57,22 +57,22 @@ class IPAddr
57
57
  ### IPAddr.jss_cidr_from_ends '10.0.0.0', '10.0.0.255' # => 24
58
58
  ###
59
59
  def self.jss_cidr_from_ends(starting,ending)
60
-
60
+
61
61
  starting = IPAddr.new(starting) unless starting.kind_of? IPAddr
62
62
  ending = IPAddr.new(ending) unless ending.kind_of? IPAddr
63
-
63
+
64
64
  ### how many possible addresses in the range?
65
65
  num_addrs = ending.to_i - starting.to_i + 1
66
-
67
- ### convert the number of possible addresses to
66
+
67
+ ### convert the number of possible addresses to
68
68
  ### binary then subtract the number of bits from
69
- ### the full length of an IPv4 addr
69
+ ### the full length of an IPv4 addr
70
70
  ### (32 bits) and that gives the CIDR prefix
71
71
  return 32 - num_addrs.to_s(2).length + 1
72
-
72
+
73
73
  end #self.get_cidr(starting,ending)
74
74
 
75
- ### Convert a starting address (either String or IPAddr) and a
75
+ ### Convert a starting address (either String or IPAddr) and a
76
76
  ### CIDR notation routing prefix mask into the IPv4 address
77
77
  ### of at the end of the range of addresses.
78
78
  ###
@@ -88,5 +88,5 @@ class IPAddr
88
88
  def self.jss_ending_address(starting, cidr)
89
89
  IPAddr.new( "#{starting}/#{cidr}").to_range.max
90
90
  end # ending_address
91
-
91
+
92
92
  end # Class IPAddr
@@ -27,6 +27,6 @@
27
27
  module JSS
28
28
 
29
29
  ### The version of the JSS ruby gem
30
- VERSION = '0.6.7'.freeze
30
+ VERSION = '0.7.0'.freeze
31
31
 
32
32
  end # module
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-jss
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.7
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Lasell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-04 00:00:00.000000000 Z
11
+ date: 2017-02-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: plist
@@ -87,7 +87,8 @@ description: |2
87
87
  email: ruby-jss@pixar.com
88
88
  executables:
89
89
  - cgrouper
90
- - subnet-update
90
+ - netseg-update
91
+ - jss-webhook-server
91
92
  extensions: []
92
93
  extra_rdoc_files:
93
94
  - README.md
@@ -101,7 +102,8 @@ files:
101
102
  - README.md
102
103
  - THANKS.md
103
104
  - bin/cgrouper
104
- - bin/subnet-update
105
+ - bin/jss-webhook-server
106
+ - bin/netseg-update
105
107
  - data/ruby-jss.conf.example
106
108
  - lib/jss-api.rb
107
109
  - lib/jss.rb
@@ -1,401 +0,0 @@
1
- #!/usr/bin/ruby
2
-
3
- ### Copyright 2017 Pixar
4
-
5
- ###
6
- ### Licensed under the Apache License, Version 2.0 (the "Apache License")
7
- ### with the following modification; you may not use this file except in
8
- ### compliance with the Apache License and the following modification to it:
9
- ### Section 6. Trademarks. is deleted and replaced with:
10
- ###
11
- ### 6. Trademarks. This License does not grant permission to use the trade
12
- ### names, trademarks, service marks, or product names of the Licensor
13
- ### and its affiliates, except as required to comply with Section 4(c) of
14
- ### the License and to reproduce the content of the NOTICE file.
15
- ###
16
- ### You may obtain a copy of the Apache License at
17
- ###
18
- ### http://www.apache.org/licenses/LICENSE-2.0
19
- ###
20
- ### Unless required by applicable law or agreed to in writing, software
21
- ### distributed under the Apache License with the above modification is
22
- ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
23
- ### KIND, either express or implied. See the Apache License for the specific
24
- ### language governing permissions and limitations under the Apache License.
25
-
26
- ##############################
27
- # == Synopsis
28
- # Add, remove, or change the Network Segments in the JSS based on data from an input file
29
- # in CSV, tab, or other delimited format.
30
- #
31
- # == Usage
32
- # subnet-update [-t | -d delimiter] [-h] file
33
- #
34
- #
35
- # == Author
36
- # Chris Lasell <chrisl@pixar.com>
37
- #
38
- # == Copyright
39
- # Copyright (c) 2014 Pixar Animation Studios
40
-
41
- ##############################
42
- # Libraries
43
- require 'jss-api'
44
- require 'getoptlong'
45
-
46
- ##############################
47
- # The app object
48
- class App
49
-
50
- ##############################
51
- # Constants
52
-
53
- USAGE = "Usage: #{File.basename($0)} [-d delim] [--header] [-c col1,col2,col3 ] [-m manual-prefix] [--help] /path/to/file"
54
-
55
- POTENTIAL_COLUMNS = [:name, :starting, :ending, :cidr]
56
-
57
- # Whenever we process a file, we store it here. The next time we
58
- # run, if the input file is identical to this, we exit witout doing anything.
59
- DEFAULT_CACHE_FILE = Pathname.new("~/.last_subnet_update").expand_path
60
-
61
- DEFAULT_DELIMITER = "\t"
62
- DEFAULT_COLUMNS = [:name, :starting, :ending]
63
- DEFAULT_MANUAL_PREFIX = "Manual-"
64
-
65
-
66
- attr_reader :debug
67
-
68
- ###############
69
- # set up
70
- def initialize(args)
71
-
72
- # set defaults
73
- @debug = false
74
-
75
- @delim = DEFAULT_DELIMITER
76
- @header = false
77
- @columns = DEFAULT_COLUMNS
78
- @cache_file = DEFAULT_CACHE_FILE
79
- @manual_prefix = DEFAULT_MANUAL_PREFIX
80
-
81
-
82
- #define the cli opts
83
- cli_opts = GetoptLong.new(
84
- [ '--help', '-H', GetoptLong::NO_ARGUMENT ],
85
- [ '--delimiter', '--delim', '-d', GetoptLong::REQUIRED_ARGUMENT],
86
- [ '--header', '-h', GetoptLong::NO_ARGUMENT],
87
- [ '--columns', '-c', GetoptLong::OPTIONAL_ARGUMENT],
88
- [ '--manual-prefix', '-m', GetoptLong::OPTIONAL_ARGUMENT],
89
- [ '--cache', GetoptLong::REQUIRED_ARGUMENT ],
90
- [ '--debug', GetoptLong::NO_ARGUMENT],
91
- [ '--server', '-S', GetoptLong::OPTIONAL_ARGUMENT],
92
- [ '--port', '-P', GetoptLong::OPTIONAL_ARGUMENT],
93
- [ '--user', '-U', GetoptLong::OPTIONAL_ARGUMENT],
94
- [ '--no-verify-cert', '-V', GetoptLong::NO_ARGUMENT],
95
- [ '--timeout', '-T', GetoptLong::OPTIONAL_ARGUMENT]
96
- )
97
-
98
- # parse the cli opts
99
- cli_opts.each do |opt, arg|
100
- case opt
101
- when '--help' then show_help
102
- when '--delimiter' then @delim = arg
103
- when '--header' then @header = true
104
- when '--columns' then @columns = arg.split(',').map{|c| c.to_sym}
105
- when '--manual-prefix' then @manual_prefix = arg
106
- when '--cache' then @cache_file = Pathname.new arg
107
- when '--debug' then @debug = true
108
- when '--server'
109
- @server = arg
110
-
111
- when '--port'
112
- @port = arg
113
-
114
- when '--user'
115
- @user = arg
116
-
117
- when '--no-verify-cert'
118
- @verify_cert = false
119
-
120
- when '--timeout'
121
- @timeout = arg
122
-
123
- end # case
124
- end # each opt arg
125
-
126
-
127
- @columns = nil if @columns and @columns.empty?
128
-
129
- @file = args.shift
130
-
131
-
132
- end # init
133
-
134
- ###############
135
- # Go!
136
- def run
137
-
138
- unless @file
139
- puts "No input file specified."
140
- puts USAGE
141
- return
142
- end
143
-
144
- @file = Pathname.new @file
145
-
146
- unless parse_file
147
- puts "File hasn't changed since last time, no changes to make!"
148
- return
149
- end
150
-
151
- # use any config settings defined....
152
- @user ||= JSS::CONFIG.api_username
153
- @server ||= JSS::CONFIG.api_server_name
154
- @getpass = $stdin.tty? ? :prompt : :stdin
155
-
156
- raise JSS::MissingDataError, "No JSS Username provided or found in the JSS gem config." unless @user
157
- raise JSS::MissingDataError, "No JSS Server provided or found in the JSS gem config." unless @server
158
-
159
- JSS::API.connect( :server => @server,
160
- :port => @port,
161
- :verify_cert => @verify_cert,
162
- :user => @user,
163
- :pw => @getpass,
164
- :stdin_line => 1,
165
- :timeout => @timeout
166
- )
167
-
168
- update_network_segments
169
-
170
- end # run
171
-
172
- #####################################
173
- ###
174
- ### Show Help
175
- ###
176
- def show_help
177
- puts <<-FULLHELP
178
- Update the JSS Network Segments from a delimited file of subnet information.
179
-
180
- #{USAGE}
181
-
182
- Options:
183
- -d, --delimiter - The field delimiter in the file, defaults to tab.
184
- -c, --columns [col1,col2,col3]
185
- - The column order in file, must include 'name', 'starting',
186
- and either 'ending' or 'cidr'
187
- -h, --header - The first line of the file is a header line,
188
- possibly defining the columns
189
- -m, --manual-prefix - Network Segment names in the JSS with this prefix are ignored.
190
- Defaults to 'Manual-'
191
- --cache /path/.. - Where read/save the input data for comparison between runs.
192
- Defaults to ~/.last_subnet_update
193
- -S, --server srvr - specify the JSS API server name
194
- -P, --port portnum - specify the JSS API port
195
- -U, --user username - specify the JSS API user
196
- -V, --no-verify-cert - Allow self-signed, unverified SSL certificate
197
- -T, --timeout secs - specify the JSS API timeout
198
- -H, --help - show this help
199
- --debug - show the ruby backtrace when errors occur
200
-
201
- This program parses the input file line by line (possibly accounting for a header line).
202
- Each line defines the name and IP-range of a subnet/network segment.
203
-
204
- - If a segment doesn't exist in the JSS, it is created.
205
- - If a segment's range has changed, it is updated in the JSS.
206
- - If a JSS segment doesn't exist in the file, it is deleted from the JSS
207
- unless its name starts with the --manual-prefix
208
-
209
- Input File:
210
- - The file must contain three columns, separated by the --delimiter,
211
- with these names, in any order:
212
- - 'name' (the network segment name)
213
- - 'starting' (the starting IP address of the network segment)
214
- - EITHER of:
215
- - 'ending' (the ending IP address of the network segment)
216
- - 'cidr' (the network range of the segment as a CIDR bitmask, e.g. '24')
217
- Notes:
218
- - The --columns option is a comma-separted list of the three
219
- column names aboveindicating the column-order in the file.
220
-
221
- - If --columns are not provided, and --header is specified, the first line
222
- is assumed to contain the column names, separated by the delimiter
223
-
224
- - If --header is provided with --columns, the first line of the file is ignored.
225
-
226
- - The raw data from the file is cached and compared to the input file at
227
- the next run. If the data is identical, no JSS connection is made.
228
-
229
- - If no API settings are provided, they will be read from /etc/jss_gem.conf
230
- and ~/.jss_gem.conf. See the JSS Gem docs for details.
231
-
232
- - The password for the connection will be read from STDIN or prompted if needed
233
-
234
- FULLHELP
235
- exit 0
236
- end
237
-
238
- ########################
239
- # parse the incoming data file.
240
- # If the file hasn't changed from the last time we processed it
241
- # then return false
242
- # otherwise parse it into @parsed_data and return true
243
- # @parsed_data is an array of hashes, each with :name, :starting, and :ending
244
- #
245
- def parse_file
246
-
247
- raise "'#{@file}' is not readable, or not a regular file" unless @file.readable? and @file.file?
248
-
249
- # read in the file
250
- @raw_data = @file.read
251
-
252
- # compare it to the one we used last time
253
- if @cache_file.readable?
254
- return false if @raw_data == @cache_file.read
255
- end
256
-
257
- # split the data into an array by newlines
258
- lines = @raw_data.split "\n"
259
-
260
- # remove the first line if its a header, and parse it into the columns
261
- # if needed
262
- if @header
263
- header = lines.shift
264
- @columns ||= header.split(/\s*#{@delim}\s*/).map{|c| c.to_sym}
265
- end
266
-
267
- # check some state
268
- raise "Columns must include 'name' and 'starting'" unless @columns.include?(:name) and @columns.include?(:starting)
269
- raise "Columns must include either 'ending' or 'cidr'" unless @columns.include?(:ending) or @columns.include?(:cidr)
270
-
271
- @use_cidr = @columns.include? :cidr
272
-
273
-
274
- # which columns are which in the file?
275
- name = @columns.index :name
276
- starting = @columns.index :starting
277
- ending = @use_cidr ? @columns.index(:cidr) : @columns.index(:ending)
278
-
279
- # split each line and convert it into a hash
280
- @parsed_data = lines.map do |line|
281
-
282
- parts = line.split(@delim).map{|f| f.strip }
283
-
284
- unless parts[name] and parts[starting] and parts[ending]
285
- puts "Skipping invalid line: #{line}"
286
- next
287
- end
288
-
289
-
290
- {:name => parts[name], :starting => parts[starting], :ending => parts[ending]}
291
- end
292
-
293
- # parsed data is now an array of hashes
294
- return true
295
- end
296
-
297
- #############################################
298
- #############################################
299
- # Update the JSS Network Segments from GIT_NETBLOCKS_URL, q.v.
300
- def update_network_segments
301
-
302
- # CREATE any that are in the parsed data but not yet in the JSS,
303
- # and UPDATE any that exist but have modified ranges.
304
- # While looping through, make a hash of JSS::NetworkSegment objects, keyed by their name.
305
- segs_from_data = {}
306
-
307
- @parsed_data.each do |pd|
308
-
309
- # skip anthing with the manual prefix
310
- next if pd[:name].start_with? @manual_prefix
311
-
312
- ender = @use_cidr ? :cidr : :ending_address
313
-
314
- begin
315
- this_seg = JSS::NetworkSegment.new(:id => :new, :name => pd[:name], :starting_address => pd[:starting], ender => pd[:ending])
316
-
317
- # If the new netsegment should have other settings (dist. point, netboot server, etc...)
318
- # here's where you should apply those settings.
319
-
320
- this_seg.create
321
- puts "Added Network Segment '#{this_seg.name}' to the JSS"
322
-
323
- # it already exists, so see if it needs any changes
324
- rescue JSS::AlreadyExistsError
325
-
326
- # there's already one with this name, so just grab it.
327
- this_seg = JSS::NetworkSegment.new( :name => pd[:name])
328
-
329
- # does the startng addres need to be changed?
330
- needs_update = this_seg.starting_address.to_s != pd[:starting].to_s
331
-
332
- # even if we don't need to update the starting, we might need to update
333
- # the ending...
334
- unless needs_update
335
- if @use_cidr
336
- needs_update = this_seg.cidr.to_i != pd[:ending].to_i
337
- else
338
- needs_update = this_seg.ending_address.to_s != pd[:ending].to_s
339
- end # if @use_cidr
340
- end #unless needs update
341
-
342
- # did we decide we need an update?
343
- if needs_update
344
- this_seg.starting_address = pd[:starting]
345
- if @use_cidr
346
- this_seg.cidr = pd[:ending].to_i
347
- else
348
- this_seg.ending_address = pd[:ending]
349
- end # if @use_cidr
350
- this_seg.update
351
- puts "Updated IP range for Network Segment '#{this_seg.name}'"
352
-
353
- else # doesn't need update
354
- puts "Network Segment '#{this_seg.name}' doesn't have any changes."
355
- end # if needs update
356
-
357
- # rescue other errors
358
- rescue
359
- raise "There was an error with NetworkSegment #{pd[:name]}: #{$!}"
360
- end # begin
361
-
362
- segs_from_data[this_seg.name] = this_seg
363
- end
364
-
365
-
366
- # DELETE those in jss, but not in parsed data,
367
- # unless the name starts with @manual_prefix
368
- JSS::NetworkSegment.map_all_ids_to(:name).each do |id,name|
369
-
370
- next if name.start_with? @manual_prefix
371
-
372
- unless segs_from_data.keys.include? name
373
- JSS::NetworkSegment.new(:id => id).delete
374
- puts "Deleted Network Segment '#{name}' from the JSS"
375
- end # unless
376
-
377
- end # jss_uids.each seg
378
-
379
- # save the data into a file for comparison next time
380
- @cache_file.jss_save @raw_data
381
-
382
- # all done
383
- return true
384
- end # update_network_segments
385
-
386
- end # app
387
-
388
- ##############################
389
- # create the app and go
390
- begin
391
- app = App.new(ARGV)
392
- app.run
393
- rescue
394
- # handle exceptions not handled elsewhere
395
- puts "An error occurred: #{$!}"
396
- puts "Backtrace:" if app.debug
397
- puts $@ if app.debug
398
-
399
- ensure
400
-
401
- end