ironfan 4.3.4 → 4.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +7 -0
- data/ELB.md +121 -0
- data/Gemfile +1 -0
- data/Rakefile +4 -0
- data/VERSION +1 -1
- data/ironfan.gemspec +48 -3
- data/lib/chef/knife/cluster_launch.rb +5 -0
- data/lib/chef/knife/cluster_proxy.rb +3 -3
- data/lib/chef/knife/cluster_sync.rb +4 -0
- data/lib/chef/knife/ironfan_knife_common.rb +17 -6
- data/lib/chef/knife/ironfan_script.rb +29 -11
- data/lib/ironfan.rb +2 -2
- data/lib/ironfan/broker/computer.rb +8 -3
- data/lib/ironfan/dsl/ec2.rb +133 -2
- data/lib/ironfan/headers.rb +4 -0
- data/lib/ironfan/provider.rb +48 -3
- data/lib/ironfan/provider/ec2.rb +23 -8
- data/lib/ironfan/provider/ec2/elastic_load_balancer.rb +239 -0
- data/lib/ironfan/provider/ec2/iam_server_certificate.rb +101 -0
- data/lib/ironfan/provider/ec2/machine.rb +8 -0
- data/lib/ironfan/provider/ec2/security_group.rb +3 -5
- data/lib/ironfan/requirements.rb +2 -0
- data/notes/Home.md +45 -0
- data/notes/INSTALL-cloud_setup.md +103 -0
- data/notes/INSTALL.md +134 -0
- data/notes/Ironfan-Roadmap.md +70 -0
- data/notes/advanced-superpowers.md +16 -0
- data/notes/aws_servers.jpg +0 -0
- data/notes/aws_user_key.png +0 -0
- data/notes/cookbook-versioning.md +11 -0
- data/notes/core_concepts.md +200 -0
- data/notes/declaring_volumes.md +3 -0
- data/notes/design_notes-aspect_oriented_devops.md +36 -0
- data/notes/design_notes-ci_testing.md +169 -0
- data/notes/design_notes-cookbook_event_ordering.md +249 -0
- data/notes/design_notes-meta_discovery.md +59 -0
- data/notes/ec2-pricing_and_capacity.md +69 -0
- data/notes/ec2-pricing_and_capacity.numbers +0 -0
- data/notes/homebase-layout.txt +102 -0
- data/notes/knife-cluster-commands.md +18 -0
- data/notes/named-cloud-objects.md +11 -0
- data/notes/opscode_org_key.png +0 -0
- data/notes/opscode_user_key.png +0 -0
- data/notes/philosophy.md +13 -0
- data/notes/rake_tasks.md +24 -0
- data/notes/renamed-recipes.txt +142 -0
- data/notes/silverware.md +85 -0
- data/notes/style_guide.md +300 -0
- data/notes/tips_and_troubleshooting.md +92 -0
- data/notes/version-3_2.md +273 -0
- data/notes/walkthrough-hadoop.md +168 -0
- data/notes/walkthrough-web.md +166 -0
- data/spec/fixtures/ec2/elb/snakeoil.crt +35 -0
- data/spec/fixtures/ec2/elb/snakeoil.key +51 -0
- data/spec/integration/minimal-chef-repo/chefignore +41 -0
- data/spec/integration/minimal-chef-repo/environments/_default.json +12 -0
- data/spec/integration/minimal-chef-repo/knife/credentials/knife-org.rb +19 -0
- data/spec/integration/minimal-chef-repo/knife/credentials/knife-user-ironfantester.rb +9 -0
- data/spec/integration/minimal-chef-repo/knife/knife.rb +66 -0
- data/spec/integration/minimal-chef-repo/roles/systemwide.rb +10 -0
- data/spec/integration/spec/elb_build_spec.rb +95 -0
- data/spec/integration/spec_helper.rb +16 -0
- data/spec/integration/spec_helper/launch_cluster.rb +55 -0
- data/spec/ironfan/ec2/elb_spec.rb +95 -0
- data/spec/ironfan/ec2/security_group_spec.rb +0 -6
- metadata +60 -3
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
# v4.4.0: @nickmarden adds ELB support, broader spec coverage
|
2
|
+
* Security groups: removing ensured field (never set, causing bug), making selection use VPC if applicable
|
3
|
+
* Spec coverage for full cluster launch process
|
4
|
+
* IAMServerCertificate and ElasticLoadBalancer support for EC2
|
5
|
+
* Support for cluster-wide resource aggregation
|
6
|
+
* Fixes a bug that occurs when you fat-finger a flavor name
|
7
|
+
|
1
8
|
# v4.3.4:
|
2
9
|
* whoops. actually want attributes, not compact_attributes (#191)
|
3
10
|
|
data/ELB.md
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
# Managing Elastic Load Balancers with Ironfan
|
2
|
+
|
3
|
+
## Example
|
4
|
+
|
5
|
+
Ironfan.cluster "sparky" do
|
6
|
+
|
7
|
+
cloud(:ec2) do
|
8
|
+
# This certificate can be defined at a cluster or facet level.
|
9
|
+
# However, the last call wins if the same attribute is defined
|
10
|
+
# in more than one context.
|
11
|
+
iam_server_certificate "snake-oil" do
|
12
|
+
certificate IO.read('snakeoil.crt')
|
13
|
+
private_key IO.read('snakeoil.key')
|
14
|
+
certificate_chain IO.read('snakeoil.crt.bundle') # optional
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
facet :web do
|
19
|
+
instances 2
|
20
|
+
cloud(:ec2) do
|
21
|
+
|
22
|
+
elastic_load_balancer "sparky-elb" do
|
23
|
+
map_port('HTTP', 80, 'HTTP', 81)
|
24
|
+
|
25
|
+
# This SSL listener uses the certificate defined above
|
26
|
+
map_port('HTTPS', 443, 'HTTP', 81, 'snake-oil')
|
27
|
+
|
28
|
+
# Applies to all HTTPS/SSL listeners
|
29
|
+
disallowed_ciphers(%w[ RC4-SHA ])
|
30
|
+
|
31
|
+
# Health check that is made against ALL running instances
|
32
|
+
health_check do
|
33
|
+
ping_protocol 'HTTP'
|
34
|
+
ping_port 82
|
35
|
+
ping_path '/healthcheck'
|
36
|
+
timeout 4
|
37
|
+
interval 10
|
38
|
+
unhealthy_threshold 3
|
39
|
+
healthy_threshold 2
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
## Uploading your certificate
|
48
|
+
|
49
|
+
There are two ways to supply your certificate to Ironfan. The first is to make the certificate, private key, and (optionally) certificate chain data readable by Ruby code in your cluster file.
|
50
|
+
|
51
|
+
iam_server_certificate "snake-oil" do
|
52
|
+
certificate IO.read('snakeoil.crt')
|
53
|
+
private_key IO.read('snakeoil.key')
|
54
|
+
certificate_chain IO.read('snakeoil.crt.bundle') # optional
|
55
|
+
end
|
56
|
+
|
57
|
+
Having your server certificates persistently available in your ironfan-homebase might not be optimal, so you can simply specify the ARN of the existing IAM server certificate:
|
58
|
+
|
59
|
+
iam_server_certificate "snake-oil" do
|
60
|
+
arn 'arn:aws:iam::782698214375:server-certificate/ironfan-sparky-snake-oil'
|
61
|
+
end
|
62
|
+
|
63
|
+
## When are Certificates and ELBs updated?
|
64
|
+
|
65
|
+
Your server certificates and ELBs are only relevant when there are server instances present to service them. Therefore, the following logic is applied to decide when to synchronize or update your certificate/ELB configuration:
|
66
|
+
|
67
|
+
### bootstrap, kill, launch, start, stop, sync
|
68
|
+
|
69
|
+
When one of these `knife cluster` actions finishes, the Ironfan code will examine the up-to-date list of running servers to see if there are any ELBs that are now needed, or which are no longer needed. In support of these feature, any required certificate uploads, health check modifications, SSL policy updates, or listener modifications will be performed as well.
|
70
|
+
|
71
|
+
If an ELB is no longer needed, it will be destroyed **but any corresponding certificates will not be destroyed**. This is a convenience for system administrators who want to load their sensitive/precious certificates into AWS just once, and is intended to be used in conjunction with the `iam_server_certificate.arn` attribute.
|
72
|
+
|
73
|
+
(To get a list of existing ARNs, try the [IAM Command Line Toolkit](http://aws.amazon.com/developertools/AWS-Identity-and-Access-Management/4143) provided by AWS.)
|
74
|
+
|
75
|
+
### kick, list, proxy, pry, show, ssh
|
76
|
+
|
77
|
+
These `knife cluster` commands are not associated with updates of the Chef or IAAS configurations of your server instances, so no certificate or ELB modifications occur after these commands complete.
|
78
|
+
|
79
|
+
## SSL policy
|
80
|
+
|
81
|
+
The SSL policy control in Ironfan is very rudimentary. You may control which ciphers are explicitly disallowed as follows
|
82
|
+
|
83
|
+
elastic_load_balancer "sparky-elb" do
|
84
|
+
...
|
85
|
+
disallowed_ciphers(%w[ RC4-SHA ])
|
86
|
+
...
|
87
|
+
end
|
88
|
+
|
89
|
+
Note that the default behavior is to disallow ciphers that are hypothetically vulnerable to the [BEAST attack](http://vnhacker.blogspot.com/2011/09/beast.html). You probably don't want or need to change it.
|
90
|
+
|
91
|
+
## How do port mappings work?
|
92
|
+
|
93
|
+
A port mapping is a mapping between a TCP port on the ELB and a TCP port on your instance. A request arriving at _external_port_number_ on your ELB will be negotiated using the _external_protocol_, and will be forwarded to the _internal_port_ on one of your instances using _internal_protocol_.
|
94
|
+
|
95
|
+
If _external_protocol_ is 'HTTPS' and _internal_protocol_ is 'HTTP' (which is referred to as "SSL termination" at the ELB), you'll probably want to know that in your server code. ELBs set the header [X-Forwarded-Proto](http://en.wikipedia.org/wiki/List_of_HTTP_header_fields) to let you know what protocol was used to connect to the ELB. Awareness of that header in your server allows you to aboid redirect loops if, for example, your code insists that clients connect over HTTPS.
|
96
|
+
|
97
|
+
The format of the map_port call is as follows:
|
98
|
+
|
99
|
+
map_port(external_protocol, external_port_number, internal_protocol, internal_port_number [, certificate])
|
100
|
+
|
101
|
+
You'll need a certificate if the _external\_protocol_ is 'HTTPS' or 'SSL'. It will be ignored otherwise.
|
102
|
+
|
103
|
+
Your one-and-only SSL policy (probably the BEAST-defeating default) will be applied to all port mappings with certificates.
|
104
|
+
|
105
|
+
## Other policies
|
106
|
+
|
107
|
+
The Ironfan ELB code does not support other types of listener policies. Please contact me using the information below if you need other types of policy support.
|
108
|
+
|
109
|
+
## VPC support
|
110
|
+
|
111
|
+
There is no explicit VPC support in this code. If you need to use Ironfan-based ELBs in a VPC context and find that this code doesn't give you what you need, please submit an issue or, better yet, a pull request.
|
112
|
+
|
113
|
+
## Spanning facets
|
114
|
+
|
115
|
+
An ELB **can** be declared at the cluster level rather than the facet level, but that's a weird thing to do. But don't let me tell you not to be weird!
|
116
|
+
|
117
|
+
Note that since each ELB has only one health check, it would need to be the case that your servers in each facet could respond to the same health check request. If they can, they should probably be members of the same facet.
|
118
|
+
|
119
|
+
# Contact me
|
120
|
+
|
121
|
+
This feature was initially created by [Nick Marden](https://github.com/nickmarden). I'd love your feedback and suggestions.
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -72,6 +72,10 @@ RSpec::Core::RakeTask.new(:rcov) do |spec|
|
|
72
72
|
spec.rcov_opts = %w[ --exclude .rvm --no-comments --text-summary ]
|
73
73
|
end
|
74
74
|
|
75
|
+
RSpec::Core::RakeTask.new(:integration) do |spec|
|
76
|
+
spec.pattern = 'spec/integration/**/*_spec.rb'
|
77
|
+
end
|
78
|
+
|
75
79
|
# ---------------------------------------------------------------------------
|
76
80
|
#
|
77
81
|
# Yard -- documentation
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
4.
|
1
|
+
4.4.0
|
data/ironfan.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "ironfan"
|
8
|
-
s.version = "4.
|
8
|
+
s.version = "4.4.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Infochimps"]
|
12
|
-
s.date = "2012-10-
|
12
|
+
s.date = "2012-10-22"
|
13
13
|
s.description = "Ironfan allows you to orchestrate not just systems but clusters of machines. It includes a powerful layer on top of knife and a collection of cloud cookbooks."
|
14
14
|
s.email = "coders@infochimps.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -21,6 +21,7 @@ Gem::Specification.new do |s|
|
|
21
21
|
".rspec",
|
22
22
|
".yardopts",
|
23
23
|
"CHANGELOG.md",
|
24
|
+
"ELB.md",
|
24
25
|
"Gemfile",
|
25
26
|
"Guardfile",
|
26
27
|
"LICENSE.md",
|
@@ -77,6 +78,8 @@ Gem::Specification.new do |s|
|
|
77
78
|
"lib/ironfan/provider/ec2.rb",
|
78
79
|
"lib/ironfan/provider/ec2/ebs_volume.rb",
|
79
80
|
"lib/ironfan/provider/ec2/elastic_ip.rb",
|
81
|
+
"lib/ironfan/provider/ec2/elastic_load_balancer.rb",
|
82
|
+
"lib/ironfan/provider/ec2/iam_server_certificate.rb",
|
80
83
|
"lib/ironfan/provider/ec2/keypair.rb",
|
81
84
|
"lib/ironfan/provider/ec2/machine.rb",
|
82
85
|
"lib/ironfan/provider/ec2/placement_group.rb",
|
@@ -84,11 +87,53 @@ Gem::Specification.new do |s|
|
|
84
87
|
"lib/ironfan/provider/virtualbox.rb",
|
85
88
|
"lib/ironfan/provider/virtualbox/machine.rb",
|
86
89
|
"lib/ironfan/requirements.rb",
|
90
|
+
"notes/Home.md",
|
91
|
+
"notes/INSTALL-cloud_setup.md",
|
92
|
+
"notes/INSTALL.md",
|
93
|
+
"notes/Ironfan-Roadmap.md",
|
94
|
+
"notes/advanced-superpowers.md",
|
95
|
+
"notes/aws_servers.jpg",
|
96
|
+
"notes/aws_user_key.png",
|
97
|
+
"notes/cookbook-versioning.md",
|
98
|
+
"notes/core_concepts.md",
|
99
|
+
"notes/declaring_volumes.md",
|
100
|
+
"notes/design_notes-aspect_oriented_devops.md",
|
101
|
+
"notes/design_notes-ci_testing.md",
|
102
|
+
"notes/design_notes-cookbook_event_ordering.md",
|
103
|
+
"notes/design_notes-meta_discovery.md",
|
104
|
+
"notes/ec2-pricing_and_capacity.md",
|
105
|
+
"notes/ec2-pricing_and_capacity.numbers",
|
106
|
+
"notes/homebase-layout.txt",
|
107
|
+
"notes/knife-cluster-commands.md",
|
108
|
+
"notes/named-cloud-objects.md",
|
109
|
+
"notes/opscode_org_key.png",
|
110
|
+
"notes/opscode_user_key.png",
|
111
|
+
"notes/philosophy.md",
|
112
|
+
"notes/rake_tasks.md",
|
113
|
+
"notes/renamed-recipes.txt",
|
114
|
+
"notes/silverware.md",
|
115
|
+
"notes/style_guide.md",
|
116
|
+
"notes/tips_and_troubleshooting.md",
|
117
|
+
"notes/version-3_2.md",
|
118
|
+
"notes/walkthrough-hadoop.md",
|
119
|
+
"notes/walkthrough-web.md",
|
87
120
|
"spec/chef/cluster_bootstrap_spec.rb",
|
121
|
+
"spec/fixtures/ec2/elb/snakeoil.crt",
|
122
|
+
"spec/fixtures/ec2/elb/snakeoil.key",
|
88
123
|
"spec/fixtures/gunbai.rb",
|
89
124
|
"spec/fixtures/gunbai_slice.json",
|
125
|
+
"spec/integration/minimal-chef-repo/chefignore",
|
126
|
+
"spec/integration/minimal-chef-repo/environments/_default.json",
|
127
|
+
"spec/integration/minimal-chef-repo/knife/credentials/knife-org.rb",
|
128
|
+
"spec/integration/minimal-chef-repo/knife/credentials/knife-user-ironfantester.rb",
|
129
|
+
"spec/integration/minimal-chef-repo/knife/knife.rb",
|
130
|
+
"spec/integration/minimal-chef-repo/roles/systemwide.rb",
|
131
|
+
"spec/integration/spec/elb_build_spec.rb",
|
132
|
+
"spec/integration/spec_helper.rb",
|
133
|
+
"spec/integration/spec_helper/launch_cluster.rb",
|
90
134
|
"spec/ironfan/cluster_spec.rb",
|
91
135
|
"spec/ironfan/ec2/cloud_provider_spec.rb",
|
136
|
+
"spec/ironfan/ec2/elb_spec.rb",
|
92
137
|
"spec/ironfan/ec2/security_group_spec.rb",
|
93
138
|
"spec/spec_helper.rb",
|
94
139
|
"spec/spec_helper/dummy_chef.rb",
|
@@ -100,7 +145,7 @@ Gem::Specification.new do |s|
|
|
100
145
|
s.require_paths = ["lib"]
|
101
146
|
s.rubygems_version = "1.8.24"
|
102
147
|
s.summary = "Ironfan allows you to orchestrate not just systems but clusters of machines. It includes a powerful layer on top of knife and a collection of cloud cookbooks."
|
103
|
-
s.test_files = ["spec/spec_helper/dummy_chef.rb", "spec/ironfan/cluster_spec.rb", "spec/ironfan/ec2/cloud_provider_spec.rb", "spec/ironfan/ec2/security_group_spec.rb", "spec/chef/cluster_bootstrap_spec.rb", "spec/fixtures/gunbai_slice.json", "spec/fixtures/gunbai.rb", "spec/spec_helper.rb", "spec/test_config.rb"]
|
148
|
+
s.test_files = ["spec/spec_helper/dummy_chef.rb", "spec/integration/spec_helper/launch_cluster.rb", "spec/integration/minimal-chef-repo/roles/systemwide.rb", "spec/integration/minimal-chef-repo/environments/_default.json", "spec/integration/minimal-chef-repo/chefignore", "spec/integration/minimal-chef-repo/knife/knife.rb", "spec/integration/minimal-chef-repo/knife/credentials/knife-user-ironfantester.rb", "spec/integration/minimal-chef-repo/knife/credentials/knife-org.rb", "spec/integration/spec/elb_build_spec.rb", "spec/integration/spec_helper.rb", "spec/ironfan/cluster_spec.rb", "spec/ironfan/ec2/cloud_provider_spec.rb", "spec/ironfan/ec2/elb_spec.rb", "spec/ironfan/ec2/security_group_spec.rb", "spec/chef/cluster_bootstrap_spec.rb", "spec/fixtures/gunbai_slice.json", "spec/fixtures/ec2/elb/snakeoil.key", "spec/fixtures/ec2/elb/snakeoil.crt", "spec/fixtures/gunbai.rb", "spec/spec_helper.rb", "spec/test_config.rb"]
|
104
149
|
|
105
150
|
if s.respond_to? :specification_version then
|
106
151
|
s.specification_version = 3
|
@@ -31,12 +31,7 @@ module Ironfan
|
|
31
31
|
#
|
32
32
|
# @return [Ironfan::ServerSlice] the requested slice
|
33
33
|
def get_slice(slice_string, *args)
|
34
|
-
|
35
|
-
slice_string = [slice_string, args].flatten.join("-")
|
36
|
-
ui.info("")
|
37
|
-
ui.warn("Please specify server slices joined by dashes and not separate args:\n\n knife cluster #{sub_command} #{slice_string}\n\n")
|
38
|
-
end
|
39
|
-
cluster_name, facet_name, slice_indexes = slice_string.split(/[\s\-]/, 3)
|
34
|
+
cluster_name, facet_name, slice_indexes = pick_apart(slice_string, *args)
|
40
35
|
desc = predicate_str(cluster_name, facet_name, slice_indexes)
|
41
36
|
#
|
42
37
|
ui.info("Inventorying servers in #{desc}")
|
@@ -47,6 +42,22 @@ module Ironfan
|
|
47
42
|
computers.slice(facet_name, slice_indexes)
|
48
43
|
end
|
49
44
|
|
45
|
+
def all_computers(slice_string, *args)
|
46
|
+
cluster_name, facet_name, slice_indexes = pick_apart(slice_string, *args)
|
47
|
+
computers = broker.discover! Ironfan.load_cluster(cluster_name)
|
48
|
+
ui.info("Loaded information for #{computers.size} computer(s) in cluster #{cluster_name}")
|
49
|
+
computers
|
50
|
+
end
|
51
|
+
|
52
|
+
def pick_apart(slice_string, *args)
|
53
|
+
if not args.empty?
|
54
|
+
slice_string = [slice_string, args].flatten.join("-")
|
55
|
+
ui.info("")
|
56
|
+
ui.warn("Please specify server slices joined by dashes and not separate args:\n\n knife cluster #{sub_command} #{slice_string}\n\n")
|
57
|
+
end
|
58
|
+
slice_string.split(/[\s\-]/, 3)
|
59
|
+
end
|
60
|
+
|
50
61
|
def predicate_str(cluster_name, facet_name, slice_indexes)
|
51
62
|
[ "#{ui.color(cluster_name, :bold)} cluster",
|
52
63
|
(facet_name ? "#{ui.color(facet_name, :bold)} facet" : "#{ui.color("all", :bold)} facets"),
|
@@ -44,26 +44,44 @@ module Ironfan
|
|
44
44
|
|
45
45
|
target = get_relevant_slice(* @name_args)
|
46
46
|
|
47
|
-
|
47
|
+
unless target.empty?
|
48
|
+
ui.info(["\n",
|
49
|
+
ui.color("Running #{sub_command}", :cyan),
|
50
|
+
" on #{target.joined_names}..."].join())
|
51
|
+
unless config[:yes]
|
52
|
+
ui.info("")
|
53
|
+
confirm_execution(target)
|
54
|
+
end
|
55
|
+
#
|
56
|
+
perform_execution(target)
|
57
|
+
end
|
58
|
+
|
59
|
+
if healthy? and aggregates? and (aggregates_on_noop? or not target.empty?)
|
60
|
+
ui.info "Applying aggregations:"
|
61
|
+
all_computers(*@name_args).aggregate
|
62
|
+
end
|
48
63
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
unless config[:yes]
|
64
|
+
if target.empty?
|
65
|
+
ui.warn("No computers to #{sub_command}")
|
66
|
+
else
|
53
67
|
ui.info("")
|
54
|
-
|
68
|
+
ui.info "Finished! Current state:"
|
69
|
+
display(target)
|
55
70
|
end
|
56
71
|
#
|
57
|
-
perform_execution(target)
|
58
|
-
ui.info("")
|
59
|
-
ui.info "Finished! Current state:"
|
60
|
-
display(target)
|
61
|
-
#
|
62
72
|
exit_if_unhealthy!
|
63
73
|
end
|
64
74
|
|
65
75
|
def perform_execution(target)
|
66
76
|
target.send(sub_command)
|
67
77
|
end
|
78
|
+
|
79
|
+
def aggregates?
|
80
|
+
true
|
81
|
+
end
|
82
|
+
|
83
|
+
def aggregates_on_noop?
|
84
|
+
false
|
85
|
+
end
|
68
86
|
end
|
69
87
|
end
|
data/lib/ironfan.rb
CHANGED
@@ -148,8 +148,8 @@ module Ironfan
|
|
148
148
|
ui.info(" #{"%-15s" % (name.to_s+":")}\t#{ui.color(desc.to_s, *style)}")
|
149
149
|
end
|
150
150
|
|
151
|
-
def self.substep(name, desc)
|
152
|
-
step(name, " - #{desc}",
|
151
|
+
def self.substep(name, desc, color = :gray)
|
152
|
+
step(name, " - #{desc}", color) if (verbosity >= 1 or color != :gray)
|
153
153
|
end
|
154
154
|
|
155
155
|
def self.verbosity
|
@@ -293,11 +293,16 @@ module Ironfan
|
|
293
293
|
end
|
294
294
|
|
295
295
|
def validate
|
296
|
-
providers = values.map {|c| c.providers.values}.flatten
|
297
296
|
computers = self
|
298
|
-
|
299
297
|
values.each{|c| c.validate }
|
300
|
-
providers.each{|p| p.validate computers }
|
298
|
+
values.map {|c| c.providers.values}.flatten.uniq.each {|p| p.validate computers }
|
299
|
+
end
|
300
|
+
|
301
|
+
def aggregate
|
302
|
+
computers = self
|
303
|
+
provider_keys = values.map {|c| c.chosen_providers({ :providers => :iaas})}.flatten.uniq
|
304
|
+
providers = provider_keys.map { |pk| values.map { |c| c.providers[pk] } }.flatten.uniq
|
305
|
+
providers.each { |p| p.aggregate! computers }
|
301
306
|
end
|
302
307
|
|
303
308
|
#
|
data/lib/ironfan/dsl/ec2.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
|
1
3
|
module Ironfan
|
2
4
|
class Dsl
|
3
5
|
|
@@ -12,7 +14,9 @@ module Ironfan
|
|
12
14
|
magic :bootstrap_distro, String, :default => ->{ image_info[:bootstrap_distro] }
|
13
15
|
magic :chef_client_script, String
|
14
16
|
magic :default_availability_zone, String, :default => ->{ availability_zones.first }
|
17
|
+
collection :elastic_load_balancers, Ironfan::Dsl::Ec2::ElasticLoadBalancer, :key_method => :name
|
15
18
|
magic :flavor, String, :default => 't1.micro'
|
19
|
+
collection :iam_server_certificates, Ironfan::Dsl::Ec2::IamServerCertificate, :key_method => :name
|
16
20
|
magic :image_id, String
|
17
21
|
magic :image_name, String
|
18
22
|
magic :keypair, String
|
@@ -23,9 +27,9 @@ module Ironfan
|
|
23
27
|
magic :provider, Whatever, :default => Ironfan::Provider::Ec2
|
24
28
|
magic :public_ip, String
|
25
29
|
magic :region, String, :default => ->{ default_region }
|
30
|
+
collection :security_groups, Ironfan::Dsl::Ec2::SecurityGroup, :key_method => :name
|
26
31
|
magic :ssh_user, String, :default => ->{ image_info[:ssh_user] }
|
27
32
|
magic :ssh_identity_dir, String, :default => ->{ Chef::Config.ec2_key_dir }
|
28
|
-
collection :security_groups, Ironfan::Dsl::Ec2::SecurityGroup, :key_method => :name
|
29
33
|
magic :subnet, String
|
30
34
|
magic :validation_key, String, :default => ->{ IO.read(Chef::Config.validation_key) rescue '' }
|
31
35
|
magic :vpc, String
|
@@ -63,7 +67,7 @@ module Ironfan
|
|
63
67
|
|
64
68
|
def flavor_info
|
65
69
|
if not Chef::Config[:ec2_flavor_info].has_key?(flavor)
|
66
|
-
ui.warn("Unknown machine image flavor '#{
|
70
|
+
ui.warn("Unknown machine image flavor '#{flavor}'")
|
67
71
|
list_flavors
|
68
72
|
return nil
|
69
73
|
end
|
@@ -136,6 +140,133 @@ module Ironfan
|
|
136
140
|
end
|
137
141
|
end
|
138
142
|
|
143
|
+
class ElasticLoadBalancer
|
144
|
+
|
145
|
+
class HealthCheck < Ironfan::Dsl
|
146
|
+
magic :ping_protocol, String, :default => 'HTTP'
|
147
|
+
magic :ping_port, Integer, :default => 80
|
148
|
+
magic :ping_path, String, :default => '/'
|
149
|
+
magic :timeout, Integer, :default => 5
|
150
|
+
magic :interval, Integer, :default => 30
|
151
|
+
magic :unhealthy_threshold, Integer, :default => 2
|
152
|
+
magic :healthy_threshold, Integer, :default => 10
|
153
|
+
|
154
|
+
def target
|
155
|
+
if %w[ HTTP HTTPS ].include?(self.ping_protocol)
|
156
|
+
"#{self.ping_protocol}:#{self.ping_port}#{self.ping_path}"
|
157
|
+
else
|
158
|
+
"#{self.ping_protocol}:#{self.ping_port}"
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def to_fog
|
163
|
+
health_check = {
|
164
|
+
'HealthyThreshold' => healthy_threshold,
|
165
|
+
'Timeout' => timeout,
|
166
|
+
'UnhealthyThreshold' => unhealthy_threshold,
|
167
|
+
'Interval' => interval,
|
168
|
+
'Target' => target
|
169
|
+
}
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
# SSL ciphers susceptible to the BEAST attack
|
175
|
+
BEAST_VULNERABLE_CIPHERS = %w[
|
176
|
+
Protocol-SSLv2
|
177
|
+
ADH-AES128-SHA
|
178
|
+
ADH-AES256-SHA
|
179
|
+
ADH-CAMELLIA128-SHA
|
180
|
+
ADH-CAMELLIA256-SHA
|
181
|
+
ADH-DES-CBC-SHA
|
182
|
+
ADH-DES-CBC3-SHA
|
183
|
+
ADH-RC4-MD5
|
184
|
+
ADH-SEED-SHA
|
185
|
+
AES128-SHA
|
186
|
+
AES256-SHA
|
187
|
+
DES-CBC-MD5
|
188
|
+
DES-CBC-SHA
|
189
|
+
DES-CBC3-MD5
|
190
|
+
DES-CBC3-SHA
|
191
|
+
DHE-DSS-AES128-SHA
|
192
|
+
DHE-DSS-AES256-SHA
|
193
|
+
DHE-RSA-AES128-SHA
|
194
|
+
DHE-RSA-AES256-SHA
|
195
|
+
EDH-DSS-DES-CBC-SHA
|
196
|
+
EDH-DSS-DES-CBC3-SHA
|
197
|
+
EDH-RSA-DES-CBC-SHA
|
198
|
+
EDH-RSA-DES-CBC3-SHA
|
199
|
+
EXP-ADH-DES-CBC-SHA
|
200
|
+
EXP-ADH-RC4-MD5
|
201
|
+
EXP-DES-CBC-SHA
|
202
|
+
EXP-EDH-DSS-DES-CBC-SHA
|
203
|
+
EXP-EDH-RSA-DES-CBC-SHA
|
204
|
+
EXP-KRB5-DES-CBC-MD5
|
205
|
+
EXP-KRB5-DES-CBC-SHA
|
206
|
+
EXP-KRB5-RC2-CBC-MD5
|
207
|
+
EXP-KRB5-RC2-CBC-SHA
|
208
|
+
EXP-RC2-CBC-MD5
|
209
|
+
IDEA-CBC-SHA
|
210
|
+
KRB5-DES-CBC-MD5
|
211
|
+
KRB5-DES-CBC-SHA
|
212
|
+
KRB5-DES-CBC3-MD5
|
213
|
+
KRB5-DES-CBC3-SHA
|
214
|
+
PSK-3DES-EDE-CBC-SHA
|
215
|
+
PSK-AES128-CBC-SHA
|
216
|
+
PSK-AES256-CBC-SHA
|
217
|
+
RC2-CBC-MD5
|
218
|
+
]
|
219
|
+
|
220
|
+
field :name, String
|
221
|
+
field :port_mappings, Array, :default => []
|
222
|
+
magic :disallowed_ciphers, Array, :default => BEAST_VULNERABLE_CIPHERS
|
223
|
+
member :health_check, HealthCheck
|
224
|
+
|
225
|
+
def map_port(load_balancer_protocol = 'HTTP', load_balancer_port = 80, internal_protocol = 'HTTP', internal_port = 80, iam_server_certificate = nil)
|
226
|
+
port_mappings << [ load_balancer_protocol, load_balancer_port, internal_protocol, internal_port, iam_server_certificate ]
|
227
|
+
port_mappings.compact!
|
228
|
+
port_mappings.uniq!
|
229
|
+
end
|
230
|
+
|
231
|
+
def ssl_policy_to_fog
|
232
|
+
result = Hash[ *disallowed_ciphers.collect { |c| [ c, false ] }.flatten ]
|
233
|
+
return {
|
234
|
+
:name => Digest::MD5.hexdigest("#{disallowed_ciphers.sort.join('')}"),
|
235
|
+
:attributes => result,
|
236
|
+
}
|
237
|
+
end
|
238
|
+
|
239
|
+
def listeners_to_fog(cert_lookup)
|
240
|
+
port_mappings.map do |pm|
|
241
|
+
result = {
|
242
|
+
'Protocol' => pm[0], # load_balancer_protocl
|
243
|
+
'LoadBalancerPort' => pm[1], # load_balancer_port
|
244
|
+
'InstanceProtocol' => pm[2], # internal_protocol
|
245
|
+
'InstancePort' => pm[3], # internal_port
|
246
|
+
}
|
247
|
+
result['SSLCertificateId'] = cert_lookup[pm[4]] if pm[4]
|
248
|
+
result
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
end
|
253
|
+
|
254
|
+
# Although it is unreasonable to talk about an IAM Server Certificate object
|
255
|
+
# without a certificate or private_key field value, we also allow users to
|
256
|
+
# simply specify the arn of an existing IAM Server Certificate so that their
|
257
|
+
# web server certificate is not required to be present in their recipes repo,
|
258
|
+
# for security purposes. In that case the :arn field would be non-nil while
|
259
|
+
# the :certificate and :private_key fields would be nil, which hints to the
|
260
|
+
# EC2 Provider code that it should attempt to validate the existence of the
|
261
|
+
# IAM Server Certificate in the EC2 cloud rather than trying to create it.
|
262
|
+
class IamServerCertificate < Ironfan::Dsl
|
263
|
+
field :name, String
|
264
|
+
magic :arn, String, :default => nil
|
265
|
+
magic :certificate, String, :default => nil # Actually a PEM encoding
|
266
|
+
magic :private_key, String, :default => nil # Actually a PEM encoding
|
267
|
+
magic :certificate_chain, String, :default => nil # Actually a PEM encoding
|
268
|
+
end
|
269
|
+
|
139
270
|
end
|
140
271
|
|
141
272
|
end
|