This file is indexed.

/usr/lib/python2.7/dist-packages/shinken/complexexpression.py is in shinken-common 1.4-2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
#!/usr/bin/env python

# -*- coding: utf-8 -*-

# Copyright (C) 2009-2012:
#     Gabes Jean, naparuba@gmail.com
#     Gerhard Lausser, Gerhard.Lausser@consol.de
#     Gregory Starck, g.starck@gmail.com
#     Hartmut Goebel, h.goebel@goebel-consult.de
#
# This file is part of Shinken.
#
# Shinken is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Shinken is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with Shinken.  If not, see <http://www.gnu.org/licenses/>.

import re
from shinken.util import strip_and_uniq


"""
Here is a node class for complex_expression(s) and a factory to create them
"""

class ComplexExpressionNode(object):
    def __init__(self):
        self.operand = None
        self.sons = []
        self.configuration_errors = []
        self.not_value = False
        # If leaf, the content will be the hostgroup or hosts
        # that are selected with this node
        self.leaf = False
        self.content = None
        
        
        
    def __str__(self):
        if not self.leaf:
            return "Op:'%s' Leaf:%s Sons:'[%s] IsNot:%s'" % (self.operand, self.leaf, ','.join([str(s) for s in self.sons]), self.not_value)
        else:
            return 'IS LEAF %s' % self.content


    def resolve_elements(self):
        # If it's a leaf, we just need to dump a set with the content of the node
        if self.leaf:
            #print "Is a leaf", self.content
            if not self.content:
                return set()

            return set(self.content)
        
        
        # first got the not ones in a list, and the other in the other list
        not_nodes = [s for s in self.sons if s.not_value]
        positiv_nodes = [s for s in self.sons if not s.not_value] # ok a not not is hard to read...

        #print "Not nodes", not_nodes
        #print "Positiv nodes", positiv_nodes

        # By default we are using a OR rule
        if not self.operand:
            self.operand = '|'

        res = set()

        #print "Will now merge all of this", self.operand

        # The operand will change the positiv loop only
        i = 0
        for n in positiv_nodes:
            node_members = n.resolve_elements()
            if self.operand == '|':
                #print "OR rule", node_members
                res = res.union(node_members)
            elif self.operand == '&':
                #print "AND RULE", node_members
                # The first elements of an AND rule should be used
                if i == 0:
                    res = node_members
                else:
                    res = res.intersection(node_members)
            i += 1

        # And we finally remove all NOT elements from the result
        for n in not_nodes:
            node_members = n.resolve_elements()
            res = res.difference(node_members)
        
        return res
    

    # Check for empty (= not found) leaf nodes
    def is_valid(self):

        valid = True
        if not self.sons:
            valid = False
        else:
            for s in self.sons:
                if isinstance(s, DependencyNode) and not s.is_valid():
                    self.configuration_errors.extend(s.configuration_errors)
                    valid = False
        return valid



