97 lines
2.2 KiB
Python
97 lines
2.2 KiB
Python
#!/usr/bin/env python
|
|
|
|
import os
|
|
import sys
|
|
import time
|
|
import urllib.request
|
|
import yaml
|
|
|
|
def eprint(*args, **kwargs):
|
|
print(*args, file=sys.stderr, **kwargs)
|
|
|
|
# The key is the url
|
|
# The value holds the content and the timestamp
|
|
file_cache = {}
|
|
file_cache_ttl = 60
|
|
|
|
mapper_file = ''
|
|
with open('/var/openfaas/secrets/url-mapper-file', 'r') as f:
|
|
mapper_file = f.read().strip()
|
|
|
|
def get_url_content(url):
|
|
if url in file_cache:
|
|
cache_entry = file_cache[url]
|
|
if cache_entry['timestamp'] + file_cache_ttl > time.time():
|
|
return cache_entry['content']
|
|
|
|
try:
|
|
response = urllib.request.urlopen(url)
|
|
targets = yaml.safe_load(response.read())
|
|
except Exception as e:
|
|
eprint("Failed to load URL mapper file: %s" % e)
|
|
return None
|
|
|
|
file_cache[url] = {
|
|
'content': targets,
|
|
'timestamp': time.time()
|
|
}
|
|
return targets
|
|
|
|
def get_dict_entry_fallback(d, key, fallback):
|
|
if key and key in d:
|
|
return d[key]
|
|
if key.isnumeric() and int(key) in d:
|
|
return d[int(key)]
|
|
if fallback in d:
|
|
return d[fallback]
|
|
return d.get('_default', None)
|
|
|
|
def get_entry(args, targets):
|
|
while args:
|
|
arg = args.pop(0)
|
|
if not arg:
|
|
continue
|
|
|
|
# Fallback to _404 if the key is not found
|
|
targets = get_dict_entry_fallback(targets, arg, '_404')
|
|
if isinstance(targets, dict):
|
|
continue
|
|
return targets, args
|
|
|
|
# Try to match an index entry
|
|
return get_dict_entry_fallback(targets, '', '_index'), args
|
|
|
|
def get_entry_for_url(url, args):
|
|
targets = get_url_content(url)
|
|
if not targets:
|
|
return None
|
|
|
|
entry, args = get_entry(args, targets)
|
|
if not entry:
|
|
return None
|
|
if entry.startswith('include:'):
|
|
entry = entry.split(':', 1)[1]
|
|
return get_entry_for_url(entry, args)
|
|
return entry
|
|
|
|
|
|
def handle(event, context):
|
|
|
|
args = event.path.split('/')
|
|
|
|
url = get_entry_for_url(mapper_file, args)
|
|
|
|
|
|
if not url:
|
|
return {
|
|
"statusCode": 404,
|
|
"body": "URL not found"
|
|
}
|
|
|
|
return {
|
|
"statusCode": 302,
|
|
"body": url,
|
|
"headers": {
|
|
"Location": url
|
|
}
|
|
}
|