stuck with status check of amazon ec2 instance - python

I am using Python to launch an ec2 instance, after I get "running" state of my instance, I am trying to SCP a shell script and run it via ssh.
I am getting the following error
"ssh: connect to host ec2-xx-xxx-xxx-xxx.compute-1.amazonaws.com port 22: Connection refused"
When I check in the console, the Status check is "Initializing", once It changes "2/2 checks passed", I am able to ssh or run any script.
Is there any way I can get the "status check" via python boto API?
I am using Python 2.7.5+,
boto 2.19.0
Thanks in advance.

Simple way is to check the port 22 of the newly created instance is reachable or not by using socket module
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect(('hostname', 22))
print "Port 22 reachable"
except socket.error as e:
print "Error on connect: %s" % e
s.close()
When you will able to reach the port 22 then you can invoke ssh to it.

Lazy way
import boto.ec2
for region in boto.ec2.regions():
connection = boto.ec2.connect_to_region(region.name,
aws_access_key_id = '<aws access key>', aws_secret_access_key = '<aws secret key>')
existing_instances = connection.get_all_instance_status()
print 'Listing instances from region ' + region.name
for instance in existing_instances:
print instance.system_status.status + '/' + instance.instance_status.status

Related

SSH twice with Python [duplicate]

This question already has an answer here:
Connecting to a server via another server using Paramiko
(1 answer)
Closed 1 year ago.
I would like to SSH in host1 first then SSH to host2 to get some files. SSH to host one by using Paramiko was success. But when I did the same as host1, it cannot SSH to host2. It shows 'Unable to establish SSH connection: Server 'host2' not found in known_hosts'
import paramiko
from paramiko.ssh_exception import AuthenticationException, SSHException, BadHostKeyException
try:
client = paramiko.SSHClient()
client.load_system_host_keys()
client.connect('host1', username='user1', password='pass1', timeout=5)
print ("Accessed host1 already")
try:
client2 = paramiko.SSHClient()
client2.load_system_host_keys()
client2.connect('host2', username='user2', password='pass2', timeout=5)
print ("Accessed host2 already")
except AuthenticationException:
print("Authentication failed, please verify your credentials: %s")
except SSHException as sshException:
print("Unable to establish SSH connection: %s" % sshException)
except BadHostKeyException as badHostKeyException:
print("Unable to verify server's host key: %s" % badHostKeyException)
except Exception as e:
print("Operation error: %s" % e)
except :
print ("SSH to host1 failed!!!")
Also I tried using command to get into host2 but it is still in host1 all the time. Not sure is this the right way to do. Please recommend how can I do. Thank you.
stdin1, stdout1, stderr1 = client.exec_command('ssh user2#host2;pass2;cd /;ls')
rawd = stdout1.read().decode('ascii').strip("\n")
print(rawd)
For an initial connection, SSH asks if you trust the remote computer. When you type yes, it gets stored in ~/.ssh/known_hosts.
On the system where you run the script, try making a SSH connection manually in console, let it store the server's info in that file, then start your program.

Checking user's network environment - Python application

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
.....

Port forwarding with Paramiko

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)

Amazon Web Service/Boto: Upload and execute remote python/bash script via SSH on localhost

I am able to fire up AWS Ubuntu EC2 instance with boto. Have anyone tried to upload the script to the remote Ubuntu EC2 (More than 1) and execute the script via SSH locally?
The main objective is to automate the whole process using a Python script written on localhost. Is there an alternative way or Amazon api tools to made this possible?
I'd recommend Fabric, it's made for this kind of thing.
Use paramiko API
Here, Paramiko code to execute in remote AWS EC2 Python :
import paramiko
sftp, transport= None, None, None
try:
if keyfilepath=='': keyfilepath= AWS_KEY_PEM
if keyfiletype == 'DSA': key = paramiko.DSSKey.from_private_key_file(keyfilepath)
else: key = paramiko.RSAKey.from_private_key_file(keyfilepath)
if contype== 'sftp' :
transport = paramiko.Transport((host, port))
transport.add_server_key(key)
transport.connect(None, username, pkey=key)
sftp = paramiko.SFTPClient.from_transport(transport)
if isprint : print('Root Directory :\n ', sftp.listdir())
return sftp
except Exception as e:
print('An error occurred creating client: %s: %s' % (e.__class__, e))
if sftp is not None: sftp.close()
if transport is not None: transport.close()
if ssh is not None: ssh.close()

