Most of the examples we have provided of how to interact with the Abiquo API are written in Python, so now it’s time to put some rubies in our blog. We will show you how to use Ruby to interact with Abiquo APIs. First we will consume events by connecting to the Outbound API, but we will not process event data, we will just use it as a trigger. When we detect a deploy/undeploy action, we will retrieve more information about deployed VMs by calling the REST API.
The purpose of this script will be to modify the novnc_tokens script written by Marc Cirauqui, so instead of running from a cron daemon it will generate the token file every time a deploy or undeploy event is received from the Outbound API. Note that this is a POC and there is no actual benefit of this script over the original one, because deployment time will be greater than the configured cron frequency, but it is fun to play around with Ruby!
Connecting to the Outbound API
Starting to consume events from Abiquo is really easy with em-eventsource gem, a server-sent events consumer library for the event machine. We will handle all event reception in a block like this:
[code lang=”ruby” light=”true”] EM.run do source = EM::EventSource.new(“http://#{@host}/m/stream”, { ‘X-Atmosphere-Transport’ => ‘sse’, ‘X-Atmosphere-Framework’ => ‘1.0’, ‘action’ => ‘DEPLOY,UNDEPLOY’}, { ‘Authorization’ => “Basic #{@auth.strip}” }) source.message do |message| puts “Received event #{message}” get_all_vms end source.error do |error| puts “error #{error}” end source.start end[/code]Note the query params we pass to the API server. We will list Atmosphere parameters but we are only interested in deploy-related events, so we will filter the subscription using the action param. In your implementation, for example, you may be interested in processing events for a specific enterprise or datacenter only.
To simplify this example, we will use HTTP basic authorization to identify ourselves to the API, which is just:
[code lang="ruby" light="true"]@auth = Base64.encode64("#{@user}:#{@pass}").to_s[/code]
We should see the first blank event received message as soon as the consumer is connected. Eventmachine will handle the connection, retry and timeouts.
Querying the Abiquo API
From the eventmachine block that processes the received message, we call a method that will retrieve all deployed VM information and generate the token file. In our daily work we use Ruby to interact with Abiquo, so we have some different classes that use the rest-client gem as a client to handle REST API operations and the Nokogiri gem to parse and extract XML elements (we support JSON in Abiquo 2.6!)
The get_all_vms function looks like this:
[code lang="ruby" light="true"] def get_all_vms() @tokens=[] begin url = "http://#{@host}/api/admin/enterprises" entxml = RestClient::Request.new(:method => :get, :url => url, :user => @user, :password => @pass).execute Nokogiri::XML.parse(entxml).xpath('//enterprises/enterprise').each do |ent| ent.xpath('./link[@rel="virtualmachines"]').each do |entvm| url = entvm.attribute("href").to_s vmxml = RestClient::Request.new(:method => :get, :url => url, :user => @user, :password => @pass).execute Nokogiri::XML.parse(vmxml).xpath('//virtualMachines/virtualMachine').each do |vm| unless vm.at('vdrpIP').nil? or vm.at('vdrpPort').nil? conn = "#{vm.at('vdrpIP').to_str}:#{vm.at('vdrpPort').to_str}" digest = Digest::MD5.hexdigest(conn) line = "#{digest}: #{conn}" @tokens << line #an error occurred, dir not writable etc. end end end end rescue SocketError puts "Cannot connect to specified @host." exit 1 end begin file = File.open(@outputfile, "w") @tokens.each { |line| file.write("#{line}n")} rescue IOError => e #some error occurred, dir not writable etc. ensure file.close end end [/code] To make an API call, just provide a URI and credentials to restclient, which will return the XML entity. You can also provide a specific header to request another format for the returned entity.
[code lang="ruby" light="true"] url = "http://#{@host}/api/admin/enterprises"</div> entxml = RestClient::Request.new(:method => :get, :url => url, :user => @user, :password => @pass).execute[/code]
We get a list of all enterprises accessing the URI.
[code light="true"]http://{abiquo_server}/api/admin/enterprises[/code]
And from each enterprise we get all of its configured virtualmachines from the URI
[code light="true"]http://{abiquo_server}/api/admin/enterprises/{enteprise_id}/action/virtualmachines[/code]
When we have retrieved all the information about all the virtual machines, we extract the VNC connection data with Nokogiri and some XPath magic.