proxmox-api 0.1.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cbf823b601fbcb8595b19af7580881ef311ce140d1e5d971a9451a3a50c7249a
4
- data.tar.gz: 246a3d239a3ffa4966022e2f28c95addcf9787b6b1fd236b2c163a54dd2b837b
3
+ metadata.gz: cfffdfb8c0570120b8dd060da7d5d7fa379c00989d83523a4297264616f2d8f3
4
+ data.tar.gz: 0a48cc99643a7a2aa894f3f6b5f5ad354b83f428f89b891296701b5bd386aa6e
5
5
  SHA512:
6
- metadata.gz: 42b320222e6b040bd9d06fa103f61bb177f63b6d9d8c2c034d5ca243387c9526b5cdb0cae56229cabbe2e45f15722c729e8240e880f47c2f4c3da4d67f2789a1
7
- data.tar.gz: 2617997f456c221ab6fabfd933c3b3c4b51944a51a43a2204403e23265a59ccef0dbb6b09c3e99b09317f8b3c5d8a05622b48cf17a063f735a16f4fb2a2bd317
6
+ metadata.gz: 7087e2ceba545878007e3d00a006ab22cc50068058d95acf2d8afb95482d94a68a4152394f1a82a710e612fad085d466413d2fc00b27fabba8e2ac41915f7e98
7
+ data.tar.gz: a580714df5b78651b3d82583a425f8474825f9c21e4ceee75805802730b9089a7f43ed55acd98ba17596913fd7670eaa5d1a8c2d6b8bde283208ac5d4166e675
data/lib/proxmox_api.rb CHANGED
@@ -3,13 +3,20 @@
3
3
  require 'rest_client'
4
4
  require 'json'
5
5
 
6
+ # This class is wrapper for Proxmox PVE APIv2.
7
+ # See README for usage examples.
8
+ #
9
+ # @author Eugene Lapeko
6
10
  class ProxmoxAPI
7
- AUTH_PARAMS = %i[username realm password otp path privs].freeze
11
+ AUTH_PARAMS = %i[username realm password otp].freeze
8
12
  REST_METHODS = %i[get post put delete].freeze
9
- SSL_OPTIONS = %i[ssl_client_cert ssl_client_key ssl_ca_file verify_ssl].freeze
10
13
 
14
+ # This class is used to collect api path before request
11
15
  class ApiPath
16
+ # @param [ProxmoxAPI] api ProxmoxAPI object to call when request is executed
12
17
  def initialize(api)
18
+ raise ArgumentError, 'Not an instance of ProxmoxAPI' unless api.is_a? ProxmoxAPI
19
+
13
20
  @api = api
14
21
  @path = []
15
22
  end
@@ -24,7 +31,7 @@ class ProxmoxAPI
24
31
  end
25
32
 
26
33
  def method_missing(method, *args)
