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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1b145630b5a65cce82856ed253d85e59a598814a
4
- data.tar.gz: c125d9477ddb35c16744cc2dbf87ea8c3efc61c5
3
+ metadata.gz: 6837056b4cff07402d608702a95d56d6be14ec38
4
+ data.tar.gz: 82526825eb93b43aef2160e3fc1ebcb5a689114d
5
5
  SHA512:
6
- metadata.gz: 4a09082fd8700233b8b14479d86c210b76b075549ddb955fb6f57f4efdb2af95530935607644dd990dc6e7663bea74986a78892fdd1bc8bbe4466ec837752ca9
7
- data.tar.gz: dbe49e4b6dc737786fb35217cb894e72375d3c17f7a1f9f5ecf9a63c4498771336d95b1755de68a672a465057930ff084eb50254e4bc5283e670af9ce7c67b74
6
+ metadata.gz: 3ff71fa95959d11049d3d55398fd17f8b84baf43600c6bf38990ae9ccf58ba5521b3b82d405a1691085257854caa0d90755421d2ec0a4d5734b72a06eb879819
7
+ data.tar.gz: 7a158330aff7be804d5a9f386bf6b0baff416ef6b176eb4e3521d0de512384b9381051fb77338f0f35c083f1259adb4a052921a5c734e138157dfa0fd597d970
@@ -1,3 +1,3 @@
1
1
  class UpcloudApi
2
- VERSION = "1.3.0"
2
+ VERSION = "1.5.0".freeze
3
3
  end
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
- # @param user [String] Upcloud API account
9
- # @param password [String] Upcloud API password
10
- def initialize user, password
11
- @user = user
12
- @password = password
13
- @auth = { username: @user, password: @password }
14
- end
15
-
16
- # Tests that authentication to Upcloud works.
17
- #
18
- # This is not required to use, as authentication is used
19
- # with HTTP basic auth with each request.
20
- #
21
- # Calls GET /1.2/server
22
- #
23
- # Returns true in success, false if not
24
- def login
25
- response = get "server"
26
- response.code == 200
27
- end
28
-
29
- # Returns available credits.
30
- #
31
- # Calls GET /1.2/acccount
32
- def account_information
33
- response = get "account"
34
- data = JSON.parse response.body
35
- data["acccount"]["credits"]
36
- end
37
-
38
- # Lists servers associated with the account
39
- #
40
- # Calls GET /1.2/server
41
- #
42
- # Returns array of servers with values
43
- # - zone
44
- # - core_number
45
- # - title
46
- # - hostname
47
- # - memory_amount
48
- # - uuid
49
- # - state
50
- def servers
51
- response = get "server"
52
- data = JSON.parse response.body
53
- data["servers"]["server"]
54
- end
55
-
56
- # Shows details of a server.
57
- #
58
- # Calls GET /1.2/server/#{uuid}
59
- #
60
- # @param uuid from UpcloudApi#servers
61
- def server_details uuid
62
- response = get "server/#{uuid}"
63
- data = JSON.parse response.body
64
- data
65
- end
66
-
67
- # Lists templates available from Upcloud
68
- #
69
- # Calls GET /1.2/storage/template
70
- def templates
71
- response = get "storage/template"
72
- data = JSON.parse response.body
73
- data
74
- end
75
-
76
- # Creates new server from template.
77
- #
78
- # Calls POST /1.2/server
79
- #
80
- # Storage devices should be array of hashes containing following data:
81
- #
82
- # {
83
- # "action" => "clone" # Can be "create", "clone" or "attach"
84
- # "storage" => template_uuid, # Should be passed only for "clone" or "attach"
85
- # "title" => disk_name # Name of the storage,
86
- # "tier" => "maxiops" # No sense using HDD any more
87
- # }
88
- #
89
- # Returns HTTParty response
90
- def create_server zone: "fi-hel1", title:, hostname:, core_number: 1, memory_amount: 1024, storage_devices:
91
- data = {
92
- "server" => {
93
- "zone" => zone,
94
- "title" => title,
95
- "hostname" => hostname,
96
- "core_number" => core_number,
97
- "memory_amount" => memory_amount,
98
- "storage_devices" => { "storage_device" => storage_devices }
99
- }
100
- }
101
-
102
- json = JSON.generate data
103
- response = post "server", json
104
-
105
- response
106
- end
107
-
108
- # Modifies existing server.
109
- #
110
- # In order to modify a server, the server must be stopped first.
111
- #
112
- # Calls PUT /1.2/server/#{uuid}
113
- #
114
- # @param server_uuid [String] UUID of the server that will be modified.
115
- # @param params [Hash] Hash of params that will be passed to be changed.
116
- def modify_server server_uuid, params
117
- data = { "server" => params }
118
- json = JSON.generate data
119
- response = put "server/#{server_uuid}", json
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
- def delete action, body = ""
440
- HTTParty.delete "https://api.upcloud.com/1.2/#{action}", basic_auth: @auth, headers: { "Content-Type" => "application/json" }
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.3.0
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: 2015-05-13 00:00:00.000000000 Z
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.6
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