예제 #1
0
    def getDBSize(db, dbName=None):
        if db not in ('zodb', 'zep'):
            print "ERROR: Bad database string: %s" % db
            sys.exit(1)
        globalSettings = globalConfToDict()
        user = globalSettings.get('%s-admin-user' % db, None)
        if not user:
            print 'ERROR: Unable to determine admin db user for %s' % db
            sys.exit(1)
        cmd = ['mysql', '-s', '--skip-column-names', '-u%s' % str(user)]
        host = globalSettings.get('%s-host' % db, None)
        if host and host != 'localhost':
            cmd.append('-h%s' % str(host))
        port = globalSettings.get('%s-port' % db, None)
        if port and str(port) != '3306':
            cmd.append('--port=%s' % str(port))
        cred = globalSettings.get('%s-admin-password' % db, None)
        if cred:
            cmd.append('-p%s' % str(cred))
        if not dbName:
            dbName = globalSettings.get('%s-db' % db, None)     # Save this for later
        if not dbName:
            print 'ERROR: Unable to locate database name in global config'
            sys.exit(1)

        cmd.append('-e')
        selectStr = "\"SELECT Data_BB / POWER(1024,2) FROM (SELECT SUM(data_length) Data_BB FROM information_schema.tables WHERE table_schema = '%s') A;\"" % dbName
        cmd.append(selectStr)

        DBSize = int(float(subprocess.check_output(' '.join(cmd), shell=True).strip())) + 1
        return DBSize
예제 #2
0
def setPassword(event):
    """
    Handler for IZopeApplicationOpenedEvent which sets zauth-user password based
      on the settings in global.conf.
    """
    zport = getattr(event.app, 'zport', None)
    # zport may not exist if we are using zenbuild to initialize the database
    if not zport:
        return

    globalConf = globalConfToDict()
    user = globalConf.get('zauth-username', 'zenoss_system')
    password = globalConf.get('zauth-password', "MY_PASSWORD")

    try:
        zport.acl_users.userManager.getUserInfo(user)
    except KeyError:
        zport.dmd.ZenUsers.manage_addUser(user,
                                          password=password,
                                          roles=('Manager', ))
        return

    if not zport.acl_users.userManager.authenticateCredentials(
        {
            'login': user,
            'password': password
        }):
        zport.acl_users.userManager.updateUserPassword(user, password)
예제 #3
0
    def getDBSize(db, dbName=None):
        if db not in ('zodb', 'zep'):
            print "ERROR: Bad database string: %s" % db
            sys.exit(1)
        globalSettings = globalConfToDict()
        user = globalSettings.get('%s-admin-user' % db, None)
        if not user:
            print 'ERROR: Unable to determine admin db user for %s' % db
            sys.exit(1)
        cmd = ['mysql', '-s', '--skip-column-names', '-u%s' % str(user)]
        host = globalSettings.get('%s-host' % db, None)
        if host and host != 'localhost':
            cmd.append('-h%s' % str(host))
        port = globalSettings.get('%s-port' % db, None)
        if port and str(port) != '3306':
            cmd.append('--port=%s' % str(port))
        cred = globalSettings.get('%s-admin-password' % db, None)
        if cred:
            cmd.append('-p%s' % str(cred))
        if not dbName:
            dbName = globalSettings.get('%s-db' % db,
                                        None)  # Save this for later
        if not dbName:
            print 'ERROR: Unable to locate database name in global config'
            sys.exit(1)

        cmd.append('-e')
        selectStr = "\"SELECT Data_BB / POWER(1024,2) FROM (SELECT SUM(data_length) Data_BB FROM information_schema.tables WHERE table_schema = '%s') A;\"" % dbName
        cmd.append(selectStr)

        DBSize = int(
            float(subprocess.check_output(' '.join(cmd),
                                          shell=True).strip())) + 1
        return DBSize
예제 #4
0
 def get(self, name=None):
     """Return the ZODB connection factory by name or look up in global.conf."""
     if name is None:
         settings = globalConfToDict()
         name = settings.get('zodb-db-type', 'mysql')
     connectionFactory = queryUtility(IZodbFactory, name)
     return connectionFactory
예제 #5
0
 def get(self, name=None):
     """Return the ZODB connection factory by name or look up in global.conf."""
     if name is None:
         settings = globalConfToDict()
         name = settings.get('zodb-db-type', 'mysql')
     connectionFactory = queryUtility(IZodbFactory, name)
     return connectionFactory
예제 #6
0
 def selected(self):
     requestURL = self.request.getURL().replace('/@@', '/')
     if bool(globalConfToDict().get('zcml-enable-cz-dashboard', '')) and \
             self.title == "Event Console" and requestURL.endswith("dmd/Events"):
         return True
     for url in chain((self.url, ), self.subviews):
         if re.search(url, requestURL):
             return True
     return False
예제 #7
0
def getConnectionSettings(options=None):
    if options is None:
        o = globalConfToDict()
    else:
        o = options
    settings = {
        "host": o.get("controlplane-host"),
        "port": o.get("controlplane-port"),
        "user": o.get("controlplane-user", "zenoss"),
        "password": o.get("controlplane-password", "zenoss"),
    }
    return settings
