def __getIpObjectFromDestinationData(ip_address, ip_mac_address):
    '''
    @types: str, str -> IPAddress
    try to get ip address by mac address from ARP Cache
    '''
    foundIp = clientdiscoveryutils.getIPAddressOnlyFromMacAddress(ip_mac_address)
    if foundIp:
        ip_address = foundIp
    return ip_addr.IPAddress(ip_address)
def DiscoveryMain(Framework):
    SHELL_CLIENT_PROTOCOLS = _getSupportedShellProtocols(Framework)

    ip = Framework.getDestinationAttribute('ip_address')
    domain = Framework.getDestinationAttribute('ip_domain')
    codepage = Framework.getCodePage()
    useLastState = Framework.getParameter('useLastSuccessConnection')

    vector = ObjectStateHolderVector()
    warningsList = []
    errorsList = []

    # preparing empty dictionary for storing credentials later
    credentialsByType = {}

    # take the latest used credentials if any
    lastState = None
    if useLastState and useLastState.lower() == 'true':
        lastState = Framework.loadState()

    if lastState:
        credentialsByType[None] = [lastState]

    # try to get ip address by mac address from ARP Cache
    macAddress = Framework.getDestinationAttribute('ip_mac_address')
    foundIp = clientdiscoveryutils.getIPAddressOnlyFromMacAddress(macAddress)
    if foundIp:
        ip = foundIp

    # Gather credentials for protocols
    for clientType in SHELL_CLIENT_PROTOCOLS:
        # getting an ordered list of credentials for the given client type and storing them in the credentials dictionary
        protocols = netutils.getAvailableProtocols(Framework, clientType, ip, domain)
        if protocols:
            credentialsByType[clientType] = protocols

    ##########################################################################################################
    ##################################Start Special processing for Universal Discovery Agent##################
    # take Universal Discovery Agent credentials if new Universal Discovery Agent installed on that IP

    connectedDDMAgentCredentials = None
    if useLastState and useLastState.lower() == 'true':
        connectedDDMAgentCredentials = Framework.loadGlobalState(ip)

    client = None
    udaNotAlive = 0

    if connectedDDMAgentCredentials:
        logger.debug('Found global state credentials ', connectedDDMAgentCredentials, ' of installed agent on ip:', ip)
        client = createClient(Framework, ClientsConsts.DDM_AGENT_PROTOCOL_NAME, [connectedDDMAgentCredentials], ip, codepage, warningsList, errorsList)
        # If we are successfully connected
        if client:
            logger.debug('Succeeded to connect with global state credentials ', client.getCredentialId(), ' of installed agent')
            Framework.saveState(client.getCredentialId())
        else:
            logger.debug('Failed to connect with global state credentials ', connectedDDMAgentCredentials, ' on ip:', ip)
            udaNotAlive = 1
            #AgentUtils.clearGlobalState(Framework)
    # only for case where no connection established before
    if not client:
        # checks whether there are credential for specified protocol
        if credentialsByType:
            if lastState:
                client = createClientFromLastState(Framework, lastState, warningsList, errorsList)
                if not client:
                    logger.debug('Failed to create client using last state properties. Will try to connect using other credentials.')
            if not client:
                for clientType in SHELL_CLIENT_PROTOCOLS:
                    credentials = credentialsByType.get(clientType)
                    if credentials:
                        client = createClient(Framework, clientType, credentials, ip, codepage, warningsList, errorsList)
                        if client:
                            warningsList = []
                            errorsList = []
                            # save credentials id for further reuse
                            Framework.saveState(client.getCredentialId())
                            break
        else:
            for shellType in SHELL_CLIENT_PROTOCOLS:
                msg = errormessages.makeErrorMessage(shellType, pattern=errormessages.ERROR_NO_CREDENTIALS)
                errobj = errorobject.createError(errorcodes.NO_CREDENTIALS_FOR_TRIGGERED_IP, [shellType], msg)
                warningsList.append(errobj)

    if not client:
        Framework.clearState()
    else:
        # successfully connected, do discovery
        shell = None
        clientType = client.getClientType()

        connectedOSCredentialID = None
        try:
            try:
                shellFactory = shellutils.ShellFactory()
                shell = shellFactory.createShell(client, clientType)

                connectedOSCredentialID = ConnectedOSCredentialFinder.findCredential(Framework, shell, client,
                    errorsList, warningsList)

                # If we got a default value, we just pass None later
                # Else - we need to signal the existing client which can be only UDA by now that it has a credential
                # to take sudo password from, if it needs it
                if (not connectedOSCredentialID
                    or connectedOSCredentialID == ConnectedOSCredentialFinder.NO_CONNECTED_CRED_ID):
                    connectedOSCredentialID = None
                else:
                    try:
                        client.setConnectedShellCredentialID(connectedOSCredentialID)
                    except:
                        logger.warn('Failed to setConnectedShellCredentialID, sudo commands may not work in this run')

                vector.addAll(doDiscovery(Framework, shell, client, ip, codepage, connectedOSCredentialID))
            except (Exception, JException), jex:
                msg = str(jex)
                logger.debugException(msg)
                errormessages.resolveAndAddToObjectsCollections(msg,
                                        clientType, warningsList, errorsList)
        finally:
            if udaNotAlive and client:
                logger.debug('find another shell can be connected. ', shell)
                logger.debug('Removing the connected uda shell because it failed to connect')

                agentOsh = ObjectStateHolder(ClientsConsts.DDM_AGENT_PROTOCOL_NAME)

                agentOsh.setAttribute('application_ip', ip)
                agentOsh.setAttribute('data_name', ClientsConsts.DDM_AGENT_PROTOCOL_NAME)

                #agentOsh.setAttribute('application_port', shell.getPort())
                agentOsh.setContainer(modeling.createHostOSH(ip))
                Framework.deleteObject(agentOsh)
                Framework.flushObjects()

                Framework.clearGlobalState(ip)
            if shell:
                try:
                    shell.closeClient()
                except:
                    errobj = errorobject.createError(errorcodes.CLIENT_NOT_CLOSED_PROPERLY, None, "Client was not closed properly")
                    warningsList.append(errobj)
                    logger.warnException('')
            # close client anyway
            if client and client.close(): pass
            # create shell OSH if connection established but discovery failed
            if not vector.size():
                logger.warn('Discovery failed, though shell object will be created')
                hostOsh = modeling.createHostOSH(ip, filter_client_ip=True)
                if hostOsh:
                    languageName = None
                    langBund = Framework.getEnvironmentInformation().getBundle('langNetwork', languageName)
                    shellOsh = createShellObj(client, client, ip, langBund, languageName, codepage, connectedShellCredId=connectedOSCredentialID)
                    shellOsh.setContainer(hostOsh)

                    vector.add(shellOsh)
                else:
                    logger.warn('Failed to create node and shell since IP is of a Client range type, not enough data for reconciliation.')

    for errobj in warningsList:
        logger.reportWarningObject(errobj)
    for errobj in errorsList:
        logger.reportErrorObject(errobj)

    return vector
