Forum Discussion

ldoodle's avatar
ldoodle
Icon for Advisor rankAdvisor
10 months ago

Dynamic Device Groups - constrain membership to parent folder

Hi, We have the following hierarchy setup: Our company is top level, e.g. LOGICMONITOR |--Customer Name, e.g. GOOGLE, MICROSOFT |----’All Devices’ static group (when we add new devices, we add th...
  • Anonymous's avatar
    Anonymous
    10 months ago

    So it seems tenant id would only work if each customer resourced is statically placed in a customer nested folder in the first place.

    Yes, the relationship between the device and the customer will have to be defined by you somewhere.

    It does seem a shame (maybe omission) that you can’t map a collector to its collector group and in turn the collector group name, since for us the collector group name is the exact acronym we need.

    You can do this. You just need to make an API call to grab the collector groups. Unintuitively, that wouldn’t be a call to /setting/collector/groups as that doesn’t return the IDs of the collectors in the group. Instead, do a get to /setting/collector/collectors/:id. This will give you back the collector’s group name (among other things, but we can specify that we only want collectorGroupName). 

    So, it would be something like this:

    import com.santaba.agent.util.Settings
    import groovy.json.*
    import javax.crypto.Mac
    import javax.crypto.spec.SecretKeySpec
    import org.apache.commons.codec.binary.Hex
    import org.apache.http.client.methods.*
    import org.apache.http.entity.*
    import org.apache.http.HttpEntity
    import org.apache.http.impl.client.*
    import org.apache.http.util.EntityUtils

    deviceCollectorId = hostProps.get("system.collectorId")
    collector = LM_API("GET","/setting/collector/collectors/${deviceCollectorId}","lmaccess",[:],["fields": "collectorGroupName"])
    if (collector.code == 200){
    println("organization=${collector?.body?.collectorGroupName}")
    }
    return 0

    def LM_API(httpVerb, endpointPath, creds="lmaccess", data = [:], queryParams=[:]){
    def api_id = hostProps.get("${creds}.id")
    def api_key = hostProps.get("${creds}.key")
    def api_company = hostProps.get("${creds}.company") ?: Settings.getSetting(Settings.AGENT_COMPANY)
    def queryParamsString = queryParams.collect{k,v->"${k}=${v}"}.join("&")
    def url = "https://${api_company}.logicmonitor.com/santaba/rest${endpointPath}?${queryParamsString}"
    epoch_time = System.currentTimeMillis()
    def json_data = JsonOutput.toJson(data)
    if ((httpVerb == "GET") || (httpVerb == "DELETE")){requestVars = httpVerb + epoch_time + endpointPath}
    else {requestVars = httpVerb + epoch_time + json_data + endpointPath}
    hmac = Mac.getInstance("HmacSHA256")
    secret = new SecretKeySpec(api_key.getBytes(), "HmacSHA256")
    hmac.init(secret)
    hmac_signed = Hex.encodeHexString(hmac.doFinal(requestVars.getBytes()))
    signature = hmac_signed.bytes.encodeBase64()
    CloseableHttpClient httpclient = HttpClients.createDefault()
    if (httpVerb == "GET"){http_request = new HttpGet(url)}
    else if (httpVerb == "PATCH"){
    http_request = new HttpPatch(url)
    http_request.setEntity(new StringEntity(json_data, ContentType.APPLICATION_JSON))}
    else if (httpVerb == "PUT"){
    http_request = new HttpPut(url)
    http_request.setEntity(new StringEntity(json_data, ContentType.APPLICATION_JSON))}
    else if (httpVerb == "POST"){
    http_request = new HttpPost(url)
    http_request.setEntity(new StringEntity(json_data, ContentType.APPLICATION_JSON))}
    else {http_request = null}
    if (http_request){
    http_request.setHeader("Authorization" , "LMv1 " + api_id + ":" + signature + ":" + epoch_time)
    http_request.setHeader("Accept", "application/json")
    http_request.setHeader("Content-type", "application/json")
    http_request.setHeader("X-Version", "3")
    response = httpclient.execute(http_request)
    body = EntityUtils.toString(response.getEntity())
    code = response.getStatusLine().getStatusCode()
    return ["body":new JsonSlurper().parseText(body), "code":code]}
    else {return ["body":"", "code": -1]}
    }

    You’d need to set properties at the root for lmaccess.id, lmaccess.key and optionally, lmaccess.company. If you wanted to generate an API credential set specifically to this task (and you should), just change the prefix in line 13 from “lmaccess” to whatever you want to prefix the properties with.

    This outputs a property called auto.organization with the value of the collector group name of the collector identified by system.collectorId.