foreman_kubevirt 0.4.2 → 0.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 39fc9c907b2357c24a43be724a2e00b2105452abd42911c836b1cd5dc0f6b085
4
- data.tar.gz: 00b5f9b3bcf1c36c540e6a1261c1c68fb2f9f337fc0ef6b669ef5da182f22d7d
3
+ metadata.gz: c3f29a8f48b11e762c608eb0214c101a9bca7e87e8abc43419f5b04d538461a8
4
+ data.tar.gz: f6d536736bc4b8589ac3edb77ad28c85370bc3408bad137674e6ead7017076e1
5
5
  SHA512:
6
- metadata.gz: aedfe24b1155d7140ca79bb056292fa28abfdc33c64bb401fa76c482ba61950b81461832d21a0fda69b94e805d508079b1959661c01e5fc96770a503db67d62a
7
- data.tar.gz: f3879d38d591219040d0bf4bd4f1b645548ef0b7c471ae3da62705a1a5a5d4b44619f5e2d7b6c3c24f5d9e9c0fb6c1f20b77a0e65b8649205cf95b8469c96126
6
+ metadata.gz: 1497af24453af9057568e04f1106e11e0e1b9fab1d460d9007baebb64b5165db2fb2b549ef6a5c432ce8393f60dac11cf60533ce2c4908cc9c64a6b4eae65b47
7
+ data.tar.gz: 32ee5c20e2a13e59fe10fef1186db415ca4f06da8fbf22e24d64df7f366f9e5b9775d33eb7618fbc4bc3e6b5553fe2830910a50e295c35e0c95143c83f49e38b
@@ -183,13 +183,14 @@ module ForemanKubevirt
183
183
  user_data = { "userData" => options[:user_data] } if options[:user_data].present?
184
184
 
185
185
  begin
186
- volumes = create_volumes_for_vm(options)
186
+ volumes, volume_templates = create_volumes_for_vm(options)
187
187
  interfaces, networks = create_network_devices_for_vm(options, volumes)
188
188
  client.vms.create(:vm_name => options[:name],
189
189
  :cpus => options[:cpu_cores].to_i,
190
190
  :memory_size => convert_memory(options[:memory] + "b", :mi).to_s,
191
191
  :memory_unit => "Mi",
192
192
  :volumes => volumes,
193
+ :volume_templates => volume_templates,
193
194
  :cloudinit => user_data,
194
195
  :networks => networks,
195
196
  :interfaces => interfaces)
@@ -221,7 +222,8 @@ module ForemanKubevirt
221
222
  def vm_instance_defaults
222
223
  {
223
224
  :memory => 1024.megabytes.to_s,
224
- :cpu_cores => '1'
225
+ :cpu_cores => '1',
226
+ :volumes => [new_volume].compact,
225
227
  }
226
228
  end
227
229
 
@@ -344,7 +346,7 @@ module ForemanKubevirt
344
346
  :kubevirt_namespace => namespace,
345
347
  :kubevirt_token => token,
346
348
  :kubevirt_log => logger,
347
- :kubevirt_verify_ssl => ca_cert.present?,
349
+ :kubevirt_verify_ssl => true,
348
350
  :kubevirt_ca_cert => ca_cert,
349
351
  :kubevirt_version => "v1alpha3"
350
352
  )
@@ -376,22 +378,42 @@ module ForemanKubevirt
376
378
  (volumes_attributes.present? || image)
377
379
  end
378
380
 
379
- def verify_booting_from_image_is_possible(volumes)
380
- raise ::Foreman::Exception.new _('It is not possible to set a bootable volume and image based provisioning.') if
381
- volumes&.any? { |_, v| v[:bootable] == "true" }
381
+ def add_volume_for_image_provision(options)
382
+ volume = Fog::Kubevirt::Compute::Volume.new
383
+ volume.config = { name: rootdisk_name(options) }
384
+ volume.boot_order = 1
385
+ volume.name = 'rootdisk'
386
+ volume.type = 'dataVolume'
387
+ volume
382
388
  end
383
389
 
384
- def add_volume_for_image_provision(options)
390
+ def add_volume_template_for_image_provision(options)
385
391
  image = options[:image_id]
