Active IQ Unified Manager Discussions

Creating Custom Powershell Functions in WFA?

mbeattie
4,775 Views

Hi Guys,

Is there any documentation or examples on how to create custom powershell functions in WFA? Below is some powershell code I wrote to connect to filer and volume then compare the volume's available space to a specified threshold in gigabytes. The function returns True or False based on the volumes available space if it is greater than or equal to the threshold provided. (And yes i know you could query the DFM cache for this but I just want an example of how to query the filer directly for a property of a storage object which might not be in the DFM cache)

My questions are:

  • What is the sytax to convert powershell code into a WFA command?
  • What is the "Advanced Properties" string when creating a WFA command? Should this represent the input or output of the function?
  • Where is the SDK for the WFA function scripting language?
  • How can the return value of the (True\False) of the function be used to determine the workflow execution?
  • What parameters does the "Get-WFALogger" support. For example "-Info" "-warn" "-error"? (or is the first parameter just a string to including in the logging function?)


Cheers Matt

#'---------------------------------------------------------------------------------

Function Test-VolumeSize{

   <#

   .SYNOPSIS

   Connects to a filer and volume to determine if the available space is greater

   than or equal to a given threshold value in gigabytes.

   .DESCRIPTION

   The function returns True or False based on the volumes available space

   in comparison to the threshold value specified.

   .PARAMETER

   Hostname is a string containing the netBIOS name of the filer to connect to.

   .PARAMETER

   volumeName is a string containing the Volume Name to check.

   .PARAMETER

   Threshold is an integer representing the minimum available gigabytes.

   It is used to determine if a volume has sufficent capacity available.

   .EXAMPLE

   Test-VolumeSize filer1 aggr1 4000

   #>

   #'------------------------------------------------------------------------------

   [CmdletBinding()]

   Param(

      [Parameter(Position=0,

         Mandatory=$True,

         ValueFromPipeLine=$True,

         ValueFromPipeLineByPropertyName=$True)]

      [string]$hostName,

      [Parameter(Position=1,

         Mandatory=$True,

         ValueFromPipeLine=$True,

         ValueFromPipeLineByPropertyName=$True)]

      [string]$volumeName,

      [Parameter(Position=2,

         Mandatory=$True,

         ValueFromPipeLine=$True,

         ValueFromPipeLineByPropertyName=$True)]

      [int]$threshold

   )

   #'------------------------------------------------------------------------------

   #Connect to the storage controller.

   #'------------------------------------------------------------------------------

   Try{

      Connect-NaController $hostName -ErrorAction "Stop" | Out-Null

      #Write-Host "Connected to $hostName"

   }Catch{

      #Write-Host "Failed connecting to $hostName"

      Break;

   }

   Try{

      $volume = Get-NaVol $volumeName | Select-Object -Property Name,SizeAvailable

   }Catch{

      #Write-Host "Failed enumerating Volumes properties on aggregate $aggrName"

      Break;

   }

   #'------------------------------------------------------------------------------

   #Enumerate the volume size in GB for each volume and compare it to the threshold.

   #'------------------------------------------------------------------------------  

   $sizeGB = ($volume.SizeAvailable / 1GB)

   If($sizeGB -ge $threshold){

      Return $True;

   }Else{

      Return $False;

   }

}

#'---------------------------------------------------------------------------------

Import-Module "DataOnTap"

[string]$hostName   = "filer1"

[string]$volumeName = "vol1"

[int]$threshold     = 1000

#'---------------------------------------------------------------------------------

#'Check the volumes available space and determine if a share or volume should be created.

#'---------------------------------------------------------------------------------

If(Test-VolumeSize $hostName $volumeName $threshold){

   Write-Host "Volume $volumeName on $hostName has sufficent capacity."

   Write-Host "Create a new CIFS share"

}Else{

   Write-Host "Volume $volumeName on $hostName does not have sufficent capacity."

   Write-Host "Create new volume"

}

#'---------------------------------------------------------------------------------

My best guess at how to convert this into WFA is:

#'---------------------------------------------------------------------------------

Param(
   [Parameter(Mandatory=$True, HelpMessage="Host name or IP Address")]
   [string]$hostName,

   [Parameter(Mandatory=$True, HelpMessage="Volume name")]
   [string]$volumeName,

   [Parameter(Mandatory=$True, HelpMessage="Desired Gigabytes available")]
   [int]$threshold
   )

Get-WFALogger -Info -message $("Connecting to " + $hostName)
Try{
   Connect-WFAController -Array $hostName -ErrorAction "Stop"
}Catch{
   Get-WFALogger -Error -message $("Connecting to " + $hostName)
   Break;
}
Get-WFALogger -Info -message $("Connecting to volume " + $volumeName)
Try{
   $volume = Get-NaVol $volumeName | Select-Object -Property Name,SizeAvailable
}Catch{
   Get-WFALogger -Warn -message $("Connecting to volume " + $volumeName)
   Break;

$sizeGB = ($volume.SizeAvailable / 1GB)
Get-WFALogger -Info -message $($volumeName + " volume has " + $sizeGB + " available space")
If($sizeGB -ge $threshold){
   Get-WFALogger -Info -message $($volumeName + " has sufficent space")
   Return $True;
}Else{
   Get-WFALogger -Info -message $($volumeName + " does not have sufficent space")
   Return $False;
}

#'---------------------------------------------------------------------------------

If this post resolved your issue, help others by selecting ACCEPT AS SOLUTION or adding a KUDO.
2 REPLIES 2

hill
4,775 Views

Hi,

I'll attempt to answer your questions:

Firstly the title of the discussion and your questions deal with both WFA Functions and WFA Commands.  Both are very different. Commands are currently written in Java or Powershell, and coming soon Perl.  Functions are written in MVEL...which is basically a javascript variant.

Your questions:

1.) Is there any documentation or examples on how to create custom powershell functions in WFA?

