Skip to content

Commit

Permalink
Add XenApi for Xen/XenServer
Browse files Browse the repository at this point in the history
Add support for XenAPI via xenapi-ruby gem.
Initial methods scaffolded from VMWare vSphere and Fog

Tested against XenServer6.1 and 6.0.2

Testing procedure:
```
controller = ::Lab::Controllers::VmController.new
controller.build_from_running(opts)
controller[<name from name_label field of a running VM>]
```

TODO: OpenSSL still refuses to accept self-signed certificates.
Would also be nice to rewire XMLRPC::Client to run over Rex::Socket
This may also help to maintain session keepalives and query many
endpoints conrurrently for faster processing.
  • Loading branch information
RageLtMan committed Mar 21, 2013
1 parent bb2f7cc commit 77332da
Show file tree
Hide file tree
Showing 7 changed files with 318 additions and 84 deletions.
67 changes: 67 additions & 0 deletions lib/lab/controller/xenapi_controller.rb
@@ -0,0 +1,67 @@
require 'xenapi-ruby'

# Ignore certs, this needs to get smarter
# Goes into "use Rex for XMLRPC TODO list"
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE

module Lab
module Controllers
module XenApiController

# Get vm UUIDs and pull info hashes
def self.vm_list_all(user,host,pass,running_only=false)
s = self.get_xapi_session(user,host,pass)
vms = []
s.VM.get_all.map do |vref|
vm = s.VM.get_record(vref)
next if vm['is_a_template'] or vm['s_a_snapshot'] or vm['name_label'].match(/^Control domain/)
vms << vm.merge('vmid' => vref)
end

return running_only ? vms.keep_if {|v| v['power_state'] == 'Running'} : vms
end

# Get SR UUIDs and pull info hashes
def self.sr_list_all(user,host,pass)
s = self.get_xapi_session(user,host,pass)
return s.SR.get_all.map {|srid| s.SR.get_record(srid)}
end

# Compat method wrappers

def self.running_list(user,host,pass)
self.vm_list_all(user,host,pass,true)
end

def self.config_list
end

def self.storage_list
end

def self.hosts_list
end

def self.dir_list
end

private

def self.get_xapi_session(user,host,pass,port=443)
begin
# Try SSL with port
s = XenAPI::Session.new("https://#{host}:#{port}")
s.login_with_password(user,pass)
rescue
# Miserable HTTP on 80 faildown
s = XenAPI::Session.new("http://#{host}")
s.login_with_password(user,pass)
return s
end
# If this is somehow nil we will get upstream errors
return s
end

end
end
end
1 change: 1 addition & 0 deletions lib/lab/controllers.rb
Expand Up @@ -5,5 +5,6 @@
require 'controller/remote_workstation_controller'
require 'controller/remote_esxi_controller'
require 'controller/vsphere_controller'
require 'controller/xenapi_controller'
#require 'controller/qemu_controller'
#require 'controller/qemudo_controller'
30 changes: 15 additions & 15 deletions lib/lab/driver/vm_driver.rb
Expand Up @@ -5,19 +5,19 @@
#
# !!WARNING!! - All drivers are expected to filter input before running
# anything based on it. This is particularly important in the case
# of the drivers which wrap a command line to provide functionality.
# of the drivers which wrap a command line to provide functionality.
#

module Lab
module Drivers
class VmDriver

attr_accessor :vmid
attr_accessor :vmid
attr_accessor :location
attr_accessor :os
attr_accessor :tools
attr_accessor :credentials

def initialize(config)

@vmid = filter_command(config["vmid"].to_s)
Expand All @@ -42,7 +42,7 @@ def initialize(config)
def register
raise "Command not Implemented"
end

def unregister
raise "Command not Implemented"
end
Expand Down Expand Up @@ -83,14 +83,14 @@ def delete_snapshot(snapshot)
raise "Command not Implemented"
end

def run_command(command)
def run_command(command)
raise "Command not Implemented"
end

def copy_from(from, to)
raise "Command not Implemented"
end

def copy_to(from, to)
raise "Command not Implemented"
end
Expand Down Expand Up @@ -137,9 +137,9 @@ def scp_to(local,remote)
puts "DEBUG: uploading #{local} to #{remote}"
scp.upload!(local,remote)
end
end
end
end

def scp_from(remote, local)
# download a file from a remote server
if @vm_keyfile
Expand All @@ -155,7 +155,7 @@ def scp_from(remote, local)
end
end
end

