Class: Cisco::Node
- Inherits:
-
Object
- Object
- Cisco::Node
- 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())
Instance Attribute Summary collapse
-
#client ⇒ Object
readonly
Here and below are implementation details and private APIs that most providers shouldn’t need to know about or use.
-
#cmd_ref ⇒ Object
readonly
Here and below are implementation details and private APIs that most providers shouldn’t need to know about or use.
Class Method Summary collapse
- .instance ⇒ Object
-
.reset_instance ⇒ Object
Allow instance cache to be reset.
Instance Method Summary collapse
-
#boot ⇒ String
Such as “bootflash:///n3000-uk9-kickstart.6.0.2.U5.0.941.bin”.
- #cache_auto=(enable) ⇒ Object
- #cache_auto? ⇒ Boolean
- #cache_enable=(enable) ⇒ Object
- #cache_enable? ⇒ Boolean
-
#cache_flush ⇒ Object
Clear the cache of CLI output results.
-
#config_get(feature, property, *args) ⇒ String, ...
Convenience wrapper for get() Uses CommandReference to look up the given show command and key of interest, executes that command, and returns the value corresponding to that key.
-
#config_get_default(feature, property) ⇒ String?
Uses CommandReference to lookup the default value for a given feature and feature property.
-
#config_set(feature, property, *args) ⇒ Object
Uses CommandReference to look up the given config command(s) of interest and then applies the configuration.
-
#delete_yang(yang) ⇒ Object
Delete the specified JSON YANG config from the device.
-
#domain_name ⇒ String
Such as “example.com”.
-
#drill_down_structured(value, ref) ⇒ Object
Drill down into structured nxapi table data and return value from the row specified by a two part key.
-
#get(**kwargs) ⇒ Object
Send a show command to the device.
-
#get_yang(yang_path) ⇒ Object
Retrieve JSON YANG config from the device for the specified path.
-
#get_yang_oper(yang_path) ⇒ Object
Retrieve JSON YANG operational data for the specified path.
-
#host_name ⇒ String
Such as “bxb-oa-n3k-7”.
-
#initialize ⇒ Node
constructor
A new instance of Node.
- #inspect ⇒ Object
-
#last_reset_reason ⇒ String
Such as “Reset Requested by CLI command reload”.
-
#last_reset_time ⇒ String
Timestamp of last reset time.
-
#massage(value, ref) ⇒ Object
Attempt to massage the given value into the format specified by the given CmdRef object.
- #massage_kind(value, ref) ⇒ Object
-
#massage_structured(get_args, ref) ⇒ Object
The yaml file may specifiy an Array as the get_value to drill down into nxapi_structured table output.
-
#merge_yang(yang) ⇒ Object
Merge the specified JSON YANG config with the running config on the device.
-
#os ⇒ String
Such as “Cisco Nexus Operating System (NX-OS) Software”.
-
#os_version ⇒ String
Such as “6.0(2)U5(1) [build 6.0(2)U5(0.941)]”.
- #os_version_get(feature, property) ⇒ Object
- #prod_qualifier(prod, inventory) ⇒ Object
-
#product_description ⇒ String
Such as “Nexus 3048 Chassis”.
-
#product_id ⇒ String
Such as “N3K-C3048TP-1GE”.
-
#product_serial_number ⇒ String
Such as “FOC1722R0ET”.
-
#product_version_id ⇒ String
Such as “V01”.
-
#replace_yang(yang) ⇒ Object
Replace the running config on the device with the specified JSON YANG config.
-
#set(**kwargs) ⇒ Object
Send a config command to the device.
-
#system ⇒ String
Such as “bootflash:///n3000-uk9.6.0.2.U5.0.941.bin”.
-
#system_cpu_utilization ⇒ Float
Combined user/kernel CPU utilization.
-
#system_uptime ⇒ Integer
System uptime, in seconds.
- #to_s ⇒ Object
Constructor Details
#initialize ⇒ Node
Returns a new instance of Node.
245 246 247 248 249 250 251 252 |
# File 'lib/cisco_node_utils/node.rb', line 245 def initialize @client = Cisco::Client.create @cmd_ref = nil @cmd_ref = CommandReference.new(product: product_id, platform: @client.platform, data_formats: @client.data_formats) cache_flush end |
Instance Attribute Details
#client ⇒ Object (readonly)
Here and below are implementation details and private APIs that most providers shouldn’t need to know about or use.
234 235 236 |
# File 'lib/cisco_node_utils/node.rb', line 234 def client @client end |
#cmd_ref ⇒ Object (readonly)
Here and below are implementation details and private APIs that most providers shouldn’t need to know about or use.
234 235 236 |
# File 'lib/cisco_node_utils/node.rb', line 234 def cmd_ref @cmd_ref end |
Class Method Details
.instance ⇒ Object
236 237 238 |
# File 'lib/cisco_node_utils/node.rb', line 236 def self.instance @instance ||= new end |
.reset_instance ⇒ Object
Allow instance cache to be reset
241 242 243 |
# File 'lib/cisco_node_utils/node.rb', line 241 def self.reset_instance @instance = nil end |
Instance Method Details
#boot ⇒ String
Returns such as “bootflash:///n3000-uk9-kickstart.6.0.2.U5.0.941.bin”.
430 431 432 |
# File 'lib/cisco_node_utils/node.rb', line 430 def boot config_get('show_version', 'boot_image') end |
#cache_auto=(enable) ⇒ Object
274 275 276 |
# File 'lib/cisco_node_utils/node.rb', line 274 def cache_auto=(enable) @client.cache_auto = enable end |
#cache_auto? ⇒ Boolean
270 271 272 |
# File 'lib/cisco_node_utils/node.rb', line 270 def cache_auto? @client.cache_auto? end |
#cache_enable=(enable) ⇒ Object
266 267 268 |
# File 'lib/cisco_node_utils/node.rb', line 266 def cache_enable=(enable) @client.cache_enable = enable end |
#cache_enable? ⇒ Boolean
262 263 264 |
# File 'lib/cisco_node_utils/node.rb', line 262 def cache_enable? @client.cache_enable? end |
#cache_flush ⇒ Object
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.
227 228 229 |
# File 'lib/cisco_node_utils/node.rb', line 227 def cache_flush @client.cache_flush end |
#config_get(feature, property, *args) ⇒ String, ...
Convenience wrapper for get() Uses CommandReference to look up the given show command and key of interest, executes that command, and returns the value corresponding to that key.
53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/cisco_node_utils/node.rb', line 53 def config_get(feature, property, *args) ref = @cmd_ref.lookup(feature, property) # If we have a default value but no getter, just return the default return ref.default_value if ref.default_value? && !ref.getter? get_args, ref = massage_structured(ref.getter(*args).clone, ref) data = get(command: get_args[:command], data_format: get_args[:data_format], context: get_args[:context], value: get_args[:value]) massage(data, ref) end |
#config_get_default(feature, property) ⇒ String?
Uses CommandReference to lookup the default value for a given feature and feature property.
196 197 198 199 |
# File 'lib/cisco_node_utils/node.rb', line 196 def config_get_default(feature, property) ref = @cmd_ref.lookup(feature, property) ref.default_value end |
#config_set(feature, property, *args) ⇒ Object
Uses CommandReference to look up the given config command(s) of interest and then applies the configuration.
216 217 218 219 220 |
# File 'lib/cisco_node_utils/node.rb', line 216 def config_set(feature, property, *args) ref = @cmd_ref.lookup(feature, property) set_args = ref.setter(*args) set(**set_args) end |
#delete_yang(yang) ⇒ Object
Delete the specified JSON YANG config from the device.
310 311 312 |
# File 'lib/cisco_node_utils/node.rb', line 310 def delete_yang(yang) @client.set(data_format: :yang_json, values: [yang], mode: :delete_config) end |
#domain_name ⇒ String
Returns such as “example.com”.
396 397 398 |
# File 'lib/cisco_node_utils/node.rb', line 396 def domain_name config_get('dnsclient', 'domain_name') end |
#drill_down_structured(value, ref) ⇒ Object
Drill down into structured nxapi table data and return value from the row specified by a two part key.
Example: Get vlanshowbr-vlanname in the row that contains vlan id 1000 “get_value”=>[“vlanshowbr-vlanid-utf 1000”, “vlanshowbr-vlanname”] Example with optional regexp match “get_value”=>[“vlanshowbr-vlanid-utf 1000”, “vlanshowbr-vlanname”,
'/^shutdown$/']
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/cisco_node_utils/node.rb', line 105 def drill_down_structured(value, ref) # Nothing to do unless nxapi_structured return value unless ref.hash['drill_down'] row_key = ref.hash['get_value'][0][/^\S+/] # Escape special characters if any in row_index and add # anchors for exact match. row_index = Regexp.escape(ref.hash['get_value'][0][/\S+$/]) row_index = "^#{row_index}$" data_key = ref.hash['get_value'][1] regexp_filter = nil if ref.hash['get_value'][2] regexp_filter = Regexp.new ref.hash['get_value'][2][1..-2] end # Get the value using the row_key, row_index and data_key value = value.is_a?(Hash) ? [value] : value data = nil value.each do |row| if row[row_key].to_s[/#{row_index}/] data = row[data_key] data = data.nil? ? '' : data end end return value if data.nil? if regexp_filter filtered = regexp_filter.match(data) return filtered.nil? ? filtered : filtered[filtered.size - 1] end data end |
#get(**kwargs) ⇒ Object
Send a show command to the device. In general, clients should use config_get() rather than calling this function directly.
292 293 294 |
# File 'lib/cisco_node_utils/node.rb', line 292 def get(**kwargs) @client.get(**kwargs) end |
#get_yang(yang_path) ⇒ Object
Retrieve JSON YANG config from the device for the specified path.
315 316 317 |
# File 'lib/cisco_node_utils/node.rb', line 315 def get_yang(yang_path) @client.get(data_format: :yang_json, command: yang_path) end |
#get_yang_oper(yang_path) ⇒ Object
Retrieve JSON YANG operational data for the specified path.
320 321 322 |
# File 'lib/cisco_node_utils/node.rb', line 320 def get_yang_oper(yang_path) @client.get(data_format: :yang_json, command: yang_path, mode: :get_oper) end |
#host_name ⇒ String
Returns such as “bxb-oa-n3k-7”.
391 392 393 |
# File 'lib/cisco_node_utils/node.rb', line 391 def host_name config_get('show_version', 'host_name') end |
#inspect ⇒ Object
258 259 260 |
# File 'lib/cisco_node_utils/node.rb', line 258 def inspect "Node: client:'#{client.inspect}' cmd_ref:'#{cmd_ref.inspect}'" end |
#last_reset_reason ⇒ String
Returns such as “Reset Requested by CLI command reload”.
417 418 419 |
# File 'lib/cisco_node_utils/node.rb', line 417 def last_reset_reason config_get('show_version', 'last_reset_reason') end |
#last_reset_time ⇒ String
Returns timestamp of last reset time.
412 413 414 |
# File 'lib/cisco_node_utils/node.rb', line 412 def last_reset_time config_get('show_version', 'last_reset_time') end |
#massage(value, ref) ⇒ Object
Attempt to massage the given value into the format specified by the given CmdRef object.
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/cisco_node_utils/node.rb', line 140 def massage(value, ref) Cisco::Logger.debug "Massaging '#{value}' (#{value.inspect})" value = drill_down_structured(value, ref) if value.is_a?(Array) && !ref.multiple fail "Expected zero/one value but got '#{value}'" if value.length > 1 value = value[0] end if (value.nil? || value.to_s.empty?) && ref.default_value? && ref.auto_default Cisco::Logger.debug "Default: #{ref.default_value}" return ref.default_value end if ref.multiple && ref.hash['get_data_format'] == :nxapi_structured return value if value.nil? value = [value.to_s] if value.is_a?(String) || value.is_a?(Fixnum) end return value unless ref.kind value = massage_kind(value, ref) Cisco::Logger.debug "Massaged to '#{value}'" value end |
#massage_kind(value, ref) ⇒ Object
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/cisco_node_utils/node.rb', line 162 def massage_kind(value, ref) case ref.kind when :boolean if value.nil? || value.empty? value = false elsif /^no / =~ value value = false elsif /disable$/ =~ value value = false else value = true end when :int value = value.to_i unless value.nil? when :string value = '' if value.nil? value = value.to_s.strip when :symbol value = value.to_sym unless value.nil? end value end |
#massage_structured(get_args, ref) ⇒ Object
The yaml file may specifiy an Array as the get_value to drill down into nxapi_structured table output. The table may contain multiple rows but only one of the rows has the interesting data.
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/cisco_node_utils/node.rb', line 70 def massage_structured(get_args, ref) # Nothing to do unless nxapi_structured. return [get_args, ref] unless ref.hash['get_data_format'] == :nxapi_structured # The CmdRef object will contain a get_value Array with 2 values. # The first value is the key to identify the correct row in the table # of structured output and the second is the key to identify the data # to retrieve. # # Example: Get vlanshowbr-vlanname in the row that contains a specific # vlan_id. # "get_value"=>["vlanshowbr-vlanid-utf <vlan_id>", "vlanshowbr-vlanname"] # # TBD: Why do we need to check is_a?(Array) here? if ref.hash['get_value'].is_a?(Array) && ref.hash['get_value'].size >= 2 # Replace the get_value hash entry with the value after any tokens # specified in the yaml file have been replaced and set get_args[:value] # to nil so that the structured table data can be retrieved properly. ref.hash['get_value'] = get_args[:value] ref.hash['drill_down'] = true get_args[:value] = nil cache_flush end [get_args, ref] end |
#merge_yang(yang) ⇒ Object
Merge the specified JSON YANG config with the running config on the device.
298 299 300 |
# File 'lib/cisco_node_utils/node.rb', line 298 def merge_yang(yang) @client.set(data_format: :yang_json, values: [yang], mode: :merge_config) end |
#os ⇒ String
Returns such as “Cisco Nexus Operating System (NX-OS) Software”.
325 326 327 328 329 |
# File 'lib/cisco_node_utils/node.rb', line 325 def os o = config_get('show_version', 'header') fail 'failed to retrieve operating system information' if o.nil? o.split("\n")[0] end |
#os_version ⇒ String
Returns such as “6.0(2)U5(1) [build 6.0(2)U5(0.941)]”.
332 333 334 |
# File 'lib/cisco_node_utils/node.rb', line 332 def os_version config_get('show_version', 'version') end |
#os_version_get(feature, property) ⇒ Object
440 441 442 |
# File 'lib/cisco_node_utils/node.rb', line 440 def os_version_get(feature, property) @cmd_ref.lookup(feature, property).os_version end |
#prod_qualifier(prod, inventory) ⇒ Object
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
# File 'lib/cisco_node_utils/node.rb', line 363 def prod_qualifier(prod, inventory) case prod when /N(3|9)K/ # one datapoint is used to determine if the current n9k/n3k # platform is a fretta based or non-fretta. # # Module == *-R inventory.each do |row| if row['productid'][/-R/] # Append -F for fretta platform. return prod.concat('-F') unless prod[/-F/] end end end prod end |
#product_description ⇒ String
Returns such as “Nexus 3048 Chassis”.
337 338 339 |
# File 'lib/cisco_node_utils/node.rb', line 337 def product_description config_get('show_version', 'description') end |
#product_id ⇒ String
Returns such as “N3K-C3048TP-1GE”.
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 |
# File 'lib/cisco_node_utils/node.rb', line 342 def product_id if @cmd_ref prod = config_get('inventory', 'productid') all = config_get('inventory', 'all') prod_qualifier(prod, all) else # We use this function to *find* the appropriate CommandReference if @client.platform == :nexus entries = get(command: 'show inventory', data_format: :nxapi_structured) prod = entries['TABLE_inv']['ROW_inv'][0]['productid'] prod_qualifier(prod, entries['TABLE_inv']['ROW_inv']) elsif @client.platform == :ios_xr # No support for structured output for this command yet output = get(command: 'show inventory', data_format: :cli) return /NAME: .*\nPID: (\S+)/.match(output)[1] end end end |
#product_serial_number ⇒ String
Returns such as “FOC1722R0ET”.
386 387 388 |
# File 'lib/cisco_node_utils/node.rb', line 386 def product_serial_number config_get('inventory', 'serialnum') end |
#product_version_id ⇒ String
Returns such as “V01”.
381 382 383 |
# File 'lib/cisco_node_utils/node.rb', line 381 def product_version_id config_get('inventory', 'versionid') end |
#replace_yang(yang) ⇒ Object
Replace the running config on the device with the specified JSON YANG config.
304 305 306 307 |
# File 'lib/cisco_node_utils/node.rb', line 304 def replace_yang(yang) @client.set(data_format: :yang_json, values: [yang], mode: :replace_config) end |
#set(**kwargs) ⇒ Object
Send a config command to the device. In general, clients should use config_set() rather than calling this function directly.
283 284 285 |
# File 'lib/cisco_node_utils/node.rb', line 283 def set(**kwargs) @client.set(**kwargs) end |
#system ⇒ String
Returns such as “bootflash:///n3000-uk9.6.0.2.U5.0.941.bin”.
436 437 438 |
# File 'lib/cisco_node_utils/node.rb', line 436 def system config_get('show_version', 'system_image') end |
#system_cpu_utilization ⇒ Float
Returns combined user/kernel CPU utilization.
422 423 424 425 426 |
# File 'lib/cisco_node_utils/node.rb', line 422 def system_cpu_utilization output = config_get('system', 'resources') return output if output.nil? output['cpu_state_user'].to_f + output['cpu_state_kernel'].to_f end |
#system_uptime ⇒ Integer
Returns System uptime, in seconds.
401 402 403 404 405 406 407 408 409 |
# File 'lib/cisco_node_utils/node.rb', line 401 def system_uptime cache_flush t = config_get('show_system', 'uptime') fail 'failed to retrieve system uptime' if t.nil? # 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_s ⇒ Object
254 255 256 |
# File 'lib/cisco_node_utils/node.rb', line 254 def to_s client.to_s end |