Forum Discussion

Paul_Carroll's avatar
7 years ago

Add device to Collector with least devices in rest api

I hope someone here can help,

Using powershell and the rest API I would like to do a lookup of selected collectors find which has the least amount of devices on it then add the a new device .

I have the script for adding the device and that works great just need the collector lookup, has anyone done something similar.

Thank you in advanced for all help provided

Paul

  • Here is what I use to "report" on collectors and their versions.

     

    $status = $null
    $body = $null
    $response = $null
    
    <# Use TLS 1.2 #>
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
    
    <# account info #>
    $accessId = ''
    $accessKey = ''
    $company = 'SITE'
    
    <# request details #>
    $httpVerb = 'GET'
    $resourcePath = '/setting/collectors'
    $queryParams = '?size=1000&fields=id,description,hostname,platform,collectorGroupName,collectorSize,numberOfHosts,build'
    #$queryParams = ''
    $status = $null
    $body = $null
    $response = $null
    $data = ''
    
    <# Construct URL #>
    $url = 'https://' + $company + '.logicmonitor.com/santaba/rest' + $resourcePath + $queryParams
    
    <# Get current time in milliseconds #>
    $epoch = [Math]::Round((New-TimeSpan -start (Get-Date -Date "1/1/1970") -end (Get-Date).ToUniversalTime()).TotalMilliseconds)
    
    <# Concatenate Request Details #>
    $requestVars = $httpVerb + $epoch + $data + $resourcePath
    
    <# Construct Signature #>
    $hmac = New-Object System.Security.Cryptography.HMACSHA256
    $hmac.Key = [Text.Encoding]::UTF8.GetBytes($accessKey)
    $signatureBytes = $hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes($requestVars))
    $signatureHex = [System.BitConverter]::ToString($signatureBytes) -replace '-'
    $signature = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($signatureHex.ToLower()))
    
    <# Construct Headers #>
    $auth = 'LMv1 ' + $accessId + ':' + $signature + ':' + $epoch
    $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
    $headers.Add("Authorization",$auth)
    $headers.Add("Content-Type",'application/json')
    
    <# Make Request #>
    $response = Invoke-RestMethod -Uri $url -Method $httpVerb -Header $headers 
    
    <# Print status and body of response #>
    $status = $response.status
    #$body = $response.data| ConvertTo-Json -Depth 5
    
    $body = $response.data | ConvertTo-Json -Depth 2
    $Collectors = $body | ConvertFrom-Json
    
    #$Collectors.items | Sort collectorGroupName | format-table -AutoSize
    $Collectors.items | Sort collectorGroupName | Out-Gridview
    #$body

     

    The numberOfHosts would help you out in this case.

  • I was being more general in my example. When using the LM API, you need to separate the endpoint part (/device/devices) from the query part (part after the "?") because of how LM does API authentication. Which is likely why you are getting auth failed error.

    So using the example Paul provided above, you would use something like this:

    $resourcePath = "/device/devices"
    $queryParams = "?size=1000&fields=id,name&filter=preferredCollectorId:COLLECTOR_ID_HERE"

    (You would also need to change the ending part of his script as devices have different properties than collectors.

  • I'm still not getting any response from the API using the URL above.  Here's the response I get... the function to retrieve data works for other queries:

    Invoke-RestMethod : {"errorMessage":"Authentication failed","errorCode":1401,"errorDetail":null}
    At line:51 char:23
    +     $response       = Invoke-RestMethod `
    +                       ~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], 
        WebException
        + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodComma 
       nd

    I get a good response with device/devices raw.  I get the above error with just the ?size=1000 as well as all of the following pieces in that query you'd posted.  I've gone so far as to separate all of the individual pieces and test them alone and no dice.  Am I using the wrong question mark?

  • Calling the REST API with the below should get you a list of all the devices assigned to that collector:

    /device/devices?size=1000&fields=id,name&filter=preferredCollectorId:COLLECTOR_ID_HERE

    Replace COLLECTOR_ID_HERE with the collector ID number which you can get from the Collector Settings page and/or via the API. If there are more than 1000 devices on a collector then you need to call this multiple times with an index as the API maxes at 1000 devices per call. I believe there are examples in the API docs.

  • On ‎6‎/‎21‎/‎2019 at 9:38 PM, Forrest Evans - LM said:

    Hey Cole,

    Are you having trouble with the newly released Auto Balanced Collectors feature?  If so please open a ticket so we can look into it and help.

    ~Forrest

    I did... but I need the solution before you'll be able to fix it.  I ended up on a call with Casey and we walked through troubleshooting it.  The metrics being used to balance aren't evaluating correctly for our environment, so the load is unbalanced.  I am using a far simpler method of determining load to perform a balance which will reduce our VM spend (as opposed to adding more collectors to handle the load) to be able to monitor our environments.

    I'm at the point in the script where I just need to grab the list of devices reporting to the Collector with the most devices associated with it, and then I'll make a random selection to cover the sum difference to redistribute and change them to the other Collector/s in the group.  We currently don't have more that 2 collectors / group, but I'm writing my script as if we did to make it more portable and save time in the future having to re-read what I'd done in the first place to refashion it for a broader use case.

    Ticket # 155345 or your reference.  If you're interested to see how I'm doing what I'm doing, I'm making a DataSource (specifically so I can schedule its run) that I will applyTo our primary Collector so it has somewhere to run.  It then uses the REST API to gather data and make changes to the environment.  I'd love you guys to add a "ScriptSource" that would allow us to trigger a script based on an alert of a specific type, or on a schedule.  This would allow me to write auto-remediation scripts for common simple alerts so we could save the staffing costs to manually address them.  Right now, we have SCOM performing quite a bit of small maintenance tasks, but we'll be turning it off (replaced by LM) and it's going to get really busy with menial tasks for our technicians when we do.

  • Hey Cole,

    Are you having trouble with the newly released Auto Balanced Collectors feature?  If so please open a ticket so we can look into it and help.

    ~Forrest

  • Have you found an efficient way to get a list of devices reporting to a specific Collector?  I'm having autobalancer issues and am writing my own as a datasource so I can fire it off once a day.  I've got all of the logic solved and am just at the point where I have to get the list of devices reporting to the Collector with the most of them, then randomly select x number of them and assign them to the other collector(s) in the collector group.

  • On 13/11/2018 at 5:31 AM, Joe Williams said:

    Here is what I use to "report" on collectors and their versions.

     

    
    $status = $null
    $body = $null
    $response = $null
    
    <# Use TLS 1.2 #>
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
    
    <# account info #>
    $accessId = ''
    $accessKey = ''
    $company = 'SITE'
    
    <# request details #>
    $httpVerb = 'GET'
    $resourcePath = '/setting/collectors'
    $queryParams = '?size=1000&fields=id,description,hostname,platform,collectorGroupName,collectorSize,numberOfHosts,build'
    #$queryParams = ''
    $status = $null
    $body = $null
    $response = $null
    $data = ''
    
    <# Construct URL #>
    $url = 'https://' + $company + '.logicmonitor.com/santaba/rest' + $resourcePath + $queryParams
    
    <# Get current time in milliseconds #>
    $epoch = [Math]::Round((New-TimeSpan -start (Get-Date -Date "1/1/1970") -end (Get-Date).ToUniversalTime()).TotalMilliseconds)
    
    <# Concatenate Request Details #>
    $requestVars = $httpVerb + $epoch + $data + $resourcePath
    
    <# Construct Signature #>
    $hmac = New-Object System.Security.Cryptography.HMACSHA256
    $hmac.Key = [Text.Encoding]::UTF8.GetBytes($accessKey)
    $signatureBytes = $hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes($requestVars))
    $signatureHex = [System.BitConverter]::ToString($signatureBytes) -replace '-'
    $signature = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($signatureHex.ToLower()))
    
    <# Construct Headers #>
    $auth = 'LMv1 ' + $accessId + ':' + $signature + ':' + $epoch
    $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
    $headers.Add("Authorization",$auth)
    $headers.Add("Content-Type",'application/json')
    
    <# Make Request #>
    $response = Invoke-RestMethod -Uri $url -Method $httpVerb -Header $headers 
    
    <# Print status and body of response #>
    $status = $response.status
    #$body = $response.data| ConvertTo-Json -Depth 5
    
    $body = $response.data | ConvertTo-Json -Depth 2
    $Collectors = $body | ConvertFrom-Json
    
    #$Collectors.items | Sort collectorGroupName | format-table -AutoSize
    $Collectors.items | Sort collectorGroupName | Out-Gridview
    #$body

     

    The numberOfHosts would help you out in this case.

     Thanks Joe.

    Really appreciated

    I have added the below which filters by selected collectors and selects the one with the least number of machines

    Where-Object {($_.id -eq "CollectorId") -or ($_.id -eq "CollectorId")} | Sort-Object numberOfHosts -Descending:$false | Select-Object -First 1| Out-Gridview
  • Here is what I use to "report" on collectors and their versions.

     

    $status = $null
    $body = $null
    $response = $null
    
    <# Use TLS 1.2 #>
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
    
    <# account info #>
    $accessId = ''
    $accessKey = ''
    $company = 'SITE'
    
    <# request details #>
    $httpVerb = 'GET'
    $resourcePath = '/setting/collectors'
    $queryParams = '?size=1000&fields=id,description,hostname,platform,collectorGroupName,collectorSize,numberOfHosts,build'
    #$queryParams = ''
    $status = $null
    $body = $null
    $response = $null
    $data = ''
    
    <# Construct URL #>
    $url = 'https://' + $company + '.logicmonitor.com/santaba/rest' + $resourcePath + $queryParams
    
    <# Get current time in milliseconds #>
    $epoch = [Math]::Round((New-TimeSpan -start (Get-Date -Date "1/1/1970") -end (Get-Date).ToUniversalTime()).TotalMilliseconds)
    
    <# Concatenate Request Details #>
    $requestVars = $httpVerb + $epoch + $data + $resourcePath
    
    <# Construct Signature #>
    $hmac = New-Object System.Security.Cryptography.HMACSHA256
    $hmac.Key = [Text.Encoding]::UTF8.GetBytes($accessKey)
    $signatureBytes = $hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes($requestVars))
    $signatureHex = [System.BitConverter]::ToString($signatureBytes) -replace '-'
    $signature = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($signatureHex.ToLower()))
    
    <# Construct Headers #>
    $auth = 'LMv1 ' + $accessId + ':' + $signature + ':' + $epoch
    $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
    $headers.Add("Authorization",$auth)
    $headers.Add("Content-Type",'application/json')
    
    <# Make Request #>
    $response = Invoke-RestMethod -Uri $url -Method $httpVerb -Header $headers 
    
    <# Print status and body of response #>
    $status = $response.status
    #$body = $response.data| ConvertTo-Json -Depth 5
    
    $body = $response.data | ConvertTo-Json -Depth 2
    $Collectors = $body | ConvertFrom-Json
    
    #$Collectors.items | Sort collectorGroupName | format-table -AutoSize
    $Collectors.items | Sort collectorGroupName | Out-Gridview
    #$body

     

    The numberOfHosts would help you out in this case.

  • Hi Paul,

    We are actively working on an enhancement to LogicMonitor to support Load Balanced Collectors.  One of the key features is that when adding a device you can pick a Collector Group instead of an individual collector.  More to come in the next month or two!

    ~Forrest