• 0
Joe Williams

Issues With Creating A Datasource

Question

I took a working groovy script datasource and am now trying to adjust it to some needs we have. This data will end up giving us alert totals for each month so we can build reports. Any ideas?

Here is what I have so far.

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Hex;
import groovy.json.JsonSlurper;

//define credentials and url
def accessId = hostProps.get('lmaccess.id');
def accessKey = hostProps.get('lmaccess.key');
def account = hostProps.get('lmaccount');
def alertgroup = hostProps.get('lmaccess.group');

def collectionFailures = 0
def failures = [:]

def client = new LogicMonitorRestClient(accessId, accessKey, account, this.&println)



try {
    def alerts = client.get("/device/groups/" + alertgroup + "/alerts", fields: "severity", filter: "startEpoch>:1538370000,endEpoch<:1541048399,cleared:*")
    //warnings = alerts.findAll {it.severity == 2}.size()
    println "WarningCount: ${alerts.findAll {it.severity == 2}.size()}"
    println "ErrorCount: ${alerts.findAll { it.severity == 3 }.size()}"
    println "CriticalCount: ${alerts.findAll { it.severity == 4 }.size()}"
    println "TotalAlerts: ${alerts.size()}"
}
catch (Throwable e) {
    failures["alerts"] = e.toString()
    collectionFailures += 1
}



// Do error reporting
println "CollectionFailures:${collectionFailures}"

failures.each{
    query, exception ->
        println "Exception while querying $query:"
        println exception
}

return 0


//////////////////////
// HELPER FUNCTIONS //
//////////////////////

class LogicMonitorRestClient {
    String userKey
    String userId
    String account

    int maxPages = 20
    int itemsPerPage = 1000

    def println

    LogicMonitorRestClient(userId, userKey,  account, printFunction) {
        this.userId = userId
        this.userKey = userKey
        this.account = account
        this.println = printFunction
    }

    def generateHeaders(verb, path) {
        def headers = [:]

        def epoch = System.currentTimeMillis()
        def requestVars = verb + epoch + path

        // Calculate signature
        def hmac = Mac.getInstance('HmacSHA256')
        def secret = new SecretKeySpec(userKey.getBytes(), 'HmacSHA256')
        hmac.init(secret)

        // Sign the request
        def hmac_signed = Hex.encodeHexString(hmac.doFinal(requestVars.getBytes()))
        def signature = hmac_signed.bytes.encodeBase64()

        headers["Authorization"] = "LMv1 " + userId + ":" + signature + ":" + epoch
        headers["Content-Type"] = "application/json"
        return headers
    }

    def packParams(params) {
        def pairs = []
        params.each{ k, v -> pairs << ("${k}=${v}")}
        return pairs.join("&")
    }

    // Non paginating, raw version of the get function
    def _rawGet(path, params) {
        def baseUrl = 'https://' + account + '.logicmonitor.com' + '/santaba/rest' + path

        def packedParams = ""
        if(params) {
            packedParams = "?"+packParams(params)
        }

        def query = baseUrl+packedParams
        def url = query.toURL()

        def response = url.getText(useCaches: true, allowUserInteraction: false,
        requestProperties: generateHeaders("GET", path))

        return response
    }

    // Public interface for getting stuff.
    def get(Map args=[:], path) {
        def itemsReceived = []
        def pageReads = 0

        // Impose our own paging parameters.
        args.size = itemsPerPage
        args.offset = 0

        while(true)
        {
            // Do da nastieh
            def response = new JsonSlurper().parseText(_rawGet(path, args))

            if (response.errmsg == "OK")
            {

                // Catch individual items
                if (response.data.items == null) {
                    return response.data
                }

                itemsReceived += response.data.items

                // Check if there are more items
                // if (response.data.total > itemsReceived.size())
                // {
                    args.offset = args.size + args.offset
                // }
                // else
                // {
                //     break // we are done
                // }
            }
            else
            {
                // Throw an exception with whatever error message we got.
                throw new Exception(response.errmsg)
            }

            pageReads += 1

            // Check that we don't exceed max pages.
            if (pageReads >= maxPages)
            {
                break
            }
            if (response.data.total > 0)
            {
                break
            }
        }
        return itemsReceived
    }
}

 

If I run the URL with the API creds in my test powershell script, it works perfectly. When I test it in LM as a datasource, I get the attached error.

 

Quote

Exception while querying alerts: java.io.IOException: Server returned HTTP response code: 400 for URL https://XXX.logicmonitor.com/santaba/rest/device/groups/224/alerts?fields=severity&filter=startEpoch>:1538370000,endEpoch<:1541048399,cleared:*

 

error_code_lm_datasource.png

Share this post


Link to post
Share on other sites

5 answers to this question

Recommended Posts

  • 1

Since it's part of a URL you might have to use urlencode rather than htmlentieies. So ">" would be "%3C". There is also java.net.URLEncoder in Groovy. I would look at perhaps using something like pairs << ("${k}=${URLEncoder.encode(v, "UTF-8")}") in your packParams() function. https://stackoverflow.com/questions/10187344/how-to-encode-url-in-groovy

Edited by Mike Moniz
  • Upvote 1

Share this post


Link to post
Share on other sites
  • 0

I haven't tested your code but I would try doing some testing and attempt to narrow down which part exactly is causing the issue. For example does your code work fine if you remove all the parameters from the URL? And if you remove just the filter part? My gut feeling would look at the non-alphanumeric characters in your filter and there might be differences between how REST calls work in PS vs Groovy. Perhaps they need to be escaped. You might also want to simplify your code, just for testing, in case there are issues with function parameters or the like.

Share this post


Link to post
Share on other sites
  • 0
6 hours ago, Mike Moniz said:

Since it's part of a URL you might have to use urlencode rather than htmlentieies. So ">" would be "%3C". There is also java.net.URLEncoder in Groovy. I would look at perhaps using something like pairs << ("${k}=${URLEncoder.encode(v, "UTF-8")}") in your packParams() function. https://stackoverflow.com/questions/10187344/how-to-encode-url-in-groovy

This was it. Thank you!

Next yeah I will work on using the encoder to fix future issues.

 

@Michael Rodrigues I went with MIke's suggestion and yeah that worked. Thanks!

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.