ruby-jss 0.6.7 → 0.7.0

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.

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