The transition to NetApp MS Azure AD B2C is complete. If you missed the pre-registration, you will be invited to register at next log in.
Please note that access to your NetApp data may take up to 1 hour.
To learn more, read the FAQ and watch the video.
Need assistance? Complete this form and select “Registration Issue” as the Feedback Category.

Active IQ Unified Manager Discussions

Return parameters for operation results

MPARDINIRTP

I'm working on a custom command in WFA for polling two controllers for option differences. I have the results in an array, but I'm having a hard time figuring out how to get that output to the workflow user. I see the return parameters tab in the workflow results window and I'm wondering how I can get the results into that tab so the user can see the differences. Any ideas?

24 REPLIES 24

paragp

This is possible in WFA 2.2RC and onwards.  If you are using powershell commands you will need to add this line in your command

Add-WfaWorkflowParameter -Name volumeOptions -Value $volOptions -AddAsReturnParameter

and for perl it is

my $wfaUtil = WFAUtil->new();

$wfaUtil->addWfaWorkflowParameter(‘volumeOptions’, $volOptions, 1);

  The Add-WfaWorkflowParameter and Get-WfaWorkflowParameter are primarily used for transferring information between commands during execution. The last parameter -AddAsReturnParameter adds the value as a return parameter to the workflow

MPARDINIRTP

Thanks for the info. I'll run an upgrade and try it out!

sinhaa

Add-WfaWorkflowParameter -Name volumeOptions -Value $volOptions -AddAsReturnParameter

-Value takes only a string argument, and as you said you have an Array, you can't use the array object directly. I suggest you join the array object to a string and then use it in the above command.. Something like below.

# Joining on a colon :

$volOptions = $volArray -join ":"

Add-WfaWorkflowParameter -Name volumeOptions -Value $volOptions -AddAsReturnParameter



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

francoisbnc

Is there any improvements in wfa 4.0 version with Add-WfaWorkflowParameter.

 

Francois

 

abhit

No.

Anything specific you are looking for?

 

Regards

Abhi

francoisbnc

I think the main missing thing is add-wfaworkflowparameter accept only [string] type. Array of objects  will be great.

 

François

sinhaa

@francoisbnc

 

 

I think you wanted array of Objects  and not just an array, did you?

 

This is not possible with cmdlet, the cmdlet writes this dynamic name-value pair into a file and then fetches this data back to you. 

 

The same join-split can help you in this case too.

 

sinhaa

 

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

francoisbnc

Yes it is.

 

Many return values is difficult to read and maintain, a simple objet or array of objects would simple to manage.

 

sinhaa

@francoisbnc

 

If you want to pass an object or even a array of objects between WFA commands, powershell itself provided you ways to do it. 

 

You can use Powershell cmdlet Export-Clixml to save the object into the file in comamnd-1

 

and Import-Clixml to retrieve that object from the above file in command-2

 

See how to use them here. If you need assistance in using this cmdlets, I can help as well.

 

sinhaa

 

 

 

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

francoisbnc

I will have a try. Many thanks.

sinhaa

@francoisbnc

 

 

It works like this:

 

In command-1

===

#Have an object parameter. Not string but a Powershell Object. You can have any data type, strings, arrays, array of objects.

 

$Date = Get-Date

Export-Clixml -Path ".\date.xml" -InputObject $Date

 

#It will create a file date.xml in the WFA temp directory. You can choose any other path as well

=====

 

In command-2

==

$Date = Import-Clixml -Path ".\date.xml"

 

#The date object is obtained successfully. Now you can call all methods on this obtained object as you could.

 

$Date.day

 

====

 

 

sinhaa

 

 

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

francoisbnc

@sinhaa

Your workaround looks good thanks, but just in case of simultaneous run of same workflow, I have to manage to name of the export file that cannot be the same.

I can add a random number at the end, pass it  to the next command with add-wfaparameter,  not so simple to have a clear overview of the workflow at the first look.

 

 

 

 

 

 

mbeattie

Hi @francoisbnc

 