386
392
  raise ::Foreman::Exception.new _('VM should be created based on an image') unless image
387
393
 
388
- verify_booting_from_image_is_possible(options[:volumes_attributes])
394
+ namespace, name = image.split('/', 2)
395
+ if name.nil?
396
+ name = namespace
397
+ namespace = nil
398
+ end
389
399
 
390
- volume = Fog::Kubevirt::Compute::Volume.new
391
- volume.info = image
392
- volume.boot_order = 1
393
- volume.type = 'containerDisk'
394
- volume
400
+ volumes_attributes = options.fetch(:volumes_attributes, {})
401
+ _, boot_volume = volumes_attributes.find { |_, vol| vol[:bootable] == 'true' }
402
+ raise ::Foreman::Exception.new _('A bootable volume is required as a target for the image') unless boot_volume
403
+ capacity = boot_volume[:capacity]
404
+ capacity += "G" unless capacity.end_with? "G"
405
+ storage_class = boot_volume[:storage_class]
406
+ storage = { resources: { requests: { storage: capacity } } }
407
+ storage[:storageClassName] = storage_class if storage_class.present?
408
+
409
+ source_ref = { kind: 'DataSource', name: name, namespace: namespace }.compact
410
+ metadata = { name: rootdisk_name(options) }
411
+ { kind: 'DataVolume', metadata: metadata, spec: { sourceRef: source_ref, storage: storage } }
412
+ end
413
+
414
+ def rootdisk_name(options)
415
+ vm_name = options[:name].parameterize
416
+ "#{vm_name}-root"
395
417
  end
396
418
 
397
419
  def validate_volume_capacity(volumes_attributes)
@@ -443,6 +465,8 @@ module ForemanKubevirt
443
465
  volumes = []
444
466
  vm_name = options[:name].gsub(/[._]+/, '-')
445
467
  volumes_attributes.each_with_index do |(_, v), index|
468
+ # skip if this is a boot volume for image provisioning
469
+ next if image_provision && v[:bootable]
446
470
  # Add PVC as volumes to the virtual machine
447
471
  pvc_name = vm_name + "-claim-" + (index + 1).to_s
448
472
  capacity = v[:capacity]
@@ -465,10 +489,15 @@ module ForemanKubevirt
465
489
 
466
490
  # Add image as volume to the virtual machine
467
491
  volumes = []
492
+ volume_templates = []
468
493
  image_provision = options[:provision_method] == "image"
469
494
 
470
495
  volumes << add_volume_for_image_provision(options) if image_provision
471
496
  volumes.concat(add_volumes_based_on_pvcs(options, image_provision))
497
+
498
+ volume_templates << add_volume_template_for_image_provision(options) if image_provision
499
+
500
+ [volumes, volume_templates]
472
501
  end
473
502
 
474
503
  def create_pod_network_element
@@ -9,7 +9,7 @@
9
9
  %>
10
10
 
11
11
  <%= textarea_f f, :ca_cert, :label => _("X509 Certification Authorities"),
12
- :placeholder => _("Optionally provide a CA, or a correctly ordered CA chain or a path to a file. If left blank - insecure.") %>
12
+ :placeholder => _("Optionally provide a CA, or a correctly ordered CA chain or a path to a file.") %>
13
13
 
14
14
  <div class="col-md-offset-2">
15
15
  <%= test_connection_button_f(f, f.object.connection_valid?) %>
@@ -1,4 +1,4 @@
1
1
  <%= text_f f, :username, :value => @image.username || "root", :help_inline => _("The user that is used to ssh into the instance, normally cloud-user, ec2-user, ubuntu, root etc") %>
2
2
  <%= password_f f, :password, :help_inline => _("Password to authenticate with - used for SSH finish step.") %>
3
3
  <%= checkbox_f f, :user_data, :help_inline => _("Does this image support user data input (e.g. via cloud-init)?") %>
4
- <%= image_field(f, :label => _("Image"), :help_inline => _("The name of the image in the registry.")) %>
4
+ <%= image_field(f, :label => _("Image"), :help_inline => _("The name of the DataSource that contains the image. Use namespace/name notation to use a DataSource in a different namespace.")) %>
@@ -1,3 +1,3 @@
1
1
  module ForemanKubevirt
