steamcannon-deltacloud-core 0.0.8.1 → 0.1.1.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/Rakefile +3 -9
- data/bin/deltacloudd +17 -15
- data/deltacloud.rb +1 -0
- data/lib/deltacloud/backend_capability.rb +21 -0
- data/lib/deltacloud/base_driver/base_driver.rb +6 -0
- data/lib/deltacloud/base_driver/features.rb +22 -0
- data/lib/deltacloud/base_driver/mock_driver.rb +24 -27
- data/lib/deltacloud/drivers/ec2/ec2_driver.rb +432 -494
- data/lib/deltacloud/drivers/gogrid/gogrid_client.rb +4 -7
- data/lib/deltacloud/drivers/gogrid/gogrid_driver.rb +116 -3
- data/lib/deltacloud/drivers/mock/mock_driver.rb +56 -2
- data/lib/deltacloud/drivers/rhevm/rhevm_driver.rb +5 -19
- data/lib/deltacloud/helpers/application_helper.rb +26 -3
- data/lib/deltacloud/models/image.rb +2 -1
- data/lib/deltacloud/models/instance.rb +22 -5
- data/lib/deltacloud/models/key.rb +17 -0
- data/lib/deltacloud/models/load_balancer.rb +39 -0
- data/lib/deltacloud/models/storage_volume.rb +2 -0
- data/lib/sinatra/rabbit.rb +4 -7
- data/public/javascripts/application.js +10 -24
- data/public/stylesheets/compiled/application.css +2 -0
- data/server.rb +214 -75
- data/views/blobs/new.html.haml +10 -0
- data/views/blobs/show.html.haml +21 -15
- data/views/buckets/index.html.haml +1 -1
- data/views/buckets/show.html.haml +5 -2
- data/views/errors/backend_capability_failure.html.haml +11 -0
- data/views/errors/backend_capability_failure.xml.haml +4 -0
- data/views/errors/backend_error.html.haml +3 -0
- data/views/errors/not_allowed.html.haml +6 -0
- data/views/errors/not_allowed.xml.haml +2 -0
- data/views/instances/index.html.haml +1 -1
- data/views/instances/new.html.haml +8 -0
- data/views/instances/show.html.haml +1 -1
- data/views/keys/show.xml.haml +2 -0
- data/views/load_balancers/index.html.haml +33 -0
- data/views/load_balancers/index.xml.haml +5 -0
- data/views/load_balancers/new.html.haml +38 -0
- data/views/load_balancers/show.html.haml +37 -0
- data/views/load_balancers/show.xml.haml +21 -0
- data/views/realms/index.html.haml +4 -7
- data/views/storage_snapshots/index.html.haml +3 -0
- data/views/storage_snapshots/index.xml.haml +0 -2
- data/views/storage_snapshots/new.html.haml +9 -0
- data/views/storage_snapshots/show.xml.haml +0 -2
- data/views/storage_volumes/attach.html.haml +20 -0
- data/views/storage_volumes/index.html.haml +16 -1
- data/views/storage_volumes/index.xml.haml +1 -20
- data/views/storage_volumes/new.html.haml +17 -0
- data/views/storage_volumes/show.xml.haml +13 -19
- metadata +53 -99
@@ -9,7 +9,7 @@ class GoGridClient
|
|
9
9
|
apikey='YOUR API KEY',
|
10
10
|
secret='YOUR SHARED SECRET',
|
11
11
|
format='json',
|
12
|
-
version='1.
|
12
|
+
version='1.6')
|
13
13
|
@server = server
|
14
14
|
@secret = secret
|
15
15
|
@default_params = {'format'=>format, 'v'=>version,'api_key' => apikey}
|
@@ -35,12 +35,9 @@ class GoGridClient
|
|
35
35
|
@default_params['v'] = version
|
36
36
|
else
|
37
37
|
@default_params['v'] = '1.5'
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
rescue Exception => e
|
42
|
-
STDERR.puts("ERROR: #{e.message}")
|
43
|
-
end
|
38
|
+
end
|
39
|
+
request = sendAPIRequest(method, params)
|
40
|
+
JSON::parse(request)
|
44
41
|
end
|
45
42
|
|
46
43
|
def encode_params(params)
|
@@ -45,7 +45,7 @@ class GogridDriver < Deltacloud::BaseDriver
|
|
45
45
|
|
46
46
|
def supported_collections
|
47
47
|
DEFAULT_COLLECTIONS.reject! { |c| [ :storage_volumes, :storage_snapshots ].include?(c) }
|
48
|
-
DEFAULT_COLLECTIONS + [ :keys ]
|
48
|
+
DEFAULT_COLLECTIONS + [ :keys, :load_balancers ]
|
49
49
|
end
|
50
50
|
|
51
51
|
def images(credentials, opts=nil)
|
@@ -176,6 +176,88 @@ class GogridDriver < Deltacloud::BaseDriver
|
|
176
176
|
end
|
177
177
|
end
|
178
178
|
|
179
|
+
def create_load_balancer(credentials, opts={})
|
180
|
+
gogrid = new_client(credentials)
|
181
|
+
balancer, l_instance = nil, nil
|
182
|
+
safely do
|
183
|
+
virtip = get_free_ip_from_realm(credentials, opts['realm_id'])
|
184
|
+
if opts['instance_id']
|
185
|
+
l_instance = instance(credentials, :id => opts['instance_id'])
|
186
|
+
real_ip = {
|
187
|
+
'realiplist.0.port' => opts['listener_inst_port'],
|
188
|
+
'realiplist.0.ip' => l_instance ? l_instance.public_addresses.first : ""
|
189
|
+
}
|
190
|
+
else
|
191
|
+
real_ip = false
|
192
|
+
end
|
193
|
+
request = {
|
194
|
+
'name' => opts['name'],
|
195
|
+
'virtualip.ip' => virtip,
|
196
|
+
'virtualip.port' => opts['listener_lbr_port'],
|
197
|
+
}
|
198
|
+
request.merge!(real_ip) if real_ip
|
199
|
+
balancer = gogrid.request('grid/loadbalancer/add', request)['list'].first
|
200
|
+
end
|
201
|
+
balancer = convert_load_balancer(credentials, balancer)
|
202
|
+
balancer.instances = [l_instance] if l_instance
|
203
|
+
balancer
|
204
|
+
end
|
205
|
+
|
206
|
+
def destroy_load_balancer(credentials, id)
|
207
|
+
gogrid = new_client(credentials)
|
208
|
+
balancer = nil
|
209
|
+
safely do
|
210
|
+
balancer = gogrid.request('grid/loadbalancer/delete', { 'name' => id })
|
211
|
+
balancer = load_balancer(credentials, :id => id) unless balancer
|
212
|
+
end
|
213
|
+
convert_load_balancer(credentials, balancer)
|
214
|
+
end
|
215
|
+
|
216
|
+
def load_balancers(credentials, opts={})
|
217
|
+
gogrid = new_client(credentials)
|
218
|
+
balancers = []
|
219
|
+
safely do
|
220
|
+
balancer = gogrid.request('grid/loadbalancer/list', opts || {})['list'].each do |balancer|
|
221
|
+
balancers << balancer
|
222
|
+
end
|
223
|
+
end
|
224
|
+
balancers.collect { |b| convert_load_balancer(credentials, b) }
|
225
|
+
end
|
226
|
+
|
227
|
+
def load_balancer(credentials, opts={})
|
228
|
+
gogrid = new_client(credentials)
|
229
|
+
balancer = nil
|
230
|
+
begin
|
231
|
+
balancer = gogrid.request('grid/loadbalancer/get', { 'name' => opts[:id] })['list'].first
|
232
|
+
balancer['instances'] = instances(credentials)
|
233
|
+
return convert_load_balancer(credentials, balancer)
|
234
|
+
rescue OpenURI::HTTPError
|
235
|
+
balancer = load_balancers(credentials, :id => opts[:id]).first
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
|
240
|
+
def lb_register_instance(credentials, opts={})
|
241
|
+
client = new_client(credentials)
|
242
|
+
instance = instance(credentials, :id => opts[:instance_id])
|
243
|
+
balancer = client.request('grid/loadbalancer/get', { 'name' => opts[:id]})['list'].first
|
244
|
+
safely do
|
245
|
+
convert_load_balancer(credentials, client.request('grid/loadbalancer/edit', {
|
246
|
+
"id" => balancer['id'],
|
247
|
+
"realiplist.#{balancer['realiplist'].size}.ip" => instance.public_addresses.first,
|
248
|
+
"realiplist.#{balancer['realiplist'].size}.port" => balancer['virtualip']['port']
|
249
|
+
}))
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
# Move this to capabilities
|
254
|
+
def lb_unregister_instance(credentials, opts={})
|
255
|
+
raise Deltacloud::BackendFeatureUnsupported.new('501',
|
256
|
+
'Unregistering instances from load balancer is not supported in GoGrid')
|
257
|
+
end
|
258
|
+
|
259
|
+
|
260
|
+
|
179
261
|
def key(credentials, opts=nil)
|
180
262
|
keys(credentials, opts).first
|
181
263
|
end
|
@@ -213,8 +295,39 @@ class GogridDriver < Deltacloud::BaseDriver
|
|
213
295
|
|
214
296
|
def new_client(credentials)
|
215
297
|
GoGridClient.new('https://api.gogrid.com/api', credentials.user, credentials.password)
|
298
|
+
end
|
216
299
|
|
300
|
+
def convert_load_balancer(credentials, loadbalancer)
|
301
|
+
if loadbalancer['datacenter']
|
302
|
+
b_realm = realm(credentials, :id => loadbalancer['datacenter']['id'])
|
303
|
+
else
|
304
|
+
# Report first Realm until loadbalancer become ready
|
305
|
+
b_realm = realm(credentials, :id => 1)
|
306
|
+
end
|
307
|
+
balancer = LoadBalancer.new({
|
308
|
+
:id => loadbalancer['name'],
|
309
|
+
:realms => [b_realm]
|
310
|
+
})
|
311
|
+
balancer.public_addresses = [loadbalancer['virtualip']['ip']['ip']] if loadbalancer['virtualip'] and loadbalancer['virtualip']['ip']
|
312
|
+
balancer.listeners = []
|
313
|
+
balancer.instances = []
|
314
|
+
instance_ips = []
|
315
|
+
loadbalancer['realiplist'].each do |instance_ip|
|
316
|
+
balancer.add_listener({
|
317
|
+
:protocol => 'TCP',
|
318
|
+
:load_balancer_port => loadbalancer['virtualip']['port'],
|
319
|
+
:instance_port => instance_ip['port']
|
320
|
+
})
|
321
|
+
instance_ips << instance_ip['ip']['ip']
|
322
|
+
end if loadbalancer['realiplist']
|
323
|
+
balancer.instances = get_load_balancer_instances(instance_ips, loadbalancer['instances'])
|
324
|
+
return balancer
|
217
325
|
end
|
326
|
+
|
327
|
+
def get_load_balancer_instances(instance_ips, instances)
|
328
|
+
instances.select { |i| instance_ips.include?(i.public_addresses.first) } if instances
|
329
|
+
end
|
330
|
+
|
218
331
|
|
219
332
|
def get_login_data(client, instance_id)
|
220
333
|
login_data = {}
|
@@ -316,11 +429,11 @@ class GogridDriver < Deltacloud::BaseDriver
|
|
316
429
|
state.eql?('Off') ? 'STOPPED' : 'RUNNING'
|
317
430
|
end
|
318
431
|
|
319
|
-
def get_free_ip_from_realm(credentials, realm_id)
|
432
|
+
def get_free_ip_from_realm(credentials, realm_id, ip_type = 1)
|
320
433
|
ip = ""
|
321
434
|
safely do
|
322
435
|
ip = new_client(credentials).request('grid/ip/list', {
|
323
|
-
'ip.type' =>
|
436
|
+
'ip.type' => "#{ip_type}",
|
324
437
|
'ip.state' => '1',
|
325
438
|
'datacenter' => realm_id
|
326
439
|
})['list'].first['ip']
|
@@ -26,7 +26,7 @@ module Deltacloud
|
|
26
26
|
class MockDriver < Deltacloud::BaseDriver
|
27
27
|
|
28
28
|
def supported_collections
|
29
|
-
DEFAULT_COLLECTIONS + [ :buckets ]
|
29
|
+
DEFAULT_COLLECTIONS + [ :buckets, :keys]
|
30
30
|
end
|
31
31
|
|
32
32
|
( REALMS = [
|
@@ -81,6 +81,7 @@ class MockDriver < Deltacloud::BaseDriver
|
|
81
81
|
end
|
82
82
|
|
83
83
|
feature :instances, :user_name
|
84
|
+
feature :instances, :authentication_key
|
84
85
|
|
85
86
|
def initialize
|
86
87
|
if ENV["DELTACLOUD_MOCK_STORAGE"]
|
@@ -131,11 +132,21 @@ class MockDriver < Deltacloud::BaseDriver
|
|
131
132
|
# Instances
|
132
133
|
#
|
133
134
|
|
135
|
+
def instance(credentials, opts={})
|
136
|
+
check_credentials( credentials )
|
137
|
+
instance_filename = File.join(@storage_root, 'instances', "#{opts[:id]}.yml")
|
138
|
+
return nil unless File.exists?(instance_filename)
|
139
|
+
instance = YAML::load_file(instance_filename)
|
140
|
+
instance[:actions] = instance_actions_for( instance[:state] )
|
141
|
+
instance[:id] = File::basename(instance_filename, ".yml")
|
142
|
+
Instance.new(instance)
|
143
|
+
end
|
144
|
+
|
134
145
|
def instances(credentials, opts=nil)
|
135
146
|
check_credentials( credentials )
|
136
147
|
instances = []
|
137
148
|
Dir[ "#{@storage_root}/instances/*.yml" ].each do |instance_file|
|
138
|
-
instance = YAML
|
149
|
+
instance = YAML::load_file(instance_file)
|
139
150
|
if ( instance[:owner_id] == credentials.user )
|
140
151
|
instance[:id] = File.basename( instance_file, ".yml" )
|
141
152
|
instance[:actions] = instance_actions_for( instance[:state] )
|
@@ -254,6 +265,49 @@ class MockDriver < Deltacloud::BaseDriver
|
|
254
265
|
snapshots
|
255
266
|
end
|
256
267
|
|
268
|
+
def keys(credentials, opts={})
|
269
|
+
check_credentials(credentials)
|
270
|
+
result = []
|
271
|
+
key_dir = File.join(@storage_root, 'keys')
|
272
|
+
Dir[key_dir + '/*.yml'].each do |key_file|
|
273
|
+
result << Key.new(YAML::load(File.read(key_file)))
|
274
|
+
end
|
275
|
+
result = filter_on( result, :id, opts )
|
276
|
+
result
|
277
|
+
end
|
278
|
+
|
279
|
+
def key(credentials, opts={})
|
280
|
+
keys(credentials, opts).first
|
281
|
+
end
|
282
|
+
|
283
|
+
def create_key(credentials, opts={})
|
284
|
+
check_credentials(credentials)
|
285
|
+
key_hash = {
|
286
|
+
:id => opts[:key_name],
|
287
|
+
:credential_type => :key,
|
288
|
+
:fingerprint => Key::generate_mock_fingerprint,
|
289
|
+
:pem_rsa_key => Key::generate_mock_pem
|
290
|
+
}
|
291
|
+
key_dir = File.join(@storage_root, 'keys')
|
292
|
+
if File.exists?(key_dir + "/#{key_hash[:id]}.yml")
|
293
|
+
raise Deltacloud::BackendError.new(403, self.class.to_s, "key-exists",
|
294
|
+
["Key with same name already exists"])
|
295
|
+
end
|
296
|
+
FileUtils.mkdir_p(key_dir) unless File.directory?(key_dir)
|
297
|
+
File.open(key_dir + "/#{key_hash[:id]}.yml", 'w') do |f|
|
298
|
+
f.puts(YAML::dump(key_hash))
|
299
|
+
end
|
300
|
+
return Key.new(key_hash)
|
301
|
+
end
|
302
|
+
|
303
|
+
def destroy_key(credentials, opts={})
|
304
|
+
key = key(credentials, opts)
|
305
|
+
safely do
|
306
|
+
key_dir = File.join(@storage_root, 'keys')
|
307
|
+
File.delete(key_dir + "/#{key.id}.yml")
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
257
311
|
#--
|
258
312
|
# Buckets
|
259
313
|
#--
|
@@ -35,6 +35,10 @@ class RHEVMDriver < Deltacloud::BaseDriver
|
|
35
35
|
|
36
36
|
feature :instances, :user_name
|
37
37
|
|
38
|
+
def supported_collections
|
39
|
+
DEFAULT_COLLECTIONS.reject { |c| [ :storage_volumes, :storage_snapshots ].include?(c) }
|
40
|
+
end
|
41
|
+
|
38
42
|
#
|
39
43
|
# Execute a Powershell command, and convert the output
|
40
44
|
# to YAML in order to get back an array of maps.
|
@@ -85,6 +89,7 @@ class RHEVMDriver < Deltacloud::BaseDriver
|
|
85
89
|
"STOPPED"
|
86
90
|
when "POWERING UP"
|
87
91
|
"PENDING"
|
92
|
+
end
|
88
93
|
end
|
89
94
|
|
90
95
|
define_hardware_profile 'rhevm'
|
@@ -232,25 +237,6 @@ class RHEVMDriver < Deltacloud::BaseDriver
|
|
232
237
|
vm = execute(credentials, "deleteVm.ps1", image_id)
|
233
238
|
vm_to_instance(vm[0])
|
234
239
|
end
|
235
|
-
|
236
|
-
#
|
237
|
-
# Storage Volumes
|
238
|
-
#
|
239
|
-
|
240
|
-
def storage_volumes(credentials, ids=nil)
|
241
|
-
volumes = []
|
242
|
-
volumes
|
243
|
-
end
|
244
|
-
|
245
|
-
#
|
246
|
-
# Storage Snapshots
|
247
|
-
#
|
248
|
-
|
249
|
-
def storage_snapshots(credentials, ids=nil)
|
250
|
-
snapshots = []
|
251
|
-
snapshots
|
252
|
-
end
|
253
|
-
|
254
240
|
end
|
255
241
|
|
256
242
|
end
|
@@ -38,11 +38,15 @@ module ApplicationHelper
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def instance_action_method(action)
|
41
|
-
|
41
|
+
action_method(action, :instances)
|
42
42
|
end
|
43
43
|
|
44
|
-
def
|
45
|
-
|
44
|
+
def action_method(action, collection)
|
45
|
+
collections[collection].operations[action.to_sym].method
|
46
|
+
end
|
47
|
+
|
48
|
+
def driver_has_feature?(feature_name, collection_name = :instances)
|
49
|
+
not driver.features(collection_name).select{ |f| f.name.eql?(feature_name) }.empty?
|
46
50
|
end
|
47
51
|
|
48
52
|
def driver_has_auth_features?
|
@@ -102,6 +106,14 @@ module ApplicationHelper
|
|
102
106
|
end
|
103
107
|
|
104
108
|
def instance_action(name)
|
109
|
+
original_instance = driver.instance(credentials, :id => params[:id])
|
110
|
+
|
111
|
+
# If original instance doesn't include called action
|
112
|
+
# return with 405 error (Method is not Allowed)
|
113
|
+
unless driver.instance_actions_for(original_instance.state).include?(name.to_sym)
|
114
|
+
return report_error(405, 'not_allowed')
|
115
|
+
end
|
116
|
+
|
105
117
|
@instance = driver.send(:"#{name}_instance", credentials, params["id"])
|
106
118
|
|
107
119
|
return redirect(instances_url) if name.eql?(:destroy) or @instance.class!=Instance
|
@@ -122,4 +134,15 @@ module ApplicationHelper
|
|
122
134
|
"<pem><![CDATA[#{text.strip}]]></pem>"
|
123
135
|
end
|
124
136
|
|
137
|
+
def link_to_action(action, url, method)
|
138
|
+
capture_haml do
|
139
|
+
haml_tag :form, :method => :post, :action => url, :class => :link do
|
140
|
+
haml_tag :input, :type => :hidden, :name => '_method', :value => method
|
141
|
+
haml_tag :button, :type => :submit do
|
142
|
+
haml_concat action
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
125
148
|
end
|
@@ -29,10 +29,27 @@ class Instance < BaseModel
|
|
29
29
|
attr_accessor :private_addresses
|
30
30
|
attr_accessor :instance_profile
|
31
31
|
attr_accessor :launch_time
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
32
|
+
attr_accessor :keyname
|
33
|
+
attr_accessor :authn_error
|
34
|
+
|
35
|
+
def initialize(init=nil)
|
36
|
+
super(init)
|
37
|
+
self.actions = [] if self.actions.nil?
|
38
|
+
self.public_addresses = [] if self.public_addresses.nil?
|
39
|
+
self.private_addresses = [] if self.private_addresses.nil?
|
40
|
+
end
|
41
|
+
|
42
|
+
def method_missing(name, *args)
|
43
|
+
if name =~ /is_(\w+)\?/
|
44
|
+
return true if self.state.downcase.eql?($1)
|
45
|
+
else
|
46
|
+
raise NoMethodError
|
47
|
+
end
|
37
48
|
end
|
49
|
+
|
50
|
+
def authn_feature_failed?
|
51
|
+
return true unless authn_error.nil?
|
52
|
+
end
|
53
|
+
|
54
|
+
|
38
55
|
end
|
@@ -23,6 +23,7 @@ class Key < BaseModel
|
|
23
23
|
attr_accessor :username
|
24
24
|
attr_accessor :password
|
25
25
|
attr_accessor :pem_rsa_key
|
26
|
+
attr_accessor :state
|
26
27
|
|
27
28
|
def is_password?
|
28
29
|
true if @credential_type.eql?(:password)
|
@@ -32,4 +33,20 @@ class Key < BaseModel
|
|
32
33
|
true if @credential_type.eql?(:key)
|
33
34
|
end
|
34
35
|
|
36
|
+
# Mock fingerprint generator
|
37
|
+
# 1f:51:ae:28:bf:89:e9:d8:1f:25:5d:37:2d:7d:b8:ca:9f:f5:f1:6f
|
38
|
+
def self.generate_mock_fingerprint
|
39
|
+
(0..19).map { "%02x" % (rand * 0xff) }.join(':')
|
40
|
+
end
|
41
|
+
|
42
|
+
# Mock PEM file
|
43
|
+
# NOTE: This is a fake PEM file, it will not work against SSH
|
44
|
+
def self.generate_mock_pem
|
45
|
+
chars = (('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a + %w(= / + ))
|
46
|
+
pem_material = (1..21).map do
|
47
|
+
(1..75).collect{|a| chars[rand(chars.size)] }.join
|
48
|
+
end.join("\n") + "\n" + (1..68).collect{|a| chars[rand(chars.size)] }.join
|
49
|
+
"-----BEGIN RSA PRIVATE KEY-----\n"+pem_material+"-----END RSA PRIVATE KEY-----"
|
50
|
+
end
|
51
|
+
|
35
52
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2009 Red Hat, Inc.
|
3
|
+
#
|
4
|
+
# Licensed to the Apache Software Foundation (ASF) under one or more
|
5
|
+
# contributor license agreements. See the NOTICE file distributed with
|
6
|
+
# this work for additional information regarding copyright ownership. The
|
7
|
+
# ASF licenses this file to you under the Apache License, Version 2.0 (the
|
8
|
+
# "License"); you may not use this file except in compliance with the
|
9
|
+
# License. You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
15
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
16
|
+
# License for the specific language governing permissions and limitations
|
17
|
+
# under the License.
|
18
|
+
|
19
|
+
|
20
|
+
class LoadBalancer < BaseModel
|
21
|
+
|
22
|
+
attr_accessor :realms
|
23
|
+
attr_accessor :listeners
|
24
|
+
attr_accessor :instances
|
25
|
+
attr_accessor :public_addresses
|
26
|
+
attr_accessor :created_at
|
27
|
+
|
28
|
+
def add_listener(opts)
|
29
|
+
@listeners << Listener.new(opts)
|
30
|
+
end
|
31
|
+
|
32
|
+
class Listener < BaseModel
|
33
|
+
attr_accessor :protocol
|
34
|
+
attr_accessor :load_balancer_port
|
35
|
+
attr_accessor :instance_port
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|