15

I'm trying to set up a python logger to send error emails when it logs an error iff the instance has a tag set. I then quickly run into the problem of local dev computers that aren't on aws. Is there an easy and fast way to check if the script is being run on aws?

I was loading the instance data with:

import boto.utils
from boto.ec2.connection import EC2Connection
metadata = boto.utils.get_instance_metadata()
conn = EC2Connection()
instance = conn.get_only_instances(instance_ids=metadata['instance-id'])[0]

I can of course use a timeout on get_instance_metadata, but there is then a tension between now long to make developers wait vs the possibility of not sending an error email in production.

Can anyone think of a nice solution?

TristanMatthews
  • 2,451
  • 4
  • 24
  • 34

5 Answers5

14

Alternatively, you can check if your environment contains any AWS environmental variables:

is_aws = True if os.environ.get("AWS_DEFAULT_REGION") else False

I chose to inspect if my user name is an ec2 instance: (Not a great solution, but it works)

my_user = os.environ.get("USER")
is_aws = True if "ec2" in my_user else False
Yaakov Bressler
  • 9,056
  • 2
  • 45
  • 69
6

Similar to @cgseller, assuming python3, one could do something like:

from urllib.request import urlopen

def is_ec2_instance():
    """Check if an instance is running on AWS."""
    result = False
    meta = 'http://169.254.169.254/latest/meta-data/public-ipv4'
    try:
        result = urlopen(meta).status == 200
    except ConnectionError:
        return result
    return result
sedeh
  • 7,083
  • 6
  • 48
  • 65
5

AWS instances have metadata, so you could make a call to the metadata service and get a response, if the response is valid, you are @ AWS, otherwise you are not.

for example:

import urllib2
meta = 'http://169.254.169.254/latest/meta-data/ami-id'
req = urllib2.Request(meta)
try:
    response = urllib2.urlopen(req).read()
    if 'ami' in response:
        _msg = 'I am in AWS running on {}'.format(response)
    else:
        _msg = 'I am in dev - no AWS AMI'
except Exception as nometa:
    _msg = 'no metadata, not in AWS'

print _msg

This is just a stab - there are likely better checks but this one will get you the feel for it and you can improve upon it as you see fit. IF you are using OpenStack or another cloud service locally you of course will get a metadata response, so you will have to adjust your check accordingly...

(you could also do this with cloud-init stuff if you are using some kind of launch tool or manager like chef, puppet, homegrown, etc. Drop an /ec2 file in the file system if it's in AWS, or better yet if local drop a /DEV on the box)

Marco Castelluccio
  • 10,152
  • 2
  • 33
  • 48
cgseller
  • 3,875
  • 2
  • 19
  • 21
  • This takes long time on non instance, as urlopen will block. Better to add `urlopen(meta, timeout=1)` or something similar. – Marcin Jan 03 '23 at 23:05
2

A simple solution would be to check the contents of the file /var/lib/cloud/instance/datasource, which on an Ec2 instance contains DataSourceEc2Local: DataSourceEc2Local:

$ sudo cat /var/lib/cloud/instance/datasource
DataSourceEc2Local: DataSourceEc2Local

so in Python:

datasource_file = "/var/lib/cloud/instance/datasource"
try:
    with open(datasource_file) as f:
        line = f.readlines()
        if "DataSourceEc2Local" in line[0]:
            print("I'm running on EC2!")
except FileNotFoundError:
        print(f"{datasource_file} not found")
Paolo
  • 21,270
  • 6
  • 38
  • 69
1

I don't think this is really a boto issue. EC2 (and boto in turn) don't care or know anything about what scripts you're running on your servers.

If your script has a particular signature -- e.g. listening on a port -- that would be the best way to check, but shy of that, you can just look for its signature in the OS -- its process.

Use the subprocess module and your preferred bash magic to check if it's running:

command = ["ssh", "{user}@{server}", "pgrep", "-fl", "{scriptname}"]
try:
    is_running = bool(subprocess.check_output(command))
except subprocess.CalledProcessError:
    log.exception("Checking for script failed")
    is_running = False
Community
  • 1
  • 1
jwilner
  • 6,348
  • 6
  • 35
  • 47
  • Yep your right, its not really a boto issue. I like Nathan Binkert answer to this post. http://stackoverflow.com/questions/10907418/how-to-check-application-runs-in-aws-ec2-instance – TristanMatthews Apr 11 '15 at 01:54
  • Oooh, I get your question now. Why don't you just have dev computers set an environment variable and check for that environment variable in the script? Seems simplest. – jwilner Apr 11 '15 at 02:01
  • We talked about that, but I'd rather avoid a solution that requires doing something like that on all dev or all production machines. – TristanMatthews Apr 11 '15 at 02:15