Initial commit of version 2
This commit is contained in:
commit
ff7105eedc
23 changed files with 782 additions and 0 deletions
23
cloud/Domaene.py
Normal file
23
cloud/Domaene.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
from cloud.LocalGraph import LocalGraph
|
||||
class Domaene(object):
|
||||
def __init__(self, name, shapes, globalGraph):
|
||||
self.name = name
|
||||
self.__shapes__ = shapes
|
||||
self.__globalGraph__ = globalGraph
|
||||
self.localGraphs = self.__getLocalGraphsInDomaene__()
|
||||
|
||||
def __getLocalGraphsInDomaene__(self):
|
||||
graphs = []
|
||||
for localGraph in self.__globalGraph__.localGraphs:
|
||||
if self.isLocalGraphInDomaene(localGraph) == True:
|
||||
graphs.append(localGraph)
|
||||
return graphs
|
||||
|
||||
def isLocalGraphInDomaene(self, localGraph):
|
||||
return self.isPointInDomaene(localGraph.getGeoCenterOfNodeCloud())
|
||||
|
||||
def isPointInDomaene(self, point):
|
||||
for shape in self.__shapes__.shapes:
|
||||
if point.within(shape):
|
||||
return True
|
||||
return False
|
46
cloud/GlobalGraph.py
Normal file
46
cloud/GlobalGraph.py
Normal file
|
@ -0,0 +1,46 @@
|
|||
from cloud.LocalGraph import LocalGraph
|
||||
from cloud.Graph import Graph
|
||||
from exceptions.HieraException import HieraException
|
||||
class GlobalGraph(Graph):
|
||||
def __init__(self, nodes, links, debugPrint = False):
|
||||
super().__init__(nodes, links)
|
||||
self.__enableDebugPrinting__ = debugPrint
|
||||
self.localGraphs = self.__buildLocalGraphs__()
|
||||
|
||||
if self.__enableDebugPrinting__:
|
||||
self.__debugPrint__()
|
||||
|
||||
def __buildLocalGraphs__(self):
|
||||
nodeIDs = self.getListOfNodeIDsOnline()
|
||||
localGraphs = []
|
||||
while len(nodeIDs) > 0:
|
||||
connectedNodes = self.__getConnectedNodes__(nodeIDs[0])
|
||||
try:
|
||||
localGraphs.append(self.__createLocalCloudByNodesList__(connectedNodes))
|
||||
print('Create LocalGraph object #',len(localGraphs), '\r',end = '')
|
||||
except HieraException:
|
||||
print('Was not able to add local cloud, because no VPN link was found.')
|
||||
nodeIDs = [x for x in nodeIDs if x not in connectedNodes]
|
||||
print('')
|
||||
return localGraphs
|
||||
|
||||
def __getConnectedNodes__(self, nodeID, trace = []):
|
||||
neighNodeIDs = self.getNeighbourNodeIDsForNodeID(nodeID)
|
||||
trace_new = trace[:] + [x for x in neighNodeIDs if x not in trace]
|
||||
for neighNodeID in neighNodeIDs:
|
||||
if neighNodeID not in trace:
|
||||
trace_new = trace_new + [x for x in self.__getConnectedNodes__(neighNodeID, trace_new) if x not in trace_new]
|
||||
return trace_new
|
||||
|
||||
def __createLocalCloudByNodesList__(self, nodesIDList):
|
||||
nodes = {}
|
||||
links = []
|
||||
for nodeID in nodesIDList:
|
||||
nodes[nodeID] = self.__nodes__[nodeID]
|
||||
links = links + [x for x in self.getLinksByNodeID(nodeID) if x not in links]
|
||||
return LocalGraph(nodes, links, self.__enableDebugPrinting__)
|
||||
|
||||
def __debugPrint__(self):
|
||||
for localGraph in self.localGraphs:
|
||||
for node in localGraph.getNodesWithNoDependencies():
|
||||
print(node.hostname, node.publicIPv6Addresses)
|
45
cloud/Graph.py
Normal file
45
cloud/Graph.py
Normal file
|
@ -0,0 +1,45 @@
|
|||
from oauthlib.oauth1.rfc5849 import endpoints
|
||||
class Graph(object):
|
||||
def __init__(self, nodes, links):
|
||||
self.__nodes__ = nodes
|
||||
self.__links__ = links
|
||||
|
||||
def getListOfNodeIDs(self, getGateways = False):
|
||||
nodeIDs = []
|
||||
for k, v in self.__nodes__.items():
|
||||
if getGateways == True or v.isGateway == False:
|
||||
nodeIDs.append(k)
|
||||
return nodeIDs
|
||||
|
||||
def getListOfNodeIDsOnline(self, getGateways = False):
|
||||
onlineNodeIDs = []
|
||||
nodeIDs = self.getListOfNodeIDs(getGateways)
|
||||
for nodeID in nodeIDs:
|
||||
if self.__nodes__[nodeID].isOnline == True:
|
||||
onlineNodeIDs.append(nodeID)
|
||||
return onlineNodeIDs
|
||||
|
||||
def getNeighbourNodeIDsForNodeID(self, nodeID):
|
||||
neighNodeIDs = [nodeID]
|
||||
endpoints = []
|
||||
for link in self.__links__:
|
||||
if link.isVpn == False:
|
||||
endpoints = link.getEndpointNodeIDs(getGateways = False)
|
||||
if nodeID in endpoints:
|
||||
neighNodeIDs = neighNodeIDs + [x for x in endpoints if x not in neighNodeIDs]
|
||||
return neighNodeIDs
|
||||
|
||||
def getLinksByNodeID(self, nodeID):
|
||||
links = []
|
||||
for link in self.__links__:
|
||||
endpoints = link.getEndpointNodeIDs()
|
||||
if nodeID in endpoints:
|
||||
if link not in links:
|
||||
links.append(link)
|
||||
return links
|
||||
|
||||
def getLinkCount(self):
|
||||
return len(self.__links__)
|
||||
|
||||
def getNodesCount(self):
|
||||
return len(self.__nodes__)
|
52
cloud/Link.py
Normal file
52
cloud/Link.py
Normal file
|
@ -0,0 +1,52 @@
|
|||
class Link(object):
|
||||
def __init__(self, LinkJsonObject, srcNode, dstNode):
|
||||
self.__jsonObject__ = LinkJsonObject
|
||||
self.__srcNode__ = srcNode
|
||||
self.__dstNode__ = dstNode
|
||||
self.linkType = self.__getLinkType__()
|
||||
self.isVpn = self.__getLinkVpnState__()
|
||||
|
||||
|
||||
def __getLinkType__(self):
|
||||
if self.__srcNode__ != None:
|
||||
for k, v in self.__srcNode__.interfaces.items():
|
||||
if self.__jsonObject__['source']['interface_mac'] in v:
|
||||
return k
|
||||
if self.__dstNode__ != None:
|
||||
for k, v in self.__dstNode__.interfaces.items():
|
||||
if self.__jsonObject__['target']['interface_mac'] in v:
|
||||
return k
|
||||
return 'unknown'
|
||||
|
||||
def __getLinkVpnState__(self):
|
||||
if self.__jsonObject__['vpn'] == True:
|
||||
return True
|
||||
for node in self.getEndpointNodes(getGateways = True):
|
||||
if node.isGateway == True:
|
||||
return True
|
||||
return False
|
||||
|
||||
def getEndpointNodes(self, getGateways = False):
|
||||
nodes = []
|
||||
if self.__srcNode__ != None:
|
||||
if getGateways == True or self.__srcNode__.isGateway == False:
|
||||
nodes.append(self.__srcNode__)
|
||||
if self.__dstNode__ != None:
|
||||
if getGateways == True or self.__dstNode__.isGateway == False:
|
||||
nodes.append(self.__dstNode__)
|
||||
return nodes
|
||||
|
||||
def getEndpointNodeIDs(self, getGateways = True):
|
||||
nodeIDs = []
|
||||
for node in self.getEndpointNodes(getGateways):
|
||||
nodeIDs.append(node.nodeID)
|
||||
return nodeIDs
|
||||
|
||||
def isNodeIDinLink(self, nodeID):
|
||||
for endpoint in self.getEndpointNodes():
|
||||
if endpoint.nodeID == nodeID:
|
||||
return True
|
||||
return False
|
||||
|
||||
def isNodeInLink(self, node):
|
||||
return self.isNodeIDinLink(node.nodeID)
|
118
cloud/LocalGraph.py
Normal file
118
cloud/LocalGraph.py
Normal file
|
@ -0,0 +1,118 @@
|
|||
from cloud.Graph import Graph
|
||||
from shapely.geometry import MultiPoint
|
||||
from exceptions.HieraException import HieraException
|
||||
class LocalGraph(Graph):
|
||||
def __init__(self, nodes, links, debugPrint = False):
|
||||
super().__init__(nodes, links)
|
||||
self.__enableDebugPrinting__ = debugPrint
|
||||
if self.__enableDebugPrinting__:
|
||||
self.__debugPrint__()
|
||||
|
||||
def getNodesWithVpn(self):
|
||||
nodes = []
|
||||
for link in self.__links__:
|
||||
if link.isVpn == True:
|
||||
nodes = nodes + [x for x in link.getEndpointNodes() if x not in nodes]
|
||||
return nodes
|
||||
|
||||
def getCountOfNodesWithVpn(self):
|
||||
return len(self.getNodesWithVpn())
|
||||
|
||||
def getDeptOfNode(self, node):
|
||||
return self.getDeptOfNodeByID(node.nodeID, [])
|
||||
|
||||
def getDeptOfNodeByID(self, nodeID, trace):
|
||||
if self.getCountOfNodesWithVpn() == 0:
|
||||
raise HieraException('No VPN Node in LocalCloud was found!')
|
||||
new_trace = trace[:]
|
||||
new_trace.append(nodeID)
|
||||
lowestDepth = None
|
||||
currentDept = None
|
||||
links = self.getLinksByNodeID(nodeID)
|
||||
endpoints = []
|
||||
for link in links:
|
||||
endpoints = endpoints + [x for x in link.getEndpointNodeIDs() if x not in endpoints]
|
||||
if link.isVpn == True:
|
||||
return 0
|
||||
for childNodeID in endpoints:
|
||||
if childNodeID not in new_trace:
|
||||
currentDept = self.getDeptOfNodeByID(childNodeID, new_trace + endpoints)
|
||||
if currentDept != None:
|
||||
currentDept = currentDept + 1
|
||||
if lowestDepth == None or currentDept < lowestDepth:
|
||||
lowestDepth = currentDept
|
||||
return lowestDepth
|
||||
|
||||
def getMaxDepth(self):
|
||||
maxDepth = 0
|
||||
for k,v in self.__nodes__.items():
|
||||
nodeDepth = self.getDeptOfNode(v)
|
||||
maxDepth = nodeDepth if nodeDepth > maxDepth else maxDepth
|
||||
return maxDepth
|
||||
|
||||
def getAllNodesWithDepthEquals(self, depth):
|
||||
nodes = []
|
||||
for k,v in self.__nodes__.items():
|
||||
if self.getDeptOfNode(v) == depth:
|
||||
nodes.append(v)
|
||||
return nodes
|
||||
|
||||
def getNodesWithNoDependencies(self):
|
||||
#TODO: Implement smarter selection
|
||||
return self.getAllNodesWithDepthEquals(self.getMaxDepth())
|
||||
|
||||
def isAutoupdaterEnabledOnAllNodes(self):
|
||||
for k, v in self.__nodes__.items():
|
||||
if v.isAutoupdaterEnabled == False:
|
||||
return False
|
||||
return True
|
||||
|
||||
def getLanLinksInCloud(self):
|
||||
links = []
|
||||
for link in self.__links__:
|
||||
if link.linkType == 'other' and link.isVpn == False:
|
||||
links.append(link)
|
||||
return links
|
||||
|
||||
def areLanLinksInCloud(self):
|
||||
for link in self.__links__:
|
||||
if link.linkType == 'other' and link.isVpn == False:
|
||||
return True
|
||||
return False
|
||||
|
||||
def getBranchesThatExistsInCloud(self):
|
||||
branches = []
|
||||
for k, v in self.__nodes__.items():
|
||||
if v.autoupdaterBranch not in branches:
|
||||
branches.append(v.autoupdaterBranch)
|
||||
return branches
|
||||
|
||||
def getGeoCenterOfNodeCloud(self):
|
||||
geoPoints = []
|
||||
for k, v in self.__nodes__.items():
|
||||
if v.geo != None:
|
||||
geoPoints.append((v.geo['lon'], v.geo['lat']))
|
||||
return MultiPoint(geoPoints).representative_point()
|
||||
|
||||
def __debugPrint__(self):
|
||||
print('nodes:')
|
||||
for k,v in self.__nodes__.items():
|
||||
print('>',v.hostname)
|
||||
|
||||
print('nodes with vpn:')
|
||||
for node in self.getNodesWithVpn():
|
||||
print('>',node.hostname)
|
||||
|
||||
print('nodes with no dependencies:')
|
||||
for node in self.getNodesWithNoDependencies():
|
||||
print('>', node.hostname)
|
||||
|
||||
print('maxdepth:', self.getMaxDepth())
|
||||
print('isAutoupdaterEnabledOnAllNodes:', self.isAutoupdaterEnabledOnAllNodes())
|
||||
print('areLanLinksInCloud:', self.areLanLinksInCloud())
|
||||
print('BranchesThatExistsInCloud:', self.getBranchesThatExistsInCloud())
|
||||
print('lan links in cloud:')
|
||||
for link in self.getLanLinksInCloud():
|
||||
if link.__srcNode__ != None and link.__dstNode__ != None:
|
||||
print(' ', link.__srcNode__.hostname, '<--->', link.__dstNode__.hostname)
|
||||
print('=====')
|
4
cloud/Node.py
Normal file
4
cloud/Node.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
from cloud.NodeInit import NodeInit
|
||||
class Node(NodeInit):
|
||||
def __init__(self, NodeJsonObject):
|
||||
super().__init__(NodeJsonObject)
|
54
cloud/NodeInit.py
Normal file
54
cloud/NodeInit.py
Normal file
|
@ -0,0 +1,54 @@
|
|||
class NodeInit(object):
|
||||
def __init__(self, NodeJsonObject):
|
||||
self.__jsonObject__ = NodeJsonObject
|
||||
self.nodeID = self.__jsonObject__['nodeinfo']['node_id']
|
||||
self.interfaces = self.__getInterfaces__()
|
||||
self.hostname = self.__jsonObject__['nodeinfo']['hostname']
|
||||
self.isGateway = self.__jsonObject__['flags']['gateway']
|
||||
self.geo = self.__getGeo__()
|
||||
self.isAutoupdaterEnabled = self.__getAutoupdaterStatus__()
|
||||
self.autoupdaterBranch = self.__getBranch__()
|
||||
self.isOnline = self.__jsonObject__['flags']['online']
|
||||
self.publicIPv6Addresses = self.__getPublicAddresses__()
|
||||
self.domID = self.__getSiteCode__()
|
||||
|
||||
def __getInterfaces__(self):
|
||||
try:
|
||||
return self.__jsonObject__['nodeinfo']['network']['mesh']['bat0']['interfaces']
|
||||
except:
|
||||
return {}
|
||||
|
||||
def __getAutoupdaterStatus__(self):
|
||||
if 'autoupdater' in self.__jsonObject__['nodeinfo']['software']:
|
||||
return self.__jsonObject__['nodeinfo']['software']['autoupdater']['enabled']
|
||||
else:
|
||||
return False
|
||||
|
||||
def __getBranch__(self):
|
||||
if 'autoupdater' in self.__jsonObject__['nodeinfo']['software']:
|
||||
return self.__jsonObject__['nodeinfo']['software']['autoupdater']['branch']
|
||||
else:
|
||||
return None
|
||||
|
||||
def __getGeo__(self):
|
||||
geo = {}
|
||||
if 'location' in self.__jsonObject__['nodeinfo'] and 'latitude' in self.__jsonObject__['nodeinfo']['location'] and 'longitude' in self.__jsonObject__['nodeinfo']['location']:
|
||||
geo['lat'] = self.__jsonObject__['nodeinfo']['location']['latitude']
|
||||
geo['lon'] = self.__jsonObject__['nodeinfo']['location']['longitude']
|
||||
return geo
|
||||
return None
|
||||
|
||||
def __getPublicAddresses__(self):
|
||||
addresses = []
|
||||
if 'addresses' in self.__jsonObject__['nodeinfo']['network']:
|
||||
for address in self.__jsonObject__['nodeinfo']['network']['addresses']:
|
||||
#TODO: make more generic
|
||||
if address.startswith('2a03'):
|
||||
addresses.append(address)
|
||||
return addresses
|
||||
|
||||
def __getSiteCode__(self):
|
||||
try:
|
||||
return self.__jsonObject__['nodeinfo']['system']['site_code']
|
||||
except:
|
||||
return None
|
0
cloud/__init__.py
Normal file
0
cloud/__init__.py
Normal file
Loading…
Add table
Add a link
Reference in a new issue