ruby
14 TopicsRuby NAT Maker
Problem this snippet solves: The purpose of the NAT Maker tool is to add or delete a list of NATs. The file bigip-config.ylm contains the information about the BIG-IP that the tool is to connect to. It needs to be updated with the name and IP address of the BIG-IP as well as the username and password of the administrator account on the BIG-IP. The file LocalLB.NAT.WSDL defines the NAT section of iControl. This WSDL was used to generate some classes used this tool. It also needs to be updated. The 4th to last line in this file is < soap:address location="https://:443/iControl/iControlPortal.cgi"/> This line needs to be altered to use the IP address of the actual BIG-IP to which this script will connect. How to use this snippet: Tool Usage Add a list of NATs NATMaker.rb -a inputfile Delete a list of NATs NATMaker.rb -d inputfile Delete all NATs NATMaker.rb -dd Note: The input file should consist of a series of NATs, each on its own line. A NAT is defined by two IP addresses separated by a space. The first address is the origin address, and the second is the translation address. Code : # missing file185Views0likes0CommentsRuby VIP Maker
Problem this snippet solves: This is a utility created for the purpose of producing large numbers of virtual servers, including pools. This was created to make our testing efforts easier. Configuration For MakeVips and DeleteVips to work, the following files need the following edits: ltmbigip-config.yml needs to be updated with the correct IP address of the LTM and the username and password. LocalLB.Pool.wsdl needs to have the IP address on the second to last line of the file updated to the correct IP of the LTM LocalLB.VirtualServer.wsdl needs to have the IP address on the second to last line of the file updated to the correct IP of the LTM How to use this snippet: Tool Usage Add Virtual Servers MakeVips.rb namePrefix numberOfVIPs vipStartIP port ipsPerPool poolStartIP This will create numberOfVIPs virtual servers on the BIG-IP. These virtual servers will have names that begin with namePrefix. Each VIP will answer on its own IP address beginning with vipStartIP and counting up. The IP addresses roll over at their boundaries. Every VIP will answer on the specified port. Every VIP will have its own unique pool containing ipsPerPool number of IP addresses as members. These nodes begin at poolStartIP IP address and count up just as the VIP IP addresses do. There will be numberOfVips multiplied by ipsPerPool number of nodes created by this utility. Delete Virtual Servers DeleteVips.rb namePrefix numberOfVIPs This will delete the first numberOfVIPs virtual servers from the BIG-IP beginning with namePrefix, along with the pools associated with those virtual servers, assuming that they were created with the same utility as described above.287Views0likes0CommentsRuby Wide IP Maker
Problem this snippet solves: This is a utility created for the purpose of producing large numbers of WideIPs, including pools. This was created to make our testing efforts easier. Configuration For MakeWideIps and DeleteWideIps to work, the following files need the following edits: gtmbigip-config.yml needs to be updated with the correct IP address of the GTM and the username and password. GlobalLB.Pool.wsdl needs to have the IP address on the second to last line of the file updated to the correct IP of the GTM GlobalLB.WideIp.wsdl needs to have the IP address on the second to last line of the file updated to the correct IP of the GTM How to use this snippet: Tool Usage Add WideIPs MakeWideIps.rb namePrefix numberOfWideIPs port ipsPerPool poolStartIP This will create numberOfWideIPs WideIPs on the BIG-IP. These WideIPs will have names that begin with namePrefix. Every WideIP will answer on the specified port. Every WideIP will have its own unique pool containing ipsPerPool number of IP addresses as members. These nodes begin at poolStartIP IP address and count up . The IP addresses roll over at their boundaries. There will be numberOfWideIPs multiplied by ipsPerPool number of nodes created by this utility. Delete WideIPs DeleteWideIps.rb namePrefix numberOfWideIPs This will delete the first numberOfWideIPs WideIPs from the BIG-IP beginning with namePrefix, along with the pools associated with them, assuming that they were created with the same utility as described above.217Views0likes0CommentsiControlREST: Ruby: To Output a List of Virtual Servers and their Associated Pools and Pool Members.
Problem this snippet solves: This script enumerates virtual servers and their associated pools and pool members and their status, each virtual server on a line of its own in the ";' delimited format. Essentially, the code shows a way to parse the 'ltm/virtual' object and get the information required. It had a specific need to address when it was written, and it can be modified to suit other similar requirements. How to use this snippet: This code has been tested with Ruby 2.3.1p112. Code : #!/usr/local/bin/ruby -w # # This script enumerates virtual servers and their associated pools and # pool members and their status, each virtual server on a line of its own # in the ";' delimited format. # #------------------------------------------------------------------------- require 'rubygems' require 'rest-client' require 'json' # define program-wide variables BIGIP_ADDRESS = 'mgmt_IP_addr' BIGIP_USER = 'admin' BIGIP_PASS = 'admin' SLEEP_TIME = 20 bigip = RestClient::Resource.new( "https://#{BIGIP_ADDRESS}/mgmt/tm/", :user => BIGIP_USER, :password => BIGIP_PASS, :headers => { :content_type => 'application/json' }, :verify_ssl => false ) # Get virtual servers: vservers = bigip['ltm/virtual'].get vservers_obj = JSON.parse(vservers) # Get pools: pools = bigip['ltm/pool?expandSubcollections=true'].get pools_obj = JSON.parse(pools) # Output header: puts "Virtual Server Name;Virtual Server Destination;Virtual Server Partition;Pool Name;Pool LB Mode;Pool Member Name (address)(state)" $output = '' # Process data: vservers_obj.each do |vserver_obj| vserver_obj.each do |vserver_obj_element| if vserver_obj_element.is_a?(Array) vserver_obj_element.each do |vserver_obj_element_property| if vserver_obj_element_property.is_a?(Hash) if vserver_obj_element_property.has_key?("name") vs_name = vserver_obj_element_property.fetch("name") $output = $output + vs_name + ';' end if vserver_obj_element_property.has_key?("destination") vs_destination = vserver_obj_element_property.fetch("destination") $output = $output + vs_destination + ';' end if vserver_obj_element_property.has_key?("partition") vs_partition = vserver_obj_element_property.fetch("partition") $output = $output + vs_partition + ';' end if vserver_obj_element_property.has_key?("pool") pool_name_from_vs = vserver_obj_element_property.fetch("pool") pools_obj.each_pair do |key, val| next if key == "kind" next if key == "selfLink" for x in 0..(val.length-1) if val[x]["fullPath"] == pool_name_from_vs $output = $output + val[x]["name"] + ";" + val[x]["loadBalancingMode"] if val[x].has_key?("membersReference") val[x]["membersReference"].each_pair do |mrefkey,mrefval| next if mrefkey == "link" next if mrefkey == "isSubcollection" for i in 0..(mrefval.length-1) if i == 0 $output = $output + ";" + mrefval[i]["name"] + "(" + mrefval[i]["address"] + ")(" + mrefval[i]["state"] + ")," else $output = $output + mrefval[i]["name"] + "(" + mrefval[i]["address"] + ")(" + mrefval[i]["state"] + ")," end if i == mrefval.length-1 $output.chop! $output += "\n" end end end else $output = $output + ";;\n" end break end end end else $output = $output + ";;\n" end end end end end end puts $output #---END--- Tested this on version: 11.6269Views0likes0CommentsEnumerate All Modules
Problem this snippet solves: The iControl REST Users Guide documents a way to discover all components by using the curl command to manually scroll through all the different modules. I wanted something a bit more automated, so I came up with this short program to enumerate through all the possible modules. The program loads in all the top-level API modules into a stack, then proceeds to query the iControl REST API daemon (tmapid) for the contents of those containers. As the sub-modules are discovered, they are pushed down on to the stack to be queried as well. Since the REST API makes use of the same command processor as TMSH, you will notice that the item REST paths just about match up with TMSH. If you know the TMSH path, you can just about guess what the REST URI should look like. Code : #!/usr/bin/ruby #---------------------------------------------------------------------------- # iControl_REST_Enum.rb #---------------------------------------------------------------------------- # # # Before you can run this program, you need to enable the tmapid daemon: #tmsh modify /sys service tmapid enable # tmsh start /sys service tmapid # # You can query the iControl REST API from the command line using curl: # # $ curl -s -k -u admin:admin https://10.147.29.117/mgmt/tm/sys/application | python -mjson.tool # { # "apiPartition": "/Common/", # "currentItemCount": 4, # "items": [ # { # "apiName": "apl-script", # "kind": "tm:sys:application:apl-script:apl-scriptstate", # "selfLink": "https://localhost/mgmt/tm/sys/application/apl-script" # }, # { # "apiName": "custom-stat", # "kind": "tm:sys:application:custom-stat:custom-statstate", # "selfLink": "https://localhost/mgmt/tm/sys/application/custom-stat" # }, # { # "apiName": "service", # "kind": "tm:sys:application:service:servicestate", # "selfLink": "https://localhost/mgmt/tm/sys/application/service" # }, # { # "apiName": "template", # "kind": "tm:sys:application:template:templatestate", # "selfLink": "https://localhost/mgmt/tm/sys/application/template" # } # ], # "kind": "tm:sys:application:applicationstate", # "nextLink": null, # "pageIndex": 1, # "previousLink": null, # "selfLink": "https://localhost/mgmt/tm/sys/application", # "startIndex": 1, # "totalItems": 4, # "totalPages": 1 # } # # The python json.tool on the end of the command line just formats the JSON into something # more readable. #---------------------------------------------------------------------------- # Software is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See # the License for the specific language governing rights and limitations # under the License. # # The Initial Developer of the Original Code is F5 Networks, # Inc. Seattle, WA, USA. Portions created by F5 are Copyright (C) 2013 F5 Networks, # Inc. All Rights Reserved. # # Author: John D. Allen, Principal Solutions Engineer # Email: john.allen@f5.com #---------------------------------------------------------------------------- # # Version: #1.0INITIAL Version #1.1Corrected to work with new icrd daemon JSON format. # #---------------------------------------------------------------------------- require 'rubygems' require 'net/http' require 'net/https' require 'uri' require 'json' REST_host = "//10.147.29.121" ## Your BIGIP v11.4 host IP or Name here. The '//' at the start need to be there. def RESTcall(x) ## Yes there are other ways to do this call, but I already had the tried and true code in hand. uri = URI.parse(x) http = Net::HTTP.new(uri.host, uri.port) req = Net::HTTP::Get.new(uri.request_uri) req.basic_auth "admin", "admin" ## You will need to change this if you have a different password. http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE ## if your like me, you don't have a valid cert on your BIGIP return http.request(req) end ##----- Load the query stack -----## stack = [] stack.push "https:#{REST_host}/mgmt/tm/sys" stack.push "https:#{REST_host}/mgmt/tm/net" stack.push "https:#{REST_host}/mgmt/tm/ltm" stack.push "https:#{REST_host}/mgmt/tm/cm" stack.push "https:#{REST_host}/mgmt/tm/cli" stack.push "https:#{REST_host}/mgmt/tm/auth" stack.push "https:#{REST_host}/mgmt/tm/pem" stack.push "https:#{REST_host}/mgmt/tm/security" stack.push "https:#{REST_host}/mgmt/tm/afm" stack.push "https:#{REST_host}/mgmt/tm/analytics" stack.push "https:#{REST_host}/mgmt/tm/apm" stack.push "https:#{REST_host}/mgmt/tm/gtm" stack.push "https:#{REST_host}/mgmt/tm/wam" ## If you don't have a module installed, you will get a '500' error, but the program will continue. resp = "" ## ## Check our host to see if it is ready ## For some reason the initial REST API calls usually timeout while the tmapid daemon works on the ## first API packet. Once going, it seems to be fine. This call just checks to see if it is ## responding back with a correct '200' status code. If not, tmapid responds back with a '000' ## status code. We just loop until we get a 200, or die trying. ## i = 0 loop do i += 1 resp = RESTcall("https:#{REST_host}/mgmt/tm/ltm/available") break if resp.code == "200" or i > 5 puts "--> Waking up tmapid daemon" end if i > 5 puts "--->Unable to wake up tmapid daemon on BIGIP host." exit end ## ## Main Loop ## ## This program uses a simple FILO stack to enumerate through all the items exposed from the iControl REST API. ## Some containers have large numbers of items, so if there are more than 50, they are not pushed onto the stack. ## There are a few containers that seem to reference themselves, and thus were causing loops in the program. So ## if the selfLink field of the item matches the selfLink field of the container, the item is ignored. Some of ## the containers seem to have items defined that cause errors when queried for. Not sure if that is by design, ## or if it is a bug in the v11.4 Beta code. ## loop do uri = stack.pop uu = URI.parse(uri) puts uu.path uri.gsub!(/\/\/localhost/, REST_host) ## BIGIP REST interface returns 'localhost' in its URI's for some strange reason. i = 0 loop do i += 1 resp = RESTcall(uri) break if resp.code == "200" or i > 3 end if i > 3 case resp.code ## This is the HTTP response code from the REST API call. when "400" puts "--->[400] Item(s) not currently available?" when "401" puts "--->[401] Not Authorized to Access." when "403" puts "--->[403] Verboten" when "404" puts "--->[404] Item(s) Not Found." when "500" puts "--->[500] Not Definded to API server?" end else api = JSON.parse(resp.body) if api.has_key?('items') ## if container, not end parameter if api['totalItems'].to_i < 50 ## some containers have hundreds!! api['items'].each do |r| if r.has_key?('selfLink') stack.push r['selfLink'] if api['selfLink'] != r['selfLink'].chop ## some items reference themselves?!?! else stack.push r['reference']['link'] ## v11.4 Build 145 has a different format from Beta I. end end else puts "---> Too many Items to store (#{api['totalItems']})" end end end break if stack.empty? end exit197Views0likes1CommentRuby Virtual Server and Pool Creation
Problem this snippet solves: A simple script to add and delete both Virtual IPs and Pools in: Ruby Code : require 'rubygems' require 'rest-client' require 'json' # define program-wide variables BIGIP_ADDRESS = 'test-ltm-03.element.local' BIGIP_USER = 'admin' BIGIP_PASS = 'admin' SLEEP_TIME = 20 VS_NAME = 'test-http-virtual_ruby' VS_ADDRESS = '1.1.1.1' VS_PORT = '80' POOL_NAME = 'test-http-pool_ruby' POOL_LB_METHOD = 'least-connections-member' POOL_MEMBERS = [ '10.0.0.1:80', '10.0.0.2:80', '10.0.0.3:80' ] # create/delete methods def create_pool bigip, name, members, lb_method # convert member format members.collect { |member| { :kind => 'ltm:pool:members', :name => member} } # define test pool payload = { :kind => 'tm:ltm:pool:poolstate', :name => name, :description => 'A Ruby rest-client test pool', :loadBalancingMode => lb_method, :monitor => 'http', :members => members } bigip['ltm/pool'].post payload.to_json end def create_http_virtual bigip, name, address, port, pool # define test virtual payload = { :kind => 'tm:ltm:virtual:virtualstate', :name => name, :description => 'A Ruby rest-client test virtual server', :destination => "#{address}:#{port}", :mask => '255.255.255.255', :ipProtocol => 'tcp', :sourceAddressTranslation => { :type => 'automap' }, :profiles => [ { :kind => 'ltm:virtual:profile', :name => 'http' }, { :kind => 'ltm:virtual:profile', :name => 'tcp' } ], :pool => pool } bigip['ltm/virtual'].post payload.to_json end def delete_pool bigip, name url = "ltm/pool/#{name}" bigip[url].delete end def delete_virtual bigip, name url = "ltm/virtual/#{name}" bigip[url].delete end # REST resource for BIG-IP that all other requests will use bigip = RestClient::Resource.new( "https://#{BIGIP_ADDRESS}/mgmt/tm/", :user => BIGIP_USER, :password => BIGIP_PASS, :headers => { :content_type => 'application/json' } ) puts "created REST resource for BIG-IP at #{BIGIP_ADDRESS}..." # create pool create_pool bigip, POOL_NAME, POOL_MEMBERS, POOL_LB_METHOD puts "created pool \"#{POOL_NAME}\" with members #{POOL_MEMBERS.join(', ')}..." # create virtual create_http_virtual bigip, VS_NAME, VS_ADDRESS, VS_PORT, POOL_NAME puts "created virtual server \"#{VS_NAME}\" with destination #{VS_ADDRESS}:#{VS_PORT}..." # sleep for a little while puts "sleeping for #{SLEEP_TIME} seconds, check for successful creation..." sleep SLEEP_TIME # delete virtual delete_virtual bigip, VS_NAME puts "deleted virtual server \"#{VS_NAME}\"..." # delete pool delete_pool bigip, POOL_NAME puts "deleted pool \"#{POOL_NAME}\"..."222Views0likes1CommentVirtual Address ARP Switcher
Problem this snippet solves: The virtual-address-arp-switcher script is used to quickly and efficiently migrate virtual addresses from one BIG-IP to another. The BIG-IP that is active and currently holds the ARP-enabled virtual address is referred to as the 'source'. The BIG-IP holding the same virtual address with ARP disabled is the 'target'. This script will login to both units, ensure that the virtual address is present on both units and that the ARP setting for both the source and target are in their correct state. A delay can be inserted during which both virtual addresses are in the disabled state. The delay can be set to the ARP cache timeout to ensure that duplicates ARP entries do not exist in the caches. How to use this snippet: Requirements Ruby Ruby Gems F5 iControl for Ruby library (http://devcentral.f5.com/Tutorials/TechTips/tabid/63/articleType/ArticleView/articleId/1086421/Getting-Started-With-Ruby-and-iControl.aspx) other dependencies will be installed with the iControl gem Installation Steps Install Ruby, Ruby's OpenSSL library, Ruby Gems, and the Ruby iControl libraries http://devcentral.f5.com/Tutorials/TechTips/tabid/63/articleType/ArticleView/articleId/1086421/Getting-Started-With-Ruby-and-iControl.aspx Copy this code to /usr/local/bin and chmod +x to make the script executable Run it! virtual-address-arp-switcher --bigip-address-source 10.0.0.10 --bigip-address-target 10.0.0.20 -u admin -p admin -v 192.168.22.44 -d 10 Code : #!/usr/bin/ruby # == Synopsis # # virtual-address-arp-switcher - quickly swap virtual addresses between BIG-IPs # # The virtual-address-arp-switcher script is used to quickly and efficiently migrate virtual addresses from one BIG-IP to another. The BIG-IP that is active and currently holds the ARP-enabled virtual address is referred to as the 'source'. The BIG-IP holding the same virtual address with ARP disabled is the 'target'. This script will login to both units, ensure that the virtual address is present on both units and that the ARP setting for both the source and target are in their correct state. A delay can be inserted during which both virtual addresses are in the disabled state. The delay can be set to the ARP cache timeout to ensure that duplicates ARP entries do not exist in the caches. # # == Usage # # virtual-address-arp-switcher [OPTIONS] # # -h, --help: # show help # # --bigip-address-source, -b [hostname]: # specify the hostname or IP address for source BIG-IP # # --bigip-user-source, -u [username]: # username for source BIG-IP # # --bigip-pass-source, -p [password]: # password for source BIG-IP # # --bigip-address-target [hostname]: # specify the target BIG-IP address # # --bigip-user-target [username]: # username for target BIG-IP, by default assumes same as source BIG-IP # # --bigip-pass-target [password]: # password for target BIG-IP, by default assumes same as source BIG-IP # # --virtual-address, -v [ip address]: # virtual address for which to disable and enable ARP # # --delay, -d [seconds]: # delay between disabling ARP on the source BIG-IP and enabling on target require 'rubygems' require 'f5-icontrol' require 'getoptlong' require 'rdoc/usage' options = GetoptLong.new( [ '--bigip-address-source', '-b', GetoptLong::REQUIRED_ARGUMENT ], [ '--bigip-user-source', '-u', GetoptLong::REQUIRED_ARGUMENT ], [ '--bigip-pass-source', '-p', GetoptLong::REQUIRED_ARGUMENT ], [ '--bigip-address-target', GetoptLong::REQUIRED_ARGUMENT ], [ '--bigip-user-target', GetoptLong::REQUIRED_ARGUMENT ], [ '--bigip-pass-target', GetoptLong::REQUIRED_ARGUMENT ], [ '--virtual-address', '-v', GetoptLong::REQUIRED_ARGUMENT ], [ '--delay', '-d', GetoptLong::REQUIRED_ARGUMENT ], [ '--help', '-h', GetoptLong::NO_ARGUMENT ] ) # set inital values bigip_address_source = '' bigip_user_source = '' bigip_pass_source = '' bigip_address_target = '' bigip_user_target = '' bigip_pass_target = '' virtual_address = '' delay = 0 options.each do |option, arg| case option when '--bigip-address-source' bigip_address_source = arg when '--bigip-user-source' bigip_user_source = arg when '--bigip-pass-source' bigip_pass_source = arg when '--bigip-address-target' bigip_address_target = arg when '--bigip-user-target' bigip_user_target = arg when '--bigip-pass-target' bigip_pass_target = arg when '--virtual-address' if arg =~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ virtual_address = arg end when '--delay' delay = arg.to_i when '--help' RDoc::usage end end RDoc::usage if bigip_address_source.empty? \ or bigip_user_source.empty? \ or bigip_pass_source.empty? \ or bigip_address_target.empty? \ or virtual_address.empty? bigip_user_target = bigip_user_source if bigip_user_target.empty? bigip_pass_target = bigip_pass_source if bigip_pass_target.empty? # Initiate SOAP RPC connection to BIG-IP begin bigip_source = F5::IControl.new(bigip_address_source, bigip_user_source, bigip_pass_source, ['LocalLB.VirtualAddress']).get_interfaces rescue puts 'ERROR: Connection error occured while connecting to the source BIG-IP at ' puts "#{bigip_address_source}." exit 1 end begin bigip_target = F5::IControl.new(bigip_address_target, bigip_user_target, bigip_pass_target, ['LocalLB.VirtualAddress']).get_interfaces rescue puts 'ERROR: Connection error occured while connecting to the target BIG-IP at ' puts "#{bigip_address_target}." exit 1 end # Make sure that the virtual address is available on both BIG-IPs unless bigip_source['LocalLB.VirtualAddress'].get_list.include? virtual_address puts 'ERROR: The source BIG-IP does not contain the virtual address provided.' exit 1 end unless bigip_target['LocalLB.VirtualAddress'].get_list.include? virtual_address puts 'ERROR: The target BIG-IP does not contain the virtual address provided.' exit 1 end # Ensure that the ARP state of both addresses is correct bigip_source_arp_state = bigip_source['LocalLB.VirtualAddress'].get_arp_state(virtual_address).to_s bigip_target_arp_state = bigip_target['LocalLB.VirtualAddress'].get_arp_state(virtual_address).to_s if bigip_source_arp_state == 'STATE_DISABLED' and bigip_target_arp_state == 'STATE_ENABLED' puts 'ERROR: ARP is currently disabled for the virtual address on the source BIG-IP and enabled on the target. It appears that the two are reversed. Please read the help message for more information on which unit should be the source and the other the target.' exit 1 elsif (bigip_source_arp_state and bigip_target_arp_state) == 'STATE_ENABLED' puts 'ERROR: ARP is enabled for the virtual address on both BIG-IPs. It is likely that there is an IP address conflict at the moment.' exit 1 elsif bigip_source_arp_state == 'STATE_DISABLED' puts 'ERROR: ARP is currently disabled for the virtual address on the source BIG-IP and needs to be enabled to proceed.' exit 1 elsif bigip_target_arp_state == 'STATE_ENABLED' puts 'ERROR: ARP is currently enabled for the virtual address on the target BIG-IP and needs to be disabled to proceed.' exit 1 end # Everything looks good so far, confirm the swap, then proceed puts "Virtual address details" puts "-" * 20 puts "Virtual address: #{virtual_address}" puts "Current location: #{bigip_address_source}" puts "Future location: #{bigip_address_target}" puts "Delay: #{delay} seconds" answer = '' print "\nAre you sure you want to proceed? (no/yes) " STDOUT.flush answer = STDIN.gets.chomp exit unless answer == "yes" # Begin the swap puts "WARNING: Commencing swap! Do not exit script! Wait for exit!" puts "INFO: Disabling ARP for virtual address #{virtual_address} on #{bigip_address_source}..." bigip_source['LocalLB.VirtualAddress'].set_arp_state([virtual_address], ['STATE_DISABLED']) puts "INFO: Sleeping for #{delay} seconds..." sleep delay puts "INFO: Enabling ARP for virtual address #{virtual_address} on #{bigip_address_target}..." bigip_target['LocalLB.VirtualAddress'].set_arp_state([virtual_address], ['STATE_ENABLED'])200Views0likes0CommentsSSLKeyAndCSRCreator
Problem this snippet solves: This is a script will generate a private key and output a certificate signing request. This is all done from a workstation command line and communicated to the BIG-IP via iControl. How to use this snippet: Requirements Ruby Ruby Gems F5 iControl for Ruby library other dependencies will be installed with the iControl gem Installation Steps Install Ruby, Ruby's ""OpenSSL"" library, Ruby Gems, and the Ruby iControl libraries Getting-Started-With-Ruby-and-iControl.aspx Copy this code to /usr/local/bin and chmod +x to make the script executable Run it! minimal options: ssl-key-and-csr-creator.rb -b 192.168.1.245 -u admin -i test-key-001 full options: ssl-key-and-csr-creator.rb -b 192.168.1.245 -u admin -p admin -i test-key-001 -t RSA -l 4096 -s fips --common-name=www.example.com --country=US --state=Washington --locality=Seattle --organization="Example Company, Inc." --division="Information Technology" -o /my-ssl-directory/ -k -c Code : #!/usr/bin/ruby require "rubygems" require "f5-icontrol" require "getoptlong" options = GetoptLong.new( [ "--bigip-address", "-b", GetoptLong::REQUIRED_ARGUMENT ], [ "--bigip-user", "-u", GetoptLong::REQUIRED_ARGUMENT ], [ "--bigip-pass", "-p", GetoptLong::REQUIRED_ARGUMENT ], [ "--key-id", "-i", GetoptLong::REQUIRED_ARGUMENT ], [ "--key-type", "-t", GetoptLong::OPTIONAL_ARGUMENT ], [ "--key-bit-length", "-l", GetoptLong::OPTIONAL_ARGUMENT ], [ "--key-security", "-s", GetoptLong::OPTIONAL_ARGUMENT ], [ "--common-name", GetoptLong::OPTIONAL_ARGUMENT ], [ "--country", GetoptLong::OPTIONAL_ARGUMENT ], [ "--state", GetoptLong::OPTIONAL_ARGUMENT ], [ "--locality", GetoptLong::OPTIONAL_ARGUMENT ], [ "--organization", GetoptLong::OPTIONAL_ARGUMENT ], [ "--division", GetoptLong::OPTIONAL_ARGUMENT ], [ "--output-dir", "-o", GetoptLong::OPTIONAL_ARGUMENT ], [ "--key-output", "-k", GetoptLong::NO_ARGUMENT ], [ "--csr-output", "-c", GetoptLong::NO_ARGUMENT ], [ "--help", "-h", GetoptLong::NO_ARGUMENT ] ) def usage puts $0 + " -b -u -i " puts puts "BIG-IP connection parameters" puts "-" * 20 puts " -b (--bigip-address) BIG-IP management-accessible address" puts " -u (--bigip-user) BIG-IP username" puts " -p (--bigip-pass) BIG-IP password (will prompt if left blank" puts puts "Private key parameters" puts "-" * 20 puts " -i (--key-id) key ID: must be unique and should be indicative of the purpose (required)" puts " -t (--key-type) key type: [RSA|DSA] (default is 'RSA')" puts " -l (--key-bit-length) key bit length: should be a minimum of 1024-bit (default is 2048; most CAs won't sign weaker keys)" puts " -s (--key-security) key security: [normal|fips|password] (default is 'normal' with no passphrase)" puts puts "X.509 data parameters (if blank, you'll be prompted for the answers)" puts "-" * 20 puts " (--common-name) common name: FQDN for virtual server (www.example.com)" puts " (--country) country: two letter country abbreviation (US, CN, etc.)" puts " (--state) state: two letter state abbreviation (WA, OR, CA, etc.)" puts " (--locality) locality: locality or city name (Seattle, Portland, etc.)" puts " (--organization) organization: organization or company name (F5 Networks, Company XYZ, etc.)" puts " (--division) division: department or division name (IT, HR, Finance, etc.)" puts puts "Output options" puts "-" * 20 puts " -o (--output-dir) CSR/key output directory: location to output private key and CSR files (defaults to current working directory)" puts " -k (--key-output) key output: save private key to a local file (saved as key_id.key)" puts " -c (--csr-output) CSR output: save certificate signing request to a local file (saved as key_id.csr)" puts puts "Help and usage" puts "-" * 20 puts " -h (--help) shows this help/usage dialog" puts exit end # set STDOUT buffer to synchronous STDOUT.sync = true # global variables KEY_TYPES = { "RSA" => "KTYPE_RSA_PRIVATE", "DSA" => "KTYPE_DSA_PRIVATE" } KEY_SECURITIES = { "normal" => "STYPE_NORMAL", "fips" => "STYPE_FIPS", "password" => "STYPE_PASSWORD" } # initial parameter values overwrite_key = false # key/CSR default output file values key_output = false csr_output = false output_dir = Dir.pwd # BIG-IP connection parameters bigip = {} bigip['address'] = '' bigip['user'] = '' bigip['pass'] = '' # private key parameters key_data = {} key_data['id'] = '' key_data['key_type'] = KEY_TYPES["RSA"] key_data['bit_length'] = 2048 key_data['security'] = KEY_SECURITIES["normal"] # X.509 data parameters x509_data = {} x509_data['common_name'] = '' x509_data['country_name'] = '' x509_data['state_name'] = '' x509_data['locality_name'] = '' x509_data['organization_name'] = '' x509_data['division_name'] = '' # loop through command line options options.each do |option, arg| case option when "--bigip-address" bigip['address'] = arg when "--bigip-user" bigip['user'] = arg when "--bigip-pass" bigip['pass'] = arg when "--key-id" key_data['id'] = arg when "--key-type" if KEY_TYPES.keys.include? arg.upcase key_data['key_type'] = KEY_TYPES[arg.upcase] else puts "Error: Invalid key type. Exiting." exit 1 end when "--key-bit-length" key_data['bit_length'] = arg.to_i when "--key-security" if KEY_SECURITIES.keys.include? arg.downcase key_data['security'] = KEY_SECURITIES[arg.downcase] else puts "Error: Invalid key security type. Exiting." exit 1 end when "--common-name" x509_data['common_name'] = arg when "--country" if arg =~ /[a-z]{2}/i x509_data['country_name'] = arg.upcase else puts "Error: Use exactly two letters for the country code. Exiting." exit 1 end when "--state" x509_data['state_name'] = arg when "--locality" x509_data['locality_name'] = arg when "--organization" x509_data['organization_name'] = arg when "--division" x509_data['division_name'] = arg when "--output-dir" if File.directory? arg output_dir = arg else puts "Error: Invalid directory for output. Exiting." end when "--key-output" key_output = true when "--csr-output" csr_output = true when "--help" usage end end # we need at least the BIG-IP's address, user, and a key ID to proceed usage if bigip['address'].empty? or bigip['user'].empty? or key_data['id'].empty? if bigip['pass'].empty? puts "Please enter the BIG-IPs password..." print "Password: " system("stty", "-echo") bigip['pass'] = gets.chomp system("stty", "echo") puts end # set up connection to BIG-IP and Management.KeyCertificate interface bigip = F5::IControl.new(bigip['address'], bigip['user'], bigip['pass'], ["Management.KeyCertificate"]).get_interfaces #grab a list of existing keys and confirm overwrite if a conflict exists existing_keys = bigip["Management.KeyCertificate"].get_key_list('MANAGEMENT_MODE_DEFAULT').collect { |key| key["key_info"]["id"] } if existing_keys.include? key_data['id'] print "A key with an ID of '#{key_data['id']}' already exists. Overwrite it? (yes/no) " answer = gets.chomp if answer !~ /^yes$/i puts "Will not overwrite existing key. Exiting." exit else overwrite_key = true end end # time to play 20 questions with the X.509 data if x509_data.values.delete_if { |value| !value.empty? }.size > 0 puts "Please fill in the following X.509 data parameters..." end x509_data.sort.each do |key, value| if value.empty? print key.capitalize.gsub('_', ' ') + "? " x509_data[key] = gets.chomp end end bigip["Management.KeyCertificate"].key_generate('MANAGEMENT_MODE_DEFAULT', [key_data], [x509_data], true, overwrite_key) # write private key to local file if specified by user if key_output key_output_file = output_dir + "/" + key_data['id'] + ".key" key = bigip["Management.KeyCertificate"].key_export_to_pem('MANAGEMENT_MODE_DEFAULT', [key_data['id']])[0] File.open(key_output_file, 'w') { |file| file.write(key) } end # display subject information for CSR as well as the CSR puts "Certificate Request" puts "-" * 20 puts "Subject: C=#{x509_data['country_name']}, ST=#{x509_data['state_name']}, L=#{x509_data['locality_name']}, O=#{x509_data['organization_name']}, OU=#{x509_data['division_name']}, CN=#{x509_data['common_name']}" csr = bigip["Management.KeyCertificate"].certificate_request_export_to_pem('MANAGEMENT_MODE_DEFAULT', [key_data['id']]) # write csr key to local file if specified by user if csr_output csr_output_file = output_dir + "/" + key_data['id'] + ".csr" File.open(csr_output_file, 'w') { |file| file.write(csr) } end puts puts csr250Views0likes0CommentsSSL Certificate Report
Problem this snippet solves: This is a script will generate a report of all or some of the certificates managed by a BIG-IP. It will output a multitude of information including: subject and issuers properties, serial, public key bit-length, and expiration dates. How to use this snippet: Requirements Ruby Ruby Gems F5 iControl for Ruby library (http://devcentral.f5.com/Tutorials/TechTips/tabid/63/articleType/ArticleView/articleId/1086421/Getting-Started-With-Ruby-and-iControl.aspx) other dependencies will be installed with the iControl gem Installation Steps Install Ruby, Ruby's OpenSSL library, Ruby Gems, and the Ruby iControl libraries http://devcentral.f5.com/Tutorials/TechTips/tabid/63/articleType/ArticleView/articleId/1086421/Getting-Started-With-Ruby-and-iControl.aspx Copy this code to /usr/local/bin and chmod +x to make the script executable Run it! ssl-certificate-report.rb -b 192.168.1.245 -u admin -p admin -v Code : #!/usr/bin/ruby require "rubygems" require "f5-icontrol" require "getoptlong" options = GetoptLong.new( [ "--bigip-address", "-b", GetoptLong::REQUIRED_ARGUMENT ], [ "--bigip-user", "-u", GetoptLong::REQUIRED_ARGUMENT ], [ "--bigip-pass", "-p", GetoptLong::REQUIRED_ARGUMENT ], [ "--cert-name", "-n", GetoptLong::OPTIONAL_ARGUMENT ], [ "--cert-list", "-l", GetoptLong::NO_ARGUMENT ], [ "--watermark-days", "-d", GetoptLong::OPTIONAL_ARGUMENT ], [ "--no-color", "-c", GetoptLong::NO_ARGUMENT ], [ "--verbose", "-v", GetoptLong::OPTIONAL_ARGUMENT ], [ "--help", "-h", GetoptLong::NO_ARGUMENT ] ) def usage puts $0 + " -b -u " puts " -b (--bigip-address) BIG-IP management-accessible address" puts " -u (--bigip-user) BIG-IP username" puts " -p (--bigip-pass) BIG-IP password (will prompt if left blank" puts " -n (--cert-name) name of certificate to display (display all by default)" puts " -l (--cert-list) list of certificates managed by the BIG-IP" puts " -d (--watermark-days) certificates expiring inside this number of days will" puts " be marked as \"expiring soon\", default is 30 days" puts " -c (--no-color) disable color coding for the shell (useful if piping" puts " output to less or are using Windows)" puts " -v (--verbose) show all certificate information (brief by default)" puts " -h (--help) shows this help/usage dialog" exit end # initial parameter values bigip_address = '' bigip_user = '' bigip_pass = '' cert_name = '' cert_list = false watermark_days = 30 verbose = false # the color_code variable must be global to be read within the format_text method $color_code = true options.each do |option, arg| case option when "--bigip-address" bigip_address = arg when "--bigip-user" bigip_user = arg when "--bigip-pass" bigip_pass = arg when "--cert-name" cert_name = arg when "--cert-list" cert_list = true when "--watermark-days" arg = arg.to_i watermark_days = arg when "--no-color" $color_code = false when "--verbose" verbose = true when "--help" usage end end usage if bigip_address.empty? or bigip_user.empty? if bigip_pass.empty? puts "Please enter the BIG-IPs password..." print "Password: " system("stty", "-echo") bigip_pass = gets.chomp system("stty", "echo") end bigip = F5::IControl.new(bigip_address, bigip_user, bigip_pass, ["Management.KeyCertificate"]).get_interfaces def format_text(text, code) if $color_code "#{code}#{text}\e[00m" else text end end def red(text) format_text(text, "\e[01;31m") end def green(text) format_text(text, "\e[01;32m") end def yellow(text) format_text(text, "\e[01;33m") end def bold(text) format_text(text, "\e[1m") end def underline(text) format_text(text, "\e[4m") end def bold_underline(text) format_text(text, "\e[4;1m") end def cert_validity_label(expire_text) case expire_text when "VTYPE_CERTIFICATE_VALID" green("valid") when "VTYPE_CERTIFICATE_EXPIRED" red("expired") when "VTYPE_CERTIFICATE_WILL_EXPIRE" yellow("expiring soon") when "VTYPE_CERTIFICATE_INVALID" red("invalid") else yellow("unknown") end end def key_strength_label(key_length) case(key_length) when 0..1023 red("low") when 1024..2047 yellow("medium") else green("strong") end end def key_type_label(key_type) case key_type when "KTYPE_RSA_PRIVATE" "RSA private key" when "KTYPE_RSA_PUBLIC" "RSA public key" when "KTYPE_DSA_PRIVATE" "DSA private key" when "KTYPE_DSA_PUBLIC" "DSA public key" else "Unkown" end end # collect certificate properties certs = {} bigip["Management.KeyCertificate"].get_certificate_list("MANAGEMENT_MODE_DEFAULT").each do |cert| id = cert['certificate']['cert_info']['id'] certs[id] = {} # general properties certs[id]['expires'] = Time.at(cert['certificate']['expiration_date']).strftime("%b %e, %Y") certs[id]['version'] = cert['certificate']['version'] certs[id]['serial'] = cert['certificate']['serial_number'] certs[id]['serial'] = 'unavailable' if certs[id]['serial'].empty? # subject and issuers properties ['subject', 'issuer'].each do |x| certs[id][x] = {} ['common_name', 'organization_name', 'division_name', 'locality_name', 'state_name', 'country_name'].each do |y| certs[id][x][y] = cert['certificate'][x][y] end end certs[id]['key'] = {} certs[id]['key']['length'] = cert['certificate']['bit_length'] certs[id]['key']['length_text'] = key_strength_label(cert['certificate']['bit_length'].to_i) certs[id]['key']['type'] = key_type_label(cert['certificate']['key_type']) end # collect certificate validity information validity_states = bigip["Management.KeyCertificate"].certificate_check_validity('MANAGEMENT_MODE_DEFAULT', certs.keys, ([watermark_days] * certs.keys.size)) x = 0 certs.each do |id,cert| cert['expire_text'] = cert_validity_label(validity_states[x]) x += 1 end # display BIG-IP information puts bold("\nConnected to BIG-IP at #{bigip_address} with user '#{bigip_user}'...") # if user only wants list, display it and exit if cert_list puts puts underline("Available certificates\n") puts certs.keys.sort.collect { |id| id = " " + id } puts exit end unless cert_name.empty? if certs.key? cert_name certs = { cert_name => certs[cert_name] } else puts "Error: could not locate a certificate by that name, try '-l' for a list" exit end end puts bold_underline(" " * 80) puts certs.keys.sort.each do |id| puts underline("General Properties") puts "\t" + bold("Name: ") + id puts "\t" + bold("Certificate Subject(s): ") + certs[id]['subject']['common_name'] + ", " + certs[id]['subject']['organization_name'] + "\n\n" puts underline("Certificate Properties") puts "\t" + bold("Expires: \t") + certs[id]['expires'] + " (" + certs[id]['expire_text'] + ")" puts "\t" + bold("Version: \t") + certs[id]['version'].to_s puts "\t" + bold("Serial: \t") + certs[id]['serial'] if verbose ['subject', 'issuer'].each do |section| puts "\t" + bold(section.capitalize) + ":" subsections = { 'Common Name' => 'common_name', \ 'Organization' => 'organization_name', \ 'Division' => 'division_name', \ 'Locality' => 'locality_name', \ 'State (Prov)' => 'state_name', \ 'Country' => 'country_name' } \ subsections.each do |key, subsection| puts "\t\t\t" + key + ": \t" + certs[id][section][subsection] unless certs[id][section][subsection].empty? end end puts end puts underline("Public Key Properties") puts "\t" + bold("Key Type: ") + certs[id]['key']['type'] puts "\t" + bold("Size: ") + certs[id]['key']['length'].to_s + " (" + certs[id]['key']['length_text'] + ")" puts puts bold_underline(" " * 80) puts end296Views0likes0CommentsRuby Web Accelerator Policy Switcher Class
Problem this snippet solves: The WAPolicySwitcher class will connect to two BIG-IPs and allow for Web Accelerator application policies to be added and removed from a Web Accelerator. In our testing, we use this class to adjust how the web accelerator is dealing with traffic. Important: This class must be called from within a Ruby program. Configuration The following files need to be changed: Edit the bigip-config.ylm and bigip2-config.ylm files to include the addresses and credentials for the two BIG-IPs. Edit the WebAccelerator.Applications.wsdl and WebAccelerator.Applications2.wsdl files to include the correct IP addresses for the two BIG-IPs. (4th to last line in each file) How to use this snippet: Methods: deleteAppPolicy Requires the name of the application to delete. createPolicy Takes the name for the application, the local policy name, the remote policy name, and a list of domain names to use for the application. makePolicySymmetric Takes the name for the application, a single policy name, and a list of one or more host domain names to use for the application. Calls createPolicy. Will use the specified policy for both the local and remote policies. makePolicyAsymmetric Takes the name for the application, a single policy name, and a list of one or more host domain names to use for the application. Calls createPolicy. Will use the specified policy for the local policy and “Symmetric Deployment” for the remote policy. Code : # missing file291Views0likes0Comments