def ssh_exec(command)
if @vm_keyfile
#puts "DEBUG: authenticating to #{@hostname} as #{@vm_user} with key #{@vm_keyfile}"
Expand All @@ -173,18 +173,18 @@ def ssh_exec(command)
def filter_input(string)
return "" unless string # nil becomes empty string
return unless string.class == String # Allow other types unmodified
unless /^[\d\w\s\[\]\{\}\/\\\.\-\"\(\):!]*$/.match string

unless /^[\:\d\w\s\[\]\{\}\/\\\.\-\"\(\):!]*$/.match string
raise "WARNING! Invalid character in: #{string}"
end
string
end

def filter_command(string)
return "" unless string # nil becomes empty string
return unless string.class == String # Allow other types unmodified
unless /^[\d\w\s\[\]\{\}\/\\\.\-\"\(\)]*$/.match string
return unless string.class == String # Allow other types unmodified

unless /^[\:\d\w\s\[\]\{\}\/\\\.\-\"\(\)]*$/.match string
raise "WARNING! Invalid character in: #{string}"
end
string
Expand Down
150 changes: 150 additions & 0 deletions lib/lab/driver/xenapi_driver.rb
@@ -0,0 +1,150 @@
require 'vm_driver'

##
## $Id$
##

# This driver was built against:
# XenServer 6.1 and 6.0.2

module Lab
module Drivers

class XenApiDriver < VmDriver


def initialize(config)
unless config['user'] then raise ArgumentError, "Must provide a username" end
unless config['host'] then raise ArgumentError, "Must provide a hostname" end
unless config['pass'] then raise ArgumentError, "Must provide a password" end
super(config)

# Load XenAPI
begin
require 'xenapi-ruby'
rescue LoadError
raise "WARNING: Library xenapi-ruby not found. Could not create driver!"
end

@user = filter_command(config['user'])
@host = filter_command(config['host'])
@pass = config['pass']
@port = filter_input(config['port']) || nil

@vm = ensure_xen_session.VM.get_record(@vmid) or fail "VM not found"
end

def start
ensure_xen_session.VM.start @vmid
end

def stop
ensure_xen_session.VM.stop @vmid
end

def suspend
ensure_xen_session.VM.susupend @vmid
end

def pause
ensure_xen_session.VM.pause @vmid
end

def resume
ensure_xen_session.VM.resume @vmid
end

def reset
ensure_xen_session.VM.power_state_reset @vmid
end

def create_snapshot(snapshot)
snapshot = filter_input(snapshot)
begin
snap_res = ensure_xen_session.VM.snapshot_with_quiesce(@vmid,snapshot)
rescue
snap_res = ensure_xen_session.VM.snapshot(@vmid,snapshot)
end
return snap_res
end

def revert_snapshot(snapshot)
snapshot = filter_input(snapshot)
ensure_xen_session.VM.revert(snapshot)
end

def delete_snapshot(snapshot, remove_children=false)
raise "Unimplemented"
# If we got here, the snapshot didn't exist
raise "Invalid Snapshot Name"
end

def delete_all_snapshots
raise "Unimplemented"
end

def run_command(command)
raise "Unimplemented"
end

def copy_from(from, to)
if @os == "linux"
scp_from(from, to)
else
raise "Unimplemented"
end
end

def copy_to(from, to)
if @os == "linux"
scp_to(from, to)
else
raise "Unimplemented"
end
end

def check_file_exists(file)
raise "Unimplemented"
end

def create_directory(directory)
raise "Unimplemented"
end

def cleanup
raise "Unimplemented"
end

def running?
raise "Unimplemented"
end

def xen_info_hash
@vm
end

def ensure_xen_session
# HTTP/HTTPS XMLRPC session and auth
# This block ensures the session lives and we dont keep starting new ones
begin
@xen_session.VM.get_all
rescue
@xen_session = Lab::Controllers::XenApiController.get_xapi_session(
@user,
@host,
@pass,
@port
)
end
@xen_session
end

# Pass VM.get_all to test
def raw_api_call(sttring)
eval "ensure_xen_session.#{string}"
end

end

end
end
1 change: 1 addition & 0 deletions lib/lab/drivers.rb
Expand Up @@ -5,5 +5,6 @@
require 'driver/remote_workstation_driver'
require 'driver/remote_esxi_driver'
require 'driver/vsphere_driver'
require 'driver/xenapi_driver'
#require 'driver/qemu_driver'
#require 'driver/qemudo_driver'

0 comments on commit 77332da

Please sign in to comment.