Skip to content

Conversation

@autonomouse
Copy link

Added "config_mode_cmd='configure private'" to the send_config_set command for use with juniper switches.

Unfortunatley, this has to include a temporary hack to allow the config mode to be set to "configure private", because there is an output = self.config_mode() in send_config_set. This will override any external call to config_mode which is required to set it to 'configure private'. The real fix is needed upstream in the netmiko codebase, but until such time as that PR is accepted, this hack is necessary.

@autonomouse autonomouse changed the base branch from juniper to stackhpc/pike October 5, 2017 11:02
LOG.debug("Nothing to execute")
return

for count in range(num_retries):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need the multiple retries? I think I missed that bit of the conversation.

error=e)
LOG.debug(output)
if not final_attempt:
LOG.error(e)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think technically this this wants to be a warning log, would be an error log on the final error I think.

with netmiko.ConnectHandler(**self.config) as net_connect:
net_connect.enable()
output = net_connect.send_config_set(config_commands=cmd_set)
output = net_connect.send_config_set(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be tempted to split this into two commits, just so we have the history of each change described in the commit message, for when we come back to this.

ip='host')
connect_mock.send_config_set.assert_called_once_with(
config_commands=['spam ham aaaa'])
# FIXME: uncommented out once netmiko patch is accepted upstream:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I see any differences here? Which seems wrong I guess.

@autonomouse autonomouse force-pushed the retries_and_configure_private branch from 38ac4be to c82344d Compare October 5, 2017 11:04
output = net_connect._sanitize_output(output)
return output


Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This entire method is lifted from netmiko, with the only alterations being the selfs being changed to net_connects, config_mode now accepting config_mode_cmd as an arg, and the appropriate extra args passed in at the top

Copy link
Member

@JohnGarbutt JohnGarbutt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would really like to try an explicit call to set the config mode, rather than changing the existing method.

Either way we need to make sure this doesn't break the other drivers, which is simpler if its just one extra method call.

# config_mode_cmd='configure private',
# config_commands=cmd_set)
# FIXME: use the above, commented out version of
# send_config_set once netmiko patch is accepted upstream.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would try just adding this before the existing send_config_set(), I think that should be OK, because it only activates config mode if its not already enabled:

net_connect.config_mode(config_command='configure private')

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

technically we would need to copy the save_configuration pattern and add something like start_config_transaction() that is a no op for all drivers except the juniper.

I would have much more hope of getting the above accepted upstream, if that does turn out to work.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we want to go this route, we would need a new driver method I think, the default could call net_connect.send_config_set and the juniper driver can override that method with the above changes.

Having said that, I still think my preference is trying an explicit start configuration call that only gets made by the juniper.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just adding net_connect.config_mode(config_command='configure private') would be the ideal solution, I agree, but that's the problem.
As it stands, the send_config_set method in netmiko has a line that reads: output = self.config_mode()
so this will override any value provided (such as 'configure private') and revert to the default for the driver. In the case of juniper, that's ''.
This is why I have had to hack the whole send_config_set method, above.

It's a good point about making this juniper specific though. That was an oversight, I'll fix that now.

connect_mock = mock.MagicMock(SAVE_CONFIGURATION=None)
connect_mock.__enter__.return_value = connect_mock
nm_mock.return_value = connect_mock

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I guess we can drop this.

@autonomouse autonomouse force-pushed the retries_and_configure_private branch from 76825b0 to 7e1569b Compare October 5, 2017 12:46
@autonomouse autonomouse force-pushed the retries_and_configure_private branch from 7e1569b to 54f8727 Compare October 5, 2017 12:47
@autonomouse
Copy link
Author

I would too, but as config_mode() is always rerun just prior to write_channel when the content of cmd_set is executed, I don't see a way of doing this, other than what I've done here (at least until that PR to netmiko is accepted)

@autonomouse autonomouse force-pushed the retries_and_configure_private branch from 9c6874c to 0143af6 Compare October 5, 2017 15:03
Copy link

@markgoddard markgoddard left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Darren, some thoughts inline.

if exit_config_mode:
output += net_connect.exit_config_mode()
output = net_connect._sanitize_output(output)
return output

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this work:

    @tenacity.retry(reraise=True, stop=tenacity.stop_after_attempt(3),
                    wait=tenacity.wait_fixed(14))
    def send_config_set(self, net_connect, config_commands=None):
        net_connect.config_mode(config_command='configure private')
        net_connect.send_config_set(config_commands)

Once set to private config mode, netmiko should not change it to a different config mode.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a self.config_mode() call within send_config_set prior to any commands being sent, which presumable would reset the config_command back to it's defaults, which in the case of juniper, would be an empty string. Phil has suggested just monkey patching the config_mode, but it would still need to be called from a monkey-patched send_config_set so we may as well just override that, as I've done here.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, but it's a noop if the switch is already in config mode:

     def config_mode(self, config_command='', pattern=''):
         """Enter into config_mode."""
         output = ''
         if not self.check_config_mode():
             self.write_channel(self.normalize_cmd(config_command))
             output = self.read_until_pattern(pattern=pattern)
             if not self.check_config_mode():
                 raise ValueError("Failed to enter configuration mode.")
         return output

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, the monkey patching I'm suggesting would take place entirely in netmiko_devices.juniper.Juniper and amounts to overriding the superclass _get_connection(). Darren has my example code now to take a look at.

)

@tenacity.retry(reraise=True, stop=tenacity.stop_after_attempt(3),
wait=tenacity.wait_fixed(14))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

14 seconds seems like quite a long delay. Would it be better to allow more retries and a shorter interval?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Darren and I talked about this. I think he used this time based on my statement as to the average commit duration. I agree with your approach of more retries at a shorter interval.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, I think your retry could just be wrapped around the net_connect.commt() call in Juniper#save_configuration(), when the former raises a ValueError. You might want to check the error message, though, to only retry when it matches the expected error ('error: configuration database locked' or whatever it is).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds like a reasonable approach. If only they'd used a more specific exception we'd be more sure of what had gone wrong.

)

@tenacity.retry(reraise=True, stop=tenacity.stop_after_attempt(3),
wait=tenacity.wait_fixed(14))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In what conditions will this actually perform a retry? I'm not sure there is much error checking at this level, which is in itself an issue. For instance, if a bogus command were to be entered, I'm not sure that netmiko would detect the failure. It should detect failure to commit changes.

@markgoddard
Copy link

No longer required - superseded by #2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants