Add support for commit label in iosxr_config (#42931)
* Add support for commit label in iosxr_config * sanity pep8 etc fixes
This commit is contained in:
parent
4f1746ee1d
commit
bf544c2200
4 changed files with 130 additions and 8 deletions
|
@ -27,6 +27,7 @@
|
||||||
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#
|
#
|
||||||
import json
|
import json
|
||||||
|
import re
|
||||||
from difflib import Differ
|
from difflib import Differ
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
@ -334,7 +335,8 @@ def discard_config(module):
|
||||||
conn.discard_changes()
|
conn.discard_changes()
|
||||||
|
|
||||||
|
|
||||||
def commit_config(module, comment=None, confirmed=False, confirm_timeout=None, persist=False, check=False):
|
def commit_config(module, comment=None, confirmed=False, confirm_timeout=None,
|
||||||
|
persist=False, check=False, label=None):
|
||||||
conn = get_connection(module)
|
conn = get_connection(module)
|
||||||
reply = None
|
reply = None
|
||||||
|
|
||||||
|
@ -344,7 +346,7 @@ def commit_config(module, comment=None, confirmed=False, confirm_timeout=None, p
|
||||||
if is_netconf(module):
|
if is_netconf(module):
|
||||||
reply = conn.commit(confirmed=confirmed, timeout=confirm_timeout, persist=persist)
|
reply = conn.commit(confirmed=confirmed, timeout=confirm_timeout, persist=persist)
|
||||||
elif is_cliconf(module):
|
elif is_cliconf(module):
|
||||||
reply = conn.commit(comment=comment)
|
reply = conn.commit(comment=comment, label=label)
|
||||||
|
|
||||||
return reply
|
return reply
|
||||||
|
|
||||||
|
@ -373,8 +375,18 @@ def get_config(module, config_filter=None, source='running'):
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
|
|
||||||
|
def check_existing_commit_labels(conn, label):
|
||||||
|
out = conn.get(command='show configuration history detail | include %s' % label)
|
||||||
|
label_exist = re.search(label, out, re.M)
|
||||||
|
if label_exist:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def load_config(module, command_filter, commit=False, replace=False,
|
def load_config(module, command_filter, commit=False, replace=False,
|
||||||
comment=None, admin=False, running=None, nc_get_filter=None):
|
comment=None, admin=False, running=None, nc_get_filter=None,
|
||||||
|
label=None):
|
||||||
|
|
||||||
conn = get_connection(module)
|
conn = get_connection(module)
|
||||||
|
|
||||||
|
@ -404,6 +416,16 @@ def load_config(module, command_filter, commit=False, replace=False,
|
||||||
elif is_cliconf(module):
|
elif is_cliconf(module):
|
||||||
# to keep the pre-cliconf behaviour, make a copy, avoid adding commands to input list
|
# to keep the pre-cliconf behaviour, make a copy, avoid adding commands to input list
|
||||||
cmd_filter = deepcopy(command_filter)
|
cmd_filter = deepcopy(command_filter)
|
||||||
|
# If label is present check if label already exist before entering
|
||||||
|
# config mode
|
||||||
|
if label:
|
||||||
|
old_label = check_existing_commit_labels(conn, label)
|
||||||
|
if old_label:
|
||||||
|
module.fail_json(
|
||||||
|
msg='commit label {%s} is already used for'
|
||||||
|
' an earlier commit, please choose a different label'
|
||||||
|
' and rerun task' % label
|
||||||
|
)
|
||||||
cmd_filter.insert(0, 'configure terminal')
|
cmd_filter.insert(0, 'configure terminal')
|
||||||
if admin:
|
if admin:
|
||||||
cmd_filter.insert(0, 'admin')
|
cmd_filter.insert(0, 'admin')
|
||||||
|
@ -424,7 +446,7 @@ def load_config(module, command_filter, commit=False, replace=False,
|
||||||
cmd.append('end')
|
cmd.append('end')
|
||||||
conn.edit_config(cmd)
|
conn.edit_config(cmd)
|
||||||
elif commit:
|
elif commit:
|
||||||
commit_config(module, comment=comment)
|
commit_config(module, comment=comment, label=label)
|
||||||
conn.edit_config('end')
|
conn.edit_config('end')
|
||||||
if admin:
|
if admin:
|
||||||
conn.edit_config('exit')
|
conn.edit_config('exit')
|
||||||
|
|
|
@ -135,6 +135,14 @@ options:
|
||||||
type: bool
|
type: bool
|
||||||
default: 'no'
|
default: 'no'
|
||||||
version_added: "2.4"
|
version_added: "2.4"
|
||||||
|
label:
|
||||||
|
description:
|
||||||
|
- Allows a commit label to be specified to be included when the
|
||||||
|
configuration is committed. A valid label must begin with an alphabet
|
||||||
|
and not exceed 30 characters, only alphabets, digits, hyphens and
|
||||||
|
underscores are allowed. If the configuration is not changed or
|
||||||
|
committed, this argument is ignored.
|
||||||
|
version_added: "2.7"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
EXAMPLES = """
|
EXAMPLES = """
|
||||||
|
@ -239,6 +247,18 @@ def check_args(module, warnings):
|
||||||
if module.params['comment']:
|
if module.params['comment']:
|
||||||
if len(module.params['comment']) > 60:
|
if len(module.params['comment']) > 60:
|
||||||
module.fail_json(msg='comment argument cannot be more than 60 characters')
|
module.fail_json(msg='comment argument cannot be more than 60 characters')
|
||||||
|
if module.params['label']:
|
||||||
|
label = module.params['label']
|
||||||
|
if len(label) > 30:
|
||||||
|
module.fail_json(msg='label argument cannot be more than 30 characters')
|
||||||
|
if not label[0].isalpha():
|
||||||
|
module.fail_json(msg='label argument must begin with an alphabet')
|
||||||
|
valid_chars = re.match(r'[\w-]*$', label)
|
||||||
|
if not valid_chars:
|
||||||
|
module.fail_json(
|
||||||
|
msg='label argument must only contain alphabets,' +
|
||||||
|
'digits, underscores or hyphens'
|
||||||
|
)
|
||||||
if module.params['force']:
|
if module.params['force']:
|
||||||
warnings.append('The force argument is deprecated, please use '
|
warnings.append('The force argument is deprecated, please use '
|
||||||
'match=none instead. This argument will be '
|
'match=none instead. This argument will be '
|
||||||
|
@ -340,6 +360,7 @@ def run(module, result):
|
||||||
comment = module.params['comment']
|
comment = module.params['comment']
|
||||||
admin = module.params['admin']
|
admin = module.params['admin']
|
||||||
check_mode = module.check_mode
|
check_mode = module.check_mode
|
||||||
|
label = module.params['label']
|
||||||
|
|
||||||
candidate_config = get_candidate(module)
|
candidate_config = get_candidate(module)
|
||||||
running_config = get_running_config(module)
|
running_config = get_running_config(module)
|
||||||
|
@ -376,7 +397,11 @@ def run(module, result):
|
||||||
result['commands'] = commands
|
result['commands'] = commands
|
||||||
|
|
||||||
commit = not check_mode
|
commit = not check_mode
|
||||||
diff = load_config(module, commands, commit=commit, replace=replace_config, comment=comment, admin=admin)
|
diff = load_config(
|
||||||
|
module, commands, commit=commit,
|
||||||
|
replace=replace_config, comment=comment, admin=admin,
|
||||||
|
label=label
|
||||||
|
)
|
||||||
if diff:
|
if diff:
|
||||||
result['diff'] = dict(prepared=diff)
|
result['diff'] = dict(prepared=diff)
|
||||||
|
|
||||||
|
@ -405,7 +430,8 @@ def main():
|
||||||
config=dict(),
|
config=dict(),
|
||||||
backup=dict(type='bool', default=False),
|
backup=dict(type='bool', default=False),
|
||||||
comment=dict(default=DEFAULT_COMMIT_COMMENT),
|
comment=dict(default=DEFAULT_COMMIT_COMMENT),
|
||||||
admin=dict(type='bool', default=False)
|
admin=dict(type='bool', default=False),
|
||||||
|
label=dict()
|
||||||
)
|
)
|
||||||
|
|
||||||
argument_spec.update(iosxr_argument_spec)
|
argument_spec.update(iosxr_argument_spec)
|
||||||
|
|
|
@ -89,9 +89,13 @@ class Cliconf(CliconfBase):
|
||||||
def get(self, command=None, prompt=None, answer=None, sendonly=False, newline=True):
|
def get(self, command=None, prompt=None, answer=None, sendonly=False, newline=True):
|
||||||
return self.send_command(command=command, prompt=prompt, answer=answer, sendonly=sendonly, newline=newline)
|
return self.send_command(command=command, prompt=prompt, answer=answer, sendonly=sendonly, newline=newline)
|
||||||
|
|
||||||
def commit(self, comment=None):
|
def commit(self, comment=None, label=None):
|
||||||
if comment:
|
if comment and label:
|
||||||
|
command = 'commit label {0} comment {1}'.format(label, comment)
|
||||||
|
elif comment:
|
||||||
command = 'commit comment {0}'.format(comment)
|
command = 'commit comment {0}'.format(comment)
|
||||||
|
elif label:
|
||||||
|
command = 'commit label {0}'.format(label)
|
||||||
else:
|
else:
|
||||||
command = 'commit'
|
command = 'commit'
|
||||||
self.send_command(command)
|
self.send_command(command)
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
---
|
||||||
|
- debug: msg="START cli/commit_label.yaml on connection={{ ansible_connection }}"
|
||||||
|
|
||||||
|
- name: setup
|
||||||
|
iosxr_config:
|
||||||
|
commands:
|
||||||
|
- no description
|
||||||
|
- no shutdown
|
||||||
|
parents:
|
||||||
|
- interface Loopback999
|
||||||
|
match: none
|
||||||
|
|
||||||
|
- name: get a unique and valid label
|
||||||
|
set_fact:
|
||||||
|
label: "ansible_{{ 1001 | random | to_uuid | truncate(20, true, '_') }}"
|
||||||
|
|
||||||
|
- name: configure device with a label and a comment
|
||||||
|
iosxr_config:
|
||||||
|
src: basic/config.j2
|
||||||
|
comment: "this is sensible commit message"
|
||||||
|
label: "{{ label }}"
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "result.changed == true"
|
||||||
|
|
||||||
|
- name: setup
|
||||||
|
iosxr_config:
|
||||||
|
commands:
|
||||||
|
- no description
|
||||||
|
- no shutdown
|
||||||
|
parents:
|
||||||
|
- interface Loopback999
|
||||||
|
match: none
|
||||||
|
|
||||||
|
- name: Try to commit with old label, fail with a msg that label is alreay used
|
||||||
|
iosxr_config:
|
||||||
|
src: basic/config.j2
|
||||||
|
label: "{{ label }}"
|
||||||
|
register: result
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "result.changed == false"
|
||||||
|
- "'already used' in result.msg"
|
||||||
|
|
||||||
|
- name: setup
|
||||||
|
iosxr_config:
|
||||||
|
commands:
|
||||||
|
- no description
|
||||||
|
- no shutdown
|
||||||
|
parents:
|
||||||
|
- interface Loopback999
|
||||||
|
match: none
|
||||||
|
|
||||||
|
- name: Try to commit with invalid chars($) in label
|
||||||
|
iosxr_config:
|
||||||
|
src: basic/config.j2
|
||||||
|
label: 'ansible_iosxr_config_$'
|
||||||
|
register: result
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "result.changed == false"
|
||||||
|
- "'only contain alphabets' in result.msg"
|
||||||
|
|
||||||
|
- debug: msg="END cli/commit_label.yaml on connection={{ ansible_connection }}"
|
Loading…
Reference in a new issue