napalm-automation / napalm-ansible

Apache License 2.0
245 stars 103 forks source link

Optional Args Not working for Arista #146

Closed derfUrban closed 6 years ago

derfUrban commented 6 years ago

When attempting to push a config to Arista using napalm_install_config the subsystem fails to recognize the optional_args being passed.

According to the readthedocs entry here, https://media.readthedocs.org/pdf/napalmsdf/latest/napalmsdf.pdf, there is a list of optional args expected and on page 36 it says we can add to them but it isn't clear where the model exists to add the optional args needed for our use case.

In either case I lack the confidence that the subsystem will operate as needed if the model is updated accordingly. Please advise.

Below is sample yaml

- name: Load configuration into the device and diff
  napalm_install_config:
    hostname: "{{ ansible_host }}"
    username: test_user
    dev_os: "{{ ansible_os_family }}"
    optional_args:
      commit_session: "{{ ansible_host }}"
      commit: True
      commit_timer: 00:02:00
      commit_comments: "word"
    password: test_password
    config_file: "{{ config_file_name }}"
    commit_changeas: True
    replace_config: False
    get_diffs: False
    diff_file: "{{ ansible_os_family }}.{{ state }}.conf.diff"
  when:  has_pending_config == false
  tags: [print_action]`

Below is output error s you can see optional_args is null fatal: [arista7508e.cvr]: FAILED! => {"changed": false, "failed": true, "invocation": {"module_args": {"archive_file": null, "candidate_file": null, "commit_changes": false, "config": null, "config_file": "/arista7508e.cvr.eos.present.conf", "dev_os": "eos", "diff_file": "/arista7508e.cvr.eos.present.conf.diff", "get_diffs": true, "hostname": "arista7508e.cvr.d0cdn.net", "optional_args": null, "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", "provider": null, "replace_config": false, "timeout": 60, "username": "fjone"}, "module_name": "napalm_install_config"}, "msg": "cannot load config: Error [1002]: CLI command 3 of 4510 'commit timer ' failed: invalid command [incomplete command (at token 2: None)]"}

I can manually edit the eos.py class however we want dynamic variable input rather than static.

dbarrosop commented 6 years ago

Optional args need to be supported by the corresponding napalm drivers. So in order for those to work you'd need to implement them first here.

I am closing this issue as it's not related to napalm-ansible. Feel free to open a PR in napalm or open an issue there for discussion.

derfUrban commented 6 years ago

This response is a bit confusing as the eos drivers appears to support the optional args parameter unless I am missing something.

So adding this in my playbook...

- name: Load configuration into the device and diff
  napalm_install_config:
    hostname: "{{ ansible_host }}"
    username: fjone
    dev_os: "{{ ansible_os_family }}"
    optional_args:
      commit_session: "{{ ansible_host }}"
      commit_pending: True
      commit_timer: 00:02:00
      commit_comments: "word"
    password: test123
    config_file: "{{ config_file_name }}"
    commit_changeas: True
    replace_config: False
    get_diffs: False
    diff_file: "{{ path }}/{{ hostname }}.conf.diff"
  when:  has_pending_config == false
  tags: [print_action]

Add this to eos.py ` def init(self, hostname, username, password, comments, timeout=60, optional_args=None): """Constructor.""" self.device = None self.hostname = hostname self.username = username self.password = password self.timeout = timeout self.config_session = None self.commit_timer = None self.comments = None self.locked = False

    if optional_args is None:
        optional_args = {}

    # eos_transport is there for backwards compatibility, transport is the preferred method
    self.transport = optional_args.get('transport', optional_args.get('eos_transport', 'https'))
    self.config_session = 'napalm_{}'.format(optional_args.get('commit_session', 'Testing Session Commit'))
    self.commit_timer = optional_args.get('commit_timer', '00:05:00')
    self.comments =  optional_args.get('commit_comments', 'Testing comments')
    self.commit_pending =  optional_args.get('commit_pending', 'Testing comments')`

And it produces null optional_args as displayed above.

So either ansible is passing null to napalm_ansible or na is passing null to eos.py but somewhere optional_args isn't making it to the code I've implemented.

Digging deeper into the code I see in napalm_install_config is instantiating the optional args object to Ansible module

module = AnsibleModule( argument_spec=dict( hostname=dict(type='str', required=False, aliases=['host']), username=dict(type='str', required=False), password=dict(type='str', required=False, no_log=True), provider=dict(type='dict', required=False), timeout=dict(type='int', required=False, default=60), optional_args=dict(required=False, type='dict', default=None), config_file=dict(type='str', required=False), config=dict(type='str', required=False), dev_os=dict(type='str', required=False), commit_changes=dict(type='bool', required=True), replace_config=dict(type='bool', required=False, default=False), diff_file=dict(type='str', required=False, default=None), get_diffs=dict(type='bool', required=False, default=True), archive_file=dict(type='str', required=False, default=None), candidate_file=dict(type='str', required=False, default=None) ), supports_check_mode=True

Then this code digging deep in and instantiating the the network driver object with the eos class.

` if module.params['optional_args'] is None: optional_args = {} else: optional_args = module.params['optional_args']

