foreman_fog_proxmox 0.11.1 → 0.13.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 (78) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +12 -3
  3. data/app/assets/javascripts/foreman_fog_proxmox/proxmox_compute_resource.js +24 -2
  4. data/app/assets/javascripts/foreman_fog_proxmox/proxmox_vm.js +124 -52
  5. data/app/assets/javascripts/foreman_fog_proxmox/proxmox_vm_server.js +0 -48
  6. data/app/assets/javascripts/foreman_fog_proxmox/proxmox_volume.js +39 -0
  7. data/app/assets/javascripts/foreman_fog_proxmox/proxmox_volume_cdrom.js +63 -0
  8. data/app/assets/javascripts/foreman_fog_proxmox/proxmox_volume_cloudinit.js +25 -0
  9. data/app/controllers/concerns/foreman_fog_proxmox/controller/parameters/compute_resource.rb +1 -1
  10. data/app/helpers/proxmox_compute_controllers_helper.rb +39 -0
  11. data/app/helpers/proxmox_compute_resources_helper.rb +49 -0
  12. data/app/helpers/proxmox_compute_selectors_helper.rb +11 -44
  13. data/app/helpers/proxmox_form_helper.rb +12 -4
  14. data/app/{models/concerns/fog_extensions/proxmox/volume.rb → helpers/proxmox_storages_helper.rb} +5 -8
  15. data/app/{models/foreman_fog_proxmox/proxmox_token_expiration.rb → helpers/proxmox_vm_cdrom_helper.rb} +15 -10
  16. data/app/helpers/proxmox_vm_cloudinit_helper.rb +43 -0
  17. data/app/helpers/proxmox_vm_config_helper.rb +159 -0
  18. data/app/helpers/proxmox_vm_helper.rb +24 -70
  19. data/app/helpers/proxmox_vm_interfaces_helper.rb +85 -0
  20. data/app/helpers/proxmox_vm_os_template_helper.rb +47 -0
  21. data/app/helpers/proxmox_vm_volumes_helper.rb +105 -0
  22. data/app/models/concerns/fog_extensions/proxmox/disk.rb +17 -2
  23. data/app/models/concerns/fog_extensions/proxmox/interface.rb +19 -4
  24. data/app/models/concerns/fog_extensions/proxmox/server.rb +8 -3
  25. data/app/models/concerns/fog_extensions/proxmox/server_config.rb +8 -30
  26. data/app/models/concerns/host_ext/proxmox/interfaces.rb +7 -2
  27. data/app/models/concerns/orchestration/proxmox/compute.rb +1 -0
  28. data/app/models/foreman_fog_proxmox/proxmox.rb +58 -15
  29. data/app/models/foreman_fog_proxmox/proxmox_compute_attributes.rb +20 -12
  30. data/app/models/foreman_fog_proxmox/proxmox_connection.rb +14 -9
  31. data/app/models/foreman_fog_proxmox/proxmox_images.rb +2 -1
  32. data/app/models/foreman_fog_proxmox/proxmox_interfaces.rb +53 -28
  33. data/app/models/foreman_fog_proxmox/proxmox_operating_systems.rb +1 -1
  34. data/app/models/foreman_fog_proxmox/proxmox_version.rb +7 -2
  35. data/app/models/foreman_fog_proxmox/proxmox_vm_commands.rb +19 -30
  36. data/app/models/foreman_fog_proxmox/proxmox_vm_new.rb +108 -94
  37. data/app/models/foreman_fog_proxmox/proxmox_vm_queries.rb +2 -1
  38. data/app/models/foreman_fog_proxmox/proxmox_volumes.rb +79 -22
  39. data/app/views/compute_resources/form/_proxmox.html.erb +23 -10
  40. data/app/views/compute_resources/show/_proxmox.html.erb +6 -6
  41. data/app/views/compute_resources_vms/form/proxmox/_add_vm_type_to_nic_provider_specific_form.html.erb +4 -2
  42. data/app/views/compute_resources_vms/form/proxmox/_add_vm_type_to_volumes_edit.html.erb +46 -29
  43. data/app/views/compute_resources_vms/form/proxmox/_base.html.erb +3 -3
  44. data/app/views/compute_resources_vms/form/proxmox/_removable_layout.html.erb +2 -1
  45. data/app/views/compute_resources_vms/form/proxmox/container/_network.html.erb +8 -7
  46. data/app/views/compute_resources_vms/form/proxmox/server/_advanced.html.erb +0 -2
  47. data/app/views/compute_resources_vms/form/proxmox/server/_config.html.erb +16 -14
  48. data/app/views/compute_resources_vms/form/proxmox/server/_network.html.erb +2 -2
  49. data/app/views/compute_resources_vms/form/proxmox/server/_volume_cdrom.html.erb +34 -0
  50. data/app/views/compute_resources_vms/form/proxmox/server/_volume_cloud_init.html.erb +29 -0
  51. data/app/views/compute_resources_vms/form/proxmox/server/{_volume.html.erb → _volume_hard_disk.html.erb} +7 -3
  52. data/app/views/compute_resources_vms/show/_proxmox.html.erb +2 -0
  53. data/lib/foreman_fog_proxmox/engine.rb +9 -10
  54. data/lib/foreman_fog_proxmox/hash_collection.rb +69 -0
  55. data/lib/foreman_fog_proxmox/version.rb +1 -1
  56. data/lib/tasks/foreman_fog_proxmox_tasks.rake +0 -3
  57. data/test/factories/foreman_fog_proxmox/proxmox_container_mock_factory.rb +20 -8
  58. data/test/factories/foreman_fog_proxmox/proxmox_node_mock_factory.rb +5 -5
  59. data/test/factories/foreman_fog_proxmox/proxmox_server_mock_factory.rb +17 -7
  60. data/test/factories/proxmox_factory.rb +4 -4
  61. data/test/functional/compute_resources_controller_test.rb +4 -4
  62. data/test/unit/foreman_fog_proxmox/helpers/proxmox_container_helper_test.rb +49 -29
  63. data/test/unit/foreman_fog_proxmox/helpers/proxmox_server_helper_test.rb +53 -30
  64. data/test/unit/foreman_fog_proxmox/helpers/proxmox_vm_helper_test.rb +22 -20
  65. data/test/unit/foreman_fog_proxmox/helpers/proxmox_vm_volumes_helper_test.rb +50 -0
  66. data/test/unit/foreman_fog_proxmox/proxmox_compute_attributes_test.rb +12 -5
  67. data/test/unit/foreman_fog_proxmox/proxmox_interfaces_test.rb +38 -10
  68. data/test/unit/foreman_fog_proxmox/proxmox_version_test.rb +10 -10
  69. data/test/unit/foreman_fog_proxmox/proxmox_vm_commands_container_test.rb +34 -24
  70. data/test/unit/foreman_fog_proxmox/proxmox_vm_commands_server_create_test.rb +21 -7
  71. data/test/unit/foreman_fog_proxmox/proxmox_vm_commands_server_update_cdrom_test.rb +181 -0
  72. data/test/unit/foreman_fog_proxmox/proxmox_vm_commands_server_update_cloudinit_test.rb +131 -0
  73. data/test/unit/foreman_fog_proxmox/{proxmox_vm_commands_server_update_volumes_test.rb → proxmox_vm_commands_server_update_hard_disk_test.rb} +45 -19
  74. data/test/unit/foreman_fog_proxmox/proxmox_vm_commands_server_update_test.rb +21 -21
  75. data/test/unit/foreman_fog_proxmox/proxmox_vm_new_test.rb +3 -3
  76. metadata +44 -27
  77. data/app/helpers/proxmox_container_helper.rb +0 -163
  78. data/app/helpers/proxmox_server_helper.rb +0 -155
