def manage_runAllRulesets(self, REQUEST=None):
        """ build current/potential matches
            for devices matching all ruleset rules
        """
        data = ProfileData(self.dmd)
        rmvs = []
        adds = []
        print "building adds and removes sets"
        for ruleset in self.getAllRulesets():
            print "ruleset", ruleset.id
            rmvs.append(set(ruleset.applyRules(True)))
            adds.append(set(ruleset.applyRules(False)))
        print "rebuilding components for all rulesets"
        self.setRulesetComponents()
        from ProfileSets import ProfileSets

        setMgr = ProfileSets(self.dmd)
        rmdevs = setMgr.evalSets(rmvs, False)
        addevs = setMgr.evalSets(adds, False)
        message = "No changes were made"
        if len(rmdevs) > 0 or len(addevs) > 0:
            message = ""
            if len(rmdevs) > 0:
                message += "Rulesets unapplied to %s" % ", ".join(data.getDeviceNames(rmdevs))
            if len(addevs) > 0:
                message += " Rulesets applied to %s" % ", ".join(data.getDeviceNames(addevs))
        if REQUEST:
            messaging.IMessageSender(self).sendToBrowser(message, message)
            return self.callZenScreen(REQUEST)
 def getPotentialDeviceMatches(self):
     """ return list of potential member devices 
         complying with any or all rules in a set
     """
     setMgr = ProfileSets(self.dmd)
     setData = ProfileData(self.dmd)
     sets = []
     for rule in self.rules(): 
         if rule.enabled == True:
             dset = set(rule.rulePotentialMatches)
             sets.append(dset)
     devices = setMgr.evalSets(sets,self.matchAll)
     return setData.getDeviceObjects(devices)
 def getRuleTypes(self):
     """ return list of supported rule types
     """
     setData = ProfileData(self.dmd)
     ruletypes = setData.getAllComponentMetaTypes()
     ruletypes.sort()
     ruletypes.append('Template')
     ruletypes.append('Ruleset')
     ruletypes.append('System')
     ruletypes.append('Group')
     ruletypes.append('Device')
     ruletypes.append('Location')
     return ruletypes
 def setRuleMatches(self):
     """ find potential matches for this rule:
         potential matches match the rule, but are not members of all 
         rule organizers
     """
     self.rulePotentialMatches = []
     self.ruleCurrentMatches = []
     setmgr = ProfileSets(self.dmd)
     data = ProfileData(self.dmd)
     devices = setmgr.evalRule(self)
     if devices:
         data.setRuleMembers(self,devices)
     else:
         self.rulePotentialMatches = []
         self.ruleCurrentMatches = [] 
 def getRemovableDeviceMatches(self):
     """ find devices that no longer match a given ruleset
         
     """
     currentMatches = set()
     for rule in self.rules():
         for d in rule.ruleCurrentMatches:
             if d not in currentMatches:
                 currentMatches.add(d)
     #currentMatches = set(self.getCurrentDeviceMatches())
     self.updateMatches()
     removableMatches = set(self.getCurrentDeviceMatches())
     formerMatches = currentMatches.difference(removableMatches)
     setData = ProfileData(self.dmd)
     return setData.getDeviceObjects(formerMatches)
 def manage_runRuleset(self, REQUEST=None):
     """ manage memberships and template bindings
     """
     data = ProfileData(self.dmd)
     rmvs = self.applyRules(True)
     adds = self.applyRules(False)
     message = 'No changes were made'
     if len(rmvs) > 0 or len(adds) > 0:
         message = ''
         if len(rmvs) > 0:
             message += 'Ruleset unapplied to %s' % ', '.join(data.getDeviceNames(rmvs))
         if len(adds) > 0:
             message += ' Ruleset applied to %s' % ', '.join(data.getDeviceNames(adds))
     if REQUEST:
         messaging.IMessageSender(self).sendToBrowser(message,message)
         return self.callZenScreen(REQUEST)
