def test_add_to_known_hosts_dry(self, mock_popen): hosts = [ msshcopyid.Host(hostname='server1'), msshcopyid.Host(hostname='server2'), msshcopyid.Host(hostname='server3') ] known_hosts = MagicMock() server1_ssh_key = 'server1 ssh-rsa KRDZhqpguSRxeiqLseaD' server2_ssh_key = 'server2 ssh-rsa AAAAB3NzaC1yc2EAAAAB' server3_ssh_key = 'server3 ssh-rsa O2gDXC6h6QDXCaHo6pOH' server4_ssh_key = 'server4 ssh-rsa hdHWpZ8fDvQArTUFCfgU' keyscans = [server2_ssh_key, server3_ssh_key, server1_ssh_key] mock_popen.return_value.communicate.return_value = ( '\n'.join(keyscans), MagicMock()) known_hosts_content = [server1_ssh_key, server4_ssh_key] mock_bopen = mock_open(read_data='\n'.join(known_hosts_content)) with patch('msshcopyid.open', mock_bopen): self.sshcopyid.add_to_known_hosts(hosts, known_hosts=known_hosts, dry=True) mock_bopen.return_value.writelines.assert_not_called()
def test_remove_from_known_hosts_error(self, mock_logger, mock_check_call, mock_format_error, mock_format_exception): hosts = [ msshcopyid.Host(hostname='server1'), msshcopyid.Host(hostname='server2'), msshcopyid.Host(hostname='server3') ] known_hosts = '/path/to/known_hosts' cmds = [] check_call_side_effect = [] for host in hosts: cmd = ['ssh-keygen', '-f', known_hosts, '-R', host.hostname] cmds.append(cmd) check_call_side_effect.append(subprocess.CalledProcessError( 1, cmd)) mock_check_call.side_effect = check_call_side_effect self.sshcopyid.remove_from_known_hosts(hosts, known_hosts=known_hosts, dry=False) for cmd, ex in zip(cmds, check_call_side_effect): mock_check_call.assert_any_call(cmd) mock_logger.error.assert_any_call( mock_format_error(mock_format_exception(ex)))
def test_remove_from_known_hosts_dry(self, mock_check_call): hosts = [ msshcopyid.Host(hostname='server1'), msshcopyid.Host(hostname='server2'), msshcopyid.Host(hostname='server3') ] known_hosts = '/path/to/known_hosts' self.sshcopyid.remove_from_known_hosts(hosts, known_hosts=known_hosts, dry=True) mock_check_call.assert_not_called()
def test_remove_from_known_hosts(self, mock_check_call): hosts = [ msshcopyid.Host(hostname='server1'), msshcopyid.Host(hostname='server2'), msshcopyid.Host(hostname='server3') ] known_hosts = '/path/to/known_hosts' self.sshcopyid.remove_from_known_hosts(hosts, known_hosts=known_hosts, dry=False) for host in hosts: cmd = ['ssh-keygen', '-f', known_hosts, '-R', host.hostname] mock_check_call.assert_any_call(cmd)
def test_copy_ssh_keys_to_host_wrong_password(self, mock_ssh_client, mock_auto_add_policy, mock_isfile): host = msshcopyid.Host(hostname='server1', port=12345, user='******', password='******') known_hosts = MagicMock() client = mock_ssh_client.return_value auth_exception = paramiko.ssh_exception.AuthenticationException( 'authentication exception') client.connect.side_effect = auth_exception self.sshcopyid.priv_key = MagicMock() self.sshcopyid.pub_key_content = 'ssh-rsa AAAAB3NzaC1yc2EAAAAD' password = None with self.assertRaises(paramiko.ssh_exception.SSHException) as exctx: self.sshcopyid.copy_ssh_keys_to_host(host, password=password, no_add_host=True, known_hosts=known_hosts) self.assertEqual(exctx.exception, auth_exception) client.set_missing_host_key_policy.assert_not_called() client.connect.assert_called_once_with( host.hostname, port=host.port, username=host.user, password=password, key_filename=self.sshcopyid.priv_key) client.exec_command.assert_not_called()
def test_copy_ssh_keys_to_host(self, mock_ssh_client, mock_auto_add_policy, mock_isfile): host = msshcopyid.Host(hostname='server1', port=12345, user='******', password='******') known_hosts = MagicMock() self.sshcopyid.priv_key = MagicMock() self.sshcopyid.pub_key_content = 'ssh-rsa AAAAB3NzaC1yc2EAAAAD' password = None self.sshcopyid.copy_ssh_keys_to_host(host, password=password, no_add_host=False, known_hosts=known_hosts) client = mock_ssh_client.return_value client.set_missing_host_key_policy.assert_called_once_with( mock_auto_add_policy.return_value) client.connect.assert_called_once_with( host.hostname, port=host.port, username=host.user, password=password, key_filename=self.sshcopyid.priv_key) cmd = (r'''mkdir -p ~/.ssh && chmod 700 ~/.ssh && \ k='{0}' && if ! grep -qFx "$k" ~/.ssh/authorized_keys; then echo "$k" >> ~/.ssh/authorized_keys; fi''' .format(self.sshcopyid.pub_key_content)) client.exec_command.assert_called_once_with(cmd)
def parse_hosts(hosts, ssh_port=None, ssh_config=None): """ Parse a list of hosts (string) and return a list of `msshcopyid.Host` objects. The information about the host are taken in this order of priority: - host: - from the host (string) itself. - user: - from the host (string) itself. - from the `paramiko.config.SSHConfig` object. - current logged user. - port: - from the function argument `port`. - from the `paramiko.config.SSHConfig` object. - default SSH port: 22 :param hosts: list of hosts (string). Eg: ['server1', 'user1@server2'] :param ssh_config: a `paramiko.config.SSHConfig` object. :return: a list of `msshcopyid.Host` objects. """ host_list = [] # list of Host objects current_user = getpass.getuser() for host in hosts: # host_info = {'hostname': 'server1', 'hashknownhosts': 'no', 'user': '******'} if ssh_config is not None: host_info = ssh_config.lookup(host) else: host_info = {} # hostname & user if '@' in host: user, hostname = host.split('@', 1) else: hostname = host user = host_info.get('user', current_user) # port port = ssh_port or host_info.get('port', DEFAULT_SSH_PORT) host_list.append( msshcopyid.Host(hostname=hostname, port=port, user=user)) return host_list