ironfan 3.1.0.rc1

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.
Files changed (59) hide show
  1. data/.gitignore +51 -0
  2. data/.rspec +3 -0
  3. data/CHANGELOG.md +130 -0
  4. data/Gemfile +26 -0
  5. data/LICENSE.md +201 -0
  6. data/README.md +328 -0
  7. data/Rakefile +104 -0
  8. data/TODO.md +16 -0
  9. data/VERSION +1 -0
  10. data/chefignore +41 -0
  11. data/cluster_chef-knife.gemspec +123 -0
  12. data/cluster_chef.gemspec +111 -0
  13. data/config/client.rb +59 -0
  14. data/config/proxy.pac +12 -0
  15. data/config/ubuntu10.04-ironfan.erb +157 -0
  16. data/config/ubuntu11.10-ironfan.erb +145 -0
  17. data/ironfan.gemspec +121 -0
  18. data/lib/chef/knife/bootstrap/ubuntu10.04-ironfan.erb +157 -0
  19. data/lib/chef/knife/bootstrap/ubuntu11.10-ironfan.erb +145 -0
  20. data/lib/chef/knife/cluster_bootstrap.rb +74 -0
  21. data/lib/chef/knife/cluster_kick.rb +94 -0
  22. data/lib/chef/knife/cluster_kill.rb +73 -0
  23. data/lib/chef/knife/cluster_launch.rb +164 -0
  24. data/lib/chef/knife/cluster_list.rb +50 -0
  25. data/lib/chef/knife/cluster_proxy.rb +126 -0
  26. data/lib/chef/knife/cluster_show.rb +61 -0
  27. data/lib/chef/knife/cluster_ssh.rb +141 -0
  28. data/lib/chef/knife/cluster_start.rb +40 -0
  29. data/lib/chef/knife/cluster_stop.rb +43 -0
  30. data/lib/chef/knife/cluster_sync.rb +77 -0
  31. data/lib/chef/knife/generic_command.rb +66 -0
  32. data/lib/chef/knife/knife_common.rb +195 -0
  33. data/lib/ironfan.rb +143 -0
  34. data/lib/ironfan/chef_layer.rb +299 -0
  35. data/lib/ironfan/cloud.rb +412 -0
  36. data/lib/ironfan/cluster.rb +118 -0
  37. data/lib/ironfan/compute.rb +153 -0
  38. data/lib/ironfan/deprecated.rb +33 -0
  39. data/lib/ironfan/discovery.rb +177 -0
  40. data/lib/ironfan/dsl_object.rb +124 -0
  41. data/lib/ironfan/facet.rb +144 -0
  42. data/lib/ironfan/fog_layer.rb +150 -0
  43. data/lib/ironfan/private_key.rb +130 -0
  44. data/lib/ironfan/role_implications.rb +58 -0
  45. data/lib/ironfan/security_group.rb +119 -0
  46. data/lib/ironfan/server.rb +281 -0
  47. data/lib/ironfan/server_slice.rb +260 -0
  48. data/lib/ironfan/volume.rb +157 -0
  49. data/spec/ironfan/cluster_spec.rb +13 -0
  50. data/spec/ironfan/facet_spec.rb +69 -0
  51. data/spec/ironfan/server_slice_spec.rb +19 -0
  52. data/spec/ironfan/server_spec.rb +112 -0
  53. data/spec/ironfan_spec.rb +193 -0
  54. data/spec/spec_helper.rb +50 -0
  55. data/spec/spec_helper/dummy_chef.rb +25 -0
  56. data/spec/test_config.rb +20 -0
  57. data/tasks/chef_config.rake +38 -0
  58. data/tasks/jeweler_use_alt_branch.rake +53 -0
  59. metadata +217 -0
