foreman_fog_proxmox 0.23.1 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/helpers/proxmox_vm_attrs_helper.rb +1 -1
- data/app/helpers/proxmox_vm_cdrom_helper.rb +9 -2
- data/app/helpers/proxmox_vm_cloudinit_helper.rb +8 -2
- data/app/helpers/proxmox_vm_volumes_helper.rb +14 -0
- data/app/models/concerns/orchestration/proxmox/compute.rb +8 -1
- data/app/models/foreman_fog_proxmox/proxmox_compute_attributes.rb +8 -1
- data/app/models/foreman_fog_proxmox/proxmox_vm_commands.rb +13 -5
- data/app/models/foreman_fog_proxmox/proxmox_vm_new.rb +11 -0
- data/app/models/foreman_fog_proxmox/proxmox_volumes.rb +16 -7
- data/app/views/compute_resources/show/_proxmox.html.erb +4 -0
- data/app/views/compute_resources_vms/form/proxmox/_base.html.erb +1 -0
- data/lib/foreman_fog_proxmox/engine.rb +15 -10
- data/lib/foreman_fog_proxmox/version.rb +1 -1
- data/test/unit/foreman_fog_proxmox/helpers/proxmox_server_helper_test.rb +10 -0
- data/test/unit/foreman_fog_proxmox/proxmox_compute_attributes_test.rb +7 -0
- data/test/unit/foreman_fog_proxmox/proxmox_orchestration_compute_test.rb +34 -0
- data/test/unit/foreman_fog_proxmox/proxmox_vm_commands_server_create_test.rb +41 -7
- data/test/unit/foreman_fog_proxmox/proxmox_vm_commands_server_update_cdrom_test.rb +51 -1
- data/test/unit/foreman_fog_proxmox/proxmox_vm_commands_test.rb +25 -0
- data/test/unit/foreman_fog_proxmox/proxmox_vm_new_test.rb +46 -0
- data/webpack/components/ProxmoxServer/ProxmoxServerStorage.js +32 -11
- data/webpack/components/ProxmoxServer/components/CDRom.js +49 -9
- data/webpack/components/ProxmoxStoragesUtils.js +6 -2
- data/webpack/components/ProxmoxVmType.js +4 -0
- data/webpack/global_test_setup.js +2 -1
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 329a340fdfd2b5e117a05a227477e29108df61d303a5ce5a5a2dc148ae41ec7c
|
|
4
|
+
data.tar.gz: '08b9aa3dca59fb2b7a80c2f1e6b0b59c9931f0d974e8d9849a720d6d37a819be'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '094a19a8592b2ed3ad7a88c637c7859f3bbc631a4f08f2fb781ec21a8b9620789fb701dbab917973ee122fb2ead5a44d6af12a28fe6dd2d99dad2267c8d051a7'
|
|
7
|
+
data.tar.gz: ce956eaac9a5faf92f2decd8721910dd72fd9a0e7f0ccfbeab40462c1cfc7892897235e7d2fef925405abf993b85f902edac0f4afcb1ec685649d27df0e61168
|
|
@@ -76,7 +76,7 @@ module ProxmoxVMAttrsHelper
|
|
|
76
76
|
keys = ['id', 'volid', 'storage_type', 'storage', 'controller', 'device', 'cache', 'size', '_delete', 'backup']
|
|
77
77
|
type = 'hard_disk'
|
|
78
78
|
elsif vol.cdrom?
|
|
79
|
-
keys = ['id', 'storage_type', 'cdrom', 'storage', 'volid']
|
|
79
|
+
keys = ['id', 'storage_type', 'cdrom', 'storage', 'volid', '_delete']
|
|
80
80
|
type = 'cdrom'
|
|
81
81
|
elsif vol.cloud_init?
|
|
82
82
|
keys = ['id', 'volid', 'storage_type', 'storage', 'controller', 'device']
|
|
@@ -26,8 +26,15 @@ require 'foreman_fog_proxmox/hash_collection'
|
|
|
26
26
|
module ProxmoxVMCdromHelper
|
|
27
27
|
def parse_server_cdrom(args)
|
|
28
28
|
cdrom_media = args['cdrom'] if args.key?('cdrom')
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
return {} unless cdrom_media
|
|
30
|
+
cdrom_image = args['volid'] if args.key?('volid') && cdrom_media == 'image'
|
|
31
|
+
volid = if cdrom_image.present?
|
|
32
|
+
cdrom_image
|
|
33
|
+
elsif cdrom_media == 'none'
|
|
34
|
+
'none'
|
|
35
|
+
elsif ['physical', 'cdrom'].include?(cdrom_media)
|
|
36
|
+
'cdrom'
|
|
37
|
+
end
|
|
31
38
|
return {} unless volid
|
|
32
39
|
|
|
33
40
|
{ id: 'ide2', volid: volid, media: 'cdrom' }
|
|
@@ -111,8 +111,14 @@ module ProxmoxVMCloudinitHelper
|
|
|
111
111
|
end
|
|
112
112
|
|
|
113
113
|
def attach_cloudinit_iso(node, iso)
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
volume = nil
|
|
115
|
+
storages(node, 'iso').each do |storage|
|
|
116
|
+
volume = storage.volumes.detect { |v| v.volid.include? File.basename(iso) }
|
|
117
|
+
break if volume
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
raise ::Foreman::Exception, "Could not find generated cloud-init ISO #{File.basename(iso)} on any ISO storage for node #{node}" unless volume
|
|
121
|
+
|
|
116
122
|
{ ide2: "#{volume.volid},media=cdrom" }
|
|
117
123
|
end
|
|
118
124
|
|
|
@@ -86,15 +86,29 @@ module ProxmoxVMVolumesHelper
|
|
|
86
86
|
if args.key?('storage_type')
|
|
87
87
|
args['storage_type'] == type
|
|
88
88
|
else
|
|
89
|
+
return true if type == 'cdrom' && args.key?('cdrom')
|
|
90
|
+
|
|
89
91
|
Fog::Proxmox::DiskHelper.cloud_init?(args['volid']) if type == 'cloud_init'
|
|
90
92
|
Fog::Proxmox::DiskHelper.cdrom?(args['volid']) if type == 'cdrom'
|
|
91
93
|
Fog::Proxmox::DiskHelper.disk?(args['id']) if ['hard_disk', 'rootfs', 'mp'].include?(type)
|
|
92
94
|
end
|
|
93
95
|
end
|
|
94
96
|
|
|
97
|
+
def validate_cdrom_image_permission!(volume_attributes)
|
|
98
|
+
volume_attributes = volume_attributes.with_indifferent_access
|
|
99
|
+
|
|
100
|
+
return unless volume_type?(volume_attributes, 'cdrom')
|
|
101
|
+
return unless volume_attributes[:cdrom].to_s == 'image'
|
|
102
|
+
return if User.current&.can?(:attach_cdrom_image, self)
|
|
103
|
+
|
|
104
|
+
raise ::Foreman::Exception,
|
|
105
|
+
_('You are not authorized to attach or change CD-ROM ISO images.')
|
|
106
|
+
end
|
|
107
|
+
|
|
95
108
|
def parse_typed_volume(args, type)
|
|
96
109
|
return if Foreman::Cast.to_bool(args['_delete'])
|
|
97
110
|
logger.debug("parse_typed_volume(#{type}): args=#{args}")
|
|
111
|
+
validate_cdrom_image_permission!(args)
|
|
98
112
|
disk = parse_hard_disk_volume(args) if volume_type?(args,
|
|
99
113
|
'hard_disk') || volume_type?(args, 'mp') || volume_type?(args, 'rootfs')
|
|
100
114
|
disk = parse_server_cloudinit(args) if volume_type?(args, 'cloud_init')
|
|
@@ -63,7 +63,14 @@ module Orchestration
|
|
|
63
63
|
|
|
64
64
|
def computeValue(foreman_attr, fog_attr)
|
|
65
65
|
value = ''
|
|
66
|
-
|
|
66
|
+
|
|
67
|
+
if foreman_attr == :uuid
|
|
68
|
+
vm_value = vm.send(fog_attr).to_s
|
|
69
|
+
return vm_value if vm_value.match?(/\A\d+_\d+\z/)
|
|
70
|
+
|
|
71
|
+
value += compute_resource.id.to_s + '_'
|
|
72
|
+
end
|
|
73
|
+
|
|
67
74
|
value += vm.send(fog_attr).to_s
|
|
68
75
|
value
|
|
69
76
|
end
|
|
@@ -64,8 +64,15 @@ module ForemanFogProxmox
|
|
|
64
64
|
vm_attrs
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
+
def cdrom_compute_attributes(attrs)
|
|
68
|
+
return unless attrs[:storage_type].to_s == 'cdrom' || attrs[:media].to_s == 'cdrom'
|
|
69
|
+
|
|
70
|
+
{ cdrom: attrs[:volid].to_s }
|
|
71
|
+
end
|
|
72
|
+
|
|
67
73
|
def volume_compute_attributes(volume_attributes)
|
|
68
|
-
volume_attributes.merge(_delete: '0')
|
|
74
|
+
attrs = volume_attributes.merge(_delete: '0')
|
|
75
|
+
cdrom_compute_attributes(attrs) || attrs
|
|
69
76
|
end
|
|
70
77
|
|
|
71
78
|
def vm_compute_attributes(vm)
|
|
@@ -36,8 +36,6 @@ module ForemanFogProxmox
|
|
|
36
36
|
type = args[:type]
|
|
37
37
|
node = client.nodes.get(args[:node_id])
|
|
38
38
|
vmid = args[:vmid] = assign_vmid(args[:vmid].to_i, node)
|
|
39
|
-
raise ::Foreman::Exception, format(N_('invalid vmid=%<vmid>s'), vmid: vmid) unless node.servers.id_valid?(vmid)
|
|
40
|
-
|
|
41
39
|
image_id = args[:image_id]
|
|
42
40
|
remove_volume_keys(args)
|
|
43
41
|
if image_id
|
|
@@ -55,8 +53,15 @@ module ForemanFogProxmox
|
|
|
55
53
|
raise e
|
|
56
54
|
end
|
|
57
55
|
|
|
58
|
-
def assign_vmid(vmid, node)
|
|
59
|
-
|
|
56
|
+
def assign_vmid(vmid, node, log: true)
|
|
57
|
+
vmid = node.servers.next_id if vmid < 1
|
|
58
|
+
|
|
59
|
+
unless node.servers.id_valid?(vmid)
|
|
60
|
+
logger.warn("Requested VMID #{vmid} is occupied or out of range, requesting a new VMID") if log
|
|
61
|
+
vmid = node.servers.next_id
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
vmid
|
|
60
65
|
end
|
|
61
66
|
|
|
62
67
|
def compute_clone_attributes(args, container, type)
|
|
@@ -113,7 +118,10 @@ module ForemanFogProxmox
|
|
|
113
118
|
|
|
114
119
|
volumes_attributes = new_attributes['volumes_attributes']
|
|
115
120
|
logger.debug("save_vm(#{uuid}) volumes_attributes=#{volumes_attributes}")
|
|
116
|
-
volumes_attributes&.each_value
|
|
121
|
+
volumes_attributes&.each_value do |volume_attributes|
|
|
122
|
+
validate_cdrom_image_permission!(volume_attributes)
|
|
123
|
+
save_volume(vm, volume_attributes)
|
|
124
|
+
end
|
|
117
125
|
|
|
118
126
|
efidisk_attributes = new_attributes['efidisk_attributes']
|
|
119
127
|
if vm.config.efidisk.present? && efidisk_attributes.empty?
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# rubocop:disable Metrics/ModuleLength
|
|
4
|
+
|
|
3
5
|
# Copyright 2019 Tristan Robert
|
|
4
6
|
|
|
5
7
|
# This file is part of ForemanFogProxmox.
|
|
@@ -182,10 +184,17 @@ module ForemanFogProxmox
|
|
|
182
184
|
config_attributes.delete_if { |key, _value| ['disks', 'interfaces'].include?(key) }
|
|
183
185
|
end
|
|
184
186
|
|
|
187
|
+
def assign_available_vmid(new_attr, node)
|
|
188
|
+
return if new_attr['vmid'].blank? || new_attr['node_id'].blank?
|
|
189
|
+
|
|
190
|
+
new_attr['vmid'] = assign_vmid(new_attr['vmid'].to_i, node, log: false)
|
|
191
|
+
end
|
|
192
|
+
|
|
185
193
|
def new_typed_vm(new_attr, type)
|
|
186
194
|
convert_config_attributes(new_attr) if new_attr.key?(:config_attributes)
|
|
187
195
|
node_id = new_attr['node_id']
|
|
188
196
|
node = node_id ? client.nodes.get(node_id) : default_node
|
|
197
|
+
assign_available_vmid(new_attr, node)
|
|
189
198
|
new_attr_type = new_attr['type']
|
|
190
199
|
new_attr_type ||= new_attr['config_attributes']['type'] if new_attr.key?('config_attributes')
|
|
191
200
|
new_attr_type ||= type
|
|
@@ -201,3 +210,5 @@ module ForemanFogProxmox
|
|
|
201
210
|
end
|
|
202
211
|
end
|
|
203
212
|
end
|
|
213
|
+
|
|
214
|
+
# rubocop:enable Metrics/ModuleLength
|
|
@@ -47,7 +47,7 @@ module ForemanFogProxmox
|
|
|
47
47
|
def update_volume_required?(old_volume_attributes, new_volume_attributes)
|
|
48
48
|
old_h = ForemanFogProxmox::HashCollection.new_hash_reject_empty_values(old_volume_attributes)
|
|
49
49
|
new_h = ForemanFogProxmox::HashCollection.new_hash_reject_empty_values(new_volume_attributes)
|
|
50
|
-
new_h = ForemanFogProxmox::HashCollection.new_hash_reject_keys(new_h, ['
|
|
50
|
+
new_h = ForemanFogProxmox::HashCollection.new_hash_reject_keys(new_h, ['cloudinit', 'storage_type'])
|
|
51
51
|
!ForemanFogProxmox::HashCollection.equals?(old_h.with_indifferent_access, new_h.with_indifferent_access)
|
|
52
52
|
end
|
|
53
53
|
|
|
@@ -112,6 +112,8 @@ module ForemanFogProxmox
|
|
|
112
112
|
end
|
|
113
113
|
|
|
114
114
|
def volume_exists?(vm, volume_attributes)
|
|
115
|
+
return vm.config.disks.get('ide2').present? if volume_type?(volume_attributes, 'cdrom')
|
|
116
|
+
|
|
115
117
|
disk = vm.config.disks.get(volume_attributes['id'])
|
|
116
118
|
return false unless disk
|
|
117
119
|
|
|
@@ -128,14 +130,14 @@ module ForemanFogProxmox
|
|
|
128
130
|
end
|
|
129
131
|
|
|
130
132
|
def extract_id(vm, volume_attributes)
|
|
131
|
-
|
|
133
|
+
return 'ide2' if volume_type?(volume_attributes, 'cdrom')
|
|
134
|
+
|
|
132
135
|
if volume_exists?(vm, volume_attributes)
|
|
133
|
-
|
|
136
|
+
volume_attributes['id']
|
|
134
137
|
else
|
|
135
138
|
device = vm.container? ? 'mp' : volume_attributes['controller']
|
|
136
|
-
|
|
139
|
+
device + volume_attributes['device']
|
|
137
140
|
end
|
|
138
|
-
id
|
|
139
141
|
end
|
|
140
142
|
|
|
141
143
|
def add_volume(vm, id, volume_attributes)
|
|
@@ -145,7 +147,10 @@ module ForemanFogProxmox
|
|
|
145
147
|
disk_attributes[:storage] = volume_attributes['storage']
|
|
146
148
|
disk_attributes[:size] = volume_attributes['size']
|
|
147
149
|
elsif volume_type?(volume_attributes, 'cdrom')
|
|
148
|
-
|
|
150
|
+
cdrom_attributes = parse_server_cdrom(volume_attributes)
|
|
151
|
+
return if cdrom_attributes.empty?
|
|
152
|
+
|
|
153
|
+
disk_attributes.merge!(cdrom_attributes)
|
|
149
154
|
elsif volume_type?(volume_attributes, 'cloud_init')
|
|
150
155
|
disk_attributes[:storage] = volume_attributes['storage']
|
|
151
156
|
disk_attributes[:volid] = "#{volume_attributes['storage']}:cloudinit"
|
|
@@ -164,7 +169,11 @@ module ForemanFogProxmox
|
|
|
164
169
|
else
|
|
165
170
|
disk = vm.config.disks.get(id)
|
|
166
171
|
normalized_volume_attributes = normalize_existing_volume_attributes(disk, volume_attributes)
|
|
167
|
-
|
|
172
|
+
if volume_type?(volume_attributes, 'cdrom')
|
|
173
|
+
update_volume(vm, disk, normalized_volume_attributes)
|
|
174
|
+
elsif update_volume_required?(disk.attributes, normalized_volume_attributes)
|
|
175
|
+
update_volume(vm, disk, normalized_volume_attributes)
|
|
176
|
+
end
|
|
168
177
|
end
|
|
169
178
|
else
|
|
170
179
|
add_volume(vm, id, volume_attributes)
|
|
@@ -19,6 +19,10 @@ along with ForemanFogProxmox. If not, see <http://www.gnu.org/licenses/>. %>
|
|
|
19
19
|
<td><%= _("URL") %></td>
|
|
20
20
|
<td><%= @compute_resource.url %></td>
|
|
21
21
|
</tr>
|
|
22
|
+
<tr>
|
|
23
|
+
<td><%= _("Username") %></td>
|
|
24
|
+
<td><%= @compute_resource.user %></td>
|
|
25
|
+
</tr>
|
|
22
26
|
<tr>
|
|
23
27
|
<td><%= _("Version") %></td>
|
|
24
28
|
<td><%= @compute_resource.version %></td>
|
|
@@ -44,6 +44,7 @@ along with ForemanFogProxmox. If not, see <http://www.gnu.org/licenses/>. %>
|
|
|
44
44
|
props = {
|
|
45
45
|
vmAttrs: vm_attrs,
|
|
46
46
|
computeResourceId: compute_resource.id,
|
|
47
|
+
canAttachCdromImage: User.current.can?(:attach_cdrom_image, compute_resource),
|
|
47
48
|
propsLoaded: false,
|
|
48
49
|
fromProfile: from_profile,
|
|
49
50
|
newVm: new_vm,
|
|
@@ -43,17 +43,22 @@ module ForemanFogProxmox
|
|
|
43
43
|
parameter_filter(ComputeResource, :uuid)
|
|
44
44
|
# add dashboard widget
|
|
45
45
|
widget 'foreman_fog_proxmox_widget', name: N_('Foreman Fog Proxmox widget'), sizex: 8, sizey: 1
|
|
46
|
+
|
|
47
|
+
p = Foreman::AccessControl.permission(:view_compute_resources)
|
|
48
|
+
p.actions.concat(%w[foreman_fog_proxmox/compute_resources/ostemplates_by_id_and_node_and_storage
|
|
49
|
+
foreman_fog_proxmox/compute_resources/isos_by_id_and_node_and_storage
|
|
50
|
+
foreman_fog_proxmox/compute_resources/ostemplates_by_id_and_node
|
|
51
|
+
foreman_fog_proxmox/compute_resources/isos_by_id_and_node
|
|
52
|
+
foreman_fog_proxmox/compute_resources/storages_by_id_and_node
|
|
53
|
+
foreman_fog_proxmox/compute_resources/iso_storages_by_id_and_node
|
|
54
|
+
foreman_fog_proxmox/compute_resources/bridges_by_id_and_node
|
|
55
|
+
foreman_fog_proxmox/compute_resources/volumes_by_node_and_storage
|
|
56
|
+
foreman_fog_proxmox/compute_resources/metadata])
|
|
57
|
+
p.actions.uniq!
|
|
58
|
+
|
|
46
59
|
security_block :foreman_fog_proxmox do
|
|
47
|
-
permission :
|
|
48
|
-
|
|
49
|
-
:isos_by_id_and_node_and_storage,
|
|
50
|
-
:ostemplates_by_id_and_node,
|
|
51
|
-
:isos_by_id_and_node,
|
|
52
|
-
:storages_by_id_and_node,
|
|
53
|
-
:iso_storages_by_id_and_node,
|
|
54
|
-
:bridges_by_id_and_node,
|
|
55
|
-
:volumes_by_node_and_storage,
|
|
56
|
-
:metadata] }
|
|
60
|
+
permission :attach_cdrom_image, {},
|
|
61
|
+
:resource_type => 'ComputeResource'
|
|
57
62
|
end
|
|
58
63
|
end
|
|
59
64
|
end
|
|
@@ -107,6 +107,16 @@ module ForemanFogProxmox
|
|
|
107
107
|
assert_equal 'cdrom', cdrom[:media]
|
|
108
108
|
end
|
|
109
109
|
|
|
110
|
+
test '#cdrom physical' do
|
|
111
|
+
cdrom = parse_server_cdrom('cdrom' => 'physical')
|
|
112
|
+
assert cdrom.key?(:id)
|
|
113
|
+
assert_equal 'ide2', cdrom[:id]
|
|
114
|
+
assert cdrom.key?(:volid)
|
|
115
|
+
assert_equal 'cdrom', cdrom[:volid]
|
|
116
|
+
assert cdrom.key?(:media)
|
|
117
|
+
assert_equal 'cdrom', cdrom[:media]
|
|
118
|
+
end
|
|
119
|
+
|
|
110
120
|
test '#vm' do
|
|
111
121
|
expected_vm = ActiveSupport::HashWithIndifferentAccess.new(
|
|
112
122
|
{
|
|
@@ -150,6 +150,13 @@ module ForemanFogProxmox
|
|
|
150
150
|
assert_not vm_attrs[:compute_attributes].key?(:macaddr)
|
|
151
151
|
end
|
|
152
152
|
|
|
153
|
+
it 'normalizes cdrom volume attributes to form shape' do
|
|
154
|
+
assert_equal({ cdrom: 'none' }, @cr.volume_compute_attributes({ storage_type: 'cdrom', volid: 'none', media: 'cdrom' }))
|
|
155
|
+
assert_equal({ cdrom: 'cdrom' }, @cr.volume_compute_attributes({ storage_type: 'cdrom', volid: 'cdrom', media: 'cdrom' }))
|
|
156
|
+
assert_equal({ cdrom: 'local-lvm:iso/debian-netinst.iso' },
|
|
157
|
+
@cr.volume_compute_attributes({ storage_type: 'cdrom', volid: 'local-lvm:iso/debian-netinst.iso', media: 'cdrom' }))
|
|
158
|
+
end
|
|
159
|
+
|
|
153
160
|
it 'converts a server to hash' do
|
|
154
161
|
vm, config_attributes, volume_attributes, interface_attributes = mock_server_vm
|
|
155
162
|
vm_attrs = @cr.vm_compute_attributes(vm)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'test_plugin_helper'
|
|
4
|
+
|
|
5
|
+
module ForemanFogProxmox
|
|
6
|
+
class ProxmoxOrchestrationComputeTest < ActiveSupport::TestCase
|
|
7
|
+
class ComputeValueHost
|
|
8
|
+
include Orchestration::Proxmox::Compute
|
|
9
|
+
|
|
10
|
+
attr_accessor :compute_resource, :vm
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
test '#computeValue prefixes raw vmid for uuid' do
|
|
14
|
+
host = host_with_vm_value('113')
|
|
15
|
+
|
|
16
|
+
assert_equal '4_113', host.computeValue(:uuid, :foreman_uuid)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
test '#computeValue does not prefix existing proxmox uuid' do
|
|
20
|
+
host = host_with_vm_value('4_113')
|
|
21
|
+
|
|
22
|
+
assert_equal '4_113', host.computeValue(:uuid, :foreman_uuid)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def host_with_vm_value(value)
|
|
28
|
+
host = ComputeValueHost.new
|
|
29
|
+
host.compute_resource = OpenStruct.new(id: 4)
|
|
30
|
+
host.vm = OpenStruct.new(foreman_uuid: value)
|
|
31
|
+
host
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -31,15 +31,18 @@ module ForemanFogProxmox
|
|
|
31
31
|
include ProxmoxVMHelper
|
|
32
32
|
|
|
33
33
|
describe 'create_vm' do
|
|
34
|
-
it '
|
|
35
|
-
args = { vmid: '100' }
|
|
34
|
+
it 'uses next vmid when requested vmid is occupied or out of range' do
|
|
35
|
+
args = { vmid: '100', type: 'qemu', node_id: 'proxmox', start_after_create: '0' }
|
|
36
36
|
servers = mock('servers')
|
|
37
|
-
servers.
|
|
37
|
+
servers.expects(:id_valid?).with(100).returns(false)
|
|
38
|
+
servers.expects(:next_id).returns('101')
|
|
38
39
|
cr = mock_node_servers(ForemanFogProxmox::Proxmox.new, servers)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
cr.stubs(:parse_typed_vm).with(args, 'qemu').returns(args)
|
|
41
|
+
vm = mock('vm')
|
|
42
|
+
servers.expects(:create).with(args).returns(vm)
|
|
43
|
+
cr.create_vm(args)
|
|
44
|
+
|
|
45
|
+
assert_equal '101', args[:vmid]
|
|
43
46
|
end
|
|
44
47
|
|
|
45
48
|
it 'computes next vmid when vmid == 0 and creates server' do
|
|
@@ -107,6 +110,37 @@ module ForemanFogProxmox
|
|
|
107
110
|
vm.expects(:update).with(expected_args)
|
|
108
111
|
cr.create_vm(args)
|
|
109
112
|
end
|
|
113
|
+
|
|
114
|
+
it 'attaches generated cloud-init ISO from a later ISO storage' do
|
|
115
|
+
cr = ForemanFogProxmox::Proxmox.new
|
|
116
|
+
first_storage = mock('first_storage')
|
|
117
|
+
second_storage = mock('second_storage')
|
|
118
|
+
volume = mock('volume')
|
|
119
|
+
|
|
120
|
+
first_storage.stubs(:volumes).returns([])
|
|
121
|
+
volume.stubs(:volid).returns('local:iso/name_cloudinit.iso')
|
|
122
|
+
second_storage.stubs(:volumes).returns([volume])
|
|
123
|
+
cr.stubs(:storages).with('proxmox', 'iso').returns([first_storage, second_storage])
|
|
124
|
+
|
|
125
|
+
assert_equal({ ide2: 'local:iso/name_cloudinit.iso,media=cdrom' },
|
|
126
|
+
cr.attach_cloudinit_iso('proxmox', '/var/lib/vz/template/iso/name_cloudinit.iso'))
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it 'raises Foreman::Exception when generated cloud-init ISO is not on any ISO storage' do
|
|
130
|
+
cr = ForemanFogProxmox::Proxmox.new
|
|
131
|
+
storage = mock('storage')
|
|
132
|
+
other_volume = mock('other_volume')
|
|
133
|
+
|
|
134
|
+
other_volume.stubs(:volid).returns('local:iso/other.iso')
|
|
135
|
+
storage.stubs(:volumes).returns([other_volume])
|
|
136
|
+
cr.stubs(:storages).with('proxmox', 'iso').returns([storage])
|
|
137
|
+
|
|
138
|
+
err = assert_raises Foreman::Exception do
|
|
139
|
+
cr.attach_cloudinit_iso('proxmox', '/var/lib/vz/template/iso/name_cloudinit.iso')
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
assert err.message.end_with?('Could not find generated cloud-init ISO name_cloudinit.iso on any ISO storage for node proxmox')
|
|
143
|
+
end
|
|
110
144
|
end
|
|
111
145
|
end
|
|
112
146
|
end
|
|
@@ -35,7 +35,8 @@ module ForemanFogProxmox
|
|
|
35
35
|
@cr = FactoryBot.build_stubbed(:proxmox_cr)
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
-
it 'saves modified server config with added cdrom' do
|
|
38
|
+
it 'saves modified server config with added cdrom image when user has permission' do
|
|
39
|
+
User.current = users(:admin)
|
|
39
40
|
uuid = '100'
|
|
40
41
|
config = mock('config')
|
|
41
42
|
disks = mock('disks')
|
|
@@ -58,6 +59,7 @@ module ForemanFogProxmox
|
|
|
58
59
|
vm.stubs(:type).returns('qemu')
|
|
59
60
|
vm.stubs(:node_id).returns('proxmox')
|
|
60
61
|
@cr.stubs(:find_vm_by_uuid).returns(vm)
|
|
62
|
+
User.current.stubs(:can?).with(:attach_cdrom_image, @cr).returns(true)
|
|
61
63
|
new_attributes = {
|
|
62
64
|
'templated' => '0',
|
|
63
65
|
'node_id' => 'proxmox',
|
|
@@ -88,6 +90,54 @@ module ForemanFogProxmox
|
|
|
88
90
|
@cr.save_vm(uuid, new_attributes)
|
|
89
91
|
end
|
|
90
92
|
|
|
93
|
+
it 'rejects added cdrom image when user has no permission' do
|
|
94
|
+
User.current = users(:admin)
|
|
95
|
+
uuid = '100'
|
|
96
|
+
config = mock('config')
|
|
97
|
+
disks = mock('disks')
|
|
98
|
+
disks.stubs(:get).returns
|
|
99
|
+
config.stubs(:disks).returns(disks)
|
|
100
|
+
config.stubs(:efidisk).returns(nil)
|
|
101
|
+
config.stubs(:attributes).returns(:cores => '')
|
|
102
|
+
vm = mock('vm')
|
|
103
|
+
vm.stubs(:identity).returns(uuid)
|
|
104
|
+
vm.stubs(:attributes).returns('' => '')
|
|
105
|
+
vm.stubs(:config).returns(config)
|
|
106
|
+
vm.stubs(:container?).returns(false)
|
|
107
|
+
vm.stubs(:type).returns('qemu')
|
|
108
|
+
vm.stubs(:node_id).returns('proxmox')
|
|
109
|
+
@cr.stubs(:find_vm_by_uuid).returns(vm)
|
|
110
|
+
User.current.stubs(:can?).with(:attach_cdrom_image, @cr).returns(false)
|
|
111
|
+
new_attributes = {
|
|
112
|
+
'templated' => '0',
|
|
113
|
+
'node_id' => 'proxmox',
|
|
114
|
+
'config_attributes' => {
|
|
115
|
+
'cores' => '1',
|
|
116
|
+
'cpulimit' => '1',
|
|
117
|
+
},
|
|
118
|
+
'volumes_attributes' => {
|
|
119
|
+
'0' => {
|
|
120
|
+
'id' => 'ide2',
|
|
121
|
+
'_delete' => '',
|
|
122
|
+
'device' => '2',
|
|
123
|
+
'controller' => 'ide',
|
|
124
|
+
'storage_type' => 'cdrom',
|
|
125
|
+
'storage' => 'local-lvm',
|
|
126
|
+
'cdrom' => 'image',
|
|
127
|
+
'volid' => 'local-lvm:iso/ubuntu-20_4.iso',
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
}.with_indifferent_access
|
|
131
|
+
@cr.stubs(:parse_server_vm).returns('vmid' => '100', 'node_id' => 'proxmox', 'type' => 'qemu', 'cores' => '1',
|
|
132
|
+
'cpulimit' => '1', 'onboot' => '0')
|
|
133
|
+
vm.expects(:attach).never
|
|
134
|
+
vm.expects(:update).never
|
|
135
|
+
|
|
136
|
+
assert_raises(::Foreman::Exception) do
|
|
137
|
+
@cr.save_vm(uuid, new_attributes)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
91
141
|
it 'saves modified server config with removed cdrom' do
|
|
92
142
|
uuid = '100'
|
|
93
143
|
config = mock('config')
|
|
@@ -39,5 +39,30 @@ module ForemanFogProxmox
|
|
|
39
39
|
assert cr.destroy_vm('abc')
|
|
40
40
|
end
|
|
41
41
|
end
|
|
42
|
+
|
|
43
|
+
describe 'assign_vmid' do
|
|
44
|
+
it 'uses next vmid when requested vmid is already occupied' do
|
|
45
|
+
cr = ForemanFogProxmox::Proxmox.new
|
|
46
|
+
servers = mock('servers')
|
|
47
|
+
node = mock('node')
|
|
48
|
+
node.stubs(:servers).returns(servers)
|
|
49
|
+
servers.expects(:id_valid?).with(100).returns(false)
|
|
50
|
+
servers.expects(:next_id).returns('101')
|
|
51
|
+
|
|
52
|
+
assert_equal '101', cr.assign_vmid(100, node)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it 'does not log when logging is disabled' do
|
|
56
|
+
cr = ForemanFogProxmox::Proxmox.new
|
|
57
|
+
servers = mock('servers')
|
|
58
|
+
node = mock('node')
|
|
59
|
+
node.stubs(:servers).returns(servers)
|
|
60
|
+
servers.expects(:id_valid?).with(100).returns(false)
|
|
61
|
+
servers.expects(:next_id).returns('101')
|
|
62
|
+
cr.logger.expects(:warn).never
|
|
63
|
+
|
|
64
|
+
assert_equal '101', cr.assign_vmid(100, node, log: false)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
42
67
|
end
|
|
43
68
|
end
|
|
@@ -111,5 +111,51 @@ module ForemanFogProxmox
|
|
|
111
111
|
assert_equal vm, @cr.new_vm(attr)
|
|
112
112
|
end
|
|
113
113
|
end
|
|
114
|
+
|
|
115
|
+
describe 'assign_available_vmid' do
|
|
116
|
+
before do
|
|
117
|
+
@cr = FactoryBot.build_stubbed(:proxmox_cr)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
it 'uses next vmid when requested vmid is already occupied' do
|
|
121
|
+
attr = { 'vmid' => '100', 'node_id' => 'proxmox' }.with_indifferent_access
|
|
122
|
+
servers = mock('servers')
|
|
123
|
+
node = mock('node')
|
|
124
|
+
node.stubs(:servers).returns(servers)
|
|
125
|
+
servers.expects(:id_valid?).with(100).returns(false)
|
|
126
|
+
servers.expects(:next_id).returns('101')
|
|
127
|
+
@cr.logger.expects(:warn).never
|
|
128
|
+
|
|
129
|
+
@cr.assign_available_vmid(attr, node)
|
|
130
|
+
|
|
131
|
+
assert_equal '101', attr['vmid']
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it 'keeps requested vmid when it is available' do
|
|
135
|
+
attr = { 'vmid' => '100', 'node_id' => 'proxmox' }.with_indifferent_access
|
|
136
|
+
servers = mock('servers')
|
|
137
|
+
node = mock('node')
|
|
138
|
+
node.stubs(:servers).returns(servers)
|
|
139
|
+
servers.expects(:id_valid?).with(100).returns(true)
|
|
140
|
+
servers.expects(:next_id).never
|
|
141
|
+
|
|
142
|
+
@cr.assign_available_vmid(attr, node)
|
|
143
|
+
|
|
144
|
+
assert_equal 100, attr['vmid']
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it 'does not assign vmid when requested vmid is blank' do
|
|
148
|
+
attr = { 'vmid' => '', 'node_id' => 'proxmox' }.with_indifferent_access
|
|
149
|
+
servers = mock('servers')
|
|
150
|
+
node = mock('node')
|
|
151
|
+
node.stubs(:servers).returns(servers)
|
|
152
|
+
servers.expects(:id_valid?).never
|
|
153
|
+
servers.expects(:next_id).never
|
|
154
|
+
|
|
155
|
+
@cr.assign_available_vmid(attr, node)
|
|
156
|
+
|
|
157
|
+
assert_equal '', attr['vmid']
|
|
158
|
+
end
|
|
159
|
+
end
|
|
114
160
|
end
|
|
115
161
|
end
|
|
@@ -33,6 +33,7 @@ const ProxmoxServerStorage = ({
|
|
|
33
33
|
isTabActive,
|
|
34
34
|
selectedImage,
|
|
35
35
|
provisionMethodState,
|
|
36
|
+
canAttachCdromImage,
|
|
36
37
|
}) => {
|
|
37
38
|
const bootDiskId = React.useMemo(() => {
|
|
38
39
|
if (!bootOrder) return null;
|
|
@@ -70,6 +71,8 @@ const ProxmoxServerStorage = ({
|
|
|
70
71
|
const [nextId, setNextId] = useState(0);
|
|
71
72
|
const [cdRom, setCdRom] = useState(false);
|
|
72
73
|
const [cdRomData, setCdRomData] = useState(null);
|
|
74
|
+
const [cdRomHidden, setCdRomHidden] = useState(false);
|
|
75
|
+
const [cdRomIsNew, setCdRomIsNew] = useState(false);
|
|
73
76
|
const [efiDisk, setEfiDisk] = useState(false);
|
|
74
77
|
const [efiDiskData, setEfiDiskData] = useState(null);
|
|
75
78
|
const [nextDeviceNumbers, setNextDeviceNumbers] = useState({
|
|
@@ -309,7 +312,7 @@ const ProxmoxServerStorage = ({
|
|
|
309
312
|
value: '',
|
|
310
313
|
},
|
|
311
314
|
storageType: {
|
|
312
|
-
name: `${paramScope}[volumes_attributes][${nextId}][
|
|
315
|
+
name: `${paramScope}[volumes_attributes][${nextId}][storage_type]`,
|
|
313
316
|
value: 'cdrom',
|
|
314
317
|
},
|
|
315
318
|
storage: {
|
|
@@ -318,17 +321,29 @@ const ProxmoxServerStorage = ({
|
|
|
318
321
|
},
|
|
319
322
|
cdrom: {
|
|
320
323
|
name: `${paramScope}[volumes_attributes][${nextId}][cdrom]`,
|
|
321
|
-
value: '',
|
|
324
|
+
value: 'none',
|
|
325
|
+
},
|
|
326
|
+
_delete: {
|
|
327
|
+
name: `${paramScope}[volumes_attributes][${nextId}][_delete]`,
|
|
322
328
|
},
|
|
323
329
|
};
|
|
324
330
|
|
|
325
331
|
setCdRom(true);
|
|
326
332
|
setCdRomData(initCDRom);
|
|
333
|
+
setCdRomHidden(false);
|
|
334
|
+
setCdRomIsNew(!isPreExisting);
|
|
327
335
|
},
|
|
328
336
|
[cdRom, nextId, paramScope, createUniqueDevice]
|
|
329
337
|
);
|
|
330
338
|
|
|
331
|
-
const removeCDRom = () =>
|
|
339
|
+
const removeCDRom = () => {
|
|
340
|
+
if (cdRomIsNew) {
|
|
341
|
+
setCdRom(false);
|
|
342
|
+
setCdRomData(null);
|
|
343
|
+
} else {
|
|
344
|
+
setCdRomHidden(true);
|
|
345
|
+
}
|
|
346
|
+
};
|
|
332
347
|
|
|
333
348
|
const addEfiDisk = useCallback(
|
|
334
349
|
(event, initialData = null, isPreExisting = false) => {
|
|
@@ -432,14 +447,18 @@ const ProxmoxServerStorage = ({
|
|
|
432
447
|
</FormHelperText>
|
|
433
448
|
)}
|
|
434
449
|
{cdRom && cdRomData && (
|
|
435
|
-
<
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
450
|
+
<div style={{ display: cdRomHidden ? 'none' : 'block' }}>
|
|
451
|
+
<CDRom
|
|
452
|
+
onRemove={removeCDRom}
|
|
453
|
+
data={cdRomData}
|
|
454
|
+
storages={storages}
|
|
455
|
+
nodeId={nodeId}
|
|
456
|
+
computeResourceId={computeResourceId}
|
|
457
|
+
isTabActive={isTabActive}
|
|
458
|
+
canAttachCdromImage={canAttachCdromImage}
|
|
459
|
+
hidden={cdRomHidden}
|
|
460
|
+
/>
|
|
461
|
+
</div>
|
|
443
462
|
)}
|
|
444
463
|
{efiDisk && efiDiskData && (
|
|
445
464
|
<EFIDisk
|
|
@@ -537,6 +556,7 @@ ProxmoxServerStorage.propTypes = {
|
|
|
537
556
|
isTabActive: PropTypes.bool,
|
|
538
557
|
selectedImage: PropTypes.object,
|
|
539
558
|
provisionMethodState: PropTypes.string,
|
|
559
|
+
canAttachCdromImage: PropTypes.bool,
|
|
540
560
|
};
|
|
541
561
|
|
|
542
562
|
ProxmoxServerStorage.defaultProps = {
|
|
@@ -553,6 +573,7 @@ ProxmoxServerStorage.defaultProps = {
|
|
|
553
573
|
isTabActive: false,
|
|
554
574
|
selectedImage: null,
|
|
555
575
|
provisionMethodState: '',
|
|
576
|
+
canAttachCdromImage: false,
|
|
556
577
|
};
|
|
557
578
|
|
|
558
579
|
export default ProxmoxServerStorage;
|
|
@@ -6,6 +6,9 @@ import {
|
|
|
6
6
|
PageSection,
|
|
7
7
|
Radio,
|
|
8
8
|
Spinner,
|
|
9
|
+
FormHelperText,
|
|
10
|
+
HelperText,
|
|
11
|
+
HelperTextItem,
|
|
9
12
|
} from '@patternfly/react-core';
|
|
10
13
|
import { TimesIcon } from '@patternfly/react-icons';
|
|
11
14
|
import { translate as __ } from 'foremanReact/common/I18n';
|
|
@@ -13,7 +16,15 @@ import { createStoragesMap } from '../../ProxmoxStoragesUtils';
|
|
|
13
16
|
import InputField from '../../common/FormInputs';
|
|
14
17
|
import useVolumes from '../../hooks/useVolumes';
|
|
15
18
|
|
|
16
|
-
const CDRom = ({
|
|
19
|
+
const CDRom = ({
|
|
20
|
+
onRemove,
|
|
21
|
+
data,
|
|
22
|
+
storages,
|
|
23
|
+
nodeId,
|
|
24
|
+
computeResourceId,
|
|
25
|
+
canAttachCdromImage,
|
|
26
|
+
hidden,
|
|
27
|
+
}) => {
|
|
17
28
|
const [cdrom, setCdrom] = useState(data);
|
|
18
29
|
|
|
19
30
|
const storagesMap = useMemo(
|
|
@@ -85,13 +96,20 @@ const CDRom = ({ onRemove, data, storages, nodeId, computeResourceId }) => {
|
|
|
85
96
|
const imagesMap = useMemo(
|
|
86
97
|
() => [
|
|
87
98
|
{ value: '', label: '' },
|
|
88
|
-
...volumes
|
|
99
|
+
...volumes
|
|
100
|
+
.filter(v => v.content === 'iso')
|
|
101
|
+
.map(v => ({ value: v.volid, label: v.volid })),
|
|
89
102
|
],
|
|
90
103
|
[volumes]
|
|
91
104
|
);
|
|
92
105
|
|
|
93
106
|
return (
|
|
94
107
|
<div style={{ position: 'relative' }}>
|
|
108
|
+
<input
|
|
109
|
+
name={cdrom?._delete?.name}
|
|
110
|
+
type="hidden"
|
|
111
|
+
value={hidden ? '1' : '0'}
|
|
112
|
+
/>
|
|
95
113
|
<div
|
|
96
114
|
style={{
|
|
97
115
|
display: 'flex',
|
|
@@ -130,7 +148,7 @@ const CDRom = ({ onRemove, data, storages, nodeId, computeResourceId }) => {
|
|
|
130
148
|
name={cdrom?.cdrom?.name}
|
|
131
149
|
label={__('None')}
|
|
132
150
|
value="none"
|
|
133
|
-
isChecked={
|
|
151
|
+
isChecked={mediaValue === 'none'}
|
|
134
152
|
onChange={(e, _) => handleMediaChange(_, e)}
|
|
135
153
|
/>
|
|
136
154
|
<Radio
|
|
@@ -138,8 +156,8 @@ const CDRom = ({ onRemove, data, storages, nodeId, computeResourceId }) => {
|
|
|
138
156
|
id="radio-physical"
|
|
139
157
|
name={cdrom?.cdrom?.name}
|
|
140
158
|
label={__('Physical')}
|
|
141
|
-
value="
|
|
142
|
-
isChecked={
|
|
159
|
+
value="cdrom"
|
|
160
|
+
isChecked={mediaValue === 'cdrom'}
|
|
143
161
|
onChange={(e, _) => handleMediaChange(_, e)}
|
|
144
162
|
/>
|
|
145
163
|
<Radio
|
|
@@ -148,12 +166,25 @@ const CDRom = ({ onRemove, data, storages, nodeId, computeResourceId }) => {
|
|
|
148
166
|
name={cdrom?.cdrom?.name}
|
|
149
167
|
label={__('Image')}
|
|
150
168
|
value="image"
|
|
151
|
-
isChecked={
|
|
169
|
+
isChecked={mediaValue === 'image'}
|
|
152
170
|
onChange={(e, _) => handleMediaChange(_, e)}
|
|
171
|
+
isDisabled={!canAttachCdromImage}
|
|
153
172
|
/>
|
|
154
173
|
</div>
|
|
155
174
|
|
|
156
|
-
{
|
|
175
|
+
{!canAttachCdromImage && (
|
|
176
|
+
<FormHelperText>
|
|
177
|
+
<HelperText id="helper-cdrom-image-permission">
|
|
178
|
+
<HelperTextItem variant="warning">
|
|
179
|
+
{__(
|
|
180
|
+
'You are not authorized to attach or change CD-ROM ISO images'
|
|
181
|
+
)}
|
|
182
|
+
</HelperTextItem>
|
|
183
|
+
</HelperText>
|
|
184
|
+
</FormHelperText>
|
|
185
|
+
)}
|
|
186
|
+
|
|
187
|
+
{mediaValue === 'image' && (
|
|
157
188
|
<PageSection padding={{ default: 'noPadding' }}>
|
|
158
189
|
<Title ouiaId="proxmox-server-cdrom-image-title" headingLevel="h5">
|
|
159
190
|
{__('Image')}
|
|
@@ -170,6 +201,7 @@ const CDRom = ({ onRemove, data, storages, nodeId, computeResourceId }) => {
|
|
|
170
201
|
}
|
|
171
202
|
options={storagesMap}
|
|
172
203
|
onChange={handleChange}
|
|
204
|
+
disabled={!canAttachCdromImage}
|
|
173
205
|
/>
|
|
174
206
|
|
|
175
207
|
{loadingVolumes ? (
|
|
@@ -191,6 +223,7 @@ const CDRom = ({ onRemove, data, storages, nodeId, computeResourceId }) => {
|
|
|
191
223
|
value={cdrom?.volid?.value}
|
|
192
224
|
options={imagesMap}
|
|
193
225
|
onChange={handleChange}
|
|
226
|
+
disabled={!canAttachCdromImage}
|
|
194
227
|
error={
|
|
195
228
|
volumeError
|
|
196
229
|
? __('Failed fetching images ISO please try again.')
|
|
@@ -198,8 +231,6 @@ const CDRom = ({ onRemove, data, storages, nodeId, computeResourceId }) => {
|
|
|
198
231
|
}
|
|
199
232
|
/>
|
|
200
233
|
)}
|
|
201
|
-
|
|
202
|
-
<input name={cdrom?.storageType?.name} type="hidden" value="cdrom" />
|
|
203
234
|
</PageSection>
|
|
204
235
|
)}
|
|
205
236
|
</div>
|
|
@@ -224,10 +255,19 @@ CDRom.propTypes = {
|
|
|
224
255
|
storageType: PropTypes.shape({
|
|
225
256
|
name: PropTypes.string.isRequired,
|
|
226
257
|
}).isRequired,
|
|
258
|
+
_delete: PropTypes.shape({
|
|
259
|
+
name: PropTypes.string.isRequired,
|
|
260
|
+
}),
|
|
227
261
|
}).isRequired,
|
|
228
262
|
storages: PropTypes.array.isRequired,
|
|
229
263
|
nodeId: PropTypes.string.isRequired,
|
|
230
264
|
computeResourceId: PropTypes.number.isRequired,
|
|
265
|
+
canAttachCdromImage: PropTypes.bool.isRequired,
|
|
266
|
+
hidden: PropTypes.bool,
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
CDRom.defaultProps = {
|
|
270
|
+
hidden: false,
|
|
231
271
|
};
|
|
232
272
|
|
|
233
273
|
export default CDRom;
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { sprintf, translate as __ } from 'foremanReact/common/I18n';
|
|
2
2
|
|
|
3
|
+
// Unit selection uses a 1024 step (binary); the value is scaled by 1000 (decimal).
|
|
4
|
+
const BYTE_UNIT_STEP = 1024;
|
|
5
|
+
const BYTE_UNIT_DIVISOR = 1000;
|
|
6
|
+
|
|
3
7
|
const humanSize = size => {
|
|
4
|
-
const i = Math.floor(Math.log(size) / Math.log(
|
|
5
|
-
return `${(size /
|
|
8
|
+
const i = Math.floor(Math.log(size) / Math.log(BYTE_UNIT_STEP));
|
|
9
|
+
return `${(size / BYTE_UNIT_DIVISOR ** i).toFixed(2) * 1} ${
|
|
6
10
|
['B', 'kB', 'MB', 'GB', 'TB'][i]
|
|
7
11
|
}`;
|
|
8
12
|
};
|
|
@@ -35,6 +35,7 @@ const ProxmoxVmType = ({
|
|
|
35
35
|
registerComp,
|
|
36
36
|
untemplatable,
|
|
37
37
|
computeResourceId,
|
|
38
|
+
canAttachCdromImage,
|
|
38
39
|
propsLoaded,
|
|
39
40
|
}) => {
|
|
40
41
|
const [activeTabKey, setActiveTabKey] = useState(0);
|
|
@@ -233,6 +234,7 @@ const ProxmoxVmType = ({
|
|
|
233
234
|
isLoading={!metaLoaded}
|
|
234
235
|
isTabActive={activeTabKey === 4}
|
|
235
236
|
computeResourceId={computeResourceId}
|
|
237
|
+
canAttachCdromImage={canAttachCdromImage}
|
|
236
238
|
selectedImage={selectedImage}
|
|
237
239
|
provisionMethodState={provisionMethodState}
|
|
238
240
|
/>
|
|
@@ -415,6 +417,7 @@ ProxmoxVmType.propTypes = {
|
|
|
415
417
|
registerComp: PropTypes.bool,
|
|
416
418
|
untemplatable: PropTypes.bool,
|
|
417
419
|
computeResourceId: PropTypes.number,
|
|
420
|
+
canAttachCdromImage: PropTypes.bool,
|
|
418
421
|
propsLoaded: PropTypes.bool,
|
|
419
422
|
};
|
|
420
423
|
|
|
@@ -426,6 +429,7 @@ ProxmoxVmType.defaultProps = {
|
|
|
426
429
|
registerComp: false,
|
|
427
430
|
untemplatable: false,
|
|
428
431
|
computeResourceId: null,
|
|
432
|
+
canAttachCdromImage: false,
|
|
429
433
|
propsLoaded: false,
|
|
430
434
|
};
|
|
431
435
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: foreman_fog_proxmox
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.25.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tristan Robert
|
|
@@ -264,6 +264,7 @@ files:
|
|
|
264
264
|
- test/unit/foreman_fog_proxmox/proxmox_images_test.rb
|
|
265
265
|
- test/unit/foreman_fog_proxmox/proxmox_interfaces_test.rb
|
|
266
266
|
- test/unit/foreman_fog_proxmox/proxmox_operating_systems_test.rb
|
|
267
|
+
- test/unit/foreman_fog_proxmox/proxmox_orchestration_compute_test.rb
|
|
267
268
|
- test/unit/foreman_fog_proxmox/proxmox_test.rb
|
|
268
269
|
- test/unit/foreman_fog_proxmox/proxmox_version_test.rb
|
|
269
270
|
- test/unit/foreman_fog_proxmox/proxmox_vm_commands_container_test.rb
|
|
@@ -324,7 +325,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
324
325
|
- !ruby/object:Gem::Version
|
|
325
326
|
version: '0'
|
|
326
327
|
requirements: []
|
|
327
|
-
rubygems_version: 4.0.
|
|
328
|
+
rubygems_version: 4.0.16
|
|
328
329
|
specification_version: 4
|
|
329
330
|
summary: Foreman plugin that adds Proxmox VE compute resource using fog-proxmox
|
|
330
331
|
test_files:
|
|
@@ -344,6 +345,7 @@ test_files:
|
|
|
344
345
|
- test/unit/foreman_fog_proxmox/proxmox_images_test.rb
|
|
345
346
|
- test/unit/foreman_fog_proxmox/proxmox_interfaces_test.rb
|
|
346
347
|
- test/unit/foreman_fog_proxmox/proxmox_operating_systems_test.rb
|
|
348
|
+
- test/unit/foreman_fog_proxmox/proxmox_orchestration_compute_test.rb
|
|
347
349
|
- test/unit/foreman_fog_proxmox/proxmox_test.rb
|
|
348
350
|
- test/unit/foreman_fog_proxmox/proxmox_version_test.rb
|
|
349
351
|
- test/unit/foreman_fog_proxmox/proxmox_vm_commands_container_test.rb
|