def DiscoveryMain(Framework):
    SHELL_CLIENT_PROTOCOLS = _getSupportedShellProtocols(Framework)

    ip = Framework.getDestinationAttribute('ip_address')
    domain = Framework.getDestinationAttribute('ip_domain')
    codepage = Framework.getCodePage()
    useLastState = Framework.getParameter('useLastSuccessConnection')

    vector = ObjectStateHolderVector()
    warningsList = []
    errorsList = []

    # preparing empty dictionary for storing credentials later
    credentialsByType = {}

    # take the latest used credentials if any
    lastState = None
    if useLastState and useLastState.lower() == 'true':
        lastState = Framework.loadState()

    if lastState:
        credentialsByType[None] = [lastState]

    # try to get ip address by mac address from ARP Cache
    macAddress = Framework.getDestinationAttribute('ip_mac_address')
    foundIp = clientdiscoveryutils.getIPAddressOnlyFromMacAddress(macAddress)
    if foundIp:
        ip = foundIp

    # Gather credentials for protocols
    for clientType in SHELL_CLIENT_PROTOCOLS:
        # getting an ordered list of credentials for the given client type and storing them in the credentials dictionary
        protocols = netutils.getAvailableProtocols(Framework, clientType, ip,
                                                   domain)
        if protocols:
            credentialsByType[clientType] = protocols

    ##########################################################################################################
    ##################################Start Special processing for Universal Discovery Agent##################
    # take Universal Discovery Agent credentials if new Universal Discovery Agent installed on that IP

    connectedDDMAgentCredentials = None
    if useLastState and useLastState.lower() == 'true':
        connectedDDMAgentCredentials = Framework.loadGlobalState(ip)

    client = None
    udaNotAlive = 0

    if connectedDDMAgentCredentials:
        logger.debug('Found global state credentials ',
                     connectedDDMAgentCredentials,
                     ' of installed agent on ip:', ip)
        client = createClient(Framework, ClientsConsts.DDM_AGENT_PROTOCOL_NAME,
                              [connectedDDMAgentCredentials], ip, codepage,
                              warningsList, errorsList)
        # If we are successfully connected
        if client:
            logger.debug('Succeeded to connect with global state credentials ',
                         client.getCredentialId(), ' of installed agent')
            Framework.saveState(client.getCredentialId())
        else:
            logger.debug('Failed to connect with global state credentials ',
                         connectedDDMAgentCredentials, ' on ip:', ip)
            udaNotAlive = 1
            #AgentUtils.clearGlobalState(Framework)
    # only for case where no connection established before
    if not client:
        # checks whether there are credential for specified protocol
        if credentialsByType:
            if lastState:
                client = createClientFromLastState(Framework, lastState,
                                                   warningsList, errorsList)
                if not client:
                    logger.debug(
                        'Failed to create client using last state properties. Will try to connect using other credentials.'
                    )
            if not client:
                for clientType in SHELL_CLIENT_PROTOCOLS:
                    credentials = credentialsByType.get(clientType)
                    if credentials:
                        client = createClient(Framework, clientType,
                                              credentials, ip, codepage,
                                              warningsList, errorsList)
                        if client:
                            warningsList = []
                            errorsList = []
                            # save credentials id for further reuse
                            Framework.saveState(client.getCredentialId())
                            break
        else:
            for shellType in SHELL_CLIENT_PROTOCOLS:
                msg = errormessages.makeErrorMessage(
                    shellType, pattern=errormessages.ERROR_NO_CREDENTIALS)
                errobj = errorobject.createError(
                    errorcodes.NO_CREDENTIALS_FOR_TRIGGERED_IP, [shellType],
                    msg)
                warningsList.append(errobj)

    if not client:
        Framework.clearState()
    else:
        # successfully connected, do discovery
        shell = None
        clientType = client.getClientType()

        connectedOSCredentialID = None
        try:
            try:
                shellFactory = shellutils.ShellFactory()
                shell = shellFactory.createShell(client, clientType)

                connectedOSCredentialID = ConnectedOSCredentialFinder.findCredential(
                    Framework, shell, client, errorsList, warningsList)

                # If we got a default value, we just pass None later
                # Else - we need to signal the existing client which can be only UDA by now that it has a credential
                # to take sudo password from, if it needs it
                if (not connectedOSCredentialID or connectedOSCredentialID
                        == ConnectedOSCredentialFinder.NO_CONNECTED_CRED_ID):
                    connectedOSCredentialID = None
                else:
                    try:
                        client.setConnectedShellCredentialID(
                            connectedOSCredentialID)
                    except:
                        logger.warn(
                            'Failed to setConnectedShellCredentialID, sudo commands may not work in this run'
                        )

                vector.addAll(
                    doDiscovery(Framework, shell, client, ip, codepage,
                                connectedOSCredentialID))
            except (Exception, JException), jex:
                msg = str(jex)
                logger.debugException(msg)
                errormessages.resolveAndAddToObjectsCollections(
                    msg, clientType, warningsList, errorsList)
        finally:
            if udaNotAlive and client:
                logger.debug('find another shell can be connected. ', shell)
                logger.debug(
                    'Removing the connected uda shell because it failed to connect'
                )

                agentOsh = ObjectStateHolder(
                    ClientsConsts.DDM_AGENT_PROTOCOL_NAME)

                agentOsh.setAttribute('application_ip', ip)
                agentOsh.setAttribute('data_name',
                                      ClientsConsts.DDM_AGENT_PROTOCOL_NAME)

                #agentOsh.setAttribute('application_port', shell.getPort())
                agentOsh.setContainer(modeling.createHostOSH(ip))
                Framework.deleteObject(agentOsh)
                Framework.flushObjects()

                Framework.clearGlobalState(ip)
            if shell:
                try:
                    shell.closeClient()
                except:
                    errobj = errorobject.createError(
                        errorcodes.CLIENT_NOT_CLOSED_PROPERLY, None,
                        "Client was not closed properly")
                    warningsList.append(errobj)
                    logger.warnException('')
            # close client anyway
            if client and client.close(): pass
            # create shell OSH if connection established but discovery failed
            if not vector.size():
                logger.warn(
                    'Discovery failed, though shell object will be created')
                hostOsh = modeling.createHostOSH(ip, filter_client_ip=True)
                if hostOsh:
                    languageName = None
                    langBund = Framework.getEnvironmentInformation().getBundle(
                        'langNetwork', languageName)
                    shellOsh = createShellObj(
                        client,
                        client,
                        ip,
                        langBund,
                        languageName,
                        codepage,
                        connectedShellCredId=connectedOSCredentialID)
                    shellOsh.setContainer(hostOsh)

                    vector.add(shellOsh)
                else:
                    logger.warn(
                        'Failed to create node and shell since IP is of a Client range type, not enough data for reconciliation.'
                    )

    for errobj in warningsList:
        logger.reportWarningObject(errobj)
    for errobj in errorsList:
        logger.reportErrorObject(errobj)

    return vector
