libvirt 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.md +5 -0
- data/Gemfile.lock +6 -6
- data/Rakefile +21 -0
- data/lib/libvirt/connection.rb +1 -1
- data/lib/libvirt/domain.rb +8 -0
- data/lib/libvirt/exception.rb +9 -0
- data/lib/libvirt/spec.rb +1 -0
- data/lib/libvirt/spec/device.rb +27 -0
- data/lib/libvirt/spec/device/disk.rb +25 -5
- data/lib/libvirt/spec/device/graphics.rb +39 -0
- data/lib/libvirt/spec/device/input.rb +40 -0
- data/lib/libvirt/spec/device/interface.rb +47 -0
- data/lib/libvirt/spec/device/sound.rb +32 -0
- data/lib/libvirt/spec/device/video.rb +47 -0
- data/lib/libvirt/spec/device/video_model.rb +53 -0
- data/lib/libvirt/spec/domain.rb +80 -5
- data/lib/libvirt/spec/domain/clock.rb +35 -0
- data/lib/libvirt/spec/domain/memtune.rb +29 -0
- data/lib/libvirt/spec/domain/os_booting.rb +27 -1
- data/lib/libvirt/spec/util.rb +43 -0
- data/lib/libvirt/version.rb +1 -1
- data/libvirt.gemspec +3 -4
- data/test/libvirt/domain_test.rb +6 -0
- data/test/libvirt/spec/device_test.rb +21 -0
- data/test/libvirt/spec/devices/disk_test.rb +21 -87
- data/test/libvirt/spec/devices/graphics_test.rb +25 -0
- data/test/libvirt/spec/devices/input_test.rb +25 -0
- data/test/libvirt/spec/devices/interface_test.rb +35 -0
- data/test/libvirt/spec/devices/sound_test.rb +20 -0
- data/test/libvirt/spec/devices/video_model_test.rb +36 -0
- data/test/libvirt/spec/domain/clock_test.rb +20 -0
- data/test/libvirt/spec/domain/os_booting_test.rb +31 -0
- data/test/libvirt/spec/domain_test.rb +123 -1
- metadata +32 -7
data/lib/libvirt/spec/domain.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
|
+
require 'libvirt/spec/domain/clock'
|
2
|
+
require 'libvirt/spec/domain/memtune'
|
1
3
|
require 'libvirt/spec/domain/os_booting'
|
2
4
|
|
3
5
|
module Libvirt
|
4
6
|
module Spec
|
5
7
|
# A specification of a domain. This translates directly down to XML
|
6
8
|
# which can be used to define and launch domains on a node by libvirt.
|
7
|
-
#
|
8
|
-
# **Note:** This class may only be temporary, and the functionality
|
9
|
-
# may be merged back into {Domain}. Also, the interface will likely
|
10
|
-
# change.
|
11
9
|
class Domain
|
10
|
+
include Util
|
11
|
+
|
12
12
|
attr_accessor :hypervisor
|
13
13
|
attr_accessor :name
|
14
14
|
attr_accessor :uuid
|
@@ -16,17 +16,72 @@ module Libvirt
|
|
16
16
|
attr_accessor :os
|
17
17
|
attr_accessor :memory
|
18
18
|
attr_accessor :current_memory
|
19
|
+
attr_accessor :memory_backing
|
20
|
+
attr_accessor :memtune
|
19
21
|
attr_accessor :vcpu
|
22
|
+
attr_accessor :features
|
20
23
|
|
21
24
|
attr_accessor :on_poweroff
|
22
25
|
attr_accessor :on_reboot
|
23
26
|
attr_accessor :on_crash
|
24
27
|
|
28
|
+
attr_accessor :clock
|
25
29
|
attr_accessor :devices
|
26
30
|
|
27
|
-
|
31
|
+
# Initializes a domain specification. If a valid XML string for a domain
|
32
|
+
# is given, the it will attempt to be parsed into the structure. This
|
33
|
+
# is still very experimental. As such, if there is something which is
|
34
|
+
# found which is not parseable, an {Exception::UnparseableSpec} exception
|
35
|
+
# will be raised. Catch this and inspect the message for more information.
|
36
|
+
#
|
37
|
+
# @param [String] xml XML spec to attempt to parse into the structure.
|
38
|
+
def initialize(xml=nil)
|
28
39
|
@os = OSBooting.new
|
40
|
+
@memtune = Memtune.new
|
41
|
+
@features = []
|
42
|
+
@clock = Clock.new
|
29
43
|
@devices = []
|
44
|
+
|
45
|
+
load!(xml) if xml
|
46
|
+
end
|
47
|
+
|
48
|
+
# Attempts to load the attributes from an XML specification. **Warning:
|
49
|
+
# this will overwrite any already set attributes which exist in the XML.**
|
50
|
+
#
|
51
|
+
# @param [String] xml XML spec to attempt to parse into the structure.
|
52
|
+
def load!(xml)
|
53
|
+
root = Nokogiri::XML(xml).root
|
54
|
+
try(root.xpath("//domain[@type]"), :preserve => true) { |result| self.hypervisor = result["type"].to_sym }
|
55
|
+
try(root.xpath("//domain/name")) { |result| self.name = result.text }
|
56
|
+
try(root.xpath("//domain/uuid")) { |result| self.uuid = result.text }
|
57
|
+
try(root.xpath("//domain/memory")) { |result| self.memory = result.text }
|
58
|
+
try(root.xpath("//domain/currentMemory")) { |result| self.current_memory = result.text }
|
59
|
+
try(root.xpath("//domain/vcpu")) { |result| self.vcpu = result.text }
|
60
|
+
|
61
|
+
try(root.xpath("//domain/on_poweroff")) { |result| self.on_poweroff = result.text.to_sym }
|
62
|
+
try(root.xpath("//domain/on_reboot")) { |result| self.on_reboot = result.text.to_sym }
|
63
|
+
try(root.xpath("//domain/on_crash")) { |result| self.on_crash = result.text.to_sym }
|
64
|
+
|
65
|
+
try(root.xpath("//domain/clock")) { |result| self.clock = Clock.new(result) }
|
66
|
+
try(root.xpath("//domain/os")) { |result| self.os = OSBooting.new(result) }
|
67
|
+
|
68
|
+
try(root.xpath("//domain/devices")) do |result|
|
69
|
+
self.devices = []
|
70
|
+
|
71
|
+
result.element_children.each do |device|
|
72
|
+
self.devices << Device.load!(device)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
try(root.xpath("//domain/features")) do |result|
|
77
|
+
self.features = []
|
78
|
+
|
79
|
+
result.element_children.each do |feature|
|
80
|
+
self.features << feature.name.to_sym
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
raise_if_unparseables(root.xpath("//domain/*"))
|
30
85
|
end
|
31
86
|
|
32
87
|
# Returns the XML for this specification. This XML may be passed
|
@@ -52,11 +107,31 @@ module Libvirt
|
|
52
107
|
xml.currentMemory current_memory if current_memory
|
53
108
|
xml.vcpu vcpu if vcpu
|
54
109
|
|
110
|
+
if memory_backing == :huge_pages
|
111
|
+
xml.memoryBacking do
|
112
|
+
xml.hugepages
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Memtune handles whether or not to render itself
|
117
|
+
memtune.to_xml(xml)
|
118
|
+
|
119
|
+
if !features.empty?
|
120
|
+
xml.features do
|
121
|
+
features.each do |feature|
|
122
|
+
xml.send(feature)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
55
127
|
# Lifecycle control
|
56
128
|
xml.on_poweroff on_poweroff if on_poweroff
|
57
129
|
xml.on_reboot on_reboot if on_reboot
|
58
130
|
xml.on_crash on_crash if on_crash
|
59
131
|
|
132
|
+
# Clock
|
133
|
+
clock.to_xml(xml)
|
134
|
+
|
60
135
|
# Devices
|
61
136
|
if !devices.empty?
|
62
137
|
xml.devices do
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Libvirt
|
2
|
+
module Spec
|
3
|
+
class Domain
|
4
|
+
# Time keeping configuration for a domain.
|
5
|
+
class Clock
|
6
|
+
include Util
|
7
|
+
|
8
|
+
attr_accessor :offset
|
9
|
+
|
10
|
+
# Initializes a clock specification. This should never be called
|
11
|
+
# directly. Instead, use a {Libvirt::Spec::Domain} spec, which
|
12
|
+
# contains a clock attribute.
|
13
|
+
def initialize(xml=nil)
|
14
|
+
load!(xml) if xml
|
15
|
+
end
|
16
|
+
|
17
|
+
# Loads clock information from the given XML string. This shouldn't
|
18
|
+
# be called directly, since the domain spec automatically calls
|
19
|
+
# this.
|
20
|
+
def load!(root)
|
21
|
+
root = Nokogiri::XML(root).root if !root.is_a?(Nokogiri::XML::Element)
|
22
|
+
try(root.xpath("//clock[@offset]"), :preserve => true) { |result| self.offset = result["offset"].to_sym }
|
23
|
+
raise_if_unparseables(root.xpath("//clock/*"))
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_xml(parent=Nokogiri::XML::Builder.new)
|
27
|
+
return if !offset
|
28
|
+
|
29
|
+
parent.clock :offset => offset
|
30
|
+
parent.to_xml
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Libvirt
|
2
|
+
module Spec
|
3
|
+
class Domain
|
4
|
+
# Allows the modification of details regarding the memory tuneable
|
5
|
+
# parameters for this domain.
|
6
|
+
class Memtune
|
7
|
+
attr_accessor :hard_limit
|
8
|
+
attr_accessor :soft_limit
|
9
|
+
attr_accessor :swap_hard_limit
|
10
|
+
attr_accessor :min_guarantee
|
11
|
+
|
12
|
+
def to_xml(parent=Nokogiri::XML::Builder.new)
|
13
|
+
# If nothing has been modified, then don't do anything
|
14
|
+
return if !hard_limit && !soft_limit &&
|
15
|
+
!swap_hard_limit && !min_guarantee
|
16
|
+
|
17
|
+
parent.memtune do |m|
|
18
|
+
m.hard_limit hard_limit if hard_limit
|
19
|
+
m.soft_limit soft_limit if soft_limit
|
20
|
+
m.swap_hard_limit swap_hard_limit if swap_hard_limit
|
21
|
+
m.min_guarantee min_guarantee if min_guarantee
|
22
|
+
end
|
23
|
+
|
24
|
+
parent.to_xml
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -11,6 +11,8 @@ module Libvirt
|
|
11
11
|
#
|
12
12
|
# TODO: Host bootloader and direct kernel bootloader options.
|
13
13
|
class OSBooting
|
14
|
+
include Util
|
15
|
+
|
14
16
|
attr_accessor :type
|
15
17
|
attr_accessor :arch
|
16
18
|
attr_accessor :loader # Part of the BIOS bootloader
|
@@ -26,8 +28,13 @@ module Libvirt
|
|
26
28
|
attr_accessor :initrd
|
27
29
|
attr_accessor :cmdline
|
28
30
|
|
29
|
-
|
31
|
+
# Initializes an OS booting specification. This shouldn't be
|
32
|
+
# called directly since the domain spec automatically loads
|
33
|
+
# this.
|
34
|
+
def initialize(xml=nil)
|
30
35
|
@boot = []
|
36
|
+
|
37
|
+
load!(xml) if xml
|
31
38
|
end
|
32
39
|
|
33
40
|
# Enables or disables the interactive boot menu prompt on guest startup.
|
@@ -36,6 +43,25 @@ module Libvirt
|
|
36
43
|
@bootmenu_enabled = !!value
|
37
44
|
end
|
38
45
|
|
46
|
+
# Loads the OS booting information from the given XML string. This
|
47
|
+
# shouldn't be called directly, since the domain spec automatically
|
48
|
+
# calls this.
|
49
|
+
def load!(root)
|
50
|
+
root = Nokogiri::XML(root).root if !root.is_a?(Nokogiri::XML::Element)
|
51
|
+
try(root.xpath("//os/type[@arch]"), :preserve => true) { |result| self.arch = result["arch"].to_sym }
|
52
|
+
try(root.xpath("//os/type")) { |result| self.type = result.text.to_sym }
|
53
|
+
|
54
|
+
try(root.xpath("//os/boot"), :multi => true) do |results|
|
55
|
+
self.boot = []
|
56
|
+
|
57
|
+
results.each do |result|
|
58
|
+
self.boot << result["dev"].to_sym
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
raise_if_unparseables(root.xpath("//os/*"))
|
63
|
+
end
|
64
|
+
|
39
65
|
# Convert just the OS booting section to its XML representation.
|
40
66
|
def to_xml(parent=Nokogiri::XML::Builder.new)
|
41
67
|
parent.os do |os|
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Libvirt
|
2
|
+
module Spec
|
3
|
+
# Utility methods for the spec classes. This module is typically
|
4
|
+
# included for each class.
|
5
|
+
module Util
|
6
|
+
# Tries the given XML search, running the block if there are any
|
7
|
+
# results. This allows a concise syntax for loading data from
|
8
|
+
# XML which may or may not exist.
|
9
|
+
#
|
10
|
+
# **Warning:** By default, the result of the search given will
|
11
|
+
# be removed from the XML tree. See the options below for information
|
12
|
+
# on how to avoid this.
|
13
|
+
#
|
14
|
+
# An additional parameter supports options given as a hash. This
|
15
|
+
# allows for the following to be set:
|
16
|
+
#
|
17
|
+
# * `multi` - If true, then all results will be returned, not just
|
18
|
+
# the first one.
|
19
|
+
# * `preserve` - If true, then the node will not be deleted after
|
20
|
+
# yielding to the block.
|
21
|
+
#
|
22
|
+
# @param [Array] search_result
|
23
|
+
# @param [Hash] options Additional options, which are outlined
|
24
|
+
# above.
|
25
|
+
def try(search_result, options=nil)
|
26
|
+
options ||= {}
|
27
|
+
return if search_result.empty?
|
28
|
+
search_result = search_result.first if !options[:multi]
|
29
|
+
yield search_result
|
30
|
+
search_result.remove if !options[:preserve]
|
31
|
+
end
|
32
|
+
|
33
|
+
# This will raise an {Exception::UnparseableSpec} exception if there
|
34
|
+
# are any search results given. This is meant as a helper to reduce
|
35
|
+
# the duplicity of this feature across specs.
|
36
|
+
#
|
37
|
+
# @param [Array] search_result
|
38
|
+
def raise_if_unparseables(search_result)
|
39
|
+
raise Exception::UnparseableSpec, search_result if !search_result.empty?
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/libvirt/version.rb
CHANGED
data/libvirt.gemspec
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
3
|
-
require "libvirt/version"
|
2
|
+
require File.expand_path("../lib/libvirt/version", __FILE__)
|
4
3
|
|
5
4
|
Gem::Specification.new do |s|
|
6
5
|
s.name = "libvirt"
|
@@ -9,8 +8,8 @@ Gem::Specification.new do |s|
|
|
9
8
|
s.authors = ["Mitchell Hashimoto"]
|
10
9
|
s.email = ["mitchell.hashimoto@gmail.com"]
|
11
10
|
s.homepage = "http://rubygems.org/gems/libvirt"
|
12
|
-
s.summary = "A ruby client library providing
|
13
|
-
s.description = "A ruby client library providing
|
11
|
+
s.summary = "A ruby client library providing an interface to libvirt via FFI."
|
12
|
+
s.description = "A ruby client library providing an interface to libvirt via FFI."
|
14
13
|
|
15
14
|
s.rubyforge_project = "libvirt"
|
16
15
|
|
data/test/libvirt/domain_test.rb
CHANGED
@@ -90,6 +90,12 @@ Protest.describe("domain") do
|
|
90
90
|
assert !result.empty?
|
91
91
|
end
|
92
92
|
|
93
|
+
should "provide the spec object for the domain" do
|
94
|
+
result = nil
|
95
|
+
assert_nothing_raised { result = @instance.spec }
|
96
|
+
assert result.is_a?(Libvirt::Spec::Domain)
|
97
|
+
end
|
98
|
+
|
93
99
|
should "return result of active status" do
|
94
100
|
@instance.start
|
95
101
|
assert @instance.active?
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
Protest.describe("Domain devices") do
|
4
|
+
setup do
|
5
|
+
@klass = Libvirt::Spec::Device
|
6
|
+
end
|
7
|
+
|
8
|
+
should "parse from XML" do
|
9
|
+
@instance = @klass.load!("<disk type='file'></disk>")
|
10
|
+
assert @instance.is_a?(Libvirt::Spec::Device::Disk)
|
11
|
+
assert_equal :file, @instance.type
|
12
|
+
end
|
13
|
+
|
14
|
+
should "be able to get defined classes by name" do
|
15
|
+
assert_equal Libvirt::Spec::Device::Disk, @klass.get(:disk)
|
16
|
+
end
|
17
|
+
|
18
|
+
should "raise an exception if an unknown device name is given" do
|
19
|
+
assert_raises(NameError) { @klass.get(:foo) }
|
20
|
+
end
|
21
|
+
end
|
@@ -5,103 +5,37 @@ Protest.describe("Disk device spec") do
|
|
5
5
|
@klass = Libvirt::Spec::Device::Disk
|
6
6
|
end
|
7
7
|
|
8
|
-
context "
|
9
|
-
|
10
|
-
@instance = @klass.new(
|
8
|
+
context "initialization and parsing XML" do
|
9
|
+
should "parse the type" do
|
10
|
+
@instance = @klass.new("<disk type='file'></disk>")
|
11
|
+
assert_equal :file, @instance.type
|
11
12
|
end
|
12
13
|
|
13
|
-
should "
|
14
|
-
|
14
|
+
should "parse the device attribute" do
|
15
|
+
@instance = @klass.new("<disk device='disk'></disk>")
|
16
|
+
assert_equal :disk, @instance.device
|
15
17
|
end
|
16
18
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
assert_not_element @instance.to_xml, "//disk/source"
|
21
|
-
end
|
22
|
-
|
23
|
-
should "output source attr as dev for block devices" do
|
24
|
-
@instance.type = :block
|
25
|
-
@instance.source = "foo"
|
26
|
-
assert_xpath @instance.source, @instance.to_xml, "//disk/source/@dev"
|
27
|
-
end
|
28
|
-
|
29
|
-
should "output source attr as file for other devices" do
|
30
|
-
@instance.type = :file
|
31
|
-
@instance.source = "foo"
|
32
|
-
assert_xpath @instance.source, @instance.to_xml, "//disk/source/@file"
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
context "target" do
|
37
|
-
should "not output target if not specified" do
|
38
|
-
@instance.target_dev = nil
|
39
|
-
assert_not_element @instance.to_xml, "//disk/target"
|
40
|
-
end
|
41
|
-
|
42
|
-
should "not output target if only bus is given" do
|
43
|
-
@instance.target_dev = nil
|
44
|
-
@instance.target_bus = "foo"
|
45
|
-
assert_not_element @instance.to_xml, "//disk/target"
|
46
|
-
end
|
47
|
-
|
48
|
-
should "output specified dev on target" do
|
49
|
-
@instance.target_dev = "foo"
|
50
|
-
assert_xpath @instance.target_dev, @instance.to_xml, "//disk/target/@dev"
|
51
|
-
end
|
52
|
-
|
53
|
-
should "output specified bus on target" do
|
54
|
-
@instance.target_dev = "foo"
|
55
|
-
@instance.target_bus = "bar"
|
56
|
-
assert_xpath @instance.target_bus, @instance.to_xml, "//disk/target/@bus"
|
57
|
-
end
|
19
|
+
should "parse the file from the source" do
|
20
|
+
@instance = @klass.new("<disk type='file'><source file='foo'/></disk>")
|
21
|
+
assert_equal 'foo', @instance.source
|
58
22
|
end
|
59
23
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
assert_not_element @instance.to_xml, "//disk/driver"
|
64
|
-
end
|
65
|
-
|
66
|
-
should "output with specified driver" do
|
67
|
-
@instance.driver = "foo"
|
68
|
-
assert_xpath @instance.driver, @instance.to_xml, "//disk/driver/@name"
|
69
|
-
end
|
70
|
-
|
71
|
-
should "output with specified type if given" do
|
72
|
-
@instance.driver = "foo"
|
73
|
-
@instance.driver_type = "bar"
|
74
|
-
assert_xpath @instance.driver_type, @instance.to_xml, "//disk/driver/@type"
|
75
|
-
end
|
76
|
-
|
77
|
-
should "output with specified cache if given" do
|
78
|
-
@instance.driver = "foo"
|
79
|
-
@instance.driver_cache = "bar"
|
80
|
-
assert_xpath @instance.driver_cache, @instance.to_xml, "//disk/driver/@cache"
|
81
|
-
end
|
24
|
+
should "parse the dev from the source" do
|
25
|
+
@instance = @klass.new("<disk type='file'><source dev='bar'/></disk>")
|
26
|
+
assert_equal 'bar', @instance.source
|
82
27
|
end
|
83
28
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
should "be shareable if specified" do
|
90
|
-
@instance.shareable = true
|
91
|
-
assert_element @instance.to_xml, "//disk/shareable"
|
92
|
-
end
|
29
|
+
should "parse the target" do
|
30
|
+
@instance = @klass.new("<disk type='file'><target bus='foo' dev='bar'/></disk>")
|
31
|
+
assert_equal 'foo', @instance.target_bus
|
32
|
+
assert_equal 'bar', @instance.target_dev
|
93
33
|
end
|
94
34
|
|
95
|
-
|
96
|
-
|
97
|
-
@
|
98
|
-
|
99
|
-
end
|
100
|
-
|
101
|
-
should "have serial if specified" do
|
102
|
-
@instance.serial = "foobar"
|
103
|
-
assert_xpath @instance.serial, @instance.to_xml, "//disk/serial"
|
104
|
-
end
|
35
|
+
should "raise an exception if unsupported tags exist" do
|
36
|
+
assert_raises(Libvirt::Exception::UnparseableSpec) {
|
37
|
+
@klass.new("<disk><foo/></disk>")
|
38
|
+
}
|
105
39
|
end
|
106
40
|
end
|
107
41
|
end
|