@@ -20,76 +20,74 @@
20
20
  require 'fog/proxmox'
21
21
  require 'fog/proxmox/helpers/nic_helper'
22
22
  require 'fog/proxmox/helpers/disk_helper'
23
+ require 'foreman_fog_proxmox/hash_collection'
23
24
 
24
25
  module ForemanFogProxmox
25
26
  module ProxmoxVmNew
26
27
  include ProxmoxVmHelper
27
28
 
28
- def volume_server_defaults(controller = 'scsi', device = 0)
29
- id = "#{controller}#{device}"
30
- { id: id, storage: storages.first.identity.to_s, size: (8 * GIGA), options: { cache: 'none' } }
29
+ def cdrom_defaults
30
+ { storage_type: 'cdrom', id: 'ide2', volid: 'none', media: 'cdrom' }
31
31
  end
32
32
 
33
- def volume_container_defaults(id = 'rootfs')
34
- { id: id, storage: storages.first.identity.to_s, size: (8 * GIGA), options: {} }
33
+ def cloudinit_defaults
34
+ { storage_type: 'cloud_init', id: 'ide0', storage: storages.first.identity.to_s, media: 'cdrom' }
35
35
  end
36
36
 
37
- def new_volume(attr = {})
38
- type = attr['type']
39
- type ||= 'qemu'
40
- case type
41
- when 'lxc'
42
- new_volume_server(attr)
37
+ def hard_disk_typed_defaults(vm_type)
38
+ options = {}
39
+ volume_attributes_h = { storage: storages.first.identity.to_s, size: (8 * GIGA) }
40
+ case vm_type
43
41
  when 'qemu'
