ytti / oxidized

Oxidized is a network device configuration backup tool. It's a RANCID replacement!
Apache License 2.0
2.8k stars 925 forks source link

Improve handling of enable mode? #926

Closed candlerb closed 1 year ago

candlerb commented 7 years ago

I have some Dell Powerconnect 5524 and an N1548.

5524 are fine. With the N1548, initially I was getting downloaded and stored config like this:

! 
! Machine Description............... Dell Networking Switch
! System Model ID................... N1548
! Machine Type...................... Dell Networking N1548
! Serial Number..................... XXXX
! Manufacturer...................... 0xbc00
! Burned In MAC Address............. XXXX.XXXX.XXXX
! System Object ID.................. 1.3.6.1.4.1.674.10895.3065
! SOC Version....................... BCM56150_A0
! HW Version........................ 2
! CPLD Version...................... 16
! 
! unit active      backup      current-active next-active
! ---- ----------- ----------- -------------- --------------
! 1    6.2.6.6     6.2.6.6     6.2.6.6        6.2.6.6
! 
! System Description: Dell Networking Switch
! USB Port Power Status:
! ----------------------
! Device Not Present
                                    ^
% Invalid input detected at '^' marker.

The problem was actually that I had not set an enable password in oxidized, and after configuring it was fine.

However it would be good if the powerconnect module (and perhaps others) could be more robust against problems with not being in enable mode when necessary. Ideas:

  1. Match the enable and non-enable prompts separately; error if we are not in enable mode and no enable password has been set. (This would basically auto-detect whether the enable command needs to be sent)

  2. If there is an error from command output, abort rather than accepting it as valid

I'm not sure the best way to approach this within oxidized framework. I see that ios.rb has some code to do this, but it is commented out and "non-preferred"

  # non-preferred way to handle additional PW prompt
  #expect /^[\w.]+>$/ do |data|
  #  send "enable\n"
  #  send vars(:enable) + "\n"
  #  data
  #end

As an aside, that code also doesn't check whether an enable password is prompted for. Some AAA configs will take you straight into enable mode when you type "enable".

ytti commented 7 years ago

The example is broken, send does not expect prompt. If prompt anyhow comes, then next cmd may end before it sees any new text, because it sees unconsumed prompt in output and decides it got the config.

We have at least 3 cases: a) no enable b) enable, but no password (returns to propmt) c) enable, with password (gets enable password prompt)

This would take care of those three cases:


post_login do
  if vars(:enable) == true
   cmd "enable"
  elsif vars(:enable)
    send "enable\n" ## optionally add second argument which is regexp for the enable pw prompt
    cmd vars(:enable)
  end
end
candlerb commented 7 years ago

That's better, but you still have to correctly configure which devices need enable plus password, which devices need enable, and which devices don't need enable.

Could this be handled automatically?

This would allow you to set a global default enable password, which would only be used when required.

ytti commented 7 years ago

Well this clearly isn't universal. Whole concept of 'enable' isn't universal. Prompt isn't universal. So what ever it is, it has to be in the model, not generic.

And if you have enable password, we cannot know what it is, so you have to give it to us, if you give it to us, we know we need to enable.

Only thing that could be improved, is case where enable is needed but not enable password. But which platforms cannot be configured to autoenable? I know IOS can (And should) be, so how many use cases i it actually covering?

candlerb commented 7 years ago

Actually, in rancid I also had to explicitly set add autoenable ... 1 to those devices which didn't require an enable command to be sent, so I can't really complain :-)

However, rancid (at least clogin) does automatically detect after sending the "enable" command whether any password needs to be sent or not:

    send "$enacmd\r"
    expect {
        -re "$u_prompt" { send -- "$enauser\r"; exp_continue}
        -re "$e_prompt" { send -- "$enapasswd\r"; exp_continue}
        "#"             { set prompt "#" }

In oxidized I have to set either enable: "string" or enable: True, which is not an unreasonable requirement. However if I map the "enable" var to a column in the CSV file, I can't set the True value. The only way I can think of doing this is to have a fake model:

models:
  powerconnect_autoenable:
    vars:
      enable: true
model_map:
  powerconnect_autoenable: powerconnect

That's a little messy. Alternatives might be to have a special sentinel value in the CSV file, or a separate autoenable var instead of the magic value enable: True.


Aside: I only reported this because I've just done a migration of a bunch of devices from rancid to oxidized, and oxidized is better than rancid in almost every way.

But with rancid, I do find login problems are easier to debug since you can run clogin and friends directly from the command line.

The approach I ended up with for oxidized was:

  1. comment out all of the devices except the first from router.db
  2. start oxidized with input debugging
  3. look at the log file
  4. fix that device
  5. comment it out and uncomment the next device
  6. go back to step 2

I didn't leave the previous devices uncommented, because each time I restart oxidized, it starts connecting to all devices again from scratch. Perhaps I could have changed router.db and then used the "reload" or "refresh" functionality in oxidized-web; I only realised this afterwards.

If oxidized-web had a button for "connect to this device now and show me the debug output", that would be awesome :-) (And also no automatic retries in that debug mode)

But I am nit-picking. After I had managed to work out why each device was failing to login, it is working very nicely now. Thank you!

ytti commented 7 years ago

"true" string in CVS file will become true value, so you can do it from CSV, if you can't its a bug.

This is nothing inherently stopping you from detecting enable prompt in model and sending enter if no enable is configured. We can look at the prompt, look if it has > and send enable + new line, per model.

For debugging, you're right. Easiest is just to have mock router.db with single device. I'm happy to accept PR for enhancements to debugging too.