From 94df740ca347bdc080a52579aadf34139814bab2 Mon Sep 17 00:00:00 2001
From: Senthil Kumar Ganesan <skg.net.dev@gmail.com>
Date: Thu, 8 Sep 2016 22:55:31 -0700
Subject: [PATCH 1/2] Added support for dnos6_command module

---
 CHANGELOG.md                                  |  3 +
 lib/ansible/module_utils/dnos6.py             | 95 +++++++++++++++++++
 .../utils/module_docs_fragments/dnos6.py      | 86 +++++++++++++++++
 3 files changed, 184 insertions(+)
 create mode 100644 lib/ansible/module_utils/dnos6.py
 create mode 100644 lib/ansible/utils/module_docs_fragments/dnos6.py

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 65168efed0b..8e670afb33b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -73,6 +73,9 @@ Ansible Changes By Release
 - exoscale:
   * exo_dns_domain
   * exo_dns_record
+- dnos6
+  * dnos6_command
+
 - f5:
   * bigip_device_dns
   * bigip_device_ntp
diff --git a/lib/ansible/module_utils/dnos6.py b/lib/ansible/module_utils/dnos6.py
new file mode 100644
index 00000000000..9b5e95ea46f
--- /dev/null
+++ b/lib/ansible/module_utils/dnos6.py
@@ -0,0 +1,95 @@
+# 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.
+#
+# 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.
+#
+
+import re
+
+from ansible.module_utils.shell import CliBase
+from ansible.module_utils.network import Command, register_transport, to_list
+from ansible.module_utils.netcfg import NetworkConfig
+
+def get_config(module):
+    contents = module.params['running_config']
+    if not contents:
+        contents = module.cli('show running-config all')[0]
+        module.params['running_config'] = contents
+
+    return NetworkConfig(indent=1, contents=contents)
+
+
+class Cli(CliBase):
+
+    NET_PASSWD_RE = re.compile(r"[\r\n]?password:\s?$", re.I)
+
+    CLI_PROMPTS_RE = [
+        re.compile(r"[\r\n]?[\w+\-\.:\/\[\]]+(?:\([^\)]+\)){,3}(?:>|#) ?$"),
+        re.compile(r"\[\w+\@[\w\-\.]+(?: [^\]])\] ?[>#\$] ?$")
+    ]
+
+    CLI_ERRORS_RE = [
+        re.compile(r"% ?Error"),
+        re.compile(r"% ?Bad secret"),
+        re.compile(r"invalid input", re.I),
+        re.compile(r"(?:incomplete|ambiguous) command", re.I),
+        re.compile(r"connection timed out", re.I),
+        re.compile(r"[^\r\n]+ not found", re.I),
+        re.compile(r"'[^']' +returned error code: ?\d+"),
+    ]
+
+
+    def connect(self, params, **kwargs):
+        super(Cli, self).connect(params, kickstart=False, **kwargs)
+
+
+    def authorize(self, params, **kwargs):
+        passwd = params['auth_pass']
+        self.run_commands(
+            Command('enable', prompt=self.NET_PASSWD_RE, response=passwd)
+        )
+        self.run_commands('terminal length 0')
+
+
+    def configure(self, commands, **kwargs):
+        cmds = ['configure terminal']
+        cmds.extend(to_list(commands))
+        cmds.append('end')
+        responses = self.execute(cmds)
+        responses.pop(0)
+        return responses
+
+
+    def get_config(self, **kwargs):
+        return self.execute(['show running-config'])
+
+
+    def load_config(self, commands, **kwargs):
+        return self.configure(commands)
+
+
+    def save_config(self):
+        self.execute(['copy running-config startup-config'])
+
+
+Cli = register_transport('cli', default=True)(Cli)
diff --git a/lib/ansible/utils/module_docs_fragments/dnos6.py b/lib/ansible/utils/module_docs_fragments/dnos6.py
new file mode 100644
index 00000000000..9dde0094c21
--- /dev/null
+++ b/lib/ansible/utils/module_docs_fragments/dnos6.py
@@ -0,0 +1,86 @@
+# 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/>.
+
+
+class ModuleDocFragment(object):
+
+    # Standard files documentation fragment
+    DOCUMENTATION = """
+options:
+  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.
+    required: true
+  port:
+    description:
+      - Specifies the port to use when building the connection to the remote
+        device.
+    required: false
+    default: 22
+  username:
+    description:
+      - This value I(username) is used to authenticate the SSH session to the
+        remote device. If the value is not specified in the task, the
+        value of environment variable ANSIBLE_NET_USERNAME will be used instead.
+    required: false
+  password:
+    description:
+      - This value I(password) is used to authenticate the SSH session to 
+        the remote device. If the value is not specified in the task, the
+        value of environment variable ANSIBLE_NET_PASSWORD will be used instead.
+    required: false
+    default: null
+  ssh_keyfile:
+    description:
+      - This value I(ssh_keyfile) is the path to the key used to authenticate 
+        the SSH session to the remote device.  If the value is not specified
+        in the task, the value of environment variable ANSIBLE_NET_SSH_KEYFILE
+        will be used instead.
+    required: false
+  authorize:
+    description:
+      - Instructs the module to enter priviledged mode on the remote device
+        before sending any commands.  If not specified, the device will
+        attempt to excecute all commands in non-priviledged mode. If the value
+        is not specified in the task, the value of environment variable
+        ANSIBLE_NET_AUTHORIZE will be used instead.
+    required: false
+    default: no
+    choices: ['yes', 'no']
+  auth_pass:
+    description:
+      - Specifies the password to use if required to enter privileged mode
+        on the remote device.  If I(authorize) is false, then this argument
+        does nothing. If the value is not specified in the task, the value of
+        environment variable ANSIBLE_NET_AUTH_PASS will be used instead.
+    required: false
+    default: none
+  timeout:
+    description:
+      - Specifies idle timeout (in seconds) for the connection. Useful if the
+        console freezes before continuing. For example when saving
+        configurations.
+    required: false
+    default: 10
+  provider:
+    description:
+      - Convenience method that allows all M(dnos6) arguments to be passed as
+        a dict object.  All constraints (required, choices, etc) must be
+        met either by individual arguments or values in this dict.
+    required: false
+    default: null
+"""

