foreman_fog_proxmox 0.24.0 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 494d9e13c53b6e6e1a4821d8c046d145060bac1058f9285763661bd935e5a4ef
4
- data.tar.gz: ba0639aa5659316381788213a3d6049ae98a8238a1612dd1dc8db7eed583d11f
3
+ metadata.gz: 329a340fdfd2b5e117a05a227477e29108df61d303a5ce5a5a2dc148ae41ec7c
4
+ data.tar.gz: '08b9aa3dca59fb2b7a80c2f1e6b0b59c9931f0d974e8d9849a720d6d37a819be'
5
5
  SHA512:
6
- metadata.gz: 4d7e5fc3d3bff0e58256217b5f69910dc03d0f08662dcc2ef1af35e242e5115f4e8023c565afa99cd83821dea73018d66b235354106766a4dbed351266c165ce
7
- data.tar.gz: 6ec6c8942c3e58cc7b3a05be5f2c0131bc47a0fb3cb9a4948d46cea8b51610ee33b7b6f0cbd8a08eac66818e7e83a2f0f51e3dca2ce8d0a9c051092d84c21c81
6
+ metadata.gz: '094a19a8592b2ed3ad7a88c637c7859f3bbc631a4f08f2fb781ec21a8b9620789fb701dbab917973ee122fb2ead5a44d6af12a28fe6dd2d99dad2267c8d051a7'
7
+ data.tar.gz: ce956eaac9a5faf92f2decd8721910dd72fd9a0e7f0ccfbeab40462c1cfc7892897235e7d2fef925405abf993b85f902edac0f4afcb1ec685649d27df0e61168
@@ -27,8 +27,7 @@ module ForemanFogProxmox
27
27
  def compute_resource_params_filter
28
28
  super.tap do |filter|
29
29
  filter.permit :ssl_verify_peer,
30
- :ssl_certs, :disable_proxy, :auth_method, :token_id, :token,
31
- :caching_enabled
30
+ :ssl_certs, :disable_proxy, :auth_method, :token_id, :token
32
31
  end
33
32
  end
34
33
 
@@ -84,8 +84,7 @@ module ForemanFogProxmox
84
84
  node_id = params[:node_id]
85
85
  storage = params[:storage]
86
86
 
87
- node = cr.send(:client).nodes.get(node_id)
88
- vols = node&.storages&.get(storage)&.volumes || []
87
+ vols = cr.storages(node_id).find { |s| s.storage == storage }&.volumes || []
89
88
 
