Chat with us, powered by LiveChat

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.

Once all connection data is retrieved, we process the information to generate the token and dump all information to the file that the websockify proxy will read to route incoming connections. You can find the complete script here.