2
- VERSION = '0.4.2'.freeze
2
+ VERSION = '0.5.0'.freeze
3
3
  end
@@ -9,6 +9,23 @@ class ForemanKubevirtTest < ActiveSupport::TestCase
9
9
  ::FactoryBot.build(:compute_resource_kubevirt)
10
10
  end
11
11
 
12
+ def mocked_client
13
+ vms = stub
14
+ pvcs = stub
15
+ pvcs.stubs(:create)
16
+ pvcs.stubs(:delete)
17
+ servers = stub
18
+ servers.stubs(:get)
19
+ storageclasses = stub
20
+ storageclasses.stubs(:all).returns([{ 'name': 'local' }])
21
+ client = stub
22
+ client.stubs(:vms).returns(vms)
23
+ client.stubs(:pvcs).returns(pvcs)
24
+ client.stubs(:servers).returns(servers)
25
+ client.stubs(:storageclasses).returns(storageclasses)
26
+ client
27
+ end
28
+
12
29
  test "host_interfaces_attrs" do
13
30
  record = new_kubevirt_vcr
14
31
  host = ::FactoryBot.build(:host_kubevirt, :with_interfaces)
@@ -23,26 +40,65 @@ class ForemanKubevirtTest < ActiveSupport::TestCase
23
40
 
24
41
  describe "create_vm" do
25
42
  test "uses sanitized NIC names" do
26
- vms = stub
27
- pvcs = stub
28
- pvcs.stubs(:create)
29
- pvcs.stubs(:delete)
30
- servers = stub
31
- servers.stubs(:get)
32
- client = stub
33
- client.stubs(:vms).returns(vms)
34
- client.stubs(:pvcs).returns(pvcs)
35
- client.stubs(:servers).returns(servers)
36
43
  record = new_kubevirt_vcr
44
+ client = mocked_client
37
45
  record.stubs(:client).returns(client)
38
46
 
39
47
  expected_networks = [{ :name => "default-network", :multus => { :networkName => "default/network" } }]
40
48
  expected_interfaces = [{ :bridge => {}, :name => "default-network" }]
41
49
 
42
- vms.expects(:create).with(vm_name: anything, cpus: anything, memory_size: anything, memory_unit: anything, volumes: anything, cloudinit: anything, networks: expected_networks, interfaces: expected_interfaces)
50
+ client.vms.expects(:create).with do |args|
51
+ assert_equal expected_networks, args[:networks]
52
+ assert_equal expected_interfaces, args[:interfaces]
53
+ end
43
54
 
44
55
  record.create_vm({ :name => "test", :volumes_attributes => { 0 => { :capacity => "5" } }, :interfaces_attributes => { "0" => { "cni_provider" => "multus", "network" => "default/network" } } })
45
56
  end
57
+
58
+ test "raises an error for image based provisioning without an explicit boot volume" do
59
+ record = new_kubevirt_vcr
60
+
61
+ error = assert_raises(Foreman::Exception) do
62
+ record.create_vm({ :name => "test", :provision_method => 'image', :image_id => "default/template", :volumes_attributes => {}, :interfaces_attributes => { "0" => { "cni_provider" => "multus", "network" => "default/network" } } })
63
+ end
64
+ assert_match(/A bootable volume is required as a target for the image/, error.message)
65
+ end
66
+
67
+ test "uses dataVolume for image based provisioning with an explicit boot volume" do
68
+ record = new_kubevirt_vcr
69
+ client = mocked_client
70
+ record.stubs(:client).returns(client)
71
+
72
+ client.vms.expects(:create).with do |args|
73
+ assert_equal 1, args[:volumes].length
74
+ assert_equal 1, args[:volume_templates].length
75
+
76
+ volume = args[:volumes].first
77
+ assert_equal 'dataVolume', volume.type
78
+ assert_equal 'test-root', volume.config[:name]
79
+ assert_equal 'rootdisk', volume.name
80
+ assert_equal 1, volume.boot_order
81
+
82
+ volume_template = args[:volume_templates].first
83
+ assert_equal 'DataVolume', volume_template[:kind]
84
+ assert_equal 'test-root', volume_template[:metadata][:name]
85
+ assert_equal 'DataSource', volume_template[:spec][:sourceRef][:kind]
86
+ assert_equal 'default', volume_template[:spec][:sourceRef][:namespace]
87
+ assert_equal 'template', volume_template[:spec][:sourceRef][:name]
88
+ assert_equal '10G', volume_template[:spec][:storage][:resources][:requests][:storage]
89
+ end
90
+
91
+ record.create_vm({ :name => "test", :provision_method => 'image', :image_id => "default/template", :volumes_attributes => { "0" => { :capacity => "10", :bootable => "true" } }, :interfaces_attributes => { "0" => { "cni_provider" => "multus", "network" => "default/network" } } })
92
+ end
93
+
94
+ test "raises an error for image based provisioning with only an extra data volume" do
95
+ record = new_kubevirt_vcr
96
+
97
+ error = assert_raises(Foreman::Exception) do
98
+ record.create_vm({ :name => "test", :provision_method => 'image', :image_id => "default/template", :volumes_attributes => { "0" => { :capacity => "10" } }, :interfaces_attributes => { "0" => { "cni_provider" => "multus", "network" => "default/network" } } })
99
+ end
100
+ assert_match(/A bootable volume is required as a target for the image/, error.message)
101
+ end
46
102
  end
47
103
 
48
104
  describe "create_network_element" do
@@ -40,7 +40,7 @@ class ForemanKubevirtTest < ActiveSupport::TestCase
40
40
  "memory" => "1073741824",
41
41
  "start" => "1",
42
42
  "volumes_attributes" => {
43
- "0" => { "_delete" => "", "storage_class" => "local-storage", "capacity" => "1", "bootable" => "false" }
43
+ "0" => { "_delete" => "", "storage_class" => "local-storage", "capacity" => "1", "bootable" => "true" }
44
44
  },
45
45
  "image_id" => "kubevirt/fedora-cloud-registry-disk-demo",
46
46
  "name" => "olive-kempter.example.com",
@@ -73,26 +73,16 @@ class ForemanKubevirtTest < ActiveSupport::TestCase
73
73
  assert_equal 1, server.interfaces.count
74
74
  end
75
75
 
76
- test "create_vm image based without additional volumes should pass" do
76
+ test "create_vm image based without additional volumes should fail" do
77
77
  vm_args = IMAGE_BASED_VM_ARGS.deep_dup
78
78
  vm_args.delete("volumes_attributes")
79
79
 
80
- Fog.mock!
81
- compute_resource = new_kubevirt_vcr
82
- server = compute_resource.create_vm(vm_args)
83
-
84
- assert_equal "olive-kempter.example.com", server.name
85
- end
86
-
87
- test "should fail when creating a VM with_bootable flag and image based" do
88
- vm_args = IMAGE_BASED_VM_ARGS.deep_dup
89
- vm_args["volumes_attributes"]["0"]["bootable"] = "true"
90
80
  Fog.mock!
91
81
  compute_resource = new_kubevirt_vcr
92
82
  exception = assert_raise(Foreman::Exception) do
93
83
  compute_resource.create_vm(vm_args)
94
84
  end
95
- assert_match(/It is not possible to set a bootable volume and image based provisioning./, exception.message)
85
+ assert_match(/A bootable volume is required as a target for the image/, exception.message)
96
86
  end
97
87
 
98
88
  test "should fail when creating a VM without an image or pvc" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman_kubevirt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Moti Asayag
@@ -15,7 +15,7 @@ dependencies:
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: 1.3.3
18
+ version: 1.6.0
19
19
  - - "<"
20
20
  - !ruby/object:Gem::Version
21
21
  version: '2'
@@ -25,7 +25,7 @@ dependencies:
25
25
  requirements:
26
26
  - - ">="
27
27
  - !ruby/object:Gem::Version
28
- version: 1.3.3
28
+ version: 1.6.0
29
29
  - - "<"
30
30
  - !ruby/object:Gem::Version
31
31
  version: '2'