fog-proxmox 0.16.2 → 1.1.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: 4cdecf83035e83be1e7ceb19a56e551e65c0761ec0330ddfc23c834dccdf369c
4
- data.tar.gz: 7469eec6715cb9210eff2da78364d8b8d67a24fc7e4bb52dd809b5202135eb79
3
+ metadata.gz: d571150b56652b8f22fc3172ac26caf7918bdc167c5202b9f0809f138693da0f
4
+ data.tar.gz: f26c7b0f98d625306b573bdc2c848974438b03260ac7814b796d055e9967c88a
5
5
  SHA512:
6
- metadata.gz: 9588e62afafb53c22eac52bca2bc65d3e9c9adab8445fa2afa41c97b9933b0bcb49680f6a099df2c2f8ea8be1b5f270064e864991beb46cafdd7a949f3d5c28f
7
- data.tar.gz: e96d35aa10121df4325f45908276e65af1413d900e508b7d9064cae608f74dc0033886a80e139eac313114e93e6ff7a2215f2282739b660ce4a5ebff0a6c67ef
6
+ metadata.gz: df89614d08202bce01cc9f9be6d0fe3bd03a763672016ef363a0666a70e08625c6babed6d5969344496334d1aa5f59ef9584bf4e10b1b8f1b39a60d648d8b3b0
7
+ data.tar.gz: 4fea613dea946a99e5376f6b691eaf6112c1f21d8116497a44e0cc67aba0ddb081a766941b9a1fb8922e40160e451791984a2c06176670fce9f979556fc730bd
data/CHANGELOG.md CHANGED
@@ -1,5 +1,39 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.1.0](https://github.com/fog/fog-proxmox/compare/v1.0.0...v1.1.0) (2026-10-21)
4
+
5
+
6
+ ### Features
7
+
8
+ * Add hotplug support ([#158](https://github.com/fog/fog-proxmox/issues/158)) ([0745f60](https://github.com/fog/fog-proxmox/commit/0745f6013003af9d0b1ec7304749a5c52038fa62))
9
+ * Add VirtIO RNG device support ([#160](https://github.com/fog/fog-proxmox/issues/160)) ([a31b9d3](https://github.com/fog/fog-proxmox/commit/a31b9d39927d82b2db9da6c1889b9fd556905b5c))
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * ISO upload task polling ([3dc3c31](https://github.com/fog/fog-proxmox/commit/3dc3c31fe8cd72fc719954917dad39afa6b08ebd))
15
+
16
+ ## [1.0.0](https://github.com/fog/fog-proxmox/compare/v0.16.2...v1.0.0) (2026-09-14)
17
+
18
+
19
+ ### ⚠ BREAKING CHANGES
20
+
21
+ * Add support for ISO uploads via Proxmox API ([#148](https://github.com/fog/fog-proxmox/issues/148))
22
+
23
+ ### Features
24
+
25
+ * Add support for ISO uploads via Proxmox API ([#148](https://github.com/fog/fog-proxmox/issues/148)) ([396d08c](https://github.com/fog/fog-proxmox/commit/396d08c573feceda8443072d2c76cffd3c2a4918))
26
+
27
+
28
+ ### Bug Fixes
29
+
30
+ * RuboCop extra spacing offenses ([#149](https://github.com/fog/fog-proxmox/issues/149)) ([9a303bc](https://github.com/fog/fog-proxmox/commit/9a303bc03a3d5049ded43d3ad1fa6ea79febd43e))
31
+
32
+
33
+ ### Miscellaneous Chores
34
+
35
+ * allow major releases before 1.0 ([#156](https://github.com/fog/fog-proxmox/issues/156)) ([0752d55](https://github.com/fog/fog-proxmox/commit/0752d55fcfa0628c452c3bc7d7a137e341c8da4a))
36
+
3
37
  ## [0.16.2](https://github.com/fog/fog-proxmox/compare/v0.16.1...v0.16.2) (2026-08-12)
4
38
 
5
39
 
data/README.md CHANGED
@@ -2,14 +2,14 @@
2
2
 
3
3
  # Fog::Proxmox
4
4
 
5
- ![CI](https://github.com/fog/fog-proxmox/workflows/CI/badge.svg)
5
+ [![CI](https://github.com/fog/fog-proxmox/actions/workflows/ci.yml/badge.svg)](https://github.com/fog/fog-proxmox/actions/workflows/ci.yml)
6
6
  [![Maintainability](https://api.codeclimate.com/v1/badges/dfcdcc32f096abf1b2b4/maintainability)](https://codeclimate.com/github/fog/fog-proxmox/maintainability)
7
7
  [![Test Coverage](https://api.codeclimate.com/v1/badges/dfcdcc32f096abf1b2b4/test_coverage)](https://codeclimate.com/github/fog/fog-proxmox/test_coverage)
8
8
  [![Gem Version](https://badge.fury.io/rb/fog-proxmox.svg)](https://badge.fury.io/rb/fog-proxmox)
9
9
 
10
- This is a [FOG](http://fog.io/) (>= 2.1) module gem to support [Proxmox VE](https://www.proxmox.com/en/proxmox-ve)
10
+ This is a [FOG](https://fog.github.io/) (>= 2.1) module gem to support [Proxmox VE](https://www.proxmox.com/en/proxmox-ve)
11
11
 
12
- It is intended to satisfy this [feature](https://github.com/fog/fog/issues/3644), but Proxmox provider only, and above all this [Foreman](http://www.theforeman.org) [feature](https://projects.theforeman.org/issues/2186).
12
+ It is intended to satisfy this [feature](https://github.com/fog/fog/issues/3644), but Proxmox provider only, and above all this [Foreman](https://www.theforeman.org) [feature](https://projects.theforeman.org/issues/2186).
13
13
 
14
14
  It is inspired by the great [fog-openstack](https://github.com/fog/fog-openstack) module.
15
15
 
@@ -102,7 +102,7 @@ bundle exec rake --tasks
102
102
  ## Contributing
103
103
 
104
104
  You can reach the [contributors](.github/CONTRIBUTORS.md).
105
- Bug reports and pull requests are welcome on GitHub at [Fog-Proxmox](https://github.com/fog/fog-proxmox/issues). This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
105
+ Bug reports and pull requests are welcome on GitHub at [Fog-Proxmox](https://github.com/fog/fog-proxmox/issues). This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](https://www.contributor-covenant.org) code of conduct.
106
106
 
107
107
  Please read [how to contribute](.github/CONTRIBUTING.md).
108
108
 
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is part of Fog::Proxmox.
4
+
5
+ # Fog::Proxmox is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+
10
+ # Fog::Proxmox is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with Fog::Proxmox. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ module Fog
19
+ module Proxmox
20
+ # An IO-like multipart body that streams a file between a prefix and suffix.
21
+ class MultipartBody
22
+ attr_reader :size
23
+
24
+ def initialize(prefix, file, suffix)
25
+ @prefix = prefix
26
+ @file = file
27
+ @suffix = suffix
28
+ @size = prefix.bytesize + file_size + suffix.bytesize
29
+ rewind
30
+ end
31
+
32
+ def read(length = nil, outbuf = nil)
33
+ length = @size - @position if length.nil?
34
+ raise ArgumentError, 'negative length' if length.negative?
35
+
36
+ result = ::String.new(encoding: Encoding::BINARY)
37
+ read_into(result, length)
38
+ result = nil if result.empty? && length.positive? && @part > 2
39
+
40
+ return result unless outbuf
41
+
42
+ outbuf.replace(result || '')
43
+ result && outbuf
44
+ end
45
+
46
+ def rewind
47
+ @file.rewind
48
+ @part = 0
49
+ @offset = 0
50
+ @position = 0
51
+ 0
52
+ end
53
+
54
+ def binmode
55
+ @file.binmode if @file.respond_to?(:binmode)
56
+ self
57
+ end
58
+
59
+ private
60
+
61
+ def file_size
62
+ return @file.size if @file.respond_to?(:size)
63
+ return @file.stat.size if @file.respond_to?(:stat)
64
+
65
+ raise ArgumentError, 'Upload file size cannot be determined'
66
+ end
67
+
68
+ def read_into(result, length)
69
+ while result.bytesize < length && @part <= 2
70
+ remaining = length - result.bytesize
71
+ chunk = @part == 1 ? @file.read(remaining) : read_string_part(remaining)
72
+
73
+ if chunk.nil? || chunk.empty?
74
+ @part += 1
75
+ @offset = 0
76
+ else
77
+ result << chunk
78
+ @position += chunk.bytesize
79
+ end
80
+ end
81
+ end
82
+
83
+ def read_string_part(length)
84
+ string = @part.zero? ? @prefix : @suffix
85
+ chunk = string.byteslice(@offset, length)
86
+ @offset += chunk.bytesize if chunk
87
+ chunk
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is part of Fog::Proxmox.
4
+
5
+ # Fog::Proxmox is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+
10
+ # Fog::Proxmox is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with Fog::Proxmox. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ require 'securerandom'
19
+ require 'excon'
20
+ require 'fog/proxmox/compute/models/multipart_body'
21
+
22
+ module Fog
23
+ module Proxmox
24
+ # Prepares a streamed multipart ISO upload and its content type.
25
+ class MultipartIsoUpload
26
+ attr_reader :body, :content_type
27
+
28
+ def initialize(body_params)
29
+ filename = body_params.fetch(:filename)
30
+ raise ArgumentError, "Invalid ISO filename: #{filename}" unless filename.match?(/\A[a-zA-Z0-9][a-zA-Z0-9._-]*\.iso\z/i)
31
+
32
+ file = body_params.fetch(:file)
33
+
34
+ boundary = '-' * 30 + SecureRandom.hex(15)
35
+ prefix = build_multipart_content(boundary, 'content', 'iso')
36
+ prefix << build_multipart_header(boundary, 'filename', filename: filename)
37
+ @body = MultipartBody.new(prefix, file, build_multipart_closing(boundary))
38
+
39
+ @content_type = "multipart/form-data; boundary=#{boundary}"
40
+ end
41
+
42
+ private
43
+
44
+ def build_multipart_header(boundary, name, filename: nil)
45
+ newline = Excon::CR_NL
46
+ header = ::String.new(encoding: Encoding::BINARY)
47
+ header << "--#{boundary}#{newline}"
48
+ header << %(Content-Disposition: form-data; name="#{name}")
49
+ header << %(; filename="#{filename}") if filename
50
+ header << newline
51
+ header << "Content-Type: application/octet-stream#{newline}" if filename
52
+ header << newline
53
+ end
54
+
55
+ def build_multipart_content(boundary, name, value)
56
+ build_multipart_header(boundary, name) << value << Excon::CR_NL
57
+ end
58
+
59
+ def build_multipart_closing(boundary)
60
+ "#{Excon::CR_NL}--#{boundary}--#{Excon::CR_NL}".b
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is part of Fog::Proxmox.
4
+
5
+ # Fog::Proxmox is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+
10
+ # Fog::Proxmox is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with Fog::Proxmox. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ require 'fog/proxmox/helpers/rng_helper'
19
+
20
+ module Fog
21
+ module Proxmox
22
+ class Compute
23
+ # VirtIO RNG device; period is in milliseconds and max_bytes is in bytes.
24
+ class Rng < Fog::Model
25
+ attribute :max_bytes
26
+ attribute :period
27
+ attribute :source
28
+
29
+ def flatten
30
+ Fog::Proxmox::RngHelper.flatten(attributes)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -21,6 +21,7 @@ require 'fog/proxmox/attributes'
21
21
  require 'fog/proxmox/helpers/nic_helper'
22
22
  require 'fog/proxmox/helpers/controller_helper'
23
23
  require 'fog/proxmox/helpers/efidisk_helper'
24
+ require 'fog/proxmox/helpers/rng_helper'
24
25
 
25
26
  module Fog
26
27
  module Proxmox
@@ -41,6 +42,7 @@ module Fog
41
42
  attribute :onboot
42
43
  attribute :boot
43
44
  attribute :agent
45
+ attribute :hotplug
44
46
  attribute :scsihw
45
47
  attribute :sockets
46
48
  attribute :memory
@@ -80,6 +82,7 @@ module Fog
80
82
  attribute :searchdomain
81
83
  attribute :nameserver
82
84
  attribute :efidisk
85
+ attribute :rng
83
86
 
84
87
  def initialize(new_attributes = {})
85
88
  prepare_service_value(new_attributes)
@@ -88,6 +91,7 @@ module Fog
88
91
  initialize_interfaces(new_attributes)
89
92
  initialize_disks(new_attributes)
90
93
  initialize_efidisk(new_attributes)
94
+ initialize_rng(new_attributes)
91
95
  super(new_attributes)
92
96
  end
93
97
 
@@ -103,9 +107,10 @@ module Fog
103
107
  end
104
108
 
105
109
  def flatten
106
- flat_hash = attributes.reject { |attribute| %i[node_id type vmid disks interfaces].include? attribute }
110
+ flat_hash = attributes.reject { |attribute| %i[node_id type vmid disks interfaces rng].include? attribute }
107
111
  flat_hash.merge(interfaces_flatten)
108
112
  flat_hash.merge(disks_flatten)
113
+ flat_hash.merge!(rng.flatten) unless rng.nil?
109
114
  flat_hash
110
115
  end
111
116
 
@@ -166,6 +171,14 @@ module Fog
166
171
  efidisk_hash = Fog::Proxmox::EfidiskHelper.extract(efidisk)
167
172
  attributes[:efidisk] = Fog::Proxmox::Compute::Efidisk.new(efidisk_hash)
168
173
  end
174
+
175
+ def initialize_rng(new_attributes)
176
+ rng = new_attributes[:rng0] || new_attributes['rng0']
177
+ return if rng.nil?
178
+
179
+ rng_hash = Fog::Proxmox::RngHelper.extract(rng)
180
+ attributes[:rng] = Fog::Proxmox::Compute::Rng.new(rng_hash)
181
+ end
169
182
  end
170
183
  end
171
184
  end
@@ -26,6 +26,8 @@
26
26
 
27
27
  # frozen_string_literal: true
28
28
 
29
+ require 'fog/proxmox/storage/models/iso_upload'
30
+
29
31
  module Fog
30
32
  module Proxmox
31
33
  class Compute
@@ -53,6 +55,10 @@ module Fog
53
55
  super(new_attributes)
54
56
  end
55
57
 
58
+ def upload_iso(path)
59
+ Fog::Proxmox::Storage::IsoUpload.new(service: service, node_id: node_id, storage_id: identity, path: path).upload
60
+ end
61
+
56
62
  private
57
63
 
58
64
  def initialize_volumes
@@ -37,6 +37,7 @@ module Fog
37
37
  model :disk
38
38
  collection :disks
39
39
  model :efidisk
40
+ model :rng
40
41
  model :server_config
41
42
  model :volume
42
43
  collection :volumes
@@ -93,8 +93,8 @@ module Fog
93
93
  begin
94
94
  authenticate! if expired?
95
95
  request_options = params.merge(path: "#{@path}/#{params[:path]}",
96
- headers: @auth_token.headers(
97
- params[:method], params.respond_to?(:headers) ? params[:headers] : {}, {}
96
+ headers: (params[:headers] || {}).merge(
97
+ @auth_token.headers(params[:method], {}, {})
98
98
  ))
99
99
  response = @connection.request(request_options)
100
100
  rescue Excon::Errors::Unauthorized => e
@@ -102,6 +102,7 @@ module Fog
102
102
  if !%w[Bad username or password, invalid token
103
103
  value!].include?(e.response.body) && @proxmox_can_reauthenticate && !retried
104
104
  authenticate!
105
+ params[:body].rewind if params[:body].respond_to?(:rewind)
105
106
  retried = true
106
107
  retry
107
108
  # bad credentials or token renewal not possible
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is part of Fog::Proxmox.
4
+
5
+ # Fog::Proxmox is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+
10
+ # Fog::Proxmox is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with Fog::Proxmox. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ module Fog
19
+ module Proxmox
20
+ # Convert guest agent settings to and from Proxmox configuration strings.
21
+ module AgentHelper
22
+ DEFAULTS = {
23
+ 'enabled' => '0',
24
+ 'freeze-fs-on-backup' => '1',
25
+ 'fstrim_cloned_disks' => '0',
26
+ 'type' => 'virtio'
27
+ }.freeze
28
+
29
+ def self.extract(agent)
30
+ settings = DEFAULTS.dup
31
+ agent.to_s.split(',').each do |option|
32
+ key, value = option.split('=', 2)
33
+ if value.nil?
34
+ settings['enabled'] = key
35
+ else
36
+ settings[key] = value
37
+ end
38
+ end
39
+
40
+ settings['freeze-fs-on-backup'] = settings.fetch('freeze-fs', settings['freeze-fs-on-backup'])
41
+ settings
42
+ end
43
+
44
+ def self.flatten(settings)
45
+ "enabled=#{settings['enabled']},freeze-fs-on-backup=#{settings['freeze-fs-on-backup']}," \
46
+ "fstrim_cloned_disks=#{settings['fstrim_cloned_disks']},type=#{settings['type']}"
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is part of Fog::Proxmox.
4
+
5
+ # Fog::Proxmox is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+
10
+ # Fog::Proxmox is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with Fog::Proxmox. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ module Fog
19
+ module Proxmox
20
+ # Convert hotplug settings to and from Proxmox configuration strings.
21
+ module HotplugHelper
22
+ DEVICES = %w[disk network usb cpu memory].freeze
23
+ DEFAULTS = %w[disk network usb].freeze
24
+
25
+ def self.extract(hotplug)
26
+ hotplug = hotplug.to_s
27
+ {
28
+ enabled: hotplug != '0',
29
+ devices: hotplug.empty? || hotplug == '1' ? DEFAULTS.dup : hotplug.split(',')
30
+ }
31
+ end
32
+
33
+ def self.flatten(settings)
34
+ return '0' unless settings[:enabled]
35
+
36
+ devices = DEVICES.select { |device| settings[:devices].include?(device) }
37
+ devices.empty? ? '0' : devices.join(',')
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is part of Fog::Proxmox.
4
+
5
+ # Fog::Proxmox is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+
10
+ # Fog::Proxmox is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with Fog::Proxmox. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ require 'fog/proxmox/hash'
19
+
20
+ module Fog
21
+ module Proxmox
22
+ # Convert RNG devices to and from Proxmox configuration strings
23
+ module RngHelper
24
+ RNG_SOURCES = %w[/dev/urandom /dev/random /dev/hwrng].freeze
25
+
26
+ def self.flatten(rng)
27
+ return {} if rng.nil?
28
+
29
+ options = rng.select do |key, value|
30
+ %i[max_bytes period source].include?(key) && !value.nil? && value != ''
31
+ end
32
+
33
+ validate(options)
34
+
35
+ { rng0: Fog::Proxmox::Hash.stringify(options) }
36
+ end
37
+
38
+ def self.validate(rng)
39
+ raise ArgumentError, 'RNG source is required and must be /dev/urandom, /dev/random, or /dev/hwrng' unless RNG_SOURCES.include?(rng[:source].to_s)
40
+
41
+ %i[max_bytes period].each do |key|
42
+ next if rng[key].nil? || rng[key] == ''
43
+ next if rng[key].to_s.match?(/\A[0-9]+\z/)
44
+
45
+ raise ArgumentError, "RNG #{key} must be a non-negative integer"
46
+ end
47
+
48
+ true
49
+ end
50
+
51
+ def self.extract(rng)
52
+ options = rng.split(',').each_with_object({}) do |option, values|
53
+ key, value = option.split('=', 2)
54
+ values[key.to_sym] = value&.sub(/\A"(.*)"\z/, '\1')
55
+ end
56
+
57
+ options.slice(:max_bytes, :period, :source)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fog
4
+ module Proxmox
5
+ class Storage
6
+ # Uploads a local ISO and waits for the Proxmox task to finish.
7
+ class IsoUpload < Fog::Model
8
+ attribute :node_id
9
+ attribute :storage_id
10
+ attribute :path
11
+
12
+ def upload
13
+ requires :node_id, :storage_id, :path
14
+
15
+ filename = File.basename(path)
16
+ size = File.size(path)
17
+ Fog::Logger.debug("Starting Proxmox ISO upload filename=#{filename} size=#{size} bytes node=#{node_id} storage=#{storage_id}")
18
+ response = File.open(path, 'rb') do |file|
19
+ Fog::Proxmox::Storage.new(service.config).upload_iso(
20
+ { node: node_id, storage: storage_id },
21
+ { filename: filename, file: file }
22
+ )
23
+ end
24
+ Fog::Logger.debug("Upload response: #{response.inspect}")
25
+ task_node = response.to_s[/\AUPID:([^:]+):/, 1]
26
+ raise Fog::Errors::Error, "Unexpected upload response: #{response.inspect}" unless task_node
27
+
28
+ service.nodes.get(task_node).tasks.wait_for(response)
29
+ response
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is part of Fog::Proxmox.
4
+
5
+ # Fog::Proxmox is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+
10
+ # Fog::Proxmox is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with Fog::Proxmox. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ require 'fog/proxmox/compute/models/multipart_iso_upload'
19
+
20
+ module Fog
21
+ module Proxmox
22
+ class Storage
23
+ # class Real upload_iso request
24
+ class Real
25
+ def upload_iso(path_params, body_params)
26
+ node = path_params[:node]
27
+ storage = path_params[:storage]
28
+ upload = MultipartIsoUpload.new(body_params)
29
+
30
+ request(
31
+ expects: [200],
32
+ method: 'POST',
33
+ path: "nodes/#{node}/storage/#{storage}/upload",
34
+ body: upload.body,
35
+ headers: { 'Content-Type' => upload.content_type }
36
+ )
37
+ end
38
+ end
39
+
40
+ # class Mock upload_iso request
41
+ class Mock
42
+ def upload_iso(_path_params, _body_params); end
43
+ end
44
+ end
45
+ end
46
+ end