Class: Cisco::Utils
- Inherits:
-
Object
- Object
- Cisco::Utils
- Defined in:
- lib/cisco_node_utils/cisco_cmn_utils.rb
Overview
General utility class
Class Method Summary collapse
-
.add_quotes(value) ⇒ Object
merge_range.
-
.array_to_str(array, sort = true) ⇒ Object
This method converts an array to string form for ex: if the array has 1, 2 to 10, 83 to 2014, 3022 and the string will be “1,2-10,83-2014,3022”.
-
.attach_prefix(val, prop, prefix = nil) ⇒ Object
This method is used in config_set for CLIs which can set multiple properties using the same CLI.
- .bitmask_to_length(bitmask) ⇒ Object
- .chassis_pid?(ver_regexp) ⇒ Boolean
-
.dash_range_to_elements(range) ⇒ Object
Convert a dash-range set into individual elements.
-
.dash_range_to_ruby_range(range) ⇒ Object
Convert a cli-dash-syntax range to ruby-range.
- .delta_add_remove(should, current = [], opt = nil) ⇒ Object
-
.depth(a) ⇒ Object
Helper to build a hash of add/remove commands for a nested array.
-
.extract_value(match_method, prop, prefix = nil) ⇒ Object
This method is used in config_get for CLIs which have multiple properties in the same output Given a match_method which defines regex pattern and the match criteria, this method, extracts the value of a property with or without a prefix.
- .fretta? ⇒ Boolean
-
.get_reset_range(total_range, remove_ranges) ⇒ Object
For spanning tree range based parameters, the range is very dynamic and so before the parameters are set, the rest of the range needs to be reset For ex: if the ranges 2-42 and 83-200 are getting set, and the total range of the given parameter is 1-4000 then 1,43-82,201-4000 needs to be reset.
- .image_version?(ver_regexp) ⇒ Boolean
-
.length_to_bitmask(length) ⇒ Object
delta_add_remove.
-
.merge_range(range) ⇒ Object
Merge overlapping ranges.
-
.nexus_i2_image ⇒ Object
Helper utility to check for older Nexus I2 images.
-
.normalize_intf_pattern(show_name) ⇒ Object
Helper utility to normalize the interface name pattern to be filtered.
-
.normalize_range_array(range, fmt = :array) ⇒ Object
normalize_range_array.
-
.process_network_mask(network) ⇒ Object
Helper utility method for ip/prefix format networks.
-
.ruby_range_to_dash_range(range, type = :array) ⇒ Object
Convert a ruby-range to cli-dash-syntax.
-
.zero_pad_macaddr(mac) ⇒ Object
Helper to 0-pad a mac address.
Class Method Details
.add_quotes(value) ⇒ Object
merge_range
372 373 374 375 376 377 |
# File 'lib/cisco_node_utils/cisco_cmn_utils.rb', line 372 def self.add_quotes(value) return value if image_version?(/7.3.[0-1]/) || value.nil? value = "'#{value}'" unless value.start_with?('"', "'") && value.end_with?('"', "'") value end |
.array_to_str(array, sort = true) ⇒ Object
This method converts an array to string form for ex: if the array has 1, 2 to 10, 83 to 2014, 3022 and the string will be “1,2-10,83-2014,3022”
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 |
# File 'lib/cisco_node_utils/cisco_cmn_utils.rb', line 220 def self.array_to_str(array, sort=true) farray = sort ? array.compact.uniq.sort : array.compact lranges = [] unless farray.empty? l = array.first r = nil farray.each do |aelem| if r && aelem != r.succ if l == r lranges << l else lranges << Range.new(l, r) end l = aelem end r = aelem end if l == r lranges << l else lranges << Range.new(l, r) end end lranges.to_s.gsub('..', '-').delete('[').delete(']').delete(' ') end |
.attach_prefix(val, prop, prefix = nil) ⇒ Object
This method is used in config_set for CLIs which can set multiple properties using the same CLI. This method attaches prefix to the given property when the prefix is different from the property name else it attaches property name itself. It also appends the value to be set. For ex. if the set_value is <precedence> <time_range> the prop for precedence could be ‘precedence’, and for time_range, the prop and prefix could be ‘time_range’ and ‘time-range’
414 415 416 417 |
# File 'lib/cisco_node_utils/cisco_cmn_utils.rb', line 414 def self.attach_prefix(val, prop, prefix=nil) prefix = prop.to_s if prefix.nil? val.to_s.empty? ? val : "#{prefix} #{val}" end |
.bitmask_to_length(bitmask) ⇒ Object
172 173 174 175 176 177 178 |
# File 'lib/cisco_node_utils/cisco_cmn_utils.rb', line 172 def self.bitmask_to_length(bitmask) # Convert bitmask to a 32-bit integer, # convert that to binary, and count the 1s IPAddr.new(bitmask).to_i.to_s(2).count('1') rescue IPAddr::InvalidAddressError => e raise ArgumentError, "bitmask '#{bitmask}' is not valid: #{e}" end |
.chassis_pid?(ver_regexp) ⇒ Boolean
111 112 113 114 |
# File 'lib/cisco_node_utils/cisco_cmn_utils.rb', line 111 def self.chassis_pid?(ver_regexp) require_relative 'platform' return true if Platform.chassis['pid'][ver_regexp] end |
.dash_range_to_elements(range) ⇒ Object
Convert a dash-range set into individual elements. This is useful for preparing inputs to delta_add_remove().
Inputs an array or string of dash-ranges:
["2-5", "9", "4-6"] or '2-5, 9, 4-6' or ['2-5, 9, 4-6']
Returns an array of range elements:
["2", "3", "4", "5", "6", "9"]
336 337 338 339 340 341 342 343 344 345 346 347 348 |
# File 'lib/cisco_node_utils/cisco_cmn_utils.rb', line 336 def self.dash_range_to_elements(range) return [] if range.nil? range = range.shift if range.is_a?(Array) && range.length == 1 range = range.split(',') if range.is_a?(String) final = [] range = dash_range_to_ruby_range(range) range.each do |rng| # 2..5 maps to ["2", "3", "4", "5"] final << rng.map(&:to_s) end final.flatten.uniq.sort end |
.dash_range_to_ruby_range(range) ⇒ Object
Convert a cli-dash-syntax range to ruby-range. This is useful for preparing inputs to merge_range().
Inputs an array or string of dash-syntax ranges -> returns an array of ruby ranges.
Accepts an array or string: [“2-5”, “9”, “4-6”] or ‘2-5, 9, 4-6’ Returns an array of ranges: [2..5, 9..9, 4..6]
290 291 292 293 294 295 296 297 298 299 300 301 302 |
# File 'lib/cisco_node_utils/cisco_cmn_utils.rb', line 290 def self.dash_range_to_ruby_range(range) range = range.split(',') if range.is_a?(String) range.map! do |rng| if rng[/-/] # '2-5' -> 2..5 rng.split('-').inject { |a, e| a.to_i..e.to_i } else # '9' -> 9..9 rng.to_i..rng.to_i end end range end |
.delta_add_remove(should, current = [], opt = nil) ⇒ Object
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/cisco_node_utils/cisco_cmn_utils.rb', line 144 def self.delta_add_remove(should, current=[], opt=nil) current = [] if current.nil? should = [] if should.nil? # Remove nil entries from array should.each(&:compact!) if depth(should) > 1 delta = { add: should - current, remove: current - should } # Some cli properties cannot be updated, thus must be removed first return delta if opt == :updates_not_allowed # Delete entries from :remove if f1 is an update to an existing command delta[:add].each do |id, _| # Differentiate between comparing nested and unnested arrays by # checking the depth of the array. if depth(should) == 1 delta[:remove].delete_if { |f1| [f1] if f1.to_s == id.to_s } else delta[:remove].delete_if { |f1, f2| [f1, f2] if f1.to_s == id.to_s } end end delta end |
.depth(a) ⇒ Object
Helper to build a hash of add/remove commands for a nested array. Useful for network, redistribute, etc.
should: an array of expected cmds (manifest/recipe)
current: an array of existing cmds on the device
139 140 141 142 |
# File 'lib/cisco_node_utils/cisco_cmn_utils.rb', line 139 def self.depth(a) return 0 unless a.is_a?(Array) 1 + depth(a[0]) end |
.extract_value(match_method, prop, prefix = nil) ⇒ Object
This method is used in config_get for CLIs which have multiple properties in the same output Given a match_method which defines regex pattern and the match criteria, this method, extracts the value of a property with or without a prefix. For ex. if the regex pattern is something like: (?<action>S+)? the property to extract is action and prefix is nil for (?<src_port>range S+) the property to extract is src_port and prefix is range
389 390 391 392 393 394 395 396 397 398 399 400 401 402 |
# File 'lib/cisco_node_utils/cisco_cmn_utils.rb', line 389 def self.extract_value(match_method, prop, prefix=nil) prefix = prop if prefix.nil? mm = match_method return nil if mm.nil? return nil unless mm.names.include?(prop) # extract and return value that follows prefix + <space> regexp = Regexp.new("#{Regexp.escape(prefix)} (?<extracted>.*)") value_match = regexp.match(mm[prop]) return nil if value_match.nil? value_match[:extracted] end |
.fretta? ⇒ Boolean
116 117 118 119 120 121 122 |
# File 'lib/cisco_node_utils/cisco_cmn_utils.rb', line 116 def self.fretta? require_relative 'platform' Platform.slots.each do |_x, row| return true if row['pid'][/-R/] end false end |
.get_reset_range(total_range, remove_ranges) ⇒ Object
For spanning tree range based parameters, the range is very dynamic and so before the parameters are set, the rest of the range needs to be reset For ex: if the ranges 2-42 and 83-200 are getting set, and the total range of the given parameter is 1-4000 then 1,43-82,201-4000 needs to be reset. This method takes the set ranges and gives back the range to be reset
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/cisco_node_utils/cisco_cmn_utils.rb', line 194 def self.get_reset_range(total_range, remove_ranges) fail 'invalid range' unless total_range.include?('-') return total_range if remove_ranges.empty? trs = total_range.gsub('-', '..') tra = trs.split('..').map { |d| Integer(d) } tr = tra[0]..tra[1] tarray = tr.to_a remove_ranges.each do |rr, _val| rarray = rr.gsub('-', '..').split(',') rarray.each do |elem| if elem.include?('..') elema = elem.split('..').map { |d| Integer(d) } ele = elema[0]..elema[1] tarray -= ele.to_a else tarray.delete(elem.to_i) end end end Utils.array_to_str(tarray) end |
.image_version?(ver_regexp) ⇒ Boolean
106 107 108 109 |
# File 'lib/cisco_node_utils/cisco_cmn_utils.rb', line 106 def self.image_version?(ver_regexp) require_relative 'platform' return true if Platform.image_version[ver_regexp] end |
.length_to_bitmask(length) ⇒ Object
delta_add_remove
168 169 170 |
# File 'lib/cisco_node_utils/cisco_cmn_utils.rb', line 168 def self.length_to_bitmask(length) IPAddr.new('255.255.255.255').mask(length).to_s end |
.merge_range(range) ⇒ Object
Merge overlapping ranges.
Inputs an array of ruby ranges: [2..5, 9..9, 4..6] Returns an array of merged ruby ranges: [2..6, 9..9]
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 |
# File 'lib/cisco_node_utils/cisco_cmn_utils.rb', line 355 def self.merge_range(range) # sort to lowest range 'first' values: # [2..5, 9..9, 4..6] -> [2..5, 4..6, 9..9] range = range.sort_by(&:first) *merged = range.shift range.each do |r| lastr = merged[-1] if lastr.last >= r.first - 1 merged[-1] = lastr.first..[r.last, lastr.last].max else merged.push(r) end end merged end |
.nexus_i2_image ⇒ Object
Helper utility to check for older Nexus I2 images
101 102 103 104 |
# File 'lib/cisco_node_utils/cisco_cmn_utils.rb', line 101 def self.nexus_i2_image require_relative 'platform' true if Platform.image_version[/7.0.3.I2/] end |
.normalize_intf_pattern(show_name) ⇒ Object
Helper utility to normalize the interface name pattern to be filtered. This is only a problem on N7k which has to use a section filter due to a show run int bug (no ‘all’ keyword for some interfaces).
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 |
# File 'lib/cisco_node_utils/cisco_cmn_utils.rb', line 422 def self.normalize_intf_pattern(show_name) return '' if show_name.nil? || show_name.empty? require_relative 'platform' return show_name unless Platform.hardware_type[/Nexus7/] return show_name if show_name[-1] == '$' # already normalized pat = show_name.downcase + '$' case pat when /ethernet/ pat.sub!(/ethernet/, 'Ethernet') when /loopback/ pat.sub!(/loopback/, 'loopback') when /port-channel/ pat.sub!(/port-channel/, 'port-channel') when /vlan/ pat.sub!(/vlan/, 'Vlan') else # wildcard the first char of the name pat.sub!(/./, '.') end pat end |
.normalize_range_array(range, fmt = :array) ⇒ Object
normalize_range_array
Given a list of ranges, merge any overlapping ranges and sort them.
Note: The ranges are converted to ruby ranges for easy merging, then converted back to a cli-syntax range.
Accepts an array or string:
["2-5", "9", "4-6"] -or- '2-5, 9, 4-6' -or- ["2-5, 9, 4-6"]
Returns a merged and ordered range as an array or string:
["2-6", "9"] -or- '2-6,9'
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
# File 'lib/cisco_node_utils/cisco_cmn_utils.rb', line 258 def self.normalize_range_array(range, fmt=:array) return range if range.nil? || range.empty? range = range.clone # Handle string within an array: ["2-5, 9, 4-6"] to '2-5, 9, 4-6' range = range.shift if range.is_a?(Array) && range.length == 1 # Handle string only: '2-5, 9, 4-6' to ["2-5", "9", "4-6"] range = range.split(',') if range.is_a?(String) # Convert to ruby-syntax ranges range = dash_range_to_ruby_range(range) # Sort & Merge merged = merge_range(range) # Convert back to cli dash-syntax merged_array = ruby_range_to_dash_range(merged) return merged_array.join(',') if fmt == :string merged_array end |
.process_network_mask(network) ⇒ Object
Helper utility method for ip/prefix format networks. For ip/prefix format ‘1.1.1.1/24’ or ‘2000:123:38::34/64’, we need to mask the address using the prefix length so that they are converted to ‘1.1.1.0/24’ or ‘2000:123:38::/64’
128 129 130 131 132 133 |
# File 'lib/cisco_node_utils/cisco_cmn_utils.rb', line 128 def self.process_network_mask(network) mask = network.split('/')[1] address = IPAddr.new(network).to_s network = address + '/' + mask unless mask.nil? network end |
.ruby_range_to_dash_range(range, type = :array) ⇒ Object
Convert a ruby-range to cli-dash-syntax.
Inputs an array of ruby ranges -> returns an array or string of dash-syntax ranges.
when (:array) [2..6, 9..9] -> [‘2-6’, ‘9’]
when (:string) [2..6, 9..9] -> ‘2-6, 9’
313 314 315 316 317 318 319 320 321 322 323 324 325 326 |
# File 'lib/cisco_node_utils/cisco_cmn_utils.rb', line 313 def self.ruby_range_to_dash_range(range, type=:array) fail unless range.is_a?(Array) range.map! do |r| if r.first == r.last # 9..9 -> '9' r.first.to_s else # 2..6 -> '2-6' r.first.to_s + '-' + r.last.to_s end end return range.join(', ') if type == :string range end |
.zero_pad_macaddr(mac) ⇒ Object
Helper to 0-pad a mac address.
181 182 183 184 185 |
# File 'lib/cisco_node_utils/cisco_cmn_utils.rb', line 181 def self.zero_pad_macaddr(mac) return nil if mac.nil? || mac.empty? o1, o2, o3 = mac.split('.').map { |o| o.to_i(16).to_s(10) } sprintf('%04x.%04x.%04x', o1, o2, o3) end |