kelbim 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.
@@ -0,0 +1,37 @@
1
+ require 'ostruct'
2
+ require 'set'
3
+ require 'kelbim/dsl/load-balancer'
4
+
5
+ module Kelbim
6
+ class DSL
7
+ class EC2
8
+ attr_reader :result
9
+
10
+ def initialize(vpc, &block)
11
+ @names = []
12
+ @error_identifier = "EC2 `#{vpc || :classic}`"
13
+
14
+ @result = OpenStruct.new({
15
+ :vpc => vpc,
16
+ :load_balancers => [],
17
+ })
18
+
19
+ instance_eval(&block)
20
+ end
21
+
22
+ private
23
+ def load_balancer(name, opts = {}, &block)
24
+ if @names.include?(name)
25
+ raise "#{@error_identifier}: `#{name}` is already defined"
26
+ end
27
+
28
+ unless (invalid_keys = (opts.keys - [:internal])).empty?
29
+ raise "LoadBalancer `#{name}`: Invalid option keys: #{invalid_keys}"
30
+ end
31
+
32
+ @result.load_balancers << LoadBalancer.new(name, @result.vpc, opts[:internal], &block).result
33
+ @names << name
34
+ end
35
+ end # EC2
36
+ end # DSL
37
+ end # Kelbim
@@ -0,0 +1,57 @@
1
+ require 'ostruct'
2
+ require 'kelbim/dsl/checker'
3
+
4
+ module Kelbim
5
+ class DSL
6
+ class EC2
7
+ class LoadBalancer
8
+ class HealthCheck
9
+ include Checker
10
+
11
+ def initialize(load_balancer, &block)
12
+ @error_identifier = "LoadBalancer `#{load_balancer}`"
13
+ @result = {}
14
+ instance_eval(&block)
15
+ end
16
+
17
+ def result
18
+ [:target, :timeout, :interval, :healthy_threshold, :unhealthy_threshold].each do |name|
19
+ required(name, @result[name])
20
+ end
21
+
22
+ @result
23
+ end
24
+
25
+ def target(value)
26
+ call_once(:target)
27
+ @result[:target] = value
28
+ end
29
+
30
+ def timeout(value)
31
+ call_once(:timeout)
32
+ expected_type(value, Integer)
33
+ @result[:timeout] = value
34
+ end
35
+
36
+ def interval(value)
37
+ call_once(:interval)
38
+ expected_type(value, Integer)
39
+ @result[:interval] = value
40
+ end
41
+
42
+ def healthy_threshold(value)
43
+ call_once(:healthy_threshold)
44
+ expected_type(value, Integer)
45
+ @result[:healthy_threshold] = value
46
+ end
47
+
48
+ def unhealthy_threshold(value)
49
+ call_once(:unhealthy_threshold)
50
+ expected_type(value, Integer)
51
+ @result[:unhealthy_threshold] = value
52
+ end
53
+ end # HealthCheck
54
+ end # LoadBalancer
55
+ end # EC2
56
+ end # DSL
57
+ end # Kelbim
@@ -0,0 +1,61 @@
1
+ require 'ostruct'
2
+ require 'kelbim/dsl/checker'
3
+ require 'kelbim/policy-types'
4
+
5
+ module Kelbim
6
+ class DSL
7
+ class EC2
8
+ class LoadBalancer
9
+ class Listeners
10
+ class Listener
11
+ include Checker
12
+
13
+ def initialize(load_balancer, protocol_prots, &block)
14
+ @error_identifier = "LoadBalancer `#{load_balancer}`: #{protocol_prots}"
15
+
16
+ @result = OpenStruct.new({
17
+ :policies => []
18
+ })
19
+
20
+ instance_eval(&block)
21
+ end
22
+
23
+ attr_reader :result
24
+
25
+ def server_certificate(value)
26
+ call_once(:server_certificate)
27
+ @result.server_certificate = value
28
+ end
29
+
30
+ def policies(value)
31
+ call_once(:policies)
32
+ expected_type(value, Hash)
33
+
34
+ unless value.kind_of?(Hash)
35
+ raise "LoadBalancer `#{@load_balancer}`: #{@protocol_prots}: Invalid policies: #{value}"
36
+ end
37
+
38
+ value = value.map do |policy, name_or_attrs|
39
+ expected_type(name_or_attrs, String, Hash)
40
+ policy = PolicyTypes.symbol_to_string(policy)
41
+ [policy, name_or_attrs]
42
+ end
43
+
44
+ @result.policies = value
45
+ end
46
+
47
+ PolicyTypes::POLICIES.keys.each do |attr_name|
48
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
49
+ def #{attr_name}(name_or_attrs)
50
+ call_once(#{attr_name.inspect})
51
+ expected_type(name_or_attrs, String, Hash, Array)
52
+ @result.policies << [#{attr_name.inspect}, name_or_attrs]
53
+ end
54
+ EOS
55
+ end
56
+ end # Listener
57
+ end # Listeners
58
+ end # LoadBalancer
59
+ end # EC2
60
+ end # DSL
61
+ end # Kelbim
@@ -0,0 +1,56 @@
1
+ require 'ostruct'
2
+ require 'kelbim/dsl/checker'
3
+ require 'kelbim/dsl/listener'
4
+
5
+ module Kelbim
6
+ class DSL
7
+ class EC2
8
+ class LoadBalancer
9
+ class Listeners
10
+ include Checker
11
+
12
+ def initialize(load_balancer, &block)
13
+ @error_identifier = "LoadBalancer `#{load_balancer}`"
14
+ @result = {}
15
+ instance_eval(&block)
16
+ end
17
+
18
+ def result
19
+ required(:listener, @result)
20
+
21
+ @result.map do |protocol_ports, listener|
22
+ protocol, port, instance_protocol, instance_port = protocol_ports.first.flatten
23
+
24
+ OpenStruct.new({
25
+ :protocol => protocol,
26
+ :port => port,
27
+ :instance_protocol => instance_protocol,
28
+ :instance_port => instance_port,
29
+ :server_certificate => listener.server_certificate,
30
+ :policies => listener.policies,
31
+ })
32
+ end
33
+ end
34
+
35
+ private
36
+ def listener(protocol_ports, &block)
37
+ expected_type(protocol_ports, Hash)
38
+ expected_length(protocol_ports, 1)
39
+
40
+ block = proc {} unless block
41
+
42
+ protocol_ports.first.each do |protocol_port|
43
+ protocol, port = protocol_port
44
+ expected_type(protocol_port, Array)
45
+ expected_length(protocol_port, 2)
46
+ expected_value(protocol, :http, :https, :tcp, :ssl)
47
+ expected_type(port, Integer)
48
+ end
49
+
50
+ @result[protocol_ports] = Listener.new(@load_balancer, protocol_ports, &block).result
51
+ end
52
+ end # Listeners
53
+ end # LoadBalancer
54
+ end # EC2
55
+ end # DSL
56
+ end # Kelbim
@@ -0,0 +1,85 @@
1
+ require 'ostruct'
2
+ require 'kelbim/dsl/checker'
3
+ require 'kelbim/dsl/health-check'
4
+ require 'kelbim/dsl/listeners'
5
+
6
+ module Kelbim
7
+ class DSL
8
+ class EC2
9
+ class LoadBalancer
10
+ include Checker
11
+
12
+ def initialize(name, vpc, internal, &block)
13
+ @name = name
14
+ @vpc = vpc
15
+ @error_identifier = "LoadBalancer `#{name}`"
16
+
17
+ @result = OpenStruct.new({
18
+ :name => name,
19
+ :instances => [],
20
+ :internal => internal,
21
+ })
22
+
23
+ instance_eval(&block)
24
+ end
25
+
26
+ def result
27
+ required(:listeners, @result.listeners)
28
+ required(:health_check, @result.health_check)
29
+
30
+ if @vpc
31
+ required(:subnets, @result.subnets)
32
+ required(:security_groups, @result.security_groups)
33
+ else
34
+ required(:availability_zones, @result.availability_zones)
35
+ end
36
+
37
+ @result
38
+ end
39
+
40
+ def test(&block)
41
+ call_once(:instances)
42
+ @result.test = block
43
+ end
44
+
45
+ def instances(*values)
46
+ call_once(:instances)
47
+
48
+ values.each do |instance_id_or_name|
49
+ instance_id = instance_id_or_name
50
+ not_include(instance_id_or_name, @result.instances)
51
+ @result.instances << instance_id
52
+ end
53
+ end
54
+
55
+ def listeners(&block)
56
+ call_once(:listeners)
57
+ @result.listeners = Listeners.new(@name, &block).result
58
+ end
59
+
60
+ def health_check(&block)
61
+ call_once(:health_check)
62
+ @result.health_check = HealthCheck.new(@name, &block).result
63
+ end
64
+
65
+ def subnets(*values)
66
+ call_once(:subnets)
67
+ raise "#{@error_identifier}: Subnet cannot be specified in EC2-Classic" unless @vpc
68
+ @result.subnets = values
69
+ end
70
+
71
+ def security_groups(*values)
72
+ call_once(:security_groups)
73
+ raise "#{@error_identifier}: SecurityGroup cannot be specified in EC2-Classic" unless @vpc
74
+ @result.security_groups = values
75
+ end
76
+
77
+ def availability_zones(*values)
78
+ call_once(:availability_zone)
79
+ raise "#{@error_identifier}: SecurityGroup cannot be specified in EC2-VPC" if @vpc
80
+ @result.availability_zones = values
81
+ end
82
+ end # LoadBalancer
83
+ end # EC2
84
+ end # DSL
85
+ end # Kelbim
data/lib/kelbim/dsl.rb ADDED
@@ -0,0 +1,44 @@
1
+ require 'ostruct'
2
+ require 'kelbim/dsl/converter'
3
+ require 'kelbim/dsl/ec2'
4
+
5
+ module Kelbim
6
+ class DSL
7
+ class << self
8
+ def define(source, path)
9
+ self.new(path) do
10
+ eval(source, binding)
11
+ end
12
+ end
13
+
14
+ def convert(exported, instance_names)
15
+ Converter.convert(exported, instance_names)
16
+ end
17
+ end # of class methods
18
+
19
+ attr_reader :result
20
+
21
+ def initialize(path, &block)
22
+ @path = path
23
+ @result = OpenStruct.new(:ec2s => {})
24
+ instance_eval(&block)
25
+ end
26
+
27
+ private
28
+ def require(file)
29
+ balancerfile = File.expand_path(File.join(File.dirname(@path), file))
30
+
31
+ if File.exist?(balancerfile)
32
+ instance_eval(File.read(balancerfile))
33
+ elsif File.exist?(balancerfile + '.rb')
34
+ instance_eval(File.read(balancerfile + '.rb'))
35
+ else
36
+ Kernel.require(file)
37
+ end
38
+ end
39
+
40
+ def ec2(vpc = nil, &block)
41
+ @result.ec2s[vpc] = EC2.new(vpc, &block).result
42
+ end
43
+ end # DSL
44
+ end # Kelbim
@@ -0,0 +1,66 @@
1
+ require 'kelbim/ext/elb-load-balancer-ext'
2
+ require 'kelbim/ext/elb-listener-ext'
3
+
4
+ module Kelbim
5
+ class Exporter
6
+ class << self
7
+ def export(elb)
8
+ self.new(elb).export
9
+ end
10
+ end # of class methods
11
+
12
+ def initialize(elb)
13
+ @elb = elb
14
+ end
15
+
16
+ def export
17
+ result = {}
18
+
19
+ @elb.load_balancers.each do |lb|
20
+ result[lb.vpc_id] ||= {}
21
+ result[lb.vpc_id][lb.name] = export_load_balancer(lb)
22
+ end
23
+
24
+ return result
25
+ end
26
+
27
+ private
28
+ def export_load_balancer(load_balancer)
29
+ attrs = {
30
+ :instances => load_balancer.instances.map {|i| i.id },
31
+ :listeners => load_balancer.listeners.map {|i| export_listener(i) },
32
+ :health_check => load_balancer.health_check,
33
+ :scheme => load_balancer.scheme,
34
+ :dns_name => load_balancer.dns_name,
35
+ }
36
+
37
+ if load_balancer.vpc_id
38
+ attrs[:subnets] = load_balancer.subnets.map {|i| i.id }
39
+ attrs[:security_groups] = load_balancer.security_groups.map {|i| i.name }
40
+ else
41
+ attrs[:availability_zones] = load_balancer.availability_zones.map {|i| i.name }
42
+ end
43
+
44
+ return attrs
45
+ end
46
+
47
+ def export_listener(listener)
48
+ {
49
+ :protocol => listener.protocol,
50
+ :port => listener.port,
51
+ :instance_protocol => listener.instance_protocol,
52
+ :instance_port => listener.instance_port,
53
+ :server_certificate => listener.server_certificate,
54
+ :policies => listener.policies.map {|i| export_policy(i) },
55
+ }
56
+ end
57
+
58
+ def export_policy(policy)
59
+ {
60
+ :name => policy.name,
61
+ :type => policy.type,
62
+ :attributes => policy.attributes
63
+ }
64
+ end
65
+ end # Exporter
66
+ end # Kelbim
@@ -0,0 +1,27 @@
1
+ require 'aws-sdk'
2
+
3
+ module AWS
4
+ class EC2
5
+ def instance_names
6
+ vpc_instance_id_names = {}
7
+
8
+ self.instances.each do |i|
9
+ vpc_instance_id_names[i.vpc_id] ||= {}
10
+ vpc_instance_id_names[i.vpc_id][i.id] = i.tags['Name']
11
+ end
12
+
13
+ return vpc_instance_id_names
14
+ end
15
+
16
+ def security_group_names
17
+ vpc_sg_id_names = {}
18
+
19
+ self.security_groups.each do |i|
20
+ vpc_sg_id_names[i.vpc_id] ||= {}
21
+ vpc_sg_id_names[i.vpc_id][i.id] = i.name
22
+ end
23
+
24
+ return vpc_sg_id_names
25
+ end
26
+ end # EC2
27
+ end # AWS
@@ -0,0 +1,21 @@
1
+ require 'aws-sdk'
2
+
3
+ module AWS
4
+ class ELB
5
+ class Listener
6
+ def policy_names
7
+ _description[:policy_names]
8
+ end
9
+
10
+ def policies
11
+ if AWS.memoizing? and @policy_list
12
+ return @policy_list
13
+ end
14
+
15
+ @policy_list = policy_names.map do |name|
16
+ load_balancer.policies.find {|i| i.name == name }
17
+ end
18
+ end
19
+ end # Listener
20
+ end # ELB
21
+ end # AWS
@@ -0,0 +1,15 @@
1
+ require 'aws-sdk'
2
+
3
+ module AWS
4
+ class ELB
5
+ class LoadBalancer
6
+ attribute :vpc_id, :static => true
7
+
8
+ populates_from(:describe_load_balancers) do |resp|
9
+ resp.data[:load_balancer_descriptions].find do |lb|
10
+ lb[:load_balancer_name] == name
11
+ end
12
+ end
13
+ end # LoadBalancer
14
+ end # ELB
15
+ end # AWS
@@ -0,0 +1,27 @@
1
+ require 'term/ansicolor'
2
+
3
+ class String
4
+ @@colorize = false
5
+
6
+ class << self
7
+ def colorize=(value)
8
+ @@colorize = value
9
+ end
10
+
11
+ def colorize
12
+ @@colorize
13
+ end
14
+ end # of class methods
15
+
16
+ Term::ANSIColor::Attribute.named_attributes.map do |attr|
17
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
18
+ def #{attr.name}
19
+ if @@colorize
20
+ Term::ANSIColor.send(#{attr.name.inspect}, self)
21
+ else
22
+ self
23
+ end
24
+ end
25
+ EOS
26
+ end
27
+ end # String
@@ -0,0 +1,33 @@
1
+ require 'logger'
2
+ require 'singleton'
3
+ require 'kelbim/ext/string-ext'
4
+
5
+ module Kelbim
6
+ class Logger < ::Logger
7
+ include Singleton
8
+
9
+ def initialize
10
+ super($stdout)
11
+
12
+ self.formatter = proc do |severity, datetime, progname, msg|
13
+ "#{msg}\n"
14
+ end
15
+
16
+ self.level = Logger::INFO
17
+ end
18
+
19
+ def set_debug(value)
20
+ self.level = value ? Logger::DEBUG : Logger::INFO
21
+ end
22
+
23
+ module ClientHelper
24
+ def log(level, message, color, log_id = nil)
25
+ message = "[#{level.to_s.upcase}] #{message}" unless level == :info
26
+ message << ": #{log_id}" if log_id
27
+ message << ' (dry-run)' if @options && @options.dry_run
28
+ logger = (@options && @options.logger) || Kelbim::Logger.instance
29
+ logger.send(level, message.send(color))
30
+ end
31
+ end # ClientHelper
32
+ end # Logger
33
+ end # Kelbim
@@ -0,0 +1,100 @@
1
+ module Kelbim
2
+ module PolicyTypes
3
+ POLICIES = {
4
+ :ssl_negotiation => 'SSLNegotiationPolicyType',
5
+ :app_cookie_stickiness => 'AppCookieStickinessPolicyType',
6
+ :lb_cookie_stickiness => 'LBCookieStickinessPolicyType',
7
+ #:proxy_protocol => 'ProxyProtocolPolicyType',
8
+ #:backend_server_authentication => 'BackendServerAuthenticationPolicyType',
9
+ #:public_key => 'PublicKeyPolicyType',
10
+ }
11
+
12
+ EXPANDERS = {
13
+ :ssl_negotiation => proc {|attrs|
14
+ attrs.select {|name, value|
15
+ value[0] =~ /\Atrue\Z/i
16
+ }.map {|n, v| n }
17
+ },
18
+ :app_cookie_stickiness => proc {|attrs| h = {}; attrs.map {|k, v| h[k] = [v].flatten[0] }; h },
19
+ :lb_cookie_stickiness => proc {|attrs| h = {}; attrs.map {|k, v| h[k] = [v].flatten[0] }; h },
20
+ }
21
+
22
+ UNEXPANDERS = {
23
+ :ssl_negotiation => proc {|attrs|
24
+ unexpanded = {}
25
+
26
+ attrs.each do |name|
27
+ unexpanded[name] = ['true']
28
+ end
29
+
30
+ unexpanded
31
+ },
32
+ :app_cookie_stickiness => proc {|attrs| h = {}; attrs.map {|k, v| h[k] = [v].flatten }; h },
33
+ :lb_cookie_stickiness => proc {|attrs| h = {}; attrs.map {|k, v| h[k] = [v].flatten }; h },
34
+ }
35
+
36
+ class << self
37
+ def symbol_to_string(sym)
38
+ str = POLICIES[sym]
39
+ raise "PolicyTypes `#{sym}` is not supported" unless str
40
+ return str
41
+ end
42
+
43
+ def string_to_symbol(str)
44
+ sym = POLICIES.key(str)
45
+ raise "PolicyTypes `#{str}` is not supported" unless sym
46
+ return sym
47
+ end
48
+
49
+ def convert_to_dsl(policy)
50
+ policy_name = policy[:name]
51
+ policy_type = policy[:type]
52
+ policy_attrs = policy[:attributes]
53
+ sym = string_to_symbol(policy_type)
54
+
55
+ if (expander = EXPANDERS[sym])
56
+ policy_attrs = expander.call(policy_attrs)
57
+
58
+ if policy_attrs.kind_of?(Hash)
59
+ new_policy_attrs = {}
60
+
61
+ policy_attrs.each do |name, value|
62
+ value = value[0] if value.length < 2
63
+ new_policy_attrs[name] = value
64
+ end
65
+
66
+ args = new_policy_attrs.inspect.gsub(/\A\s*\{/, '').gsub(/\}\s*\Z/, '')
67
+ else
68
+ args = policy_attrs.inspect
69
+ end
70
+ else
71
+ args = policy_name.inspect
72
+ end
73
+
74
+ "#{sym} #{args}"
75
+ end
76
+
77
+ def name?(name_or_attrs)
78
+ name_or_attrs.kind_of?(String)
79
+ end
80
+
81
+ def expand(sym_or_str, policy_attrs)
82
+ if sym_or_str.kind_of?(String)
83
+ sym_or_str = string_to_symbol(sym_or_str)
84
+ end
85
+
86
+ expander = EXPANDERS[sym_or_str]
87
+ expander ? expander.call(policy_attrs) : policy_attrs
88
+ end
89
+
90
+ def unexpand(sym_or_str, expanded_attrs)
91
+ if sym_or_str.kind_of?(String)
92
+ sym_or_str = string_to_symbol(sym_or_str)
93
+ end
94
+
95
+ unexpander = UNEXPANDERS[sym_or_str]
96
+ unexpander ? unexpander.call(expanded_attrs) : expanded_attrs
97
+ end
98
+ end # of class methods
99
+ end # PolicyTypes
100
+ end # Kelbim
@@ -0,0 +1,3 @@
1
+ module Kelbim
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,21 @@
1
+ require 'kelbim/wrapper/load-balancer-collection'
2
+ require 'kelbim/ext/ec2-ext'
3
+
4
+ module Kelbim
5
+ class ELBWrapper
6
+ def initialize(elb, options)
7
+ @elb = elb
8
+ @options = options.dup
9
+ @options.instance_names = @options.ec2.instance_names
10
+ @options.security_group_names = @options.ec2.security_group_names
11
+ end
12
+
13
+ def load_balancers
14
+ LoadBalancerCollection.new(@elb.load_balancers, @options)
15
+ end
16
+
17
+ def updated?
18
+ !!@options.updated
19
+ end
20
+ end # EC2Wrapper
21
+ end # Kelbim