Class: Cisco::Node

Inherits:
Object
  • Object
show all
Includes:
Singleton
Defined in:
lib/cisco_node_utils/node.rb

Overview

class Cisco::Node Singleton representing the network node (switch/router) that is running this code. The singleton is lazily instantiated, meaning that it doesn’t exist until some client requests it (with Node.instance())

Constant Summary collapse

@@lazy_connect =

For unit testing - we won’t know the node connection info at load time.

false

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeNode

Returns a new instance of Node.



122
123
124
125
126
# File 'lib/cisco_node_utils/node.rb', line 122

def initialize
  @client = nil
  @cmd_ref = nil
  connect unless @@lazy_connect
end

Instance Attribute Details

#clientObject (readonly)

hidden as well



113
114
115
# File 'lib/cisco_node_utils/node.rb', line 113

def client
  @client
end

#cmd_refObject (readonly)

END NODE API Here and below are implementation details and private APIs that most providers shouldn’t need to know about or use.



113
114
115
# File 'lib/cisco_node_utils/node.rb', line 113

def cmd_ref
  @cmd_ref
end

Class Method Details

.lazy_connect=(val) ⇒ Object



118
119
120
# File 'lib/cisco_node_utils/node.rb', line 118

def Node.lazy_connect=(val)
  @@lazy_connect = val
end

Instance Method Details

#bootString

Returns such as “bootflash:///n3000-uk9-kickstart.6.0.2.U5.0.941.bin”.

Returns:

  • (String)

    such as “bootflash:///n3000-uk9-kickstart.6.0.2.U5.0.941.bin”



573
574
575
# File 'lib/cisco_node_utils/node.rb', line 573

def boot
  config_get("show_version", "boot_image")
end

#build_config_get(feature, ref, type) ⇒ String, Array

Helper method to use the feature, name config_get if present else use feature, “template” config_get

Parameters:

Returns:

  • (String, Array)


274
275
276
277
278
279
280
281
282
283
284
# File 'lib/cisco_node_utils/node.rb', line 274

def build_config_get(feature, ref, type)
  raise "lazy_connect specified but did not request connect" unless @cmd_ref
  # Use feature name config_get string if present
  # else use feature template: config_get
  if ref.hash.key?("config_get")
    return show(ref.config_get, type)
  else
    template = @cmd_ref.lookup(feature, "_template")
    return show(template.config_get, type)
  end
end

#build_config_get_token(feature, ref, args) ⇒ String, Array

Helper method to build a multi-line config_get_token if the feature, name contains a config_get_token_append entry.

Parameters:

Returns:

  • (String, Array)


237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
# File 'lib/cisco_node_utils/node.rb', line 237

def build_config_get_token(feature, ref, args)
  raise "lazy_connect specified but did not request connect" unless @cmd_ref
  # Why clone token? A bug in some ruby versions caused token to convert
  # to type Regexp unexpectedly. The clone hard copy resolved it.

  # If the options are presented as type Hash process as
  # key-value replacement pairs
  return ref.config_get_token.clone unless args[0].is_a?(Hash)
  options = args[0]
  token = []
  # Use _template yaml entry if config_get_token_append
  if ref.to_s[/config_get_token_append/]
    # Get yaml feature template:
    template = @cmd_ref.lookup(feature, "_template")
    # Process config_get_token: from template:
    token.push(replace_token_ids(template.config_get_token, options))
    # Process config_get_token_append sequence: from template:
    template.config_get_token_append.each do |line|
      token.push(replace_token_ids(line, options))
    end
    # Add feature->property config_get_token append line
    token.push(ref.config_get_token_append)
  else
    token.push(replace_token_ids(ref.config_get_token, options))
  end
  token.flatten!
  token.compact!
  token
end

#build_config_set(feature, ref, args) ⇒ String, Array

Helper method to build a multi-line config_set if the feature, name contains a config_get_set_append yaml entry.

Parameters:

Returns:

  • (String, Array)


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
# File 'lib/cisco_node_utils/node.rb', line 293

