Controlling a Pool Members Ratio and Priority Group with iControl
A Little Background A question came in through the iControl forums about controlling a pool members ratio and priority programmatically. The issue really involves how the API’s use multi-dimensional arrays but I thought it would be a good opportunity to talk about ratio and priority groups for those that don’t understand how they work. In the first part of this article, I’ll talk a little about what pool members are and how their ratio and priorities apply to how traffic is assigned to them in a load balancing setup. The details in this article were based on BIG-IP version 11.1, but the concepts can apply to other previous versions as well. Load Balancing In it’s very basic form, a load balancing setup involves a virtual ip address (referred to as a VIP) that virtualized a set of backend servers. The idea is that if your application gets very popular, you don’t want to have to rely on a single server to handle the traffic. A VIP contains an object called a “pool” which is essentially a collection of servers that it can distribute traffic to. The method of distributing traffic is referred to as a “Load Balancing Method”. You may have heard the term “Round Robin” before. In this method, connections are passed one at a time from server to server. In most cases though, this is not the best method due to characteristics of the application you are serving. Here are a list of the available load balancing methods in BIG-IP version 11.1. Load Balancing Methods in BIG-IP version 11.1 Round Robin: Specifies that the system passes each new connection request to the next server in line, eventually distributing connections evenly across the array of machines being load balanced. This method works well in most configurations, especially if the equipment that you are load balancing is roughly equal in processing speed and memory. Ratio (member): Specifies that the number of connections that each machine receives over time is proportionate to a ratio weight you define for each machine within the pool. Least Connections (member): Specifies that the system passes a new connection to the node that has the least number of current connections in the pool. This method works best in environments where the servers or other equipment you are load balancing have similar capabilities. This is a dynamic load balancing method, distributing connections based on various aspects of real-time server performance analysis, such as the current number of connections per node or the fastest node response time. Observed (member): Specifies that the system ranks nodes based on the number of connections. Nodes that have a better balance of fewest connections receive a greater proportion of the connections. This method differs from Least Connections (member), in that the Least Connections method measures connections only at the moment of load balancing, while the Observed method tracks the number of Layer 4 connections to each node over time and creates a ratio for load balancing. This dynamic load balancing method works well in any environment, but may be particularly useful in environments where node performance varies significantly. Predictive (member): Uses the ranking method used by the Observed (member) methods, except that the system analyzes the trend of the ranking over time, determining whether a node's performance is improving or declining. The nodes in the pool with better performance rankings that are currently improving, rather than declining, receive a higher proportion of the connections. This dynamic load balancing method works well in any environment. Ratio (node): Specifies that the number of connections that each machine receives over time is proportionate to a ratio weight you define for each machine across all pools of which the server is a member. Least Connections (node): Specifies that the system passes a new connection to the node that has the least number of current connections out of all pools of which a node is a member. This method works best in environments where the servers or other equipment you are load balancing have similar capabilities. This is a dynamic load balancing method, distributing connections based on various aspects of real-time server performance analysis, such as the number of current connections per node, or the fastest node response time. Fastest (node): Specifies that the system passes a new connection based on the fastest response of all pools of which a server is a member. This method might be particularly useful in environments where nodes are distributed across different logical networks. Observed (node): Specifies that the system ranks nodes based on the number of connections. Nodes that have a better balance of fewest connections receive a greater proportion of the connections. This method differs from Least Connections (node), in that the Least Connections method measures connections only at the moment of load balancing, while the Observed method tracks the number of Layer 4 connections to each node over time and creates a ratio for load balancing. This dynamic load balancing method works well in any environment, but may be particularly useful in environments where node performance varies significantly. Predictive (node): Uses the ranking method used by the Observed (member) methods, except that the system analyzes the trend of the ranking over time, determining whether a node's performance is improving or declining. The nodes in the pool with better performance rankings that are currently improving, rather than declining, receive a higher proportion of the connections. This dynamic load balancing method works well in any environment. Dynamic Ratio (node) : This method is similar to Ratio (node) mode, except that weights are based on continuous monitoring of the servers and are therefore continually changing. This is a dynamic load balancing method, distributing connections based on various aspects of real-time server performance analysis, such as the number of current connections per node or the fastest node response time. Fastest (application): Passes a new connection based on the fastest response of all currently active nodes in a pool. This method might be particularly useful in environments where nodes are distributed across different logical networks. Least Sessions: Specifies that the system passes a new connection to the node that has the least number of current sessions. This method works best in environments where the servers or other equipment you are load balancing have similar capabilities. This is a dynamic load balancing method, distributing connections based on various aspects of real-time server performance analysis, such as the number of current sessions. Dynamic Ratio (member): This method is similar to Ratio (node) mode, except that weights are based on continuous monitoring of the servers and are therefore continually changing. This is a dynamic load balancing method, distributing connections based on various aspects of real-time server performance analysis, such as the number of current connections per node or the fastest node response time. L3 Address: This method functions in the same way as the Least Connections methods. We are deprecating it, so you should not use it. Weighted Least Connections (member): Specifies that the system uses the value you specify in Connection Limit to establish a proportional algorithm for each pool member. The system bases the load balancing decision on that proportion and the number of current connections to that pool member. For example,member_a has 20 connections and its connection limit is 100, so it is at 20% of capacity. Similarly, member_b has 20 connections and its connection limit is 200, so it is at 10% of capacity. In this case, the system select selects member_b. This algorithm requires all pool members to have a non-zero connection limit specified. Weighted Least Connections (node): Specifies that the system uses the value you specify in the node's Connection Limitand the number of current connections to a node to establish a proportional algorithm. This algorithm requires all nodes used by pool members to have a non-zero connection limit specified. Ratios The ratio is used by the ratio-related load balancing methods to load balance connections. The ratio specifies the ratio weight to assign to the pool member. Valid values range from 1 through 100. The default is 1, which means that each pool member has an equal ratio proportion. So, if you have server1 a with a ratio value of “10” and server2 with a ratio value of “1”, server1 will get served 10 connections for every one that server2 receives. This can be useful when you have different classes of servers with different performance capabilities. Priority Group The priority group is a number that groups pool members together. The default is 0, meaning that the member has no priority. To specify a priority, you must activate priority group usage when you create a new pool or when adding or removing pool members. When activated, the system load balances traffic according to the priority group number assigned to the pool member. The higher the number, the higher the priority, so a member with a priority of 3 has higher priority than a member with a priority of 1. The easiest way to think of priority groups is as if you are creating mini-pools of servers within a single pool. You put members A, B, and C in to priority group 5 and members D, E, and F in priority group 1. Members A, B, and C will be served traffic according to their ratios (assuming you have ratio loadbalancing configured). If all those servers have reached their thresholds, then traffic will be distributed to servers D, E, and F in priority group 1. he default setting for priority group activation is Disabled. Once you enable this setting, you can specify pool member priority when you create a new pool or on a pool member's properties screen. The system treats same-priority pool members as a group. To enable priority group activation in the admin GUI, select Less than from the list, and in the Available Member(s) box, type a number from 0 to 65535 that represents the minimum number of members that must be available in one priority group before the system directs traffic to members in a lower priority group. When a sufficient number of members become available in the higher priority group, the system again directs traffic to the higher priority group. Implementing in Code The two methods to retrieve the priority and ratio values are very similar. They both take two parameters: a list of pools to query, and a 2-D array of members (a list for each pool member passed in). long [] [] get_member_priority( in String [] pool_names, in Common__AddressPort [] [] members ); long [] [] get_member_ratio( in String [] pool_names, in Common__AddressPort [] [] members ); The following PowerShell function (utilizing the iControl PowerShell Library), takes as input a pool and a single member. It then make a call to query the ratio and priority for the specific member and writes it to the console. function Get-PoolMemberDetails() { param( $Pool = $null, $Member = $null ); $AddrPort = Parse-AddressPort $Member; $RatioAofA = (Get-F5.iControl).LocalLBPool.get_member_ratio( @($Pool), @( @($AddrPort) ) ); $PriorityAofA = (Get-F5.iControl).LocalLBPool.get_member_priority( @($Pool), @( @($AddrPort) ) ); $ratio = $RatioAofA[0][0]; $priority = $PriorityAofA[0][0]; "Pool '$Pool' member '$Member' ratio '$ratio' priority '$priority'"; } Setting the values with the set_member_priority and set_member_ratio methods take the same first two parameters as their associated get_* methods, but add a third parameter for the priorities and ratios for the pool members. set_member_priority( in String [] pool_names, in Common::AddressPort [] [] members, in long [] [] priorities ); set_member_ratio( in String [] pool_names, in Common::AddressPort [] [] members, in long [] [] ratios ); The following Powershell function takes as input the Pool and Member with optional values for the Ratio and Priority. If either of those are set, the function will call the appropriate iControl methods to set their values. function Set-PoolMemberDetails() { param( $Pool = $null, $Member = $null, $Ratio = $null, $Priority = $null ); $AddrPort = Parse-AddressPort $Member; if ( $null -ne $Ratio ) { (Get-F5.iControl).LocalLBPool.set_member_ratio( @($Pool), @( @($AddrPort) ), @($Ratio) ); } if ( $null -ne $Priority ) { (Get-F5.iControl).LocalLBPool.set_member_priority( @($Pool), @( @($AddrPort) ), @($Priority) ); } } In case you were wondering how to create the Common::AddressPort structure for the $AddrPort variables in the above examples, here’s a helper function I wrote to allocate the object and fill in it’s properties. function Parse-AddressPort() { param($Value); $tokens = $Value.Split(":"); $r = New-Object iControl.CommonAddressPort; $r.address = $tokens[0]; $r.port = $tokens[1]; $r; } Download The Source The full source for this example can be found in the iControl CodeShare under PowerShell PoolMember Ratio and Priority.28KViews0likes3CommentsBigIP Report Old
Problem this snippet solves: This codeshare has been deprecated due to a hosting platform corruption. I have movedcode and conversation to a new record (on the same original URL) https://devcentral.f5.com/s/articles/bigip-report can be Overview This is a script which will generate a report of the BigIP LTM configuration on all your load balancers making it easy to find information and get a comprehensive overview of virtual servers and pools connected to them. This information is used to relay information to our NOC and developers to give them insight in where things are located and to be able to plan patching and deploys. I also use it myself as a quick way get information or gather data used as a foundation for RFC's, ie get a list of all external virtual servers without compression profiles. The script has been running on 13 pairs of load balancers, indexing over 1200 virtual servers for several years now and the report is widely used across the company and by many companies and governments across the world. It's easy to setup and use and only requires guest permissions on your devices. Demo/Preview Please note that it takes time to make these so sometimes they're a bit outdated and they only cover one HA pair. However, they still serve the purpose of showing what you can expect from the report. Interactive demo http://loadbalancing.se/bigipreportdemo/ Screen shots The main report: The device overview: Certificate details: How to use this snippet: This codeshare has been deprecated due to a hosting platform corruption. I have movedcode and conversation to a new record (on the same original URL) https://devcentral.f5.com/s/articles/bigip-report Installation instructions BigipReport REST This is the only branch we're updating since middle of 2020 and it supports 12.x and upwards (maybe even 11.6). Download:https://loadbalancing.se/downloads/bigipreport-v5.5.4.zip Documentation, installation instructions and troubleshooting:https://loadbalancing.se/bigipreport-rest/ Docker support This will be the recommended way of running bigipreport in the near future. It's still undergoing testing but it's looking really good so far. https://loadbalancing.se/2021/01/05/running-bigipreport-on-docker/ BigipReport (Legacy) Older version of the report that only runs on Windows and is depending on a Powershell plugin originally written by Joe Pruitt (F5). BigipReport (Stable): https://loadbalancing.se/downloads/bigipreport-5.3.1.zip BigipReport (BETA): https://loadbalancing.se/downloads/bigipreport-5.4.0-beta.zip iControl Snapin: https://loadbalancing.se/downloads/f5-icontrol.zip Documentation and installation instructions: https://loadbalancing.se/bigip-report/ Upgrade instructions Protect the report using APM and active directory Written by DevCentral member Shann_P: https://loadbalancing.se/2018/04/08/protecting-bigip-report-behind-an-apm-by-shannon-poole/ Got issues/problems/feedback? Still have issues? Drop a comment below. We usually reply quite fast. Any bugs found, issues detected or ideas contributed makes the report better for everyone, so it's always appreciated. --- Also trying out a Discord channel now. You're welcome to hang out with us there: https://discord.gg/7JJvPMYahA Code : 85931,86647,90730 Tested this on version: 13.026KViews16likes974CommentsBIG-IP Report
Problem this snippet solves: Overview This is a script which will generate a report of the BIG-IP LTM configuration on all your load balancers making it easy to find information and get a comprehensive overview of virtual servers and pools connected to them. This information is used to relay information to NOC and developers to give them insight in where things are located and to be able to plan patching and deploys. I also use it myself as a quick way get information or gather data used as a foundation for RFC's, ie get a list of all external virtual servers without compression profiles. The script has been running on 13 pairs of load balancers, indexing over 1200 virtual servers for several years now and the report is widely used across the company and by many companies and governments across the world. It's easy to setup and use and only requires auditor (read-only) permissions on your devices. Demo/Preview Interactive demo http://loadbalancing.se/bigipreportdemo/ Screen shots The main report: The device overview: Certificate details: How to use this snippet: Installation instructions BigipReport REST This is the only branch we're updating since middle of 2020 and it supports 12.x and upwards (maybe even 11.6). Downloads (two latest versions): https://loadbalancing.se/downloads/bigipreport-v5.7.11.zip https://loadbalancing.se/downloads/bigipreport-v5.7.10.zip Documentation, installation instructions and troubleshooting:https://loadbalancing.se/bigipreport-rest/ Docker support https://loadbalancing.se/2021/01/05/running-bigipreport-on-docker/ Kubernetes support https://loadbalancing.se/2021/04/16/bigipreport-on-kubernetes/ BIG-IP Report (Legacy) Older version of the report that only runs on Windows and is depending on a Powershell plugin originally written by Joe Pruitt (F5) BIG-IP Report (only download this if you have v10 devices): https://loadbalancing.se/downloads/bigipreport-5.4.0-beta.zip iControl Snapin https://loadbalancing.se/downloads/f5-icontrol.zip Documentation and Installation Instructions https://loadbalancing.se/bigip-report/ Upgrade instructions Protect the report using APM and active directory Written by DevCentral member Shann_P: https://loadbalancing.se/2018/04/08/protecting-bigip-report-behind-an-apm-by-shannon-poole/ Got issues/problems/feedback? Still have issues? Drop a comment below. We usually reply quite fast. Any bugs found, issues detected or ideas contributed makes the report better for everyone, so it's always appreciated. --- Join us on Discord: https://discord.gg/7JJvPMYahA Code : BigIP Report Tested this on version: 12, 13, 14, 15, 1613KViews20likes94Comments"ASN1_CHECK_TLEN:wrong tag" when importing a PEM certificate
Hi all i'm having an issue on importing a certificate into the F5. When i import the certificate, i'm having this error message: "Import Failed: Open SSL error: error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag The certificate file began by: ---BEGIN CERTIFICATE--------------------- Proc-Type: 4, ENCRYPTED DEK-Info: DES-EDE3-CBC,F488.... (And here the certificate code) -----------END CERTFICATE------ Do i need to do somethink with open ssl befor importing the file? How can i do to import it? Thanks in advance for your help.8.2KViews0likes7CommentsHow to check the support id.
Hi Guys, I am new for F5. Dome times users can able to access our clients network from outside. User provides us a support id. Now my query is how to check this support id in LTM and allow that URL so that user's can able to access the URL.Kindly help me to fix issue. Please tell me the steps. Regards Tan_Sal6.2KViews0likes12CommentsMicrosoft Powershell with iControl
This component is not supported and we recommend reviewing Joel Newton's Powershell Module for iControlREST Code submission first. From the desk of Joe Pruitt (July 29, 2013) When we shipped DC4, we started looking at Windows PowerShell and how we could build some integration points with our products. The first pass was a set of PowerShell script files that we introduced in the PowerShell Labs section of DevCentral. No soon after we posted them, the requests started pouring in on when we would provide some native PowerShell CmdLets in addition to the function scripts. Well, I spent a little bit of time working some out and whipped out a good first rough draft. I've been holding on to these for a while now but figured they would do better out in the wild then trapped in a folder on my laptop. So, last night I posted an installer for the first release of the iControl CmdLets for PowerShell. Here's a step by step on getting up and running with the new bits. Download and install PowerShell from Microsoft Go to the PowerShell Labs page on DevCentral and select the "Download Now" link. This will download the Cmdlet installer. Run the iControlSnapInSetup.msi installer. This will install the SnapIn into the c:\program files\F5 Networks\iControlSnapIn directory. Start PowerShell from the Windows Start menu. Cd to c:\program files\F5 Networks\iControlSnapIn directory Dot Source the setup script (only once after the install) PS > . .\setupSnapIn.ps1) Load the SnapIn into the Runtime PS > Add-PSSnapIn iControlSnapIn Initialize the iControl connection with the Initialize-F5.iControl CmdLet PS > Initialize-F5.iControl -Hostname bigip_address -Credentials (Get-Credential) Run the Get-F5.iControlCommands CmdLet to list out all the available Cmdlets. PS > Get-F5.iControlCommands Try out some of the CmdLets PS > Get-F5.LTMPool Notes From the Legacy Download: Comment made 08-Jun-2016 by Patrik Jonsson Needed to add .Net 2.0 in add/remove windows features. Then it worked in Windows 10. The installation script should be changed to throw and error if the installutil file does not exist instead of quitting silently. Ken B Comment made 22-Jun-2016 by Ken B The problem I had getting this working was that I had to right-click the downloaded .zip file, properties, and click the "unblock" button on the General tab. Then I had to copy the files from the .zip to a folder under c:\Program Files\f5\icontrol. Then I ran PS As Administrator, then ran .\setupSnapIn.ps1, then I was *finally* able to run the "Add-PSSnapIn iControlSnapIn" command to get things going. Comment made 17-Jan-2017 by Joel Newton You can update the InstallPSSnapin.ps1 script to reference the .NET v4 install utility. Just replace the reference in setupSnapin.ps1 from $env:windir\Microsoft.Net\Framework${platform}\v2.0.50727\installUtil.exe to $env:windir\Microsoft.Net\Framework${platform}\v4.0.30319\installUtil.exe I don't believe there are any plans to replace the snapin with a module. My recommendation would be to use the REST API if possible. Comment made 05-Jul-2017 by Patrik Jonsson You can also use Joel's module: Powershell Module for the F5 LTM REST API Downloads: v11.00.00 Released August 10, 2013 v11.04.01 Released December 02, 2013 v11.05.00 Released February 18, 2014 v11.06.00 Released August 28, 2014 v12.01.00 Released May 09, 2016 v13.00.00 Released March 21, 2017 v13.01.00 Released November 11, 20175.5KViews2likes6CommentsHow to Configure Cookie Sticky configurations
I am new to F5. We have a requirement to configure Cookie sticky session. I believe i need to create "persistence" profile and configure Coockie methods but i am not sure what needs to be done... does anyone in this group know how i can use the GUI to configure this? thanks.4.7KViews0likes5CommentsGetting Started with iControl: Working with Statistics
In the previous article in the Getting Started with iControl series, we threw the lion's share of languages at you for both iControl portals, exposing you to many of the possible attack angles available for programmatically interacting with the BIG-IP. In this article, we're going to scale back a bit, focusing a few rest-based examples on how to gather statistics. Note: This article published by Jason Rahm but co-authored with Joe Pruitt. Statistics on BIG-IP As much as you can do with iControl, it isn’t the only methodology for gathering statistics. In fact, I’d argue that there are at least two better ways to get at them, besides the on-box rrd graphs. SNMP - Yes, it’s old school. But it has persisted as long as it has for a reason. It’s broad and lightweight. It does, however, require client-side software to do something with all that data. AVR - By provisioning the AVR module on BIG-IP, you can configure an expansive amount of metrics to measure. Combined with syslog to send the data off-box, this push approach is also pretty lightweight, though like with snmp, having a tool to consume those stats is helpful. Ken Bocchinoreleased an analytics iApp that combines AVR and its data output with Splunk and its indexing ability to deliver quite a solution. But maybe you don’t have those configured, or available, and you just need to do some lab testing and would like to consume those stats locally as you generate your test traffic. In these code samples, we’ll take a look at virtual server and pool stats. Pool Stats At the pool level, several stats are available for consumption, primarily around bandwidth utilization and connection counts. You can also get state information as well, though I'd argue that's not really a statistic, unless I suppose you are counting how often the state is available. With snmp, the stats come in high/low form, so you have to do some bit shifting in order to arrive at the actual value. Not so with with iControl. The value comes as is. In each of these samples below, you'll see two functions. The first is the list function, where when you run the script you will get a list of pools so you can then specify which pool you want stats for. The second function will then take that pool as an argument and return the statistics. Node.js Powershell Python Node.Js Pool Stats //-------------------------------------------------------- function getPoolList(name) { //-------------------------------------------------------- var uri = "/mgmt/tm/ltm/pool"; handleVERB("GET", uri, null, function(json) { //console.log(json); var obj = JSON.parse(json); var items = obj.items; console.log("POOLS"); console.log("-----------"); for(var i=0; i<items.length; i++) { var fullPath = items[i].fullPath; console.log(" " + fullPath); } }); } //-------------------------------------------------------- function getPoolStats(name) { //-------------------------------------------------------- var uri = "/mgmt/tm/ltm/pool/" + name + "/stats"; handleVERB("GET", uri, null, function(json) { //console.log(json); var obj = JSON.parse(json); var selfLink = obj.selfLink; var entries = obj.entries; for(var n in entries) { console.log("--------------------------------------"); console.log("NAME : " + getStatsDescription(entries[n].nestedStats, "tmName")); console.log("--------------------------------------"); console.log("AVAILABILITY STATE : " + getStatsDescription(entries[n].nestedStats, "status.availabilityState")); console.log("ENABLED STATE : " + getStatsDescription(entries[n].nestedStats, "status.enabledState")); console.log("REASON : " + getStatsDescription(entries[n].nestedStats, "status.statusReason")); console.log("SERVER BITS IN : " + getStatsValue(entries[n].nestedStats, "serverside.bitsIn")); console.log("SERVER BITS OUT : " + getStatsValue(entries[n].nestedStats, "serverside.bitsOut")); console.log("SERVER PACKETS IN : " + getStatsValue(entries[n].nestedStats, "serverside.pktsIn")); console.log("SERVER PACKETS OUT : " + getStatsValue(entries[n].nestedStats, "serverside.pktsOut")); console.log("CURRENT CONNECTIONS : " + getStatsValue(entries[n].nestedStats, "serverside.curConns")); console.log("MAXIMUM CONNECTIONS : " + getStatsValue(entries[n].nestedStats, "serverside.maxConns")); console.log("TOTAL CONNECTIONS : " + getStatsValue(entries[n].nestedStats, "serverside.totConns")); console.log("TOTAL REQUESTS : " + getStatsValue(entries[n].nestedStats, "totRequests")); } }); } Powershell Pool Stats #---------------------------------------------------------------------------- function Get-PoolList() # # Description: # This function returns the list of pools # # Parameters: # None #---------------------------------------------------------------------------- { $uri = "/mgmt/tm/ltm/pool"; $link = "https://$Bigip$uri"; $headers = @{}; $headers.Add("ServerHost", $Bigip); $secpasswd = ConvertTo-SecureString $Pass -AsPlainText -Force $mycreds = New-Object System.Management.Automation.PSCredential ($User, $secpasswd) $obj = Invoke-RestMethod -Method GET -Headers $headers -Uri $link -Credential $mycreds $items = $obj.items; Write-Host "POOL NAMES"; Write-Host "----------"; for($i=0; $i -lt $items.length; $i++) { $name = $items[$i].fullPath; Write-Host " $name"; } } #---------------------------------------------------------------------------- function Get-PoolStats() # # Description: # This function returns the statistics for a pool # # Parameters: # Name - The name of the pool #---------------------------------------------------------------------------- { $uri = "/mgmt/tm/ltm/pool/${Name}/stats"; $link = "https://$Bigip$uri"; $headers = @{}; $headers.Add("ServerHost", $Bigip); $secpasswd = ConvertTo-SecureString $Pass -AsPlainText -Force $mycreds = New-Object System.Management.Automation.PSCredential ($User, $secpasswd) $obj = Invoke-RestMethod -Method GET -Headers $headers -Uri $link -Credential $mycreds $entries = $obj.entries; $names = $entries | get-member -MemberType NoteProperty | select -ExpandProperty Name; $desc = $entries | Select -ExpandProperty $names $nestedStats = $desc.nestedStats; Write-Host ("--------------------------------------"); Write-Host ("NAME : $(Get-StatsDescription $nestedStats 'tmName')"); Write-Host ("--------------------------------------"); Write-Host ("AVAILABILITY STATE : $(Get-StatsDescription $nestedStats 'status.availabilityState')"); Write-Host ("ENABLED STATE : $(Get-StatsDescription $nestedStats 'status.enabledState')"); Write-Host ("REASON : $(Get-StatsDescription $nestedStats 'status.statusReason')"); Write-Host ("SERVER BITS IN : $(Get-StatsValue $nestedStats 'serverside.bitsIn')"); Write-Host ("SERVER BITS OUT : $(Get-StatsValue $nestedStats 'serverside.bitsOut')"); Write-Host ("SERVER PACKETS IN : $(Get-StatsValue $nestedStats 'serverside.pktsIn')"); Write-Host ("SERVER PACKETS OUT : $(Get-StatsValue $nestedStats 'serverside.pktsOut')"); Write-Host ("CURRENT CONNECTIONS : $(Get-StatsValue $nestedStats 'serverside.curConns')"); Write-Host ("MAXIMUM CONNECTIONS : $(Get-StatsValue $nestedStats 'serverside.maxConns')"); Write-Host ("TOTAL CONNECTIONS : $(Get-StatsValue $nestedStats 'serverside.totConns')"); Write-Host ("TOTAL REQUESTS : $(Get-StatsValue $nestedStats 'totRequests')"); } Python Pool Stats def get_pool_list(bigip, url): try: pools = bigip.get("%s/ltm/pool" % url).json() print "POOL LIST" print " ---------" for pool in pools['items']: print " /%s/%s" % (pool['partition'], pool['name']) except Exception, e: print e def get_pool_stats(bigip, url, pool): try: pool_stats = bigip.get("%s/ltm/pool/%s/stats" % (url, pool)).json() selflink = "https://localhost/mgmt/tm/ltm/pool/%s/~Common~%s/stats" % (pool, pool) nested_stats = pool_stats['entries'][selflink]['nestedStats']['entries'] print '' print ' --------------------------------------' print ' NAME : %s' % nested_stats['tmName']['description'] print ' --------------------------------------' print ' AVAILABILITY STATE : %s' % nested_stats['status.availabilityState']['description'] print ' ENABLED STATE : %s' % nested_stats['status.enabledState']['description'] print ' REASON : %s' % nested_stats['status.statusReason']['description'] print ' SERVER BITS IN : %s' % nested_stats['serverside.bitsIn']['value'] print ' SERVER BITS OUT : %s' % nested_stats['serverside.bitsOut']['value'] print ' SERVER PACKETS IN : %s' % nested_stats['serverside.pktsIn']['value'] print ' SERVER PACKETS OUT : %s' % nested_stats['serverside.pktsOut']['value'] print ' CURRENT CONNECTIONS : %s' % nested_stats['serverside.curConns']['value'] print ' MAXIMUM CONNECTIONS : %s' % nested_stats['serverside.maxConns']['value'] print ' TOTAL CONNECTIONS : %s' % nested_stats['serverside.totConns']['value'] print ' TOTAL REQUESTS : %s' % nested_stats['totRequests']['value'] Virtual Server Stats The virtual server stats are very similar in nature to the pool stats, though you are getting an aggregate view of traffic to the virtual server, whereas there might be several pools of traffic being serviced by that single virtual server. In any event, if you compare the code below to the code from the pool functions, they are nearly functionally identical. The only differences should be discernable: the method calls themselves and then the object properties that are different (clientside/serverside for example.) Node.js Powershell Python Node.Js Virtual Server Stats //-------------------------------------------------------- function getVirtualList(name) { //-------------------------------------------------------- var uri = "/mgmt/tm/ltm/virtual"; handleVERB("GET", uri, null, function(json) { //console.log(json); var obj = JSON.parse(json); var items = obj.items; console.log("VIRTUALS"); console.log("-----------"); for(var i=0; i<items.length; i++) { var fullPath = items[i].fullPath; console.log(" " + fullPath); } }); } //-------------------------------------------------------- function getVirtualStats(name) { //-------------------------------------------------------- var uri = "/mgmt/tm/ltm/virtual/" + name + "/stats"; handleVERB("GET", uri, null, function(json) { //console.log(json); var obj = JSON.parse(json); var selfLink = obj.selfLink; var entries = obj.entries; for(var n in entries) { console.log("--------------------------------------"); console.log("NAME : " + getStatsDescription(entries[n].nestedStats, "tmName")); console.log("--------------------------------------"); console.log("DESTINATION : " + getStatsDescription(entries[n].nestedStats, "destination")); console.log("AVAILABILITY STATE : " + getStatsDescription(entries[n].nestedStats, "status.availabilityState")); console.log("ENABLED STATE : " + getStatsDescription(entries[n].nestedStats, "status.enabledState")); console.log("REASON : " + getStatsDescription(entries[n].nestedStats, "status.statusReason")); console.log("CLIENT BITS IN : " + getStatsValue(entries[n].nestedStats, "clientside.bitsIn")); console.log("CLIENT BITS OUT : " + getStatsValue(entries[n].nestedStats, "clientside.bitsOut")); console.log("CLIENT PACKETS IN : " + getStatsValue(entries[n].nestedStats, "clientside.pktsIn")); console.log("CLIENT PACKETS OUT : " + getStatsValue(entries[n].nestedStats, "clientside.pktsOut")); console.log("CURRENT CONNECTIONS : " + getStatsValue(entries[n].nestedStats, "clientside.curConns")); console.log("MAXIMUM CONNECTIONS : " + getStatsValue(entries[n].nestedStats, "clientside.maxConns")); console.log("TOTAL CONNECTIONS : " + getStatsValue(entries[n].nestedStats, "clientside.totConns")); console.log("TOTAL REQUESTS : " + getStatsValue(entries[n].nestedStats, "totRequests")); } }); } Powershell Virtual Server Stats #---------------------------------------------------------------------------- function Get-VirtualList() # # Description: # This function lists all virtual servers. # # Parameters: # None #---------------------------------------------------------------------------- { $uri = "/mgmt/tm/ltm/virtual"; $link = "https://$Bigip$uri"; $headers = @{}; $headers.Add("ServerHost", $Bigip); $secpasswd = ConvertTo-SecureString $Pass -AsPlainText -Force $mycreds = New-Object System.Management.Automation.PSCredential ($User, $secpasswd) $obj = Invoke-RestMethod -Method GET -Headers $headers -Uri $link -Credential $mycreds $items = $obj.items; Write-Host "POOL NAMES"; Write-Host "----------"; for($i=0; $i -lt $items.length; $i++) { $name = $items[$i].fullPath; Write-Host " $name"; } } #---------------------------------------------------------------------------- function Get-VirtualStats() # # Description: # This function returns the statistics for a virtual server # # Parameters: # Name - The name of the virtual server #---------------------------------------------------------------------------- { param( [string]$Name ); $uri = "/mgmt/tm/ltm/virtual/${Name}/stats"; $link = "https://$Bigip$uri"; $headers = @{}; $headers.Add("ServerHost", $Bigip); $secpasswd = ConvertTo-SecureString $Pass -AsPlainText -Force $mycreds = New-Object System.Management.Automation.PSCredential ($User, $secpasswd) $obj = Invoke-RestMethod -Method GET -Headers $headers -Uri $link -Credential $mycreds $entries = $obj.entries; $names = $entries | get-member -MemberType NoteProperty | select -ExpandProperty Name; $desc = $entries | Select -ExpandProperty $names $nestedStats = $desc.nestedStats; Write-Host ("--------------------------------------"); Write-Host ("NAME : $(Get-StatsDescription $nestedStats 'tmName')"); Write-Host ("--------------------------------------"); Write-Host ("DESTINATION : $(Get-StatsDescription $nestedStats 'destination')"); Write-Host ("AVAILABILITY STATE : $(Get-StatsDescription $nestedStats 'status.availabilityState')"); Write-Host ("ENABLED STATE : $(Get-StatsDescription $nestedStats 'status.enabledState')"); Write-Host ("REASON : $(Get-StatsDescription $nestedStats 'status.statusReason')"); Write-Host ("CLIENT BITS IN : $(Get-StatsValue $nestedStats 'clientside.bitsIn')"); Write-Host ("CLIENT BITS OUT : $(Get-StatsValue $nestedStats 'clientside.bitsOut')"); Write-Host ("CLIENT PACKETS IN : $(Get-StatsValue $nestedStats 'clientside.pktsIn')"); Write-Host ("CLIENT PACKETS OUT : $(Get-StatsValue $nestedStats 'clientside.pktsOut')"); Write-Host ("CURRENT CONNECTIONS : $(Get-StatsValue $nestedStats 'clientside.curConns')"); Write-Host ("MAXIMUM CONNECTIONS : $(Get-StatsValue $nestedStats 'clientside.maxConns')"); Write-Host ("TOTAL CONNECTIONS : $(Get-StatsValue $nestedStats 'clientside.totConns')"); Write-Host ("TOTAL REQUESTS : $(Get-StatsValue $nestedStats 'totRequests')"); } Python Virtual Server Stats def get_virtual_list(bigip, url): try: vips = bigip.get("%s/ltm/virtual" % url).json() print "VIRTUAL SERVER LIST" print " -------------------" for vip in vips['items']: print " /%s/%s" % (vip['partition'], vip['name']) except Exception, e: print e def get_virtual_stats(bigip, url, vip): try: vip_stats = bigip.get("%s/ltm/virtual/%s/stats" % (url, vip)).json() selflink = "https://localhost/mgmt/tm/ltm/virtual/%s/~Common~%s/stats" % (vip, vip) nested_stats = vip_stats['entries'][selflink]['nestedStats']['entries'] print '' print ' --------------------------------------' print ' NAME : %s' % nested_stats['tmName']['description'] print ' --------------------------------------' print ' AVAILABILITY STATE : %s' % nested_stats['status.availabilityState']['description'] print ' ENABLED STATE : %s' % nested_stats['status.enabledState']['description'] print ' REASON : %s' % nested_stats['status.statusReason']['description'] print ' CLIENT BITS IN : %s' % nested_stats['clientside.bitsIn']['value'] print ' CLIENT BITS OUT : %s' % nested_stats['clientside.bitsOut']['value'] print ' CLIENT PACKETS IN : %s' % nested_stats['clientside.pktsIn']['value'] print ' CLIENT PACKETS OUT : %s' % nested_stats['clientside.pktsOut']['value'] print ' CURRENT CONNECTIONS : %s' % nested_stats['clientside.curConns']['value'] print ' MAXIMUM CONNECTIONS : %s' % nested_stats['clientside.maxConns']['value'] print ' TOTAL CONNECTIONS : %s' % nested_stats['clientside.totConns']['value'] print ' TOTAL REQUESTS : %s' % nested_stats['totRequests']['value'] Going Further So now that you have scripts that will pull stats from the pools and virtual servers, what might you do to extend these? As an exercise in skill development, I’d suggest trying these tasks below. Note that there are dozens of existing articles on iControl that you can glean details from that will help you in your quest. Given that you can pull back a list of pools or virtual servers by not providing one specifically, iterate through the appropriate list and print stats for all of them instead of just one. Extend that even further, building a table of virtual servers and their respective stats These stats are a point in time, and not terribly useful as a single entity. Create a timer where the stats are pulled back every 10s or so and take a delta to display. Extend that even further by narrowing down to maybe the bits in and out, and graph them over time. Resources All the scripts for this article are available in the codeshare under "Getting Started with iControl Code Samples."4.5KViews0likes3CommentsGetting Started with iControl: Working with Configuration Objects
In the previous articles in the Getting Started with iControl series, we covered the history of iControl, taxonomy, and introduced the languages most common to our community. In this article, we'll start looking at some code samples. With each task we cover, we'll show an example for a few languages for both the soap and rest interface. The sheer amount of space in this article required to show full samples of each language for both soap and rest would be overwhelming in line, so for the sample code, we have pulled out the appropriate sections of the code for you to study. Understand that based on the libraries used, if at all, some of the work may be abstracted. Full scripts for each language and portal preference are linked at the bottom of this article. If you click each of the iControl REST and iControl SOAP tabs, you'll see a language listing for the sample code provided. Joe Pruitt is the super hero providing everything not python here, so give him a shout out next time you see him in these parts. Note: This article published by Jason Rahm but co-authored with Joe Pruitt. With all the disclaimers out of the way, let's get down to business! The first thing you have to do to talk to the BIG-IP is know where to connect. Some prerequisites: BIG-IP Hostname Username Password Portal URL rest: https://host/mgmt/<tm> (most calls are for /tm, though there are others) soap: https://host/iControl/iControlPortal.cgi There are dozens of articles and codeshare samples on DevCentral on creating/modifying objects both in rest and soap, so we're not going to cover all the details ad nauseam here. But we do want to introduce the basic concepts of retrieving, creating, and modifying a couple simple objects in this article. The first one we'll tackle is one of the most important building blocks of the BIG-IP configuration: the pool. Working with the Pool Object The pool has many attributes that can be set, but not all are required. In this exercise however, we're going to simply demonstrate the creation of a pool and a pool listing. The pool object can be created via rest with a simple name, and with soap with the name, the lb method, and the members attribute (it can be empty, but the attribute needs to be present.) iControl SOAP Java Perl Powershell Python iControl REST Node.js Perl Powershell Python Java SOAP Example public void displayAllPools() throws Exception { String [] pool_list = m_interfaces.getLocalLBPool().get_list(); System.out.println("Pools\n"); System.out.println("-----------\n"); for(int i=0; i<pool_list.length; i++) { System.out.println(pool_list[i]); } } public void createPool(String poolname, String partition) throws Exception { String [] pool_list = new String[] {"/" + partition + "/" + poolname}; iControl.LocalLBLBMethod [] lb_methods = new iControl.LocalLBLBMethod[] { iControl.LocalLBLBMethod.LB_METHOD_ROUND_ROBIN }; iControl.CommonIPPortDefinition[][] membersAofA = new iControl.CommonIPPortDefinition[1][]; membersAofA[0] = new iControl.CommonIPPortDefinition[1]; membersAofA[0][0] = new iControl.CommonIPPortDefinition(); membersAofA[0][0].setAddress("10.10.10.10"); membersAofA[0][0].setPort(80); m_interfaces.getLocalLBPool().create( pool_list, lb_methods, membersAofA ); System.out.println("Pool " + poolname + " created in partition " + partition); } Perl SOAP Example #---------------------------------------------------------------------------- # getPoolList #---------------------------------------------------------------------------- sub getPoolList() { $soapResponse = $Pool->get_list(); &checkResponse($soapResponse); my @pool_list = @{$soapResponse->result}; print "POOL LIST\n"; print "---------\n"; foreach $pool (@pool_list) { print " ${pool}\n"; } } #---------------------------------------------------------------------------- # createPool() #---------------------------------------------------------------------------- sub createPool() { my ($partition, $pool) = @_; print "CREATING POOL $pool\n"; my @pool_names = [$pool]; my @lb_methods = ["LB_METHOD_ROUND_ROBIN"]; $member = { address => "10.10.10.10", port => 80 }; # memberA is the 1st dimension of the array, we need one for each pool push @memberA, $member; # memberAofA is the 2nd dimension. push pool members for each pool here. push @memberAofA, [@memberA]; $soapResponse = $Pool->create( SOAP::Data->name( pool_names => ["/$partition/$pool"]), SOAP::Data->name( lb_methods => ["LB_METHOD_ROUND_ROBIN"]), SOAP::Data->name(members => [@memberAofA]) ); &checkResponse($soapResponse); print "POOL ${pool} created in partition ${partition}...\n"; } Powershell SOAP Example #---------------------------------------------------------------------------- function Get-PoolList() #---------------------------------------------------------------------------- { $pool_list = $(Get-F5.iControl).LocalLBPool.get_list(); Write-Host "POOL LIST"; Write-Host "---------"; foreach($pool in $pool_list) { Write-Host " $pool"; } } #---------------------------------------------------------------------------- function Create-Pool() # # Description: # This function creates a new pool if the given pool name doesn't # already exist. # # Parameters: # Name - The Name of the pool you wish to create. # MemberList - A string list of pool member addresses. # MemberPort - The port the pool members will be configured with. #---------------------------------------------------------------------------- { param( [string]$Name, [string[]]$MemberList, [int]$MemberPort ); $IPPortDefList = New-Object -TypeName iControl.CommonIPPortDefinition[] $MemberList.Length; for($i=0; $i-lt$MemberList.Length; $i++) { $IPPortDefList[$i] = New-Object -TypeName iControl.CommonIPPortDefinition; $IPPortDefList[$i].address = $MemberList[$i]; $IPPortDefList[$i].port = $MemberPort; } Write-Host "Creating Pool $Name"; $(Get-F5.iControl).LocalLBPool.create( (,$Name), (,"LB_METHOD_ROUND_ROBIN"), (,$IPPortDefList) ); Write-Host "Pool '$Name' Successfully Created"; } Python SOAP Example def get_pool_list(bigip): try: poollist = bigip.LocalLB.Pool.get_list() print "POOL LIST" print " ---------" for pool in poollist: print " %s" % pool except Exception, e: print e def create_pool(bigip, pool): try: bigip.LocalLB.Pool.create_v2([pool], ['LB_METHOD_ROUND_ROBIN'], [[]]) except Exception, e: print e Node.js REST Example //-------------------------------------------------------- function handleVERB(verb, resource, body, callback) { //-------------------------------------------------------- getAuthToken( function(token) { httpRequest(verb, resource, body, null, null, token, function(json) { callback(json); }); }); } //-------------------------------------------------------- function handleGetPoolList(callback) { //-------------------------------------------------------- var uri = "/mgmt/tm/ltm/pool"; handleVERB("GET", uri, null, function(json) { callback(json); }); } //-------------------------------------------------------- function handleCreatePool(pool, partition, callback) { //-------------------------------------------------------- var uri = "/mgmt/tm/ltm/pool"; var body = '{"name":"' + pool + '", "partition":"' + partition + '"}'; console.log("BODY: " + body); handleVERB("POST", uri, body, function(json) { callback(json); }); } Perl REST Example #--------------------------------------------------- sub getPoolList() { #--------------------------------------------------- $resp_json = &handleGET("/mgmt/tm/ltm/pool"); $resp = decode_json($resp_json); @items = @{$resp->{"items"}}; print "POOL NAMES\n"; print "----------\n"; foreach $item (@items) { $fullPath = $item->{"fullPath"}; print " $fullPath\n"; print Dumper($item); } } #--------------------------------------------------- sub handleGET() { #--------------------------------------------------- my ($resource) = @_; $url = &buildURL($resource); $resp = &getHttpRequest($url); return $resp; } #--------------------------------------------------- sub createPool() { #--------------------------------------------------- my ($pool, $partition) = @_; my $poolObj; $poolObj->{"name"} = $pool; $poolObj->{"partition"} = $partition; my $json = encode_json($poolObj); print "JSON: $json\n"; exit(); $resp = &handlePOST("/mgmt/tm/ltm/pool", $json); print Dumper($resp); } #--------------------------------------------------- sub handlePOST() { #--------------------------------------------------- my ($resource, $body) = @_; if ( $body eq "" ) { &usage(); } $url = &buildURL($resource); $resp = &postHttpRequest($url, $body); return $resp; } Powershell REST Example #---------------------------------------------------------------------------- function Get-PoolList() #---------------------------------------------------------------------------- { $uri = "/mgmt/tm/ltm/pool"; $link = "https://$Bigip$uri"; $headers = @{}; $headers.Add("ServerHost", $Bigip); $secpasswd = ConvertTo-SecureString $Pass -AsPlainText -Force $mycreds = New-Object System.Management.Automation.PSCredential ($User, $secpasswd) $obj = Invoke-RestMethod -Method GET -Headers $headers -Uri $link -Credential $mycreds $items = $obj.items; Write-Host "POOL NAMES"; Write-Host "----------"; for($i=0; $i -lt $items.length; $i++) { $name = $items[$i].fullPath; Write-Host " $name"; } } #---------------------------------------------------------------------------- function Create-Pool() # # Description: # This function creates a new pool if the given pool name doesn't # already exist. # # Parameters: # Name - The Name of the pool you wish to create. # Partition - The name of the partition to place the pool in. #---------------------------------------------------------------------------- { param( [string]$Name, [string]$Partition ); $uri = "/mgmt/tm/ltm/pool"; $link = "https://$Bigip$uri"; $headers = @{}; $headers.Add("ServerHost", $Bigip); $headers.Add("Content-Type", "application/json"); $obj = @{ name=$Name partition=$Partition }; $body = $obj | ConvertTo-Json $secpasswd = ConvertTo-SecureString $Pass -AsPlainText -Force $mycreds = New-Object System.Management.Automation.PSCredential ($User, $secpasswd) $obj = Invoke-RestMethod -Method POST -Uri $link -Headers $headers -Credential $mycreds -Body $body; Write-Host "Pool ${Name} created in partition ${Partition}" } Python REST Example def get_pool_list(bigip, url): try: pools = bigip.get("%s/ltm/pool" % url).json() print "POOL LIST" print " ---------" for pool in pools['items']: print " /%s/%s" % (pool['partition'], pool['name']) except Exception, e: print e def create_pool(bigip, url, pool, part=None): try: payload = {} payload['name'] = pool if part is not None: payload['partition'] = part pool_config = bigip.post("%s/ltm/pool" % url, json.dumps(payload)).json() print pool_config except Exception, e: print e Working with the Data-Group Object Data-groups are interesting objects with which to work, primarily because you can have internal data-groups, which are wholly contained within bigip.conf, and external data-groups, which has it's definition in bigip.conf but the records are kept in an external file. Also interesting is that this particular object has different attributes via soap than it does in rest. In soap, all the records can be individually managed, so you can add, find, and delete on a record by record basis. Not so with rest. In rest we have the concepts of collections and a subcollections. A collection is like a list of pools. A sub-collection would be the members of a pool. Ideally, a data-group itself would be part of a collection, and it's records would be a subcollection, but that is not the case today. This has major implications if you want to update a data-group. Say you have a data-group with 10,000 records. You want add a record, so you issue an HTTP PUT method with your payload of one record. Instead of the desired outcome of a modified data-group with 10,001 records, you now have a much smaller data-group of exactly one record. Not good! So make sure if you are using the rest interface with data-groups, you store all the existing records, make all your adds/changes/deletes, then PUT the entire record collection. But where the soap interface has the upper hand with being able to update individual records, rest punches back with the ability to list out all data-group at once, whereas with soap, you have to query each type of data-group among string, integer, and address. So there are some pros and cons to both approaches to weigh as you dig in. iControl SOAP Java Perl Powershell Python iControl REST Node.js Perl Powershell Python Java SOAP Example public void createDataGroup(String datagroup) throws Exception { // Create String Class iControl.LocalLBClassStringClass [] StringClassA = new iControl.LocalLBClassStringClass[1]; StringClassA[0] = new iControl.LocalLBClassStringClass(); StringClassA[0].setName(datagroup); StringClassA[0].setMembers(new String [] { "a", "b", "c" }); m_interfaces.getLocalLBClass().create_string_class(StringClassA); // Set Values String [][] valuesAofA = new String[1][]; valuesAofA[0] = new String[] { "data 1", "data 2", "data 3" }; m_interfaces.getLocalLBClass().set_string_class_member_data_value( StringClassA, valuesAofA ); getDataGroup(datagroup); } public void removeFromDataGroup(String datagroup) throws Exception { String [] names = new String[] {"c"}; iControl.LocalLBClassStringClass [] StringClassA = new iControl.LocalLBClassStringClass[1]; StringClassA[0] = new iControl.LocalLBClassStringClass(); StringClassA[0].setName(datagroup); StringClassA[0].setMembers(new String [] { "c" }); m_interfaces.getLocalLBClass().delete_string_class_member(StringClassA); getDataGroup(datagroup); } //-------------------------------------------------------------------------- // //-------------------------------------------------------------------------- public void addToDataGroup(String datagroup) throws Exception { // Create String Class iControl.LocalLBClassStringClass [] StringClassA = new iControl.LocalLBClassStringClass[1]; StringClassA[0] = new iControl.LocalLBClassStringClass(); StringClassA[0].setName(datagroup); StringClassA[0].setMembers(new String [] { "d", "e" }); m_interfaces.getLocalLBClass().add_string_class_member(StringClassA); // Set Values String [][] valuesAofA = new String[1][]; valuesAofA[0] = new String[] { "data 4", "data 5" }; m_interfaces.getLocalLBClass().set_string_class_member_data_value( StringClassA, valuesAofA ); getDataGroup(datagroup); } Perl SOAP Example #---------------------------------------------------------------------------- sub createDataGroup() #---------------------------------------------------------------------------- { my ($datagroup) = @_; my @names = ("a", "b", "c"); my $StringClass = { name => $datagroup, members => [@names] }; # Create Data group with names $soapResponse = $Class->create_string_class( SOAP::Data->name(classes => [$StringClass]) ); &checkResponse($soapResponse); # Set values # Build Values 2-D Array for values parameter my @valuesA = ("data 1", "data 2", "data 3"); my @valuesAofA; push @valuesAofA, [@valuesA]; $soapResponse = $Class->set_string_class_member_data_value ( SOAP::Data->name(class_members => [$StringClass]), SOAP::Data->name(values => [@valuesAofA]) ); &checkResponse($soapResponse); &getDataGroup($datagroup); } #---------------------------------------------------------------------------- sub removeFromDataGroup() #---------------------------------------------------------------------------- { my ($datagroup) = @_; my @names = ("c"); my $StringClass = { name => $datagroup, members => [@names] }; # Create Data group with names $soapResponse = $Class->delete_string_class_member( SOAP::Data->name(class_members => [$StringClass]) ); &checkResponse($soapResponse); &getDataGroup($datagroup); } #---------------------------------------------------------------------------- sub addToDataGroup() #---------------------------------------------------------------------------- { my ($datagroup) = @_; my @names = ("d", "e"); my $StringClass = { name => $datagroup, members => [@names] }; # Create Data group with names $soapResponse = $Class->add_string_class_member( SOAP::Data->name(class_members => [$StringClass]) ); &checkResponse($soapResponse); # Set values # Build Values 2-D Array for values parameter my @valuesA = ("data 4", "data 5"); my @valuesAofA; push @valuesAofA, [@valuesA]; $soapResponse = $Class->set_string_class_member_data_value ( SOAP::Data->name(class_members => [$StringClass]), SOAP::Data->name(values => [@valuesAofA]) ); &checkResponse($soapResponse); &getDataGroup($datagroup); } Powershell SOAP Example #------------------------------------------------------------------------- function Create-DataGroup() #------------------------------------------------------------------------- { param( [string]$Name ); $StringClassA = New-Object -TypeName iControl.LocalLBClassStringClass[] 1; $StringClassA[0] = New-Object -TypeName iControl.LocalLBClassStringClass; $StringClassA[0].name = $Name; $StringClassA[0].members = ("a", "b", "c"); $(Get-F5.iControl).LocalLBClass.create_string_class( $StringClassA ); $DataValueA = ("data 1", "data 2", "data 3"); $DataValuesAofA = $(Get-F5.iControl).LocalLBClass.set_string_class_member_data_value( $StringClassA, (, $DataValueA) ) Get-DataGroup -Name $Name; } #------------------------------------------------------------------------- function RemoveFrom-DataGroup() #------------------------------------------------------------------------- { param( [string]$Name ); $StringClassA = New-Object -TypeName iControl.LocalLBClassStringClass[] 1; $StringClassA[0] = New-Object -TypeName iControl.LocalLBClassStringClass; $StringClassA[0].name = $Name; $StringClassA[0].members = ("c"); $(Get-F5.iControl).LocalLBClass.delete_string_class_member( $StringClassA ); Get-DataGroup -Name $Name; } #------------------------------------------------------------------------- function AddTo-DataGroup() #------------------------------------------------------------------------- { param( [string]$Name ); $StringClassA = New-Object -TypeName iControl.LocalLBClassStringClass[] 1; $StringClassA[0] = New-Object -TypeName iControl.LocalLBClassStringClass; $StringClassA[0].name = $Name; $StringClassA[0].members = ("d", "e"); $(Get-F5.iControl).LocalLBClass.add_string_class_member( $StringClassA ); $DataValueA = ("data 4", "data 5"); $DataValuesAofA = $(Get-F5.iControl).LocalLBClass.set_string_class_member_data_value( $StringClassA, (, $DataValueA) ) Get-DataGroup -Name $Name; } Python SOAP Example def get_dg_list(bigip): try: dg_str_list = bigip.LocalLB.Class.get_string_class_list() dg_str_names = bigip.LocalLB.Class.get_string_class(dg_str_list) for dg in dg_str_names: print dg print ' Data Group: %s' % dg['name'] for x in dg['members']: print ' %s' % x except Exception, e: print e def extend_dg(bigip, dgname, keys, values): try: bigip.LocalLB.Class.add_string_class_member([{'name': dgname, 'members': keys}]) bigip.LocalLB.Class.set_string_class_member_data_value([{'name': dgname, 'members': keys}], [[values]]) except Exception, e: print e def contract_dg(bigip, dgname, keys): try: bigip.LocalLB.Class.delete_string_class_member([{'name': dgname, 'members': keys}]) except Exception, e: print e def create_dg(bigip, dgname, keys, values): try: bigip.LocalLB.Class.create_string_class([{'name': dgname, 'members': keys}]) bigip.LocalLB.Class.set_string_class_member_data_value([{'name': dgname, 'members': keys}], [[values]]) except Exception, e: print e Node.js REST Example //-------------------------------------------------------- function createDataGroup(datagroup) { //-------------------------------------------------------- datagroup = datagroup.replace(/\//g, "~"); var uri = "/mgmt/tm/ltm/data-group/internal"; var dgObj = {}; dgObj.name = datagroup; dgObj.type = "string"; dgObj.records = [ {name: "a", data: "data 1"}, {name: "b", data: "data 2"}, {name: "c", data: "data 3"}, ]; var body = JSON.stringify(dgObj); handleVERB("POST", uri, body, function(json) { console.log(json); }); } //-------------------------------------------------------- function removeFromDataGroup(datagroup) { //-------------------------------------------------------- dg_uri = datagroup.replace(/\//g, "~"); var uri = "/mgmt/tm/ltm/data-group/internal/" + dg_uri; var dgObj = {}; dgObj.name = datagroup; dgObj.records = [ {name: "a", data: "data 1"}, {name: "b", data: "data 2"} ]; var body = JSON.stringify(dgObj); handleVERB("PATCH", uri, body, function(json) { console.log(json); }); } //-------------------------------------------------------- function addToDataGroup(datagroup) { //-------------------------------------------------------- dg_uri = datagroup.replace(/\//g, "~"); var uri = "/mgmt/tm/ltm/data-group/internal/" + dg_uri; var dgObj = {}; dgObj.name = datagroup; dgObj.records = [ {name: "a", data: "data 1"}, {name: "b", data: "data 2"}, {name: "d", data: "data 4"}, {name: "e", data: "data 5"} ]; var body = JSON.stringify(dgObj); handleVERB("PATCH", uri, body, function(json) { console.log(json); }); } Perl REST Example #---------------------------------------------------------------------------- sub createDataGroup() #---------------------------------------------------------------------------- { my ($datagroup) = @_; my @names = ("a", "b", "c"); my $StringClass = { name => $datagroup, members => [@names] }; # Create Data group with names $soapResponse = $Class->create_string_class( SOAP::Data->name(classes => [$StringClass]) ); &checkResponse($soapResponse); # Set values # Build Values 2-D Array for values parameter my @valuesA = ("data 1", "data 2", "data 3"); my @valuesAofA; push @valuesAofA, [@valuesA]; $soapResponse = $Class->set_string_class_member_data_value ( SOAP::Data->name(class_members => [$StringClass]), SOAP::Data->name(values => [@valuesAofA]) ); &checkResponse($soapResponse); &getDataGroup($datagroup); } #---------------------------------------------------------------------------- sub removeFromDataGroup() #---------------------------------------------------------------------------- { my ($datagroup) = @_; my @names = ("c"); my $StringClass = { name => $datagroup, members => [@names] }; # Create Data group with names $soapResponse = $Class->delete_string_class_member( SOAP::Data->name(class_members => [$StringClass]) ); &checkResponse($soapResponse); &getDataGroup($datagroup); } #---------------------------------------------------------------------------- sub addToDataGroup() #---------------------------------------------------------------------------- { my ($datagroup) = @_; my @names = ("d", "e"); my $StringClass = { name => $datagroup, members => [@names] }; # Create Data group with names $soapResponse = $Class->add_string_class_member( SOAP::Data->name(class_members => [$StringClass]) ); &checkResponse($soapResponse); # Set values # Build Values 2-D Array for values parameter my @valuesA = ("data 4", "data 5"); my @valuesAofA; push @valuesAofA, [@valuesA]; $soapResponse = $Class->set_string_class_member_data_value ( SOAP::Data->name(class_members => [$StringClass]), SOAP::Data->name(values => [@valuesAofA]) ); &checkResponse($soapResponse); &getDataGroup($datagroup); } Powershell REST Example #---------------------------------------------------------------------------- function Create-DataGroup() # # Description: # This function creates a new internal data group # # Parameters: # Name - The Name of the data group #---------------------------------------------------------------------------- { param( [string]$Name ); $uri = "/mgmt/tm/ltm/data-group/internal"; $link = "https://$Bigip$uri"; $headers = @{}; $headers.Add("ServerHost", $Bigip); $headers.Add("Content-Type", "application/json"); $obj = @{ name=$Name type="string" records= ( @{ name="a" data="data 1" }, @{ name="b" data="data 2" }, @{ name="c" data="data 3" } ) }; $body = $obj | ConvertTo-Json $secpasswd = ConvertTo-SecureString $Pass -AsPlainText -Force $mycreds = New-Object System.Management.Automation.PSCredential ($User, $secpasswd) $obj = Invoke-RestMethod -Method POST -Uri $link -Headers $headers -Credential $mycreds -Body $body; Write-Host "Pool ${Name} created in partition ${Partition}" } #---------------------------------------------------------------------------- function RemoveFrom-DataGroup() # # Description: # This function removes an entry from a data group # # Parameters: # Name - The Name of the data group #---------------------------------------------------------------------------- { param( [string]$Name ); $uri = "/mgmt/tm/ltm/data-group/internal/${Name}"; $link = "https://$Bigip$uri"; $headers = @{}; $headers.Add("ServerHost", $Bigip); $headers.Add("Content-Type", "application/json"); $obj = @{ name=$Name records= ( @{ name="a" data="data 1" }, @{ name="b" data="data 2" } ) }; $body = $obj | ConvertTo-Json $secpasswd = ConvertTo-SecureString $Pass -AsPlainText -Force $mycreds = New-Object System.Management.Automation.PSCredential ($User, $secpasswd) $obj = Invoke-RestMethod -Method PATCH -Uri $link -Headers $headers -Credential $mycreds -Body $body; $obj | Format-List } #---------------------------------------------------------------------------- function AddTo-DataGroup() # # Description: # This function adds records to an existing data group # # Parameters: # Name - The Name of the data group #---------------------------------------------------------------------------- { param( [string]$Name ); $uri = "/mgmt/tm/ltm/data-group/internal/${Name}"; $link = "https://$Bigip$uri"; $headers = @{}; $headers.Add("ServerHost", $Bigip); $headers.Add("Content-Type", "application/json"); $obj = @{ name=$Name records= ( @{ name="a" data="data 1" }, @{ name="b" data="data 2" }, @{ name="d" data="data 4" }, @{ name="e" data="data 5" } ) }; $body = $obj | ConvertTo-Json $secpasswd = ConvertTo-SecureString $Pass -AsPlainText -Force $mycreds = New-Object System.Management.Automation.PSCredential ($User, $secpasswd) $obj = Invoke-RestMethod -Method PATCH -Uri $link -Headers $headers -Credential $mycreds -Body $body; $obj | Format-List } Python REST Example def get_dg_list(rq, url): try: dg_list = rq.get('%s/ltm/data-group/internal' % url).json() for dg in dg_list['items']: print dg print ' Data Group: %s' % dg['name'] print ' --------------' if 'records' in dg: for record in dg['records']: if 'data' in record: print ' %s: %s' % (record['name'], record['data']) else: print ' %s' % record['name'] except Exception, e: print e def extend_dg(rq, url, dgname, additional_records): dg = rq.get('%s/ltm/data-group/internal/%s' % (url, dgname)).json() current_records = dg['records'] new_records = [] for record in current_records: if 'data' in record: nr = [{'name': record['name'], 'data': record['data']}] else: nr = [{'name': record['name']}] new_records.extend(nr) for record in additional_records: if 'data' in record: nr = [{'name': record['name'], 'data': record['data']}] else: nr = [{'name': record['name']}] new_records.extend(nr) payload = {} payload['records'] = new_records rq.put('%s/ltm/data-group/internal/%s' % (url, dgname), json.dumps(payload)) def contract_dg(rq, url, dgname, removal_records): dg = rq.get('%s/ltm/data-group/internal/%s' % (url, dgname)).json() current_records = dg['records'] new_records = [] for record in removal_records: if 'data' in record: nr = [{'name': record['name'], 'data': record['data']}] else: nr = [{'name': record['name']}] new_records.extend(nr) new_records = [x for x in current_records if x not in new_records] payload = {} payload['records'] = new_records rq.put('%s/ltm/data-group/internal/%s' % (url, dgname), json.dumps(payload)) def create_dg(rq, url, dgname, records): new_records = [] for record in records: if 'data' in record: nr = [{'name': record['name'], 'data': record['data']}] else: nr = [{'name': record['name']}] new_records.extend(nr) payload = {} payload['type'] = 'string' payload['name'] = dgname payload['records'] = new_records try: rq.post('%s/ltm/data-group/internal' % url, json.dumps(payload)) except Exception, e: print e Resources All the scripts for this article are available in the codeshare under "Getting Started with iControl Code Samples."3.7KViews0likes0Comments