예제 #8
0
def addGlobalFeatures(_context):
    # inject into zcml context the global features specified in global.conf
    conf = globalConfToDict()
    for key, value in conf.iteritems():
        if key[:_flen] == _FEATURE_PREFIX:
            feature = key[_flen:]

            if not feature or not isinstance(value, basestring) or ( value.lower() != "feature" and value.lower() != "yes" ):

                continue
            # add the feature to the existing global zcml context
            _context.provideFeature(unicode(feature))
예제 #9
0
def addGlobalFeatures(_context):
    # inject into zcml context the global features specified in global.conf
    conf = globalConfToDict()
    for key, value in conf.iteritems():
        if key[:_flen] == _FEATURE_PREFIX:
            feature = key[_flen:]

            if not feature or not isinstance(value, basestring) or (
                    value.lower() != "feature" and value.lower() != "yes"):

                continue
            # add the feature to the existing global zcml context
            _context.provideFeature(unicode(feature))
예제 #10
0
def getConnectionSettings(options=None):
    if options is None:
        o = globalConfToDict()
    else:
        o = options
    settings = {
        "user": o.get("controlplane-user", "zenoss"),
        "password": o.get("controlplane-password", "zenoss"),
        }
    # allow these to be set from the global.conf for development but
    # give preference to the environment variables
    settings["user"] = os.environ.get('CONTROLPLANE_SYSTEM_USER', settings['user'])
    settings["password"] = os.environ.get('CONTROLPLANE_SYSTEM_PASSWORD', settings['password'])
    return settings
예제 #11
0
def _getDefaults(options=None):
    if options is None:
       o = globalConfToDict()
    else:
       o = options
    settings = {
        'host': o.get('zodb-host', "localhost"),
        'port': o.get('zodb-port', 5432),
        'user': o.get('zodb-user', 'zenoss'),
        'password': o.get('zodb-password', 'zenoss'),
        'dbname': o.get('zodb-db', 'zodb'),
    }
    if 'zodb-socket' in o:
        settings['socket'] = o['zodb-socket']
    return settings
예제 #12
0
def _getDefaults(options=None):
    if options is None:
        o = globalConfToDict()
    else:
        o = options
    settings = {
        'host': o.get('zodb-host', "localhost"),
        'port': o.get('zodb-port', 5432),
        'user': o.get('zodb-user', 'zenoss'),
        'password': o.get('zodb-password', 'zenoss'),
        'dbname': o.get('zodb-db', 'zodb'),
    }
    if 'zodb-socket' in o:
        settings['socket'] = o['zodb-socket']
    return settings
예제 #13
0
def _getDefaults(options=None):
    if options is None:
        o = globalConfToDict()
    else:
        o = options
    settings = {
        'host': o.get('zodb-host', "localhost"),
        'port': o.get('zodb-port', _ZENDS_CONFIG.get("port",
                                                     _DEFAULT_MYSQLPORT)),
        'user': o.get('zodb-user', 'zenoss'),
        'passwd': o.get('zodb-password', 'zenoss'),
        'db': o.get('zodb-db', 'zodb'),
    }
    if 'zodb-socket' in o:
        settings['unix_socket'] = o['zodb-socket']
    return settings
def _getDefaults(options=None):
    if options is None:
       o = globalConfToDict()
    else:
       o = options
    settings = {
        'host': o.get('zodb-host', "localhost"),
        'port': o.get(
            'zodb-port', _ZENDS_CONFIG.get("port", _DEFAULT_MYSQLPORT)
        ),
        'user': o.get('zodb-user', 'zenoss'),
        'passwd': o.get('zodb-password', 'zenoss'),
        'db': o.get('zodb-db', 'zodb'),
    }
    if 'zodb-socket' in o:
        settings['unix_socket'] = o['zodb-socket']
    return settings
예제 #15
0
    def readZEPSettings(self):
        """
        Read in and store the ZEP DB configuration options
        to the 'options' object.
        """
        globalSettings = globalConfToDict()
        zepsettings = {
            'zep-user': '******',
            'zep-host': 'zepdbhost',
            'zep-db': 'zepdbname',
            'zep-password': '******',
            'zep-port': 'zepdbport'
        }

        for key in zepsettings:
            if key in globalSettings:
                value = str(globalSettings[key])
                setattr(self.options, zepsettings[key], value)
예제 #16
0
    def readZEPSettings(self):
        """
        Read in and store the ZEP DB configuration options
        to the 'options' object.
        """
        globalSettings = globalConfToDict()
        zepsettings = {
            'zep-user': '******',
            'zep-host': 'zepdbhost',
            'zep-db': 'zepdbname',
            'zep-password': '******',
            'zep-port': 'zepdbport'
        }

        for key in zepsettings:
            if key in globalSettings:
                value = str(globalSettings[key])
                setattr(self.options, zepsettings[key], value)
예제 #17
0
def setPassword(event):
    """
    Handler for IZopeApplicationOpenedEvent which sets zauth-user password based
      on the settings in global.conf.
    """
    zport = getattr(event.app, 'zport', None)
    # zport may not exist if we are using zenbuild to initialize the database
    if not zport:
        return

    globalConf = globalConfToDict()
    user = globalConf.get('zauth-username', 'zenoss_system')
    password = globalConf.get('zauth-password', "MY_PASSWORD")

    try:
        zport.acl_users.userManager.getUserInfo(user)
    except KeyError:
        zport.dmd.ZenUsers.manage_addUser(user, password=password, roles=('Manager',))
        return

    if not zport.acl_users.userManager.authenticateCredentials({'login':user, 'password':password} ):
        zport.acl_users.userManager.updateUserPassword(user, password)