From 05e016e4aa15e792e40a2bde6d8816096a7aa40b Mon Sep 17 00:00:00 2001
From: Senthil Kumar Ganesan <skg.net.dev@gmail.com>
Date: Fri, 9 Sep 2016 10:03:05 -0700
Subject: [PATCH 2/2] Addressed @gundalow review comments

---
 CHANGELOG.md                                  |  1 -
 .../utils/module_docs_fragments/dnos6.py      | 19 +++++++++----------
 2 files changed, 9 insertions(+), 11 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8e670afb33b..5c7e310392f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -75,7 +75,6 @@ Ansible Changes By Release
   * exo_dns_record
 - dnos6
   * dnos6_command
-
 - f5:
   * bigip_device_dns
   * bigip_device_ntp
diff --git a/lib/ansible/utils/module_docs_fragments/dnos6.py b/lib/ansible/utils/module_docs_fragments/dnos6.py
index 9dde0094c21..28d732add37 100644
--- a/lib/ansible/utils/module_docs_fragments/dnos6.py
+++ b/lib/ansible/utils/module_docs_fragments/dnos6.py
@@ -33,23 +33,22 @@ options:
     default: 22
   username:
     description:
-      - This value I(username) is used to authenticate the SSH session to the
-        remote device. If the value is not specified in the task, the
-        value of environment variable ANSIBLE_NET_USERNAME will be used instead.
+      - User to authenticate the SSH session to the remote device. If the
+        value is not specified in the task, the value of environment variable
+        ANSIBLE_NET_USERNAME will be used instead.
     required: false
   password:
     description:
-      - This value I(password) is used to authenticate the SSH session to 
-        the remote device. If the value is not specified in the task, the
-        value of environment variable ANSIBLE_NET_PASSWORD will be used instead.
+      - Password to authenticate the SSH session to the remote device. If the
+        value is not specified in the task, the value of environment variable
+        ANSIBLE_NET_PASSWORD will be used instead.
     required: false
     default: null
   ssh_keyfile:
     description:
-      - This value I(ssh_keyfile) is the path to the key used to authenticate 
-        the SSH session to the remote device.  If the value is not specified
-        in the task, the value of environment variable ANSIBLE_NET_SSH_KEYFILE
-        will be used instead.
+      - Path to an ssh key used to authenticate the SSH session to the remote
+        device.  If the value is not specified in the task, the value of
+        environment variable ANSIBLE_NET_SSH_KEYFILE will be used instead.
     required: false
   authorize:
     description: