rubber 3.1.0 → 3.2.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.
@@ -1,9 +1,10 @@
1
1
  require 'json'
2
+ require 'rubber/cloud/aws'
2
3
 
3
4
  module Rubber
4
5
  module Cloud
5
6
 
6
- class AwsTableStore
7
+ class Aws::TableStore
7
8
 
8
9
  RETRYABLE_EXCEPTIONS = [Excon::Errors::Error]
9
10
 
@@ -0,0 +1,612 @@
1
+ require 'rubber/cloud/aws/base'
2
+ require 'rubber/util'
3
+
4
+ module Rubber
5
+ module Cloud
6
+
7
+ class Aws::Vpc < Aws::Base
8
+
9
+ def before_create_instance(instance)
10
+ host_env = load_bound_env(instance.name)
11
+ cloud_env = host_env.cloud_providers[env.cloud_provider]
12
+
13
+ instance.network = cloud_env.vpc_alias
14
+ instance.vpc_cidr = cloud_env.vpc_cidr
15
+
16
+ # Remember that instance.network is our more generic term for vpc_alias
17
+ role_names = instance.roles.map(&:name)
18
+ instance.vpc_id = setup_vpc(instance.network, instance.vpc_cidr).id
19
+ instance.gateway = host_env.private_nic.gateway
20
+ private_public = instance.gateway == 'public' ? 'public' : 'private'
21
+
22
+ instance.subnet_id = setup_vpc_subnet(
23
+ instance.vpc_id,
24
+ instance.network,
25
+ host_env.private_nic,
26
+ instance.zone,
27
+ "#{instance.network} #{instance.zone} #{private_public}"
28
+ ).subnet_id
29
+
30
+ setup_security_groups(instance.vpc_id, instance.name, instance.role_names)
31
+ end
32
+
33
+ def after_create_instance(instance)
34
+ super
35
+
36
+ # Creating an instance with both a subnet id and groups doesn't seem to
37
+ # result in the groups actually sticking. Lucky, VPC instances have
38
+ # mutable security groups
39
+ group_ids = describe_security_groups(instance.vpc_id).map { |g|
40
+ if instance.security_groups.include?(g[:name])
41
+ g[:group_id]
42
+ else
43
+ nil
44
+ end
45
+ }.compact
46
+
47
+ compute_provider.modify_instance_attribute(instance.instance_id, {
48
+ 'GroupId' => group_ids
49
+ })
50
+
51
+ if instance.roles.map(&:name).include? "nat_gateway"
52
+ # NAT gateways need the sourceDestCheck attribute to be false for AWS
53
+ # to allow them to route traffic
54
+ server = compute_provider.servers.get(instance.instance_id)
55
+
56
+ server.network_interfaces.each do |interface|
57
+ # Sometimes we get a blank interface back
58
+ next unless interface.count > 0
59
+
60
+ interface_id = interface['networkInterfaceId']
61
+
62
+ compute_provider.modify_network_interface_attribute(
63
+ interface_id,
64
+ 'sourceDestCheck',
65
+ false
66
+ )
67
+ end
68
+ end
69
+ end
70
+
71
+ def setup_security_groups(vpc_id, host=nil, roles=[])
72
+ rubber_cfg = Rubber::Configuration.get_configuration(Rubber.env)
73
+ scoped_env = rubber_cfg.environment.bind(roles, host)
74
+ security_group_defns = Hash[scoped_env.security_groups.to_a]
75
+
76
+ if scoped_env.auto_security_groups
77
+ sghosts = (scoped_env.rubber_instances.collect{|ic| ic.name } + [host]).uniq.compact
78
+ sgroles = (scoped_env.rubber_instances.all_roles + roles).uniq.compact
79
+ security_group_defns = inject_auto_security_groups(security_group_defns, sghosts, sgroles)
80
+ end
81
+
82
+ sync_security_groups(vpc_id, security_group_defns)
83
+ end
84
+
85
+ def setup_vpc(vpc_alias, vpc_cidr)
86
+ bound_env = load_bound_env
87
+
88
+ # First, check to see if the VPC is defined in the instance file. If it
89
+ # isn't, then check AWS for any VPCs with the same tag:RubberAlias.
90
+ # Failing that, create it
91
+
92
+ vpc = compute_provider.vpcs.all("tag:RubberAlias" => vpc_alias).first
93
+ vpc_id = vpc && vpc.id
94
+
95
+ if vpc_id
96
+ capistrano.logger.debug "Using #{vpc_id} #{vpc_alias}"
97
+ else
98
+ vpc = create_vpc(
99
+ "#{bound_env.app_name} #{Rubber.env}",
100
+ vpc_alias,
101
+ vpc_cidr
102
+ )
103
+
104
+ vpc_id = vpc.id
105
+
106
+ capistrano.logger.debug "Created #{vpc_id} #{vpc_alias}"
107
+ end
108
+
109
+ vpc
110
+ end
111
+
112
+ def setup_vpc_subnet(vpc_id, vpc_alias, private_nic, availability_zone, name)
113
+ subnet = find_or_create_vpc_subnet(
114
+ vpc_id,
115
+ vpc_alias,
116
+ name,
117
+ availability_zone,
118
+ private_nic.subnet_cidr,
119
+ private_nic.gateway
120
+ )
121
+
122
+ capistrano.logger.debug "Using #{subnet.subnet_id} #{name}"
123
+
124
+ subnet
125
+ end
126
+
127
+ def destroy_vpc(vpc_alias)
128
+ %w[
129
+ subnets
130
+ route_tables
131
+ security_groups
132
+ internet_gateways
133
+ ].each do |resource_name|
134
+ destroy_vpc_resource(vpc_alias, resource_name.strip)
135
+ end
136
+
137
+ vpc = compute_provider.vpcs.all('tag:RubberAlias' => vpc_alias).first
138
+ if vpc
139
+ compute_provider.vpcs.destroy(vpc.id)
140
+
141
+ capistrano.logger.info "Destroyed #{vpc.id} #{vpc_alias}"
142
+ else
143
+ capistrano.logger.info "No VPC found with alias #{vpc_alias}"
144
+ end
145
+ end
146
+
147
+ def describe_vpcs
148
+ compute_provider.vpcs.all.map do |vpc|
149
+ subnets = compute_provider.subnets.all('vpc-id' => vpc.id).map do |subnet|
150
+ tags = compute_provider.tags.all('resource-id' => subnet.subnet_id)
151
+
152
+ {
153
+ id: subnet.subnet_id,
154
+ public: (tags.to_s == 'true'),
155
+ cidr_block: subnet.cidr_block
156
+ }
157
+ end
158
+
159
+ {
160
+ id: vpc.id,
161
+ name: vpc.tags['Name'],
162
+ rubber_alias: vpc.tags['RubberAlias'],
163
+ subnets: subnets
164
+ }
165
+ end
166
+ end
167
+
168
+ def destroy_internet_gateways(vpc_alias)
169
+ vpc = compute_provider.vpcs.all("tag:RubberAlias" => vpc_alias).first
170
+ gateways = compute_provider.internet_gateways.all('tag:RubberVpcAlias' => vpc_alias)
171
+
172
+ gateways.each do |gateway|
173
+ compute_provider.detach_internet_gateway(gateway.id, vpc.id)
174
+
175
+ sleep 5
176
+
177
+ gateway.reload
178
+
179
+ if gateway.attachment_set.length > 0
180
+ compute_provider.delete_tags gateway.id, { "RubberVpcAlias" => vpc_alias }
181
+ capistrano.logger.info "not destroying #{gateway.id} due to other VPC attachments"
182
+ else
183
+ gateway.destroy
184
+ end
185
+ end
186
+
187
+ capistrano.logger.info "destroyed internet_gateways"
188
+ end
189
+
190
+ def destroy_security_groups(vpc_alias)
191
+ vpc = compute_provider.vpcs.all("tag:RubberAlias" => vpc_alias).first
192
+
193
+ groups = compute_provider.security_groups.all('vpc-id' => vpc.id)
194
+
195
+ groups.all.each do |group|
196
+ begin
197
+ group.destroy
198
+ rescue ::Fog::Compute::AWS::Error => e
199
+ # Some groups cannot be deleted by users. Just ignore these
200
+ raise e unless e.message =~ /CannotDelete/
201
+ end
202
+ end
203
+
204
+ capistrano.logger.info "destroyed security_groups"
205
+ end
206
+
207
+ def destroy_vpc_resource(vpc_alias, resource_name_plural)
208
+ specific_call = "destroy_#{resource_name_plural}"
209
+
210
+ if self.respond_to? specific_call
211
+ should_destroy = self.send specific_call, vpc_alias
212
+ else
213
+ resources = compute_provider.send(resource_name_plural).all('tag:RubberVpcAlias' => vpc_alias)
214
+
215
+ resources.each(&:destroy)
216
+
217
+ capistrano.logger.info "destroyed #{resource_name_plural}"
218
+ end
219
+ end
220
+
221
+ def describe_security_groups(vpc_id, group_name=nil)
222
+ groups = []
223
+
224
+ # As of 10/2/2015, vpcId isn't a valid filter, so we have to filter
225
+ # manually
226
+ opts = {
227
+ 'vpc-id' => vpc_id
228
+ }
229
+ opts["group-name"] = group_name if group_name
230
+ response = compute_provider.security_groups.all(opts)
231
+
232
+ response.each do |item|
233
+ group = {}
234
+ group[:group_id] = item.group_id
235
+ group[:name] = item.name
236
+ group[:description] = item.description
237
+
238
+ item.ip_permissions.each do |ip_item|
239
+ group[:permissions] ||= []
240
+ rule = {}
241
+
242
+ rule[:protocol] = ip_item["ipProtocol"]
243
+ rule[:from_port] = ip_item["fromPort"]
244
+ rule[:to_port] = ip_item["toPort"]
245
+
246
+ ip_item["groups"].each do |rule_group|
247
+ rule[:source_groups] ||= []
248
+ source_group = {}
249
+ source_group[:account] = rule_group["userId"]
250
+
251
+ # Amazon doesn't appear to be returning the groupName value when running in a default VPC. It's possible
252
+ # it's only returned for EC2 Classic. This is distinctly in conflict with the API documents and thus
253
+ # appears to be a bug on Amazon's end. Nonetheless, we need to handle it because otherwise our security
254
+ # group rule matching logic will fail and it messes up our users.
255
+ #
256
+ # Since every top-level item has both an ID and a name, if we're lacking the groupName we can search
257
+ # through the items for the one matching the groupId we have and then use its name value. This should
258
+ # represent precisely the same data.
259
+ source_group[:name] = if rule_group["groupName"]
260
+ rule_group["groupName"]
261
+ elsif rule_group["groupId"]
262
+ matching_security_group = response.find { |item| item.group_id == rule_group["groupId"] }
263
+ matching_security_group ? matching_security_group.name : nil
264
+ else
265
+ nil
266
+ end
267
+
268
+ source_group[:group_id] = rule_group["groupId"]
269
+
270
+ rule[:source_groups] << source_group
271
+ end if ip_item["groups"]
272
+
273
+ ip_item["ipRanges"].each do |ip_range|
274
+ rule[:source_ips] ||= []
275
+ rule[:source_ips] << ip_range["cidrIp"]
276
+ end if ip_item["ipRanges"]
277
+
278
+ group[:permissions] << rule
279
+ end
280
+
281
+ groups << group
282
+ end
283
+
284
+ groups
285
+ end
286
+
287
+ private
288
+
289
+ def create_vpc(name, vpc_alias, subnet_str)
290
+ vpc = compute_provider.vpcs.create(:cidr_block => subnet_str)
291
+
292
+ Rubber::Util.retry_on_failure(StandardError, :retry_sleep => 1, :retry_count => 120) do
293
+ create_tags(vpc.id,
294
+ :Name => name,
295
+ :Environment => Rubber.env,
296
+ :RubberAlias => vpc_alias)
297
+ end
298
+
299
+ vpc
300
+ end
301
+
302
+ def find_or_create_vpc_subnet(vpc_id, vpc_alias, name, availability_zone, cidr_block, gateway)
303
+ unless Rubber::Util.is_instance_id?(gateway) ||
304
+ Rubber::Util.is_internet_gateway_id?(gateway) ||
305
+ (gateway == 'public')
306
+ raise "gateway must be an instance id, gateway id, or \"public\""
307
+ end
308
+
309
+ subnet = compute_provider.subnets.all(
310
+ 'tag:RubberVpcAlias' => vpc_alias,
311
+ 'cidr-block' => cidr_block,
312
+ 'availability-zone' => availability_zone
313
+ ).first
314
+
315
+ unless subnet
316
+ subnet = compute_provider.subnets.create :vpc_id => vpc_id,
317
+ :cidr_block => cidr_block,
318
+ :availability_zone => availability_zone
319
+
320
+
321
+ Rubber::Util.retry_on_failure(StandardError, :retry_sleep => 1, :retry_count => 120) do
322
+ create_tags(subnet.subnet_id,
323
+ 'Name' => name,
324
+ 'Environment' => Rubber.env,
325
+ 'RubberVpcAlias' => vpc_alias
326
+ )
327
+ end
328
+
329
+ route_table = compute_provider.route_tables.all(
330
+ 'vpc-id' => vpc_id,
331
+ 'association.subnet-id' => subnet.subnet_id,
332
+ 'tag:RubberVpcAlias' => vpc_alias
333
+ ).first
334
+
335
+ route_table_id = route_table && route_table.id
336
+
337
+ unless route_table_id
338
+ resp = compute_provider.create_route_table(vpc_id)
339
+
340
+ route_table_id = resp.body['routeTable'].first['routeTableId']
341
+
342
+ Rubber::Util.retry_on_failure(StandardError, :retry_sleep => 1, :retry_count => 120) do
343
+ create_tags(
344
+ route_table_id,
345
+ 'Name' => name,
346
+ 'Environment' => Rubber.env,
347
+ 'RubberVpcAlias' => vpc_alias,
348
+ 'Public' => (gateway == 'public')
349
+ )
350
+ end
351
+
352
+ compute_provider.associate_route_table(route_table_id, subnet.subnet_id)
353
+ end
354
+
355
+ if Rubber::Util.is_instance_id?(gateway)
356
+ compute_provider.create_route(route_table_id, "0.0.0.0/0", nil, gateway)
357
+ elsif Rubber::Util.is_internet_gateway_id?(gateway)
358
+ compute_provider.create_route(route_table_id, "0.0.0.0/0", gateway)
359
+ else
360
+ internet_gateway = find_or_create_vpc_internet_gateway(vpc_id, vpc_alias, "#{name} gateway")
361
+
362
+ compute_provider.create_route(route_table_id, "0.0.0.0/0", internet_gateway.id)
363
+
364
+ capistrano.logger.debug "Created #{subnet.subnet_id} #{name}"
365
+ end
366
+ end
367
+
368
+ subnet
369
+ end
370
+
371
+ def find_or_create_vpc_internet_gateway(vpc_id, vpc_alias, name)
372
+ gateway = compute_provider.internet_gateways.all(
373
+ 'tag:RubberVpcAlias' => vpc_alias
374
+ ).first
375
+
376
+ unless gateway
377
+ gateway = compute_provider.internet_gateways.create
378
+ gateway.attach(vpc_id)
379
+ Rubber::Util.retry_on_failure(StandardError, :retry_sleep => 1, :retry_count => 120) do
380
+ create_tags(
381
+ gateway.id,
382
+ 'Name' => name,
383
+ 'Environment' => Rubber.env,
384
+ 'RubberVpcAlias' => vpc_alias
385
+ )
386
+ end
387
+
388
+ capistrano.logger.debug "Created #{gateway.id} #{name}"
389
+ end
390
+
391
+ gateway
392
+ end
393
+
394
+ def destroy_subnet(subnet_id)
395
+ compute_provider.subnets.destroy(subnet_id)
396
+ end
397
+
398
+ def create_security_group(vpc_id, group_name, group_description)
399
+ compute_provider.security_groups.create :vpc_id => vpc_id,
400
+ :name => group_name,
401
+ :description => group_description
402
+ end
403
+
404
+ def destroy_security_group(group_id)
405
+ compute_provider.security_groups.get(group_id).destroy
406
+ end
407
+
408
+ def add_security_group_rule(group_id, protocol, from_port, to_port, source)
409
+ group = compute_provider.security_groups.all('group-id' => group_id).first
410
+ # ip_protocol of -1 means all
411
+ # See: http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_AuthorizeSecurityGroupIngress.html
412
+ opts = {:ip_protocol => protocol || '-1' }
413
+
414
+ if source.instance_of? Hash
415
+ opts[:group] = {source[:account] => (source[:id] || source[:name])}
416
+ else
417
+ opts[:cidr_ip] = source
418
+ end
419
+
420
+ # VPC Security Rules sometimes have nil to/from ports which means the
421
+ # entire range is authorized
422
+ from_port = 0 if from_port.nil?
423
+ to_port = 65535 if to_port.nil?
424
+
425
+ group.authorize_port_range(from_port.to_i..to_port.to_i, opts)
426
+ end
427
+
428
+ def remove_security_group_rule(group_id, protocol, from_port, to_port, source)
429
+ group = compute_provider.security_groups.get(group_id)
430
+ opts = {:ip_protocol => protocol || 'tcp'}
431
+
432
+ if source.instance_of? Hash
433
+ opts[:group] = {source[:account] => source[:name]}
434
+ else
435
+ opts[:cidr_ip] = source
436
+ end
437
+
438
+ group.revoke_port_range(from_port.to_i..to_port.to_i, opts)
439
+ end
440
+
441
+ def sync_security_groups(vpc_id, groups)
442
+ return unless groups
443
+
444
+ groups = Rubber::Util::stringify(groups)
445
+ groups = isolate_groups(groups)
446
+ group_keys = groups.keys.clone()
447
+
448
+ # For each group that does already exist in cloud
449
+ cloud_groups = describe_security_groups(vpc_id)
450
+ cloud_groups.each do |cloud_group|
451
+ group_name = cloud_group[:name]
452
+ group_id = cloud_group[:group_id]
453
+
454
+ # skip those groups that don't belong to this project/env
455
+ next if env.isolate_security_groups && group_name !~ /^#{isolate_prefix}/
456
+
457
+ if group_keys.delete(group_name)
458
+ # sync rules
459
+ capistrano.logger.debug "Security Group already in cloud, syncing rules: #{group_name}"
460
+ group = groups[group_name]
461
+
462
+ # Convert the special case default rule into what it actually looks like when
463
+ # we query ec2 so that we can match things up when syncing. Also,
464
+ # retain a reference to the default rule so we can add the source_group_id
465
+ # when we sync from the cloud
466
+ default_rules = []
467
+
468
+ rules = group['rules'].clone
469
+ group['rules'].each do |rule|
470
+ if [2, 3].include?(rule.size) && rule['source_group_name'] && rule['source_group_account']
471
+ # source_group_id value will be populated when we fetch rules from the cloud
472
+ # TODO we appear to have a mismatch on source_group_account for some reason
473
+ default_rule = rule.merge({
474
+ "source_group_id" => nil,
475
+ "protocol" => "-1",
476
+ "from_port" => "",
477
+ "to_port" => ""
478
+ })
479
+ rules << default_rule
480
+ default_rules << default_rule
481
+ rules.delete(rule)
482
+ end
483
+ end
484
+
485
+ rule_maps = []
486
+
487
+ # first collect the rule maps from the request (group/user pairs are duplicated for tcp/udp/icmp,
488
+ # so we need to do this up frnot and remove duplicates before checking against the local rubber rules)
489
+ cloud_group[:permissions].each do |rule|
490
+ source_groups = rule.delete(:source_groups)
491
+ if source_groups
492
+ source_groups.each do |source_group|
493
+ rule_map = rule.clone
494
+ rule_map.delete(:source_ips)
495
+ rule_map[:source_group_name] = source_group[:name]
496
+ rule_map[:source_group_id] = source_group[:group_id]
497
+ rule_map[:source_group_account] = source_group[:account]
498
+
499
+ # Update the special case default rule with the group id if
500
+ # appropriate
501
+ if (rule_map[:protocol] == "-1") && rule_map[:to_port].nil? && rule_map[:from_port].nil?
502
+ default_rules.each do |default_rule|
503
+ if default_rule['source_group_account'] == source_group[:account]
504
+ default_rule['source_group_id'] = rule_map[:source_group_id]
505
+ end
506
+ end
507
+ end
508
+
509
+ rule_map = Rubber::Util::stringify(rule_map)
510
+ rule_maps << rule_map unless rule_maps.include?(rule_map)
511
+ end
512
+ else
513
+ rule_map = Rubber::Util::stringify(rule)
514
+ rule_maps << rule_map unless rule_maps.include?(rule_map)
515
+ end
516
+ end if cloud_group[:permissions]
517
+
518
+ # For each rule, if it exists, do nothing, otherwise remove it as its no longer defined locally
519
+ rule_maps.each do |rule_map|
520
+ if rules.delete(rule_map)
521
+ # rules match, don't need to do anything
522
+ # logger.debug "Rule in sync: #{rule_map.inspect}"
523
+ else
524
+ # rules don't match, remove them from cloud and re-add below
525
+ answer = nil
526
+ msg = "Rule '#{rule_map.inspect}' exists in cloud, but not locally"
527
+ if env.prompt_for_security_group_sync
528
+ answer = Capistrano::CLI.ui.ask("#{msg}, remove from cloud? [y/N]: ")
529
+ else
530
+ capistrano.logger.info(msg)
531
+ end
532
+
533
+ if answer =~ /^y/
534
+ rule_map = Rubber::Util::symbolize_keys(rule_map)
535
+ if rule_map[:source_group_id]
536
+ remove_security_group_rule(group_id, rule_map[:protocol], rule_map[:from_port], rule_map[:to_port], {:id => rule_map[:source_group_id], :account => rule_map[:source_group_account]})
537
+ else
538
+ rule_map[:source_ips].each do |source_ip|
539
+ remove_security_group_rule(group_id, rule_map[:protocol], rule_map[:from_port], rule_map[:to_port], source_ip)
540
+ end if rule_map[:source_ips]
541
+ end
542
+ end
543
+ end
544
+ end
545
+
546
+ rules.each do |rule_map|
547
+ # create non-existing rules
548
+ capistrano.logger.debug "Missing rule, creating: #{rule_map.inspect}"
549
+ rule_map = Rubber::Util::symbolize_keys(rule_map)
550
+ if rule_map[:source_group_id]
551
+ add_security_group_rule(group_id, rule_map[:protocol], rule_map[:from_port], rule_map[:to_port], {:id => rule_map[:source_group_id], :account => rule_map[:source_group_account]})
552
+ else
553
+ rule_map[:source_ips].each do |source_ip|
554
+ add_security_group_rule(group_id, rule_map[:protocol], rule_map[:from_port], rule_map[:to_port], source_ip)
555
+ end if rule_map[:source_ips]
556
+ end
557
+ end
558
+ else
559
+ # delete group
560
+ answer = nil
561
+ msg = "Security group '#{group_name}' exists in cloud but not locally"
562
+ if env.prompt_for_security_group_sync
563
+ answer = Capistrano::CLI.ui.ask("#{msg}, remove from cloud? [y/N]: ")
564
+ else
565
+ capistrano.logger.debug(msg)
566
+ end
567
+ destroy_security_group(group_name) if answer =~ /^y/
568
+ end
569
+ end
570
+
571
+ # For each group that didnt already exist in cloud
572
+ group_keys.each do |group_name|
573
+ group = groups[group_name]
574
+ capistrano.logger.debug "Creating new security group: #{group_name}"
575
+ # create each group
576
+ new_group = create_security_group(vpc_id, group_name, group['description'])
577
+ group_id = new_group.group_id
578
+ # create rules for group
579
+ group['rules'].each do |rule_map|
580
+ capistrano.logger.debug "Creating new rule: #{rule_map.inspect}"
581
+ rule_map = Rubber::Util::symbolize_keys(rule_map)
582
+ if rule_map[:source_group_name]
583
+ source = { :account => rule_map[:source_group_account] }
584
+
585
+ if rule_map[:source_group_id]
586
+ source[:id] = rule_map[:source_group_id]
587
+ elsif rule_map[:source_group_name]
588
+ cloud_group = describe_security_groups(vpc_id, rule_map[:source_group_name]).first
589
+
590
+ if cloud_group
591
+ source[:id] = cloud_group[:group_id]
592
+ end
593
+ end
594
+
595
+ add_security_group_rule(group_id, rule_map[:protocol], rule_map[:from_port], rule_map[:to_port], source)
596
+ else
597
+ rule_map[:source_ips].each do |source_ip|
598
+ add_security_group_rule(group_id, rule_map[:protocol], rule_map[:from_port], rule_map[:to_port], source_ip)
599
+ end if rule_map[:source_ips]
600
+ end
601
+ end
602
+ end
603
+ end
604
+
605
+ def load_bound_env(host=nil)
606
+ rubber_cfg = Rubber::Configuration.get_configuration(Rubber.env)
607
+ scoped_env = rubber_cfg.environment.bind(nil, host)
608
+ end
609
+ end
610
+ end
611
+ end
612
+