Forum Discussion

Jason_44516's avatar
Jason_44516
Icon for Nimbostratus rankNimbostratus
Sep 11, 2013

iControl PoolMember stats returning a calculated negative value.

Hello, I have been working with the iControl for some time now in PowerShell and python. I have recently been working towards gathering statistics values through the iControl api. In testing the controls work well, but once i deploy into production I am seeing negative numbers being calculated. I was wondering if anyone has any thoughts to this. Below is the Posh code that relates to the Stats. I have tried with and without the Invoke-Inline function that I saw from some other examples.

 

function GetPoolStatisticsAll()
{
    param($PoolName);

  $value = $(Get-F5.iControl).LocalLBPool.get_all_member_statistics($PoolName)

  return $value

} end of function GetPoolStatisticsAll

function Convert-To64Bit()
{
  param($high, $low);

   Other way to calculate value
  return ($high*[Math]::Pow(2,32)) + $low;
  return Invoke-Inline "result.Add((Convert.ToUInt64($high)<<32) | (Convert.ToUInt64($low)));"
} end of function Convert-To64Bit

https://devcentral.f5.com/wiki/iControl.PsRateBasedStatistics.ashx
function Invoke-Inline()
{
  param(
    [string[]] $code, 
    [object[]] $arguments,
    [string[]] $reference = @()
  )

   Stores a cache of generated inline objects.  If this library is dot-sourced 
   from a script, these objects go away when the script exits. 
  if(-not (Test-Path Variable:\inlineCode.Cache))
  {
    ${GLOBAL:inlineCode.Cache} = @{}
  }

  $using = $null;
  $source = $null;
  if($code.length -eq 1) {
    $source = $code[0]
  } elseif($code.Length -eq 2){
    $using = $code[0]
    $source = $code[1]
  } else {
    Write-Error "You have to pass some code, or this won&39;t do anything ..."
  }

   un-nesting magic (why do I need this?)
  $params = @()
  foreach($arg in $arguments) { $params += $arg }
  $arguments = $params

   The main function to execute inline C.
   Pass the argument to the function as a strongly-typed variable.  They will
   be available from C code as the Object variable, "arg". 
   Any values assigned to the "returnValue" object by the C code will be
   returned to MSH as a return value.

   See if the code has already been compiled and cached 
  $cachedObject = ${inlineCode.Cache}[$source] 
  Write-Verbose "Type: $($arguments[0].GetType())"

   The code has not been compiled or cached 
  if($cachedObject -eq $null)
  {
    $codeToCompile = 
@"
    using System;
    using System.Collections.Generic;
    $using

    public class InlineRunner 
    { 
      public List Invoke(Object[] args) 
      { 
        List result = new List(); 

        $source 

        if( result.Count > 0 ) {
          return result;
        } else {
          return null;
        }
      } 
    } 
"@

    Write-Verbose $codeToCompile

     Obtains an ICodeCompiler from a CodeDomProvider class. 
    $provider = New-Object Microsoft.CSharp.CSharpCodeProvider 

     Get the location for System.Management.Automation DLL 
    $dllName = [PsObject].Assembly.Location

     Configure the compiler parameters 
    $compilerParameters = New-Object System.CodeDom.Compiler.CompilerParameters 

    $assemblies = @("System.dll", $dllName) 
    $compilerParameters.ReferencedAssemblies.AddRange($assemblies) 
    $compilerParameters.ReferencedAssemblies.AddRange($reference)
    $compilerParameters.IncludeDebugInformation = $true 
    $compilerParameters.GenerateInMemory = $true 

     Invokes compilation.  
    $compilerResults =
      $provider.CompileAssemblyFromSource($compilerParameters, $codeToCompile) 

     Write any errors if generated.         
    if($compilerResults.Errors.Count -gt 0) 
    { 
      $errorLines = "" 
      foreach($error in $compilerResults.Errors) 
      { 
        $errorLines += "`n`t" + $error.Line + ":`t" + $error.ErrorText 
      } 
      Write-Error $errorLines 
    } 
     There were no errors.  Store the resulting object in the object 
     cache. 
    else 
    { 
      ${inlineCode.Cache}[$source] = 
        $compilerResults.CompiledAssembly.CreateInstance("InlineRunner") 
    } 

    $cachedObject = ${inlineCode.Cache}[$source] 

  }

  Write-Verbose "Argument $arguments $cachedObject"
   Finally invoke the C code 
  if($cachedObject -ne $null)
  {
    return $cachedObject.Invoke($arguments)
  }
} end function Invoke-Inline

$val = Convert-To64Bit $foo.statistics[$StatTypeCount].value.high $foo.statistics[$StatTypeCount].value.low