44
- new_volume_container(attr)
42
+ controller = 'virtio'
43
+ device = 0
44
+ id = "#{controller}#{device}"
45
+ options = { cache: 'none' }
46
+ volume_attributes_h = volume_attributes_h.merge(controller: controller, device: device)
47
+ when 'lxc'
48
+ id = 'rootfs'
49
+ volume_attributes_h = volume_attributes_h.merge(storage_type: 'rootfs')
45
50
  end
51
+ volume_attributes_h[:id] = id
52
+ volume_attributes_h[:options] = options
53
+ volume_attributes_h
46
54
  end
47
55
 
48
- def new_volume_server(attr = {})
49
- opts = volume_server_defaults.merge(attr.to_h).deep_symbolize_keys
50
- opts[:size] = opts[:size].to_s
56
+ def new_typed_volume(attr, vm_type, volume_type)
57
+ volume_defaults = hard_disk_typed_defaults(vm_type) if ['hard_disk', 'rootfs', 'mp'].include?(volume_type)
58
+ volume_defaults = cdrom_defaults if volume_type == 'cdrom'
59
+ volume_defaults = cloudinit_defaults if volume_type == 'cloud_init'
60
+ opts = volume_defaults.merge(attr.to_h).deep_symbolize_keys
61
+ opts = ForemanFogProxmox::HashCollection.new_hash_transform_values(opts, :to_s)
51
62
  Fog::Proxmox::Compute::Disk.new(opts)
52
63
  end
53
64
 
54
- def new_volume_container(attr = {})
55
- opts = volume_container_defaults.merge(attr.to_h).deep_symbolize_keys
56
- opts[:size] = opts[:size].to_s
57
- Fog::Proxmox::Compute::Disk.new(opts)
65
+ def new_volume(attr = {})
66
+ type = attr['type']
67
+ type ||= 'qemu'
68
+ new_typed_volume(attr, type, 'hard_disk')
58
69
  end
59
70
 
60
71
  def interface_defaults(id = 'net0')
61
- { id: id, model: 'virtio', name: 'eth0', bridge: bridges.first.identity.to_s }
72
+ { id: id, compute_attributes: { model: 'virtio', name: 'eth0', bridge: bridges.first.identity.to_s } }
62
73
  end
63
74
 
64
- def interface_server_defaults(id = 'net0')
65
- { id: id, model: 'virtio', bridge: bridges.first.identity.to_s }
75
+ def interface_typed_defaults(type)
76
+ interface_attributes_h = { id: 'net0', compute_attributes: {} }
77
+ interface_attributes_h[:compute_attributes] = { model: 'virtio', bridge: bridges.first.identity.to_s } if type == 'qemu'
78
+ interface_attributes_h[:compute_attributes] = { name: 'eth0', bridge: bridges.first.identity.to_s, dhcp: 1, dhcp6: 1 } if type == 'lxc'
79
+ interface_attributes_h
66
80
  end
67
81
 
68
- def interface_container_defaults(id = 'net0')
69
- { id: id, name: 'eth0', bridge: bridges.first.identity.to_s, dhcpv4: 1, dhcpv6: 1 }
82
+ def new_typed_interface(attr, type)
83
+ opts = interface_typed_defaults(type).merge(attr.to_h).deep_symbolize_keys
84
+ Fog::Proxmox::Compute::Interface.new(opts)
70
85
  end
71
86
 
72
87
  def new_interface(attr = {})
73
88
  type = attr['type']
74
89
  type ||= 'qemu'
