events
36 TopicsAdd Outlook Web Access Login Options to the APM Logon Page
Outlook Web Access is the web interface to the Microsoft Exchange environment, and many customers have secured the portal behind their BIG-IP APM architecture. In looking at the OWA logon page, however, you'll notice that there are a couple extra options than the default APM logon page supports: This article will show you how to add these options to a custom BIG-IP APM logon page, however, it assumes the portal app with SSO is already configured and working. If you need help with that, drop a comment below. Configuration Steps First, enable two additional text boxes on the APM Logon page Now that you have the variables where they will be part of the session you need to modify the logon page to display radio boxes and checkboxes for the fields we added instead of the textbox. You do this by first going to the customization section of the access policy module. Next, change the Edit Mode to Advanced. Then navigate to the logon page. Find this section of code in logon.inc: foreach( $fields_settings as $id=>$field_settings ) { if( $field_settings["type"] != "none" ) { Immediately after the opening curly brace in that section of code, add these lines (highlighted in red) so that the section of code now looks like this: foreach( $fields_settings as $id=>$field_settings ) { if( $field_settings["name"] == "pubpriv" ) { continue; } if( $field_settings["name"] == "lightversion" ) { continue; } if( $field_settings["type"] != "none" ) { The section should look like this now: Note the closing four curly braces at the bottom of the screen shot. You need to add this section of code below between the third and fourth curly brace: ?> <tr> <td colspan=2 class="credentials_table_unified_cell" > <label for="text">Security</label> <input type="radio" name=pubpriv value="public" checked> This is a public or shared computer<br> <input type="radio" name=pubpriv value="private"> This is a private computer </td> </tr> <tr> <td colspan=2 class="credentials_table_unified_cell" > <label for="text">Light Version?</label> <input type="checkbox" name=lightversion value="yes"> Use the light version of Outlook Web App </td> </tr> <? Now the section, complete, should look like this: Now click Save Draft, the click Save in the editor tool bar. Now that the customizations are done, we need to create an iRule to see what the form values are and then set the values will push into the SSO object. The values are found by looking at the post variables OWA uses. Go to "Local Traffic" section in the menu, then iRules and click "Create". I named my iRule "owa_form_values_iRule" and pasted the following code when ACCESS_POLICY_AGENT_EVENT { if {[ACCESS::session data get "session.logon.last.pubpriv"] eq "private"} { if {[ACCESS::session data get "session.logon.last.lightversion"] eq "yes"} { ACCESS::session data set "session.custom.owa.flags" 5 ACCESS::session data set "session.custom.owa.trusted" 4 } else { ACCESS::session data set "session.custom.owa.flags" 4 ACCESS::session data set "session.custom.owa.trusted" 4 } } else { if {[ACCESS::session data get "session.logon.last.lightversion"] eq "yes"} { ACCESS::session data set "session.custom.owa.flags" 1 ACCESS::session data set "session.custom.owa.trusted" 0 } else { ACCESS::session data set "session.custom.owa.flags" 0 ACCESS::session data set "session.custom.owa.trusted" 0 } } } Next go back to the visual policy editor and add an iRule Event after the logon page in the process flow but before the resource assign and enter the name of the iRule we created in the ID field. Finally, edit the SSO configuration object. In the hidden form parameters modify the values of "flags" and "trusted" to use the new session variables created in the iRule. The other variables should remain the same. flags %{session.custom.owa.flags} trusted %{session.custom.owa.trusted} Shown in the SSO object: Now apply the policy and you are good to go! OWA through APM will provide the same functions as the direct OWA logon page!2KViews0likes14CommentsiControl 101 - #13 - Data Groups
Data Groups can be useful when writing iRules. A data group is simply a group of related elements, such as a set of IP addresses, URI paths, or document extensions. When used in conjuction with the matchclass or findclass commands, you eliminate the need to list multiple values as arguments in an iRule expression. This article will discuss how to use the methods in the LocalLB::Class interface to manage the Data Groups for use within iRules. Terminology You will first notice a mixing up of terms. A "Class" and a "Data Group" can be used interchangeably. Class was the original development term and the marketing folks came up with Data Group later on so you will see "Class" embedded in the core configuration and iControl methods, thus the LocalLB::Class interface, and "Data Groups" will most often be how they are referenced in the administration GUI. Data Groups come in 4 flavors: Address, Integer, String, and External. Address Data Groups consist of a list of IP Addresses with optional netmasks and are useful for applying a policy based on a originating subnet. Integer Data Groups hold numeric integers and, to add more confusion, are referred as "value" types in the API. String Data Groups can hold a valid ascii-based string. All of the Data Group types have methods specific to their type (ie get_string_class_list(), add_address_class_member(), find_value_class_member()). External Data Groups are special in that they have one of the previous types but there are no direct accessor methods to add/remove elements from the file. The configuration consists of a file path and name, along with the type (Address, Integer, String). You will have to use the ConfigSync file transfer APIs to remotely manipulate External Data Groups. External Data Groups are meant for very large lists of lists that change frequently. This article will focus on String Data Groups, but the usage for Address and Integer classes will be similar in nature. Initialization This article uses PowerShell and the iControl Cmdlets for PowerShell as the client environment for querying the data. The following setup will be required for the examples contained in this article. PS> Add-PSSnapIn iControlSnapIn PS> Initialize-F5.iControl -Hostname bigip_address -Username bigip_user -Password bigip_pass PS> $Class = (Get-F5.iControl).LocalLBClass Listing data groups The first thing you'll want to do is determine which Data Groups exist. The get_string_class_list() method will return a array of strings containing the names of all of the existing String based Data Groups. PS> $Class.get_string_class_list() test_list test_class carp images Creating a Data Group You have to start from somewhere, so most likely you'll be creating a new Data Group to do your bidding. This example will create a data group of image extensions for use in a URI based filtering iRule. The create_string_class() takes as input an array of LocalLB::Class::StringClass structures, each containing the class name and an array of members. In this example, the string class "img_extensions" is created with the values ".jpg", ".gif", and ".png". Then the get_string_class_list() method is called to make sure the class was created and the get_string_class() method is called to return the values passed in the create method. PS> $StringClass = New-Object -typename iControl.LocalLBClassStringClass PS> $StringClass.name = "img_extensions" PS> $StringClass.members = (".jpg", ".gif", ".png") PS> $Class.create_string_class(,$StringClass) PS> $Class.get_string_class_list() test_list test_class carp images img_extensions PS> $Class.get_string_class((,"img_extensions")) name members ---- ------- img_extensions {.gif, .jpg, .png} Adding Data Group items Once you have an existing Data Group, you most likely will want to add something to it. The add_string_class_member() method will take as input the same LocalLB::Class::StringClass structure containing the name of the Data Group and the list of new items to add to it. The following code will add two values: ".ico" and ".bmp" to the img_extensions Data Group and then will query the values of the Data Group to make sure the call succeeded. PS> $StringClass.members = (".ico", ".bmp") PS> $Class.add_string_class_member(,$StringClass) PS> $Class.get_string_class((,"img_extensions")) name members ---- ------- img_extensions {.bmp, .gif, .ico, .jpg...} Removing Data Group Items If you want to add items, you may very well want to delete items. That's where the delete_string_class_member() method comes in. Like the previous examples, it takes the LocalLB::Class::StringClass structure containing the name of the Data Group and the values you would like to remove. The following example removes the ".gif" and ".jpg" value and queries the current value of the list. PS> $StringClass.members = (".gif", ".jpg") PS> $Class.delete_string_class_member(,$StringClass) PS> $Class.get_string_class((,"img_extensions")) name members ---- ------- img_extensions {.bmp, .ico, .png} Deleting Data Groups The interface wouldn't be complete if you couldn't delete the Data Groups you previously created. The delete_class() method takes as input a string array of class names. This example will delete the img_extensions Data Group and then call the get_string_class_list() method to verify that it was deleted. PS> $Class.delete_class(,"img_extensions") PS> $Class.get_string_class_list() ts_reputation test_list test_class carp images Conclusion That's about it! Just replace the "string" with "address" and "value" in the above methods and you should be well on your way to building any type of Data Group you need for all your iRule needs. Get the Flash Player to see this player.1.1KViews0likes6CommentsiControl 101 - #16 - SelfIPs
In this article, I will discuss the Networking.SelfIP interface in which you have control over the IP addresses owned by the BIG-IP system that you use to access the internal and external VLANs. Initialization This article uses PowerShell and the iControl Cmdlets for PowerShell as the client environment for querying the data. The following setup will be required for the examples contained in this article. PS C:\> add-pssnapin icontrolsnapin PS C:\> initialize-f5.icontrol -HostName theboss -Username admin -Password admin True PS C:\> $SelfIP = (Get-F5.iControl).NetworkingSelfIP Determining the list of configured Self IP Addresses As is common in most interfaces, the Networking.SelfIP interface has a get_list() method that takes as input no parameters and returns a string list of all the defined SelfIP addresses. On my system, I have two Self IP addresses: 10.10.10.1 and 20.20.20.1 PS C:\> $SelfIP.get_list() 10.10.10.1 20.20.20.1 Creating a Self IP The create() method can be used to create a Self IP address. The create() method takes as input a list of self_ip addresses, vlan_names, netmasks, unit_ids, and floating_states (for floating self-ip addresses across redundant systems). If you specify STATE_DISABLED for the floating_state, you must use a unit_id value of 0. If you are creating a floating address, you must use a unit_id of 1 or 2 and make sure that you have a fixed address on the same network as the floating address with the same netmask. This example creates a fixed Self IP on the "internal2" vlan with an address of "30.30.30.1", a netmask of "255.255.255.0". PS C:\> $SelfIP.create( (,"30.30.30.1"), (,"internal2"), (,"255.255.255.0"), (,0), (,"STATE_DISABLED") ) PS C:\> $SelfIP.get_list() 10.10.10.1 20.20.20.1 30.30.30.1 VLANs You can get and set the vlan that a Self IP address is attached to with the get_vlan() and set_vlan() methods respectively. The get_vlan() method takes as input a list of Self IP addresses and the set_vlan() method takes the same list but also a list of new VLAN names to use for each respective Self IP. The following code with modify the VLAN for the previously created 30.30.30.1 Self IP to the "internal1" VLAN. It will then query the value of the VLAN to verify that the method worked. PS C:\> $SelfIP.set_vlan((,"30.30.30.1"), (,"internal1")) PS C:\> $SelfIP.get_vlan((,"30.30.30.1")) internal1 Netmasks The netmask on the Self IP definition can be retrieved or modified with the get_netmask() and set_netmask() method. Both methods take as input a list of Self IP addresses but the set_netmask() method has an additional parameter to pass in the new netmasks for the specified Self IPs. This example will modify the netmask for the previously created 30.30.30.1 Self IP to 255.255.0.0 and query the value. I will then change the value back to it's original 255.255.255.0. PS C:\> $SelfIP.set_netmask((,"30.30.30.1"), (,"255.255.0.0")) PS C:\> $SelfIP.get_netmask((,"30.30.30.1")) 255.255.0.0 PS C:\> $SelfIP.set_netmask((,"30.30.30.1"), (,"255.255.255.0")) PS C:\> $SelfIP.get_netmask((,"30.30.30.1")) 255.255.255.0 Floating Self IP Addresses If you are running a redundant setup and would like your Self IP address to float to the active unit, you can do so by creating a floating Self IP address. This is accomplished by setting the floating_state to STATE_ENABLED and setting the unit_id to either 1 or 2 corresponding the the unit_id in your redundant setup that you would like to own the configuration for the address. The following example will create a new floating Self IP address 30.30.30.2 on the internal1 vlan configured with a unit_id value of 1. PS C:\> $SelfIP.create( (,"30.30.30.2"), (,"internal1"), (,"255.255.255.0"), (,1), (,"STATE_ENABLED") ) PS C:\> $SelfIP.get_list() 10.10.10.1 20.20.20.1 30.30.30.1 30.30.30.2 Unit IDs You can get the unit id of a Self IP address with the get_unit_id() method that takes as input a list of Self IP addresses and returns the list of unit_ids for those values. For floating Self IPs you can also call the set_unit_id() method to change the value to either 1 or 2. This example changes the Unit Id value in the previously created 30.30.30.2 Self IP from 1 to 2 and then queries the value. PS C:\> $SelfIP.set_unit_id((,"30.30.30.2"), (,2)) PS C:\> $SelfIP.get_unit_id((,"30.30.30.2")) 2 Toggling between Floating and Fixed If you decided you no longer wish to have your Self IP be floating, you can change it to fixed by calling the set_floating_state() method which takes as input a list of self ips, and a list of ENABLED_STATE enum values. In this example I'm disabling the floating state by passing in STATE_DISABLED. You'll notice that the unit_id has changed from 2 to 0. I followed that up by turning it back into a floating Self IP by passing in STATE_ENABLED. In this case, you'll see that the unit_id was set to 1 as the default. If you want it back to the value of 2 as was set above, you will have to call the set_unit_id() method again specifying a value of 2 for the unit_id. PS C:\> $SelfIP.set_floating_state((,"30.30.30.2"), (,"STATE_DISABLED")) PS C:\> $SelfIP.get_unit_id((,"30.30.30.2")) 0 PS C:\> $SelfIP.set_floating_state((,"30.30.30.2"), (,"STATE_ENABLED")) PS C:\> $SelfIP.get_unit_id((,"30.30.30.2")) 1 Deleting Self IPs If your Self IP not longer has any use to you and you would like to get rid of it for good, then the delete_self_ip() method is what you want, Just pass in a list of Self IP addresses and it will wipe them out. PS C:\> $SelfIP.delete_self_ip(("30.30.30.1", "30.30.30.2")) PS C:\> $SelfIP.get_list() 10.10.10.1 20.20.20.1 Oh, and for those who like to live on the edge, there is also a delete_all_self_ips() method that takes no input and deletes all defined Self IPs on the system. Use this method wisely... Conclusion By knowing how to use the methods in the Networking.SelfIP interface, you now have all the tools to automate the creation, management, and deletion of Self IP addresses on your BIG-IP. Get the Flash Player to see this player. 20080605-iControl101_16_SelfIPs.mp31KViews0likes1CommentiControl Apps - #04 - Graceful Server Shutdown
This question comes up quite often here on DevCentral: "How can I gracefully shut down my servers for maintenance without disrupting current user sessions?". In fact, I answered this question just the other day again in the iControl forum and figured I'd throw out an application that accomplished this. So I went about writing this application to allow for the graceful shutdown of a given pool member. Of course, the application wouldn't be complete without listing the pools and members for a specified pool as well as allowing for enabling and disabling of the server so I went ahead and included those pieces as a bonus. Usage The arguments for this application are the address, username, and password of the BIG-IP along with optional arguments for the specified pool, pool member and enabled state. This is declared in the top of the script with the following param statement. There is also a Write-Usage function to display the arguments to the user. param ( $g_bigip = $null, $g_uid = $null, $g_pwd = $null, $g_pool = $null, $g_member = $null, $g_mode = $null ); Set-PSDebug -strict; function Write-Usage() { Write-Host "Usage: PoolMemberControl.ps1 host uid pwd [pool [member:ip [mode = "enable"|"disable"]]]"; exit; } Initialization As is with all of my PowerShell scripts, the initialization component will look to see if the iControlSnapIn is loaded into the current PowerShell session. If not, the Add-PSSnapIn Cmdlet is called to add the snapin into the runtime. Then a call to the Initialize-F5.iControl cmdlet to setup the connection to the BIG-IP. If this succeeds then success, then the rest of the optional arguments are processed. If a pool name is not specified the Get-Pools function will be called to list out all of the available pools on the BIG-IP. If a pool is specified but a member is not, then the Get-PoolMembers function will be called passing in the pool name and this function will then list the currently configured members within that pool. If a pool as well as the pool member are specified but no enabled state is specified, the Get-PoolMemberStatus function is called in which the enabled and availablility status of the specified pool member is displayed. If a pool, pool member, and state are specified, the Enable-Member or Disable-Member method will be called depending on whether the state is "enabled" or "disabled". The code for this process is listed below. #------------------------------------------------------------------------- # Do-Initialize #------------------------------------------------------------------------- function Do-Initialize() { if ( (Get-PSSnapin | Where-Object { $_.Name -eq "iControlSnapIn"}) -eq $null ) { Add-PSSnapIn iControlSnapIn } $success = Initialize-F5.iControl -HostName $g_bigip -Username $g_uid -Password $g_pwd; return $success; } #------------------------------------------------------------------------- # Main Application Logic #------------------------------------------------------------------------- if ( ($g_bigip -eq $null) -or ($g_uid -eq $null) -or ($g_pwd -eq $null) ) { Write-Usage; } if ( Do-Initialize ) { if ( $g_pool -eq $null ) { Get-Pools; } elseif ( $g_member -eq $null ) { Get-PoolMembers $g_pool; } elseif ( $g_mode -eq $null ) { Get-PoolMemberStatus $g_pool $g_member; } else { switch ($g_mode.ToLower()) { "enable" { Enable-Member $g_pool $g_member; } "disable" { Disable-Member $g_pool $g_member; } default { Write-Usage; } } } } else { Write-Error "ERROR: iControl subsystem not initialized" } Listing Pools As mentioned above, if no pool is specified to the program, the Get-Pools function is called in which the LocalLB.Pool.get_list() method is called. This method returns a list of pool names and the function will loop through this list and write them to the console. function Get-Pools() { $pool_list = (Get-F5.iControl).LocalLBPool.get_list(); Write-Host "Available Pools:"; foreach ($pool in $pool_list) { Write-Host " $pool"; } } An example usage of the Get-Pools function is illustrated here: PS C:\> .\PoolMemberControl.ps1 theboss admin admin Available Pools: xpbert-ftp pool_1 catbert-http catbert-ssh pool_2 test-pool xpbert-http xpbert-ssh Listing Pool Members If you don't happen the know the specific addresses of the pool members in your given pool, the application will call the Get-PoolMembers function which in turn calls the iControl LocalLB.Pool.get_member() method passing in the supplied pool name. Returned is a 2-d array of Common.IPPortDefinition structures with the first dimension corresponding to each pool name passed in (in this case just one) and the second dimension for the list of pool members for that specified pool. The function will then iterate through that array and print the results to the console. Function Get-PoolMembers() { param($pool_name); $member_lists = (Get-F5.iControl).LocalLBPool.get_member((, $pool_name)); Write-Host "Members for Pool ${pool_name}:" foreach($member in $member_lists[0]) { $addr = $member.address; $port = $member.port; Write-Host " ${addr}:${port}" } } The following example will list the pool members for pool "xpbert-http". PS C:\> .\PoolMemberControl.ps1 theboss admin admin xpbert-http Members for Pool xpbert-http 10.10.10.149:80 Querying Pool Member Status If your ultimate goal is to take a server out of provisioning, it's likely a good idea to know what it's current state is. By not passing in a state while passing in a pool name and member details, the application will call the local Get-PoolMemberStatus method which then calls the iControl LocalLB.PoolMember.get_object_status() method which returns a 2-D array of MemberObjectStatus structures. Packed inside there are the availability statuses, enabled statuses, and status descriptions for each of the pool members for the specified pool. This method will loop through that returned list and if it finds a match for the specified pool member, it will display the status values. If no match is found, an error is displayed. Function Get-PoolMemberStatus() { param($pool_name, $member); $vals = $member.Split( (, ':')); $member_addr = $vals[0]; $member_port = $vals[1]; $bFound = 0; $MemberObjectStatusAofA = (Get-F5.iControl).LocalLBPoolMember.get_object_status((, $pool_name)); foreach($MemberObjectStatus in $MemberObjectStatusAofA[0]) { $a2 = $MemberObjectStatus.member.address; $p2 = $MemberObjectStatus.member.port; if ( "${member_addr}:${member_port}" -eq "${a2}:${p2}" ) { $Availability = $MemberObjectStatus.object_status.availability_status; $Enabled = $MemberObjectStatus.object_status.enabled_status; $Description = $MemberObjectStatus.object_status.status_description; Write-Host "Pool $pool_name, Member ${member_addr}:${member_port} status:" Write-Host " Availability : $Availability" Write-Host " Enabled : $Enabled" Write-Host " Description : $Description" $bFound = 1; } } if ( $bFound -eq 0 ) { Write-Host "Member ${member_addr}:${member_port} could not be found in pool $pool_name!" } } The following command will query the state of the 10.10.10.149:80 pool member in pool xpbert-http. PS C:\> .\PoolMemberControl.ps1 theboss admin admin xpbert-http 10.10.10.149:80 Pool xpbert-http, Member 10.10.10.149:80 status: Availability : Enabled : ENABLED_STATUS_ENABLED Description : Pool member is available Gracefully disabling a Pool Member Now for the meat of this article: how to gracefully shutdown a pool member. If a pool name, member, and state of "disable" is passed into the application, the local Delete-Member function is called to take down the pool member. Remember that we want to "gracefully" take down the pool member so we'll want to make sure that all current sessions are allowed to run their course before the pool member is disabled for good. So, the first step is to disable any new sessions to that pool member with the LocalLB.PoolMember.set_session_enabled_state() iControl method passing in the pool and member details along with a session_state of "STATE_DISABLED". Remember, that this will not fully disable the pool member but will just stop new connections from being established. The function then queries the current connections statistic with the LocalLB.PoolMember.get_statistics() method. The value of "STATISTIC_SERVER_SIDE_CURRENT_CONNECTIONS" is then extracted into the cur_connections variable. A loop is performed until this value is down to zero. As long as the value is greater than zero, the function sleeps for 1 second and then queries the statistic again. Once the current connections statistic reaches zero, all current connections to the pool member have been removed so it's safe to disable it. The LocalLB.PoolMember.set_monitor_state() method is used to forcefully take down a pool member. Since there are no connections to the pool member any more a forceful take down is actually graceful to the users... Once the pool member is offline, the local Get-PoolMemberStatus function is called to query and display the current status of the pool member to make sure that it's really down. function Disable-Member() { param($pool_name, $member); $vals = $member.Split( (, ':')); $member_addr = $vals[0]; $member_port = $vals[1]; Write-Host "Disabling Session Enabled State..."; $MemberSessionState = New-Object -TypeName iControl.LocalLBPoolMemberMemberSessionState; $MemberSessionState.member = New-Object -TypeName iControl.CommonIPPortDefinition; $MemberSessionState.member.address = $member_addr; $MemberSessionState.member.port = $member_port; $MemberSessionState.session_state = "STATE_DISABLED"; $MemberSessionStateAofA = New-Object -TypeName "iControl.LocalLBPoolMemberMemberSessionState[][]" 1,1 $MemberSessionStateAofA[0][0] = $MemberSessionState; (Get-F5.iControl).LocalLBPoolMember.set_session_enabled_state( (, $pool_name), $MemberSessionStateAofA); Write-Host "Waiting for current connections to drop to zero..." $MemberDef = New-Object -TypeName iControl.CommonIPPortDefinition; $MemberDef.address = $member_addr; $MemberDef.port = $member_port; $MemberDefAofA = New-Object -TypeName "iControl.CommonIPPortDefinition[][]" 1,1 $MemberDefAofA[0][0] = $MemberDef; $cur_connections = 1; while ( $cur_connections -gt 0 ) { $MemberStatisticsA = (Get-F5.iControl).LocalLBPoolMember.get_statistics( (, $pool_name), $MemberDefAofA); $MemberStatisticEntry = $MemberStatisticsA[0].statistics[0]; $Statistics = $MemberStatisticEntry.statistics; foreach ($Statistic in $Statistics) { $type = $Statistic.type; $value = $Statistic.value; if ( $type -eq "STATISTIC_SERVER_SIDE_CURRENT_CONNECTIONS" ) { # just use the low value. Odds are there aren't over 2^32 current connections. # If your site is this big, you'll have to convert this to a 64 bit number. $cur_connections = $value.low; Write-Host "Current Connections: $cur_connections" } } Start-Sleep -s 1 } Write-Host "Disabling Monitor State..."; $MemberMonitorState = New-Object -TypeName iControl.LocalLBPoolMemberMemberMonitorState; $MemberMonitorState.member = New-Object -TypeName iControl.CommonIPPortDefinition; $MemberMonitorState.member.address = $member_addr; $MemberMonitorState.member.port = $member_port; $MemberMonitorState.monitor_state = "STATE_DISABLED"; $MemberMonitorStateAofA = New-Object -TypeName "iControl.LocalLBPoolMemberMemberMonitorState[][]" 1,1 $MemberMonitorStateAofA[0][0] = $MemberMonitorState; (Get-F5.iControl).LocalLBPoolMember.set_monitor_state( (, $pool_name), $MemberMonitorStateAofA); Get-PoolMemberStatus $pool_name $member } The following command will disable pool member 10.10.10.149:80 from pool xpbert-http gracefully by first stopping new connections, then waiting until the connection count drops to zero, and then fully disabling the pool member. PS C:\> .\PoolMemberControl.ps1 theboss admin admin xpbert-http 10.10.10.149:80 disable Disabling Session Enabled State... Waiting for current connections to drop to zero... Current Connections: 50 Current Connections: 47 Current Connections: 47 Current Connections: 0 Disabling Monitor State... Pool xpbert-http, Member 10.10.10.149:80 status: Availability : AVAILABILITY_STATUS_RED Enabled : ENABLED_STATUS_DISABLED Description : Forced down Enabling a Pool Member Now that your server maintenance is performed, you'll likely want to put the pool member back into rotation. This can be done by passing the application the pool name, member name, and a state of "enable". When this is done, the local Enable-Member function is called that basically reverses the Disable-Member functions actions. It first set's the monitor state to "STATE_ENABLED" and then enables new connections by calling the LocalLB.PoolMember.set_session_enabled_state() iControl method with the "STATE_ENABLED" value as well. After the pool is enabled, the Get-PoolMemberStatus function is called to make sure that it is in fact re-enabled. function Enable-Member() { param($pool_name, $member); $vals = $member.Split( (, ':')); $member_addr = $vals[0]; $member_port = $vals[1]; $MemberMonitorState = New-Object -TypeName iControl.LocalLBPoolMemberMemberMonitorState; $MemberMonitorState.member = New-Object -TypeName iControl.CommonIPPortDefinition; $MemberMonitorState.member.address = $member_addr; $MemberMonitorState.member.port = $member_port; $MemberMonitorState.monitor_state = "STATE_ENABLED"; $MemberMonitorStateAofA = New-Object -TypeName "iControl.LocalLBPoolMemberMemberMonitorState[][]" 1,1 $MemberMonitorStateAofA[0][0] = $MemberMonitorState; Write-Host "Setting Montior State to Enabled"; (Get-F5.iControl).LocalLBPoolMember.set_monitor_state( (, $pool_name), $MemberMonitorStateAofA); $MemberSessionState = New-Object -TypeName iControl.LocalLBPoolMemberMemberSessionState; $MemberSessionState.member = New-Object -TypeName iControl.CommonIPPortDefinition; $MemberSessionState.member.address = $member_addr; $MemberSessionState.member.port = $member_port; $MemberSessionState.session_state = "STATE_ENABLED"; $MemberSessionStateAofA = New-Object -TypeName "iControl.LocalLBPoolMemberMemberSessionState[][]" 1,1 $MemberSessionStateAofA[0][0] = $MemberSessionState; Write-Host "Setting Session Enabled State to Enabled"; (Get-F5.iControl).LocalLBPoolMember.set_session_enabled_state( (, $pool_name), $MemberSessionStateAofA); Get-PoolMemberStatus $pool_name $member } The following command will re-enable the 10.10.10.149:80 pool member from pool xpbert-http by enabling the monitor state and allowing new connections. PS C:\> .\PoolMemberControl.ps1 theboss admin admin xpbert-http 10.10.10.149:80 enable Setting Montior State to Enabled Setting Session Enabled State to Enabled Pool xpbert-http, Member 10.10.10.149:80 status: Availability : AVAILABILITY_STATUS_GREEN Enabled : ENABLED_STATUS_ENABLED Description : Pool member is available Conclusion While this application was written in PowerShell, the logic should transfer to any development language you choose to use. You now have the tools you need to automate the maintenance of your application servers. The code for this application can be found in the iControl CodeShare wiki under PsPoolMemberControl. Get the Flash Player to see this player. 20080716-iControlApps_4_GracefulServerShutdown.mp31KViews0likes15CommentsiControl 101 - #11 - Performance Graphs
The BIG-IP stores history of certain types of data for reporting purposes. The Performance item in the Overview tab shows the report graphs for this performance data. The management GUI gives you the options to customize the graph interval but it stops short of giving you access to the raw data behind the graphs. Never fear, the System.Statistics interface contains methods to query the report types and extract the CSV data behind them. You can even select the start and end times as well as the poll intervals. This article will discuss the performance graph methods and how you can query the data behind them and build a chart of your own. Initialization This article uses PowerShell and the iControl Cmdlets for PowerShell as the client environment for querying the data. The following setup will be required for the examples contained in this article. PS> Add-PSSnapIn iControlSnapIn PS> Initialize-F5.iControl -Hostname bigip_address -Username bigip_user -Password bigip_pass PS> $SystemStats = (Get-F5.iControl).SystemStatistics Now that that is taken care of, let's dive right in. In the System.Statistics interface, there are two methods that get you to the performance graph data. The first is the get_performance_graph_list() method. This method takes no parameters and returns a list of structures containing each graph name, title, and description. PS> $SystemStats.get_performance_graph_list() graph_name graph_title graph_description ---------- ----------- ----------------- memory Memory Used Memory Used activecons Active Connections Active Connections newcons New Connections New Connections throughput Throughput Throughput httprequests HTTP Requests HTTP Requests ramcache RAM Cache Utilization RAM Cache Utilization detailactcons1 Active Connections Active Connections detailactcons2 Active PVA Connections Active PVA Connections detailactcons3 Active SSL Connections Active SSL Connections detailnewcons1 Total New Connections Total New Connections detailnewcons2 New PVA Connections New PVA Connections detailnewcons3 New ClientSSL Profile Connections New ClientSSL Profile Connections detailnewcons4 New Accepts/Connects New Accepts/Connects detailthroughput1 Client-side Throughput Client-side Throughput detailthroughput2 Server-side Throughput Server-side Throughput detailthroughput3 HTTP Compression Rate HTTP Compression Rate SSLTPSGraph SSL Transactions/Sec SSL Transactions/Sec GTMGraph GTM Performance GTM Requests and Resolutions GTMrequests GTM Requests GTM Requests GTMresolutions GTM Resolutions GTM Resolutions GTMpersisted GTM Resolutions Persisted GTM Resolutions Persisted GTMret2dns GTM Resolutions Returned to DNS GTM Resolutions Returned to DNS detailcpu0 CPU Utilization CPU Usage detailcpu1 CPU Utilization CPU Usage CPU CPU Utilization CPU Usage detailtmm0 TMM Utilization TMM Usage TMM TMM Utilization TMM CPU Utilization Creating a Report Ok, so you've now got the graph names, it's time to move on to accessing the data. The method you'll want is the get_performance_graph_csv_statistics() method. This method takes an array of PerformanceStatisticQuery structures containing the query parameters and returns an array of PerformanceGraphDataCSV structures, one for each input query. The following code illustrates how to make a simple query. The object_name corresponds to the graph_name in the get_performance_graph_list() method. The start_time and end_time allow you to control what the data range is. Values of 0 (the default) will return the entire result set. If the user specifies a start_time, end_time, and interval that does not exactly match the corresponding value used within the database, the database will attempt to use to closest time or interval as requested. The actual values used will be returned to the user on output. For querying purposes, the start_time can be specified as: 0: in which case by default, it means 24 hours ago. N: where N represents the number of seconds since Jan 1, 1970. -N: where -N represents the number of seconds before now, for example: -3600 means 3600 seconds ago, or now - 3600 seconds. For querying purposes, the end_time can be specified as: 0: in which case by default, it means now. N: where N represents the number of seconds since Jan 1, 1970. -N: where -N represents the number of seconds before now, for example: -3600 means 3600 seconds ago, or now - 3600 seconds. The interval is the suggested sampling interval in seconds. The default of 0 uses the system default. The maximum_rows value allows you to limit the returned rows. Values are started at the start_time and if the number of rows exceeds the value of maximum_rows, then the data is truncated at the maximum_rows value. A value of 0 implies the default of all rows. PS> # Allocate a new Query Object PS> $Query = New-Object -TypeName iControl.SystemStatisticsPerformanceStatisticQuery PS> $Query.object_name = "CPU" PS> $Query.start_time = 0 PS> $Query.end_time = 0 PS> $Query.interval = 0 PS> $Query.maximum_rows = 0 PS> # Make method call passing in an array of size one with the specified query PS> $ReportData = $SystemStats.get_performance_graph_csv_statistics( (,$Query) ) PS> # Look at the contents of the returned data. PS> $ReportData object_name : throughput start_time : 1208354160 end_time : 1208440800 interval : 240 statistic_data : {116, 105, 109, 101...} Processing the Data The statistic_data, much like the ConfigSync's file transfer data, is transferred as a base64 encoded string, which translates to a byte array in .Net. We will need to convert this byte array into a string and that can be done with the System.Text.ASCIIEncoding class. PS> # Allocate a new encoder and turn the byte array into a string PS> $ASCII = New-Object -TypeName System.Text.ASCIIEncoding PS> $csvdata = $ASCII.GetString($ReportData[0].statistic_data) PS> # Look at the resulting dataset PS> $csvdata timestamp,"CPU 0","CPU 1" 1208364000,4.3357230000e+00,0.0000000000e+00 1208364240,3.7098920000e+00,0.0000000000e+00 1208364480,3.7187980000e+00,0.0000000000e+00 1208364720,3.3311110000e+00,0.0000000000e+00 1208364960,3.5825310000e+00,0.0000000000e+00 1208365200,3.4826450000e+00,8.3330000000e-03 ... Building a Chart You will see the returned dataset is in the form of a comma separated value file. At this point you can take this data and import it into your favorite reporting package. But, if you want a quick and dirty way to see this visually, you can use PowerShell to control Excel into loading the data and generating a default report. The following code converts the csv format into a tab separated format, creates an instance of an Excel Application, loads the data, cleans it up, and inserts a default line graph based on the input data. PS> # Replace commas with tabs in the report data and save to c:\temp\tabdata.txt PS> $csvdata.Replace(",", "`t") > c:\temp\tabdata.txt PS> # Allocate an Excel application object and make it visible. PS> $e = New-Object -comobject "Excel.Application" PS> $e.visible = $true PS> # Load the tab delimited data into a workbook and get an instance of the worksheet it was inserted into. PS> $wb = $e.Workbooks.Open("c:\temp\tabdata.txt") PS> $ws = $wb.WorkSheets.Item(1) PS> # Let's remove the first row of timestamps. Ideally you'll want this to be the PS> # horizontal axis and I'll leave it up to you to figure that one out. PS> $ws.Columns.Item(1).EntireColumn.Select() PS> $ws.Columns.Item(1).Delete() PS> # The last row of the data is filled with NaN to indicate the end of the result set. Let's delete that row. PS> $ws.Rows.Item($ws.UsedRange.Rows.Count).Select() PS> $ws.Rows.Item($ws.UsedRange.Rows.Count).Delete() PS> # Select all the data in the worksheet, create a chart, and change it to a line graph. PS> $ws.UsedRange.Select() PS> $chart = $e.Charts.Add() PS> $chart.Type = 4 Conclusion Now you should have everything you need to get access to the data behind the performance graphs. There are many ways you could take these examples and I'll leave it to the chart gurus out there to figure out interesting ways to represent the data. If anyone does find some interesting ways to manipulate this data, please let me know! Get the Flash Player to see this player.1KViews0likes5CommentsCreating An iControl PowerShell Monitoring Dashboard With Google Charts
PowerShell is a very extensible scripting language and the fact that it integrates so nicely with iControl means you can do all sorts of fun things with it. In this tech tip, I'll illustrate how to use just a couple of iControl method calls (3 to be exact) to create a load distribution dashboard for you desktop (with a little help from the Google Chart API). Usage The arguments for this application are the address, username, and password for your BIG-IP. param ( $g_bigip = $null, $g_uid = $null, $g_pwd = $null ); The main control flow then looks for the input parameters and if they are not present, a usage message is displayed to the console indicating the required inputs. If the connection info is specified, then the standard Do-Initialize function is called which will look to see if the iControl Snapin is installed and the Initialize-F5.iControl cmdlet is called to initialize the connection to the BIG-IP. If an error occurs during the connection, then an error is logged and the application exits. function Write-Usage() { Write-Host "Usage: iControlDashboard.ps1 host uid pwd"; exit; } function Do-Initialize() { if ( (Get-PSSnapin | Where-Object { $_.Name -eq "iControlSnapIn"}) -eq $null ) { Add-PSSnapIn iControlSnapIn } $success = Initialize-F5.iControl -HostName $g_bigip -Username $g_uid -Password $g_pwd; return $success; } #------------------------------------------------------------------------- # Main Application Logic #------------------------------------------------------------------------- if ( ($g_bigip -eq $null) -or ($g_uid -eq $null) -or ($g_pwd -eq $null) ) { Write-Usage; } if ( Do-Initialize ) { Run-Dashboard } else { Write-Error "ERROR: iControl subsystem not initialized" Kill-Browser } Global Variables This appliction will make use of the Google Chart APIs to generate graphs and as such we need a browser to render it in. Since we will be interacting with another process (in this case Internet Explorer), it is probably a good idea to gracefully shutdown if an error occurs. A generic Exception Trap is created to log the error and shutdown the application properly. Trap [Exception] { Write-Host $("TRAPPED: " + $_.Exception.GetType().FullName); Write-Host $("TRAPPED: " + $_.Exception.Message); Kill-Browser Exit; } A few global variables are used to make the app more configurable. You can specify the title that comes up in the browsers header as well as the graph size for each report graph along with the chart type and polling interval. I opted for a pie chart but other options are available that may or may not be to your liking. At this point I go ahead and create a empty browser window and point it to the about:blank page giving us a context to manipulate the contents of the browser window. I make the window visible and set it to full screen theatermode. $g_title = "iControl PowerShell Dashboard"; $g_graphsize = "300x150"; $g_charttype = "p"; $g_interval = 5; $g_browser = New-Object -com InternetExplorer.Application; $g_browser.Navigate2("About:blank"); $g_browser.Visible = $true; $g_browser.TheaterMode = $true; Browser Control The following functions are to control the browser and the data going into it. The Refresh-Browser function takes as input the HTML to display. The Document object is then accessed from the InternetExplorer.Application object and from there we can access the DocumentElement. Then we set the InnerHTML to the input parameter $html_data and that is displayed in the browser window. #------------------------------------------------------------------------- # function Refresh-Browser #------------------------------------------------------------------------- function Refresh-Browser() { param($html_data); if ( $null -eq $g_browser ) { Write-Host "Creating new Browser" $g_browser = New-Object -com InternetExplorer.Application; $g_browser.Navigate2("About:blank"); $g_browser.Visible = $true; $g_browser.TheaterMode = $true; } $docBody = $g_browser.Document.DocumentElement.lastChild; $docBody.InnerHTML = $html_data; } #------------------------------------------------------------------------- # function Kill-Browser #------------------------------------------------------------------------- function Kill-Browser() { if ( $null -ne $g_browser ) { $g_browser.TheaterMode = $false; $g_browser.Quit(); $g_browser = $null; } } Main Application Loop The main logic for this application is a little infinite loop where we call the Get-Data function, refresh the browser with the newly acquired report, and sleep for the configured interval until the next poll occurs. function Run-Dashboard() { while($true) { #Write-Host "Requesting data..." $html_data = Get-Data; Refresh-Browser $html_data; Start-Sleep $g_interval; } } Generating the Report Here's where all the good stuff happens. The Get-Data function will make a few iControl calls (LocalLB.Pool.get_list(), LocalLB.PoolMember.get_all_statistics(), and LocalLB.PoolMember.get_object_status()) and from that generate a HTML report with charts generated with the Google Chart API. The local variable $html-data is used to store the resulting HTML data that will be sent to Internet Explorer for display and we start off the function by filling in the title and start of the report table. Then the three previously mentioned iControl calls are made and the resulting values are stored in local varables for later reference. The main loop here goes over each of the pools in the MemberStatisticsA local array variable. A few hash tables and counters are created and then we loop over each pool member for the current pool we are processing. Then entries are added to the local hash tables for total connections, current connections, bytes in, and status for later reference. Also a sum of all the values for those hash tables are stored so we can calculate percentages later on. At this point we will use the hash tables for generating the report. Each numeric value is calculated into a percent and chart variables are created to contain the data as well as the labels for the generated pie charts. Once all the number crunching has been performed the actual chart images are specified in the $chart_total, $chart_current, and $chart_bytes variables and the row in the report for the given pool is added to the $html_data variable. function Get-Data() { # TODO - get connection statistics $now = [DateTime]::Now; $html_data = "<html> <head> <title>$g_title</title> </head> <body> <center><h1>$g_title</h1><br/><h2>$now</h2></center> <center><table border='0' bgcolor='#C0C0C0'><tr><td><table border='0' cellspacing='0' bgcolor='#FFFFFF'>"; $html_data += " <tr bgcolor='#C0C0C0'><th>Pool</th><th>Total Connections</th><th>Current Connections</th><th>Bytes In</th></tr>"; $charts_total = ""; $charts_current = ""; $charts_bytes = ""; $PoolList = (Get-F5.iControl).LocalLBPool.get_list() | Sort-Object; $MemberStatisticsA = (Get-F5.iControl).LocalLBPoolMember.get_all_statistics($PoolList) $MemberObjectStatusAofA = (Get-F5.iControl).LocalLBPoolMember.get_object_status($PoolList); # loop over each pool $i = 0; foreach($MemberStatistics in $MemberStatisticsA) { $hash_total = @{}; $hash_current = @{}; $hash_bytes = @{}; $hash_status = @{}; $sum_total = 0; $sum_current = 0; $sum_bytes = 0; $PoolName = $PoolList[$i]; # loop over each member $MemberStatisticEntryA = $MemberStatistics.statistics; foreach($MemberStatisticEntry in $MemberStatisticEntryA) { $member = $MemberStatisticEntry.member; $addr = $member.address; $port = $member.port; $addrport = "${addr}:${port}"; $StatisticA = $MemberStatisticEntry.statistics; $total = Extract-Statistic $StatisticA "STATISTIC_SERVER_SIDE_TOTAL_CONNECTIONS" [long]$sum_total += $total; $hash_total.Add($addrport, $total); $current = Extract-Statistic $StatisticA "STATISTIC_SERVER_SIDE_CURRENT_CONNECTIONS" $sum_current += $current; $hash_current.Add($addrport, $current); $bytes = Extract-Statistic $StatisticA "STATISTIC_SERVER_SIDE_BYTES_IN" [long]$sum_bytes += $bytes; $hash_bytes.Add($addrport, $bytes); $color = Extract-Status $MemberObjectStatusAofA[$i] $member; $hash_status.Add($addrport, $color); } $chd_t = ""; $chd_c = ""; $chd_b = ""; $chl_t = ""; $chl_c = ""; $chl_b = ""; $chdl_t = ""; $chdl_c = ""; $chdl_b = ""; $tbl_t = ""; $tbl_c = ""; $tbl_b = ""; # enumerate the total connections foreach($k in $hash_total.Keys) { $member = $k; $v_t = $hash_total[$k]; $v_c = $hash_current[$k]; $v_b = $hash_bytes[$k]; $color = $hash_status[$k]; $div = $sum_total; if ($div -eq 0 ) { $div = 1; } $p_t = ($v_t/$div)*100; $div = $sum_current; if ($div -eq 0 ) { $div = 1; } $p_c = ($v_c/$div)*100; $div = $sum_bytes; if ($div -eq 0 ) { $div = 1; } $p_b = ($v_b/$div)*100; if ( $chd_t.Length -gt 0 ) { $chd_t += ","; $chd_c += ","; $chd_b += ","; } $chd_t += $p_t; $chd_c += $p_c; $chd_b += $p_b; if ( $chl_t.Length -gt 0 ) { $chl_t += "|"; $chl_c += "|"; $chl_b += "|"; $chdl_t += "|"; $chdl_c += "|"; $chdl_b += "|"; } $chl_t += "$member"; $chl_c += "$member"; $chl_b += "$member"; $chdl_t += "$member - $v_t"; $chdl_c += "$member - $v_c"; $chdl_b += "$member - $v_b"; #$alt_t += "($member,$v_t)"; #$alt_c += "($member,$v_c)"; #$alt_b += "($member,$v_b)"; $tbl_t += "<tr><td bgcolor='$color'>$member</td><td align='right'>$v_t</td></tr>"; $tbl_c += "<tr><td bgcolor='$color'>$member</td><td align='right'>$v_c</td></tr>"; $tbl_b += "<tr><td bgcolor='$color'>$member</td><td align='right'>$v_b</td></tr>"; } if ( $sum_total -gt 0 ) { $chart_total = "<img src='http://chart.apis.google.com/chart? chs=$g_graphsize &chd=t:$chd_t &cht=$g_charttype &chdl=$chl_t' alt='Total Connections for pool $PoolName' />"; } else { $chart_total = ""; } if ( $sum_current -gt 0 ) { $chart_current = "<img src='http://chart.apis.google.com/chart? chs=$g_graphsize &chd=t:$chd_c &cht=$g_charttype &chdl=$chl_c' alt='Current Connections for pool $PoolName' />"; } else { $chart_current = ""; } if ( $sum_bytes -gt 0 ) { $chart_bytes = "<img src='http://chart.apis.google.com/chart? chs=$g_graphsize &chd=t:$chd_b &cht=$g_charttype &chdl=$chl_b' alt='Incoming Bytes for pool $PoolName' />"; } else { $chart_current = ""; } if ( $i -gt 0 ) { $html_data += "<tr><td colspan='4'><hr/></td></tr>"; } $html_data += " <tr><th nowrap='nowrap'>$PoolName</th> <td valign='bottom'>$chart_total<br/> <center><table border='1'><tr><th>Member</th><th>Value</th></tr>$tbl_t</table> </td> <td valign='bottom'>$chart_current<br/> <center><table border='1'><tr><th>Member</th><th>Value</th></tr>$tbl_c</table> </td> <td valign='bottom'>$chart_bytes<br/> <center><table border='1'><tr><th>Member</th><th>Value</th></tr>$tbl_b</table> </td> </tr>"; $i++; } $html_data += "</table></td></tr></table></body></html>"; return $html_data; } Utility Functions It's always useful to extract common code into utility functions and this application is no exception. In here I've got a Convert-To64Bit function that takes the high and low 32 bits of a 64 bit number and does the math to convert them into a native 64 bit value. The Extract-Statistic function takes as input a Common.Statsistic Array along with a type to look for in that array. It loops over the array of Statistic values and returns the 64 bit value of the match, if one is found. And finally the Extract-Status function is used to look through the returned value from the LocalLB.PoolMember.get_object_status iControl method for a specific pool member. This function returns a color to display in the generated HTML table, green for good, red for bad. The only way a green will show up will be if both it's availability_status and enabled_status values are AVAILABILITY_STATUS_GREEN and ENABLED_STATUS_ENABLED respectively. function Convert-To64Bit() { param($high, $low); $low = [Convert]::ToString($low,2).PadLeft(32,'0') if($low.length -eq "64") { $low = $low.substring(32,32) } return [Convert]::ToUint64([Convert]::ToString($high,2).PadLeft(32,'0')+$low,2); } function Extract-Statistic() { param($StatisticA, $type); $value = -1; foreach($Statistic in $StatisticA) { if ( $Statistic.type -eq $type ) { $value = Convert-To64Bit $Statistic.value.high $Statistic.value.low; break; } } return $value; } function Extract-Status() { param($MemberObjectStatusA, $IPPortDefinition); $color = "#FF0000"; foreach($MemberObjectStatus in $MemberObjectStatusA) { if ( ($MemberObjectStatus.member.address -eq $IPPortDefinition.address) -and ($MemberObjectStatus.member.port -eq $IPPortDefinition.port) ) { $availability_status = $MemberObjectStatus.object_status.availability_status; $enabled_status = $MemberObjectStatus.object_status.enabled_status; if ( ($availability_status -eq "AVAILABILITY_STATUS_GREEN") -and ($enabled_status -eq "ENABLED_STATUS_ENABLED" ) ) { $color = "#00FF00"; } } } return $color; } Running The Application After running the application on the console, Internet Explorer will be created in Theater Mode (Full Screen) and will look something like this. My system is somewhat inactive so you'll see that some of the charts are missing. This was by design in that charts with no data are not very informative. Assuming you have traffic across all your pools, charts will be created. Extending This Application This application merely looks at load distribution and state for members within the pools. It would be trivial to change or extend the types of charts presented. iControl provides you with all the data you need to build your own monitoring dashboard regardless of the types of metrics you would like to keep an eye on. For the full application, check out the PsiControlDashboard entry in the iControl CodeShare Get the Flash Player to see this player. 20081106-iControlApps-15-iControlDashboard.mp3811Views0likes28CommentsiControl 101 - #08 - Partitions
In a previous article, I discussed user management and the concepts of user roles. User roles form half of what we refer to as Administrative Domains. The second half of Administrative Domains are Configuration Partitions. Configuration Partitions allow you to control access to BIG-IP system resources by BIG-IP administrative users. This article will discuss how to manage Configuration Partitions with the iControl programming interfaces. Configuration partitions are essentially logical containers that you can use to group local traffic management objects. Think of it as different "buckets" you can place your virtuals, pools, rules, etc into. You can then control who can peek into those buckets by the user name and, for those lucky enough to be able to peek in, what they can do by their user roles. There is always at least one partition. For new installs, or upgrades, a special partition called "Common" is created that is the default for all traffic management objects. You can create many partitions with zero or more users assigned access to them. The following examples will illustrate how to interact with the partitions. The samples use the iControl CmdLets for PowerShell so check out the PowerShell Labs Project if you want to test them out for yourself. Initializing the iControl PowerShell SnapIn For a new PowerShell instance, you will need to add the iControl SnapIn and initialize it for your BIG-IP. PS> Add-PSSnapIn iControlSnapIn PS> Initialize-F5.iControl -hostname bigip_address -username bigip_username -password bigip_password PS> $ic = Get-F5.iControl Querying Partitions The Management::Partition::get_partition_list() method will return the list of all Configuration partitions along with the corresponding description attribute. PS> $ic.ManagementPartition.get_list() partition_name description -------------- ----------- Common Repository for system objects and shared objects. Accounting Partition for Accounting Department DevCentral DevCentral administrative partition Finance Partition for Finance Departmen Creating Partitions So, let's say you've got a new department that needs a separate configuration space on your BIG-IP. Creating a new Partition is as easy as this: PS > $partition = New-Object -TypeName iControl.ManagementPartitionAuthZPartition PS > $partition.partition_name = "NewDept" PS > $partition.description = "New Department" PS > $ic.ManagementPartition.create_partition( (,$partition) ) PS> $ic.ManagementPartition.get_list() partition_name description -------------- ----------- Common Repository for system objects and shared objects. NewDept New Department Accounting Partition for Accounting Department DevCentral DevCentral administrative partition Finance Partition for Finance Departmen Deleting Partitions Now, let's suppose that the NewDept group that insisted on a separate configuration space, has gone 2 years without adding a single object and they are now no longer anywhere to be seen. Well, it's very simple to delete that partition you created for them with the delete_partition() method. PS> $ic.ManagementPartition.delete_partition( (,"NewDept") ) PS> $ic.ManagementPartition.get_list() partition_name description -------------- ----------- Common Repository for system objects and shared objects. DevCentral DevCentral administrative partition Accounting Partition for Accounting Department Finance Partition for Finance Departmen Active Partitions So, you've found out how to query, create, and delete partitions. The last piece of info you need to know is how you specify which partition a object is going into when you are using all of the other 2500+ iControl methods that deal directly with the configuration objects. When you initialize an iControl connection, you authenticate with a given username. How do you determine which partition this user context is operating in? Well, it's all right there with the other Partition methods. You can use the get_active_partition() method to query the current active partition for a given user and the set_active_partition() method to change the current active partition. A reason why you might want to do this is so that when you are logging in as admin, you can create and manage objects in various partitions buckets. Here's an example of querying the current partition and then changing it. PS> $ic.ManagementPartition.get_active_partition() Common PS> $ic.ManagementPartition.set_active_partition( (,"DevCentral") ) PS> $ic.ManagementPartition.get_active_partition() DevCentral Conclusion By combining the User Roles aspects of the Management::UserManagement interface and the Partition methods in the Management::Partition interface, you have all the tools you need to implement and manage Administrative Domains programmatically. Get the Flash Player to see this player.804Views0likes2CommentsiControl 101 - #09 - iRules
iRules are the internal scripting language of the BIG-IP and can be used to attain full control of traffic flowing through your network. But, did you know that you can automate the management of iRules across your Virtual Servers with iControl? This article will discuss the iControl methods that can be used to query, create, delete iRules as well as how to apply them to Virtual Servers. The Interfaces There are two interfaces that I will highlight in this article. For the management of the iRules themselves such as querying, creating, and deleting, you will want to look in the LocalLB::Rule interface. This fairly small interface (11 methods) gives you the power to have full control of the management of the iRules on the system. Once you have created your iRules and are ready to put them into production, you'll want to head over to the LocalLB::VirtualServer interface. iRules are attributes of a Virtual Server so, consequently, there are methods in there to add and remove configured rules to the specified Virtuals. The following examples will use the iControl CmdLet's for Microsoft PowerShell as the iControl client. If you are using one of the many other languages that are supported with iControl, the logic will be the same. For these examples, the following setup is required for the iControl Cmdlets. PS> Add-PSSnapIn iControlSnapIn PS> Initialize-F5.iControl -Hostname bigip_address -Username username -Password password PS> $ic = Get-F5.iControl Determining the iRules on your system. The LocalLB::Rule::query_all_rules() method will return an array of RuleDefinition structures, one for each iRule. The RuleDefinition Structure contains the "rule_name" and "rule_definition". The following example will call the query_all_rules() method and list out all of the Rule names followed by the actual iRule content (rule_definition). PS> $RuleDefinitions = $ic.LocalLBRule.query_all_rules() PS> $RuleDefinitions | Format-List rule_name : _sys_auth_ldap rule_definition : when HTTP_REQUEST { if {not [info exists tmm_auth_http_sids(ldap)]} { set tmm_auth_sid [AUTH::start pam default_ldap] set tmm_auth_http_sids(ldap) $tmm_auth_sid if {[info exists tmm_auth_subscription]} { ... The LocalLB::Rule::query_rule() method is also available if you want to specify a specific list of iRules to query. Creating an iRule The LocalLB::Rule::create() method takes in an array of RuleDefinition structures defining the new iRules to be created. For this example, I am allocating a single RuleDefinition structure for a single iRule and passing in an array size of one to the create method. I will then call the query_rule() method to show you the creation took effect. PS> $RuleDefinition = New-Object -TypeName iControl.LocalLBRuleRuleDefinition PS> $RuleDefinition.rule_name = "MyCoolRule" PS> $RuleDefinition.rule_definition = @" >> when HTTP_REQUEST { >> log local0. {URI: [HTTP::uri]} >> } >> "@ >> PS> $ic.LocalLBRule.create( (,$RuleDefinition) ) PS> $ic.LocalLBRule.query_rule( (,"MyCoolRule") ) | Format-List rule_name : MyCoolRule rule_definition : when HTTP_REQUEST { log local0. {URI: [HTTP::uri]} } Deleting an iRule Deleting an iRule is as simple as passing the rule name to the LocalLB::Rule::delete_rule() method. The following sample will delete the previously created "MyCoolRule" iRule and then attempt to query it again and show the exception that is thrown as a result of the requested iRule name not existing on the system. PS> $ic.LocalLBRule.delete_rule( (,"MyCoolRule") ) PS> $ic.LocalLBRule.query_rule( (,"MyCoolRule") ) | format-list Exception calling "query_rule" with "1" argument(s): "Exception caught in LocalLB::Rule::query_rule() Exception: Common::OperationFailed primary_error_code : 16908342 (0x01020036) secondary_error_code : 0 error_string : 01020036:3: The requested rule (MyCoolRule) was not found." At line:1 char:27 + $ic.LocalLBRule.query_rule( <<<< (,"MyCoolRule") ) | format-list Applying the iRule to a Virtual Server Now, go ahead and recreate that iRule by calling the create() method again. Once you've got the iRule in place, You'll want to jump over to the LocalLB::VirtualServer interface and it's add_rule() method. This method takes an array of virtual servers and a 2-d array for the iRules (1-n iRules for each virtual server passed in). PS> # Create the iRule PS> $ic.LocalLBRule.create( (,$RuleDefinition) ) PS> PS> # Allocate and populate parameters PS> $VirtualServerRule = New-Object -TypeName iControl.LocalLBVirtualServerVirtualServerRule PS> $VirtualServerRule.rule_name = "MyCoolRule" PS> $VirtualServerRule.priority = 500 PS> $VirtualServerRules = New-Object -TypeName "iControl.LocalLBVirtualServerVirtualServerRule[][]" 1,1 PS> $VirtualServerRules[0][0] = $VirtualServerRule PS> PS> # Call add_rule to add the iRule to the specified virtual servers resource list. PS> $ic.LocalLBVirtualServer.add_rule( (,"virtual_name"), $VirtualServerRules ) PS> PS> # Call get_rule to make sure the add_rule call worked. PS> $ic.LocalLBVirtualServer.get_rule( (,"virtual_name") ) | format-list rule_name : MyCoolRule priority : 500 Conclusion While the iRule Editor makes this easy to do on a single system, there may be a time when you need to deploy an iRule to multiple systems and an automated approach sounds more appealing than the manual effort required for mass deployment. In this case, whip out your favorite programming language, spend a couple of minutes building a solution, click "GO" and grab a cup of coffee and relax. Get the Flash Player to see this player.799Views0likes1CommentTest Lab Guide: Demonstrate the F5 Networks BIG-IP Load Balancer for SharePoint Server 2010
**Many thanks to F5's Helen Johnson and Microsoft engineers Joe Davies and Craig Schwandt for putting this guide together!** Introduction Applications running across networks encounter a wide range of performance, security, and availability challenges. These problems cost organizations an enormous amount in lost productivity, missed opportunities, and damage to reputation. The BIG-IP product family is a system of integrated application delivery services that work together on the same best-in-class hardware. From load balancing, SSL offload, and web acceleration to network security, application security, access control, and much more, the BIG-IP system creates an agile infrastructure to ensure your applications are awlays fast, secure, and available. The modular BIG-IP system is built on the TMOS platform, which offers tremendous scalability and customization. You can start with one specific function to meet your current business needs and budget, and add more capacity and functionality as your application and business demands change. With TMOS, you gain the adaptability to adjust to network conditions and business policies using iControl, F5’s highly versatile open API, and iRules, the F5 custom, event-driven scripting language. You also get a unique, application-centric view of your infrastructure with powerful iApps features. iApps enables you to deploy and manage network services for each of your specific applications with unprecedented speed and accuracy. In addition, TMOS also gives you unique ScaleN functionality, which enables you to virtualize, scale up, or scale out on demand as your business needs change. The BIG-IP product family gives you granular control, scalability, and flexibility that are not available with other traffic management technologies. In this guide This paper contains instructions for setting up a test lab that demonstrates F5 BIG-IP load balancing for SharePoint Server 2010 based on the Test Lab Guide: Configure SharePoint Server 2010 in a Three-Tier Farm. Important The following instructions are for configuring a BIG-IP test lab by using the minimum number of computers in a virtualizaed environment. Individual computers are needed to separate the services provided on the network and to clearly show the desired functionality. This configuration is neither designed to reflect best practices nor does it reflect a desired or recommended configuration for a production network. The configuration, including IP addresses and all other configuration parameters, is designed only to work on a separate test lab network. Attempting to adapt this test lab configuration to a pilot or production deployment can result in configuration or functionality issues. Test lab overview In this virtualized test lab, BIG-IP load balancing functionality for SharePoint Server 2010 is deployed with: · One computer, named DC1, that runs Windows ® Server ® 2008 R2 Enterprise Edition and that is configured as an intranet domain controller, Domain Name System (DNS) server, DHCP server, and enterprise root certification authority (CA). · One intranet member server, named SQL1, that runs Windows Server 2008 R2 Enterprise Edition and is configured as a SQL database server. · One intranet member server, named APP1, that runs Windows Server 2008 R2 Enterprise Edition and is configured as the SharePoint Server 2010 application server. · One intranet member server, named WFE1, that runs Windows Server 2008 R2 Enterprise Edition and is configured as a SharePoint Web front-end server. · One intranet member server, named WFE2, that runs Windows Server 2008 R2 Enterprise Edition and is configured as a SharePoint Web front-end server. · One member client computer, named CLIENT1, that runs Windows 7 Enterprise or Ultimate. · One virtualized BIG-IP load balancer named BIGIP1. The BIG-IP test lab consists of a single subnet named Corpnet (10.0.0.0/24) that simulates a private intranet. Computers and the BIP-IP virtualized device on the Corpnet subnet connect by using a hub or switch. See the following figure. Hardware and software requirements The following are required components of the test lab: · The product disc or files for Windows Server 2008 R2. For an evaluation copy of Windows Server 2008 R2 Enterprise Edition in download and virtual hard disk (VHD) form, see Windows Server 2008 R2 Evaluation Free 180-Day Trial (http://go.microsoft.com/fwlink/?LinkID=102582). · The product disc or files for Windows 7. · The product disc or files for Microsoft SQL Server 2008 R2. See SQL Server 2008 R2 Trial for a trial version of Microsoft SQL Server 2008 R2. · The product disc or files for SharePoint Server 2010. See Download SharePoint 2010 Trial for a trial version of SharePoint Server 2010 (for example, choose the SharePoint Server 2010 Enterprise Client Access License features version on the Download Microsoft SharePoint Server 2010 web page). · Five computers that meet the minimum hardware requirements for Windows Server 2008 R2 Enterprise Edition. For more information, see Windows Server 2008 System Requirements. · One computer that meets the minimum hardware requirements for Windows 7 Enterprise or Ultimate. For more information, see Windows 7 system requirements. · An instance of the F5 BIG-IP LTM VE Edition (http://downloads.f5.com). Steps for Configuring the BIP-IP Load Balancing for SharePoint Server 2010 Test Lab There arefive steps to follow when setting up the BIG-IP load balancing for SharePoint server 2010 test lab. 1. Set up the SharePoint Server 2010 3-tier farm test lab. 2. Install and configure a new server named WFE2. 3. Install SharePoint Server 2010 on WFE2. 4. Set up the BIG-IP LTM VE. 5. Configure and demonstrate BIG-IP load balancing for SharePoint. Note You must be logged on as a member of the Domain Admins group or a member of the Administrators group on each computer to complete the tasks described in this guide. If you cannot complete a task while you are logged on with an account that is a member of the Administrators group, try performing the task while you are logged on with an account that is a member of the Domain Admins group. The following sections provide details about how to perform these steps. Step 1: Set up the SharePoint Server 2010 3-tier Farm Test Lab Set up the SharePoint Server 2010 3-tier farm test lab by using the procedures in the Test Lab Guide: Configure SharePoint Server 2010 in a Three-Tier Farm.757Views0likes2CommentsiControl 101 - #20 - Port Lockdown
A Self IP address is an IP address that you associate with a VLAN, to access hosts in that VLAN. By virtue of its netmask, a self IP address represents an address space, that is, a range of IP addresses spanning the hosts in the VLAN, rather than a single host address. You can associate self IP addresses not only with VLANs, but also with VLAN group. Self IP addresses serve two purposes. First, when sending a message to a destination server, the BIG-IP system uses the self IP addresses of its VLANs to determine the specific VLAN in which a destination server resides. Second, a self IP address serves as the default route for each destination server in the corresponding VLAN. In this case, the self IP address of a VLAN appears as the destination IP address in the packet header when the server sends a response to the BIG-IP system. Each self IP address has a feature known as port lockdown. Port lockdown is a security feature that allows you to specify particular UDP and TCP protocols and services from which the self IP address can accept traffic. This article will dicuss how to use the iControl API to manage Port Lockdown Access Lists. Usage The following code samples will build a PowerShell command line application allowing control over Self IP access lists. This program takes as input the bigip, username, and password as well as a subcommand and optional parameters. Usage is displayed with the Write-Usage function. param ( $g_bigip = $null, $g_uid = $null, $g_pwd = $null, $g_cmd = $null, $g_selfip = $null, $g_arg1 = $null, $g_arg2 = $null, $g_arg3 = $null, $g_arg4 = $null ); Set-PSDebug -strict; function Write-Usage() { Write-Host @" Usage: SelfIPPortLockdown.ps1 host uid pwd [options] options ------- list - Get a list of Self IPs getaccesslist <selfip> - Gets the access lists for the specified self IP. addaccesslist <selfip> <mode> <protocol> <port> - Adds the list of access methods, with optional protocols/ports, for the specified self IP. deleteaccesslist <selfip> <mode> <protocol> <port> - Deletes protocols and ports from the allow access list for the specified self IP. getdefaccesslist - Gets the default protocol/port access list on which access is allowed. adddefaccesslist <protocol> <port> - Adds to the default list of protocols/ports on which access is allowed. removedefaccesslist <protocol> <port> - Remove protocols and ports from the default list of protocols/ports on which access is allowed. "@; exit; } Initialization As is with all of my iControl PowerShell scripts, validation is made as to whether the iControlSnapin is loaded into the current powershell context. The Initialize-F5.iControl cmdlet is then called to setup the connection to the BIG-IP for subsequent calls. The main application logic checks for the passed in command and then passes control to one of the location functions defined below. function Do-Initialize() { if ( (Get-PSSnapin | Where-Object { $_.Name -eq "iControlSnapIn"}) -eq $null ) { Add-PSSnapIn iControlSnapIn } $success = Initialize-F5.iControl -HostName $g_bigip -Username $g_uid -Password $g_pwd; return $success; } #------------------------------------------------------------------------- # Main Application Logic #------------------------------------------------------------------------- if ( ($g_bigip -eq $null) -or ($g_uid -eq $null) -or ($g_pwd -eq $null) ) { Write-Usage; } if ( Do-Initialize ) { switch ($g_cmd) { "" { Get-SelfIPList; } "getaccesslist" { Get-AccessList $g_selfip; } "addaccesslist" { Add-AccessList $g_selfip $g_arg1 $g_arg2 $g_arg3 $g_arg4; } "deleteaccesslist" { Delete-AccessList $g_selfip; } "getdefaccesslist" { Get-DefaultAccessList $g_selfip; } "adddefaccesslist" { Add-DefaultAccessList $g_selfip $g_arg1 $g_arg2; } "removedefaccesslist" { Remove-DefaultAccessList $g_selfip $g_arg1 $g_arg2; } default { Write-Usage; } } } else { Write-Error "ERROR: iControl subsystem not initialized" } Getting a List of Self IP Addresses If you don't know the configured Self IP addresses on your system, you can retrieve them with the iControl Networking.SelfIP.get_list() method. The Get-SelfIPList function calls this iControl method and prints out the Self IP addresses returned from the iControl call. function Get-SelfIPList() { $ip_list = (Get-F5.iControl).NetworkingSelfIP.get_list(); Write-Host "Available SelfIPs:"; foreach ($ip in $ip_list) { Write-Host " $ip"; } } PS C:\> .\SelfIPPortLockdown.ps1 bigip username password Available SelfIPs: 10.10.10.1 20.20.20.1 Querying the Port Lockdown Access Lists for a Self IP Now that you have the Self IP address you want to work on, you can use the Get-AccessList local function to call the iControl Networking.SelfIPPortLockdown.get_allow_access_list() method This takes as input an array of Self IP addresses and returns the associated Port Lockdown settings. In my example, I do not have a Port Lockdown configured for my Self IP so it returns a Port Lockdown mode of ALLOW_MODE_ALL which means that all traffic is allowed on that Self IP. function Get-AccessList() { param([string]$selfip = $null); $pld = (Get-F5.iControl).NetworkingSelfIPPortLockdown; $SelfIPAccessA = $pld.get_allow_access_list( (,$selfip) ); foreach ($SelfIPAccess in $SelfIPAccessA) { Write-Host "--------------------------------"; Write-Host "Self IP : " $SelfIPAccess.self_ip; Write-Host "Mode : " $SelfIPAccess.mode; Write-Host "Protocol Ports : "; $pA = $SelfIPAccess.protocol_ports; foreach ($ProtocolPort in $pA) { Write-Host " Protocol : " $ProtocolPort.protocol; Write-Host " Port : " $ProtocolPort.port; } } } PS C:\> .\SelfIPPortLockdown.ps1 bigip username password getaccesslist 10.10.10.1 -------------------------------------- Self IP : 10.10.10.1 Mode : ALLOW_MODE_ALL Protocol Ports : Adding a Port Lockdown to a Self IP The local Add-AccessList function takes as input a Self IP address, a Port Lockdown mode, a Protocol type, and a port to lockdown. The available Allow Modes are: ALLOW_MODE_PROTOCOL_PORT - Access to the Self IP is allowed through the specified protocol/port. ALLOW_MODE_NONE - Allow no access to the Self IP. ALLOW_MODE_DEFAULTS - Allow access ot the Self IP using a pre-determined set of protocols/ports. ALLOW_MODE_ALL - Allow full access to the Self IP. And the Protocol types are: PROTOCOL_ANY - Wildcard protocol. PROTOCOL_IPV6 - IPv6 header. PROTOCOL_ROUTING - Routing header. PROTOCOL_NONE - Next header. PROTOCOL_FRAGMENT - Fragment header. PROTOCOL_DSTOPTS - Destination options. PROTOCOL_TCP - TCP protocol. PROTOCOL_UDP - UCP protocol. PROTOCOL_ICMP - ICMP protcool. PROTOCOL_ICMPV6 - ICMPv6 protocol. PROTOCOL_OSPF - OSPF protocol. PROTOCOL_SCTP - SCTP protocol. In the below example I'll add a TCP port 44 Allow. function Add-AccessList() { param( [string]$selfip = $null, [string]$mode = "ALLOW_MODE_NONE", [string]$protocol = "PROTOCOL_ANY", [int]$port = 0); $pld = (Get-F5.iControl).NetworkingSelfIPPortLockdown; $SelfIPAccess = New-Object -TypeName iControl.NetworkingSelfIPPortLockdownSelfIPAccess; $SelfIPAccess.self_ip = $selfip; $SelfIPAccess.mode = $mode; $SelfIPAccess.protocol_ports = New-Object -TypeName iControl.NetworkingSelfIPPortLockdownProtocolPort; $(${SelfIPAccess}.protocol_ports).protocol = $protocol; $(${SelfIPAccess}.protocol_ports).port = $port; $pld.add_allow_access_list( (,$SelfIPAccess) ); Get-AccessList $selfip; } PS C:\> .\SelfIPPortLockdown.ps1 bigip username password addaccesslist 10.10.10.1 ALLOW_MODE_PROTOCOL_PORT PROTOCOL_TCP 44 -------------------------------------- Self IP : 10.10.10.1 Mode : ALLOW_MODE_PROTOCOL_PORT Protocol Ports : Protocol : PROTOCOL_ANY Port : 0 Protocol : PROTOCOL_TCP Port : 44 Deleting a Port Lockdown From a Self IP If you want to add a Port Lockdown, you will likely want to delete one as well. The Delete-AccessList list function takes the same parameters as the Add-AccessList function and it calls the iControl Networking.SelfIPPortLockdown.delete_allow_access_list() method to remove the Port Lockdown settings from the specified Self IP. You'll notice that by removing the last Port Lockdown on a Self IP, the mode will be set to ALLOW_MODE_NONE allowing no traffic on the Self IP. To re-enable traffic on the Self IP, you'll need to add another Port Lockdown with the ALLOW_MODE_ALL mode. function Delete-AccessList() { param( [string]$selfip = $null, [string]$mode = "ALLOW_MODE_NONE", [string]$protocol = "PROTOCOL_ANY", [int]$port = 0); $pld = (Get-F5.iControl).NetworkingSelfIPPortLockdown; $SelfIPAccess = New-Object -TypeName iControl.NetworkingSelfIPPortLockdownSelfIPAccess; $SelfIPAccess.self_ip = $selfip; $SelfIPAccess.mode = $mode; $SelfIPAccess.protocol_ports = New-Object -TypeName iControl.NetworkingSelfIPPortLockdownProtocolPort; $(${SelfIPAccess}.protocol_ports).protocol = $protocol; $(${SelfIPAccess}.protocol_ports).port = $port; $pld.delete_allow_access_list( (,$SelfIPAccess) ); Get-AccessList $selfip; } PS C:\> .\SelfIPPortLockdown.ps1 bigip username password deleteaccesslist 10.10.10.1 ALLOW_MODE_PROTOCOL_PORT PROTOCOL_TCP 44 -------------------------------------- Self IP : 10.10.10.1 Mode : ALLOW_MODE_NONE PS C:\> .\SelfIPPortLockdown.ps1 bigip username password addaccesslist 10.10.10.1 ALLOW_MODE_ALL PROTOCOL_TCP 0 -------------------------------------- Self IP : 10.10.10.1 Mode : ALLOW_ALL Querying the Default Port Lockdown Access List Above, I mentioned that you can configure a Port Lockdown on a Self IP to mode ALLOW_MODE_DEFAULTS. These default settings can be queried with the iControl Networking.SelfIPPortLockdown.get_default_protocol_port_access_list() method. The local Get-DefaultAccessList function calls this iControl command and prints out all the default Protocol Port allow lists. function Get-DefaultAccessList() { $pld = (Get-F5.iControl).NetworkingSelfIPPortLockdown; $ProtocolPortA = $pld.get_default_protocol_port_access_list(); if ( $ProtocolPortA.Length ) { foreach ($ProtocolPort in $ProtocolPortA) { Write-Host "--------------------------------"; Write-Host "Protocol : " $ProtocolPort.protocol; Write-Host " Port : " $ProtocolPort.port; } } else { Write-Host "No default Protocol Port Access Lists defined"; } } PS C:\> .\SelfIPPortLockdown.ps1 bigip username password getdefaccesslist No default Protocol Port Access Lists defined. Adding a Default Port Lockdown Access List The local Add-DefaultAccessList function takes as input a Protocol Type and Port and then calls the iControl Networking.SelfIPPortLockdown.add_default_protocol_port_access_list() method. In my example I add a default allow list of PROTOCOL_TCP on Port 44. function Add-DefaultAccessList() { param([string]$protocol = "PROTOCOL_ANY", [int]$port = 0); $pld = (Get-F5.iControl).NetworkingSelfIPPortLockdown; $protocol_port = New-Object -TypeName iControl.NetworkingSelfIPPortLockdownProtocolPort; $protocol_port.protocol = $protocol; $protocol_port.port = $port; $pld.add_default_protocol_port_access_list( (,$protocol_port) ); Get-DefaultAccessList; } PS C:\> .\SelfIPPortLockdown.ps1 bigip username password adddefaccesslist PROTOCOL_TCP 44 --------------------------------- Protocol : PROTOCOL_TCP Port : 44 Removing a Default Port Lockdown Access List If you have a default Port Lockdown Access List that you no longer need, you can remove it with the iControl Networking.SelfIPPortLockdown.remove_default_protocol_port_access_list() method. function Remove-DefaultAccessList() { param([string]$protocol = "PROTOCOL_ANY", [int]$port = 0); $pld = (Get-F5.iControl).NetworkingSelfIPPortLockdown; $protocol_port = New-Object -TypeName iControl.NetworkingSelfIPPortLockdownProtocolPort; $protocol_port.protocol = $protocol; $protocol_port.port = $port; $pld.remove_default_protocol_port_access_list( (,$protocol_port) ); Get-DefaultAccessList; } PS C:\> .\SelfIPPortLockdown.ps1 bigip username password removedefaccesslist No default Protocol Port Access Lists defined. Conclusion Now you have all the tools you need to automate the management of you Port Lockdown Access Lists on your BIG-IP. The full application can be found in the iControl CodeShare under PsSelfIPPortLockdown. Get the Flash Player to see this player. 20090115-iControl101_20_PortLockdown.mp3738Views0likes0Comments