def build_config_set(feature, ref, args)
  raise "lazy_connect specified but did not request connect" unless @cmd_ref
  # If the options are presented as type Hash process as
  # key-value replacement pairs
  return ref.config_set unless args[0].is_a?(Hash)
  options = args[0]
  config_set = []
  # Use _template yaml entry if config_set_append
  if ref.to_s[/config_set_append/]
    # Get yaml feature template:
    template = @cmd_ref.lookup(feature, "_template")
    # Process config_set: from template:
    config_set.push(replace_token_ids(template.config_set, options))
    # Process config_set_append sequence: from template:
    template.config_set_append.each do |line|
      config_set.push(replace_token_ids(line, options))
    end
    # Add feature->property config_set append line
    config_set.push(replace_token_ids(ref.config_set_append, options))
  else
    config_set.push(replace_token_ids(ref.config_set, options))
  end
  config_set.flatten!
  config_set.compact!
  config_set
end

#cache_auto=(enable) ⇒ Object



163
164
165
# File 'lib/cisco_node_utils/node.rb', line 163

def cache_auto=(enable)
  @client.cache_auto = enable
end

#cache_auto?Boolean

Returns:

  • (Boolean)


159
160
161
# File 'lib/cisco_node_utils/node.rb', line 159

def cache_auto?
  @client.cache_auto?
end

#cache_enable=(enable) ⇒ Object



155
156
157
# File 'lib/cisco_node_utils/node.rb', line 155

def cache_enable=(enable)
  @client.cache_enable = enable
end

#cache_enable?Boolean

Returns:

  • (Boolean)


151
152
153
# File 'lib/cisco_node_utils/node.rb', line 151

def cache_enable?
  @client.cache_enable?
end

#cache_flushObject

Clear the cache of CLI output results.

If cache_auto is true (default) then this will be performed automatically whenever a config_set() is called, but providers may also call this to explicitly force the cache to be cleared.



106
107
# File 'lib/cisco_node_utils/node.rb', line 106

def cache_flush
end

#config(commands) ⇒ Object

Send a config command to the device. In general, clients should use config_set() rather than calling this function directly.

Raises:



467
468
469
470
471
# File 'lib/cisco_node_utils/node.rb', line 467

def config(commands)
  @client.config(commands)
rescue CiscoNxapi::CliError => e
  raise Cisco::CliError.new(e.input, e.clierror, e.previous)
end

#config_get(feature, name, *args) ⇒ String, ...

Convenience wrapper for show(command, :structured). Uses CommandReference to look up the given show command and key of interest, executes that command, and returns the value corresponding to that key.

Examples:

config_get(“show_version”, “system_image”)

config_get(“ospf”, “router_id”,

{:name => "green", :vrf => "one"})

Parameters:

  • feature (String)
  • name (String)

Returns:

  • (String, Hash, Array)

Raises:

  • (IndexError)

    if the given (feature, name) pair is not in the CommandReference data or if the data doesn’t have values defined for the ‘config_get’ and (optional) ‘config_get_token’ fields.

  • (Cisco::CliError)

    if the given command is rejected by the device.



71
72
# File 'lib/cisco_node_utils/node.rb', line 71

def config_get(feature, name)
end

#config_get_default(feature, name) ⇒ String

Uses CommandReference to lookup the default value for a given feature and feature property.

Examples:

config_get_default(“vtp”, “file”)

Parameters:

  • feature (String)
  • name (String)

Returns:

  • (String)

Raises:

  • (IndexError)

    if the given (feature, name) pair is not in the CommandReference data or if the data doesn’t have values defined for the ‘default_value’ field.



84
85
# File 'lib/cisco_node_utils/node.rb', line 84

def config_get_default(feature, name)
end

#config_set(feature, name, *args) ⇒ Object

Uses CommandReference to look up the given config command(s) of interest and then applies the configuration.

Examples:

config_set(“vtp”, “domain”, “example.com”)

config_set(“ospf”, “router_id”,

{:name => "green", :vrf => "one", :state => "",
 :router_id => "192.0.0.1"})

Parameters:

  • feature (String)
  • name (String)
  • args (*String)

    zero or more args to be substituted into the cmdref.

Raises:

  • (IndexError)

    if no relevant cmd_ref config_set exists

  • (ArgumentError)

    if too many or too few args are provided.

  • (Cisco::CliError)

    if any command is rejected by the device.



98
99
# File 'lib/cisco_node_utils/node.rb', line 98

def config_set(feature, name, *args)
end

#connect(*args) ⇒ Object

“hidden” API - used for UT but shouldn’t be used elsewhere



133
134
135
136
137
# File 'lib/cisco_node_utils/node.rb', line 133

