2 #Copyright (C) 2009-2010 :
3 # Gabes Jean, naparuba@gmail.com
4 # Gerhard Lausser, Gerhard.Lausser@consol.de
5 # Gregory Starck, g.starck@gmail.com
6 # Hartmut Goebel, h.goebel@goebel-consult.de
8 #This file is part of Shinken.
10 #Shinken is free software: you can redistribute it and/or modify
11 #it under the terms of the GNU Affero General Public License as published by
12 #the Free Software Foundation, either version 3 of the License, or
13 #(at your option) any later version.
15 #Shinken is distributed in the hope that it will be useful,
16 #but WITHOUT ANY WARRANTY; without even the implied warranty of
17 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 #GNU Affero General Public License for more details.
20 #You should have received a copy of the GNU Affero General Public License
21 #along with Shinken. If not, see <http://www.gnu.org/licenses/>.
24 #Graph is a class to make graph things like DFS checks or accessibility
25 #Why use an atomic bomb when a little hammer is enought?
34 def add_node(self
, node
):
39 def add_nodes(self
, nodes
):
43 #Add an edge to the graph from->to
44 def add_edge(self
, from_node
, to_node
):
45 #Maybe to_node is unknown
46 if to_node
not in self
.nodes
:
47 self
.add_node(to_node
)
50 self
.nodes
[from_node
].append(to_node
)
51 #If from_node do not exist, add it with it's son
53 self
.nodes
[from_node
] = [to_node
]
56 #Return all nodes that are in a loop. So if return [], no loop
59 #Add the tag for dfs check
60 for node
in self
.nodes
:
61 node
.dfs_loop_status
= 'DFS_UNCHECKED'
64 for node
in self
.nodes
:
65 #Run the dfs only if the node is not already done */
66 if node
.dfs_loop_status
== 'DFS_UNCHECKED':
67 self
.dfs_loop_search(node
)
68 #If LOOP_INSIDE, must be returned
69 if node
.dfs_loop_status
== 'DFS_LOOP_INSIDE':
73 for node
in self
.nodes
:
74 del node
.dfs_loop_status
79 #DFS_UNCHECKED default value
80 #DFS_TEMPORARY_CHECKED check just one time
81 #DFS_OK no problem for node and it's childs
82 #DFS_NEAR_LOOP has trouble sons
83 #DFS_LOOP_INSIDE is a part of a loop!
84 def dfs_loop_search(self
, root
):
85 #Make the root temporary checkded
86 root
.dfs_loop_status
= 'DFS_TEMPORARY_CHECKED'
88 #We are scanning the sons
89 for child
in self
.nodes
[root
]:
90 child_status
= child
.dfs_loop_status
91 #If a child is not checked, check it
92 if child_status
== 'DFS_UNCHECKED':
93 self
.dfs_loop_search(child
)
94 child_status
= child
.dfs_loop_status
96 #If a child already temporary checked, its a problem,
97 #loop inside, and its a acked status
98 if child_status
== 'DFS_TEMPORARY_CHECKED':
99 child
.dfs_loop_status
= 'DFS_LOOP_INSIDE'
100 root
.dfs_loop_status
= 'DFS_LOOP_INSIDE'
102 #If a child already temporary checked, its a problem, loop inside
103 if child_status
in ('DFS_NEAR_LOOP', 'DFS_LOOP_INSIDE'):
104 #if a node is know to be part of a loop, do not let it be less
105 if root
.dfs_loop_status
!= 'DFS_LOOP_INSIDE':
106 root
.dfs_loop_status
= 'DFS_NEAR_LOOP'
107 #We already saw this child, it's a problem
108 child
.dfs_loop_status
= 'DFS_LOOP_INSIDE'
110 #If root have been modified, do not set it OK
111 #A node is OK if and only if all of his childs are OK
112 #if it does not have child, goes ok
113 if root
.dfs_loop_status
== 'DFS_TEMPORARY_CHECKED':
114 root
.dfs_loop_status
= 'DFS_OK'
117 #Get accessibility packs of the graph : in one pack,
118 #element are related in a way. Between packs, there is no relation
120 #TODO : Get it work for directionnal graph too
121 #Because for now, edge must be father->son AND son->father
122 def get_accessibility_packs(self
):
124 #Add the tag for dfs check
125 for node
in self
.nodes
:
126 node
.dfs_loop_status
= 'DFS_UNCHECKED'
128 for node
in self
.nodes
:
129 #Run the dfs only if the node is not already done */
130 if node
.dfs_loop_status
== 'DFS_UNCHECKED':
131 packs
.append(self
.dfs_get_all_childs(node
))
134 for node
in self
.nodes
:
135 del node
.dfs_loop_status
140 #Return all mychilds, and all childs of my childs
141 def dfs_get_all_childs(self
, root
):
142 root
.dfs_loop_status
= 'DFS_CHECKED'
148 ret
.update(self
.nodes
[root
])
150 for child
in self
.nodes
[root
]:
151 #I just don't care about already check childs
152 if child
.dfs_loop_status
== 'DFS_UNCHECKED':
153 ret
.update(self
.dfs_get_all_childs(child
))