foreman_kubevirt 0.1.1 → 0.1.2
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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f2ab728beaf6449390b9686a3578738848ac1da3
|
4
|
+
data.tar.gz: dc79c8e150b8d7cb02c679c9e1ffd4cf63495e0b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 53d8317d77b47588d0b049ae083aa4e261ac4983c6a047870f4dc4eb899c77fa3b1b32d2edbe1f4e23201bec197a6c171708b9a77710fde52bf78a5805a612f9
|
7
|
+
data.tar.gz: d961f6dff0ebf22b0e8a326b08c7c20d555b9e2ce6aed4bae7e4b39c6922c512a1c3f04c2215371f55a13b461bc0d3836d5938a47e1bd65e2cb746877ef29655
|
@@ -1,5 +1,5 @@
|
|
1
1
|
bootableRadio = function (item) {
|
2
|
-
|
2
|
+
disabled = $('[id$=_bootable_true]:disabled:checked:visible');
|
3
3
|
|
4
4
|
$('[id$=_bootable_true]').prop('checked', false);
|
5
5
|
if (disabled.length > 0) {
|
@@ -10,8 +10,8 @@ bootableRadio = function (item) {
|
|
10
10
|
}
|
11
11
|
|
12
12
|
cniProviderSelected = function (item) {
|
13
|
-
|
14
|
-
|
13
|
+
selected = $(item).val().toLowerCase();
|
14
|
+
networks = $(item).parentsUntil('.fields').parent().find('#networks');
|
15
15
|
|
16
16
|
if (selected == "pod") {
|
17
17
|
disableDropdown(networks);
|
@@ -57,7 +57,8 @@ module ForemanKubevirt
|
|
57
57
|
def networks
|
58
58
|
client.networkattachmentdefs.all
|
59
59
|
rescue StandardError => e
|
60
|
-
logger.warn("Failed to retrieve network attachments definition from KubeVirt,
|
60
|
+
logger.warn("Failed to retrieve network attachments definition from KubeVirt,
|
61
|
+
make sure KubeVirt has CNI provider and NetworkAttachmentDefinition CRD deployed: #{e.message}")
|
61
62
|
[]
|
62
63
|
end
|
63
64
|
|
@@ -130,84 +131,16 @@ module ForemanKubevirt
|
|
130
131
|
# "capacity"=>"2"
|
131
132
|
# }
|
132
133
|
# }
|
133
|
-
|
134
|
-
def verify_booting_from_image_is_possible(volumes)
|
135
|
-
raise ::Foreman::Exception.new N_('It is not possible to set a bootable volume and image based provisioning.') if
|
136
|
-
volumes.any? { |_, v| v["bootable"] == "true" }
|
137
|
-
end
|
138
|
-
|
139
134
|
def create_vm(args = {})
|
140
135
|
options = vm_instance_defaults.merge(args.to_hash.deep_symbolize_keys)
|
141
136
|
logger.debug("creating VM with the following options: #{options.inspect}")
|
142
|
-
volumes = []
|
143
|
-
|
144
|
-
image = args["image_id"]
|
145
|
-
volumes_attributes = args["volumes_attributes"]
|
146
|
-
raise ::Foreman::Exception.new N_('VM should be created based on Persistent Volume Claim or Image') unless (volumes_attributes.present? || image)
|
147
|
-
|
148
|
-
# Add image as volume to the virtual machine
|
149
|
-
image_provision = args["provision_method"] == "image"
|
150
|
-
if image_provision
|
151
|
-
verify_booting_from_image_is_possible(volumes_attributes)
|
152
|
-
volume = Fog::Kubevirt::Compute::Volume.new
|
153
|
-
raise ::Foreman::Exception.new N_('VM should be created based on an image') unless image
|
154
|
-
|
155
|
-
volume.info = image
|
156
|
-
volume.boot_order = 1
|
157
|
-
volume.type = 'containerDisk'
|
158
|
-
volumes << volume
|
159
|
-
end
|
160
137
|
|
161
|
-
|
162
|
-
volumes_attributes&.each_with_index do |(_, v), index|
|
163
|
-
# Add PVC as volumes to the virtual machine
|
164
|
-
pvc_name = options[:name].gsub(/[._]+/, '-') + "-claim-" + (index + 1).to_s
|
165
|
-
capacity = v["capacity"]
|
166
|
-
storage_class = v["storage_class"]
|
167
|
-
bootable = v["bootable"] && !image_provision
|
168
|
-
|
169
|
-
volume = create_vm_volume(pvc_name, capacity, storage_class, bootable)
|
170
|
-
volumes << volume
|
171
|
-
end
|
138
|
+
volumes = create_volumes_for_vm(options)
|
172
139
|
|
173
140
|
# FIXME: Add cloud-init support
|
174
141
|
# init = { 'userData' => "#!/bin/bash\necho \"fedora\" | passwd fedora --stdin"}
|
175
142
|
|
176
|
-
interfaces =
|
177
|
-
networks = []
|
178
|
-
|
179
|
-
args["interfaces_attributes"].values.each do |iface|
|
180
|
-
if iface["cni_provider"] == 'pod'
|
181
|
-
nic = {
|
182
|
-
:bridge => {},
|
183
|
-
:name => 'pod'
|
184
|
-
}
|
185
|
-
|
186
|
-
net = { :name => 'pod', :pod => {} }
|
187
|
-
else
|
188
|
-
nic = {
|
189
|
-
:bridge => {},
|
190
|
-
:name => iface["network"]
|
191
|
-
}
|
192
|
-
|
193
|
-
cni = iface["cni_provider"].to_sym
|
194
|
-
net = {
|
195
|
-
:name => iface["network"],
|
196
|
-
cni => { :networkName => iface["network"] }
|
197
|
-
}
|
198
|
-
end
|
199
|
-
|
200
|
-
# TODO: Consider replacing with 'free' boot order, also verify uniqueness
|
201
|
-
# there is a bug with bootOrder https://bugzilla.redhat.com/show_bug.cgi?id=1687341
|
202
|
-
# therefore adding to the condition not to boot from netwotk device if already asked
|
203
|
-
# to boot from disk
|
204
|
-
if iface["provision"] == true && volumes.select { |v| v.boot_order == 1 }.empty?
|
205
|
-
nic[:bootOrder] = 1
|
206
|
-
end
|
207
|
-
nic[:macAddress] = iface["mac"] if iface["mac"]
|
208
|
-
interfaces << nic
|
209
|
-
networks << net
|
210
|
-
end
|
143
|
+
interfaces, networks = create_network_devices_for_vm(options, volumes)
|
211
144
|
|
212
145
|
begin
|
213
146
|
client.vms.create(:vm_name => options[:name],
|
@@ -224,34 +157,6 @@ module ForemanKubevirt
|
|
224
157
|
end
|
225
158
|
end
|
226
159
|
|
227
|
-
def create_new_pvc(pvc_name, capacity, storage_class)
|
228
|
-
client.pvcs.create(:name => pvc_name,
|
229
|
-
:namespace => namespace,
|
230
|
-
:storage_class => storage_class,
|
231
|
-
:access_modes => ['ReadWriteOnce'],
|
232
|
-
:requests => { :storage => capacity + "G" })
|
233
|
-
end
|
234
|
-
|
235
|
-
def delete_pvcs(volumes)
|
236
|
-
volumes.each do |volume|
|
237
|
-
begin
|
238
|
-
client.pvcs.delete(volume.info) if volume.type == "persistentVolumeClaim"
|
239
|
-
rescue StandardError => e
|
240
|
-
logger.error("The PVC #{volume.info} couldn't be delete due to #{e.message}")
|
241
|
-
end
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
|
-
def create_vm_volume(pvc_name, capacity, storage_class, bootable)
|
246
|
-
create_new_pvc(pvc_name, capacity, storage_class)
|
247
|
-
|
248
|
-
volume = Fog::Kubevirt::Compute::Volume.new
|
249
|
-
volume.type = 'persistentVolumeClaim'
|
250
|
-
volume.info = pvc_name
|
251
|
-
volume.boot_order = 1 if bootable == "true"
|
252
|
-
volume
|
253
|
-
end
|
254
|
-
|
255
160
|
def destroy_vm(vm_uuid)
|
256
161
|
vm = find_vm_by_uuid(vm_uuid)
|
257
162
|
delete_pvcs(vm.volumes)
|
@@ -315,11 +220,13 @@ module ForemanKubevirt
|
|
315
220
|
vm_attrs = super
|
316
221
|
interfaces = vm.interfaces || []
|
317
222
|
vm_attrs[:interfaces_attributes] = interfaces.each_with_index.each_with_object({}) do |(interface, index), hsh|
|
318
|
-
interface_attrs = {
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
223
|
+
interface_attrs = {
|
224
|
+
mac: interface.mac,
|
225
|
+
compute_attributes: {
|
226
|
+
network: interface.network,
|
227
|
+
cni_provider: interface.cni_provider
|
228
|
+
}
|
229
|
+
}
|
323
230
|
hsh[index.to_s] = interface_attrs
|
324
231
|
end
|
325
232
|
|
@@ -385,5 +292,141 @@ module ForemanKubevirt
|
|
385
292
|
ca_cert
|
386
293
|
)
|
387
294
|
end
|
295
|
+
|
296
|
+
private
|
297
|
+
|
298
|
+
def verify_at_least_one_volume_provided(options)
|
299
|
+
image = options[:image_id]
|
300
|
+
volumes_attributes = options[:volumes_attributes]
|
301
|
+
raise ::Foreman::Exception.new N_('VM should be created based on Persistent Volume Claim or Image') unless
|
302
|
+
(volumes_attributes.present? || image)
|
303
|
+
end
|
304
|
+
|
305
|
+
def verify_booting_from_image_is_possible(volumes)
|
306
|
+
raise ::Foreman::Exception.new N_('It is not possible to set a bootable volume and image based provisioning.') if
|
307
|
+
volumes.any? { |_, v| v[:bootable] == "true" }
|
308
|
+
end
|
309
|
+
|
310
|
+
def add_volume_for_image_provision(options)
|
311
|
+
image = options[:image_id]
|
312
|
+
raise ::Foreman::Exception.new N_('VM should be created based on an image') unless image
|
313
|
+
|
314
|
+
verify_booting_from_image_is_possible(options[:volumes_attributes])
|
315
|
+
|
316
|
+
volume = Fog::Kubevirt::Compute::Volume.new
|
317
|
+
volume.info = image
|
318
|
+
volume.boot_order = 1
|
319
|
+
volume.type = 'containerDisk'
|
320
|
+
volume
|
321
|
+
end
|
322
|
+
|
323
|
+
def validate_volume_capacity(volumes_attributes)
|
324
|
+
volumes_attributes.each { |_, v| raise ::Foreman::Exception.new N_('Capacity was not found') if v[:capacity].empty? }
|
325
|
+
end
|
326
|
+
|
327
|
+
def validate_only_single_bootable_volume(volumes_attributes)
|
328
|
+
raise ::Foreman::Exception.new N_('Only one volume can be bootable') if volumes_attributes.select { |_, v| v[:bootable] == "true" }.count > 1
|
329
|
+
end
|
330
|
+
|
331
|
+
def create_new_pvc(pvc_name, capacity, storage_class)
|
332
|
+
client.pvcs.create(:name => pvc_name,
|
333
|
+
:namespace => namespace,
|
334
|
+
:storage_class => storage_class,
|
335
|
+
:access_modes => ['ReadWriteOnce'],
|
336
|
+
:requests => { :storage => capacity + "G" })
|
337
|
+
end
|
338
|
+
|
339
|
+
def delete_pvcs(volumes)
|
340
|
+
volumes.each do |volume|
|
341
|
+
begin
|
342
|
+
client.pvcs.delete(volume.info) if volume.type == "persistentVolumeClaim"
|
343
|
+
rescue StandardError => e
|
344
|
+
logger.error("The PVC #{volume.info} couldn't be delete due to #{e.message}")
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
def create_vm_volume(pvc_name, capacity, storage_class, bootable)
|
350
|
+
create_new_pvc(pvc_name, capacity, storage_class)
|
351
|
+
|
352
|
+
volume = Fog::Kubevirt::Compute::Volume.new
|
353
|
+
volume.type = 'persistentVolumeClaim'
|
354
|
+
volume.info = pvc_name
|
355
|
+
volume.boot_order = 1 if bootable == "true"
|
356
|
+
volume
|
357
|
+
end
|
358
|
+
|
359
|
+
def add_volumes_based_on_pvcs(options, image_provision)
|
360
|
+
volumes_attributes = options[:volumes_attributes]
|
361
|
+
return [] if volumes_attributes.blank?
|
362
|
+
|
363
|
+
validate_volume_capacity(volumes_attributes)
|
364
|
+
validate_only_single_bootable_volume(volumes_attributes)
|
365
|
+
|
366
|
+
volumes = []
|
367
|
+
vm_name = options[:name].gsub(/[._]+/, '-')
|
368
|
+
volumes_attributes.each_with_index do |(_, v), index|
|
369
|
+
# Add PVC as volumes to the virtual machine
|
370
|
+
pvc_name = vm_name + "-claim-" + (index + 1).to_s
|
371
|
+
capacity = v[:capacity]
|
372
|
+
storage_class = v[:storage_class]
|
373
|
+
bootable = v[:bootable] && !image_provision
|
374
|
+
|
375
|
+
volume = create_vm_volume(pvc_name, capacity, storage_class, bootable)
|
376
|
+
volumes << volume
|
377
|
+
end
|
378
|
+
|
379
|
+
volumes
|
380
|
+
end
|
381
|
+
|
382
|
+
# Creates volume elements for the VM based on provided parameters
|
383
|
+
#
|
384
|
+
# @param options[Hash] contains VM creation parameters
|
385
|
+
#
|
386
|
+
def create_volumes_for_vm(options)
|
387
|
+
verify_at_least_one_volume_provided(options)
|
388
|
+
|
389
|
+
# Add image as volume to the virtual machine
|
390
|
+
volumes = []
|
391
|
+
image_provision = options[:provision_method] == "image"
|
392
|
+
|
393
|
+
volumes << add_volume_for_image_provision(options) if image_provision
|
394
|
+
volumes.concat(add_volumes_based_on_pvcs(options, image_provision))
|
395
|
+
end
|
396
|
+
|
397
|
+
def create_pod_network_element
|
398
|
+
nic = { bridge: {}, name: 'pod' }
|
399
|
+
net = { name: 'pod', pod: {} }
|
400
|
+
[nic, net]
|
401
|
+
end
|
402
|
+
|
403
|
+
def create_network_element(iface)
|
404
|
+
nic = { bridge: {}, name: iface[:network] }
|
405
|
+
cni = iface[:cni_provider].to_sym
|
406
|
+
net = { :name => iface[:network], cni => { :networkName => iface[:network] } }
|
407
|
+
[nic, net]
|
408
|
+
end
|
409
|
+
|
410
|
+
def create_network_devices_for_vm(options, volumes)
|
411
|
+
interfaces = []
|
412
|
+
networks = []
|
413
|
+
|
414
|
+
options[:interfaces_attributes].values.each do |iface|
|
415
|
+
if iface[:cni_provider] == 'pod'
|
416
|
+
nic, net = create_pod_network_element
|
417
|
+
else
|
418
|
+
nic, net = create_network_element(iface)
|
419
|
+
end
|
420
|
+
|
421
|
+
if iface[:provision] == true && volumes.select { |v| v.boot_order == 1 }.empty?
|
422
|
+
nic[:bootOrder] = 1
|
423
|
+
end
|
424
|
+
nic[:macAddress] = iface[:mac] if iface[:mac]
|
425
|
+
interfaces << nic
|
426
|
+
networks << net
|
427
|
+
end
|
428
|
+
|
429
|
+
[interfaces, networks]
|
430
|
+
end
|
388
431
|
end
|
389
432
|
end
|
@@ -19,11 +19,42 @@ class ForemanKubevirtTest < ActiveSupport::TestCase
|
|
19
19
|
|
20
20
|
require 'kubeclient'
|
21
21
|
|
22
|
-
|
23
|
-
|
22
|
+
NETWORK_BASED_VM_ARGS = {
|
23
|
+
"cpu_cores" => "1",
|
24
|
+
"memory" => "1073741824",
|
25
|
+
"start" => "1",
|
26
|
+
"volumes_attributes" => {
|
27
|
+
"0" => { "_delete" => "", "storage_class" => "local-storage", "capacity" => "1", "bootable" => "true" },
|
28
|
+
"1" => { "_delete" => "", "storage_class" => "local-storage", "capacity" => "2" }
|
29
|
+
},
|
30
|
+
"name" => "robin-rykert.example.com",
|
31
|
+
"provision_method" => "build",
|
32
|
+
"firmware_type" => :bios,
|
33
|
+
"interfaces_attributes" => {
|
34
|
+
"0" => { "cni_provider" => "multus", "network" => "ovs-foreman", "ip" => "192.168.111.193", "mac" => "a2:b4:a2:b6:a2:a8", "provision" => true }
|
35
|
+
}
|
36
|
+
}.freeze
|
37
|
+
|
38
|
+
IMAGE_BASED_VM_ARGS = {
|
39
|
+
"cpu_cores" => "1",
|
40
|
+
"memory" => "1073741824",
|
41
|
+
"start" => "1",
|
42
|
+
"volumes_attributes" => {
|
43
|
+
"0" => { "_delete" => "", "storage_class" => "local-storage", "capacity" => "1", "bootable" => "false" }
|
44
|
+
},
|
45
|
+
"image_id" => "kubevirt/fedora-cloud-registry-disk-demo",
|
46
|
+
"name" => "olive-kempter.example.com",
|
47
|
+
"provision_method" => "image",
|
48
|
+
"firmware_type" => :bios,
|
49
|
+
"interfaces_attributes" => {
|
50
|
+
"0" => { "cni_provider" => "multus", "network" => "ovs-foreman", "ip" => "192.168.111.184", "mac" => "a2:a4:a2:b2:a2:b6", "provision" => true }
|
51
|
+
}
|
52
|
+
}.freeze
|
53
|
+
|
54
|
+
test "create_vm network based should pass" do
|
24
55
|
Fog.mock!
|
25
56
|
compute_resource = new_kubevirt_vcr
|
26
|
-
server = compute_resource.create_vm(
|
57
|
+
server = compute_resource.create_vm(NETWORK_BASED_VM_ARGS)
|
27
58
|
|
28
59
|
assert_equal "robin-rykert.example.com", server.name
|
29
60
|
assert_equal 2, server.volumes.count
|
@@ -31,11 +62,10 @@ class ForemanKubevirtTest < ActiveSupport::TestCase
|
|
31
62
|
assert_equal 1, server.interfaces.count
|
32
63
|
end
|
33
64
|
|
34
|
-
test "create_vm image based" do
|
35
|
-
vm_args = { "cpu_cores" => "1", "memory" => "1073741824", "start" => "1", "volumes_attributes" => { "1554649143334" => { "_delete" => "", "storage_class" => "local-storage", "capacity" => "1", "bootable" => "false" } }, "image_id" => "kubevirt/fedora-cloud-registry-disk-demo", "name" => "olive-kempter.example.com", "provision_method" => "image", "firmware_type" => :bios, "interfaces_attributes" => { "0" => { "cni_provider" => "multus", "network" => "ovs-foreman", "ip" => "192.168.111.184", "mac" => "a2:a4:a2:b2:a2:b6", "provision" => true } } }
|
65
|
+
test "create_vm image based should pass" do
|
36
66
|
Fog.mock!
|
37
67
|
compute_resource = new_kubevirt_vcr
|
38
|
-
server = compute_resource.create_vm(
|
68
|
+
server = compute_resource.create_vm(IMAGE_BASED_VM_ARGS)
|
39
69
|
|
40
70
|
assert_equal "olive-kempter.example.com", server.name
|
41
71
|
assert_equal 2, server.volumes.count
|
@@ -44,7 +74,18 @@ class ForemanKubevirtTest < ActiveSupport::TestCase
|
|
44
74
|
end
|
45
75
|
|
46
76
|
test "should fail when creating a VM with_bootable flag and image based" do
|
47
|
-
vm_args =
|
77
|
+
vm_args = IMAGE_BASED_VM_ARGS.deep_dup
|
78
|
+
vm_args["volumes_attributes"]["0"]["bootable"] = "true"
|
79
|
+
Fog.mock!
|
80
|
+
compute_resource = new_kubevirt_vcr
|
81
|
+
assert_raise(Foreman::Exception) do
|
82
|
+
compute_resource.create_vm(vm_args)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
test "should fail when creating a VM without an image or pvc" do
|
87
|
+
vm_args = IMAGE_BASED_VM_ARGS.deep_dup
|
88
|
+
vm_args["image_id"] = nil
|
48
89
|
Fog.mock!
|
49
90
|
compute_resource = new_kubevirt_vcr
|
50
91
|
assert_raise(Foreman::Exception) do
|
@@ -52,8 +93,10 @@ class ForemanKubevirtTest < ActiveSupport::TestCase
|
|
52
93
|
end
|
53
94
|
end
|
54
95
|
|
55
|
-
test "should fail when creating
|
56
|
-
vm_args =
|
96
|
+
test "should fail when creating image-based VM without an image" do
|
97
|
+
vm_args = IMAGE_BASED_VM_ARGS.deep_dup
|
98
|
+
vm_args["volumes_attributes"] = {}
|
99
|
+
vm_args["image_id"] = nil
|
57
100
|
Fog.mock!
|
58
101
|
compute_resource = new_kubevirt_vcr
|
59
102
|
assert_raise(Foreman::Exception) do
|
@@ -62,7 +105,19 @@ class ForemanKubevirtTest < ActiveSupport::TestCase
|
|
62
105
|
end
|
63
106
|
|
64
107
|
test "should fail when creating a VM with PVC and not providing a capacity" do
|
65
|
-
vm_args =
|
108
|
+
vm_args = NETWORK_BASED_VM_ARGS.deep_dup
|
109
|
+
vm_args["volumes_attributes"]["0"]["capacity"] = nil
|
110
|
+
Fog.mock!
|
111
|
+
compute_resource = new_kubevirt_vcr
|
112
|
+
assert_raise(Foreman::Exception) do
|
113
|
+
compute_resource.create_vm(vm_args)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
test "should fail when creating a VM with two bootable PVCs" do
|
118
|
+
vm_args = NETWORK_BASED_VM_ARGS.deep_dup
|
119
|
+
vm_args["volumes_attributes"]["0"]["bootable"] = "true"
|
120
|
+
vm_args["volumes_attributes"]["1"]["bootable"] = "true"
|
66
121
|
Fog.mock!
|
67
122
|
compute_resource = new_kubevirt_vcr
|
68
123
|
assert_raise(Foreman::Exception) do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreman_kubevirt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Moti Asayag
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-04-
|
11
|
+
date: 2019-04-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -96,7 +96,7 @@ files:
|
|
96
96
|
- test/unit/foreman_kubevirt_test.rb
|
97
97
|
homepage: https://github.com/theforeman/foreman_kubevirt
|
98
98
|
licenses:
|
99
|
-
-
|
99
|
+
- GPL-3.0
|
100
100
|
metadata: {}
|
101
101
|
post_install_message:
|
102
102
|
rdoc_options: []
|