예제 #18
0
 def login(self):
     """
     Perform a login.  This actually logs us in to both zauth (so that we can
     use zproxy) and CC (so that we can hit elastic).  Note that a new session
     is created here.
     """
     self.session = requests.Session()
     gConf = globalConfToDict()
     # log into zauth
     if not (gConf.get('zauth-username', None)
             and gConf.get('zauth-password', None)):
         raise ElasticClientException(
             'Unable to determine zauth credentials')
     resp = self.session.post(_ZPROXY_URL + _ZAUTH_LOGIN_URI,
                              auth=(gConf['zauth-username'],
                                    gConf['zauth-password']))
     if resp.status_code != 200:
         raise ElasticClientException('Unable to authenticate with zauth')
     if not resp.headers.get('X-Zauth-Tokenid', None):
         raise ElasticClientException(
             'Did not recieve X-Zauth-Tokenid, cannot authenticate')
     self.session.headers['X-Zauth-Token'] = resp.headers['X-Zauth-Tokenid']
     # log into CC (for elastic quesries)
     connSettings = getConnectionSettings()
     if not all(param in connSettings for param in ('user', 'password')):
         raise ElasticClientException(
             'Unable to determine Control Center credentials')
     ccLoginBody = json.dumps({
         'username': connSettings['user'],
         'password': connSettings['password']
     })
     self.session.verify = False
     resp = self.session.post(self.ccURL + _CC_LOGIN_URI, data=ccLoginBody)
     if resp.status_code != 200:
         raise ElasticClientException(
             'Unable to authenticate with Control Center', resp)
예제 #19
0
 def isActiveCZDashboard(self):
     return globalConfToDict().get('zcml-enable-cz-dashboard', '')
