rbovirt 0.1.0 → 0.1.1
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.
- checksums.yaml +4 -4
- data/CHANGES.rdoc +22 -0
- data/lib/client/host_api.rb +10 -4
- data/lib/client/instance_type_api.rb +20 -0
- data/lib/client/operating_system_api.rb +10 -0
- data/lib/client/vm_api.rb +29 -1
- data/lib/ovirt/instance_type.rb +73 -0
- data/lib/ovirt/operating_system.rb +11 -0
- data/lib/ovirt/template.rb +5 -4
- data/lib/ovirt/template_version.rb +2 -2
- data/lib/ovirt/version.rb +1 -1
- data/lib/ovirt/vm.rb +73 -21
- data/lib/rbovirt.rb +42 -25
- data/spec/integration/api_spec.rb +41 -0
- data/spec/integration/instance_type_spec.rb +16 -0
- data/spec/integration/vm_crud_spec.rb +124 -0
- data/spec/unit/vm_spec.rb +44 -0
- metadata +11 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 58cb5fab7fdfa1f4dce04d45532618c7415c8be5
|
4
|
+
data.tar.gz: ad23cc3fa62db7186b4bf14ae198f5d7e95c74bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 22b5ba8ada4d36d8ece11c9be5520188385c6978c80bdee0640b5fe898b559af46a6dd450d4e0b4195e36e3603d027722dc0197fff191c47e01cf789b3d6dde8
|
7
|
+
data.tar.gz: 47ba3a1763257b788c3bba4eb5596be1dbed85e36345f4f6a4c7ffaaca9cf97cd96024412020fbcb620f95412c1dd3e85f77e210a0e531f9115645d9c87e0c95
|
data/CHANGES.rdoc
CHANGED
@@ -6,6 +6,28 @@ _rbovirt_ project.
|
|
6
6
|
Note that this list of changes was added with the 0.0.30 release,
|
7
7
|
previous releases aren't described here.
|
8
8
|
|
9
|
+
== 0.1.1
|
10
|
+
|
11
|
+
New features:
|
12
|
+
|
13
|
+
* Support operating systems
|
14
|
+
* Added missing brackets for template display
|
15
|
+
* Support for using the persistent-auth
|
16
|
+
* Add instance types support.
|
17
|
+
* Fixes Blank template display
|
18
|
+
* Added support for VMS search options max/pages
|
19
|
+
* Handle template's disk
|
20
|
+
* Fix cloud init for OVirt >= 3.5
|
21
|
+
* Set storage domain for template when provided.
|
22
|
+
* Include disks in VM XML.
|
23
|
+
* Make comment of vm or template editable
|
24
|
+
* Adding override_iptables parameter to reinstall_host
|
25
|
+
* Implement stricter checks of nicsdef content
|
26
|
+
* Implement cloud-init for multiple nics
|
27
|
+
* Fix broken OVIRT::Template#volumes
|
28
|
+
* Fix for cloudinit so nokogiri correctly processes the files section
|
29
|
+
* Add option to set description on VM create.
|
30
|
+
|
9
31
|
== 0.1.0 / 2015-05-07
|
10
32
|
|
11
33
|
New features:
|
data/lib/client/host_api.rb
CHANGED
@@ -17,11 +17,17 @@ module OVIRT
|
|
17
17
|
http_post("/hosts/%s/approve" % host_id, "<action></action>")
|
18
18
|
end
|
19
19
|
|
20
|
-
def reinstall_host(host_id, opts={})
|
20
|
+
def reinstall_host(host_id, override_iptables=False, opts={})
|
21
21
|
http_post("/hosts/%s/install" % host_id,
|
22
|
-
"<action
|
23
|
-
|
24
|
-
|
22
|
+
"<action>
|
23
|
+
<ssh>
|
24
|
+
<authentication_method>PublicKey</authentication_method>
|
25
|
+
</ssh>
|
26
|
+
<host>
|
27
|
+
<override_iptables>" + override_iptables + "</override_iptables>
|
28
|
+
</host>
|
29
|
+
</action>"
|
30
|
+
)
|
25
31
|
end
|
26
32
|
end
|
27
33
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module OVIRT
|
2
|
+
class Client
|
3
|
+
def instance_type(instance_type_id)
|
4
|
+
begin
|
5
|
+
instance_type = http_get("/instancetypes/%s" % instance_type_id)
|
6
|
+
OVIRT::InstanceType::new(self, instance_type.root)
|
7
|
+
rescue
|
8
|
+
handle_fault $!
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def instance_types(opts={})
|
13
|
+
search = opts[:search] ||""
|
14
|
+
instance_types = http_get("/instancetypes?search=%s" % CGI.escape(search))
|
15
|
+
instance_types.xpath('/instance_types/instance_type').collect do |it|
|
16
|
+
OVIRT::InstanceType::new(self, it)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/client/vm_api.rb
CHANGED
@@ -6,7 +6,11 @@ module OVIRT
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def vms(opts={})
|
9
|
-
|
9
|
+
if opts[:without_details]
|
10
|
+
headers = {:accept => "application/xml"}
|
11
|
+
else
|
12
|
+
headers = {:accept => "application/xml; detail=disks; detail=nics; detail=hosts"}
|
13
|
+
end
|
10
14
|
path = "/vms"
|
11
15
|
path += search_url(opts) unless filtered_api
|
12
16
|
http_get(path, headers).xpath('/vms/vm').collect do |vm|
|
@@ -14,6 +18,21 @@ module OVIRT
|
|
14
18
|
end
|
15
19
|
end
|
16
20
|
|
21
|
+
def process_vm_opts(opts)
|
22
|
+
if (opts[:template] or opts[:template_name]) and (opts[:storagedomain] or opts[:storagedomain_name])
|
23
|
+
template_id = opts[:template] || templates.select{|t| t.name == opts[:template_name]}.first.id
|
24
|
+
template_disks = template_volumes(template_id)
|
25
|
+
storagedomain_id = opts[:storagedomain] || storagedomains.select{|s| s.name == opts[:storagedomain_name]}.first.id
|
26
|
+
|
27
|
+
# Make sure the 'clone' option is set if any of the disks defined by
|
28
|
+
# the template is stored on a different storage domain than requested
|
29
|
+
opts[:clone] = true unless opts[:clone] == true || template_disks.empty? || template_disks.all? { |d| d.storage_domain == storagedomain_id }
|
30
|
+
|
31
|
+
# Create disks map
|
32
|
+
opts[:disks] = template_disks.collect { |d| {:id => d.id, :storagedomain => storagedomain_id} }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
17
36
|
def create_vm(opts)
|
18
37
|
cluster_major_ver, cluster_minor_ver = cluster_version(self.cluster_id)
|
19
38
|
|
@@ -32,6 +51,9 @@ module OVIRT
|
|
32
51
|
raise BackendVersionUnsupportedException.new
|
33
52
|
end
|
34
53
|
end
|
54
|
+
|
55
|
+
process_vm_opts(opts)
|
56
|
+
|
35
57
|
opts[:cluster_name] ||= clusters.first.name unless opts[:cluster]
|
36
58
|
OVIRT::VM::new(self, http_post("/vms",OVIRT::VM.to_xml(opts)).root)
|
37
59
|
end
|
@@ -122,6 +144,12 @@ module OVIRT
|
|
122
144
|
end
|
123
145
|
|
124
146
|
def vm_start_with_cloudinit(id, opts={})
|
147
|
+
# Get the api and cluster version on which the VM is provisioned.
|
148
|
+
# This is required for VM::cloudinit.
|
149
|
+
opts.merge!(
|
150
|
+
:cluster_version => cluster_version(vm(id).cluster.id),
|
151
|
+
:api_version => api_version.split('.').map(&:to_i)
|
152
|
+
)
|
125
153
|
xml = OVIRT::VM.cloudinit(opts)
|
126
154
|
xml_response = http_post("/vms/%s/%s" % [id, 'start'], xml, {} )
|
127
155
|
return (xml_response/'action/status').first.text.strip.upcase=="COMPLETE"
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module OVIRT
|
2
|
+
# Instance types are added to oVirt 3.5 and have been updated in oVirt 3.6
|
3
|
+
class InstanceType < BaseObject
|
4
|
+
# Common attributes to all oVirt version supported at this time
|
5
|
+
attr_reader :name, :description, :memory, :cores, :os, :creation_time
|
6
|
+
attr_reader :ha, :ha_priority, :display, :usb, :migration_downtime
|
7
|
+
|
8
|
+
# oVirt 3.5 attributes
|
9
|
+
attr_reader :type, :status, :cpu_shares, :boot_menu, :origin, :stateless
|
10
|
+
attr_reader :delete_protected, :sso, :timezone
|
11
|
+
|
12
|
+
# oVirt 3.6 attributes
|
13
|
+
attr_reader :migration, :io_threads, :memory_guaranteed
|
14
|
+
|
15
|
+
def initialize(client, xml)
|
16
|
+
super(client, xml[:id], xml[:href], (xml/'name').first.text)
|
17
|
+
parse_xml_attributes!(xml)
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def parse_xml_attributes!(xml)
|
23
|
+
# Common attributes
|
24
|
+
@description = ((xml/'description').first.text rescue '')
|
25
|
+
@memory = (xml/'memory').first.text
|
26
|
+
@cores = ((xml/'cpu/topology').first[:cores].to_i * (xml/'cpu/topology').first[:sockets].to_i rescue nil)
|
27
|
+
@os = {
|
28
|
+
:type => (xml/'os').first[:type],
|
29
|
+
:boot => (xml/'os/boot').collect {|boot| boot[:dev] }
|
30
|
+
}
|
31
|
+
@creation_time = (xml/'creation_time').text
|
32
|
+
@ha = parse_bool((xml/'high_availability/enabled').first.text)
|
33
|
+
@ha_priority = ((xml/'high_availability/priority').first.text rescue nil)
|
34
|
+
@display = {
|
35
|
+
:type => (xml/'display/type').first.text,
|
36
|
+
:monitors => (xml/'display/monitors').first.text,
|
37
|
+
:single_qxl_pci => parse_bool((xml/'display/single_qxl_pci').first.text),
|
38
|
+
:smartcard_enabled => parse_bool((xml/'display/smartcard_enabled').first.text),
|
39
|
+
|
40
|
+
}
|
41
|
+
@usb = parse_bool((xml/'usb/enabled').first.text)
|
42
|
+
@migration_downtime = ((xml/'migration_downtime').first.text)
|
43
|
+
|
44
|
+
# oVirt 3.5 attributes
|
45
|
+
@type = ((xml/'type').first.text rescue nil)
|
46
|
+
@status = ((xml/'status').first.text rescue nil)
|
47
|
+
@cpu_shares = (((xml/'cpu_shares').first.text) rescue nil)
|
48
|
+
potential_bool = ((xml/'bios/boot_menu/enabled').first.text rescue nil)
|
49
|
+
@boot_menu = potential_bool.nil? ? nil : parse_bool(potential_bool)
|
50
|
+
@origin = ((xml/'origin').text rescue nil)
|
51
|
+
potential_bool = ((xml/'stateless').first.text rescue nil)
|
52
|
+
@stateless = potential_bool.nil? ? nil : parse_bool(potential_bool)
|
53
|
+
potential_bool = ((xml/'delete_protected').first.text rescue nil)
|
54
|
+
@delete_protected = potential_bool.nil? ? nil : parse_bool(potential_bool)
|
55
|
+
#@sso = ((xml/'sso/methods').first.text rescue nil)
|
56
|
+
@timezone = ((xml/'timezone').first.text rescue nil)
|
57
|
+
potential_bool = ((xml/'display/allow_override').first.text rescue nil)
|
58
|
+
@display[:allow_override] = potential_bool.nil? ? nil : parse_bool(potential_bool)
|
59
|
+
potential_bool = ((xml/'display/file_transfer_enabled').first.text rescue nil)
|
60
|
+
@display[:file_transfer_enabled] = potential_bool.nil? ? nil : parse_bool(potential_bool)
|
61
|
+
potential_bool = ((xml/'display/copy_paste_enabled').first.text rescue nil)
|
62
|
+
@display[:copy_paste_enabled] = potential_bool.nil? ? nil : parse_bool(potential_bool)
|
63
|
+
|
64
|
+
# oVirt 3.6 attributes
|
65
|
+
@migration = {
|
66
|
+
:auto_converge => ((xml/'migration/auto_converge').first.text rescue nil),
|
67
|
+
:compressed => ((xml/'migration/compressed').first.text rescue nil)
|
68
|
+
}
|
69
|
+
@io_threads = ((xml/'io/threads').first.text rescue nil)
|
70
|
+
@memory_guaranteed = ((xml/'memory_policy/guaranteed').first.text rescue nil)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/ovirt/template.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module OVIRT
|
2
2
|
class Template < BaseObject
|
3
|
-
attr_reader :description, :
|
3
|
+
attr_reader :description, :status, :cluster, :creation_time, :os, :storage, :display, :profile, :memory, :version
|
4
|
+
attr_accessor :comment
|
4
5
|
|
5
6
|
def initialize(client, xml)
|
6
7
|
super(client, xml[:id], xml[:href], (xml/'name').first.text)
|
@@ -25,7 +26,7 @@ module OVIRT
|
|
25
26
|
end
|
26
27
|
|
27
28
|
def volumes
|
28
|
-
@volumes ||= @client.
|
29
|
+
@volumes ||= @client.template_volumes(id)
|
29
30
|
end
|
30
31
|
|
31
32
|
private
|
@@ -38,8 +39,8 @@ module OVIRT
|
|
38
39
|
@profile = (xml/'type').first.text
|
39
40
|
@cluster = Link::new(@client, (xml/'cluster').first[:id], (xml/'cluster').first[:href])
|
40
41
|
@display = {
|
41
|
-
:type => (xml/'display/type').first.text,
|
42
|
-
:monitors => (xml/'display/monitors').first.text
|
42
|
+
:type => ((xml/'display/type').first.text rescue ''),
|
43
|
+
:monitors => ((xml/'display/monitors').first.text rescue 0)
|
43
44
|
}
|
44
45
|
@cores = ((xml/'cpu/topology').first[:cores].to_i * (xml/'cpu/topology').first[:sockets].to_i rescue nil)
|
45
46
|
@storage = ((xml/'disks/disk/size').first.text rescue nil)
|
@@ -8,7 +8,7 @@ module OVIRT
|
|
8
8
|
def parse_xml_attributes(xml)
|
9
9
|
@base_template = (xml/"base_template").first[:id]
|
10
10
|
@version_number = (xml/"version_number").first.text
|
11
|
-
@version_name = (xml/"version_name").first.text
|
11
|
+
@version_name = ((xml/"version_name").first.text rescue nil)
|
12
12
|
end
|
13
13
|
end
|
14
|
-
end
|
14
|
+
end
|
data/lib/ovirt/version.rb
CHANGED
data/lib/ovirt/vm.rb
CHANGED
@@ -4,9 +4,9 @@ module OVIRT
|
|
4
4
|
FILEINJECT_PATH = "user-data.txt"
|
5
5
|
|
6
6
|
class VM < BaseObject
|
7
|
-
attr_reader :description, :
|
7
|
+
attr_reader :description, :status, :memory, :profile, :display, :host, :cluster, :template
|
8
8
|
attr_reader :storage, :cores, :creation_time, :os, :ha, :ha_priority, :ips, :vnc, :quota, :clone
|
9
|
-
attr_accessor :interfaces, :volumes
|
9
|
+
attr_accessor :comment, :interfaces, :volumes
|
10
10
|
|
11
11
|
def initialize(client, xml)
|
12
12
|
super(client, xml[:id], xml[:href], (xml/'name').first.text)
|
@@ -50,6 +50,7 @@ module OVIRT
|
|
50
50
|
builder = Nokogiri::XML::Builder.new do
|
51
51
|
vm{
|
52
52
|
name_ opts[:name] || "i-#{Time.now.to_i}"
|
53
|
+
description_ opts[:description] || ""
|
53
54
|
if opts[:comment]
|
54
55
|
comment_ opts[:comment]
|
55
56
|
end
|
@@ -79,18 +80,23 @@ module OVIRT
|
|
79
80
|
end
|
80
81
|
# os element must not be sent when template is present (RHBZ 1104235)
|
81
82
|
if opts[:template].nil? || opts[:template].empty?
|
82
|
-
os
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
83
|
+
os_opts = opts[:os] ? opts[:os].dup : {}
|
84
|
+
os_opts[:type] ||= opts[:os_type] || 'unassigned'
|
85
|
+
os_opts[:boot] ||= [opts.fetch(:boot_dev1, 'network'), opts.fetch(:boot_dev2, 'hd')]
|
86
|
+
os_opts[:kernel] ||= opts[:os_kernel]
|
87
|
+
os_opts[:initrd] ||= opts[:os_initrd]
|
88
|
+
os_opts[:cmdline] ||= opts[:os_cmdline]
|
89
|
+
if opts[:first_boot_dev]
|
90
|
+
os_opts[:boot] = os_opts[:boot].sort_by.with_index do |device, index|
|
91
|
+
device == opts[:first_boot_dev] ? -1 : index
|
89
92
|
end
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
93
|
+
end
|
94
|
+
os(:type => os_opts[:type]) do
|
95
|
+
os_opts[:boot].each { |device| boot(:dev => device) }
|
96
|
+
kernel os_opts[:kernel]
|
97
|
+
initrd os_opts[:initrd]
|
98
|
+
cmdline os_opts[:cmdline]
|
99
|
+
end
|
94
100
|
end
|
95
101
|
if !opts[:ha].nil? || !opts[:ha_priority].nil?
|
96
102
|
high_availability_{
|
@@ -98,7 +104,16 @@ module OVIRT
|
|
98
104
|
priority_(opts[:ha_priority]) unless opts[:ha_priority].nil?
|
99
105
|
}
|
100
106
|
end
|
101
|
-
disks_ {
|
107
|
+
disks_ {
|
108
|
+
clone_(opts[:clone]) if opts[:clone]
|
109
|
+
if opts[:disks]
|
110
|
+
opts[:disks].each do |d|
|
111
|
+
disk(:id => d[:id]) {
|
112
|
+
storage_domains { storage_domain(:id => d[:storagedomain]) }
|
113
|
+
}
|
114
|
+
end
|
115
|
+
end
|
116
|
+
}
|
102
117
|
display_{
|
103
118
|
type_(opts[:display][:type])
|
104
119
|
} if opts[:display]
|
@@ -136,11 +151,14 @@ module OVIRT
|
|
136
151
|
gateway = opts[:gateway]
|
137
152
|
domain = opts[:domain]
|
138
153
|
nicname = opts[:nicname]
|
154
|
+
nicsdef = opts[:nicsdef]
|
139
155
|
user = opts[:user] || 'root'
|
140
156
|
password = opts[:password]
|
141
157
|
ssh_authorized_keys = opts[:ssh_authorized_keys]
|
142
158
|
fileslist = opts[:files]
|
143
159
|
runcmd = opts[:runcmd]
|
160
|
+
cluster_major, cluster_minor = opts[:cluster_version]
|
161
|
+
api_major,api_minor, api_build, api_revision = opts[:api_version]
|
144
162
|
extracmd = nil
|
145
163
|
unless opts[:phone_home].nil?
|
146
164
|
phone_home = \
|
@@ -164,6 +182,23 @@ module OVIRT
|
|
164
182
|
end
|
165
183
|
builder = Nokogiri::XML::Builder.new do
|
166
184
|
action {
|
185
|
+
# An API has changed in version 3.5.5. Make sure
|
186
|
+
# <use_cloud_init>true</use_cloud_init> is used only if the endpoint
|
187
|
+
# if of that version or higher and the cluster the VM is provisioned
|
188
|
+
# to is of version 3.5 or higher.
|
189
|
+
# NOTE: RHEV-m/OVirt versions prior to 3.6.0 contain a bug
|
190
|
+
# (https://bugzilla.redhat.com/show_bug.cgi?id=1206068) which causes
|
191
|
+
# that build and revision parameters ov API version are set to 0.
|
192
|
+
# This may have an impact on conditional inclusion of <use_cloud_init>
|
193
|
+
# and thus leaving the guest unconfigured.
|
194
|
+
# You can either upgrade to RHEV-m/OVirt 3.6+ or work this around by
|
195
|
+
# manually forcing the ovirt engine to report an appropriate version:
|
196
|
+
# % rhevm-config -s VdcVersion=<major>.<minor>.<build>.<revision>
|
197
|
+
# % service ovirt-engine restart
|
198
|
+
# Please replace the placeholders with appropriate values.
|
199
|
+
if api_major > 3 || (api_major == 3 && api_minor > 5) || (api_major == 3 && api_minor == 5 && api_build >= 5)
|
200
|
+
use_cloud_init true if cluster_major > 3 || (cluster_major == 3 && cluster_minor >= 5)
|
201
|
+
end
|
167
202
|
vm {
|
168
203
|
initialization {
|
169
204
|
unless runcmd.nil?
|
@@ -194,18 +229,35 @@ module OVIRT
|
|
194
229
|
}
|
195
230
|
}
|
196
231
|
end
|
197
|
-
network_configuration {
|
198
|
-
|
232
|
+
network_configuration {
|
233
|
+
if !nicname.nil?
|
199
234
|
nics {
|
200
235
|
nic {
|
201
|
-
|
236
|
+
name_ nicname
|
202
237
|
unless ip.nil? || netmask.nil? || gateway.nil?
|
203
238
|
network { ip(:'address'=> ip , :'netmask'=> netmask, :'gateway'=> gateway ) }
|
204
239
|
boot_protocol 'STATIC'
|
205
240
|
on_boot 'true'
|
206
241
|
end
|
207
242
|
}
|
208
|
-
}
|
243
|
+
}
|
244
|
+
elsif nicsdef.is_a?(Array) && !nicsdef.empty? && nicsdef.all? { |n| n.is_a?(Hash) }
|
245
|
+
nics {
|
246
|
+
nicsdef.each do |n|
|
247
|
+
nic {
|
248
|
+
name_(n[:nicname])
|
249
|
+
boot_protocol_(n[:boot_protocol] || 'NONE') # Defaults to NONE boot proto
|
250
|
+
on_boot_(n[:on_boot] || 'true') # Defaults to 'true'
|
251
|
+
unless n[:ip].nil? || n[:netmask].nil?
|
252
|
+
network_ {
|
253
|
+
n[:gateway].nil? ?
|
254
|
+
ip_(:address => n[:ip], :netmask => n[:netmask]) :
|
255
|
+
ip_(:address => n[:ip], :netmask => n[:netmask], :gateway => n[:gateway])
|
256
|
+
}
|
257
|
+
end
|
258
|
+
}
|
259
|
+
end
|
260
|
+
}
|
209
261
|
end
|
210
262
|
dns {
|
211
263
|
unless dns.nil?
|
@@ -223,7 +275,7 @@ module OVIRT
|
|
223
275
|
regenerate_ssh_keys 'true'
|
224
276
|
files {
|
225
277
|
unless extracmd.nil?
|
226
|
-
|
278
|
+
file_ {
|
227
279
|
name_ 'ignored'
|
228
280
|
content extracmd
|
229
281
|
type 'PLAINTEXT'
|
@@ -259,12 +311,12 @@ module OVIRT
|
|
259
311
|
@host = Link::new(@client, (xml/'host').first[:id], (xml/'host').first[:href]) rescue nil
|
260
312
|
@cluster = Link::new(@client, (xml/'cluster').first[:id], (xml/'cluster').first[:href])
|
261
313
|
@display = {
|
262
|
-
:type => (xml/'display/type').first.text,
|
314
|
+
:type => ((xml/'display/type').first.text rescue ''),
|
263
315
|
:address => ((xml/'display/address').first.text rescue nil),
|
264
316
|
:port => ((xml/'display/port').first.text rescue nil),
|
265
317
|
:secure_port => ((xml/'display/secure_port').first.text rescue nil),
|
266
318
|
:subject => ((xml/'display/certificate/subject').first.text rescue nil),
|
267
|
-
:monitors => (xml/'display/monitors').first.text
|
319
|
+
:monitors => ((xml/'display/monitors').first.text rescue 0)
|
268
320
|
}
|
269
321
|
@cores = ((xml/'cpu/topology').first[:cores].to_i * (xml/'cpu/topology').first[:sockets].to_i rescue nil)
|
270
322
|
@storage = ((xml/'disks/disk/size').first.text rescue nil)
|
data/lib/rbovirt.rb
CHANGED
@@ -12,7 +12,9 @@ require "ovirt/interface"
|
|
12
12
|
require "ovirt/network"
|
13
13
|
require "ovirt/quota"
|
14
14
|
require "ovirt/affinity_group"
|
15
|
+
require "ovirt/instance_type"
|
15
16
|
require "ovirt/version"
|
17
|
+
require "ovirt/operating_system"
|
16
18
|
|
17
19
|
require "client/vm_api"
|
18
20
|
require "client/template_api"
|
@@ -24,6 +26,8 @@ require "client/quota_api"
|
|
24
26
|
require "client/disk_api"
|
25
27
|
require "client/affinity_group_api"
|
26
28
|
require "client/disk_profile_api"
|
29
|
+
require "client/instance_type_api"
|
30
|
+
require "client/operating_system_api"
|
27
31
|
|
28
32
|
require "nokogiri"
|
29
33
|
require "rest_client"
|
@@ -45,7 +49,7 @@ module OVIRT
|
|
45
49
|
|
46
50
|
class Client
|
47
51
|
|
48
|
-
attr_reader :credentials, :api_entrypoint, :datacenter_id, :cluster_id, :filtered_api, :ca_cert_file, :ca_cert_store, :ca_no_verify
|
52
|
+
attr_reader :credentials, :api_entrypoint, :datacenter_id, :cluster_id, :filtered_api, :ca_cert_file, :ca_cert_store, :ca_no_verify, :persistent_auth, :jsessionid
|
49
53
|
|
50
54
|
# Construct a new ovirt client class.
|
51
55
|
# mandatory parameters
|
@@ -67,20 +71,26 @@ module OVIRT
|
|
67
71
|
:cluster_id => backward_compatibility_cluster,
|
68
72
|
:filtered_api => backward_compatibility_filtered}
|
69
73
|
end
|
70
|
-
@api_entrypoint
|
71
|
-
@credentials
|
72
|
-
@datacenter_id
|
73
|
-
@cluster_id
|
74
|
-
@filtered_api
|
75
|
-
@ca_cert_file
|
76
|
-
@ca_cert_store
|
77
|
-
@ca_no_verify
|
74
|
+
@api_entrypoint = api_entrypoint
|
75
|
+
@credentials = { :username => username, :password => password }
|
76
|
+
@datacenter_id = options[:datacenter_id]
|
77
|
+
@cluster_id = options[:cluster_id]
|
78
|
+
@filtered_api = options[:filtered_api]
|
79
|
+
@ca_cert_file = options[:ca_cert_file]
|
80
|
+
@ca_cert_store = options[:ca_cert_store]
|
81
|
+
@ca_no_verify = options[:ca_no_verify]
|
82
|
+
@persistent_auth = options[:persistent_auth]
|
83
|
+
@jsessionid = options[:jsessionid]
|
78
84
|
end
|
79
85
|
|
80
86
|
def api_version
|
81
87
|
return @api_version unless @api_version.nil?
|
82
88
|
xml = http_get("/")/'/api/product_info/version'
|
83
|
-
|
89
|
+
major = (xml/'version').first[:major]
|
90
|
+
minor = (xml/'version').first[:minor]
|
91
|
+
build = (xml/'version').first[:build]
|
92
|
+
revision = (xml/'version').first[:revision]
|
93
|
+
@api_version = "#{major}.#{minor}.#{build}.#{revision}"
|
84
94
|
end
|
85
95
|
|
86
96
|
def api_version?(major, minor=nil)
|
@@ -93,9 +103,13 @@ module OVIRT
|
|
93
103
|
end
|
94
104
|
|
95
105
|
private
|
106
|
+
|
96
107
|
def search_url opts
|
97
|
-
search = opts[:search] ||
|
98
|
-
"
|
108
|
+
search = opts[:search] || ''
|
109
|
+
search += " datacenter=\"%s\"" % current_datacenter.name
|
110
|
+
search += " page #{opts[:page]}" if opts[:page]
|
111
|
+
max = opts[:max] ? ";max=#{opts[:max]}" : ''
|
112
|
+
"#{max}?search=#{CGI.escape(search)}"
|
99
113
|
end
|
100
114
|
|
101
115
|
def current_datacenter
|
@@ -108,9 +122,7 @@ module OVIRT
|
|
108
122
|
|
109
123
|
def http_get(suburl, headers={})
|
110
124
|
begin
|
111
|
-
|
112
|
-
puts "#{res}\n" if ENV['RBOVIRT_LOG_RESPONSE']
|
113
|
-
Nokogiri::XML(res)
|
125
|
+
handle_success(rest_client(suburl).get(http_headers(headers)))
|
114
126
|
rescue
|
115
127
|
handle_fault $!
|
116
128
|
end
|
@@ -118,9 +130,7 @@ module OVIRT
|
|
118
130
|
|
119
131
|
def http_post(suburl, body, headers={})
|
120
132
|
begin
|
121
|
-
|
122
|
-
puts "#{res}\n" if ENV['RBOVIRT_LOG_RESPONSE']
|
123
|
-
Nokogiri::XML(res)
|
133
|
+
handle_success(rest_client(suburl).post(body, http_headers(headers)))
|
124
134
|
rescue
|
125
135
|
handle_fault $!
|
126
136
|
end
|
@@ -128,9 +138,7 @@ module OVIRT
|
|
128
138
|
|
129
139
|
def http_put(suburl, body, headers={})
|
130
140
|
begin
|
131
|
-
|
132
|
-
puts "#{res}\n" if ENV['RBOVIRT_LOG_RESPONSE']
|
133
|
-
Nokogiri::XML(res)
|
141
|
+
handle_success(rest_client(suburl).put(body, http_headers(headers)))
|
134
142
|
rescue
|
135
143
|
handle_fault $!
|
136
144
|
end
|
@@ -140,9 +148,7 @@ module OVIRT
|
|
140
148
|
begin
|
141
149
|
headers = body ? http_headers(headers) :
|
142
150
|
{:accept => 'application/xml'}.merge(auth_header).merge(filter_header)
|
143
|
-
|
144
|
-
puts "#{res}\n" if ENV['RBOVIRT_LOG_RESPONSE']
|
145
|
-
Nokogiri::XML(res)
|
151
|
+
handle_success(rest_client(suburl).delete_with_payload(body, headers))
|
146
152
|
rescue
|
147
153
|
handle_fault $!
|
148
154
|
end
|
@@ -151,7 +157,12 @@ module OVIRT
|
|
151
157
|
def auth_header
|
152
158
|
# This is the method for strict_encode64:
|
153
159
|
encoded_credentials = ["#{@credentials[:username]}:#{@credentials[:password]}"].pack("m0").gsub(/\n/,'')
|
154
|
-
{ :authorization => "Basic " + encoded_credentials }
|
160
|
+
headers = { :authorization => "Basic " + encoded_credentials }
|
161
|
+
if persistent_auth
|
162
|
+
headers[:prefer] = 'persistent-auth'
|
163
|
+
headers[:cookie] = "JSESSIONID=#{jsessionid}" if jsessionid
|
164
|
+
end
|
165
|
+
headers
|
155
166
|
end
|
156
167
|
|
157
168
|
def rest_client(suburl)
|
@@ -189,6 +200,12 @@ module OVIRT
|
|
189
200
|
}).merge(headers)
|
190
201
|
end
|
191
202
|
|
203
|
+
def handle_success(response)
|
204
|
+
puts "#{response}\n" if ENV['RBOVIRT_LOG_RESPONSE']
|
205
|
+
@jsessionid ||= response.cookies['JSESSIONID']
|
206
|
+
Nokogiri::XML(response)
|
207
|
+
end
|
208
|
+
|
192
209
|
def handle_fault(f)
|
193
210
|
if f.is_a?(RestClient::BadRequest) || f.is_a?(RestClient::Conflict)
|
194
211
|
fault = (Nokogiri::XML(f.http_body)/'//fault/detail')
|
@@ -58,6 +58,28 @@ describe OVIRT, "Https authentication" do
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
+
describe OVIRT, "Persistent authentication" do
|
62
|
+
context 'use persistent authentication' do
|
63
|
+
|
64
|
+
it "test_request_with_persistent_authentication" do
|
65
|
+
user, password, url, datacenter = endpoint
|
66
|
+
cert = ca_cert(url)
|
67
|
+
store = OpenSSL::X509::Store.new().add_cert(
|
68
|
+
OpenSSL::X509::Certificate.new(cert))
|
69
|
+
|
70
|
+
client = ::OVIRT::Client.new(user, password, url, {:ca_cert_store => store, :persistent_auth => true})
|
71
|
+
client.api_version.class.should eql(String)
|
72
|
+
client.persistent_auth.should eql(true)
|
73
|
+
client.jsessionid.should_not be_nil
|
74
|
+
|
75
|
+
# When performing a new request the jsessionid should remain the same
|
76
|
+
orig_jsession_id = client.jsessionid
|
77
|
+
client.datacenters.class.should eql(Array)
|
78
|
+
client.jsessionid.should eql(orig_jsession_id)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
61
83
|
describe OVIRT, "Admin API" do
|
62
84
|
|
63
85
|
before(:all) do
|
@@ -97,3 +119,22 @@ describe OVIRT, "User API" do
|
|
97
119
|
end
|
98
120
|
|
99
121
|
end
|
122
|
+
|
123
|
+
describe OVIRT, "Operating systems API" do
|
124
|
+
|
125
|
+
before(:all) do
|
126
|
+
setup_client
|
127
|
+
end
|
128
|
+
|
129
|
+
context 'basic user api and listing' do
|
130
|
+
it "exposes supported operating systems" do
|
131
|
+
oses = @client.operating_systems
|
132
|
+
oses.should_not be_empty
|
133
|
+
os = oses.first
|
134
|
+
os.id.should_not be_empty
|
135
|
+
os.name.should_not be_empty
|
136
|
+
os.description.should_not be_empty
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../spec_helper"
|
2
|
+
|
3
|
+
describe "Basic Instance type life cycle" do
|
4
|
+
before(:all) do
|
5
|
+
setup_client
|
6
|
+
end
|
7
|
+
|
8
|
+
it "test_should_return_instance_types" do
|
9
|
+
@client.instance_types
|
10
|
+
end
|
11
|
+
|
12
|
+
it "test_should_return_an_instance_type" do
|
13
|
+
@instance_type = @client.instance_types.first
|
14
|
+
@client.instance_type(@instance_type.id).id.should eql(@instance_type.id)
|
15
|
+
end
|
16
|
+
end
|
@@ -51,6 +51,8 @@ shared_examples_for "Basic VM Life cycle" do
|
|
51
51
|
end
|
52
52
|
|
53
53
|
it "test_should_set_vm_ticket" do
|
54
|
+
while @client.vm(@vm.id).status.strip != 'down' do
|
55
|
+
end
|
54
56
|
@client.vm_action(@vm.id, :start)
|
55
57
|
while !@client.vm(@vm.id).running? do
|
56
58
|
end
|
@@ -117,6 +119,7 @@ shared_examples_for "VM Life cycle without template" do
|
|
117
119
|
end
|
118
120
|
end
|
119
121
|
|
122
|
+
|
120
123
|
describe "Admin API VM Life cycle" do
|
121
124
|
|
122
125
|
before(:all) do
|
@@ -149,3 +152,124 @@ describe "User API VM Life cycle" do
|
|
149
152
|
it_behaves_like "Basic VM Life cycle"
|
150
153
|
end
|
151
154
|
end
|
155
|
+
|
156
|
+
describe "VM API support functions" do
|
157
|
+
|
158
|
+
before(:all) do
|
159
|
+
setup_client
|
160
|
+
if @client.templates.empty?
|
161
|
+
name = 'vm-'+Time.now.to_i.to_s
|
162
|
+
@cluster = @client.clusters.select{|c| c.name == cluster_name}.first.id
|
163
|
+
vm = @client.create_vm(:name => name, :cluster => @cluster)
|
164
|
+
@client.add_volume(vm.id)
|
165
|
+
@client.add_interface(vm.id, :network_name => network_name)
|
166
|
+
while !@client.vm(vm.id).ready? do
|
167
|
+
end
|
168
|
+
@client.create_template(:vm => vm.id, :name => "template-#{name}", :description => "test_template", :comment => "test_template")
|
169
|
+
end
|
170
|
+
|
171
|
+
@template_name = @config['template'] || @client.templates.first.name
|
172
|
+
@template = @client.templates.find { |t| t.name == @template_name }.id
|
173
|
+
@template_disks = @client.template_volumes(@template)
|
174
|
+
@storagedomain = @client.storagedomains.first.id
|
175
|
+
@storagedomain_name = @client.storagedomains.first.name
|
176
|
+
end
|
177
|
+
|
178
|
+
context 'options processing' do
|
179
|
+
it "should process template option into disk decriptions" do
|
180
|
+
t_id = @template
|
181
|
+
opts = {:template => t_id}
|
182
|
+
t_name = opts[:template_name]
|
183
|
+
@client.process_vm_opts(opts)
|
184
|
+
opts[:template].should eql(t_id)
|
185
|
+
opts[:template_name].should eql(t_name)
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should process template_name option into disk decriptions" do
|
189
|
+
t_name = @template_name
|
190
|
+
opts = {:template_name => t_name}
|
191
|
+
t_id = opts[:template]
|
192
|
+
@client.process_vm_opts(opts)
|
193
|
+
opts[:template].should eql(t_id)
|
194
|
+
opts[:template_name].should eql(t_name)
|
195
|
+
end
|
196
|
+
|
197
|
+
it "should process template and storagedomain options into disk decriptions" do
|
198
|
+
t_id = @template
|
199
|
+
s_id = @storagedomain
|
200
|
+
opts = {:template => t_id,
|
201
|
+
:storagedomain => s_id}
|
202
|
+
t_name = opts[:template_name]
|
203
|
+
s_name = opts[:storagedomain_name]
|
204
|
+
@client.process_vm_opts(opts)
|
205
|
+
opts[:disks].length.should eql(@template_disks.length)
|
206
|
+
unless @template_disks.empty?
|
207
|
+
opts[:disks].first[:id].should_not be_nil
|
208
|
+
opts[:disks].first[:storagedomain].should eql(s_id)
|
209
|
+
end
|
210
|
+
opts[:template].should eql(t_id)
|
211
|
+
opts[:template_name].should eql(t_name)
|
212
|
+
opts[:storagedomain].should eql(s_id)
|
213
|
+
opts[:storagedomain_name].should eql(s_name)
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should process template_name and storagedomain options into disk decriptions" do
|
217
|
+
t_name = @template_name
|
218
|
+
s_id = @storagedomain
|
219
|
+
opts = {:template_name => t_name,
|
220
|
+
:storagedomain => s_id}
|
221
|
+
t_id = opts[:template]
|
222
|
+
s_name = opts[:storagedomain_name]
|
223
|
+
@client.process_vm_opts(opts)
|
224
|
+
opts[:disks].length.should eql(@template_disks.length)
|
225
|
+
unless @template_disks.empty?
|
226
|
+
opts[:disks].first[:id].should_not be_nil
|
227
|
+
opts[:disks].first[:storagedomain].should eql(s_id)
|
228
|
+
end
|
229
|
+
opts[:template].should eql(t_id)
|
230
|
+
opts[:template_name].should eql(t_name)
|
231
|
+
opts[:storagedomain].should eql(s_id)
|
232
|
+
opts[:storagedomain_name].should eql(s_name)
|
233
|
+
end
|
234
|
+
|
235
|
+
it "should process template and storagedomain_name options into disk decriptions" do
|
236
|
+
t_id = @template
|
237
|
+
s_name = @storagedomain_name
|
238
|
+
opts = {:template => t_id,
|
239
|
+
:storagedomain_name => s_name}
|
240
|
+
t_name = opts[:template_name]
|
241
|
+
s_id = opts[:storagedomain_id]
|
242
|
+
@client.process_vm_opts(opts)
|
243
|
+
opts[:disks].length.should eql(@template_disks.length)
|
244
|
+
unless @template_disks.empty?
|
245
|
+
opts[:disks].first[:id].should_not be_nil
|
246
|
+
opts[:disks].first[:storagedomain].should eql(@storagedomain)
|
247
|
+
end
|
248
|
+
opts[:template].should eql(t_id)
|
249
|
+
opts[:template_name].should eql(t_name)
|
250
|
+
opts[:storagedomain].should eql(s_id)
|
251
|
+
opts[:storagedomain_name].should eql(s_name)
|
252
|
+
end
|
253
|
+
|
254
|
+
it "should process template_name and storagedomain_name options into disk decriptions" do
|
255
|
+
t_name = @template_name
|
256
|
+
s_name = @storagedomain_name
|
257
|
+
opts = {:template_name => t_name,
|
258
|
+
:storagedomain_name => s_name}
|
259
|
+
t_id = opts[:template]
|
260
|
+
s_id = opts[:storagedomain]
|
261
|
+
@client.process_vm_opts(opts)
|
262
|
+
opts[:disks].length.should eql(@template_disks.length)
|
263
|
+
unless @template_disks.empty?
|
264
|
+
opts[:disks].first[:id].should_not be_nil
|
265
|
+
opts[:disks].first[:storagedomain].should eql(@storagedomain)
|
266
|
+
end
|
267
|
+
opts[:template].should eql(t_id)
|
268
|
+
opts[:template_name].should eql(t_name)
|
269
|
+
opts[:storagedomain].should eql(s_id)
|
270
|
+
opts[:storagedomain_name].should eql(s_name)
|
271
|
+
end
|
272
|
+
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
data/spec/unit/vm_spec.rb
CHANGED
@@ -232,6 +232,50 @@ END_HEREDOC
|
|
232
232
|
xml.nil?.should eql(false)
|
233
233
|
end
|
234
234
|
|
235
|
+
it "create vm xml without description" do
|
236
|
+
opts = {
|
237
|
+
:cluster_name =>'cluster',
|
238
|
+
:template_name =>'template',
|
239
|
+
}
|
240
|
+
xml = OVIRT::VM.to_xml(opts)
|
241
|
+
xml.nil?.should eql(false)
|
242
|
+
Nokogiri::XML(xml).xpath("//description").length.should eql(1)
|
243
|
+
Nokogiri::XML(xml).xpath("//description")[0].children.length.should eql(0)
|
244
|
+
end
|
245
|
+
|
246
|
+
it "create vm xml with description" do
|
247
|
+
opts = {
|
248
|
+
:cluster_name =>'cluster',
|
249
|
+
:template_name =>'template',
|
250
|
+
:description => 'a description',
|
251
|
+
}
|
252
|
+
xml = OVIRT::VM.to_xml(opts)
|
253
|
+
xml.nil?.should eql(false)
|
254
|
+
Nokogiri::XML(xml).xpath("//description").length.should eql(1)
|
255
|
+
Nokogiri::XML(xml).xpath("//description")[0].children.length.should eql(1)
|
256
|
+
Nokogiri::XML(xml).xpath("//description")[0].children[0].text?.should eql(true)
|
257
|
+
Nokogiri::XML(xml).xpath("//description")[0].content.should eql("a description")
|
258
|
+
end
|
259
|
+
|
260
|
+
it "create vm xml with disks" do
|
261
|
+
disk = "00000000-0000-0000-0000-000000000000"
|
262
|
+
storagedomain = "00000000-0000-0000-0000-000000000001"
|
263
|
+
disks = [{:id => disk, :storagedomain => storagedomain}]
|
264
|
+
opts = {
|
265
|
+
:cluster_name => 'cluster',
|
266
|
+
:disks => disks,
|
267
|
+
}
|
268
|
+
xml = OVIRT::VM.to_xml(opts)
|
269
|
+
puts xml
|
270
|
+
xml.nil?.should eql(false)
|
271
|
+
Nokogiri::XML(xml).xpath("//disks").length.should eql(1)
|
272
|
+
Nokogiri::XML(xml).xpath("//disks")[0].element_children.length.should eql(1)
|
273
|
+
Nokogiri::XML(xml).xpath("//disks/disk[contains(@id,'#{disk}')]").length.should eql(1)
|
274
|
+
Nokogiri::XML(xml).xpath("//disks/disk/storage_domains").length.should eql(1)
|
275
|
+
Nokogiri::XML(xml).xpath("//disks/disk/storage_domains")[0].element_children.length.should eql(1)
|
276
|
+
Nokogiri::XML(xml).xpath("//disks/disk/storage_domains/storage_domain[contains(@id,'#{storagedomain}')]").length.should eql(1)
|
277
|
+
end
|
278
|
+
|
235
279
|
it "should be running" do
|
236
280
|
vm = OVIRT::VM.new(nil, Nokogiri::XML(@xml).xpath('/').first)
|
237
281
|
vm.running?.should eql(true)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbovirt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Amos Benari
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-04-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -80,8 +80,7 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
-
description:
|
84
|
-
A Ruby client for oVirt REST API
|
83
|
+
description: " A Ruby client for oVirt REST API\n"
|
85
84
|
email:
|
86
85
|
- abenari@redhat.com
|
87
86
|
executables: []
|
@@ -103,6 +102,8 @@ files:
|
|
103
102
|
- lib/client/disk_api.rb
|
104
103
|
- lib/client/disk_profile_api.rb
|
105
104
|
- lib/client/host_api.rb
|
105
|
+
- lib/client/instance_type_api.rb
|
106
|
+
- lib/client/operating_system_api.rb
|
106
107
|
- lib/client/quota_api.rb
|
107
108
|
- lib/client/storage_domain_api.rb
|
108
109
|
- lib/client/template_api.rb
|
@@ -113,8 +114,10 @@ files:
|
|
113
114
|
- lib/ovirt/datacenter.rb
|
114
115
|
- lib/ovirt/disk_profile.rb
|
115
116
|
- lib/ovirt/host.rb
|
117
|
+
- lib/ovirt/instance_type.rb
|
116
118
|
- lib/ovirt/interface.rb
|
117
119
|
- lib/ovirt/network.rb
|
120
|
+
- lib/ovirt/operating_system.rb
|
118
121
|
- lib/ovirt/quota.rb
|
119
122
|
- lib/ovirt/storage_domain.rb
|
120
123
|
- lib/ovirt/template.rb
|
@@ -127,6 +130,7 @@ files:
|
|
127
130
|
- rbovirt.gemspec
|
128
131
|
- spec/endpoint.yml.example
|
129
132
|
- spec/integration/api_spec.rb
|
133
|
+
- spec/integration/instance_type_spec.rb
|
130
134
|
- spec/integration/vm_crud_spec.rb
|
131
135
|
- spec/spec_helper.rb
|
132
136
|
- spec/unit/client_spec.rb
|
@@ -157,14 +161,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
157
161
|
version: '0'
|
158
162
|
requirements: []
|
159
163
|
rubyforge_project:
|
160
|
-
rubygems_version: 2.
|
164
|
+
rubygems_version: 2.0.14
|
161
165
|
signing_key:
|
162
166
|
specification_version: 4
|
163
167
|
summary: A Ruby client for oVirt REST API
|
164
168
|
test_files:
|
165
169
|
- spec/endpoint.yml.example
|
166
170
|
- spec/integration/api_spec.rb
|
171
|
+
- spec/integration/instance_type_spec.rb
|
167
172
|
- spec/integration/vm_crud_spec.rb
|
168
173
|
- spec/spec_helper.rb
|
169
174
|
- spec/unit/client_spec.rb
|
170
175
|
- spec/unit/vm_spec.rb
|
176
|
+
has_rdoc:
|