foreman_xen 0.7.1 → 1.0.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 +4 -4
- data/README.md +12 -1
- data/app/assets/javascripts/foreman_xen/xenserver/cache_refresh.js +31 -18
- data/app/controllers/foreman_xen/cache_controller.rb +8 -5
- data/app/helpers/xen_compute_helper.rb +8 -103
- data/app/models/concerns/fog_extensions/xenserver/host.rb +23 -0
- data/app/models/concerns/fog_extensions/xenserver/server.rb +21 -3
- data/app/models/concerns/fog_extensions/xenserver/storage_repository.rb +45 -0
- data/app/models/concerns/fog_extensions/xenserver/vdi.rb +11 -0
- data/app/models/concerns/foreman_xen/host_extensions.rb +17 -0
- data/app/models/foreman_xen/xenserver.rb +395 -172
- data/app/views/api/v1/compute_resources/xenserver.json.rabl +1 -1
- data/app/views/api/v2/compute_resources/xenserver.json.rabl +1 -1
- data/app/views/compute_resources/form/_xenserver.html.erb +2 -4
- data/app/views/compute_resources_vms/form/_hypervisors.html.erb +15 -11
- data/app/views/compute_resources_vms/form/_image_provisioning.html.erb +49 -0
- data/app/views/compute_resources_vms/form/_isos.html.erb +15 -0
- data/app/views/compute_resources_vms/form/_network_provisioning.html.erb +26 -0
- data/app/views/compute_resources_vms/form/_profile.html.erb +5 -0
- data/app/views/compute_resources_vms/form/_templates.html.erb +13 -34
- data/app/views/compute_resources_vms/form/xenserver/_base.html.erb +22 -178
- data/app/views/compute_resources_vms/form/xenserver/_network.html.erb +23 -0
- data/app/views/compute_resources_vms/form/xenserver/_volume.html.erb +15 -0
- data/app/views/compute_resources_vms/index/_xenserver.html.erb +1 -1
- data/app/views/images/form/_xenserver.html.erb +4 -0
- data/lib/foreman_xen/engine.rb +14 -3
- data/lib/foreman_xen/version.rb +1 -1
- data/test/test_helper.rb +1 -3
- metadata +14 -7
- data/app/assets/javascripts/foreman_xen/xenserver/populate_fields.js +0 -32
- data/app/views/compute_resources_vms/form/_network.html.erb +0 -20
- data/app/views/compute_resources_vms/form/_volume.html.erb +0 -18
- data/app/views/compute_resources_vms/form/_xenstore.html.erb +0 -119
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ef04a811068d68a27dc16b361c4974e63aa95586ceba0d0d071ff167e3c17288
|
4
|
+
data.tar.gz: 9e198c6d56cc2f9f93bfa9b4eb998f1976ed7459f7559470512aa05d2fcf4eff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: be7c66d98d7078da40393baa466e46904fd6bf2dc6484d9430c6f2261f103e8d5144d308fa170c06744602a85dd36f018af818997a1f5d26f13102e47776957e
|
7
|
+
data.tar.gz: 9f004290f17fb9c2d5b2eb69c7d7bf58831ce9a45beae9bbbf20543c5b1ceba95aea40d24cd8f13fc3e0e61c0b2b74569c4fad0918460c2f4216a15cde98c6e4
|
data/README.md
CHANGED
@@ -13,6 +13,16 @@ Please see the Foreman manual for further instructions:
|
|
13
13
|
|
14
14
|
* [Foreman: How to Install a Plugin](http://theforeman.org/plugins/#2.Installation)
|
15
15
|
|
16
|
+
## Image based provisioning
|
17
|
+
|
18
|
+
In order to use the cloud-init functionality users need to:
|
19
|
+
|
20
|
+
- install the `genisoimage` package
|
21
|
+
- mount a "NFS ISO Library" (as XenServer calls it) which is attached to the Xen pool to a location writable by the foreman user.
|
22
|
+
- set this mount point / path as ISO library mountpoint in the compute resource
|
23
|
+
|
24
|
+
foreman_xen then creates a network configuration file, renders the user_data template, puts them in an ISO, copies this ISO to the attached ISO-library and attaches it to the created VM, where cloud-init can use the data provided to initialize the VM.
|
25
|
+
|
16
26
|
## Compatibility
|
17
27
|
|
18
28
|
| Foreman Version | Plugin Version |
|
@@ -24,7 +34,8 @@ Please see the Foreman manual for further instructions:
|
|
24
34
|
| >=1.13, <1.14 | 0.4.x (unmaintained) |
|
25
35
|
| >=1.14, <1.17 | 0.5.x (unmaintained) |
|
26
36
|
| >=1.17, <1.18 | 0.6.x (unmaintained) |
|
27
|
-
| >=1.18
|
37
|
+
| >=1.18, <1.20 | 0.7.x (unmaintained) |
|
38
|
+
| >=1.20 | 1.0.0 |
|
28
39
|
|
29
40
|
## Support
|
30
41
|
|
@@ -1,20 +1,33 @@
|
|
1
|
-
function refreshCache(item
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
function refreshCache(item) {
|
2
|
+
tfm.tools.showSpinner();
|
3
|
+
attribute_name = $(item).data('attribute');
|
4
|
+
sel = $(item).closest('.input-group').children('select')
|
5
|
+
data = {
|
6
|
+
type: attribute_name,
|
7
|
+
compute_resource_id: $(item).data('compute-resource-id')
|
8
|
+
};
|
9
|
+
$.ajax({
|
10
|
+
type:'post',
|
11
|
+
url: $(item).data('url'),
|
12
|
+
data: data,
|
13
|
+
complete: function(){
|
14
|
+
tfm.tools.hideSpinner();
|
15
|
+
},
|
16
|
+
error: function(){
|
17
|
+
notify(__("Error refreshing cache for " + attribute_name), 'error', true);
|
18
|
+
},
|
19
|
+
success: function(results, textStatus, jqXHR){
|
20
|
+
var elements = sel.children()
|
21
|
+
if (elements.first().val() == "") { //include_empty
|
22
|
+
elements = elements.slice(1);
|
23
|
+
}
|
24
|
+
elements.remove();
|
25
|
+
for (var i = 0; i < results.length; i++) {
|
26
|
+
var result = results[i];
|
27
|
+
var id = ('uuid' in result) ? result['uuid'] : result['id'];
|
28
|
+
var name = ('display_name' in result) ? result['display_name'] : result['name'];
|
29
|
+
sel.append('<option value=' + id + '>' + name + '</option>');
|
30
|
+
}
|
7
31
|
}
|
8
|
-
|
9
|
-
type:'post',
|
10
|
-
url: $(item).data('url'),
|
11
|
-
data: data,
|
12
|
-
complete: function(){
|
13
|
-
tfm.tools.hideSpinner();
|
14
|
-
},
|
15
|
-
error: function(){
|
16
|
-
notify(__("Error refreshing cache for " + attribute_name), 'error', true);
|
17
|
-
},
|
18
|
-
success: on_success
|
19
|
-
})
|
32
|
+
});
|
20
33
|
}
|
@@ -6,9 +6,7 @@ module ForemanXen
|
|
6
6
|
def refresh
|
7
7
|
type = params[:type]
|
8
8
|
|
9
|
-
unless cache_attribute_whitelist.include?(type)
|
10
|
-
process_error(:error_msg => "Error refreshing cache. #{type} is not a white listed attribute")
|
11
|
-
end
|
9
|
+
process_error(:error_msg => "Error refreshing cache. #{type} is not a white listed attribute") unless cache_attribute_whitelist.include?(type)
|
12
10
|
|
13
11
|
unless @compute_resource.respond_to?("#{type}!")
|
14
12
|
process_error(:error_msg => "Error refreshing cache. Method '#{type}!' not found for compute resource" +
|
@@ -16,7 +14,12 @@ module ForemanXen
|
|
16
14
|
end
|
17
15
|
|
18
16
|
respond_to do |format|
|
19
|
-
format.json
|
17
|
+
format.json do
|
18
|
+
filtered_data = @compute_resource.public_send("#{type}!").map do |e|
|
19
|
+
e.attributes.slice(:id, :uuid, :name, :display_name)
|
20
|
+
end
|
21
|
+
render json: filtered_data
|
22
|
+
end
|
20
23
|
end
|
21
24
|
end
|
22
25
|
|
@@ -24,7 +27,7 @@ module ForemanXen
|
|
24
27
|
|
25
28
|
# List of methods to permit
|
26
29
|
def cache_attribute_whitelist
|
27
|
-
%w[networks hypervisors templates
|
30
|
+
%w[isos networks available_hypervisors hypervisors templates builtin_templates storage_pools]
|
28
31
|
end
|
29
32
|
|
30
33
|
def load_compute_resource
|
@@ -1,121 +1,26 @@
|
|
1
1
|
module XenComputeHelper
|
2
|
-
def
|
3
|
-
|
4
|
-
|
5
|
-
elsif controller_name == 'compute_attributes'
|
6
|
-
attribute_map = compute_resource_controller_attribute_map(params, compute_resource)
|
7
|
-
end
|
8
|
-
attribute_map
|
9
|
-
end
|
2
|
+
def compute_attributes_from_params(compute_resource)
|
3
|
+
id = params.dig('host', 'compute_profile_id') || params.dig('compute_profile_id')
|
4
|
+
return compute_resource.compute_profile_attributes_for id if id
|
10
5
|
|
11
|
-
|
12
|
-
vmdata = {
|
13
|
-
:ifs => {
|
14
|
-
'0' => {
|
15
|
-
:ip => '',
|
16
|
-
:gateway => '',
|
17
|
-
:netmask => ''
|
18
|
-
}
|
19
|
-
},
|
20
|
-
:nameserver1 => '',
|
21
|
-
:nameserver2 => '',
|
22
|
-
:environment => ''
|
23
|
-
}
|
6
|
+
{}
|
24
7
|
end
|
25
8
|
|
26
9
|
private
|
27
10
|
|
28
|
-
def hosts_controller_compute_attribute_map(params, compute_resource, new)
|
29
|
-
attribute_map = empty_attribute_map
|
30
|
-
if new.try(:new_record?)
|
31
|
-
compute_attributes = compute_resource.compute_profile_attributes_for(params['host']['compute_profile_id'])
|
32
|
-
attribute_map = filter_compute_attributes(attribute_map, compute_attributes)
|
33
|
-
elsif new
|
34
|
-
attribute_map[:cpu_count] = new.vcpus_max || nil
|
35
|
-
attribute_map[:memory_min] = new.memory_static_min || nil
|
36
|
-
attribute_map[:memory_max] = new.memory_static_max || nil
|
37
|
-
if new.vbds
|
38
|
-
vdi = new.vbds.first.vdi
|
39
|
-
if vdi
|
40
|
-
attribute_map[:volume_selected] = vdi.sr.uuid || nil
|
41
|
-
attribute_map[:volume_size] = vdi.virtual_size ? (vdi.virtual_size.to_i / 1_073_741_824).to_s : nil
|
42
|
-
end
|
43
|
-
end
|
44
|
-
attribute_map[:network_selected] = new.vifs.first.network.name || nil if new.vifs
|
45
|
-
end
|
46
|
-
attribute_map
|
47
|
-
end
|
48
|
-
|
49
|
-
def compute_resource_controller_attribute_map(params, compute_resource)
|
50
|
-
attribute_map = empty_attribute_map
|
51
|
-
if params && params['compute_profile_id']
|
52
|
-
compute_attributes = compute_resource.compute_profile_attributes_for(params['compute_profile_id'])
|
53
|
-
elsif params && params['host'] && params['host']['compute_profile_id']
|
54
|
-
compute_attributes = compute_resource.compute_profile_attributes_for(params['host']['compute_profile_id'])
|
55
|
-
end
|
56
|
-
attribute_map = filter_compute_attributes(attribute_map, compute_attributes) if compute_attributes
|
57
|
-
attribute_map
|
58
|
-
end
|
59
|
-
|
60
|
-
def empty_attribute_map
|
61
|
-
{ :volume_size => nil,
|
62
|
-
:volume_selected => nil,
|
63
|
-
:network_selected => nil,
|
64
|
-
:template_selected_custom => nil,
|
65
|
-
:template_selected_builtin => nil,
|
66
|
-
:cpu_count => nil,
|
67
|
-
:memory_min => nil,
|
68
|
-
:memory_max => nil,
|
69
|
-
:power_on => nil }
|
70
|
-
end
|
71
|
-
|
72
|
-
def filter_compute_attributes(attribute_map, compute_attributes)
|
73
|
-
if compute_attributes['VBDs']
|
74
|
-
attribute_map[:volume_size] = compute_attributes['VBDs']['physical_size']
|
75
|
-
attribute_map[:volume_selected] = compute_attributes['VBDs']['sr_uuid']
|
76
|
-
end
|
77
|
-
attribute_map[:network_selected] = compute_attributes['VIFs']['print'] if compute_attributes['VIFs']
|
78
|
-
attribute_map[:template_selected_custom] = compute_attributes['custom_template_name']
|
79
|
-
attribute_map[:template_selected_builtin] = compute_attributes['builtin_template_name']
|
80
|
-
attribute_map[:cpu_count] = compute_attributes['vcpus_max']
|
81
|
-
attribute_map[:memory_min] = compute_attributes['memory_min']
|
82
|
-
attribute_map[:memory_max] = compute_attributes['memory_max']
|
83
|
-
attribute_map[:power_on] = compute_attributes['start']
|
84
|
-
attribute_map
|
85
|
-
end
|
86
|
-
|
87
|
-
def xen_builtin_template_map(compute_resource)
|
88
|
-
compute_resource.builtin_templates.map { |t| [t.name, t.name] }
|
89
|
-
end
|
90
|
-
|
91
|
-
def xen_custom_template_map(compute_resource)
|
92
|
-
compute_resource.custom_templates.map { |t| [t.name, t.name] }
|
93
|
-
end
|
94
|
-
|
95
|
-
def xen_storage_pool_map(compute_resource)
|
96
|
-
compute_resource.storage_pools.map { |item| [item[:display_name], item[:uuid]] }
|
97
|
-
end
|
98
|
-
|
99
|
-
def xen_hypervisor_map(compute_resource)
|
100
|
-
compute_resource.available_hypervisors!.map do |t|
|
101
|
-
[t.name + ' - ' + (
|
102
|
-
t.metrics.memory_free.to_f / t.metrics.memory_total.to_f * 100
|
103
|
-
).round(2).to_s + '% free mem', t.name]
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
11
|
def selectable_f_with_cache_invalidation(f, attr, array,
|
108
12
|
select_options = {}, html_options = {}, input_group_options = {})
|
109
13
|
unless html_options.key?('input_group_btn')
|
110
14
|
html_options[:input_group_btn] = link_to_function(
|
111
15
|
icon_text('refresh'),
|
112
|
-
|
16
|
+
'refreshCache(this)',
|
113
17
|
:class => 'btn btn-primary',
|
114
18
|
:title => _(input_group_options[:title]),
|
115
19
|
:data => {
|
116
20
|
:url => input_group_options[:url],
|
117
|
-
:compute_resource_id => input_group_options[:
|
118
|
-
:attribute => input_group_options[:attribute]
|
21
|
+
:compute_resource_id => input_group_options[:compute_resource_id],
|
22
|
+
:attribute => input_group_options[:attribute],
|
23
|
+
:select_attr => attr
|
119
24
|
}
|
120
25
|
)
|
121
26
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module FogExtensions
|
2
|
+
module Xenserver
|
3
|
+
module Host
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
attribute :display_name
|
8
|
+
prepend FogExtensions::Xenserver::Host
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(new_attributes = {})
|
12
|
+
super(new_attributes)
|
13
|
+
attributes[:display_name] = "#{name} - #{mem_free_gb} GB free memory"
|
14
|
+
end
|
15
|
+
|
16
|
+
def mem_free_gb
|
17
|
+
return metrics.memory_free.to_i / 1024 / 1024 / 1024 if metrics
|
18
|
+
|
19
|
+
0
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -5,8 +5,13 @@ module FogExtensions
|
|
5
5
|
|
6
6
|
include ActionView::Helpers::NumberHelper
|
7
7
|
|
8
|
-
attr_accessor :start
|
9
|
-
attr_accessor :memory_min, :memory_max, :
|
8
|
+
attr_accessor :start, :image_id, :hypervisor_host, :iso, :target_sr
|
9
|
+
attr_accessor :memory_min, :memory_max, :builtin_template
|
10
|
+
attr_writer :volumes, :interfaces
|
11
|
+
|
12
|
+
def id
|
13
|
+
uuid
|
14
|
+
end
|
10
15
|
|
11
16
|
def to_s
|
12
17
|
name
|
@@ -16,6 +21,13 @@ module FogExtensions
|
|
16
21
|
|
17
22
|
def volumes_attributes=(attrs); end
|
18
23
|
|
24
|
+
def volumes
|
25
|
+
@volumes ||= []
|
26
|
+
disks = vbds.compact.select(&:disk?)
|
27
|
+
disks.sort! { |x, y| x.userdevice <=> y.userdevice }
|
28
|
+
(disks.map(&:vdi) + @volumes).uniq
|
29
|
+
end
|
30
|
+
|
19
31
|
def memory
|
20
32
|
memory_static_max.to_i
|
21
33
|
end
|
@@ -45,12 +57,18 @@ module FogExtensions
|
|
45
57
|
end
|
46
58
|
|
47
59
|
def interfaces
|
48
|
-
vifs
|
60
|
+
(vifs + @interfaces).uniq
|
49
61
|
end
|
50
62
|
|
51
63
|
def select_nic(fog_nics, nic)
|
52
64
|
fog_nics[0]
|
53
65
|
end
|
66
|
+
|
67
|
+
def user_data
|
68
|
+
return !other_config['default_template'] if is_a_template
|
69
|
+
|
70
|
+
false
|
71
|
+
end
|
54
72
|
end
|
55
73
|
end
|
56
74
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module FogExtensions
|
2
|
+
module Xenserver
|
3
|
+
module StorageRepository
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
attribute :display_name
|
8
|
+
prepend FogExtensions::Xenserver::StorageRepository
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(new_attributes = {})
|
12
|
+
super(new_attributes)
|
13
|
+
attributes[:display_name] = init_display_name
|
14
|
+
end
|
15
|
+
|
16
|
+
def free_space
|
17
|
+
physical_size.to_i - physical_utilisation.to_i
|
18
|
+
end
|
19
|
+
|
20
|
+
def free_space_gb
|
21
|
+
free_space.to_i / 1024 / 1024 / 1024
|
22
|
+
end
|
23
|
+
|
24
|
+
def physical_size_gb
|
25
|
+
physical_size.to_i / 1024 / 1024 / 1024
|
26
|
+
end
|
27
|
+
|
28
|
+
def physical_utilisation_gb
|
29
|
+
physical_utilisation.to_i / 1024 / 1024 / 1024
|
30
|
+
end
|
31
|
+
|
32
|
+
def init_display_name
|
33
|
+
srname = name
|
34
|
+
unless shared
|
35
|
+
pbd = pbds.first
|
36
|
+
srname = "#{name} - #{pbd.host.name}" unless pbd.nil?
|
37
|
+
end
|
38
|
+
format('%{n} (%{f}: %{f_gb} GB - %{u}: %{u_gb} GB - %{t}: %{t_gb} GB)',
|
39
|
+
n: srname, f: _('free'), f_gb: free_space_gb,
|
40
|
+
u: _('used'), u_gb: physical_utilisation_gb,
|
41
|
+
t: _('total'), t_gb: physical_size_gb)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ForemanXen
|
2
|
+
module HostExtensions
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
def built(installed = true)
|
6
|
+
compute_resource.cleanup_configdrive(uuid) if compute_resource && compute_resource.type == 'ForemanXen::Xenserver'
|
7
|
+
super(installed)
|
8
|
+
end
|
9
|
+
|
10
|
+
def disassociate!
|
11
|
+
# Disassociated host object cannot be saved unless provision_method
|
12
|
+
# is supported by the default compute resource
|
13
|
+
self.provision_method = 'build'
|
14
|
+
super
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -2,19 +2,63 @@ module ForemanXen
|
|
2
2
|
class Xenserver < ComputeResource
|
3
3
|
validates :url, :user, :password, :presence => true
|
4
4
|
|
5
|
+
GB_BYTES = 1_073_741_824 # 1gb in bytes
|
6
|
+
|
5
7
|
def provided_attributes
|
6
8
|
super.merge(
|
7
|
-
:uuid => :
|
9
|
+
:uuid => :uuid,
|
8
10
|
:mac => :mac
|
9
11
|
)
|
10
12
|
end
|
11
13
|
|
12
14
|
def capabilities
|
13
|
-
[
|
15
|
+
%i[build image new_volume]
|
16
|
+
end
|
17
|
+
|
18
|
+
def host_compute_attrs(host)
|
19
|
+
super(host).merge(
|
20
|
+
name_description: host.comment,
|
21
|
+
is_a_template: false,
|
22
|
+
is_a_shapshot: false,
|
23
|
+
xenstore: host_xenstore_data(host),
|
24
|
+
network_data: host_network_data(host)
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
def user_data_supported
|
29
|
+
true
|
30
|
+
end
|
31
|
+
|
32
|
+
def iso_library_mountpoint
|
33
|
+
attrs[:iso_library_mountpoint]
|
34
|
+
end
|
35
|
+
|
36
|
+
def iso_library_mountpoint=(path)
|
37
|
+
mountpoint = path.to_s.end_with?('/') ? path.to_s : "#{path}/"
|
38
|
+
mountpoint = nil if path.to_s.strip.empty?
|
39
|
+
attrs[:iso_library_mountpoint] = mountpoint
|
40
|
+
end
|
41
|
+
|
42
|
+
def cleanup_configdrive(uuid)
|
43
|
+
iso_file_name = "foreman-configdrive-#{uuid}.iso"
|
44
|
+
begin
|
45
|
+
path = File.join(iso_library_mountpoint, iso_file_name)
|
46
|
+
exist = File.exist? path
|
47
|
+
FileUtils.rm(path) if exist
|
48
|
+
rescue
|
49
|
+
return true unless exist
|
50
|
+
|
51
|
+
return false
|
52
|
+
end
|
14
53
|
end
|
15
54
|
|
55
|
+
# rubocop:disable Rails/DynamicFindBy
|
56
|
+
# Fog::XenServer::Compute (client) isn't an ActiveRecord model which
|
57
|
+
# supports find_by()
|
16
58
|
def find_vm_by_uuid(uuid)
|
17
|
-
client.servers.
|
59
|
+
return client.servers.find { |s| s.reference == uuid } if uuid.start_with? 'OpaqueRef:'
|
60
|
+
|
61
|
+
client.servers.find_by_uuid(uuid)
|
18
62
|
rescue Fog::XenServer::RequestFailed => e
|
19
63
|
Foreman::Logging.exception("Failed retrieving xenserver vm by uuid #{uuid}", e)
|
20
64
|
raise(ActiveRecord::RecordNotFound) if e.message.include?('HANDLE_INVALID')
|
@@ -22,10 +66,12 @@ module ForemanXen
|
|
22
66
|
|
23
67
|
raise e
|
24
68
|
end
|
69
|
+
# rubocop:enable Rails/DynamicFindBy
|
25
70
|
|
26
71
|
# we default to destroy the VM's storage as well.
|
27
72
|
def destroy_vm(ref, args = {})
|
28
73
|
logger.info "destroy_vm: #{ref} #{args}"
|
74
|
+
cleanup_configdrive(ref) if iso_library_mountpoint
|
29
75
|
find_vm_by_uuid(ref).destroy
|
30
76
|
rescue ActiveRecord::RecordNotFound
|
31
77
|
true
|
@@ -60,23 +106,39 @@ module ForemanXen
|
|
60
106
|
errors[:base] << e.message
|
61
107
|
end
|
62
108
|
|
109
|
+
def available_images
|
110
|
+
custom_templates!
|
111
|
+
end
|
112
|
+
|
63
113
|
def available_hypervisors
|
64
|
-
|
114
|
+
hypervisors.select(&:enabled)
|
65
115
|
end
|
66
116
|
|
67
117
|
def available_hypervisors!
|
68
|
-
|
118
|
+
hypervisors!.select(&:enabled)
|
119
|
+
end
|
120
|
+
|
121
|
+
def hypervisors
|
122
|
+
read_from_cache('hypervisors', 'hypervisors!')
|
123
|
+
end
|
124
|
+
|
125
|
+
def hypervisors!
|
126
|
+
store_in_cache('hypervisors') do
|
69
127
|
hosts = client.hosts
|
70
128
|
hosts.sort_by(&:name)
|
71
129
|
end
|
72
130
|
end
|
73
131
|
|
74
132
|
def new_nic(attr = {})
|
75
|
-
client.
|
133
|
+
client.vifs.new attr
|
76
134
|
end
|
77
135
|
|
78
136
|
def new_volume(attr = {})
|
79
|
-
|
137
|
+
size = attr[:virtual_size_gb].to_i * GB_BYTES
|
138
|
+
vdi = client.vdis.new virtual_size: size.to_s
|
139
|
+
vdi.type = 'user'
|
140
|
+
vdi.sr = storage_pools.find { |s| s.uuid == attr[:sr].to_s } if attr[:sr]
|
141
|
+
vdi
|
80
142
|
end
|
81
143
|
|
82
144
|
def storage_pools
|
@@ -85,34 +147,42 @@ module ForemanXen
|
|
85
147
|
|
86
148
|
def storage_pools!
|
87
149
|
store_in_cache('storage_pools') do
|
88
|
-
|
89
|
-
|
90
|
-
storages.each do |sr|
|
91
|
-
subresults = {}
|
92
|
-
found = false
|
93
|
-
|
94
|
-
available_hypervisors.each do |host|
|
95
|
-
next unless sr.reference == host.suspend_image_sr
|
96
|
-
|
97
|
-
found = true
|
98
|
-
subresults[:name] = sr.name
|
99
|
-
subresults[:display_name] = sr.name + '(' + host.hostname + ')'
|
100
|
-
subresults[:uuid] = sr.uuid
|
101
|
-
break
|
102
|
-
end
|
103
|
-
unless found
|
104
|
-
subresults[:name] = sr.name
|
105
|
-
subresults[:display_name] = sr.name
|
106
|
-
subresults[:uuid] = sr.uuid
|
107
|
-
end
|
108
|
-
results.push(subresults)
|
150
|
+
pools = client.storage_repositories.select do |sr|
|
151
|
+
sr.type != 'udev' && sr.type != 'iso'
|
109
152
|
end
|
110
|
-
|
153
|
+
pools.sort_by(&:display_name)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def isos
|
158
|
+
all_isos.reject do |iso|
|
159
|
+
iso.name =~ /foreman-configdrive/
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def isos!
|
164
|
+
all_isos!.reject do |iso|
|
165
|
+
iso.name =~ /foreman-configdrive/
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def all_isos
|
170
|
+
read_from_cache('isos', 'isos!')
|
171
|
+
end
|
172
|
+
|
173
|
+
def all_isos!
|
174
|
+
store_in_cache('isos') do
|
175
|
+
isos = iso_libraries.map(&:vdis).flatten
|
176
|
+
isos.sort_by(&:name)
|
111
177
|
end
|
112
178
|
end
|
113
179
|
|
180
|
+
def new_interface(attr = {})
|
181
|
+
client.vifs.new attr
|
182
|
+
end
|
183
|
+
|
114
184
|
def interfaces
|
115
|
-
client.
|
185
|
+
client.vifs
|
116
186
|
rescue
|
117
187
|
[]
|
118
188
|
end
|
@@ -186,158 +256,137 @@ module ForemanXen
|
|
186
256
|
end
|
187
257
|
|
188
258
|
def new_vm(attr = {})
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
259
|
+
attr = attr.to_hash.deep_symbolize_keys
|
260
|
+
%i[networks interfaces].each do |collection|
|
261
|
+
nested_attr = attr.delete("#{collection}_attributes".to_sym)
|
262
|
+
attr[collection] = nested_attributes_for(collection, nested_attr) if nested_attr
|
263
|
+
end
|
264
|
+
if attr[:volumes_attributes]
|
265
|
+
vol_attr = nested_attributes_for('volumes', attr[:volumes_attributes])
|
266
|
+
attr[:volumes] = vol_attr.map { |v| new_volume(v) }
|
197
267
|
end
|
198
|
-
|
199
|
-
|
268
|
+
attr.reject! { |_, v| v.nil? }
|
269
|
+
super(attr)
|
270
|
+
end
|
271
|
+
|
272
|
+
def vm_attr_from_args(args)
|
273
|
+
{
|
274
|
+
name: args[:name],
|
275
|
+
name_description: args[:comment],
|
276
|
+
VCPUs_max: args[:vcpus_max],
|
277
|
+
VCPUs_at_startup: args[:vcpus_max],
|
278
|
+
memory_static_max: args[:memory_max],
|
279
|
+
memory_dynamic_max: args[:memory_max],
|
280
|
+
memory_dynamic_min: args[:memory_min],
|
281
|
+
memory_static_min: args[:memory_min]
|
282
|
+
}
|
200
283
|
end
|
201
284
|
|
202
285
|
def create_vm(args = {})
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
if builtin_template_name != '' && custom_template_name != ''
|
207
|
-
logger.info "custom_template_name: #{custom_template_name}"
|
208
|
-
logger.info "builtin_template_name: #{builtin_template_name}"
|
209
|
-
raise 'you can select at most one template type'
|
210
|
-
end
|
286
|
+
args = args.deep_symbolize_keys
|
287
|
+
logger.debug('create_vm args:')
|
288
|
+
logger.debug(args)
|
211
289
|
begin
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
logger.info e
|
222
|
-
logger.info e.backtrace.join("\n")
|
223
|
-
return false
|
224
|
-
end
|
225
|
-
end
|
290
|
+
# Create VM Object
|
291
|
+
attr = vm_attr_from_args(args)
|
292
|
+
if args[:provision_method] == 'image'
|
293
|
+
image = available_images.find { |i| i.uuid == args[:image_id].to_s }
|
294
|
+
sr = storage_pools.find { |s| s.uuid == args[:target_sr].to_s }
|
295
|
+
vm = create_vm_from_image(image, attr, sr)
|
296
|
+
else
|
297
|
+
template = builtin_templates.find { |t| t.uuid == args[:builtin_template].to_s }
|
298
|
+
raise 'Template not found' unless template
|
226
299
|
|
227
|
-
|
228
|
-
|
229
|
-
mem_min = args[:memory_min]
|
300
|
+
vm = create_vm_from_template(attr, template)
|
301
|
+
end
|
230
302
|
|
231
|
-
|
303
|
+
raise 'Error creating VM' unless vm
|
232
304
|
|
233
|
-
|
305
|
+
# Set correct affinity
|
306
|
+
set_vm_affinity(vm, args[:hypervisor_host].to_s)
|
234
307
|
|
235
|
-
|
308
|
+
# Add NICs
|
309
|
+
vm.interfaces = args[:interfaces_attributes].map do |_, v|
|
310
|
+
create_interface(vm, v[:network])
|
311
|
+
end
|
236
312
|
|
237
|
-
|
238
|
-
|
239
|
-
vm.affinity = host
|
313
|
+
# Attach ConfigDrive
|
314
|
+
create_and_attach_configdrive(vm, args) if args[:configdrive] == '1' && args[:provision_method] == 'image'
|
240
315
|
|
241
|
-
|
316
|
+
# Attach ISO
|
317
|
+
unless args[:iso].empty?
|
318
|
+
iso_vdi = isos.find { |i| i.uuid == args[:iso] }
|
319
|
+
attach_iso(vm, iso_vdi)
|
320
|
+
end
|
242
321
|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
322
|
+
# Add new Volumes
|
323
|
+
unless args[:volumes_attributes].nil?
|
324
|
+
vm.volumes = args[:volumes_attributes].map do |_, v|
|
325
|
+
create_volume(vm, v) unless v[:_delete] == '1'
|
326
|
+
end
|
327
|
+
end
|
248
328
|
|
249
|
-
|
329
|
+
# Write XenStore data
|
330
|
+
xenstore_data = xenstore_set_mac(vm, args[:xenstore])
|
331
|
+
set_xenstore_data(vm, xenstore_data)
|
250
332
|
|
251
|
-
|
252
|
-
|
333
|
+
# Fix Description
|
334
|
+
vm.set_attribute('name-description', args[:name_description])
|
253
335
|
|
254
|
-
|
255
|
-
|
256
|
-
vm.
|
257
|
-
vm
|
258
|
-
vm.
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
vm.set_attribute('memory_dynamic_min', mem_min)
|
263
|
-
vm.set_attribute('memory_dynamic_max', mem_max)
|
264
|
-
vm.set_attribute('memory_static_max', mem_max)
|
336
|
+
return vm
|
337
|
+
rescue => e
|
338
|
+
cleanup_configdrive(vm.uuid) if vm&.uuid
|
339
|
+
vm&.destroy
|
340
|
+
vm.volumes.each(&:destroy) if vm&.volumes
|
341
|
+
logger.info e
|
342
|
+
logger.info e.backtrace.join("\n")
|
343
|
+
raise e
|
265
344
|
end
|
345
|
+
end
|
266
346
|
|
267
|
-
|
268
|
-
|
269
|
-
i
|
270
|
-
|
271
|
-
vbd.vdi.set_attribute('name-label', "#{args[:name]}_#{i}")
|
272
|
-
i += 1
|
347
|
+
def create_vm_from_template(attr, template)
|
348
|
+
vm_attr = template.attributes.dup.merge(attr)
|
349
|
+
%i[uuid domid reference allowed_operations].each do |a|
|
350
|
+
vm_attr.delete(a)
|
273
351
|
end
|
352
|
+
vm_attr[:is_a_template] = false
|
353
|
+
vm_attr[:other_config].delete('default_template')
|
354
|
+
vm_attr[:other_config]['mac_seed'] = SecureRandom.uuid
|
355
|
+
vm = new_vm(vm_attr)
|
356
|
+
# Set any host affinity (required for saving) - correct later
|
357
|
+
vm.affinity = client.hosts.first
|
358
|
+
vm.save
|
274
359
|
vm
|
275
360
|
end
|
276
361
|
|
277
|
-
def
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
builtin_template_name = args[:builtin_template_name]
|
286
|
-
builtin_template_name = builtin_template_name.to_s
|
287
|
-
|
288
|
-
storage_repository = client.storage_repositories.find { |sr| sr.uuid == (args[:VBDs][:sr_uuid]).to_s }
|
289
|
-
|
290
|
-
gb = 1_073_741_824 # 1gb in bytes
|
291
|
-
size = args[:VBDs][:physical_size].to_i * gb
|
292
|
-
vdi = client.vdis.create :name => "#{args[:name]}-disk1",
|
293
|
-
:storage_repository => storage_repository,
|
294
|
-
:description => "#{args[:name]}-disk_1",
|
295
|
-
:virtual_size => size.to_s
|
362
|
+
def create_vm_from_image(image, attr, sr)
|
363
|
+
vm_ref = client.copy_server image.reference, attr[:name], sr.reference
|
364
|
+
client.provision_server vm_ref
|
365
|
+
vm = client.servers.find { |s| s.reference == vm_ref }
|
366
|
+
set_vm_profile_attributes(vm, attr)
|
367
|
+
rename_cloned_volumes(vm)
|
368
|
+
vm
|
369
|
+
end
|
296
370
|
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
371
|
+
def set_vm_profile_attributes(vm, attr)
|
372
|
+
# Memory limits must satisfy:
|
373
|
+
# static_min <= dynamic_min <= dynamic_max <= static_max
|
374
|
+
mem = %w[memory_static_max memory_dynamic_max
|
375
|
+
memory_dynamic_min memory_static_min]
|
376
|
+
mem.reverse! if vm.memory_static_max.to_i > attr[:memory_static_max].to_i
|
377
|
+
# VCPU values must satisfy: 0 < VCPUs_at_startup <= VCPUs_max
|
378
|
+
cpu = %w[VCPUs_max VCPUs_at_startup]
|
379
|
+
cpu.reverse! if vm.vcpus_at_startup > attr[:VCPUs_at_startup]
|
380
|
+
(mem + cpu).each { |e| vm.set_attribute e, attr[e.to_sym] }
|
381
|
+
end
|
382
|
+
|
383
|
+
def rename_cloned_volumes(vm)
|
384
|
+
vm.volumes.each do |vol|
|
385
|
+
udev = vol.vbds.find { |v| v.vm.uuid == vm.uuid }.userdevice
|
386
|
+
name = "#{vm.name}-#{udev}"
|
387
|
+
vol.set_attribute 'name-label', name
|
388
|
+
vol.set_attribute 'name-description', name
|
304
389
|
end
|
305
|
-
vm = client.servers.new :name => args[:name],
|
306
|
-
:affinity => host,
|
307
|
-
:pv_bootloader => '',
|
308
|
-
:hvm_boot_params => { :order => 'dnc' },
|
309
|
-
:other_config => other_config,
|
310
|
-
:memory_static_max => mem_max,
|
311
|
-
:memory_static_min => mem_min,
|
312
|
-
:memory_dynamic_max => mem_max,
|
313
|
-
:memory_dynamic_min => mem_min
|
314
|
-
|
315
|
-
vm.save :auto_start => false
|
316
|
-
client.vbds.create :vm => vm, :vdi => vdi
|
317
|
-
|
318
|
-
create_network(vm, args)
|
319
|
-
|
320
|
-
if args[:xstools] == '1'
|
321
|
-
# Add xs-tools ISO to newly created VMs
|
322
|
-
dvd_vdi = client.vdis.find { |isovdi| isovdi.name == 'xs-tools.iso' || isovdi.name == 'guest-tools.iso' }
|
323
|
-
vbdconnectcd = {
|
324
|
-
'vdi' => dvd_vdi,
|
325
|
-
'vm' => vm.reference,
|
326
|
-
'userdevice' => '1',
|
327
|
-
'mode' => 'RO',
|
328
|
-
'type' => 'cd',
|
329
|
-
'other_config' => {},
|
330
|
-
'qos_algorithm_type' => '',
|
331
|
-
'qos_algorithm_params' => {}
|
332
|
-
}
|
333
|
-
vm.vbds = client.vbds.create vbdconnectcd
|
334
|
-
vm.reload
|
335
|
-
end
|
336
|
-
|
337
|
-
vm.provision
|
338
|
-
vm.set_attribute('HVM_boot_policy', 'BIOS order')
|
339
|
-
vm.reload
|
340
|
-
vm
|
341
390
|
end
|
342
391
|
|
343
392
|
def console(uuid)
|
@@ -373,9 +422,10 @@ module ForemanXen
|
|
373
422
|
|
374
423
|
def client
|
375
424
|
@client ||= Fog::XenServer::Compute.new(
|
376
|
-
:
|
377
|
-
:
|
378
|
-
:
|
425
|
+
xenserver_url: url,
|
426
|
+
xenserver_username: user,
|
427
|
+
xenserver_password: password,
|
428
|
+
xenserver_timeout: 1800
|
379
429
|
)
|
380
430
|
end
|
381
431
|
|
@@ -384,30 +434,94 @@ module ForemanXen
|
|
384
434
|
@client = nil
|
385
435
|
end
|
386
436
|
|
387
|
-
def vm_instance_defaults
|
388
|
-
super.merge({})
|
389
|
-
end
|
390
|
-
|
391
437
|
private
|
392
438
|
|
393
|
-
def
|
394
|
-
|
439
|
+
def create_volume(vm, attr)
|
440
|
+
vdi = new_volume attr
|
441
|
+
udev = find_free_userdevice(vm)
|
442
|
+
vdi.name = "#{vm.name}-#{udev}"
|
443
|
+
vdi.description = "#{vm.name}-#{udev}"
|
444
|
+
vdi.save
|
445
|
+
# Attach VDI to VM
|
446
|
+
client.vbds.create vm: vm, vdi: vdi, userdevice: udev.to_s, bootable: true
|
447
|
+
vdi
|
448
|
+
end
|
449
|
+
|
450
|
+
def create_interface(vm, network_uuid)
|
451
|
+
net = client.networks.find { |n| n.uuid == network_uuid }
|
452
|
+
devices = vm.vifs.map(&:device)
|
453
|
+
device = 0
|
454
|
+
device += 1 while devices.include?(device.to_s)
|
395
455
|
net_config = {
|
396
456
|
'mac_autogenerated' => 'True',
|
397
457
|
'vm' => vm.reference,
|
398
458
|
'network' => net.reference,
|
399
459
|
'mac' => '',
|
400
|
-
'device' =>
|
460
|
+
'device' => device.to_s,
|
401
461
|
'mtu' => '0',
|
402
462
|
'other_config' => {},
|
403
463
|
'qos_algorithm_type' => 'ratelimit',
|
404
464
|
'qos_algorithm_params' => {}
|
405
465
|
}
|
406
|
-
|
407
|
-
|
466
|
+
client.vifs.create net_config
|
467
|
+
end
|
468
|
+
|
469
|
+
def attach_iso(vm, iso_vdi)
|
470
|
+
cd_drive = client.vbds.find { |v| v.vm == vm && v.type == 'CD' }
|
471
|
+
if cd_drive&.empty
|
472
|
+
client.insert_vbd cd_drive.reference, iso_vdi.reference
|
473
|
+
else
|
474
|
+
# Windows VMs expect the CDROM drive on userdevice 3
|
475
|
+
vbds = client.vbds.select { |v| v.vm == vm }
|
476
|
+
udev = vbds.map(&:userdevice).include?('3') ? find_free_userdevice(vm) : '3'
|
477
|
+
vbd = {
|
478
|
+
'vdi' => iso_vdi,
|
479
|
+
'vm' => vm,
|
480
|
+
'userdevice' => udev.to_s,
|
481
|
+
'mode' => 'RO',
|
482
|
+
'type' => 'CD',
|
483
|
+
'other_config' => {},
|
484
|
+
'qos_algorithm_type' => '',
|
485
|
+
'qos_algorithm_params' => {}
|
486
|
+
}
|
487
|
+
client.vbds.create vbd
|
488
|
+
end
|
489
|
+
true
|
490
|
+
end
|
491
|
+
|
492
|
+
def find_free_userdevice(vm)
|
493
|
+
# Find next free userdevice id for vbd
|
494
|
+
# vm.vbds is not current, vm.reload not working.
|
495
|
+
vbds = client.vbds.select { |v| v.vm == vm }
|
496
|
+
userdevices = vbds.map(&:userdevice)
|
497
|
+
udev = 0
|
498
|
+
udev += 1 while userdevices.include?(udev.to_s)
|
499
|
+
udev
|
500
|
+
end
|
501
|
+
|
502
|
+
def xenstore_set_mac(vm, xenstore_data)
|
503
|
+
xenstore_data[:'vm-data'][:ifs][:'0'][:mac] = vm.interfaces.first.mac
|
504
|
+
xenstore_data
|
505
|
+
end
|
506
|
+
|
507
|
+
def set_xenstore_data(vm, xenstore_data)
|
508
|
+
xenstore_data = xenstore_hash_flatten(xenstore_data)
|
509
|
+
vm.set_attribute('xenstore_data', xenstore_data)
|
408
510
|
end
|
409
511
|
|
410
|
-
def
|
512
|
+
def host_xenstore_data(host)
|
513
|
+
p_if = host.primary_interface
|
514
|
+
subnet = p_if.subnet || p_if.subnet6
|
515
|
+
{ 'vm-data' => { 'ifs' => { '0' =>
|
516
|
+
{ 'ip' => p_if.ip.empty? ? p_if.ip6 : p_if.ip,
|
517
|
+
'gateway' => subnet.nil? ? '' : subnet.gateway,
|
518
|
+
'netmask' => subnet.nil? ? '' : subnet.mask } } },
|
519
|
+
'nameserver1' => subnet.nil? ? '' : subnet.dns_primary,
|
520
|
+
'nameserver2' => subnet.nil? ? '' : subnet.dns_secondary,
|
521
|
+
'environment' => host.environment.to_s }
|
522
|
+
end
|
523
|
+
|
524
|
+
def xenstore_hash_flatten(nested_hash, _key = nil, keychain = nil, out_hash = {})
|
411
525
|
nested_hash.each do |k, v|
|
412
526
|
if v.is_a? Hash
|
413
527
|
xenstore_hash_flatten(v, k, "#{keychain}#{k}/", out_hash)
|
@@ -418,6 +532,115 @@ module ForemanXen
|
|
418
532
|
out_hash
|
419
533
|
end
|
420
534
|
|
535
|
+
# rubocop:disable Rails/DynamicFindBy
|
536
|
+
# Fog::XenServer::Compute (client) isn't an ActiveRecord model which
|
537
|
+
# supports find_by()
|
538
|
+
def set_vm_affinity(vm, hypervisor)
|
539
|
+
if hypervisor.empty?
|
540
|
+
vm.set_attribute('affinity', '')
|
541
|
+
else
|
542
|
+
vm.set_attribute('affinity', client.hosts.find_by_uuid(hypervisor))
|
543
|
+
end
|
544
|
+
end
|
545
|
+
# rubocop:enable Rails/DynamicFindBy
|
546
|
+
|
547
|
+
def create_and_attach_configdrive(vm, attr)
|
548
|
+
network_data = add_mac_to_network_data(attr[:network_data], vm)
|
549
|
+
iso_name = generate_configdrive(vm.uuid,
|
550
|
+
vm_meta_data(vm).to_json,
|
551
|
+
network_data.deep_stringify_keys.to_json,
|
552
|
+
attr[:user_data],
|
553
|
+
iso_library_mountpoint)
|
554
|
+
rescan_iso_libraries
|
555
|
+
iso_vdi = all_isos!.find { |iso| iso.name == iso_name }
|
556
|
+
raise 'Unable to locate metadata iso on iso libraries' unless iso_vdi
|
557
|
+
|
558
|
+
attach_iso(vm, iso_vdi)
|
559
|
+
end
|
560
|
+
|
561
|
+
def vm_meta_data(vm)
|
562
|
+
{ 'uuid' => vm.uuid, 'hostname' => vm.name }
|
563
|
+
end
|
564
|
+
|
565
|
+
# openstack configdive network_data format spec:
|
566
|
+
# https://github.com/openstack/nova-specs/blob/master/specs/liberty/implemented/metadata-service-network-info.rst
|
567
|
+
def host_network_data(host)
|
568
|
+
p_if = host.primary_interface
|
569
|
+
network_data = { links: [], networks: [], services: [] }
|
570
|
+
network = { id: 'network0', routes: [] }
|
571
|
+
if p_if.subnet
|
572
|
+
sn = p_if.subnet
|
573
|
+
network[:ip_address] = p_if.ip unless p_if.ip.empty?
|
574
|
+
network[:type] = sn.boot_mode == 'DHCP' ? 'ipv4_dhcp' : 'ipv4'
|
575
|
+
end
|
576
|
+
if p_if.subnet6
|
577
|
+
sn = p_if.subnet6
|
578
|
+
network[:ip_address] = p_if.ip6 unless p_if.ip6.empty?
|
579
|
+
network[:type] = sn.boot_mode == 'DHCP' ? 'ipv6_dhcp' : 'ipv6'
|
580
|
+
end
|
581
|
+
link = { type: 'phy' }
|
582
|
+
link[:id] = p_if.name.empty? ? 'eth0' : p_if.identifier
|
583
|
+
link[:name] = link[:id]
|
584
|
+
link[:mtu] = sn.mtu
|
585
|
+
link[:ethernet_mac_address] = p_if.mac unless p_if.mac.empty?
|
586
|
+
network_data[:links] << link
|
587
|
+
network[:netmask] = sn.mask unless sn.mask.empty?
|
588
|
+
network[:link] = link[:id]
|
589
|
+
route = { network: '0.0.0.0', netmask: '0.0.0.0' }
|
590
|
+
route[:gateway] = sn.gateway unless sn.gateway.empty?
|
591
|
+
network[:routes] << route
|
592
|
+
network_data[:networks] << network
|
593
|
+
unless sn.dns_primary.empty?
|
594
|
+
dns1 = { type: 'dns', address: sn.dns_primary }
|
595
|
+
network_data[:services] << dns1
|
596
|
+
end
|
597
|
+
unless sn.dns_secondary.empty?
|
598
|
+
dns2 = { type: 'dns', address: sn.dns_secondary }
|
599
|
+
network_data[:services] << dns2
|
600
|
+
end
|
601
|
+
network_data
|
602
|
+
end
|
603
|
+
|
604
|
+
def add_mac_to_network_data(network_data, vm)
|
605
|
+
network_data[:links][0][:ethernet_mac_address] = vm.interfaces.first.mac unless network_data[:links][0][:ethernet_mac_address]
|
606
|
+
network_data
|
607
|
+
end
|
608
|
+
|
609
|
+
def generate_configdrive(vm_uuid, meta_data, network_data, user_data, dst_dir)
|
610
|
+
Dir.mktmpdir('foreman-configdrive') do |wd|
|
611
|
+
iso_file_name = "foreman-configdrive-#{vm_uuid}.iso"
|
612
|
+
iso_file_path = File.join(wd, iso_file_name)
|
613
|
+
config_dir = FileUtils.mkdir_p(File.join(wd, 'openstack/latest')).first
|
614
|
+
meta_data_path = File.join(config_dir, 'meta_data.json')
|
615
|
+
user_data_path = File.join(config_dir, 'user_data')
|
616
|
+
network_data_path = File.join(config_dir, 'network_data.json')
|
617
|
+
File.write(meta_data_path, meta_data)
|
618
|
+
File.write(user_data_path, user_data)
|
619
|
+
File.write(network_data_path, network_data)
|
620
|
+
|
621
|
+
cmd = ['/usr/bin/genisoimage', '-output', iso_file_path,
|
622
|
+
'-volid', 'config-2', '-joliet', '-rock', wd]
|
623
|
+
|
624
|
+
raise ::Foreman::Exception, N_('ISO build failed, is the genisoimage package installed?') unless system(*cmd)
|
625
|
+
|
626
|
+
FileUtils.cp(iso_file_path, dst_dir)
|
627
|
+
|
628
|
+
return iso_file_name
|
629
|
+
end
|
630
|
+
end
|
631
|
+
|
632
|
+
def rescan_iso_libraries
|
633
|
+
iso_libraries.each do |sr|
|
634
|
+
client.scan_sr sr.reference
|
635
|
+
end
|
636
|
+
end
|
637
|
+
|
638
|
+
def iso_libraries
|
639
|
+
client.storage_repositories.select do |sr|
|
640
|
+
sr.type == 'iso'
|
641
|
+
end
|
642
|
+
end
|
643
|
+
|
421
644
|
def get_templates(templates)
|
422
645
|
tmps = templates.reject(&:is_a_snapshot)
|
423
646
|
tmps.sort_by(&:name)
|