series-icontrol-101
20 TopicsiControl 101 - #06 - File Transfer APIs
The main use we see for iControl applications is with the automation of control features such as adding, removing, enabling, and disabling objects. Another key step in multi-device management is the automation of applying hotfixes and other software updates as well as the downloading of configurations for archival and disaster recovery purposes. iControl has a set of methods that enable the uploading and downloading of files for these purposes. This article will discuss these "file transfer" APIs and how you can use them for various management purposes. The File Transfer APIs The API methods uses to transfer files to and from the device can be found in the System::ConfigSync interface. You may ask: Why are they ConfigSync interface? The answer is quite simple actually. In our first version of iControl, we had the need to transfer configurations across devices in a HA pair as part of the Configuration Sync process. So in doing so, we introduced the upload_configuration() and download_configuration() methods. When we later added more generic file transfer APIs, it seemed logical to place them next to the pre-existing configuration transfer methods. So, that's the reason... The following methods are used to download content: FileTransferContext System::ConfigSync::download_configuration( in String config_name, in long chunk_size, inout long file_offset ); FileTransferContext System::ConfigSync::download_file( in String file_name, in long chunk_size, inout long file_offset ); And the following two methods are used to upload content: void System::ConfigSync::upload_configuration( in String config_name, in System::ConfigSync::FileTransferContext file_context ); void System::ConfigSync::upload_file( in String file_name, in System::ConfigSync::FileTransferContext file_context ); The above methods use the following enum and structure as part of the control enum Common::FileChainType { FILE_UNDEFINED = 0 FILE_FIRST = 1, FILE_MIDDLE = 2, FILE_UNUSED = 3, FILE_LAST = 4, FILE_FIRST_AND_LAST }; struct System.::ConfigSync::FileTransferContext { char [] file_data, Common::FileChainType chain_type }; Chunks Due to the limitations with SOAP's with regards to payload and processing of large messages, we designed the file transfer APIs to work in "chunks". This means that for a multi-megabyte file, you a loop in your code to send up "chunks" in whatever chunk sizes you wish from 1 byte to 100's of Ks. We recommend not getting too extreme on either end of the chunk size ranges. Typically we recommend 64 to 256k per chunk. How to use the download methods. The process for downloading content is fairly straightforward. In this example, we'll use the download_configuration method. 1. Make a call to the download_configuration method with a given configuration name (a list of existing configurations can be returned from ConfigSync::get_configuration_list) with the requested chunk_size (ie 64k) and the starting file_offset of 0. 2. The first response will come back in the FileTransferContext with the data and the FileChainType describing whether this was the first chunk, a middle chunk, the last chunk, or the first and last chunk. 3. take the encoded data stored in the FileTransferContext.file_data array and save it locally. 4. If the FileChainType is FILE_LAST or FILE_FIRST_AND_LAST, you are done. 5. Otherwise, use the incremented file_offset go to step #1. The following snippet of code taken from the iControl SDK's ConfigSync C# sample application illustrates how to deal with downloading a file with an unknown size. void handle_download(string config_name, string local_file) { ConfigSync.SystemConfigSyncFileTransferContext ctx; long chunk_size = (64*1024); long file_offset = 0; bool bContinue = true; FileMode fm = FileMode.CreateNew; if ( File.Exists(local_file) ) { fm = FileMode.Truncate; } FileStream fs = new FileStream(local_file, fm); BinaryWriter w = new BinaryWriter(fs); while ( bContinue ) { ctx = ConfigSync.download_configuration(config_name, chunk_size, ref file_offset); // Append data to file w.Write(ctx.file_data, 0, ctx.file_data.Length); Console.WriteLine("Bytes Transferred: " + file_offset); if ( (CommonFileChainType.FILE_LAST == ctx.chain_type) || (CommonFileChainType.FILE_FIRST_AND_LAST == ctx.chain_type) ) { bContinue = false; } } w.Close(); } How to use the upload methods The upload methods work in a similar way but in the opposite direction. To use the upload_configuration configuration method, you would use the following logic. 1. Determine the chunk size you are going to use (64k - 256k recommended) and fill the file_data array with the first chunk of data. 2. Set the FileChainType to FILE_TYPE_FIRST_AND_LAST if all your data can fit in the first chunk size. 3. Set the FileChainType to FILE_FIRST if you fill up the data with your chunk size and there is more data to follow. 4. Make a call to upload_configuration with the configuration name and the FileTransferContext with the data and the FileChainType. 5. If the data has all been sent, stop processing. 6. Else if the remaining data will able to fit in the given chunk size, set the FileChainType to FILE_LAST, otherwise set it to FILE_MIDDLE. 7. Fill the file_data with the next chunk of data. 8. Goto Step #4. The following example taken from the iControl SDK ConfigSync perl sample and illustrates taking a local configuration file and uploading it to the device. sub uploadConfiguration() { my ($localFile, $configName) = (@_); $success = 0; $bContinue = 1; $chain_type = $FILE_FIRST; $preferred_chunk_size = 65536; $chunk_size = 65536; $total_bytes = 0; open(LOCAL_FILE, "<$localFile") or die("Can't open $localFile for input: $!"); binmode(LOCAL_FILE); while (1 == $bContinue ) { $file_data = ""; $bytes_read = read(LOCAL_FILE, $file_data, $chunk_size); if ( $preferred_chunk_size != $bytes_read ) { if ( $total_bytes == 0 ) { $chain_type = $FILE_FIRST_AND_LAST; } else { $chain_type = $FILE_LAST; } $bContinue = 0; } $total_bytes += $bytes_read; $FileTransferContext = { file_data => SOAP::Data->type(base64 => $file_data), chain_type => $chain_type }; $soap_response = $ConfigSync->upload_configuration ( SOAP::Data->name(config_name => $configName), SOAP::Data->name(file_context => $FileTransferContext) ); if ( $soap_response->fault ) { print $soap_response->faultcode, " ", $soap_response->faultstring, "\n"; $success = 0; $bContinue = 0; } else { print "Uploaded $total_bytes bytes\n"; $success = 1; } $chain_type = $FILE_MIDDLE; } print "\n"; close(LOCAL_FILE); return $success; } Other methods of data transfer The two methods illustrated above are specific to system configurations. The more generic upload_file() and download_file() commands may be used to do things like backing up other system files as well as, but not limited to, uploading hotfixes to be later installed with the System::SoftwareManagement::install_hotfix() method. The usage of those methods is identical to the configuration transfer methods except in the fact that the config_name parameter is now replaced with a fully qualified file system name. Note that there are some restrictions as to the file system locations that are readable and writable. You wouldn't want to accidentally overwrite the system kernel with your latest hotfix would you? Conclusion Hopefully this article gave you some insights on how to use the various file transfer APIs to manipulate file system content on your F5 devices. Get the Flash Player to see this player.879Views0likes2CommentsiControl 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.1KViews0likes5CommentsiControl 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.mp31.1KViews0likes1CommentiControl 101 - #14 - License Administration
An important aspect of system management is maintaining the licenses on the devices you are responsible for. The BIG-IP includes a programmatic interface to allow you to query the current license information and upload and apply new licenses to the device allowing the automation of this management task. This article will discuss the Management.LicenseManagement interface in the iControl API and how you can use it to keep your BIG-IP's license up to date. 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> $LA = (Get-F5.iControl).ManagementLicenseAdministration PS> $ASCII = New-Object -TypeName System.Text.ASCIIEncoding Is the device licensed? The first step will be to determine whether the device has been licensed. If not, the likely you'll know about it as you won't be able to make use of most of the features since they will be disabled. The get_license_activation_status() method returns an EnabledState enumeration to let you know whether the device has been licensed. You'll see from the following response that my device has indeed been licensed. PS> $LA.get_license_activation_status() STATE_ENABLED Is the device in an evaluation mode? Once you know that the device has been licensed, The next step will be to determine whether your device is under an evaluation license. Whether you are giving BIG-IP a test drive or are, like me, running a developer license, then you'll want to double check that you are running under an evaluation license. The is_evaluation_license() method returns a boolean value of true or false depending on whether the current license is an evaluation or not. You will see below that my BIG-IP is indeed under evaluation. PS> $LA.is_evaluation_license() True License Expiration The next thing you are likely to ask is when your evaluation license is set to expire. Never fear, the get_evaluation_license_expiration() method will return the current system time as well as the start time for the evaluation and the date and time the license is set to expire. This example shows that my license is set to expire at 1210752000. PS> $EvaluationExpiration = $LA.get_evaluation_license_expiration() PS> $EvaluationExpiration | fl current_system_time : 1210257101 evaluation_start : 1170662400 evaluation_expire : 1210752000 What? You don't know how to do conversion from the number of seconds elapsed since 00:00:00 on January 1, 1970 coordinated Universal Time? That can be corrected by creating a DateTime object based on 12:00am Jan 1, 1970 and then adding the values as seconds. Then, since the time is in Universal Time, you'll want to adjust the GMT time that your BIG-IP is located at. The GMT offset can be retrieved from the System.SystemInfo.get_time_zone() method. The following code will take the previous values and perform the conversions to correctly reflect the local time on the BIG-IP. PS> $origin = [DateTime]::Parse("Jan 1, 1970 12:00:00AM") PS> $gmt_offset = ((Get-F5.iControl).SystemSystemInfo.get_time_zone()).gmt_offset PS> $origin.AddSeconds($EvaluationExpiration.current_system_time).AddHours($gmt_offset) Thursday, May 08, 2008 2:51:09 PM PS> $origin.AddSeconds($EvaluationExpiration.evaluation_start).AddHours($gmt_offset) Monday, February 05, 2007 8:00:00 AM PS> $origin.AddSeconds($EvaluationExpiration.evaluation_expire).AddHours($gmt_offset) Wednesday, May 14, 2008 8:00:00 AM Other Misc methods that may be of interest are the get_copyright_file(), get_eula_file(). The following example uses the ASCII Encoding to convert the returned byte array from the get_copyright_file() method into a string and displays the contents. If you want the eula contents, then replace the method call with get_eula_file(). PS> $ASCII.GetString($LA.get_copyright_file()) Begin F5 Networks, Inc. Copyright --------------------------------------- All of the documentation and software included in this product release is copyrighted by F5 Networks, Inc., except where explicitly noted. ... The installed License File Have you ever wondered what the license file looks like once you have one? Well, the get_license_file() method will return the contents of the current license file. Again, make sure you convert the returned array of bytes into an ASCII string. PS> $ASCII.GetString($LA.get_license_file()) # Auth vers : 5b # # # BIG-IP System License Key File # DO NOT EDIT THIS FILE!! ... Registration Keys Part of the licensing process is the set of registration keys that control the basic features that you are having licensed. The get_registration_keys() method will return a string array of registration keys that you have configured on the device. PS> $keys = $LA.get_registration_keys() PS> $keys J9Q42-63R73-8S271-91217-3682254 O102366-9462636 O914836-9853398 E169309-8947262 E065642-5132297 System Dossier Like James Bond has when he's investigating the bad guys, each system has a unique dossier that identifies the system with all of it's features. This dossier is used to generate new licenses through the F5 license server. The get_system_dossier() method will return this dossier which is an encrypted string. Before passing registration keys to this method, it's likely a good idea to check if the crc checksum passes for each of the registration keys. This can be done with the check_registration_key_crc() method which takes as input an array of strings containing the registration keys and returns an array of boolean values indicating whether the keys passed a checksum validation. PS> $LA.check_registration_key_crc($keys) True True True True True PS> $LA.get_system_dossier($keys) 5475f4c659b69f8ef875d54b2b956181cfd9d5fc25d27460a8dff1ad9717255a8944604e4155636b084a0f6b007... Licensing your system F5 has a licensing server at activate.f5.com. You'll have to login to that site with a browser, enter the previous dossier and go through the activation process to get an updated license file. Once you have that license file, you can use that in the install_license() method to activate your system. Remember that this method takes an array of bytes as input so you'll need to convert the string into the byte array before making the method call. PS> $lic = Get-Content c:\temp\bigip_license.txt PS> $LA.install_license($ASCII.GetBytes($lic)) Conclusion Now you have all the tools you need to automate the licensing of your systems. Get the Flash Player to see this player. 20080508-iControl101_14_LicenseAdministration.mp3576Views0likes1CommentiControl 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.832Views0likes2CommentsiControl 101 - #21 - Rate Classes
The BIG-IP local traffic management system includes a feature called rate shaping which allows you to enforce a throughput policy on incoming traffic. Throughput policies are useful for prioritizing and restricting bandwidth on selected traffic patterns. Rate shaping can be useful for an e-commerce site that has preferred clients and would like to offer higher throughput for preferred customers, and lower throughput for other site traffic. This article will discuss how to create and manage rate classes as well as how to assign them to virtual servers. The rate shaping feature works by first queuing selected packets under a rate class, and then dequeuing the packets at the indicated rate and in the indicated order specified by the rate class. A rate class is a rate-shaping policy that defines throughput limitatations and a packet scheduling method to be applied to all traffic handled by that rate class. Usage The following code samples will build a PowerShell command line application allowing control over Rate Classes. 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_name = $null, $g_arg1 = $null, $g_arg2 = $null, $g_arg3 = $null, $g_arg4 = $null ); Set-PSDebug -strict; #------------------------------------------------------------------------- # function Write-Usage #------------------------------------------------------------------------- function Write-Usage() { Write-Host @" Usage: Rateclass.ps1 host uid pwd [options] options ------- list - Get a list of rate classess create name rate [UNIT_BPS|UNIT_KBPS|UNIT_MBPS] - Create a Rate class with the given max throughput rates. delete name - Delete the specified rate class. setbaserate name rate [UNIT_BPS|UNIT_KBPS|UNIT_MBPS] - Set the maximum throughput to allot to traffic for this rate class. setburstsize name size - Set the maximum number of bytes that traffic is allowed to burst beyond the base rate. setceilingrate name rate [UNIT_BPS|UNIT_KBPS|UNIT_MBPS] - Set how far beyond the base rate the traffic is allowed to flow when bursting. setdirection name [DIRECTION_ANY|DIRECTION_CLIENT|DIRECTION_SERVER] - Set the direction that the rate class is applied. setparent name parent - Set the parent rate class that this class is allowed to borrow from. setqueuetype name [QUEUE_NONE|QUEUE_STOCHASTIC_FAIR|QUEUE_PRIORITY_FIFO] - Set the type of queue used by the specified rate class. setvsrateclass name virtual - Set the rate class for the specified virtual server. removerateclass name virtual - Remove the rate class from the specified virtual server. "@; 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; } if ( ($g_bigip -eq $null) -or ($g_uid -eq $null) -or ($g_pwd -eq $null) ) { Write-Usage; } if ( Do-Initialize ) { switch ($g_cmd) { "" { Get-RateClassList; } "list" { Get-RateClassList $g_name; } "create" { Create-RateClass $g_name $g_arg1 $g_arg2; } "delete" { Delete-RateClass $g_name; } "setbaserate" { Set-RateClassBaseRate $g_name $g_arg1 $g_arg2; } "setburstsize" { Set-RateclassBurstSize $g_name $g_arg1; } "setceilingrate" { Set-RateClassCeilingRate $g_name $g_arg1 $g_arg2; } "setdirection" { Set-RateClassDirection $g_name $g_arg1; } "setparent" { Set-RateClassParent $g_name $g_arg1; } "setqueuetype" { Set-RateClassQueueType $g_name $g_arg1; } "setvsrateclass" { Set-VirtualServerRateClass $g_name $g_arg1; } "removevsrateclass" { Remove-VirtualServerRateClass $g_name $g_arg1; } default { Write-Usage; } } } else { Write-Error "ERROR: iControl subsystem not initialized" } Retrieving Rate Class Information The following function will either query the information about all the rate classes, or if a rate class name is passed in as an argument, it will get the information for just that one. All of the configurable attributes will be displayed. I will discuss each attribute in the following sections below. Finally after the rate class attributes are displayed, I will do a reverse lookup on the Virtual Servers to see if any of them are using the specific rate class. If a Virtual Server is configured with the given rate class, it will be displayed to the user as well. In my example below, you will see that I have no rate classes defined so it will return an empty list. function Get-RateClassList() { param([string]$rc = $null ); if ( $rc ) { $rc_list = ,$rc; } else { $rc_list = (Get-F5.iControl).LocalLBRateClass.get_list(); } $vs_list = (Get-F5.iControl).LocalLBVirtualServer.get_list(); $vsrc_list = (Get-F5.iControl).LocalLBVirtualServer.get_rate_class($vs_list); Write-Host "Rate Classes:"; if ( $rc_list ) { $base_rates = (Get-F5.iControl).LocalLBRateClass.get_base_rate( $rc_list ); $burst_sizes = (Get-F5.iControl).LocalLBRateClass.get_burst_size( $rc_list ); $ceiling_rates = (Get-F5.iControl).LocalLBRateClass.get_ceiling_rate( $rc_list ); $directions = (Get-F5.iControl).LocalLBRateClass.get_direction( $rc_list ); $parents = (Get-F5.iControl).LocalLBRateClass.get_parent( $rc_list ); $queue_types = (Get-F5.iControl).LocalLBRateClass.get_queue_type( $rc_list ); for($i=0; $i -lt $rc_list.Length; $i++) { Write-Host @" -------------------- Rate Class $($rc_list[$i]) Base Rate : $($base_rates[$i].rate) $($base_rates[$i].unit) Burst Size : $($burst_sizes[$i]) Ceiling Rate : $($ceiling_rates[$i].rate) $($ceiling_rates[$i].unit) Direction : $($directions[$i]) Parent : $($parents[$i]) Queue Type : $($queue_types[$i]) "@ Write-Host " Virtuals :"; for($j=0; $j -lt $vsrc_list.Length; $j++) { if ( $vsrc_list[$j] -eq $rc_list[$i] ) { Write-Host " $($vs_list[$j])" } } } } } PS C:\> .\PsRateClass.ps1 bigip user pass Rate Classes: Creating a Rate Class The only attribute needed to create a rate class is the base rate unit. This is defined as a rate value along with a unit of UNIT_BPS, UNIT_KBPS, or UNIT_MBPS for bits per second, kilobits per second, or megabits per second respectively. The following function takes these values as arguments and then call the iControl.LocalLBRateClass.create method with the rate class name along with the rate unit structure. In my example below, a rate class named "myrc" is created with a base rate of 100 megabits per second. You'll see the default values for the other attributes below. Since this is a new rate class, it is not assigned to any virtual servers, so that list will be empty. function Create-RateClass() { param([string]$name = $null, [int]$rate = 0, [string]$unit = "UNIT_BPS"); if ( $name -and $rate ) { $rateunit = New-Object -TypeName iControl.LocalLBRateClassRateUnit; $rateunit.rate = $rate; $rateunit.unit = $unit; (Get-F5.iControl).LocalLBRateClass.create( (,$name), (,$rateunit) ); Write-Host "Rate Class $name created..."; Get-RateClassList $name; } } PS C:\> .\PsRateClass.ps1 bigip user pass create myrc 100 UNIT_MBPS Rate Classes: ------------------- Rate Class myrc Base Rate : 100 UNIT_MBPS Burst Size : 0 Ceiling Rate : 100 UNIT_MBPS Direction : DIRECTION_ANY Parent : Queue Type : QUEUE_STOCHASTIC_FAIR Virtuals : Deleting a Rate Class Well, if you want to create a rate class, it make sense that you may want to delete one. This can be done with the local Delete-RateClass function. It just takes the name of a rate class and calls the iControl.LocalLBRateClass.delete_rate_class() method. The Get-RateClass function is then called to list out the remaining rate classes. function Delete-RateClass() { param([string]$name = $null); if ( $name ) { (Get-F5.iControl).LocalLBRateClass.delete_rate_class( (,$name) ); Write-Host "Rate Class $name deleted..."; Get-RateClassList; } } PS C:\> .\PsRateClass.ps1 bigip user pass delete myrc ------------------ Rate Classes: Assigning the Rate Class Base Rate The base rate specifies the throughput rate allowed for traffic that the rate class handles. Packets are generally not allowed to exceed the specified rate. You can use the iControl.LocalLBRateClass.set_base_rate() method to assign a new base rate to a rate class. You'll notice that this method is very similar to the create() method illustrated above. In the below example, I'll change the previously defined base rate of 100 mbps to 100 kbps. Notice that the base rate is changed but the ceiling rate remains the original value. To update the ceiling rate, you will need to modify that separately as described below. function Set-RateClassBaseRate() { param([string]$name = $null, [int]$rate = 0, [string]$unit = "UNIT_BPS"); if ( $name -and $rate ) { $rateunit = New-Object -TypeName iControl.LocalLBRateClassRateUnit; $rateunit.rate = $rate; $rateunit.unit = $unit; (Get-F5.iControl).LocalLBRateClass.set_base_rate( (,$name), (,$rateunit) ); Get-RateClassList $name; } } PS C:\> .\PsRateClass.ps1 bigip user pass setbaserate 100 UNIT_KBPS Rate Classes: -------------------- Rate Class myrc Base Rate : 100 UNIT_KBPS Burst Size : 0 Ceiling Rate : 100 UNIT_MBPS Direction : DIRECTION_ANY Parent : Queue Type : QUEUE_STOCHASTIC_FAIR Virtuals : Assigning a Burst Size The burst size is the maximum number of bytes that traffic is allowed to burst beyond the base rate, before needing to borrow bandwidth. When this value is set to 0, no bursting is allowed. You use the burst size setting when you want to allow the rate of traffic flow that a rate class controls to exceed the base rate. Exceeding the base rate is known as bursting. When you configure a rate class to allow bursting, the BIG-IP system saves any unused bandwidth and uses that bandwidth later to enable the rate of traffic to flow to temporarily exceed the base rate. Specifying a burst size is useful for smoothing out traffic patterns that tend to fluctuate or exceed the base rate such as HTTP traffic. The following function allows you to set the burst rate (in bytes) by calling the iControl.LocalLBRateClass.set_burst_size() method. I will set the burst rate to 1000 bytes for the previously defined rate class. function Set-RateClassBurstSize() { param([string]$name = $null, [int]$size = 0); if ( $name -and $size ) { (Get-F5.iControl).LocalLBRateClass.set_burst_size( (,$name), (,$size) ); Get-RateClassList $name; } } PS C:\> .\PsRateClass.ps1 bigip user pass setburstsize myrc 1000 Rate Classes: -------------------- Rate Class myrc Base Rate : 100 UNIT_KBPS Burst Size : 1000 Ceiling Rate : 100 UNIT_MBPS Direction : DIRECTION_ANY Parent : Queue Type : QUEUE_STOCHASTIC_FAIR Virtuals : Setting the Ceiling Rate The ceiling rate setting specifies the absolute limit at which traffic is allowed to flow when bursting or borrowing. Just like for the base rate, you can specify the ceiling rate in bits per second, kilobits per second, or megabits per second. The ceiling rate must be equal to or greater than the base rate. If the ceiling rate equals the base rate, traffic throughput can never exceed the base rate. The Set-RateClassCelingRate function takes as input the rate class name along with a ceiling rate and unit and then calls the iControl.LocalLBRateClass.set_ceiling_rate() method with those parameters. The Get-RateClass function is then called to show that the changes took effect. function Set-RateClassCeilingRate() { param([string]$name = $null, [int]$rate = 0, [string]$unit = "UNIT_BPS"); if ( $name -and $rate ) { $rateunit = New-Object -TypeName iControl.LocalLBRateClassRateUnit; $rateunit.rate = $rate; $rateunit.unit = $unit; (Get-F5.iControl).LocalLBRateClass.set_ceiling_rate( (,$name), (,$rateunit) ); Get-RateClassList $name; } } PS C:\> .\PsRateClass.ps1 bigip user pass setceilingrate myrc 1000 UNIT_MBPS Rate Classes: -------------------- Rate Class myrc Base Rate : 100 UNIT_KBPS Burst Size : 1000 Ceiling Rate : 1000 UNIT_MBPS Direction : DIRECTION_ANY Parent : Queue Type : QUEUE_STOCHASTIC_FAIR Virtuals : Setting the Rate Class Direction Using the direction setting, you can apply a rate class to traffic going to a client, to a server, or to both client and server. Specifying direction is useful in cases where the nature of traffic is directionally based. For example, if you offer an FTP service to external clients, you might be more interested in limiting throughput for those clients uploading files to your site than you are for clients downloading files from your site. In this case, you would want a rate class based on traffic going to your server. In the following example, I'll change the direction on this rate class from the default value of DIRECTION_ANY to DIRECTION_SERVER to allow this rate class to only work on traffic going to the destination server. function Set-RateClassDirection() { param([string]$name = $null, [string]$direction = "DIRECTION_ANY"); if ( $name ) { (Get-F5.iControl).LocalLBRateClass.set_direction( (,$name), (,$direction) ); Get-RateClassList $name; } } PS C:\> .\PsRateClass.ps1 bigip user pass setdirection myrc DIRECTION_SERVER Rate Classes: -------------------- Rate Class myrc Base Rate : 100 UNIT_KBPS Burst Size : 1000 Ceiling Rate : 1000 UNIT_MBPS Direction : DIRECTION_SERVER Parent : Queue Type : QUEUE_STOCHASTIC_FAIR Virtuals : Assigning a Rate Class Parent Class When you create a rate class, you can use the Parent Class setting to specify that the rate class has a parent class. This allows the rate class to borrow unused bandwidth from that parent class. A child class can borrow unused bandwidth from its parent, but a parent class cannot borrow from a child class. Borrowing is also not possible between two child classes of the same parent class or between two unrelated rate classes. A parent class can itself have a parent class, provided that you do not create a circular dependency (ie. when a rate class is direct, or indirect, child of itself). The following example will set the parent class of the "myrc" rate class to the rate class "baserc". function Set-RateClassParent() { param([string]$name = $null, [string]$parent = ""); if ( $name ) { (Get-F5.iControl).LocalLBRateClass.set_parent( (,$name), (,$parent) ); Get-RateClassList $name; } } PS C:\> .\PsRateClass.ps1 bigip user pass setparent myrc baserc Rate Classes: -------------------- Rate Class myrc Base Rate : 100 UNIT_KBPS Burst Size : 1000 Ceiling Rate : 1000 UNIT_MBPS Direction : DIRECTION_SERVER Parent : baserc Queue Type : QUEUE_STOCHASTIC_FAIR Virtuals : Setting the Queue Type The Queue Type (or Queue Discipline) setting determines the method and order in which the BIG-IP system dequeues packets. The type can be QUEUE_STOCHASTIC_FAIR or QUEUE_PRIORITY_FIFO. Stochastic Fair Queuing is a queueing method that queues traffic under a set of many lists, choosing the specific list based on a periodically changing hash of the connection information. This results in traffic from the same connection always being queued in the same list. It then dequeues traffic from the set of lists in a round-robin fashion. The overall effect is that fairness of dequeueing is achieved because one high-speed connection cannot monopolize the queue at the expense of slower connections. Priority FIFO is a queueing method that queues all trafffic under a set of five lists based on the Type of Service (ToS) field of the traffic. Four of the lists correspond to the four possible ToS values (Minimum delay, Maximum througput, Maximum reliability, and Minimum cost). the fifth list represents traffic with no ToS value. The PFIFO method then processes these five lists in a way that attempts to preserve the meaning of the ToS field as much as possible. In the following example, I'll set the queue type of the myrc rate class from the default QUEUE_STOCHASTIC_FAIR to QUEUE_PRIORITY_FIFO with the local Set-RateClassQueueType function. This calls the iControl.LocalLBRateClass.set_queue_type() method. function Set-RateClassQueueType() { param([string]$name = $null, [string]$type = "QUEUE_STOCHASTIC_FAIR"); if ( $name ) { (Get-F5.iControl).LocalLBRateClass.set_queue_type( (,$name), (,$type) ); Get-RateClassList $name; } } PS C:\> .\PsRateClass.ps1 bigip user pass setqueuetype myrc QUEUE_PRIORITY_FIFO Rate Classes: -------------------- Rate Class myrc Base Rate : 100 UNIT_KBPS Burst Size : 1000 Ceiling Rate : 1000 UNIT_MBPS Direction : DIRECTION_SERVER Parent : baserc Queue Type : QUEUE_PRIORITY_FIFO Virtuals : Assigning a Rate Class to a Virtual Server Having a rate class is good and all, but it doesn't really do anything until you allow traffic to pass through it. This can be done by assigning it as an attriute to a Virtual Server. The iControl.LocalLBVirtualServer.set_rate_class() takes a list of virtual server name and the corresponding rate class names to assign to those virtual servers. The following example will assign the "myrc" rate class to the Virtual Server "xpbert-http". After the call is made, you will see in the listing that the reverse lookup through the virtual servers showed this rate class was applied to virtual server xpbert-http. function Set-VirtualServerRateClass() { param([string]$name = $null, [string]$vs = $null); if ( $name ) { (Get-F5.iControl).LocalLBVirtualServer.set_rate_class( (,$vs), (,$name) ); Get-RateClassList $name; } } PS C:\> .\PsRateClass.ps1 bigip user pass setvsrateclass myrc xpbert-http Rate Classes: -------------------- Rate Class myrc Base Rate : 100 UNIT_KBPS Burst Size : 1000 Ceiling Rate : 1000 UNIT_MBPS Direction : DIRECTION_SERVER Parent : baserc Queue Type : QUEUE_PRIORITY_FIFO Virtuals : xpbert-http Removing a Rate Class from a Virtual Server There is no corresponding remove_rate_class method in the LocalLBVirtualServer interface. Instead, if you want to remove the rate class, you just pass in an empty string for the rate class name to the set_rate_class() method. The following example will remove the rate class "myrc" from virtual server "xpbert-http"; function Remove-VirtualServerRateClass() { param([string]$name = $null, [string]$vs = $null); if ( $name ) { (Get-F5.iControl).LocalLBVirtualServer.set_rate_class( (,$vs), (,"") ); Get-RateClassList $name; } } PS C:\> .\PsRateClass.ps1 bigip user pass removevsrateclass myrc xpbert-http Rate Classes: -------------------- Rate Class myrc Base Rate : 100 UNIT_KBPS Burst Size : 1000 Ceiling Rate : 1000 UNIT_MBPS Direction : DIRECTION_SERVER Parent : baserc Queue Type : QUEUE_PRIORITY_FIFO Virtuals : Conclusion You know have all the tools you need to create, modify, and apply a rate class to start controlling the traffic flow to and from your servers. The code for this article can be found under the PsRateClass entry in the iControl CodeShare. Get the Flash Player to see this player. 20090122-iControl101_22_RateClass.mp3621Views0likes1CommentiControl 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.829Views0likes1CommentiControl 101 - #24 - Folders
Bucket Way back in time (well, not so way back), configuration objects were stored in one location in the configuration. For the sake of this article, we’ll call this the root “bucket”. This worked fine for small organizations but we found that as companies grew and, as a consequence, the number of applications they needed to support increased, it became more difficult to manage all the objects in a single “bucket”. vs_1 vs_2 pool_1 pool_2 monitor_1 monitor_2 Buckets In BIG-IP version 9.4, we introduced the concept of “Partitions”. With Partitions, you could create additional “buckets” of configuration objects. Each partition could contain objects and have it’s own set of authorization roles protecting them allowing the administrator to group them together and allow each application team to manage those objects without exposing access to objects they weren’t in control of. I discussed this interface in my article titled: iControl 101 - #08 - Partitions. A layout of the previously defined objects could now look like the following: /APP1 vs_1 pool_1 monitor_1 /APP2 vs_2 pool_2 monitor_2 This still has the limitation in that it’s not easy to determine which groupings of objects (APP1, APP2, …) belong together. The next logical extension is to allow arbitrary “buckets” of objects which is what I will talk about for the rest of this article. Buckets of Buckets BIG-IP version 11, introduced the concepts of Folders. Here’s an excerpt from the iControl SDK’s reference page for the Folder interface: A folder stores an arbitrary set of configuration objects. The system uses folders to control access to objects and to control synchronization of these objects within a device group. Folders are organized in a tree heirarchy, much like the folders or directories on a computer's file system. Objects stored in folders are referenced by the name of the individual object, preceded by its folder name, preceded by the names of any parent folders, up to the root folder (/), all separated by slashes (/), e.g., /george/server/virt-a. Note: methods to access the active folder for a session are found in the System::Session interface. So, now we can have the objects look something like this /APPGROUP /APP1 vs_1 pool_1 monitor_1 /APP2 vs_2 pool_2 monitor_2 Since I’m a console-kind-of-guy at heart, and how folders are very similar to directories in a file system, I figured, I’d write a companion sample for this article that emulated a directory shell allowing you to navigate through, create, remove, and modify folders while illustrating how to use the various iControl methods for those tasks. The Application: A Folder Shell I wrote this application in PowerShell, but it could have just as easily been coded in Java, Perl, Python, .Net, or whatever you tend to use with your projects. Let’s take a look at the implementation, the actions that it performs, and some sample output Initialization This application will take only three parameters as input. The address of the BIG-IP, and the username and password for authentication. The main application loop consists of: Verifying the connection information is valid with the code in the Do-Initialize method. Setting the prompt to the users current folder Reading a command from the user and passing it to the Process-Input function described below. param ( $bigip = $null, $uid = $null, $pwd = $null ) Set-PSDebug -strict; # Global Script variables $script:DEBUG = $false; $script:FOLDER = $null; $script:RECURSE = "STATE_DISABLED"; function Do-Initialize() { if ( (Get-PSSnapin | Where-Object { $_.Name -eq "iControlSnapIn"}) -eq $null ) { Add-PSSnapIn iControlSnapIn } $success = Initialize-F5.iControl -HostName $bigip -Username $uid -Password $pwd; return $success; } # Main Application Logic if ( ($bigip -eq $null) -or ($uid -eq $null) -or ($pwd -eq $null) ) { usage; } if ( Do-Initialize ) { $s = Get-RecursiveState; while(1) { $prompt = Get-Prompt; # Not using Read-Host here so we can support responses starting with ! $host.UI.Write($prompt); $i = $host.UI.ReadLine().Trim(); Process-Input $i; } } else { Write-Error "ERROR: iControl subsystem not initialized" } The Main Application Loop The main application loop passes commands to the Process-Input function. A wildcard match is performed against the passed in command and if there is a match, control is passed to the appropriate handler function. I won’t describe them all here but they should be fairly self explanatory. The main types of actions are described in the upcoming sections. function Process-Input() #---------------------------------------------------------------------------- { param($i); Debug-Message "< $($MyInvocation.MyCommand.Name) '$i' >"; if ( $i.Length -gt 0 ) { Debug-Message "CommandLine: '$i'..."; switch -Wildcard ($i.Trim().ToLower()) { "" { break; } "cd *" { Change-Folder (Get-Args $i); } "cd" { Get-CurrentFolder; } "d" { $script:DEBUG = -not $script:DEBUG; } "dir" { Get-ChildFolders | Sort-Object Folder; } "gd *" { Get-FolderDescription (Get-Args $i); } "h" { Show-Help; } "ls" { Get-ChildFolders | Sort-Object Folder; } "ls -l" { Get-ChildFolders -Long | Sort-Object Folder; } "ls -lr" { Get-ChildFolders -Recurse -Long | Sort-Object Folder; } "ls -r" { Get-ChildFolders -Recurse | Sort-Object Folder; } "md *" { Create-Folder (Get-Args $i); } "mkdir *" { Create-Folder (Get-Args $i); } "pwd" { Get-CurrentFolder; } "r" { Set-RecursiveState; } "r *" { Set-RecursiveState (Get-Args $i); } "rd *" { Remove-Folder (Get-Args $i); } "rmdir *" { Remove-Folder (Get-Args $i); } "sd *" { Set-FolderDescription (Get-Args $i); } "q" { exit; } "! *" { Execute-Command (Get-Args $i); } "$*" { Execute-Command $i.SubString(1); } ".." { Move-Up; } default { Show-Help; } } } } Querying The Current Folder The location of the users current, or “active”, folder is determined by calling the System.Session.get_active_folder() method. This is a server side variable that is stored during the lifetime of the iControl Portals instance and tied to the current authenticated user. This Get-CurentFolder function does some internal caching with the $script:FOLDER variable to avoid repetitive calls to the server. The caching can be overridden by passing in the “-Force” argument to the function causing a forced call to query the active folder. The value is then returned to the calling code. function Get-CurrentFolder() { param([switch]$Force = $false); if ( ($($script:FOLDER) -eq $null) -or ($Force) ) { $folder = (Get-F5.iControl).SystemSession.get_active_folder(); } else { $folder = $script:FOLDER; } $folder; } Listing the Child Folders The Get-ChildFolders function has several options you can use with it. If “-Recurse” is passed to the function, the recursive query state is set to STATE_ENABLED telling the server to return all child objects in all child folders relative to the currently active one. This is similar to a “dir /s” on Windows or “ls -r” on Unix. The second parameter is “-Long”. If this is passed in, then a “long” listing will be presented to the user containing the folder name, description, and device group. Folder descriptions are described below while I’m leaving device groups to be a task for the reader to follow up on. The function gathers the requested information and then packs the output into objects and returns them along the PowerShell pipeline to the calling code. function Get-ChildFolders() { param([switch]$Recurse = $false, [switch]$Long = $false); if ( $Recurse ) { $oldstate = (Get-F5.iControl).SystemSession.get_recursive_query_state(); (Get-F5.iControl).SystemSession.set_recursive_query_state("STATE_ENABLED"); } $folders = (Get-F5.iControl).ManagementFolder.get_list(); if ( $Recurse -and ($oldstate -ne "STATE_ENABLED") ) { (Get-F5.iControl).SystemSession.set_recursive_query_state($oldstate); } $descriptions = (Get-F5.iControl).ManagementFolder.get_description($folders); $groups = (Get-F5.iControl).ManagementFolder.get_device_group($folders); $curfolder = Get-CurrentFolder; if ( $curfolder -eq "/" ) { $curfolder = "ZZZZZZZZ"; } for($i=0;$i-lt$folders.length;$i++) { if ( $Long ) { $o = 1 | select "Folder", "Description", "DeviceGroup"; $o.Folder = $folders[$i].Replace($curfolder, ""); $o.Description = $descriptions[$i]; $o.DeviceGroup = $groups[$i]; } else { $o = 1 | select "Folder"; $o.Folder = $folders[$i].Replace($curfolder, ""); } $o; } } Changing The Current Folder The Change-Folder function emulates the “cd” or “chdir” functionality in command shells. The folder parameter can either be a fully qualified folder name (ie /PARTITION1/FOLDER1/SUBFOLDER), a relative child folder path (ie. FOLDER1/SUBFOLDER, SUBFOLDER, etc), or the special “..” folder which means to go up one level on the folder hierarchy. function Change-Folder() #---------------------------------------------------------------------------- { param($folder); Debug-Message "Setting active folder to '$folder'"; if ( $folder -eq ".." ) { Move-Up; } else { (Get-F5.iControl).SystemSession.set_active_folder($folder); } $f = Get-CurrentFolder -Force; } Moving Up A Folder I wrote a special function to move up one folder from the currently active folder. The Move-Up function parses the current folder and moves up a path using the PowerShell Split-Path cmdlet. If the path isn’t the top folder (meaning it has a parent), then the call to System.Session.set_active_folder() is made and the new current folder is queried and cached for future use. function Move-Up() { $folder = Get-CurrentFolder; $parent = (Split-Path $folder).Replace('\', '/'); if ( $parent.Length -gt 0 ) { Debug-Message "Setting active folder to '$parent'"; (Get-F5.iControl).SystemSession.set_active_folder($parent); } $f = Get-CurrentFolder -Force; } Creating And Removing Folders Navigating folders is fun, but it’s more fun to create and destroy them! The Create-Folder and Remove-Folder functions do just that. They call the Management.Folder.create() and Management.Folder.delete_folder() methods to do these actions. function Create-Folder() { param($folder); Debug-Message "Creating folder '$folder'"; (Get-F5.iControl).ManagementFolder.create($folder); Write-Host "Folder '$folder' successfully created!"; } function Remove-Folder() { param($folder); Debug-Message "Removing folder '$folder'"; (Get-F5.iControl).ManagementFolder.delete_folder($folder); Write-Host "Folder '$folder' successfully removed!"; } Folder Descriptions One great feature of folders is the ability to attach a description to it. A folder is just another type of object and it’s sometimes useful to be able to store some metadata in there with information that you can’t fit into the name. The Set-FolderDescription and Get-FolderDescription functions call the Management.Folder.set_description() and Management.Folder.get_description() iControl methods to, well, get and set the descriptions. function Set-FolderDescription() { param($cmd); $tokens = $cmd.Split(" "); if ( $tokens.Length -eq 1 ) { $f = $cmd; $d = ""; Debug-Message "Setting folder '$folder' description to '$d'"; (Get-F5.iControl).ManagementFolder.set_description($f, $d); Get-FolderDescription $f; } elseif ( $tokens.Length -gt 1 ) { # folder description goes here $f = $tokens[0]; $d = $tokens[1]; for($i=2; $i-lt$tokens.Length; $i++) { $d += " "; $d += $tokens[$i]; } Debug-Message "Setting folder '$f' description to '$d'"; (Get-F5.iControl).ManagementFolder.set_description($f, $d); Get-FolderDescription $f; } else { Show-Help; } } function Get-FolderDescription() { param($folder); Debug-Message "Retrieving folder description for '$folder'"; $descriptions = (Get-F5.iControl).ManagementFolder.get_description($folder); $descriptions[0]; } Controling The Recursive State For Queries I touched at the recursive query option above when I was showing how to query child folders. This recursive state not only applies to folder queries, but all queries across the iControl API! The Set-RecursiveState function sets this configuration variable to either STATE_ENABLED or STATE_DISABLED. If the recursive_query_state is set to STATE_DISABLED, then queries will only return objects in the current active folder. But, if it’s set to STATE_ENABLED, then it will return all child objects in all child folders. So, by setting this one value, you can determine whether you get just the objects (pools, virtuals, vlans, monitors, etc) in the current folder, or all of them in all child folders. Cool stuff! function Set-RecursiveState() { param($state = $null); $newState = "STATE_DISABLED"; if ( $state -eq $null ) { # toggle $oldState = (Get-F5.iControl).SystemSession.get_recursive_query_state(); if ( $oldState -eq "STATE_DISABLED" ) { $newState = "STATE_ENABLED"; } } else { # set if ( $state.ToLower().Contains("enable") ) { $newState = "STATE_ENABLED"; } } $script:RECURSE = $newState; (Get-F5.iControl).SystemSession.set_recursive_query_state($newState); Write-Host "Recursive State set to '$newState'"; } function Get-RecursiveState() { $oldState = (Get-F5.iControl).SystemSession.get_recursive_query_state(); $script:RECURSE = $oldState; $oldState; } Executing Arbitrary iControl Commands I threw this in to help illustrate how the recursive state described above works. By passing in the command “! LocalLBVirtualServer.get_list()”, that iControl call will be executed and the results passed to the output. By using the Invoke-Expression cmdlet, any iControl call can arbitrarily be made within the shell. Again, cool stuff! function Execute-Command() { param($cmd); $fullcmd = $cmd; if ( -not $fullcmd.ToLower().StartsWith("(get-f5.icontrol).") ) { $fullcmd = "(Get-F5.iControl).$cmd"; } Debug-Message "Executing command '$fullcmd'"; Invoke-Expression $fullcmd; } A Demo Walkthrough Conclusion Folders will allow administrators more control of grouping their objects together, thus enabling them with the long-term manageability of those objects. This example illustrated how to use the iControl methods to interact with folders and, hopefully, in doing so, showed the ease at building powerful iControl solutions. The Source Code The Full Source can be found in the iControl Wiki in the CodeShare entry titled PowerShellManagementFolder. Related Content on DevCentral v11 - DevCentral - F5 DevCentral Groups - Microsoft PowerShell with iControl PowerShell - DevCentral Wiki Lori MacVittie - v11 ABLE Infrastructure: The Next Generation – Introducing v11 v11 iRules: Intro to Sideband Connections > DevCentral > Tech Tips ... F5 Friday: You Will Appsolutely Love v11 PowerShell ABC's - A To Z Webcast - BIG-IP v11 and Microsoft Technologies FREE F5 Virtual Event - All About V11 and Microsoft - Thursday ... Technorati Tags: powershell, folders, v11, automation, Joe Pruitt696Views0likes0CommentsiControl 101 - #23 - Module Resource Provisioning
A somewhat unknown feature on the BIG-IP is the ability to override the default resource allocations for core modules on the BIG-IP. This is available in the product GUI under the System’s “Resource Provisioning menu”. In this article, I’m going to walk you through the iControl Management.Provision interface and show you how to automate the configuration of the resources. The Provision interface manages the partitioning of system memory, disk space, and CPU usage among the modules (e.g., LTM, GTM, WOM) licensed to run on the system. The modules and the “host" system (everything not dedicated to network traffic processing) are first assigned a minimal set of resources, based on pre-determined values and the available system memory. The remaining resources are distributed among the modules, according to pre-determined rules, which can be modified by values which can be set via this iControl interface. The pre-defined module resource allocation handles a wide variety of circumstances, so this allocation should only need to be changed for unusual circumstances, such as turning modules on or off and large network traffic or configurations. Read that last sentence: “allocation should only need to be changed for unusual circumstances”. So, unless you have a need for doing so, I’d recommend keeping the default configuration. With that said, on with the article. Querying the Provisioning settings The default settings in the GUI can be found by looking on the System “Resource Provisioning” menu. A form similar to the following will be presented. You’ll notice that I have 6 modules on my system: LTM, GTM, PSM, ASM, WAM, and LC. Your configuration may be different depending on the version of your BIG-IP. In my configuration, only LTM and GTM are enabled and they have the default allocation of “Nominal”. The iControl Management.Provision interface contains the following methods to query the data from this form: get_list() - Query the list of LTM Modules get_provisioned_list() - Query the list of modules that have resources to run on the system (ie. not set to None) get_level(), set_level() - get or set the allocation level (none, minimal, nominal, dedicated, custom) get_custom_cpu_ratio(), set_custom_cpu_ratio() - get or set the custom CPU ratio (only for custom level) get_custom_disk_ratio(), set_custom_disk_ratio() - get or set the custom disk ratio (only for custom level) get_custom_memory_ratio(), set_custom_memory_ratio() - get or set the custom memory level (only for custom level) Here’s a PowerShell function that will use the iControl PowerShell Cmdlets to pull out the list of modules and then query the custom ratios for them. 1: function Get-Provisioning() 2: { 3: Write-Host "Retrieving the Provisioning List..."; 4: 5: $module_list = (Get-F5.iControl).ManagementProvision.get_list(); 6: $levels = (Get-F5.iControl).ManagementProvision.get_level($module_list); 7: $cpu_ratios = (Get-F5.iControl).ManagementProvision.get_custom_cpu_ratio($module_list); 8: $disk_ratios = (Get-F5.iControl).ManagementProvision.get_custom_disk_ratio($module_list); 9: $memory_ratios = (Get-F5.iControl).ManagementProvision.get_custom_memory_ratio($module_list); 10: 11: Write-Entry "Module Name" "Level" "CPU Ratio" "Disk Ratio" "Memory Ratio" 12: Write-Entry 13: for($i=0; $i -lt $module_list.Length; $i++) 14: { 15: $level = $levels[$i].ToString().Replace("PROVISION_LEVEL_", ""); 16: Write-Entry $module_list[$i] $level $cpu_ratios[$i] $disk_ratios[$i] $memory_ratios[$i] 17: } 18: } Running this function on my system results in this output showing the 6 modules and that only LTM and GTM are provisioned. Retrieving the Provisioning List... Module Name Level CPU Ratio Disk Ratio Memory Ratio ---------------- --------- ------------ ------------ ------------ TMOS_MODULE_LTM NOMINAL 0 0 0 TMOS_MODULE_GTM NOMINAL 0 0 0 TMOS_MODULE_LC NONE 0 0 0 TMOS_MODULE_PSM NONE 0 0 0 TMOS_MODULE_ASM NONE 0 0 0 TMOS_MODULE_WAM NONE 0 0 0 Changing The Resource Allocation Setting Now, let’s assume we have a need to tweak the configuration for some reason. In my example I’m going to illustrate how to set the allocation setting to Custom and tweak the various ratio settings for cpu, disk, and memory. 1: function Set-Custom() 2: { 3: Write-Host "Setting Custom Provisioning levels"; 4: 5: $modules = ("TMOS_MODULE_LTM", "TMOS_MODULE_GTM"); 6: $levels = ("PROVISION_LEVEL_CUSTOM", "PROVISION_LEVEL_CUSTOM"); 7: (Get-F5.iControl).ManagementProvision.set_level($modules, $levels); 8: (Get-F5.iControl).ManagementProvision.set_custom_cpu_ratio($modules, (60, 30)); 9: (Get-F5.iControl).ManagementProvision.set_custom_disk_ratio($modules, (100, 100)); 10: (Get-F5.iControl).ManagementProvision.set_custom_memory_ratio($modules, (75, 50)); 11: } One thing that you’ll need to know for setting custom levels is that it’s an all or nothing thing. To set one module to a custom setting, you have to set ALL other modules that have allocated resources to custom as well. You’ll notice in my script above that I set both LTM and GTM to the Custom level in the same method call. I then set the CPU ratios to 60 and 30, the Disk ratios to 100 and 100, and the Memory ratios to 75 and 50 respectively. There is no rhyme nor reason to these numbers, I just picked some different values. The Ratio itself is a number from 0 to 255 with 0 being equivalent to the “minimal” allocation level. After running this script the results can be seen by calling the above Get-Provisioning function in Powershell. Retrieving the Provisioning List... Module Name Level CPU Ratio Disk Ratio Memory Ratio ---------------- --------- ------------ ------------ ------------ TMOS_MODULE_LTM CUSTOM 60 100 75 TMOS_MODULE_GTM CUSTOM 30 100 50 TMOS_MODULE_LC NONE 0 0 0 TMOS_MODULE_PSM NONE 0 0 0 TMOS_MODULE_ASM NONE 0 0 0 TMOS_MODULE_WAM NONE 0 0 0 And the management GUI will look like this. Resetting The Resource Allocations To The Defaults The default values for the allocation levels are the “Nominal” settings. To reset the values, you will have to switch all modules away from the “custom” settings at one shot (remember, it’s an all-or-nothing thing). 1: function Set-Nominal() 2: { 3: Write-Host "Resetting Provisioning Levels to NOMINAL..."; 4: 5: $modules = ("TMOS_MODULE_LTM", "TMOS_MODULE_GTM"); 6: $levels = ("PROVISION_LEVEL_NOMINAL", "PROVISION_LEVEL_NOMINAL"); 7: $ratios = (0, 0); 8: (Get-F5.iControl).ManagementProvision.set_level($modules, $levels); 9: (Get-F5.iControl).ManagementProvision.set_custom_cpu_ratio($modules, $ratios); 10: (Get-F5.iControl).ManagementProvision.set_custom_disk_ratio($modules, $ratios); 11: (Get-F5.iControl).ManagementProvision.set_custom_memory_ratio($modules, $ratios); 12: } I went ahead and set all the ratios to zero but those values are ignored for any allocation levels other than “custom”. Download The Source The source for this article can be found in the iControl CodeShare under PowerShellManagementProvision.575Views0likes0Comments