Class: Cisco::CommandReference
- Inherits:
-
Object
- Object
- Cisco::CommandReference
- Defined in:
- lib/cisco_node_utils/command_reference.rb
Overview
Builds reference hash for the platform specified in the product id.
Constant Summary collapse
- KNOWN_FILTERS =
%w(cli_nexus)- @@debug =
rubocop:disable Style/ClassVars
false
Instance Attribute Summary collapse
-
#cli ⇒ Object
readonly
Returns the value of attribute cli.
-
#files ⇒ Object
readonly
Returns the value of attribute files.
-
#platform ⇒ Object
readonly
Returns the value of attribute platform.
-
#product_id ⇒ Object
readonly
Returns the value of attribute product_id.
Class Method Summary collapse
- .debug=(value) ⇒ Object
-
.filter_hash(hash, platform: nil, product_id: nil, cli: false, allow_unknown_keys: true) ⇒ Object
Helper method Given a Hash of command reference data as read from YAML, does: - Filter out any API-specific data not applicable to this API - Filter any platform-specific data not applicable to this product_id Returns the filtered hash (possibly empty).
-
.hash_merge(input_hash, base_hash = nil) ⇒ Object
Helper method Given a suitably filtered Hash of command reference data, does: - Inherit data from the given base_hash (if any) and extend/override it with the given input data.
- .key_match(key, platform, product_id, cli) ⇒ Object
-
.value_append(base_value, new_value) ⇒ Object
Helper method.
Instance Method Summary collapse
-
#build_cmd_ref ⇒ Object
Build complete reference hash.
-
#debug(text) ⇒ Object
Print debug statements.
- #empty? ⇒ Boolean
- #filter_hash(input_hash) ⇒ Object
-
#initialize(product: nil, platform: nil, cli: false, files: nil) ⇒ CommandReference
constructor
Constructor.
-
#load_yaml(yaml_file) ⇒ Object
Read in yaml file.
-
#lookup(feature, name) ⇒ Object
Get the command reference.
- #to_s ⇒ Object
Constructor Details
#initialize(product: nil, platform: nil, cli: false, files: nil) ⇒ CommandReference
Constructor. Normal usage is to pass product, platform, cli, in which case usual YAML files will be located then the list will be filtered down to only those matching the given settings. For testing purposes (only!) you can pass an explicit list of files to load instead. This list will NOT be filtered further by product_id.
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
# File 'lib/cisco_node_utils/command_reference.rb', line 268 def initialize(product: nil, platform: nil, cli: false, files: nil) @product_id = product @platform = platform @cli = cli @hash = {} if files @files = files else @files = Dir.glob(__dir__ + '/cmd_ref/*.yaml') end build_cmd_ref end |
Instance Attribute Details
#cli ⇒ Object (readonly)
Returns the value of attribute cli.
260 261 262 |
# File 'lib/cisco_node_utils/command_reference.rb', line 260 def cli @cli end |
#files ⇒ Object (readonly)
Returns the value of attribute files.
260 261 262 |
# File 'lib/cisco_node_utils/command_reference.rb', line 260 def files @files end |
#platform ⇒ Object (readonly)
Returns the value of attribute platform.
260 261 262 |
# File 'lib/cisco_node_utils/command_reference.rb', line 260 def platform @platform end |
#product_id ⇒ Object (readonly)
Returns the value of attribute product_id.
260 261 262 |
# File 'lib/cisco_node_utils/command_reference.rb', line 260 def product_id @product_id end |
Class Method Details
.debug=(value) ⇒ Object
254 255 256 257 258 |
# File 'lib/cisco_node_utils/command_reference.rb', line 254 def self.debug=(value) fail ArgumentError, 'Debug must be boolean' unless value == true || value == false @@debug = value # rubocop:disable Style/ClassVars end |
.filter_hash(hash, platform: nil, product_id: nil, cli: false, allow_unknown_keys: true) ⇒ Object
Helper method Given a Hash of command reference data as read from YAML, does:
-
Filter out any API-specific data not applicable to this API
-
Filter any platform-specific data not applicable to this product_id
Returns the filtered hash (possibly empty)
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 |
# File 'lib/cisco_node_utils/command_reference.rb', line 361 def self.filter_hash(hash, platform: nil, product_id: nil, cli: false, allow_unknown_keys: true) result = {} exclude = hash.delete('_exclude') || [] exclude.each do |value| if key_match(value, platform, product_id, cli) == true debug 'Exclude this product (#{product_id}, #{value})' return result end end # to_inspect: sub-keys we want to recurse into to_inspect = [] # regexp_match: did we find a product_id regexp that matches? regexp_match = false hash.each do |key, value| if CmdRef.keys.include?(key) result[key] = value elsif key != 'else' match = key_match(key, platform, product_id, cli) next if match == false if match == :unknown fail "Unrecognized key '#{key}'" unless allow_unknown_keys end regexp_match = true if match == true to_inspect << key end end # If we didn't find any platform regexp match, # and an 'else' sub-hash is provided, descend into 'else' to_inspect << 'else' if hash.key?('else') && !regexp_match # Recurse! Sub-hashes can override the base hash to_inspect.each do |key| unless hash[key].is_a?(Hash) result[key] = hash[key] next end begin result[key] = filter_hash(hash[key], platform: platform, product_id: product_id, cli: cli, allow_unknown_keys: false) rescue RuntimeError => e raise "[#{key}]: #{e}" end end result end |
.hash_merge(input_hash, base_hash = nil) ⇒ Object
Helper method Given a suitably filtered Hash of command reference data, does:
-
Inherit data from the given base_hash (if any) and extend/override it with the given input data.
-
Append ‘config_set_append’ data to any existing ‘config_set’ data
-
Append ‘config_get_token_append’ data to ‘config_get_token’, ditto
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 |
# File 'lib/cisco_node_utils/command_reference.rb', line 429 def self.hash_merge(input_hash, base_hash=nil) result = base_hash result ||= {} # to_inspect: sub-hashes we want to recurse into to_inspect = [] input_hash.each do |key, value| if CmdRef.keys.include?(key) if key == 'config_set_append' result['config_set'] = value_append(result['config_set'], value) elsif key == 'config_get_token_append' result['config_get_token'] = value_append( result['config_get_token'], value) else result[key] = value end elsif value.is_a?(Hash) to_inspect << value else fail "Unexpected non-hash data: #{value}" end end # Recurse! Sub-hashes can override the base hash to_inspect.each do |hash| result = hash_merge(hash, result) end result end |
.key_match(key, platform, product_id, cli) ⇒ Object
344 345 346 347 348 349 350 351 352 353 354 |
# File 'lib/cisco_node_utils/command_reference.rb', line 344 def self.key_match(key, platform, product_id, cli) if key[0] == '/' && key[-1] == '/' # It's a product-id regexp. Does it match our given product_id? return Regexp.new(key[1..-2]) =~ product_id ? true : false elsif KNOWN_FILTERS.include?(key) return false if key.match(/cli/) && !cli return Regexp.new(platform.to_s) =~ key ? true : false else return :unknown end end |
.value_append(base_value, new_value) ⇒ Object
Helper method. Combines the two given values (either or both of which may be arrays) into a single combined array value_append(‘foo’, ‘bar’) ==> [‘foo’, ‘bar’] value_append(‘foo’, [‘bar’, ‘baz’]) ==> [‘foo’, ‘bar’, ‘baz’]
463 464 465 466 467 |
# File 'lib/cisco_node_utils/command_reference.rb', line 463 def self.value_append(base_value, new_value) base_value = [base_value] unless base_value.is_a?(Array) new_value = [new_value] unless new_value.is_a?(Array) base_value + new_value end |
Instance Method Details
#build_cmd_ref ⇒ Object
Build complete reference hash.
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 |
# File 'lib/cisco_node_utils/command_reference.rb', line 286 def build_cmd_ref # Example id's: N3K-C3048TP-1GE, N3K-C3064PQ-10GE, N7K-C7009, N7K-C7009 debug "Product: #{@product_id}" debug "Files being used: #{@files.join(', ')}" @files.each do |file| feature = File.basename(file).split('.')[0] debug "Processing file '#{file}' as feature '#{feature}'" feature_hash = load_yaml(file) if feature_hash.empty? debug "Feature #{feature} is empty" next end feature_hash = filter_hash(feature_hash) if feature_hash.empty? debug "Feature #{feature} is excluded" @hash[feature] = UnsupportedCmdRef.new(feature, nil, file) next end base_hash = {} if feature_hash.key?('_template') base_hash = CommandReference.hash_merge(feature_hash['_template']) end feature_hash.each do |name, value| fail "No entries under '#{name}' in '#{file}'" if value.nil? @hash[feature] ||= {} if value.empty? @hash[feature][name] = UnsupportedCmdRef.new(feature, name, file) else values = CommandReference.hash_merge(value, base_hash.clone) @hash[feature][name] = CmdRef.new(feature, name, values, file) end end end end |
#debug(text) ⇒ Object
Print debug statements
338 339 340 |
# File 'lib/cisco_node_utils/command_reference.rb', line 338 def debug(text) puts "DEBUG: #{text}" if @@debug end |
#empty? ⇒ Boolean
333 334 335 |
# File 'lib/cisco_node_utils/command_reference.rb', line 333 def empty? @hash.empty? end |
#filter_hash(input_hash) ⇒ Object
416 417 418 419 420 421 |
# File 'lib/cisco_node_utils/command_reference.rb', line 416 def filter_hash(input_hash) CommandReference.filter_hash(input_hash, platform: platform, product_id: product_id, cli: cli) end |
#load_yaml(yaml_file) ⇒ Object
Read in yaml file. The expectation is that a file corresponds to a feature
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 |
# File 'lib/cisco_node_utils/command_reference.rb', line 561 def load_yaml(yaml_file) fail "File #{yaml_file} doesn't exist." unless File.exist?(yaml_file) # Parse YAML file into a tree of nodes # Psych::SyntaxError doesn't inherit from StandardError in some versions, # so we want to explicitly catch it if using Psych. rescue_errors = [::StandardError, ::Psych::SyntaxError] yaml_parsed = File.open(yaml_file, 'r') do |f| begin YAML.parse(f) rescue *rescue_errors => e raise "unable to parse #{yaml_file}: #{e}" end end return {} unless yaml_parsed # Validate the node tree validate_yaml(yaml_parsed, yaml_file) # If validation passed, convert the node tree to a Ruby Hash. yaml_parsed.transform end |
#lookup(feature, name) ⇒ Object
Get the command reference
326 327 328 329 330 331 |
# File 'lib/cisco_node_utils/command_reference.rb', line 326 def lookup(feature, name) value = @hash[feature] value = value[name] if value.is_a? Hash fail IndexError, "No CmdRef defined for #{feature}, #{name}" if value.nil? value end |
#to_s ⇒ Object
581 582 583 |
# File 'lib/cisco_node_utils/command_reference.rb', line 581 def to_s @hash.each_value { |names| names.each_value(&:to_s) } end |