# ------------------------------------------------------------------------------
dist_doc_DATA = \
- COPYING
+ COPYING \
+ README
# ------------------------------------------------------------------------------
src/buildservice/database.py \
src/buildservice/decorators.py \
src/buildservice/distribution.py \
+ src/buildservice/geoip.py \
src/buildservice/git.py \
src/buildservice/keys.py \
src/buildservice/logs.py \
crondir = $(sysconfdir)/cron.d
+dist_geoip_DATA = \
+ src/geoip/GeoLite2-Country.mmdb
+
+geoipdir = $(datadir)/geoip
+
+EXTRA_DIST += \
+ src/tools/update-geoip-database.sh
+
# ------------------------------------------------------------------------------
substitutions = \
--- /dev/null
+
+REQUIREMENTS
+ Python modules:
+ * geoip2
+
+
+This product includes GeoLite2 data created by MaxMind, available from
+ https://dev.maxmind.com/geoip/geoip2/geolite2/
user = pakfire
pass = pakfire
db = pakfire
-
-[geoip-database]
-; Credentials to the geoip database.
-
-host = mysql-master.ipfire.org
-user = pakfire
-pass = pakfire
-db = geoip
from . import cache
from . import database
from . import distribution
+from . import geoip
from . import keys
from . import logs
from . import messages
# Read configuration file.
self.config = self.read_config(config_file)
- # Connect to databases.
- self.geoip_db = self.connect_database("geoip-database")
-
# Global pakfire settings (from database).
self.settings = settings.Settings(self)
self.arches = arches.Arches(self)
self.builds = builds.Builds(self)
self.cache = cache.Cache(self)
- self.geoip = mirrors.GeoIP(self)
+ self.geoip = geoip.GeoIP(self)
self.jobs = builds.Jobs(self)
self.builders = builders.Builders(self)
self.distros = distribution.Distributions(self)
"""
return self.backend
- @property
- def geoip(self):
- return self.backend.geoip
-
class DataObject(Object):
# Table name
# Import all constants from the pakfire module.
from pakfire.constants import *
+# XXX must be set by configure
+DATADIR = "/usr/share/pakfire-build-service"
+
PAKFIRE_DIR = "/pakfire"
PACKAGES_DIR = os.path.join(PAKFIRE_DIR, "packages")
BUILD_RELEASE_DIR = os.path.join(PACKAGES_DIR, "release")
--- /dev/null
+#!/usr/bin/python
+
+import geoip2.database
+import geoip2.errors
+import os.path
+
+from . import base
+
+from .constants import DATADIR
+
+class GeoIP(base.Object):
+ def init(self):
+ path = os.path.join(DATADIR, "geoip/GeoLite2-Country.mmdb")
+
+ # Open the database
+ self.db = geoip2.database.Reader(path)
+
+ def guess_from_address(self, address):
+ # Query the database
+ try:
+ result = self.db.country(address)
+
+ # Return nothing if the address could not be found
+ except geoip2.errors.AddressNotFoundError:
+ return
+
+ if result:
+ return result.country.iso_code
from . import base
from . import logs
-class GeoIP(object):
- def __init__(self, pakfire):
- self.pakfire = pakfire
-
- self.db = self.pakfire.geoip_db
-
- def __encode_ip(self, addr):
- # We get a tuple if there were proxy headers.
- addr = addr.split(", ")
- if addr:
- addr = addr[-1]
-
- # ip is calculated as described in http://dev.maxmind.com/geoip/csv
- try:
- a1, a2, a3, a4 = addr.split(".")
-
- a1 = int(a1)
- a2 = int(a2)
- a3 = int(a3)
- a4 = int(a4)
- except:
- return 0
-
- return (16777216 * a1) + (65536 * a2) + (256 * a3) + a4
-
- def get_all(self, addr):
- addr = self.__encode_ip(addr)
-
- ret = self.db.get("\
- SELECT * FROM locations \
- JOIN addresses ON addresses.location = locations.id \
- WHERE \
- %s BETWEEN addresses.start_ip_num AND addresses.end_ip_num \
- LIMIT 1", addr)
-
- # If location was not determinable
- if ret and ret.latitude == 0 and ret.longitude == 0:
- return None
-
- return ret
-
+from .decorators import lazy_property
class Mirrors(base.Object):
def get_all(self):
return Mirror(self.pakfire, mirror.id)
def get_for_location(self, addr):
- distance = 10
+ country_code = self.backend.geoip.guess_from_address(addr)
- # Get all mirrors in here.
- _mirrors = self.get_all()
+ # Cannot return any good mirrors if location is unknown
+ if not country_code:
+ return []
mirrors = []
- while len(mirrors) <= 2 and distance <= 270:
- for mirror in _mirrors:
- if not mirror.enabled:
- continue
- if mirror in mirrors:
- continue
+ # Walk through all mirrors
+ for mirror in self.get_all():
+ if not mirror.enabled:
+ continue
- # Cannot calc the distance for mirrors when their location is unknown.
- if mirror.location is None:
- continue
+ if mirror.country_code == country_code:
+ mirrors.append(mirror)
- if mirror.distance_to(addr) <= distance:
- mirrors.append(mirror)
-
- distance *= 1.2
+ # XXX needs to search for nearby countries
return mirrors
def address(self):
return socket.gethostbyname(self.hostname)
- @property
- def location(self):
- if self._location is None:
- self._location = self.geoip.get_all(self.address)
-
- return self._location
-
- @property
+ @lazy_property
def country_code(self):
- if self.location:
- return self.location.country_code
-
- return "UNKNOWN"
-
- @property
- def latitude(self):
- if self.location:
- return self.location.latitude
-
- return 0
-
- @property
- def longitude(self):
- if self.location:
- return self.location.longitude
-
- return 0
-
- def distance_to(self, addr):
- location = self.geoip.get_all(addr)
- if not location:
- return 0
-
- #if location.country_code.lower() in self.prefer_for_countries:
- # return 0
-
- distance_vector = (
- self.latitude - location.latitude,
- self.longitude - location.longitude
- )
-
- distance = 0
- for i in distance_vector:
- distance += i**2
-
- return math.sqrt(distance)
+ return self.backend.geoip.guess_from_address(self.address) or "UNKNOWN"
def get_history(self, *args, **kwargs):
kwargs["mirror"] = self
</div>
<div class="span6">
- {% if mirror.longitude and mirror.latitude %}
- <iframe width="100%" height="350" frameborder="0" scrolling="no" marginheight="0" marginwidth="0"
- src="http://www.openstreetmap.org/export/embed.html?bbox={{ mirror.longitude - 4 }},{{ mirror.latitude - 4 }},{{ mirror.longitude + 4 }},{{ mirror.latitude + 4 }}&layer=mapquest&marker={{ mirror.latitude }},{{ mirror.longitude }}" style="border: 1px solid black">
- </iframe>
- <p>
- <a href="http://www.openstreetmap.org/?lat={{ mirror.latitude }}&lon={{ mirror.longitude }}&zoom=8&layers=M&mlat={{ mirror.latitude }}&mlon={{ mirror.longitude }}" target="_blank">{{ _("View larger map") }}</a>
- -
- © <a href="http://www.openstreetmap.org/" target="_blank">OpenStreetMap</a> contributors, CC-BY-SA
- </p>
- <p class="muted">
- {{ _("The location of the mirror server is estimated by the IP address.") }}
- </p>
- {% else %}
- <p class="muted">
- {{ _("The location of the mirror server could not be estimated.") }}
- </p>
- {% end %}
+ <p class="muted">
+ {{ _("The location of the mirror server could not be estimated.") }}
+ </p>
</div>
</div>
--- /dev/null
+#!/bin/bash
+
+URL="http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.tar.gz"
+
+tmpfile=$(mktemp)
+
+# Download the file
+if ! wget "${URL}" -O "${tmpfile}"; then
+ echo "Could not download the database file" >&2
+ unlink "${tmpfile}"
+
+ exit 1
+fi
+
+# Extract database from tarball
+if ! tar xvOf "${tmpfile}" "*/GeoLite2-Country.mmdb" > src/geoip/GeoLite2-Country.mmdb; then
+ echo "Could not extract the database" >&2
+ unlink "${tmpfile}"
+
+ exit 1
+fi
+
+echo "OK"
+exit 0