1. Update the mock ec2 data with some of the pubkey code from smosers ec2 metadata server.

2. Allow the setting of the ip addr (not just to 0.0.0.0)
3. Add comment as to how to use this for the 169 'magic' addr
This commit is contained in:
Joshua Harlow
2012-07-03 12:46:55 -07:00
parent fb95590638
commit b40dfc6e9e

View File

@@ -4,6 +4,19 @@
# #
# http://docs.amazonwebservices.com/AWSEC2/2007-08-29/DeveloperGuide/AESDG-chapter-instancedata.html # http://docs.amazonwebservices.com/AWSEC2/2007-08-29/DeveloperGuide/AESDG-chapter-instancedata.html
"""
To use this to mimic the EC2 metadata service entirely, run it like:
# Where 'eth0' is *some* interface.
sudo ifconfig eth0:0 169.254.169.254 netmask 255.255.255.255
sudo ./mock-meta -a 169.254.169.254 -p 80
Then:
wget -q http://169.254.169.254/latest/meta-data/instance-id -O -; echo
curl --silent http://169.254.169.254/latest/meta-data/instance-id ; echo
ec2metadata --instance-id
"""
import functools import functools
import httplib import httplib
import json import json
@@ -20,7 +33,6 @@ from BaseHTTPServer import (HTTPServer, BaseHTTPRequestHandler)
log = logging.getLogger('meta-server') log = logging.getLogger('meta-server')
# Constants
EC2_VERSIONS = [ EC2_VERSIONS = [
'1.0', '1.0',
'2007-01-19', '2007-01-19',
@@ -69,6 +81,14 @@ META_CAPABILITIES = [
'security-groups' 'security-groups'
] ]
PUB_KEYS = {
'brickies': [
'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA3I7VUf2l5gSn5uavROsc5HRDpZdQueUq5ozemNSj8T7enqKHOEaFoU2VoPgGEWC9RyzSQVeyD6s7APMcE82EtmW4skVEgEGSbDc1pvxzxtchBj78hJP6Cf5TCMFSXw+Fz5rF1dR23QDbN1mkHs7adr8GW4kSWqU7Q7NDwfIrJJtO7Hi42GyXtvEONHbiRPOe8stqUly7MvUoN+5kfjBM8Qqpfl2+FNhTYWpMfYdPUnE7u536WqzFmsaqJctz3gBxH9Ex7dFtrxR4qiqEr9Qtlu3xGn7Bw07/+i1D+ey3ONkZLN+LQ714cgj8fRS4Hj29SCmXp5Kt5/82cD/VN3NtHw== brickies',
'',
],
}
INSTANCE_TYPES = [ INSTANCE_TYPES = [
'm1.small', 'm1.small',
'm1.medium', 'm1.medium',
@@ -136,6 +156,8 @@ class MetaDataHandler(object):
def get_data(self, params, who, **kwargs): def get_data(self, params, who, **kwargs):
if not params: if not params:
# Show the root level capabilities when
# no params are passed...
caps = sorted(META_CAPABILITIES) caps = sorted(META_CAPABILITIES)
return "\n".join(caps) return "\n".join(caps)
action = params[0] action = params[0]
@@ -172,6 +194,43 @@ class MetaDataHandler(object):
return "r-%s" % (id_generator(lower=True)) return "r-%s" % (id_generator(lower=True))
elif action == 'product-codes': elif action == 'product-codes':
return "%s" % (id_generator(size=8)) return "%s" % (id_generator(size=8))
elif action == 'public-keys':
nparams = params[1:]
# public-keys is messed up. a list of /latest/meta-data/public-keys/
# shows something like: '0=brickies'
# but a GET to /latest/meta-data/public-keys/0=brickies will fail
# you have to know to get '/latest/meta-data/public-keys/0', then
# from there you get a 'openssh-key', which you can get.
# this hunk of code just re-works the object for that.
key_ids = sorted(list(PUB_KEYS.keys()))
if nparams:
mybe_key = nparams[0]
try:
key_id = int(mybe_key)
key_name = key_ids[key_id]
except:
raise WebException(httplib.BAD_REQUEST, "Unknown key id %r" % mybe_key)
# Extract the possible sub-params
key_info = {
"openssh-key": "\n".join(PUB_KEYS[key_name]),
}
result = dict(key_info)
for k in nparams[1:]:
try:
result = result.get(k)
except (AttributeError, TypeError):
result = None
break
if isinstance(result, (dict)):
result = json.dumps(result)
if result is None:
result = ''
return str(result)
else:
contents = []
for (i, key_id) in enumerate(key_ids):
contents.append("%s=%s" % (i, key_id))
return "\n".join(contents)
elif action == 'placement': elif action == 'placement':
nparams = params[1:] nparams = params[1:]
if not nparams: if not nparams:
@@ -198,10 +257,8 @@ class UserDataHandler(object):
def _get_user_blob(self, **kwargs): def _get_user_blob(self, **kwargs):
blob = None blob = None
if self.opts['user_data_file']: if self.opts['user_data_file'] is not None:
with open(opts['user_data_file'], 'rb') as fh: blob = self.opts['user_data_file']
blob = fh.read()
blob = blob.strip()
if not blob: if not blob:
blob_mp = { blob_mp = {
'hostname': kwargs.get('who', 'localhost'), 'hostname': kwargs.get('who', 'localhost'),
@@ -312,6 +369,8 @@ def extract_opts():
parser = OptionParser() parser = OptionParser()
parser.add_option("-p", "--port", dest="port", action="store", type=int, default=80, parser.add_option("-p", "--port", dest="port", action="store", type=int, default=80,
help="port from which to serve traffic (default: %default)", metavar="PORT") help="port from which to serve traffic (default: %default)", metavar="PORT")
parser.add_option("-a", "--addr", dest="address", action="store", type=str, default='0.0.0.0',
help="address from which to serve traffic (default: %default)", metavar="ADDRESS")
parser.add_option("-f", '--user-data-file', dest='user_data_file', action='store', parser.add_option("-f", '--user-data-file', dest='user_data_file', action='store',
help="user data filename to serve back to incoming requests", metavar='FILE') help="user data filename to serve back to incoming requests", metavar='FILE')
(options, args) = parser.parse_args() (options, args) = parser.parse_args()
@@ -319,10 +378,12 @@ def extract_opts():
out['extra'] = args out['extra'] = args
out['port'] = options.port out['port'] = options.port
out['user_data_file'] = None out['user_data_file'] = None
out['address'] = options.address
if options.user_data_file: if options.user_data_file:
if not os.path.isfile(options.user_data_file): if not os.path.isfile(options.user_data_file):
parser.error("Option -f specified a non-existent file") parser.error("Option -f specified a non-existent file")
out['user_data_file'] = options.user_data_file with open(options.user_data_file, 'rb') as fh:
out['user_data_file'] = fh.read()
return out return out
@@ -340,9 +401,10 @@ def run_server():
setup_logging(logging.DEBUG) setup_logging(logging.DEBUG)
setup_fetchers(opts) setup_fetchers(opts)
log.info("CLI opts: %s", opts) log.info("CLI opts: %s", opts)
server = HTTPServer(('0.0.0.0', opts['port']), Ec2Handler) server_address = (opts['address'], opts['port'])
server = HTTPServer(server_address, Ec2Handler)
sa = server.socket.getsockname() sa = server.socket.getsockname()
log.info("Serving server on %s using port %s ...", sa[0], sa[1]) log.info("Serving ec2 metadata on %s using port %s ...", sa[0], sa[1])
server.serve_forever() server.serve_forever()