def test_connect_does_not_prompt_password_when_ssh_raises_channel_exception( self): def raise_channel_exception_once(*args, **kwargs): if raise_channel_exception_once.should_raise_channel_exception: raise_channel_exception_once.should_raise_channel_exception = False raise ssh.ChannelException(2, 'Connect failed') raise_channel_exception_once.should_raise_channel_exception = True def generate_fake_client(): fake_client = Fake('SSHClient', allows_any_call=True, expect_call=True) fake_client.provides('connect').calls(raise_channel_exception_once) return fake_client fake_ssh = Fake('ssh', allows_any_call=True) fake_ssh.provides('SSHClient').calls(generate_fake_client) # We need the real exceptions here to preserve the inheritence structure fake_ssh.SSHException = ssh.SSHException fake_ssh.ChannelException = ssh.ChannelException patched_connect = patch_object('fabric.network', 'ssh', fake_ssh) patched_password = patch_object( 'fabric.network', 'prompt_for_password', Fake('prompt_for_password', callable=True).times_called(0)) try: connect('user', 'localhost', 22, HostConnectionCache()) finally: # Restore ssh patched_connect.restore() patched_password.restore()
def parallel_task_target(task, args, kwargs, env, queue): """ Wrap in another callable that: * nukes the connection cache to prevent shared-access problems * knows how to send the tasks' return value back over a Queue * captures exceptions raised by the task """ from fabric import state as _state from fabric.network import HostConnectionCache # Reset all connections from pre-fork _state.connections = HostConnectionCache() def submit(result): queue.put({'name': env.host_string, 'result': result}) try: with settings(**env): submit(task.run(*args, **kwargs)) except BaseException, e: # We really do want to capture everything # SystemExit implies use of abort(), which prints its own # traceback, host info etc -- so we don't want to double up # on that. For everything else, though, we need to make # clear what host encountered the exception that will # print. if e.__class__ is not SystemExit: print >> sys.stderr, "!!! Parallel execution exception under host %r:" % env.host_string submit(e) # Here, anything -- unexpected exceptions, or abort() # driven SystemExits -- will bubble up and terminate the # child process. raise
def disconnect(): yield host = env.host_string if host and host in connections: normalized_host = normalize(host) connections[host].get_transport().close() connect(normalized_host[0], normalized_host[1], normalized_host[2], HostConnectionCache())
def wcl(self): with closing( connect(self.user, self.host, self.port, HostConnectionCache())) as ssh: stdin, stdout, stderr = ssh.exec_command('wc -l %s' % self.filename) return int( stdout.readlines()[0].split()[0]) - (1 if self.header else 0)
def test_aborts_on_password_prompt_with_abort_on_prompt(self): """ abort_on_prompt=True should abort when password prompts occur """ env.password = None env.abort_on_prompts = True with password_response(PASSWORDS[env.user], times_called=1): cache = HostConnectionCache() cache[env.host_string]
def rowns(self): with closing( connect(self.user, self.host, self.port, HostConnectionCache())) as ssh: stdin, stdout, stderr = ssh.exec_command( 'awk \'BEGIN{FS="%s"}{print $1}\' %s%s' % (self.sep, self.filename, '' if not self.header else ' | tail -n +2')) return [x.strip() for x in stdout.readlines()]
def open(self, return_header=True): with closing( connect(self.user, self.host, self.port, HostConnectionCache())) as ssh: with closing(ssh.open_sftp()) as sftp: with closing(sftp.open(self.filename)) as f: if not return_header: line = f.readline() for line in f: yield line
def test_saved_authentication_returns_client_object(): # Fake client whose connect() doesn't raise any errors. # Note that we don't need verify/clear_calls/etc as this Fake isn't # expecting anything. f = (Fake('SSHClient').provides('__init__').provides('connect').provides( 'load_system_host_keys').provides('set_missing_host_key_policy')) with patched_context('paramiko', 'SSHClient', f): # Any connection attempts will "succeed" and return the client object cache = HostConnectionCache() eq_(cache['localhost'], f)
def check_connection_calls(host_strings, num_calls): # Clear Fudge call stack # Patch connect() with Fake obj set to expect num_calls calls patched_connect = patch_object('fabric.network', 'connect', Fake('connect', expect_call=True).times_called(num_calls) ) try: # Make new cache object cache = HostConnectionCache() # Connect to all connection strings for host_string in host_strings: # Obtain connection from cache, potentially calling connect() cache[host_string] finally: # Restore connect() patched_connect.restore()
def test_connection_cache_deletion(self): """ HostConnectionCache should delete correctly w/ non-full keys """ hcc = HostConnectionCache() fake = Fake('connect', callable=True) with patched_context('fabric.network', 'connect', fake): for host_string in ('hostname', 'user@hostname', 'user@hostname:222'): # Prime hcc[host_string] # Test ok_(host_string in hcc) # Delete del hcc[host_string] # Test ok_(host_string not in hcc)
def test_prompts_for_password_without_good_authentication(): # Fake client whose connect() raises an AuthenticationException on first # call, mimicing behavior when auth is bad or doesn't exist yet f = (Fake('SSHClient').provides('__init__').provides('connect').raises( paramiko.AuthenticationException).next_call().returns(True).provides( 'load_system_host_keys').provides('set_missing_host_key_policy')) with patched_context('paramiko', 'SSHClient', f): # Fake builtin getpass() method which expects to be called once f2 = Fake('getpass', expect_call=True).times_called(1).returns('passwd') with patched_context('getpass', 'getpass', f2): try: # Connect attempt will result in getpass() being called cache = HostConnectionCache() cache['localhost'] verify() finally: clear_expectations()
for option in env_options: env[option.dest] = option.default # # Command dictionary # # Keys are the command/function names, values are the callables themselves. # This is filled in when main() runs. commands = {} # # Host connection dict/cache # connections = HostConnectionCache() def _open_session(): return connections[env.host_string].get_transport().open_session() def default_channel(): """ Return a channel object based on ``env.host_string``. """ try: chan = _open_session() except ssh.SSHException as err: if str(err) == 'SSH session not active': connections[env.host_string].close()
def test_prompts_for_password_without_good_authentication(self): env.password = None with password_response(PASSWORDS[env.user], times_called=1): cache = HostConnectionCache() cache[env.host_string]
def test_saved_authentication_returns_client_object(self): cache = HostConnectionCache() assert isinstance(cache[env.host_string], paramiko.SSHClient)
def test_aborts_on_password_prompt_with_abort_on_prompt(self): env.password = None env.prompt = False with password_response(PASSWORDS[env.user], times_called=1): cache = HostConnectionCache() cache[env.host_string]