27
- return @api.__send__(:submit, method, to_s, *args) if REST_METHODS.include?(method)
34
+ return @api.__send__(:submit, method, to_s, *args) if REST_METHODS.any? { |rm| /^#{rm}!?$/.match? method }
28
35
 
29
36
  @path << method.to_s
30
37
  self
@@ -35,10 +42,38 @@ class ProxmoxAPI
35
42
  end
36
43
  end
37
44
 
45
+ # This exception is raised when Proxmox API returns error code
46
+ #
47
+ # @!attribute [r] response
48
+ # @return [RestClient::Response] answer from Proxmox server
49
+ class ApiException < RuntimeError
50
+ attr_reader :response
51
+
52
+ def initialize(response, description)
53
+ @response = response
54
+
55
+ super description
56
+ end
57
+ end
58
+
59
+ # Constructor method for ProxmoxAPI
60
+ #
61
+ # @param [String] cluster hostname/ip of cluster to control
62
+ # @param [Hash] options cluster connection parameters
63
+ #
64
+ # @option options [String] :username - username to be used for connection
65
+ # @option options [String] :password - password to be used for connection
66
+ # @option options [String] :realm - auth realm, can be given in :username ('user@realm')
67
+ # @option options [String] :otp - one-time password for two-factor auth
68
+ #
69
+ # @option options [Boolean] :verify_ssl - verify server certificate
70
+ #
71
+ # You can also pass here all ssl options supported by rest-client gem
72
+ # @see https://github.com/rest-client/rest-client
38
73
  def initialize(cluster, options)
39
74
  @connection = RestClient::Resource.new(
40
75
  "https://#{cluster}:#{options[:port] || 8006}/api2/json/",
41
- options.select { |k, _v| SSL_OPTIONS.include? k }
76
+ options.select { |k, _v| RestClient::Request::SSLOptionList.unshift('verify_ssl').include? k.to_s }
42
77
  )
43
78
  @auth_ticket = create_auth_ticket(options.select { |k, _v| AUTH_PARAMS.include? k })
44
79
  end
@@ -57,9 +92,16 @@ class ProxmoxAPI
57
92
 
58
93
  private
59
94
 
95
+ def raise_on_failure(response, message = 'Proxmox API request failed')
96
+ return unless response.code.to_i >= 400
97
+
98
+ raise ApiException.new(response, message)
99
+ end
100
+
60
101
  def create_auth_ticket(options)
61
102
  @connection['access/ticket'].post options do |response, _request, _result, &_block|
62
- # TODO: raise unless response.code == 200
103
+ raise_on_failure(response, 'Proxmox authentication failure')
104
+
63
105
  data = JSON.parse(response.body, symbolize_names: true)[:data]
64
106
  {
65
107
  cookies: { PVEAuthCookie: data[:ticket] },
@@ -80,8 +122,14 @@ class ProxmoxAPI
80
122
  end
81
123
 
82
124
  def submit(method, url, data = {})
125
+ if /!$/.match? method
126
+ method = method.to_s.tr('!', '').to_sym
127
+ skip_raise = true
128
+ end
129
+
83
130
  @connection[url].__send__(method, *prepare_options(method, data)) do |response|
84
- # TODO: raise unless response.code == 200
131
+ raise_on_failure(response) unless skip_raise
132
+
85
133
  JSON.parse(response.body, symbolize_names: true)[:data]
86
134
  end
87
135
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec'
4
+
5
+ describe 'ApiPath' do
6
+ before(:each) do
7
+ @api_object = double('ProxmoxAPI')
8
+ allow(@api_object).to receive(:is_a?).with(ProxmoxAPI) { true }
9
+ end
10
+
11
+ it 'raises exception when object is not ProxmoxAPI' do
12
+ [1, 'String', Class].each do |item|
13
+ expect { ProxmoxAPI::ApiPath.new(item) }.to raise_error(ArgumentError)
14
+ end
15
+ end
16
+
17
+ it 'collects api path using methods' do
18
+ expect(ProxmoxAPI::ApiPath.new(@api_object).ticket.to_s).to eq 'ticket'
19
+ expect(ProxmoxAPI::ApiPath.new(@api_object).nodes.pve1.to_s).to eq 'nodes/pve1'
20
+ end
21
+
22
+ it 'collects api path using []' do
23
+ expect(ProxmoxAPI::ApiPath.new(@api_object)[:ticket].to_s).to eq 'ticket'
24
+ expect(ProxmoxAPI::ApiPath.new(@api_object)[:nodes]['pve1'][15].to_s).to eq 'nodes/pve1/15'
25
+ end
26
+
27
+ it 'collects api path combining [] and methods' do
28
+ expect(ProxmoxAPI::ApiPath.new(@api_object).nodes['pve1'].lxc.to_s).to eq 'nodes/pve1/lxc'
29
+ end
30
+
31
+ %i[get post delete put].each do |method|
32
+ it "should send #{method} to ProxmoxAPI" do
33
+ expect(@api_object).to receive(:submit).with(method, 'nodes/pve')
34
+ ProxmoxAPI::ApiPath.new(@api_object).nodes.pve.__send__(method)
35
+ end
36
+
37
+ it "should send #{method}! to ProxmoxAPI" do
38
+ expect(@api_object).to receive(:submit).with("#{method}!".to_sym, 'nodes/pve')
39
+ ProxmoxAPI::ApiPath.new(@api_object).nodes.pve.__send__("#{method}!")
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'proxmox_api'
4
+
5
+ # This file was generated by the `rspec --init` command. Conventionally, all
6
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
7
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
8
+ # this file to always be loaded, without a need to explicitly require it in any
9
+ # files.
10
+ #
11
+ # Given that it is always loaded, you are encouraged to keep this file as
12
+ # light-weight as possible. Requiring heavyweight dependencies from this file
13
+ # will add to the boot time of your test suite on EVERY test run, even for an
14
+ # individual file that may not need all of that loaded. Instead, consider making
15
+ # a separate helper file that requires the additional dependencies and performs
16
+ # the additional setup, and require it from the spec files that actually need
17
+ # it.
18
+ #
19
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
20
+ RSpec.configure do |config|
21
+ # rspec-expectations config goes here. You can use an alternate
22
+ # assertion/expectation library such as wrong or the stdlib/minitest
23
+ # assertions if you prefer.
24
+ config.expect_with :rspec do |expectations|
25
+ # This option will default to `true` in RSpec 4. It makes the `description`
26
+ # and `failure_message` of custom matchers include text for helper methods
27
+ # defined using `chain`, e.g.:
28
+ # be_bigger_than(2).and_smaller_than(4).description
29
+ # # => "be bigger than 2 and smaller than 4"
30
+ # ...rather than:
31
+ # # => "be bigger than 2"
32
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
33
+ end
34
+
35
+ # rspec-mocks config goes here. You can use an alternate test double
36
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
37
+ config.mock_with :rspec do |mocks|
38
+ # Prevents you from mocking or stubbing a method that does not exist on
39
+ # a real object. This is generally recommended, and will default to
40
+ # `true` in RSpec 4.
41
+ mocks.verify_partial_doubles = true
42
+ end
43
+
44
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
45
+ # have no way to turn it off -- the option exists only for backwards
46
+ # compatibility in RSpec 3). It causes shared context metadata to be
47
+ # inherited by the metadata hash of host groups and examples, rather than
48
+ # triggering implicit auto-inclusion in groups with matching metadata.
49
+ config.shared_context_metadata_behavior = :apply_to_host_groups
50
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: proxmox-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eugene Lapeko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-27 00:00:00.000000000 Z
11
+ date: 2021-03-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -38,7 +38,49 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2.1'
41
- description: A library to manage Proxmox VE cluster using APIv2
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Proxmox VE REST API wrapper
42
84
  email: eugene@lapeko.info
43
85
  executables: []
44
86
  extensions: []
@@ -47,6 +89,8 @@ files:
47
89
  - Gemfile
48
90
  - LICENSE
49
91
  - lib/proxmox_api.rb
92
+ - spec/api_path_spec.rb
93
+ - spec/spec_helper.rb
50
94
  homepage: https://github.com/L-Eugene/proxmox-api
51
95
  licenses:
52
96
  - MIT
@@ -69,5 +113,7 @@ requirements: []
69
113
  rubygems_version: 3.0.8
70
114
  signing_key:
71
115
  specification_version: 4
72
- summary: A library to manage Proxmox VE cluster
73
- test_files: []
116
+ summary: Proxmox VE REST API wrapper
117
+ test_files:
118
+ - spec/spec_helper.rb
119
+ - spec/api_path_spec.rb