""" TODO: Add some comment about this class for the doc"""
class ComplexExpressionFactory(object):
    def __init__(self, ctx='hostgroups', grps=None, all_elements=None):
        self.ctx = ctx
        self.grps = grps
        self.all_elements = all_elements
        

    # the () will be eval in a recursiv way, only one level of ()
    def eval_cor_pattern(self, pattern):
        pattern = pattern.strip()
        #print "eval_cor_pattern::", pattern
        complex_node = False

        # Look if it's a complex pattern (with rule) or
        # if it's a leaf ofit, like a host/service
        for m in '()+&|,':
            if m in pattern:
                complex_node = True

        node = ComplexExpressionNode()
        #print "Is so complex?", complex_node, pattern, node
        
        # if it's a single expression like !linux or production
        # we will get the objects from it and return a leaf node
        if not complex_node:
            # If it's a not value, tag the node and find
            # the name without this ! operator
            if pattern.startswith('!'):
                node.not_value = True
                pattern = pattern[1:]
            
            node.operand = self.ctx
            node.leaf = True
            obj, error = self.find_object(pattern)
            if obj is not None:
                node.content = obj
            else:
                node.configuration_errors.append(error)
            return node

        in_par = False
        tmp = ''
        stacked_par = 0
        for c in pattern:
            #print "MATCHING", c
            if c == ',' or c == '|':
                # Maybe we are in a par, if so, just stack it
                if in_par:
                    #print ", in a par, just staking it"
                    tmp += c
                else:
                    # Oh we got a real cut in an expression, if so, cut it
                    #print "REAL , for cutting"
                    tmp = tmp.strip()
                    node.operand = '|'
                    if tmp != '':
                        #print "Will analyse the current str", tmp
                        o = self.eval_cor_pattern(tmp)
                        node.sons.append(o)
                    tmp = ''

            elif c == '&' or c == '+':
                # Maybe we are in a par, if so, just stack it
                if in_par:
                    #print " & in a par, just staking it"
                    tmp += c
                else:
                    # Oh we got a real cut in an expression, if so, cut it
                    #print "REAL & for cutting"
                    tmp = tmp.strip()
                    node.operand = '&'
                    if tmp != '':
                        #print "Will analyse the current str", tmp
                        o = self.eval_cor_pattern(tmp)
                        node.sons.append(o)
                    tmp = ''
            
            elif c == '(':
                stacked_par += 1
                #print "INCREASING STACK TO", stacked_par
                
                in_par = True
                tmp = tmp.strip()
                # Maybe we just start a par, but we got some things in tmp
                # that should not be good in fact !
                if stacked_par == 1 and tmp != '':
                    #TODO : real error
                    print "ERROR : bad expression near", tmp
                    continue

                # If we are already in a par, add this (
                # but not if it's the first one so
                if stacked_par > 1:
                    tmp += c
                    #o = self.eval_cor_pattern(tmp)
                    #print "1( I've %s got new sons" % pattern , o
                    #node.sons.append(o)
                    
            elif c == ')':
                #print "Need closeing a sub expression?", tmp
                stacked_par -= 1

                if stacked_par < 0:
                    # TODO : real error
                    print "Error : bad expression near", tmp, "too much ')'"
                    continue
                
                if stacked_par == 0:
                    #print "THIS is closing a sub compress expression", tmp
                    tmp = tmp.strip()
                    o = self.eval_cor_pattern(tmp)
                    node.sons.append(o)
                    in_par = False
                    # OK now clean the tmp so we start clean
                    tmp = ''
                    continue

                # ok here we are still in a huge par, we just close one sub one
                tmp += c
            # Maybe it's a classic character, if so, continue
            else:
                tmp += c

        # Be sure to manage the trainling part when the line is done
        tmp = tmp.strip()
        if tmp != '':
            #print "Managing trainling part", tmp
            o = self.eval_cor_pattern(tmp)
            #print "4end I've %s got new sons" % pattern , o
            node.sons.append(o)

        #print "End, tmp", tmp
        #print "R %s:" % pattern, node
        return node


    # We've got an object, like super-grp, so we should link th group here
    def find_object(self, pattern):
        obj = None
        error = None
        pattern = pattern.strip()

        
        if pattern == '*':
            obj = [h.host_name for h in self.all_elements.items.values()
                   if getattr(h, 'host_name', '') != '' and not h.is_tpl()]
            return obj, error

        
        # Ok a more classic way

        #print "GRPS", self.grps
        
        if self.ctx == 'hostgroups':
            # Ok try to find this hostgroup
            hg = self.grps.find_by_name(pattern)
            # Maybe it's an known one?
            if not hg:
                error = "Error : cannot find the %s of the expression '%s'" % (self.ctx, pattern)
                return hg, error
            # Ok the group is found, get the elements!
            elts = hg.get_hosts().split(',')
            elts = strip_and_uniq(elts)

            # Maybe the hostgroup memebrs is '*', if so expand with all hosts
            if '*' in elts:
                elts.extend([h.host_name for h in self.all_elements.items.values()
                             if getattr(h, 'host_name', '') != '' and not h.is_tpl()])
                # And remove this strange hostname too :)
                elts.remove('*')
            return elts, error
                
        else: #templates
            obj = self.grps.find_hosts_that_use_template(pattern)
        
        return obj, error