Issues trying to SSH into a fresh EC2 instance with Paramiko

I'm working on a script that spins up a fresh EC2 instance with boto and uses the Paramiko SSH client to execute remote commands on the instance. For whatever reason, the Paramiko client is unabled to connect, I get the error:
Traceback (most recent call last):
File "scripts/sconfigure.py", line 29, in <module>
ssh.connect(instance.ip_address, username='ubuntu', key_filename=os.path.expanduser('~/.ssh/test'))
File "build/bdist.macosx-10.3-fat/egg/paramiko/client.py", line 291, in connect
File "<string>", line 1, in connect
socket.error: [Errno 61] Connection refused
I can ssh in fine manually using the same key file and user. Has anyone run into issues using Paramiko? My full code is below. Thanks.
import boto.ec2, time, paramiko, os
# Connect to the us-west-1 region
ec2 = boto.ec2.regions()[3].connect()
image_id = 'ami-ad7e2ee8'
image_name = 'Ubuntu 10.10 (Maverick Meerkat) 32-bit EBS'
new_reservation = ec2.run_instances(
image_id=image_id,
key_name='test',
security_groups=['web'])
instance = new_reservation.instances[0]
print "Spinning up instance for '%s' - %s. Waiting for it to boot up." % (image_id, image_name)
while instance.state != 'running':
print "."
time.sleep(1)
instance.update()
print "Instance is running, ip: %s" % instance.ip_address
print "Connecting to %s as user %s" % (instance.ip_address, 'ubuntu')
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(instance.ip_address, username='ubuntu', key_filename=os.path.expanduser('~/.ssh/test'))
stdin, stdout, stderr = ssh.exec_command('echo "TEST"')
print stdout.readlines()
ssh.close()
I seem to have figured this out by trial and error. Even though the instance status is "running" according to boto, there is a delay for when it will actually allow an SSH connection. Adding a "time.sleep(30)" before the "ssh.connect(...)" seems to do the trick for me, though this may vary.
The way to check it's ssh available is to make sure its two status checks both passes. On web UI it looks like this:
And using boto3 (the original question used boto but it was 5 years ago), we can do:
session = boto3.Session(...)
client = session.client('ec2')
res = client.run_instances(...) # launch instance
instance_id = res['Instances'][0]['InstanceId']
while True:
statuses = client.describe_instance_status(InstanceIds=[instance_id])
status = statuses['InstanceStatuses'][0]
if status['InstanceStatus']['Status'] == 'ok' \
and status['SystemStatus']['Status'] == 'ok':
break
print '.'
time.sleep(5)
print "Instance is running, you are ready to ssh to it"
Why not use boto.manage.cmdshell instead?
cmd = boto.manage.cmdshell.sshclient_from_instance(instance,
key_path,
user_name='ec2_user')
(code taken from line 152 in ec2_launch_instance.py)
For available cmdshell commands have a look at the SSHClient class from cmdshell.py.
I recently ran into this issue. The "correct" way would be to initiate a close() first and then reopen the connection. However on older versions, close() was broken.
With this version or later, it should be fixed:
https://github.com/boto/boto/pull/412
"Proper" method:
newinstance = image.run(min_count=instancenum, max_count=instancenum, key_name=keypair, security_groups=security_group, user_data=instancename, instance_type=instancetype, placement=zone)
time.sleep(2)
newinstance.instances[0].add_tag('Name',instancename)
print "Waiting for public_dns_name..."
counter = 0
while counter < 70:
time.sleep(1)
conn.close()
conn = boto.ec2.connection.EC2Connection(ec2auth.access_key,ec2auth.private_key)
startedinstance = conn.get_all_instances(instance_ids=str(newinstance.instances[0].id))[0]
counter = counter + 1
if str(startedinstance.instances[0].state) == "running":
break
if counter == 69:
print "Timed out waiting for instance to start."
print "Added: " + startedinstance.instances[0].tags['Name'] + " " + startedinstance.instances[0].public_dns_name
I recently view this code and I have a suggestion for code,
Instead of running while loop to check whether the instance is running or not, you can try "wait_until_running()".
Following is the sample code...
client = boto3.resource(
'ec2',
region_name="us-east-1"
)
Instance_ID = "<your Instance_ID>"
instance = client.Instance(Instance_ID)
instance.start()
instance.wait_until_running()
After that try to code for the ssh connection code.

Categories

Resources