[8280] | 1 | #!/usr/bin/env python
|
---|
| 2 | # vim:ts=2:et:sw=2:ai
|
---|
| 3 | #
|
---|
| 4 | # Build topological network graph
|
---|
| 5 | # Rick van der Zwet <info@rickvanderzwet.nl>
|
---|
| 6 | import re
|
---|
| 7 | import sys
|
---|
| 8 | import glob
|
---|
| 9 | import tempfile
|
---|
| 10 | import subprocess
|
---|
| 11 | import gformat
|
---|
| 12 |
|
---|
| 13 | import urllib
|
---|
| 14 | import re
|
---|
| 15 | import yaml
|
---|
| 16 |
|
---|
| 17 | def get_yaml(gfile):
|
---|
| 18 | """ Get configuration yaml for 'item'"""
|
---|
| 19 | f = open(gfile, 'r')
|
---|
| 20 | datadump = yaml.load(f)
|
---|
| 21 | return datadump
|
---|
| 22 |
|
---|
| 23 | def write_yaml(gfile, datadump):
|
---|
| 24 | """ Write configuration yaml for 'item'"""
|
---|
| 25 | f = open(gfile, 'w')
|
---|
| 26 | f.write(yaml.dump(datadump, default_flow_style=False))
|
---|
| 27 | f.close()
|
---|
| 28 |
|
---|
| 29 | CACHE_FILE = '/tmp/rd2etrs.yaml'
|
---|
| 30 | coordinates = None
|
---|
| 31 |
|
---|
| 32 | def rd2etrs(xrd, yrd, hnap=0.0):
|
---|
| 33 | """ Convert rd to etrs """
|
---|
| 34 | global coordinates
|
---|
| 35 | if coordinates == None:
|
---|
| 36 | try:
|
---|
| 37 | coordinates = get_yaml(CACHE_FILE)
|
---|
| 38 | if coordinates.has_key((xrd, yrd)):
|
---|
| 39 | return coordinates[(xrd, yrd)]
|
---|
| 40 | except (IOError,AttributeError):
|
---|
| 41 | coordinates = dict()
|
---|
| 42 | pass
|
---|
| 43 |
|
---|
| 44 | item = dict()
|
---|
| 45 | item['xrd'] = xrd
|
---|
| 46 | item['yrd'] = yrd
|
---|
| 47 | item['hnap'] = hnap
|
---|
| 48 | f = urllib.urlopen('http://www.rdnap.nl/cgi-bin/rdetrs.pl?func=rd2etrs&xrd=%(xrd)s&yrd=%(yrd)s&hnap=%(hnap)s' % item)
|
---|
| 49 | raw = f.read()
|
---|
| 50 |
|
---|
| 51 | r = re.compile('name="([a-z_]+)" value="([0-9\.]+)"')
|
---|
| 52 | for i in r.finditer(raw):
|
---|
| 53 | name, value = i.group(1,2)
|
---|
| 54 | value = float(value)
|
---|
| 55 | item[name] = value
|
---|
| 56 |
|
---|
| 57 | lam = item['lam_deg'] + (item['lam_min'] + (item['lam_sec'] / 60)) / 60
|
---|
| 58 | phi = item['phi_deg'] + (item['phi_min'] + (item['phi_sec'] / 60)) / 60
|
---|
| 59 | coordinates[(xrd, yrd)] = (phi, lam)
|
---|
| 60 | write_yaml(CACHE_FILE, coordinates)
|
---|
| 61 | return (lam, phi)
|
---|
| 62 |
|
---|
| 63 | OUTFILE = 'network.png'
|
---|
| 64 |
|
---|
| 65 | def make_graph():
|
---|
[8282] | 66 | f = open('kmlfile.kml', 'w')
|
---|
| 67 | f.write("""
|
---|
| 68 | <?xml version="1.0" encoding="UTF-8"?>
|
---|
| 69 | <kml xmlns="http://earth.google.com/kml/2.0">
|
---|
| 70 | <Document>
|
---|
| 71 | <name>KML Samples</name>
|
---|
| 72 | <open>1</open>
|
---|
| 73 | <description>Unleash your creativity with the help of these examples!</description>
|
---|
| 74 | <Style id="downArrowIcon">
|
---|
| 75 | <IconStyle>
|
---|
| 76 | <Icon>
|
---|
| 77 | <href>http://maps.google.com/mapfiles/kml/pal4/icon28.png</href>
|
---|
| 78 | </Icon>
|
---|
| 79 | </IconStyle>
|
---|
| 80 | </Style>
|
---|
| 81 | <Style id="globeIcon">
|
---|
| 82 | <IconStyle>
|
---|
| 83 | <Icon>
|
---|
| 84 | <href>http://maps.google.com/mapfiles/kml/pal3/icon19.png</href>
|
---|
| 85 | </Icon>
|
---|
| 86 | </IconStyle>
|
---|
| 87 | <LineStyle>
|
---|
| 88 | <width>2</width>
|
---|
| 89 | </LineStyle>
|
---|
| 90 | </Style>
|
---|
| 91 | <Style id="transPurpleLineGreenPoly">
|
---|
| 92 | <LineStyle>
|
---|
| 93 | <color>7fff00ff</color>
|
---|
| 94 | <width>4</width>
|
---|
| 95 | </LineStyle>
|
---|
| 96 | <PolyStyle>
|
---|
| 97 | <color>7f00ff00</color>
|
---|
| 98 | </PolyStyle>
|
---|
| 99 | </Style>
|
---|
| 100 | <Style id="yellowLineGreenPoly">
|
---|
| 101 | <LineStyle>
|
---|
| 102 | <color>7f00ffff</color>
|
---|
| 103 | <width>4</width>
|
---|
| 104 | </LineStyle>
|
---|
| 105 | <PolyStyle>
|
---|
| 106 | <color>7f00ff00</color>
|
---|
| 107 | </PolyStyle>
|
---|
| 108 | </Style>
|
---|
| 109 | <Style id="thickBlackLine">
|
---|
| 110 | <LineStyle>
|
---|
| 111 | <color>87000000</color>
|
---|
| 112 | <width>10</width>
|
---|
| 113 | </LineStyle>
|
---|
| 114 | </Style>
|
---|
| 115 | <Style id="redLineBluePoly">
|
---|
| 116 | <LineStyle>
|
---|
| 117 | <color>ff0000ff</color>
|
---|
| 118 | </LineStyle>
|
---|
| 119 | <PolyStyle>
|
---|
| 120 | <color>ffff0000</color>
|
---|
| 121 | </PolyStyle>
|
---|
| 122 | </Style>
|
---|
| 123 | <Style id="blueLineRedPoly">
|
---|
| 124 | <LineStyle>
|
---|
| 125 | <color>ffff0000</color>
|
---|
| 126 | </LineStyle>
|
---|
| 127 | <PolyStyle>
|
---|
| 128 | <color>ff0000ff</color>
|
---|
| 129 | </PolyStyle>
|
---|
| 130 | </Style>
|
---|
| 131 | <Style id="transRedPoly">
|
---|
| 132 | <LineStyle>
|
---|
| 133 | <width>1.5</width>
|
---|
| 134 | </LineStyle>
|
---|
| 135 | <PolyStyle>
|
---|
| 136 | <color>7d0000ff</color>
|
---|
| 137 | </PolyStyle>
|
---|
| 138 | </Style>
|
---|
| 139 | <Style id="transBluePoly">
|
---|
| 140 | <LineStyle>
|
---|
| 141 | <width>1.5</width>
|
---|
| 142 | </LineStyle>
|
---|
| 143 | <PolyStyle>
|
---|
| 144 | <color>7dff0000</color>
|
---|
| 145 | </PolyStyle>
|
---|
| 146 | </Style>
|
---|
| 147 | <Style id="transGreenPoly">
|
---|
| 148 | <LineStyle>
|
---|
| 149 | <width>1.5</width>
|
---|
| 150 | </LineStyle>
|
---|
| 151 | <PolyStyle>
|
---|
| 152 | <color>7d00ff00</color>
|
---|
| 153 | </PolyStyle>
|
---|
| 154 | </Style>
|
---|
| 155 | <Style id="transYellowPoly">
|
---|
| 156 | <LineStyle>
|
---|
| 157 | <width>1.5</width>
|
---|
| 158 | </LineStyle>
|
---|
| 159 | <PolyStyle>
|
---|
| 160 | <color>7d00ffff</color>
|
---|
| 161 | </PolyStyle>
|
---|
| 162 | </Style>
|
---|
| 163 | <Style id="noDrivingDirections">
|
---|
| 164 | <BalloonStyle>
|
---|
| 165 | <text><![CDATA[
|
---|
| 166 | <b>$[name]</b>
|
---|
| 167 | <br /><br />
|
---|
| 168 | $[description]
|
---|
| 169 | ]]></text>
|
---|
| 170 | </BalloonStyle>
|
---|
| 171 | </Style>
|
---|
| 172 | <Folder>
|
---|
| 173 | <name>Paths</name>
|
---|
| 174 | <visibility>0</visibility>
|
---|
| 175 | <description>Examples of paths. Note that the tessellate tag is by default
|
---|
| 176 | set to 0. If you want to create tessellated lines, they must be authored
|
---|
| 177 | (or edited) directly in KML.</description>
|
---|
| 178 | """)
|
---|
| 179 |
|
---|
[8280] | 180 | poel = {}
|
---|
| 181 | link_type = {}
|
---|
| 182 | node = {}
|
---|
| 183 |
|
---|
| 184 | nodes = []
|
---|
| 185 | links = []
|
---|
| 186 | try:
|
---|
| 187 | for host in gformat.get_proxylist() + gformat.get_nodelist():
|
---|
| 188 | print "## Processing host", host
|
---|
| 189 | datadump = gformat.get_yaml(host)
|
---|
| 190 | iface_keys = [elem for elem in datadump.keys() if (elem.startswith('iface_') and not "lo0" in elem)]
|
---|
| 191 | for iface_key in iface_keys:
|
---|
| 192 | l = datadump[iface_key]['ip']
|
---|
| 193 | addr, mask = l.split('/')
|
---|
| 194 |
|
---|
| 195 | addr = gformat.parseaddr(addr)
|
---|
| 196 | mask = int(mask)
|
---|
| 197 | addr = addr & ~((1 << (32 - mask)) - 1)
|
---|
| 198 | if poel.has_key(addr):
|
---|
| 199 | poel[addr] += [host]
|
---|
| 200 | else:
|
---|
| 201 | poel[addr] = [host]
|
---|
| 202 | # Assume all eth2wifibridge to be 11a for a moment
|
---|
| 203 | if datadump[iface_key].has_key('eth2wifibridge'):
|
---|
| 204 | link_type[addr] = '11a'
|
---|
| 205 | else:
|
---|
| 206 | link_type[addr] = datadump[iface_key]['type']
|
---|
| 207 | print "### %s [%s] is of type %s" % (gformat.showaddr(addr), iface_key, link_type[addr])
|
---|
| 208 | lam, phi = rd2etrs(datadump['rdnap_x'], datadump['rdnap_y'])
|
---|
| 209 | node[host] = (lam, phi)
|
---|
[8282] | 210 | f.write("""
|
---|
| 211 | <Placemark>
|
---|
| 212 | <name>Blue Icon</name>
|
---|
| 213 | <description>Just another blue icon.</description>
|
---|
| 214 | <styleUrl>./styles.kml#blueIcons</styleUrl>
|
---|
| 215 | <Point>
|
---|
| 216 | <coordinates>%s,%s,630</coordinates>
|
---|
| 217 | </Point>
|
---|
| 218 | </Placemark>
|
---|
| 219 | """ % (lam, phi))
|
---|
[8280] | 220 | nodes += [("POINT(%s, %s)" % (lam, phi))]
|
---|
| 221 | except (KeyError, ValueError), e:
|
---|
| 222 | print "[FOUT] in '%s' interface '%s'" % (host,iface_key)
|
---|
| 223 | print e
|
---|
| 224 | sys.exit(1)
|
---|
| 225 |
|
---|
| 226 | for addr,leden in poel.iteritems():
|
---|
| 227 | if link_type[addr] == '11a':
|
---|
| 228 | color = 'red'
|
---|
| 229 | weight = 4
|
---|
| 230 | elif link_type[addr] == 'eth':
|
---|
| 231 | color = 'blue'
|
---|
| 232 | weight = 8
|
---|
| 233 | else:
|
---|
| 234 | color = 'black'
|
---|
| 235 | weight = 1
|
---|
| 236 | leden = sorted(set(leden))
|
---|
| 237 | for index,lid in enumerate(leden[:-1]):
|
---|
| 238 | for buur in leden[index + 1:]:
|
---|
[8282] | 239 | f.write("""
|
---|
| 240 | <Placemark>
|
---|
| 241 | <name>Untessellated</name>
|
---|
| 242 | <visibility>0</visibility>
|
---|
| 243 | <description><![CDATA[If the <tessellate> tag has a value of 0, the line follow a simple straight-line path from point to point]]></description>
|
---|
| 244 | <LineString>
|
---|
| 245 | <tessellate>0</tessellate>
|
---|
| 246 | <coordinates> %s, %s, 0
|
---|
| 247 | %s , %s, 0 </coordinates>
|
---|
| 248 | </LineString>
|
---|
| 249 | </Placemark>
|
---|
| 250 | """ % (node[lid][0], node[lid][1], node[buur][0], node[buur][1]))
|
---|
| 251 | f.write("""
|
---|
| 252 | </Folder>
|
---|
| 253 | </Document>
|
---|
| 254 | </kml>
|
---|
| 255 | """)
|
---|
[8280] | 256 | f.close()
|
---|
| 257 |
|
---|
| 258 |
|
---|
| 259 | if __name__ == "__main__":
|
---|
| 260 | make_graph()
|
---|
| 261 |
|
---|