try:
    network_driver = get_network_driver(dev_os)
except ModuleImportError as e:
    module.fail_json(msg="Failed to import napalm driver: " + str(e))`

So I added this code to check what this is actually doing...

` #ToDO FWJ_NET_719 I believe variable scope is eating the optional args here

if module.params['optional_args'] is None:
    optional_args = {}
    save_to_file('No optional args', '/tmp/option_args/no_args.txt')
else:
    save_to_file(module.params['optional_args'], '/tmp/option_args/no_args.txt')
    optional_args = module.params['optional_args']
    save_to_file(optional_args, '/tmp/option_args/no_args.txt')`

And the output of that file is... [Tue Oct 02 21:53:25] fjones@nae501.lc:~/nae/bin$ cat /tmp/option_args/no_args.txt No optional args[Tue Oct 02 21:53:36] fjones@nae501.dle.lc4:~/nae/bin$ vi ../nae/library/napalm_ansible/modules/napalm_install_config.py [Tue Oct 02 21:54:56] fjones@nae501.lc:~/nae/bin$

And the output of that execution is...

fatal: [arista7508e.cvr]: FAILED! => {"changed": false, "failed": true, "invocation": {"module_args": {"archive_file": null, "candidate_file": null, "commit_changes": false, "config": null, "config_file": "/aristae.cvr.eos.present.conf", "dev_os": "eos", "diff_file": "/aristae.cvr.eos.present.conf.diff", "get_diffs": true, "hostname": "aristae.cvr.d0cdn.net", "optional_args": null, "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", "provider": null, "replace_config": false, "timeout": 60, "username": "fjone"}, "module_name": "napalm_install_config"},

So again even though I have edited the eos.py driver and made my playbook role with the optional_args it is not being passed accordingly so please reopen this issue or advise where I need to go to get this resolved.

ktbyers commented 6 years ago

Here is a simple example, I just ran in my lab:

---
- name: Test optional_args
  hosts: nxos
  tasks:
    - name: Verify IP interface
      napalm_get_facts:
        hostname: "{{ ansible_host }}"
        username: "{{ ansible_user }}"
        password: "{{ ansible_ssh_pass }}"
        dev_os: "nxos"
        optional_args:
          port: 8443
        filter: "interfaces_ip"

Which runs correct and debugging shows this (only included relevant section)

    "invocation": {
        "module_args": {
            "args": null, 
            "dev_os": "nxos", 
            "filter": [
                "interfaces_ip"
            ], 
            "hostname": "nxos1.domain.com", 
            "ignore_notimplemented": false, 
            "optional_args": {
                "port": 8443
            }, 
            "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", 
            "provider": {
                "hostname": "nxos1.domain.com", 
                "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", 
                "timeout": 60, 
                "username": "admin"
            }, 
            "timeout": 60, 
            "username": "admin"
        }
    }

So everything I see indicates that napalm-ansible is running correctly. My guess is that you are doing something wrong on the Ansible side.

ktbyers commented 6 years ago

For grins, I added an arbitrary argument to optional_args:

        optional_args:
          port: 8443
          foo: bar

This also showed up in the invocation arguments. This was using Ansible 2.6.5

derfUrban commented 6 years ago

@ktbyers That example is on napalm_get_facts, could you show and example a similar output on napalm_install_config and dev_os: eos which is the method routine my issues is occurring on?