# Path: shakedown/dcos/helpers.py
# def validate_key(key_path):
#     """ Validate a key
# 
#         :param key_path: path to a key to use for authentication
#         :type key_path: str
# 
#         :return: key object used for authentication
#         :rtype: paramiko.RSAKey
#     """
# 
#     key_path = os.path.expanduser(key_path)
# 
#     if not os.path.isfile(key_path):
#         return False
# 
#     return paramiko.RSAKey.from_private_key_file(key_path)
# 
# def try_close(obj):
#     try:
#         obj.close()
#     except:
#         pass
# 
# def get_transport(host, username, key):
#     """ Create a transport object
# 
#         :param host: the hostname to connect to
#         :type host: str
#         :param username: SSH username
#         :type username: str
#         :param key: key object used for authentication
#         :type key: paramiko.RSAKey
# 
#         :return: a transport object
#         :rtype: paramiko.Transport
#     """
# 
#     if host == shakedown.master_ip():
#         transport = paramiko.Transport(host)
#     else:
#         transport_master = paramiko.Transport(shakedown.master_ip())
#         transport_master = start_transport(transport_master, username, key)
# 
#         if not transport_master.is_authenticated():
#             print("error: unable to authenticate {}@{} with key {}".format(username, shakedown.master_ip(), key))
#             return False
# 
#         try:
#             channel = transport_master.open_channel('direct-tcpip', (host, 22), ('127.0.0.1', 0))
#         except paramiko.SSHException:
#             print("error: unable to connect to {}".format(host))
#             return False
# 
#         transport = paramiko.Transport(channel)
# 
#     return transport
# 
# def start_transport(transport, username, key):
#     """ Begin a transport client and authenticate it
# 
#         :param transport: the transport object to start
#         :type transport: paramiko.Transport
#         :param username: SSH username
#         :type username: str
#         :param key: key object used for authentication
#         :type key: paramiko.RSAKey
# 
#         :return: the transport object passed
#         :rtype: paramiko.Transport
#     """
# 
#     transport.start_client()
# 
#     agent = paramiko.agent.Agent()
#     keys = itertools.chain((key,) if key else (), agent.get_keys())
#     for test_key in keys:
#         try:
#             transport.auth_publickey(username, test_key)
#             break
#         except paramiko.AuthenticationException as e:
#             pass
#     else:
#         raise ValueError('No valid key supplied')
# 
#     return transport


import shlex
import subprocess
import time
import paramiko
import shakedown
from _thread import RLock
from functools import wraps
from select import select
from dcos.errors import DCOSException
from .helpers import validate_key, try_close, get_transport, start_transport
                del cache[key]

        # key is not in the cache, so try to recreate it
        # it may have been removed just above.
        if key not in cache:
            conn = func(host, username, *args, **kwargs)
            if conn is not None:
                cache[key] = conn
            return conn

        # not sure how to reach this point, but just in case.
        return None

    def get_cache() -> dict:
        return cache

    def purge(key: str=None):
        with lock:
            if key is None:
                conns = [(k, v) for k, v in cache.items()]
            elif key in cache:
                conns = ((key, cache[key]), )
            else:
                conns = list()

            for k, v in conns:
                try_close(v)
                del cache[k]

    func_wrapper.get_cache = get_cache

# Path: shakedown/dcos/helpers.py
# def validate_key(key_path):
#     """ Validate a key
# 
#         :param key_path: path to a key to use for authentication
#         :type key_path: str
# 
#         :return: key object used for authentication
#         :rtype: paramiko.RSAKey
#     """
# 
#     key_path = os.path.expanduser(key_path)
# 
#     if not os.path.isfile(key_path):
#         return False
# 
#     return paramiko.RSAKey.from_private_key_file(key_path)
# 
# def try_close(obj):
#     try:
#         obj.close()
#     except:
#         pass
# 
# def get_transport(host, username, key):
#     """ Create a transport object
# 
#         :param host: the hostname to connect to
#         :type host: str
#         :param username: SSH username
#         :type username: str
#         :param key: key object used for authentication
#         :type key: paramiko.RSAKey
# 
#         :return: a transport object
#         :rtype: paramiko.Transport
#     """
# 
#     if host == shakedown.master_ip():
#         transport = paramiko.Transport(host)
#     else:
#         transport_master = paramiko.Transport(shakedown.master_ip())
#         transport_master = start_transport(transport_master, username, key)
# 
#         if not transport_master.is_authenticated():
#             print("error: unable to authenticate {}@{} with key {}".format(username, shakedown.master_ip(), key))
#             return False
# 
#         try:
#             channel = transport_master.open_channel('direct-tcpip', (host, 22), ('127.0.0.1', 0))
#         except paramiko.SSHException:
#             print("error: unable to connect to {}".format(host))
#             return False
# 
#         transport = paramiko.Transport(channel)
# 
#     return transport
# 
# def start_transport(transport, username, key):
#     """ Begin a transport client and authenticate it
# 
#         :param transport: the transport object to start
#         :type transport: paramiko.Transport
#         :param username: SSH username
#         :type username: str
#         :param key: key object used for authentication
#         :type key: paramiko.RSAKey
# 
#         :return: the transport object passed
#         :rtype: paramiko.Transport
#     """
# 
#     transport.start_client()
# 
#     agent = paramiko.agent.Agent()
#     keys = itertools.chain((key,) if key else (), agent.get_keys())
#     for test_key in keys:
#         try:
#             transport.auth_publickey(username, test_key)
#             break
#         except paramiko.AuthenticationException as e:
#             pass
#     else:
#         raise ValueError('No valid key supplied')
# 
#     return transport


# Path: shakedown/dcos/command.py
import shlex
import subprocess
import time
import paramiko
import shakedown
from _thread import RLock
from functools import wraps
from select import select
from dcos.errors import DCOSException
from .helpers import validate_key, try_close, get_transport, start_transport

                del cache[key]

        # key is not in the cache, so try to recreate it
        # it may have been removed just above.
        if key not in cache:
            conn = func(host, username, *args, **kwargs)
            if conn is not None:
                cache[key] = conn
            return conn

        # not sure how to reach this point, but just in case.
        return None

    def get_cache() -> dict:
        return cache

    def purge(key: str=None):
        with lock:
            if key is None:
                conns = [(k, v) for k, v in cache.items()]
            elif key in cache:
                conns = ((key, cache[key]), )
            else:
                conns = list()

            for k, v in conns:
                try_close(v)
                del cache[k]

    func_wrapper.get_cache = get_cache

    func_wrapper.purge = purge