예제 #20
0
class DataRoot(ZenModelRM, OrderedFolder, Commandable, ZenMenuable):
    implements(IDataRoot)

    meta_type = portal_type = 'DataRoot'

    manage_main = OrderedFolder.manage_main

    manage_options = OrderedFolder.manage_options

    #setTitle = DTMLFile('dtml/setTitle',globals())

    uuid = None
    availableVersion = None
    lastVersionCheck = 0
    lastVersionCheckAttempt = 0
    versionCheckOptIn = True
    reportMetricsOptIn = True
    acceptedTerms = True
    cz_prefix = getUtility(IVirtualRoot).get_prefix()
    instanceIdentifier = 'Zenoss - %s' % cz_prefix.replace('/', '')
    zenossHostname = 'localhost:8080'
    smtpHost = ''
    pageCommand = ''
    smtpPort = 25
    smtpUser = ''
    smtpPass = ''
    smtpUseTLS = 0
    emailFrom = ''
    iconMap = {}
    geomapapikey = ''
    version = ""
    # how we should store our user credentials
    AUTH_TYPE_SESSION = "session"
    AUTH_TYPE_COOKIE = "cookie"
    userAuthType = AUTH_TYPE_SESSION
    userTheme = "z-cse"
    pauseHubNotifications = False
    zendmdStartupCommands = []
    pauseADMStart = datetime.min

    _properties = (
        {
            'id': 'title',
            'type': 'string',
            'mode': 'w'
        },
        {
            'id': 'prodStateDashboardThresh',
            'type': 'int',
            'mode': 'w'
        },
        {
            'id': 'prodStateConversions',
            'type': 'lines',
            'mode': 'w'
        },
        {
            'id': 'priorityConversions',
            'type': 'lines',
            'mode': 'w'
        },
        {
            'id': 'priorityDashboardThresh',
            'type': 'int',
            'mode': 'w'
        },
        {
            'id': 'statusConversions',
            'type': 'lines',
            'mode': 'w'
        },
        {
            'id': 'interfaceStateConversions',
            'type': 'lines',
            'mode': 'w'
        },
        {
            'id': 'uuid',
            'type': 'string',
            'mode': 'w'
        },
        {
            'id': 'availableVersion',
            'type': 'string',
            'mode': 'w'
        },
        {
            'id': 'lastVersionCheck',
            'type': 'long',
            'mode': 'w'
        },
        {
            'id': 'lastVersionCheckAttempt',
            'type': 'long',
            'mode': 'w'
        },
        {
            'id': 'versionCheckOptIn',
            'type': 'boolean',
            'mode': 'w'
        },
        {
            'id': 'reportMetricsOptIn',
            'type': 'boolean',
            'mode': 'w'
        },
        {
            'id': 'instanceIdentifier',
            'type': 'string',
            'mode': 'w'
        },
        {
            'id': 'zenossHostname',
            'type': 'string',
            'mode': 'w'
        },
        {
            'id': 'smtpHost',
            'type': 'string',
            'mode': 'w'
        },
        {
            'id': 'smtpPort',
            'type': 'int',
            'mode': 'w'
        },
        {
            'id': 'pageCommand',
            'type': 'string',
            'mode': 'w'
        },
        {
            'id': 'smtpUser',
            'type': 'string',
            'mode': 'w'
        },
        {
            'id': 'smtpPass',
            'type': 'password',
            'mode': 'w'
        },
        {
            'id': 'smtpUseTLS',
            'type': 'int',
            'mode': 'w'
        },
        {
            'id': 'emailFrom',
            'type': 'string',
            'mode': 'w'
        },
        {
            'id': 'geomapapikey',
            'type': 'string',
            'mode': 'w'
        },
        {
            'id': 'userAuthType',
            'type': 'string',
            'mode': 'w'
        },
        {
            'id': 'userTheme',
            'type': 'string',
            'mode': 'w'
        },
        {
            'id': 'pauseHubNotifications',
            'type': 'boolean',
            'mode': 'w'
        },
        {
            'id': 'zendmdStartupCommands',
            'type': 'lines',
            'mode': 'w'
        },
        {
            'id': 'pauseADMStart',
            'type': 'datetime',
            'mode': 'w'
        },
    )

    _relations = (
        ('userCommands',
         ToManyCont(ToOne, 'Products.ZenModel.UserCommand', 'commandable')),
        # packs is depracated.  Has been moved to dmd.ZenPackManager.packs
        # Should be removed post Zenoss 2.2
        # TODO
        ('packs', ToManyCont(ToOne, 'Products.ZenModel.ZenPack', 'root')),
        ('zenMenus', ToManyCont(ToOne, 'Products.ZenModel.ZenMenu',
                                'menuable')),
    )

    # Screen action bindings (and tab definitions)
    factory_type_information = ({
        'id':
        'DataRoot',
        'meta_type':
        'DataRoot',
        'description':
        """Arbitrary device grouping class""",
        'icon':
        'DataRoot_icon.gif',
        'product':
        'ZenModel',
        'factory':
        'manage_addStatusMonitorconf',
        'immediate_view':
        'Dashboard',
        'actions': (
            {
                'id': 'settings',
                'name': 'Settings',
                'action': 'editSettings',
                'permissions': (ZEN_MANAGE_GLOBAL_SETTINGS, )
            },
            {
                'id': 'manage',
                'name': 'Commands',
                'action': 'dataRootManage',
                'permissions': (ZEN_MANAGE_GLOBAL_COMMANDS, )
            },
            {
                'id':
                'users',
                'name':
                'Users',
                'action':
                'ZenUsers/manageUserFolder',
                'permissions': (
                    ZEN_VIEW_USERS,
                    ZEN_MANAGE_USERS,
                    ZEN_MANAGE_GROUPS,
                )
            },
            {
                'id': 'packs',
                'name': 'ZenPacks',
                'action': 'ZenPackManager/viewZenPacks',
                'permissions': (ZEN_MANAGE_ZENPACKS, )
            },
            {
                'id': 'portlets',
                'name': 'Portlets',
                'action': 'editPortletPerms',
                'permissions': ("Manage DMD", )
            },
            {
                'id': 'versions',
                'name': 'Versions',
                'action': '../About/zenossVersions',
                'permissions': (ZEN_VIEW_SOFTWARE_VERSIONS, )
            },
            {
                'id': 'eventConfig',
                'name': 'Events',
                'action': 'eventConfig',
                'permissions': (ZEN_MANAGE_EVENT_CONFIG, )
            },
            {
                'id': 'userInterfaceConfig',
                'name': 'User Interface',
                'action': 'userInterfaceConfig',
                'permissions': (ZEN_MANAGE_UI_SETTINGS, )
            },
        )
    }, )

    if not bool(globalConfToDict().get('zcml-enable-cz-dashboard', '')):
        factory_type_information[0]['immediate_view'] = "Events"
        del factory_type_information[0]['factory']

    security = ClassSecurityInfo()

    # production state threshold at which devices show on dashboard
    prodStateDashboardThresh = 1000

    # priority threshold at which devices show on dashboard
    priorityDashboardThresh = 2

    prodStateConversions = [
        'Production:1000',
        'Pre-Production:500',
        'Test:400',
        'Maintenance:300',
        'Decommissioned:-1',
    ]

    priorityConversions = [
        'Highest:5',
        'High:4',
        'Normal:3',
        'Low:2',
        'Lowest:1',
        'Trivial:0',
    ]

    statusConversions = [
        'Up:0',
        'None:-1',
        'No DNS:-2',
    ]

    interfaceStateConversions = [
        'up:1',
        'down:2',
        'testing:3',
        'unknown:4',
        'dormant:5',
        'notPresent:6',
        'lowerLayerDown:7',
    ]

    defaultDateRange = 129600
    performanceDateRanges = [(
        'Hourly',
        129600,
    ), (
        'Daily',
        864000,
    ), (
        'Weekly',
        3628800,
    ), (
        'Monthly',
        41472000,
    ), (
        'Yearly',
        62208000,
    )]

    # when calculating the primary path this will be its root
    zPrimaryBasePath = ("", "zport")

    def __init__(self, id, title=None):
        ZenModelRM.__init__(self, id, title)
        from ZVersion import VERSION
        self.version = "Zenoss " + VERSION

    def index_html(self):
        return self()

    def getEventCount(self, **kwargs):
        """Return the current event list for this managed entity.
        """
        return self.ZenEventManager.getEventCount(**kwargs)

    security.declareProtected(ZEN_COMMON, 'getEventClassNames')

    def getEventClassNames(self):
        """
        Get a list of all event class names within the permission scope.
        """
        return self.Events.getOrganizerNames()

    def getDmdRoots(self):
        return filter(lambda o: o.isInTree, self.objectValues())

    def exportXmlHook(self, ofile, ignorerels):
        map(lambda x: x.exportXml(ofile, ignorerels), self.getDmdRoots())

    security.declareProtected(ZEN_COMMON, 'getProdStateConversions')

    def getProdStateConversions(self):
        """getProdStateConversions() -> return a list of tuples
        for prodstat select edit box"""
        return self.getConversions(self.prodStateConversions)

    security.declareProtected(ZEN_COMMON, 'convertProdState')

    def convertProdState(self, prodState):
        '''convert a numeric production state to a
        textual representation using the prodStateConversions
        map'''
        return self.convertAttribute(prodState, self.prodStateConversions)

    security.declareProtected(ZEN_COMMON, 'getStatusConversions')

    def getStatusConversions(self):
        """get text strings for status field"""
        return self.getConversions(self.statusConversions)

    security.declareProtected(ZEN_COMMON, 'convertStatus')

    def convertStatus(self, status):
        """get text strings for status field"""
        return self.convertAttribute(status, self.statusConversions)

    security.declareProtected(ZEN_COMMON, 'getPriorityConversions')

    def getPriorityConversions(self):
        return self.getConversions(self.priorityConversions)

    security.declareProtected(ZEN_COMMON, 'convertPriority')

    def convertPriority(self, priority):
        return self.convertAttribute(priority, self.priorityConversions)

    security.declareProtected(ZEN_COMMON, 'getInterfaceStateConversions')

    def getInterfaceStateConversions(self):
        """get text strings for interface status"""
        if hasattr(self, 'interfaceStateConversions'):
            return self.getConversions(self.interfaceStateConversions)

    security.declareProtected(ZEN_COMMON, 'convertAttribute')

    def convertAttribute(self, numbValue, conversions):
        '''convert a numeric production state to a
        textual representation using the prodStateConversions
        map'''
        if numbValue is None:
            return 'Unknown'

        numbValue = int(numbValue)
        for line in conversions:
            line = line.rstrip()
            (name, number) = line.split(':')
            if int(number) == numbValue:
                return name
        return numbValue

    security.declareProtected(ZEN_COMMON, 'convertStatusToDot')

    def convertStatusToDot(self, status):
        colors = ['green', 'yellow', 'orange', 'red']
        try:
            return colors[status]
        except IndexError:
            return 'grey'

    security.declareProtected(ZEN_COMMON, 'getConversions')

    def getConversions(self, attribute):
        """get the text list of itmes that convert to ints"""
        convs = []
        for item in attribute:
            tup = item.split(':')
            try:
                tup[1] = int(tup[1])
            except (IndexError, ValueError):
                continue
            convs.append(tup)
        return convs

    security.declarePrivate('filterObjectsRegex')

    def filterObjectsRegex(self,
                           filter,
                           objects,
                           filteratt='id',
                           negatefilter=0):
        """filter a list of objects based on a regex"""
        filter = re.compile(filter).search
        filteredObjects = []
        for obj in objects:
            value = getattr(obj, filteratt, None)
            if callable(value):
                value = value()
            fvalue = filter(value)
            if (fvalue and not negatefilter) or (not fvalue and negatefilter):
                filteredObjects.append(obj)
        return filteredObjects

    security.declareProtected('View', 'myUserGroups')

    def myUserGroups(self):
        user = self.REQUEST.get('AUTHENTICATED_USER')
        if hasattr(user, 'getGroups'):
            return user.getGroups()
        else:
            return ()

    security.declareProtected('View', 'getAllUserGroups')

    def getAllUserGroups(self):
        return self.acl_users.getGroups()

    security.declareProtected(ZEN_VIEW, 'zenoss_error_message')

    def zenoss_error_message(self, error_type, error_value, error_traceback,
                             error_message):
        """Return an error page that is more friendly then the standard stack
        trace + feedback page for ConflictErrors and MySQL errors (we need to
        add out of disk space errors). If one of these is not found we return
        the old stacktrace page
        """
        from ZODB.POSException import ConflictError
        from Products.ZenEvents.Exceptions import MySQLConnectionError

        from zope.component import getUtility
        from Products.ZenUtils.ZodbFactory import IZodbFactoryLookup
        connectionFactory = getUtility(IZodbFactoryLookup).get()

        if isinstance(error_value, ConflictError):
            return self.zenoss_conflict_error_message()
        elif isinstance(error_value, MySQLConnectionError) \
                or isinstance(error_value, connectionFactory.exceptions.Error):
            return self.zenoss_mysql_error_message(error_value=error_value)
        elif isinstance(error_value, Unauthorized):
            self.REQUEST.response.status = httplib.UNAUTHORIZED
            return

        from traceback import format_exception_only
        error_formatted = ''.join(
            format_exception_only(error_type, error_value))
        return self.zenoss_feedback_error_message(
            error_type=error_type,
            error_value=error_value,
            error_traceback=error_traceback,
            error_formatted=error_formatted)

    def reportError(self):
        ''' send an email to the zenoss error email address
            then send user to a thankyou page or an email error page.
        '''
        if self.smtpHost: host = self.smtpHost
        else: host = None
        port = self.smtpPort and self.smtpPort or 25
        usetls = self.smtpUseTLS
        usr = self.smtpUser
        pwd = self.smtpPass

        mailSent = SiteError.sendErrorEmail(
            self.REQUEST.errorType, self.REQUEST.errorValue,
            self.REQUEST.errorTrace, self.REQUEST.errorUrl,
            self.About.getZenossVersionShort(), self.REQUEST.contactName,
            self.REQUEST.contactEmail, self.REQUEST.comments, host, port,
            usetls, usr, pwd)
        if not mailSent:
            body = SiteError.createReport(
                self.REQUEST.errorType, self.REQUEST.errorValue,
                self.REQUEST.errorTrace, self.REQUEST.errorUrl,
                self.About.getZenossVersionShort(), True,
                self.REQUEST.contactName, self.REQUEST.contactEmail,
                self.REQUEST.comments)
            return self.errorEmailFailure(toAddress=SiteError.ERRORS_ADDRESS,
                                          body=body)
        return self.errorEmailThankYou()

    @unpublished
    def writeExportRows(self, fieldsAndLabels, objects, out=None):
        '''Write out csv rows with the given objects and fields.
        If out is not None then call out.write() with the result and return None
        otherwise return the result.
        Each item in fieldsAndLabels is either a string representing a
         field/key/index (see getDataField) or it is a tuple of (field, label)
         where label is the string to be used in the first row as label
         for that column.
        Objects can be either dicts, lists/tuples or other objects. Field
         is interpreted as a key, index or attribute depending on what
         object is.
        Method names can be passed instead of attribute/key/indices as field.
         In this case the method is called and the return value is used in
         the export.
        '''
        import csv
        import StringIO
        if out:
            buffer = out
        else:
            buffer = StringIO.StringIO()
        fields = []
        labels = []
        if not fieldsAndLabels:
            fieldsAndLabels = []
        if not objects:
            objects = []
        for p in fieldsAndLabels:
            if isinstance(p, tuple):
                fields.append(p[0])
                labels.append(p[1])
            else:
                fields.append(p)
                labels.append(p)
        writer = csv.writer(buffer)
        writer.writerow(labels)

        def getDataField(thing, field):
            if not isinstance(field, basestring):
                value = field(getEngine().getContext({
                    'here': thing,
                    'device': thing,
                    'dev': thing
                }))
            else:
                if isinstance(thing, dict):
                    value = thing.get(field, '')
                elif isinstance(thing, list) or isinstance(thing, tuple):
                    value = thing[int(field)]
                else:
                    value = getattr(thing, field, '')
            if isinstance(value, ZenModelBase):
                value = value.id
            elif callable(value):
                value = value()
            if value is None:
                value = ''
            return str(value)

        for i, field in enumerate(fields):
            testTales = field.split(':', 1)[0].strip().lower()
            if testTales == 'python':
                fields[i] = talesCompile(field)
        for o in objects:
            writer.writerow([getDataField(o, f) for f in fields])
        if out:
            result = None
        else:
            result = buffer.getvalue()
        # aborting the long running export transaction so it is not retried
        import transaction
        transaction.abort()
        return result

    def getUserCommandTargets(self):
        ''' Called by Commandable.doCommand() to ascertain objects on which
        a UserCommand should be executed.
        '''
        raise NotImplemented

    def getUrlForUserCommands(self):
        return self.getPrimaryUrlPath() + '/dataRootManage'

    def getDefaultEmailFrom(self):
        hostname = self.zenossHostname
        hostname = hostname.replace("https://", "")
        hostname = hostname.replace("http://", "")
        return 'zenossuser_%s@%s' % (getSecurityManager().getUser().getId(),
                                     hostname)

    def getEmailFrom(self):
        ''' Return self.emailFrom or a suitable default
        '''
        return self.emailFrom or self.getDefaultEmailFrom()

    def checkValidId(self, id, prep_id=False):
        """Checks a valid id
        """
        if len(id) > 128:
            return 'Command definition names can not be longer than 128 characters.'
        allowed = set(string.ascii_letters + string.digits + '_')
        attempted = set(id)
        if not attempted.issubset(allowed):
            return 'Only letters, digits and underscores are allowed' + \
                    ' in command definition names.'
        return ZenModelRM.checkValidId(self, id, prep_id)

    def goToStatusPage(self, objid, REQUEST=None):
        """ Find a device or network and redirect
            to its status page.
        """
        import urllib
        objid = urllib.unquote(objid)
        try:
            devid = objid
            if not devid.endswith('*'): devid += '*'
            obj = self.Devices.findDevice(devid)
        except Exception:
            obj = None
        if not obj:
            try:
                obj = self.Networks.getNet(objid)
            except IpAddressError:
                return None
        if not obj: return None
        if REQUEST is not None:
            path = getUtility(IVirtualRoot).ensure_virtual_root(
                obj.getPrimaryUrlPath())
            REQUEST['RESPONSE'].redirect(path)

    def getXMLEdges(self, objid, depth=1, filter="/"):
        """ Get the XML representation of network nodes
            and edges using the obj with objid as a root
        """
        import urllib
        objid = cgi.escape(urllib.unquote(objid))
        try:
            devid = objid
            if not devid.endswith('*'): devid += '*'
            obj = self.Networks.getNet(objid)
        except Exception:
            obj = None
        if not obj:
            obj = self.Devices.findDevice(devid)
        if not obj:
            return '<graph><Start name="%s"/></graph>' % objid
        # for modpagespeed and others do not transform these results
        if hasattr(self, "REQUEST"):
            self.REQUEST.response.setHeader('Cache-Control', 'no-transform')
        return obj.getXMLEdges(int(depth),
                               filter,
                               start=(obj.id, obj.getPrimaryUrlPath()))

    security.declareProtected(ZEN_MANAGE_DMD, 'getBackupFilesInfo')

    def getBackupFilesInfo(self):
        return self.getFilesInfo('backups')

    def getFilesInfo(self, path):
        """
        Retrieve a list of dictionaries describing the files in
        $ZENHOME/backups.
        """
        import stat
        import operator

        def FmtFileSize(size):
            for power, units in ((3, 'GB'), (2, 'MB'), (1, 'KB')):
                if size > pow(1024, power):
                    fmt = '%.2f %s' % ((size * 1.0) / pow(1024, power), units)
                    break
            else:
                fmt = '%s bytes' % size
            return fmt

        backupsDir = zenPath(path)
        fileInfo = []
        if os.path.isdir(backupsDir):
            for dirPath, dirNames, fileNames in os.walk(backupsDir):
                dirNames[:] = []
                for fileName in fileNames:
                    filePath = os.path.join(backupsDir, fileName)
                    info = os.stat(filePath)
                    fileInfo.append({
                        'fileName':
                        fileName,
                        'size':
                        info[stat.ST_SIZE],
                        'sizeFormatted':
                        FmtFileSize(info[stat.ST_SIZE]),
                        'modDate':
                        info[stat.ST_MTIME],
                        'modDateFormatted':
                        datetime.fromtimestamp(
                            info[stat.ST_MTIME]).strftime('%c'),
                    })
        fileInfo.sort(key=operator.itemgetter('modDate'))
        return fileInfo

    security.declareProtected(ZEN_MANAGE_DMD, 'manage_createBackup')

    def manage_createBackup(self,
                            includeEvents=None,
                            includeMysqlLogin=None,
                            timeout=120,
                            REQUEST=None,
                            writeMethod=None):
        """
        Create a new backup file using zenbackup and the options specified
        in the request.

        This method makes use of the fact that DataRoot is a Commandable
        in order to use Commandable.write
        """
        import popen2
        import fcntl
        import time
        import select

        def write(s):
            if writeMethod:
                writeMethod(s)
            elif REQUEST:
                self.write(REQUEST.RESPONSE, s)

        footer = None
        if REQUEST and not writeMethod:
            header, footer = self.commandOutputTemplate().split('OUTPUT_TOKEN')
            REQUEST.RESPONSE.write(str(header))
        write('')
        try:
            cmd = binPath('zenbackup') + ' -v10'
            if not includeEvents:
                cmd += ' --no-eventsdb'
            if not includeMysqlLogin:
                cmd += ' --no-save-mysql-access'
            try:
                timeout = int(timeout)
            except ValueError:
                timeout = 120
            timeout = max(timeout, 1)
            child = popen2.Popen4(cmd)
            flags = fcntl.fcntl(child.fromchild, fcntl.F_GETFL)
            fcntl.fcntl(child.fromchild, fcntl.F_SETFL, flags | os.O_NDELAY)
            endtime = time.time() + timeout
            write('%s' % cmd)
            write('')
            pollPeriod = 1
            firstPass = True
            while time.time() < endtime and (firstPass or child.poll() == -1):
                firstPass = False
                r, w, e = select.select([child.fromchild], [], [], pollPeriod)
                if r:
                    t = child.fromchild.read()
                    # We are sometimes getting to this point without any data
                    # from child.fromchild.  I don't think that should happen
                    # but the conditional below seems to be necessary.
                    if t:
                        write(t)

            if child.poll() == -1:
                write('Backup timed out after %s seconds.' % timeout)
                import signal
                os.kill(child.pid, signal.SIGKILL)

            write('DONE')
        except Exception:
            write('Exception while performing backup.')
            write('type: %s  value: %s' % tuple(sys.exc_info()[:2]))
        else:
            if REQUEST or writeMethod:
                audit('UI.Backup.Create')
        write('')
        if REQUEST and footer:
            REQUEST.RESPONSE.write(footer)

    security.declareProtected(ZEN_MANAGE_DMD, 'manage_deleteBackups')

    def manage_deleteBackups(self, fileNames=(), REQUEST=None):
        """
        Delete the specified files from $ZENHOME/backups
        """
        backupsDir = zenPath('backups')
        removed = []
        if os.path.isdir(backupsDir):
            for dirPath, dirNames, dirFileNames in os.walk(backupsDir):
                dirNames[:] = []
                for fileName in fileNames:
                    if fileName in dirFileNames:
                        toRemove = os.path.join(dirPath, fileName)
                        res = os.remove(toRemove)
                        if not res:
                            removed.append(toRemove)
            if REQUEST:
                audit('UI.Backup.Delete', files=removed)
                messaging.IMessageSender(self).sendToBrowser(
                    'Backups Deleted',
                    '%s backup files have been deleted.' % len(removed))
        else:
            if REQUEST:
                messaging.IMessageSender(self).sendToBrowser(
                    'Backup Directory Missing',
                    'Unable to find $ZENHOME/backups.', messaging.WARNING)
        if REQUEST:
            return self.callZenScreen(REQUEST)

    def getProductName(self):
        """
        Return a string that represents the Zenoss product that is installed.
        Currently this is something like 'core' or 'enterprise'.  This is
        used in the version check code to retrieve the available version
        for the correct product.
        """
        return getattr(self, 'productName', 'core')

    def getProductHelpLink(self):
        """
        Return a URL to docs for the Zenoss product that is installed.
        """
        return "https://help.zenoss.com/docs/collection-zone"

    def getDocFilesInfo(self):
        docDir = os.path.join(zenPath("Products"), 'ZenUI3', 'docs')
        product = self.getProductName()
        docCategories = ['admin', 'install', 'notes', 'zenpacks']
        downloadable = []

        for category in docCategories:
            for root, dirs, files in os.walk(
                    os.path.join(docDir, category, product)):
                for file in files:
                    if file.endswith(".pdf"):
                        downloadable.append({
                            "title":
                            file,
                            "filename":
                            category + "/" + product + "/pdf/" + file
                        })

        return downloadable

    def error_handler(self, error=None):
        """
        Returns pretty messages when errors are raised in templates.

        Access this method from a template like so:
            <div tal:content="..."
                 ...
                 tal:on-error="structure python:here.dmd.error_handler(error)">

        @param error: A TALES.ErrorInfo instance with attributes type, value
                      and traceback.
        @return: HTML fragment with an error message
        """
        if error.type == MySQLConnectionError:
            msg = "Unable to connect to the MySQL server."

        elif error.type in [pythonThresholdException, rpnThresholdException]:
            msg = error.value

        else:
            raise

        return '<b class="errormsg">%s</b>' % msg

    @json
    def isDebugMode(self):
        """
        Whether we're in debug mode, so that javascript will behave accordingly
        """
        return DevelopmentMode

    def versionId(self):
        """
        Get a string representative of the code version, to override JS
        caching.
        """
        return self.About.getZenossVersion().full().replace(
            'Zenoss', '').replace(' ', '').replace('.', '')

    def _updateEmailNotifications(self, REQUEST):
        """update email notifications that use system-wide settings"""

        # translates dmd property to notification content key
        email_props = dict(smtpHost="host",
                           smtpPort="port",
                           smtpUser="******",
                           smtpPass="******",
                           smtpUseTLS="useTls",
                           emailFrom="email_from")

        # did the system-wide email properties change?
        email_props_changed = False
        for prop in email_props:
            if self.getProperty(prop) != REQUEST.get(prop):
                email_props_changed = True
                break

        # if so, find all email notifications that use the system-wide
        # settings and update them
        if email_props_changed:
            for notif in self.NotificationSubscriptions.objectValues():
                if notif.action == "email":

                    notif_uses_system_props = True
                    for prop, content_key in email_props.iteritems():

                        value = self.getProperty(prop)
                        notif_value = notif.content[content_key]
                        if prop == "emailFrom":
                            value = self.getEmailFrom()
                        elif prop == "smtpPort":
                            try:
                                notif_value = int(notif_value)
                            except ValueError:
                                # ZEN-26409: port is not convertible to an int,
                                # so don't bother trying to make it equal value.
                                pass

                        if notif_value != value:
                            notif_uses_system_props = False
                            break

                    if notif_uses_system_props:
                        notif._p_changed = True
                        for prop, content_key in email_props.iteritems():
                            notif.content[content_key] = REQUEST.get(prop)
                        if not notif.content["email_from"]:
                            notif.content[
                                "email_from"] = self.getDefaultEmailFrom()

    security.declareProtected('Manage DMD', 'zmanage_editProperties')

    def zmanage_editProperties(self, REQUEST=None, redirect=False):
        """Handle our authentication mechanism
        """

        if REQUEST:
            app = self.unrestrictedTraverse('/')
            if REQUEST.get('userAuthType') == self.AUTH_TYPE_SESSION:
                activateSessionBasedAuthentication(self.zport)
                activateSessionBasedAuthentication(app)  # for admin
            elif REQUEST.get('userAuthType') == self.AUTH_TYPE_COOKIE:
                activateCookieBasedAuthentication(self.zport)
                activateCookieBasedAuthentication(app)  # for admin
            self._updateEmailNotifications(REQUEST)
        return super(DataRoot, self).zmanage_editProperties(REQUEST, redirect)

    def addZendmdStartupCommand(self, command):
        if not self.zendmdStartupCommands:
            self.zendmdStartupCommands = PersistentList()
        self.zendmdStartupCommands.append(command)

    def getZenDMDStartupCommands(self):
        return self.zendmdStartupCommands

    def removeZendmdStartupCommand(self, command):
        self.zendmdStartupCommands = PersistentList(
            [x for x in self.zendmdStartupCommands if x != command])

    def getPauseADMLife(self):
        """
        Gets time in seconds since pauseADMStart
        """
        return (datetime.utcnow() - self.pauseADMStart).total_seconds()

    @transact
    def startPauseADM(self):
        """
        Sets pauseADMStart to the current time
        """
        self.pauseADMStart = datetime.utcnow()

    @transact
    def stopPauseADM(self):
        """
        Sets pauseADMStart to the min datetime
        """
        self.pauseADMStart = datetime.min