proxmox 0.0.1
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.
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +24 -0
- data/Guardfile +19 -0
- data/LICENSE.txt +22 -0
- data/README.md +86 -0
- data/Rakefile +6 -0
- data/lib/proxmox.rb +355 -0
- data/lib/proxmox/version.rb +3 -0
- data/proxmox.gemspec +26 -0
- data/spec/lib/proxmox_spec.rb +227 -0
- data/spec/spec_helper.rb +29 -0
- metadata +148 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in proxmox.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
group :developpement do
|
7
|
+
gem "guard"
|
8
|
+
gem "guard-rspec"
|
9
|
+
gem "guard-bundler"
|
10
|
+
|
11
|
+
gem "growl"
|
12
|
+
gem "spork"
|
13
|
+
gem "guard-spork"
|
14
|
+
|
15
|
+
gem "yard"
|
16
|
+
gem "redcarpet"
|
17
|
+
gem "guard-yard"
|
18
|
+
end
|
19
|
+
|
20
|
+
group :test do
|
21
|
+
gem "simplecov"
|
22
|
+
gem "json", '~> 1.7.7'
|
23
|
+
gem "coveralls"
|
24
|
+
end
|
data/Guardfile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard 'bundler' do
|
5
|
+
watch('Gemfile')
|
6
|
+
watch(/^.+\.gemspec/)
|
7
|
+
end
|
8
|
+
|
9
|
+
guard :rspec do
|
10
|
+
watch(%r{^spec/.+_spec\.rb$})
|
11
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
12
|
+
watch('spec/spec_helper.rb') { "spec" }
|
13
|
+
end
|
14
|
+
|
15
|
+
group :docs do
|
16
|
+
guard 'yard' do
|
17
|
+
watch(%r{lib/.+\.rb})
|
18
|
+
end
|
19
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Nicolas Ledez
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
# Proxmox
|
2
|
+
|
3
|
+
You need to manage a proxmox host with Ruby? This library is for you.
|
4
|
+
|
5
|
+
!!! Warning, it's a experimental version. Some methods could be renamed !!!
|
6
|
+
|
7
|
+
Current build:
|
8
|
+
[](https://travis-ci.org/nledez/proxmox)
|
9
|
+
[](https://coveralls.io/r/nledez/proxmox)
|
10
|
+
[](https://gemnasium.com/nledez/proxmox)
|
11
|
+
[](https://codeclimate.com/github/nledez/proxmox)
|
12
|
+
|
13
|
+
Inspirated from:
|
14
|
+
https://bitbucket.org/jmoratilla/knife-proxmox/ but I would like to have
|
15
|
+
the same without chef.
|
16
|
+
https://github.com/maxschulze/uv_proxmox but listing some task does not
|
17
|
+
work for me. No tests, use ssh.
|
18
|
+
|
19
|
+
So I start to create one fully tested (TDD method).
|
20
|
+
|
21
|
+
|
22
|
+
## Installation
|
23
|
+
|
24
|
+
Add this line to your application's Gemfile:
|
25
|
+
|
26
|
+
gem 'proxmox'
|
27
|
+
|
28
|
+
And then execute:
|
29
|
+
|
30
|
+
$ bundle
|
31
|
+
|
32
|
+
Or install it yourself as:
|
33
|
+
|
34
|
+
$ gem install proxmox
|
35
|
+
|
36
|
+
## Usage
|
37
|
+
|
38
|
+
require 'awesome_print'
|
39
|
+
require 'proxmox'
|
40
|
+
|
41
|
+
def wait_status(server1, task)
|
42
|
+
puts task
|
43
|
+
while server1.task_status(task) == "running"
|
44
|
+
puts '.'
|
45
|
+
sleep 1
|
46
|
+
end
|
47
|
+
|
48
|
+
puts server1.task_status(task)
|
49
|
+
end
|
50
|
+
|
51
|
+
server1 =
|
52
|
+
Proxmox::Proxmox.new("https://the-proxmox-server:8006/api2/json/",
|
53
|
+
"node", "root", "secret", "pam")
|
54
|
+
ap server1.templates
|
55
|
+
|
56
|
+
vm1 = server1.openvz_post("ubuntu-10.04-standard_10.04-4_i386", 200)
|
57
|
+
wait_status(server1, vm1)
|
58
|
+
|
59
|
+
ap server1.openvz_vm_status(200)
|
60
|
+
vm1 = server1.openvz_vm_start(200)
|
61
|
+
begin
|
62
|
+
wait_status(server1, vm1)
|
63
|
+
rescue
|
64
|
+
end
|
65
|
+
sleep 5
|
66
|
+
ap server1.openvz_vm_shutdown(200)
|
67
|
+
begin
|
68
|
+
wait_status(server1, vm1)
|
69
|
+
rescue
|
70
|
+
end
|
71
|
+
sleep 5
|
72
|
+
ap server1.openvz_vm_status(200)
|
73
|
+
|
74
|
+
vm1 = server1.openvz_delete(200)
|
75
|
+
wait_status(server1, vm1)
|
76
|
+
|
77
|
+
## Contributing
|
78
|
+
|
79
|
+
1. Fork it
|
80
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
81
|
+
3. Create spec (in file spec/lib/proxmox_spec.rb)
|
82
|
+
4. Write your code (in lib/proxmox.rb)
|
83
|
+
5. Check spec & coverage (`bundle exec rspec` or `bundle exec guard`)
|
84
|
+
6. Commit your changes (`git commit -am 'Add some feature'`)
|
85
|
+
7. Push to the branch (`git push origin my-new-feature`)
|
86
|
+
8. Create new Pull Request
|
data/Rakefile
ADDED
data/lib/proxmox.rb
ADDED
@@ -0,0 +1,355 @@
|
|
1
|
+
require "proxmox/version"
|
2
|
+
require 'rest_client'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
# This module encapsulates ability to manage Proxmox server
|
6
|
+
module Proxmox
|
7
|
+
# Object to manage Proxmox server
|
8
|
+
class Proxmox
|
9
|
+
# Return connection status
|
10
|
+
# - connected
|
11
|
+
# - error
|
12
|
+
attr_reader :connection_status
|
13
|
+
|
14
|
+
# Create a object to manage a Proxmox server through API
|
15
|
+
#
|
16
|
+
# :call-seq:
|
17
|
+
# new(pve_cluster, node, username, password, realm) -> Proxmox
|
18
|
+
#
|
19
|
+
# Example:
|
20
|
+
#
|
21
|
+
# Proxmox::Proxmox.new("https://the-proxmox-server:8006/api2/json/", "node", "root", "secret", "pam")
|
22
|
+
#
|
23
|
+
def initialize(pve_cluster, node, username, password, realm)
|
24
|
+
@pve_cluster = pve_cluster
|
25
|
+
@node = node
|
26
|
+
@username = username
|
27
|
+
@password = password
|
28
|
+
@realm = realm
|
29
|
+
@connection_status = "error"
|
30
|
+
@site = RestClient::Resource.new(@pve_cluster)
|
31
|
+
@auth_params = create_ticket
|
32
|
+
end
|
33
|
+
|
34
|
+
# Get task status
|
35
|
+
#
|
36
|
+
# :call-seq:
|
37
|
+
# task_status(task-id) -> String
|
38
|
+
#
|
39
|
+
# - taksstatus
|
40
|
+
# - taskstatus:exitstatus
|
41
|
+
#
|
42
|
+
# Example:
|
43
|
+
#
|
44
|
+
# taskstatus "UPID:localhost:00051DA0:119EAABC:521CCB19:vzcreate:203:root@pam:"
|
45
|
+
#
|
46
|
+
# Examples return:
|
47
|
+
# - running
|
48
|
+
# - stopped:OK
|
49
|
+
#
|
50
|
+
def task_status(upid)
|
51
|
+
data = http_action_get "nodes/#{@node}/tasks/#{URI::encode upid}/status"
|
52
|
+
status = data['status']
|
53
|
+
exitstatus = data['exitstatus']
|
54
|
+
if exitstatus
|
55
|
+
"#{status}:#{exitstatus}"
|
56
|
+
else
|
57
|
+
"#{status}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Get template list
|
62
|
+
#
|
63
|
+
# :call-seq:
|
64
|
+
# templates -> Hash
|
65
|
+
#
|
66
|
+
# Return a Hash of all templates
|
67
|
+
#
|
68
|
+
# Example:
|
69
|
+
#
|
70
|
+
# templates
|
71
|
+
#
|
72
|
+
# Example return:
|
73
|
+
#
|
74
|
+
# {
|
75
|
+
# "ubuntu-10.04-standard_10.04-4_i386" => {
|
76
|
+
# "format" => "tgz",
|
77
|
+
# "content" => "vztmpl",
|
78
|
+
# "volid" => "local:vztmpl/ubuntu-10.04-standard_10.04-4_i386.tar.gz",
|
79
|
+
# "size" => 142126884
|
80
|
+
# },
|
81
|
+
# "ubuntu-12.04-standard_12.04-1_i386" => {
|
82
|
+
# "format" => "tgz",
|
83
|
+
# "content" => "vztmpl",
|
84
|
+
# "volid" => "local:vztmpl/ubuntu-12.04-standard_12.04-1_i386.tar.gz",
|
85
|
+
# "size" => 130040792
|
86
|
+
# }
|
87
|
+
# }
|
88
|
+
#
|
89
|
+
def templates
|
90
|
+
data = http_action_get "nodes/#{@node}/storage/local/content"
|
91
|
+
template_list = Hash.new
|
92
|
+
data.each do |ve|
|
93
|
+
name = ve['volid'].gsub(/^local:vztmpl\/(.*).tar.gz$/, '\1')
|
94
|
+
template_list[name] = ve
|
95
|
+
end
|
96
|
+
template_list
|
97
|
+
end
|
98
|
+
|
99
|
+
# Get CT list
|
100
|
+
#
|
101
|
+
# :call-seq:
|
102
|
+
# openvz_get -> Hash
|
103
|
+
#
|
104
|
+
# Return a Hash of all openvz container
|
105
|
+
#
|
106
|
+
# Example:
|
107
|
+
#
|
108
|
+
# openvz_get
|
109
|
+
#
|
110
|
+
# Example return:
|
111
|
+
# {
|
112
|
+
# "101" => {
|
113
|
+
# "maxswap" => 536870912,
|
114
|
+
# "disk" => 405168128,
|
115
|
+
# "ip" => "192.168.1.5",
|
116
|
+
# "status" => "running",
|
117
|
+
# "netout" => 272,
|
118
|
+
# "maxdisk" => 4294967296,
|
119
|
+
# "maxmem" => 536870912,
|
120
|
+
# "uptime" => 3068073,
|
121
|
+
# "swap" => 0,
|
122
|
+
# "vmid" => "101",
|
123
|
+
# "nproc" => "10",
|
124
|
+
# "diskread" => 0,
|
125
|
+
# "cpu" => 0.00031670581100007,
|
126
|
+
# "netin" => 0,
|
127
|
+
# "name" => "test2.domain.com",
|
128
|
+
# "failcnt" => 0,
|
129
|
+
# "diskwrite" => 0,
|
130
|
+
# "mem" => 22487040,
|
131
|
+
# "type" => "openvz",
|
132
|
+
# "cpus" => 1
|
133
|
+
# },
|
134
|
+
# [...]
|
135
|
+
# }
|
136
|
+
def openvz_get
|
137
|
+
data = http_action_get "nodes/#{@node}/openvz"
|
138
|
+
ve_list = Hash.new
|
139
|
+
data.each do |ve|
|
140
|
+
ve_list[ve['vmid']] = ve
|
141
|
+
end
|
142
|
+
ve_list
|
143
|
+
end
|
144
|
+
|
145
|
+
# Create CT container
|
146
|
+
#
|
147
|
+
# :call-seq:
|
148
|
+
# openvz_post(ostemplate, vmid) -> String
|
149
|
+
# openvz_post(ostemplate, vmid, options) -> String
|
150
|
+
#
|
151
|
+
# Return a String as task ID
|
152
|
+
#
|
153
|
+
# Examples:
|
154
|
+
#
|
155
|
+
# openvz_post("ubuntu-10.04-standard_10.04-4_i386", 200)
|
156
|
+
# openvz_post("ubuntu-10.04-standard_10.04-4_i386", 200, {'hostname' => 'test.test.com', 'password' => 'testt' })
|
157
|
+
#
|
158
|
+
# Example return:
|
159
|
+
#
|
160
|
+
# UPID:localhost:000BC66A:1279E395:521EFC4E:vzcreate:200:root@pam:
|
161
|
+
#
|
162
|
+
def openvz_post(ostemplate, vmid, config = {})
|
163
|
+
config['vmid'] = vmid
|
164
|
+
config['ostemplate'] = "local%3Avztmpl%2F#{ostemplate}.tar.gz"
|
165
|
+
vm_definition = config.to_a.map { |v| v.join '=' }.join '&'
|
166
|
+
|
167
|
+
http_action_post("nodes/#{@node}/openvz", vm_definition)
|
168
|
+
end
|
169
|
+
|
170
|
+
# Delete CT
|
171
|
+
#
|
172
|
+
# :call-seq:
|
173
|
+
# openvz_delete(vmid) -> String
|
174
|
+
#
|
175
|
+
# Return a string as task ID
|
176
|
+
#
|
177
|
+
# Example:
|
178
|
+
#
|
179
|
+
# openvz_delete(200)
|
180
|
+
#
|
181
|
+
# Example return:
|
182
|
+
#
|
183
|
+
# UPID:localhost:000BC66A:1279E395:521EFC4E:vzdelete:200:root@pam:
|
184
|
+
#
|
185
|
+
def openvz_delete(vmid)
|
186
|
+
http_action_delete "nodes/#{@node}/openvz/#{vmid}"
|
187
|
+
end
|
188
|
+
|
189
|
+
# Get CT status
|
190
|
+
#
|
191
|
+
# :call-seq:
|
192
|
+
# openvz_delete(vmid) -> String
|
193
|
+
#
|
194
|
+
# Return a string as task ID
|
195
|
+
#
|
196
|
+
# Example:
|
197
|
+
#
|
198
|
+
# openvz_delete(200)
|
199
|
+
#
|
200
|
+
# Example return:
|
201
|
+
#
|
202
|
+
# UPID:localhost:000BC66A:1279E395:521EFC4E:vzdelete:200:root@pam:
|
203
|
+
#
|
204
|
+
def openvz_status(vmid)
|
205
|
+
http_action_get "nodes/#{@node}/openvz/#{vmid}/status/current"
|
206
|
+
end
|
207
|
+
|
208
|
+
# Start CT
|
209
|
+
#
|
210
|
+
# :call-seq:
|
211
|
+
# openvz_start(vmid) -> String
|
212
|
+
#
|
213
|
+
# Return a string as task ID
|
214
|
+
#
|
215
|
+
# Example:
|
216
|
+
#
|
217
|
+
# openvz_start(200)
|
218
|
+
#
|
219
|
+
# Example return:
|
220
|
+
#
|
221
|
+
# UPID:localhost:000BC66A:1279E395:521EFC4E:vzstart:200:root@pam:
|
222
|
+
#
|
223
|
+
def openvz_start(vmid)
|
224
|
+
http_action_post "nodes/#{@node}/openvz/#{vmid}/status/start"
|
225
|
+
end
|
226
|
+
|
227
|
+
# Stop CT
|
228
|
+
#
|
229
|
+
# :call-seq:
|
230
|
+
# openvz_stop(vmid) -> String
|
231
|
+
#
|
232
|
+
# Return a string as task ID
|
233
|
+
#
|
234
|
+
# Example:
|
235
|
+
#
|
236
|
+
# openvz_stop(200)
|
237
|
+
#
|
238
|
+
# Example return:
|
239
|
+
#
|
240
|
+
# UPID:localhost:000BC66A:1279E395:521EFC4E:vzstop:200:root@pam:
|
241
|
+
#
|
242
|
+
def openvz_stop(vmid)
|
243
|
+
http_action_post "nodes/#{@node}/openvz/#{vmid}/status/stop"
|
244
|
+
end
|
245
|
+
|
246
|
+
# Shutdown CT
|
247
|
+
#
|
248
|
+
# :call-seq:
|
249
|
+
# openvz_shutdown(vmid) -> String
|
250
|
+
#
|
251
|
+
# Return a string as task ID
|
252
|
+
#
|
253
|
+
# Example:
|
254
|
+
#
|
255
|
+
# openvz_shutdown(200)
|
256
|
+
#
|
257
|
+
# Example return:
|
258
|
+
#
|
259
|
+
# UPID:localhost:000BC66A:1279E395:521EFC4E:vzshutdown:200:root@pam:
|
260
|
+
#
|
261
|
+
def openvz_shutdown(vmid)
|
262
|
+
http_action_post "nodes/#{@node}/openvz/#{vmid}/status/shutdown"
|
263
|
+
end
|
264
|
+
|
265
|
+
# Get CT config
|
266
|
+
#
|
267
|
+
# :call-seq:
|
268
|
+
# openvz_config(vmid) -> String
|
269
|
+
#
|
270
|
+
# Return a string as task ID
|
271
|
+
#
|
272
|
+
# Example:
|
273
|
+
#
|
274
|
+
# openvz_config(200)
|
275
|
+
#
|
276
|
+
# Example return:
|
277
|
+
#
|
278
|
+
# {
|
279
|
+
# "quotaugidlimit" => 0,
|
280
|
+
# "disk" => 0,
|
281
|
+
# "ostemplate" => "ubuntu-10.04-standard_10.04-4_i386.tar.gz",
|
282
|
+
# "hostname" => "test.test.com",
|
283
|
+
# "nameserver" => "127.0.0.1 192.168.1.1",
|
284
|
+
# "memory" => 256,
|
285
|
+
# "searchdomain" => "domain.com",
|
286
|
+
# "onboot" => 0,
|
287
|
+
# "cpuunits" => 1000,
|
288
|
+
# "swap" => 256,
|
289
|
+
# "quotatime" => 0,
|
290
|
+
# "digest" => "e7e6e21a215af6b9da87a8ecb934956b8983f960",
|
291
|
+
# "cpus" => 1,
|
292
|
+
# "storage" => "local"
|
293
|
+
# }
|
294
|
+
#
|
295
|
+
def openvz_config(vmid)
|
296
|
+
http_action_get "nodes/#{@node}/openvz/#{vmid}/config"
|
297
|
+
end
|
298
|
+
|
299
|
+
private
|
300
|
+
# Methods manages auth
|
301
|
+
def create_ticket
|
302
|
+
post_param = { :username=>@username, :realm=>@realm, :password=>@password }
|
303
|
+
@site['access/ticket'].post post_param do |response, request, result, &block|
|
304
|
+
if response.code == 200
|
305
|
+
extract_ticket response
|
306
|
+
else
|
307
|
+
@connection_status = "error"
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
# Method create ticket
|
313
|
+
def extract_ticket(response)
|
314
|
+
data = JSON.parse(response.body)
|
315
|
+
ticket = data['data']['ticket']
|
316
|
+
csrf_prevention_token = data['data']['CSRFPreventionToken']
|
317
|
+
unless ticket.nil?
|
318
|
+
token = 'PVEAuthCookie=' + ticket.gsub!(/:/,'%3A').gsub!(/=/,'%3D')
|
319
|
+
end
|
320
|
+
@connection_status = "connected"
|
321
|
+
{
|
322
|
+
:CSRFPreventionToken => csrf_prevention_token,
|
323
|
+
:cookie => token
|
324
|
+
}
|
325
|
+
end
|
326
|
+
|
327
|
+
# Extract data or return error
|
328
|
+
def check_response(response)
|
329
|
+
if (response.code == 200) then
|
330
|
+
JSON.parse(response.body)['data']
|
331
|
+
else
|
332
|
+
"NOK: error code = " + response.code.to_s
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
# Methods manage http dialogs
|
337
|
+
def http_action_post(url, data = "")
|
338
|
+
@site[url].post data, @auth_params do |response, request, result, &block|
|
339
|
+
check_response response
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
def http_action_get(url)
|
344
|
+
@site[url].get @auth_params do |response, request, result, &block|
|
345
|
+
check_response response
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
def http_action_delete(url)
|
350
|
+
@site[url].delete @auth_params do |response, request, result, &block|
|
351
|
+
check_response response
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
data/proxmox.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'proxmox/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "proxmox"
|
8
|
+
spec.version = Proxmox::VERSION
|
9
|
+
spec.authors = ["Nicolas Ledez"]
|
10
|
+
spec.email = ["github@ledez.net"]
|
11
|
+
spec.description = %q{A library to drive a Proxmox host}
|
12
|
+
spec.summary = %q{You need to manage a proxmox host with Ruby? This library is for you.}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.add_dependency "rest-client", ">=1.6.7"
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
spec.add_development_dependency "rspec"
|
25
|
+
spec.add_development_dependency "webmock"
|
26
|
+
end
|
@@ -0,0 +1,227 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'webmock/rspec'
|
3
|
+
require 'proxmox'
|
4
|
+
|
5
|
+
describe Proxmox do
|
6
|
+
before(:each) do
|
7
|
+
@common_headers_in = { 'User-Agent' => 'Ruby',
|
8
|
+
'Cookie' => /.*/,
|
9
|
+
'Csrfpreventiontoken' => /.*/ }
|
10
|
+
@common_headers_out = { :connection => "close",
|
11
|
+
:server => "pve-api-daemon/3.0",
|
12
|
+
:content_type => "application/json;charset=UTF-8" }
|
13
|
+
|
14
|
+
# Common auth
|
15
|
+
stub_request(:post, "http://localhost:8006/api2/json/access/ticket").with(
|
16
|
+
:headers => {
|
17
|
+
'Content-Type' => 'application/x-www-form-urlencoded',
|
18
|
+
'User-Agent' => 'Ruby'
|
19
|
+
},
|
20
|
+
:body => {
|
21
|
+
"username" => "root",
|
22
|
+
"password" => "secret",
|
23
|
+
"realm" => "pam"
|
24
|
+
}
|
25
|
+
).to_return(
|
26
|
+
:status => 200,
|
27
|
+
:headers => @common_headers_out,
|
28
|
+
:body => '{"data":{"cap":{"dc":{"Sys.Audit":1},"access":{"Group.Allocate":1,"User.Modify":1},"nodes":{"Sys.Audit":1,"Sys.Syslog":1,"Sys.Console":1,"Sys.Modify":1,"Sys.PowerMgmt":1},"vms":{"VM.Backup":1,"VM.Allocate":1,"VM.Config.CPU":1,"VM.Config.Network":1,"VM.Migrate":1,"VM.Config.Memory":1,"VM.Config.Options":1,"Permissions.Modify":1,"VM.Monitor":1,"VM.Console":1,"VM.Config.Disk":1,"VM.Config.HWType":1,"VM.Clone":1,"VM.Snapshot":1,"VM.Audit":1,"VM.PowerMgmt":1,"VM.Config.CDROM":1},"storage":{"Datastore.AllocateTemplate":1,"Datastore.Allocate":1,"Datastore.Audit":1,"Permissions.Modify":1,"Datastore.AllocateSpace":1}},"CSRFPreventionToken":"51F00E60:Pnd0AHehuTE++j87nUz0nLuyW+0","ticket":"PVE:root@pam:51F00E60::OS5lBKlaabgnmekdbVY2JYAbd5Z/MPWCeZ9b33UwjsE1yVB1esIwUQoXJ4Xgb/+UVE9mtS2K3dJ65wyPDsGYTDc0TCl0VmdOGz7djXMlMy5ShRjXcX/GLs77LHXlLQOO+ED/jCoz0tHV55igNSBNMG2UrSLlTGvgm8zf1fNqAsVszrAWgeFu+e/1CLIfs//cWyimBuDx+r3m/NOjaoyeb2u63eBCPrWyEiCJZniMZDVnqqQcOm32tE2XQj4D2LS+xaHn2fdZDlcAo0uY4qVspKiMjf9g2AudRblkobCTf7KdhanIm0kCSqkvHJy2EMcAbxcqnGnjPiYSH0WYZMTnlA==","username":"root@pam"}}'
|
29
|
+
)
|
30
|
+
|
31
|
+
@server1 = Proxmox::Proxmox.new("http://localhost:8006/api2/json/", "localhost", "root", "secret", "pam")
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should connect to Proxmox server' do
|
35
|
+
# Bad auth
|
36
|
+
stub_request(:post, "http://localhost:8006/api2/json/access/ticket").with(
|
37
|
+
:headers => {
|
38
|
+
'Content-Type' => 'application/x-www-form-urlencoded',
|
39
|
+
'User-Agent' => 'Ruby'
|
40
|
+
},
|
41
|
+
:body => {
|
42
|
+
"username" => "root",
|
43
|
+
"password" => "bad",
|
44
|
+
"realm" => "pam"
|
45
|
+
}
|
46
|
+
).to_return(
|
47
|
+
:status => 500,
|
48
|
+
:headers => @common_headers_out,
|
49
|
+
:body => '{"data":null}'
|
50
|
+
)
|
51
|
+
@server1.connection_status.should == "connected"
|
52
|
+
|
53
|
+
server2 = Proxmox::Proxmox.new("http://localhost:8006/api2/json/", "localhost", "root", "bad", "pam")
|
54
|
+
server2.connection_status.should == "error"
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should get task status" do
|
58
|
+
# Status done
|
59
|
+
stub_request(:get, "http://localhost:8006/api2/json/nodes/localhost/tasks/UPID:localhost:00051DA0:119EAABB:521CCB19:vzcreate:200:root@pam:/status").with(
|
60
|
+
:headers => @common_headers_in).to_return(
|
61
|
+
:status => 200,
|
62
|
+
:headers => {
|
63
|
+
:connection => "close", :server => "pve-api-daemon/3.0", :content_type => "application/json;charset=UTF-8", },
|
64
|
+
:body => '{"data":{"exitstatus":"OK","status":"stopped","upid":"UPID:localhost:00051DA0:119EAABB:521CCB19:vzcreate:200:root@pam:","node":"localhost","pid":335264,"starttime":1377618713,"user":"root@pam","type":"vzcreate","id":"200","pstart":295611067}}'
|
65
|
+
)
|
66
|
+
|
67
|
+
# Status running
|
68
|
+
stub_request(:get, "http://localhost:8006/api2/json/nodes/localhost/tasks/UPID:localhost:00055DDA:11A99D07:521CE71F:vzcreate:200:root@pam:/status").with(
|
69
|
+
:headers => @common_headers_in).to_return(
|
70
|
+
:status => 200,
|
71
|
+
:headers => @common_headers_out,
|
72
|
+
:body => '{"data":{"status":"running","upid":"UPID:localhost:00055DDA:11A99D07:521CE71F:vzcreate:200:root@pam:","node":"localhost","pid":351706,"starttime":1377625887,"user":"root@pam","type":"vzcreate","id":"200","pstart":296328455}}'
|
73
|
+
)
|
74
|
+
|
75
|
+
# Get status
|
76
|
+
@server1.task_status("UPID:localhost:00051DA0:119EAABB:521CCB19:vzcreate:200:root@pam:").should be_eql "stopped:OK"
|
77
|
+
@server1.task_status("UPID:localhost:00055DDA:11A99D07:521CE71F:vzcreate:200:root@pam:").should be_eql "running"
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should get template list" do
|
81
|
+
# First template list
|
82
|
+
stub_request(:get, "http://localhost:8006/api2/json/nodes/localhost/storage/local/content").with(
|
83
|
+
:headers => @common_headers_in).to_return(
|
84
|
+
:status => 200,
|
85
|
+
:headers => @common_headers_out,
|
86
|
+
:body => '{"data":[{"format":"tgz","content":"vztmpl","volid":"local:vztmpl/ubuntu-10.04-standard_10.04-4_i386.tar.gz","size":142126884},{"format":"tgz","content":"vztmpl","volid":"local:vztmpl/ubuntu-12.04-standard_12.04-1_i386.tar.gz","size":130040792}]}'
|
87
|
+
)
|
88
|
+
|
89
|
+
@server1.templates.should be_an_instance_of Hash
|
90
|
+
@server1.templates.keys.sort.should be_eql [ 'ubuntu-10.04-standard_10.04-4_i386', 'ubuntu-12.04-standard_12.04-1_i386' ]
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should get openvz vm list" do
|
94
|
+
# First VM list
|
95
|
+
stub_request(:get, "http://localhost:8006/api2/json/nodes/localhost/openvz").with(
|
96
|
+
:headers => @common_headers_in).to_return(
|
97
|
+
:status => 200,
|
98
|
+
:headers => @common_headers_out,
|
99
|
+
:body => '{"data":[{"maxswap":536870912,"disk":404037632,"ip":"192.168.1.5","status":"running","netout":272,"maxdisk":4294967296,"maxmem":536870912,"uptime":3847,"swap":0,"vmid":"101","nproc":"10","diskread":0,"cpu":0.00183354942808597,"netin":0,"name":"test2.dummy.tld","failcnt":0,"diskwrite":0,"mem":21303296,"type":"openvz","cpus":1},{"maxswap":536870912,"disk":387186688,"ip":"192.168.1.1","status":"running","netout":272,"maxdisk":4294967296,"maxmem":536870912,"uptime":17120,"swap":0,"vmid":"100","nproc":"17","diskread":0,"cpu":0.000504170031344927,"netin":0,"name":"test.dummy.tld","failcnt":0,"diskwrite":0,"mem":27987968,"type":"openvz","cpus":1}]}'
|
100
|
+
)
|
101
|
+
|
102
|
+
# Second VM list
|
103
|
+
stub_request(:get, "http://localhost:8006/api2/json/nodes/otherone/openvz").with(
|
104
|
+
:headers => @common_headers_in).to_return(
|
105
|
+
:status => 200,
|
106
|
+
:headers => @common_headers_out,
|
107
|
+
:body => '{"data":[{"maxswap":536870912,"disk":404041728,"ip":"192.168.1.5","status":"running","netout":272,"maxdisk":4294967296,"maxmem":536870912,"uptime":6176,"swap":0,"vmid":"101","nproc":"10","diskread":0,"cpu":0.00161487378340585,"netin":0,"name":"test2.dummy.tld","failcnt":0,"diskwrite":0,"mem":21299200,"type":"openvz","cpus":1},{"maxswap":2147483648,"disk":0,"ip":"10.0.0.1","status":"stopped","netout":0,"maxdisk":10737418240,"maxmem":1073741824,"uptime":0,"swap":0,"vmid":"102","nproc":0,"diskread":0,"cpu":0,"netin":0,"name":"test3.other.domain","failcnt":0,"diskwrite":0,"mem":0,"type":"openvz","cpus":2},{"maxswap":536870912,"disk":387194880,"ip":"192.168.1.1","status":"running","netout":272,"maxdisk":4294967296,"maxmem":536870912,"uptime":19449,"swap":0,"vmid":"100","nproc":"17","diskread":0,"cpu":0.000589570582552814,"netin":0,"name":"test.dummy.tld","failcnt":0,"diskwrite":0,"mem":28282880,"type":"openvz","cpus":1}]}'
|
108
|
+
)
|
109
|
+
|
110
|
+
@server1.openvz_get.should be_an_instance_of Hash
|
111
|
+
@server1.openvz_get.keys.sort.should be_eql [ '100', '101' ]
|
112
|
+
|
113
|
+
server2 = Proxmox::Proxmox.new("http://localhost:8006/api2/json/", "otherone", "root", "secret", "pam")
|
114
|
+
server2.openvz_get.should be_an_instance_of Hash
|
115
|
+
server2.openvz_get.keys.sort.should be_eql [ '100', '101', '102' ]
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should create a container" do
|
119
|
+
# Create VM
|
120
|
+
stub_request(:post, "http://localhost:8006/api2/json/nodes/localhost/openvz").with(
|
121
|
+
:body => "vmid=200&ostemplate=local%3Avztmpl%2Fubuntu-10.04-standard_10.04-4_i386.tar.gz",
|
122
|
+
:headers => @common_headers_in).to_return(
|
123
|
+
:status => 200,
|
124
|
+
:headers => @common_headers_out,
|
125
|
+
:body => '{"data":"UPID:localhost:00051DA0:119EAABB:521CCB19:vzcreate:200:root@pam:"}'
|
126
|
+
)
|
127
|
+
|
128
|
+
stub_request(:post, "http://localhost:8006/api2/json/nodes/localhost/openvz").with(
|
129
|
+
:body => "hostname=vm1.domain.com&password=secret&memory=512&swap=512&disk=4&vmid=203&ostemplate=local%3Avztmpl%2Fubuntu-10.04-standard_10.04-4_i386.tar.gz",
|
130
|
+
:headers => @common_headers_in).to_return(
|
131
|
+
:status => 200,
|
132
|
+
:headers => @common_headers_out,
|
133
|
+
:body => '{"data":"UPID:localhost:00051DA0:119EAABC:521CCB19:vzcreate:203:root@pam:"}'
|
134
|
+
)
|
135
|
+
|
136
|
+
stub_request(:post, "http://localhost:8006/api2/json/nodes/localhost/openvz").with(
|
137
|
+
:body => "vmid=204&ostemplate=local%3Avztmpl%2Fubuntu-10.04-standard_10.04-4_i386.tar.gz",
|
138
|
+
:headers => @common_headers_in).to_return(
|
139
|
+
:status => 500,
|
140
|
+
:headers => { :connection => "close", :server => "pve-api-daemon/3.0", :content_type => "application/json;charset=UTF-8",
|
141
|
+
},
|
142
|
+
:body => 'NOK: error code = 500'
|
143
|
+
)
|
144
|
+
|
145
|
+
#Create the vm
|
146
|
+
@server1.openvz_post("ubuntu-10.04-standard_10.04-4_i386", 200).should be_eql "UPID:localhost:00051DA0:119EAABB:521CCB19:vzcreate:200:root@pam:"
|
147
|
+
@server1.openvz_post("ubuntu-10.04-standard_10.04-4_i386", 203, { 'hostname' => 'vm1.domain.com', 'password' => 'secret', 'memory' => 512, 'swap' => 512, 'disk' => 4 }).should be_eql "UPID:localhost:00051DA0:119EAABC:521CCB19:vzcreate:203:root@pam:"
|
148
|
+
@server1.openvz_post("ubuntu-10.04-standard_10.04-4_i386", 204).should be_eql "NOK: error code = 500"
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should delete openvz container" do
|
152
|
+
# Delete VM
|
153
|
+
stub_request(:delete, "http://localhost:8006/api2/json/nodes/localhost/openvz/200").with(
|
154
|
+
:headers => @common_headers_in).to_return(
|
155
|
+
:status => 200,
|
156
|
+
:headers => @common_headers_out,
|
157
|
+
:body => '{"data":"UPID:localhost:0005C1EB:11BAA4EB:521D12B8:vzdestroy:200:root@pam:"}'
|
158
|
+
)
|
159
|
+
|
160
|
+
stub_request(:delete, "http://localhost:8006/api2/json/nodes/localhost/openvz/201").with(
|
161
|
+
:headers => @common_headers_in).to_return(
|
162
|
+
:status => 500,
|
163
|
+
:headers => @common_headers_out,
|
164
|
+
:body => 'NOK: error code = 500'
|
165
|
+
)
|
166
|
+
|
167
|
+
# Delete the vm
|
168
|
+
@server1.openvz_delete(200).should be_eql 'UPID:localhost:0005C1EB:11BAA4EB:521D12B8:vzdestroy:200:root@pam:'
|
169
|
+
@server1.openvz_delete(201).should be_eql 'NOK: error code = 500'
|
170
|
+
end
|
171
|
+
|
172
|
+
it "should get container status" do
|
173
|
+
# VM Status
|
174
|
+
stub_request(:get, "http://localhost:8006/api2/json/nodes/localhost/openvz/200/status/current").with(
|
175
|
+
:headers => @common_headers_in).to_return(
|
176
|
+
:status => 200,
|
177
|
+
:headers => @common_headers_out,
|
178
|
+
:body => '{"data":{"maxswap":268435456,"disk":0,"ip":"-","status":"stopped","ha":0,"netout":0,"maxdisk":9.44473296573929e+21,"maxmem":268435456,"uptime":0,"swap":0,"nproc":0,"diskread":0,"cpu":0,"netin":0,"name":"CT200","failcnt":0,"diskwrite":0,"mem":0,"type":"openvz","cpus":1}}'
|
179
|
+
)
|
180
|
+
|
181
|
+
@server1.openvz_status(200).should be_an_instance_of Hash
|
182
|
+
@server1.openvz_status(200)['status'].should be_eql "stopped"
|
183
|
+
@server1.openvz_status(200)['cpus'].should be_eql 1
|
184
|
+
end
|
185
|
+
|
186
|
+
it "should start & stop vm" do
|
187
|
+
# VM Status
|
188
|
+
stub_request(:post, "http://localhost:8006/api2/json/nodes/localhost/openvz/200/status/start").with(
|
189
|
+
:headers => @common_headers_in).to_return(
|
190
|
+
:status => 200,
|
191
|
+
:headers => @common_headers_out,
|
192
|
+
:body => '{"data":"UPID:ks311324:0005D91C:11BE5277:521D1C23:vzstart:200:root@pam:"}'
|
193
|
+
)
|
194
|
+
|
195
|
+
stub_request(:post, "http://localhost:8006/api2/json/nodes/localhost/openvz/200/status/stop").with(
|
196
|
+
:headers => @common_headers_in).to_return(
|
197
|
+
:status => 200,
|
198
|
+
:headers => @common_headers_out,
|
199
|
+
:body => '{"data":"UPID:ks311324:0005D91C:11BE5277:521D1C23:vzstop:200:root@pam:"}'
|
200
|
+
)
|
201
|
+
|
202
|
+
stub_request(:post, "http://localhost:8006/api2/json/nodes/localhost/openvz/200/status/shutdown").with(
|
203
|
+
:headers => @common_headers_in).to_return(
|
204
|
+
:status => 200,
|
205
|
+
:headers => @common_headers_out,
|
206
|
+
:body => '{"data":"UPID:ks311324:0005D91C:11BE5277:521D1C23:vzshutdown:200:root@pam:"}'
|
207
|
+
)
|
208
|
+
|
209
|
+
@server1.openvz_start(200).should be_eql "UPID:ks311324:0005D91C:11BE5277:521D1C23:vzstart:200:root@pam:"
|
210
|
+
@server1.openvz_stop(200).should be_eql "UPID:ks311324:0005D91C:11BE5277:521D1C23:vzstop:200:root@pam:"
|
211
|
+
@server1.openvz_shutdown(200).should be_eql "UPID:ks311324:0005D91C:11BE5277:521D1C23:vzshutdown:200:root@pam:"
|
212
|
+
end
|
213
|
+
|
214
|
+
it "should get container config" do
|
215
|
+
# VM config
|
216
|
+
stub_request(:get, "http://localhost:8006/api2/json/nodes/localhost/openvz/200/config").with(
|
217
|
+
:headers => @common_headers_in).to_return(
|
218
|
+
:status => 200,
|
219
|
+
:headers => @common_headers_out,
|
220
|
+
:body => '{"data":{"quotaugidlimit":0,"disk":0,"ostemplate":"ubuntu-10.04-standard_10.04-4_i386.tar.gz","nameserver":"127.0.0.1 192.168.1.1","memory":256,"searchdomain":"domain.com","onboot":0,"cpuunits":1000,"swap":256,"quotatime":0,"digest":"5a6f4052d559d3ecc89c849214f482217018a07e","cpus":1,"storage":"local"}}'
|
221
|
+
)
|
222
|
+
|
223
|
+
@server1.openvz_config(200).should be_an_instance_of Hash
|
224
|
+
@server1.openvz_config(200)['searchdomain'].should be_eql "domain.com"
|
225
|
+
@server1.openvz_config(200)['ostemplate'].should be_eql "ubuntu-10.04-standard_10.04-4_i386.tar.gz"
|
226
|
+
end
|
227
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spork'
|
2
|
+
require 'rspec'
|
3
|
+
|
4
|
+
Spork.prefork do
|
5
|
+
unless ENV['DRB']
|
6
|
+
require 'simplecov'
|
7
|
+
SimpleCov.start 'rails'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
Spork.each_run do
|
12
|
+
if ENV['DRB']
|
13
|
+
require 'simplecov'
|
14
|
+
SimpleCov.start 'rails'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
if ENV["CI"]
|
19
|
+
require 'coveralls'
|
20
|
+
Coveralls.wear!
|
21
|
+
end
|
22
|
+
|
23
|
+
RSpec.configure do |config|
|
24
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
25
|
+
config.run_all_when_everything_filtered = true
|
26
|
+
config.filter_run :focus
|
27
|
+
|
28
|
+
config.order = 'random'
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: proxmox
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Nicolas Ledez
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-08-29 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rest-client
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.6.7
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.6.7
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: bundler
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '1.3'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '1.3'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: webmock
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
description: A library to drive a Proxmox host
|
95
|
+
email:
|
96
|
+
- github@ledez.net
|
97
|
+
executables: []
|
98
|
+
extensions: []
|
99
|
+
extra_rdoc_files: []
|
100
|
+
files:
|
101
|
+
- .gitignore
|
102
|
+
- .rspec
|
103
|
+
- .travis.yml
|
104
|
+
- Gemfile
|
105
|
+
- Guardfile
|
106
|
+
- LICENSE.txt
|
107
|
+
- README.md
|
108
|
+
- Rakefile
|
109
|
+
- lib/proxmox.rb
|
110
|
+
- lib/proxmox/version.rb
|
111
|
+
- proxmox.gemspec
|
112
|
+
- spec/lib/proxmox_spec.rb
|
113
|
+
- spec/spec_helper.rb
|
114
|
+
homepage: ''
|
115
|
+
licenses:
|
116
|
+
- MIT
|
117
|
+
post_install_message:
|
118
|
+
rdoc_options: []
|
119
|
+
require_paths:
|
120
|
+
- lib
|
121
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
122
|
+
none: false
|
123
|
+
requirements:
|
124
|
+
- - ! '>='
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
segments:
|
128
|
+
- 0
|
129
|
+
hash: -2928921111459929323
|
130
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
|
+
none: false
|
132
|
+
requirements:
|
133
|
+
- - ! '>='
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
version: '0'
|
136
|
+
segments:
|
137
|
+
- 0
|
138
|
+
hash: -2928921111459929323
|
139
|
+
requirements: []
|
140
|
+
rubyforge_project:
|
141
|
+
rubygems_version: 1.8.23
|
142
|
+
signing_key:
|
143
|
+
specification_version: 3
|
144
|
+
summary: You need to manage a proxmox host with Ruby? This library is for you.
|
145
|
+
test_files:
|
146
|
+
- spec/lib/proxmox_spec.rb
|
147
|
+
- spec/spec_helper.rb
|
148
|
+
has_rdoc:
|