class ProfileEvents(ZenPackable):
    """ Class containing routines for handling 
        event filters
    """
    
    def __init__(self,dmd):
        self.dmd = dmd
        self.data = ProfileData(self.dmd)

    def createRulesetGroup(self,ruleset):
        """ create Group named after this ruleset
            if it doesn't exist
        """
        ruleset.rulesetGroups = []
        if ruleset.id not in self.dmd.ZenUsers.getAllGroupSettingsNames():
            ruleset.dmd.ZenUsers.manage_addGroup(ruleset.id)
        if ruleset.id not in ruleset.rulesetGroups:
            ruleset.rulesetGroups.append(ruleset.id)
            
    def addRulesetUsersToGroups(self,ruleset):
        """ add rulesetUsers to rulesetGroups
        """
        for g in ruleset.rulesetGroups:
            group = self.dmd.ZenUsers.getGroupSettings(g)
            for u in ruleset.rulesetUsers:
                if u not in group.getMemberUserIds():
                    user = self.dmd.ZenUsers.getUserSettings(u)
                    group.manage_addUsersToGroup([user.id])
        
    def setRulesetAdminGroups(self,ruleset):
        """ build Add rulesetGroups to Administrative
            Roles on Group/System Organizers
        """
        for rulesetGroup in ruleset.rulesetGroups:
            usergroup = self.dmd.ZenUsers.getGroupSettings(rulesetGroup)
            for group in ruleset.rulesetGroupOrganizers:
                usergroup.manage_addAdministrativeRole(group,type='group')
                usergroup.manage_editAdministrativeRoles(group,role='ZenManager',level=1)
            for system in ruleset.rulesetSystemOrganizers:
                usergroup.manage_addAdministrativeRole(system,type='system')
                usergroup.manage_editAdministrativeRoles(system,role='ZenManager',level=1)
    
    def createRulesetEventView(self,ruleset):
        """ build the event view object for a ruleset
        """
        eventWhere = self.rulesetWhere(ruleset)
        ruleset.rulesetEventWhere = eventWhere
        for g in ruleset.rulesetGroups:
            groupSettings = self.dmd.ZenUsers.getGroupSettings(g)
            eventViewName = g + '-eventview-' + ruleset.id
            ids = []
            for eventView in groupSettings.objectValues(spec='CustomEventView'):
                ids.append(eventView.id)
            if eventViewName not in ids:
                groupSettings.manage_addCustomEventView(eventViewName)
            for eventView in groupSettings.objectValues(spec='CustomEventView'):
                if eventView.id == eventViewName:
                    eventView.where = eventWhere

    def createRulesetAlert(self,ruleset):
        """ build the alert object for a ruleset
        """
        eventWhere = self.rulesetWhere(ruleset)
        for g in ruleset.rulesetGroups:
            alertName = g + '-ruleset-'+ruleset.id
            groupSettings = self.dmd.ZenUsers.getGroupSettings(g)
            ids = []
            for alert in groupSettings.getActionRules():
                ids.append(alert.id)
            if alertName not in ids:
                groupSettings.manage_addActionRule(alertName)
            for alert in groupSettings.getActionRules():
                if alert.id == alertName:
                    if len(ruleset.rulesetUsers) > 0:
                        alert.enabled = True
                    else:
                        alert.enabled = False
                    alert.where = ''
                    if len(ruleset.rulesetAlertWhere) > 0:
                        alert.where += ruleset.rulesetAlertWhere + ' and '
                    alert.where += eventWhere
                    alert.clearFormat = alert.clearFormat.replace('[zenoss]',ruleset.id)
                    alert.format = alert.format.replace('[zenoss]',ruleset.id)
            if alertName not in ruleset.rulesetAlerts:
                ruleset.rulesetAlerts.append(alertName)
    
    def rulesetWhere(self,ruleset):
        """ create where statement for ruleset
        """
        # create "AND" conditions to narrow events by org membership
        condition = ''
        orgWheres = []
        for group in ruleset.rulesetGroupOrganizers:
            orgWheres.append(self.groupWhere(group))
        for system in ruleset.rulesetSystemOrganizers:
            orgWheres.append(self.systemWhere(system))
        orgCondition = self.compoundWhere(orgWheres,"and")
        # add "OR" conditions to collect events for each rule
        ruleWheres = []
        for rule in ruleset.rules():
            if rule.enabled == True:
                if rule.ruleKey != 'System' and rule.ruleKey != 'Group':
                    rulewhere = self.ruleWhere(rule)
                    ruleWheres.append(rulewhere)
        if ruleset.matchAll == True:
            ruleCondition = self.compoundWhere(ruleWheres,"and")
        else:
            ruleCondition = self.compoundWhere(ruleWheres,"or")
        # join organizational and rule-based filters
        if len(orgWheres) > 0 :
            condition += '('+ orgCondition
            if len(ruleWheres) > 0:
                condition += ' and ' + ruleCondition
            condition += ')'
        else:
            if len(ruleWheres) > 0:
                condition += ruleCondition
        return condition
    
    def ruleWhere(self,rule):
        """ create where statement for ruleset
        """
        conditions = []
        if rule.ruleKey in self.data.getAllComponentMetaTypes():
            conditions.append(self.componentWhere(rule.ruleValue))
            if rule.ruleEventClass != None: # if there is an event class associated w/the rule
                conditions.append(self.eventClassWhere(rule.ruleEventClass))
        elif rule.ruleKey == 'Template':
            conditions.append(self.templateWhere(rule))    
        elif rule.ruleKey == 'Ruleset':
            ruleset = self.dmd.Profiles.findRuleset(rule.ruleValue)
            if ruleset != None:
                conditions.append(self.rulesetWhere(ruleset))
        elif rule.ruleKey == 'Location':
            conditions.append(self.locationWhere(rule.ruleValue))   
        elif rule.ruleKey == 'Device':
            conditions.append(self.deviceWhere(rule.ruleValue))
        where = self.compoundWhere(conditions,"and")
        return where
    
    def templateWhere(self,rule):
        """ create where statement for template
        """
        properties = self.findTemplateProperties(rule)
        conditions = []
        where = ''
        for property in properties:
            tConds = []
            eventclass,component = property
            if len(eventclass) > 0:
                tConds.append(self.eventClassWhere(eventclass))
            if len(component) > 0:
                tConds.append(self.componentWhere(component))
            if len(tConds) > 0:
                if len(tConds) == 1:
                    conditions.append(tConds[0])
                else:
                    conditions.append(self.compoundWhere(tConds,"and"))
        if len(conditions) > 0:
            if len(conditions) == 1:
                where = conditions[0]
            else:
                where = self.compoundWhere(conditions,"or")
        return where
    
    def compoundWhere(self,wheres,conjunction):
        """ combine where statements
        """
        condition = '('
        entries = len(wheres)
        for i in range(entries):
            condition += wheres[i]
            if i < entries-1:
                condition += " " + conjunction + " "
        condition += ')'
        return condition 
    
    def systemWhere(self,system):
        """ conditional expression for system organizer
        """
        return '(systems like \'%|' + system + '%\')'
    
    def groupWhere(self,group):
        """ conditional expression for system organizer
        """
        return '(deviceGroups like \'%|' + group + '%\')'
    
    def deviceWhere(self,device):
        """ conditional expression for event device
        """
        return 'device like \'%' + device + '%\''
    
    def locationWhere(self,location):
        """ conditional expression for event device
        """
        return 'location like \'%' + location + '%\''
    
    def componentWhere(self,component):
        """ conditional expression for event component
        """
        return 'component like \'%' + component + '%\''
    
    def eventClassWhere(self,eventclass):
        """ conditional expression for event class
        """
        return 'eventClass like \''+eventclass+'%\''
    
    def findTemplateProperties(self,rule):
        """ find filter-related properties for template alert
        """
        properties = []
        for template in self.dmd.Devices.getAllRRDTemplates():
            if template.id.find(rule.ruleValue) >=0:
                for ds in template.getRRDDataSources():
                    eventclass = ds.eventClass
                    component = ds.component
                    properties.append((eventclass,component))
        return properties
 def __init__(self,dmd):
     self.dmd = dmd
     self.data = ProfileData(self.dmd)
 def getRuleCurrentMatches(self):
     """ find current rule matches that are 
         already members of groups
     """
     data = ProfileData(self.dmd)
     return data.getDeviceObjects(self.ruleCurrentMatches)
 def getRulePotentialMatches(self):
     """ find potential matches for this rule:
     """
     data = ProfileData(self.dmd)
     return data.getDeviceObjects(self.rulePotentialMatches)
class ProfileSets(ZenPackable):
    '''  Class containing logic for evaluating rule outcomes.
    '''
    
    def __init__(self,dmd):
        self.dmd = dmd
        self.data = ProfileData(self.dmd)

    def evalSets(self,sets,matchAll):
        """  compute union or intersection of a set of sets
            matchAll of True == intersection, union otherwise
        """
        resultSet = None
        for i in range(len(sets)):
            setI = sets[i]
            if resultSet == None:
                resultSet = setI
            for j in range(i):
                setJ = sets[j]
                if matchAll == True:
                    matchSet = setI.intersection(setJ)
                    resultSet = resultSet.intersection(matchSet)
                else:
                    matchSet = setI.union(setJ)
                    resultSet = resultSet.union(matchSet)
        return resultSet
    
    def evalRulesets(self,rulesets,matchAll):
        """  evaluate multiple rulesets
        """
        sets = []
        for ruleset in rulesets:
            rset = self.evalRuleset(ruleset)
            sets.append(rset)
        return self.evalSets(sets,matchAll)
    
    def evalRuleset(self,ruleset,easy=False):
        """  evaluate all rules in a ruleset, return set of matching devices
        """
        sets = [] # array containing sets of rule-matched devices
        if ruleset != None:
            rules = ruleset.rules()
            for rule in rules:
                results = []
                if rule.enabled == True:
                    if easy == True:
                        results = self.evalRuleSimple(rule)
                    else:
                        results = self.evalRule(rule)
                    #if len(results) > 0:
                    sets.append(results)
        if len(sets) > 0:
            return self.evalSets(sets,ruleset.matchAll)
        else:
            "returning sets"
            return sets
    
    def evalRuleSimple(self,rule):
        """ faster testing assuming that matches are already built
        """
        ruleMatches = []
        ruleMatches += rule.getRulePotentialMatches() 
        ruleMatches += rule.getRuleCurrentMatches()
        return set(ruleMatches)

    def evalRule(self,rule):
        """ evaluate a rule, return set of matching devices
        """
        if rule.ruleKey == 'Ruleset':
            ruleSet = self.dmd.Profiles.findRuleset(rule.ruleValue)
            return self.evalRuleset(ruleSet,easy=True)
        ruleMatches = set()
        for device in self.dmd.Devices.getSubDevices():
            if self.data.evalRuleOnDevice(rule,device) == True:
                ruleMatches.add(device)
        return ruleMatches

    def evalRuleComponents(self,rule,devices,getAll=True):
        """ evaluate a rule, return set of matching components
        """
        components = []
        if rule.ruleKey != 'System' and rule.ruleKey != 'Group' and rule.ruleKey != 'Ruleset' and rule.ruleKey != 'Location' and rule.ruleKey != 'Device':
            for device in devices:
                components += self.data.evalRuleWithObjects(rule,device)
        if rule.ruleKey == 'Ruleset':
            rs = self.dmd.Profiles.findRuleset(rule.ruleValue)
            if getAll == True:
                components += self.getRulesetComponents(rs,devices)
            else:
                components += self.getRulesetFilteredComponents(rs,devices)
        #print "found",len(components),"components on rule",rule.ruleKey,rule.ruleValue,"for",len(devices),"devices"
        rule.ruleComponents = components
        return components
    
    def getRulesetComponents(self,ruleset,devices):
        print "components on ruleset",ruleset.id,"for",len(devices),"devices"
        components = []
        for rule in ruleset.rules():
            if rule.ruleKey != 'System' and rule.ruleKey != 'Group' and rule.ruleKey != 'Location' and rule.ruleKey != 'Device':
                comps = self.evalRuleComponents(rule,devices)
                components += comps
        #print "found",len(components),"components"
        return components
    
    def getRulesetFilteredComponents(self,ruleset,devices):
        #print "components on ruleset",ruleset.id,"for",len(devices),"devices"
        componentsets = []
        for rule in ruleset.rules():
            if rule.ruleKey != 'System' and rule.ruleKey != 'Group' and rule.ruleKey != 'Location' and rule.ruleKey != 'Device':
                comps = self.evalRuleComponents(rule,devices,False)
                if len(comps) > 0:
                    componentsets.append(set(comps))
        rulesetcomponents = self.evalSets(componentsets,ruleset.matchAll)
        #print "set of rs components",len(rulesetcomponents)
        if rulesetcomponents != None:
            return rulesetcomponents
        else:
            return []
 def getAllRulesets(self):
     """ find all rulesets recursively
     """
     data = ProfileData(self.dmd)
     rulesets = data.getAllRulesets()
     return rulesets