90
89
  render json: Array(vols).map { |v|
91
90
  h = v.respond_to?(:as_json) ? v.as_json : v
@@ -36,8 +36,6 @@ module ForemanFogProxmox
36
36
  include ProxmoxVersion
37
37
  include ProxmoxConsole
38
38
  include ComputeAttributesUpdateDetector
39
- include ComputeResourceCaching
40
-
41
39
  validates :url, :format => { :with => URI::DEFAULT_PARSER.make_regexp }, :presence => true
42
40
  validates :auth_method, :presence => true, :inclusion => { in: ['access_ticket', 'user_token'],
43
41
  message: ->(value) do format('%<value>s is not a valid authentication method', { value: value }) end }
@@ -131,14 +129,6 @@ module ForemanFogProxmox
131
129
 
132
130
  private
133
131
 
134
- def structs_from_cache(items)
135
- Array(items).map { |item| OpenStruct.new(item) }
136
- end
137
-
138
- def extract_attributes(resource, fields)
139
- slice_vm_attributes(fields.index_with { |field| resource.try(field) }, fields)
140
- end
141
-
142
132
  def fog_credentials
143
133
  hash = {
144
134
  proxmox_url: url,
@@ -24,18 +24,11 @@ module ForemanFogProxmox
24
24
  end
25
25
 
26
26
  def images_by_storage(node_id, storage_id, type = 'iso')
27
- cached_images = cache.cache(:"images_by_storage-#{node_id}-#{storage_id}-#{type}") do
28
- node = client.nodes.get(node_id) || default_node
29
- storage = node.storages.get storage_id if storage_id
30
- logger.debug("images_by_storage(): node_id #{node_id} storage_id #{storage_id} type #{type}")
31
- next [] unless storage
32
-
33
- storage.volumes.list_by_content_type(type).sort_by(&:volid).map do |volume|
34
- extract_attributes(volume, [:volid, :content, :format, :size, :used])
35
- end
36
- end
37
-
38
- structs_from_cache(cached_images)
27
+ node = client.nodes.get node_id
28
+ node ||= default_node
29
+ storage = node.storages.get storage_id if storage_id
30
+ logger.debug("images_by_storage(): node_id #{node_id} storage_id #{storage_id} type #{type}")
31
+ storage.volumes.list_by_content_type(type).sort_by(&:volid) if storage
39
32
  end
40
33
 
41
34
  def template_name(template)
@@ -52,31 +45,25 @@ module ForemanFogProxmox
52
45
  end
53
46
 
54
47
  def templates
55
- cached_templates = cache.cache(:templates) do
56
- volumes = fog_nodes.flat_map do |node|
57
- storages = node.storages.list_by_content_type 'images'
58
- logger.debug("storages(): node_id #{node.node} type images")
59
- storages.reject { |storage| storage.active.to_i.zero? }.sort_by(&:storage).flat_map do |storage|
60
- # Skip disabled storages (enabled == 0 or nil)
61
- unless storage.enabled.to_i == 1
62
- logger.warn("Skipping disabled storage #{storage.identity} on #{node.node}")
63
- next []
64
- end
65
-
66
- # Fetch QEMU and LXC template images
67
- storage.volumes.list_by_content_type('images') + storage.volumes.list_by_content_type('rootdir')
68
- rescue StandardError => e
69
- logger.error("Failed to fetch volumes for storage #{storage.identity} on #{node.node}: #{e.message}")
70
- []
48
+ volumes = []
49
+ nodes.each do |node|
50
+ storages(node.node).each do |storage|
51
+ # Skip disabled storages (enabled == 0 or nil)
52
+ unless storage.enabled.to_i == 1
53
+ logger.warn("Skipping disabled storage #{storage.identity} on #{node.node}")
54
+ next
71
55
  end
72
- end
73
56
 
74
- volumes.select(&:template?).map do |volume|
75
- extract_attributes(volume, [:vmid, :name, :volid, :node_id]).merge(template: true)
57
+ # Fetch QEMU and LXC template images
58
+ volumes += storage.volumes.list_by_content_type('images')
59
+ volumes += storage.volumes.list_by_content_type('rootdir')
60
+ rescue StandardError => e
61
+ logger.error("Failed to fetch volumes for storage #{storage.identity} on #{node.node}: #{e.message}")
62
+ next
76
63
  end
77
64
  end
78
-
79
- structs_from_cache(cached_templates)
65
+ # for creating image, only list volumes which are templated
66
+ volumes.select(&:template?)
80
67
  end
81
68
 
82
69
  def template(uuid)
@@ -20,25 +20,8 @@
20
20
  module ForemanFogProxmox
21
21
  module ProxmoxPools
22
22
  def pools
23
- cached_pools = cache.cache(:pools) do
24
- pools = identity_client.pools.all
25
- pools.sort_by(&:poolid).map do |pool|
26
- extract_attributes(pool, [:poolid, :comment]).merge(
27
- members: Array(pool.try(:members)).map do |member|
28
- { vmid: member['vmid'] }
29
- end
30
- )
31
- end
32
- end
33
-
34
- # Store only serializable hashes in the cache. After retrieval we recreate the pool objects and reattach the `has_server?` helper method.
35
- Array(cached_pools).map do |pool|
36
- OpenStruct.new(pool).tap do |pool_object|
37
- pool_object.define_singleton_method(:has_server?) do |vmid|
38
- Array(members).any? { |member| member[:vmid].to_s == vmid.to_s || member['vmid'].to_s == vmid.to_s }
39
- end
40
- end
41
- end
23
+ pools = identity_client.pools.all
24
+ pools.sort_by(&:poolid)
42
25
  end
43
26
 
44
27
  def pool_owner(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
- (vmid < 1) ? node.servers.next_id : vmid
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)
@@ -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.
@@ -97,7 +99,7 @@ module ForemanFogProxmox
97
99
  end
98
100
 
99
101
  def default_node
100
- fog_nodes.first
102
+ nodes.first
101
103
  end
102
104
 
103
105
  def default_node_id
@@ -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
@@ -23,47 +23,29 @@ module ForemanFogProxmox
23
23
  include ProxmoxVMUuidHelper
24
24
 
25
25
  def nodes
26
- cached_nodes = cache.cache(:nodes) do
27
- nodes = client.nodes.all if client
28
- nodes&.sort_by(&:node)&.map do |node|
29
- { node: node.node }
30
- end
31
- end
32
-
33
- structs_from_cache(cached_nodes)
26
+ nodes = client.nodes.all if client
27
+ nodes&.sort_by(&:node)
34
28
  end
35
29
 
36
30
  def storages(node_id = default_node_id, type = 'images')
37
- cached_storages = cache.cache(:"storages-#{node_id}-#{type}") do
38
- node = client.nodes.get(node_id) || default_node
39
- storages = node.storages.list_by_content_type type
40
- logger.debug("storages(): node_id #{node_id} type #{type}")
41
- storages.reject { |s| s.enabled.to_i.zero? || s.active.to_i.zero? }.sort_by(&:storage).map do |storage|
42
- fields = [:storage, :enabled, :active, :content, :node_id, :avail, :used, :total]
43
- extract_attributes(storage, fields).merge(identity: storage.storage)
44
- end
45
- end
46
-
47
- structs_from_cache(cached_storages)
31
+ node = client.nodes.get node_id
32
+ node ||= default_node
33
+ storages = node.storages.list_by_content_type type
34
+ logger.debug("storages(): node_id #{node_id} type #{type}")
35
+ storages.reject { |s| s.enabled.to_i.zero? || s.active.to_i.zero? }.sort_by(&:storage)
48
36
  end
49
37
 
50
38
  def bridges(node_id = default_node_id)
51
- cached_bridges = cache.cache(:"bridges-#{node_id}") do
52
- node = network_client.nodes.get node_id
53
- node ||= network_client.nodes.first
54
- bridges = node.networks.all(type: 'any_bridge')
55
- bridges.sort_by(&:iface).map do |bridge|
56
- extract_attributes(bridge, [:iface, :node_id]).merge(identity: bridge.iface)
57
- end
58
- end
59
-
60
- structs_from_cache(cached_bridges)
39
+ node = network_client.nodes.get node_id
40
+ node ||= network_client.nodes.first
41
+ bridges = node.networks.all(type: 'any_bridge')
42
+ bridges.sort_by(&:iface)
61
43
  end
62
44
 
63
45
  # TODO: Pagination with filters
64
46
  def vms(opts = {})
65
47
  vms = []
66
- fog_nodes.each { |node| vms += node.servers.all + node.containers.all }
48
+ nodes.each { |node| vms += node.servers.all + node.containers.all }
67
49
  vms.each { |vm| attach_compute_resource_id(vm) }
68
50
  if opts.key?(:eager_loading) && opts[:eager_loading]
69
51
  vms_eager = []
@@ -77,7 +59,7 @@ module ForemanFogProxmox
77
59
  # look for the uuid on all known nodes
78
60
  vm = nil
79
61
  vmid = extract_vmid(uuid)
80
- fog_nodes.each do |node|
62
+ nodes.each do |node|
81
63
  vm = find_vm_in_servers_by_vmid(node.servers, vmid)
82
64
  vm ||= find_vm_in_servers_by_vmid(node.containers, vmid)
83
65
  next if vm.nil?
@@ -100,11 +82,6 @@ module ForemanFogProxmox
100
82
 
101
83
  private
102
84
 
103
- def fog_nodes
104
- nodes = client.nodes.all if client
105
- nodes&.sort_by(&:node) || []
106
- end
107
-
108
85
  def attach_compute_resource_id(virtual_machine)
109
86
  return virtual_machine if virtual_machine.nil?
110
87
 
@@ -1,3 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- attributes :url, :user, :ssl_verify_peer, :ssl_certs, :renew, :caching_enabled
3
+ attributes :url, :user, :ssl_verify_peer, :ssl_certs, :renew
@@ -36,8 +36,6 @@ along with ForemanFogProxmox. If not, see <http://www.gnu.org/licenses/>. %>
36
36
  :wrapper_class => "form-group #{'hide' unless ssl_verify_peer}",
37
37
  :placeholder => _("Optionally provide a CA, or a correctly ordered CA chain. If left blank, disable ssl_verify_peer.") %>
38
38
  <% end %>
39
- <%= checkbox_f f, :caching_enabled, :label => _("Enable Caching"),
40
- :help_inline => _("Cache Proxmox resources.") %>
41
39
  <div class="col-md-offset-2">
42
40
  <%= test_connection_button_f(f, (f.object.nodes rescue true)) %>
43
41
  </div>
@@ -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>
@@ -27,10 +31,6 @@ along with ForemanFogProxmox. If not, see <http://www.gnu.org/licenses/>. %>
27
31
  <td><%= _("Authentication method") %></td>
28
32
  <td><%= @compute_resource.auth_method %></td>
29
33
  </tr>
30
- <tr>
31
- <td><%= _("Caching") %></td>
32
- <td><%= @compute_resource.caching_enabled ? _("Enabled") : _("Disabled") %></td>
33
- </tr>
34
34
  <tr>
35
35
  <td><%= _("User token expires") %></td>
36
36
  <td><%= user_token_expiration_date(@compute_resource) %></td>
@@ -43,17 +43,20 @@ 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 :view_compute_resources, { :'foreman_fog_proxmox/compute_resources' =>
48
- [:ostemplates_by_id_and_node_and_storage,
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] }
57
60
  permission :attach_cdrom_image, {},
58
61
  :resource_type => 'ComputeResource'
59
62
  end
@@ -18,5 +18,5 @@
18
18
  # along with ForemanFogProxmox. If not, see <http://www.gnu.org/licenses/>.
19
19
 
20
20
  module ForemanFogProxmox
21
- VERSION = '0.24.0'
21
+ VERSION = '0.25.0'
22
22
  end
@@ -69,18 +69,6 @@ module ForemanFogProxmox
69
69
  assert_not show_response.empty?
70
70
  end
71
71
  test 'should get volumes by node and storage' do
72
- mock_storage = mock('storage')
73
- mock_storage.stubs(:volumes).returns([])
74
- mock_storages = mock('storages')
75
- mock_storages.stubs(:get).with('local').returns(mock_storage)
76
- mock_node = mock('node')
77
- mock_node.stubs(:storages).returns(mock_storages)
78
- mock_nodes = mock('nodes')
79
- mock_nodes.stubs(:get).with('proxmox').returns(mock_node)
80
- mock_client = mock('client')
81
- mock_client.stubs(:nodes).returns(mock_nodes)
82
- @compute_resource.stubs(:client).returns(mock_client)
83
-
84
72
  get :volumes_by_node_and_storage,
85
73
  params: { :compute_resource_id => @compute_resource.id, :node_id => 'proxmox', :storage => 'local' },
86
74
  session: set_session_user
@@ -108,12 +108,6 @@ module ForemanFogProxmox
108
108
  assert cr.update_required?(old_attrs, new_attrs)
109
109
  end
110
110
 
111
- test 'supports compute resource cache refreshing' do
112
- cr = FactoryBot.build_stubbed(:proxmox_cr)
113
-
114
- assert_respond_to cr, :refresh_cache
115
- end
116
-
117
111
  test '#node' do
118
112
  node = mock('node')
119
113
  cr = FactoryBot.build_stubbed(:proxmox_cr)
@@ -121,27 +115,6 @@ module ForemanFogProxmox
121
115
  assert_equal node, (as_admin { cr.node })
122
116
  end
123
117
 
124
- test '#extract_attributes returns selected resource attributes' do
125
- cr = FactoryBot.build_stubbed(:proxmox_cr)
126
-
127
- resource = OpenStruct.new(
128
- vmid: 101,
129
- name: 'template-101',
130
- ignored: 'ignored'
131
- )
132
-
133
- attributes = cr.send(:extract_attributes, resource, [:vmid, :name, :missing])
134
-
135
- assert_equal(
136
- {
137
- vmid: 101,
138
- name: 'template-101',
139
- missing: nil,
140
- },
141
- attributes
142
- )
143
- end
144
-
145
118
  private
146
119
 
147
120
  def hdd_compute_attrs(volumes_attrs)
@@ -31,15 +31,18 @@ module ForemanFogProxmox
31
31
  include ProxmoxVMHelper
32
32
 
33
33
  describe 'create_vm' do
34
- it 'raises Foreman::Exception when vmid <= 100 and vmid > 0' do
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.stubs(:id_valid?).returns(false)
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
- err = assert_raises Foreman::Exception do
40
- cr.create_vm(args)
41
- end
42
- assert err.message.end_with?('invalid vmid=100')
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
@@ -149,11 +149,11 @@ module ForemanFogProxmox
149
149
  pools = mock('pools')
150
150
  pool1 = mock('pool1')
151
151
  pool1.stubs(:poolid).returns('pool1')
152
- pool1.stubs(:members).returns([{ 'vmid' => '100' }])
152
+ pool1.stubs(:has_server?).with('100').returns(true)
153
153
  pool1.expects(:remove_server).with(uuid)
154
154
  pool2 = mock('pool2')
155
155
  pool2.stubs(:poolid).returns('pool2')
156
- pool2.stubs(:members).returns([])
156
+ pool2.stubs(:has_server?).with('100').returns(false)
157
157
  pool2.expects(:add_server).with(uuid)
158
158
  pools.stubs(:all).returns([pool1, pool2])
159
159
  pools.expects(:get).with('pool1').returns(pool1)
@@ -185,7 +185,7 @@ module ForemanFogProxmox
185
185
  identity_client = mock('identity_client')
186
186
  pools = mock('pools')
187
187
  pool1 = mock('pool1')
188
- pool1.stubs(:members).returns([{ 'vmid' => '100' }])
188
+ pool1.stubs(:has_server?).with('100').returns(true)
189
189
  pool1.stubs(:poolid).returns('pool1')
190
190
  pool1.expects(:remove_server).with(uuid)
191
191
  pools.stubs(:all).returns([pool1])
@@ -218,7 +218,7 @@ module ForemanFogProxmox
218
218
  identity_client = mock('identity_client')
219
219
  pools = mock('pools')
220
220
  pool2 = mock('pool2')
221
- pool2.stubs(:members).returns([])
221
+ pool2.stubs(:has_server?).with('100').returns(false)
222
222
  pool2.stubs(:poolid).returns('pool2')
223
223
  pool2.expects(:add_server).with(uuid)
224
224
  pools.stubs(:all).returns([pool2])
@@ -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,22 +33,6 @@ module ForemanFogProxmox
33
33
  include ProxmoxContainerMockFactory
34
34
  include ProxmoxVMHelper
35
35
 
36
- describe 'nodes' do
37
- it 'caches nodes for persisted compute resources' do
38
- cr = FactoryBot.build_stubbed(:proxmox_cr, :caching_enabled => true)
39
- node_z = OpenStruct.new(node: 'z-proxmox')
40
- node_a = OpenStruct.new(node: 'a-proxmox')
41
- nodes = mock('nodes')
42
- nodes.expects(:all).once.returns([node_z, node_a])
43
- client = mock('client')
44
- client.stubs(:nodes).returns(nodes)
45
- cr.stubs(:client).returns(client)
46
-
47
- assert_equal %w[a-proxmox z-proxmox], cr.nodes.map(&:node)
48
- assert_equal %w[a-proxmox z-proxmox], cr.nodes.map(&:node)
49
- end
50
- end
51
-
52
36
  describe 'storages' do
53
37
  before do
54
38
  @cr = ForemanFogProxmox::Proxmox.new
@@ -66,11 +50,7 @@ module ForemanFogProxmox
66
50
  active_storage = OpenStruct.new(storage: 'local', enabled: 1, active: 1)
67
51
  @storages_collection.stubs(:list_by_content_type).with('images').returns([active_storage])
68
52
 
69
- storage = @cr.storages('proxmox').first
70
- assert_equal 'local', storage.storage
71
- assert_equal 1, storage.enabled
72
- assert_equal 1, storage.active
73
- assert_equal 'local', storage.identity
53
+ assert_equal [active_storage], @cr.storages('proxmox')
74
54
  end
75
55
 
76
56
  it 'returns active storages sorted by storage name' do
@@ -87,7 +67,7 @@ module ForemanFogProxmox
87
67
 
88
68
  @storages_collection.stubs(:list_by_content_type).with('images').returns([valid, invalid])
89
69
 
90
- assert_equal ['good'], @cr.storages('proxmox').map(&:storage)
70
+ assert_equal [valid], @cr.storages('proxmox')
91
71
  end
92
72
 
93
73
  it 'excludes disabled storages (enabled=0)' do
@@ -117,45 +97,6 @@ module ForemanFogProxmox
117
97
 
118
98
  assert_empty @cr.storages('proxmox')
119
99
  end
120
-
121
- it 'caches storages by node and content type for persisted compute resources' do
122
- cr = FactoryBot.build_stubbed(:proxmox_cr, :caching_enabled => true)
123
- active_storage = OpenStruct.new(storage: 'local', enabled: 1, active: 1)
124
- storages_collection = mock('storages_collection')
125
- storages_collection.expects(:list_by_content_type).with('images').once.returns([active_storage])
126
- node = mock('node')
127
- node.stubs(:storages).returns(storages_collection)
128
- nodes = mock('nodes')
129
- nodes.stubs(:get).with('proxmox').returns(node)
130
- client = mock('client')
131
- client.stubs(:nodes).returns(nodes)
132
- cr.stubs(:client).returns(client)
133
-
134
- assert_equal [active_storage.storage], cr.storages('proxmox').map(&:storage)
135
- assert_equal [active_storage.storage], cr.storages('proxmox').map(&:storage)
136
- end
137
-
138
- it 'restores cached storages with normalized attributes' do
139
- cr = FactoryBot.build_stubbed(:proxmox_cr, :caching_enabled => true)
140
- active_storage = OpenStruct.new(storage: 'local', enabled: 1, active: 1)
141
- storages_collection = mock('storages_collection')
142
- storages_collection.expects(:list_by_content_type).with('images').once.returns([active_storage])
143
- node = mock('node')
144
- node.stubs(:storages).returns(storages_collection)
145
- nodes = mock('nodes')
146
- nodes.stubs(:get).with('proxmox').returns(node)
147
- client = mock('client')
148
- client.stubs(:nodes).returns(nodes)
149
- cr.stubs(:client).returns(client)
150
-
151
- cr.storages('proxmox')
152
- cached_storage = cr.storages('proxmox').first
153
-
154
- assert_equal 'local', cached_storage.storage
155
- assert_equal 'local', cached_storage.identity
156
- assert_equal [:active, :avail, :content, :enabled, :identity, :node_id, :storage, :total, :used],
157
- cached_storage.to_h.keys.sort
158
- end
159
100
  end
160
101
 
161
102
  describe 'find_vm_by_uuid' do
@@ -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(1024));
5
- return `${(size / 1000 ** i).toFixed(2) * 1} ${
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
  };
@@ -8,4 +8,5 @@ global.console.error = (error, stack) => {
8
8
  };
9
9
 
10
10
  // Increase jest timeout as some tests using multiple http mocks can time out on CI systems.
11
- jest.setTimeout(10000);
11
+ const JEST_TIMEOUT_MS = 10000;
12
+ jest.setTimeout(JEST_TIMEOUT_MS);
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.24.0
4
+ version: 0.25.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tristan Robert
@@ -325,7 +325,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
325
325
  - !ruby/object:Gem::Version
326
326
  version: '0'
327
327
  requirements: []
328
- rubygems_version: 4.0.10
328
+ rubygems_version: 4.0.16
329
329
  specification_version: 4
330
330
  summary: Foreman plugin that adds Proxmox VE compute resource using fog-proxmox
331
331
  test_files: