Git Product home page Git Product logo

f5-icontrol's Introduction

F5::Icontrol

Build Status

This is the F5-icontrol gem. If you have an F5, it can use the iControl API to automate things

This is not the official library. That one is here. This copy is without warranty. Heck, it probably doesn't even work.

I originally set out to improve the official one:

  • Improve testing using rspec and vcr
  • Convert to a supported SOAP parser, such as savon
  • Support Ruby 2.0.0 and 2.1.0
  • Make the interface to the library more Ruby-esque

But given the original one was pretty bare-bones, I started over.

Installation

Add this line to your application's Gemfile:

gem 'f5-icontrol'

And then execute:

$ bundle

Or install it yourself as:

$ gem install f5-icontrol

Usage (REST interface)

NOTE: The REST interface is still a work in progress! The conventions may change until we release.

First configure an instance of the API to point to your F5

require 'f5/icontrol'

f5 = F5::Icontrol::RAPI.new username: 'admin', password: 'admin', host: '10.1.1.1'

After that, the calls should line up directly to the API Docs. For collections, use the following methods:

HTTP Verb Method
GET get_collection

Note that get_collection is optional if you call #each or some Enumberable method. So foo.get_collection.each can be shortened to foo.each.

For resources

HTTP Verb Method
GET load
PUT update
DELETE delete
POST create

For example, to get all the pools:

pools = f5.mgmt.tm.ltm.pool.get_collection

puts pools.map(&:name)

# shorter method
puts f5.mgmt.tm.ltm.pool.map(&:name)

It'll also understand subresources:

members = pools.members.load
puts members.map(&:address)

Or, let's create a pool:

api.mgmt.tm.ltm.pool.create(name: 'seanstestrest')

Usage (SOAP interface)

Note - SOAP will likely be deprecated prior to version 1.0 of this gem. The REST interface is more intuitive and dropping SOAP makes this gem so much lighter.

First, configure the gem:

F5::Icontrol.configure do |f|
  f.host = "hostname.of.bigip"
  f.username = "username"
  f.password = "password"
end

Then use it:

api = F5::Icontrol::API.new
response = api.LocalLB.Pool.get_list

or You can configure per api client.

api = F5::Icontrol::API.new(
    host: "hostname.of.bigip",
    username: "username",
    password: "password",
)
response = api.LocalLB.Pool.get_list

See specs subdir for more examples, especially as it pertains to passing parameters.

Logging

This gem uses the Savon client to wrap the SOAP endpoints, and it is sometimes useful to be able to see the SOAP request and response XML.

You can pass in a few options during configuration of the api client which are forwarded to the internal Savon client:

api = F5::Icontrol::API.new(
    host: "hostname.of.bigip",
    username: "username",
    password: "password",

    # Savon logging options
    enable_logging: true,   # defaults to: false
    log_level: :debug,      # defaults to: debug
    pretty_print_xml: true, # defaults to: true
)

CLI

There's a command line version that's still being roughed out. You'll need a ~/.f5.yml file containing your login information:

default:
  host: foo.bar.com
  username: admin
  password: abc123
lb2:
  host: 1.2.3.4
  username: admin
  password: abc123

Then run f5 and it'll provide help

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

f5-icontrol's People

Contributors

davidalpert avatar fspijkerman avatar josh5k avatar mattlqx avatar nikushi avatar steve-medeiros avatar swalberg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

f5-icontrol's Issues

Support everything

Right now we need an object structure that mirrors the API, e.g. F5::Icontrol::LocalLB::Pool. That class is boilerplate that uses method_missing to make the final call, and each of these classes is identical except for the name of the object.

Instead, it should be something along the lines of

api = F5::Icontrol::API.new
api.locallb.pool.get_list()

REST TODO

To get a version out with basic/complete REST support...

  • Support #update to PUT a resource
  • Support #delete to DELETE a resource
  • Rename F5::RAPI to F5::REST
  • Check that we still correctly pull subresources
  • Handle errors ourselves rather than passing through exceptions from rest-client or JSON.

Unable to get more than one iRule to upload

I am trying to upload a list of 4 iRules to a virtual server like so:

        api.LocalLB.VirtualServer.add_rule(
          virtual_servers: { item: [ '/Common/virtual_server'] },
          rules: {
            [
              item: {
                rule_name: '/Common/rule1',
                priority: 1
              },
              item: {
                rule_name: '/Common/rule2',
                priority: 2
              },
              item: {
                rule_name: '/Common/rule3',
                priority: 3
              },
              item: {
                rule_name: '/Common/rule4',
                priority: 4
              }
            ]
          }
        )

However, it is only uploading the last one in the list. Not sure what I am doing wrong, was hoping to get some extra eyes on it.

Unable to get pool members from RAPI

Greetings,
I'm using f5-icontrol 0.3.2 with F5 12.1.0 and 11.5.1 and I'm not able to fetch the members of a pool because we use underscore ( _ ) in our pool name and when I do "pool_members.load", it return me "404 Not Found".
By changing the private method «url» from the class RAPI to not change the underscore for a dash, it works perfectly.

Do you change that character for a particular reason?
Is it possible to disable the character replacement for method_chain when it is a call for members?

P.s.

Thanks.

Remove the need for the user to understand SOAP

Many of the calls expect an array, but between SOAP and Savon we need to do some mangling, e.g.

get_cpu_usage_extended_information(host_ids: { item: ["0-50-56-94-10-19.example.com"] } )

It should either behave as expected:

get_cpu_usage_extended_information(host_ids: ["0-50-56-94-10-19.example.com"])

or there should be some kind of object to wrap that:

get_cpu_usage_extended_information(F5::Icontrol:HostList(["0-50-56-94-10-19.example.com"]))

Leaving this until some of the internals are a bit more solidified. Savon doesn't provide the greatest insight into the requirements of the call so this may be challenging.

LocalLB.VirtualAddressV2.create doesn't work

Gem Version: 0.1.6
F5 Version: BIG-IP 12.1.0 Build 0.0.1434 Final

f5 = F5::Icontrol::API.new(nil,{
    host: "172.16.104.129",
    username: "admin",
    password: "admin"
})
f5.LocalLB.VirtualAddressV2.create(
    virtual_addresses: ["/Common/12.3.4.5"],
    addresses: ["12.3.4.5"],
    netmasks: ["255.255.255.0"]
)

doesn't create a new record.

REST: Calls to objects loaded from references use URLs with redundant info

Took me a little bit to track this down, but I integrated the f5-icontrol gem with my own in-house gem that abstracts a few of our different load balancing brands. Tests ran good in that. And then I upgraded that gem in one of our Chef cookbooks that handles checking pool health. Tests there started getting strange. Pools would load fine, but when I tried to members.load off of that returned object, I got this (note the URL that's actually being called):

     Failure/Error: expect(f5_obj.lb.health_percentage_for_pool('foo')).to eq(1)
     
     WebMock::NetConnectNotAllowedError:
       Real HTTP connections are disabled. Unregistered request: GET https://127.0.0.1/https://127.0.0.1/mgmt/tm/ltm/pool/~Common~foo/members with headers {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Authorization'=>'Basic YWRtaW46Zm9v', 'Host'=>'127.0.0.1', 'User-Agent'=>'rest-client/2.1.0 (darwin16.7.0 x86_64) ruby/2.5.5p157'}
     
       You can stub this request with the following snippet:
     
       stub_request(:get, "https://127.0.0.1/https://127.0.0.1/mgmt/tm/ltm/pool/~Common~foo/members").
         with(
           headers: {
       	  'Accept'=>'*/*',
       	  'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
       	  'Authorization'=>'Basic YWRtaW46Zm9v',
       	  'Host'=>'127.0.0.1',
       	  'User-Agent'=>'rest-client/2.1.0 (darwin16.7.0 x86_64) ruby/2.5.5p157'
           }).
         to_return(status: 200, body: "", headers: {})
     
       registered request stubs:
     
       stub_request(:get, "https://127.0.0.1/mgmt/tm/ltm/pool/~Common~foo/members")
       stub_request(:get, "https://127.0.0.1/mgmt/tm/ltm/pool/foo")
       stub_request(:get, "https://127.0.0.1/mgmt/tm/ltm/pool/")
     
       ============================================================
     # /Users/matt/.chefdk/gem/ruby/2.5.0/gems/webmock-3.7.6/lib/webmock/http_lib_adapters/net_http.rb:114:in `request'
     # /Users/matt/.chefdk/gem/ruby/2.5.0/gems/rest-client-2.1.0/lib/restclient/request.rb:473:in `net_http_do_request'
     # /Users/matt/.chefdk/gem/ruby/2.5.0/gems/rest-client-2.1.0/lib/restclient/request.rb:733:in `block in transmit'
     # /Users/matt/.chefdk/gem/ruby/2.5.0/gems/webmock-3.7.6/lib/webmock/http_lib_adapters/net_http.rb:123:in `start_without_connect'
     # /Users/matt/.chefdk/gem/ruby/2.5.0/gems/webmock-3.7.6/lib/webmock/http_lib_adapters/net_http.rb:150:in `start'
     # /Users/matt/.chefdk/gem/ruby/2.5.0/gems/rest-client-2.1.0/lib/restclient/request.rb:727:in `transmit'
     # /Users/matt/.chefdk/gem/ruby/2.5.0/gems/rest-client-2.1.0/lib/restclient/request.rb:163:in `execute'
     # /Users/matt/.chefdk/gem/ruby/2.5.0/gems/rest-client-2.1.0/lib/restclient/request.rb:63:in `execute'
     # /Users/matt/.chefdk/gem/ruby/2.5.0/gems/f5-icontrol-0.3.5/lib/f5/icontrol/rapi.rb:17:in `load'
...

The problem is here: https://github.com/swalberg/f5-icontrol/blob/4182f7def686df1ba5165acd6446e2ab64017c4c/lib/f5/icontrol/rapi/resource.rb

Everything worked great in my gem's tests suite because it was using localhost as a mock target for testing. But my cookbook's test suite was mocking with 127.0.0.1. I'm not sure the reason why a rigid regex was used to remove the scheme and host portion of the reference link instead of something that matches any host, but any sort of referencing and subsequent loading will fail if the host isn't localhost with the current code.

I'll have a pull coming shortly.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.