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.

Files changed (113) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +619 -0
  3. data/README.md +290 -0
  4. data/Rakefile +49 -0
  5. data/app/assets/javascripts/foreman_fog_proxmox/proxmox_compute_resource.js +33 -0
  6. data/app/assets/javascripts/foreman_fog_proxmox/proxmox_vm.js +187 -0
  7. data/app/assets/javascripts/foreman_fog_proxmox/proxmox_vm_container.js +24 -0
  8. data/app/assets/javascripts/foreman_fog_proxmox/proxmox_vm_server.js +125 -0
  9. data/app/controllers/concerns/foreman_fog_proxmox/controller/parameters/compute_resource.rb +41 -0
  10. data/app/controllers/foreman_fog_proxmox/compute_resources_controller.rb +86 -0
  11. data/app/helpers/node_dashboard_helper.rb +35 -0
  12. data/app/helpers/proxmox_compute_selectors_helper.rb +184 -0
  13. data/app/helpers/proxmox_container_helper.rb +163 -0
  14. data/app/helpers/proxmox_form_helper.rb +70 -0
  15. data/app/helpers/proxmox_server_helper.rb +155 -0
  16. data/app/helpers/proxmox_vm_helper.rb +88 -0
  17. data/app/models/concerns/fog_extensions/proxmox/disk.rb +29 -0
  18. data/app/models/concerns/fog_extensions/proxmox/interface.rb +40 -0
  19. data/app/models/concerns/fog_extensions/proxmox/node.rb +41 -0
  20. data/app/models/concerns/fog_extensions/proxmox/server.rb +93 -0
  21. data/app/models/concerns/fog_extensions/proxmox/server_config.rb +71 -0
  22. data/app/models/concerns/fog_extensions/proxmox/volume.rb +29 -0
  23. data/app/models/concerns/host_ext/proxmox/interfaces.rb +52 -0
  24. data/app/models/concerns/orchestration/proxmox/compute.rb +42 -0
  25. data/app/models/foreman_fog_proxmox/options_select.rb +36 -0
  26. data/app/models/foreman_fog_proxmox/proxmox.rb +133 -0
  27. data/app/models/foreman_fog_proxmox/proxmox_compute_attributes.rb +67 -0
  28. data/app/models/foreman_fog_proxmox/proxmox_connection.rb +67 -0
  29. data/app/models/foreman_fog_proxmox/proxmox_console.rb +41 -0
  30. data/app/models/foreman_fog_proxmox/proxmox_images.rb +61 -0
  31. data/app/models/foreman_fog_proxmox/proxmox_interfaces.rb +103 -0
  32. data/app/models/foreman_fog_proxmox/proxmox_operating_systems.rb +49 -0
  33. data/app/models/foreman_fog_proxmox/proxmox_pools.rb +56 -0
  34. data/app/models/foreman_fog_proxmox/proxmox_token_expiration.rb +30 -0
  35. data/app/models/foreman_fog_proxmox/proxmox_version.rb +36 -0
  36. data/app/models/foreman_fog_proxmox/proxmox_vm_commands.rb +116 -0
  37. data/app/models/foreman_fog_proxmox/proxmox_vm_new.rb +178 -0
  38. data/app/models/foreman_fog_proxmox/proxmox_vm_queries.rb +75 -0
  39. data/app/models/foreman_fog_proxmox/proxmox_volumes.rb +94 -0
  40. data/app/models/foreman_fog_proxmox/vms.rb +37 -0
  41. data/app/overrides/compute_resources_vms/form/add_clone_to_new_vm_compute_detail.rb +25 -0
  42. data/app/overrides/compute_resources_vms/form/add_from_profile_to_compute_attributes_form.rb +34 -0
  43. data/app/overrides/compute_resources_vms/form/add_vm_type_node_to_new_form.rb +25 -0
  44. data/app/overrides/compute_resources_vms/form/add_vm_type_to_networks_form.rb +34 -0
  45. data/app/overrides/compute_resources_vms/form/add_vm_type_to_nic_provider_specific_form.rb +26 -0
  46. data/app/overrides/compute_resources_vms/form/add_vm_type_to_volumes_edit.rb +25 -0
  47. data/app/overrides/compute_resources_vms/form/add_vm_type_to_volumes_new_volume.rb +25 -0
  48. data/app/overrides/compute_resources_vms/form/remove_new_vm_from_removable_layout.rb +25 -0
  49. data/app/services/foreman_fog_proxmox/node_dashboard/data.rb +37 -0
  50. data/app/views/api/v2/compute_resources/proxmox.json.rabl +3 -0
  51. data/app/views/compute_resources/form/_proxmox.html.erb +29 -0
  52. data/app/views/compute_resources/show/_proxmox.html.erb +37 -0
  53. data/app/views/compute_resources_vms/form/proxmox/_add_from_profile_to_compute_attributes_form.html.erb +23 -0
  54. data/app/views/compute_resources_vms/form/proxmox/_add_from_profile_to_compute_form.html.erb +23 -0
  55. data/app/views/compute_resources_vms/form/proxmox/_add_from_profile_to_hosts_compute_detail_form.html.erb +24 -0
  56. data/app/views/compute_resources_vms/form/proxmox/_add_vm_type_node_to_new_form.html.erb +24 -0
  57. data/app/views/compute_resources_vms/form/proxmox/_add_vm_type_to_networks_form.html.erb +28 -0
  58. data/app/views/compute_resources_vms/form/proxmox/_add_vm_type_to_networks_new_childs_form.html.erb +32 -0
  59. data/app/views/compute_resources_vms/form/proxmox/_add_vm_type_to_nic_provider_specific_form.html.erb +30 -0
  60. data/app/views/compute_resources_vms/form/proxmox/_add_vm_type_to_volumes_edit.html.erb +71 -0
  61. data/app/views/compute_resources_vms/form/proxmox/_base.html.erb +39 -0
  62. data/app/views/compute_resources_vms/form/proxmox/_general.html.erb +39 -0
  63. data/app/views/compute_resources_vms/form/proxmox/_network.html.erb +19 -0
  64. data/app/views/compute_resources_vms/form/proxmox/_removable_layout.html.erb +27 -0
  65. data/app/views/compute_resources_vms/form/proxmox/container/_advanced.html.erb +31 -0
  66. data/app/views/compute_resources_vms/form/proxmox/container/_config.html.erb +41 -0
  67. data/app/views/compute_resources_vms/form/proxmox/container/_extended.html.erb +27 -0
  68. data/app/views/compute_resources_vms/form/proxmox/container/_network.html.erb +33 -0
  69. data/app/views/compute_resources_vms/form/proxmox/container/_volume_mp.html.erb +27 -0
  70. data/app/views/compute_resources_vms/form/proxmox/container/_volume_rootfs.html.erb +24 -0
  71. data/app/views/compute_resources_vms/form/proxmox/server/_advanced.html.erb +31 -0
  72. data/app/views/compute_resources_vms/form/proxmox/server/_config.html.erb +60 -0
  73. data/app/views/compute_resources_vms/form/proxmox/server/_network.html.erb +30 -0
  74. data/app/views/compute_resources_vms/form/proxmox/server/_volume.html.erb +28 -0
  75. data/app/views/compute_resources_vms/index/_proxmox.html.erb +49 -0
  76. data/app/views/compute_resources_vms/show/_proxmox.html.erb +42 -0
  77. data/app/views/dashboard/_foreman_fog_proxmox_widget.erb +21 -0
  78. data/app/views/images/form/_proxmox.html.erb +21 -0
  79. data/config/routes.rb +30 -0
  80. data/lib/foreman_fog_proxmox.rb +23 -0
  81. data/lib/foreman_fog_proxmox/engine.rb +105 -0
  82. data/lib/foreman_fog_proxmox/semver.rb +102 -0
  83. data/lib/foreman_fog_proxmox/value.rb +26 -0
  84. data/lib/foreman_fog_proxmox/version.rb +22 -0
  85. data/lib/tasks/foreman_fog_proxmox_tasks.rake +37 -0
  86. data/locale/Makefile +60 -0
  87. data/locale/en/foreman_fog_proxmox.po +401 -0
  88. data/locale/foreman_fog_proxmox.pot +627 -0
  89. data/locale/fr/foreman_fog_proxmox.po +401 -0
  90. data/locale/gemspec.rb +4 -0
  91. data/test/factories/foreman_fog_proxmox/proxmox_container_mock_factory.rb +137 -0
  92. data/test/factories/foreman_fog_proxmox/proxmox_node_mock_factory.rb +87 -0
  93. data/test/factories/foreman_fog_proxmox/proxmox_server_mock_factory.rb +134 -0
  94. data/test/factories/proxmox_factory.rb +79 -0
  95. data/test/functional/compute_resources_controller_test.rb +48 -0
  96. data/test/test_plugin_helper.rb +19 -0
  97. data/test/unit/foreman_fog_proxmox/helpers/proxmox_container_helper_test.rb +204 -0
  98. data/test/unit/foreman_fog_proxmox/helpers/proxmox_server_helper_test.rb +149 -0
  99. data/test/unit/foreman_fog_proxmox/helpers/proxmox_vm_helper_test.rb +216 -0
  100. data/test/unit/foreman_fog_proxmox/proxmox_compute_attributes_test.rb +124 -0
  101. data/test/unit/foreman_fog_proxmox/proxmox_images_test.rb +52 -0
  102. data/test/unit/foreman_fog_proxmox/proxmox_interfaces_test.rb +117 -0
  103. data/test/unit/foreman_fog_proxmox/proxmox_test.rb +58 -0
  104. data/test/unit/foreman_fog_proxmox/proxmox_version_test.rb +94 -0
  105. data/test/unit/foreman_fog_proxmox/proxmox_vm_commands_container_test.rb +280 -0
  106. data/test/unit/foreman_fog_proxmox/proxmox_vm_commands_server_create_test.rb +110 -0
  107. data/test/unit/foreman_fog_proxmox/proxmox_vm_commands_server_update_test.rb +222 -0
  108. data/test/unit/foreman_fog_proxmox/proxmox_vm_commands_server_update_volumes_test.rb +308 -0
  109. data/test/unit/foreman_fog_proxmox/proxmox_vm_commands_test.rb +43 -0
  110. data/test/unit/foreman_fog_proxmox/proxmox_vm_new_test.rb +71 -0
  111. data/test/unit/foreman_fog_proxmox/proxmox_vm_queries_test.rb +68 -0
  112. data/test/unit/foreman_fog_proxmox/semver_test.rb +111 -0
  113. 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