def mainFunction(Framework, isClient, ip_address = None):
    _vector = ObjectStateHolderVector()
    errStr = ''
    ip_domain  = Framework.getDestinationAttribute('ip_domain')
    host_cmdbid = Framework.getDestinationAttribute('host_cmdbid')
    host_key = Framework.getDestinationAttribute('host_key')
    host_macs = Framework.getTriggerCIDataAsList('mac_addrs')
    ip_arp_mac = Framework.getDestinationAttribute('ip_mac')

    # try to get ip address by mac address from ARP Cache
    foundIp = clientdiscoveryutils.getIPAddressOnlyFromMacAddress(ip_arp_mac)
    if foundIp:
        ip_address = foundIp

    if (ip_address == None):
        ip_address = Framework.getDestinationAttribute('ip_address')
    if (ip_domain == None):
        ip_domain = DomainScopeManager.getDomainByIp(ip_address, None)

    protocols = netutils.getAvailableProtocols(Framework, ClientsConsts.SNMP_PROTOCOL_NAME, ip_address, ip_domain)
    if len(protocols) == 0:
        errStr = 'No credentials defined for the triggered ip'
        logger.debug(errStr)
        errObj = errorobject.createError(errorcodes.NO_CREDENTIALS_FOR_TRIGGERED_IP, [ClientsConsts.SNMP_PROTOCOL_NAME], errStr)
        return (_vector, errObj)

    connected = 0
    for protocol in protocols:
        client = None
        try:
            try:
                logger.debug('try to get snmp agent for: %s:%s' % (ip_address, ip_domain))
                if (isClient == TRUE):
                    properties = Properties()
                    properties.setProperty(CollectorsConstants.DESTINATION_DATA_IP_ADDRESS, ip_address)
                    properties.setProperty(CollectorsConstants.DESTINATION_DATA_IP_DOMAIN, ip_domain)
                    client = Framework.createClient(protocol, properties)
                else:
                    properties = Properties()
                    properties.setProperty(CollectorsConstants.DESTINATION_DATA_IP_ADDRESS, ip_address)
                    client = Framework.createClient(protocol, properties)
                logger.debug('Running test connection queries')
                testConnection(client)
                Framework.saveState(protocol)
                logger.debug('got snmp agent for: %s:%s' % (ip_address, ip_domain))
                isMultiOid = client.supportMultiOid()
                logger.debug('snmp server isMultiOid state=%s' %isMultiOid)
                # create snmp OSH
                snmpOSH = modeling.createSnmpOSH(ip_address, client.getPort())
                snmpOSH.setAttribute('application_timeout', client.getTimeout())
                snmpOSH.setAttribute('snmp_port', client.getPort())
                snmpOSH.setAttribute('credentials_id', client.getCredentialId())
                snmpOSH.setAttribute('snmp_retry', client.getRetries())
                snmpOSH.setAttribute('snmp_timeout', client.getTimeout())
                #obtain SNMP protocol version
                snmpVersion = definedSnmpProtocolVersion(protocol, Framework)
                snmpOSH.setAttribute('application_version_number', snmpVersion)
                if ip_arp_mac and ip_arp_mac != 'NA':
                    snmpOSH.setAttribute('arp_mac', ip_arp_mac)

                if isMultiOid == 1:
                    snmpOSH.setBoolAttribute('snmp_supportmultioid', 1)
                else:
                    snmpOSH.setBoolAttribute('snmp_supportmultioid', 0)

                _vector = doSnmp(client, isClient, snmpOSH, ip_address, ip_domain, Framework, host_cmdbid, host_key, host_macs)
                client.close()
                client = None

                if _vector.size() > 0:
                    connected = 1

                    break
            except BroadcastIpDiscoveryException:
                msg = "Job has been triggered on broadcast IP, no results will be reported"
                errObj = errorobject.createError(errorcodes.NO_RESULTS_WILL_BE_REPORTED, ["Job has been triggered on broadcast IP"], msg)
                if client != None:
                    client.close()
                    client = None
                return (_vector, errObj)
            except:
                if client != None:
                    client.close()
                    client = None
                logger.debugException('Unexpected SNMP_AGENT Exception:')
                lastExceptionStr = str(sys.exc_info()[1]).strip()
        finally:
            if client != None:
                client.close()
                client = None

    error = errorobject.INTERNAL_ERROR
    if (not connected):
        errStr = errormessages.makeErrorMessage('SNMP', pattern=errormessages.ERROR_CONNECTION_FAILED)
        error = errorobject.createError(errorcodes.CONNECTION_FAILED, ['SNMP'], errStr)
        logger.debug(errStr)
        Framework.clearState()
    elif (_vector.size() == 0):
        error = errormessages.resolveError(lastExceptionStr, 'SNMP')
    return (_vector, error)