Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge pull request #1432 from rubiojr/new-xenserver-features

New xenserver features and examples
  • Loading branch information...
commit 9db7f34aa8119c16a6908416dbb3de186b215a05 2 parents e21a308 + 731ba25
Sergio Rubio authored
3  lib/fog/xenserver/compute.rb
View
@@ -60,6 +60,9 @@ class XenServer < Fog::Service
request :reboot_server
request :provision_server
request :scan_sr
+ request :unplug_pbd
+ request :destroy_sr
+ request :create_sr
class Real
99 lib/fog/xenserver/examples/chage_default_storage_repository.md
View
@@ -0,0 +1,99 @@
+# How To Change the Default Storage Repository to File-based VHD-on-EXT3
+
+**NOTE: Requires fog > 1.8 (currently in development as of this writing)**
+
+This tutorial explains how to convert a local Logical Volume Manager (LVM)
+based storage repository into a file-based (VHD) storage repository.
+
+It's the fog/xenserver version of the original Citrix KB article:
+
+http://support.citrix.com/article/ctx116324
+
+To create this tutorial, I've used a vanilla XCP 1.6 ISO install in VirtualBox.
+
+## Create the connection
+
+```ruby
+require 'fog'
+
+conn = Fog::Compute.new({
+ :provider => 'XenServer',
+ :xenserver_url => '192.168.1.39',
+ :xenserver_username => 'root',
+ :xenserver_password => 'secret'
+})
+```
+
+## Remove the LVM-backed storage repository (SR).
+
+Find the default LVM storage repository:
+
+```ruby
+#
+# Equivalent to:
+# xe sr-list type=lvm
+#
+lvm_sr = nil
+conn.storage_repositories.each do |sr|
+ lvm_sr = sr if sr.type == 'lvm'
+end
+```
+
+Determine the UUID for your default SR's physical block device:
+
+```ruby
+#
+# Equivalent to:
+# xe pbd-list sr-uuid=your SR UUID
+#
+if lvm_sr
+ conn.pbds.each do |pbd|
+ # Unplug it if found
+ # Equivalent to:
+ # xe pbd-unplug uuid=your PBD UUID
+ #
+ pbd.unplug if pbd.storage_repository.uuid == lvm_sr.uuid
+ end
+ # Destroy the SR
+ lvm_sr.destroy
+end
+```
+
+Create a new VHD-backed SR:
+
+```ruby
+#
+# Equivalent to:
+#
+# xe sr-create content-type="local SR" \
+# host-uuid=5d189b7a-cd5e-4029-9940-d4daaa34633d \
+# type=ext device-config-device=/dev/sda3 shared=false \
+# name-label="Local File SR"
+#
+sr = conn.storage_repositories.create :name => 'Local File SR',
+ :host => conn.hosts.first,
+ :type => 'ext',
+ :content_type => 'local SR',
+ :device_config => { :device => '/dev/sda3' },
+ :shared => false
+```
+
+Set your SR as the default SR on the system:
+
+```ruby
+#
+# Equivalent command:
+# xe pool-param-set suspend-image-SR='YOUR NEW SR UUID' uuid=bleh
+#
+conn.pools.first.default_storage_repository = sr
+```
+
+Set your SR as the default location for suspended VM images:
+
+```ruby
+#
+# Equivalent command:
+# xe pool-param-set suspend-image-SR= YOUR NEW SR UUID uuid=bleh
+#
+conn.pools.first.suspend_image_sr = sr
+```
5 lib/fog/xenserver/models/compute/pbd.rb
View
@@ -13,6 +13,7 @@ class PBD < Fog::Model
attribute :uuid
attribute :__host, :aliases => :host
attribute :__sr, :aliases => :SR
+ attribute :currently_attached
def sr
connection.storage_repositories.get __sr
@@ -25,6 +26,10 @@ def storage_repository
def host
connection.hosts.get __host
end
+
+ def unplug
+ connection.unplug_pbd reference
+ end
end
22 lib/fog/xenserver/models/compute/pool.rb
View
@@ -19,19 +19,41 @@ class Pool < Fog::Model
attribute :restrictions
attribute :ha_enabled
attribute :vswitch_controller
+ attribute :__suspend_image_sr, :aliases => :suspend_image_SR
def default_sr
connection.storage_repositories.get __default_sr
end
+ def default_sr=(sr)
+ connection.set_attribute( 'pool', reference, 'default_SR', sr.reference )
+ end
+ alias :default_storage_repository= :default_sr=
+
def default_storage_repository
default_sr
end
+ def suspend_image_sr=(sr)
+ connection.set_attribute( 'pool', reference, 'suspend_image_SR', sr.reference )
+ end
+
+ def suspend_image_sr
+ connection.storage_repositories.get __suspend_image_sr
+ end
+
def master
connection.hosts.get __master
end
+
+ def set_attribute(name, *val)
+ data = connection.set_attribute( 'pool', reference, name, *val )
+ # Do not reload automatically for performance reasons
+ # We can set multiple attributes at the same time and
+ # then reload manually
+ #reload
+ end
end
43 lib/fog/xenserver/models/compute/storage_repository.rb
View
@@ -40,6 +40,49 @@ def scan
reload
end
+ def destroy
+ connection.destroy_sr reference
+ end
+
+ def save
+ requires :name
+ requires :type
+
+ # host is not a model attribute (not in XAPI at least),
+ # but we need it here
+ host = attributes[:host]
+ raise ArgumentError.new('host is required for this operation') unless
+ host
+
+ # Not sure if this is always required, so not raising exception if nil
+ device_config = attributes[:device_config]
+
+ # create_sr request provides sane defaults if some attributes are
+ # missing
+ attr = connection.get_record(
+ connection.create_sr( host.reference,
+ name,
+ type,
+ description,
+ device_config,
+ physical_size,
+ content_type,
+ shared || false,
+ sm_config),
+ 'SR'
+ )
+ merge_attributes attr
+ true
+ end
+
+ def set_attribute(name, *val)
+ data = connection.set_attribute( 'SR', reference, name, *val )
+ # Do not reload automatically for performance reasons
+ # We can set multiple attributes at the same time and
+ # then reload manually
+ #reload
+ end
+
end
end
72 lib/fog/xenserver/requests/compute/create_sr.rb
View
@@ -0,0 +1,72 @@
+module Fog
+ module Compute
+ class XenServer
+
+ class Real
+
+ #
+ # Create a storage repository (SR)
+ #
+ # @see http://docs.vmd.citrix.com/XenServer/6.0.0/1.0/en_gb/api/?c=SR
+ #
+ # @param [String] host_ref host reference
+ # @param [String] name_label repository label
+ # @param [String] type storage repository type
+ # @param [String] name_description storage repository description
+ # @param [Hash] device_config used to specify block device path, like
+ # { :device => /dev/sdb } for example
+ # @param [String] physical_size '0' will use the whole device (FIXME
+ # needs confirmation)
+ # @param [String] content_type the type of the SR's content.
+ # According to Citrix documentation, used only to distinguish ISO
+ # libraries from other SRs. Set it to 'iso' for storage repositories
+ # that store a library of ISOs, 'user' or '' (empty) otherwise.
+ # @see http://docs.vmd.citrix.com/XenServer/6.1.0/1.0/en_gb/reference.html#cli-xe-commands_sr
+ # @param [String] shared
+ #
+ # @return [String] an OpaqueRef to the storage repository
+ def create_sr( host_ref,
+ name_label,
+ type,
+ name_description = '',
+ device_config = {},
+ physical_size = '0',
+ content_type = 'user',
+ shared = false,
+ sm_config = {} )
+
+ @connection.request(
+ {:parser => Fog::Parsers::XenServer::Base.new, :method => 'SR.create'},
+ host_ref,
+ device_config || {},
+ physical_size || '0',
+ name_label,
+ name_description || '',
+ type,
+ content_type,
+ shared || false,
+ sm_config || {}
+ )
+ end
+
+ end
+
+ class Mock
+
+ def create_sr( host_ref,
+ name_label,
+ type,
+ name_description = nil,
+ device_config = {},
+ physical_size = '0',
+ content_type = nil,
+ shared = false,
+ sm_config = {} )
+ Fog::Mock.not_implemented
+ end
+
+ end
+
+ end
+ end
+end
30 lib/fog/xenserver/requests/compute/destroy_sr.rb
View
@@ -0,0 +1,30 @@
+module Fog
+ module Compute
+ class XenServer
+
+ class Real
+
+ #
+ # Destroy a Storage Repository
+ #
+ # http://docs.vmd.citrix.com/XenServer/6.0.0/1.0/en_gb/api/?c=SR
+ #
+ def destroy_sr( sr_ref )
+ @connection.request(
+ {:parser => Fog::Parsers::XenServer::Base.new, :method => 'SR.destroy'},
+ sr_ref
+ )
+ end
+
+ end
+
+ class Mock
+
+ def destroy_sr( sr_ref )
+ Fog::Mock.not_implemented
+ end
+
+ end
+ end
+ end
+end
25 lib/fog/xenserver/requests/compute/unplug_pbd.rb
View
@@ -0,0 +1,25 @@
+module Fog
+ module Compute
+ class XenServer
+
+ class Real
+
+ def unplug_pbd( ref )
+ @connection.request(
+ {:parser => Fog::Parsers::XenServer::Base.new, :method => 'PBD.unplug'},
+ ref
+ )
+ end
+
+ end
+
+ class Mock
+
+ def unplug_pbd( ref )
+ Fog::Mock.not_implemented
+ end
+
+ end
+ end
+ end
+end
34 tests/xenserver/models/compute/pbd_tests.rb
View
@@ -6,6 +6,7 @@
tests('The PBD model should') do
tests('have the action') do
test('reload') { pbd.respond_to? 'reload' }
+ test('unplug') { pbd.respond_to? 'reload' }
end
tests('have attributes') do
model_attribute_hash = pbd.attributes
@@ -13,7 +14,8 @@
:reference,
:uuid,
:__host,
- :__sr
+ :__sr,
+ :currently_attached
]
tests("The PBD model should respond to") do
attributes.each do |attribute|
@@ -38,6 +40,36 @@
tests("return valid storage repository") do
test("should be a Fog::Compute::XenServer::StorageRepository") { pbd.storage_repository.kind_of? Fog::Compute::XenServer::StorageRepository }
end
+ # FIXME: find a better way (faster, lighter) to tests this
+ tests("be plugged or unplugged") do
+ compute = Fog::Compute[:xenserver]
+ # Create a storage repository only to tests PBD.unplug
+ ref = compute.create_sr compute.hosts.first.reference,
+ 'FOG TEST SR',
+ 'ext',
+ '',
+ { :device => '/dev/sdb' },
+ '0',
+ 'user',
+ false,
+ {}
+ sr = compute.storage_repositories.find { |sr| sr.name == 'FOG TEST SR' }
+ pbd = sr.pbds.first
+ test('plugged') do
+ pbd.currently_attached == true
+ end
+ pbd.unplug
+ pbd.reload
+ test('unplugged') do
+ pbd.currently_attached == false
+ end
+ # Clean-up
+ compute.storage_repositories.each do |sr|
+ next unless sr.name == 'FOG TEST SR'
+ sr.pbds.each { |pbd| pbd.unplug }
+ sr.destroy
+ end
+ end
end
8 tests/xenserver/models/compute/pool_tests.rb
View
@@ -19,7 +19,8 @@
:tags,
:restrictions,
:ha_enabled,
- :vswitch_controller
+ :vswitch_controller,
+ :__suspend_image_sr
]
tests("The Pool model should respond to") do
attributes.each do |attribute|
@@ -44,6 +45,11 @@
tests("return valid Host as the master") do
test("should be a Fog::Compute::XenServer::Host") { pool.master.kind_of? Fog::Compute::XenServer::Host }
end
+ test("be able to be configured as a valid suspend_image_sr") do
+ pool.suspend_image_sr = pool.default_storage_repository
+ pool.reload
+ pool.suspend_image_sr.reference == pool.default_storage_repository.reference
+ end
end
26 tests/xenserver/models/compute/storage_repository_tests.rb
View
@@ -6,6 +6,9 @@
tests('The StorageRepository model should') do
tests('have the action') do
test('reload') { storage_repository.respond_to? 'reload' }
+ test('destroy') { storage_repository.respond_to? 'destroy' }
+ test('scan') { storage_repository.respond_to? 'scan' }
+ test('save') { storage_repository.respond_to? 'save' }
end
tests('have attributes') do
model_attribute_hash = storage_repository.attributes
@@ -25,7 +28,9 @@
:tags,
:__vdis,
:physical_size,
- :physical_utilisation
+ :physical_utilisation,
+ :virtual_allocation,
+ :sm_config
]
tests("The StorageRepository model should respond to") do
attributes.each do |attribute|
@@ -60,4 +65,23 @@
end
end
+ test('#save') do
+ conn = Fog::Compute[:xenserver]
+ sr = conn.storage_repositories.create :name => 'FOG TEST SR',
+ :host => conn.hosts.first,
+ :type => 'ext',
+ :content_type => 'local SR',
+ :device_config => { :device => '/dev/sdb' },
+ :shared => false
+ !(conn.storage_repositories.find { |sr| sr.name == 'FOG TEST SR' }).nil?
+ end
+
+ test('#destroy') do
+ conn = Fog::Compute[:xenserver]
+ sr = (conn.storage_repositories.find { |sr| sr.name == 'FOG TEST SR' })
+ sr.pbds.each { |pbd| pbd.unplug }
+ sr.destroy
+ (conn.storage_repositories.find { |sr| sr.name == 'FOG TEST SR' }).nil?
+ end
+
end
54 tests/xenserver/requests/compute/create_sr_tests.rb
View
@@ -0,0 +1,54 @@
+#
+# @rubiojr
+#
+# Testing this requires a very specific setup:
+#
+# I use VirtualBox to virtualize XenServer/XCP and create the XenServer VM using
+# two virtual disks under the same SATA controller. One of the virtual disks
+# will be /dev/sdb, used to perform the tests.
+#
+
+Shindo.tests('Fog::Compute[:xenserver] | create_sr request', ['xenserver']) do
+
+ compute = Fog::Compute[:xenserver]
+
+ tests('#create_sr "FOG TEST SR" with device /dev/sdb') do
+ test('create an EXT SR') do
+ ref = compute.create_sr compute.hosts.first.reference,
+ 'FOG TEST SR',
+ 'ext',
+ '',
+ { :device => '/dev/sdb' },
+ '0',
+ 'user',
+ false,
+ {}
+ valid_ref? ref
+ end
+
+ raises(Fog::XenServer::RequestFailed, 'raise when device in use') do
+ ref = compute.create_sr compute.hosts.first.reference,
+ 'FOG TEST SR',
+ 'ext',
+ '',
+ { :device => '/dev/sdb' },
+ '0',
+ 'user',
+ false,
+ {}
+ valid_ref? ref
+ end
+ end
+
+ tests('The expected options') do
+ raises(ArgumentError, 'raises ArgumentError when arguments missing') { compute.create_sr }
+ end
+
+ # Clean-up
+ compute.storage_repositories.each do |sr|
+ next unless sr.name == 'FOG TEST SR'
+ sr.pbds.each { |pbd| pbd.unplug }
+ sr.destroy
+ end
+
+end
46 tests/xenserver/requests/compute/destroy_sr_tests.rb
View
@@ -0,0 +1,46 @@
+#
+# @rubiojr
+#
+# Testing this requires a very specific setup:
+#
+# I use VirtualBox to virtualize XenServer/XCP and create the XenServer VM using
+# two virtual disks under the same SATA controller. One of the virtual disks
+# will be /dev/sdb, used to perform the tests.
+#
+
+Shindo.tests('Fog::Compute[:xenserver] | destroy_sr request', ['xenserver']) do
+
+ compute = Fog::Compute[:xenserver]
+ # We need the SR available for this to work, so create it first
+ ref = compute.create_sr compute.hosts.first.reference,
+ 'FOG TEST SR',
+ 'ext',
+ '',
+ { :device => '/dev/sdb' },
+ '0',
+ 'user',
+ false,
+ {}
+
+ tests('#destroy_sr') do
+ test('destroyed "FOG TEST SR"') do
+ compute.storage_repositories.each do |sr|
+ next unless sr.name == 'FOG TEST SR'
+ sr.pbds.each { |pbd| pbd.unplug }
+ end
+ compute.destroy_sr ref
+ (compute.storage_repositories.find { |sr| sr.name == 'FOG TEST SR' }).nil?
+ end
+
+ raises(Fog::XenServer::RequestFailed,
+ 'raises HandleInvalid trying to destroy it twice') do
+ compute.destroy_sr ref
+ end
+ end
+
+ tests('The expected options') do
+ raises(ArgumentError, 'raises ArgumentError when arguments missing') \
+ { compute.destroy_sr }
+ end
+
+end
48 tests/xenserver/requests/compute/unplug_pbd_tests.rb
View
@@ -0,0 +1,48 @@
+#
+# @rubiojr
+#
+# Testing this requires a very specific setup:
+#
+# I use VirtualBox to virtualize XenServer/XCP and create the XenServer VM using
+# two virtual disks under the same SATA controller. One of the virtual disks
+# will be /dev/sdb, used to perform the tests.
+#
+
+Shindo.tests('Fog::Compute[:xenserver] | unplug_pbd request', ['xenserver']) do
+
+ compute = Fog::Compute[:xenserver]
+ # Creating a new SR automatically plugs the PBD
+ # We need the SR available for this to work, so create it first
+ ref = compute.create_sr compute.hosts.first.reference,
+ 'FOG TEST SR',
+ 'ext',
+ '',
+ { :device => '/dev/sdb' },
+ '0',
+ 'user',
+ false,
+ {}
+
+ tests('#unplug_pbd') do
+ test('unplugged') do
+ sr = compute.storage_repositories.find { |sr| sr.name == 'FOG TEST SR' }
+ pbd = sr.pbds.first
+ compute.unplug_pbd pbd.reference
+ pbd.reload
+ pbd.currently_attached == false
+ end
+ end
+
+ tests('The expected options') do
+ raises(ArgumentError, 'raises ArgumentError when arguments missing') \
+ { compute.unplug_pbd }
+ end
+
+ # Clean-up
+ compute.storage_repositories.each do |sr|
+ next unless sr.name == 'FOG TEST SR'
+ sr.pbds.each { |pbd| pbd.unplug }
+ sr.destroy
+ end
+
+end
Please sign in to comment.
Something went wrong with that request. Please try again.