nxos cliconf plugin refactor (#43203)

* nxos cliconf plugin refactor

Fixes #39056

*  Refactor nxos cliconf plugin as per new api definition
*  Minor changes in ios, eos, vyos cliconf plugin
*  Change nxos httpapi plugin edit_config method to be in sync with
   nxos cliconf edit_config

* Fix CI failure

* Fix unit test failure and review comment
This commit is contained in:
Ganesh Nalawade 2018-07-27 11:05:40 +05:30 committed by GitHub
parent e215f842ba
commit af3f510316
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 426 additions and 245 deletions

View file

@ -59,23 +59,6 @@ class Cliconf(CliconfBase):
def __init__(self, *args, **kwargs):
super(Cliconf, self).__init__(*args, **kwargs)
self._session_support = None
if isinstance(self._connection, NetworkCli):
self.network_api = 'network_cli'
elif isinstance(self._connection, HttpApi):
self.network_api = 'eapi'
else:
raise ValueError("Invalid connection type")
def _get_command_with_output(self, command, output):
options_values = self.get_option_values()
if output not in options_values['output']:
raise ValueError("'output' value %s is invalid. Valid values are %s" % (output, ','.join(options_values['output'])))
if output == 'json' and not command.endswith('| json'):
cmd = '%s | json' % command
else:
cmd = command
return cmd
def send_command(self, command, **kwargs):
"""Executes a cli command and returns the results
@ -83,10 +66,12 @@ class Cliconf(CliconfBase):
the results to the caller. The command output will be returned as a
string
"""
if self.network_api == 'network_cli':
if isinstance(self._connection, NetworkCli):
resp = super(Cliconf, self).send_command(command, **kwargs)
else:
elif isinstance(self._connection, HttpApi):
resp = self._connection.send_request(command, **kwargs)
else:
raise ValueError("Invalid connection type")
return resp
@enable_mode
@ -108,32 +93,19 @@ class Cliconf(CliconfBase):
return self.send_command(cmd)
@enable_mode
def edit_config(self, candidate=None, commit=True, replace=False, comment=None):
if not candidate:
raise ValueError("must provide a candidate config to load")
if commit not in (True, False):
raise ValueError("'commit' must be a bool, got %s" % commit)
def edit_config(self, candidate=None, commit=True, replace=None, comment=None):
operations = self.get_device_operations()
if replace not in (True, False):
raise ValueError("'replace' must be a bool, got %s" % replace)
if replace and not operations['supports_replace']:
raise ValueError("configuration replace is supported only with configuration session")
if comment and not operations['supports_commit_comment']:
raise ValueError("commit comment is not supported")
self.check_edit_config_capabiltiy(operations, candidate, commit, replace, comment)
if (commit is False) and (not self.supports_sessions):
raise ValueError('check mode is not supported without configuration session')
response = {}
resp = {}
session = None
if self.supports_sessions:
session = 'ansible_%s' % int(time.time())
response.update({'session': session})
resp.update({'session': session})
self.send_command('configure session %s' % session)
if replace:
self.send_command('rollback clean-config')
@ -141,6 +113,7 @@ class Cliconf(CliconfBase):
self.send_command('configure')
results = []
requests = []
multiline = False
for line in to_list(candidate):
if not isinstance(line, collections.Mapping):
@ -160,15 +133,17 @@ class Cliconf(CliconfBase):
if cmd != 'end' and cmd[0] != '!':
try:
results.append(self.send_command(**line))
requests.append(cmd)
except AnsibleConnectionFailure as e:
self.discard_changes(session)
raise AnsibleConnectionFailure(e.message)
response['response'] = results
resp['request'] = requests
resp['response'] = results
if self.supports_sessions:
out = self.send_command('show session-config diffs')
if out:
response['diff'] = out.strip()
resp['diff'] = out.strip()
if commit:
self.commit()
@ -176,7 +151,7 @@ class Cliconf(CliconfBase):
self.discard_changes(session)
else:
self.send_command('end')
return response
return resp
def get(self, command, prompt=None, answer=None, sendonly=False, output=None):
if output:
@ -224,7 +199,7 @@ class Cliconf(CliconfBase):
responses.append(out)
return responses
def get_diff(self, candidate=None, running=None, match='line', diff_ignore_lines=None, path=None, replace='line'):
def get_diff(self, candidate=None, running=None, diff_match='line', diff_ignore_lines=None, path=None, diff_replace='line'):
diff = {}
device_operations = self.get_device_operations()
option_values = self.get_option_values()
@ -232,26 +207,25 @@ class Cliconf(CliconfBase):
if candidate is None and device_operations['supports_generate_diff']:
raise ValueError("candidate configuration is required to generate diff")
if match not in option_values['diff_match']:
raise ValueError("'match' value %s in invalid, valid values are %s" % (match, ', '.join(option_values['diff_match'])))
if diff_match not in option_values['diff_match']:
raise ValueError("'match' value %s in invalid, valid values are %s" % (diff_match, ', '.join(option_values['diff_match'])))
if replace not in option_values['diff_replace']:
raise ValueError("'replace' value %s in invalid, valid values are %s" % (replace, ', '.join(option_values['diff_replace'])))
if diff_replace not in option_values['diff_replace']:
raise ValueError("'replace' value %s in invalid, valid values are %s" % (diff_replace, ', '.join(option_values['diff_replace'])))
# prepare candidate configuration
candidate_obj = NetworkConfig(indent=3)
candidate_obj.load(candidate)
if running and match != 'none' and replace != 'config':
if running and diff_match != 'none' and diff_replace != 'config':
# running configuration
running_obj = NetworkConfig(indent=3, contents=running, ignore_lines=diff_ignore_lines)
configdiffobjs = candidate_obj.difference(running_obj, path=path, match=match, replace=replace)
configdiffobjs = candidate_obj.difference(running_obj, path=path, match=diff_match, replace=diff_replace)
else:
configdiffobjs = candidate_obj.items
configdiff = dumps(configdiffobjs, 'commands') if configdiffobjs else ''
diff['config_diff'] = configdiff if configdiffobjs else {}
diff['config_diff'] = dumps(configdiffobjs, 'commands') if configdiffobjs else ''
return diff
@property
@ -317,8 +291,25 @@ class Cliconf(CliconfBase):
result = {}
result['rpc'] = self.get_base_rpc()
result['device_info'] = self.get_device_info()
result['network_api'] = self.network_api
result['device_info'] = self.get_device_info()
result['device_operations'] = self.get_device_operations()
result.update(self.get_option_values())
if isinstance(self._connection, NetworkCli):
result['network_api'] = 'cliconf'
elif isinstance(self._connection, HttpApi):
result['network_api'] = 'eapi'
else:
raise ValueError("Invalid connection type")
return json.dumps(result)
def _get_command_with_output(self, command, output):
options_values = self.get_option_values()
if output not in options_values['output']:
raise ValueError("'output' value %s is invalid. Valid values are %s" % (output, ','.join(options_values['output'])))
if output == 'json' and not command.endswith('| json'):
cmd = '%s | json' % command
else:
cmd = command
return cmd