foreman_kubevirt 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +619 -0
  3. data/README.md +156 -0
  4. data/Rakefile +44 -0
  5. data/app/assets/javascripts/foreman_kubevirt/kubevirt.js +31 -0
  6. data/app/assets/javascripts/foreman_kubevirt/nic_info.js +9 -0
  7. data/app/controllers/foreman_kubevirt/concerns/api/compute_resources_controller_extensions.rb +26 -0
  8. data/app/models/concerns/fog_extensions/kubevirt/network.rb +11 -0
  9. data/app/models/concerns/fog_extensions/kubevirt/server.rb +55 -0
  10. data/app/models/concerns/fog_extensions/kubevirt/vmnic.rb +12 -0
  11. data/app/models/concerns/fog_extensions/kubevirt/volume.rb +26 -0
  12. data/app/models/foreman_kubevirt/kubevirt.rb +370 -0
  13. data/app/views/api/v2/compute_resources/kubevirt.json.rabl +1 -0
  14. data/app/views/compute_resources/form/_kubevirt.html.erb +14 -0
  15. data/app/views/compute_resources/show/_kubevirt.html.erb +14 -0
  16. data/app/views/compute_resources_vms/form/kubevirt/_base.html.erb +27 -0
  17. data/app/views/compute_resources_vms/form/kubevirt/_network.html.erb +15 -0
  18. data/app/views/compute_resources_vms/form/kubevirt/_volume.html.erb +21 -0
  19. data/app/views/compute_resources_vms/index/_kubevirt.html.erb +29 -0
  20. data/app/views/compute_resources_vms/show/_kubevirt.html.erb +55 -0
  21. data/app/views/images/form/_kubevirt.html.erb +4 -0
  22. data/config/routes.rb +2 -0
  23. data/lib/foreman_kubevirt/engine.rb +75 -0
  24. data/lib/foreman_kubevirt/version.rb +3 -0
  25. data/lib/foreman_kubevirt.rb +4 -0
  26. data/lib/tasks/foreman_kubevirt_tasks.rake +47 -0
  27. data/locale/Makefile +60 -0
  28. data/locale/en/foreman_kubevirt.po +19 -0
  29. data/locale/foreman_kubevirt.pot +19 -0
  30. data/locale/gemspec.rb +2 -0
  31. data/test/factories/compute_resource_factories.rb +10 -0
  32. data/test/factories/host_factories.rb +49 -0
  33. data/test/factories/nic_factories.rb +31 -0
  34. data/test/models/compute_resources/kubevirt_test.rb +69 -0
  35. data/test/test_plugin_helper.rb +7 -0
  36. data/test/unit/foreman_kubevirt_test.rb +45 -0
  37. metadata +127 -0
@@ -0,0 +1,370 @@
1
+ require 'foreman/exception'
2
+
3
+ module ForemanKubevirt
4
+ class Kubevirt < ComputeResource
5
+ alias_attribute :hostname, :url
6
+ alias_attribute :token, :password
7
+ alias_attribute :namespace, :user
8
+ validates :hostname, :api_port, :namespace, :token, :presence => true
9
+ validate :test_connection
10
+
11
+ def ca_cert
12
+ attrs[:ca_cert]
13
+ end
14
+
15
+ def ca_cert=(key)
16
+ attrs[:ca_cert] = key
17
+ end
18
+
19
+ def api_port
20
+ attrs[:api_port]
21
+ end
22
+
23
+ def api_port=(key)
24
+ attrs[:api_port] = key
25
+ end
26
+
27
+ def capabilities
28
+ %i[build image new_volume]
29
+ end
30
+
31
+ def provided_attributes
32
+ { :uuid => :name, :mac => :mac }
33
+ end
34
+
35
+ def available_images
36
+ []
37
+ end
38
+
39
+ def self.provider_friendly_name
40
+ 'KubeVirt'
41
+ end
42
+
43
+ def to_label
44
+ "#{name} (#{provider_friendly_name})"
45
+ end
46
+
47
+ def self.model_name
48
+ ComputeResource.model_name
49
+ end
50
+
51
+ def test_connection(_options = {})
52
+ client&.valid? && client&.virt_supported?
53
+ rescue StandardError => e
54
+ errors[:base] << e.message
55
+ end
56
+
57
+ def networks
58
+ client.networkattachmentdefs.all
59
+ rescue StandardError => e
60
+ logger.warn("Failed to retrieve network attachments definition from KubeVirt, make sure KubeVirt has CNI provider and NetworkAttachmentDefinition CRD deployed: #{e.message}")
61
+ []
62
+ end
63
+
64
+ def find_vm_by_uuid(uuid)
65
+ super
66
+ rescue Fog::Kubevirt::Errors::ClientError => e
67
+ Foreman::Logging.exception("Failed retrieving KubeVirt vm by uuid #{uuid}", e)
68
+ raise ActiveRecord::RecordNotFound
69
+ end
70
+
71
+ def volumes
72
+ client.volumes.all
73
+ end
74
+
75
+ def storage_classes
76
+ client.storageclasses.all
77
+ end
78
+
79
+ def storage_classes_for_select
80
+ storage_classes.map { |sc| OpenStruct.new(id: sc.name, description: "#{sc.name} (#{sc.provisioner})") }
81
+ end
82
+
83
+ def new_volume(attr = {})
84
+ return unless new_volume_errors.empty?
85
+
86
+ Fog::Kubevirt::Compute::Volume.new(attr)
87
+ end
88
+
89
+ def new_volume_errors
90
+ errors = []
91
+ errors.push _('no Persistent Volumes available on provider') if storage_classes.empty?
92
+ errors
93
+ end
94
+
95
+ def cni_providers
96
+ [[_("multus"), :multus], [_("genie"), :genie], [_("pod"), :pod]]
97
+ end
98
+
99
+ # @param args[Hash] contains VM creation parameters
100
+ # cpu_cores[str] - the number of cpu cores
101
+ # memory[str] - the memory for the VM
102
+ # start[bool] - indicates if the vm should be started
103
+ # name[str] - the name of the VM
104
+ # interfaces_attributes[Hash] - the attributes for the interfaces, i.e.:
105
+ # {
106
+ # "0" => {
107
+ # "network" => "ovs-foreman",
108
+ # "boot" => "1",
109
+ # "cni_provider" => "multus"
110
+ # },
111
+ # "1" => {
112
+ # "cni_provider" => "pod"
113
+ # "boot" => "0"
114
+ # }
115
+ # }
116
+ #
117
+ # volumes_attributes[Hash] - the attributes for the persistent volume claims:
118
+ # {
119
+ # "1554394214729" => {
120
+ # "storage_class" => "local-storage",
121
+ # "name" => "alvin-hinojosa1",
122
+ # "capacity" => "3",
123
+ # "bootable"=>"true"
124
+ # },
125
+ # "1554394230987" => {
126
+ # "storage_class" => "local-storage",
127
+ # "name" => "alvin-hinojosa",
128
+ # "capacity"=>"2"
129
+ # }
130
+ # }
131
+ def create_vm(args = {})
132
+ options = vm_instance_defaults.merge(args.to_hash.deep_symbolize_keys)
133
+ logger.debug("creating VM with the following options: #{options.inspect}")
134
+ volumes = []
135
+
136
+ image = args["image_id"]
137
+ volumes_attributes = args["volumes_attributes"]
138
+ raise "VM should be created based on Persistent Volume Claim or Image" unless (volumes_attributes.present? || image)
139
+
140
+ # Add image as volume to the virtual machine
141
+ image_provision = args["provision_method"] == "image"
142
+ if image_provision
143
+ volume = Fog::Kubevirt::Compute::Volume.new
144
+ raise "VM should be created based on an image" unless image
145
+
146
+ volume.info = image
147
+ volume.boot_order = 1
148
+ volume.type = 'containerDisk'
149
+ volumes << volume
150
+ end
151
+
152
+ volumes_attributes&.each_with_index do |(_, v), index|
153
+ # Add PVC as volumes to the virtual machine
154
+ pvc_name = options[:name].gsub(/[._]+/, '-') + "-claim-" + (index + 1).to_s
155
+ capacity = v["capacity"]
156
+ storage_class = v["storage_class"]
157
+ bootable = v["bootable"] && !image_provision
158
+
159
+ volume = create_vm_volume(pvc_name, capacity, storage_class, bootable)
160
+ volumes << volume
161
+ end
162
+
163
+ # FIXME: Add cloud-init support
164
+ # init = { 'userData' => "#!/bin/bash\necho \"fedora\" | passwd fedora --stdin"}
165
+
166
+ interfaces = []
167
+ networks = []
168
+
169
+ args["interfaces_attributes"].values.each do |iface|
170
+ if iface["cni_provider"] == 'pod'
171
+ nic = {
172
+ :bridge => {},
173
+ :name => 'pod'
174
+ }
175
+
176
+ net = { :name => 'pod', :pod => {} }
177
+ else
178
+ nic = {
179
+ :bridge => {},
180
+ :name => iface["network"]
181
+ }
182
+
183
+ cni = iface["cni_provider"].to_sym
184
+ net = {
185
+ :name => iface["network"],
186
+ cni => { :networkName => iface["network"] }
187
+ }
188
+ end
189
+
190
+ # TODO: Consider replacing with 'free' boot order, also verify uniqueness
191
+ # there is a bug with bootOrder https://bugzilla.redhat.com/show_bug.cgi?id=1687341
192
+ # therefore adding to the condition not to boot from netwotk device if already asked
193
+ # to boot from disk
194
+ if iface["provision"] == true && volumes.select { |v| v.boot_order == 1 }.empty?
195
+ nic[:bootOrder] = 1
196
+ end
197
+ nic[:macAddress] = iface["mac"] if iface["mac"]
198
+ interfaces << nic
199
+ networks << net
200
+ end
201
+
202
+ begin
203
+ client.vms.create(:vm_name => options[:name],
204
+ :cpus => options[:cpu_cores].to_i,
205
+ :memory_size => options[:memory].to_i / 2**20,
206
+ :volumes => volumes,
207
+ # :cloudinit => init,
208
+ :networks => networks,
209
+ :interfaces => interfaces)
210
+ client.servers.get(options[:name])
211
+ rescue Fog::Kubevirt::Errors::ClientError => e
212
+ delete_pvcs(volumes)
213
+ raise e
214
+ end
215
+ end
216
+
217
+ def create_new_pvc(pvc_name, capacity, storage_class)
218
+ client.pvcs.create(:name => pvc_name,
219
+ :namespace => namespace,
220
+ :storage_class => storage_class,
221
+ :access_modes => ['ReadWriteOnce'],
222
+ :requests => { :storage => capacity + "G" })
223
+ end
224
+
225
+ def delete_pvcs(volumes)
226
+ volumes.each do |volume|
227
+ begin
228
+ client.pvcs.delete(volume.info) if volume.type == "persistentVolumeClaim"
229
+ rescue StandardError => e
230
+ logger.error("The PVC #{volume.info} couldn't be delete due to #{e.message}")
231
+ end
232
+ end
233
+ end
234
+
235
+ def create_vm_volume(pvc_name, capacity, storage_class, bootable)
236
+ create_new_pvc(pvc_name, capacity, storage_class)
237
+
238
+ volume = Fog::Kubevirt::Compute::Volume.new
239
+ volume.type = 'persistentVolumeClaim'
240
+ volume.info = pvc_name
241
+ volume.boot_order = 1 if bootable == "true"
242
+ volume
243
+ end
244
+
245
+ def destroy_vm(vm_uuid)
246
+ vm = find_vm_by_uuid(vm_uuid)
247
+ delete_pvcs(vm.volumes)
248
+ vm.destroy
249
+ rescue ActiveRecord::RecordNotFound
250
+ true
251
+ end
252
+
253
+ def host_compute_attrs(host)
254
+ attrs = super
255
+ attrs[:interfaces_attributes].each_value { |nic| nic["network"] = nil if nic["cni_provider"] == "pod" }
256
+ attrs
257
+ end
258
+
259
+ #
260
+ # Since 'name' is the identity/UUID of server/vm, we need to override
261
+ # default values that assign also value for 'name' so vm_exists? will
262
+ # return 'false'
263
+ def vm_instance_defaults
264
+ {
265
+ :memory => 1024.megabytes,
266
+ :cpu_cores => '1'
267
+ }
268
+ end
269
+
270
+ def new_interface(attr = {})
271
+ Fog::Kubevirt::Compute::VmNic.new attr
272
+ end
273
+
274
+ #
275
+ # Overrding base class implementation since 'mac' is required for the created interface
276
+ #
277
+ def host_interfaces_attrs(host)
278
+ host.interfaces.select(&:physical?).each.with_index.reduce({}) do |hash, (nic, index)|
279
+ hash.merge(index.to_s => nic.compute_attributes.merge(ip: nic.ip, mac: nic.mac, provision: nic.provision))
280
+ end
281
+ end
282
+
283
+ #
284
+ # Overrding base class implementation since 'pvc' is required
285
+ #
286
+ def set_vm_volumes_attributes(vm, vm_attrs)
287
+ volumes = vm.volumes.collect do |vol|
288
+ next unless vol.type == 'persistentVolumeClaim'
289
+
290
+ begin
291
+ vol.pvc = client.pvcs.get(vol.info)
292
+ vol
293
+ rescue StandardError => e
294
+ # An import of a VM where one of its PVC doesn't exist
295
+ Foreman::Logging.exception("Import VM fail: The PVC #{vol.info} does not exist for VM #{vm.name}", e)
296
+ nil
297
+ end
298
+ end.compact
299
+ vm_attrs[:volumes_attributes] = Hash[volumes.each_with_index.map { |volume, idx| [idx.to_s, volume.attributes] }]
300
+
301
+ vm_attrs
302
+ end
303
+
304
+ def vm_compute_attributes(vm)
305
+ vm_attrs = super
306
+ interfaces = vm.interfaces || []
307
+ vm_attrs[:interfaces_attributes] = interfaces.each_with_index.each_with_object({}) do |(interface, index), hsh|
308
+ interface_attrs = {}
309
+ interface_attrs[:compute_attributes] = {}
310
+ interface_attrs[:mac] = interface.mac
311
+ interface_attrs[:compute_attributes][:network] = interface.network
312
+ interface_attrs[:compute_attributes][:cni_provider] = interface.cni_provider
313
+ hsh[index.to_s] = interface_attrs
314
+ end
315
+
316
+ vm_attrs
317
+ end
318
+
319
+ def associated_host(vm)
320
+ associate_by("mac", vm.mac)
321
+ end
322
+
323
+ # TODO: max supported values should be fetched according to namespace
324
+ # capabilities: kubectl get limits namespace_name
325
+ def max_cpu_count
326
+ 16
327
+ end
328
+
329
+ def max_socket_count
330
+ 16
331
+ end
332
+
333
+ def max_memory
334
+ 64.gigabytes
335
+ end
336
+
337
+ protected
338
+
339
+ def client
340
+ return @client if @client
341
+
342
+ @client ||= Fog::Kubevirt::Compute.new(
343
+ :kubevirt_hostname => hostname,
344
+ :kubevirt_port => api_port,
345
+ :kubevirt_namespace => namespace,
346
+ :kubevirt_token => token,
347
+ :kubevirt_log => logger,
348
+ :kubevirt_verify_ssl => ca_cert.present?,
349
+ :kubevirt_ca_cert => ca_cert
350
+ )
351
+ rescue OpenSSL::X509::CertificateError
352
+ raise_certification_failure_exception
353
+ rescue StandardError => e
354
+ if e.message =~ /SSL_connect.*certificate verify failed/ ||
355
+ e.message =~ /Peer certificate cannot be authenticated with given CA certificates/
356
+ raise_certification_failure_exception
357
+ else
358
+ raise e
359
+ end
360
+ end
361
+
362
+ def raise_certification_failure_exception
363
+ raise Foreman::FingerprintException.new(
364
+ N_("The remote system presented a public key signed by an unidentified certificate authority.
365
+ If you are sure the remote system is authentic, go to the compute resource edit page, press the 'Test Connection' button and submit"),
366
+ ca_cert
367
+ )
368
+ end
369
+ end
370
+ end
@@ -0,0 +1 @@
1
+ attributes :hostname, :api_port, :namespace
@@ -0,0 +1,14 @@
1
+ <%= text_f f, :hostname, :label => _("Hostname") %>
2
+ <%= text_f f, :api_port, :label => _("API Port"), :required => true %>
3
+ <%= text_f f, :namespace, :label => _("Namespace"), :required => true %>
4
+ <%= password_f f, :password, :label => _("Token"), :required => true,
5
+ :keep_value => true, :unset => unset_password?,
6
+ :help_block => _("e.g. eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9..."),
7
+ :help_inline => documentation_button('5.2.10PasswordEncryption') %>
8
+
9
+ <%= textarea_f f, :ca_cert, :label => _("X509 Certification Authorities"),
10
+ :placeholder => _("Optionally provide a CA, or a correctly ordered CA chain or a path to a file. If left blank - insecure.") %>
11
+
12
+ <div class="col-md-offset-2">
13
+ <%= test_connection_button_f(f, true) %>
14
+ </div>
@@ -0,0 +1,14 @@
1
+ <tr>
2
+ <td><%= _("Hostname") %></td>
3
+ <td><%= @compute_resource.hostname %></td>
4
+ </tr>
5
+
6
+ <tr>
7
+ <td><%= _("API Port") %></td>
8
+ <td><%= @compute_resource.api_port %></td>
9
+ </tr>
10
+
11
+ <tr>
12
+ <td><%= _("Namespace") %></td>
13
+ <td><%= @compute_resource.user %></td>
14
+ </tr>
@@ -0,0 +1,27 @@
1
+ <%= javascript_tag("$(document).on('ContentLoad', tfm.numFields.initAll)"); %>
2
+
3
+ <%= text_f f, :name, :label => _('Name'), :label_size => "col-md-2", :disabled => !new_vm if show_vm_name? %>
4
+
5
+ <%= counter_f f, :cpu_cores, :disabled => !new_vm, :label => _('CPUs'), :label_size => 'col-md-2', :'data-soft-max' => compute_resource.max_cpu_count %>
6
+
7
+ <%= byte_size_f f, :memory, :disabled => !new_vm, :label => _('Memory'), :label_size => "col-md-2", :'data-soft-max' => compute_resource.max_memory %>
8
+
9
+ <% checked = params[:host] && params[:host][:compute_attributes] && params[:host][:compute_attributes][:start] || '1' %>
10
+ <%= checkbox_f f, :start, { :checked => (checked == '1'), :help_inline => _("Power ON this machine"), :label => _('Start'), :label_size => "col-md-2"} if new_vm && controller_name != "compute_attributes" %>
11
+
12
+
13
+ <% unless local_assigns[:hide_image] %>
14
+ <%
15
+ arch ||= nil ; os ||= nil
16
+ images = possible_images(compute_resource, arch, os)
17
+ -%>
18
+
19
+ <div id='image_selection'>
20
+ <%= select_f f, :image_id, images, :uuid, :name,
21
+ { :include_blank => (images.empty? || images.size == 1) ? false : _('Please select an image') },
22
+ { :disabled => images.empty?, :label => _('Image'), :label_size => "col-md-2" } %>
23
+ </div>
24
+ <% end %>
25
+
26
+ <%= javascript_include_tag("foreman_kubevirt/nic_info.js") %>
27
+ <%= javascript_include_tag("foreman_kubevirt/kubevirt.js") %>
@@ -0,0 +1,15 @@
1
+ <%= selectable_f f, :cni_provider, compute_resource.cni_providers, {},
2
+ :class => "col-md-3 kubevirt-cni-provider",
3
+ :disabled => !new_vm,
4
+ :label => _('CNI Provider'),
5
+ :label_size => "col-md-3",
6
+ :onchange => "cniProviderSelected(this)" %>
7
+
8
+ <%= select_f f, :network, compute_resource.networks,
9
+ :id,
10
+ :name,
11
+ {},
12
+ :disabled => !new_vm || f.object.cni_provider == 'pod',
13
+ :class => "col-md-3 kubevirt-network",
14
+ :label => _('Network'),
15
+ :label_size => "col-md-3" %>
@@ -0,0 +1,21 @@
1
+ <% if f.object.type.nil? || f.object.type == 'persistentVolumeClaim' %>
2
+ <% storage_classes = compute_resource.storage_classes %>
3
+
4
+ <%= select_f f, :storage_class,
5
+ compute_resource.storage_classes_for_select,
6
+ :id,
7
+ :description,
8
+ { },
9
+ :label => _('Storage Class'),
10
+ :label_size => "col-md-2",
11
+ :disabled => !new_vm,
12
+ :class => "col-md-2" %>
13
+
14
+ <%= text_f f,:capacity, :label => _('Size (GB)'), :label_size => "col-md-2", :disabled => !new_vm, :class => "col-md-2 pvc-size" %>
15
+
16
+ <% bootable = f.object.boot_order.nil? ? false : f.object.bootable %>
17
+ <%= field(f, :bootable, :label => _('Bootable'), :label_size => "col-md-2") do
18
+ radio_button_f f, :bootable, {:disabled => !new_vm, :checked => bootable, :onclick => 'bootableRadio(this)',
19
+ :text => _('Only one volume can be bootable')}
20
+ end %>
21
+ <% end %>
@@ -0,0 +1,29 @@
1
+ <thead>
2
+ <tr>
3
+ <th><%= _('Name') %></th>
4
+ <th><%= _('CPUs') %></th>
5
+ <th><%= _('Memory') %></th>
6
+ <th><%= _('Power') %></th>
7
+ <th><%= _('Actions') %></th>
8
+ </tr>
9
+ </thead>
10
+ <tbody>
11
+ <% @vms.each do |vm| %>
12
+ <tr>
13
+ <td><%= link_to_if_authorized vm.name, hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity).merge(:auth_object => @compute_resource, :auth_action => 'view', :authorizer => authorizer) %></td>
14
+ <td><%= vm.cpu_cores %></td>
15
+ <td><%= vm.memory %></td>
16
+ <td>
17
+ <span <%= vm_power_class(vm.ready?) %>>
18
+ <%= vm_state(vm) %></span>
19
+ </td>
20
+ <td>
21
+ <%=
22
+ action_buttons(vm_power_action(vm, authorizer),
23
+ vm_import_action(vm),
24
+ display_delete_if_authorized(hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity).merge(:auth_object => @compute_resource, :authorizer => authorizer)))
25
+ %>
26
+ </td>
27
+ </tr>
28
+ <% end %>
29
+ </tbody>
@@ -0,0 +1,55 @@
1
+ <% title @vm.name %>
2
+
3
+ <div class='col-md-12'>
4
+ <table class="<%= table_css_classes %>">
5
+ <thead>
6
+ <tr><th colspan="2"><%=_('Properties') %></th></tr>
7
+ </thead>
8
+ <tbody>
9
+ <tr>
10
+ <td><%= _('Name') %></td>
11
+ <td><%= @vm.identity %></td>
12
+ </tr>
13
+ <tr>
14
+ <td><%= _('VCPU(s)') %></td>
15
+ <td><%= @vm.cpu_cores %></td>
16
+ </tr>
17
+ <tr>
18
+ <td><%= _('UUID') %></td>
19
+ <td><%= @vm.uid %></td>
20
+ </tr>
21
+ <tr>
22
+ <td><%= _('Memory') %></td>
23
+ <td><%= number_to_human_size @vm.memory %>
24
+ </td>
25
+ </tr>
26
+ <tr>
27
+ <td><%= _('Namespace') %></td>
28
+ <td><%= @vm.namespace %></td>
29
+ </tr>
30
+ <tr>
31
+ <td><%= _('Type') %></td>
32
+ <td><%= @vm.machine_type %></td>
33
+ </tr>
34
+
35
+ <% @vm.interfaces.each do |nic| %>
36
+ <tr>
37
+ <td><%= _('NIC') %></td>
38
+ <td><%= "#{nic.name} - #{nic.mac_address} (#{nic.type})" %></td>
39
+ </tr>
40
+ <% end %>
41
+
42
+ <% @vm.volumes.each do |vol| %>
43
+ <tr>
44
+ <td><%= _('Disk') %></td>
45
+ <td><%= "#{vol.name} - #{vol.type} (#{vol.info})" %></td>
46
+ </tr>
47
+ <% end %>
48
+
49
+ <tr>
50
+ <td><%= _('Running on') %></td>
51
+ <td><%= link_to @compute_resource, compute_resource_path(@compute_resource) %></td>
52
+ </tr>
53
+ </tbody>
54
+ </table>
55
+ </div>
@@ -0,0 +1,4 @@
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
+ <%= password_f f, :password, :help_inline => _("Password to authenticate with - used for SSH finish step.") %>
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.")) %>
data/config/routes.rb ADDED
@@ -0,0 +1,2 @@
1
+ Rails.application.routes.draw do
2
+ end
@@ -0,0 +1,75 @@
1
+ module ForemanKubevirt
2
+ class Engine < ::Rails::Engine
3
+ engine_name "foreman_kubevirt"
4
+ config.autoload_paths += Dir["#{config.root}/app/models/concerns"]
5
+ initializer "foreman_kubevirt.register_plugin", :before => :finisher_hook do |_app|
6
+ Foreman::Plugin.register :foreman_kubevirt do
7
+ requires_foreman ">= 1.7"
8
+ compute_resource(ForemanKubevirt::Kubevirt)
9
+
10
+ parameter_filter(ComputeResource, :hostname, :url)
11
+ parameter_filter(ComputeResource, :namespace, :user)
12
+ parameter_filter(ComputeResource, :token, :password)
13
+ parameter_filter(ComputeResource, :ca_cert)
14
+ parameter_filter(ComputeResource, :api_port)
15
+ end
16
+ end
17
+
18
+ assets_to_precompile =
19
+ Dir.chdir(root) do
20
+ Dir['app/assets/javascripts/**/*', 'app/assets/stylesheets/**/*'].map do |f|
21
+ f.split(File::SEPARATOR, 4).last
22
+ end
23
+ end
24
+
25
+ initializer 'foreman_kubevirt.assets.precompile' do |app|
26
+ app.config.assets.precompile += assets_to_precompile
27
+ end
28
+
29
+ initializer 'foreman_kubevirt.filter_parameters' do |app|
30
+ app.config.filter_parameters += [:token]
31
+ end
32
+
33
+ initializer 'foreman_kubevirt.configure_assets', group: :assets do
34
+ SETTINGS[:foreman_kubevirt] = { assets: { precompile: assets_to_precompile } }
35
+ end
36
+
37
+ initializer "foreman_kubevirt.add_rabl_view_path" do
38
+ Rabl.configure do |config|
39
+ config.view_paths << ForemanKubevirt::Engine.root.join('app', 'views')
40
+ end
41
+ end
42
+
43
+ # Include concerns in this config.to_prepare block
44
+ config.to_prepare do
45
+ begin
46
+ require "fog/kubevirt"
47
+ require "fog/kubevirt/compute/models/server"
48
+ require File.expand_path("../../app/models/concerns/fog_extensions/kubevirt/server", __dir__)
49
+
50
+ ::Api::V2::ComputeResourcesController.send :include, ForemanKubevirt::Concerns::Api::ComputeResourcesControllerExtensions
51
+ Fog::Kubevirt::Compute::Server.send(:include, ::FogExtensions::Kubevirt::Server)
52
+
53
+ require "fog/kubevirt/compute/models/volume"
54
+ require File.expand_path("../../app/models/concerns/fog_extensions/kubevirt/volume", __dir__)
55
+ Fog::Kubevirt::Compute::Volume.send(:include, ::FogExtensions::Kubevirt::Volume)
56
+
57
+ require "fog/kubevirt/compute/models/vmnic"
58
+ require File.expand_path("../../app/models/concerns/fog_extensions/kubevirt/vmnic", __dir__)
59
+ Fog::Kubevirt::Compute::VmNic.send(:include, ::FogExtensions::Kubevirt::VmNic)
60
+
61
+ require "fog/kubevirt/compute/models/networkattachmentdef"
62
+ require File.expand_path("../../app/models/concerns/fog_extensions/kubevirt/network", __dir__)
63
+ Fog::Kubevirt::Compute::Networkattachmentdef.send(:include, ::FogExtensions::Kubevirt::Network)
64
+ rescue StandardError => e
65
+ Rails.logger.warn "Foreman-Kubevirt: skipping engine hook (#{e})"
66
+ end
67
+ end
68
+
69
+ initializer "foreman_kubevirt.register_gettext", after: :load_config_initializers do |_app|
70
+ locale_dir = File.join(File.expand_path("../..", __dir__), "locale")
71
+ locale_domain = "foreman_kubevirt"
72
+ Foreman::Gettext::Support.add_text_domain locale_domain, locale_dir
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,3 @@
1
+ module ForemanKubevirt
2
+ VERSION = '0.1.0'.freeze
3
+ end
@@ -0,0 +1,4 @@
1
+ require 'foreman_kubevirt/engine'
2
+
3
+ module ForemanKubevirt
4
+ end