75
- case type
76
- when 'lxc'
77
- new_container_interface(attr)
78
- when 'qemu'
79
- new_server_interface(attr)
80
- end
81
- end
82
-
83
- def new_server_interface(attr = {})
84
- logger.debug('new_server_interface')
85
- opts = interface_server_defaults.merge(attr.to_h).deep_symbolize_keys
86
- Fog::Proxmox::Compute::Interface.new(opts)
87
- end
88
-
89
- def new_container_interface(attr = {})
90
- logger.debug('new_container_interface')
91
- opts = interface_container_defaults.merge(attr.to_h).deep_symbolize_keys
92
- Fog::Proxmox::Compute::Interface.new(opts)
90
+ new_typed_interface(attr, type)
93
91
  end
94
92
 
95
93
  def default_node
@@ -104,74 +102,90 @@ module ForemanFogProxmox
104
102
  default_node.servers.next_id
105
103
  end
106
104
 
107
- def vm_server_instance_defaults
108
- ActiveSupport::HashWithIndifferentAccess.new(
109
- name: "foreman_#{Time.now.to_i}",
110
- vmid: next_vmid,
111
- type: 'qemu',
112
- node_id: default_node_id,
113
- cores: 1,
114
- sockets: 1,
115
- kvm: 1,
116
- vga: 'std',
117
- memory: 512 * MEGA,
118
- ostype: 'l26',
119
- keyboard: 'en-us',
120
- cpu: 'kvm64',
121
- scsihw: 'virtio-scsi-pci',
122
- ide2: 'none,media=cdrom',
123
- templated: 0
124
- ).merge(Fog::Proxmox::DiskHelper.flatten(volume_server_defaults)).merge(Fog::Proxmox::DiskHelper.flatten(volume_container_defaults)).merge(Fog::Proxmox::NicHelper.flatten(interface_defaults))
125
- end
126
-
127
- def vm_container_instance_defaults
128
- ActiveSupport::HashWithIndifferentAccess.new(
129
- name: "foreman_#{Time.now.to_i}",
130
- vmid: next_vmid,
131
- type: 'lxc',
132
- node_id: default_node_id,
133
- memory: 512 * MEGA,
134
- templated: 0
135
- ).merge(Fog::Proxmox::DiskHelper.flatten(volume_container_defaults)).merge(Fog::Proxmox::DiskHelper.flatten(volume_server_defaults)).merge(Fog::Proxmox::NicHelper.flatten(interface_defaults))
105
+ def add_default_typed_interface(type, new_attr)
106
+ interfaces_attributes = []
107
+ interfaces_attributes.push(interface_typed_defaults(type))
108
+ new_attr = new_attr.merge(interfaces_attributes: interfaces_attributes.map.with_index.to_h.invert)
109
+ logger.debug(format(_('add_default_typed_interface(%<type>s) to new_attr=%<new_attr>s'), type: type, new_attr: new_attr))
110
+ new_attr
111
+ end
112
+
113
+ def add_default_typed_volume(new_attr)
114
+ volumes_attributes = []
115
+ volumes_attributes.push(hard_disk_typed_defaults('qemu'))
116
+ volumes_attributes.push(hard_disk_typed_defaults('lxc'))
117
+ new_attr = new_attr.merge(volumes_attributes: volumes_attributes.map.with_index.to_h.invert)
118
+ logger.debug(format(_('add_default_typed_volume(%<type>s) to new_attr=%<new_attr>s'), type: type, new_attr: new_attr))
119
+ new_attr
136
120
  end
137
121
 
138
122
  def vm_instance_defaults
139
- super.merge(vmid: next_vmid, node_id: default_node_id)
123
+ super.merge(vmid: next_vmid, node_id: default_node_id, type: 'qemu')
124
+ end
125
+
126
+ def vm_typed_instance_defaults(type)
127
+ defaults = vm_instance_defaults
128
+ defaults = defaults.merge(config_attributes: config_attributes(type))
129
+ defaults = add_default_typed_volume(defaults)
130
+ defaults = add_default_typed_interface(type, defaults)
131
+ defaults
132
+ end
133
+
134
+ def config_attributes(type = 'qemu')
135
+ case type
136
+ when 'qemu'
137
+ config_attributes = {
138
+ cores: 1,
139
+ sockets: 1,
140
+ kvm: 0,
141
+ vga: 'std',
142
+ memory: 512 * MEGA,
143
+ ostype: 'l26',
144
+ cpu: 'cputype=kvm64',
145
+ scsihw: 'virtio-scsi-pci',
146
+ templated: 0
147
+ }
148
+ config_attributes = config_attributes
149
+ when 'lxc'
150
+ config_attributes = {
151
+ memory: 512 * MEGA,
152
+ templated: 0
153
+ }
154
+ end
155
+ config_attributes
140
156
  end
