Created
November 26, 2013 19:42
-
-
Save wido/7664859 to your computer and use it in GitHub Desktop.
PowerDNS backend for Ceph's RGW It responds with a CNAME to the correct bucket location
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
from flask import abort, Flask, request, Response | |
import json | |
import subprocess | |
listen_port = 6780 | |
listen_addr = "0.0.0.0" | |
debug_mode = True | |
# The DNS zone this backend serves for | |
dns_zone = "o.myobject.store" | |
dns_soa_ttl = 3600 | |
dns_default_ttl = 60 | |
# Map region names to hostnames | |
region_map = {} | |
region_map.update({'eu': 'o.myobject.eu'}) | |
# The Flask App | |
app = Flask(__name__) | |
# PowerDNS expects a 200 what ever happends and always wants | |
# 'result' to 'true' if the query fails | |
def abort_early(): | |
return json.dumps({'result': 'true'}) + "\n" | |
# Call radosgw-admin to get bucket metadata information | |
def get_radosgw_metadata(key): | |
try: | |
info = subprocess.check_output(["radosgw-admin", "metadata", "get", key]) | |
except subprocess.CalledProcessError as e: | |
return None | |
return json.loads(info) | |
# Returns a string of the region where the bucket is in | |
def get_bucket_region(bucket): | |
meta = get_radosgw_metadata("bucket:%s" % bucket) | |
bucket_id = meta['data']['bucket']['bucket_id'] | |
meta_instance = get_radosgw_metadata("bucket.instance:%s:%s" % (bucket, bucket_id)) | |
region = meta_instance['data']['bucket_info']['region'] | |
return region | |
# Returns the correct host for the bucket based on the region | |
def get_bucket_host(bucket): | |
region = get_bucket_region(bucket) | |
return bucket + "." + region_map[region] | |
@app.route('/') | |
def index(): | |
abort(404) | |
@app.route("/dns/lookup/<qname>/<qtype>") | |
def bucket_location(qname, qtype): | |
if len(qname) == 0: | |
return abort_early() | |
split = qname.split(".", 1) | |
if len(split) != 2: | |
return abort_early() | |
bucket = split[0] | |
zone = split[1] | |
# If the received qname doesn't match our zone abort | |
if zone != dns_zone: | |
return abort_early() | |
# We do not serve MX records | |
if qtype == "MX": | |
return abort_early() | |
# The basic result we always return | |
response = {'result': 'true'} | |
result = {} | |
# A hardcoded SOA response | |
if qtype == "SOA": | |
result.update({'qtype': qtype}) | |
result.update({'qname': qname}) | |
result.update({'content':'dns1.icann.org. hostmaster.icann.org. 2012080849 7200 3600 1209600 3600'}) | |
result.update({'ttl': dns_soa_ttl}) | |
else: | |
region_hostname = get_bucket_host(bucket) | |
result.update({'qtype': 'CNAME'}) | |
result.update({'qname': qname}) | |
result.update({'content': region_hostname}) | |
result.update({'ttl': dns_default_ttl}) | |
if len(result) > 0: | |
res = [] | |
res.append(result) | |
response['result'] = res | |
return json.dumps(response) + "\n" | |
if __name__ == '__main__': | |
app.debug = debug_mode | |
app.run(host=listen_addr, port=listen_port) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment