foreman_fog_proxmox 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of foreman_fog_proxmox might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/LICENSE +619 -0
- data/README.md +290 -0
- data/Rakefile +49 -0
- data/app/assets/javascripts/foreman_fog_proxmox/proxmox_compute_resource.js +33 -0
- data/app/assets/javascripts/foreman_fog_proxmox/proxmox_vm.js +187 -0
- data/app/assets/javascripts/foreman_fog_proxmox/proxmox_vm_container.js +24 -0
- data/app/assets/javascripts/foreman_fog_proxmox/proxmox_vm_server.js +125 -0
- data/app/controllers/concerns/foreman_fog_proxmox/controller/parameters/compute_resource.rb +41 -0
- data/app/controllers/foreman_fog_proxmox/compute_resources_controller.rb +86 -0
- data/app/helpers/node_dashboard_helper.rb +35 -0
- data/app/helpers/proxmox_compute_selectors_helper.rb +184 -0
- data/app/helpers/proxmox_container_helper.rb +163 -0
- data/app/helpers/proxmox_form_helper.rb +70 -0
- data/app/helpers/proxmox_server_helper.rb +155 -0
- data/app/helpers/proxmox_vm_helper.rb +88 -0
- data/app/models/concerns/fog_extensions/proxmox/disk.rb +29 -0
- data/app/models/concerns/fog_extensions/proxmox/interface.rb +40 -0
- data/app/models/concerns/fog_extensions/proxmox/node.rb +41 -0
- data/app/models/concerns/fog_extensions/proxmox/server.rb +93 -0
- data/app/models/concerns/fog_extensions/proxmox/server_config.rb +71 -0
- data/app/models/concerns/fog_extensions/proxmox/volume.rb +29 -0
- data/app/models/concerns/host_ext/proxmox/interfaces.rb +52 -0
- data/app/models/concerns/orchestration/proxmox/compute.rb +42 -0
- data/app/models/foreman_fog_proxmox/options_select.rb +36 -0
- data/app/models/foreman_fog_proxmox/proxmox.rb +133 -0
- data/app/models/foreman_fog_proxmox/proxmox_compute_attributes.rb +67 -0
- data/app/models/foreman_fog_proxmox/proxmox_connection.rb +67 -0
- data/app/models/foreman_fog_proxmox/proxmox_console.rb +41 -0
- data/app/models/foreman_fog_proxmox/proxmox_images.rb +61 -0
- data/app/models/foreman_fog_proxmox/proxmox_interfaces.rb +103 -0
- data/app/models/foreman_fog_proxmox/proxmox_operating_systems.rb +49 -0
- data/app/models/foreman_fog_proxmox/proxmox_pools.rb +56 -0
- data/app/models/foreman_fog_proxmox/proxmox_token_expiration.rb +30 -0
- data/app/models/foreman_fog_proxmox/proxmox_version.rb +36 -0
- data/app/models/foreman_fog_proxmox/proxmox_vm_commands.rb +116 -0
- data/app/models/foreman_fog_proxmox/proxmox_vm_new.rb +178 -0
- data/app/models/foreman_fog_proxmox/proxmox_vm_queries.rb +75 -0
- data/app/models/foreman_fog_proxmox/proxmox_volumes.rb +94 -0
- data/app/models/foreman_fog_proxmox/vms.rb +37 -0
- data/app/overrides/compute_resources_vms/form/add_clone_to_new_vm_compute_detail.rb +25 -0
- data/app/overrides/compute_resources_vms/form/add_from_profile_to_compute_attributes_form.rb +34 -0
- data/app/overrides/compute_resources_vms/form/add_vm_type_node_to_new_form.rb +25 -0
- data/app/overrides/compute_resources_vms/form/add_vm_type_to_networks_form.rb +34 -0
- data/app/overrides/compute_resources_vms/form/add_vm_type_to_nic_provider_specific_form.rb +26 -0
- data/app/overrides/compute_resources_vms/form/add_vm_type_to_volumes_edit.rb +25 -0
- data/app/overrides/compute_resources_vms/form/add_vm_type_to_volumes_new_volume.rb +25 -0
- data/app/overrides/compute_resources_vms/form/remove_new_vm_from_removable_layout.rb +25 -0
- data/app/services/foreman_fog_proxmox/node_dashboard/data.rb +37 -0
- data/app/views/api/v2/compute_resources/proxmox.json.rabl +3 -0
- data/app/views/compute_resources/form/_proxmox.html.erb +29 -0
- data/app/views/compute_resources/show/_proxmox.html.erb +37 -0
- data/app/views/compute_resources_vms/form/proxmox/_add_from_profile_to_compute_attributes_form.html.erb +23 -0
- data/app/views/compute_resources_vms/form/proxmox/_add_from_profile_to_compute_form.html.erb +23 -0
- data/app/views/compute_resources_vms/form/proxmox/_add_from_profile_to_hosts_compute_detail_form.html.erb +24 -0
- data/app/views/compute_resources_vms/form/proxmox/_add_vm_type_node_to_new_form.html.erb +24 -0
- data/app/views/compute_resources_vms/form/proxmox/_add_vm_type_to_networks_form.html.erb +28 -0
- data/app/views/compute_resources_vms/form/proxmox/_add_vm_type_to_networks_new_childs_form.html.erb +32 -0
- data/app/views/compute_resources_vms/form/proxmox/_add_vm_type_to_nic_provider_specific_form.html.erb +30 -0
- data/app/views/compute_resources_vms/form/proxmox/_add_vm_type_to_volumes_edit.html.erb +71 -0
- data/app/views/compute_resources_vms/form/proxmox/_base.html.erb +39 -0
- data/app/views/compute_resources_vms/form/proxmox/_general.html.erb +39 -0
- data/app/views/compute_resources_vms/form/proxmox/_network.html.erb +19 -0
- data/app/views/compute_resources_vms/form/proxmox/_removable_layout.html.erb +27 -0
- data/app/views/compute_resources_vms/form/proxmox/container/_advanced.html.erb +31 -0
- data/app/views/compute_resources_vms/form/proxmox/container/_config.html.erb +41 -0
- data/app/views/compute_resources_vms/form/proxmox/container/_extended.html.erb +27 -0
- data/app/views/compute_resources_vms/form/proxmox/container/_network.html.erb +33 -0
- data/app/views/compute_resources_vms/form/proxmox/container/_volume_mp.html.erb +27 -0
- data/app/views/compute_resources_vms/form/proxmox/container/_volume_rootfs.html.erb +24 -0
- data/app/views/compute_resources_vms/form/proxmox/server/_advanced.html.erb +31 -0
- data/app/views/compute_resources_vms/form/proxmox/server/_config.html.erb +60 -0
- data/app/views/compute_resources_vms/form/proxmox/server/_network.html.erb +30 -0
- data/app/views/compute_resources_vms/form/proxmox/server/_volume.html.erb +28 -0
- data/app/views/compute_resources_vms/index/_proxmox.html.erb +49 -0
- data/app/views/compute_resources_vms/show/_proxmox.html.erb +42 -0
- data/app/views/dashboard/_foreman_fog_proxmox_widget.erb +21 -0
- data/app/views/images/form/_proxmox.html.erb +21 -0
- data/config/routes.rb +30 -0
- data/lib/foreman_fog_proxmox.rb +23 -0
- data/lib/foreman_fog_proxmox/engine.rb +105 -0
- data/lib/foreman_fog_proxmox/semver.rb +102 -0
- data/lib/foreman_fog_proxmox/value.rb +26 -0
- data/lib/foreman_fog_proxmox/version.rb +22 -0
- data/lib/tasks/foreman_fog_proxmox_tasks.rake +37 -0
- data/locale/Makefile +60 -0
- data/locale/en/foreman_fog_proxmox.po +401 -0
- data/locale/foreman_fog_proxmox.pot +627 -0
- data/locale/fr/foreman_fog_proxmox.po +401 -0
- data/locale/gemspec.rb +4 -0
- data/test/factories/foreman_fog_proxmox/proxmox_container_mock_factory.rb +137 -0
- data/test/factories/foreman_fog_proxmox/proxmox_node_mock_factory.rb +87 -0
- data/test/factories/foreman_fog_proxmox/proxmox_server_mock_factory.rb +134 -0
- data/test/factories/proxmox_factory.rb +79 -0
- data/test/functional/compute_resources_controller_test.rb +48 -0
- data/test/test_plugin_helper.rb +19 -0
- data/test/unit/foreman_fog_proxmox/helpers/proxmox_container_helper_test.rb +204 -0
- data/test/unit/foreman_fog_proxmox/helpers/proxmox_server_helper_test.rb +149 -0
- data/test/unit/foreman_fog_proxmox/helpers/proxmox_vm_helper_test.rb +216 -0
- data/test/unit/foreman_fog_proxmox/proxmox_compute_attributes_test.rb +124 -0
- data/test/unit/foreman_fog_proxmox/proxmox_images_test.rb +52 -0
- data/test/unit/foreman_fog_proxmox/proxmox_interfaces_test.rb +117 -0
- data/test/unit/foreman_fog_proxmox/proxmox_test.rb +58 -0
- data/test/unit/foreman_fog_proxmox/proxmox_version_test.rb +94 -0
- data/test/unit/foreman_fog_proxmox/proxmox_vm_commands_container_test.rb +280 -0
- data/test/unit/foreman_fog_proxmox/proxmox_vm_commands_server_create_test.rb +110 -0
- data/test/unit/foreman_fog_proxmox/proxmox_vm_commands_server_update_test.rb +222 -0
- data/test/unit/foreman_fog_proxmox/proxmox_vm_commands_server_update_volumes_test.rb +308 -0
- data/test/unit/foreman_fog_proxmox/proxmox_vm_commands_test.rb +43 -0
- data/test/unit/foreman_fog_proxmox/proxmox_vm_new_test.rb +71 -0
- data/test/unit/foreman_fog_proxmox/proxmox_vm_queries_test.rb +68 -0
- data/test/unit/foreman_fog_proxmox/semver_test.rb +111 -0
- metadata +249 -0
@@ -0,0 +1,163 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2018 Tristan Robert
|
4
|
+
|
5
|
+
# This file is part of ForemanFogProxmox.
|
6
|
+
|
7
|
+
# ForemanFogProxmox is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
|
12
|
+
# ForemanFogProxmox is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with ForemanFogProxmox. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
require 'fog/proxmox/helpers/disk_helper'
|
21
|
+
require 'fog/proxmox/helpers/nic_helper'
|
22
|
+
require 'foreman_fog_proxmox/value'
|
23
|
+
|
24
|
+
module ProxmoxContainerHelper
|
25
|
+
def config_keys
|
26
|
+
general_a = ['node_id', 'name', 'type', 'config_attributes', 'volumes_attributes', 'interfaces_attributes']
|
27
|
+
general_a += ['firmware_type', 'provision_method', 'container_volumes', 'server_volumes', 'start_after_create']
|
28
|
+
keys = { general: general_a }
|
29
|
+
keys.store(:main, ['name', 'type', 'node_id', 'vmid', 'interfaces', 'mount_points', 'disks'])
|
30
|
+
keys.store(:cpu, ['arch', 'cpulimit', 'cpuunits', 'cores'])
|
31
|
+
keys.store(:memory, ['memory', 'swap'])
|
32
|
+
keys
|
33
|
+
end
|
34
|
+
|
35
|
+
def ostemplate_keys
|
36
|
+
['ostemplate', 'ostemplate_storage', 'ostemplate_file']
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse_ostemplate_without_keys(args)
|
40
|
+
parse_container_ostemplate(args.select { |key, _value| ostemplate_keys.include? key })
|
41
|
+
end
|
42
|
+
|
43
|
+
def config_general_or_ostemplate_key?(key)
|
44
|
+
config_keys[:general].include?(key) || ostemplate_keys.include?(key)
|
45
|
+
end
|
46
|
+
|
47
|
+
def parse_container_vm(args)
|
48
|
+
logger.debug("parse_container_vm args=#{args}")
|
49
|
+
args = ActiveSupport::HashWithIndifferentAccess.new(args)
|
50
|
+
return {} unless args
|
51
|
+
return {} if args.empty?
|
52
|
+
return {} unless args['type'] == 'lxc'
|
53
|
+
|
54
|
+
config = args['config_attributes']
|
55
|
+
config ||= args.reject { |key, _value| config_keys[:main].include? key }
|
56
|
+
ostemplate = parse_ostemplate_without_keys(args)
|
57
|
+
ostemplate = parse_ostemplate_without_keys(config) unless ostemplate[:ostemplate]
|
58
|
+
volumes = parse_container_volumes(args['volumes_attributes'])
|
59
|
+
cpu = parse_container_cpu(config.select { |key, _value| config_keys[:cpu].include? key })
|
60
|
+
memory = parse_container_memory(config.select { |key, _value| config_keys[:memory].include? key })
|
61
|
+
interfaces_attributes = args['interfaces_attributes']
|
62
|
+
interfaces_to_add, interfaces_to_delete = parse_container_interfaces(interfaces_attributes)
|
63
|
+
logger.debug("config_keys[:general]: #{config_keys[:general]}")
|
64
|
+
parsed_vm = args.reject { |key, value| config_general_or_ostemplate_key?(key) || ForemanFogProxmox::Value.empty?(value) }
|
65
|
+
parsed_config = config.reject { |key, value| config_keys.include?(key) || ForemanFogProxmox::Value.empty?(value) }
|
66
|
+
logger.debug("parse_container_config(): #{parsed_config}")
|
67
|
+
parsed_vm = parsed_vm.merge(parsed_config).merge(cpu).merge(memory).merge(ostemplate)
|
68
|
+
interfaces_to_add.each { |interface| parsed_vm = parsed_vm.merge(interface) }
|
69
|
+
parsed_vm = parsed_vm.merge(delete: interfaces_to_delete.join(',')) unless interfaces_to_delete.empty?
|
70
|
+
volumes.each { |volume| parsed_vm = parsed_vm.merge(volume) }
|
71
|
+
logger.debug("parse_container_vm(): #{parsed_vm}")
|
72
|
+
parsed_vm
|
73
|
+
end
|
74
|
+
|
75
|
+
def parse_container_memory(args)
|
76
|
+
memory = {}
|
77
|
+
args.delete_if { |_key, value| ForemanFogProxmox::Value.empty?(value) }
|
78
|
+
memory.store(:memory, args['memory'].to_i) if args['memory']
|
79
|
+
memory.store(:swap, args['swap'].to_i) if args['swap']
|
80
|
+
logger.debug("parse_container_memory(): #{memory}")
|
81
|
+
memory
|
82
|
+
end
|
83
|
+
|
84
|
+
def parse_container_cpu(args)
|
85
|
+
cpu = {}
|
86
|
+
args.delete_if { |_key, value| ForemanFogProxmox::Value.empty?(value) }
|
87
|
+
cpu.store(:arch, args['arch'].to_s) if args['arch']
|
88
|
+
cpu.store(:cpulimit, args['cpulimit'].to_i) if args['cpulimit']
|
89
|
+
cpu.store(:cpuunits, args['cpuunits'].to_i) if args['cpuunits']
|
90
|
+
cpu.store(:cores, args['cores'].to_i) if args['cores']
|
91
|
+
logger.debug("parse_container_cpu(): #{cpu}")
|
92
|
+
cpu
|
93
|
+
end
|
94
|
+
|
95
|
+
def parse_container_ostemplate(args)
|
96
|
+
ostemplate = args['ostemplate']
|
97
|
+
ostemplate_file = args['ostemplate_file']
|
98
|
+
ostemplate ||= ostemplate_file
|
99
|
+
ostemplate_storage = args['ostemplate_storage']
|
100
|
+
ostemplate_storage, ostemplate_file, _size = Fog::Proxmox::DiskHelper.extract_storage_volid_size(ostemplate) unless ForemanFogProxmox::Value.empty?(ostemplate)
|
101
|
+
parsed_ostemplate = { ostemplate: ostemplate, ostemplate_file: ostemplate_file, ostemplate_storage: ostemplate_storage }
|
102
|
+
logger.debug("parse_container_ostemplate(): #{parsed_ostemplate}")
|
103
|
+
parsed_ostemplate
|
104
|
+
end
|
105
|
+
|
106
|
+
def parse_container_volume(args)
|
107
|
+
disk = {}
|
108
|
+
id = args['id']
|
109
|
+
id = "mp#{args['device']}" if args.key?('device')
|
110
|
+
logger.debug("parse_container_volume() args=#{args}")
|
111
|
+
return args if ForemanFogProxmox::Value.empty?(id) || Fog::Proxmox::DiskHelper.server_disk?(id)
|
112
|
+
|
113
|
+
args.delete_if { |_key, value| ForemanFogProxmox::Value.empty?(value) }
|
114
|
+
disk.store(:id, id)
|
115
|
+
disk.store(:volid, args['volid'])
|
116
|
+
disk.store(:storage, args['storage'].to_s)
|
117
|
+
disk.store(:size, args['size'].to_i)
|
118
|
+
options = args.reject { |key, _value| ['id', 'volid', 'device', 'storage', 'size', '_delete'].include? key }
|
119
|
+
disk.store(:options, options)
|
120
|
+
logger.debug("parse_container_volume(): disk=#{disk}")
|
121
|
+
Fog::Proxmox::DiskHelper.flatten(disk)
|
122
|
+
end
|
123
|
+
|
124
|
+
def parse_container_volumes(args)
|
125
|
+
logger.debug("parse_container_volumes() args=#{args}")
|
126
|
+
volumes = []
|
127
|
+
args&.each_value { |value| volumes.push(parse_container_volume(value)) }
|
128
|
+
logger.debug("parse_container_volumes(): volumes=#{volumes}")
|
129
|
+
volumes
|
130
|
+
end
|
131
|
+
|
132
|
+
def parse_container_interfaces(interfaces_attributes)
|
133
|
+
interfaces_to_add = []
|
134
|
+
interfaces_to_delete = []
|
135
|
+
interfaces_attributes&.each_value { |value| add_container_interface(value, interfaces_to_delete, interfaces_to_add) }
|
136
|
+
logger.debug("parse_container_interfaces(): interfaces_to_add=#{interfaces_to_add}, interfaces_to_delete=#{interfaces_to_delete}")
|
137
|
+
[interfaces_to_add, interfaces_to_delete]
|
138
|
+
end
|
139
|
+
|
140
|
+
def add_container_interface(interface_attributes, interfaces_to_delete, interfaces_to_add)
|
141
|
+
interface_attributes.delete_if { |_key, value| ForemanFogProxmox::Value.empty?(value) }
|
142
|
+
nic = {}
|
143
|
+
id = interface_attributes['id']
|
144
|
+
logger.debug("parse_container_interface(): id=#{id}")
|
145
|
+
delete = interface_attributes['_delete'].to_i == 1
|
146
|
+
if delete
|
147
|
+
interfaces_to_delete.push(id.to_s)
|
148
|
+
else
|
149
|
+
nic.store(:id, id)
|
150
|
+
nic.store(:hwaddr, interface_attributes['macaddr']) if interface_attributes['macaddr']
|
151
|
+
nic.store(:name, interface_attributes['name'].to_s)
|
152
|
+
nic.store(:bridge, interface_attributes['bridge'].to_s) if interface_attributes['bridge']
|
153
|
+
nic.store(:ip, interface_attributes['ip'].to_s) if interface_attributes['ip']
|
154
|
+
nic.store(:ip6, interface_attributes['ip6'].to_s) if interface_attributes['ip6']
|
155
|
+
nic.store(:gw, interface_attributes['gw'].to_s) if interface_attributes['gw']
|
156
|
+
nic.store(:gw6, interface_attributes['gw6'].to_s) if interface_attributes['gw6']
|
157
|
+
nic.store(:rate, interface_attributes['rate'].to_i) if interface_attributes['rate']
|
158
|
+
nic.store(:tag, interface_attributes['tag'].to_i) if interface_attributes['tag']
|
159
|
+
logger.debug("parse_container_interface(): add nic=#{nic}")
|
160
|
+
interfaces_to_add.push(Fog::Proxmox::NicHelper.flatten(nic))
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2018 Tristan Robert
|
4
|
+
|
5
|
+
# This file is part of ForemanFogProxmox.
|
6
|
+
|
7
|
+
# ForemanFogProxmox is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
|
12
|
+
# ForemanFogProxmox is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with ForemanFogProxmox. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
module ProxmoxFormHelper
|
21
|
+
def password_proxmox_f(f, attr, options = {})
|
22
|
+
unset_button = options.delete(:unset)
|
23
|
+
value = f.object[attr] if options.delete(:keep_value)
|
24
|
+
password_field_tag(:fakepassword, value, :style => 'display: none', :autocomplete => 'new-password-fake') +
|
25
|
+
field(f, attr, options) do
|
26
|
+
options[:autocomplete] ||= 'new-password'
|
27
|
+
options[:placeholder] ||= password_proxmox_placeholder(f.object, attr)
|
28
|
+
options[:disabled] = true if unset_button
|
29
|
+
options[:value] = value if value.present?
|
30
|
+
addClass options, 'form-control'
|
31
|
+
pass = f.password_field(attr, options) +
|
32
|
+
content_tag(:span, '', class: 'glyphicon glyphicon-warning-sign input-addon',
|
33
|
+
title: 'Caps lock ON', style: 'display:none')
|
34
|
+
if unset_button
|
35
|
+
button = link_to_function(icon_text('edit', '', :kind => 'pficon'), 'toggle_input_group(this)', :id => 'disable-pass-btn', :class => 'btn btn-default', :title => _('Change the password'))
|
36
|
+
input_group(pass, input_group_btn(button))
|
37
|
+
else
|
38
|
+
pass
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def password_proxmox_placeholder(obj, attr = nil)
|
44
|
+
pass = obj.attributes.key?(attr)
|
45
|
+
pass ? '********' : ''
|
46
|
+
end
|
47
|
+
|
48
|
+
def new_child_fields_template_typed(form_builder, association, options = {})
|
49
|
+
if options[:object].blank?
|
50
|
+
association_object = form_builder.object.class.reflect_on_association(association)
|
51
|
+
options[:object] = association_object.klass.new(association_object.foreign_key => form_builder.object.id)
|
52
|
+
end
|
53
|
+
options[:partial] ||= association.to_s.singularize
|
54
|
+
options[:form_builder_local] ||= :f
|
55
|
+
options[:form_builder_attrs] ||= {}
|
56
|
+
|
57
|
+
content_tag(:div, :class => "#{options[:type]}_#{association}_fields_template form_template ", :style => 'display: none;') do
|
58
|
+
form_builder.fields_for(association, options[:object], :child_index => "new_#{options[:type]}_#{association}") do |f|
|
59
|
+
render(:partial => options[:partial], :layout => options[:layout],
|
60
|
+
:locals => { options[:form_builder_local] => f }.merge(options[:form_builder_attrs]))
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def add_child_link_typed(name, association, type, opts = {})
|
66
|
+
opts[:class] = [opts[:class], 'add_nested_fields btn btn-primary'].compact.join(' ')
|
67
|
+
opts[:"data-association"] = (type + '_' + association.to_s).to_sym
|
68
|
+
link_to_function(name.to_s, 'add_child_node(this);tfm.numFields.initAll();', opts)
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2018 Tristan Robert
|
4
|
+
|
5
|
+
# This file is part of ForemanFogProxmox.
|
6
|
+
|
7
|
+
# ForemanFogProxmox is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
|
12
|
+
# ForemanFogProxmox is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with ForemanFogProxmox. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
require 'fog/proxmox/helpers/disk_helper'
|
21
|
+
require 'fog/proxmox/helpers/nic_helper'
|
22
|
+
require 'foreman_fog_proxmox/value'
|
23
|
+
|
24
|
+
module ProxmoxServerHelper
|
25
|
+
def parse_server_vm(args)
|
26
|
+
logger.debug("parse_server_vm args=#{args}")
|
27
|
+
args = ActiveSupport::HashWithIndifferentAccess.new(args)
|
28
|
+
return {} unless args
|
29
|
+
return {} if args.empty?
|
30
|
+
return {} unless args['type'] == 'qemu'
|
31
|
+
|
32
|
+
config = args['config_attributes']
|
33
|
+
main_a = ['name', 'type', 'node_id', 'vmid', 'interfaces', 'mount_points', 'disks']
|
34
|
+
config ||= args.reject { |key, _value| main_a.include? key }
|
35
|
+
cdrom_a = ['cdrom', 'cdrom_storage', 'cdrom_iso']
|
36
|
+
cdrom = parse_server_cdrom(config.select { |key, _value| cdrom_a.include? key })
|
37
|
+
vols = args['volumes_attributes']
|
38
|
+
volumes = parse_server_volumes(vols)
|
39
|
+
cpu_a = ['cpu_type', 'spectre', 'pcid']
|
40
|
+
cpu = parse_server_cpu(config.select { |key, _value| cpu_a.include? key })
|
41
|
+
memory_a = ['memory', 'balloon', 'shares']
|
42
|
+
memory = parse_server_memory(config.select { |key, _value| memory_a.include? key })
|
43
|
+
interfaces_attributes = args['interfaces_attributes']
|
44
|
+
interfaces_to_add, interfaces_to_delete = parse_server_interfaces(interfaces_attributes)
|
45
|
+
general_a = ['node_id', 'type', 'config_attributes', 'volumes_attributes', 'interfaces_attributes']
|
46
|
+
general_a += ['firmware_type', 'provision_method', 'container_volumes', 'server_volumes', 'start_after_create']
|
47
|
+
logger.debug("general_a: #{general_a}")
|
48
|
+
parsed_vm = args.reject { |key, value| general_a.include?(key) || ForemanFogProxmox::Value.empty?(value) }
|
49
|
+
config_a = []
|
50
|
+
config_a += cpu_a
|
51
|
+
config_a += cdrom_a
|
52
|
+
config_a += memory_a
|
53
|
+
config_a += general_a
|
54
|
+
parsed_config = config.reject { |key, value| config_a.include?(key) || ForemanFogProxmox::Value.empty?(value) }
|
55
|
+
logger.debug("parse_server_config(): #{parsed_config}")
|
56
|
+
parsed_vm = parsed_vm.merge(parsed_config).merge(cpu).merge(memory).merge(cdrom)
|
57
|
+
interfaces_to_add.each { |interface| parsed_vm = parsed_vm.merge(interface) }
|
58
|
+
parsed_vm = parsed_vm.merge(delete: interfaces_to_delete.join(',')) unless interfaces_to_delete.empty?
|
59
|
+
volumes.each { |volume| parsed_vm = parsed_vm.merge(volume) }
|
60
|
+
logger.debug("parse_server_vm(): #{parsed_vm}")
|
61
|
+
parsed_vm
|
62
|
+
end
|
63
|
+
|
64
|
+
def parse_server_memory(args)
|
65
|
+
memory = {}
|
66
|
+
memory.store(:memory, args['memory'].to_i) if args['memory']
|
67
|
+
memory.store(:shares, args['shares'].to_i) if args['shares']
|
68
|
+
memory.store(:balloon, args['balloon'].to_i) if args['balloon']
|
69
|
+
logger.debug("parse_server_memory(): #{memory}")
|
70
|
+
memory
|
71
|
+
end
|
72
|
+
|
73
|
+
def parse_server_cpu(args)
|
74
|
+
return {} unless args['cpu_type']
|
75
|
+
|
76
|
+
cpu = "cputype=#{args['cpu_type']}"
|
77
|
+
spectre = args['spectre'].to_i == 1
|
78
|
+
pcid = args['pcid'].to_i == 1
|
79
|
+
cpu += ',flags=' if spectre || pcid
|
80
|
+
cpu += '+spec-ctrl' if spectre
|
81
|
+
cpu += ';' if spectre && pcid
|
82
|
+
cpu += '+pcid' if pcid
|
83
|
+
args.delete_if { |key, value| ['cpu_type', 'spectre', 'pcid'].include?(key) || ForemanFogProxmox::Value.empty?(value) }
|
84
|
+
args.each_value(&:to_i)
|
85
|
+
parsed_cpu = { cpu: cpu }.merge(args)
|
86
|
+
logger.debug("parse_server_cpu(): #{parsed_cpu}")
|
87
|
+
parsed_cpu
|
88
|
+
end
|
89
|
+
|
90
|
+
def parse_server_cdrom(args)
|
91
|
+
cdrom = args['cdrom']
|
92
|
+
cdrom_image = args['cdrom_iso']
|
93
|
+
volid = cdrom_image.empty? ? cdrom : cdrom_image
|
94
|
+
return {} unless volid
|
95
|
+
|
96
|
+
cdrom = "#{volid},media=cdrom"
|
97
|
+
{ ide2: cdrom }
|
98
|
+
end
|
99
|
+
|
100
|
+
def parse_server_volume(args)
|
101
|
+
disk = {}
|
102
|
+
volid = args['volid'] if args.key?('volid')
|
103
|
+
id = args['id'] if volid
|
104
|
+
id = "#{args['controller']}#{args['device']}" if args.key?('controller') && args.key?('device') && !id
|
105
|
+
return args if ForemanFogProxmox::Value.empty?(id) || id == 'rootfs'
|
106
|
+
|
107
|
+
args.delete_if { |_key, value| ForemanFogProxmox::Value.empty?(value) }
|
108
|
+
disk.store(:id, id)
|
109
|
+
disk.store(:volid, args['volid']) if args.key?('volid')
|
110
|
+
disk.store(:storage, args['storage'].to_s) if args.key?('storage')
|
111
|
+
disk.store(:size, args['size'].to_i) if args.key?('size')
|
112
|
+
options = args.reject { |key, _value| ['id', 'volid', 'controller', 'device', 'storage', 'size', '_delete'].include? key }
|
113
|
+
disk.store(:options, options)
|
114
|
+
logger.debug("parse_server_volume(): disk=#{disk}")
|
115
|
+
Fog::Proxmox::DiskHelper.flatten(disk)
|
116
|
+
end
|
117
|
+
|
118
|
+
def parse_server_volumes(args)
|
119
|
+
volumes = []
|
120
|
+
args&.each_value { |value| volumes.push(parse_server_volume(value)) }
|
121
|
+
logger.debug("parse_server_volumes(): volumes=#{volumes}")
|
122
|
+
volumes
|
123
|
+
end
|
124
|
+
|
125
|
+
def parse_server_interfaces(interfaces_attributes)
|
126
|
+
interfaces_to_add = []
|
127
|
+
interfaces_to_delete = []
|
128
|
+
interfaces_attributes&.each_value { |value| add_server_interface(value, interfaces_to_delete, interfaces_to_add) }
|
129
|
+
logger.debug("parse_server_interfaces(): interfaces_to_delete=#{interfaces_to_delete} interfaces_to_add=#{interfaces_to_add}")
|
130
|
+
[interfaces_to_add, interfaces_to_delete]
|
131
|
+
end
|
132
|
+
|
133
|
+
def add_server_interface(interface_attributes, interfaces_to_delete, interfaces_to_add)
|
134
|
+
interface_attributes.delete_if { |_key, value| ForemanFogProxmox::Value.empty?(value) }
|
135
|
+
nic = {}
|
136
|
+
id = interface_attributes['id']
|
137
|
+
logger.debug("add_server_interface(): id=#{id}")
|
138
|
+
delete = interface_attributes['_delete'].to_i == 1
|
139
|
+
if delete
|
140
|
+
interfaces_to_delete.push(id.to_s)
|
141
|
+
else
|
142
|
+
nic.store(:id, id)
|
143
|
+
nic.store(:macaddr, interface_attributes['macaddr']) if interface_attributes['macaddr']
|
144
|
+
nic.store(:tag, interface_attributes['tag'].to_i) if interface_attributes['tag']
|
145
|
+
nic.store(:model, interface_attributes['model'].to_s)
|
146
|
+
nic.store(:bridge, interface_attributes['bridge'].to_s) if interface_attributes['bridge']
|
147
|
+
nic.store(:firewall, interface_attributes['firewall'].to_i) if interface_attributes['firewall']
|
148
|
+
nic.store(:rate, interface_attributes['rate'].to_i) if interface_attributes['rate']
|
149
|
+
nic.store(:link_down, interface_attributes['link_down'].to_i) if interface_attributes['link_down']
|
150
|
+
nic.store(:queues, interface_attributes['queues'].to_i) if interface_attributes['queues']
|
151
|
+
logger.debug("add_server_interface(): add nic=#{nic}")
|
152
|
+
interfaces_to_add.push(Fog::Proxmox::NicHelper.flatten(nic))
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2018 Tristan Robert
|
4
|
+
|
5
|
+
# This file is part of ForemanFogProxmox.
|
6
|
+
|
7
|
+
# ForemanFogProxmox is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
|
12
|
+
# ForemanFogProxmox is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with ForemanFogProxmox. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
require 'fog/proxmox/helpers/disk_helper'
|
21
|
+
require 'fog/proxmox/helpers/nic_helper'
|
22
|
+
require 'foreman_fog_proxmox/value'
|
23
|
+
|
24
|
+
module ProxmoxVmHelper
|
25
|
+
KILO = 1024
|
26
|
+
MEGA = KILO * KILO
|
27
|
+
GIGA = KILO * MEGA
|
28
|
+
|
29
|
+
def object_to_config_hash(vm)
|
30
|
+
vm_h = ActiveSupport::HashWithIndifferentAccess.new
|
31
|
+
main_a = ['hostname', 'name', 'vmid']
|
32
|
+
main = vm.attributes.select { |key, _value| main_a.include? key }
|
33
|
+
main_a += ['templated']
|
34
|
+
config = vm.config.attributes.reject { |key, _value| main_a.include?(key) || Fog::Proxmox::DiskHelper.disk?(key) || Fog::Proxmox::NicHelper.nic?(key) }
|
35
|
+
vm_h = vm_h.merge(main)
|
36
|
+
vm_h = vm_h.merge('config_attributes': config)
|
37
|
+
vm_h
|
38
|
+
end
|
39
|
+
|
40
|
+
def add_cdrom_to_config_server(vm, config)
|
41
|
+
cd_disks = vm.config.disks.select { |disk| disk.id == 'ide2' }
|
42
|
+
cdrom = {}
|
43
|
+
disk_to_cdrom(cd_disks.first, cdrom)
|
44
|
+
config = config.merge(cdrom)
|
45
|
+
config
|
46
|
+
end
|
47
|
+
|
48
|
+
def disk_to_cdrom(disk, cdrom)
|
49
|
+
volid = disk.volid
|
50
|
+
cdrom_a = ['none', 'cdrom']
|
51
|
+
if cdrom_a.include? volid
|
52
|
+
cdrom.store('cdrom', volid)
|
53
|
+
else
|
54
|
+
cdrom.store('cdrom', 'image')
|
55
|
+
cdrom.store('cdrom_iso', volid)
|
56
|
+
cdrom.store('cdrom_storage', disk.storage)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def convert_memory_sizes(args)
|
61
|
+
convert_memory_size(args['config_attributes'], 'memory')
|
62
|
+
convert_memory_size(args['config_attributes'], 'balloon')
|
63
|
+
convert_memory_size(args['config_attributes'], 'shares')
|
64
|
+
convert_memory_size(args['config_attributes'], 'swap')
|
65
|
+
end
|
66
|
+
|
67
|
+
def convert_volumes_size(args)
|
68
|
+
args['volumes_attributes'].each_value { |value| value['size'] = (value['size'].to_i / GIGA).to_s unless ForemanFogProxmox::Value.empty?(value['size']) }
|
69
|
+
end
|
70
|
+
|
71
|
+
def convert_sizes(args)
|
72
|
+
convert_memory_size(args['config_attributes'], 'memory')
|
73
|
+
convert_memory_size(args['config_attributes'], 'balloon')
|
74
|
+
convert_memory_size(args['config_attributes'], 'shares')
|
75
|
+
convert_memory_size(args['config_attributes'], 'swap')
|
76
|
+
args['volumes_attributes'].each_value { |value| value['size'] = (value['size'].to_i / GIGA).to_s unless ForemanFogProxmox::Value.empty?(value['size']) }
|
77
|
+
end
|
78
|
+
|
79
|
+
def remove_deletes(args)
|
80
|
+
args['volumes_attributes']&.delete_if { |_key, value| value.key? '_delete' }
|
81
|
+
end
|
82
|
+
|
83
|
+
def convert_memory_size(config_hash, key)
|
84
|
+
# default unit memory size is Mb
|
85
|
+
memory = (config_hash[key].to_i / MEGA).to_s == '0' ? config_hash[key] : (config_hash[key].to_i / MEGA).to_s
|
86
|
+
config_hash.store(key, memory)
|
87
|
+
end
|
88
|
+
end
|