|
Packit Service |
9bfd13 |
#!/usr/bin/env python3
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Provides a somewhat random, somewhat compat, somewhat useful mock version of
|
|
Packit Service |
a04d08 |
# http://docs.amazonwebservices.com
|
|
Packit Service |
a04d08 |
# /AWSEC2/2007-08-29/DeveloperGuide/AESDG-chapter-instancedata.htm
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
"""
|
|
Packit Service |
a04d08 |
To use this to mimic the EC2 metadata service entirely, run it like:
|
|
Packit Service |
a04d08 |
# Where 'eth0' is *some* interface.
|
|
Packit Service |
a04d08 |
sudo ifconfig eth0:0 169.254.169.254 netmask 255.255.255.255
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
sudo ./mock-meta.py -a 169.254.169.254 -p 80
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
Then:
|
|
Packit Service |
a04d08 |
wget -q http://169.254.169.254/latest/meta-data/instance-id -O -; echo
|
|
Packit Service |
a04d08 |
curl --silent http://169.254.169.254/latest/meta-data/instance-id ; echo
|
|
Packit Service |
a04d08 |
ec2metadata --instance-id
|
|
Packit Service |
a04d08 |
"""
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
import argparse
|
|
Packit Service |
a04d08 |
import functools
|
|
Packit Service |
a04d08 |
import json
|
|
Packit Service |
a04d08 |
import logging
|
|
Packit Service |
a04d08 |
import os
|
|
Packit Service |
a04d08 |
import random
|
|
Packit Service |
a04d08 |
import socket
|
|
Packit Service |
a04d08 |
import string
|
|
Packit Service |
a04d08 |
import sys
|
|
Packit Service |
a04d08 |
import yaml
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
|
|
Packit Service |
a04d08 |
import httplib as hclient
|
|
Packit Service |
a04d08 |
except ImportError:
|
|
Packit Service |
a04d08 |
from http.server import HTTPServer, BaseHTTPRequestHandler
|
|
Packit Service |
a04d08 |
from http import client as hclient
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
log = logging.getLogger('meta-server')
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
EC2_VERSIONS = [
|
|
Packit Service |
a04d08 |
'1.0',
|
|
Packit Service |
a04d08 |
'2007-01-19',
|
|
Packit Service |
a04d08 |
'2007-03-01',
|
|
Packit Service |
a04d08 |
'2007-08-29',
|
|
Packit Service |
a04d08 |
'2007-10-10',
|
|
Packit Service |
a04d08 |
'2007-12-15',
|
|
Packit Service |
a04d08 |
'2008-02-01',
|
|
Packit Service |
a04d08 |
'2008-09-01',
|
|
Packit Service |
a04d08 |
'2009-04-04',
|
|
Packit Service |
a04d08 |
]
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
BLOCK_DEVS = [
|
|
Packit Service |
a04d08 |
'ami',
|
|
Packit Service |
a04d08 |
'ephemeral0',
|
|
Packit Service |
a04d08 |
'root',
|
|
Packit Service |
a04d08 |
]
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
DEV_PREFIX = 'v' # This seems to vary alot depending on images...
|
|
Packit Service |
a04d08 |
DEV_MAPPINGS = {
|
|
Packit Service |
a04d08 |
'ephemeral0': '%sda2' % (DEV_PREFIX),
|
|
Packit Service |
a04d08 |
'root': '/dev/%sda1' % (DEV_PREFIX),
|
|
Packit Service |
a04d08 |
'ami': '%sda1' % (DEV_PREFIX),
|
|
Packit Service |
a04d08 |
'swap': '%sda3' % (DEV_PREFIX),
|
|
Packit Service |
a04d08 |
}
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
META_CAPABILITIES = [
|
|
Packit Service |
a04d08 |
'aki-id',
|
|
Packit Service |
a04d08 |
'ami-id',
|
|
Packit Service |
a04d08 |
'ami-launch-index',
|
|
Packit Service |
a04d08 |
'ami-manifest-path',
|
|
Packit Service |
a04d08 |
'ari-id',
|
|
Packit Service |
a04d08 |
'block-device-mapping/',
|
|
Packit Service |
a04d08 |
'hostname',
|
|
Packit Service |
a04d08 |
'instance-action',
|
|
Packit Service |
a04d08 |
'instance-id',
|
|
Packit Service |
a04d08 |
'instance-type',
|
|
Packit Service |
a04d08 |
'local-hostname',
|
|
Packit Service |
a04d08 |
'local-ipv4',
|
|
Packit Service |
a04d08 |
'placement/',
|
|
Packit Service |
a04d08 |
'product-codes',
|
|
Packit Service |
a04d08 |
'public-hostname',
|
|
Packit Service |
a04d08 |
'public-ipv4',
|
|
Packit Service |
a04d08 |
'public-keys/',
|
|
Packit Service |
a04d08 |
'reservation-id',
|
|
Packit Service |
a04d08 |
'security-groups'
|
|
Packit Service |
a04d08 |
]
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
PUB_KEYS = {
|
|
Packit Service |
a04d08 |
'brickies': [
|
|
Packit Service |
a04d08 |
('ssh-rsa '
|
|
Packit Service |
a04d08 |
'AAAAB3NzaC1yc2EAAAABIwAAAQEA3I7VUf2l5gSn5uavROsc5HRDpZdQueUq5ozemN'
|
|
Packit Service |
a04d08 |
'Sj8T7enqKHOEaFoU2VoPgGEWC9RyzSQVeyD6s7APMcE82EtmW4skVEgEGSbDc1pvxz'
|
|
Packit Service |
a04d08 |
'xtchBj78hJP6Cf5TCMFSXw+Fz5rF1dR23QDbN1mkHs7adr8GW4kSWqU7Q7NDwfIrJJ'
|
|
Packit Service |
a04d08 |
'tO7Hi42GyXtvEONHbiRPOe8stqUly7MvUoN+5kfjBM8Qqpfl2+FNhTYWpMfYdPUnE7'
|
|
Packit Service |
a04d08 |
'u536WqzFmsaqJctz3gBxH9Ex7dFtrxR4qiqEr9Qtlu3xGn7Bw07/+i1D+ey3ONkZLN'
|
|
Packit Service |
a04d08 |
'+LQ714cgj8fRS4Hj29SCmXp5Kt5/82cD/VN3NtHw== brickies'),
|
|
Packit Service |
a04d08 |
'',
|
|
Packit Service |
a04d08 |
],
|
|
Packit Service |
a04d08 |
}
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
INSTANCE_TYPES = [
|
|
Packit Service |
a04d08 |
'm1.large',
|
|
Packit Service |
a04d08 |
'm1.medium',
|
|
Packit Service |
a04d08 |
'm1.small',
|
|
Packit Service |
a04d08 |
'm1.xlarge',
|
|
Packit Service |
a04d08 |
]
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
AVAILABILITY_ZONES = [
|
|
Packit Service |
a04d08 |
"us-east-1a",
|
|
Packit Service |
a04d08 |
"us-east-1b",
|
|
Packit Service |
a04d08 |
"us-east-1c",
|
|
Packit Service |
a04d08 |
"us-east-1d",
|
|
Packit Service |
a04d08 |
'eu-west-1a',
|
|
Packit Service |
a04d08 |
'eu-west-1b',
|
|
Packit Service |
a04d08 |
'us-west-1',
|
|
Packit Service |
a04d08 |
]
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
PLACEMENT_CAPABILITIES = {
|
|
Packit Service |
a04d08 |
'availability-zone': AVAILABILITY_ZONES,
|
|
Packit Service |
a04d08 |
}
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
NOT_IMPL_RESPONSE = json.dumps({})
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
class WebException(Exception):
|
|
Packit Service |
a04d08 |
def __init__(self, code, msg):
|
|
Packit Service |
a04d08 |
Exception.__init__(self, msg)
|
|
Packit Service |
a04d08 |
self.code = code
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def yamlify(data):
|
|
Packit Service |
a04d08 |
formatted = yaml.dump(data,
|
|
Packit Service |
a04d08 |
line_break="\n",
|
|
Packit Service |
a04d08 |
indent=4,
|
|
Packit Service |
a04d08 |
explicit_start=True,
|
|
Packit Service |
a04d08 |
explicit_end=True,
|
|
Packit Service |
a04d08 |
default_flow_style=False)
|
|
Packit Service |
a04d08 |
return formatted
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def format_text(text):
|
|
Packit Service |
a04d08 |
if not len(text):
|
|
Packit Service |
a04d08 |
return "<<"
|
|
Packit Service |
a04d08 |
lines = text.splitlines()
|
|
Packit Service |
a04d08 |
nlines = []
|
|
Packit Service |
a04d08 |
for line in lines:
|
|
Packit Service |
a04d08 |
nlines.append("<< %s" % line)
|
|
Packit Service |
a04d08 |
return "\n".join(nlines)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def traverse(keys, mp):
|
|
Packit Service |
a04d08 |
result = dict(mp)
|
|
Packit Service |
a04d08 |
for k in keys:
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
result = result.get(k)
|
|
Packit Service |
a04d08 |
except (AttributeError, TypeError):
|
|
Packit Service |
a04d08 |
result = None
|
|
Packit Service |
a04d08 |
break
|
|
Packit Service |
a04d08 |
return result
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
ID_CHARS = [c for c in (string.ascii_uppercase + string.digits)]
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def id_generator(size=6, lower=False):
|
|
Packit Service |
a04d08 |
txt = ''.join(random.choice(ID_CHARS) for x in range(size))
|
|
Packit Service |
a04d08 |
if lower:
|
|
Packit Service |
a04d08 |
return txt.lower()
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
return txt
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def get_ssh_keys():
|
|
Packit Service |
a04d08 |
keys = {}
|
|
Packit Service |
a04d08 |
keys.update(PUB_KEYS)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Nice helper to add in the 'running' users key (if they have one)
|
|
Packit Service |
a04d08 |
key_pth = os.path.expanduser('~/.ssh/id_rsa.pub')
|
|
Packit Service |
a04d08 |
if not os.path.isfile(key_pth):
|
|
Packit Service |
a04d08 |
key_pth = os.path.expanduser('~/.ssh/id_dsa.pub')
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if os.path.isfile(key_pth):
|
|
Packit Service |
a04d08 |
with open(key_pth, 'rb') as fh:
|
|
Packit Service |
a04d08 |
contents = fh.read()
|
|
Packit Service |
a04d08 |
keys[os.getlogin()] = [contents, '']
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
return keys
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
class HTTPServerV6(HTTPServer):
|
|
Packit Service |
a04d08 |
address_family = socket.AF_INET6
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
class MetaDataHandler(object):
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def __init__(self, opts):
|
|
Packit Service |
a04d08 |
self.opts = opts
|
|
Packit Service |
a04d08 |
self.instances = {}
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def get_data(self, params, who, **kwargs):
|
|
Packit Service |
a04d08 |
if not params:
|
|
Packit Service |
a04d08 |
# Show the root level capabilities when
|
|
Packit Service |
a04d08 |
# no params are passed...
|
|
Packit Service |
a04d08 |
caps = sorted(META_CAPABILITIES)
|
|
Packit Service |
a04d08 |
return "\n".join(caps)
|
|
Packit Service |
a04d08 |
action = params[0]
|
|
Packit Service |
a04d08 |
action = action.lower()
|
|
Packit Service |
a04d08 |
if action == 'instance-id':
|
|
Packit Service |
a04d08 |
return 'i-%s' % (id_generator(lower=True))
|
|
Packit Service |
a04d08 |
elif action == 'ami-launch-index':
|
|
Packit Service |
a04d08 |
return "%s" % random.choice([0, 1, 2, 3])
|
|
Packit Service |
a04d08 |
elif action == 'aki-id':
|
|
Packit Service |
a04d08 |
return 'aki-%s' % (id_generator(lower=True))
|
|
Packit Service |
a04d08 |
elif action == 'ami-id':
|
|
Packit Service |
a04d08 |
return 'ami-%s' % (id_generator(lower=True))
|
|
Packit Service |
a04d08 |
elif action == 'ari-id':
|
|
Packit Service |
a04d08 |
return 'ari-%s' % (id_generator(lower=True))
|
|
Packit Service |
a04d08 |
elif action == 'block-device-mapping':
|
|
Packit Service |
a04d08 |
nparams = params[1:]
|
|
Packit Service |
a04d08 |
if not nparams:
|
|
Packit Service |
a04d08 |
return "\n".join(BLOCK_DEVS)
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
subvalue = traverse(nparams, DEV_MAPPINGS)
|
|
Packit Service |
a04d08 |
if not subvalue:
|
|
Packit Service |
a04d08 |
return "\n".join(sorted(list(DEV_MAPPINGS.keys())))
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
return str(subvalue)
|
|
Packit Service |
a04d08 |
elif action in ['hostname', 'local-hostname', 'public-hostname']:
|
|
Packit Service |
a04d08 |
# Just echo back there own hostname that they called in on..
|
|
Packit Service |
a04d08 |
return "%s" % (who)
|
|
Packit Service |
a04d08 |
elif action == 'instance-type':
|
|
Packit Service |
a04d08 |
return random.choice(INSTANCE_TYPES)
|
|
Packit Service |
a04d08 |
elif action == 'ami-manifest-path':
|
|
Packit Service |
a04d08 |
return 'my-amis/spamd-image.manifest.xml'
|
|
Packit Service |
a04d08 |
elif action == 'security-groups':
|
|
Packit Service |
a04d08 |
return 'default'
|
|
Packit Service |
a04d08 |
elif action in ['local-ipv4', 'public-ipv4']:
|
|
Packit Service |
a04d08 |
# Just echo back there own ip that they called in on...
|
|
Packit Service |
a04d08 |
return "%s" % (kwargs.get('client_ip', '10.0.0.1'))
|
|
Packit Service |
a04d08 |
elif action == 'reservation-id':
|
|
Packit Service |
a04d08 |
return "r-%s" % (id_generator(lower=True))
|
|
Packit Service |
a04d08 |
elif action == 'product-codes':
|
|
Packit Service |
a04d08 |
return "%s" % (id_generator(size=8))
|
|
Packit Service |
a04d08 |
elif action == 'public-keys':
|
|
Packit Service |
a04d08 |
nparams = params[1:]
|
|
Packit Service |
a04d08 |
# This is a weird kludge, why amazon why!!!
|
|
Packit Service |
a04d08 |
# public-keys is messed up, list of /latest/meta-data/public-keys/
|
|
Packit Service |
a04d08 |
# shows something like: '0=brickies'
|
|
Packit Service |
a04d08 |
# but a GET to /latest/meta-data/public-keys/0=brickies will fail
|
|
Packit Service |
a04d08 |
# you have to know to get '/latest/meta-data/public-keys/0', then
|
|
Packit Service |
a04d08 |
# from there you get a 'openssh-key', which you can get.
|
|
Packit Service |
a04d08 |
# this hunk of code just re-works the object for that.
|
|
Packit Service |
a04d08 |
avail_keys = get_ssh_keys()
|
|
Packit Service |
a04d08 |
key_ids = sorted(list(avail_keys.keys()))
|
|
Packit Service |
a04d08 |
if nparams:
|
|
Packit Service |
a04d08 |
mybe_key = nparams[0]
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
key_id = int(mybe_key)
|
|
Packit Service |
a04d08 |
key_name = key_ids[key_id]
|
|
Packit Service |
9bfd13 |
except ValueError as e:
|
|
Packit Service |
9bfd13 |
raise WebException(
|
|
Packit Service |
9bfd13 |
hclient.BAD_REQUEST, "%s: not an integer" % mybe_key
|
|
Packit Service |
9bfd13 |
) from e
|
|
Packit Service |
9bfd13 |
except IndexError as e:
|
|
Packit Service |
9bfd13 |
raise WebException(
|
|
Packit Service |
9bfd13 |
hclient.NOT_FOUND, "Unknown key id %r" % mybe_key
|
|
Packit Service |
9bfd13 |
) from e
|
|
Packit Service |
a04d08 |
# Extract the possible sub-params
|
|
Packit Service |
a04d08 |
result = traverse(nparams[1:], {
|
|
Packit Service |
a04d08 |
"openssh-key": "\n".join(avail_keys[key_name]),
|
|
Packit Service |
a04d08 |
})
|
|
Packit Service |
a04d08 |
if isinstance(result, (dict)):
|
|
Packit Service |
a04d08 |
# TODO(harlowja): This might not be right??
|
|
Packit Service |
a04d08 |
result = "\n".join(sorted(result.keys()))
|
|
Packit Service |
a04d08 |
if not result:
|
|
Packit Service |
a04d08 |
result = ''
|
|
Packit Service |
a04d08 |
return result
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
contents = []
|
|
Packit Service |
a04d08 |
for (i, key_id) in enumerate(key_ids):
|
|
Packit Service |
a04d08 |
contents.append("%s=%s" % (i, key_id))
|
|
Packit Service |
a04d08 |
return "\n".join(contents)
|
|
Packit Service |
a04d08 |
elif action == 'placement':
|
|
Packit Service |
a04d08 |
nparams = params[1:]
|
|
Packit Service |
a04d08 |
if not nparams:
|
|
Packit Service |
a04d08 |
pcaps = sorted(PLACEMENT_CAPABILITIES.keys())
|
|
Packit Service |
a04d08 |
return "\n".join(pcaps)
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
pentry = nparams[0].strip().lower()
|
|
Packit Service |
a04d08 |
if pentry == 'availability-zone':
|
|
Packit Service |
a04d08 |
zones = PLACEMENT_CAPABILITIES[pentry]
|
|
Packit Service |
a04d08 |
return "%s" % random.choice(zones)
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
return "%s" % (PLACEMENT_CAPABILITIES.get(pentry, ''))
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
log.warning(("Did not implement action %s, "
|
|
Packit Service |
a04d08 |
"returning empty response: %r"),
|
|
Packit Service |
a04d08 |
action, NOT_IMPL_RESPONSE)
|
|
Packit Service |
a04d08 |
return NOT_IMPL_RESPONSE
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
class UserDataHandler(object):
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def __init__(self, opts):
|
|
Packit Service |
a04d08 |
self.opts = opts
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def _get_user_blob(self, **kwargs):
|
|
Packit Service |
a04d08 |
blob = None
|
|
Packit Service |
a04d08 |
if self.opts['user_data_file'] is not None:
|
|
Packit Service |
a04d08 |
blob = self.opts['user_data_file']
|
|
Packit Service |
a04d08 |
if not blob:
|
|
Packit Service |
a04d08 |
blob_mp = {
|
|
Packit Service |
a04d08 |
'hostname': kwargs.get('who', 'localhost'),
|
|
Packit Service |
a04d08 |
}
|
|
Packit Service |
a04d08 |
lines = [
|
|
Packit Service |
a04d08 |
"#cloud-config",
|
|
Packit Service |
a04d08 |
yamlify(blob_mp),
|
|
Packit Service |
a04d08 |
]
|
|
Packit Service |
a04d08 |
blob = "\n".join(lines)
|
|
Packit Service |
a04d08 |
return blob.strip()
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def get_data(self, params, who, **kwargs):
|
|
Packit Service |
a04d08 |
if not params:
|
|
Packit Service |
a04d08 |
return self._get_user_blob(who=who)
|
|
Packit Service |
a04d08 |
return NOT_IMPL_RESPONSE
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Seem to need to use globals since can't pass
|
|
Packit Service |
a04d08 |
# data into the request handlers instances...
|
|
Packit Service |
a04d08 |
# Puke!
|
|
Packit Service |
a04d08 |
meta_fetcher = None
|
|
Packit Service |
a04d08 |
user_fetcher = None
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
class Ec2Handler(BaseHTTPRequestHandler):
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def _get_versions(self):
|
|
Packit Service |
a04d08 |
versions = ['latest'] + EC2_VERSIONS
|
|
Packit Service |
a04d08 |
versions = sorted(versions)
|
|
Packit Service |
a04d08 |
return "\n".join(versions)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def log_message(self, fmt, *args):
|
|
Packit Service |
a04d08 |
msg = "%s - %s" % (self.address_string(), fmt % (args))
|
|
Packit Service |
a04d08 |
log.info(msg)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def _find_method(self, path):
|
|
Packit Service |
a04d08 |
# Puke! (globals)
|
|
Packit Service |
a04d08 |
func_mapping = {
|
|
Packit Service |
a04d08 |
'user-data': user_fetcher.get_data,
|
|
Packit Service |
a04d08 |
'meta-data': meta_fetcher.get_data,
|
|
Packit Service |
a04d08 |
}
|
|
Packit Service |
a04d08 |
segments = [piece for piece in path.split('/') if len(piece)]
|
|
Packit Service |
a04d08 |
log.info("Received segments %s", segments)
|
|
Packit Service |
a04d08 |
if not segments:
|
|
Packit Service |
a04d08 |
return self._get_versions
|
|
Packit Service |
a04d08 |
date = segments[0].strip().lower()
|
|
Packit Service |
a04d08 |
if date not in self._get_versions():
|
|
Packit Service |
a04d08 |
raise WebException(hclient.BAD_REQUEST,
|
|
Packit Service |
a04d08 |
"Unknown version format %r" % date)
|
|
Packit Service |
a04d08 |
if len(segments) < 2:
|
|
Packit Service |
a04d08 |
raise WebException(hclient.BAD_REQUEST, "No action provided")
|
|
Packit Service |
a04d08 |
look_name = segments[1].lower()
|
|
Packit Service |
a04d08 |
if look_name not in func_mapping:
|
|
Packit Service |
a04d08 |
raise WebException(hclient.BAD_REQUEST,
|
|
Packit Service |
a04d08 |
"Unknown requested data %r" % look_name)
|
|
Packit Service |
a04d08 |
base_func = func_mapping[look_name]
|
|
Packit Service |
a04d08 |
who = self.address_string()
|
|
Packit Service |
a04d08 |
ip_from = self.client_address[0]
|
|
Packit Service |
a04d08 |
if who == ip_from:
|
|
Packit Service |
a04d08 |
# Nothing resolved, so just use 'localhost'
|
|
Packit Service |
a04d08 |
who = 'localhost'
|
|
Packit Service |
a04d08 |
kwargs = {
|
|
Packit Service |
a04d08 |
'params': list(segments[2:]),
|
|
Packit Service |
a04d08 |
'who': who,
|
|
Packit Service |
a04d08 |
'client_ip': ip_from,
|
|
Packit Service |
a04d08 |
}
|
|
Packit Service |
a04d08 |
return functools.partial(base_func, **kwargs)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def _do_response(self):
|
|
Packit Service |
a04d08 |
who = self.client_address
|
|
Packit Service |
a04d08 |
log.info("Got a call from %s for path %s", who, self.path)
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
func = self._find_method(self.path)
|
|
Packit Service |
a04d08 |
data = func()
|
|
Packit Service |
a04d08 |
if not data:
|
|
Packit Service |
a04d08 |
data = ''
|
|
Packit Service |
a04d08 |
self.send_response(hclient.OK)
|
|
Packit Service |
a04d08 |
self.send_header("Content-Type", "binary/octet-stream")
|
|
Packit Service |
a04d08 |
self.send_header("Content-Length", len(data))
|
|
Packit Service |
a04d08 |
log.info("Sending data (len=%s):\n%s", len(data),
|
|
Packit Service |
a04d08 |
format_text(data))
|
|
Packit Service |
a04d08 |
self.end_headers()
|
|
Packit Service |
a04d08 |
self.wfile.write(data.encode())
|
|
Packit Service |
a04d08 |
except RuntimeError as e:
|
|
Packit Service |
a04d08 |
log.exception("Error somewhere in the server.")
|
|
Packit Service |
a04d08 |
self.send_error(hclient.INTERNAL_SERVER_ERROR, message=str(e))
|
|
Packit Service |
a04d08 |
except WebException as e:
|
|
Packit Service |
a04d08 |
code = e.code
|
|
Packit Service |
a04d08 |
log.exception(str(e))
|
|
Packit Service |
a04d08 |
self.send_error(code, message=str(e))
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def do_GET(self):
|
|
Packit Service |
a04d08 |
self._do_response()
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def do_POST(self):
|
|
Packit Service |
a04d08 |
self._do_response()
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def setup_logging(log_level, fmt='%(levelname)s: @%(name)s : %(message)s'):
|
|
Packit Service |
a04d08 |
root_logger = logging.getLogger()
|
|
Packit Service |
a04d08 |
console_logger = logging.StreamHandler(sys.stdout)
|
|
Packit Service |
a04d08 |
console_logger.setFormatter(logging.Formatter(fmt))
|
|
Packit Service |
a04d08 |
root_logger.addHandler(console_logger)
|
|
Packit Service |
a04d08 |
root_logger.setLevel(log_level)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def extract_opts():
|
|
Packit Service |
a04d08 |
parser = argparse.ArgumentParser()
|
|
Packit Service |
a04d08 |
parser.add_argument("-p", "--port", dest="port", action="store", type=int,
|
|
Packit Service |
a04d08 |
default=80, metavar="PORT",
|
|
Packit Service |
a04d08 |
help=("port from which to serve traffic"
|
|
Packit Service |
a04d08 |
" (default: %default)"))
|
|
Packit Service |
a04d08 |
parser.add_argument("-a", "--addr", dest="address", action="store",
|
|
Packit Service |
a04d08 |
type=str, default='::', metavar="ADDRESS",
|
|
Packit Service |
a04d08 |
help=("address from which to serve traffic"
|
|
Packit Service |
a04d08 |
" (default: %default)"))
|
|
Packit Service |
a04d08 |
parser.add_argument("-f", '--user-data-file', dest='user_data_file',
|
|
Packit Service |
a04d08 |
action='store', metavar='FILE',
|
|
Packit Service |
a04d08 |
help=("user data filename to serve back to"
|
|
Packit Service |
a04d08 |
"incoming requests"))
|
|
Packit Service |
a04d08 |
parser.add_argument('extra', nargs='*')
|
|
Packit Service |
a04d08 |
args = parser.parse_args()
|
|
Packit Service |
a04d08 |
out = {'port': args.port, 'address': args.address, 'extra': args.extra,
|
|
Packit Service |
a04d08 |
'user_data_file': None}
|
|
Packit Service |
a04d08 |
if args.user_data_file:
|
|
Packit Service |
a04d08 |
if not os.path.isfile(args.user_data_file):
|
|
Packit Service |
a04d08 |
parser.error("Option -f specified a non-existent file")
|
|
Packit Service |
a04d08 |
with open(args.user_data_file, 'rb') as fh:
|
|
Packit Service |
a04d08 |
out['user_data_file'] = fh.read()
|
|
Packit Service |
a04d08 |
return out
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def setup_fetchers(opts):
|
|
Packit Service |
a04d08 |
global meta_fetcher
|
|
Packit Service |
a04d08 |
global user_fetcher
|
|
Packit Service |
a04d08 |
meta_fetcher = MetaDataHandler(opts)
|
|
Packit Service |
a04d08 |
user_fetcher = UserDataHandler(opts)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def run_server():
|
|
Packit Service |
a04d08 |
# Using global here since it doesn't seem like we
|
|
Packit Service |
a04d08 |
# can pass opts into a request handler constructor...
|
|
Packit Service |
a04d08 |
opts = extract_opts()
|
|
Packit Service |
a04d08 |
setup_logging(logging.DEBUG)
|
|
Packit Service |
a04d08 |
setup_fetchers(opts)
|
|
Packit Service |
a04d08 |
log.info("CLI opts: %s", opts)
|
|
Packit Service |
a04d08 |
server_address = (opts['address'], opts['port'])
|
|
Packit Service |
a04d08 |
server = HTTPServerV6(server_address, Ec2Handler)
|
|
Packit Service |
a04d08 |
sa = server.socket.getsockname()
|
|
Packit Service |
a04d08 |
log.info("Serving ec2 metadata on %s using port %s ...", sa[0], sa[1])
|
|
Packit Service |
a04d08 |
server.serve_forever()
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if __name__ == '__main__':
|
|
Packit Service |
a04d08 |
run_server()
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# vi: ts=4 expandtab
|