6 Replies

  • Hard to read your code since it's all bunched up and not formatted right, but here's what you need to know about decoding statistics.

     

    Values are return with a high order 32-bit signed value and low order 32-bit signed value. You need to combine these and turn them into a 64-bit unsigned integer value.

     

    In Python, it would look something like this:

     

    def convert_to_64_bit(high, low):
        """ Converts two 32 bit signed integers to a 64-bit unsigned integer.
        """
        if high < 0:
            high = high + (1 << 32)
        if low < 0:
            low = low + (1 << 32)
        value = long((high << 32) | low)
        assert(value >= 0)
        return value

    Hope this helps.

     

    • mhite_60883's avatar
      mhite_60883
      Icon for Cirrocumulus rankCirrocumulus
      It looks like it munged my code, too! Try this link: https://gist.github.com/mhite/cb01cc23a0fede93f335
  • I fixed the formatting as I too see that it was an epic failure on my part for the pasting.

     

    This is the Posh function i was using then with the Invoke-Inline function call.

     

    function Convert-To64Bit()
    {
      param($high, $low);
      return Invoke-Inline "result.Add((Convert.ToUInt64($high)<<32) | (Convert.ToUInt64($low)));"
    } end of function Convert-To64Bit
    function Invoke-Inline()
     https://devcentral.f5.com/wiki/iControl.PsRateBasedStatistics.ashx
    {
      param(
        [string[]] $code, 
        [object[]] $arguments,
        [string[]] $reference = @()
      )
    
       Stores a cache of generated inline objects.  If this library is dot-sourced 
       from a script, these objects go away when the script exits. 
      if(-not (Test-Path Variable:\inlineCode.Cache))
      {
        ${GLOBAL:inlineCode.Cache} = @{}
      }
    
      $using = $null;
      $source = $null;
      if($code.length -eq 1) {
        $source = $code[0]
      } elseif($code.Length -eq 2){
        $using = $code[0]
        $source = $code[1]
      } else {
        Write-Error "You have to pass some code, or this won't do anything ..."
      }
    
       un-nesting magic (why do I need this?)
      $params = @()
      foreach($arg in $arguments) { $params += $arg }
      $arguments = $params
    
       The main function to execute inline C.   
       Pass the argument to the function as a strongly-typed variable.  They will  
       be available from C code as the Object variable, "arg". 
       Any values assigned to the "returnValue" object by the C code will be  
       returned to MSH as a return value. 
    
       See if the code has already been compiled and cached 
      $cachedObject = ${inlineCode.Cache}[$source] 
      Write-Verbose "Type: $($arguments[0].GetType())"
    
       The code has not been compiled or cached 
      if($cachedObject -eq $null)
      {
        $codeToCompile = 
    @"
        using System;
        using System.Collections.Generic;
        $using
    
        public class InlineRunner 
        { 
          public List Invoke(Object[] args) 
          { 
            List result = new List(); 
    
            $source 
    
            if( result.Count > 0 ) {
                return result;
            } else {
                return null;
            }
          } 
        } 
    "@
        Write-Verbose $codeToCompile
    
         Obtains an ICodeCompiler from a CodeDomProvider class. 
        $provider = New-Object Microsoft.CSharp.CSharpCodeProvider 
    
         Get the location for System.Management.Automation DLL 
        $dllName = [PsObject].Assembly.Location
    
         Configure the compiler parameters 
        $compilerParameters = New-Object System.CodeDom.Compiler.CompilerParameters 
    
        $assemblies = @("System.dll", $dllName) 
        $compilerParameters.ReferencedAssemblies.AddRange($assemblies) 
        $compilerParameters.ReferencedAssemblies.AddRange($reference)
        $compilerParameters.IncludeDebugInformation = $true 
        $compilerParameters.GenerateInMemory = $true 
    
         Invokes compilation.  
        $compilerResults =
          $provider.CompileAssemblyFromSource($compilerParameters, $codeToCompile) 
    
         Write any errors if generated.         
        if($compilerResults.Errors.Count -gt 0) 
        { 
          $errorLines = "" 
          foreach($error in $compilerResults.Errors) 
          { 
            $errorLines += "`n`t" + $error.Line + ":`t" + $error.ErrorText 
          } 
          Write-Error $errorLines 
        } 
         There were no errors.  Store the resulting object in the object 
         cache. 
        else 
        { 
          ${inlineCode.Cache}[$source] = 
            $compilerResults.CompiledAssembly.CreateInstance("InlineRunner") 
        } 
    
        $cachedObject = ${inlineCode.Cache}[$source] 
       } 
    
       Write-Verbose "Argument $arguments`n`n$cachedObject"
        Finally invoke the C code 
       if($cachedObject -ne $null)
       {
         return $cachedObject.Invoke($arguments)
       }
    } end function Invoke-Inline
    • mhite_60883's avatar
      mhite_60883
      Icon for Cirrocumulus rankCirrocumulus
      Maybe you could put it in a gist? The F5 web site still munges it for some reason.
  • Good call. I added the formatting tags but apparently they didnt take...

     

    Here is the gist https://gist.github.com/anonymous/6531744

     

    • mhite_60883's avatar
      mhite_60883
      Icon for Cirrocumulus rankCirrocumulus
      Yeah, looks like you are using the same convert to 64-bit function Joe Pruitt has put in all his Powershell statistics example posted on devcentral. I am unfortunately no use advising you with Powershell, but technically the final product should be an unsigned integer. If you see a negative number, I would suspect either a problem with your 64-bit conversion (unlikely, given Joe posted it) or the 64-bit result is being interpreted/displayed as a signed value.