141
157
 
142
158
  def new_vm(new_attr = {})
143
159
  new_attr = ActiveSupport::HashWithIndifferentAccess.new(new_attr)
144
160
  type = new_attr['type']
145
161
  type ||= 'qemu'
146
- case type
147
- when 'lxc'
148
- vm = new_container_vm(new_attr)
149
- when 'qemu'
150
- vm = new_server_vm(new_attr)
151
- end
152
- logger.debug(format(_('new_vm() vm.config=%<config>s'), config: vm.config.inspect))
162
+ vm = new_typed_vm(new_attr, type)
153
163
  vm
154
164
  end
155
165
 
156
- def new_container_vm(new_attr = {})
157
- options = new_attr
158
- node_id = new_attr['node_id']
159
- node = node_id ? client.nodes.get(node_id) : default_node
160
- options = options.merge(type: 'lxc').merge(vmid: next_vmid)
161
- options = vm_container_instance_defaults.merge(options) if new_attr.empty?
162
- vm = node.containers.new(parse_container_vm(options).deep_symbolize_keys)
163
- logger.debug(format(_('new_container_vm() vm.config=%<config>s'), config: vm.config.inspect))
164
- vm
166
+ def convert_config_attributes(new_attr)
167
+ config_attributes = new_attr[:config_attributes]
168
+ config_attributes[:volumes_attributes] = Hash[config_attributes[:disks].each_with_index.map { |disk, idx| [idx.to_s, disk.attributes] }] if config_attributes.key?(:disks)
169
+ if config_attributes.key?(:interfaces)
170
+ config_attributes[:interfaces_attributes] = Hash[config_attributes[:interfaces].each_with_index.map { |interface, idx| [idx.to_s, interface_compute_attributes(interface.attributes)] }]
171
+ end
172
+ config_attributes.delete_if { |key, _value| ['disks', 'interfaces'].include?(key) }
165
173
  end
166
174
 
167
- def new_server_vm(new_attr = {})
168
- options = new_attr
175
+ def new_typed_vm(new_attr, type)
176
+ convert_config_attributes(new_attr) if new_attr.key?(:config_attributes)
169
177
  node_id = new_attr['node_id']
170
178
  node = node_id ? client.nodes.get(node_id) : default_node
171
- options = options.merge(type: 'qemu').merge(vmid: next_vmid)
172
- options = vm_server_instance_defaults.merge(options) if new_attr.empty?
173
- vm = node.servers.new(parse_server_vm(options).deep_symbolize_keys)
174
- logger.debug(format(_('new_server_vm() vm.config=%<config>s'), config: vm.config.inspect))
179
+ new_attr_type = new_attr['type']
180
+ new_attr_type ||= new_attr['config_attributes']['type'] if new_attr.key?('config_attributes')
181
+ new_attr_type ||= type
182
+ logger.debug(format(_('new_typed_vm(%<type>s): new_attr_type=%<new_attr_type>s'), type: type, new_attr_type: new_attr_type))
183
+ logger.debug(format(_('new_typed_vm(%<type>s): new_attr=%<new_attr>s'), type: type, new_attr: new_attr))
184
+ options = !new_attr.key?('vmid') || ForemanFogProxmox::Value.empty?(new_attr['vmid']) ? new_attr.merge(vm_typed_instance_defaults(type)).merge(type: type) : new_attr
185
+ logger.debug(format(_('new_typed_vm(%<type>s): options=%<options>s'), type: type, options: options))
186
+ vm_h = parse_typed_vm(options, type).deep_symbolize_keys
187
+ logger.debug(format(_('new_typed_vm(%<type>s): vm_h=%<vm_h>s'), type: type, vm_h: vm_h))
188
+ vm = node.send(vm_collection(type)).new(vm_h)
175
189
  vm
176
190
  end
177
191
  end
@@ -30,6 +30,7 @@ module ForemanFogProxmox
30
30
  node = client.nodes.get node_id
31
31
  node ||= default_node
32
32
  storages = node.storages.list_by_content_type type
33
+ logger.debug(format(_('storages(): node_id %<node_id>s type %<type>s'), node_id: node_id, type: type))
33
34
  storages.sort_by(&:storage)
34
35
  end
35
36
 
@@ -62,7 +63,7 @@ module ForemanFogProxmox
62
63
  end
63
64
 
64
65
  def find_vm_in_servers_by_uuid(servers, uuid)
65
- vm = servers.get(uuid) if !uuid.nil? && !uuid.to_s.empty?
66
+ vm = servers.get(uuid) unless ForemanFogProxmox::Value.empty?(uuid)
66
67
  pool_owner(vm) if vm
67
68
  vm
68
69
  rescue Fog::Errors::NotFound
@@ -18,13 +18,17 @@
18
18
  # along with ForemanFogProxmox. If not, see <http://www.gnu.org/licenses/>.
19
19
 
20
20
  require 'fog/proxmox/helpers/disk_helper'
21
+ require 'foreman_fog_proxmox/hash_collection'
21
22
 
22
23
  module ForemanFogProxmox
23
24
  module ProxmoxVolumes
24
25
  include ProxmoxVmHelper
25
26
 
26
- def delete_volume(vm, id)
27
+ def delete_volume(vm, id, volume_attributes)
28
+ logger.info(format(_('vm %<vmid>s delete volume %<volume_id>s'), vmid: vm.identity, volume_id: id))
27
29
  vm.detach(id)
30
+ return unless volume_type?(volume_attributes, 'hard_disk')
31
+
28
32
  device = Fog::Proxmox::DiskHelper.extract_device(id)
29
33
  vm.detach('unused' + device.to_s)
30
34
  end
@@ -36,25 +40,65 @@ module ForemanFogProxmox
36
40
  options
37
41
  end
38
42
 
39
- def update_volume(vm, id, volume_attributes)
40
- disk = vm.config.disks.get(id)
41
- diff_size = volume_attributes['size'].to_i - disk.size
42
- raise ::Foreman::Exception, format(_('Unable to shrink %<id>s size. Proxmox allows only increasing size.'), id: id) unless diff_size >= 0
43
+ def update_volume_required?(old_volume_attributes, new_volume_attributes)
44
+ old_h = ForemanFogProxmox::HashCollection.new_hash_reject_empty_values(old_volume_attributes)
45
+ new_h = ForemanFogProxmox::HashCollection.new_hash_reject_empty_values(new_volume_attributes)
46
+ new_h = ForemanFogProxmox::HashCollection.new_hash_reject_keys(new_h, ['cdrom', 'cloudinit', 'storage_type'])
47
+ !ForemanFogProxmox::HashCollection.equals?(old_h.with_indifferent_access, new_h.with_indifferent_access)
48
+ end
43
49
 
44
- if diff_size > 0
45
- extension = '+' + (diff_size / GIGA).to_s + 'G'
46
- vm.extend(id, extension)
47
- elsif disk.storage != volume_attributes['storage']
48
- vm.move(id, volume_attributes['storage'])
50
+ def update_cdrom(vm, disk, volume_attributes)
51
+ new_disk = { id: disk.id }
52
+ if ['none', 'cdrom'].include?(volume_attributes[:cdrom])
53
+ new_disk[:volid] = volume_attributes[:cdrom]
49
54
  else
