upcloud_api 1.3.0 → 1.5.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 +4 -4
- data/lib/upcloud_api/version.rb +1 -1
- data/lib/upcloud_api.rb +525 -433
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6837056b4cff07402d608702a95d56d6be14ec38
|
4
|
+
data.tar.gz: 82526825eb93b43aef2160e3fc1ebcb5a689114d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ff71fa95959d11049d3d55398fd17f8b84baf43600c6bf38990ae9ccf58ba5521b3b82d405a1691085257854caa0d90755421d2ec0a4d5734b72a06eb879819
|
7
|
+
data.tar.gz: 7a158330aff7be804d5a9f386bf6b0baff416ef6b176eb4e3521d0de512384b9381051fb77338f0f35c083f1259adb4a052921a5c734e138157dfa0fd597d970
|
data/lib/upcloud_api/version.rb
CHANGED
data/lib/upcloud_api.rb
CHANGED
@@ -1,442 +1,534 @@
|
|
1
|
-
|
2
1
|
require "timeout"
|
3
2
|
|
4
3
|
require "httparty"
|
5
4
|
|
5
|
+
# Class to serve as a Ruby API for the UpCloud HTTP API
|
6
6
|
class UpcloudApi
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
response
|
122
|
-
end
|
123
|
-
|
124
|
-
# Deletes a server.
|
125
|
-
#
|
126
|
-
# In order to delete a server, the server must be stopped first.
|
127
|
-
#
|
128
|
-
# Calls DELETE /1.2/server/#{uuid}
|
129
|
-
def delete_server server_uuid
|
130
|
-
response = delete "server/#{server_uuid}"
|
131
|
-
|
132
|
-
response
|
133
|
-
end
|
134
|
-
|
135
|
-
# Starts server that is shut down.
|
136
|
-
#
|
137
|
-
# Calls POST /1.2/server/#{uuid}/start
|
138
|
-
#
|
139
|
-
# @param server_uuid UUID of the server
|
140
|
-
def start_server server_uuid
|
141
|
-
response = post "server/#{server_uuid}/start"
|
142
|
-
|
143
|
-
response
|
144
|
-
end
|
145
|
-
|
146
|
-
# Shuts down a server that is currently running
|
147
|
-
#
|
148
|
-
# Calls POST /1.2/server/#{uuid}/stop
|
149
|
-
#
|
150
|
-
# Hard shutdown means practically same as taking the power cable off from the computer.
|
151
|
-
# Soft shutdown sends ACPI signal to the server, which should then automatically handle shutdown routines by itself.
|
152
|
-
# If timeout is given, server will be forcibly shut down after the timeout has expired.
|
153
|
-
#
|
154
|
-
# @param server_uuid UUID of the server
|
155
|
-
# @param type Type of the shutdown. Available types are :hard and :soft. Defaults to :soft.
|
156
|
-
# @param timeout Time after server will be hard stopped if it didn’t close cleanly. Only affects :soft type.
|
157
|
-
# @param asynchronous If false, this call will wait until the server has really stopped.
|
158
|
-
#
|
159
|
-
# Raises Timeout::Error in case server does not shut down in 300 seconds in non-asynchronous mode.
|
160
|
-
def stop_server server_uuid, type: :soft, timeout: nil, asynchronous: false
|
161
|
-
data = {
|
162
|
-
"stop_server" => {
|
163
|
-
"stop_type" => type.to_s
|
164
|
-
}
|
165
|
-
}
|
166
|
-
data["stop_server"]["timeout"] = timeout unless timeout.nil?
|
167
|
-
|
168
|
-
json = JSON.generate data
|
169
|
-
|
170
|
-
response = post "server/#{server_uuid}/stop", json
|
171
|
-
|
172
|
-
return response if asynchronous
|
173
|
-
|
174
|
-
Timeout::timeout 300 do
|
175
|
-
loop do
|
176
|
-
details = server_details server_uuid
|
177
|
-
return response if details["server"]["state"] == "stopped"
|
178
|
-
end
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
# Restarts down a server that is currently running
|
183
|
-
#
|
184
|
-
# Calls POST /1.2/server/#{uuid}/restart
|
185
|
-
#
|
186
|
-
# Hard shutdown means practically same as taking the power cable off from the computer.
|
187
|
-
# Soft shutdown sends ACPI signal to the server, which should then automatically handle shutdown routines by itself.
|
188
|
-
# If timeout is given, server will be forcibly shut down after the timeout has expired.
|
189
|
-
#
|
190
|
-
# @param server_uuid UUID of the server
|
191
|
-
# @param type Type of the shutdown. Available types are :hard and :soft. Defaults to :soft.
|
192
|
-
# @param timeout Time after server will be hard stopped if it didn’t close cleanly. Only affects :soft type.
|
193
|
-
# @param timeout_action What will happen when timeout happens. :destroy hard stops the server and :ignore makes
|
194
|
-
# server if timeout happens. Default is :ignore.
|
195
|
-
def restart_server server_uuid, type: :soft, timeout: nil, timeout_action: :ignore
|
196
|
-
data = {
|
197
|
-
"stop_server" => {
|
198
|
-
"stop_type" => type.to_s
|
199
|
-
}
|
200
|
-
}
|
201
|
-
data["stop_server"]["timeout"] = timeout unless timeout.nil?
|
202
|
-
|
203
|
-
json = JSON.generate data
|
204
|
-
|
205
|
-
response = post "server/#{server_uuid}/restart", json
|
206
|
-
|
207
|
-
response
|
208
|
-
end
|
209
|
-
|
210
|
-
# Lists all storages or storages matching to given type.
|
211
|
-
#
|
212
|
-
# Calls GET /1.2/storage or /1.2/storage/#{type}
|
213
|
-
#
|
214
|
-
# Available types:
|
215
|
-
# - public
|
216
|
-
# - private
|
217
|
-
# - normal
|
218
|
-
# - backup
|
219
|
-
# - cdrom
|
220
|
-
# - template
|
221
|
-
# - favorite
|
222
|
-
#
|
223
|
-
# @param type Type of the storages to be returned on nil
|
224
|
-
def storages type: nil
|
225
|
-
response = get(type && "storage/#{type}" || "storage")
|
226
|
-
data = JSON.parse response.body
|
227
|
-
data
|
228
|
-
end
|
229
|
-
|
230
|
-
# Shows detailed information of single storage.
|
231
|
-
#
|
232
|
-
# Calls GET /1.2/storage/#{uuid}
|
233
|
-
#
|
234
|
-
# @param storage_uuid UUID of the storage
|
235
|
-
def storage_details storage_uuid
|
236
|
-
response = get "storage/#{storage_uuid}"
|
237
|
-
data = JSON.parse response.body
|
238
|
-
data
|
239
|
-
end
|
240
|
-
|
241
|
-
# Creates new storage.
|
242
|
-
#
|
243
|
-
# Calls POST /1.2/storage
|
244
|
-
#
|
245
|
-
# backup_rule should be hash with following attributes:
|
246
|
-
# - interval # allowed values: daily / mon / tue / wed / thu / fri / sat / sun
|
247
|
-
# - time # allowed values: 0000-2359
|
248
|
-
# - retention # How many days backup will be kept. Allowed values: 1-1095
|
249
|
-
#
|
250
|
-
# @param size Size of the storage in gigabytes
|
251
|
-
# @param tier Type of the disk. maxiops is SSD powered disk, other allowed value is "hdd"
|
252
|
-
# @param title Name of the disk
|
253
|
-
# @param zone Where the disk will reside. Needs to be within same zone with the server
|
254
|
-
# @param backup_rule Hash of backup information. If not given, no backups will be automatically created.
|
255
|
-
def create_storage size:, tier: "maxiops", title:, zone: "fi-hel1", backup_rule: nil
|
256
|
-
data = {
|
257
|
-
"storage" => {
|
258
|
-
"size" => size,
|
259
|
-
"tier" => tier,
|
260
|
-
"title" => title,
|
261
|
-
"zone" => zone,
|
262
|
-
"backup_rule" => backup_rule
|
263
|
-
}
|
264
|
-
}
|
265
|
-
|
266
|
-
json = JSON.generate data
|
267
|
-
|
268
|
-
response = post "storage", json
|
269
|
-
|
270
|
-
response
|
271
|
-
end
|
272
|
-
|
273
|
-
# Modifies existing storage.
|
274
|
-
#
|
275
|
-
# Calls PUT /1.2/storage/#{uuid}
|
276
|
-
#
|
277
|
-
# backup_rule should be hash with following attributes:
|
278
|
-
# - interval # allowed values: daily / mon / tue / wed / thu / fri / sat / sun
|
279
|
-
# - time # allowed values: 0000-2359
|
280
|
-
# - retention # How many days backup will be kept. Allowed values: 1-1095
|
281
|
-
#
|
282
|
-
# @param storage_uuid UUID of the storage that will be modified
|
283
|
-
# @param size Size of the storage in gigabytes
|
284
|
-
# @param title Name of the disk
|
285
|
-
# @param backup_rule Hash of backup information. If not given, no backups will be automatically created.
|
286
|
-
def modify_storage storage_uuid, size:, title:, backup_rule: nil
|
287
|
-
data = {
|
288
|
-
"storage" => {
|
289
|
-
"size" => size,
|
290
|
-
"title" => title,
|
291
|
-
"backup_rule" => backup_rule
|
292
|
-
}
|
293
|
-
}
|
294
|
-
|
295
|
-
json = JSON.generate data
|
296
|
-
|
297
|
-
response = put "storage/#{storage_uuid}", json
|
298
|
-
|
299
|
-
response
|
300
|
-
end
|
301
|
-
|
302
|
-
# Clones existing storage.
|
303
|
-
#
|
304
|
-
# This operation is asynchronous.
|
305
|
-
#
|
306
|
-
# Calls POST /1.2/storage/#{uuid}/clone
|
307
|
-
#
|
308
|
-
# backup_rule should be hash with following attributes:
|
309
|
-
# - interval # allowed values: daily / mon / tue / wed / thu / fri / sat / sun
|
310
|
-
# - time # allowed values: 0000-2359
|
311
|
-
# - retention # How many days backup will be kept. Allowed values: 1-1095
|
312
|
-
#
|
313
|
-
# @param storage_uuid UUID of the storage that will be modified
|
314
|
-
# @param tier Type of the disk. maxiops is SSD powered disk, other allowed value is "hdd"
|
315
|
-
# @param title Name of the disk
|
316
|
-
# @param zone Where the disk will reside. Needs to be within same zone with the server
|
317
|
-
def clone_storage storage_uuid, zone: "fi-hel1", title:, tier: "maxiops"
|
318
|
-
data = {
|
319
|
-
"storage" => {
|
320
|
-
"zone" => zone,
|
321
|
-
"title" => title,
|
322
|
-
"tier" => tier
|
323
|
-
}
|
324
|
-
}
|
325
|
-
|
326
|
-
json = JSON.generate data
|
327
|
-
|
328
|
-
response = post "storage/#{storage_uuid}/clone", json
|
329
|
-
|
330
|
-
response
|
331
|
-
end
|
332
|
-
|
333
|
-
# Attaches a storage to a server. Server must be stopped before the storage can be attached.
|
334
|
-
#
|
335
|
-
# Calls POST /1.2/server/#{server_uuid}/storage/attach
|
336
|
-
#
|
337
|
-
# Valid values for address are: ide[01]:[01] / scsi:0:[0-7] / virtio:[0-7]
|
338
|
-
#
|
339
|
-
# @param type Type of the disk. Valid values are "disk" and "cdrom".
|
340
|
-
# @param address Address where the disk will be attached to. Defaults to next available address.
|
341
|
-
# @param server_uuid UUID of the server where the disk will be attached to.
|
342
|
-
# @param storage_uuid UUID of the storage that will be attached.
|
343
|
-
def attach_storage type: "disk", address: nil, server_uuid:, storage_uuid:
|
344
|
-
data = {
|
345
|
-
"storage_device" => {
|
346
|
-
"type" => type,
|
347
|
-
"address" => address,
|
348
|
-
"storage" => storage_uuid
|
349
|
-
}
|
350
|
-
}
|
351
|
-
|
352
|
-
json = JSON.generate data
|
353
|
-
|
354
|
-
response = post "server/#{server_uuid}/storage/attach", json
|
355
|
-
|
356
|
-
response
|
357
|
-
end
|
358
|
-
|
359
|
-
# Detaches storage from a server. Server must be stopped before the storage can be detached.
|
360
|
-
#
|
361
|
-
# Calls POST /1.2/server/#{server_uuid}/storage/detach
|
362
|
-
#
|
363
|
-
# @param address Address where the storage that will be detached resides.
|
364
|
-
def detach_storage address
|
365
|
-
data = {
|
366
|
-
"storage_device" => {
|
367
|
-
"address" => address
|
368
|
-
}
|
369
|
-
}
|
370
|
-
|
371
|
-
json = JSON.generate data
|
372
|
-
|
373
|
-
response = post "server/#{server_uuid}/storage/detach", json
|
374
|
-
|
375
|
-
response
|
376
|
-
end
|
377
|
-
|
378
|
-
# Creates backup from a storage.
|
379
|
-
#
|
380
|
-
# This operation is asynchronous.
|
381
|
-
#
|
382
|
-
# Calls /1.2/storage/#{uuid}/backup
|
383
|
-
#
|
384
|
-
# @param storage_uuid UUID of the storage to be cloned
|
385
|
-
# @param title Name of the backup
|
386
|
-
def create_backup storage_uuid, title:
|
387
|
-
data = {
|
388
|
-
"storage" => {
|
389
|
-
"title" => title
|
390
|
-
}
|
391
|
-
}
|
392
|
-
|
393
|
-
json = JSON.generate data
|
394
|
-
|
395
|
-
response = post "storage/#{storage_uuid}/backup", json
|
396
|
-
|
397
|
-
response
|
398
|
-
end
|
399
|
-
|
400
|
-
# Restores a backup.
|
401
|
-
#
|
402
|
-
# If the storage is attached to server, the server must first be stopped.
|
403
|
-
#
|
404
|
-
# Calls /1.2/storage/#{uuid}/restore.
|
405
|
-
#
|
406
|
-
# @param storage_uuid TODO: is this supposed to be UUID of the storage or the backup?
|
407
|
-
def create_backup storage_uuid
|
408
|
-
response = post "storage/#{storage_uuid}/restore"
|
409
|
-
|
410
|
-
response
|
411
|
-
end
|
412
|
-
|
413
|
-
# Deletes a storage.
|
414
|
-
#
|
415
|
-
# The storage must be in "online" state and it must not be attached to any server.
|
416
|
-
# Backups will not be deleted.
|
417
|
-
#
|
418
|
-
# @param storage_uuid UUID of the storage that will be deleted.
|
419
|
-
def delete_storage storage_uuid
|
420
|
-
response = delete "storage/#{storage_uuid}"
|
421
|
-
|
422
|
-
response
|
423
|
-
end
|
424
|
-
|
425
|
-
private
|
426
|
-
|
427
|
-
def get action
|
428
|
-
HTTParty.get "https://api.upcloud.com/1.2/#{action}", basic_auth: @auth
|
429
|
-
end
|
430
|
-
|
431
|
-
def post action, body = ""
|
432
|
-
HTTParty.post "https://api.upcloud.com/1.2/#{action}", basic_auth: @auth, body: body, headers: { "Content-Type" => "application/json" }
|
433
|
-
end
|
434
|
-
|
435
|
-
def put action, body = ""
|
436
|
-
HTTParty.put "https://api.upcloud.com/1.2/#{action}", basic_auth: @auth, body: body, headers: { "Content-Type" => "application/json" }
|
7
|
+
# @param user [String] Upcloud API account
|
8
|
+
# @param password [String] Upcloud API password
|
9
|
+
def initialize(user, password)
|
10
|
+
@user = user
|
11
|
+
@password = password
|
12
|
+
@auth = { username: @user, password: @password }
|
13
|
+
end
|
14
|
+
|
15
|
+
# Tests that authentication to Upcloud works.
|
16
|
+
#
|
17
|
+
# This is not required to use, as authentication is used
|
18
|
+
# with HTTP basic auth with each request.
|
19
|
+
#
|
20
|
+
# Calls GET /1.2/server
|
21
|
+
#
|
22
|
+
# Returns true in success, false if not
|
23
|
+
def login
|
24
|
+
response = get "server"
|
25
|
+
response.code == 200
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns available server configurations.
|
29
|
+
#
|
30
|
+
# Calls GET /1.2/server_size
|
31
|
+
def server_configurations
|
32
|
+
response = get "server_size"
|
33
|
+
response["server_sizes"]["server_size"]
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns available credits.
|
37
|
+
#
|
38
|
+
# Calls GET /1.2/acccount
|
39
|
+
def account_information
|
40
|
+
response = get "account"
|
41
|
+
data = JSON.parse response.body
|
42
|
+
data["account"]["credits"]
|
43
|
+
end
|
44
|
+
|
45
|
+
# Lists servers associated with the account
|
46
|
+
#
|
47
|
+
# Calls GET /1.2/server
|
48
|
+
#
|
49
|
+
# Returns array of servers with values
|
50
|
+
# - zone
|
51
|
+
# - core_number
|
52
|
+
# - title
|
53
|
+
# - hostname
|
54
|
+
# - memory_amount
|
55
|
+
# - uuid
|
56
|
+
# - state
|
57
|
+
def servers
|
58
|
+
response = get "server"
|
59
|
+
data = JSON.parse response.body
|
60
|
+
data["servers"]["server"]
|
61
|
+
end
|
62
|
+
|
63
|
+
# Shows details of a server.
|
64
|
+
#
|
65
|
+
# Calls GET /1.2/server/#{uuid}
|
66
|
+
#
|
67
|
+
# @param uuid from UpcloudApi#servers
|
68
|
+
def server_details(uuid)
|
69
|
+
response = get "server/#{uuid}"
|
70
|
+
data = JSON.parse response.body
|
71
|
+
data
|
72
|
+
end
|
73
|
+
|
74
|
+
# Lists templates available from Upcloud
|
75
|
+
#
|
76
|
+
# Calls GET /1.2/storage/template
|
77
|
+
def templates
|
78
|
+
response = get "storage/template"
|
79
|
+
data = JSON.parse response.body
|
80
|
+
data
|
81
|
+
end
|
82
|
+
|
83
|
+
# Creates new server from template.
|
84
|
+
#
|
85
|
+
# Calls POST /1.2/server
|
86
|
+
#
|
87
|
+
# Storage devices should be array of hashes containing following data:
|
88
|
+
#
|
89
|
+
# {
|
90
|
+
# "action" => "clone" # Can be "create", "clone" or "attach"
|
91
|
+
# "storage" => template_uuid, # Should be passed only for "clone" or "attach"
|
92
|
+
# "title" => disk_name # Name of the storage,
|
93
|
+
# "tier" => "maxiops" # No sense using HDD any more
|
94
|
+
# }
|
95
|
+
#
|
96
|
+
# ip_addresses should be an array containing :public, :private and/or :ipv6. It defaults to
|
97
|
+
# :all, which means the server will get public IPv4, private IPv4 and public IPv6 addresses.
|
98
|
+
#
|
99
|
+
# Returns HTTParty response
|
100
|
+
def create_server(zone: "fi-hel1", title:, hostname:, core_number: 1,
|
101
|
+
memory_amount: 1024, storage_devices:, ip_addresses: :all)
|
102
|
+
data = {
|
103
|
+
"server" => {
|
104
|
+
"zone" => zone,
|
105
|
+
"title" => title,
|
106
|
+
"hostname" => hostname,
|
107
|
+
"core_number" => core_number,
|
108
|
+
"memory_amount" => memory_amount,
|
109
|
+
"storage_devices" => { "storage_device" => storage_devices }
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
if ip_addresses != :all
|
114
|
+
ips = []
|
115
|
+
ips << { "access" => "public", "family" => "IPv4" } if ip_addresses.include? :public
|
116
|
+
ips << { "access" => "private", "family" => "IPv4" } if ip_addresses.include? :private
|
117
|
+
ips << { "access" => "public", "family" => "IPv6" } if ip_addresses.include? :ipv6
|
118
|
+
|
119
|
+
data["server"]["ip_addresses"] = {}
|
120
|
+
data["server"]["ip_addresses"]["ip_address"] = ips
|
437
121
|
end
|
438
122
|
|
439
|
-
|
440
|
-
|
123
|
+
json = JSON.generate data
|
124
|
+
response = post "server", json
|
125
|
+
response
|
126
|
+
end
|
127
|
+
|
128
|
+
# Modifies existing server.
|
129
|
+
#
|
130
|
+
# In order to modify a server, the server must be stopped first.
|
131
|
+
#
|
132
|
+
# Calls PUT /1.2/server/#{uuid}
|
133
|
+
#
|
134
|
+
# @param server_uuid [String] UUID of the server that will be modified.
|
135
|
+
# @param params [Hash] Hash of params that will be passed to be changed.
|
136
|
+
def modify_server(server_uuid, params)
|
137
|
+
data = { "server" => params }
|
138
|
+
json = JSON.generate data
|
139
|
+
response = put "server/#{server_uuid}", json
|
140
|
+
|
141
|
+
response
|
142
|
+
end
|
143
|
+
|
144
|
+
# Deletes a server.
|
145
|
+
#
|
146
|
+
# In order to delete a server, the server must be stopped first.
|
147
|
+
#
|
148
|
+
# Calls DELETE /1.2/server/#{uuid}
|
149
|
+
def delete_server(server_uuid)
|
150
|
+
response = delete "server/#{server_uuid}"
|
151
|
+
|
152
|
+
response
|
153
|
+
end
|
154
|
+
|
155
|
+
# Starts server that is shut down.
|
156
|
+
#
|
157
|
+
# Calls POST /1.2/server/#{uuid}/start
|
158
|
+
#
|
159
|
+
# @param server_uuid UUID of the server
|
160
|
+
def start_server(server_uuid)
|
161
|
+
response = post "server/#{server_uuid}/start"
|
162
|
+
|
163
|
+
response
|
164
|
+
end
|
165
|
+
|
166
|
+
# Shuts down a server that is currently running
|
167
|
+
#
|
168
|
+
# Calls POST /1.2/server/#{uuid}/stop
|
169
|
+
#
|
170
|
+
# Hard shutdown means practically same as taking the power cable
|
171
|
+
# off from the computer. Soft shutdown sends ACPI signal to the server,
|
172
|
+
# which should then automatically handle shutdown routines by itself.
|
173
|
+
# If timeout is given, server will be forcibly shut down after the
|
174
|
+
# timeout has expired.
|
175
|
+
#
|
176
|
+
# @param server_uuid UUID of the server
|
177
|
+
# @param type Type of the shutdown. Available types are :hard and :soft.
|
178
|
+
# Defaults to :soft.
|
179
|
+
# @param timeout Time after server will be hard stopped if it did not
|
180
|
+
# close cleanly. Only affects :soft type.
|
181
|
+
# @param asynchronous If false, this call will wait until the server
|
182
|
+
# has really stopped.
|
183
|
+
#
|
184
|
+
# Raises Timeout::Error in case server does not shut down in 300
|
185
|
+
# seconds in non-asynchronous mode.
|
186
|
+
def stop_server(server_uuid, type: :soft, timeout: nil, asynchronous: false)
|
187
|
+
data = {
|
188
|
+
"stop_server" => {
|
189
|
+
"stop_type" => type.to_s
|
190
|
+
}
|
191
|
+
}
|
192
|
+
data["stop_server"]["timeout"] = timeout unless timeout.nil?
|
193
|
+
|
194
|
+
json = JSON.generate data
|
195
|
+
|
196
|
+
response = post "server/#{server_uuid}/stop", json
|
197
|
+
|
198
|
+
return response if asynchronous
|
199
|
+
|
200
|
+
Timeout.timeout 300 do
|
201
|
+
loop do
|
202
|
+
details = server_details server_uuid
|
203
|
+
return response if details["server"].nil?
|
204
|
+
return response if details["server"]["state"] == "stopped"
|
205
|
+
end
|
441
206
|
end
|
207
|
+
end
|
208
|
+
|
209
|
+
# Restarts a server that is currently running
|
210
|
+
#
|
211
|
+
# Calls POST /1.2/server/#{uuid}/restart
|
212
|
+
#
|
213
|
+
# Hard shutdown means practically same as taking the power cable
|
214
|
+
# off from the computer. Soft shutdown sends ACPI signal to the server,
|
215
|
+
# which should then automatically handle shutdown routines by itself.
|
216
|
+
# If timeout is given, server will be forcibly shut down after the
|
217
|
+
# timeout has expired.
|
218
|
+
#
|
219
|
+
# @param server_uuid UUID of the server
|
220
|
+
# @param type Type of the shutdown. Available types are :hard and :soft.
|
221
|
+
# Defaults to :soft.
|
222
|
+
# @param timeout Time after server will be hard stopped if it did not
|
223
|
+
# close cleanly. Only affects :soft type.
|
224
|
+
# @param timeout_action What will happen when timeout happens.
|
225
|
+
# :destroy hard stops the server and :ignore stops the operation
|
226
|
+
# if timeout happens. Default is :ignore.
|
227
|
+
def restart_server(server_uuid, type: :soft, timeout: nil,
|
228
|
+
timeout_action: :ignore)
|
229
|
+
data = {
|
230
|
+
"restart_server" => {
|
231
|
+
"stop_type" => type.to_s,
|
232
|
+
"timeout_action" => timeout_action
|
233
|
+
}
|
234
|
+
}
|
235
|
+
data["restart_server"]["timeout"] = timeout unless timeout.nil?
|
236
|
+
|
237
|
+
json = JSON.generate data
|
238
|
+
|
239
|
+
response = post "server/#{server_uuid}/restart", json
|
240
|
+
|
241
|
+
response
|
242
|
+
end
|
243
|
+
|
244
|
+
# Lists all storages or storages matching to given type.
|
245
|
+
#
|
246
|
+
# Calls GET /1.2/storage or /1.2/storage/#{type}
|
247
|
+
#
|
248
|
+
# Available types:
|
249
|
+
# - public
|
250
|
+
# - private
|
251
|
+
# - normal
|
252
|
+
# - backup
|
253
|
+
# - cdrom
|
254
|
+
# - template
|
255
|
+
# - favorite
|
256
|
+
#
|
257
|
+
# @param type Type of the storages to be returned on nil
|
258
|
+
def storages(type: nil)
|
259
|
+
response = get(type && "storage/#{type}" || "storage")
|
260
|
+
data = JSON.parse response.body
|
261
|
+
data
|
262
|
+
end
|
263
|
+
|
264
|
+
# Shows detailed information of single storage.
|
265
|
+
#
|
266
|
+
# Calls GET /1.2/storage/#{uuid}
|
267
|
+
#
|
268
|
+
# @param storage_uuid UUID of the storage
|
269
|
+
def storage_details(storage_uuid)
|
270
|
+
response = get "storage/#{storage_uuid}"
|
271
|
+
data = JSON.parse response.body
|
272
|
+
data
|
273
|
+
end
|
274
|
+
|
275
|
+
# Creates new storage.
|
276
|
+
#
|
277
|
+
# Calls POST /1.2/storage
|
278
|
+
#
|
279
|
+
# backup_rule should be hash with following attributes:
|
280
|
+
# - interval # allowed values: daily / mon / tue / wed / thu / fri / sat / sun
|
281
|
+
# - time # allowed values: 0000-2359
|
282
|
+
# - retention # How many days backup will be kept. Allowed values: 1-1095
|
283
|
+
#
|
284
|
+
# @param size Size of the storage in gigabytes
|
285
|
+
# @param tier Type of the disk. maxiops is SSD powered disk, other
|
286
|
+
# allowed value is "hdd"
|
287
|
+
# @param title Name of the disk
|
288
|
+
# @param zone Where the disk will reside. Needs to be within same zone
|
289
|
+
# with the server
|
290
|
+
# @param backup_rule Hash of backup information. If not given, no
|
291
|
+
# backups will be automatically created.
|
292
|
+
def create_storage(size:, tier: "maxiops", title:, zone: "fi-hel1",
|
293
|
+
backup_rule: nil)
|
294
|
+
data = {
|
295
|
+
"storage" => {
|
296
|
+
"size" => size,
|
297
|
+
"tier" => tier,
|
298
|
+
"title" => title,
|
299
|
+
"zone" => zone
|
300
|
+
}
|
301
|
+
}
|
302
|
+
data["storage"]["backup_rule"] = backup_rule unless backup_rule.nil?
|
303
|
+
|
304
|
+
json = JSON.generate data
|
305
|
+
response = post "storage", json
|
306
|
+
|
307
|
+
response
|
308
|
+
end
|
309
|
+
|
310
|
+
# Modifies existing storage.
|
311
|
+
#
|
312
|
+
# Calls PUT /1.2/storage/#{uuid}
|
313
|
+
#
|
314
|
+
# backup_rule should be hash with following attributes:
|
315
|
+
# - interval # allowed values: daily / mon / tue / wed / thu / fri / sat / sun
|
316
|
+
# - time # allowed values: 0000-2359
|
317
|
+
# - retention # How many days backup will be kept. Allowed values: 1-1095
|
318
|
+
#
|
319
|
+
# @param storage_uuid UUID of the storage that will be modified
|
320
|
+
# @param size Size of the storage in gigabytes
|
321
|
+
# @param title Name of the disk
|
322
|
+
# @param backup_rule Hash of backup information. If not given, no
|
323
|
+
# backups will be automatically created.
|
324
|
+
def modify_storage(storage_uuid, size:, title:, backup_rule: nil)
|
325
|
+
data = {
|
326
|
+
"storage" => {
|
327
|
+
"size" => size,
|
328
|
+
"title" => title
|
329
|
+
}
|
330
|
+
}
|
331
|
+
data["storage"]["backup_rule"] = backup_rule unless backup_rule.nil?
|
332
|
+
|
333
|
+
json = JSON.generate data
|
334
|
+
|
335
|
+
response = put "storage/#{storage_uuid}", json
|
336
|
+
|
337
|
+
response
|
338
|
+
end
|
339
|
+
|
340
|
+
# Clones existing storage.
|
341
|
+
#
|
342
|
+
# This operation is asynchronous.
|
343
|
+
#
|
344
|
+
# Calls POST /1.2/storage/#{uuid}/clone
|
345
|
+
#
|
346
|
+
# @param storage_uuid UUID of the storage that will be modified
|
347
|
+
# @param tier Type of the disk. maxiops is SSD powered disk, other
|
348
|
+
# allowed value is "hdd"
|
349
|
+
# @param title Name of the disk
|
350
|
+
# @param zone Where the disk will reside. Needs to be within same zone
|
351
|
+
# with the server
|
352
|
+
def clone_storage(storage_uuid, zone: "fi-hel1", title:, tier: "maxiops")
|
353
|
+
data = {
|
354
|
+
"storage" => {
|
355
|
+
"zone" => zone,
|
356
|
+
"title" => title,
|
357
|
+
"tier" => tier
|
358
|
+
}
|
359
|
+
}
|
360
|
+
|
361
|
+
json = JSON.generate data
|
362
|
+
|
363
|
+
response = post "storage/#{storage_uuid}/clone", json
|
364
|
+
|
365
|
+
response
|
366
|
+
end
|
367
|
+
|
368
|
+
# Templatizes existing storage.
|
369
|
+
#
|
370
|
+
# This operation is asynchronous.
|
371
|
+
#
|
372
|
+
# Calls POST /1.2/storage/#{uuid}/templatize
|
373
|
+
#
|
374
|
+
# @param storage_uuid UUID of the storage that will be templatized
|
375
|
+
# @param title Name of the template storage
|
376
|
+
def templatize_storage(storage_uuid, title:)
|
377
|
+
data = {
|
378
|
+
"storage" => {
|
379
|
+
"title" => title
|
380
|
+
}
|
381
|
+
}
|
382
|
+
|
383
|
+
json = JSON.generate data
|
384
|
+
|
385
|
+
response = post "storage/#{storage_uuid}/templatize", json
|
386
|
+
|
387
|
+
response
|
388
|
+
end
|
389
|
+
|
390
|
+
# Attaches a storage to a server. Server must be stopped before the
|
391
|
+
# storage can be attached.
|
392
|
+
#
|
393
|
+
# Calls POST /1.2/server/#{server_uuid}/storage/attach
|
394
|
+
#
|
395
|
+
# Valid values for address are: ide[01]:[01] / scsi:0:[0-7] / virtio:[0-7]
|
396
|
+
#
|
397
|
+
# @param server_uuid UUID of the server where the disk will be attached to.
|
398
|
+
# @param storage_uuid UUID of the storage that will be attached.
|
399
|
+
# @param type Type of the disk. Valid values are "disk" and "cdrom".
|
400
|
+
# @param address Address where the disk will be attached to. Defaults
|
401
|
+
# to next available address.
|
402
|
+
def attach_storage(server_uuid, storage_uuid:, type: "disk", address: nil)
|
403
|
+
data = {
|
404
|
+
"storage_device" => {
|
405
|
+
"type" => type,
|
406
|
+
"storage" => storage_uuid
|
407
|
+
}
|
408
|
+
}
|
409
|
+
data["storage_device"]["address"] = address unless address.nil?
|
410
|
+
|
411
|
+
json = JSON.generate data
|
412
|
+
|
413
|
+
response = post "server/#{server_uuid}/storage/attach", json
|
414
|
+
|
415
|
+
response
|
416
|
+
end
|
417
|
+
|
418
|
+
# Detaches storage from a server. Server must be stopped before the
|
419
|
+
# storage can be detached.
|
420
|
+
#
|
421
|
+
# Calls POST /1.2/server/#{server_uuid}/storage/detach
|
422
|
+
#
|
423
|
+
# @param server_uuid UUID of the server from which to detach the storage.
|
424
|
+
# @param address Address where the storage that will be detached resides.
|
425
|
+
def detach_storage(server_uuid, address:)
|
426
|
+
data = {
|
427
|
+
"storage_device" => {
|
428
|
+
"address" => address
|
429
|
+
}
|
430
|
+
}
|
431
|
+
|
432
|
+
json = JSON.generate data
|
433
|
+
|
434
|
+
response = post "server/#{server_uuid}/storage/detach", json
|
435
|
+
|
436
|
+
response
|
437
|
+
end
|
438
|
+
|
439
|
+
# Creates backup from a storage.
|
440
|
+
#
|
441
|
+
# This operation is asynchronous.
|
442
|
+
#
|
443
|
+
# Calls /1.2/storage/#{uuid}/backup
|
444
|
+
#
|
445
|
+
# @param storage_uuid UUID of the storage to be backed-up
|
446
|
+
# @param title Name of the backup
|
447
|
+
def create_backup(storage_uuid, title:)
|
448
|
+
data = {
|
449
|
+
"storage" => {
|
450
|
+
"title" => title
|
451
|
+
}
|
452
|
+
}
|
453
|
+
|
454
|
+
json = JSON.generate data
|
455
|
+
|
456
|
+
response = post "storage/#{storage_uuid}/backup", json
|
457
|
+
|
458
|
+
response
|
459
|
+
end
|
460
|
+
|
461
|
+
# Restores a backup.
|
462
|
+
#
|
463
|
+
# If the storage is attached to server, the server must first be stopped.
|
464
|
+
#
|
465
|
+
# Calls /1.2/storage/#{backup_uuid}/restore.
|
466
|
+
#
|
467
|
+
# @param backup_uuid UUID of the backup
|
468
|
+
def restore_backup(backup_uuid)
|
469
|
+
response = post "storage/#{backup_uuid}/restore"
|
470
|
+
|
471
|
+
response
|
472
|
+
end
|
473
|
+
|
474
|
+
# Adds storage to favorites
|
475
|
+
#
|
476
|
+
# Calls POST /1.2/storage/#{storage_uuid}/favorite.
|
477
|
+
#
|
478
|
+
# @param storage_uuid UUID of the storage to be included in favorites
|
479
|
+
def favorite_storage(storage_uuid)
|
480
|
+
response = post "storage/#{storage_uuid}/favorite"
|
481
|
+
|
482
|
+
response
|
483
|
+
end
|
484
|
+
|
485
|
+
# Removes storage to favorites
|
486
|
+
#
|
487
|
+
# Calls POST /1.2/storage/#{storage_uuid}/favorite.
|
488
|
+
#
|
489
|
+
# @param storage_uuid UUID of the storage to be removed from favorites
|
490
|
+
def defavorite_storage(storage_uuid)
|
491
|
+
response = delete "storage/#{storage_uuid}/favorite"
|
492
|
+
|
493
|
+
response
|
494
|
+
end
|
495
|
+
|
496
|
+
# Deletes a storage.
|
497
|
+
#
|
498
|
+
# The storage must be in "online" state and it must not be attached to
|
499
|
+
# any server.
|
500
|
+
# Backups will not be deleted.
|
501
|
+
#
|
502
|
+
# @param storage_uuid UUID of the storage that will be deleted.
|
503
|
+
def delete_storage(storage_uuid)
|
504
|
+
response = delete "storage/#{storage_uuid}"
|
505
|
+
|
506
|
+
response
|
507
|
+
end
|
508
|
+
|
509
|
+
private
|
510
|
+
|
511
|
+
def get(action)
|
512
|
+
HTTParty.get "https://api.upcloud.com/1.2/#{action}", basic_auth: @auth
|
513
|
+
end
|
514
|
+
|
515
|
+
def post(action, body = "")
|
516
|
+
HTTParty.post "https://api.upcloud.com/1.2/#{action}",
|
517
|
+
basic_auth: @auth,
|
518
|
+
body: body,
|
519
|
+
headers: { "Content-Type" => "application/json" }
|
520
|
+
end
|
521
|
+
|
522
|
+
def put(action, body = "")
|
523
|
+
HTTParty.put "https://api.upcloud.com/1.2/#{action}",
|
524
|
+
basic_auth: @auth,
|
525
|
+
body: body,
|
526
|
+
headers: { "Content-Type" => "application/json" }
|
527
|
+
end
|
528
|
+
|
529
|
+
def delete(action)
|
530
|
+
HTTParty.delete "https://api.upcloud.com/1.2/#{action}",
|
531
|
+
basic_auth: @auth,
|
532
|
+
headers: { "Content-Type" => "application/json" }
|
533
|
+
end
|
442
534
|
end
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: upcloud_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samu Voutilainen
|
8
|
+
- Mika Katara
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date:
|
12
|
+
date: 2016-04-22 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: httparty
|
@@ -53,7 +54,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
53
54
|
version: '0'
|
54
55
|
requirements: []
|
55
56
|
rubyforge_project:
|
56
|
-
rubygems_version: 2.4.
|
57
|
+
rubygems_version: 2.4.8
|
57
58
|
signing_key:
|
58
59
|
specification_version: 4
|
59
60
|
summary: Implementation of Upcloud API for VPS management
|