{"action":"created","issue":{"url":"https://api.github.com/repos/ansible/ansible/issues/31575","repository_url":"https://api.github.com/repos/ansible/ansible","labels_url":"https://api.github.com/repos/ansible/ansible/issues/31575/labels{/name}","comments_url":"https://api.github.com/repos/ansible/ansible/issues/31575/comments","events_url":"https://api.github.com/repos/ansible/ansible/issues/31575/events","html_url":"https://github.com/ansible/ansible/issues/31575","id":264551712,"number":31575,"title":"ios_config incorrectly claims success when commands fail","user":{"login":"nickrusso42518","id":20440669,"avatar_url":"https://avatars3.githubusercontent.com/u/20440669?v=4","gravatar_id":"","url":"https://api.github.com/users/nickrusso42518","html_url":"https://github.com/nickrusso42518","followers_url":"https://api.github.com/users/nickrusso42518/followers","following_url":"https://api.github.com/users/nickrusso42518/following{/other_user}","gists_url":"https://api.github.com/users/nickrusso42518/gists{/gist_id}","starred_url":"https://api.github.com/users/nickrusso42518/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nickrusso42518/subscriptions","organizations_url":"https://api.github.com/users/nickrusso42518/orgs","repos_url":"https://api.github.com/users/nickrusso42518/repos","events_url":"https://api.github.com/users/nickrusso42518/events{/privacy}","received_events_url":"https://api.github.com/users/nickrusso42518/received_events","type":"User","site_admin":false},"labels":[{"id":454885231,"url":"https://api.github.com/repos/ansible/ansible/labels/affects_2.3","name":"affects_2.3","color":"5319e7","default":false},{"id":785271699,"url":"https://api.github.com/repos/ansible/ansible/labels/bug","name":"bug","color":"fbca04","default":true},{"id":496359346,"url":"https://api.github.com/repos/ansible/ansible/labels/module","name":"module","color":"1d76db","default":false},{"id":54811101,"url":"https://api.github.com/repos/ansible/ansible/labels/needs_info","name":"needs_info","color":"eb6420","default":false},{"id":339653091,"url":"https://api.github.com/repos/ansible/ansible/labels/networking","name":"networking","color":"c7def8","default":false},{"id":669761792,"url":"https://api.github.com/repos/ansible/ansible/labels/support:network","name":"support:network","color":"ededed","default":false}],"state":"open","locked":false,"assignee":{"login":"rcarrillocruz","id":1419467,"avatar_url":"https://avatars3.githubusercontent.com/u/1419467?v=4","gravatar_id":"","url":"https://api.github.com/users/rcarrillocruz","html_url":"https://github.com/rcarrillocruz","followers_url":"https://api.github.com/users/rcarrillocruz/followers","following_url":"https://api.github.com/users/rcarrillocruz/following{/other_user}","gists_url":"https://api.github.com/users/rcarrillocruz/gists{/gist_id}","starred_url":"https://api.github.com/users/rcarrillocruz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rcarrillocruz/subscriptions","organizations_url":"https://api.github.com/users/rcarrillocruz/orgs","repos_url":"https://api.github.com/users/rcarrillocruz/repos","events_url":"https://api.github.com/users/rcarrillocruz/events{/privacy}","received_events_url":"https://api.github.com/users/rcarrillocruz/received_events","type":"User","site_admin":false},"assignees":[{"login":"rcarrillocruz","id":1419467,"avatar_url":"https://avatars3.githubusercontent.com/u/1419467?v=4","gravatar_id":"","url":"https://api.github.com/users/rcarrillocruz","html_url":"https://github.com/rcarrillocruz","followers_url":"https://api.github.com/users/rcarrillocruz/followers","following_url":"https://api.github.com/users/rcarrillocruz/following{/other_user}","gists_url":"https://api.github.com/users/rcarrillocruz/gists{/gist_id}","starred_url":"https://api.github.com/users/rcarrillocruz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rcarrillocruz/subscriptions","organizations_url":"https://api.github.com/users/rcarrillocruz/orgs","repos_url":"https://api.github.com/users/rcarrillocruz/repos","events_url":"https://api.github.com/users/rcarrillocruz/events{/privacy}","received_events_url":"https://api.github.com/users/rcarrillocruz/received_events","type":"User","site_admin":false}],"milestone":{"url":"https://api.github.com/repos/ansible/ansible/milestones/11","html_url":"https://github.com/ansible/ansible/milestone/11","labels_url":"https://api.github.com/repos/ansible/ansible/milestones/11/labels","id":2644825,"number":11,"title":"2.5.0","description":"","creator":{"login":"gundalow","id":940557,"avatar_url":"https://avatars1.githubusercontent.com/u/940557?v=4","gravatar_id":"","url":"https://api.github.com/users/gundalow","html_url":"https://github.com/gundalow","followers_url":"https://api.github.com/users/gundalow/followers","following_url":"https://api.github.com/users/gundalow/following{/other_user}","gists_url":"https://api.github.com/users/gundalow/gists{/gist_id}","starred_url":"https://api.github.com/users/gundalow/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gundalow/subscriptions","organizations_url":"https://api.github.com/users/gundalow/orgs","repos_url":"https://api.github.com/users/gundalow/repos","events_url":"https://api.github.com/users/gundalow/events{/privacy}","received_events_url":"https://api.github.com/users/gundalow/received_events","type":"User","site_admin":false},"open_issues":72,"closed_issues":427,"state":"open","created_at":"2017-07-17T13:35:32Z","updated_at":"2018-03-09T15:22:44Z","due_on":null,"closed_at":null},"comments":8,"created_at":"2017-10-11T11:32:31Z","updated_at":"2018-03-10T16:33:45Z","closed_at":null,"author_association":"NONE","body":"##### ISSUE TYPE\r\n<!--- Pick one below and delete the rest: -->\r\n - Bug Report\r\n\r\n##### COMPONENT NAME\r\n<!--- Name of the module/plugin/task/feature -->\r\nios_config\r\n\r\n##### ANSIBLE VERSION\r\n<!--- Paste verbatim output from \"ansible --version\" between quotes below -->\r\n```\r\n[ansible@localhost cmdauthz]$ ansible --version\r\nansible 2.3.1.0\r\n  config file = /etc/ansible/ansible.cfg\r\n  configured module search path = Default w/o overrides\r\n  python version = 2.7.5 (default, Nov  6 2016, 00:28:07) [GCC 4.8.5 20150623 (Red Hat 4.8.5-11)]\r\n```\r\n\r\n##### CONFIGURATION\r\n<!---\r\nIf using Ansible 2.4 or above, paste the results of \"ansible-config dump --only-changed\"\r\n\r\nOtherwise, mention any settings you have changed/added/removed in ansible.cfg\r\n(or using the ANSIBLE_* environment variables).\r\n\r\n-->\r\nansible.cfg modification:\r\nforks = 20\r\ngathering = explicit\r\nhost_key_checking = false\r\ntimeout = 60\r\nvault_password_file = ~/.ansible/vault-pass.txt\r\nretry_files_enabled = false\r\n\r\n##### OS / ENVIRONMENT\r\n<!---\r\nMention the OS you are running Ansible from, and the OS you are\r\nmanaging, or say \"N/A\" for anything that is not platform-specific.\r\nAlso mention the specific version of what you are trying to control,\r\ne.g. if this is a network bug the version of firmware on the network device.\r\n-->\r\nAWS AMI CentOS7\r\n```\r\n[ansible@localhost cmdauthz]$ uname -a\r\nLinux localhost.localdomain 3.10.0-514.26.2.el7.x86_64 #1 SMP Tue Jul 4 15:04:05 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux\r\n```\r\n\r\n##### SUMMARY\r\n<!--- Explain the problem briefly -->\r\nThere is no stdout from \"ios_config\". When you issue commands that are TACACS-unauthorized, ansible still reports \"changed\", comes back and reports success, and ignores the fact they were rejected. I assume the module is ignoring all CLI output and only looking for the next config prompt to claim success. This makes it difficult to validate that unauthorized commands were rejected and authorized commands were accepted. Such a playbook is useful as a AAA security posture checker.\r\n\r\n##### STEPS TO REPRODUCE\r\n<!---\r\nFor bugs, show exactly how to reproduce the problem, using a minimal test-case.\r\nFor new features, show how the feature would be used.\r\n-->\r\nTask sub-list shown below.\r\n<!--- Paste example playbooks or commands between quotes below -->\r\n```\r\n---\r\n- name: \"SYS >> Capture current username\"\r\n  set_fact:\r\n    USER: \"{{ PARAM_CREDS.username }}\"\r\n\r\n- name: \"IOS >> {{ USER }}: Issue unauthorized conf commands\"\r\n  ios_config:\r\n    provider: \"{{ PARAM_CREDS }}\"\r\n    match: none\r\n    commands:\r\n    - \"{{ item }}\"\r\n  register: OUTPUT\r\n  with_items: \"{{ unauth_conf_cmds_t2 }}\"\r\n\r\n- debug:\r\n    var: OUTPUT\r\n...\r\n```\r\n\r\nRelevant variables included.\r\n\r\n```\r\n---\r\nunauth_conf_cmds_t2:\r\n- \"ip bgp new-format\"\r\n- \"interface Loopback12345\"\r\n...\r\n```\r\n\r\n<!--- You can also paste gist.github.com links for larger files -->\r\n\r\n##### EXPECTED RESULTS\r\n<!--- What did you expect to happen when running the steps above? -->\r\nWhen `ios_config` determines that the commands being issued are new (a change), of if, `match: none` is set, the module should attempt to issue command in question. It should also collect any parser output, to include `Command authorization failed.`, so that the playbook writer can perform checks against it. I would recommend returning `stdout` and `stdout_lines` in much the same way that ios_command works, for consistency.\r\n\r\nNote that if you don't want to set up a TACACS server, using a `do` statement to run a show command from config mode would probably be a valid test to ensure output is being collected.\r\n\r\n##### ACTUAL RESULTS\r\n<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->\r\n`ios_config` returns correct fields per the documentation, but the lack of seeing CLI output makes it hard to discern why commands were rejected.\r\n\r\n<!--- Paste verbatim command output between quotes below -->\r\n```\r\n[ansible@localhost cmdauthz]$ ansible-playbook cmdauthz-playbook.yml \r\n\r\nPLAY [localhost] ************************************************************************************************************\r\n\r\nTASK [SYS >> Define string match facts] *************************************************************************************\r\nok: [localhost]\r\n\r\nPLAY [Verify AAA command authorization functionality] ***********************************************************************\r\n\r\nTASK [SYS >> Capture current username] **************************************************************************************\r\nok: [APG_6010_PER]\r\n\r\nTASK [IOS >> ansible2: Issue unauthorized conf commands] ********************************************************************\r\nchanged: [APG_6010_PER] => (item=ip bgp new-format)\r\nchanged: [APG_6010_PER] => (item=interface Loopback12345)\r\n\r\nTASK [debug] ****************************************************************************************************************\r\nok: [APG_6010_PER] => {\r\n    \"OUTPUT\": {\r\n        \"changed\": true, \r\n        \"msg\": \"All items completed\", \r\n        \"results\": [\r\n            {\r\n                \"_ansible_item_result\": true, \r\n                \"_ansible_no_log\": false, \r\n                \"_ansible_parsed\": true, \r\n                \"banners\": {}, \r\n                \"changed\": true, \r\n                \"commands\": [\r\n                    \"ip bgp new-format\"\r\n                ], \r\n                \"invocation\": {\r\n                    \"module_args\": {\r\n                        \"after\": null, \r\n                        \"auth_pass\": null, \r\n                        \"authorize\": null, \r\n                        \"backup\": false, \r\n                        \"before\": null, \r\n                        \"commands\": [\r\n                            \"ip bgp new-format\"\r\n                        ], \r\n                        \"config\": null, \r\n                        \"defaults\": false, \r\n                        \"force\": false, \r\n                        \"host\": null, \r\n                        \"lines\": [\r\n                            \"ip bgp new-format\"\r\n                        ], \r\n                        \"match\": \"none\", \r\n                        \"multiline_delimiter\": \"@\", \r\n                        \"parents\": null, \r\n                        \"password\": null, \r\n                        \"port\": null, \r\n                        \"provider\": {\r\n                            \"auth_pass\": null, \r\n                            \"authorize\": null, \r\n                            \"host\": \"APG_6010_PER\", \r\n                            \"password\": \"VALUE_SPECIFIED_IN_NO_LOG_PARAMETER\", \r\n                            \"port\": 3022, \r\n                            \"ssh_keyfile\": null, \r\n                            \"timeout\": 30, \r\n                            \"username\": \"ansible2\"\r\n                        }, \r\n                        \"replace\": \"line\", \r\n                        \"save\": false, \r\n                        \"src\": null, \r\n                        \"ssh_keyfile\": null, \r\n                        \"timeout\": null, \r\n                        \"username\": null\r\n                    }\r\n                }, \r\n                \"item\": \"ip bgp new-format\", \r\n                \"updates\": [\r\n                    \"ip bgp new-format\"\r\n                ]\r\n            }, \r\n            {\r\n                \"_ansible_item_result\": true, \r\n                \"_ansible_no_log\": false, \r\n                \"_ansible_parsed\": true, \r\n                \"banners\": {}, \r\n                \"changed\": true, \r\n                \"commands\": [\r\n                    \"interface Loopback12345\"\r\n                ], \r\n                \"invocation\": {\r\n                    \"module_args\": {\r\n                        \"after\": null, \r\n                        \"auth_pass\": null, \r\n                        \"authorize\": null, \r\n                        \"backup\": false, \r\n                        \"before\": null, \r\n                        \"commands\": [\r\n                            \"interface Loopback12345\"\r\n                        ], \r\n                        \"config\": null, \r\n                        \"defaults\": false, \r\n                        \"force\": false, \r\n                        \"host\": null, \r\n                        \"lines\": [\r\n                            \"interface Loopback12345\"\r\n                        ], \r\n                        \"match\": \"none\", \r\n                        \"multiline_delimiter\": \"@\", \r\n                        \"parents\": null, \r\n                        \"password\": null, \r\n                        \"port\": null, \r\n                        \"provider\": {\r\n                            \"auth_pass\": null, \r\n                            \"authorize\": null, \r\n                            \"host\": \"APG_6010_PER\", \r\n                            \"password\": \"VALUE_SPECIFIED_IN_NO_LOG_PARAMETER\", \r\n                            \"port\": 3022, \r\n                            \"ssh_keyfile\": null, \r\n                            \"timeout\": 30, \r\n                            \"username\": \"ansible2\"\r\n                        }, \r\n                        \"replace\": \"line\", \r\n                        \"save\": false, \r\n                        \"src\": null, \r\n                        \"ssh_keyfile\": null, \r\n                        \"timeout\": null, \r\n                        \"username\": null\r\n                    }\r\n                }, \r\n                \"item\": \"interface Loopback12345\", \r\n                \"updates\": [\r\n                    \"interface Loopback12345\"\r\n                ]\r\n            }\r\n        ]\r\n    }\r\n}\r\n```\r\n\r\nManually logging into the router and issuing the commands is shown below. The commands are rejected and no changes are observed.\r\n\r\n```\r\nAPG_6010_XPER#conf t\r\nEnter configuration commands, one per line.  End with CNTL/Z.\r\nAPG_6010_XPER(config)#ip bgp new-format\r\nCommand authorization failed.\r\n\r\nAPG_6010_XPER(config)#interface Loopback12345\r\nCommand authorization failed.\r\n\r\nAPG_6010_XPER(config)#end\r\n\r\nAPG_6010_XPER#show run | include Loopback12345|^ip_bgp\r\nAPG_6010_XPER#\r\nAPG_6010_XPER#show archive config differences nvram:startup-config\r\n\r\n!Contextual Config Diffs:\r\n!No changes were found\r\n```"},"comment":{"url":"https://api.github.com/repos/ansible/ansible/issues/comments/372043010","html_url":"https://github.com/ansible/ansible/issues/31575#issuecomment-372043010","issue_url":"https://api.github.com/repos/ansible/ansible/issues/31575","id":372043010,"user":{"login":"nickrusso42518","id":20440669,"avatar_url":"https://avatars3.githubusercontent.com/u/20440669?v=4","gravatar_id":"","url":"https://api.github.com/users/nickrusso42518","html_url":"https://github.com/nickrusso42518","followers_url":"https://api.github.com/users/nickrusso42518/followers","following_url":"https://api.github.com/users/nickrusso42518/following{/other_user}","gists_url":"https://api.github.com/users/nickrusso42518/gists{/gist_id}","starred_url":"https://api.github.com/users/nickrusso42518/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nickrusso42518/subscriptions","organizations_url":"https://api.github.com/users/nickrusso42518/orgs","repos_url":"https://api.github.com/users/nickrusso42518/repos","events_url":"https://api.github.com/users/nickrusso42518/events{/privacy}","received_events_url":"https://api.github.com/users/nickrusso42518/received_events","type":"User","site_admin":false},"created_at":"2018-03-10T16:33:45Z","updated_at":"2018-03-10T16:33:45Z","author_association":"NONE","body":"Just pulled latest devel which appears to be version 2.6. Perhaps this is not the version you'd like me to test, but in any case, I'll post my results. TL;DR it did not work.\r\n\r\n```\r\n[root@ip-10-125-0-100 ansible]# ansible --version\r\nansible 2.6.0\r\n  config file = /etc/ansible/ansible.cfg\r\n  configured module search path = [u'/usr/share/my_modules']\r\n  ansible python module location = /usr/lib/python2.7/site-packages/ansible\r\n  executable location = /bin/ansible\r\n  python version = 2.7.5 (default, May  3 2017, 07:55:04) [GCC 4.8.5 20150623 (Red Hat 4.8.5-14)]\r\n```\r\nHere is my simple playbook, which is logging into a Cisco CSR1000v.\r\n```\r\n[root@ip-10-125-0-100 ansible]# cat issue31575.yml \r\n---\r\n- hosts: CSR1\r\n  tasks:\r\n    - name: \"SYS >> Define router credentials\"\r\n      set_fact:\r\n        provider:\r\n          host: \"{{ inventory_hostname }}\" \r\n          username: \"ansible\"\r\n          password: \"ansible\"\r\n\r\n    - name: \"IOS >> Run show command from config mode\" \r\n      ios_config:\r\n        provider: \"{{ provider }}\"\r\n        commands: \"do show clock\"\r\n        match: none\r\n      register: output\r\n\r\n    - name: \"DEBUG >> Print output\"\r\n      debug:\r\n        var: output\r\n...\r\n```\r\nHere is the playbook execution. I used a little bit of debug to show what the module returns, and what the \"output\" dict contains. They are obviously the same, but no trace of Cisco CLI output.\r\n```\r\n[root@ip-10-125-0-100 ansible]# ansible-playbook issue31575.yml -v\r\nUsing /etc/ansible/ansible.cfg as config file\r\n\r\nPLAY [CSR1] **************************************************************************\r\n\r\nTASK [SYS >> Define router credentials] **********************************************\r\nok: [CSR1] => {\r\n    \"ansible_facts\": {\r\n        \"provider\": {\r\n            \"host\": \"CSR1\", \r\n            \"password\": \"ansible\", \r\n            \"username\": \"ansible\"\r\n        }\r\n    }, \r\n    \"changed\": false\r\n}\r\n\r\nTASK [IOS >> Run show command from config mode] **************************************\r\nchanged: [CSR1] => {\r\n    \"banners\": {}, \r\n    \"changed\": true, \r\n    \"commands\": [\r\n        \"do show clock\"\r\n    ], \r\n    \"updates\": [\r\n        \"do show clock\"\r\n    ]\r\n}\r\n\r\nTASK [DEBUG >> Print output] *******************************************************\r\nok: [CSR1] => {\r\n    \"output\": {\r\n        \"banners\": {}, \r\n        \"changed\": true, \r\n        \"commands\": [\r\n            \"do show clock\"\r\n        ], \r\n        \"failed\": false, \r\n        \"updates\": [\r\n            \"do show clock\"\r\n        ]\r\n    }\r\n}\r\n\r\nPLAY RECAP ***************************************************************************\r\nCSR1                       : ok=3    changed=1    unreachable=0    failed=0   \r\n```\r\nFurthermore, the documentation (http://docs.ansible.com/ansible/latest/ios_config_module.html) does not appear to reflect any kind of \"stdout\" or \"output\" being returned. This documentation would be for version 2.4.\r\n\r\nIs there a specific version you'd like me to test? The labels suggest 2.5.0, but please let me know. In the meantime, I'll try 2.4.2 which is the latest release, and post my results shortly.\r\n\r\nLast, in case there was any doubt that my test method is insufficient, I believe it should work fine.\r\n```\r\n[root@ip-10-125-0-100 ansible]# ssh ansible@CSR1\r\nPassword:  ansible\r\nRTR_CSR1#conf t\r\nEnter configuration commands, one per line.  End with CNTL/Z.\r\nRTR_CSR1(config)#do show clock\r\n16:32:39.057 UTC Sat Mar 10 2018\r\n```"}}
{"actor":{"display_login":"nickrusso42518"}}