We admit the documentation is a little 'light' currently and are working to improve that.  I am personally creating some of the content and also working with both NetApp U and IE to get more content created.  That said there are examples of WFA Functions included in the WFA install package and there are now examples shared on the communities HERE.  Again, Functions are in MVEL, not powershell

2.)  What is the sytax to convert powershell code into a WFA command?

I'm not sure I understand what you mean here.  Also...

  • the code sample you provided is something that would (should) be taken care of by Finders since we cache the information from DFM... and can see the space consumed by the volume and available space in the aggregate. 
  • Your coding 'translation' doesn't look too bad, the only thing here is that Commands are typically supposed to perform some sort of action against the storage sytems, OnCommand, vCenter, etc... and typically use API calls to to so. 
  • The logic you have is applicable for a WFA Function, but again, those are written in MVEL, not powershell.

3.)  What is the "Advanced Properties" string when creating a WFA command? Should this represent the input or output of the function?

The Advanced Properties string represents the Command Output format.  This is what is seen in the Overview tab of the Planning and Execution Status windows.

4.)  Where is the SDK for the WFA function scripting language?

There is no SDK for WFA Function scripting at this time.  However you can find out more easily with a quick web-search.  Doing so will give you links like THIS which will provide you more information on how to use MVEL.  You can also look at the function examples as identified in the first answer above.

5.)  How can the return value of the (True\False) of the function be used to determine the workflow execution?

The True/False return value from a function can be used in the Workflow Table for the 'Enable' parameter.  The 'Enable' can be populated by true, false, a variable that gets evaluated to true/false, or a function that returns true/false.  In that way, you can control if that WFA Command gets processed within a workflow.

6.) What parameters does the "Get-WFALogger" support. For example "-Info" "-warn" "-error"? (or is the first parameter just a string to including in the logging function?)

Correct.  The first parameter is a string to include with the logging function.

Hope this helps,

Kevin.

goodrum
4,775 Views

The PowerShell code that you provided would be better suited as a Filter and Finder combination.  The Finder could be written to accept a user input to allow for specific threshold to be validated against the cache.  I haven't really tested this out, but the following would be pretty close.  The input would be the array IP, volume prefix and available space in the volume.  The aggregate and volume prefix can be optional inputs.  This allows you to either provide the information as a hardcode or user input.  Otherwise, the volume name returned should be the one with the largest free space.

--------------------------------------------

SELECT

    vol.name, aggr.name AS 'aggr.name', array.ip AS 'array.ip', vol.available_size_mb

FROM

    storage.aggregate AS aggr, storage.volume AS vol, storage.array AS array

WHERE

    vol.aggregate_id = aggr.id AND aggr.name != 'aggr0' AND vol.array_id = array.id AND

    array.ip LIKE '${array_ip}%' AND vol.name LIKE '${vol_name}%' AND vol.available_size_mb > '${vol_size}'

ORDER

    by vol.available_size_mb desc

--------------------------------------------

4.)  Where is the SDK for the WFA function scripting language?

--------------------------------------------

I have used the Link that Kevin provided to develop a lot of my own Functions.  This is a great resource.  If you are familiar with Javascript or C then it is pretty straightforward.  If not, then the canned Functions in WFA are a great base for comparison.  Here is a great example of a custom Function that I wrote to grow a Volume based on inputs.

Here you can see two different Functions - setNewVolSize and convertToGB.  The first function is called with three parameters - growVolume, addSize, rateOfChange.  The first is the Volume Variable from the Workflow.  This is the volume that will need to be grown.  The second will be the size to add to the Volume and the third is any rate of change that will be used for SnapShot space.  The second function converts the size from GB to MB. 

For Example, in the space section of the FindChart, I would space the following - setNewVolSize(Volume1,100,40).  If the Volume was currently 100Gb then the function would return a new size of 250Gb (100Gb initial size + 150Gb added size).  This simplifies the size change by allowing optional space additions to the Volume.  This can all be based off User Input.

def setNewVolSize(growVolume, addSize, rateOfChange) {

  if (addSize=='')

     return (int)(growVolume.size_mb);

  else

     return (int)(growVolume.size_mb + (convertToGB(addSize) * (1.1+(rateOfChange/100))));

}

def convertToGB(size) {

  return (int)(size *1024);

}

--------------------------------------------

5.)  How can the return value of the (True\False) of the function be used to determine the workflow execution?

--------------------------------------------

Here is an example of a WFA Function to determine the Boolean value of an input.  I use this function on the Enable parameter of the Command.  The funciton is written in MVEL and accepts a single User input.  The idea would be to control the individual Command based on one any number of options.  One good example is to determine if a set of commands should be executed based on a User input.  For Example: The workflow asks 'Is this a new Microsoft Cluster?'. The User input would then be 'Yes or No'.  If the value is 'yes' then the Workflow would enable the commands to create a Quorum and MSDTC Lun.  Otherwise, those two Luns would not be created.  Another example would be to use a Finder to determine if a Volume exists.  The Finder would return 'false' if the Lun is found or 'true' if the Lun needs to be created.

def retBoolean(userInput) {

  if(userInput=='true') return true;

  else if (userInput=='yes') return true;

  else return false;

}

--------------------------------------------

Just my two bits

Jeremy

Public