Oxidized - Trouble Adding 2nd OS Type (Aruba CX) To Procurve Environment

Hi
I’ve had Oxidized happily trucking away for a few years with our homogeneous Procurve environment, but now we’ve added a bunch of ArubaCX switches, and I’m having trouble getting Oxidized to work with two OS types. Can anyone offer any insight?

Crash file look like this:

2023-06-01 22:15:23 UTC
uninitialized constant Aoscx::Refinements [NameError]
--------------------------------------------------
/var/lib/gems/2.7.0/gems/oxidized-0.28.0/lib/oxidized/model/aoscx.rb:2:in `<class:Aoscx>'
/var/lib/gems/2.7.0/gems/oxidized-0.28.0/lib/oxidized/model/aoscx.rb:1:in `<top (required)>'
/usr/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require'
/usr/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require'
/var/lib/gems/2.7.0/gems/oxidized-0.28.0/lib/oxidized/manager.rb:9:in `load'
/var/lib/gems/2.7.0/gems/oxidized-0.28.0/lib/oxidized/manager.rb:60:in `loader'
/var/lib/gems/2.7.0/gems/oxidized-0.28.0/lib/oxidized/manager.rb:47:in `add_model'
/var/lib/gems/2.7.0/gems/oxidized-0.28.0/lib/oxidized/node.rb:170:in `resolve_model'
/var/lib/gems/2.7.0/gems/oxidized-0.28.0/lib/oxidized/node.rb:22:in `initialize'
/var/lib/gems/2.7.0/gems/oxidized-0.28.0/lib/oxidized/nodes.rb:21:in `new'
/var/lib/gems/2.7.0/gems/oxidized-0.28.0/lib/oxidized/nodes.rb:21:in `block (2 levels) in load'
/var/lib/gems/2.7.0/gems/oxidized-0.28.0/lib/oxidized/nodes.rb:16:in `each'
/var/lib/gems/2.7.0/gems/oxidized-0.28.0/lib/oxidized/nodes.rb:16:in `block in load'
/var/lib/gems/2.7.0/gems/oxidized-0.28.0/lib/oxidized/nodes.rb:130:in `synchronize'
/var/lib/gems/2.7.0/gems/oxidized-0.28.0/lib/oxidized/nodes.rb:130:in `with_lock'
/var/lib/gems/2.7.0/gems/oxidized-0.28.0/lib/oxidized/nodes.rb:10:in `load'
/var/lib/gems/2.7.0/gems/oxidized-0.28.0/lib/oxidized/nodes.rb:125:in `initialize'
/var/lib/gems/2.7.0/gems/oxidized-0.28.0/lib/oxidized/core.rb:14:in `new'
/var/lib/gems/2.7.0/gems/oxidized-0.28.0/lib/oxidized/core.rb:14:in `initialize'
/var/lib/gems/2.7.0/gems/oxidized-0.28.0/lib/oxidized/core.rb:4:in `new'
/var/lib/gems/2.7.0/gems/oxidized-0.28.0/lib/oxidized/core.rb:4:in `new'
/var/lib/gems/2.7.0/gems/oxidized-0.28.0/lib/oxidized/cli.rb:13:in `run'
/var/lib/gems/2.7.0/gems/oxidized-0.28.0/bin/oxidized:8:in `<top (required)>'
/usr/local/bin/oxidized:23:in `load'
/usr/local/bin/oxidized:23:in `<main>'

Config look like this:

---
username: manager
password: password
model: procurve
log: /home/oxidized/.config/oxidized/logs/log
resolve_dns: false
interval: 3600
use_syslog: false
debug: true
threads: 30
timeout: 20
retries: 3
prompt: !ruby/regexp /^([\w.@-]+[#>]\s?)$/
rest: 127.0.0.1:8888
next_adds_job: false
models:
  procurve:
    username: manager
    password: password
    ssh_port: 22
   
  aoscx:
    username: admin
    password: password
    ssh_port: 22
   
groups:
  procurve:
    username: manager
    password: password
    model: procurve

  aoscx:
    username: admin
    password: password
    model: aoscx

vars:
  auth_methods:  ["password"]

pid: "/home/oxidized/.config/oxidized/pid"
crash:
  directory: "/home/oxidized/.config/oxidized/crash"
  hostnames: false
stats:
  history_size: 10
input:
  default: ssh
  debug: true
  ssh:
    secure: false
  utf8_encoded: true
output:
  default: git
  debug: true
  git:
    user: oxidized
    email : [email protected]
    repo: /home/oxidized/.config/oxidized/deviceconfigs/default.git

source:
  default: csv
  csv:
    file: "/home/oxidized/.config/oxidized/router.db"
    delimiter: !ruby/regexp /:/
    map:
      ip: 0
      model: 1
      group: 2

model_map:
  cisco: ios
  juniper: junos
  aoscx: aoscx

router.db just has two test entries for a 6000 CX and a Procurve

172.27.1.1:aoscx:aoscx
172.27.1.254:procurve:procurve

/var/lib/gems/2.7.0/gems/oxidized-0.28.0/lib/oxidized/model/aoscx.rb looks like this:

class Aoscx < Oxidized::Model
  using Refinements

  # previous command is repeated followed by "\eE", which sometimes ends up on last line
  # ssh switches prompt may start with \r, followed by the prompt itself, regex ([\w\s.-]+[#>] ), which ends the line
  # telnet switchs may start with various vt100 control characters, regex (\e\[24;[0-9][hH]), follwed by the prompt, followed
  # by at least 3 other vt100 characters
  prompt /(^\r|\e\[24;[0-9][hH])?([\w\s.-]+[#>] )($|(\e\[24;[0-9][0-9]?[hH]){3})/

  comment '! '

  # replace next line control sequence with a new line
  expect /(\e\[1M\e\[\??\d+(;\d+)*[A-Za-z]\e\[1L)|(\eE)/ do |data, re|
    data.gsub re, "\n"
  end

  # replace all used vt100 control sequences
  expect /\e\[\??\d+(;\d+)*[A-Za-z]/ do |data, re|
    data.gsub re, ''
  end

  expect /Press any key to continue(\e\[\??\d+(;\d+)*[A-Za-z])*$/ do
    send ' '
    ""
  end

  expect /Enter switch number/ do
    send "\n"
    ""
  end

  cmd :all do |cfg|
    cfg = cfg.cut_both
    cfg = cfg.gsub /^\r/, ''
    # Additional filtering for elder switches sending vt100 control chars via telnet
    cfg.gsub! /\e\[\??\d+(;\d+)*[A-Za-z]/, ''
    # Additional filtering for power usage reporting which obviously changes over time
    cfg.gsub! /^(.*AC [0-9]{3}V\/?([0-9]{3}V)?) *([0-9]{1,3}) (.*)/, '\\1 <removed> \\4'
    cfg
  end

  cmd :secret do |cfg|
    cfg.gsub! /^(snmp-server community) \S+(.*)/, '\\1 <secret hidden> \\2'
    cfg.gsub! /^(snmp-server host \S+) \S+(.*)/, '\\1 <secret hidden> \\2'
    cfg.gsub! /^(radius-server host \S+ key) \S+(.*)/, '\\1 <secret hidden> \\2'
    cfg.gsub! /^(radius-server key).*/, '\\1 <configuration removed>'
    cfg.gsub! /^(tacacs-server host \S+ key) \S+(.*)/, '\\1 <secret hidden> \\2'
    cfg.gsub! /^(tacacs-server key).*/, '\\1 <secret hidden>'
    cfg
  end

  cmd 'show version' do |cfg|
    comment cfg
  end

  cmd 'show environment' do |cfg|
    cfg.gsub! /^(LC.*\s+)\d+\s+$/, '\\1<hidden>'
    cfg.gsub! /^(\d\/\d\/\d.*\s+)\d+\s+$/, '\\1<hidden>'
    cfg.gsub! /^(\d+\/\S+\s+\S+\s+)\d+\.\d+\s+C(.*)/, '\\1<hidden>\\2'
    cfg.gsub! /^(LC.*\s+)\d+\.\d+\s+(C.*)$/, '\\1 <hidden> \\2'
    comment cfg
  end

  cmd 'show module' do |cfg|
    comment cfg
  end

  cmd 'show interface transceiver' do |cfg|
    comment cfg
  end

  cmd 'show system | exclude "Up Time" | exclude "CPU" | exclude "Memory"' do |cfg|
    comment cfg
  end

  cmd 'show running-config'

  cfg :telnet do
    username /Username:/
    password /Password:/
  end

  cfg :telnet, :ssh do
    # preferred way to handle additional passwords
    if vars :enable
      post_login do
        send "enable\n"
        cmd vars(:enable)
      end
    end
    post_login 'no page'
    pre_logout "exit"
  end

  cfg :ssh do
    pty_options(chars_wide: 1000)
  end
end
'''

Hello!

Strange… We have a similar enviroment with Procurve and Aruba CX, and here it works without any issues.

BR

Any chance you could post your config and router.db?

Hello!

Her is Our config, we dont use router.db, we get all info from LibreNMS via API.
I see that You use Ruby 2.7.0, we are using Ruby 3.0.0.

---
username: XXXXXXX
password: XXXXXXX
model: procurve
resolve_dns: true
interval: 43200
use_syslog: false
debug: false
threads: 30
timeout: 60
retries: 3
prompt: !ruby/regexp /^([\w.@-]+[#>]\s?)$/
rest: 192.168.0.1:8888
next_adds_job: false
#log: /home/oxidized/.config/oxidized/log
vars:
  auth_methods: [ "none", "publickey", "password", "keyboard-interactive" ]
groups:
  aruba:
    username: XXXXXXX
    password: XXXXXXX
  procurve:
    username: XXXXXXX
    password: XXXXXXX
  iosxe:
    username: XXXXXXX
    password: XXXXXXX
  comware:
    username: XXXXXXX
    password: XXXXXXX
  fortigate:
    username: XXXXXXX
    password: XXXXXXX
models: {}
pid: "/home/oxidized/.config/oxidized/pid"
crash:
  directory: "/home/oxidized/.config/oxidized/crashes"
  hostnames: false
stats:
  history_size: 10
input:
  default: ssh, telnet
  debug: false
  ssh:
    secure: false
  ftp:
    passive: true
  utf8_encoded: true
output:
  debug: false
  default: file
  file:
    directory: "/home/oxidized/.config/oxidized/configs"
source:
  default: http
  debug: false
  http:
    url: http://192.168.0.1/api/v0/oxidized
    map:
      name: hostname
      model: os
      group: group
    headers:
      X-Auth-Token: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
model_map:
  arubaos-cx: aoscx
  hp: comware
  cisco: iosxe
  fortigate: fortios

And here is Our /var/lib/gems/3.0.0/gems/oxidized-0.29.1/lib/oxidized/model/aoscx.rb

class Aoscx < Oxidized::Model
  using Refinements

  # previous command is repeated followed by "\eE", which sometimes ends up on last line
  # ssh switches prompt may start with \r, followed by the prompt itself, regex ([\w\s.-]+[#>] ), which ends the line
  # telnet switchs may start with various vt100 control characters, regex (\e\[24;[0-9][hH]), follwed by the prompt, followed
  # by at least 3 other vt100 characters
  prompt /(^\r|\e\[24;[0-9][hH])?([\w\s.-]+[#>] )($|(\e\[24;[0-9][0-9]?[hH]){3})/

  comment '! '

  # replace next line control sequence with a new line
  expect /(\e\[1M\e\[\??\d+(;\d+)*[A-Za-z]\e\[1L)|(\eE)/ do |data, re|
    data.gsub re, "\n"
  end

  # replace all used vt100 control sequences
  expect /\e\[\??\d+(;\d+)*[A-Za-z]/ do |data, re|
    data.gsub re, ''
  end

  expect /Press any key to continue(\e\[\??\d+(;\d+)*[A-Za-z])*$/ do
    send ' '
    ""
  end

  expect /Enter switch number/ do
    send "\n"
    ""
  end

  cmd :all do |cfg|
    cfg = cfg.cut_both
    cfg = cfg.gsub /^\r/, ''
    # Additional filtering for elder switches sending vt100 control chars via telnet
    cfg.gsub! /\e\[\??\d+(;\d+)*[A-Za-z]/, ''
    # Additional filtering for power usage reporting which obviously changes over time
    cfg.gsub! /^(.*AC [0-9]{3}V\/?([0-9]{3}V)?) *([0-9]{1,3}) (.*)/, '\\1 <removed> \\4'
    cfg
  end

  cmd :secret do |cfg|
    cfg.gsub! /^(snmp-server community) \S+(.*)/, '\\1 <secret hidden> \\2'
    cfg.gsub! /^(snmp-server host \S+) \S+(.*)/, '\\1 <secret hidden> \\2'
    cfg.gsub! /^(radius-server host \S+ key) \S+(.*)/, '\\1 <secret hidden> \\2'
    cfg.gsub! /^(radius-server key).*/, '\\1 <configuration removed>'
    cfg.gsub! /^(tacacs-server host \S+ key) \S+(.*)/, '\\1 <secret hidden> \\2'
    cfg.gsub! /^(tacacs-server key).*/, '\\1 <secret hidden>'
    cfg
  end

  cmd 'show version' do |cfg|
    comment cfg
  end

  cmd 'show environment' do |cfg|
    cfg.gsub! /^(LC.*\s+)\d+\s+$/, '\\1<hidden>'
    cfg.gsub! /^(\d\/\d\/\d.*\s+)\d+\s+$/, '\\1<hidden>'
    cfg.gsub! /^(\d+\/\S+\s+\S+\s+)\d+\.\d+\s+C(.*)/, '\\1<hidden>\\2'
    cfg.gsub! /^(LC.*\s+)\d+\.\d+\s+(C.*)$/, '\\1 <hidden> \\2'
    comment cfg
  end

  cmd 'show module' do |cfg|
    comment cfg
  end

  cmd 'show interface transceiver' do |cfg|
    comment cfg
  end

  cmd 'show system | exclude "Up Time" | exclude "CPU" | exclude "Memory"' do |cfg|
    comment cfg
  end

  cmd 'show running-config'

  cfg :telnet do
    username /Username:/
    password /Password:/
  end

  cfg :telnet, :ssh do
    # preferred way to handle additional passwords
    if vars :enable
      post_login do
        send "enable\n"
        cmd vars(:enable)
      end
    end
    post_login 'no page'
    pre_logout "exit"
  end

  cfg :ssh do
    pty_options(chars_wide: 1000)
  end
end

Thanks, Matte. I finally got it working after looking at your config and realizing I should have been using the model section and not the group section :slight_smile:

Great to hear You solved it!!

BR Matte