proxmox-sdk 0.1.0 → 0.1.2

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: c7fa64e7b8d1feec0ae521242312a0c2d46d122435b15b6053bebe6105661dbc
4
- data.tar.gz: e2cd741a0e09a87b78416d39bfb55d6f9815c95a9fd83d62a6e7bf80386c47fe
3
+ metadata.gz: 366fb7b7ffeb686acc3a60998150f76bd28422038f8df24581b25cc0181819b0
4
+ data.tar.gz: 7cf6a08e8838aae0f74f9b6e0e5a7e44decbc1fabea47f16e6ddf433bd5cd143
5
5
  SHA512:
6
- metadata.gz: 96a721ba56f055791c9281e9dd0d007944c3ee0de6e2889c7a5dc2675a70724a9b2dea4da79eb001597e6c6a9b190347379089bdcc90648780f454eeccdc8edc
7
- data.tar.gz: 104b3087f769b3a3da6a15ca6a5e2e2f5049a8a07fbf0da719b54475bc80741b38ba7b6edd50a699f0760ea31ecb2f381270e74a09bbf4cc2f9bbfa4b03b62b3
6
+ metadata.gz: 0b557b203e667b509053a55c9fb921b92bb3b7895a57e5e89117ad93339cc7ccaf2a69990ed0ecb527b9bf5f0bf2f82367f34e75b121b235bb03f547be932a1e
7
+ data.tar.gz: 2da70d05399e669f1a804d50aac56900f8a2f0300f61450eb43341fd891eff1bbfa5c9fa79b8991ba1f9b296e80d5a521357705d98bc2090555168a61b114d5e
data/CHANGELOG.md CHANGED
@@ -3,3 +3,8 @@
3
3
  ## [0.1.0] - 2025-09-30
4
4
 
5
5
  - Initial release
6
+
7
+ ## [0.1.1] - 2025-09-30
8
+
9
+ - Add Cluster functionallity
10
+ - Add Node functionallity
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # Proxmox
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/proxmox-sdk.svg)](https://badge.fury.io/rb/proxmox-sdk)
4
+
5
+ A lightweight Ruby gem that provides a clean, idiomatic interface to the Proxmox VE REST API. It handles authentication, token management, and all common API endpoints (nodes, virtual machines, storage, containers, etc.) so you can focus on building automation, orchestration, or custom tooling without dealing with raw HTTP calls.
3
6
 
4
7
  ## Installation
5
8
 
@@ -1,42 +1,123 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "faraday"
4
+ require "json"
5
+ require "time"
4
6
 
5
7
  module Proxmox
6
8
  # Proxmox SDK Http Client
7
9
  class Client
10
+ # Konstanten für die Gültigkeit des Tokens
11
+ # Proxmox Tickets sind standardmäßig 2 Stunden (7200 Sekunden) gültig.
12
+ TOKEN_VALIDITY_SECONDS = 7200
13
+ # Wir erneuern den Token 5 Minuten (300 Sekunden) vor Ablauf.
14
+ RENEWAL_BUFFER_SECONDS = 300
15
+
8
16
  attr_reader :ticket, :csrf_token, :base_url
9
17
 
10
18
  def initialize(base_url:, username:, password:, realm: "pam", ignore_ssl: false)
11
19
  @base_url = base_url
12
20
  @verify_ssl = !ignore_ssl
13
- login(username, password, realm)
21
+
22
+ # Anmeldedaten für die automatische Erneuerung speichern
23
+ @username = username
24
+ @password = password
25
+ @realm = realm
26
+
27
+ # Initiales Login
28
+ login
14
29
  end
15
30
 
16
- def login(user, pass, realm)
31
+ def login
17
32
  resp = http.post("/api2/json/access/ticket",
18
- { username: "#{user}@#{realm}", password: pass })
33
+ { username: "#{@username}@#{@realm}", password: @password })
34
+
35
+ raise "Login failed: #{resp.body}" unless resp.success?
36
+
19
37
  data = JSON.parse(resp.body)["data"]
20
- @ticket = data["ticket"]
38
+ @ticket = data["ticket"]
21
39
  @csrf_token = data["CSRFPreventionToken"]
40
+ # Zeitstempel der Ticketerstellung speichern
41
+ @ticket_creation_time = Time.now
22
42
  end
23
43
 
24
44
  def request(method, path, params = {}, body = nil)
25
- response = http.send(method) do |req|
26
- req.url "/api2/json#{path}"
27
- req.headers["Cookie"] = "PVEAuthCookie=#{ticket}"
28
- req.headers["CSRFPreventionToken"] = csrf_token if %i[post put delete].include?(method)
29
- req.params.update(params) if method == :get
30
- req.body = body.to_json if body
31
- end
45
+ # Vor jeder Anfrage die Gültigkeit des Tokens prüfen und ggf. erneuern
46
+ ensure_token_validity
32
47
 
33
- raise ApiError, response.body unless response.success?
48
+ response = perform_http_call(method, path, params, body)
34
49
 
35
- JSON.parse(response.body)["data"]
50
+ ensure_success!(response)
51
+ extract_data(response)
36
52
  end
37
53
 
38
54
  private
39
55
 
56
+ # NEUE METHODE: Stellt sicher, dass der Token gültig ist
57
+ def ensure_token_validity
58
+ login if token_expired?
59
+ end
60
+
61
+ # NEUE METHODE: Prüft, ob der Token abgelaufen ist oder bald abläuft
62
+ def token_expired?
63
+ # Wenn noch kein Ticket erstellt wurde, nicht als abgelaufen betrachten
64
+ return false if @ticket_creation_time.nil?
65
+
66
+ # Berechne die Ablaufzeit (Erstellungszeit + Gültigkeit - Puffer)
67
+ renewal_time = @ticket_creation_time + TOKEN_VALIDITY_SECONDS - RENEWAL_BUFFER_SECONDS
68
+
69
+ # Ist die aktuelle Zeit nach der errechneten Erneuerungszeit?
70
+ Time.now > renewal_time
71
+ end
72
+
73
+ def perform_http_call(method, path, params, body)
74
+ http.send(method) do |req|
75
+ set_url(req, path)
76
+ add_cookie_header(req)
77
+ set_csrf_header(req, method)
78
+ set_query_params(req, method, params)
79
+ set_body(req, body)
80
+ end
81
+ end
82
+
83
+ def set_url(req, path)
84
+ req.url "/api2/json#{path}"
85
+ end
86
+
87
+ def add_cookie_header(req)
88
+ req.headers["Cookie"] = "PVEAuthCookie=#{ticket}"
89
+ end
90
+
91
+ def set_csrf_header(req, method)
92
+ return unless %i[post put delete].include?(method)
93
+
94
+ req.headers["CSRFPreventionToken"] = csrf_token
95
+ end
96
+
97
+ def set_query_params(req, method, params)
98
+ req.params.update(params) if method == :get && params.any?
99
+ end
100
+
101
+ def set_body(req, body)
102
+ req.body = body.to_json if body
103
+ end
104
+
105
+ def ensure_success!(response)
106
+ # Optional: Wenn ein 401 (Unauthorized) Fehler kommt, könnte man hier auch ein erneutes Login erzwingen.
107
+ # if response.status == 401
108
+ # login
109
+ # # Hier könnte man die Anfrage wiederholen.
110
+ # end
111
+ raise "ApiError: #{response.body}" unless response.success?
112
+ end
113
+
114
+ def extract_data(response)
115
+ # Sicherstellen, dass der Body nicht leer ist, bevor geparst wird
116
+ return nil if response.body.nil? || response.body.empty?
117
+
118
+ JSON.parse(response.body)["data"]
119
+ end
120
+
40
121
  def http
41
122
  @http ||= Faraday.new(url: @base_url, ssl: { verify: @verify_ssl }) do |f|
42
123
  f.request :url_encoded
@@ -44,4 +125,7 @@ module Proxmox
44
125
  end
45
126
  end
46
127
  end