def connect(*args)
  @client = CiscoNxapi::NxapiClient.new(*args)
  @cmd_ref = CommandReference::CommandReference.new(product_id)
  cache_flush
end

#domain_nameString

Returns such as “example.com”.

Returns:

  • (String)

    such as “example.com”



528
529
530
531
532
533
534
535
# File 'lib/cisco_node_utils/node.rb', line 528

def domain_name
  result = config_get("domain_name", "domain_name")
  if result.nil?
    return ""
  else
    return result[0]
  end
end

#host_nameString

Returns such as “bxb-oa-n3k-7”.

Returns:

  • (String)

    such as “bxb-oa-n3k-7”



523
524
525
# File 'lib/cisco_node_utils/node.rb', line 523

def host_name
  config_get("show_version", "host_name")
end

#last_reset_reasonString

Returns such as “Reset Requested by CLI command reload”.

Returns:

  • (String)

    such as “Reset Requested by CLI command reload”



560
561
562
# File 'lib/cisco_node_utils/node.rb', line 560

def last_reset_reason
  config_get("show_version", "last_reset_reason")
end

#last_reset_timeString

Returns timestamp of last reset time.

Returns:

  • (String)

    timestamp of last reset time



550
551
552
553
554
555
556
557
# File 'lib/cisco_node_utils/node.rb', line 550

def last_reset_time
  output = config_get("show_version", "last_reset_time")
  return "" if output.nil?
  # NX-OS may provide leading/trailing whitespace:
  # " Sat Oct 25 00:39:25 2014\n"
  # so be sure to strip() it down to the actual string.
  output.strip
end

#osString

Returns such as “Cisco Nexus Operating System (NX-OS) Software”.

Returns:

  • (String)

    such as “Cisco Nexus Operating System (NX-OS) Software”



485
486
487
488
489
# File 'lib/cisco_node_utils/node.rb', line 485

def os
   o = config_get("show_version", "header")
   raise "failed to retrieve operating system information" if o.nil?
   o.split("\n")[0]
end

#os_versionString

Returns such as “6.0(2)U5(1) [build 6.0(2)U5(0.941)]”.

Returns:

  • (String)

    such as “6.0(2)U5(1) [build 6.0(2)U5(0.941)]”



492
493
494
# File 'lib/cisco_node_utils/node.rb', line 492

def os_version
  config_get("show_version", "version")
end

#product_descriptionString

Returns such as “Nexus 3048 Chassis”.

Returns:

  • (String)

    such as “Nexus 3048 Chassis”



497
498
499
# File 'lib/cisco_node_utils/node.rb', line 497

def product_description
  config_get("show_version", "description")
end

#product_idString

Returns such as “N3K-C3048TP-1GE”.

Returns:

  • (String)

    such as “N3K-C3048TP-1GE”



502
503
504
505
506
507
508
509
510
# File 'lib/cisco_node_utils/node.rb', line 502

def product_id
  if @cmd_ref
    return config_get("inventory", "productid")
  else
    # We use this function to *find* the appropriate CommandReference
    entries = show("show inventory", :structured)
    return entries["TABLE_inv"]["ROW_inv"][0]["productid"]
  end
end

#product_serial_numberString

Returns such as “FOC1722R0ET”.

Returns:

  • (String)

    such as “FOC1722R0ET”



518
519
520
# File 'lib/cisco_node_utils/node.rb', line 518

def product_serial_number
  config_get("inventory", "serialnum")
end

#product_version_idString

Returns such as “V01”.

Returns:

  • (String)

    such as “V01”



513
514
515
# File 'lib/cisco_node_utils/node.rb', line 513

def product_version_id
  config_get("inventory", "versionid")
end

#reloadObject

TODO: remove me



140
141
142
# File 'lib/cisco_node_utils/node.rb', line 140

def reload
  @client.reload
end

#replace_token_ids(regexp, values) ⇒ String

Helper method to replace <> place holders in the config_get_token and config_get_token_append yaml entries.

Parameters:

  • regexp (String)
    Array

    regexp entry with <> placeholders

  • values (Hash)

    Hash of named values to replace each <>

Returns:

  • (String)


200
201
202
203
204
# File 'lib/cisco_node_utils/node.rb', line 200

def replace_token_ids(regexp, values)
  final = replace_token_ids_string(regexp, values) if regexp.is_a?(String)
  final = replace_token_ids_array(regexp, values) if regexp.is_a?(Array)
  final
