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 +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +3 -0
- data/lib/proxmox/client.rb +97 -13
- data/lib/proxmox/resources/cluster.rb +47 -0
- data/lib/proxmox/resources/clusters/acme.rb +18 -0
- data/lib/proxmox/resources/clusters/backup.rb +18 -0
- data/lib/proxmox/resources/node.rb +7 -0
- data/lib/proxmox/version.rb +1 -1
- data/lib/proxmox.rb +3 -0
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 366fb7b7ffeb686acc3a60998150f76bd28422038f8df24581b25cc0181819b0
|
4
|
+
data.tar.gz: 7cf6a08e8838aae0f74f9b6e0e5a7e44decbc1fabea47f16e6ddf433bd5cd143
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0b557b203e667b509053a55c9fb921b92bb3b7895a57e5e89117ad93339cc7ccaf2a69990ed0ecb527b9bf5f0bf2f82367f34e75b121b235bb03f547be932a1e
|
7
|
+
data.tar.gz: 2da70d05399e669f1a804d50aac56900f8a2f0300f61450eb43341fd891eff1bbfa5c9fa79b8991ba1f9b296e80d5a521357705d98bc2090555168a61b114d5e
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# Proxmox
|
2
2
|
|
3
|
+
[](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
|
|
data/lib/proxmox/client.rb
CHANGED
@@ -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
|
-
|
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
|
31
|
+
def login
|
17
32
|
resp = http.post("/api2/json/access/ticket",
|
18
|
-
{ username: "#{
|
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
|
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
|
-
|
26
|
-
|
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
|
-
|
48
|
+
response = perform_http_call(method, path, params, body)
|
34
49
|
|
35
|
-
|
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
|
data/lib/proxmox/version.rb
CHANGED
data/lib/proxmox.rb
CHANGED
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.
|
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:
|
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.
|
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: []
|