@@ -0,0 +1,145 @@
1
+ bash <<EOF || echo "Chef bootstrap failed!"
2
+
3
+ # This is the ubuntu oneiric bootstrap script from infochimps' ironfan. It is
4
+ # based on the opscode bootstrap script, with the important differences being it:
5
+ #
6
+ # * installs ruby 1.9.2 (not 1.8.7) using the system ruby
7
+ # * upgrades rubygems rather than installing from source
8
+ # * pushes the node identity into the first-boot.json
9
+ # * installs the chef-client service and kicks off the first run of chef
10
+
11
+ set -e
12
+
13
+ <%= (@config[:verbosity].to_i > 1 ? 'set -v' : '') %>
14
+
15
+ RUBY_VERSION=1.9.1
16
+ CHEF_VERSION=<%= bootstrap_version_string.gsub(/.*[\s=]/,"") %>
17
+
18
+ mkdir -p /tmp/knife-bootstrap
19
+ chmod 700 /tmp/knife-bootstrap
20
+ cd /tmp/knife-bootstrap
21
+
22
+ <%= "export http_proxy=\"#{knife_config[:bootstrap_proxy]}\"" if knife_config[:bootstrap_proxy] -%>
23
+ eval `cat /etc/lsb-release `
24
+ export DEBIAN_FRONTEND=noninteractive
25
+
26
+ date > /etc/box_build_time
27
+
28
+ # source for sun java if you want to install it later
29
+ apt-get install -y python-software-properties
30
+ add-apt-repository -y ppa:ferramroberto/java
31
+
32
+ echo -e "`date` \n\n**** \n**** apt update:\n****\n"
33
+ apt-get -y update
34
+ apt-get -y upgrade
35
+
36
+ echo -e "`date` \n\n**** \n**** Installing base packages:\n****\n"
37
+ apt-get -y install build-essential make wget curl runit zlib1g-dev libssl-dev openssl libcurl4-openssl-dev libxml2-dev libxslt-dev libyaml-dev libreadline6 libreadline6-dev
38
+ apt-get clean
39
+
40
+ if [ ! -f /usr/bin/chef-client ]; then
41
+ echo -e "`date` \n\n**** \n**** Installing ruby version ${RUBY_VERSION}:\n****\n"
42
+
43
+ apt-get install -y ruby1.9.1 ruby1.9.1-dev
44
+
45
+ if ruby -e "exit(%x{gem --version} < \"1.6.2\" ? 0 : -1 )" ; then
46
+ echo -e "`date` \n\n**** \n**** Updating rubygems:\n****\n"
47
+ # screw you Debian
48
+ REALLY_GEM_UPDATE_SYSTEM=1 gem update --system
49
+ # screw you rubygems
50
+ for foo in /usr/lib/ruby/site_ruby/*/rubygems/deprecate.rb ; do
51
+ # Don't have to be any such deprecations, in which case $foo won't exist
52
+ [ -f "$foo" ] && sudo sed -i.bak 's!@skip ||= false!true!' "$foo"
53
+ done
54
+ fi
55
+
56
+ echo -e "`date` \n\n**** \n**** Installing chef:\n****\n"
57
+ gem install ohai --no-rdoc --no-ri
58
+ gem install chef --no-rdoc --no-ri <%= bootstrap_version_string %>
59
+ # gems needed for the client.rb or so generically useful you want them at hand
60
+ gem install --no-rdoc --no-ri extlib bundler json right_aws pry
61
+
62
+ else # no chef-client
63
+ echo -e "`date` \n\n**** \n**** Chef is present -- skipping apt/ruby/chef installation\n****\n"
64
+ fi # end ruby+chef install
65
+
66
+ # fix a bug in chef that prevents debugging template errors
67
+ # will not work with --prerelease but that's OK hopefully opscode patches this crap soon
68
+ bad_template_file="/usr/lib/ruby/gems/${RUBY_VERSION}/gems/chef-${CHEF_VERSION}/lib/chef/mixin/template.rb"
69
+ if echo "0505c482b8b0b333ac71bbc8a1795d19 $bad_template_file" | md5sum -c - 2>/dev/null ; then
70
+ curl https://github.com/mrflip/chef/commit/655a1967253a8759afb54f30b818bbcb7c309198.patch | sudo patch $bad_template_file
71
+ fi
72
+
73
+ echo -e "`date` \n\n**** \n**** Knifing in the chef client config files:\n****\n"
74
+ mkdir -p /etc/chef
75
+
76
+ <%- if @config[:client_key] %>
77
+ (
78
+ cat <<'EOP'
79
+ <%= @config[:client_key] %>
80
+ EOP
81
+ ) > /tmp/knife-bootstrap/client.pem
82
+ awk NF /tmp/knife-bootstrap/client.pem > /etc/chef/client.pem
83
+ <%- else %>
84
+ (
85
+ cat <<'EOP'
86
+ <%= validation_key %>
87
+ EOP
88
+ ) > /tmp/knife-bootstrap/validation.pem
89
+ awk NF /tmp/knife-bootstrap/validation.pem > /etc/chef/validation.pem
90
+ <%- end %>
91
+
92
+ echo -e "`date` \n\n**** \n**** Nuking our temp files:\n****\n"
93
+
94
+ cd /tmp
95
+ rm -rf /tmp/knife-bootstrap
96
+
97
+ echo -e "`date` \n\n**** \n**** Creating chef client script:\n****\n"
98
+
99
+ (
100
+ cat <<'EOP'
101
+ <%= config_content %>
102
+ <%= @config[:node].chef_client_script_content %>
103
+ EOP
104
+ ) > /etc/chef/client.rb
105
+
106
+ (
107
+ cat <<'EOP'
108
+ <%= { "run_list" => @run_list, "cluster_name" => @config[:node].cluster_name, "facet_name" => @config[:node].facet_name, "facet_index" => @config[:node].facet_index }.to_json %>
109
+ EOP
110
+ ) > /etc/chef/first-boot.json
111
+
112
+ echo -e "`date` \n\n**** \n**** Adding chef client runit scripts:\n****\n"
113
+ ( service chef-client stop >/dev/null 2>&1 ; sleep 1 ; killall chef-client 2>/dev/null ) || true
114
+ mkdir -p /var/log/chef /var/chef /etc/service /etc/sv/chef-client/{log/main,supervise}
115
+ cat > /etc/sv/chef-client/log/run <<EOP
116
+ #!/bin/bash
117
+ exec svlogd -tt ./main
118
+ EOP
119
+ cat > /etc/sv/chef-client/run <<EOP
120
+ #!/bin/bash
121
+ exec 2>&1
122
+ exec /usr/bin/env chef-client -i 43200 -s 20 -L /var/log/chef/client.log
123
+ EOP
124
+ chmod +x /etc/sv/chef-client/log/run /etc/sv/chef-client/run
125
+ ln -nfs /usr/bin/sv /etc/init.d/chef-client
126
+
127
+ service chef-client stop >/dev/null 2>&1 || true
128
+
129
+ <%- if (@config[:bootstrap_runs_chef_client].to_s == 'true') || (@chef_config.knife[:bootstrap_runs_chef_client].to_s == 'true') %>
130
+ echo -e "`date` \n\n**** \n**** First run of chef:\n****\n"
131
+ set -e
132
+ <%= start_chef %>
133
+ set +e
134
+ <%- end %>
135
+
136
+ echo -e "`date` \n\n**** \n**** Cleanup:\n****\n"
137
+ # make locate work good
138
+ updatedb
139
+
140
+ echo -e "`date` \n\n**** \n**** Enabling chef client service:\n****\n"
141
+ ln -nfs /etc/sv/chef-client /etc/service/chef-client
142
+ service chef-client start
143
+
144
+ echo -e "`date` \n\n**** \n**** Cluster Chef client bootstrap complete\n****\n"
145
+ EOF
@@ -0,0 +1,74 @@
1
+ #
2
+ # Author:: Philip (flip) Kromer (<flip@infochimps.com>)
3
+ # Copyright:: Copyright (c) 2011 Infochimps, Inc
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require File.expand_path(File.dirname(__FILE__)+"/generic_command.rb")
20
+ require 'chef/knife/bootstrap'
21
+
22
+ class Chef
23
+ class Knife
24
+ class ClusterBootstrap < Ironfan::Script
25
+
26
+ option :ssh_user,
27
+ :long => "--ssh-user USERNAME",
28
+ :short => "-x USERNAME",
29
+ :description => "The ssh username"
30
+ option :bootstrap_runs_chef_client,
31
+ :long => "--[no-]bootstrap-runs-chef-client",
32
+ :description => "If bootstrap is invoked, the bootstrap script causes an initial run of chef-client (default true).",
33
+ :boolean => true,
34
+ :default => true
35
+ option :distro,
36
+ :long => "--distro DISTRO",
37
+ :short => "-d DISTRO",
38
+ :description => "Bootstrap a distro using a template"
39
+ option :template_file,
40
+ :long => "--template-file TEMPLATE",
41
+ :description => "Full path to location of template to use"
42
+ option :use_sudo,
43
+ :long => "--sudo",
44
+ :description => "Execute the bootstrap via sudo",
45
+ :boolean => true
46
+ option :host_key_verify,
47
+ :long => "--[no-]host-key-verify",
48
+ :description => "Verify host key, enabled by default.",
49
+ :boolean => true,
50
+ :default => true
51
+
52
+ import_banner_and_options(Chef::Knife::Bootstrap,
53
+ :except => [:chef_node_name, :run_list, :ssh_user, :distro, :template_file, :no_host_key_verify, :host_key_verify])
54
+ import_banner_and_options(Ironfan::Script)
55
+
56
+ deps do
57
+ Chef::Knife::Bootstrap.load_deps
58
+ Ironfan::Script.load_deps
59
+ end
60
+
61
+ def perform_execution(target)
62
+ target.each do |svr|
63
+ run_bootstrap(svr, svr.fog_server.dns_name)
64
+ end
65
+ end
66
+
67
+ def confirm_execution(target)
68
+ ui.info "Bootstrapping the node redoes its initial setup -- only do this on an aborted launch."
69
+ confirm_or_exit("Are you absolutely certain that you want to perform this action? (Type 'Yes' to confirm) ", 'Yes')
70
+ end
71
+
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,94 @@
1
+ #
2
+ # Author:: Ash Berlin (ash_github@firemirror.om) and Philip (flip) Kromer (flip@infochimps.com)
3
+ # Copyright:: Copyright (c) 2011 DigiResults Ltd. and Infochimps, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require File.expand_path(File.dirname(__FILE__)+"/knife_common.rb")
20
+ require File.expand_path(File.dirname(__FILE__)+"/cluster_ssh.rb")
21
+
22
+ class Chef
23
+ class Knife
24
+ #
25
+ # Based on https://gist.github.com/1325982 by Ash Berlin
26
+ #
27
+ # "Since chef v0.10 you can send USR1 to the chef-client process and it
28
+ # will wake up and do a run. But the usual case when I want to do a run
29
+ # is cos I'm either testing a cookbook change or I want to deploy now. I
30
+ # could just run sudo chef-client but then that will only log to std
31
+ # out. Just run this script, it will send chef-client a USR1 signal and
32
+ # then tail the log file (but nicely so that you'll get your terminal
33
+ # back when the run completes)."
34
+ #
35
+ class ClusterKick < Chef::Knife::ClusterSsh
36
+
37
+ import_banner_and_options(Chef::Knife::ClusterSsh)
38
+ banner 'knife cluster kick "CLUSTER [FACET [INDEXES]]" (options) - start a run of chef-client on each server, tailing the logs and exiting when the run completes.'
39
+
40
+ option :pid_file,
41
+ :long => "--pid_file",
42
+ :description => "Where to find the pid file. Typically /var/run/chef/client.pid (init.d) or /etc/sv/chef-client/supervise/pid (runit)",
43
+ :default => "/etc/sv/chef-client/supervise/pid"
44
+
45
+ unless defined?(KICKSTART_SCRIPT)
46
+ KICKSTART_SCRIPT = <<EOF
47
+ #!/bin/bash
48
+ set -e
49
+ <%= ((config[:verbosity].to_i > 1) ? "set -v" : "") %>
50
+
51
+ if sudo service chef-client status ; then
52
+
53
+ # running
54
+ pid_file="<%= config[:pid_file] %>"
55
+ log_file=/var/log/chef/client.log
56
+
57
+ declare tail_pid
58
+
59
+ on_exit() {
60
+ rm -f $pipe
61
+ [ -n "$tail_pid" ] && kill $tail_pid
62
+ }
63
+
64
+ trap "on_exit" EXIT ERR
65
+
66
+ pipe=/tmp/pipe-$$
67
+ mkfifo $pipe
68
+
69
+ tail -fn0 "$log_file" > $pipe &
70
+
71
+ tail_pid=$!
72
+
73
+ sudo true
74
+ pid="$(sudo cat $pid_file)"
75
+ sudo kill -USR1 "$pid"
76
+ sed -r "/(ERROR: Sleeping for [0-9]+ seconds before trying again|INFO: Report handlers complete)\$/{q}" $pipe
77
+
78
+ else
79
+ echo -e "****\n\nchef-client daemon not running, invoking chef-client directly\n\n****\n"
80
+ sudo chef-client
81
+ fi
82
+ EOF
83
+ end
84
+
85
+ def run
86
+ @name_args = [ @name_args.join(' ') ]
87
+ script = Erubis::Eruby.new(KICKSTART_SCRIPT).result(:config => config)
88
+ @name_args[1] = script
89
+ super
90
+ end
91
+
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,73 @@
1
+ #
2
+ # Author:: Chris Howe (<howech@infochimps.com>)
3
+ # Copyright:: Copyright (c) 2011 Infochimps, Inc
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require File.expand_path(File.dirname(__FILE__)+"/generic_command.rb")
20
+
21
+ class Chef
22
+ class Knife
23
+ class ClusterKill < Ironfan::Script
24
+ import_banner_and_options(Ironfan::Script)
25
+
26
+ option :kill_bogus,
27
+ :long => "--kill-bogus",
28
+ :description => "Kill bogus servers (ones that exist, but are not defined in the clusters file)",
29
+ :boolean => true,
30
+ :default => false
31
+ option :cloud,
32
+ :long => '--[no-]cloud',
33
+ :description => "Kill machines from cloud (default is yes, terminate machines; use --no-cloud to skip)",
34
+ :boolean => true,
35
+ :default => true
36
+ option :chef,
37
+ :long => "--[no-]chef",
38
+ :description => "Delete the chef node and client (default is yes, delete chef objects; use --no-chef to skip)",
39
+ :boolean => true,
40
+ :default => true
41
+
42
+ def relevant?(server)
43
+ server.killable?
44
+ end
45
+
46
+ # Execute every last mf'ing one of em
47
+ def perform_execution(target)
48
+ if config[:cloud]
49
+ section("Killing Cloud Machines")
50
+ target.select(&:in_cloud?).destroy
51
+ end
52
+
53
+ if config[:chef]
54
+ section("Killing Chef")
55
+ target.select(&:in_chef? ).delete_chef
56
+ end
57
+ end
58
+
59
+ def display(target, *args, &block)
60
+ super
61
+ ui.info Formatador.display_line("[red]Bogus servers detected[reset]: [blue]#{target.bogus_servers.map(&:fullname).inspect}[reset]") unless target.bogus_servers.empty?
62
+ end
63
+
64
+ def confirm_execution(target)
65
+ delete_message = [
66
+ (((!config[:chef]) || target.chef_nodes.empty?) ? nil : "#{target.chef_nodes.length} chef nodes"),
67
+ (((!config[:cloud]) || target.fog_servers.empty?) ? nil : "#{target.fog_servers.length} fog servers") ].compact.join(" and ")
68
+ confirm_or_exit("Are you absolutely certain that you want to delete #{delete_message}? (Type 'Yes' to confirm) ", 'Yes')
69
+ end
70
+
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,164 @@
1
+ #
2
+ # Author:: Philip (flip) Kromer (<flip@infochimps.com>)
3
+ # Copyright:: Copyright (c) 2011 Infochimps, Inc
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require File.expand_path(File.dirname(__FILE__)+"/knife_common.rb")
20
+ require File.expand_path(File.dirname(__FILE__)+"/cluster_bootstrap.rb")
21
+
22
+ class Chef
23
+ class Knife
24
+ class ClusterLaunch < Knife
25
+ include Ironfan::KnifeCommon
26
+
27
+ deps do
28
+ require 'time'
29
+ require 'socket'
30
+ Chef::Knife::ClusterBootstrap.load_deps
31
+ end
32
+
33
+ banner "knife cluster launch CLUSTER_NAME [FACET_NAME [INDEXES]] (options)"
34
+ [ :ssh_port, :ssh_password, :identity_file, :use_sudo,
35
+ :prerelease, :bootstrap_version, :template_file, :distro,
36
+ :bootstrap_runs_chef_client, :host_key_verify
37
+ ].each do |name|
38
+ option name, Chef::Knife::ClusterBootstrap.options[name]
39
+ end
40
+
41
+ option :dry_run,
42
+ :long => "--dry-run",
43
+ :description => "Don't really run, just use mock calls",
44
+ :boolean => true,
45
+ :default => false
46
+ option :force,
47
+ :long => "--force",
48
+ :description => "Perform launch operations even if it may not be safe to do so. Default false",
49
+ :boolean => true,
50
+ :default => false
51
+
52
+ option :bootstrap,
53
+ :long => "--[no-]bootstrap",
54
+ :description => "Also bootstrap the launched node (default is NOT to bootstrap)",
55
+ :boolean => true,
56
+ :default => false
57
+
58
+ def run
59
+ load_ironfan
60
+ die(banner) if @name_args.empty?
61
+ configure_dry_run
62
+
63
+ #
64
+ # Load the facet
65
+ #
66
+ full_target = get_slice(*@name_args)
67
+ display(full_target)
68
+ target = full_target.select(&:launchable?)
69
+
70
+ warn_or_die_on_bogus_servers(full_target) unless full_target.bogus_servers.empty?
71
+
72
+ die("", "#{ui.color("All servers are running -- not launching any.",:blue)}", "", 1) if target.empty?
73
+
74
+ # Pre-populate information in chef
75
+ section("Sync'ing to chef and cloud")
76
+ target.sync_to_cloud
77
+ target.sync_to_chef
78
+
79
+ # Launch servers
80
+ section("Launching machines", :green)
81
+ target.create_servers
82
+
83
+ ui.info("")
84
+ display(target)
85
+
86
+ # As each server finishes, configure it
87
+ watcher_threads = target.parallelize do |svr|
88
+ perform_after_launch_tasks(svr)
89
+ end
90
+
91
+ progressbar_for_threads(watcher_threads)
92
+
93
+ display(target)
94
+ end
95
+
96
+ def display(target)
97
+ super(target, ["Name", "InstanceID", "State", "Flavor", "Image", "AZ", "Public IP", "Private IP", "Created At", 'Volumes', 'Elastic IP']) do |svr|
98
+ { 'launchable?' => (svr.launchable? ? "[blue]#{svr.launchable?}[reset]" : '-' ), }
99
+ end
100
+ end
101
+
102
+ def perform_after_launch_tasks(server)
103
+ # Wait for node creation on amazon side
104
+ server.fog_server.wait_for{ ready? }
105
+
106
+ # Try SSH
107
+ unless config[:dry_run]
108
+ nil until tcp_test_ssh(server.fog_server.dns_name){ sleep @initial_sleep_delay ||= 10 }
109
+ end
110
+
111
+ # Make sure our list of volumes is accurate
112
+ Ironfan.fetch_fog_volumes
113
+ server.discover_volumes!
114
+
115
+ # Attach volumes, etc
116
+ server.sync_to_cloud
117
+
118
+ # Run Bootstrap
119
+ if config[:bootstrap]
120
+ run_bootstrap(server, server.fog_server.dns_name)
121
+ end
122
+ end
123
+
124
+ def tcp_test_ssh(hostname)
125
+ tcp_socket = TCPSocket.new(hostname, 22)
126
+ readable = IO.select([tcp_socket], nil, nil, 5)
127
+ if readable
128
+ Chef::Log.debug("sshd accepting connections on #{hostname}, banner is #{tcp_socket.gets}")
129
+ yield
130
+ true
131
+ else
132
+ false
133
+ end
134
+ rescue Errno::ETIMEDOUT
135
+ false
136
+ rescue Errno::ECONNREFUSED
137
+ sleep 2
138
+ false
139
+ ensure
140
+ tcp_socket && tcp_socket.close
141
+ end
142
+
143
+ def warn_or_die_on_bogus_servers(target)
144
+ ui.info("")
145
+ ui.info "Cluster has servers in a transitional or undefined state (shown as 'bogus'):"
146
+ ui.info("")
147
+ display(target)
148
+ ui.info("")
149
+ unless config[:force]
150
+ die(
151
+ "Launch operations may be unpredictable under these circumstances.",
152
+ "You should wait for the cluster to stabilize, fix the undefined server problems",
153
+ "(run \"knife cluster show CLUSTER\" to see what the problems are), or launch",
154
+ "the cluster anyway using the --force option.", "", -2)
155
+ end
156
+ ui.info("")
157
+ ui.info "--force specified"
158
+ ui.info "Proceeding to launch anyway. This may produce undesired results."
159
+ ui.info("")
160
+ end
161
+
162
+ end
163
+ end
164
+ end