--- /dev/null
+#!/usr/bin/python
+
+import io
+import gzip
+import json
+import os
+import re
+import socket
+import subprocess
+import sys
+
+import fireinfo
+
+SETTINGS_FILE = "/var/ipfire/freifunk/settings"
+INTERFACES = ("green0", "blue0", "orange0")
+
+class Settings(object):
+ __expr = re.compile(r"^([A-Za-z_][A-Za-z0-9_]*)=([A-Za-z0-9=/,.:%_@#+-]*)$")
+
+ def __init__(self, file):
+ self._data = self.__parse(file)
+
+ def __parse(self, file):
+ ret = {}
+
+ with open(file, "r") as f:
+ for line in f.readlines():
+ m = re.match(self.__expr, line)
+ if not m:
+ continue
+
+ k, v = m.groups()
+ ret[k] = v
+
+ return ret
+
+ def get(self, key):
+ return self._data.get(key, None)
+
+
+class Announce(object):
+ id = None
+
+ def __init__(self):
+ self.settings = Settings(SETTINGS_FILE)
+
+ def generate_message(self):
+ raise NotImplementedError
+
+ def __call__(self):
+ enabled = self.settings.get("FREIFUNK_ENABLED")
+ if not enabled == "on":
+ return
+
+ # Generate message
+ msg = self.generate_message()
+
+ # Always send the node id
+ msg.update({
+ "node_id" : self.node_id,
+ })
+
+ # Export to JSON format
+ j = json.dumps(msg)
+
+ return self.send(j)
+
+ def send(self, msg):
+ debug = os.environ.get("DEBUG")
+ if debug:
+ print msg
+ return
+
+ # Compress message with GZIP
+ msg = self.compress(msg)
+
+ command = ["/usr/sbin/alfred", "-s", "%s" % self.id]
+ p = subprocess.Popen(command, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (stdout, stderr) = p.communicate(msg)
+
+ retval = p.wait()
+ if retval > 0:
+ print "alfred exited with code: %s" % retval
+ print stdout
+ print stderr
+ sys.exit(retval)
+
+ @staticmethod
+ def compress(s):
+ b = io.BytesIO()
+
+ g = gzip.GzipFile(fileobj=b, mode="wb")
+ g.write(s)
+ g.close()
+
+ return b.getvalue()
+
+ @property
+ def node_id(self):
+ return self.primary_address.replace(":", "")
+
+ @property
+ def primary_address(self):
+ for intf in INTERFACES:
+ addr = self.get_address(intf)
+ if not addr:
+ continue
+
+ return addr
+
+ @staticmethod
+ def get_address(intf):
+ try:
+ with open("/sys/class/net/%s/address" % intf) as f:
+ mac_address = f.read()
+
+ if mac_address:
+ return mac_address.strip()
+ except IOError:
+ pass
+
+
+class AnnounceNodeinfo(Announce):
+ id = 158
+
+ def generate_message(self):
+ ret = {
+ "hardware" : self.hardware,
+ "hostname" : self.hostname,
+ "location" : self.location,
+ "software" : self.software,
+ }
+
+ return ret
+
+ @property
+ def hostname(self):
+ """
+ Returns the fully-qualified domain name
+ of this machine.
+ """
+ return self.settings.get("FREIFUNK_HOSTNAME") or socket.getfqdn()
+
+ @property
+ def location(self):
+ latitude = self.settings.get("FREIFUNK_LATITUDE")
+ longitude = self.settings.get("FREIFNK_LONGITUDE")
+
+ if latitude and longitude:
+ return {
+ "latitude" : latitude,
+ "longitude" : longitude,
+ }
+
+ @property
+ def software(self):
+ return {
+ "firmware" : {
+ "base" : self.firmware_base,
+ "release" : self.firmware_release,
+ },
+ }
+
+ @property
+ def firmware_base(self):
+ return "IPFire"
+
+ @property
+ def firmware_release(self):
+ with open("/etc/system-release") as f:
+ release = f.read()
+
+ if release:
+ return release.strip()
+
+ @property
+ def hardware(self):
+ system = fireinfo.System()
+
+ return {
+ "fireinfo" : system.public_id,
+ }
+
+
+class AnnounceStats(Announce):
+ id = 159
+
+ def generate_message(self):
+ return {}
+
+
+def main():
+ basename = sys.argv[0]
+
+ if basename == "alfred-announce-nodeinfo":
+ a = AnnounceNodeinfo()
+
+ elif basename == "alfred-announce-stats":
+ a = AnnounceStats()
+
+ else:
+ print "Called with unknown basename"
+ sys.exit(1)
+
+ # Run the selected action
+ a()
+
+main()
+etc/fcron.cyclic/alfred-announce-nodeinfo
+etc/fcron.cyclic/alfred-announce-stats
usr/sbin/alfred
+usr/sbin/alfred-announce-nodeinfo
+usr/sbin/alfred-announce-stats
usr/sbin/batadv-vis
#usr/share/man/man8/alfred.8
#usr/share/man/man8/batadv-vis.8
my %settings = ();
&General::readhash("${General::swroot}/freifunk/settings", \%settings);
+ my %mainsettings = ();
+ &General::readhash("${General::swroot}/main/settings", \%mainsettings);
+
+ my $network = &GetNetwork($settings{"FREIFUNK_COMMUNITY"});
+ return unless (defined($network));
+
# Create fastd secret if none is set
if ($settings{'FASTD_SECRET'} eq '') {
$settings{'FASTD_SECRET'} = &fastdCreateKey();
+ }
- &General::writehash("${General::swroot}/freifunk/settings", \%settings);
+ # Make hostname
+ my $hostname = $mainsettings{"HOSTNAME"} . "." . $mainsettings{"DOMAINNAME"};
+ if ($network->{"prefix"}) {
+ $hostname = $network->{"prefix"} . $hostname;
}
+ $settings{"FREIFUNK_HOSTNAME"} = $hostname;
- my $network = &GetNetwork($settings{"FREIFUNK_COMMUNITY"});
- if ($network) {
- # Write configuration bits...
- open(FILE, ">$FASTD_CONFIG");
+ &General::writehash("${General::swroot}/freifunk/settings", \%settings);
- print FILE "# Logging\n";
- print FILE "log level error;\n";
- print FILE "log to syslog level info;\n\n";
+ # Write configuration bits...
+ open(FILE, ">$FASTD_CONFIG");
- print FILE "# Drop privileges\n";
- print FILE "user \"nobody\";\n\n";
+ print FILE "# Logging\n";
+ print FILE "log level error;\n";
+ print FILE "log to syslog level info;\n\n";
- print FILE "interface \"batvpn0\";\n";
- print FILE "mode tap;\n\n";
+ print FILE "# Drop privileges\n";
+ print FILE "user \"nobody\";\n\n";
- print FILE "# Authentication credentials\n";
- print FILE "secret \"$settings{'FASTD_SECRET'}\";\n";
- print FILE "secure handshakes yes;\n\n";
+ print FILE "interface \"batvpn0\";\n";
+ print FILE "mode tap;\n\n";
- print FILE "# Ciphers\n";
- my $ciphers = $network->{'ciphers'};
- foreach my $cipher (@$ciphers) {
- print FILE "method \"$cipher\";\n";
- }
- print FILE "\n";
+ print FILE "# Authentication credentials\n";
+ print FILE "secret \"$settings{'FASTD_SECRET'}\";\n";
+ print FILE "secure handshakes yes;\n\n";
- print FILE "# Upstream connection\n";
- print FILE "mtu $network->{'mtu-vpn'};\n";
+ print FILE "# Ciphers\n";
+ my $ciphers = $network->{'ciphers'};
+ foreach my $cipher (@$ciphers) {
+ print FILE "method \"$cipher\";\n";
+ }
+ print FILE "\n";
- my $nodes = $network->{'supernodes'};
- foreach my $node (@$nodes) {
- print FILE "peer \"$node->{'peer'}\" {\n";
- print FILE "\tkey \"$node->{'key'}\";\n";
- print FILE "\tremote \"$node->{'remote'}\" port $node->{'port'};\n";
- print FILE "}\n";
- }
- print FILE "\n";
+ print FILE "# Upstream connection\n";
+ print FILE "mtu $network->{'mtu-vpn'};\n";
- print FILE "# Hooks\n";
- foreach my $hook ("pre-up", "up") {
- print FILE "on $hook \"/etc/rc.d/init.d/freifunk on-$hook\";\n";
- }
+ my $nodes = $network->{'supernodes'};
+ foreach my $node (@$nodes) {
+ print FILE "peer \"$node->{'peer'}\" {\n";
+ print FILE "\tkey \"$node->{'key'}\";\n";
+ print FILE "\tremote \"$node->{'remote'}\" port $node->{'port'};\n";
+ print FILE "}\n";
+ }
+ print FILE "\n";
- close(FILE);
+ print FILE "# Hooks\n";
+ foreach my $hook ("pre-up", "up") {
+ print FILE "on $hook \"/etc/rc.d/init.d/freifunk on-$hook\";\n";
}
+ close(FILE);
+
# Restart the service.
if ($settings{'FREIFUNK_ENABLED'} eq 'on') {
system("/usr/local/bin/freifunkctrl restart &>/dev/null");
@rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar axf $(DIR_DL)/$(DL_FILE)
cd $(DIR_APP) && make $(OPTIONS) $(MAKETUNING)
cd $(DIR_APP) && make $(OPTIONS) install
+
+ # Announce scripts
+ install -v -m 755 $(DIR_SRC)/config/alfred/announce.py \
+ /usr/sbin/alfred-announce-nodeinfo
+ ln -svf alfred-announce-nodeinfo /usr/sbin/alfred-announce-stats
+
+ # Install cron jobs
+ ln -svf ../../usr/sbin/alfred-announce-nodeinfo \
+ /etc/fcron.cyclic/alfred-announce-nodeinfo
+ ln -svf ../../usr/sbin/alfred-announce-stats \
+ /etc/fcron.cyclic/alfred-announce-stats
+
@rm -rf $(DIR_APP)
@$(POSTBUILD)