50
- options = volume_options(vm, id, volume_attributes)
51
- vm.attach({ :id => disk.id, :volid => disk.volid, :size => disk.size }, options)
55
+ new_disk[:storage] = volume_attributes[:storage]
56
+ new_disk[:volid] = volume_attributes[:volid]
57
+ end
58
+ vm.attach(new_disk, {})
59
+ end
60
+
61
+ def extend_volume(vm, id, diff_size)
62
+ extension = '+' + (diff_size / GIGA).to_s + 'G'
63
+ logger.info(format(_('vm %<vmid>s extend volume %<volume_id>s to %<extension>s'), vmid: vm.identity, volume_id: id, extension: extension))
64
+ vm.extend(id, extension)
65
+ end
66
+
67
+ def move_volume(id, vm, new_storage)
68
+ logger.info(format(_('vm %<vmid>s move volume %<volume_id>s into %<new_storage>s'), vmid: vm.identity, volume_id: id, new_storage: new_storage))
69
+ vm.move(id, new_storage)
70
+ end
71
+
72
+ def update_options(disk, vm, volume_attributes)
73
+ options = volume_options(vm, disk.id, volume_attributes) if volume_type?(volume_attributes, 'hard_disk')
74
+ logger.info(format(_('vm %<vmid>s update volume %<volume_id>s to %<options>s'), vmid: vm.identity, volume_id: disk.id, options: options))
75
+ new_disk = { id: disk.id }
76
+ new_disk[:volid] = disk.volid
77
+ vm.attach(new_disk, options)
78
+ end
79
+
80
+ def update_volume(vm, disk, volume_attributes)
81
+ id = disk.id
82
+ if volume_type?(volume_attributes, 'cdrom')
83
+ update_cdrom(vm, disk, volume_attributes)
84
+ elsif volume_type?(volume_attributes, 'hard_disk')
85
+ diff_size = volume_attributes['size'].to_i - disk.size if volume_attributes['size'] && disk.size
86
+ raise ::Foreman::Exception, format(_('Unable to shrink %<id>s size. Proxmox allows only increasing size.'), id: id) unless diff_size >= 0
87
+
88
+ new_storage = volume_attributes['storage']
89
+
90
+ if diff_size > 0
91
+ extend_volume(vm, id, diff_size)
92
+ elsif disk.storage != new_storage
93
+ move_volume(id, vm, new_storage)
94
+ else
95
+ update_options(disk, vm, volume_attributes)
96
+ end
52
97
  end
53
98
  end
54
99
 
55
- def volume_exists?(volume_attributes)
56
- volid = volume_attributes.key?('volid') ? volume_attributes['volid'] : ''
57
- volid.present?
100
+ def volume_exists?(vm, volume_attributes)
101
+ vm.attributes.key?(volume_attributes['id'])
58
102
  end
59
103
 
60
104
  def volume_to_delete?(volume_attributes)
@@ -63,28 +107,41 @@ module ForemanFogProxmox
63
107
 
64
108
  def extract_id(vm, volume_attributes)
65
109
  id = ''
66
- if volume_exists?(volume_attributes)
110
+ if volume_exists?(vm, volume_attributes)
67
111
  id = volume_attributes['id']
68
112
  else
69
113
  device = vm.container? ? 'mp' : volume_attributes['controller']
70
- id = device + volume_attributes['device']
114
+ id = volume_type?(volume_attributes, 'cdrom') ? 'ide2' : device + volume_attributes['device']
71
115
  end
72
116
  id
73
117
  end
74
118
 
75
119
  def add_volume(vm, id, volume_attributes)
76
- options = volume_options(vm, id, volume_attributes)
77
- disk_attributes = { id: id, storage: volume_attributes['storage'], size: (volume_attributes['size'].to_i / GIGA).to_s }
120
+ disk_attributes = { id: id }
121
+ if volume_type?(volume_attributes, 'hard_disk')
122
+ options = volume_options(vm, id, volume_attributes)
123
+ disk_attributes[:storage] = volume_attributes['storage']
124
+ disk_attributes[:size] = (volume_attributes['size'].to_i / GIGA).to_s
125
+ elsif volume_type?(volume_attributes, 'cdrom')
126
+ disk_attributes[:volid] = volume_attributes[:iso]
127
+ elsif volume_type?(volume_attributes, 'cloud_init')
128
+ disk_attributes[:storage] = volume_attributes['storage']
129
+ disk_attributes[:volid] = "#{volume_attributes['storage']}:cloudinit"
130
+ end
131
+ logger.info(format(_('vm %<vmid>s add volume %<volume_id>s'), vmid: vm.identity, volume_id: id))
132
+ logger.debug(format(_('add_volume(%<vmid>s) disk_attributes=%<disk_attributes>s'), vmid: vm.identity, disk_attributes: disk_attributes))
78
133
  vm.attach(disk_attributes, options)
79
134
  end
80
135
 
81
136
  def save_volume(vm, volume_attributes)
137
+ logger.debug(format(_('save_volume(%<vmid>s) volume_attributes=%<volume_attributes>s'), vmid: vm.identity, volume_attributes: volume_attributes))
82
138
  id = extract_id(vm, volume_attributes)
83
- if volume_exists?(volume_attributes)
139
+ if volume_exists?(vm, volume_attributes)
84
140
  if volume_to_delete?(volume_attributes)
