# (c) 2018 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import absolute_import, division, print_function

__metaclass__ = type

DOCUMENTATION = """
author:
 - Ansible Networking Team (@ansible-network)
name: napalm
short_description: Provides persistent connection using NAPALM
description:
- This connection plugin provides connectivity to network devices using the NAPALM
  network device abstraction library.  This library requires certain features to be
  enabled on network devices depending on the destination device operating system.  The
  connection plugin requires C(napalm) to be installed locally on the Ansible controller.
version_added: 1.0.0
deprecated:
  alternative: network_cli
  why: I am pretty sure no one has ever tried to use these modules
  removed_at_date: '2022-06-01'
requirements:
- napalm
extends_documentation_fragment:
- ansible.netcommon.connection_persistent
options:
  host:
    description:
    - Specifies the remote device FQDN or IP address to establish the SSH connection
      to.
    default: inventory_hostname
    vars:
    - name: inventory_hostname
    - name: ansible_host
  port:
    type: int
    description:
    - Specifies the port on the remote device that listens for connections when establishing
      the SSH connection.
    default: 22
    ini:
    - section: defaults
      key: remote_port
    env:
    - name: ANSIBLE_REMOTE_PORT
    vars:
    - name: ansible_port
  network_os:
    description:
    - Configures the device platform network operating system.  This value is used
      to load a napalm device abstraction.
    vars:
    - name: ansible_network_os
  remote_user:
    description:
    - The username used to authenticate to the remote device when the SSH connection
      is first established.  If the remote_user is not specified, the connection will
      use the username of the logged in user.
    - Can be configured from the CLI via the C(--user) or C(-u) options.
    ini:
    - section: defaults
      key: remote_user
    env:
    - name: ANSIBLE_REMOTE_USER
    vars:
    - name: ansible_user
  password:
    description:
    - Configures the user password used to authenticate to the remote device when
      first establishing the SSH connection.
    vars:
    - name: ansible_password
    - name: ansible_ssh_pass
    - name: ansible_ssh_password
  private_key_file:
    description:
    - The private SSH key or certificate file used to authenticate to the remote device
      when first establishing the SSH connection.
    ini:
    - section: defaults
      key: private_key_file
    env:
    - name: ANSIBLE_PRIVATE_KEY_FILE
    vars:
    - name: ansible_private_key_file
  timeout:
    type: int
    description:
    - Sets the connection time, in seconds, for communicating with the remote device.  This
      timeout is used as the default timeout value for commands when issuing a command
      to the network CLI.  If the command does not return in timeout seconds, an error
      is generated.
    default: 120
  host_key_auto_add:
    type: boolean
    description:
    - By default, Ansible will prompt the user before adding SSH keys to the known
      hosts file. By enabling this option, unknown host keys will automatically be
      added to the known hosts file.
    - Be sure to fully understand the security implications of enabling this option
      on production systems as it could create a security vulnerability.
    default: false
    ini:
    - section: paramiko_connection
      key: host_key_auto_add
    env:
    - name: ANSIBLE_HOST_KEY_AUTO_ADD
"""

from ansible.errors import AnsibleConnectionFailure, AnsibleError
from ansible.module_utils.basic import missing_required_lib
from ansible_collections.ansible.netcommon.plugins.plugin_utils.connection_base import (
    NetworkConnectionBase,
)

try:
    from napalm import get_network_driver
    from napalm.base import ModuleImportError

    HAS_NAPALM = True
except ImportError:
    HAS_NAPALM = False


class Connection(NetworkConnectionBase):
    """Napalm connections"""

    transport = "ansible.netcommon.napalm"
    has_pipelining = False

    def __init__(self, play_context, new_stdin, *args, **kwargs):
        super(Connection, self).__init__(
            play_context, new_stdin, *args, **kwargs
        )

        self.napalm = None

    def _connect(self):
        if not HAS_NAPALM:
            raise AnsibleError(missing_required_lib("napalm"))

        super(Connection, self)._connect()

        if not self.connected:
            if not self._network_os:
                raise AnsibleConnectionFailure(
                    "Unable to automatically determine host network os. Please "
                    "manually configure ansible_network_os value for this host"
                )
            self.queue_message(
                "log", "network_os is set to %s" % self._network_os
            )

            try:
                driver = get_network_driver(self._network_os)
            except ModuleImportError:
                raise AnsibleConnectionFailure(
                    "Failed to import napalm driver for {0}".format(
                        self._network_os
                    )
                )

            host = self.get_option("host")
            self.napalm = driver(
                hostname=host,
                username=self.get_option("remote_user"),
                password=self.get_option("password"),
                timeout=self.get_option("persistent_command_timeout"),
            )

            self.napalm.open()

            self._sub_plugin = {"name": "napalm", "obj": self.napalm}
            self.queue_message(
                "vvvv",
                "created napalm device for network_os %s" % self._network_os,
            )
            self._connected = True

    def close(self):
        if self.napalm:
            self.napalm.close()
            self.napalm = None

        super(Connection, self).close()
