My Python application connects to a MSSQL database to verify some matter numbers, but this step is only necessary to assist with data integrity and does not bring the user any additional functionality.
The database is only accessible when on my office's local network. How do I check a user's environment during startup to see if this connection can be made?
I'm using pyodbc, but I also need this program to work on OS X, so I'm not importing that module until this check returns a positive result. Any ideas?
You could try something like this:
#!/usr/bin/python
import socket
mssql_server = 'foobar.example.not' # set this to your own value
s = socket.socket()
s.settimeout(3)
try:
server = [x for x in socket.getaddrinfo(mssql_server,1433) if x[0]==2 ][0][-1]
except socket.gaierror:
server = None
if server:
try:
s.connect(server)
except (socket.timeout, socket.error):
server = None
s.close()
... this should attempt to find an IPv4 address for your server (using the first one returned by getaddrinfo()) and then attempt to connect to the MS SQL TCP port (1433 by default) on that system. (Yes, change 1433 if your server is on a different port). If there's a timeout or any other socket error reported on the attempt, then server is set to None. Otherwise you probably have an MS SQL server that you could access.
Verify the host is available using ping before import:
import subprocess
host = "<hostname>"
# add sample text for ping resolution errors here
errors = ("could not find", "unreachable")
ping = "ping {0}".format(host)
(stdout, stderr) = subprocess.Popen(ping, stdout=subprocess.PIPE).communicate()
# stdout is a byte string and must be decoded before compare
if not any(error in stdout.decode("utf-8") for error in errors):
import pyodbc
.....
Related
Using python 3.10.10 on Windows 10 I am trying to connect to a mongo database via ssh ideally. On the command line I just do
ssh myuser#111.222.333.444
mongo
and I can query the mongo DB. With the following python code
from pymongo import MongoClient
from pymongo.errors import ConnectionFailure
HOST = "111.222.333.444"
USER = "myuser"
class Mongo:
def __init__(self):
self.host = HOST
self.user = USER
self.uri = f"mongodb://{self.user}#{self.host}"
def connection(self):
try:
client = MongoClient(self.uri)
client.server_info()
print('Connection Established')
except ConnectionFailure as err:
raise(err)
return client
mongo = Mongo()
mongo.connection()
however I get an error
pymongo.errors.ConfigurationError: A password is required.
But as I am able to just login via ssh using my public key I do not require a password. How can this be solved in python?
I also tried to run a command on the command line using ssh alone like
ssh myuser#111.222.333.444 "mongo;use mydb; show collections"
but this does not work like that either.
You do two different things. In the first command you connect via ssh (using port 22) to the remote server. On the remote server you start the mongo shell. In the second command, you try to connect directly to the mongod server (default port 27017).
In your case myuser is the user on remote server operating system, not the user on the MongoDB.
You can (almost) always connect to a MongoDB without username/password, however when you provide a username then you also need a password. Try
self.uri = f"mongodb://{self.host}"
It is not fully clear what you try to achieve. You can configure MongoDB to logon with x509 certificate instead of username/password, see Use x.509 Certificates to Authenticate Clients. These connections are also encrypted via TLS/SSL.
Or are you looking to configure a SSH-Tunnel? See https://serverfault.com/questions/597765/how-to-connect-to-mongodb-server-via-ssh-tunnel
Here is the solution that I found in the end, as simple as possible, and it can be run from within python, and without any special module to install, from a windows powershell:
import json
import subprocess
cmd_mongo = json.dumps('db.units.find({"UnitId": "971201065"})')
cmd_host = json.dumps(f"mongo mydb --eval {cmd_mongo}")
cmd_local = f"ssh {USER}#{HOST} \"{cmd_host}\""
output = subprocess.check_output(cmd_local, shell=True)
print(output)
My requirement is ability to run a PowerShell script on a Windows 2012 server remotely, this has to be triggered from a Linux server using Python script.
Need suggestions on best way to handle this and also sample code (if possible).
Below are the steps I intend to achieve but i see it's not working as expected.
PowerShell scripts to be executed are already placed in Windows server (2012).
Python3 program running on Linux (CentOS) does SSH to Windows server (2012) using netmiko module.
sends the command (PowerShell command to execute script in remote Windows server) over the SSH connection.
I was able to connect to the remote Windows server using Python. But I don't see this method working as expected.
Need an effective and efficient way to achieve this.
from netmiko import ConnectHandler
device = ConnectHandler(device_type="terminal_server",
ip="X.X.X.x",
username="username",
password="password")
hostname = device.find_prompt()
output = device.send_command("ipconfig")
print (hostname)
print (output)
device.disconnect()
Nothing much is done for 'terminal_server" device type. You have to do manual passing at the moment.
Below is extracted from COMMON_ISSUES.md
Does Netmiko support connecting via a terminal server?
There is a 'terminal_server' device_type that basically does nothing post SSH connect. This means you have to manually handle the interaction with the terminal server to connect to the end device. After you are fully connected to the end network device, you can then 'redispatch' and Netmiko will behave normally
from __future__ import unicode_literals, print_function
import time
from netmiko import ConnectHandler, redispatch
net_connect = ConnectHandler(
device_type='terminal_server', # Notice 'terminal_server' here
ip='10.10.10.10',
username='admin',
password='admin123',
secret='secret123')
# Manually handle interaction in the Terminal Server
# (fictional example, but hopefully you see the pattern)
# Send Enter a Couple of Times
net_connect.write_channel("\r\n")
time.sleep(1)
net_connect.write_channel("\r\n")
time.sleep(1)
output = net_connect.read_channel()
print(output) # Should hopefully see the terminal server prompt
# Login to end device from terminal server
net_connect.write_channel("connect 1\r\n")
time.sleep(1)
# Manually handle the Username and Password
max_loops = 10
i = 1
while i <= max_loops:
output = net_connect.read_channel()
if 'Username' in output:
net_connect.write_channel(net_connect.username + '\r\n')
time.sleep(1)
output = net_connect.read_channel()
# Search for password pattern / send password
if 'Password' in output:
net_connect.write_channel(net_connect.password + '\r\n')
time.sleep(.5)
output = net_connect.read_channel()
# Did we successfully login
if '>' in output or '#' in output:
break
net_connect.write_channel('\r\n')
time.sleep(.5)
i += 1
# We are now logged into the end device
# Dynamically reset the class back to the proper Netmiko class
redispatch(net_connect, device_type='cisco_ios')
# Now just do your normal Netmiko operations
new_output = net_connect.send_command("show ip int brief")
I am trying to ssh to a test cisco router in a test environment using python paramiko, and run cisco commands in that test router.
Everything works great except for 1 small detail.
After running the script I want the ssh session to remain open. (so I can run other commands manually).
I want to keep the ssh session open until I type "exit"
I found another link with a similar issue but I cant understand the solution.
(See here Python ssh - keep connection open after script terminates)
I would appreciate if someone can help me out here
My code
import paramiko
import time
def ssh_session(ip):
try:
session = paramiko.SSHClient() #Open the session
session.set_missing_host_key_policy(paramiko.AutoAddPolicy())
session.connect(ip, username = "ciscouser1", password = "password")
connection = session.invoke_shell()
####Running Cisco IOS commands###
connection.send("enable\n")
connection.send("password1") #sending
connection.send("\n")
connection.send("configure terminal\n\n")
time.sleep(1)
connection.send("do show ip int brief\n")
time.sleep(1)
except paramiko.AuthenticationException:
print "wrong credentials"
ssh_session("10.10.10.1")
The session timeout would be controlled by the SSH server. To the best of my knowledge, the only way to keep your session alive on the client side is to not be inactive, which can be accomplished by sending null packets. As to how to do this specifically with paramiko I am not certain. Perhaps you could send some kind of dummy command (or maybe even an empty string?) every so often?
If I run this code:
import sshtunnel
try:
with sshtunnel.open_tunnel("hello", ssh_username="user",
ssh_password="PASSWORD",
remote_bind_address=("1.2.3.4", 23)) as server:
pass
except:
pass
I get this:
2016-04-06 10:47:53,006 | ERROR | Could not resolve IP address for hello, aborting!
I am ignoring the exception, but some random line is showing up for some reason. Why? Is this just some random print statement in some library somewhere? Is this common? Seems like libraries shouldn't really be printing anything to the screen directly. How do I suppress this line?
PS. Code meant to simply replicate the error - obviously using a catch-all for exceptions and doing nothing with them is bad
That looks like a logging statement, specifically logging.error().
It's going to the screen because you haven't set up a log handler which would send it somewhere else. See https://docs.python.org/2/library/logging.html for more information.
It's going to the standard error output (which on a terminal window looks the same as the regular output.) If your code were part of a web service, it would go to the web server's error log.
The first non-keyword argument you pass to open_tunnel is expected to be the destination server (either a string, or an (ip, port) tuple (see the function's docstring).
Eventually, this leads to ssh_host being set to "hello" in the example you gave, which logs an error message in this except block.
"some random line is showing up for some reason." - its a straight-forward error message... the remote server couldn't find a host called "hello". As for why you see it, sshtunnel creates a console logger for error messages if you don't pass a logger yourself. That is a strange thing to do, IMHO. open_tunnel accepts two keywoard arguments: logger is a standard python logger and debug_level is the level to log. See python logging for details on setting up a logger.
The part where you have "Hello" should ideally have the IP address of the SSH Server that you are connecting to. The random line that you mentioned is the ERROR statement that explains it.
Although the program does not have any stdout statements, the ERROR line is from the library sshtunnel.
The statement block in the library uses a raise(exeption) statement with this particular error message. raise function is used to populate messages that can be captured by except statements.
TL;DR
add threaded=False
Hello I had exactly the same ERROR
and it appears after the closing of the tunnel (release):
2018-01-16 10:52:58,685| INFO | Shutting down tunnel ('0.0.0.0', 33553)
2018-01-16 10:52:58,764| INFO | Tunnel: 0.0.0.0:33553 <> sql_database_resolved_on_remote:1433 released
2018-01-16 10:52:58,767| ERROR | Could not establish connection from ('127.0.0.1', 33553) to remote side of the tunnel
2018-01-16 10:52:58,889| DEBUG | Transport is closed
That's somewhat normal, but why it's there?
"Solution-ish"
Add threaded=False.
Both tested with open_tunnel() and SSHTunnelForwarder in with ... as tunnel: context:
import time
import socket
from sshtunnel import SSHTunnelForwarder, open_tunnel
def test_tunnel(tunnel):
# Wait for tunnel to be established ?
#tunnel.check_tunnels()
#time.sleep(0.5)
#print tunnel.tunnel_is_up
s = socket.socket()
s.settimeout(2)
for i in range(0, 10):
"""
I create a new socket each time otherwise I get
the error 106 (errno.EISCONN):
'Transport endpoint is already connected'
"""
s = socket.socket()
s.settimeout(2)
state = s.connect_ex(('localhost', tunnel.local_bind_port))
s.close()
okoko = "OK" if state == 0 else "NO"
print "%s (%s)" % (okoko, state)
with open_tunnel(
'server_i_can_ssh_with_mykey',
ssh_username='myuser',
ssh_pkey='/home/myuser/.ssh/id_rsa',
ssh_private_key_password=None, #no pwd on my key
remote_bind_address=('sql_database_resolved_on_remote', 1433), #e.g.
debug_level=10, # remove this if you test with SSHTunnelForwarder
threaded=False,
) as tunnel:
test_tunnel(tunnel)
hth
I'm trying to do some port forwarding from a python app using Paramiko. I can set up the SSH connection just fine, but I'm a bit stumped as to how to use paramiko.Transport. I've already found this file, but I can't work out what's going on in it. From looking at the paramiko.Transport docs, it seems that a single line using the open_channel function, but I can't work out how to implement that. I'm trying to replicate a simple ssh -L 8000:localhost:8000.
Can anyone help me out?
Please find some code using paramiko-1.7.7.1, pycrypto-2.6 and the forward.py script from which I did remove code from the line 115 to the end (to avoid options parsing).
import paramiko, sys
from forward import forward_tunnel
remote_host = "target_host"
remote_port = 8000
local_port = 8000
ssh_host = "my_ssh_host"
ssh_port = 22
user = "login"
password = "s3cr3t"
transport = paramiko.Transport((ssh_host, ssh_port))
# Command for paramiko-1.7.7.1
transport.connect(hostkey = None,
username = user,
password = password,
pkey = None)
try:
forward_tunnel(local_port, remote_host, remote_port, transport)
except KeyboardInterrupt:
print 'Port forwarding stopped.'
sys.exit(0)
I've tested it successfully from a Windows station, using a ssh server under Red Hat and pointing to a 3rd server. (I'm using Python 2.7.2)
Hope it helps,
You can use https://github.com/pahaz/sshtunnel
pip install sshtunnel
Code example:
import sshtunnel
with sshtunnel.open(
(ssh_host, ssh_port),
ssh_host_key=None,
ssh_username=ssh_user,
ssh_password=ssh_password,
ssh_private_key=None,
remote_bind_address=(REMOTE_HOST, REMOTE_PORT)) as server:
def do_something(port):
# Do something with port
pass
print("LOCAL PORT:", server.local_bind_port)
do_something(server.local_bind_port)