end

#replace_token_ids_array(regexp, values) ⇒ String

Parameters:

  • regexp (Array)

    regexp entry with <> placeholders

  • values (Hash)

    Hash of named values to replace each <>

Returns:

  • (String)


223
224
225
226
227
228
229
# File 'lib/cisco_node_utils/node.rb', line 223

def replace_token_ids_array(regexp, values)
  final_regexp = []
  regexp.each do |line|
    final_regexp.push(replace_token_ids_string(line, values))
  end
  final_regexp
end

#replace_token_ids_string(regexp, values) ⇒ String

Parameters:

  • regexp (String)

    regexp entry with <> placeholders

  • values (Hash)

    Hash of named values to replace each <>

Returns:

  • (String)


209
210
211
212
213
214
215
216
217
218
# File 'lib/cisco_node_utils/node.rb', line 209

def replace_token_ids_string(regexp, values)
  replace = regexp.scan(/<(\S+)>/).flatten.map(&:to_sym)
  replace.each do |item|
    regexp = regexp.sub "<#{item}>",
      values[item].to_s if values.key?(item)
  end
  # Only return lines that actually replaced ids or did not have any
  # ids to replace. Implicit nil returned if not.
  return regexp if /<\S+>/.match(regexp).nil?
end

#show(command, type = :ascii) ⇒ Object

Send a show command to the device. In general, clients should use config_get() rather than calling this function directly.

Raises:



478
479
480
481
482
# File 'lib/cisco_node_utils/node.rb', line 478

def show(command, type=:ascii)
  @client.show(command, type)
rescue CiscoNxapi::CliError => e
  raise Cisco::CliError.new(e.input, e.clierror, e.previous)
end

#systemString

Returns such as “bootflash:///n3000-uk9.6.0.2.U5.0.941.bin”.

Returns:

  • (String)

    such as “bootflash:///n3000-uk9.6.0.2.U5.0.941.bin”



579
580
581
# File 'lib/cisco_node_utils/node.rb', line 579

def system
  config_get("show_version", "system_image")
end

#system_cpu_utilizationFloat

Returns combined user/kernel CPU utilization.

Returns:

  • (Float)

    combined user/kernel CPU utilization



565
566
567
568
569
# File 'lib/cisco_node_utils/node.rb', line 565

def system_cpu_utilization
  output = config_get("system", "resources")
  raise "failed to retrieve cpu utilization" if output.nil?
  output["cpu_state_user"].to_f + output["cpu_state_kernel"].to_f
end

#system_uptimeInteger

Returns System uptime, in seconds.

Returns:

  • (Integer)

    System uptime, in seconds



538
539
540
541
542
543
544
545
546
547
# File 'lib/cisco_node_utils/node.rb', line 538

def system_uptime
  cache_flush
  t = config_get("show_system", "uptime")
  raise "failed to retrieve system uptime" if t.nil?
  t = t.shift
  # time units: t = ["0", "23", "15", "49"]
  t.map!(&:to_i)
  d, h, m, s = t
  (s + 60 * (m + 60 * (h + 24 * (d))))
end

#to_sObject



128
129
130
# File 'lib/cisco_node_utils/node.rb', line 128

def to_s
  @client.to_s
end

#token_str_to_regexp(token, args) ⇒ Object

Helper method for converting token strings to regexps. This helper facilitates non-standard regexp options like ignore-case. Example inputs:

token = ["/%s/i", "/%s foo %s/", "/zzz/i"]
args = ["LoopBack2", "no", "bar"]

Expected outputs:

[/LoopBack2/i, /no foo bar/, /zzz/i]


175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/cisco_node_utils/node.rb', line 175

def token_str_to_regexp(token, args)
  unless args[0].is_a? Hash
    expected_args = token.join.scan(/%/).length
    raise "Given #{args.length} args, but token #{token} requires " +
      "#{expected_args}" unless args.length == expected_args
  end
  # replace all %s with *args
  token.map! { |str| sprintf(str, *args.shift(str.scan(/%/).length)) }
  # convert all to Regexp objects
  token.map! { |str|
    if str[-2..-1] == '/i'
      Regexp.new(str[1..-3], Regexp::IGNORECASE)
    else
      Regexp.new(str[1..-2])
    end
  }
  token
end