Assuming you want to pass an array of variables between WFA commands within a workflow (without using the Add-WfaWorkflowParameter cmdlet) and you are exporting those variables to file locally on your WFA server, then the file name would need to be constant to ensure all the commands in your WFA workflow read the content from the same file name. To achieve that you might consider using the workflow ID as the file name as this is a unique identifier. EG

 

$workflowID = $(Get-WfaRestParameter "workflowId")

Also you might consider using a system environment variable or reading the registry to determine the file path (or the install location of WFA) as a path to save any temporary files.

Something like this:

 

#'------------------------------------------------------------------------------
#'Enumerate the WFA install path from the registry
#'------------------------------------------------------------------------------
[String]$registryPath = "hklm:\system\currentcontrolset\services\na_wfa_srv";
[Int]$workflowID      = $(Get-WfaRestParameter "workflowId")
Try{
   [System.Object]$result  = Get-ItemProperty -Path $registryPath -ErrorAction Stop
   [String]$wfaExeSpec     = $result.ImagePath.Split("/")[0].Trim() -Replace("""", "")
   [String]$wfaServicePath = $wfaExeSpec.SubString(0, $wfaExeSpec.LastIndexOf("\"))
   [String]$installPath    = $wfaServicePath.SubString(0, $wfaServicePath.LastIndexOf("\"))
   Get-WFALogger -Info -Message "Enumerated WFA installation Path from Registry key ""$registryPath"" as ""$installPath"""
}Catch{
   Get-WFALogger -Error -Message $("Failed Reading Registry Path ""$registryPath"". Error " + $_.Exception.Message)
   Throw "Failed Reading Registry Path ""$registryPath"""
}
#'------------------------------------------------------------------------------
#'Ensure the workflows XML file exists.
#'------------------------------------------------------------------------------
[String]$fileSpec = "$installPath\$workflowID.xml"
If(Test-Path -Path $fileSpec){
   Get-WFALogger -Info -Message "Reading WFA workflow XML file ""$fileSpec"""
}Else{
   Throw "The WFA workflow XML file ""$fileSpec"" does not exist"
}
#'------------------------------------------------------------------------------

Assuming you are creating custom WFA commands, each command can enumerate the current workflow ID and hence read from the correct configuration file which will ensure a uniquie file is created and read from for each workflow in the scenario where the workflow is being executed multiple times as the ID will always be unique.

 

Hope that helps

 

/Matt

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

francoisbnc

Did you speak of workflow id or runtime id?

Because, as we gave the WFA console to multiple users, workflows can be launched at the same time with a potential of multiple RW access on file.

 

 

jauling_chou

Hi,

 

Is this the best way to properly generate the output when listing snapshots for a specific volume?

 

Since OCUM6 and OCUM7 don't have volume snapshots anymore, I've resorted to querying volume snapshots via WFA4 workflows. We toyed with using a datasource job in WFA4 to do it, but it takes multiple hours for each job run, and puts a strain on our vservers.

 

My workflow command basically runs the following (I've purposefully omitted error-handling code, so keep this paste simple):

 

Connect-WfaCluster $Cluster

$vol = Get-NcVol -Name $VolumeName -Vserver $VserverName
$snaplist = $vol | Get-NcSnapshot

Get-WFALogger -Info -message $("Vserver: " + $VserverName + " Volume: " + $VolumeName + " Snapshots:" + $snaplist)

Add-WfaWorkflowParameter -Name "SnapList" -Value $snaplist -AddAsReturnParameter $true

 

 

The Get-WFALogger command only shows the snapshot name for some reason. I had assumed it would show all the default columns. Anyone know why this is?

 

The Add-WfaWorkflowParameter obviously fails, and gives me the following error:

ERROR  [get volume snapshot list] Cannot convert 'System.Object[]' to the type 'System.String' required by parameter 'Value'. Specified method is not supported.
ERROR  [get volume snapshot list] Failed executing command. Exception: Cannot convert 'System.Object[]' to the type 'System.String' required by parameter 'Value'. Specified method is not supported.

mbeattie

Hi,

 

There are a few approaches, you can return a comma delimted string however this can be limiting if you want additional snapshot properties or require a third party orchestrator to interperet the output as an object with multiple properties.

 

If the volume contains a high number of snapshots (255 maximum) it's possible that you might also run into issues with a maximum string length of the WFA return paramater. I can't find any documentation that defines the maximum string length of a WFA return paramater but i would assume there is a limit (perhaps 1024 characters???). It's possible you might reach that limit if returning comma delimited strings in a single WFA return paramater for 255 snapshot names

 

Also if you are selecting a snapshot name (for the basis of creating a clone) then you might want to return additional properties of each snapshot such as it's creation date (rather than relying on the snapshot name to be an accurate definition of the snapshots actual creation date). WFA limits the return paramater data types to strings, integers or booleans. There is a workaround to this limitiation and that is to return a URL (which links to an XML or JSON file that your WFA command code will dynamically create and save to the the 'log-download" directory in .XML file format). EG

 

C:\Program Files\NetApp\WFA\jboss\standalone\deployments\log-download.war\$WfaJobID.xml

 

Using this method WFA can set a single return paramater URL than can be interpreted by other applications or ochrestrators as an object (not a string).

You can then have any other process read the content of the URL return parameter via https from the WFA server.

 

This can be useful if you wanted a list of volume snapshots on an ad-hoc basis and don't requrie a schedule datasource that enumerates snapshots for all clusters and all volumes. If you only want to list a single volumes snapshots on an occassional basis then it's rather inefficent to configure a WFA datasource that is constantly requesting all volume snapshots unnecessarily from all clusters. Why not just request a list of the volume snapshots when and if you actually need them?

 

Here is some example code for you. It will

 

  • enumerate snapshots (matching a snapshot naming pattern) for a specified cluster, vserver and volume
  • create the results as an XML file
  • return the URL to the XML file to be read or downloaded.

 

#'------------------------------------------------------------------------------
Param(
   [Parameter(Mandatory=$True, HelpMessage="The cluster name or IP Address")]
   [String]$ClusterName,
   [Parameter(Mandatory=$True, HelpMessage="The Vserver name")]
   [String]$VserverName,
   [Parameter(Mandatory=$True, HelpMessage="The Volume name")]
   [String]$VolumeName,
   [Parameter(Mandatory=$False, HelpMessage="The snapshot pattern to match")]
   [String]$SnapShotPatternMatch,
   [Parameter(Mandatory=$True, HelpMessage="The hostname or IP Address of the WFA server")]
   [String]$HostName,
   [Parameter(Mandatory=$False, HelpMessage="The port number of the WFA server")]
   [String]$PortNumber,
   [Parameter(Mandatory=$True, HelpMessage="The site name hosted on the WFA server")]
   [String]$SiteName,
   [Parameter(Mandatory=$False, HelpMessage="The Protocol used by the WFA server")]
   [ValidateSet("http","https")]
   [String]$Protocol
)
#'------------------------------------------------------------------------------
#'Enumerate the WFA install path from the registry
#'------------------------------------------------------------------------------
[String]$registryPath = "hklm:\system\currentcontrolset\services\na_wfa_srv";
Try{
   [System.Object]$result  = Get-ItemProperty -Path $registryPath -ErrorAction Stop
   [String]$wfaExeSpec     = $result.ImagePath.Split("/")[0].Trim() -Replace("""", "")
   [String]$wfaServicePath = $wfaExeSpec.SubString(0, $wfaExeSpec.LastIndexOf("\"))
   [String]$installPath    = $wfaServicePath.SubString(0, $wfaServicePath.LastIndexOf("\"))
   Get-WFALogger -Info -Message "Enumerated WFA installation Path from Registry key ""$registryPath"" as ""$installPath"""
}Catch{
   Get-WFALogger -Error -Message $("Failed Reading Registry Path ""$registryPath"". Error " + $_.Exception.Message)
   Throw "Failed Reading Registry Path ""$registryPath"""
}
#'------------------------------------------------------------------------------
#'Connect to the cluster.
#'------------------------------------------------------------------------------
Connect-WFACluster $ClusterName
#'------------------------------------------------------------------------------
#'Enumerate WFA envrionment variables.
#'------------------------------------------------------------------------------
[Int]$jobId           = $(Get-WfaRestParameter "jobId")
[String]$userName     = $(Get-WfaRestParameter "userName")
[String]$workflowName = $(Get-WfaRestParameter "workflowName")
[Int]$workflowId      = $(Get-WfaRestParameter "workflowId")
#'------------------------------------------------------------------------------
#'Create the XML content in an array.
#'------------------------------------------------------------------------------
[Array]$lines  = @();
[Array]$lines += "<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>"
[Array]$lines += "<root revision=""0"" schemaVersion=""0"">"
[Array]$lines += "   <cluster>"
[Array]$lines += "      <cluster_name>$ClusterName</cluster_name>"
[Array]$lines += "      <vserver>"
[Array]$lines += "         <vserver_name>$VserverName</vserver_name>"
#'------------------------------------------------------------------------------
#'Enumerate the volume snapshots.
#'------------------------------------------------------------------------------
[String]$command = "Get-NcSnapshot -Volume $VolumeName -Vserver $vserverName -ErrorAction Stop"
Try{
   $snapShots = Invoke-Expression -Command $command -ErrorAction Stop
   Get-WFALogger -Info -Message "Executed Command`: $command"
}Catch{
   Get-WFALogger -Error -Message $("Failed Executing Command`: $command. Error " + $_.Exception.Message)
   %hrow "Failed enumerating snapshots for volume ""$VolumeName"" on vserver ""$VserverName"""
}
#'------------------------------------------------------------------------------
#'Add the snapshot property values to the XML content.
#'------------------------------------------------------------------------------
[Array]$lines += "         <volume>"
[Array]$lines += "            <volume_name>$VolumeName</volume_name>"
[Array]$lines += "            <snapshots>"
ForEach($snapShot In $snapShots){
   If($SnapshotPatternMatch){
      If($snapShot.Name -Match $SnapShotPatternMatch){
         [Array]$lines += "               <snapshot>"
         [Array]$lines += "                  <snapshot_name>" + $($snapShot.Name)    + "</snapshot_name>"
         [Array]$lines += "                  <created>"       + $($snapShot.Created) + "</created>"
         [Array]$lines += "               </snapshot>"
      }
   }Else{
      [Array]$lines += "               <snapshot>"
      [Array]$lines += "                  <snapshot_name>" + $($snapShot.Name)    + "</snapshot_name>"
      [Array]$lines += "                  <created>"       + $($snapShot.Created) + "</created>"
      [Array]$lines += "               </snapshot>"
   }
}
[Array]$lines += "            </snapshots>"
[Array]$lines += "         </volume>"
[Array]$lines += "      </vserver>"
[Array]$lines += "   </cluster>"
#'------------------------------------------------------------------------------
#'Add the WFA job variables to the XML.
#'------------------------------------------------------------------------------
[Array]$lines += "   <wfa>"
[Array]$lines += "      <workflow_name>" + $workflowName + "</workflow_name>"
[Array]$lines += "      <workflow_id>"   + $workflowId   + "</workflow_id>"
[Array]$lines += "      <job_id>"        + $jobId        + "</job_id>"
[Array]$lines += "      <username>"      + $username     + "</username>"
[Array]$lines += "   </wfa>"
[Array]$lines += "</root>"
#'------------------------------------------------------------------------------
#'Create the XML file.
#'------------------------------------------------------------------------------
[String]$fileSpec = "$installPath\jboss\standalone\deployments\$SiteName.war\$jobId.xml"
Try{
   Out-File -FilePath $FileSpec -Encoding ASCII -InputObject $lines -ErrorAction Stop
   Get-WFALogger -Info -Message "Created file ""$fileSpec"""
}Catch{
   Get-WFALogger -Error -Message $("Failed Creating file ""$fileSpec"". Error " + $_.Exception.Message)
   Throw "Failed Creating XML file ""$fileSpec"""
}
#'------------------------------------------------------------------------------
#'Add the volume snapshot names as a comma delimited string.
#'------------------------------------------------------------------------------
If($PortNumber){
   [String]$url = "$Protocol`://$HostName`:$PortNumber/$SiteName/$jobId.xml"
}Else{
   [String]$url = "$Protocol`://$HostName/$SiteName/$jobId.xml"
}
#'------------------------------------------------------------------------------
#'Add WFA return parameters
#'------------------------------------------------------------------------------
Get-WFALogger -Info -Message "Adding WFA retun paramater URL`: $url"
Add-WfaWorkflowParameter -Name "URL" -Value $url -AddAsReturnParameter $True
#'------------------------------------------------------------------------------

 

Note: the above code reads the WFA installation path from the registry so it's not hard coded to the default "C:\Program Files\NetApp\WFA" so it will work if a custom install location is used.

 

Example output (filtered to return all snapshots matching the pattern "daily")

 

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root revision="0" schemaVersion="0">
   <cluster>
      <cluster_name>cluster1</cluster_name>
      <vserver>
         <vserver_name>vserver1</vserver_name>
         <volume>
            <volume_name>volume_001</volume_name>
            <snapshots>
               <snapshot>
                  <snapshot_name>daily.2017-03-31_0010</snapshot_name>
                  <created>03/31/2017 11:10:00</created>
               </snapshot>
               <snapshot>
                  <snapshot_name>daily.2017-04-01_0010</snapshot_name>
                  <created>04/01/2017 11:10:00</created>
               </snapshot>
            </snapshots>
         </volume>
      </vserver>
   </cluster>
   <wfa>
      <workflow_name>get_volume_snapshots</workflow_name>
      <workflow_id>133</workflow_id>
      <job_id>44116</job_id>
      <username>admin</username>
   </wfa>
</root>

Return parameter:

 

https://XX.XX.XX.XX/log-download/$WfaJobID.xml

 

I can send you an example workflow if you like. Hope that gives you some ideas. Let me know if you have any questions.

 

/Matt

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

sinhaa

@mbeattie @jauling_chou

 

The best approach in my opinion would be to use Export-Clixml and save the entire object into a temp timpe-stamped file. And pass this file-path Parameter to the next command.

 

On source command:

 

 

Connect-WfaCluster $Cluster

$vol = Get-NcVol -Name $VolumeName -Vserver $VserverName
$snaplist = $vol | Get-NcSnapshot 

Get-WFALogger -Info -message $("Vserver: " + $VserverName + " Volume: " + $VolumeName + " Snapshots:" + ( $snaplist | Out-String ))

$fileName = ".\myfile_" + (Get-Date -UFormat %s) + '_.xml'

Export-Clixml -Path $fileName -InputObject $snaplist

Add-WfaWorkflowParameter -Name ‘snapList’ -Value $fileName -AddAsReturnParameter $true

 

 

 

Now get the object in the destination command

 

 

 

$fileName = Get-WfaWorkflowParameter -Name ‘snapList’

$snaplist = Import-Clixml -Path $fileName

#Now do something with the object
foreach ($snap in $snaplist ) { $snap.Name , $snap.Created }


# Optionally delete this temporary file. WFA will anyway clear it off after some-time

Remove-Item $fileName

 

 

sinhaa

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

jauling_chou

Thank you @mbeattie and @sinhaa for your responses. Looks like this is putting me on the right track.

 

In response to @mbeattie:

So I took the PowerShell, then created a WFA command from it:

$snaplist = $vol | Get-NcSnapshot | select Name,Created,Dependency
$snaplist_txt = $snaplist | Out-String
Get-WFALogger -Info -message $("Vserver: " + $VserverName + " Volume: " + $VolumeName + " Snapshots:" + $snaplist_txt)

 

The output when I test the WFA command truncates the snapshot name, which is the same behavior if I run it from CLI:

01:39:02.036 INFO  [get volume snapshot list] ### Command 'get volume snapshot list' in 'POWER_SHELL' ###
01:39:03.177 INFO  [get volume snapshot list] Using cached cluster connection
01:39:04.115 INFO  [get volume snapshot list] Vserver: VSERVER_HOSTNAME Volume: VOL1 Snapshots:
Name                       Created                    Dependency               
----                       -------                    ----------               
snapmirror.8e0fd5c2-e74... 4/4/2017 1:05:20 AM                                 
snapmirror.37f0555f-cb2... 4/4/2017 1:05:22 AM                                 
snapmirror.62cc231c-1c0... 4/4/2017 1:05:24 AM                                 
snapmirror.03af9c87-bde... 4/4/2017 1:06:06 AM        busy                     
01:39:04.161 INFO  [get volume snapshot list] Command completed, took 2125 milliseconds

So I piped the first line of code to Format-Table -AutoSize, but any table formating results in an empty list to WFA for some reason. Also, not really sure how to process a output in table format if I call the WFA workflow via REST (which is my primary use case)

 

 

With regards to @sinhaa:

 

Is there a way to pass XML as the output parameter without exporting/importing via a temporary file? We've only used WFA via REST, so I'm not sure what you mean in the second code snippet where you wrote "Now get the object in the destination command"

 

EDIT:

What I'm ultimately trying to do is to create a workflow that returns a list of snapshots for a given volume in XML form (much like a filter would). Not sure if that's really possible though.

 

Much appreciated guys, thanks!

 

 

Jau

 

sinhaa

@jauling_chou

 

 

 

We've only used WFA via REST, so I'm not sure what you mean in the second code snippet where you wrote "Now get the object in the destination command"

 

-----

 

Jau,

 

The main purpose of cmdlet Add-WfaWorkflowParameter is to save a dynamically obtained data into a variable and then pass this value to another command to process further. Example: cmd-1 (source) creates a job on ontap and a job-id is returend, now I use Add-WfaWorkflowParameter to save this job-id into a variable 'jobId'. Now another cmd-2(destination) in the same workflow can get this job-ID using Get-WfaWorkflowParameter and then process further. 

 

Add-WfaWorkflowParameter also has parameter -AddAsReturnParameter which when set to true can provide the value of this dynamic data as 'Return Parameter' of the workflow excution.

 

Now this cmdlet has a major limitation that it can only save simple text values. If I have obtained a powershell object, I can't transfer it to the cmd-2. In your example, the snaplist is an object and hence Add-WfaWorkflowParameter can't transfer it to next cmd.

 

 

What I'm ultimately trying to do is to create a workflow that returns a list of snapshots for a given volume in XML form (much like a filter would). Not sure if that's really possible though.

 

----

 

If its powershell  + WFA then everything is possible ( well almost).

 

Once you get this list of snaplist, create your XML like @mbeattie gave in your example. You need to decide which attributes of a given snapshot you want .

 

 

Then do this.

 

 

$xmlDoc = [xml] $lines
$xmlValue = $xmlDoc.OuterXml

Add-WfaWorkflowParameter -Name "Snaplist" -Value $xmlValue -AddAsReturnParameter $True

 

Now when this workflow executes ( via REST as you want) , the workflow execution job will return the XML formatted list of snapshots as Return Parameters.

 

sinhaa

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

jauling_chou

Thanks so much @sinhaa!

 

I struggled a bit, since the XML that I built with @mbeattie's instructions were imbedded inside the value field in the return parameters when I process the REST output, but once I grabbed that field and then processed it as its own XML doc, then I was able to extract the data I needed. Great stuff guys, thanks so much!

 

Announcements
NetApp on Discord Image

We're on Discord, are you?

Live Chat, Watch Parties, and More!

Explore Banner

Meet Explore, NetApp’s digital sales platform

Engage digitally throughout the sales process, from product discovery to configuration, and handle all your post-purchase needs.

NetApp Insights to Action
I2A Banner
Public