mirror of https://github.com/ansible/ansible.git
ansible-test - Remove VyOS tests and support files (#83650)
The VyOS remote image required for running the tests is no longer functional.pull/83649/head
parent
d36dc70afc
commit
79f819dc54
@ -1 +0,0 @@
|
|||||||
network.sh
|
|
@ -0,0 +1,2 @@
|
|||||||
|
minor_changes:
|
||||||
|
- ansible-test - Removed the ``vyos/1.1.8`` network remote as it is no longer functional.
|
@ -1,2 +0,0 @@
|
|||||||
shippable/vyos/incidental
|
|
||||||
network/vyos
|
|
@ -1,3 +0,0 @@
|
|||||||
---
|
|
||||||
testcase: "*"
|
|
||||||
test_items: []
|
|
@ -1,26 +0,0 @@
|
|||||||
---
|
|
||||||
- name: collect all cli test cases
|
|
||||||
find:
|
|
||||||
paths: "{{ role_path }}/tests/cli"
|
|
||||||
patterns: "{{ testcase }}.yaml"
|
|
||||||
register: test_cases
|
|
||||||
delegate_to: localhost
|
|
||||||
|
|
||||||
- name: set test_items
|
|
||||||
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
|
|
||||||
|
|
||||||
- name: run test case (connection=ansible.netcommon.network_cli)
|
|
||||||
include_tasks: "file={{ test_case_to_run }}"
|
|
||||||
vars:
|
|
||||||
ansible_connection: ansible.netcommon.network_cli
|
|
||||||
with_items: "{{ test_items }}"
|
|
||||||
loop_control:
|
|
||||||
loop_var: test_case_to_run
|
|
||||||
|
|
||||||
- name: run test case (connection=local)
|
|
||||||
include_tasks: "file={{ test_case_to_run }}"
|
|
||||||
vars:
|
|
||||||
ansible_connection: local
|
|
||||||
with_first_found: "{{ test_items }}"
|
|
||||||
loop_control:
|
|
||||||
loop_var: test_case_to_run
|
|
@ -1,18 +0,0 @@
|
|||||||
---
|
|
||||||
- name: collect all cli_config test cases
|
|
||||||
find:
|
|
||||||
paths: "{{ role_path }}/tests/cli_config"
|
|
||||||
patterns: "{{ testcase }}.yaml"
|
|
||||||
register: test_cases
|
|
||||||
delegate_to: localhost
|
|
||||||
|
|
||||||
- name: set test_items
|
|
||||||
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
|
|
||||||
|
|
||||||
- name: run test case (connection=ansible.netcommon.network_cli)
|
|
||||||
include_tasks: "file={{ test_case_to_run }}"
|
|
||||||
vars:
|
|
||||||
ansible_connection: ansible.netcommon.network_cli
|
|
||||||
with_items: "{{ test_items }}"
|
|
||||||
loop_control:
|
|
||||||
loop_var: test_case_to_run
|
|
@ -1,3 +0,0 @@
|
|||||||
---
|
|
||||||
- {import_tasks: cli.yaml, tags: ['cli']}
|
|
||||||
- {import_tasks: cli_config.yaml, tags: ['cli_config']}
|
|
@ -1,113 +0,0 @@
|
|||||||
---
|
|
||||||
- debug: msg="START vyos/backup.yaml on connection={{ ansible_connection }}"
|
|
||||||
|
|
||||||
- name: collect any backup files
|
|
||||||
find:
|
|
||||||
paths: "{{ role_path }}/backup"
|
|
||||||
pattern: "{{ inventory_hostname_short }}_config*"
|
|
||||||
register: backup_files
|
|
||||||
connection: local
|
|
||||||
|
|
||||||
- name: delete backup files
|
|
||||||
file:
|
|
||||||
path: "{{ item.path }}"
|
|
||||||
state: absent
|
|
||||||
with_items: "{{backup_files.files|default([])}}"
|
|
||||||
|
|
||||||
- name: take configure backup
|
|
||||||
vyos.vyos.vyos_config:
|
|
||||||
backup: true
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == true"
|
|
||||||
|
|
||||||
- name: collect any backup files
|
|
||||||
find:
|
|
||||||
paths: "{{ role_path }}/backup"
|
|
||||||
pattern: "{{ inventory_hostname_short }}_config*"
|
|
||||||
register: backup_files
|
|
||||||
connection: local
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "backup_files.files is defined"
|
|
||||||
|
|
||||||
- name: delete configurable backup file path
|
|
||||||
file:
|
|
||||||
path: "{{ item }}"
|
|
||||||
state: absent
|
|
||||||
with_items:
|
|
||||||
- "{{ role_path }}/backup_test_dir/"
|
|
||||||
- "{{ role_path }}/backup/backup.cfg"
|
|
||||||
|
|
||||||
- name: take configuration backup in custom filename and directory path
|
|
||||||
vyos.vyos.vyos_config:
|
|
||||||
backup: true
|
|
||||||
backup_options:
|
|
||||||
filename: backup.cfg
|
|
||||||
dir_path: "{{ role_path }}/backup_test_dir/{{ inventory_hostname_short }}"
|
|
||||||
become: true
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == true"
|
|
||||||
|
|
||||||
- name: check if the backup file-1 exist
|
|
||||||
find:
|
|
||||||
paths: "{{ role_path }}/backup_test_dir/{{ inventory_hostname_short }}/backup.cfg"
|
|
||||||
register: backup_file
|
|
||||||
connection: local
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "backup_file.files is defined"
|
|
||||||
|
|
||||||
- name: take configuration backup in custom filename
|
|
||||||
vyos.vyos.vyos_config:
|
|
||||||
backup: true
|
|
||||||
backup_options:
|
|
||||||
filename: backup.cfg
|
|
||||||
become: true
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == true"
|
|
||||||
|
|
||||||
- name: check if the backup file-2 exist
|
|
||||||
find:
|
|
||||||
paths: "{{ role_path }}/backup/backup.cfg"
|
|
||||||
register: backup_file
|
|
||||||
connection: local
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "backup_file.files is defined"
|
|
||||||
|
|
||||||
- name: take configuration backup in custom path and default filename
|
|
||||||
vyos.vyos.vyos_config:
|
|
||||||
backup: true
|
|
||||||
backup_options:
|
|
||||||
dir_path: "{{ role_path }}/backup_test_dir/{{ inventory_hostname_short }}"
|
|
||||||
become: true
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == true"
|
|
||||||
|
|
||||||
- name: check if the backup file-3 exist
|
|
||||||
find:
|
|
||||||
paths: "{{ role_path }}/backup_test_dir/{{ inventory_hostname_short }}"
|
|
||||||
pattern: "{{ inventory_hostname_short }}_config*"
|
|
||||||
register: backup_file
|
|
||||||
connection: local
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "backup_file.files is defined"
|
|
||||||
|
|
||||||
- debug: msg="END vyos/backup.yaml on connection={{ ansible_connection }}"
|
|
@ -1,63 +0,0 @@
|
|||||||
---
|
|
||||||
- debug: msg="START cli/config_check.yaml on connection={{ ansible_connection }}"
|
|
||||||
|
|
||||||
- name: setup- ensure interface is not present
|
|
||||||
vyos.vyos.vyos_config:
|
|
||||||
lines: delete interfaces loopback lo
|
|
||||||
|
|
||||||
- name: setup- create interface
|
|
||||||
vyos.vyos.vyos_config:
|
|
||||||
lines:
|
|
||||||
- interfaces
|
|
||||||
- interfaces loopback lo
|
|
||||||
- interfaces loopback lo description test
|
|
||||||
register: result
|
|
||||||
|
|
||||||
# note collapsing the duplicate lines doesn't work if
|
|
||||||
# lines:
|
|
||||||
# - interfaces loopback lo description test
|
|
||||||
# - interfaces loopback lo
|
|
||||||
# - interfaces
|
|
||||||
|
|
||||||
- name: Check that multiple duplicate lines collapse into a single commands
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "{{ result.commands|length }} == 1"
|
|
||||||
|
|
||||||
- name: Check that set is correctly prepended
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "result.commands[0] == 'set interfaces loopback lo description test'"
|
|
||||||
|
|
||||||
- name: configure config_check config command
|
|
||||||
vyos.vyos.vyos_config:
|
|
||||||
lines: delete interfaces loopback lo
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == true"
|
|
||||||
|
|
||||||
- name: check config_check config command idempontent
|
|
||||||
vyos.vyos.vyos_config:
|
|
||||||
lines: delete interfaces loopback lo
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == false"
|
|
||||||
|
|
||||||
- name: check multiple line config filter is working
|
|
||||||
vyos.vyos.vyos_config:
|
|
||||||
lines:
|
|
||||||
- set system login user esa level admin
|
|
||||||
- set system login user esa authentication encrypted-password '!abc!'
|
|
||||||
- set system login user vyos level admin
|
|
||||||
- set system login user vyos authentication encrypted-password 'abc'
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "{{ result.filtered|length }} == 2"
|
|
||||||
|
|
||||||
- debug: msg="END cli/config_check.yaml on connection={{ ansible_connection }}"
|
|
@ -1,34 +0,0 @@
|
|||||||
---
|
|
||||||
- debug: msg="START cli/comment.yaml on connection={{ ansible_connection }}"
|
|
||||||
|
|
||||||
- name: setup
|
|
||||||
vyos.vyos.vyos_config:
|
|
||||||
lines: set system host-name {{ inventory_hostname_short }}
|
|
||||||
match: none
|
|
||||||
|
|
||||||
- name: configure using comment
|
|
||||||
vyos.vyos.vyos_config:
|
|
||||||
lines: set system host-name foo
|
|
||||||
comment: this is a test
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == true"
|
|
||||||
- "'set system host-name foo' in result.commands"
|
|
||||||
|
|
||||||
- name: collect system commits
|
|
||||||
vyos.vyos.vyos_command:
|
|
||||||
commands: show system commit
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "'this is a test' in result.stdout_lines[0][1]"
|
|
||||||
|
|
||||||
- name: teardown
|
|
||||||
vyos.vyos.vyos_config:
|
|
||||||
lines: set system host-name {{ inventory_hostname_short }}
|
|
||||||
match: none
|
|
||||||
|
|
||||||
- debug: msg="END cli/comment.yaml on connection={{ ansible_connection }}"
|
|
@ -1,3 +0,0 @@
|
|||||||
set service lldp
|
|
||||||
set protocols static
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
|||||||
---
|
|
||||||
- debug: msg="START cli/save.yaml on connection={{ ansible_connection }}"
|
|
||||||
|
|
||||||
- name: setup
|
|
||||||
vyos.vyos.vyos_config:
|
|
||||||
lines: set system host-name {{ inventory_hostname_short }}
|
|
||||||
match: none
|
|
||||||
|
|
||||||
- name: configure hostaname and save
|
|
||||||
vyos.vyos.vyos_config:
|
|
||||||
lines: set system host-name foo
|
|
||||||
save: true
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == true"
|
|
||||||
- "'set system host-name foo' in result.commands"
|
|
||||||
|
|
||||||
- name: configure hostaname and don't save
|
|
||||||
vyos.vyos.vyos_config:
|
|
||||||
lines: set system host-name bar
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == true"
|
|
||||||
- "'set system host-name bar' in result.commands"
|
|
||||||
|
|
||||||
- name: save config
|
|
||||||
vyos.vyos.vyos_config:
|
|
||||||
save: true
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == true"
|
|
||||||
|
|
||||||
- name: save config again
|
|
||||||
vyos.vyos.vyos_config:
|
|
||||||
save: true
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == false"
|
|
||||||
|
|
||||||
- name: teardown
|
|
||||||
vyos.vyos.vyos_config:
|
|
||||||
lines: set system host-name {{ inventory_hostname_short }}
|
|
||||||
match: none
|
|
||||||
save: true
|
|
||||||
|
|
||||||
- debug: msg="END cli/simple.yaml on connection={{ ansible_connection }}"
|
|
@ -1,53 +0,0 @@
|
|||||||
---
|
|
||||||
- debug: msg="START cli/simple.yaml on connection={{ ansible_connection }}"
|
|
||||||
|
|
||||||
- name: setup
|
|
||||||
vyos.vyos.vyos_config:
|
|
||||||
lines: set system host-name {{ inventory_hostname_short }}
|
|
||||||
match: none
|
|
||||||
|
|
||||||
- name: configure simple config command
|
|
||||||
vyos.vyos.vyos_config:
|
|
||||||
lines: set system host-name foo
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == true"
|
|
||||||
- "'set system host-name foo' in result.commands"
|
|
||||||
|
|
||||||
- name: check simple config command idempontent
|
|
||||||
vyos.vyos.vyos_config:
|
|
||||||
lines: set system host-name foo
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == false"
|
|
||||||
|
|
||||||
- name: Delete services
|
|
||||||
vyos.vyos.vyos_config: &del
|
|
||||||
lines:
|
|
||||||
- delete service lldp
|
|
||||||
- delete protocols static
|
|
||||||
|
|
||||||
- name: Configuring when commands starts with whitespaces
|
|
||||||
vyos.vyos.vyos_config:
|
|
||||||
src: "{{ role_path }}/tests/cli/config.cfg"
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == true"
|
|
||||||
- '"set service lldp" in result.commands'
|
|
||||||
- '"set protocols static" in result.commands'
|
|
||||||
|
|
||||||
- name: Delete services
|
|
||||||
vyos.vyos.vyos_config: *del
|
|
||||||
|
|
||||||
- name: teardown
|
|
||||||
vyos.vyos.vyos_config:
|
|
||||||
lines: set system host-name {{ inventory_hostname_short }}
|
|
||||||
match: none
|
|
||||||
|
|
||||||
- debug: msg="END cli/simple.yaml on connection={{ ansible_connection }}"
|
|
@ -1,114 +0,0 @@
|
|||||||
---
|
|
||||||
- debug: msg="END cli_config/backup.yaml on connection={{ ansible_connection }}"
|
|
||||||
|
|
||||||
- name: delete configurable backup file path
|
|
||||||
file:
|
|
||||||
path: "{{ item }}"
|
|
||||||
state: absent
|
|
||||||
with_items:
|
|
||||||
- "{{ role_path }}/backup_test_dir/"
|
|
||||||
- "{{ role_path }}/backup/backup.cfg"
|
|
||||||
|
|
||||||
- name: collect any backup files
|
|
||||||
find:
|
|
||||||
paths: "{{ role_path }}/backup"
|
|
||||||
pattern: "{{ inventory_hostname_short }}_config*"
|
|
||||||
register: backup_files
|
|
||||||
connection: local
|
|
||||||
|
|
||||||
- name: delete backup files
|
|
||||||
file:
|
|
||||||
path: "{{ item.path }}"
|
|
||||||
state: absent
|
|
||||||
with_items: "{{backup_files.files|default([])}}"
|
|
||||||
|
|
||||||
- name: take config backup
|
|
||||||
ansible.netcommon.cli_config:
|
|
||||||
backup: true
|
|
||||||
become: true
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == true"
|
|
||||||
|
|
||||||
- name: collect any backup files
|
|
||||||
find:
|
|
||||||
paths: "{{ role_path }}/backup"
|
|
||||||
pattern: "{{ inventory_hostname_short }}_config*"
|
|
||||||
register: backup_files
|
|
||||||
connection: local
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "backup_files.files is defined"
|
|
||||||
|
|
||||||
- name: take configuration backup in custom filename and directory path
|
|
||||||
ansible.netcommon.cli_config:
|
|
||||||
backup: true
|
|
||||||
backup_options:
|
|
||||||
filename: backup.cfg
|
|
||||||
dir_path: "{{ role_path }}/backup_test_dir/{{ inventory_hostname_short }}"
|
|
||||||
become: true
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == true"
|
|
||||||
|
|
||||||
- name: check if the backup file-1 exist
|
|
||||||
find:
|
|
||||||
paths: "{{ role_path }}/backup_test_dir/{{ inventory_hostname_short }}/backup.cfg"
|
|
||||||
register: backup_file
|
|
||||||
connection: local
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "backup_file.files is defined"
|
|
||||||
|
|
||||||
- name: take configuration backup in custom filename
|
|
||||||
ansible.netcommon.cli_config:
|
|
||||||
backup: true
|
|
||||||
backup_options:
|
|
||||||
filename: backup.cfg
|
|
||||||
become: true
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == true"
|
|
||||||
|
|
||||||
- name: check if the backup file-2 exist
|
|
||||||
find:
|
|
||||||
paths: "{{ role_path }}/backup/backup.cfg"
|
|
||||||
register: backup_file
|
|
||||||
connection: local
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "backup_file.files is defined"
|
|
||||||
|
|
||||||
- name: take configuration backup in custom path and default filename
|
|
||||||
ansible.netcommon.cli_config:
|
|
||||||
backup: true
|
|
||||||
backup_options:
|
|
||||||
dir_path: "{{ role_path }}/backup_test_dir/{{ inventory_hostname_short }}"
|
|
||||||
become: true
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == true"
|
|
||||||
|
|
||||||
- name: check if the backup file-3 exist
|
|
||||||
find:
|
|
||||||
paths: "{{ role_path }}/backup_test_dir/{{ inventory_hostname_short }}"
|
|
||||||
pattern: "{{ inventory_hostname_short }}_config*"
|
|
||||||
register: backup_file
|
|
||||||
connection: local
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "backup_file.files is defined"
|
|
||||||
|
|
||||||
- debug: msg="END cli_config/backup.yaml on connection={{ ansible_connection }}"
|
|
@ -1,28 +0,0 @@
|
|||||||
---
|
|
||||||
- debug: msg="START cli_config/cli_basic.yaml on connection={{ ansible_connection }}"
|
|
||||||
|
|
||||||
- name: setup - remove interface description
|
|
||||||
ansible.netcommon.cli_config: &rm
|
|
||||||
config: delete interfaces loopback lo description
|
|
||||||
|
|
||||||
- name: configure device with config
|
|
||||||
ansible.netcommon.cli_config: &conf
|
|
||||||
config: set interfaces loopback lo description 'this is a test'
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == true"
|
|
||||||
|
|
||||||
- name: Idempotence
|
|
||||||
ansible.netcommon.cli_config: *conf
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == false"
|
|
||||||
|
|
||||||
- name: teardown
|
|
||||||
ansible.netcommon.cli_config: *rm
|
|
||||||
|
|
||||||
- debug: msg="END cli_config/cli_basic.yaml on connection={{ ansible_connection }}"
|
|
@ -1,30 +0,0 @@
|
|||||||
---
|
|
||||||
- debug: msg="START cli_config/cli_comment.yaml on connection={{ ansible_connection }}"
|
|
||||||
|
|
||||||
- name: setup
|
|
||||||
ansible.netcommon.cli_config: &rm
|
|
||||||
config: set system host-name {{ inventory_hostname_short }}
|
|
||||||
|
|
||||||
- name: configure using comment
|
|
||||||
ansible.netcommon.cli_config:
|
|
||||||
config: set system host-name foo
|
|
||||||
commit_comment: this is a test
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == true"
|
|
||||||
|
|
||||||
- name: collect system commits
|
|
||||||
vyos.vyos.vyos_command:
|
|
||||||
commands: show system commit
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "'this is a test' in result.stdout_lines[0][1]"
|
|
||||||
|
|
||||||
- name: teardown
|
|
||||||
ansible.netcommon.cli_config: *rm
|
|
||||||
|
|
||||||
- debug: msg="END cli_config/cli_comment.yaml on connection={{ ansible_connection }}"
|
|
@ -1,2 +0,0 @@
|
|||||||
shippable/vyos/incidental
|
|
||||||
network/vyos
|
|
@ -1,3 +0,0 @@
|
|||||||
---
|
|
||||||
testcase: "[^_].*"
|
|
||||||
test_items: []
|
|
@ -1,3 +0,0 @@
|
|||||||
---
|
|
||||||
dependencies:
|
|
||||||
- incidental_vyos_prepare_tests
|
|
@ -1,19 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Collect all cli test cases
|
|
||||||
find:
|
|
||||||
paths: "{{ role_path }}/tests/cli"
|
|
||||||
patterns: "{{ testcase }}.yaml"
|
|
||||||
use_regex: true
|
|
||||||
register: test_cases
|
|
||||||
delegate_to: localhost
|
|
||||||
|
|
||||||
- name: Set test_items
|
|
||||||
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
|
|
||||||
|
|
||||||
- name: Run test case (connection=ansible.netcommon.network_cli)
|
|
||||||
include_tasks: "{{ test_case_to_run }}"
|
|
||||||
vars:
|
|
||||||
ansible_connection: ansible.netcommon.network_cli
|
|
||||||
with_items: "{{ test_items }}"
|
|
||||||
loop_control:
|
|
||||||
loop_var: test_case_to_run
|
|
@ -1,2 +0,0 @@
|
|||||||
---
|
|
||||||
- {import_tasks: cli.yaml, tags: ['cli']}
|
|
@ -1,14 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Setup
|
|
||||||
ansible.netcommon.cli_config:
|
|
||||||
config: "{{ lines }}"
|
|
||||||
vars:
|
|
||||||
lines: |
|
|
||||||
set service lldp interface eth1
|
|
||||||
set service lldp interface eth1 location civic-based country-code US
|
|
||||||
set service lldp interface eth1 location civic-based ca-type 0 ca-value ENGLISH
|
|
||||||
set service lldp interface eth2
|
|
||||||
set service lldp interface eth2 location coordinate-based latitude 33.524449N
|
|
||||||
set service lldp interface eth2 location coordinate-based altitude 2200
|
|
||||||
set service lldp interface eth2 location coordinate-based datum WGS84
|
|
||||||
set service lldp interface eth2 location coordinate-based longitude 222.267255W
|
|
@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Setup
|
|
||||||
ansible.netcommon.cli_config:
|
|
||||||
config: "{{ lines }}"
|
|
||||||
vars:
|
|
||||||
lines: |
|
|
||||||
set service lldp interface eth2
|
|
||||||
set service lldp interface eth2 location civic-based country-code US
|
|
||||||
set service lldp interface eth2 location civic-based ca-type 0 ca-value ENGLISH
|
|
||||||
set service lldp interface eth2 disable
|
|
@ -1,8 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Remove Config
|
|
||||||
ansible.netcommon.cli_config:
|
|
||||||
config: "{{ lines }}"
|
|
||||||
vars:
|
|
||||||
lines: |
|
|
||||||
delete service lldp interface
|
|
||||||
delete service lldp
|
|
@ -1,46 +0,0 @@
|
|||||||
---
|
|
||||||
- debug:
|
|
||||||
msg: "Start vyos_lldp_interfaces deleted integration tests ansible_connection={{ ansible_connection }}"
|
|
||||||
|
|
||||||
- include_tasks: _populate.yaml
|
|
||||||
|
|
||||||
- block:
|
|
||||||
- name: Delete attributes of given LLDP interfaces.
|
|
||||||
vyos.vyos.vyos_lldp_interfaces: &deleted
|
|
||||||
config:
|
|
||||||
- name: 'eth1'
|
|
||||||
- name: 'eth2'
|
|
||||||
state: deleted
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Assert that the before dicts were correctly generated
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "{{ populate | symmetric_difference(result['before']) |length == 0 }}"
|
|
||||||
|
|
||||||
- name: Assert that the correct set of commands were generated
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "{{ deleted['commands'] | symmetric_difference(result['commands']) |length == 0 }}"
|
|
||||||
|
|
||||||
- name: Assert that the after dicts were correctly generated
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "{{ deleted['after'] | symmetric_difference(result['after']) |length == 0 }}"
|
|
||||||
|
|
||||||
- name: Delete attributes of given interfaces (IDEMPOTENT)
|
|
||||||
vyos.vyos.vyos_lldp_interfaces: *deleted
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Assert that the previous task was idempotent
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == false"
|
|
||||||
- "result.commands|length == 0"
|
|
||||||
|
|
||||||
- name: Assert that the before dicts were correctly generated
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "{{ deleted['after'] | symmetric_difference(result['before']) |length == 0 }}"
|
|
||||||
always:
|
|
||||||
- include_tasks: _remove_config.yaml
|
|
@ -1,36 +0,0 @@
|
|||||||
---
|
|
||||||
- debug:
|
|
||||||
msg: "START vyos_lldp_interfaces empty_config integration tests on connection={{ ansible_connection }}"
|
|
||||||
|
|
||||||
- name: Merged with empty config should give appropriate error message
|
|
||||||
vyos.vyos.vyos_lldp_interfaces:
|
|
||||||
config:
|
|
||||||
state: merged
|
|
||||||
register: result
|
|
||||||
ignore_errors: true
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- result.msg == 'value of config parameter must not be empty for state merged'
|
|
||||||
|
|
||||||
- name: Replaced with empty config should give appropriate error message
|
|
||||||
vyos.vyos.vyos_lldp_interfaces:
|
|
||||||
config:
|
|
||||||
state: replaced
|
|
||||||
register: result
|
|
||||||
ignore_errors: true
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- result.msg == 'value of config parameter must not be empty for state replaced'
|
|
||||||
|
|
||||||
- name: Overridden with empty config should give appropriate error message
|
|
||||||
vyos.vyos.vyos_lldp_interfaces:
|
|
||||||
config:
|
|
||||||
state: overridden
|
|
||||||
register: result
|
|
||||||
ignore_errors: true
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- result.msg == 'value of config parameter must not be empty for state overridden'
|
|
@ -1,58 +0,0 @@
|
|||||||
---
|
|
||||||
- debug:
|
|
||||||
msg: "START vyos_lldp_interfaces merged integration tests on connection={{ ansible_connection }}"
|
|
||||||
|
|
||||||
- include_tasks: _remove_config.yaml
|
|
||||||
|
|
||||||
- block:
|
|
||||||
- name: Merge the provided configuration with the exisiting running configuration
|
|
||||||
vyos.vyos.vyos_lldp_interfaces: &merged
|
|
||||||
config:
|
|
||||||
- name: 'eth1'
|
|
||||||
location:
|
|
||||||
civic_based:
|
|
||||||
country_code: 'US'
|
|
||||||
ca_info:
|
|
||||||
- ca_type: 0
|
|
||||||
ca_value: 'ENGLISH'
|
|
||||||
|
|
||||||
- name: 'eth2'
|
|
||||||
location:
|
|
||||||
coordinate_based:
|
|
||||||
altitude: 2200
|
|
||||||
datum: 'WGS84'
|
|
||||||
longitude: '222.267255W'
|
|
||||||
latitude: '33.524449N'
|
|
||||||
state: merged
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Assert that before dicts were correctly generated
|
|
||||||
assert:
|
|
||||||
that: "{{ merged['before'] | symmetric_difference(result['before']) |length == 0 }}"
|
|
||||||
|
|
||||||
- name: Assert that correct set of commands were generated
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "{{ merged['commands'] | symmetric_difference(result['commands']) |length == 0 }}"
|
|
||||||
|
|
||||||
- name: Assert that after dicts was correctly generated
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "{{ merged['after'] | symmetric_difference(result['after']) |length == 0 }}"
|
|
||||||
|
|
||||||
- name: Merge the provided configuration with the existing running configuration (IDEMPOTENT)
|
|
||||||
vyos.vyos.vyos_lldp_interfaces: *merged
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Assert that the previous task was idempotent
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "result['changed'] == false"
|
|
||||||
|
|
||||||
- name: Assert that before dicts were correctly generated
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "{{ merged['after'] | symmetric_difference(result['before']) |length == 0 }}"
|
|
||||||
|
|
||||||
always:
|
|
||||||
- include_tasks: _remove_config.yaml
|
|
@ -1,49 +0,0 @@
|
|||||||
---
|
|
||||||
- debug:
|
|
||||||
msg: "START vyos_lldp_interfaces overridden integration tests on connection={{ ansible_connection }}"
|
|
||||||
|
|
||||||
- include_tasks: _remove_config.yaml
|
|
||||||
|
|
||||||
- include_tasks: _populate_intf.yaml
|
|
||||||
|
|
||||||
- block:
|
|
||||||
- name: Overrides all device configuration with provided configuration
|
|
||||||
vyos.vyos.vyos_lldp_interfaces: &overridden
|
|
||||||
config:
|
|
||||||
- name: 'eth2'
|
|
||||||
location:
|
|
||||||
elin: '0000000911'
|
|
||||||
state: overridden
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Assert that before dicts were correctly generated
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "{{ populate_intf | symmetric_difference(result['before']) |length == 0 }}"
|
|
||||||
|
|
||||||
- name: Assert that correct commands were generated
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "{{ overridden['commands'] | symmetric_difference(result['commands']) |length == 0 }}"
|
|
||||||
|
|
||||||
- name: Assert that after dicts were correctly generated
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "{{ overridden['after'] | symmetric_difference(result['after']) |length == 0 }}"
|
|
||||||
|
|
||||||
- name: Overrides all device configuration with provided configurations (IDEMPOTENT)
|
|
||||||
vyos.vyos.vyos_lldp_interfaces: *overridden
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Assert that the previous task was idempotent
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "result['changed'] == false"
|
|
||||||
|
|
||||||
- name: Assert that before dicts were correctly generated
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "{{ overridden['after'] | symmetric_difference(result['before']) |length == 0 }}"
|
|
||||||
|
|
||||||
always:
|
|
||||||
- include_tasks: _remove_config.yaml
|
|
@ -1,63 +0,0 @@
|
|||||||
---
|
|
||||||
- debug:
|
|
||||||
msg: "START vyos_lldp_interfaces replaced integration tests on connection={{ ansible_connection }}"
|
|
||||||
|
|
||||||
- include_tasks: _remove_config.yaml
|
|
||||||
|
|
||||||
- include_tasks: _populate.yaml
|
|
||||||
|
|
||||||
- block:
|
|
||||||
- name: Replace device configurations of listed LLDP interfaces with provided configurations
|
|
||||||
vyos.vyos.vyos_lldp_interfaces: &replaced
|
|
||||||
config:
|
|
||||||
- name: 'eth2'
|
|
||||||
enable: false
|
|
||||||
location:
|
|
||||||
civic_based:
|
|
||||||
country_code: 'US'
|
|
||||||
ca_info:
|
|
||||||
- ca_type: 0
|
|
||||||
ca_value: 'ENGLISH'
|
|
||||||
|
|
||||||
- name: 'eth1'
|
|
||||||
enable: false
|
|
||||||
location:
|
|
||||||
coordinate_based:
|
|
||||||
altitude: 2200
|
|
||||||
datum: 'WGS84'
|
|
||||||
longitude: '222.267255W'
|
|
||||||
latitude: '33.524449N'
|
|
||||||
state: replaced
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Assert that correct set of commands were generated
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "{{ replaced['commands'] | symmetric_difference(result['commands']) |length == 0 }}"
|
|
||||||
|
|
||||||
- name: Assert that before dicts are correctly generated
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "{{ populate | symmetric_difference(result['before']) |length == 0 }}"
|
|
||||||
|
|
||||||
- name: Assert that after dict is correctly generated
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "{{ replaced['after'] | symmetric_difference(result['after']) |length == 0 }}"
|
|
||||||
|
|
||||||
- name: Replace device configurations of listed LLDP interfaces with provided configurarions (IDEMPOTENT)
|
|
||||||
vyos.vyos.vyos_lldp_interfaces: *replaced
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Assert that task was idempotent
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "result['changed'] == false"
|
|
||||||
|
|
||||||
- name: Assert that before dict is correctly generated
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "{{ replaced['after'] | symmetric_difference(result['before']) |length == 0 }}"
|
|
||||||
|
|
||||||
always:
|
|
||||||
- include_tasks: _remove_config.yaml
|
|
@ -1,57 +0,0 @@
|
|||||||
---
|
|
||||||
- debug:
|
|
||||||
msg: "START vyos_lldp_interfaces round trip integration tests on connection={{ ansible_connection }}"
|
|
||||||
|
|
||||||
- include_tasks: _remove_config.yaml
|
|
||||||
|
|
||||||
- block:
|
|
||||||
- name: Apply the provided configuration (base config)
|
|
||||||
vyos.vyos.vyos_lldp_interfaces:
|
|
||||||
config:
|
|
||||||
- name: 'eth1'
|
|
||||||
location:
|
|
||||||
civic_based:
|
|
||||||
country_code: 'US'
|
|
||||||
ca_info:
|
|
||||||
- ca_type: 0
|
|
||||||
ca_value: 'ENGLISH'
|
|
||||||
|
|
||||||
state: merged
|
|
||||||
register: base_config
|
|
||||||
|
|
||||||
- name: Gather lldp_interfaces facts
|
|
||||||
vyos.vyos.vyos_facts:
|
|
||||||
gather_subset:
|
|
||||||
- default
|
|
||||||
gather_network_resources:
|
|
||||||
- lldp_interfaces
|
|
||||||
|
|
||||||
- name: Apply the provided configuration (config to be reverted)
|
|
||||||
vyos.vyos.vyos_lldp_interfaces:
|
|
||||||
config:
|
|
||||||
- name: 'eth2'
|
|
||||||
location:
|
|
||||||
coordinate_based:
|
|
||||||
altitude: 2200
|
|
||||||
datum: 'WGS84'
|
|
||||||
longitude: '222.267255W'
|
|
||||||
latitude: '33.524449N'
|
|
||||||
state: merged
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Assert that changes were applied
|
|
||||||
assert:
|
|
||||||
that: "{{ round_trip['after'] | symmetric_difference(result['after']) |length == 0 }}"
|
|
||||||
|
|
||||||
- name: Revert back to base config using facts round trip
|
|
||||||
vyos.vyos.vyos_lldp_interfaces:
|
|
||||||
config: "{{ ansible_facts['network_resources']['lldp_interfaces'] }}"
|
|
||||||
state: overridden
|
|
||||||
register: revert
|
|
||||||
|
|
||||||
- name: Assert that config was reverted
|
|
||||||
assert:
|
|
||||||
that: "{{ base_config['after'] | symmetric_difference(revert['after']) |length == 0 }}"
|
|
||||||
|
|
||||||
always:
|
|
||||||
- include_tasks: _remove_config.yaml
|
|
@ -1,130 +0,0 @@
|
|||||||
---
|
|
||||||
merged:
|
|
||||||
before: []
|
|
||||||
|
|
||||||
|
|
||||||
commands:
|
|
||||||
- "set service lldp interface eth1 location civic-based country-code 'US'"
|
|
||||||
- "set service lldp interface eth1 location civic-based ca-type 0 ca-value 'ENGLISH'"
|
|
||||||
- "set service lldp interface eth1"
|
|
||||||
- "set service lldp interface eth2 location coordinate-based latitude '33.524449N'"
|
|
||||||
- "set service lldp interface eth2 location coordinate-based altitude '2200'"
|
|
||||||
- "set service lldp interface eth2 location coordinate-based datum 'WGS84'"
|
|
||||||
- "set service lldp interface eth2 location coordinate-based longitude '222.267255W'"
|
|
||||||
- "set service lldp interface eth2 location coordinate-based latitude '33.524449N'"
|
|
||||||
- "set service lldp interface eth2 location coordinate-based altitude '2200'"
|
|
||||||
- "set service lldp interface eth2 location coordinate-based datum 'WGS84'"
|
|
||||||
- "set service lldp interface eth2 location coordinate-based longitude '222.267255W'"
|
|
||||||
- "set service lldp interface eth2"
|
|
||||||
|
|
||||||
after:
|
|
||||||
- name: 'eth1'
|
|
||||||
location:
|
|
||||||
civic_based:
|
|
||||||
country_code: 'US'
|
|
||||||
ca_info:
|
|
||||||
- ca_type: 0
|
|
||||||
ca_value: 'ENGLISH'
|
|
||||||
|
|
||||||
- name: 'eth2'
|
|
||||||
location:
|
|
||||||
coordinate_based:
|
|
||||||
altitude: 2200
|
|
||||||
datum: 'WGS84'
|
|
||||||
longitude: '222.267255W'
|
|
||||||
latitude: '33.524449N'
|
|
||||||
|
|
||||||
populate:
|
|
||||||
- name: 'eth1'
|
|
||||||
location:
|
|
||||||
civic_based:
|
|
||||||
country_code: 'US'
|
|
||||||
ca_info:
|
|
||||||
- ca_type: 0
|
|
||||||
ca_value: 'ENGLISH'
|
|
||||||
|
|
||||||
- name: 'eth2'
|
|
||||||
location:
|
|
||||||
coordinate_based:
|
|
||||||
altitude: 2200
|
|
||||||
datum: 'WGS84'
|
|
||||||
longitude: '222.267255W'
|
|
||||||
latitude: '33.524449N'
|
|
||||||
|
|
||||||
replaced:
|
|
||||||
commands:
|
|
||||||
- "delete service lldp interface eth2 location"
|
|
||||||
- "set service lldp interface eth2 'disable'"
|
|
||||||
- "set service lldp interface eth2 location civic-based country-code 'US'"
|
|
||||||
- "set service lldp interface eth2 location civic-based ca-type 0 ca-value 'ENGLISH'"
|
|
||||||
- "delete service lldp interface eth1 location"
|
|
||||||
- "set service lldp interface eth1 'disable'"
|
|
||||||
- "set service lldp interface eth1 location coordinate-based latitude '33.524449N'"
|
|
||||||
- "set service lldp interface eth1 location coordinate-based altitude '2200'"
|
|
||||||
- "set service lldp interface eth1 location coordinate-based datum 'WGS84'"
|
|
||||||
- "set service lldp interface eth1 location coordinate-based longitude '222.267255W'"
|
|
||||||
|
|
||||||
after:
|
|
||||||
- name: 'eth2'
|
|
||||||
enable: false
|
|
||||||
location:
|
|
||||||
civic_based:
|
|
||||||
country_code: 'US'
|
|
||||||
ca_info:
|
|
||||||
- ca_type: 0
|
|
||||||
ca_value: 'ENGLISH'
|
|
||||||
|
|
||||||
- name: 'eth1'
|
|
||||||
enable: false
|
|
||||||
location:
|
|
||||||
coordinate_based:
|
|
||||||
altitude: 2200
|
|
||||||
datum: 'WGS84'
|
|
||||||
longitude: '222.267255W'
|
|
||||||
latitude: '33.524449N'
|
|
||||||
|
|
||||||
populate_intf:
|
|
||||||
- name: 'eth2'
|
|
||||||
enable: false
|
|
||||||
location:
|
|
||||||
civic_based:
|
|
||||||
country_code: 'US'
|
|
||||||
ca_info:
|
|
||||||
- ca_type: 0
|
|
||||||
ca_value: 'ENGLISH'
|
|
||||||
|
|
||||||
overridden:
|
|
||||||
commands:
|
|
||||||
- "delete service lldp interface eth2 location"
|
|
||||||
- "delete service lldp interface eth2 'disable'"
|
|
||||||
- "set service lldp interface eth2 location elin '0000000911'"
|
|
||||||
|
|
||||||
after:
|
|
||||||
- name: 'eth2'
|
|
||||||
location:
|
|
||||||
elin: 0000000911
|
|
||||||
|
|
||||||
deleted:
|
|
||||||
commands:
|
|
||||||
- "delete service lldp interface eth1"
|
|
||||||
- "delete service lldp interface eth2"
|
|
||||||
|
|
||||||
after: []
|
|
||||||
|
|
||||||
round_trip:
|
|
||||||
after:
|
|
||||||
- name: 'eth1'
|
|
||||||
location:
|
|
||||||
civic_based:
|
|
||||||
country_code: 'US'
|
|
||||||
ca_info:
|
|
||||||
- ca_type: 0
|
|
||||||
ca_value: 'ENGLISH'
|
|
||||||
|
|
||||||
- name: 'eth2'
|
|
||||||
location:
|
|
||||||
coordinate_based:
|
|
||||||
altitude: 2200
|
|
||||||
datum: 'WGS84'
|
|
||||||
longitude: '222.267255W'
|
|
||||||
latitude: '33.524449N'
|
|
@ -1 +0,0 @@
|
|||||||
hidden
|
|
@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Ensure required interfaces are present in running-config
|
|
||||||
ansible.netcommon.cli_config:
|
|
||||||
config: "{{ lines }}"
|
|
||||||
vars:
|
|
||||||
lines: |
|
|
||||||
set interfaces ethernet eth0 address dhcp
|
|
||||||
set interfaces ethernet eth0 speed auto
|
|
||||||
set interfaces ethernet eth0 duplex auto
|
|
||||||
set interfaces ethernet eth1
|
|
||||||
set interfaces ethernet eth2
|
|
||||||
delete interfaces loopback lo
|
|
||||||
ignore_errors: true
|
|
@ -1,3 +0,0 @@
|
|||||||
# Keeping incidental for efficiency, to avoid spinning up another VM
|
|
||||||
shippable/vyos/incidental
|
|
||||||
network/vyos
|
|
@ -1,14 +0,0 @@
|
|||||||
- hosts: vyos
|
|
||||||
gather_facts: false
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Run whoami
|
|
||||||
vyos.vyos.vyos_command:
|
|
||||||
commands:
|
|
||||||
- whoami
|
|
||||||
register: whoami
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- whoami is successful
|
|
||||||
- whoami.stdout_lines[0][0] == 'atester'
|
|
@ -1,27 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -eux
|
|
||||||
export ANSIBLE_ROLES_PATH=../
|
|
||||||
|
|
||||||
function cleanup {
|
|
||||||
ansible-playbook teardown.yml -i "$INVENTORY_PATH" "$@"
|
|
||||||
}
|
|
||||||
|
|
||||||
trap cleanup EXIT
|
|
||||||
|
|
||||||
ansible-playbook setup.yml -i "$INVENTORY_PATH" "$@"
|
|
||||||
|
|
||||||
# We need a nonempty file to override key with (empty file gives a
|
|
||||||
# lovely "list index out of range" error)
|
|
||||||
foo=$(mktemp)
|
|
||||||
echo hello > "$foo"
|
|
||||||
|
|
||||||
# We want to ensure that passwords make it to the network connection plugins
|
|
||||||
# because they follow a different path than the rest of the codebase.
|
|
||||||
# In setup.yml, we create a passworded user, and now we connect as that user
|
|
||||||
# to make sure the password we pass here successfully makes it to the plugin.
|
|
||||||
ansible-playbook \
|
|
||||||
-i "$INVENTORY_PATH" \
|
|
||||||
-e ansible_user=atester \
|
|
||||||
-e ansible_password=testymctest \
|
|
||||||
-e ansible_ssh_private_key_file="$foo" \
|
|
||||||
passworded_user.yml
|
|
@ -1,14 +0,0 @@
|
|||||||
- hosts: vyos
|
|
||||||
connection: ansible.netcommon.network_cli
|
|
||||||
become: true
|
|
||||||
gather_facts: false
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Create user with password
|
|
||||||
register: result
|
|
||||||
vyos.vyos.vyos_config:
|
|
||||||
lines:
|
|
||||||
- set system login user atester full-name "Ansible Tester"
|
|
||||||
- set system login user atester authentication plaintext-password testymctest
|
|
||||||
- set system login user jsmith level admin
|
|
||||||
- delete service ssh disable-password-authentication
|
|
@ -1,14 +0,0 @@
|
|||||||
- hosts: vyos
|
|
||||||
connection: ansible.netcommon.network_cli
|
|
||||||
become: true
|
|
||||||
gather_facts: false
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Get rid of user (undo everything from setup.yml)
|
|
||||||
register: result
|
|
||||||
vyos.vyos.vyos_config:
|
|
||||||
lines:
|
|
||||||
- delete system login user atester full-name "Ansible Tester"
|
|
||||||
- delete system login user atester authentication plaintext-password testymctest
|
|
||||||
- delete system login user jsmith level admin
|
|
||||||
- set service ssh disable-password-authentication
|
|
@ -1,128 +0,0 @@
|
|||||||
#
|
|
||||||
# (c) 2016 Red Hat Inc.
|
|
||||||
#
|
|
||||||
# This file is part of Ansible
|
|
||||||
#
|
|
||||||
# Ansible is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Ansible is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import copy
|
|
||||||
|
|
||||||
from ansible_collections.ansible.netcommon.plugins.action.network import (
|
|
||||||
ActionModule as ActionNetworkModule,
|
|
||||||
)
|
|
||||||
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
|
|
||||||
load_provider,
|
|
||||||
)
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (
|
|
||||||
vyos_provider_spec,
|
|
||||||
)
|
|
||||||
from ansible.utils.display import Display
|
|
||||||
|
|
||||||
display = Display()
|
|
||||||
|
|
||||||
|
|
||||||
class ActionModule(ActionNetworkModule):
|
|
||||||
def run(self, tmp=None, task_vars=None):
|
|
||||||
del tmp # tmp no longer has any effect
|
|
||||||
|
|
||||||
module_name = self._task.action.split(".")[-1]
|
|
||||||
self._config_module = True if module_name == "vyos_config" else False
|
|
||||||
persistent_connection = self._play_context.connection.split(".")[-1]
|
|
||||||
warnings = []
|
|
||||||
|
|
||||||
if persistent_connection == "network_cli":
|
|
||||||
provider = self._task.args.get("provider", {})
|
|
||||||
if any(provider.values()):
|
|
||||||
display.warning(
|
|
||||||
"provider is unnecessary when using network_cli and will be ignored"
|
|
||||||
)
|
|
||||||
del self._task.args["provider"]
|
|
||||||
elif self._play_context.connection == "local":
|
|
||||||
provider = load_provider(vyos_provider_spec, self._task.args)
|
|
||||||
pc = copy.deepcopy(self._play_context)
|
|
||||||
pc.connection = "ansible.netcommon.network_cli"
|
|
||||||
pc.network_os = "vyos.vyos.vyos"
|
|
||||||
pc.remote_addr = provider["host"] or self._play_context.remote_addr
|
|
||||||
pc.port = int(provider["port"] or self._play_context.port or 22)
|
|
||||||
pc.remote_user = (
|
|
||||||
provider["username"] or self._play_context.connection_user
|
|
||||||
)
|
|
||||||
pc.password = provider["password"] or self._play_context.password
|
|
||||||
pc.private_key_file = (
|
|
||||||
provider["ssh_keyfile"] or self._play_context.private_key_file
|
|
||||||
)
|
|
||||||
|
|
||||||
connection = self._shared_loader_obj.connection_loader.get(
|
|
||||||
"ansible.netcommon.persistent",
|
|
||||||
pc,
|
|
||||||
sys.stdin,
|
|
||||||
task_uuid=self._task._uuid,
|
|
||||||
)
|
|
||||||
|
|
||||||
# TODO: Remove below code after ansible minimal is cut out
|
|
||||||
if connection is None:
|
|
||||||
pc.connection = "network_cli"
|
|
||||||
pc.network_os = "vyos"
|
|
||||||
connection = self._shared_loader_obj.connection_loader.get(
|
|
||||||
"persistent", pc, sys.stdin, task_uuid=self._task._uuid
|
|
||||||
)
|
|
||||||
|
|
||||||
display.vvv(
|
|
||||||
"using connection plugin %s (was local)" % pc.connection,
|
|
||||||
pc.remote_addr,
|
|
||||||
)
|
|
||||||
|
|
||||||
command_timeout = (
|
|
||||||
int(provider["timeout"])
|
|
||||||
if provider["timeout"]
|
|
||||||
else connection.get_option("persistent_command_timeout")
|
|
||||||
)
|
|
||||||
connection.set_options(
|
|
||||||
direct={"persistent_command_timeout": command_timeout}
|
|
||||||
)
|
|
||||||
|
|
||||||
socket_path = connection.run()
|
|
||||||
display.vvvv("socket_path: %s" % socket_path, pc.remote_addr)
|
|
||||||
if not socket_path:
|
|
||||||
return {
|
|
||||||
"failed": True,
|
|
||||||
"msg": "unable to open shell. Please see: "
|
|
||||||
+ "https://docs.ansible.com/ansible/latest/network/user_guide/network_debug_troubleshooting.html#category-unable-to-open-shell",
|
|
||||||
}
|
|
||||||
|
|
||||||
task_vars["ansible_socket"] = socket_path
|
|
||||||
warnings.append(
|
|
||||||
[
|
|
||||||
"connection local support for this module is deprecated and will be removed in version 2.14, use connection %s"
|
|
||||||
% pc.connection
|
|
||||||
]
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return {
|
|
||||||
"failed": True,
|
|
||||||
"msg": "Connection type %s is not valid for this module"
|
|
||||||
% self._play_context.connection,
|
|
||||||
}
|
|
||||||
|
|
||||||
result = super(ActionModule, self).run(task_vars=task_vars)
|
|
||||||
if warnings:
|
|
||||||
if "warnings" in result:
|
|
||||||
result["warnings"].extend(warnings)
|
|
||||||
else:
|
|
||||||
result["warnings"] = warnings
|
|
||||||
return result
|
|
@ -1,342 +0,0 @@
|
|||||||
#
|
|
||||||
# (c) 2017 Red Hat Inc.
|
|
||||||
#
|
|
||||||
# This file is part of Ansible
|
|
||||||
#
|
|
||||||
# Ansible is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Ansible is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
|
|
||||||
DOCUMENTATION = """
|
|
||||||
---
|
|
||||||
author: Ansible Networking Team
|
|
||||||
cliconf: vyos
|
|
||||||
short_description: Use vyos cliconf to run command on VyOS platform
|
|
||||||
description:
|
|
||||||
- This vyos plugin provides low level abstraction apis for
|
|
||||||
sending and receiving CLI commands from VyOS network devices.
|
|
||||||
version_added: "2.4"
|
|
||||||
"""
|
|
||||||
|
|
||||||
import re
|
|
||||||
import json
|
|
||||||
|
|
||||||
from collections.abc import Mapping
|
|
||||||
|
|
||||||
from ansible.errors import AnsibleConnectionFailure
|
|
||||||
from ansible.module_utils.common.text.converters import to_text
|
|
||||||
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import (
|
|
||||||
NetworkConfig,
|
|
||||||
)
|
|
||||||
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
|
|
||||||
to_list,
|
|
||||||
)
|
|
||||||
from ansible.plugins.cliconf import CliconfBase
|
|
||||||
|
|
||||||
|
|
||||||
class Cliconf(CliconfBase):
|
|
||||||
def get_device_info(self):
|
|
||||||
device_info = {}
|
|
||||||
|
|
||||||
device_info["network_os"] = "vyos"
|
|
||||||
reply = self.get("show version")
|
|
||||||
data = to_text(reply, errors="surrogate_or_strict").strip()
|
|
||||||
|
|
||||||
match = re.search(r"Version:\s*(.*)", data)
|
|
||||||
if match:
|
|
||||||
device_info["network_os_version"] = match.group(1)
|
|
||||||
|
|
||||||
match = re.search(r"HW model:\s*(\S+)", data)
|
|
||||||
if match:
|
|
||||||
device_info["network_os_model"] = match.group(1)
|
|
||||||
|
|
||||||
reply = self.get("show host name")
|
|
||||||
device_info["network_os_hostname"] = to_text(
|
|
||||||
reply, errors="surrogate_or_strict"
|
|
||||||
).strip()
|
|
||||||
|
|
||||||
return device_info
|
|
||||||
|
|
||||||
def get_config(self, flags=None, format=None):
|
|
||||||
if format:
|
|
||||||
option_values = self.get_option_values()
|
|
||||||
if format not in option_values["format"]:
|
|
||||||
raise ValueError(
|
|
||||||
"'format' value %s is invalid. Valid values of format are %s"
|
|
||||||
% (format, ", ".join(option_values["format"]))
|
|
||||||
)
|
|
||||||
|
|
||||||
if not flags:
|
|
||||||
flags = []
|
|
||||||
|
|
||||||
if format == "text":
|
|
||||||
command = "show configuration"
|
|
||||||
else:
|
|
||||||
command = "show configuration commands"
|
|
||||||
|
|
||||||
command += " ".join(to_list(flags))
|
|
||||||
command = command.strip()
|
|
||||||
|
|
||||||
out = self.send_command(command)
|
|
||||||
return out
|
|
||||||
|
|
||||||
def edit_config(
|
|
||||||
self, candidate=None, commit=True, replace=None, comment=None
|
|
||||||
):
|
|
||||||
resp = {}
|
|
||||||
operations = self.get_device_operations()
|
|
||||||
self.check_edit_config_capability(
|
|
||||||
operations, candidate, commit, replace, comment
|
|
||||||
)
|
|
||||||
|
|
||||||
results = []
|
|
||||||
requests = []
|
|
||||||
self.send_command("configure")
|
|
||||||
for cmd in to_list(candidate):
|
|
||||||
if not isinstance(cmd, Mapping):
|
|
||||||
cmd = {"command": cmd}
|
|
||||||
|
|
||||||
results.append(self.send_command(**cmd))
|
|
||||||
requests.append(cmd["command"])
|
|
||||||
out = self.get("compare")
|
|
||||||
out = to_text(out, errors="surrogate_or_strict")
|
|
||||||
diff_config = out if not out.startswith("No changes") else None
|
|
||||||
|
|
||||||
if diff_config:
|
|
||||||
if commit:
|
|
||||||
try:
|
|
||||||
self.commit(comment)
|
|
||||||
except AnsibleConnectionFailure as e:
|
|
||||||
msg = "commit failed: %s" % e.message
|
|
||||||
self.discard_changes()
|
|
||||||
raise AnsibleConnectionFailure(msg)
|
|
||||||
else:
|
|
||||||
self.send_command("exit")
|
|
||||||
else:
|
|
||||||
self.discard_changes()
|
|
||||||
else:
|
|
||||||
self.send_command("exit")
|
|
||||||
if (
|
|
||||||
to_text(
|
|
||||||
self._connection.get_prompt(), errors="surrogate_or_strict"
|
|
||||||
)
|
|
||||||
.strip()
|
|
||||||
.endswith("#")
|
|
||||||
):
|
|
||||||
self.discard_changes()
|
|
||||||
|
|
||||||
if diff_config:
|
|
||||||
resp["diff"] = diff_config
|
|
||||||
resp["response"] = results
|
|
||||||
resp["request"] = requests
|
|
||||||
return resp
|
|
||||||
|
|
||||||
def get(
|
|
||||||
self,
|
|
||||||
command=None,
|
|
||||||
prompt=None,
|
|
||||||
answer=None,
|
|
||||||
sendonly=False,
|
|
||||||
output=None,
|
|
||||||
newline=True,
|
|
||||||
check_all=False,
|
|
||||||
):
|
|
||||||
if not command:
|
|
||||||
raise ValueError("must provide value of command to execute")
|
|
||||||
if output:
|
|
||||||
raise ValueError(
|
|
||||||
"'output' value %s is not supported for get" % output
|
|
||||||
)
|
|
||||||
|
|
||||||
return self.send_command(
|
|
||||||
command=command,
|
|
||||||
prompt=prompt,
|
|
||||||
answer=answer,
|
|
||||||
sendonly=sendonly,
|
|
||||||
newline=newline,
|
|
||||||
check_all=check_all,
|
|
||||||
)
|
|
||||||
|
|
||||||
def commit(self, comment=None):
|
|
||||||
if comment:
|
|
||||||
command = 'commit comment "{0}"'.format(comment)
|
|
||||||
else:
|
|
||||||
command = "commit"
|
|
||||||
self.send_command(command)
|
|
||||||
|
|
||||||
def discard_changes(self):
|
|
||||||
self.send_command("exit discard")
|
|
||||||
|
|
||||||
def get_diff(
|
|
||||||
self,
|
|
||||||
candidate=None,
|
|
||||||
running=None,
|
|
||||||
diff_match="line",
|
|
||||||
diff_ignore_lines=None,
|
|
||||||
path=None,
|
|
||||||
diff_replace=None,
|
|
||||||
):
|
|
||||||
diff = {}
|
|
||||||
device_operations = self.get_device_operations()
|
|
||||||
option_values = self.get_option_values()
|
|
||||||
|
|
||||||
if candidate is None and device_operations["supports_generate_diff"]:
|
|
||||||
raise ValueError(
|
|
||||||
"candidate configuration is required to generate diff"
|
|
||||||
)
|
|
||||||
|
|
||||||
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 diff_replace:
|
|
||||||
raise ValueError("'replace' in diff is not supported")
|
|
||||||
|
|
||||||
if diff_ignore_lines:
|
|
||||||
raise ValueError("'diff_ignore_lines' in diff is not supported")
|
|
||||||
|
|
||||||
if path:
|
|
||||||
raise ValueError("'path' in diff is not supported")
|
|
||||||
|
|
||||||
set_format = candidate.startswith("set") or candidate.startswith(
|
|
||||||
"delete"
|
|
||||||
)
|
|
||||||
candidate_obj = NetworkConfig(indent=4, contents=candidate)
|
|
||||||
if not set_format:
|
|
||||||
config = [c.line for c in candidate_obj.items]
|
|
||||||
commands = list()
|
|
||||||
# this filters out less specific lines
|
|
||||||
for item in config:
|
|
||||||
for index, entry in enumerate(commands):
|
|
||||||
if item.startswith(entry):
|
|
||||||
del commands[index]
|
|
||||||
break
|
|
||||||
commands.append(item)
|
|
||||||
|
|
||||||
candidate_commands = [
|
|
||||||
"set %s" % cmd.replace(" {", "") for cmd in commands
|
|
||||||
]
|
|
||||||
|
|
||||||
else:
|
|
||||||
candidate_commands = str(candidate).strip().split("\n")
|
|
||||||
|
|
||||||
if diff_match == "none":
|
|
||||||
diff["config_diff"] = list(candidate_commands)
|
|
||||||
return diff
|
|
||||||
|
|
||||||
running_commands = [
|
|
||||||
str(c).replace("'", "") for c in running.splitlines()
|
|
||||||
]
|
|
||||||
|
|
||||||
updates = list()
|
|
||||||
visited = set()
|
|
||||||
|
|
||||||
for line in candidate_commands:
|
|
||||||
item = str(line).replace("'", "")
|
|
||||||
|
|
||||||
if not item.startswith("set") and not item.startswith("delete"):
|
|
||||||
raise ValueError(
|
|
||||||
"line must start with either `set` or `delete`"
|
|
||||||
)
|
|
||||||
|
|
||||||
elif item.startswith("set") and item not in running_commands:
|
|
||||||
updates.append(line)
|
|
||||||
|
|
||||||
elif item.startswith("delete"):
|
|
||||||
if not running_commands:
|
|
||||||
updates.append(line)
|
|
||||||
else:
|
|
||||||
item = re.sub(r"delete", "set", item)
|
|
||||||
for entry in running_commands:
|
|
||||||
if entry.startswith(item) and line not in visited:
|
|
||||||
updates.append(line)
|
|
||||||
visited.add(line)
|
|
||||||
|
|
||||||
diff["config_diff"] = list(updates)
|
|
||||||
return diff
|
|
||||||
|
|
||||||
def run_commands(self, commands=None, check_rc=True):
|
|
||||||
if commands is None:
|
|
||||||
raise ValueError("'commands' value is required")
|
|
||||||
|
|
||||||
responses = list()
|
|
||||||
for cmd in to_list(commands):
|
|
||||||
if not isinstance(cmd, Mapping):
|
|
||||||
cmd = {"command": cmd}
|
|
||||||
|
|
||||||
output = cmd.pop("output", None)
|
|
||||||
if output:
|
|
||||||
raise ValueError(
|
|
||||||
"'output' value %s is not supported for run_commands"
|
|
||||||
% output
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
out = self.send_command(**cmd)
|
|
||||||
except AnsibleConnectionFailure as e:
|
|
||||||
if check_rc:
|
|
||||||
raise
|
|
||||||
out = getattr(e, "err", e)
|
|
||||||
|
|
||||||
responses.append(out)
|
|
||||||
|
|
||||||
return responses
|
|
||||||
|
|
||||||
def get_device_operations(self):
|
|
||||||
return {
|
|
||||||
"supports_diff_replace": False,
|
|
||||||
"supports_commit": True,
|
|
||||||
"supports_rollback": False,
|
|
||||||
"supports_defaults": False,
|
|
||||||
"supports_onbox_diff": True,
|
|
||||||
"supports_commit_comment": True,
|
|
||||||
"supports_multiline_delimiter": False,
|
|
||||||
"supports_diff_match": True,
|
|
||||||
"supports_diff_ignore_lines": False,
|
|
||||||
"supports_generate_diff": False,
|
|
||||||
"supports_replace": False,
|
|
||||||
}
|
|
||||||
|
|
||||||
def get_option_values(self):
|
|
||||||
return {
|
|
||||||
"format": ["text", "set"],
|
|
||||||
"diff_match": ["line", "none"],
|
|
||||||
"diff_replace": [],
|
|
||||||
"output": [],
|
|
||||||
}
|
|
||||||
|
|
||||||
def get_capabilities(self):
|
|
||||||
result = super(Cliconf, self).get_capabilities()
|
|
||||||
result["rpc"] += [
|
|
||||||
"commit",
|
|
||||||
"discard_changes",
|
|
||||||
"get_diff",
|
|
||||||
"run_commands",
|
|
||||||
]
|
|
||||||
result["device_operations"] = self.get_device_operations()
|
|
||||||
result.update(self.get_option_values())
|
|
||||||
return json.dumps(result)
|
|
||||||
|
|
||||||
def set_cli_prompt_context(self):
|
|
||||||
"""
|
|
||||||
Make sure we are in the operational cli mode
|
|
||||||
:return: None
|
|
||||||
"""
|
|
||||||
if self._connection.connected:
|
|
||||||
self._update_cli_prompt_context(
|
|
||||||
config_context="#", exit_command="exit discard"
|
|
||||||
)
|
|
@ -1,64 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Copyright: (c) 2015, Peter Sprygada <psprygada@ansible.com>
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
|
|
||||||
class ModuleDocFragment(object):
|
|
||||||
|
|
||||||
# Standard files documentation fragment
|
|
||||||
DOCUMENTATION = r"""options:
|
|
||||||
provider:
|
|
||||||
description:
|
|
||||||
- B(Deprecated)
|
|
||||||
- 'Starting with Ansible 2.5 we recommend using C(connection: network_cli).'
|
|
||||||
- For more information please see the L(Network Guide, ../network/getting_started/network_differences.html#multiple-communication-protocols).
|
|
||||||
- HORIZONTALLINE
|
|
||||||
- A dict object containing connection details.
|
|
||||||
type: dict
|
|
||||||
suboptions:
|
|
||||||
host:
|
|
||||||
description:
|
|
||||||
- Specifies the DNS host name or address for connecting to the remote device
|
|
||||||
over the specified transport. The value of host is used as the destination
|
|
||||||
address for the transport.
|
|
||||||
type: str
|
|
||||||
required: true
|
|
||||||
port:
|
|
||||||
description:
|
|
||||||
- Specifies the port to use when building the connection to the remote device.
|
|
||||||
type: int
|
|
||||||
default: 22
|
|
||||||
username:
|
|
||||||
description:
|
|
||||||
- Configures the username to use to authenticate the connection to the remote
|
|
||||||
device. This value is used to authenticate the SSH session. If the value
|
|
||||||
is not specified in the task, the value of environment variable C(ANSIBLE_NET_USERNAME)
|
|
||||||
will be used instead.
|
|
||||||
type: str
|
|
||||||
password:
|
|
||||||
description:
|
|
||||||
- Specifies the password to use to authenticate the connection to the remote
|
|
||||||
device. This value is used to authenticate the SSH session. If the value
|
|
||||||
is not specified in the task, the value of environment variable C(ANSIBLE_NET_PASSWORD)
|
|
||||||
will be used instead.
|
|
||||||
type: str
|
|
||||||
timeout:
|
|
||||||
description:
|
|
||||||
- Specifies the timeout in seconds for communicating with the network device
|
|
||||||
for either connecting or sending commands. If the timeout is exceeded before
|
|
||||||
the operation is completed, the module will error.
|
|
||||||
type: int
|
|
||||||
default: 10
|
|
||||||
ssh_keyfile:
|
|
||||||
description:
|
|
||||||
- Specifies the SSH key to use to authenticate the connection to the remote
|
|
||||||
device. This value is the path to the key used to authenticate the SSH
|
|
||||||
session. If the value is not specified in the task, the value of environment
|
|
||||||
variable C(ANSIBLE_NET_SSH_KEYFILE) will be used instead.
|
|
||||||
type: path
|
|
||||||
notes:
|
|
||||||
- For more information on using Ansible to manage network devices see the :ref:`Ansible
|
|
||||||
Network Guide <network_guide>`
|
|
||||||
"""
|
|
@ -1,20 +0,0 @@
|
|||||||
# Copyright 2019 Red Hat
|
|
||||||
# GNU General Public License v3.0+
|
|
||||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
"""
|
|
||||||
The arg spec for the vyos facts module.
|
|
||||||
"""
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
|
|
||||||
class FactsArgs(object): # pylint: disable=R0903
|
|
||||||
""" The arg spec for the vyos facts module
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
pass
|
|
||||||
|
|
||||||
argument_spec = {
|
|
||||||
"gather_subset": dict(default=["!config"], type="list"),
|
|
||||||
"gather_network_resources": dict(type="list"),
|
|
||||||
}
|
|
@ -1,261 +0,0 @@
|
|||||||
#
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright 2019 Red Hat
|
|
||||||
# GNU General Public License v3.0+
|
|
||||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
#############################################
|
|
||||||
# WARNING #
|
|
||||||
#############################################
|
|
||||||
#
|
|
||||||
# This file is auto generated by the resource
|
|
||||||
# module builder playbook.
|
|
||||||
#
|
|
||||||
# Do not edit this file manually.
|
|
||||||
#
|
|
||||||
# Changes to this file will be over written
|
|
||||||
# by the resource module builder.
|
|
||||||
#
|
|
||||||
# Changes should be made in the model used to
|
|
||||||
# generate this file or in the resource module
|
|
||||||
# builder template.
|
|
||||||
#
|
|
||||||
#############################################
|
|
||||||
"""
|
|
||||||
The arg spec for the vyos_firewall_rules module
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
|
|
||||||
class Firewall_rulesArgs(object): # pylint: disable=R0903
|
|
||||||
"""The arg spec for the vyos_firewall_rules module
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
pass
|
|
||||||
|
|
||||||
argument_spec = {
|
|
||||||
"config": {
|
|
||||||
"elements": "dict",
|
|
||||||
"options": {
|
|
||||||
"afi": {
|
|
||||||
"choices": ["ipv4", "ipv6"],
|
|
||||||
"required": True,
|
|
||||||
"type": "str",
|
|
||||||
},
|
|
||||||
"rule_sets": {
|
|
||||||
"elements": "dict",
|
|
||||||
"options": {
|
|
||||||
"default_action": {
|
|
||||||
"choices": ["drop", "reject", "accept"],
|
|
||||||
"type": "str",
|
|
||||||
},
|
|
||||||
"description": {"type": "str"},
|
|
||||||
"enable_default_log": {"type": "bool"},
|
|
||||||
"name": {"type": "str"},
|
|
||||||
"rules": {
|
|
||||||
"elements": "dict",
|
|
||||||
"options": {
|
|
||||||
"action": {
|
|
||||||
"choices": [
|
|
||||||
"drop",
|
|
||||||
"reject",
|
|
||||||
"accept",
|
|
||||||
"inspect",
|
|
||||||
],
|
|
||||||
"type": "str",
|
|
||||||
},
|
|
||||||
"description": {"type": "str"},
|
|
||||||
"destination": {
|
|
||||||
"options": {
|
|
||||||
"address": {"type": "str"},
|
|
||||||
"group": {
|
|
||||||
"options": {
|
|
||||||
"address_group": {
|
|
||||||
"type": "str"
|
|
||||||
},
|
|
||||||
"network_group": {
|
|
||||||
"type": "str"
|
|
||||||
},
|
|
||||||
"port_group": {"type": "str"},
|
|
||||||
},
|
|
||||||
"type": "dict",
|
|
||||||
},
|
|
||||||
"port": {"type": "str"},
|
|
||||||
},
|
|
||||||
"type": "dict",
|
|
||||||
},
|
|
||||||
"disabled": {"type": "bool"},
|
|
||||||
"fragment": {
|
|
||||||
"choices": [
|
|
||||||
"match-frag",
|
|
||||||
"match-non-frag",
|
|
||||||
],
|
|
||||||
"type": "str",
|
|
||||||
},
|
|
||||||
"icmp": {
|
|
||||||
"options": {
|
|
||||||
"code": {"type": "int"},
|
|
||||||
"type": {"type": "int"},
|
|
||||||
"type_name": {
|
|
||||||
"choices": [
|
|
||||||
"any",
|
|
||||||
"echo-reply",
|
|
||||||
"destination-unreachable",
|
|
||||||
"network-unreachable",
|
|
||||||
"host-unreachable",
|
|
||||||
"protocol-unreachable",
|
|
||||||
"port-unreachable",
|
|
||||||
"fragmentation-needed",
|
|
||||||
"source-route-failed",
|
|
||||||
"network-unknown",
|
|
||||||
"host-unknown",
|
|
||||||
"network-prohibited",
|
|
||||||
"host-prohibited",
|
|
||||||
"TOS-network-unreachable",
|
|
||||||
"TOS-host-unreachable",
|
|
||||||
"communication-prohibited",
|
|
||||||
"host-precedence-violation",
|
|
||||||
"precedence-cutoff",
|
|
||||||
"source-quench",
|
|
||||||
"redirect",
|
|
||||||
"network-redirect",
|
|
||||||
"host-redirect",
|
|
||||||
"TOS-network-redirect",
|
|
||||||
"TOS-host-redirect",
|
|
||||||
"echo-request",
|
|
||||||
"router-advertisement",
|
|
||||||
"router-solicitation",
|
|
||||||
"time-exceeded",
|
|
||||||
"ttl-zero-during-transit",
|
|
||||||
"ttl-zero-during-reassembly",
|
|
||||||
"parameter-problem",
|
|
||||||
"ip-header-bad",
|
|
||||||
"required-option-missing",
|
|
||||||
"timestamp-request",
|
|
||||||
"timestamp-reply",
|
|
||||||
"address-mask-request",
|
|
||||||
"address-mask-reply",
|
|
||||||
"ping",
|
|
||||||
"pong",
|
|
||||||
"ttl-exceeded",
|
|
||||||
],
|
|
||||||
"type": "str",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"type": "dict",
|
|
||||||
},
|
|
||||||
"ipsec": {
|
|
||||||
"choices": ["match-ipsec", "match-none"],
|
|
||||||
"type": "str",
|
|
||||||
},
|
|
||||||
"limit": {
|
|
||||||
"options": {
|
|
||||||
"burst": {"type": "int"},
|
|
||||||
"rate": {
|
|
||||||
"options": {
|
|
||||||
"number": {"type": "int"},
|
|
||||||
"unit": {"type": "str"},
|
|
||||||
},
|
|
||||||
"type": "dict",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"type": "dict",
|
|
||||||
},
|
|
||||||
"number": {"required": True, "type": "int"},
|
|
||||||
"p2p": {
|
|
||||||
"elements": "dict",
|
|
||||||
"options": {
|
|
||||||
"application": {
|
|
||||||
"choices": [
|
|
||||||
"all",
|
|
||||||
"applejuice",
|
|
||||||
"bittorrent",
|
|
||||||
"directconnect",
|
|
||||||
"edonkey",
|
|
||||||
"gnutella",
|
|
||||||
"kazaa",
|
|
||||||
],
|
|
||||||
"type": "str",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "list",
|
|
||||||
},
|
|
||||||
"protocol": {"type": "str"},
|
|
||||||
"recent": {
|
|
||||||
"options": {
|
|
||||||
"count": {"type": "int"},
|
|
||||||
"time": {"type": "int"},
|
|
||||||
},
|
|
||||||
"type": "dict",
|
|
||||||
},
|
|
||||||
"source": {
|
|
||||||
"options": {
|
|
||||||
"address": {"type": "str"},
|
|
||||||
"group": {
|
|
||||||
"options": {
|
|
||||||
"address_group": {
|
|
||||||
"type": "str"
|
|
||||||
},
|
|
||||||
"network_group": {
|
|
||||||
"type": "str"
|
|
||||||
},
|
|
||||||
"port_group": {"type": "str"},
|
|
||||||
},
|
|
||||||
"type": "dict",
|
|
||||||
},
|
|
||||||
"mac_address": {"type": "str"},
|
|
||||||
"port": {"type": "str"},
|
|
||||||
},
|
|
||||||
"type": "dict",
|
|
||||||
},
|
|
||||||
"state": {
|
|
||||||
"options": {
|
|
||||||
"established": {"type": "bool"},
|
|
||||||
"invalid": {"type": "bool"},
|
|
||||||
"new": {"type": "bool"},
|
|
||||||
"related": {"type": "bool"},
|
|
||||||
},
|
|
||||||
"type": "dict",
|
|
||||||
},
|
|
||||||
"tcp": {
|
|
||||||
"options": {"flags": {"type": "str"}},
|
|
||||||
"type": "dict",
|
|
||||||
},
|
|
||||||
"time": {
|
|
||||||
"options": {
|
|
||||||
"monthdays": {"type": "str"},
|
|
||||||
"startdate": {"type": "str"},
|
|
||||||
"starttime": {"type": "str"},
|
|
||||||
"stopdate": {"type": "str"},
|
|
||||||
"stoptime": {"type": "str"},
|
|
||||||
"utc": {"type": "bool"},
|
|
||||||
"weekdays": {"type": "str"},
|
|
||||||
},
|
|
||||||
"type": "dict",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"type": "list",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"type": "list",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"type": "list",
|
|
||||||
},
|
|
||||||
"running_config": {"type": "str"},
|
|
||||||
"state": {
|
|
||||||
"choices": [
|
|
||||||
"merged",
|
|
||||||
"replaced",
|
|
||||||
"overridden",
|
|
||||||
"deleted",
|
|
||||||
"gathered",
|
|
||||||
"rendered",
|
|
||||||
"parsed",
|
|
||||||
],
|
|
||||||
"default": "merged",
|
|
||||||
"type": "str",
|
|
||||||
},
|
|
||||||
} # pylint: disable=C0301
|
|
@ -1,67 +0,0 @@
|
|||||||
# Copyright 2019 Red Hat
|
|
||||||
# GNU General Public License v3.0+
|
|
||||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
#############################################
|
|
||||||
# WARNING #
|
|
||||||
#############################################
|
|
||||||
#
|
|
||||||
# This file is auto generated by the resource
|
|
||||||
# module builder playbook.
|
|
||||||
#
|
|
||||||
# Do not edit this file manually.
|
|
||||||
#
|
|
||||||
# Changes to this file will be over written
|
|
||||||
# by the resource module builder.
|
|
||||||
#
|
|
||||||
# Changes should be made in the model used to
|
|
||||||
# generate this file or in the resource module
|
|
||||||
# builder template.
|
|
||||||
#
|
|
||||||
#############################################
|
|
||||||
"""
|
|
||||||
The arg spec for the vyos_interfaces module
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
|
|
||||||
class InterfacesArgs(object): # pylint: disable=R0903
|
|
||||||
"""The arg spec for the vyos_interfaces module
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
pass
|
|
||||||
|
|
||||||
argument_spec = {
|
|
||||||
"config": {
|
|
||||||
"elements": "dict",
|
|
||||||
"options": {
|
|
||||||
"description": {"type": "str"},
|
|
||||||
"duplex": {"choices": ["full", "half", "auto"]},
|
|
||||||
"enabled": {"default": True, "type": "bool"},
|
|
||||||
"mtu": {"type": "int"},
|
|
||||||
"name": {"required": True, "type": "str"},
|
|
||||||
"speed": {
|
|
||||||
"choices": ["auto", "10", "100", "1000", "2500", "10000"],
|
|
||||||
"type": "str",
|
|
||||||
},
|
|
||||||
"vifs": {
|
|
||||||
"elements": "dict",
|
|
||||||
"options": {
|
|
||||||
"vlan_id": {"type": "int"},
|
|
||||||
"description": {"type": "str"},
|
|
||||||
"enabled": {"default": True, "type": "bool"},
|
|
||||||
"mtu": {"type": "int"},
|
|
||||||
},
|
|
||||||
"type": "list",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"type": "list",
|
|
||||||
},
|
|
||||||
"state": {
|
|
||||||
"choices": ["merged", "replaced", "overridden", "deleted"],
|
|
||||||
"default": "merged",
|
|
||||||
"type": "str",
|
|
||||||
},
|
|
||||||
} # pylint: disable=C0301
|
|
@ -1,79 +0,0 @@
|
|||||||
#
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright 2019 Red Hat
|
|
||||||
# GNU General Public License v3.0+
|
|
||||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
#############################################
|
|
||||||
# WARNING #
|
|
||||||
#############################################
|
|
||||||
#
|
|
||||||
# This file is auto generated by the resource
|
|
||||||
# module builder playbook.
|
|
||||||
#
|
|
||||||
# Do not edit this file manually.
|
|
||||||
#
|
|
||||||
# Changes to this file will be over written
|
|
||||||
# by the resource module builder.
|
|
||||||
#
|
|
||||||
# Changes should be made in the model used to
|
|
||||||
# generate this file or in the resource module
|
|
||||||
# builder template.
|
|
||||||
#
|
|
||||||
#############################################
|
|
||||||
"""
|
|
||||||
The arg spec for the vyos_l3_interfaces module
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
|
|
||||||
class L3_interfacesArgs(object): # pylint: disable=R0903
|
|
||||||
"""The arg spec for the vyos_l3_interfaces module
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
pass
|
|
||||||
|
|
||||||
argument_spec = {
|
|
||||||
"config": {
|
|
||||||
"elements": "dict",
|
|
||||||
"options": {
|
|
||||||
"ipv4": {
|
|
||||||
"elements": "dict",
|
|
||||||
"options": {"address": {"type": "str"}},
|
|
||||||
"type": "list",
|
|
||||||
},
|
|
||||||
"ipv6": {
|
|
||||||
"elements": "dict",
|
|
||||||
"options": {"address": {"type": "str"}},
|
|
||||||
"type": "list",
|
|
||||||
},
|
|
||||||
"name": {"required": True, "type": "str"},
|
|
||||||
"vifs": {
|
|
||||||
"elements": "dict",
|
|
||||||
"options": {
|
|
||||||
"ipv4": {
|
|
||||||
"elements": "dict",
|
|
||||||
"options": {"address": {"type": "str"}},
|
|
||||||
"type": "list",
|
|
||||||
},
|
|
||||||
"ipv6": {
|
|
||||||
"elements": "dict",
|
|
||||||
"options": {"address": {"type": "str"}},
|
|
||||||
"type": "list",
|
|
||||||
},
|
|
||||||
"vlan_id": {"type": "int"},
|
|
||||||
},
|
|
||||||
"type": "list",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"type": "list",
|
|
||||||
},
|
|
||||||
"state": {
|
|
||||||
"choices": ["merged", "replaced", "overridden", "deleted"],
|
|
||||||
"default": "merged",
|
|
||||||
"type": "str",
|
|
||||||
},
|
|
||||||
} # pylint: disable=C0301
|
|
@ -1,78 +0,0 @@
|
|||||||
# Copyright 2019 Red Hat
|
|
||||||
# GNU General Public License v3.0+
|
|
||||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
#############################################
|
|
||||||
# WARNING #
|
|
||||||
#############################################
|
|
||||||
#
|
|
||||||
# This file is auto generated by the resource
|
|
||||||
# module builder playbook.
|
|
||||||
#
|
|
||||||
# Do not edit this file manually.
|
|
||||||
#
|
|
||||||
# Changes to this file will be over written
|
|
||||||
# by the resource module builder.
|
|
||||||
#
|
|
||||||
# Changes should be made in the model used to
|
|
||||||
# generate this file or in the resource module
|
|
||||||
# builder template.
|
|
||||||
#
|
|
||||||
#############################################
|
|
||||||
|
|
||||||
"""
|
|
||||||
The arg spec for the vyos_lag_interfaces module
|
|
||||||
"""
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
|
|
||||||
class Lag_interfacesArgs(object): # pylint: disable=R0903
|
|
||||||
"""The arg spec for the vyos_lag_interfaces module
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
pass
|
|
||||||
|
|
||||||
argument_spec = {
|
|
||||||
"config": {
|
|
||||||
"elements": "dict",
|
|
||||||
"options": {
|
|
||||||
"arp_monitor": {
|
|
||||||
"options": {
|
|
||||||
"interval": {"type": "int"},
|
|
||||||
"target": {"type": "list"},
|
|
||||||
},
|
|
||||||
"type": "dict",
|
|
||||||
},
|
|
||||||
"hash_policy": {
|
|
||||||
"choices": ["layer2", "layer2+3", "layer3+4"],
|
|
||||||
"type": "str",
|
|
||||||
},
|
|
||||||
"members": {
|
|
||||||
"elements": "dict",
|
|
||||||
"options": {"member": {"type": "str"}},
|
|
||||||
"type": "list",
|
|
||||||
},
|
|
||||||
"mode": {
|
|
||||||
"choices": [
|
|
||||||
"802.3ad",
|
|
||||||
"active-backup",
|
|
||||||
"broadcast",
|
|
||||||
"round-robin",
|
|
||||||
"transmit-load-balance",
|
|
||||||
"adaptive-load-balance",
|
|
||||||
"xor-hash",
|
|
||||||
],
|
|
||||||
"type": "str",
|
|
||||||
},
|
|
||||||
"name": {"required": True, "type": "str"},
|
|
||||||
"primary": {"type": "str"},
|
|
||||||
},
|
|
||||||
"type": "list",
|
|
||||||
},
|
|
||||||
"state": {
|
|
||||||
"choices": ["merged", "replaced", "overridden", "deleted"],
|
|
||||||
"default": "merged",
|
|
||||||
"type": "str",
|
|
||||||
},
|
|
||||||
} # pylint: disable=C0301
|
|
@ -1,54 +0,0 @@
|
|||||||
# Copyright 2019 Red Hat
|
|
||||||
# GNU General Public License v3.0+
|
|
||||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
#############################################
|
|
||||||
# WARNING #
|
|
||||||
#############################################
|
|
||||||
#
|
|
||||||
# This file is auto generated by the resource
|
|
||||||
# module builder playbook.
|
|
||||||
#
|
|
||||||
# Do not edit this file manually.
|
|
||||||
#
|
|
||||||
# Changes to this file will be over written
|
|
||||||
# by the resource module builder.
|
|
||||||
#
|
|
||||||
# Changes should be made in the model used to
|
|
||||||
# generate this file or in the resource module
|
|
||||||
# builder template.
|
|
||||||
#
|
|
||||||
#############################################
|
|
||||||
|
|
||||||
"""
|
|
||||||
The arg spec for the vyos_lldp_global module
|
|
||||||
"""
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
|
|
||||||
class Lldp_globalArgs(object): # pylint: disable=R0903
|
|
||||||
"""The arg spec for the vyos_lldp_global module
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
pass
|
|
||||||
|
|
||||||
argument_spec = {
|
|
||||||
"config": {
|
|
||||||
"options": {
|
|
||||||
"address": {"type": "str"},
|
|
||||||
"enable": {"type": "bool"},
|
|
||||||
"legacy_protocols": {
|
|
||||||
"choices": ["cdp", "edp", "fdp", "sonmp"],
|
|
||||||
"type": "list",
|
|
||||||
},
|
|
||||||
"snmp": {"type": "str"},
|
|
||||||
},
|
|
||||||
"type": "dict",
|
|
||||||
},
|
|
||||||
"state": {
|
|
||||||
"choices": ["merged", "replaced", "deleted"],
|
|
||||||
"default": "merged",
|
|
||||||
"type": "str",
|
|
||||||
},
|
|
||||||
} # pylint: disable=C0301
|
|
@ -1,87 +0,0 @@
|
|||||||
#
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright 2019 Red Hat
|
|
||||||
# GNU General Public License v3.0+
|
|
||||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
#############################################
|
|
||||||
# WARNING #
|
|
||||||
#############################################
|
|
||||||
#
|
|
||||||
# This file is auto generated by the resource
|
|
||||||
# module builder playbook.
|
|
||||||
#
|
|
||||||
# Do not edit this file manually.
|
|
||||||
#
|
|
||||||
# Changes to this file will be over written
|
|
||||||
# by the resource module builder.
|
|
||||||
#
|
|
||||||
# Changes should be made in the model used to
|
|
||||||
# generate this file or in the resource module
|
|
||||||
# builder template.
|
|
||||||
#
|
|
||||||
#############################################
|
|
||||||
"""
|
|
||||||
The arg spec for the vyos_lldp_interfaces module
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
|
|
||||||
class Lldp_interfacesArgs(object): # pylint: disable=R0903
|
|
||||||
"""The arg spec for the vyos_lldp_interfaces module
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
pass
|
|
||||||
|
|
||||||
argument_spec = {
|
|
||||||
"config": {
|
|
||||||
"elements": "dict",
|
|
||||||
"options": {
|
|
||||||
"enable": {"default": True, "type": "bool"},
|
|
||||||
"location": {
|
|
||||||
"options": {
|
|
||||||
"civic_based": {
|
|
||||||
"options": {
|
|
||||||
"ca_info": {
|
|
||||||
"elements": "dict",
|
|
||||||
"options": {
|
|
||||||
"ca_type": {"type": "int"},
|
|
||||||
"ca_value": {"type": "str"},
|
|
||||||
},
|
|
||||||
"type": "list",
|
|
||||||
},
|
|
||||||
"country_code": {
|
|
||||||
"required": True,
|
|
||||||
"type": "str",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"type": "dict",
|
|
||||||
},
|
|
||||||
"coordinate_based": {
|
|
||||||
"options": {
|
|
||||||
"altitude": {"type": "int"},
|
|
||||||
"datum": {
|
|
||||||
"choices": ["WGS84", "NAD83", "MLLW"],
|
|
||||||
"type": "str",
|
|
||||||
},
|
|
||||||
"latitude": {"required": True, "type": "str"},
|
|
||||||
"longitude": {"required": True, "type": "str"},
|
|
||||||
},
|
|
||||||
"type": "dict",
|
|
||||||
},
|
|
||||||
"elin": {"type": "str"},
|
|
||||||
},
|
|
||||||
"type": "dict",
|
|
||||||
},
|
|
||||||
"name": {"required": True, "type": "str"},
|
|
||||||
},
|
|
||||||
"type": "list",
|
|
||||||
},
|
|
||||||
"state": {
|
|
||||||
"choices": ["merged", "replaced", "overridden", "deleted"],
|
|
||||||
"default": "merged",
|
|
||||||
"type": "str",
|
|
||||||
},
|
|
||||||
} # pylint: disable=C0301
|
|
@ -1,97 +0,0 @@
|
|||||||
#
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright 2019 Red Hat
|
|
||||||
# GNU General Public License v3.0+
|
|
||||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
#############################################
|
|
||||||
# WARNING #
|
|
||||||
#############################################
|
|
||||||
#
|
|
||||||
# This file is auto generated by the resource
|
|
||||||
# module builder playbook.
|
|
||||||
#
|
|
||||||
# Do not edit this file manually.
|
|
||||||
#
|
|
||||||
# Changes to this file will be over written
|
|
||||||
# by the resource module builder.
|
|
||||||
#
|
|
||||||
# Changes should be made in the model used to
|
|
||||||
# generate this file or in the resource module
|
|
||||||
# builder template.
|
|
||||||
#
|
|
||||||
#############################################
|
|
||||||
"""
|
|
||||||
The arg spec for the vyos_static_routes module
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
|
|
||||||
class Static_routesArgs(object): # pylint: disable=R0903
|
|
||||||
"""The arg spec for the vyos_static_routes module
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
pass
|
|
||||||
|
|
||||||
argument_spec = {
|
|
||||||
"config": {
|
|
||||||
"elements": "dict",
|
|
||||||
"options": {
|
|
||||||
"address_families": {
|
|
||||||
"elements": "dict",
|
|
||||||
"options": {
|
|
||||||
"afi": {
|
|
||||||
"choices": ["ipv4", "ipv6"],
|
|
||||||
"required": True,
|
|
||||||
"type": "str",
|
|
||||||
},
|
|
||||||
"routes": {
|
|
||||||
"elements": "dict",
|
|
||||||
"options": {
|
|
||||||
"blackhole_config": {
|
|
||||||
"options": {
|
|
||||||
"distance": {"type": "int"},
|
|
||||||
"type": {"type": "str"},
|
|
||||||
},
|
|
||||||
"type": "dict",
|
|
||||||
},
|
|
||||||
"dest": {"required": True, "type": "str"},
|
|
||||||
"next_hops": {
|
|
||||||
"elements": "dict",
|
|
||||||
"options": {
|
|
||||||
"admin_distance": {"type": "int"},
|
|
||||||
"enabled": {"type": "bool"},
|
|
||||||
"forward_router_address": {
|
|
||||||
"required": True,
|
|
||||||
"type": "str",
|
|
||||||
},
|
|
||||||
"interface": {"type": "str"},
|
|
||||||
},
|
|
||||||
"type": "list",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"type": "list",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"type": "list",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "list",
|
|
||||||
},
|
|
||||||
"running_config": {"type": "str"},
|
|
||||||
"state": {
|
|
||||||
"choices": [
|
|
||||||
"merged",
|
|
||||||
"replaced",
|
|
||||||
"overridden",
|
|
||||||
"deleted",
|
|
||||||
"gathered",
|
|
||||||
"rendered",
|
|
||||||
"parsed",
|
|
||||||
],
|
|
||||||
"default": "merged",
|
|
||||||
"type": "str",
|
|
||||||
},
|
|
||||||
} # pylint: disable=C0301
|
|
@ -1,436 +0,0 @@
|
|||||||
#
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright 2019 Red Hat
|
|
||||||
# GNU General Public License v3.0+
|
|
||||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
"""
|
|
||||||
The vyos_lldp_interfaces class
|
|
||||||
It is in this file where the current configuration (as dict)
|
|
||||||
is compared to the provided configuration (as dict) and the command set
|
|
||||||
necessary to bring the current configuration to it's desired end-state is
|
|
||||||
created
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
|
|
||||||
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
|
|
||||||
ConfigBase,
|
|
||||||
)
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.facts import (
|
|
||||||
Facts,
|
|
||||||
)
|
|
||||||
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
|
|
||||||
to_list,
|
|
||||||
dict_diff,
|
|
||||||
)
|
|
||||||
from ansible.module_utils.six import iteritems
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.utils.utils import (
|
|
||||||
search_obj_in_list,
|
|
||||||
search_dict_tv_in_list,
|
|
||||||
key_value_in_dict,
|
|
||||||
is_dict_element_present,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Lldp_interfaces(ConfigBase):
|
|
||||||
"""
|
|
||||||
The vyos_lldp_interfaces class
|
|
||||||
"""
|
|
||||||
|
|
||||||
gather_subset = [
|
|
||||||
"!all",
|
|
||||||
"!min",
|
|
||||||
]
|
|
||||||
|
|
||||||
gather_network_resources = [
|
|
||||||
"lldp_interfaces",
|
|
||||||
]
|
|
||||||
|
|
||||||
params = ["enable", "location", "name"]
|
|
||||||
|
|
||||||
def __init__(self, module):
|
|
||||||
super(Lldp_interfaces, self).__init__(module)
|
|
||||||
|
|
||||||
def get_lldp_interfaces_facts(self):
|
|
||||||
""" Get the 'facts' (the current configuration)
|
|
||||||
|
|
||||||
:rtype: A dictionary
|
|
||||||
:returns: The current configuration as a dictionary
|
|
||||||
"""
|
|
||||||
facts, _warnings = Facts(self._module).get_facts(
|
|
||||||
self.gather_subset, self.gather_network_resources
|
|
||||||
)
|
|
||||||
lldp_interfaces_facts = facts["ansible_network_resources"].get(
|
|
||||||
"lldp_interfaces"
|
|
||||||
)
|
|
||||||
if not lldp_interfaces_facts:
|
|
||||||
return []
|
|
||||||
return lldp_interfaces_facts
|
|
||||||
|
|
||||||
def execute_module(self):
|
|
||||||
""" Execute the module
|
|
||||||
|
|
||||||
:rtype: A dictionary
|
|
||||||
:returns: The result from module execution
|
|
||||||
"""
|
|
||||||
result = {"changed": False}
|
|
||||||
commands = list()
|
|
||||||
warnings = list()
|
|
||||||
existing_lldp_interfaces_facts = self.get_lldp_interfaces_facts()
|
|
||||||
commands.extend(self.set_config(existing_lldp_interfaces_facts))
|
|
||||||
if commands:
|
|
||||||
if self._module.check_mode:
|
|
||||||
resp = self._connection.edit_config(commands, commit=False)
|
|
||||||
else:
|
|
||||||
resp = self._connection.edit_config(commands)
|
|
||||||
result["changed"] = True
|
|
||||||
|
|
||||||
result["commands"] = commands
|
|
||||||
|
|
||||||
if self._module._diff:
|
|
||||||
result["diff"] = resp["diff"] if result["changed"] else None
|
|
||||||
|
|
||||||
changed_lldp_interfaces_facts = self.get_lldp_interfaces_facts()
|
|
||||||
result["before"] = existing_lldp_interfaces_facts
|
|
||||||
if result["changed"]:
|
|
||||||
result["after"] = changed_lldp_interfaces_facts
|
|
||||||
|
|
||||||
result["warnings"] = warnings
|
|
||||||
return result
|
|
||||||
|
|
||||||
def set_config(self, existing_lldp_interfaces_facts):
|
|
||||||
""" Collect the configuration from the args passed to the module,
|
|
||||||
collect the current configuration (as a dict from facts)
|
|
||||||
|
|
||||||
:rtype: A list
|
|
||||||
:returns: the commands necessary to migrate the current configuration
|
|
||||||
to the desired configuration
|
|
||||||
"""
|
|
||||||
want = self._module.params["config"]
|
|
||||||
have = existing_lldp_interfaces_facts
|
|
||||||
resp = self.set_state(want, have)
|
|
||||||
return to_list(resp)
|
|
||||||
|
|
||||||
def set_state(self, want, have):
|
|
||||||
""" Select the appropriate function based on the state provided
|
|
||||||
|
|
||||||
:param want: the desired configuration as a dictionary
|
|
||||||
:param have: the current configuration as a dictionary
|
|
||||||
:rtype: A list
|
|
||||||
:returns: the commands necessary to migrate the current configuration
|
|
||||||
to the desired configuration
|
|
||||||
"""
|
|
||||||
commands = []
|
|
||||||
state = self._module.params["state"]
|
|
||||||
if state in ("merged", "replaced", "overridden") and not want:
|
|
||||||
self._module.fail_json(
|
|
||||||
msg="value of config parameter must not be empty for state {0}".format(
|
|
||||||
state
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if state == "overridden":
|
|
||||||
commands.extend(self._state_overridden(want=want, have=have))
|
|
||||||
elif state == "deleted":
|
|
||||||
if want:
|
|
||||||
for item in want:
|
|
||||||
name = item["name"]
|
|
||||||
have_item = search_obj_in_list(name, have)
|
|
||||||
commands.extend(
|
|
||||||
self._state_deleted(want=None, have=have_item)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
for have_item in have:
|
|
||||||
commands.extend(
|
|
||||||
self._state_deleted(want=None, have=have_item)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
for want_item in want:
|
|
||||||
name = want_item["name"]
|
|
||||||
have_item = search_obj_in_list(name, have)
|
|
||||||
if state == "merged":
|
|
||||||
commands.extend(
|
|
||||||
self._state_merged(want=want_item, have=have_item)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
commands.extend(
|
|
||||||
self._state_replaced(want=want_item, have=have_item)
|
|
||||||
)
|
|
||||||
return commands
|
|
||||||
|
|
||||||
def _state_replaced(self, want, have):
|
|
||||||
""" The command generator when state is replaced
|
|
||||||
|
|
||||||
:rtype: A list
|
|
||||||
:returns: the commands necessary to migrate the current configuration
|
|
||||||
to the desired configuration
|
|
||||||
"""
|
|
||||||
commands = []
|
|
||||||
if have:
|
|
||||||
commands.extend(self._state_deleted(want, have))
|
|
||||||
commands.extend(self._state_merged(want, have))
|
|
||||||
return commands
|
|
||||||
|
|
||||||
def _state_overridden(self, want, have):
|
|
||||||
""" The command generator when state is overridden
|
|
||||||
|
|
||||||
:rtype: A list
|
|
||||||
:returns: the commands necessary to migrate the current configuration
|
|
||||||
to the desired configuration
|
|
||||||
"""
|
|
||||||
commands = []
|
|
||||||
for have_item in have:
|
|
||||||
lldp_name = have_item["name"]
|
|
||||||
lldp_in_want = search_obj_in_list(lldp_name, want)
|
|
||||||
if not lldp_in_want:
|
|
||||||
commands.append(
|
|
||||||
self._compute_command(have_item["name"], remove=True)
|
|
||||||
)
|
|
||||||
|
|
||||||
for want_item in want:
|
|
||||||
name = want_item["name"]
|
|
||||||
lldp_in_have = search_obj_in_list(name, have)
|
|
||||||
commands.extend(self._state_replaced(want_item, lldp_in_have))
|
|
||||||
return commands
|
|
||||||
|
|
||||||
def _state_merged(self, want, have):
|
|
||||||
""" The command generator when state is merged
|
|
||||||
|
|
||||||
:rtype: A list
|
|
||||||
:returns: the commands necessary to merge the provided into
|
|
||||||
the current configuration
|
|
||||||
"""
|
|
||||||
commands = []
|
|
||||||
if have:
|
|
||||||
commands.extend(self._render_updates(want, have))
|
|
||||||
else:
|
|
||||||
commands.extend(self._render_set_commands(want))
|
|
||||||
return commands
|
|
||||||
|
|
||||||
def _state_deleted(self, want, have):
|
|
||||||
""" The command generator when state is deleted
|
|
||||||
|
|
||||||
:rtype: A list
|
|
||||||
:returns: the commands necessary to remove the current configuration
|
|
||||||
of the provided objects
|
|
||||||
"""
|
|
||||||
commands = []
|
|
||||||
if want:
|
|
||||||
params = Lldp_interfaces.params
|
|
||||||
for attrib in params:
|
|
||||||
if attrib == "location":
|
|
||||||
commands.extend(
|
|
||||||
self._update_location(have["name"], want, have)
|
|
||||||
)
|
|
||||||
|
|
||||||
elif have:
|
|
||||||
commands.append(self._compute_command(have["name"], remove=True))
|
|
||||||
return commands
|
|
||||||
|
|
||||||
def _render_updates(self, want, have):
|
|
||||||
commands = []
|
|
||||||
lldp_name = have["name"]
|
|
||||||
commands.extend(self._configure_status(lldp_name, want, have))
|
|
||||||
commands.extend(self._add_location(lldp_name, want, have))
|
|
||||||
|
|
||||||
return commands
|
|
||||||
|
|
||||||
def _render_set_commands(self, want):
|
|
||||||
commands = []
|
|
||||||
have = {}
|
|
||||||
lldp_name = want["name"]
|
|
||||||
params = Lldp_interfaces.params
|
|
||||||
|
|
||||||
commands.extend(self._add_location(lldp_name, want, have))
|
|
||||||
for attrib in params:
|
|
||||||
value = want[attrib]
|
|
||||||
if value:
|
|
||||||
if attrib == "location":
|
|
||||||
commands.extend(self._add_location(lldp_name, want, have))
|
|
||||||
elif attrib == "enable":
|
|
||||||
if not value:
|
|
||||||
commands.append(
|
|
||||||
self._compute_command(lldp_name, value="disable")
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
commands.append(self._compute_command(lldp_name))
|
|
||||||
|
|
||||||
return commands
|
|
||||||
|
|
||||||
def _configure_status(self, name, want_item, have_item):
|
|
||||||
commands = []
|
|
||||||
if is_dict_element_present(have_item, "enable"):
|
|
||||||
temp_have_item = False
|
|
||||||
else:
|
|
||||||
temp_have_item = True
|
|
||||||
if want_item["enable"] != temp_have_item:
|
|
||||||
if want_item["enable"]:
|
|
||||||
commands.append(
|
|
||||||
self._compute_command(name, value="disable", remove=True)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
commands.append(self._compute_command(name, value="disable"))
|
|
||||||
return commands
|
|
||||||
|
|
||||||
def _add_location(self, name, want_item, have_item):
|
|
||||||
commands = []
|
|
||||||
have_dict = {}
|
|
||||||
have_ca = {}
|
|
||||||
set_cmd = name + " location "
|
|
||||||
want_location_type = want_item.get("location") or {}
|
|
||||||
have_location_type = have_item.get("location") or {}
|
|
||||||
|
|
||||||
if want_location_type["coordinate_based"]:
|
|
||||||
want_dict = want_location_type.get("coordinate_based") or {}
|
|
||||||
if is_dict_element_present(have_location_type, "coordinate_based"):
|
|
||||||
have_dict = have_location_type.get("coordinate_based") or {}
|
|
||||||
location_type = "coordinate-based"
|
|
||||||
updates = dict_diff(have_dict, want_dict)
|
|
||||||
for key, value in iteritems(updates):
|
|
||||||
if value:
|
|
||||||
commands.append(
|
|
||||||
self._compute_command(
|
|
||||||
set_cmd + location_type, key, str(value)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
elif want_location_type["civic_based"]:
|
|
||||||
location_type = "civic-based"
|
|
||||||
want_dict = want_location_type.get("civic_based") or {}
|
|
||||||
want_ca = want_dict.get("ca_info") or []
|
|
||||||
if is_dict_element_present(have_location_type, "civic_based"):
|
|
||||||
have_dict = have_location_type.get("civic_based") or {}
|
|
||||||
have_ca = have_dict.get("ca_info") or []
|
|
||||||
if want_dict["country_code"] != have_dict["country_code"]:
|
|
||||||
commands.append(
|
|
||||||
self._compute_command(
|
|
||||||
set_cmd + location_type,
|
|
||||||
"country-code",
|
|
||||||
str(want_dict["country_code"]),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
commands.append(
|
|
||||||
self._compute_command(
|
|
||||||
set_cmd + location_type,
|
|
||||||
"country-code",
|
|
||||||
str(want_dict["country_code"]),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
commands.extend(self._add_civic_address(name, want_ca, have_ca))
|
|
||||||
|
|
||||||
elif want_location_type["elin"]:
|
|
||||||
location_type = "elin"
|
|
||||||
if is_dict_element_present(have_location_type, "elin"):
|
|
||||||
if want_location_type.get("elin") != have_location_type.get(
|
|
||||||
"elin"
|
|
||||||
):
|
|
||||||
commands.append(
|
|
||||||
self._compute_command(
|
|
||||||
set_cmd + location_type,
|
|
||||||
value=str(want_location_type["elin"]),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
commands.append(
|
|
||||||
self._compute_command(
|
|
||||||
set_cmd + location_type,
|
|
||||||
value=str(want_location_type["elin"]),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return commands
|
|
||||||
|
|
||||||
def _update_location(self, name, want_item, have_item):
|
|
||||||
commands = []
|
|
||||||
del_cmd = name + " location"
|
|
||||||
want_location_type = want_item.get("location") or {}
|
|
||||||
have_location_type = have_item.get("location") or {}
|
|
||||||
|
|
||||||
if want_location_type["coordinate_based"]:
|
|
||||||
want_dict = want_location_type.get("coordinate_based") or {}
|
|
||||||
if is_dict_element_present(have_location_type, "coordinate_based"):
|
|
||||||
have_dict = have_location_type.get("coordinate_based") or {}
|
|
||||||
location_type = "coordinate-based"
|
|
||||||
for key, value in iteritems(have_dict):
|
|
||||||
only_in_have = key_value_in_dict(key, value, want_dict)
|
|
||||||
if not only_in_have:
|
|
||||||
commands.append(
|
|
||||||
self._compute_command(
|
|
||||||
del_cmd + location_type, key, str(value), True
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
commands.append(self._compute_command(del_cmd, remove=True))
|
|
||||||
|
|
||||||
elif want_location_type["civic_based"]:
|
|
||||||
want_dict = want_location_type.get("civic_based") or {}
|
|
||||||
want_ca = want_dict.get("ca_info") or []
|
|
||||||
if is_dict_element_present(have_location_type, "civic_based"):
|
|
||||||
have_dict = have_location_type.get("civic_based") or {}
|
|
||||||
have_ca = have_dict.get("ca_info")
|
|
||||||
commands.extend(
|
|
||||||
self._update_civic_address(name, want_ca, have_ca)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
commands.append(self._compute_command(del_cmd, remove=True))
|
|
||||||
|
|
||||||
else:
|
|
||||||
if is_dict_element_present(have_location_type, "elin"):
|
|
||||||
if want_location_type.get("elin") != have_location_type.get(
|
|
||||||
"elin"
|
|
||||||
):
|
|
||||||
commands.append(
|
|
||||||
self._compute_command(del_cmd, remove=True)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
commands.append(self._compute_command(del_cmd, remove=True))
|
|
||||||
return commands
|
|
||||||
|
|
||||||
def _add_civic_address(self, name, want, have):
|
|
||||||
commands = []
|
|
||||||
for item in want:
|
|
||||||
ca_type = item["ca_type"]
|
|
||||||
ca_value = item["ca_value"]
|
|
||||||
obj_in_have = search_dict_tv_in_list(
|
|
||||||
ca_type, ca_value, have, "ca_type", "ca_value"
|
|
||||||
)
|
|
||||||
if not obj_in_have:
|
|
||||||
commands.append(
|
|
||||||
self._compute_command(
|
|
||||||
key=name + " location civic-based ca-type",
|
|
||||||
attrib=str(ca_type) + " ca-value",
|
|
||||||
value=ca_value,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return commands
|
|
||||||
|
|
||||||
def _update_civic_address(self, name, want, have):
|
|
||||||
commands = []
|
|
||||||
for item in have:
|
|
||||||
ca_type = item["ca_type"]
|
|
||||||
ca_value = item["ca_value"]
|
|
||||||
in_want = search_dict_tv_in_list(
|
|
||||||
ca_type, ca_value, want, "ca_type", "ca_value"
|
|
||||||
)
|
|
||||||
if not in_want:
|
|
||||||
commands.append(
|
|
||||||
self._compute_command(
|
|
||||||
name,
|
|
||||||
"location civic-based ca-type",
|
|
||||||
str(ca_type),
|
|
||||||
remove=True,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return commands
|
|
||||||
|
|
||||||
def _compute_command(self, key, attrib=None, value=None, remove=False):
|
|
||||||
if remove:
|
|
||||||
cmd = "delete service lldp interface "
|
|
||||||
else:
|
|
||||||
cmd = "set service lldp interface "
|
|
||||||
cmd += key
|
|
||||||
if attrib:
|
|
||||||
cmd += " " + attrib
|
|
||||||
if value:
|
|
||||||
cmd += " '" + value + "'"
|
|
||||||
return cmd
|
|
@ -1,82 +0,0 @@
|
|||||||
# Copyright 2019 Red Hat
|
|
||||||
# GNU General Public License v3.0+
|
|
||||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
"""
|
|
||||||
The facts class for vyos
|
|
||||||
this file validates each subset of facts and selectively
|
|
||||||
calls the appropriate facts gathering function
|
|
||||||
"""
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts import (
|
|
||||||
FactsBase,
|
|
||||||
)
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.interfaces.interfaces import (
|
|
||||||
InterfacesFacts,
|
|
||||||
)
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.l3_interfaces.l3_interfaces import (
|
|
||||||
L3_interfacesFacts,
|
|
||||||
)
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.lag_interfaces.lag_interfaces import (
|
|
||||||
Lag_interfacesFacts,
|
|
||||||
)
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.lldp_global.lldp_global import (
|
|
||||||
Lldp_globalFacts,
|
|
||||||
)
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.lldp_interfaces.lldp_interfaces import (
|
|
||||||
Lldp_interfacesFacts,
|
|
||||||
)
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.firewall_rules.firewall_rules import (
|
|
||||||
Firewall_rulesFacts,
|
|
||||||
)
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.static_routes.static_routes import (
|
|
||||||
Static_routesFacts,
|
|
||||||
)
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.legacy.base import (
|
|
||||||
Default,
|
|
||||||
Neighbors,
|
|
||||||
Config,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
FACT_LEGACY_SUBSETS = dict(default=Default, neighbors=Neighbors, config=Config)
|
|
||||||
FACT_RESOURCE_SUBSETS = dict(
|
|
||||||
interfaces=InterfacesFacts,
|
|
||||||
l3_interfaces=L3_interfacesFacts,
|
|
||||||
lag_interfaces=Lag_interfacesFacts,
|
|
||||||
lldp_global=Lldp_globalFacts,
|
|
||||||
lldp_interfaces=Lldp_interfacesFacts,
|
|
||||||
static_routes=Static_routesFacts,
|
|
||||||
firewall_rules=Firewall_rulesFacts,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Facts(FactsBase):
|
|
||||||
""" The fact class for vyos
|
|
||||||
"""
|
|
||||||
|
|
||||||
VALID_LEGACY_GATHER_SUBSETS = frozenset(FACT_LEGACY_SUBSETS.keys())
|
|
||||||
VALID_RESOURCE_SUBSETS = frozenset(FACT_RESOURCE_SUBSETS.keys())
|
|
||||||
|
|
||||||
def __init__(self, module):
|
|
||||||
super(Facts, self).__init__(module)
|
|
||||||
|
|
||||||
def get_facts(
|
|
||||||
self, legacy_facts_type=None, resource_facts_type=None, data=None
|
|
||||||
):
|
|
||||||
""" Collect the facts for vyos
|
|
||||||
:param legacy_facts_type: List of legacy facts types
|
|
||||||
:param resource_facts_type: List of resource fact types
|
|
||||||
:param data: previously collected conf
|
|
||||||
:rtype: dict
|
|
||||||
:return: the facts gathered
|
|
||||||
"""
|
|
||||||
if self.VALID_RESOURCE_SUBSETS:
|
|
||||||
self.get_network_resources_facts(
|
|
||||||
FACT_RESOURCE_SUBSETS, resource_facts_type, data
|
|
||||||
)
|
|
||||||
if self.VALID_LEGACY_GATHER_SUBSETS:
|
|
||||||
self.get_network_legacy_facts(
|
|
||||||
FACT_LEGACY_SUBSETS, legacy_facts_type
|
|
||||||
)
|
|
||||||
return self.ansible_facts, self._warnings
|
|
@ -1,379 +0,0 @@
|
|||||||
#
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright 2019 Red Hat
|
|
||||||
# GNU General Public License v3.0+
|
|
||||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
"""
|
|
||||||
The vyos firewall_rules fact class
|
|
||||||
It is in this file the configuration is collected from the device
|
|
||||||
for a given resource, parsed, and the facts tree is populated
|
|
||||||
based on the configuration.
|
|
||||||
"""
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
|
|
||||||
from re import findall, search, M
|
|
||||||
from copy import deepcopy
|
|
||||||
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import (
|
|
||||||
utils,
|
|
||||||
)
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.firewall_rules.firewall_rules import (
|
|
||||||
Firewall_rulesArgs,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Firewall_rulesFacts(object):
|
|
||||||
""" The vyos firewall_rules fact class
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, module, subspec="config", options="options"):
|
|
||||||
self._module = module
|
|
||||||
self.argument_spec = Firewall_rulesArgs.argument_spec
|
|
||||||
spec = deepcopy(self.argument_spec)
|
|
||||||
if subspec:
|
|
||||||
if options:
|
|
||||||
facts_argument_spec = spec[subspec][options]
|
|
||||||
else:
|
|
||||||
facts_argument_spec = spec[subspec]
|
|
||||||
else:
|
|
||||||
facts_argument_spec = spec
|
|
||||||
|
|
||||||
self.generated_spec = utils.generate_dict(facts_argument_spec)
|
|
||||||
|
|
||||||
def get_device_data(self, connection):
|
|
||||||
return connection.get_config()
|
|
||||||
|
|
||||||
def populate_facts(self, connection, ansible_facts, data=None):
|
|
||||||
""" Populate the facts for firewall_rules
|
|
||||||
:param connection: the device connection
|
|
||||||
:param ansible_facts: Facts dictionary
|
|
||||||
:param data: previously collected conf
|
|
||||||
:rtype: dictionary
|
|
||||||
:returns: facts
|
|
||||||
"""
|
|
||||||
if not data:
|
|
||||||
# typically data is populated from the current device configuration
|
|
||||||
# data = connection.get('show running-config | section ^interface')
|
|
||||||
# using mock data instead
|
|
||||||
data = self.get_device_data(connection)
|
|
||||||
# split the config into instances of the resource
|
|
||||||
objs = []
|
|
||||||
v6_rules = findall(
|
|
||||||
r"^set firewall ipv6-name (?:\'*)(\S+)(?:\'*)", data, M
|
|
||||||
)
|
|
||||||
v4_rules = findall(r"^set firewall name (?:\'*)(\S+)(?:\'*)", data, M)
|
|
||||||
if v6_rules:
|
|
||||||
config = self.get_rules(data, v6_rules, type="ipv6")
|
|
||||||
if config:
|
|
||||||
config = utils.remove_empties(config)
|
|
||||||
objs.append(config)
|
|
||||||
if v4_rules:
|
|
||||||
config = self.get_rules(data, v4_rules, type="ipv4")
|
|
||||||
if config:
|
|
||||||
config = utils.remove_empties(config)
|
|
||||||
objs.append(config)
|
|
||||||
|
|
||||||
ansible_facts["ansible_network_resources"].pop("firewall_rules", None)
|
|
||||||
facts = {}
|
|
||||||
if objs:
|
|
||||||
facts["firewall_rules"] = []
|
|
||||||
params = utils.validate_config(
|
|
||||||
self.argument_spec, {"config": objs}
|
|
||||||
)
|
|
||||||
for cfg in params["config"]:
|
|
||||||
facts["firewall_rules"].append(utils.remove_empties(cfg))
|
|
||||||
|
|
||||||
ansible_facts["ansible_network_resources"].update(facts)
|
|
||||||
return ansible_facts
|
|
||||||
|
|
||||||
def get_rules(self, data, rules, type):
|
|
||||||
"""
|
|
||||||
This function performs following:
|
|
||||||
- Form regex to fetch 'rule-sets' specific config from data.
|
|
||||||
- Form the rule-set list based on ip address.
|
|
||||||
:param data: configuration.
|
|
||||||
:param rules: list of rule-sets.
|
|
||||||
:param type: ip address type.
|
|
||||||
:return: generated rule-sets configuration.
|
|
||||||
"""
|
|
||||||
r_v4 = []
|
|
||||||
r_v6 = []
|
|
||||||
for r in set(rules):
|
|
||||||
rule_regex = r" %s .+$" % r.strip("'")
|
|
||||||
cfg = findall(rule_regex, data, M)
|
|
||||||
fr = self.render_config(cfg, r.strip("'"))
|
|
||||||
fr["name"] = r.strip("'")
|
|
||||||
if type == "ipv6":
|
|
||||||
r_v6.append(fr)
|
|
||||||
else:
|
|
||||||
r_v4.append(fr)
|
|
||||||
if r_v4:
|
|
||||||
config = {"afi": "ipv4", "rule_sets": r_v4}
|
|
||||||
if r_v6:
|
|
||||||
config = {"afi": "ipv6", "rule_sets": r_v6}
|
|
||||||
return config
|
|
||||||
|
|
||||||
def render_config(self, conf, match):
|
|
||||||
"""
|
|
||||||
Render config as dictionary structure and delete keys
|
|
||||||
from spec for null values
|
|
||||||
|
|
||||||
:param spec: The facts tree, generated from the argspec
|
|
||||||
:param conf: The configuration
|
|
||||||
:rtype: dictionary
|
|
||||||
:returns: The generated config
|
|
||||||
"""
|
|
||||||
conf = "\n".join(filter(lambda x: x, conf))
|
|
||||||
a_lst = ["description", "default_action", "enable_default_log"]
|
|
||||||
config = self.parse_attr(conf, a_lst, match)
|
|
||||||
if not config:
|
|
||||||
config = {}
|
|
||||||
config["rules"] = self.parse_rules_lst(conf)
|
|
||||||
return config
|
|
||||||
|
|
||||||
def parse_rules_lst(self, conf):
|
|
||||||
"""
|
|
||||||
This function forms the regex to fetch the 'rules' with in
|
|
||||||
'rule-sets'
|
|
||||||
:param conf: configuration data.
|
|
||||||
:return: generated rule list configuration.
|
|
||||||
"""
|
|
||||||
r_lst = []
|
|
||||||
rules = findall(r"rule (?:\'*)(\d+)(?:\'*)", conf, M)
|
|
||||||
if rules:
|
|
||||||
rules_lst = []
|
|
||||||
for r in set(rules):
|
|
||||||
r_regex = r" %s .+$" % r
|
|
||||||
cfg = "\n".join(findall(r_regex, conf, M))
|
|
||||||
obj = self.parse_rules(cfg)
|
|
||||||
obj["number"] = int(r)
|
|
||||||
if obj:
|
|
||||||
rules_lst.append(obj)
|
|
||||||
r_lst = sorted(rules_lst, key=lambda i: i["number"])
|
|
||||||
return r_lst
|
|
||||||
|
|
||||||
def parse_rules(self, conf):
|
|
||||||
"""
|
|
||||||
This function triggers the parsing of 'rule' attributes.
|
|
||||||
a_lst is a list having rule attributes which doesn't
|
|
||||||
have further sub attributes.
|
|
||||||
:param conf: configuration
|
|
||||||
:return: generated rule configuration dictionary.
|
|
||||||
"""
|
|
||||||
a_lst = [
|
|
||||||
"ipsec",
|
|
||||||
"action",
|
|
||||||
"protocol",
|
|
||||||
"fragment",
|
|
||||||
"disabled",
|
|
||||||
"description",
|
|
||||||
]
|
|
||||||
rule = self.parse_attr(conf, a_lst)
|
|
||||||
r_sub = {
|
|
||||||
"p2p": self.parse_p2p(conf),
|
|
||||||
"tcp": self.parse_tcp(conf, "tcp"),
|
|
||||||
"icmp": self.parse_icmp(conf, "icmp"),
|
|
||||||
"time": self.parse_time(conf, "time"),
|
|
||||||
"limit": self.parse_limit(conf, "limit"),
|
|
||||||
"state": self.parse_state(conf, "state"),
|
|
||||||
"recent": self.parse_recent(conf, "recent"),
|
|
||||||
"source": self.parse_src_or_dest(conf, "source"),
|
|
||||||
"destination": self.parse_src_or_dest(conf, "destination"),
|
|
||||||
}
|
|
||||||
rule.update(r_sub)
|
|
||||||
return rule
|
|
||||||
|
|
||||||
def parse_p2p(self, conf):
|
|
||||||
"""
|
|
||||||
This function forms the regex to fetch the 'p2p' with in
|
|
||||||
'rules'
|
|
||||||
:param conf: configuration data.
|
|
||||||
:return: generated rule list configuration.
|
|
||||||
"""
|
|
||||||
a_lst = []
|
|
||||||
applications = findall(r"p2p (?:\'*)(\d+)(?:\'*)", conf, M)
|
|
||||||
if applications:
|
|
||||||
app_lst = []
|
|
||||||
for r in set(applications):
|
|
||||||
obj = {"application": r.strip("'")}
|
|
||||||
app_lst.append(obj)
|
|
||||||
a_lst = sorted(app_lst, key=lambda i: i["application"])
|
|
||||||
return a_lst
|
|
||||||
|
|
||||||
def parse_src_or_dest(self, conf, attrib=None):
|
|
||||||
"""
|
|
||||||
This function triggers the parsing of 'source or
|
|
||||||
destination' attributes.
|
|
||||||
:param conf: configuration.
|
|
||||||
:param attrib:'source/destination'.
|
|
||||||
:return:generated source/destination configuration dictionary.
|
|
||||||
"""
|
|
||||||
a_lst = ["port", "address", "mac_address"]
|
|
||||||
cfg_dict = self.parse_attr(conf, a_lst, match=attrib)
|
|
||||||
cfg_dict["group"] = self.parse_group(conf, attrib + " group")
|
|
||||||
return cfg_dict
|
|
||||||
|
|
||||||
def parse_recent(self, conf, attrib=None):
|
|
||||||
"""
|
|
||||||
This function triggers the parsing of 'recent' attributes
|
|
||||||
:param conf: configuration.
|
|
||||||
:param attrib: 'recent'.
|
|
||||||
:return: generated config dictionary.
|
|
||||||
"""
|
|
||||||
a_lst = ["time", "count"]
|
|
||||||
cfg_dict = self.parse_attr(conf, a_lst, match=attrib)
|
|
||||||
return cfg_dict
|
|
||||||
|
|
||||||
def parse_tcp(self, conf, attrib=None):
|
|
||||||
"""
|
|
||||||
This function triggers the parsing of 'tcp' attributes.
|
|
||||||
:param conf: configuration.
|
|
||||||
:param attrib: 'tcp'.
|
|
||||||
:return: generated config dictionary.
|
|
||||||
"""
|
|
||||||
cfg_dict = self.parse_attr(conf, ["flags"], match=attrib)
|
|
||||||
return cfg_dict
|
|
||||||
|
|
||||||
def parse_time(self, conf, attrib=None):
|
|
||||||
"""
|
|
||||||
This function triggers the parsing of 'time' attributes.
|
|
||||||
:param conf: configuration.
|
|
||||||
:param attrib: 'time'.
|
|
||||||
:return: generated config dictionary.
|
|
||||||
"""
|
|
||||||
a_lst = [
|
|
||||||
"stopdate",
|
|
||||||
"stoptime",
|
|
||||||
"weekdays",
|
|
||||||
"monthdays",
|
|
||||||
"startdate",
|
|
||||||
"starttime",
|
|
||||||
]
|
|
||||||
cfg_dict = self.parse_attr(conf, a_lst, match=attrib)
|
|
||||||
return cfg_dict
|
|
||||||
|
|
||||||
def parse_state(self, conf, attrib=None):
|
|
||||||
"""
|
|
||||||
This function triggers the parsing of 'state' attributes.
|
|
||||||
:param conf: configuration
|
|
||||||
:param attrib: 'state'.
|
|
||||||
:return: generated config dictionary.
|
|
||||||
"""
|
|
||||||
a_lst = ["new", "invalid", "related", "established"]
|
|
||||||
cfg_dict = self.parse_attr(conf, a_lst, match=attrib)
|
|
||||||
return cfg_dict
|
|
||||||
|
|
||||||
def parse_group(self, conf, attrib=None):
|
|
||||||
"""
|
|
||||||
This function triggers the parsing of 'group' attributes.
|
|
||||||
:param conf: configuration.
|
|
||||||
:param attrib: 'group'.
|
|
||||||
:return: generated config dictionary.
|
|
||||||
"""
|
|
||||||
a_lst = ["port_group", "address_group", "network_group"]
|
|
||||||
cfg_dict = self.parse_attr(conf, a_lst, match=attrib)
|
|
||||||
return cfg_dict
|
|
||||||
|
|
||||||
def parse_icmp(self, conf, attrib=None):
|
|
||||||
"""
|
|
||||||
This function triggers the parsing of 'icmp' attributes.
|
|
||||||
:param conf: configuration to be parsed.
|
|
||||||
:param attrib: 'icmp'.
|
|
||||||
:return: generated config dictionary.
|
|
||||||
"""
|
|
||||||
a_lst = ["code", "type", "type_name"]
|
|
||||||
cfg_dict = self.parse_attr(conf, a_lst, match=attrib)
|
|
||||||
return cfg_dict
|
|
||||||
|
|
||||||
def parse_limit(self, conf, attrib=None):
|
|
||||||
"""
|
|
||||||
This function triggers the parsing of 'limit' attributes.
|
|
||||||
:param conf: configuration to be parsed.
|
|
||||||
:param attrib: 'limit'
|
|
||||||
:return: generated config dictionary.
|
|
||||||
"""
|
|
||||||
cfg_dict = self.parse_attr(conf, ["burst"], match=attrib)
|
|
||||||
cfg_dict["rate"] = self.parse_rate(conf, "rate")
|
|
||||||
return cfg_dict
|
|
||||||
|
|
||||||
def parse_rate(self, conf, attrib=None):
|
|
||||||
"""
|
|
||||||
This function triggers the parsing of 'rate' attributes.
|
|
||||||
:param conf: configuration.
|
|
||||||
:param attrib: 'rate'
|
|
||||||
:return: generated config dictionary.
|
|
||||||
"""
|
|
||||||
a_lst = ["unit", "number"]
|
|
||||||
cfg_dict = self.parse_attr(conf, a_lst, match=attrib)
|
|
||||||
return cfg_dict
|
|
||||||
|
|
||||||
def parse_attr(self, conf, attr_list, match=None):
|
|
||||||
"""
|
|
||||||
This function peforms the following:
|
|
||||||
- Form the regex to fetch the required attribute config.
|
|
||||||
- Type cast the output in desired format.
|
|
||||||
:param conf: configuration.
|
|
||||||
:param attr_list: list of attributes.
|
|
||||||
:param match: parent node/attribute name.
|
|
||||||
:return: generated config dictionary.
|
|
||||||
"""
|
|
||||||
config = {}
|
|
||||||
for attrib in attr_list:
|
|
||||||
regex = self.map_regex(attrib)
|
|
||||||
if match:
|
|
||||||
regex = match + " " + regex
|
|
||||||
if conf:
|
|
||||||
if self.is_bool(attrib):
|
|
||||||
out = conf.find(attrib.replace("_", "-"))
|
|
||||||
|
|
||||||
dis = conf.find(attrib.replace("_", "-") + " 'disable'")
|
|
||||||
if out >= 1:
|
|
||||||
if dis >= 1:
|
|
||||||
config[attrib] = False
|
|
||||||
else:
|
|
||||||
config[attrib] = True
|
|
||||||
else:
|
|
||||||
out = search(r"^.*" + regex + " (.+)", conf, M)
|
|
||||||
if out:
|
|
||||||
val = out.group(1).strip("'")
|
|
||||||
if self.is_num(attrib):
|
|
||||||
val = int(val)
|
|
||||||
config[attrib] = val
|
|
||||||
return config
|
|
||||||
|
|
||||||
def map_regex(self, attrib):
|
|
||||||
"""
|
|
||||||
- This function construct the regex string.
|
|
||||||
- replace the underscore with hyphen.
|
|
||||||
:param attrib: attribute
|
|
||||||
:return: regex string
|
|
||||||
"""
|
|
||||||
regex = attrib.replace("_", "-")
|
|
||||||
if attrib == "disabled":
|
|
||||||
regex = "disable"
|
|
||||||
return regex
|
|
||||||
|
|
||||||
def is_bool(self, attrib):
|
|
||||||
"""
|
|
||||||
This function looks for the attribute in predefined bool type set.
|
|
||||||
:param attrib: attribute.
|
|
||||||
:return: True/False
|
|
||||||
"""
|
|
||||||
bool_set = (
|
|
||||||
"new",
|
|
||||||
"invalid",
|
|
||||||
"related",
|
|
||||||
"disabled",
|
|
||||||
"established",
|
|
||||||
"enable_default_log",
|
|
||||||
)
|
|
||||||
return True if attrib in bool_set else False
|
|
||||||
|
|
||||||
def is_num(self, attrib):
|
|
||||||
"""
|
|
||||||
This function looks for the attribute in predefined integer type set.
|
|
||||||
:param attrib: attribute.
|
|
||||||
:return: True/false.
|
|
||||||
"""
|
|
||||||
num_set = ("time", "code", "type", "count", "burst", "number")
|
|
||||||
return True if attrib in num_set else False
|
|
@ -1,132 +0,0 @@
|
|||||||
#
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright 2019 Red Hat
|
|
||||||
# GNU General Public License v3.0+
|
|
||||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
"""
|
|
||||||
The vyos interfaces fact class
|
|
||||||
It is in this file the configuration is collected from the device
|
|
||||||
for a given resource, parsed, and the facts tree is populated
|
|
||||||
based on the configuration.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
|
|
||||||
from re import findall, M
|
|
||||||
from copy import deepcopy
|
|
||||||
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import (
|
|
||||||
utils,
|
|
||||||
)
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.interfaces.interfaces import (
|
|
||||||
InterfacesArgs,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class InterfacesFacts(object):
|
|
||||||
""" The vyos interfaces fact class
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, module, subspec="config", options="options"):
|
|
||||||
self._module = module
|
|
||||||
self.argument_spec = InterfacesArgs.argument_spec
|
|
||||||
spec = deepcopy(self.argument_spec)
|
|
||||||
if subspec:
|
|
||||||
if options:
|
|
||||||
facts_argument_spec = spec[subspec][options]
|
|
||||||
else:
|
|
||||||
facts_argument_spec = spec[subspec]
|
|
||||||
else:
|
|
||||||
facts_argument_spec = spec
|
|
||||||
|
|
||||||
self.generated_spec = utils.generate_dict(facts_argument_spec)
|
|
||||||
|
|
||||||
def populate_facts(self, connection, ansible_facts, data=None):
|
|
||||||
""" Populate the facts for interfaces
|
|
||||||
:param connection: the device connection
|
|
||||||
:param ansible_facts: Facts dictionary
|
|
||||||
:param data: previously collected conf
|
|
||||||
:rtype: dictionary
|
|
||||||
:returns: facts
|
|
||||||
"""
|
|
||||||
if not data:
|
|
||||||
data = connection.get_config(flags=["| grep interfaces"])
|
|
||||||
|
|
||||||
objs = []
|
|
||||||
interface_names = findall(
|
|
||||||
r"^set interfaces (?:ethernet|bonding|vti|loopback|vxlan) (?:\'*)(\S+)(?:\'*)",
|
|
||||||
data,
|
|
||||||
M,
|
|
||||||
)
|
|
||||||
if interface_names:
|
|
||||||
for interface in set(interface_names):
|
|
||||||
intf_regex = r" %s .+$" % interface.strip("'")
|
|
||||||
cfg = findall(intf_regex, data, M)
|
|
||||||
obj = self.render_config(cfg)
|
|
||||||
obj["name"] = interface.strip("'")
|
|
||||||
if obj:
|
|
||||||
objs.append(obj)
|
|
||||||
facts = {}
|
|
||||||
if objs:
|
|
||||||
facts["interfaces"] = []
|
|
||||||
params = utils.validate_config(
|
|
||||||
self.argument_spec, {"config": objs}
|
|
||||||
)
|
|
||||||
for cfg in params["config"]:
|
|
||||||
facts["interfaces"].append(utils.remove_empties(cfg))
|
|
||||||
|
|
||||||
ansible_facts["ansible_network_resources"].update(facts)
|
|
||||||
return ansible_facts
|
|
||||||
|
|
||||||
def render_config(self, conf):
|
|
||||||
"""
|
|
||||||
Render config as dictionary structure and delete keys
|
|
||||||
from spec for null values
|
|
||||||
|
|
||||||
:param spec: The facts tree, generated from the argspec
|
|
||||||
:param conf: The configuration
|
|
||||||
:rtype: dictionary
|
|
||||||
:returns: The generated config
|
|
||||||
"""
|
|
||||||
vif_conf = "\n".join(filter(lambda x: ("vif" in x), conf))
|
|
||||||
eth_conf = "\n".join(filter(lambda x: ("vif" not in x), conf))
|
|
||||||
config = self.parse_attribs(
|
|
||||||
["description", "speed", "mtu", "duplex"], eth_conf
|
|
||||||
)
|
|
||||||
config["vifs"] = self.parse_vifs(vif_conf)
|
|
||||||
|
|
||||||
return utils.remove_empties(config)
|
|
||||||
|
|
||||||
def parse_vifs(self, conf):
|
|
||||||
vif_names = findall(r"vif (?:\'*)(\d+)(?:\'*)", conf, M)
|
|
||||||
vifs_list = None
|
|
||||||
|
|
||||||
if vif_names:
|
|
||||||
vifs_list = []
|
|
||||||
for vif in set(vif_names):
|
|
||||||
vif_regex = r" %s .+$" % vif
|
|
||||||
cfg = "\n".join(findall(vif_regex, conf, M))
|
|
||||||
obj = self.parse_attribs(["description", "mtu"], cfg)
|
|
||||||
obj["vlan_id"] = int(vif)
|
|
||||||
if obj:
|
|
||||||
vifs_list.append(obj)
|
|
||||||
vifs_list = sorted(vifs_list, key=lambda i: i["vlan_id"])
|
|
||||||
|
|
||||||
return vifs_list
|
|
||||||
|
|
||||||
def parse_attribs(self, attribs, conf):
|
|
||||||
config = {}
|
|
||||||
for item in attribs:
|
|
||||||
value = utils.parse_conf_arg(conf, item)
|
|
||||||
if value and item == "mtu":
|
|
||||||
config[item] = int(value.strip("'"))
|
|
||||||
elif value:
|
|
||||||
config[item] = value.strip("'")
|
|
||||||
else:
|
|
||||||
config[item] = None
|
|
||||||
if "disable" in conf:
|
|
||||||
config["enabled"] = False
|
|
||||||
else:
|
|
||||||
config["enabled"] = True
|
|
||||||
|
|
||||||
return utils.remove_empties(config)
|
|
@ -1,141 +0,0 @@
|
|||||||
#
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright 2019 Red Hat
|
|
||||||
# GNU General Public License v3.0+
|
|
||||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
"""
|
|
||||||
The vyos l3_interfaces fact class
|
|
||||||
It is in this file the configuration is collected from the device
|
|
||||||
for a given resource, parsed, and the facts tree is populated
|
|
||||||
based on the configuration.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
|
|
||||||
import re
|
|
||||||
from copy import deepcopy
|
|
||||||
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import (
|
|
||||||
utils,
|
|
||||||
)
|
|
||||||
from ansible.module_utils.six import iteritems
|
|
||||||
from ansible_collections.ansible.netcommon.plugins.module_utils.compat import (
|
|
||||||
ipaddress,
|
|
||||||
)
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.l3_interfaces.l3_interfaces import (
|
|
||||||
L3_interfacesArgs,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class L3_interfacesFacts(object):
|
|
||||||
""" The vyos l3_interfaces fact class
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, module, subspec="config", options="options"):
|
|
||||||
self._module = module
|
|
||||||
self.argument_spec = L3_interfacesArgs.argument_spec
|
|
||||||
spec = deepcopy(self.argument_spec)
|
|
||||||
if subspec:
|
|
||||||
if options:
|
|
||||||
facts_argument_spec = spec[subspec][options]
|
|
||||||
else:
|
|
||||||
facts_argument_spec = spec[subspec]
|
|
||||||
else:
|
|
||||||
facts_argument_spec = spec
|
|
||||||
|
|
||||||
self.generated_spec = utils.generate_dict(facts_argument_spec)
|
|
||||||
|
|
||||||
def populate_facts(self, connection, ansible_facts, data=None):
|
|
||||||
""" Populate the facts for l3_interfaces
|
|
||||||
:param connection: the device connection
|
|
||||||
:param ansible_facts: Facts dictionary
|
|
||||||
:param data: previously collected conf
|
|
||||||
:rtype: dictionary
|
|
||||||
:returns: facts
|
|
||||||
"""
|
|
||||||
if not data:
|
|
||||||
data = connection.get_config()
|
|
||||||
|
|
||||||
# operate on a collection of resource x
|
|
||||||
objs = []
|
|
||||||
interface_names = re.findall(
|
|
||||||
r"set interfaces (?:ethernet|bonding|vti|vxlan) (?:\'*)(\S+)(?:\'*)",
|
|
||||||
data,
|
|
||||||
re.M,
|
|
||||||
)
|
|
||||||
if interface_names:
|
|
||||||
for interface in set(interface_names):
|
|
||||||
intf_regex = r" %s .+$" % interface
|
|
||||||
cfg = re.findall(intf_regex, data, re.M)
|
|
||||||
obj = self.render_config(cfg)
|
|
||||||
obj["name"] = interface.strip("'")
|
|
||||||
if obj:
|
|
||||||
objs.append(obj)
|
|
||||||
|
|
||||||
ansible_facts["ansible_network_resources"].pop("l3_interfaces", None)
|
|
||||||
facts = {}
|
|
||||||
if objs:
|
|
||||||
facts["l3_interfaces"] = []
|
|
||||||
params = utils.validate_config(
|
|
||||||
self.argument_spec, {"config": objs}
|
|
||||||
)
|
|
||||||
for cfg in params["config"]:
|
|
||||||
facts["l3_interfaces"].append(utils.remove_empties(cfg))
|
|
||||||
|
|
||||||
ansible_facts["ansible_network_resources"].update(facts)
|
|
||||||
return ansible_facts
|
|
||||||
|
|
||||||
def render_config(self, conf):
|
|
||||||
"""
|
|
||||||
Render config as dictionary structure and delete keys from spec for null values
|
|
||||||
:param spec: The facts tree, generated from the argspec
|
|
||||||
:param conf: The configuration
|
|
||||||
:rtype: dictionary
|
|
||||||
:returns: The generated config
|
|
||||||
"""
|
|
||||||
vif_conf = "\n".join(filter(lambda x: ("vif" in x), conf))
|
|
||||||
eth_conf = "\n".join(filter(lambda x: ("vif" not in x), conf))
|
|
||||||
config = self.parse_attribs(eth_conf)
|
|
||||||
config["vifs"] = self.parse_vifs(vif_conf)
|
|
||||||
|
|
||||||
return utils.remove_empties(config)
|
|
||||||
|
|
||||||
def parse_vifs(self, conf):
|
|
||||||
vif_names = re.findall(r"vif (\d+)", conf, re.M)
|
|
||||||
vifs_list = None
|
|
||||||
if vif_names:
|
|
||||||
vifs_list = []
|
|
||||||
for vif in set(vif_names):
|
|
||||||
vif_regex = r" %s .+$" % vif
|
|
||||||
cfg = "\n".join(re.findall(vif_regex, conf, re.M))
|
|
||||||
obj = self.parse_attribs(cfg)
|
|
||||||
obj["vlan_id"] = vif
|
|
||||||
if obj:
|
|
||||||
vifs_list.append(obj)
|
|
||||||
|
|
||||||
return vifs_list
|
|
||||||
|
|
||||||
def parse_attribs(self, conf):
|
|
||||||
config = {}
|
|
||||||
ipaddrs = re.findall(r"address (\S+)", conf, re.M)
|
|
||||||
config["ipv4"] = []
|
|
||||||
config["ipv6"] = []
|
|
||||||
|
|
||||||
for item in ipaddrs:
|
|
||||||
item = item.strip("'")
|
|
||||||
if item == "dhcp":
|
|
||||||
config["ipv4"].append({"address": item})
|
|
||||||
elif item == "dhcpv6":
|
|
||||||
config["ipv6"].append({"address": item})
|
|
||||||
else:
|
|
||||||
ip_version = ipaddress.ip_address(item.split("/")[0]).version
|
|
||||||
if ip_version == 4:
|
|
||||||
config["ipv4"].append({"address": item})
|
|
||||||
else:
|
|
||||||
config["ipv6"].append({"address": item})
|
|
||||||
|
|
||||||
for key, value in iteritems(config):
|
|
||||||
if value == []:
|
|
||||||
config[key] = None
|
|
||||||
|
|
||||||
return utils.remove_empties(config)
|
|
@ -1,151 +0,0 @@
|
|||||||
#
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright 2019 Red Hat
|
|
||||||
# GNU General Public License v3.0+
|
|
||||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
"""
|
|
||||||
The vyos lag_interfaces fact class
|
|
||||||
It is in this file the configuration is collected from the device
|
|
||||||
for a given resource, parsed, and the facts tree is populated
|
|
||||||
based on the configuration.
|
|
||||||
"""
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from re import findall, search, M
|
|
||||||
from copy import deepcopy
|
|
||||||
|
|
||||||
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import (
|
|
||||||
utils,
|
|
||||||
)
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.lag_interfaces.lag_interfaces import (
|
|
||||||
Lag_interfacesArgs,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Lag_interfacesFacts(object):
|
|
||||||
""" The vyos lag_interfaces fact class
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, module, subspec="config", options="options"):
|
|
||||||
self._module = module
|
|
||||||
self.argument_spec = Lag_interfacesArgs.argument_spec
|
|
||||||
spec = deepcopy(self.argument_spec)
|
|
||||||
if subspec:
|
|
||||||
if options:
|
|
||||||
facts_argument_spec = spec[subspec][options]
|
|
||||||
else:
|
|
||||||
facts_argument_spec = spec[subspec]
|
|
||||||
else:
|
|
||||||
facts_argument_spec = spec
|
|
||||||
|
|
||||||
self.generated_spec = utils.generate_dict(facts_argument_spec)
|
|
||||||
|
|
||||||
def populate_facts(self, connection, ansible_facts, data=None):
|
|
||||||
""" Populate the facts for lag_interfaces
|
|
||||||
:param module: the module instance
|
|
||||||
:param connection: the device connection
|
|
||||||
:param data: previously collected conf
|
|
||||||
:rtype: dictionary
|
|
||||||
:returns: facts
|
|
||||||
"""
|
|
||||||
if not data:
|
|
||||||
data = connection.get_config()
|
|
||||||
|
|
||||||
objs = []
|
|
||||||
lag_names = findall(r"^set interfaces bonding (\S+)", data, M)
|
|
||||||
if lag_names:
|
|
||||||
for lag in set(lag_names):
|
|
||||||
lag_regex = r" %s .+$" % lag
|
|
||||||
cfg = findall(lag_regex, data, M)
|
|
||||||
obj = self.render_config(cfg)
|
|
||||||
|
|
||||||
output = connection.run_commands(
|
|
||||||
["show interfaces bonding " + lag + " slaves"]
|
|
||||||
)
|
|
||||||
lines = output[0].splitlines()
|
|
||||||
members = []
|
|
||||||
member = {}
|
|
||||||
if len(lines) > 1:
|
|
||||||
for line in lines[2:]:
|
|
||||||
splitted_line = line.split()
|
|
||||||
|
|
||||||
if len(splitted_line) > 1:
|
|
||||||
member["member"] = splitted_line[0]
|
|
||||||
members.append(member)
|
|
||||||
else:
|
|
||||||
members = []
|
|
||||||
member = {}
|
|
||||||
obj["name"] = lag.strip("'")
|
|
||||||
if members:
|
|
||||||
obj["members"] = members
|
|
||||||
|
|
||||||
if obj:
|
|
||||||
objs.append(obj)
|
|
||||||
|
|
||||||
facts = {}
|
|
||||||
if objs:
|
|
||||||
facts["lag_interfaces"] = []
|
|
||||||
params = utils.validate_config(
|
|
||||||
self.argument_spec, {"config": objs}
|
|
||||||
)
|
|
||||||
for cfg in params["config"]:
|
|
||||||
facts["lag_interfaces"].append(utils.remove_empties(cfg))
|
|
||||||
|
|
||||||
ansible_facts["ansible_network_resources"].update(facts)
|
|
||||||
return ansible_facts
|
|
||||||
|
|
||||||
def render_config(self, conf):
|
|
||||||
"""
|
|
||||||
Render config as dictionary structure and delete keys
|
|
||||||
from spec for null values
|
|
||||||
|
|
||||||
:param spec: The facts tree, generated from the argspec
|
|
||||||
:param conf: The configuration
|
|
||||||
:rtype: dictionary
|
|
||||||
:returns: The generated config
|
|
||||||
"""
|
|
||||||
arp_monitor_conf = "\n".join(
|
|
||||||
filter(lambda x: ("arp-monitor" in x), conf)
|
|
||||||
)
|
|
||||||
hash_policy_conf = "\n".join(
|
|
||||||
filter(lambda x: ("hash-policy" in x), conf)
|
|
||||||
)
|
|
||||||
lag_conf = "\n".join(filter(lambda x: ("bond" in x), conf))
|
|
||||||
config = self.parse_attribs(["mode", "primary"], lag_conf)
|
|
||||||
config["arp_monitor"] = self.parse_arp_monitor(arp_monitor_conf)
|
|
||||||
config["hash_policy"] = self.parse_hash_policy(hash_policy_conf)
|
|
||||||
|
|
||||||
return utils.remove_empties(config)
|
|
||||||
|
|
||||||
def parse_attribs(self, attribs, conf):
|
|
||||||
config = {}
|
|
||||||
for item in attribs:
|
|
||||||
value = utils.parse_conf_arg(conf, item)
|
|
||||||
if value:
|
|
||||||
config[item] = value.strip("'")
|
|
||||||
else:
|
|
||||||
config[item] = None
|
|
||||||
return utils.remove_empties(config)
|
|
||||||
|
|
||||||
def parse_arp_monitor(self, conf):
|
|
||||||
arp_monitor = None
|
|
||||||
if conf:
|
|
||||||
arp_monitor = {}
|
|
||||||
target_list = []
|
|
||||||
interval = search(r"^.*arp-monitor interval (.+)", conf, M)
|
|
||||||
targets = findall(r"^.*arp-monitor target '(.+)'", conf, M)
|
|
||||||
if targets:
|
|
||||||
for target in targets:
|
|
||||||
target_list.append(target)
|
|
||||||
arp_monitor["target"] = target_list
|
|
||||||
if interval:
|
|
||||||
value = interval.group(1).strip("'")
|
|
||||||
arp_monitor["interval"] = int(value)
|
|
||||||
return arp_monitor
|
|
||||||
|
|
||||||
def parse_hash_policy(self, conf):
|
|
||||||
hash_policy = None
|
|
||||||
if conf:
|
|
||||||
hash_policy = search(r"^.*hash-policy (.+)", conf, M)
|
|
||||||
hash_policy = hash_policy.group(1).strip("'")
|
|
||||||
return hash_policy
|
|
@ -1,161 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright 2019 Red Hat
|
|
||||||
# GNU General Public License v3.0+
|
|
||||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
"""
|
|
||||||
The VyOS interfaces fact class
|
|
||||||
It is in this file the configuration is collected from the device
|
|
||||||
for a given resource, parsed, and the facts tree is populated
|
|
||||||
based on the configuration.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import platform
|
|
||||||
import re
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (
|
|
||||||
run_commands,
|
|
||||||
get_capabilities,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class LegacyFactsBase(object):
|
|
||||||
|
|
||||||
COMMANDS = frozenset()
|
|
||||||
|
|
||||||
def __init__(self, module):
|
|
||||||
self.module = module
|
|
||||||
self.facts = dict()
|
|
||||||
self.warnings = list()
|
|
||||||
self.responses = None
|
|
||||||
|
|
||||||
def populate(self):
|
|
||||||
self.responses = run_commands(self.module, list(self.COMMANDS))
|
|
||||||
|
|
||||||
|
|
||||||
class Default(LegacyFactsBase):
|
|
||||||
|
|
||||||
COMMANDS = [
|
|
||||||
"show version",
|
|
||||||
]
|
|
||||||
|
|
||||||
def populate(self):
|
|
||||||
super(Default, self).populate()
|
|
||||||
data = self.responses[0]
|
|
||||||
self.facts["serialnum"] = self.parse_serialnum(data)
|
|
||||||
self.facts.update(self.platform_facts())
|
|
||||||
|
|
||||||
def parse_serialnum(self, data):
|
|
||||||
match = re.search(r"HW S/N:\s+(\S+)", data)
|
|
||||||
if match:
|
|
||||||
return match.group(1)
|
|
||||||
|
|
||||||
def platform_facts(self):
|
|
||||||
platform_facts = {}
|
|
||||||
|
|
||||||
resp = get_capabilities(self.module)
|
|
||||||
device_info = resp["device_info"]
|
|
||||||
|
|
||||||
platform_facts["system"] = device_info["network_os"]
|
|
||||||
|
|
||||||
for item in ("model", "image", "version", "platform", "hostname"):
|
|
||||||
val = device_info.get("network_os_%s" % item)
|
|
||||||
if val:
|
|
||||||
platform_facts[item] = val
|
|
||||||
|
|
||||||
platform_facts["api"] = resp["network_api"]
|
|
||||||
platform_facts["python_version"] = platform.python_version()
|
|
||||||
|
|
||||||
return platform_facts
|
|
||||||
|
|
||||||
|
|
||||||
class Config(LegacyFactsBase):
|
|
||||||
|
|
||||||
COMMANDS = [
|
|
||||||
"show configuration commands",
|
|
||||||
"show system commit",
|
|
||||||
]
|
|
||||||
|
|
||||||
def populate(self):
|
|
||||||
super(Config, self).populate()
|
|
||||||
|
|
||||||
self.facts["config"] = self.responses
|
|
||||||
|
|
||||||
commits = self.responses[1]
|
|
||||||
entries = list()
|
|
||||||
entry = None
|
|
||||||
|
|
||||||
for line in commits.split("\n"):
|
|
||||||
match = re.match(r"(\d+)\s+(.+)by(.+)via(.+)", line)
|
|
||||||
if match:
|
|
||||||
if entry:
|
|
||||||
entries.append(entry)
|
|
||||||
|
|
||||||
entry = dict(
|
|
||||||
revision=match.group(1),
|
|
||||||
datetime=match.group(2),
|
|
||||||
by=str(match.group(3)).strip(),
|
|
||||||
via=str(match.group(4)).strip(),
|
|
||||||
comment=None,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
entry["comment"] = line.strip()
|
|
||||||
|
|
||||||
self.facts["commits"] = entries
|
|
||||||
|
|
||||||
|
|
||||||
class Neighbors(LegacyFactsBase):
|
|
||||||
|
|
||||||
COMMANDS = [
|
|
||||||
"show lldp neighbors",
|
|
||||||
"show lldp neighbors detail",
|
|
||||||
]
|
|
||||||
|
|
||||||
def populate(self):
|
|
||||||
super(Neighbors, self).populate()
|
|
||||||
|
|
||||||
all_neighbors = self.responses[0]
|
|
||||||
if "LLDP not configured" not in all_neighbors:
|
|
||||||
neighbors = self.parse(self.responses[1])
|
|
||||||
self.facts["neighbors"] = self.parse_neighbors(neighbors)
|
|
||||||
|
|
||||||
def parse(self, data):
|
|
||||||
parsed = list()
|
|
||||||
values = None
|
|
||||||
for line in data.split("\n"):
|
|
||||||
if not line:
|
|
||||||
continue
|
|
||||||
elif line[0] == " ":
|
|
||||||
values += "\n%s" % line
|
|
||||||
elif line.startswith("Interface"):
|
|
||||||
if values:
|
|
||||||
parsed.append(values)
|
|
||||||
values = line
|
|
||||||
if values:
|
|
||||||
parsed.append(values)
|
|
||||||
return parsed
|
|
||||||
|
|
||||||
def parse_neighbors(self, data):
|
|
||||||
facts = dict()
|
|
||||||
for item in data:
|
|
||||||
interface = self.parse_interface(item)
|
|
||||||
host = self.parse_host(item)
|
|
||||||
port = self.parse_port(item)
|
|
||||||
if interface not in facts:
|
|
||||||
facts[interface] = list()
|
|
||||||
facts[interface].append(dict(host=host, port=port))
|
|
||||||
return facts
|
|
||||||
|
|
||||||
def parse_interface(self, data):
|
|
||||||
match = re.search(r"^Interface:\s+(\S+),", data)
|
|
||||||
return match.group(1)
|
|
||||||
|
|
||||||
def parse_host(self, data):
|
|
||||||
match = re.search(r"SysName:\s+(.+)$", data, re.M)
|
|
||||||
if match:
|
|
||||||
return match.group(1)
|
|
||||||
|
|
||||||
def parse_port(self, data):
|
|
||||||
match = re.search(r"PortDescr:\s+(.+)$", data, re.M)
|
|
||||||
if match:
|
|
||||||
return match.group(1)
|
|
@ -1,115 +0,0 @@
|
|||||||
#
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright 2019 Red Hat
|
|
||||||
# GNU General Public License v3.0+
|
|
||||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
"""
|
|
||||||
The vyos lldp_global fact class
|
|
||||||
It is in this file the configuration is collected from the device
|
|
||||||
for a given resource, parsed, and the facts tree is populated
|
|
||||||
based on the configuration.
|
|
||||||
"""
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
|
|
||||||
from re import findall, M
|
|
||||||
from copy import deepcopy
|
|
||||||
|
|
||||||
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import (
|
|
||||||
utils,
|
|
||||||
)
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.lldp_global.lldp_global import (
|
|
||||||
Lldp_globalArgs,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Lldp_globalFacts(object):
|
|
||||||
""" The vyos lldp_global fact class
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, module, subspec="config", options="options"):
|
|
||||||
self._module = module
|
|
||||||
self.argument_spec = Lldp_globalArgs.argument_spec
|
|
||||||
spec = deepcopy(self.argument_spec)
|
|
||||||
if subspec:
|
|
||||||
if options:
|
|
||||||
facts_argument_spec = spec[subspec][options]
|
|
||||||
else:
|
|
||||||
facts_argument_spec = spec[subspec]
|
|
||||||
else:
|
|
||||||
facts_argument_spec = spec
|
|
||||||
|
|
||||||
self.generated_spec = utils.generate_dict(facts_argument_spec)
|
|
||||||
|
|
||||||
def populate_facts(self, connection, ansible_facts, data=None):
|
|
||||||
""" Populate the facts for lldp_global
|
|
||||||
:param connection: the device connection
|
|
||||||
:param ansible_facts: Facts dictionary
|
|
||||||
:param data: previously collected conf
|
|
||||||
:rtype: dictionary
|
|
||||||
:returns: facts
|
|
||||||
"""
|
|
||||||
if not data:
|
|
||||||
data = connection.get_config()
|
|
||||||
|
|
||||||
objs = {}
|
|
||||||
lldp_output = findall(r"^set service lldp (\S+)", data, M)
|
|
||||||
if lldp_output:
|
|
||||||
for item in set(lldp_output):
|
|
||||||
lldp_regex = r" %s .+$" % item
|
|
||||||
cfg = findall(lldp_regex, data, M)
|
|
||||||
obj = self.render_config(cfg)
|
|
||||||
if obj:
|
|
||||||
objs.update(obj)
|
|
||||||
lldp_service = findall(r"^set service (lldp)?('lldp')", data, M)
|
|
||||||
if lldp_service or lldp_output:
|
|
||||||
lldp_obj = {}
|
|
||||||
lldp_obj["enable"] = True
|
|
||||||
objs.update(lldp_obj)
|
|
||||||
|
|
||||||
facts = {}
|
|
||||||
params = utils.validate_config(self.argument_spec, {"config": objs})
|
|
||||||
facts["lldp_global"] = utils.remove_empties(params["config"])
|
|
||||||
|
|
||||||
ansible_facts["ansible_network_resources"].update(facts)
|
|
||||||
|
|
||||||
return ansible_facts
|
|
||||||
|
|
||||||
def render_config(self, conf):
|
|
||||||
"""
|
|
||||||
Render config as dictionary structure and delete keys
|
|
||||||
from spec for null values
|
|
||||||
:param spec: The facts tree, generated from the argspec
|
|
||||||
:param conf: The configuration
|
|
||||||
:rtype: dictionary
|
|
||||||
:returns: The generated config
|
|
||||||
"""
|
|
||||||
protocol_conf = "\n".join(
|
|
||||||
filter(lambda x: ("legacy-protocols" in x), conf)
|
|
||||||
)
|
|
||||||
att_conf = "\n".join(
|
|
||||||
filter(lambda x: ("legacy-protocols" not in x), conf)
|
|
||||||
)
|
|
||||||
config = self.parse_attribs(["snmp", "address"], att_conf)
|
|
||||||
config["legacy_protocols"] = self.parse_protocols(protocol_conf)
|
|
||||||
return utils.remove_empties(config)
|
|
||||||
|
|
||||||
def parse_protocols(self, conf):
|
|
||||||
protocol_support = None
|
|
||||||
if conf:
|
|
||||||
protocols = findall(r"^.*legacy-protocols (.+)", conf, M)
|
|
||||||
if protocols:
|
|
||||||
protocol_support = []
|
|
||||||
for protocol in protocols:
|
|
||||||
protocol_support.append(protocol.strip("'"))
|
|
||||||
return protocol_support
|
|
||||||
|
|
||||||
def parse_attribs(self, attribs, conf):
|
|
||||||
config = {}
|
|
||||||
for item in attribs:
|
|
||||||
value = utils.parse_conf_arg(conf, item)
|
|
||||||
if value:
|
|
||||||
config[item] = value.strip("'")
|
|
||||||
else:
|
|
||||||
config[item] = None
|
|
||||||
return utils.remove_empties(config)
|
|
@ -1,153 +0,0 @@
|
|||||||
#
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright 2019 Red Hat
|
|
||||||
# GNU General Public License v3.0+
|
|
||||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
"""
|
|
||||||
The vyos lldp_interfaces fact class
|
|
||||||
It is in this file the configuration is collected from the device
|
|
||||||
for a given resource, parsed, and the facts tree is populated
|
|
||||||
based on the configuration.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
|
|
||||||
from re import findall, search, M
|
|
||||||
from copy import deepcopy
|
|
||||||
|
|
||||||
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import (
|
|
||||||
utils,
|
|
||||||
)
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.lldp_interfaces.lldp_interfaces import (
|
|
||||||
Lldp_interfacesArgs,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Lldp_interfacesFacts(object):
|
|
||||||
""" The vyos lldp_interfaces fact class
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, module, subspec="config", options="options"):
|
|
||||||
self._module = module
|
|
||||||
self.argument_spec = Lldp_interfacesArgs.argument_spec
|
|
||||||
spec = deepcopy(self.argument_spec)
|
|
||||||
if subspec:
|
|
||||||
if options:
|
|
||||||
facts_argument_spec = spec[subspec][options]
|
|
||||||
else:
|
|
||||||
facts_argument_spec = spec[subspec]
|
|
||||||
else:
|
|
||||||
facts_argument_spec = spec
|
|
||||||
|
|
||||||
self.generated_spec = utils.generate_dict(facts_argument_spec)
|
|
||||||
|
|
||||||
def populate_facts(self, connection, ansible_facts, data=None):
|
|
||||||
""" Populate the facts for lldp_interfaces
|
|
||||||
:param connection: the device connection
|
|
||||||
:param ansible_facts: Facts dictionary
|
|
||||||
:param data: previously collected conf
|
|
||||||
:rtype: dictionary
|
|
||||||
:returns: facts
|
|
||||||
"""
|
|
||||||
if not data:
|
|
||||||
data = connection.get_config()
|
|
||||||
|
|
||||||
objs = []
|
|
||||||
lldp_names = findall(r"^set service lldp interface (\S+)", data, M)
|
|
||||||
if lldp_names:
|
|
||||||
for lldp in set(lldp_names):
|
|
||||||
lldp_regex = r" %s .+$" % lldp
|
|
||||||
cfg = findall(lldp_regex, data, M)
|
|
||||||
obj = self.render_config(cfg)
|
|
||||||
obj["name"] = lldp.strip("'")
|
|
||||||
if obj:
|
|
||||||
objs.append(obj)
|
|
||||||
facts = {}
|
|
||||||
if objs:
|
|
||||||
facts["lldp_interfaces"] = objs
|
|
||||||
ansible_facts["ansible_network_resources"].update(facts)
|
|
||||||
|
|
||||||
ansible_facts["ansible_network_resources"].update(facts)
|
|
||||||
return ansible_facts
|
|
||||||
|
|
||||||
def render_config(self, conf):
|
|
||||||
"""
|
|
||||||
Render config as dictionary structure and delete keys
|
|
||||||
from spec for null values
|
|
||||||
|
|
||||||
:param spec: The facts tree, generated from the argspec
|
|
||||||
:param conf: The configuration
|
|
||||||
:rtype: dictionary
|
|
||||||
:returns: The generated config
|
|
||||||
"""
|
|
||||||
config = {}
|
|
||||||
location = {}
|
|
||||||
|
|
||||||
civic_conf = "\n".join(filter(lambda x: ("civic-based" in x), conf))
|
|
||||||
elin_conf = "\n".join(filter(lambda x: ("elin" in x), conf))
|
|
||||||
coordinate_conf = "\n".join(
|
|
||||||
filter(lambda x: ("coordinate-based" in x), conf)
|
|
||||||
)
|
|
||||||
disable = "\n".join(filter(lambda x: ("disable" in x), conf))
|
|
||||||
|
|
||||||
coordinate_based_conf = self.parse_attribs(
|
|
||||||
["altitude", "datum", "longitude", "latitude"], coordinate_conf
|
|
||||||
)
|
|
||||||
elin_based_conf = self.parse_lldp_elin_based(elin_conf)
|
|
||||||
civic_based_conf = self.parse_lldp_civic_based(civic_conf)
|
|
||||||
if disable:
|
|
||||||
config["enable"] = False
|
|
||||||
if coordinate_conf:
|
|
||||||
location["coordinate_based"] = coordinate_based_conf
|
|
||||||
config["location"] = location
|
|
||||||
elif civic_based_conf:
|
|
||||||
location["civic_based"] = civic_based_conf
|
|
||||||
config["location"] = location
|
|
||||||
elif elin_conf:
|
|
||||||
location["elin"] = elin_based_conf
|
|
||||||
config["location"] = location
|
|
||||||
|
|
||||||
return utils.remove_empties(config)
|
|
||||||
|
|
||||||
def parse_attribs(self, attribs, conf):
|
|
||||||
config = {}
|
|
||||||
for item in attribs:
|
|
||||||
value = utils.parse_conf_arg(conf, item)
|
|
||||||
if value:
|
|
||||||
value = value.strip("'")
|
|
||||||
if item == "altitude":
|
|
||||||
value = int(value)
|
|
||||||
config[item] = value
|
|
||||||
else:
|
|
||||||
config[item] = None
|
|
||||||
return utils.remove_empties(config)
|
|
||||||
|
|
||||||
def parse_lldp_civic_based(self, conf):
|
|
||||||
civic_based = None
|
|
||||||
if conf:
|
|
||||||
civic_info_list = []
|
|
||||||
civic_add_list = findall(r"^.*civic-based ca-type (.+)", conf, M)
|
|
||||||
if civic_add_list:
|
|
||||||
for civic_add in civic_add_list:
|
|
||||||
ca = civic_add.split(" ")
|
|
||||||
c_add = {}
|
|
||||||
c_add["ca_type"] = int(ca[0].strip("'"))
|
|
||||||
c_add["ca_value"] = ca[2].strip("'")
|
|
||||||
civic_info_list.append(c_add)
|
|
||||||
|
|
||||||
country_code = search(
|
|
||||||
r"^.*civic-based country-code (.+)", conf, M
|
|
||||||
)
|
|
||||||
civic_based = {}
|
|
||||||
civic_based["ca_info"] = civic_info_list
|
|
||||||
civic_based["country_code"] = country_code.group(1).strip("'")
|
|
||||||
return civic_based
|
|
||||||
|
|
||||||
def parse_lldp_elin_based(self, conf):
|
|
||||||
elin_based = None
|
|
||||||
if conf:
|
|
||||||
e_num = search(r"^.* elin (.+)", conf, M)
|
|
||||||
elin_based = e_num.group(1).strip("'")
|
|
||||||
|
|
||||||
return elin_based
|
|
@ -1,180 +0,0 @@
|
|||||||
#
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright 2019 Red Hat
|
|
||||||
# GNU General Public License v3.0+
|
|
||||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
"""
|
|
||||||
The vyos static_routes fact class
|
|
||||||
It is in this file the configuration is collected from the device
|
|
||||||
for a given resource, parsed, and the facts tree is populated
|
|
||||||
based on the configuration.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from re import findall, search, M
|
|
||||||
from copy import deepcopy
|
|
||||||
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import (
|
|
||||||
utils,
|
|
||||||
)
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.static_routes.static_routes import (
|
|
||||||
Static_routesArgs,
|
|
||||||
)
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.utils.utils import (
|
|
||||||
get_route_type,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Static_routesFacts(object):
|
|
||||||
""" The vyos static_routes fact class
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, module, subspec="config", options="options"):
|
|
||||||
self._module = module
|
|
||||||
self.argument_spec = Static_routesArgs.argument_spec
|
|
||||||
spec = deepcopy(self.argument_spec)
|
|
||||||
if subspec:
|
|
||||||
if options:
|
|
||||||
facts_argument_spec = spec[subspec][options]
|
|
||||||
else:
|
|
||||||
facts_argument_spec = spec[subspec]
|
|
||||||
else:
|
|
||||||
facts_argument_spec = spec
|
|
||||||
|
|
||||||
self.generated_spec = utils.generate_dict(facts_argument_spec)
|
|
||||||
|
|
||||||
def get_device_data(self, connection):
|
|
||||||
return connection.get_config()
|
|
||||||
|
|
||||||
def populate_facts(self, connection, ansible_facts, data=None):
|
|
||||||
""" Populate the facts for static_routes
|
|
||||||
:param connection: the device connection
|
|
||||||
:param ansible_facts: Facts dictionary
|
|
||||||
:param data: previously collected conf
|
|
||||||
:rtype: dictionary
|
|
||||||
:returns: facts
|
|
||||||
"""
|
|
||||||
if not data:
|
|
||||||
data = self.get_device_data(connection)
|
|
||||||
# typically data is populated from the current device configuration
|
|
||||||
# data = connection.get('show running-config | section ^interface')
|
|
||||||
# using mock data instead
|
|
||||||
objs = []
|
|
||||||
r_v4 = []
|
|
||||||
r_v6 = []
|
|
||||||
af = []
|
|
||||||
static_routes = findall(
|
|
||||||
r"set protocols static route(6)? (\S+)", data, M
|
|
||||||
)
|
|
||||||
if static_routes:
|
|
||||||
for route in set(static_routes):
|
|
||||||
route_regex = r" %s .+$" % route[1]
|
|
||||||
cfg = findall(route_regex, data, M)
|
|
||||||
sr = self.render_config(cfg)
|
|
||||||
sr["dest"] = route[1].strip("'")
|
|
||||||
afi = self.get_afi(sr["dest"])
|
|
||||||
if afi == "ipv4":
|
|
||||||
r_v4.append(sr)
|
|
||||||
else:
|
|
||||||
r_v6.append(sr)
|
|
||||||
if r_v4:
|
|
||||||
afi_v4 = {"afi": "ipv4", "routes": r_v4}
|
|
||||||
af.append(afi_v4)
|
|
||||||
if r_v6:
|
|
||||||
afi_v6 = {"afi": "ipv6", "routes": r_v6}
|
|
||||||
af.append(afi_v6)
|
|
||||||
config = {"address_families": af}
|
|
||||||
if config:
|
|
||||||
objs.append(config)
|
|
||||||
|
|
||||||
ansible_facts["ansible_network_resources"].pop("static_routes", None)
|
|
||||||
facts = {}
|
|
||||||
if objs:
|
|
||||||
facts["static_routes"] = []
|
|
||||||
params = utils.validate_config(
|
|
||||||
self.argument_spec, {"config": objs}
|
|
||||||
)
|
|
||||||
for cfg in params["config"]:
|
|
||||||
facts["static_routes"].append(utils.remove_empties(cfg))
|
|
||||||
|
|
||||||
ansible_facts["ansible_network_resources"].update(facts)
|
|
||||||
return ansible_facts
|
|
||||||
|
|
||||||
def render_config(self, conf):
|
|
||||||
"""
|
|
||||||
Render config as dictionary structure and delete keys
|
|
||||||
from spec for null values
|
|
||||||
|
|
||||||
:param spec: The facts tree, generated from the argspec
|
|
||||||
:param conf: The configuration
|
|
||||||
:rtype: dictionary
|
|
||||||
:returns: The generated config
|
|
||||||
"""
|
|
||||||
next_hops_conf = "\n".join(filter(lambda x: ("next-hop" in x), conf))
|
|
||||||
blackhole_conf = "\n".join(filter(lambda x: ("blackhole" in x), conf))
|
|
||||||
routes_dict = {
|
|
||||||
"blackhole_config": self.parse_blackhole(blackhole_conf),
|
|
||||||
"next_hops": self.parse_next_hop(next_hops_conf),
|
|
||||||
}
|
|
||||||
return routes_dict
|
|
||||||
|
|
||||||
def parse_blackhole(self, conf):
|
|
||||||
blackhole = None
|
|
||||||
if conf:
|
|
||||||
distance = search(r"^.*blackhole distance (.\S+)", conf, M)
|
|
||||||
bh = conf.find("blackhole")
|
|
||||||
if distance is not None:
|
|
||||||
blackhole = {}
|
|
||||||
value = distance.group(1).strip("'")
|
|
||||||
blackhole["distance"] = int(value)
|
|
||||||
elif bh:
|
|
||||||
blackhole = {}
|
|
||||||
blackhole["type"] = "blackhole"
|
|
||||||
return blackhole
|
|
||||||
|
|
||||||
def get_afi(self, address):
|
|
||||||
route_type = get_route_type(address)
|
|
||||||
if route_type == "route":
|
|
||||||
return "ipv4"
|
|
||||||
elif route_type == "route6":
|
|
||||||
return "ipv6"
|
|
||||||
|
|
||||||
def parse_next_hop(self, conf):
|
|
||||||
nh_list = None
|
|
||||||
if conf:
|
|
||||||
nh_list = []
|
|
||||||
hop_list = findall(r"^.*next-hop (.+)", conf, M)
|
|
||||||
if hop_list:
|
|
||||||
for hop in hop_list:
|
|
||||||
distance = search(r"^.*distance (.\S+)", hop, M)
|
|
||||||
interface = search(r"^.*interface (.\S+)", hop, M)
|
|
||||||
|
|
||||||
dis = hop.find("disable")
|
|
||||||
hop_info = hop.split(" ")
|
|
||||||
nh_info = {
|
|
||||||
"forward_router_address": hop_info[0].strip("'")
|
|
||||||
}
|
|
||||||
if interface:
|
|
||||||
nh_info["interface"] = interface.group(1).strip("'")
|
|
||||||
if distance:
|
|
||||||
value = distance.group(1).strip("'")
|
|
||||||
nh_info["admin_distance"] = int(value)
|
|
||||||
elif dis >= 1:
|
|
||||||
nh_info["enabled"] = False
|
|
||||||
for element in nh_list:
|
|
||||||
if (
|
|
||||||
element["forward_router_address"]
|
|
||||||
== nh_info["forward_router_address"]
|
|
||||||
):
|
|
||||||
if "interface" in nh_info.keys():
|
|
||||||
element["interface"] = nh_info["interface"]
|
|
||||||
if "admin_distance" in nh_info.keys():
|
|
||||||
element["admin_distance"] = nh_info[
|
|
||||||
"admin_distance"
|
|
||||||
]
|
|
||||||
if "enabled" in nh_info.keys():
|
|
||||||
element["enabled"] = nh_info["enabled"]
|
|
||||||
nh_info = None
|
|
||||||
if nh_info is not None:
|
|
||||||
nh_list.append(nh_info)
|
|
||||||
return nh_list
|
|
@ -1,230 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright 2019 Red Hat
|
|
||||||
# GNU General Public License v3.0+
|
|
||||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
# utils
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from ansible.module_utils.six import iteritems
|
|
||||||
from ansible_collections.ansible.netcommon.plugins.module_utils.compat import (
|
|
||||||
ipaddress,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def search_obj_in_list(name, lst, key="name"):
|
|
||||||
for item in lst:
|
|
||||||
if item[key] == name:
|
|
||||||
return item
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def get_interface_type(interface):
|
|
||||||
"""Gets the type of interface
|
|
||||||
"""
|
|
||||||
if interface.startswith("eth"):
|
|
||||||
return "ethernet"
|
|
||||||
elif interface.startswith("bond"):
|
|
||||||
return "bonding"
|
|
||||||
elif interface.startswith("vti"):
|
|
||||||
return "vti"
|
|
||||||
elif interface.startswith("lo"):
|
|
||||||
return "loopback"
|
|
||||||
|
|
||||||
|
|
||||||
def dict_delete(base, comparable):
|
|
||||||
"""
|
|
||||||
This function generates a dict containing key, value pairs for keys
|
|
||||||
that are present in the `base` dict but not present in the `comparable`
|
|
||||||
dict.
|
|
||||||
|
|
||||||
:param base: dict object to base the diff on
|
|
||||||
:param comparable: dict object to compare against base
|
|
||||||
:returns: new dict object with key, value pairs that needs to be deleted.
|
|
||||||
|
|
||||||
"""
|
|
||||||
to_delete = dict()
|
|
||||||
|
|
||||||
for key in base:
|
|
||||||
if isinstance(base[key], dict):
|
|
||||||
sub_diff = dict_delete(base[key], comparable.get(key, {}))
|
|
||||||
if sub_diff:
|
|
||||||
to_delete[key] = sub_diff
|
|
||||||
else:
|
|
||||||
if key not in comparable:
|
|
||||||
to_delete[key] = base[key]
|
|
||||||
|
|
||||||
return to_delete
|
|
||||||
|
|
||||||
|
|
||||||
def diff_list_of_dicts(want, have):
|
|
||||||
diff = []
|
|
||||||
|
|
||||||
set_w = set(tuple(d.items()) for d in want)
|
|
||||||
set_h = set(tuple(d.items()) for d in have)
|
|
||||||
difference = set_w.difference(set_h)
|
|
||||||
|
|
||||||
for element in difference:
|
|
||||||
diff.append(dict((x, y) for x, y in element))
|
|
||||||
|
|
||||||
return diff
|
|
||||||
|
|
||||||
|
|
||||||
def get_lst_diff_for_dicts(want, have, lst):
|
|
||||||
"""
|
|
||||||
This function generates a list containing values
|
|
||||||
that are only in want and not in list in have dict
|
|
||||||
:param want: dict object to want
|
|
||||||
:param have: dict object to have
|
|
||||||
:param lst: list the diff on
|
|
||||||
:return: new list object with values which are only in want.
|
|
||||||
"""
|
|
||||||
if not have:
|
|
||||||
diff = want.get(lst) or []
|
|
||||||
|
|
||||||
else:
|
|
||||||
want_elements = want.get(lst) or {}
|
|
||||||
have_elements = have.get(lst) or {}
|
|
||||||
diff = list_diff_want_only(want_elements, have_elements)
|
|
||||||
return diff
|
|
||||||
|
|
||||||
|
|
||||||
def get_lst_same_for_dicts(want, have, lst):
|
|
||||||
"""
|
|
||||||
This function generates a list containing values
|
|
||||||
that are common for list in want and list in have dict
|
|
||||||
:param want: dict object to want
|
|
||||||
:param have: dict object to have
|
|
||||||
:param lst: list the comparison on
|
|
||||||
:return: new list object with values which are common in want and have.
|
|
||||||
"""
|
|
||||||
diff = None
|
|
||||||
if want and have:
|
|
||||||
want_list = want.get(lst) or {}
|
|
||||||
have_list = have.get(lst) or {}
|
|
||||||
diff = [
|
|
||||||
i
|
|
||||||
for i in want_list and have_list
|
|
||||||
if i in have_list and i in want_list
|
|
||||||
]
|
|
||||||
return diff
|
|
||||||
|
|
||||||
|
|
||||||
def list_diff_have_only(want_list, have_list):
|
|
||||||
"""
|
|
||||||
This function generated the list containing values
|
|
||||||
that are only in have list.
|
|
||||||
:param want_list:
|
|
||||||
:param have_list:
|
|
||||||
:return: new list with values which are only in have list
|
|
||||||
"""
|
|
||||||
if have_list and not want_list:
|
|
||||||
diff = have_list
|
|
||||||
elif not have_list:
|
|
||||||
diff = None
|
|
||||||
else:
|
|
||||||
diff = [
|
|
||||||
i
|
|
||||||
for i in have_list + want_list
|
|
||||||
if i in have_list and i not in want_list
|
|
||||||
]
|
|
||||||
return diff
|
|
||||||
|
|
||||||
|
|
||||||
def list_diff_want_only(want_list, have_list):
|
|
||||||
"""
|
|
||||||
This function generated the list containing values
|
|
||||||
that are only in want list.
|
|
||||||
:param want_list:
|
|
||||||
:param have_list:
|
|
||||||
:return: new list with values which are only in want list
|
|
||||||
"""
|
|
||||||
if have_list and not want_list:
|
|
||||||
diff = None
|
|
||||||
elif not have_list:
|
|
||||||
diff = want_list
|
|
||||||
else:
|
|
||||||
diff = [
|
|
||||||
i
|
|
||||||
for i in have_list + want_list
|
|
||||||
if i in want_list and i not in have_list
|
|
||||||
]
|
|
||||||
return diff
|
|
||||||
|
|
||||||
|
|
||||||
def search_dict_tv_in_list(d_val1, d_val2, lst, key1, key2):
|
|
||||||
"""
|
|
||||||
This function return the dict object if it exist in list.
|
|
||||||
:param d_val1:
|
|
||||||
:param d_val2:
|
|
||||||
:param lst:
|
|
||||||
:param key1:
|
|
||||||
:param key2:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
obj = next(
|
|
||||||
(
|
|
||||||
item
|
|
||||||
for item in lst
|
|
||||||
if item[key1] == d_val1 and item[key2] == d_val2
|
|
||||||
),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
if obj:
|
|
||||||
return obj
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def key_value_in_dict(have_key, have_value, want_dict):
|
|
||||||
"""
|
|
||||||
This function checks whether the key and values exist in dict
|
|
||||||
:param have_key:
|
|
||||||
:param have_value:
|
|
||||||
:param want_dict:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
for key, value in iteritems(want_dict):
|
|
||||||
if key == have_key and value == have_value:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def is_dict_element_present(dict, key):
|
|
||||||
"""
|
|
||||||
This function checks whether the key is present in dict.
|
|
||||||
:param dict:
|
|
||||||
:param key:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
for item in dict:
|
|
||||||
if item == key:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def get_ip_address_version(address):
|
|
||||||
"""
|
|
||||||
This function returns the version of IP address
|
|
||||||
:param address: IP address
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
address = unicode(address)
|
|
||||||
except NameError:
|
|
||||||
address = str(address)
|
|
||||||
version = ipaddress.ip_address(address.split("/")[0]).version
|
|
||||||
return version
|
|
||||||
|
|
||||||
|
|
||||||
def get_route_type(address):
|
|
||||||
"""
|
|
||||||
This function returns the route type based on IP address
|
|
||||||
:param address:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
version = get_ip_address_version(address)
|
|
||||||
if version == 6:
|
|
||||||
return "route6"
|
|
||||||
elif version == 4:
|
|
||||||
return "route"
|
|
@ -1,126 +0,0 @@
|
|||||||
# This code is part of Ansible, but is an independent component.
|
|
||||||
# This particular file snippet, and this file snippet only, is BSD licensed.
|
|
||||||
# Modules you write using this snippet, which is embedded dynamically by Ansible
|
|
||||||
# still belong to the author of the module, and may assign their own license
|
|
||||||
# to the complete work.
|
|
||||||
#
|
|
||||||
# (c) 2016 Red Hat Inc.
|
|
||||||
#
|
|
||||||
# Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
# are permitted provided that the following conditions are met:
|
|
||||||
#
|
|
||||||
# * Redistributions of source code must retain the above copyright
|
|
||||||
# notice, this list of conditions and the following disclaimer.
|
|
||||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
# this list of conditions and the following disclaimer in the documentation
|
|
||||||
# and/or other materials provided with the distribution.
|
|
||||||
#
|
|
||||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
||||||
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
|
||||||
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
#
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
from ansible.module_utils.common.text.converters import to_text
|
|
||||||
from ansible.module_utils.basic import env_fallback
|
|
||||||
from ansible.module_utils.connection import Connection, ConnectionError
|
|
||||||
|
|
||||||
_DEVICE_CONFIGS = {}
|
|
||||||
|
|
||||||
vyos_provider_spec = {
|
|
||||||
"host": dict(),
|
|
||||||
"port": dict(type="int"),
|
|
||||||
"username": dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"])),
|
|
||||||
"password": dict(
|
|
||||||
fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True
|
|
||||||
),
|
|
||||||
"ssh_keyfile": dict(
|
|
||||||
fallback=(env_fallback, ["ANSIBLE_NET_SSH_KEYFILE"]), type="path"
|
|
||||||
),
|
|
||||||
"timeout": dict(type="int"),
|
|
||||||
}
|
|
||||||
vyos_argument_spec = {
|
|
||||||
"provider": dict(
|
|
||||||
type="dict", options=vyos_provider_spec, removed_in_version=2.14
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def get_provider_argspec():
|
|
||||||
return vyos_provider_spec
|
|
||||||
|
|
||||||
|
|
||||||
def get_connection(module):
|
|
||||||
if hasattr(module, "_vyos_connection"):
|
|
||||||
return module._vyos_connection
|
|
||||||
|
|
||||||
capabilities = get_capabilities(module)
|
|
||||||
network_api = capabilities.get("network_api")
|
|
||||||
if network_api == "cliconf":
|
|
||||||
module._vyos_connection = Connection(module._socket_path)
|
|
||||||
else:
|
|
||||||
module.fail_json(msg="Invalid connection type %s" % network_api)
|
|
||||||
|
|
||||||
return module._vyos_connection
|
|
||||||
|
|
||||||
|
|
||||||
def get_capabilities(module):
|
|
||||||
if hasattr(module, "_vyos_capabilities"):
|
|
||||||
return module._vyos_capabilities
|
|
||||||
|
|
||||||
try:
|
|
||||||
capabilities = Connection(module._socket_path).get_capabilities()
|
|
||||||
except ConnectionError as exc:
|
|
||||||
module.fail_json(msg=to_text(exc, errors="surrogate_then_replace"))
|
|
||||||
|
|
||||||
module._vyos_capabilities = json.loads(capabilities)
|
|
||||||
return module._vyos_capabilities
|
|
||||||
|
|
||||||
|
|
||||||
def get_config(module, flags=None, format=None):
|
|
||||||
flags = [] if flags is None else flags
|
|
||||||
global _DEVICE_CONFIGS
|
|
||||||
|
|
||||||
if _DEVICE_CONFIGS != {}:
|
|
||||||
return _DEVICE_CONFIGS
|
|
||||||
else:
|
|
||||||
connection = get_connection(module)
|
|
||||||
try:
|
|
||||||
out = connection.get_config(flags=flags, format=format)
|
|
||||||
except ConnectionError as exc:
|
|
||||||
module.fail_json(msg=to_text(exc, errors="surrogate_then_replace"))
|
|
||||||
cfg = to_text(out, errors="surrogate_then_replace").strip()
|
|
||||||
_DEVICE_CONFIGS = cfg
|
|
||||||
return cfg
|
|
||||||
|
|
||||||
|
|
||||||
def run_commands(module, commands, check_rc=True):
|
|
||||||
connection = get_connection(module)
|
|
||||||
try:
|
|
||||||
response = connection.run_commands(
|
|
||||||
commands=commands, check_rc=check_rc
|
|
||||||
)
|
|
||||||
except ConnectionError as exc:
|
|
||||||
module.fail_json(msg=to_text(exc, errors="surrogate_then_replace"))
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
def load_config(module, commands, commit=False, comment=None):
|
|
||||||
connection = get_connection(module)
|
|
||||||
|
|
||||||
try:
|
|
||||||
response = connection.edit_config(
|
|
||||||
candidate=commands, commit=commit, comment=comment
|
|
||||||
)
|
|
||||||
except ConnectionError as exc:
|
|
||||||
module.fail_json(msg=to_text(exc, errors="surrogate_then_replace"))
|
|
||||||
|
|
||||||
return response.get("diff")
|
|
@ -1,224 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
#
|
|
||||||
# This file is part of Ansible
|
|
||||||
#
|
|
||||||
# Ansible is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Ansible is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
ANSIBLE_METADATA = {
|
|
||||||
"metadata_version": "1.1",
|
|
||||||
"status": ["preview"],
|
|
||||||
"supported_by": "network",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DOCUMENTATION = """module: vyos_command
|
|
||||||
author: Nathaniel Case (@Qalthos)
|
|
||||||
short_description: Run one or more commands on VyOS devices
|
|
||||||
description:
|
|
||||||
- The command module allows running one or more commands on remote devices running
|
|
||||||
VyOS. This module can also be introspected to validate key parameters before returning
|
|
||||||
successfully. If the conditional statements are not met in the wait period, the
|
|
||||||
task fails.
|
|
||||||
- Certain C(show) commands in VyOS produce many lines of output and use a custom pager
|
|
||||||
that can cause this module to hang. If the value of the environment variable C(ANSIBLE_VYOS_TERMINAL_LENGTH)
|
|
||||||
is not set, the default number of 10000 is used.
|
|
||||||
extends_documentation_fragment:
|
|
||||||
- vyos.vyos.vyos
|
|
||||||
options:
|
|
||||||
commands:
|
|
||||||
description:
|
|
||||||
- The ordered set of commands to execute on the remote device running VyOS. The
|
|
||||||
output from the command execution is returned to the playbook. If the I(wait_for)
|
|
||||||
argument is provided, the module is not returned until the condition is satisfied
|
|
||||||
or the number of retries has been exceeded.
|
|
||||||
required: true
|
|
||||||
wait_for:
|
|
||||||
description:
|
|
||||||
- Specifies what to evaluate from the output of the command and what conditionals
|
|
||||||
to apply. This argument will cause the task to wait for a particular conditional
|
|
||||||
to be true before moving forward. If the conditional is not true by the configured
|
|
||||||
I(retries), the task fails. See examples.
|
|
||||||
aliases:
|
|
||||||
- waitfor
|
|
||||||
match:
|
|
||||||
description:
|
|
||||||
- The I(match) argument is used in conjunction with the I(wait_for) argument to
|
|
||||||
specify the match policy. Valid values are C(all) or C(any). If the value is
|
|
||||||
set to C(all) then all conditionals in the wait_for must be satisfied. If the
|
|
||||||
value is set to C(any) then only one of the values must be satisfied.
|
|
||||||
default: all
|
|
||||||
choices:
|
|
||||||
- any
|
|
||||||
- all
|
|
||||||
retries:
|
|
||||||
description:
|
|
||||||
- Specifies the number of retries a command should be tried before it is considered
|
|
||||||
failed. The command is run on the target device every retry and evaluated against
|
|
||||||
the I(wait_for) conditionals.
|
|
||||||
default: 10
|
|
||||||
interval:
|
|
||||||
description:
|
|
||||||
- Configures the interval in seconds to wait between I(retries) of the command.
|
|
||||||
If the command does not pass the specified conditions, the interval indicates
|
|
||||||
how long to wait before trying the command again.
|
|
||||||
default: 1
|
|
||||||
notes:
|
|
||||||
- Tested against VyOS 1.1.8 (helium).
|
|
||||||
- Running C(show system boot-messages all) will cause the module to hang since VyOS
|
|
||||||
is using a custom pager setting to display the output of that command.
|
|
||||||
- If a command sent to the device requires answering a prompt, it is possible to pass
|
|
||||||
a dict containing I(command), I(answer) and I(prompt). See examples.
|
|
||||||
- This module works with connection C(network_cli). See L(the VyOS OS Platform Options,../network/user_guide/platform_vyos.html).
|
|
||||||
"""
|
|
||||||
|
|
||||||
EXAMPLES = """
|
|
||||||
tasks:
|
|
||||||
- name: show configuration on ethernet devices eth0 and eth1
|
|
||||||
vyos_command:
|
|
||||||
commands:
|
|
||||||
- show interfaces ethernet {{ item }}
|
|
||||||
with_items:
|
|
||||||
- eth0
|
|
||||||
- eth1
|
|
||||||
|
|
||||||
- name: run multiple commands and check if version output contains specific version string
|
|
||||||
vyos_command:
|
|
||||||
commands:
|
|
||||||
- show version
|
|
||||||
- show hardware cpu
|
|
||||||
wait_for:
|
|
||||||
- "result[0] contains 'VyOS 1.1.7'"
|
|
||||||
|
|
||||||
- name: run command that requires answering a prompt
|
|
||||||
vyos_command:
|
|
||||||
commands:
|
|
||||||
- command: 'rollback 1'
|
|
||||||
prompt: 'Proceed with reboot? [confirm][y]'
|
|
||||||
answer: y
|
|
||||||
"""
|
|
||||||
|
|
||||||
RETURN = """
|
|
||||||
stdout:
|
|
||||||
description: The set of responses from the commands
|
|
||||||
returned: always apart from low level errors (such as action plugin)
|
|
||||||
type: list
|
|
||||||
sample: ['...', '...']
|
|
||||||
stdout_lines:
|
|
||||||
description: The value of stdout split into a list
|
|
||||||
returned: always
|
|
||||||
type: list
|
|
||||||
sample: [['...', '...'], ['...'], ['...']]
|
|
||||||
failed_conditions:
|
|
||||||
description: The list of conditionals that have failed
|
|
||||||
returned: failed
|
|
||||||
type: list
|
|
||||||
sample: ['...', '...']
|
|
||||||
warnings:
|
|
||||||
description: The list of warnings (if any) generated by module based on arguments
|
|
||||||
returned: always
|
|
||||||
type: list
|
|
||||||
sample: ['...', '...']
|
|
||||||
"""
|
|
||||||
import time
|
|
||||||
|
|
||||||
from ansible.module_utils.common.text.converters import to_text
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
|
||||||
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.parsing import (
|
|
||||||
Conditional,
|
|
||||||
)
|
|
||||||
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
|
|
||||||
transform_commands,
|
|
||||||
to_lines,
|
|
||||||
)
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (
|
|
||||||
run_commands,
|
|
||||||
)
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (
|
|
||||||
vyos_argument_spec,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_commands(module, warnings):
|
|
||||||
commands = transform_commands(module)
|
|
||||||
|
|
||||||
if module.check_mode:
|
|
||||||
for item in list(commands):
|
|
||||||
if not item["command"].startswith("show"):
|
|
||||||
warnings.append(
|
|
||||||
"Only show commands are supported when using check mode, not "
|
|
||||||
"executing %s" % item["command"]
|
|
||||||
)
|
|
||||||
commands.remove(item)
|
|
||||||
|
|
||||||
return commands
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
spec = dict(
|
|
||||||
commands=dict(type="list", required=True),
|
|
||||||
wait_for=dict(type="list", aliases=["waitfor"]),
|
|
||||||
match=dict(default="all", choices=["all", "any"]),
|
|
||||||
retries=dict(default=10, type="int"),
|
|
||||||
interval=dict(default=1, type="int"),
|
|
||||||
)
|
|
||||||
|
|
||||||
spec.update(vyos_argument_spec)
|
|
||||||
|
|
||||||
module = AnsibleModule(argument_spec=spec, supports_check_mode=True)
|
|
||||||
|
|
||||||
warnings = list()
|
|
||||||
result = {"changed": False, "warnings": warnings}
|
|
||||||
commands = parse_commands(module, warnings)
|
|
||||||
wait_for = module.params["wait_for"] or list()
|
|
||||||
|
|
||||||
try:
|
|
||||||
conditionals = [Conditional(c) for c in wait_for]
|
|
||||||
except AttributeError as exc:
|
|
||||||
module.fail_json(msg=to_text(exc))
|
|
||||||
|
|
||||||
retries = module.params["retries"]
|
|
||||||
interval = module.params["interval"]
|
|
||||||
match = module.params["match"]
|
|
||||||
|
|
||||||
for dummy in range(retries):
|
|
||||||
responses = run_commands(module, commands)
|
|
||||||
|
|
||||||
for item in list(conditionals):
|
|
||||||
if item(responses):
|
|
||||||
if match == "any":
|
|
||||||
conditionals = list()
|
|
||||||
break
|
|
||||||
conditionals.remove(item)
|
|
||||||
|
|
||||||
if not conditionals:
|
|
||||||
break
|
|
||||||
|
|
||||||
time.sleep(interval)
|
|
||||||
|
|
||||||
if conditionals:
|
|
||||||
failed_conditions = [item.raw for item in conditionals]
|
|
||||||
msg = "One or more conditional statements have not been satisfied"
|
|
||||||
module.fail_json(msg=msg, failed_conditions=failed_conditions)
|
|
||||||
|
|
||||||
result.update(
|
|
||||||
{"stdout": responses, "stdout_lines": list(to_lines(responses)), }
|
|
||||||
)
|
|
||||||
|
|
||||||
module.exit_json(**result)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -1,355 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
#
|
|
||||||
# This file is part of Ansible
|
|
||||||
#
|
|
||||||
# Ansible is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Ansible is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
ANSIBLE_METADATA = {
|
|
||||||
"metadata_version": "1.1",
|
|
||||||
"status": ["preview"],
|
|
||||||
"supported_by": "network",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DOCUMENTATION = """module: vyos_config
|
|
||||||
author: Nathaniel Case (@Qalthos)
|
|
||||||
short_description: Manage VyOS configuration on remote device
|
|
||||||
description:
|
|
||||||
- This module provides configuration file management of VyOS devices. It provides
|
|
||||||
arguments for managing both the configuration file and state of the active configuration.
|
|
||||||
All configuration statements are based on `set` and `delete` commands in the device
|
|
||||||
configuration.
|
|
||||||
extends_documentation_fragment:
|
|
||||||
- vyos.vyos.vyos
|
|
||||||
notes:
|
|
||||||
- Tested against VyOS 1.1.8 (helium).
|
|
||||||
- This module works with connection C(network_cli). See L(the VyOS OS Platform Options,../network/user_guide/platform_vyos.html).
|
|
||||||
options:
|
|
||||||
lines:
|
|
||||||
description:
|
|
||||||
- The ordered set of configuration lines to be managed and compared with the existing
|
|
||||||
configuration on the remote device.
|
|
||||||
src:
|
|
||||||
description:
|
|
||||||
- The C(src) argument specifies the path to the source config file to load. The
|
|
||||||
source config file can either be in bracket format or set format. The source
|
|
||||||
file can include Jinja2 template variables.
|
|
||||||
match:
|
|
||||||
description:
|
|
||||||
- The C(match) argument controls the method used to match against the current
|
|
||||||
active configuration. By default, the desired config is matched against the
|
|
||||||
active config and the deltas are loaded. If the C(match) argument is set to
|
|
||||||
C(none) the active configuration is ignored and the configuration is always
|
|
||||||
loaded.
|
|
||||||
default: line
|
|
||||||
choices:
|
|
||||||
- line
|
|
||||||
- none
|
|
||||||
backup:
|
|
||||||
description:
|
|
||||||
- The C(backup) argument will backup the current devices active configuration
|
|
||||||
to the Ansible control host prior to making any changes. If the C(backup_options)
|
|
||||||
value is not given, the backup file will be located in the backup folder in
|
|
||||||
the playbook root directory or role root directory, if playbook is part of an
|
|
||||||
ansible role. If the directory does not exist, it is created.
|
|
||||||
type: bool
|
|
||||||
default: 'no'
|
|
||||||
comment:
|
|
||||||
description:
|
|
||||||
- Allows a commit description to be specified to be included when the configuration
|
|
||||||
is committed. If the configuration is not changed or committed, this argument
|
|
||||||
is ignored.
|
|
||||||
default: configured by vyos_config
|
|
||||||
config:
|
|
||||||
description:
|
|
||||||
- The C(config) argument specifies the base configuration to use to compare against
|
|
||||||
the desired configuration. If this value is not specified, the module will
|
|
||||||
automatically retrieve the current active configuration from the remote device.
|
|
||||||
save:
|
|
||||||
description:
|
|
||||||
- The C(save) argument controls whether or not changes made to the active configuration
|
|
||||||
are saved to disk. This is independent of committing the config. When set
|
|
||||||
to True, the active configuration is saved.
|
|
||||||
type: bool
|
|
||||||
default: 'no'
|
|
||||||
backup_options:
|
|
||||||
description:
|
|
||||||
- This is a dict object containing configurable options related to backup file
|
|
||||||
path. The value of this option is read only when C(backup) is set to I(yes),
|
|
||||||
if C(backup) is set to I(no) this option will be silently ignored.
|
|
||||||
suboptions:
|
|
||||||
filename:
|
|
||||||
description:
|
|
||||||
- The filename to be used to store the backup configuration. If the filename
|
|
||||||
is not given it will be generated based on the hostname, current time and
|
|
||||||
date in format defined by <hostname>_config.<current-date>@<current-time>
|
|
||||||
dir_path:
|
|
||||||
description:
|
|
||||||
- This option provides the path ending with directory name in which the backup
|
|
||||||
configuration file will be stored. If the directory does not exist it will
|
|
||||||
be first created and the filename is either the value of C(filename) or
|
|
||||||
default filename as described in C(filename) options description. If the
|
|
||||||
path value is not given in that case a I(backup) directory will be created
|
|
||||||
in the current working directory and backup configuration will be copied
|
|
||||||
in C(filename) within I(backup) directory.
|
|
||||||
type: path
|
|
||||||
type: dict
|
|
||||||
"""
|
|
||||||
|
|
||||||
EXAMPLES = """
|
|
||||||
- name: configure the remote device
|
|
||||||
vyos_config:
|
|
||||||
lines:
|
|
||||||
- set system host-name {{ inventory_hostname }}
|
|
||||||
- set service lldp
|
|
||||||
- delete service dhcp-server
|
|
||||||
|
|
||||||
- name: backup and load from file
|
|
||||||
vyos_config:
|
|
||||||
src: vyos.cfg
|
|
||||||
backup: yes
|
|
||||||
|
|
||||||
- name: render a Jinja2 template onto the VyOS router
|
|
||||||
vyos_config:
|
|
||||||
src: vyos_template.j2
|
|
||||||
|
|
||||||
- name: for idempotency, use full-form commands
|
|
||||||
vyos_config:
|
|
||||||
lines:
|
|
||||||
# - set int eth eth2 description 'OUTSIDE'
|
|
||||||
- set interface ethernet eth2 description 'OUTSIDE'
|
|
||||||
|
|
||||||
- name: configurable backup path
|
|
||||||
vyos_config:
|
|
||||||
backup: yes
|
|
||||||
backup_options:
|
|
||||||
filename: backup.cfg
|
|
||||||
dir_path: /home/user
|
|
||||||
"""
|
|
||||||
|
|
||||||
RETURN = """
|
|
||||||
commands:
|
|
||||||
description: The list of configuration commands sent to the device
|
|
||||||
returned: always
|
|
||||||
type: list
|
|
||||||
sample: ['...', '...']
|
|
||||||
filtered:
|
|
||||||
description: The list of configuration commands removed to avoid a load failure
|
|
||||||
returned: always
|
|
||||||
type: list
|
|
||||||
sample: ['...', '...']
|
|
||||||
backup_path:
|
|
||||||
description: The full path to the backup file
|
|
||||||
returned: when backup is yes
|
|
||||||
type: str
|
|
||||||
sample: /playbooks/ansible/backup/vyos_config.2016-07-16@22:28:34
|
|
||||||
filename:
|
|
||||||
description: The name of the backup file
|
|
||||||
returned: when backup is yes and filename is not specified in backup options
|
|
||||||
type: str
|
|
||||||
sample: vyos_config.2016-07-16@22:28:34
|
|
||||||
shortname:
|
|
||||||
description: The full path to the backup file excluding the timestamp
|
|
||||||
returned: when backup is yes and filename is not specified in backup options
|
|
||||||
type: str
|
|
||||||
sample: /playbooks/ansible/backup/vyos_config
|
|
||||||
date:
|
|
||||||
description: The date extracted from the backup file name
|
|
||||||
returned: when backup is yes
|
|
||||||
type: str
|
|
||||||
sample: "2016-07-16"
|
|
||||||
time:
|
|
||||||
description: The time extracted from the backup file name
|
|
||||||
returned: when backup is yes
|
|
||||||
type: str
|
|
||||||
sample: "22:28:34"
|
|
||||||
"""
|
|
||||||
import re
|
|
||||||
|
|
||||||
from ansible.module_utils.common.text.converters import to_text
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
|
||||||
from ansible.module_utils.connection import ConnectionError
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (
|
|
||||||
load_config,
|
|
||||||
get_config,
|
|
||||||
run_commands,
|
|
||||||
)
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (
|
|
||||||
vyos_argument_spec,
|
|
||||||
get_connection,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_COMMENT = "configured by vyos_config"
|
|
||||||
|
|
||||||
CONFIG_FILTERS = [
|
|
||||||
re.compile(r"set system login user \S+ authentication encrypted-password")
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def get_candidate(module):
|
|
||||||
contents = module.params["src"] or module.params["lines"]
|
|
||||||
|
|
||||||
if module.params["src"]:
|
|
||||||
contents = format_commands(contents.splitlines())
|
|
||||||
|
|
||||||
contents = "\n".join(contents)
|
|
||||||
return contents
|
|
||||||
|
|
||||||
|
|
||||||
def format_commands(commands):
|
|
||||||
"""
|
|
||||||
This function format the input commands and removes the prepend white spaces
|
|
||||||
for command lines having 'set' or 'delete' and it skips empty lines.
|
|
||||||
:param commands:
|
|
||||||
:return: list of commands
|
|
||||||
"""
|
|
||||||
return [
|
|
||||||
line.strip() if line.split()[0] in ("set", "delete") else line
|
|
||||||
for line in commands
|
|
||||||
if len(line.strip()) > 0
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def diff_config(commands, config):
|
|
||||||
config = [str(c).replace("'", "") for c in config.splitlines()]
|
|
||||||
|
|
||||||
updates = list()
|
|
||||||
visited = set()
|
|
||||||
|
|
||||||
for line in commands:
|
|
||||||
item = str(line).replace("'", "")
|
|
||||||
|
|
||||||
if not item.startswith("set") and not item.startswith("delete"):
|
|
||||||
raise ValueError("line must start with either `set` or `delete`")
|
|
||||||
|
|
||||||
elif item.startswith("set") and item not in config:
|
|
||||||
updates.append(line)
|
|
||||||
|
|
||||||
elif item.startswith("delete"):
|
|
||||||
if not config:
|
|
||||||
updates.append(line)
|
|
||||||
else:
|
|
||||||
item = re.sub(r"delete", "set", item)
|
|
||||||
for entry in config:
|
|
||||||
if entry.startswith(item) and line not in visited:
|
|
||||||
updates.append(line)
|
|
||||||
visited.add(line)
|
|
||||||
|
|
||||||
return list(updates)
|
|
||||||
|
|
||||||
|
|
||||||
def sanitize_config(config, result):
|
|
||||||
result["filtered"] = list()
|
|
||||||
index_to_filter = list()
|
|
||||||
for regex in CONFIG_FILTERS:
|
|
||||||
for index, line in enumerate(list(config)):
|
|
||||||
if regex.search(line):
|
|
||||||
result["filtered"].append(line)
|
|
||||||
index_to_filter.append(index)
|
|
||||||
# Delete all filtered configs
|
|
||||||
for filter_index in sorted(index_to_filter, reverse=True):
|
|
||||||
del config[filter_index]
|
|
||||||
|
|
||||||
|
|
||||||
def run(module, result):
|
|
||||||
# get the current active config from the node or passed in via
|
|
||||||
# the config param
|
|
||||||
config = module.params["config"] or get_config(module)
|
|
||||||
|
|
||||||
# create the candidate config object from the arguments
|
|
||||||
candidate = get_candidate(module)
|
|
||||||
|
|
||||||
# create loadable config that includes only the configuration updates
|
|
||||||
connection = get_connection(module)
|
|
||||||
try:
|
|
||||||
response = connection.get_diff(
|
|
||||||
candidate=candidate,
|
|
||||||
running=config,
|
|
||||||
diff_match=module.params["match"],
|
|
||||||
)
|
|
||||||
except ConnectionError as exc:
|
|
||||||
module.fail_json(msg=to_text(exc, errors="surrogate_then_replace"))
|
|
||||||
|
|
||||||
commands = response.get("config_diff")
|
|
||||||
sanitize_config(commands, result)
|
|
||||||
|
|
||||||
result["commands"] = commands
|
|
||||||
|
|
||||||
commit = not module.check_mode
|
|
||||||
comment = module.params["comment"]
|
|
||||||
|
|
||||||
diff = None
|
|
||||||
if commands:
|
|
||||||
diff = load_config(module, commands, commit=commit, comment=comment)
|
|
||||||
|
|
||||||
if result.get("filtered"):
|
|
||||||
result["warnings"].append(
|
|
||||||
"Some configuration commands were "
|
|
||||||
"removed, please see the filtered key"
|
|
||||||
)
|
|
||||||
|
|
||||||
result["changed"] = True
|
|
||||||
|
|
||||||
if module._diff:
|
|
||||||
result["diff"] = {"prepared": diff}
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
backup_spec = dict(filename=dict(), dir_path=dict(type="path"))
|
|
||||||
argument_spec = dict(
|
|
||||||
src=dict(type="path"),
|
|
||||||
lines=dict(type="list"),
|
|
||||||
match=dict(default="line", choices=["line", "none"]),
|
|
||||||
comment=dict(default=DEFAULT_COMMENT),
|
|
||||||
config=dict(),
|
|
||||||
backup=dict(type="bool", default=False),
|
|
||||||
backup_options=dict(type="dict", options=backup_spec),
|
|
||||||
save=dict(type="bool", default=False),
|
|
||||||
)
|
|
||||||
|
|
||||||
argument_spec.update(vyos_argument_spec)
|
|
||||||
|
|
||||||
mutually_exclusive = [("lines", "src")]
|
|
||||||
|
|
||||||
module = AnsibleModule(
|
|
||||||
argument_spec=argument_spec,
|
|
||||||
mutually_exclusive=mutually_exclusive,
|
|
||||||
supports_check_mode=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
warnings = list()
|
|
||||||
|
|
||||||
result = dict(changed=False, warnings=warnings)
|
|
||||||
|
|
||||||
if module.params["backup"]:
|
|
||||||
result["__backup__"] = get_config(module=module)
|
|
||||||
|
|
||||||
if any((module.params["src"], module.params["lines"])):
|
|
||||||
run(module, result)
|
|
||||||
|
|
||||||
if module.params["save"]:
|
|
||||||
diff = run_commands(module, commands=["configure", "compare saved"])[1]
|
|
||||||
if diff != "[edit]":
|
|
||||||
run_commands(module, commands=["save"])
|
|
||||||
result["changed"] = True
|
|
||||||
run_commands(module, commands=["exit"])
|
|
||||||
|
|
||||||
module.exit_json(**result)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -1,175 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright 2019 Red Hat
|
|
||||||
# GNU General Public License v3.0+
|
|
||||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
"""
|
|
||||||
The module file for vyos_facts
|
|
||||||
"""
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
|
|
||||||
ANSIBLE_METADATA = {
|
|
||||||
"metadata_version": "1.1",
|
|
||||||
"status": [u"preview"],
|
|
||||||
"supported_by": "network",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DOCUMENTATION = """module: vyos_facts
|
|
||||||
short_description: Get facts about vyos devices.
|
|
||||||
description:
|
|
||||||
- Collects facts from network devices running the vyos operating system. This module
|
|
||||||
places the facts gathered in the fact tree keyed by the respective resource name. The
|
|
||||||
facts module will always collect a base set of facts from the device and can enable
|
|
||||||
or disable collection of additional facts.
|
|
||||||
author:
|
|
||||||
- Nathaniel Case (@qalthos)
|
|
||||||
- Nilashish Chakraborty (@Nilashishc)
|
|
||||||
- Rohit Thakur (@rohitthakur2590)
|
|
||||||
extends_documentation_fragment:
|
|
||||||
- vyos.vyos.vyos
|
|
||||||
notes:
|
|
||||||
- Tested against VyOS 1.1.8 (helium).
|
|
||||||
- This module works with connection C(network_cli). See L(the VyOS OS Platform Options,../network/user_guide/platform_vyos.html).
|
|
||||||
options:
|
|
||||||
gather_subset:
|
|
||||||
description:
|
|
||||||
- When supplied, this argument will restrict the facts collected to a given subset. Possible
|
|
||||||
values for this argument include all, default, config, and neighbors. Can specify
|
|
||||||
a list of values to include a larger subset. Values can also be used with an
|
|
||||||
initial C(M(!)) to specify that a specific subset should not be collected.
|
|
||||||
required: false
|
|
||||||
default: '!config'
|
|
||||||
gather_network_resources:
|
|
||||||
description:
|
|
||||||
- When supplied, this argument will restrict the facts collected to a given subset.
|
|
||||||
Possible values for this argument include all and the resources like interfaces.
|
|
||||||
Can specify a list of values to include a larger subset. Values can also be
|
|
||||||
used with an initial C(M(!)) to specify that a specific subset should not be
|
|
||||||
collected. Valid subsets are 'all', 'interfaces', 'l3_interfaces', 'lag_interfaces',
|
|
||||||
'lldp_global', 'lldp_interfaces', 'static_routes', 'firewall_rules'.
|
|
||||||
required: false
|
|
||||||
"""
|
|
||||||
|
|
||||||
EXAMPLES = """
|
|
||||||
# Gather all facts
|
|
||||||
- vyos_facts:
|
|
||||||
gather_subset: all
|
|
||||||
gather_network_resources: all
|
|
||||||
|
|
||||||
# collect only the config and default facts
|
|
||||||
- vyos_facts:
|
|
||||||
gather_subset: config
|
|
||||||
|
|
||||||
# collect everything exception the config
|
|
||||||
- vyos_facts:
|
|
||||||
gather_subset: "!config"
|
|
||||||
|
|
||||||
# Collect only the interfaces facts
|
|
||||||
- vyos_facts:
|
|
||||||
gather_subset:
|
|
||||||
- '!all'
|
|
||||||
- '!min'
|
|
||||||
gather_network_resources:
|
|
||||||
- interfaces
|
|
||||||
|
|
||||||
# Do not collect interfaces facts
|
|
||||||
- vyos_facts:
|
|
||||||
gather_network_resources:
|
|
||||||
- "!interfaces"
|
|
||||||
|
|
||||||
# Collect interfaces and minimal default facts
|
|
||||||
- vyos_facts:
|
|
||||||
gather_subset: min
|
|
||||||
gather_network_resources: interfaces
|
|
||||||
"""
|
|
||||||
|
|
||||||
RETURN = """
|
|
||||||
ansible_net_config:
|
|
||||||
description: The running-config from the device
|
|
||||||
returned: when config is configured
|
|
||||||
type: str
|
|
||||||
ansible_net_commits:
|
|
||||||
description: The set of available configuration revisions
|
|
||||||
returned: when present
|
|
||||||
type: list
|
|
||||||
ansible_net_hostname:
|
|
||||||
description: The configured system hostname
|
|
||||||
returned: always
|
|
||||||
type: str
|
|
||||||
ansible_net_model:
|
|
||||||
description: The device model string
|
|
||||||
returned: always
|
|
||||||
type: str
|
|
||||||
ansible_net_serialnum:
|
|
||||||
description: The serial number of the device
|
|
||||||
returned: always
|
|
||||||
type: str
|
|
||||||
ansible_net_version:
|
|
||||||
description: The version of the software running
|
|
||||||
returned: always
|
|
||||||
type: str
|
|
||||||
ansible_net_neighbors:
|
|
||||||
description: The set of LLDP neighbors
|
|
||||||
returned: when interface is configured
|
|
||||||
type: list
|
|
||||||
ansible_net_gather_subset:
|
|
||||||
description: The list of subsets gathered by the module
|
|
||||||
returned: always
|
|
||||||
type: list
|
|
||||||
ansible_net_api:
|
|
||||||
description: The name of the transport
|
|
||||||
returned: always
|
|
||||||
type: str
|
|
||||||
ansible_net_python_version:
|
|
||||||
description: The Python version Ansible controller is using
|
|
||||||
returned: always
|
|
||||||
type: str
|
|
||||||
ansible_net_gather_network_resources:
|
|
||||||
description: The list of fact resource subsets collected from the device
|
|
||||||
returned: always
|
|
||||||
type: list
|
|
||||||
"""
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.facts.facts import (
|
|
||||||
FactsArgs,
|
|
||||||
)
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.facts import (
|
|
||||||
Facts,
|
|
||||||
)
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (
|
|
||||||
vyos_argument_spec,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
"""
|
|
||||||
Main entry point for module execution
|
|
||||||
|
|
||||||
:returns: ansible_facts
|
|
||||||
"""
|
|
||||||
argument_spec = FactsArgs.argument_spec
|
|
||||||
argument_spec.update(vyos_argument_spec)
|
|
||||||
|
|
||||||
module = AnsibleModule(
|
|
||||||
argument_spec=argument_spec, supports_check_mode=True
|
|
||||||
)
|
|
||||||
|
|
||||||
warnings = []
|
|
||||||
if module.params["gather_subset"] == "!config":
|
|
||||||
warnings.append(
|
|
||||||
"default value for `gather_subset` will be changed to `min` from `!config` v2.11 onwards"
|
|
||||||
)
|
|
||||||
|
|
||||||
result = Facts(module).get_facts()
|
|
||||||
|
|
||||||
ansible_facts, additional_warnings = result
|
|
||||||
warnings.extend(additional_warnings)
|
|
||||||
|
|
||||||
module.exit_json(ansible_facts=ansible_facts, warnings=warnings)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -1,512 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright 2019 Red Hat
|
|
||||||
# GNU General Public License v3.0+
|
|
||||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
#############################################
|
|
||||||
# WARNING #
|
|
||||||
#############################################
|
|
||||||
#
|
|
||||||
# This file is auto generated by the resource
|
|
||||||
# module builder playbook.
|
|
||||||
#
|
|
||||||
# Do not edit this file manually.
|
|
||||||
#
|
|
||||||
# Changes to this file will be over written
|
|
||||||
# by the resource module builder.
|
|
||||||
#
|
|
||||||
# Changes should be made in the model used to
|
|
||||||
# generate this file or in the resource module
|
|
||||||
# builder template.
|
|
||||||
#
|
|
||||||
#############################################
|
|
||||||
|
|
||||||
"""
|
|
||||||
The module file for vyos_lldp_interfaces
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
|
|
||||||
ANSIBLE_METADATA = {
|
|
||||||
"metadata_version": "1.1",
|
|
||||||
"status": ["preview"],
|
|
||||||
"supported_by": "network",
|
|
||||||
}
|
|
||||||
|
|
||||||
DOCUMENTATION = """module: vyos_lldp_interfaces
|
|
||||||
short_description: Manages attributes of lldp interfaces on VyOS devices.
|
|
||||||
description: This module manages attributes of lldp interfaces on VyOS network devices.
|
|
||||||
notes:
|
|
||||||
- Tested against VyOS 1.1.8 (helium).
|
|
||||||
- This module works with connection C(network_cli). See L(the VyOS OS Platform Options,../network/user_guide/platform_vyos.html).
|
|
||||||
author:
|
|
||||||
- Rohit Thakur (@rohitthakur2590)
|
|
||||||
options:
|
|
||||||
config:
|
|
||||||
description: A list of lldp interfaces configurations.
|
|
||||||
type: list
|
|
||||||
suboptions:
|
|
||||||
name:
|
|
||||||
description:
|
|
||||||
- Name of the lldp interface.
|
|
||||||
type: str
|
|
||||||
required: true
|
|
||||||
enable:
|
|
||||||
description:
|
|
||||||
- to disable lldp on the interface.
|
|
||||||
type: bool
|
|
||||||
default: true
|
|
||||||
location:
|
|
||||||
description:
|
|
||||||
- LLDP-MED location data.
|
|
||||||
type: dict
|
|
||||||
suboptions:
|
|
||||||
civic_based:
|
|
||||||
description:
|
|
||||||
- Civic-based location data.
|
|
||||||
type: dict
|
|
||||||
suboptions:
|
|
||||||
ca_info:
|
|
||||||
description: LLDP-MED address info
|
|
||||||
type: list
|
|
||||||
suboptions:
|
|
||||||
ca_type:
|
|
||||||
description: LLDP-MED Civic Address type.
|
|
||||||
type: int
|
|
||||||
required: true
|
|
||||||
ca_value:
|
|
||||||
description: LLDP-MED Civic Address value.
|
|
||||||
type: str
|
|
||||||
required: true
|
|
||||||
country_code:
|
|
||||||
description: Country Code
|
|
||||||
type: str
|
|
||||||
required: true
|
|
||||||
coordinate_based:
|
|
||||||
description:
|
|
||||||
- Coordinate-based location.
|
|
||||||
type: dict
|
|
||||||
suboptions:
|
|
||||||
altitude:
|
|
||||||
description: Altitude in meters.
|
|
||||||
type: int
|
|
||||||
datum:
|
|
||||||
description: Coordinate datum type.
|
|
||||||
type: str
|
|
||||||
choices:
|
|
||||||
- WGS84
|
|
||||||
- NAD83
|
|
||||||
- MLLW
|
|
||||||
latitude:
|
|
||||||
description: Latitude.
|
|
||||||
type: str
|
|
||||||
required: true
|
|
||||||
longitude:
|
|
||||||
description: Longitude.
|
|
||||||
type: str
|
|
||||||
required: true
|
|
||||||
elin:
|
|
||||||
description: Emergency Call Service ELIN number (between 10-25 numbers).
|
|
||||||
type: str
|
|
||||||
state:
|
|
||||||
description:
|
|
||||||
- The state of the configuration after module completion.
|
|
||||||
type: str
|
|
||||||
choices:
|
|
||||||
- merged
|
|
||||||
- replaced
|
|
||||||
- overridden
|
|
||||||
- deleted
|
|
||||||
default: merged
|
|
||||||
"""
|
|
||||||
EXAMPLES = """
|
|
||||||
# Using merged
|
|
||||||
#
|
|
||||||
# Before state:
|
|
||||||
# -------------
|
|
||||||
#
|
|
||||||
# vyos@vyos:~$ show configuration commands | grep lldp
|
|
||||||
#
|
|
||||||
- name: Merge provided configuration with device configuration
|
|
||||||
vyos_lldp_interfaces:
|
|
||||||
config:
|
|
||||||
- name: 'eth1'
|
|
||||||
location:
|
|
||||||
civic_based:
|
|
||||||
country_code: 'US'
|
|
||||||
ca_info:
|
|
||||||
- ca_type: 0
|
|
||||||
ca_value: 'ENGLISH'
|
|
||||||
|
|
||||||
- name: 'eth2'
|
|
||||||
location:
|
|
||||||
coordinate_based:
|
|
||||||
altitude: 2200
|
|
||||||
datum: 'WGS84'
|
|
||||||
longitude: '222.267255W'
|
|
||||||
latitude: '33.524449N'
|
|
||||||
state: merged
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# -------------------------
|
|
||||||
# Module Execution Result
|
|
||||||
# -------------------------
|
|
||||||
#
|
|
||||||
# before": []
|
|
||||||
#
|
|
||||||
# "commands": [
|
|
||||||
# "set service lldp interface eth1 location civic-based country-code 'US'",
|
|
||||||
# "set service lldp interface eth1 location civic-based ca-type 0 ca-value 'ENGLISH'",
|
|
||||||
# "set service lldp interface eth1",
|
|
||||||
# "set service lldp interface eth2 location coordinate-based latitude '33.524449N'",
|
|
||||||
# "set service lldp interface eth2 location coordinate-based altitude '2200'",
|
|
||||||
# "set service lldp interface eth2 location coordinate-based datum 'WGS84'",
|
|
||||||
# "set service lldp interface eth2 location coordinate-based longitude '222.267255W'",
|
|
||||||
# "set service lldp interface eth2 location coordinate-based latitude '33.524449N'",
|
|
||||||
# "set service lldp interface eth2 location coordinate-based altitude '2200'",
|
|
||||||
# "set service lldp interface eth2 location coordinate-based datum 'WGS84'",
|
|
||||||
# "set service lldp interface eth2 location coordinate-based longitude '222.267255W'",
|
|
||||||
# "set service lldp interface eth2"
|
|
||||||
#
|
|
||||||
# "after": [
|
|
||||||
# {
|
|
||||||
# "location": {
|
|
||||||
# "coordinate_based": {
|
|
||||||
# "altitude": 2200,
|
|
||||||
# "datum": "WGS84",
|
|
||||||
# "latitude": "33.524449N",
|
|
||||||
# "longitude": "222.267255W"
|
|
||||||
# }
|
|
||||||
# },
|
|
||||||
# "name": "eth2"
|
|
||||||
# },
|
|
||||||
# {
|
|
||||||
# "location": {
|
|
||||||
# "civic_based": {
|
|
||||||
# "ca_info": [
|
|
||||||
# {
|
|
||||||
# "ca_type": 0,
|
|
||||||
# "ca_value": "ENGLISH"
|
|
||||||
# }
|
|
||||||
# ],
|
|
||||||
# "country_code": "US"
|
|
||||||
# }
|
|
||||||
# },
|
|
||||||
# "name": "eth1"
|
|
||||||
# }
|
|
||||||
# ],
|
|
||||||
#
|
|
||||||
# After state:
|
|
||||||
# -------------
|
|
||||||
#
|
|
||||||
# vyos@vyos:~$ show configuration commands | grep lldp
|
|
||||||
# set service lldp interface eth1 location civic-based ca-type 0 ca-value 'ENGLISH'
|
|
||||||
# set service lldp interface eth1 location civic-based country-code 'US'
|
|
||||||
# set service lldp interface eth2 location coordinate-based altitude '2200'
|
|
||||||
# set service lldp interface eth2 location coordinate-based datum 'WGS84'
|
|
||||||
# set service lldp interface eth2 location coordinate-based latitude '33.524449N'
|
|
||||||
# set service lldp interface eth2 location coordinate-based longitude '222.267255W'
|
|
||||||
|
|
||||||
|
|
||||||
# Using replaced
|
|
||||||
#
|
|
||||||
# Before state:
|
|
||||||
# -------------
|
|
||||||
#
|
|
||||||
# vyos@vyos:~$ show configuration commands | grep lldp
|
|
||||||
# set service lldp interface eth1 location civic-based ca-type 0 ca-value 'ENGLISH'
|
|
||||||
# set service lldp interface eth1 location civic-based country-code 'US'
|
|
||||||
# set service lldp interface eth2 location coordinate-based altitude '2200'
|
|
||||||
# set service lldp interface eth2 location coordinate-based datum 'WGS84'
|
|
||||||
# set service lldp interface eth2 location coordinate-based latitude '33.524449N'
|
|
||||||
# set service lldp interface eth2 location coordinate-based longitude '222.267255W'
|
|
||||||
#
|
|
||||||
- name: Replace device configurations of listed LLDP interfaces with provided configurations
|
|
||||||
vyos_lldp_interfaces:
|
|
||||||
config:
|
|
||||||
- name: 'eth2'
|
|
||||||
location:
|
|
||||||
civic_based:
|
|
||||||
country_code: 'US'
|
|
||||||
ca_info:
|
|
||||||
- ca_type: 0
|
|
||||||
ca_value: 'ENGLISH'
|
|
||||||
|
|
||||||
- name: 'eth1'
|
|
||||||
location:
|
|
||||||
coordinate_based:
|
|
||||||
altitude: 2200
|
|
||||||
datum: 'WGS84'
|
|
||||||
longitude: '222.267255W'
|
|
||||||
latitude: '33.524449N'
|
|
||||||
state: replaced
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# -------------------------
|
|
||||||
# Module Execution Result
|
|
||||||
# -------------------------
|
|
||||||
#
|
|
||||||
# "before": [
|
|
||||||
# {
|
|
||||||
# "location": {
|
|
||||||
# "coordinate_based": {
|
|
||||||
# "altitude": 2200,
|
|
||||||
# "datum": "WGS84",
|
|
||||||
# "latitude": "33.524449N",
|
|
||||||
# "longitude": "222.267255W"
|
|
||||||
# }
|
|
||||||
# },
|
|
||||||
# "name": "eth2"
|
|
||||||
# },
|
|
||||||
# {
|
|
||||||
# "location": {
|
|
||||||
# "civic_based": {
|
|
||||||
# "ca_info": [
|
|
||||||
# {
|
|
||||||
# "ca_type": 0,
|
|
||||||
# "ca_value": "ENGLISH"
|
|
||||||
# }
|
|
||||||
# ],
|
|
||||||
# "country_code": "US"
|
|
||||||
# }
|
|
||||||
# },
|
|
||||||
# "name": "eth1"
|
|
||||||
# }
|
|
||||||
# ]
|
|
||||||
#
|
|
||||||
# "commands": [
|
|
||||||
# "delete service lldp interface eth2 location",
|
|
||||||
# "set service lldp interface eth2 'disable'",
|
|
||||||
# "set service lldp interface eth2 location civic-based country-code 'US'",
|
|
||||||
# "set service lldp interface eth2 location civic-based ca-type 0 ca-value 'ENGLISH'",
|
|
||||||
# "delete service lldp interface eth1 location",
|
|
||||||
# "set service lldp interface eth1 'disable'",
|
|
||||||
# "set service lldp interface eth1 location coordinate-based latitude '33.524449N'",
|
|
||||||
# "set service lldp interface eth1 location coordinate-based altitude '2200'",
|
|
||||||
# "set service lldp interface eth1 location coordinate-based datum 'WGS84'",
|
|
||||||
# "set service lldp interface eth1 location coordinate-based longitude '222.267255W'"
|
|
||||||
# ]
|
|
||||||
#
|
|
||||||
# "after": [
|
|
||||||
# {
|
|
||||||
# "location": {
|
|
||||||
# "civic_based": {
|
|
||||||
# "ca_info": [
|
|
||||||
# {
|
|
||||||
# "ca_type": 0,
|
|
||||||
# "ca_value": "ENGLISH"
|
|
||||||
# }
|
|
||||||
# ],
|
|
||||||
# "country_code": "US"
|
|
||||||
# }
|
|
||||||
# },
|
|
||||||
# "name": "eth2"
|
|
||||||
# },
|
|
||||||
# {
|
|
||||||
# "location": {
|
|
||||||
# "coordinate_based": {
|
|
||||||
# "altitude": 2200,
|
|
||||||
# "datum": "WGS84",
|
|
||||||
# "latitude": "33.524449N",
|
|
||||||
# "longitude": "222.267255W"
|
|
||||||
# }
|
|
||||||
# },
|
|
||||||
# "name": "eth1"
|
|
||||||
# }
|
|
||||||
# ]
|
|
||||||
#
|
|
||||||
# After state:
|
|
||||||
# -------------
|
|
||||||
#
|
|
||||||
# vyos@vyos:~$ show configuration commands | grep lldp
|
|
||||||
# set service lldp interface eth1 'disable'
|
|
||||||
# set service lldp interface eth1 location coordinate-based altitude '2200'
|
|
||||||
# set service lldp interface eth1 location coordinate-based datum 'WGS84'
|
|
||||||
# set service lldp interface eth1 location coordinate-based latitude '33.524449N'
|
|
||||||
# set service lldp interface eth1 location coordinate-based longitude '222.267255W'
|
|
||||||
# set service lldp interface eth2 'disable'
|
|
||||||
# set service lldp interface eth2 location civic-based ca-type 0 ca-value 'ENGLISH'
|
|
||||||
# set service lldp interface eth2 location civic-based country-code 'US'
|
|
||||||
|
|
||||||
|
|
||||||
# Using overridden
|
|
||||||
#
|
|
||||||
# Before state
|
|
||||||
# --------------
|
|
||||||
#
|
|
||||||
# vyos@vyos:~$ show configuration commands | grep lldp
|
|
||||||
# set service lldp interface eth1 'disable'
|
|
||||||
# set service lldp interface eth1 location coordinate-based altitude '2200'
|
|
||||||
# set service lldp interface eth1 location coordinate-based datum 'WGS84'
|
|
||||||
# set service lldp interface eth1 location coordinate-based latitude '33.524449N'
|
|
||||||
# set service lldp interface eth1 location coordinate-based longitude '222.267255W'
|
|
||||||
# set service lldp interface eth2 'disable'
|
|
||||||
# set service lldp interface eth2 location civic-based ca-type 0 ca-value 'ENGLISH'
|
|
||||||
# set service lldp interface eth2 location civic-based country-code 'US'
|
|
||||||
#
|
|
||||||
- name: Overrides all device configuration with provided configuration
|
|
||||||
vyos_lag_interfaces:
|
|
||||||
config:
|
|
||||||
- name: 'eth2'
|
|
||||||
location:
|
|
||||||
elin: 0000000911
|
|
||||||
|
|
||||||
state: overridden
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# -------------------------
|
|
||||||
# Module Execution Result
|
|
||||||
# -------------------------
|
|
||||||
#
|
|
||||||
# "before": [
|
|
||||||
# {
|
|
||||||
# "enable": false,
|
|
||||||
# "location": {
|
|
||||||
# "civic_based": {
|
|
||||||
# "ca_info": [
|
|
||||||
# {
|
|
||||||
# "ca_type": 0,
|
|
||||||
# "ca_value": "ENGLISH"
|
|
||||||
# }
|
|
||||||
# ],
|
|
||||||
# "country_code": "US"
|
|
||||||
# }
|
|
||||||
# },
|
|
||||||
# "name": "eth2"
|
|
||||||
# },
|
|
||||||
# {
|
|
||||||
# "enable": false,
|
|
||||||
# "location": {
|
|
||||||
# "coordinate_based": {
|
|
||||||
# "altitude": 2200,
|
|
||||||
# "datum": "WGS84",
|
|
||||||
# "latitude": "33.524449N",
|
|
||||||
# "longitude": "222.267255W"
|
|
||||||
# }
|
|
||||||
# },
|
|
||||||
# "name": "eth1"
|
|
||||||
# }
|
|
||||||
# ]
|
|
||||||
#
|
|
||||||
# "commands": [
|
|
||||||
# "delete service lldp interface eth2 location",
|
|
||||||
# "delete service lldp interface eth2 disable",
|
|
||||||
# "set service lldp interface eth2 location elin 0000000911"
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# "after": [
|
|
||||||
# {
|
|
||||||
# "location": {
|
|
||||||
# "elin": 0000000911
|
|
||||||
# },
|
|
||||||
# "name": "eth2"
|
|
||||||
# }
|
|
||||||
# ]
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# After state
|
|
||||||
# ------------
|
|
||||||
#
|
|
||||||
# vyos@vyos# run show configuration commands | grep lldp
|
|
||||||
# set service lldp interface eth2 location elin '0000000911'
|
|
||||||
|
|
||||||
|
|
||||||
# Using deleted
|
|
||||||
#
|
|
||||||
# Before state
|
|
||||||
# -------------
|
|
||||||
#
|
|
||||||
# vyos@vyos# run show configuration commands | grep lldp
|
|
||||||
# set service lldp interface eth2 location elin '0000000911'
|
|
||||||
#
|
|
||||||
- name: Delete lldp interface attributes of given interfaces.
|
|
||||||
vyos_lag_interfaces:
|
|
||||||
config:
|
|
||||||
- name: 'eth2'
|
|
||||||
state: deleted
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# ------------------------
|
|
||||||
# Module Execution Results
|
|
||||||
# ------------------------
|
|
||||||
#
|
|
||||||
"before": [
|
|
||||||
{
|
|
||||||
"location": {
|
|
||||||
"elin": 0000000911
|
|
||||||
},
|
|
||||||
"name": "eth2"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
# "commands": [
|
|
||||||
# "commands": [
|
|
||||||
# "delete service lldp interface eth2"
|
|
||||||
# ]
|
|
||||||
#
|
|
||||||
# "after": []
|
|
||||||
# After state
|
|
||||||
# ------------
|
|
||||||
# vyos@vyos# run show configuration commands | grep lldp
|
|
||||||
# set service 'lldp'
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
RETURN = """
|
|
||||||
before:
|
|
||||||
description: The configuration as structured data prior to module invocation.
|
|
||||||
returned: always
|
|
||||||
type: list
|
|
||||||
sample: >
|
|
||||||
The configuration returned will always be in the same format
|
|
||||||
of the parameters above.
|
|
||||||
after:
|
|
||||||
description: The configuration as structured data after module completion.
|
|
||||||
returned: when changed
|
|
||||||
type: list
|
|
||||||
sample: >
|
|
||||||
The configuration returned will always be in the same format
|
|
||||||
of the parameters above.
|
|
||||||
commands:
|
|
||||||
description: The set of commands pushed to the remote device.
|
|
||||||
returned: always
|
|
||||||
type: list
|
|
||||||
sample:
|
|
||||||
- "set service lldp interface eth2 'disable'"
|
|
||||||
- "delete service lldp interface eth1 location"
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.lldp_interfaces.lldp_interfaces import (
|
|
||||||
Lldp_interfacesArgs,
|
|
||||||
)
|
|
||||||
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.lldp_interfaces.lldp_interfaces import (
|
|
||||||
Lldp_interfaces,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
"""
|
|
||||||
Main entry point for module execution
|
|
||||||
|
|
||||||
:returns: the result form module invocation
|
|
||||||
"""
|
|
||||||
required_if = [
|
|
||||||
("state", "merged", ("config",)),
|
|
||||||
("state", "replaced", ("config",)),
|
|
||||||
("state", "overridden", ("config",)),
|
|
||||||
]
|
|
||||||
module = AnsibleModule(
|
|
||||||
argument_spec=Lldp_interfacesArgs.argument_spec,
|
|
||||||
required_if=required_if,
|
|
||||||
supports_check_mode=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
result = Lldp_interfaces(module).execute_module()
|
|
||||||
module.exit_json(**result)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -1,52 +0,0 @@
|
|||||||
#
|
|
||||||
# (c) 2016 Red Hat Inc.
|
|
||||||
#
|
|
||||||
# This file is part of Ansible
|
|
||||||
#
|
|
||||||
# Ansible is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Ansible is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
|
|
||||||
from ansible.plugins.terminal import TerminalBase
|
|
||||||
from ansible.errors import AnsibleConnectionFailure
|
|
||||||
|
|
||||||
|
|
||||||
class TerminalModule(TerminalBase):
|
|
||||||
|
|
||||||
terminal_stdout_re = [
|
|
||||||
re.compile(br"[\r\n]?[\w+\-\.:\/\[\]]+(?:\([^\)]+\)){,3}(?:>|#) ?$"),
|
|
||||||
re.compile(br"\@[\w\-\.]+:\S+?[>#\$] ?$"),
|
|
||||||
]
|
|
||||||
|
|
||||||
terminal_stderr_re = [
|
|
||||||
re.compile(br"\n\s*Invalid command:"),
|
|
||||||
re.compile(br"\nCommit failed"),
|
|
||||||
re.compile(br"\n\s+Set failed"),
|
|
||||||
]
|
|
||||||
|
|
||||||
terminal_length = os.getenv("ANSIBLE_VYOS_TERMINAL_LENGTH", 10000)
|
|
||||||
|
|
||||||
def on_open_shell(self):
|
|
||||||
try:
|
|
||||||
for cmd in (b"set terminal length 0", b"set terminal width 512"):
|
|
||||||
self._exec_cli_command(cmd)
|
|
||||||
self._exec_cli_command(
|
|
||||||
b"set terminal length %d" % self.terminal_length
|
|
||||||
)
|
|
||||||
except AnsibleConnectionFailure:
|
|
||||||
raise AnsibleConnectionFailure("unable to set terminal parameters")
|
|
Loading…
Reference in New Issue