85
- delete_volume(vm, id)
141
+ delete_volume(vm, id, volume_attributes)
86
142
  else
87
- update_volume(vm, id, volume_attributes)
143
+ disk = vm.config.disks.get(id)
144
+ update_volume(vm, disk, volume_attributes) if update_volume_required?(disk.attributes, volume_attributes)
88
145
  end
89
146
  else
90
147
  add_volume(vm, id, volume_attributes)
@@ -17,13 +17,26 @@ along with ForemanFogProxmox. If not, see <http://www.gnu.org/licenses/>. %>
17
17
 
18
18
  <%= javascript_include_tag 'foreman_fog_proxmox/proxmox_compute_resource', "data-turbolinks-track" => true %>
19
19
 
20
- <% nodes = f.object.nodes rescue nil %>
21
- <% token_expired = f.object.token_expired? %>
22
- <% token_deadline = f.object.token_deadline %>
23
- <%= checkbox_f f, :renew, :label => _("Renew expired token ?"), :checked_value => '1', :label_help => _("Token expires on #{token_deadline}") %>
24
- <%= text_f f, :url, :help_block => _("e.g. https://127.0.0.1:8006/api2/json"), :help_inline_permanent => load_button_f(f, !!nodes, _("Test failed")) %>
25
- <%= text_f f, :user , :help_block => _("e.g. root@pam") %>
26
- <%= password_f f, :password, :keep_value => true, :unset => unset_password? %>
27
- <%= checkbox_f f, :ssl_verify_peer, :label => _("SSL verify peer"), :checked_value => '1', :onchange => "sslVerifyPeerSelected()" %>
28
- <%= textarea_f f, :ssl_certs, :label => _("X509 Certification Authorities"), :size => "col-md-4",
29
- :placeholder => _("Optionally provide a CA, or a correctly ordered CA chain. If left blank, disable ssl_verify_peer.") %>
20
+ <% user_token = f.object.auth_method == 'user_token' %>
21
+ <% access_ticket = f.object.auth_method == 'access_ticket' %>
22
+ <% ssl_verify_peer = f.object.ssl_verify_peer == '1' %>
23
+ <%= select_f f, :auth_method, proxmox_auth_methods_map, :id, :name, { }, :label_help => _("Click Test connection button before changing it"), :label => _('Authentication method'), :label_size => "col-md-2", :required => true, :onchange => 'authMethodSelected();' %>
24
+ <%= field_set_tag _("Common fields"), :id => "compute_ressource_common_field_set" do %>
25
+ <%= text_f f, :url, :help_block => _("e.g. https://127.0.0.1:8006/api2/json") %>
26
+ <%= text_f f, :user , :help_block => _("e.g. root@pam") %>
27
+ <% end %>
28
+ <%= field_set_tag _("User token fields"), :id => "compute_ressource_user_token_field_set", :class => ('hide' unless user_token), :disabled => !user_token do %>
29
+ <%= text_f f, :token_id, :label => _('User token id'), :required => user_token %>
30
+ <%= text_f f, :token, :label => _('User token value'), :required => user_token, :label_help => _("Click Test connection button to check token") %>
31
+ <% end %>
32
+ <%= field_set_tag _("Access ticket fields"), :id => "compute_ressource_access_ticket_field_set", :class => ('hide' unless access_ticket), :disabled => !access_ticket do %>
33
+ <%= password_f f, :password, :keep_value => true, :unset => unset_password?, :required => access_ticket %>
34
+ <% end %>
35
+ <%= field_set_tag _("SSL fields"), :id => "compute_ressource_ssl_field_set" do %>
36
+ <%= checkbox_f f, :ssl_verify_peer, :label => _("SSL verify peer"), :label_help => _("Click Test connection button before changing it"), :checked_value => '1', :onchange => 'sslVerifyPeerSelected();' %>
37
+ <%= textarea_f f, :ssl_certs, :label => _("X509 Certification Authorities"), :size => "col-md-4",
38
+ :placeholder => _("Optionally provide a CA, or a correctly ordered CA chain. If left blank, disable ssl_verify_peer.") %>
39
+ <% end %>
40
+ <div class="col-md-offset-2">
41
+ <%= test_connection_button_f(f, (f.object.nodes rescue false)) %>
42
+ </div>