128
+
129
+ # Eigene Fehlerklasse (optional, aber guter Stil)
130
+ class ApiError < StandardError; end
47
131
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Proxmox
4
+ module Resources
5
+ # Proxmox Cluster Class
6
+ class Cluster
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ def log(max: nil)
12
+ params = {}
13
+ params[:max] = max unless max.nil?
14
+
15
+ @client.request(:get, "/cluster/log", params)
16
+ end
17
+
18
+ def nextid(vmid: nil)
19
+ params = {}
20
+ params[:vmid] = vmid unless vmid.nil?
21
+
22
+ @client.request(:get, "/cluster/nextid", params)
23
+ end
24
+
25
+ def options
26
+ @client.request(:get, "/cluster/options")
27
+ end
28
+
29
+ def resources
30
+ @client.request(:get, "/cluster/resources")
31
+ end
32
+
33
+ def status
34
+ @client.request(:get, "/cluster/status")
35
+ end
36
+
37
+ def tasks
38
+ @client.request(:get, "/cluster/tasks")
39
+ end
40
+
41
+ # Getting all Nodes
42
+ def nodes
43
+ @client.request(:get, "/nodes")
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Proxmox
4
+ module Resources
5
+ module Clusters
6
+ # Proxmox Cluster Acme class
7
+ class Acme
8
+ def initialize(client)
9
+ @client = client
10
+ end
11
+
12
+ def tos
13
+ @client.request(:get, "/cluster/acme/tos")
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Proxmox
4
+ module Resources
5
+ module Clusters
6
+ # Proxmox Cluster Acme class
7
+ class Backup
8
+ def initialize(client)
9
+ @client = client
10
+ end
11
+
12
+ def all
13
+ @client.request(:get, "/cluster/backup")
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -9,10 +9,17 @@ module Proxmox
9
9
  @node = node_name
10
10
  end
11
11
 
12
+ # Getting status of the Node
12
13
  def status
13
14
  @client.request(:get, "/nodes/#{@node}/status")
14
15
  end
15
16
 
17
+ # Getting a list of updates for the Node
18
+ def updates
19
+ @client.request(:get, "/nodes/#{@node}/apt/update")
20
+ end
21
+
22
+ # Creating Resources
16
23
  def create_vm(params)
17
24
  @client.request(:post, "/nodes/#{@node}/qemu", {}, params)
18
25
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Proxmox
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.2"
5
5
  end
data/lib/proxmox.rb CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  require "proxmox/version"
4
4
  require "proxmox/client"
5
+ require "proxmox/resources/cluster"
6
+ require "proxmox/resources/clusters/acme"
7
+ require "proxmox/resources/clusters/backup"
5
8
  require "proxmox/resources/node"
6
9
 
7
10
  module Proxmox
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: proxmox-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Wellnitz
8
+ autorequire:
8
9
  bindir: exe
9
10
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2025-10-08 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: faraday
@@ -36,6 +37,9 @@ files:
36
37
  - Rakefile
37
38
  - lib/proxmox.rb
38
39
  - lib/proxmox/client.rb
40
+ - lib/proxmox/resources/cluster.rb
41
+ - lib/proxmox/resources/clusters/acme.rb
42
+ - lib/proxmox/resources/clusters/backup.rb
39
43
  - lib/proxmox/resources/node.rb
40
44
  - lib/proxmox/version.rb
41
45
  - sig/proxmox.rbs
@@ -47,6 +51,7 @@ metadata:
47
51
  homepage_uri: https://github.com/alexohneander/proxmox-sdk-ruby
48
52
  source_code_uri: https://github.com/alexohneander/proxmox-sdk-ruby
49
53
  changelog_uri: https://raw.githubusercontent.com/alexohneander/proxmox-sdk-ruby/refs/heads/main/CHANGELOG.md
54
+ post_install_message:
50
55
  rdoc_options: []
51
56
  require_paths:
52
57
  - lib
@@ -61,7 +66,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
61
66
  - !ruby/object:Gem::Version
62
67
  version: '0'
63
68
  requirements: []
64
- rubygems_version: 3.6.9
69
+ rubygems_version: 3.5.3
70
+ signing_key:
65
71
  specification_version: 4
66
72
  summary: A gem that provides a client interface for Proxmox
67
73
  test_files: []