foreman_xen 0.7.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|