fog-hetznercloud 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.
- checksums.yaml +7 -0
- data/Gemfile +4 -0
- data/LICENSE +201 -0
- data/README.md +139 -0
- data/Rakefile +24 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/fog-hetznercloud.gemspec +33 -0
- data/lib/fog/hetznercloud.rb +13 -0
- data/lib/fog/hetznercloud/client.rb +55 -0
- data/lib/fog/hetznercloud/compute.rb +146 -0
- data/lib/fog/hetznercloud/errors.rb +37 -0
- data/lib/fog/hetznercloud/models/compute/action.rb +31 -0
- data/lib/fog/hetznercloud/models/compute/actions.rb +22 -0
- data/lib/fog/hetznercloud/models/compute/datacenter.rb +15 -0
- data/lib/fog/hetznercloud/models/compute/datacenters.rb +22 -0
- data/lib/fog/hetznercloud/models/compute/floating_ip.rb +154 -0
- data/lib/fog/hetznercloud/models/compute/floating_ips.rb +22 -0
- data/lib/fog/hetznercloud/models/compute/image.rb +78 -0
- data/lib/fog/hetznercloud/models/compute/images.rb +22 -0
- data/lib/fog/hetznercloud/models/compute/location.rb +18 -0
- data/lib/fog/hetznercloud/models/compute/locations.rb +22 -0
- data/lib/fog/hetznercloud/models/compute/server.rb +393 -0
- data/lib/fog/hetznercloud/models/compute/server_type.rb +17 -0
- data/lib/fog/hetznercloud/models/compute/server_types.rb +22 -0
- data/lib/fog/hetznercloud/models/compute/servers.rb +47 -0
- data/lib/fog/hetznercloud/models/compute/ssh_key.rb +65 -0
- data/lib/fog/hetznercloud/models/compute/ssh_keys.rb +22 -0
- data/lib/fog/hetznercloud/request_helper.rb +32 -0
- data/lib/fog/hetznercloud/requests/compute/create_floating_ip.rb +29 -0
- data/lib/fog/hetznercloud/requests/compute/create_server.rb +31 -0
- data/lib/fog/hetznercloud/requests/compute/create_ssh_key.rb +24 -0
- data/lib/fog/hetznercloud/requests/compute/delete_floating_ip.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/delete_image.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/delete_server.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/delete_ssh_key.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/execute_server_action.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/floating_ip_assign_to_server.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/floating_ip_unassign.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/floating_ip_update_dns_ptr.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/get_action.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/get_datacenter.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/get_floating_ip.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/get_image.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/get_location.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/get_server.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/get_server_type.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/get_ssh_key.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/list_actions.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/list_datacenters.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/list_floating_ips.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/list_images.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/list_locations.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/list_server_types.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/list_servers.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/list_ssh_keys.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/update_floating_ip.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/update_image.rb +17 -0
- data/lib/fog/hetznercloud/requests/compute/update_server.rb +77 -0
- data/lib/fog/hetznercloud/requests/compute/update_ssh_key.rb +17 -0
- data/lib/fog/hetznercloud/version.rb +5 -0
- metadata +244 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
module Fog
|
2
|
+
module Hetznercloud
|
3
|
+
class Compute
|
4
|
+
class FloatingIps < Fog::Collection
|
5
|
+
model Fog::Hetznercloud::Compute::FloatingIp
|
6
|
+
|
7
|
+
def all(filters = {})
|
8
|
+
floating_ips = service.list_floating_ips(filters).body['floating_ips'] || []
|
9
|
+
load(floating_ips)
|
10
|
+
end
|
11
|
+
|
12
|
+
def get(identity)
|
13
|
+
if (floating_ip = service.get_floating_ip(identity).body['floating_ip'])
|
14
|
+
new(floating_ip)
|
15
|
+
end
|
16
|
+
rescue Fog::Hetznercloud::Compute::UnknownResourceError
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Fog
|
2
|
+
module Hetznercloud
|
3
|
+
class Compute
|
4
|
+
class Image < Fog::Model
|
5
|
+
identity :id
|
6
|
+
|
7
|
+
attribute :type
|
8
|
+
attribute :status
|
9
|
+
attribute :name
|
10
|
+
attribute :description
|
11
|
+
attribute :image_size
|
12
|
+
attribute :disk_size
|
13
|
+
attribute :created
|
14
|
+
attribute :created_from
|
15
|
+
attribute :bound_to
|
16
|
+
attribute :os_flavor
|
17
|
+
attribute :os_version
|
18
|
+
attribute :rapid_deploy
|
19
|
+
|
20
|
+
def created=(value)
|
21
|
+
attributes[:created] = Time.iso8601(value)
|
22
|
+
end
|
23
|
+
|
24
|
+
def created_from=(value)
|
25
|
+
attributes[:created_from] = case value
|
26
|
+
when Hash
|
27
|
+
service.servers.new(value)
|
28
|
+
when Integer
|
29
|
+
service.servers.new(identity: value)
|
30
|
+
else
|
31
|
+
value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def bound_to=(value)
|
36
|
+
attributes[:bound_to] = case value
|
37
|
+
when Hash
|
38
|
+
service.servers.new(value)
|
39
|
+
when Integer
|
40
|
+
service.servers.new(identity: value)
|
41
|
+
else
|
42
|
+
value
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def save
|
47
|
+
update
|
48
|
+
end
|
49
|
+
|
50
|
+
def destroy
|
51
|
+
requires :identity
|
52
|
+
|
53
|
+
service.delete_image(identity)
|
54
|
+
true
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def update
|
60
|
+
requires :identity
|
61
|
+
requires_one :description, :type
|
62
|
+
|
63
|
+
body = attributes.dup
|
64
|
+
|
65
|
+
body[:description] = description
|
66
|
+
body[:type] = type
|
67
|
+
|
68
|
+
if (image = service.update_image(identity, body).body['image'])
|
69
|
+
merge_attributes(image)
|
70
|
+
true
|
71
|
+
else
|
72
|
+
false
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Fog
|
2
|
+
module Hetznercloud
|
3
|
+
class Compute
|
4
|
+
class Images < Fog::Collection
|
5
|
+
model Fog::Hetznercloud::Compute::Image
|
6
|
+
|
7
|
+
def all(filters = {})
|
8
|
+
images = service.list_images(filters).body['images'] || []
|
9
|
+
load(images)
|
10
|
+
end
|
11
|
+
|
12
|
+
def get(identity)
|
13
|
+
if (image = service.get_image(identity).body['image'])
|
14
|
+
new(image)
|
15
|
+
end
|
16
|
+
rescue Fog::Hetznercloud::Compute::UnknownResourceError
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# https://docs.hetzner.cloud/#resources-actions-get
|
2
|
+
module Fog
|
3
|
+
module Hetznercloud
|
4
|
+
class Compute
|
5
|
+
class Location < Fog::Model
|
6
|
+
identity :id
|
7
|
+
|
8
|
+
attribute :name
|
9
|
+
attribute :description
|
10
|
+
attribute :country
|
11
|
+
# attribute :extra_volumes
|
12
|
+
attribute :city
|
13
|
+
attribute :latitude
|
14
|
+
attribute :longitude
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Fog
|
2
|
+
module Hetznercloud
|
3
|
+
class Compute
|
4
|
+
class Locations < Fog::Collection
|
5
|
+
model Fog::Hetznercloud::Compute::Location
|
6
|
+
|
7
|
+
def all(filters = {})
|
8
|
+
locations = service.list_locations(filters).body['locations'] || []
|
9
|
+
load(locations)
|
10
|
+
end
|
11
|
+
|
12
|
+
def get(identity)
|
13
|
+
if (location = service.get_location(identity).body['location'])
|
14
|
+
new(location)
|
15
|
+
end
|
16
|
+
rescue Fog::Hetznercloud::Compute::UnknownResourceError
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,393 @@
|
|
1
|
+
require 'fog/compute/models/server'
|
2
|
+
|
3
|
+
module Fog
|
4
|
+
module Hetznercloud
|
5
|
+
class Compute
|
6
|
+
class Server < Fog::Compute::Server
|
7
|
+
identity :id
|
8
|
+
|
9
|
+
# Required
|
10
|
+
attribute :name
|
11
|
+
attribute :image
|
12
|
+
attribute :server_type
|
13
|
+
|
14
|
+
attribute :status
|
15
|
+
attribute :created
|
16
|
+
attribute :user_data
|
17
|
+
attribute :ssh_keys
|
18
|
+
attribute :public_net
|
19
|
+
attribute :datacenter
|
20
|
+
attribute :location
|
21
|
+
attribute :iso
|
22
|
+
attribute :rescue_enabled
|
23
|
+
attribute :locked
|
24
|
+
attribute :backup_window
|
25
|
+
attribute :start_after_create
|
26
|
+
attribute :outgoing_traffic
|
27
|
+
attribute :incoming_traffic
|
28
|
+
attribute :included_traffic
|
29
|
+
|
30
|
+
def initialize(options)
|
31
|
+
@async = true
|
32
|
+
super(options)
|
33
|
+
end
|
34
|
+
|
35
|
+
def image=(value)
|
36
|
+
attributes[:image] = case value
|
37
|
+
when Hash
|
38
|
+
service.images.new(value)
|
39
|
+
when String
|
40
|
+
service.images.all(name: value).first
|
41
|
+
when Integer
|
42
|
+
service.images.get(value)
|
43
|
+
else
|
44
|
+
value
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def ssh_keys=(value)
|
49
|
+
attributes[:ssh_keys] = []
|
50
|
+
# API does not return ssh_key
|
51
|
+
return true if value.nil?
|
52
|
+
value.each do |item|
|
53
|
+
thing = case item
|
54
|
+
when Hash
|
55
|
+
service.ssh_keys.new(item)
|
56
|
+
when String
|
57
|
+
service.ssh_keys.all(name: item).first
|
58
|
+
when Integer
|
59
|
+
service.ssh_keys.get(item)
|
60
|
+
else
|
61
|
+
value
|
62
|
+
end
|
63
|
+
attributes[:ssh_keys] << thing
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def server_type=(value)
|
68
|
+
attributes[:server_type] = case value
|
69
|
+
when Hash
|
70
|
+
service.server_types.new(value)
|
71
|
+
when String
|
72
|
+
service.server_types.all(name: value).first
|
73
|
+
when Integer
|
74
|
+
service.server_types.get(value)
|
75
|
+
else
|
76
|
+
value
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def location=(value)
|
81
|
+
attributes[:location] = case value
|
82
|
+
when Hash
|
83
|
+
service.locations.new(value)
|
84
|
+
when String
|
85
|
+
service.locations.all(name: value).first
|
86
|
+
when Integer
|
87
|
+
service.locations.get(value)
|
88
|
+
else
|
89
|
+
value
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def datacenter=(value)
|
94
|
+
attributes[:datacenter] = case value
|
95
|
+
when Hash
|
96
|
+
service.datacenters.new(value)
|
97
|
+
attributes[:location] = service.locations.new(value['location'])
|
98
|
+
when String
|
99
|
+
service.datacenters.all(name: value).first
|
100
|
+
when Integer
|
101
|
+
service.datacenters.get(value)
|
102
|
+
else
|
103
|
+
value
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def user_data=(value)
|
108
|
+
attributes[:user_data] = if value =~ /^\.?\/[^\/]+/
|
109
|
+
File.read(value)
|
110
|
+
else
|
111
|
+
value
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def name=(value)
|
116
|
+
return true if name == value
|
117
|
+
@needsupdate = true
|
118
|
+
attributes[:name] = value
|
119
|
+
end
|
120
|
+
|
121
|
+
def public_dns_name
|
122
|
+
"static.#{public_net['ipv4']['ip']}.clients.your-server.de"
|
123
|
+
end
|
124
|
+
|
125
|
+
def reverse_dns_name
|
126
|
+
public_net['ipv4']['dns_ptr']
|
127
|
+
end
|
128
|
+
|
129
|
+
def ready?
|
130
|
+
status == 'running'
|
131
|
+
end
|
132
|
+
|
133
|
+
def migrating?
|
134
|
+
status == 'migrating'
|
135
|
+
end
|
136
|
+
|
137
|
+
def stopped?
|
138
|
+
status == 'off'
|
139
|
+
end
|
140
|
+
|
141
|
+
def save
|
142
|
+
if persisted?
|
143
|
+
update
|
144
|
+
else
|
145
|
+
create
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def destroy
|
150
|
+
requires :identity
|
151
|
+
|
152
|
+
service.delete_server(identity)
|
153
|
+
true
|
154
|
+
end
|
155
|
+
|
156
|
+
def poweron(async: async_mode?)
|
157
|
+
requires :identity
|
158
|
+
|
159
|
+
execute_action('poweron', async)
|
160
|
+
end
|
161
|
+
|
162
|
+
def poweroff(async: async_mode?)
|
163
|
+
requires :identity
|
164
|
+
|
165
|
+
execute_action('poweroff', async)
|
166
|
+
end
|
167
|
+
|
168
|
+
def reboot(async: async_mode?)
|
169
|
+
requires :identity
|
170
|
+
|
171
|
+
execute_action('reboot', async)
|
172
|
+
end
|
173
|
+
|
174
|
+
def reset(async: async_mode?)
|
175
|
+
requires :identity
|
176
|
+
|
177
|
+
execute_action('reset', async)
|
178
|
+
end
|
179
|
+
|
180
|
+
def shutdown(async: async_mode?)
|
181
|
+
requires :identity
|
182
|
+
|
183
|
+
execute_action('shutdown', async)
|
184
|
+
end
|
185
|
+
|
186
|
+
def async=(value)
|
187
|
+
@async = !!value
|
188
|
+
end
|
189
|
+
|
190
|
+
def async?
|
191
|
+
@async
|
192
|
+
end
|
193
|
+
|
194
|
+
def async_mode?
|
195
|
+
async?
|
196
|
+
end
|
197
|
+
|
198
|
+
def sync=(value)
|
199
|
+
@async = !value
|
200
|
+
end
|
201
|
+
|
202
|
+
def sync?
|
203
|
+
!@async
|
204
|
+
end
|
205
|
+
|
206
|
+
def disable_rescue(async: async_mode?)
|
207
|
+
requires :identity
|
208
|
+
|
209
|
+
execute_action('disable_rescue', async)
|
210
|
+
end
|
211
|
+
|
212
|
+
def enable_rescue(type: 'linux64', ssh_keys: [], async: async_mode?)
|
213
|
+
requires :identity
|
214
|
+
|
215
|
+
# FIXME: Refactor with ssh_keys=(value) above to do DRY
|
216
|
+
sshkeys = []
|
217
|
+
ssh_keys.each do |item|
|
218
|
+
thing = case item
|
219
|
+
when Hash
|
220
|
+
service.ssh_keys.new(item)
|
221
|
+
when String
|
222
|
+
service.ssh_keys.all(name: item).first
|
223
|
+
when Integer
|
224
|
+
service.ssh_keys.get(item)
|
225
|
+
else
|
226
|
+
value
|
227
|
+
end
|
228
|
+
sshkeys << thing.identity
|
229
|
+
end
|
230
|
+
|
231
|
+
body = {
|
232
|
+
type: type,
|
233
|
+
ssh_keys: sshkeys
|
234
|
+
}
|
235
|
+
|
236
|
+
execute_action('enable_rescue', async, body)
|
237
|
+
end
|
238
|
+
|
239
|
+
# Returns action, imageObject
|
240
|
+
def create_backup(async: async_mode?, description: "Backup of #{attributes[:name]} created at #{Time.now}")
|
241
|
+
requires :identity
|
242
|
+
|
243
|
+
create_image(async: async, description: description, type: 'backup')
|
244
|
+
end
|
245
|
+
|
246
|
+
# Returns action, imageObject
|
247
|
+
def create_image(async: async_mode?, description: "image of #{attributes[:name]} created at #{Time.now}", type: 'snapshot')
|
248
|
+
requires :identity
|
249
|
+
|
250
|
+
body = {
|
251
|
+
description: description,
|
252
|
+
type: type
|
253
|
+
}
|
254
|
+
|
255
|
+
execute_action('create_image', async, body)
|
256
|
+
end
|
257
|
+
|
258
|
+
def rebuild_from_image(async: async_mode?, image:)
|
259
|
+
requires :identity
|
260
|
+
|
261
|
+
# FIXME: Lookup images by description. As API does not support
|
262
|
+
# this we need to filter our own. Probably needs pagination
|
263
|
+
# support.
|
264
|
+
image_id = case image
|
265
|
+
when Fog::Hetznercloud::Compute::Image
|
266
|
+
image.identity
|
267
|
+
when Integer
|
268
|
+
image
|
269
|
+
end
|
270
|
+
|
271
|
+
body = {
|
272
|
+
image: image_id
|
273
|
+
}
|
274
|
+
|
275
|
+
execute_action('rebuild', async, body)
|
276
|
+
end
|
277
|
+
|
278
|
+
def change_type(async: async_mode?, upgrade_disk: false, server_type:)
|
279
|
+
requires :identity
|
280
|
+
|
281
|
+
# FIXME: Should I shutdown and wait here as server needs to
|
282
|
+
# be stopped ?
|
283
|
+
|
284
|
+
body = {
|
285
|
+
upgrade_disk: upgrade_disk,
|
286
|
+
server_type: server_type
|
287
|
+
}
|
288
|
+
|
289
|
+
execute_action('change_type', async, body)
|
290
|
+
end
|
291
|
+
|
292
|
+
def enable_backup(async: async_mode?, backup_window: nil)
|
293
|
+
requires :identity
|
294
|
+
|
295
|
+
unless backup_window.nil?
|
296
|
+
body = {
|
297
|
+
backup_window: backup_window
|
298
|
+
}
|
299
|
+
end
|
300
|
+
|
301
|
+
execute_action('enable_backup', async, body)
|
302
|
+
end
|
303
|
+
|
304
|
+
def change_dns_ptr(dns_ptr, ip: public_ip_address, async: async_mode?)
|
305
|
+
requires :identity
|
306
|
+
|
307
|
+
body = {
|
308
|
+
ip: ip,
|
309
|
+
dns_ptr: dns_ptr
|
310
|
+
}
|
311
|
+
|
312
|
+
execute_action('change_dns_ptr', async, body)
|
313
|
+
end
|
314
|
+
|
315
|
+
def disable_backup(async: async_mode?)
|
316
|
+
requires :identity
|
317
|
+
|
318
|
+
execute_action('disable_backup', async)
|
319
|
+
end
|
320
|
+
|
321
|
+
# Returns action, password
|
322
|
+
def reset_root_password(async: async_mode?)
|
323
|
+
requires :identity
|
324
|
+
unless ready?
|
325
|
+
throw Fog::Hetznercloud::Error::StateError.new('ERROR: to reset the root password, the server must be running')
|
326
|
+
end
|
327
|
+
|
328
|
+
execute_action('reset_password', async)
|
329
|
+
end
|
330
|
+
|
331
|
+
def execute_action(action, async = true, body = {})
|
332
|
+
requires :identity
|
333
|
+
|
334
|
+
request_body = service.execute_server_action(identity, action, body).body
|
335
|
+
if (action = request_body['action'])
|
336
|
+
service.actions.new(action).tap do |a|
|
337
|
+
unless async
|
338
|
+
a.wait_for { a.success? }
|
339
|
+
reload
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
extra = service.images.new(request_body['image']) unless request_body['image'].nil?
|
344
|
+
extra = request_body['root_password'] unless request_body['root_password'].nil?
|
345
|
+
[action, extra]
|
346
|
+
end
|
347
|
+
|
348
|
+
def public_ip_address
|
349
|
+
public_net['ipv6']['ip'] if public_net.key?('ipv6')
|
350
|
+
public_net['ipv4']['ip'] if public_net.key?('ipv4')
|
351
|
+
end
|
352
|
+
|
353
|
+
private
|
354
|
+
|
355
|
+
def create
|
356
|
+
requires :name, :server_type, :image
|
357
|
+
|
358
|
+
options = {}
|
359
|
+
options[:ssh_keys] = ssh_keys.map(&:identity) unless ssh_keys.nil?
|
360
|
+
options[:user_data] = user_data unless user_data.nil?
|
361
|
+
options[:start_after_create] = start_after_create unless start_after_create.nil?
|
362
|
+
options[:location] = location.identity unless location.nil?
|
363
|
+
options[:datacenter] = datacenter.identity unless datacenter.nil?
|
364
|
+
|
365
|
+
if (server = service.create_server(name, image.identity, server_type.identity, options).body['server'])
|
366
|
+
merge_attributes(server)
|
367
|
+
true
|
368
|
+
else
|
369
|
+
false
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
def update
|
374
|
+
requires :identity, :name
|
375
|
+
return true unless @needsupdate
|
376
|
+
|
377
|
+
body = attributes.dup
|
378
|
+
|
379
|
+
body = {
|
380
|
+
name: name
|
381
|
+
}
|
382
|
+
|
383
|
+
if (server = service.update_server(identity, body).body['server'])
|
384
|
+
merge_attributes(server)
|
385
|
+
true
|
386
|
+
else
|
387
|
+
false
|
388
|
+
end
|
389
|
+
end
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
393
|
+
end
|