foreman_kubevirt 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
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: []
|