cluster_chef-knife 3.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/.gitignore +51 -0
  2. data/.rspec +3 -0
  3. data/CHANGELOG.md +63 -0
  4. data/Gemfile +18 -0
  5. data/LICENSE +201 -0
  6. data/README.md +332 -0
  7. data/Rakefile +92 -0
  8. data/TODO.md +8 -0
  9. data/VERSION +1 -0
  10. data/chefignore +41 -0
  11. data/cluster_chef-knife.gemspec +111 -0
  12. data/clusters/website_demo.rb +65 -0
  13. data/config/client.rb +59 -0
  14. data/lib/chef/knife/bootstrap/ubuntu10.04-basic.erb +78 -0
  15. data/lib/chef/knife/bootstrap/ubuntu10.04-cluster_chef.erb +139 -0
  16. data/lib/chef/knife/bootstrap/ubuntu11.10-cluster_chef.erb +128 -0
  17. data/lib/chef/knife/cluster_bootstrap.rb +69 -0
  18. data/lib/chef/knife/cluster_kick.rb +86 -0
  19. data/lib/chef/knife/cluster_kill.rb +73 -0
  20. data/lib/chef/knife/cluster_launch.rb +168 -0
  21. data/lib/chef/knife/cluster_list.rb +50 -0
  22. data/lib/chef/knife/cluster_proxy.rb +118 -0
  23. data/lib/chef/knife/cluster_show.rb +56 -0
  24. data/lib/chef/knife/cluster_ssh.rb +94 -0
  25. data/lib/chef/knife/cluster_start.rb +32 -0
  26. data/lib/chef/knife/cluster_stop.rb +37 -0
  27. data/lib/chef/knife/cluster_sync.rb +76 -0
  28. data/lib/chef/knife/generic_command.rb +66 -0
  29. data/lib/chef/knife/knife_common.rb +199 -0
  30. data/notes/aws_console_screenshot.jpg +0 -0
  31. data/rspec.watchr +29 -0
  32. data/spec/cluster_chef/cluster_spec.rb +13 -0
  33. data/spec/cluster_chef/facet_spec.rb +70 -0
  34. data/spec/cluster_chef/server_slice_spec.rb +19 -0
  35. data/spec/cluster_chef/server_spec.rb +112 -0
  36. data/spec/cluster_chef_spec.rb +193 -0
  37. data/spec/spec_helper/dummy_chef.rb +25 -0
  38. data/spec/spec_helper.rb +50 -0
  39. data/spec/test_config.rb +20 -0
  40. data/tasks/chef_config.rb +38 -0
  41. data/tasks/jeweler_use_alt_branch.rb +47 -0
  42. metadata +223 -0
@@ -0,0 +1,128 @@
1
+ bash -c '
2
+
3
+ # This is the ubuntu-10.04-cluster_chef script from infochimps, which
4
+ # is based on the ubuntu-10.04-gems script from opscode, but it
5
+ # * installs ruby 1.9.2, not 1.8.7 using the system ruby
6
+ # * upgrades rubygems rather than installing from source
7
+ # * pushes the node identity into the first-boot.json
8
+ # * installs the chef-client service and kicks off the first run of chef
9
+
10
+ set -e
11
+
12
+ <%= (@config[:verbosity].to_i > 1 ? 'set -v' : '') %>
13
+
14
+ mkdir -p /tmp/knife-bootstrap
15
+ chmod 700 /tmp/knife-bootstrap
16
+ cd /tmp/knife-bootstrap
17
+
18
+ <%= "export http_proxy=\"#{knife_config[:bootstrap_proxy]}\"" if knife_config[:bootstrap_proxy] -%>
19
+ eval `cat /etc/lsb-release `
20
+ export DEBIAN_FRONTEND=noninteractive
21
+
22
+ # source for sun java if you want to install it later
23
+ apt-get install -y python-software-properties
24
+ add-apt-repository ppa:ferramroberto/java
25
+ apt-get -y update
26
+
27
+ if [ ! -f /usr/bin/chef-client ]; then
28
+ echo -e "`date` \n\n**** \n**** apt update:\n****\n"
29
+ apt-get update
30
+ apt-get -y upgrade
31
+
32
+ echo -e "`date` \n\n**** \n**** Installing base packages:\n****\n"
33
+ apt-get install -y build-essential wget ruby1.9.1 ruby1.9.1-dev runit zlib1g-dev libssl-dev openssl libcurl4-openssl-dev libreadline6-dev libyaml-dev
34
+
35
+ if ruby -e "exit(%x{gem --version} < \"1.6.2\" ? 0 : -1 )" ; then
36
+ echo -e "`date` \n\n**** \n**** Updating rubygems:\n****\n"
37
+ gem update --system
38
+ # screw you rubygems
39
+ for foo in /usr/lib/ruby/site_ruby/*/rubygems/deprecate.rb ; do sudo sed -i.bak 's!@skip ||= false!true!' "$foo" ; done
40
+ fi
41
+
42
+ echo -e "`date` \n\n**** \n**** Installing chef:\n****\n"
43
+ gem install ohai --no-rdoc --no-ri
44
+ gem install chef --no-rdoc --no-ri <%= bootstrap_version_string %>
45
+ gem install --no-rdoc --no-ri bundler pry cheat
46
+
47
+ else # no chef-client
48
+ echo -e "`date` \n\n**** \n**** Chef is present -- skipping apt/ruby/chef installation\n****\n"
49
+ fi
50
+
51
+ # fix a bug in chef that prevents debugging template errors
52
+ bad_template_file='/usr/lib/ruby/gems/1.9.1/gems/chef-0.10.4/lib/chef/mixin/template.rb'
53
+ if echo "0505c482b8b0b333ac71bbc8a1795d19 $bad_template_file" | md5sum -c - 2>/dev/null ; then
54
+ curl https://github.com/mrflip/chef/commit/655a1967253a8759afb54f30b818bbcb7c309198.patch | sudo patch $bad_template_file
55
+ fi
56
+
57
+ echo -e "`date` \n\n**** \n**** Knifing in the chef client config files:\n****\n"
58
+ mkdir -p /etc/chef
59
+
60
+ <%- if @config[:client_key] %>
61
+ (
62
+ cat <<'EOP'
63
+ <%= @config[:client_key] %>
64
+ EOP
65
+ ) > /tmp/knife-bootstrap/client.pem
66
+ awk NF /tmp/knife-bootstrap/client.pem > /etc/chef/client.pem
67
+ <%- else %>
68
+ (
69
+ cat <<'EOP'
70
+ <%= validation_key %>
71
+ EOP
72
+ ) > /tmp/knife-bootstrap/validation.pem
73
+ awk NF /tmp/knife-bootstrap/validation.pem > /etc/chef/validation.pem
74
+ <%- end %>
75
+
76
+ echo -e "`date` \n\n**** \n**** Nuking our temp files:\n****\n"
77
+
78
+ cd /tmp
79
+ # rm -rf /tmp/knife-bootstrap
80
+
81
+ echo -e "`date` \n\n**** \n**** Creating chef client script:\n****\n"
82
+
83
+ (
84
+ cat <<'EOP'
85
+ <%= config_content %>
86
+ <%= @config[:node].chef_client_script_content %>
87
+ EOP
88
+ ) > /etc/chef/client.rb
89
+
90
+ (
91
+ cat <<'EOP'
92
+ <%= { "run_list" => @run_list, "cluster_name" => @config[:node].cluster_name, "facet_name" => @config[:node].facet_name, "facet_index" => @config[:node].facet_index }.to_json %>
93
+ EOP
94
+ ) > /etc/chef/first-boot.json
95
+
96
+ echo -e "`date` \n\n**** \n**** Adding chef client runit scripts:\n****\n"
97
+ (service chef-client stop >/dev/null 2>&1 ; sleep 1 ; killall chef-client 2>/dev/null) || true
98
+ mkdir -p /var/log/chef /var/chef /etc/service /etc/sv/chef-client/{log/main,supervise}
99
+ cat > /etc/sv/chef-client/log/run <<EOF
100
+ #!/bin/bash
101
+ exec svlogd -tt ./main
102
+ EOF
103
+ cat > /etc/sv/chef-client/run <<EOF
104
+ #!/bin/bash
105
+ exec 2>&1
106
+ exec /usr/bin/env chef-client -i 43200 -s 20 -L /var/log/chef/client.log
107
+ EOF
108
+ chmod +x /etc/sv/chef-client/log/run /etc/sv/chef-client/run
109
+ ln -nfs /usr/bin/sv /etc/init.d/chef-client
110
+
111
+ service chef-client stop || true
112
+
113
+ <%- if (@config[:bootstrap_runs_chef_client].to_s == 'true') || (@chef_config.knife[:bootstrap_runs_chef_client].to_s == 'true') %>
114
+ echo -e "`date` \n\n**** \n**** First run of chef:\n****\n"
115
+ set -e
116
+ <%= start_chef %>
117
+ set +e
118
+ <%- end %>
119
+
120
+ echo -e "`date` \n\n**** \n**** Cleanup:\n****\n"
121
+ updatedb
122
+
123
+ echo -e "`date` \n\n**** \n**** Enabling chef client service:\n****\n"
124
+ ln -nfs /etc/sv/chef-client /etc/service/chef-client
125
+ service chef-client start
126
+
127
+ echo -e "`date` \n\n**** \n**** Cluster Chef client bootstrap complete\n****\n"
128
+ ' || echo "Chef bootstrap failed!"
@@ -0,0 +1,69 @@
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 < ClusterChef::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
+
47
+ import_banner_and_options(Chef::Knife::Bootstrap,
48
+ :except => [:chef_node_name, :run_list, :ssh_user, :distro, :template_file])
49
+ import_banner_and_options(ClusterChef::Script)
50
+
51
+ deps do
52
+ Chef::Knife::Bootstrap.load_deps
53
+ ClusterChef::Script.load_deps
54
+ end
55
+
56
+ def perform_execution(target)
57
+ target.each do |svr|
58
+ run_bootstrap(svr, svr.fog_server.dns_name)
59
+ end
60
+ end
61
+
62
+ def confirm_execution(target)
63
+ ui.info "Bootstrapping the node redoes its initial setup -- only do this on an aborted launch."
64
+ confirm_or_exit("Are you absolutely certain that you want to perform this action? (Type 'Yes' to confirm) ", 'Yes')
65
+ end
66
+
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,86 @@
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
+ pid_file="<%= config[:pid_file] %>"
52
+ log_file=/var/log/chef/client.log
53
+
54
+ declare tail_pid
55
+
56
+ on_exit() {
57
+ rm -f $pipe
58
+ [ -n "$tail_pid" ] && kill $tail_pid
59
+ }
60
+
61
+ trap "on_exit" EXIT ERR
62
+
63
+ pipe=/tmp/pipe-$$
64
+ mkfifo $pipe
65
+
66
+ tail -fn0 "$log_file" > $pipe &
67
+
68
+ tail_pid=$!
69
+
70
+ sudo true
71
+ pid="$(sudo cat $pid_file)"
72
+ sudo kill -USR1 "$pid"
73
+ sed -r "/(ERROR: Sleeping for [0-9]+ seconds before trying again|INFO: Report handlers complete)\$/{q}" $pipe
74
+ EOF
75
+ end
76
+
77
+ def run
78
+ @name_args = [ @name_args.join(' ') ]
79
+ script = Erubis::Eruby.new(KICKSTART_SCRIPT).result(:config => config)
80
+ @name_args[1] = script
81
+ super
82
+ end
83
+
84
+ end
85
+ end
86
+ 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 < ClusterChef::Script
24
+ import_banner_and_options(ClusterChef::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 => "Delete machines from cloud (default is to delete, 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 to delete, 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,168 @@
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
+
21
+ class Chef
22
+ class Knife
23
+ class ClusterLaunch < Knife
24
+ include ClusterChef::KnifeCommon
25
+
26
+ deps do
27
+ require 'time'
28
+ require 'socket'
29
+ ClusterChef::KnifeCommon.load_deps
30
+ Chef::Knife::Bootstrap.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, :no_host_key_verify,
35
+ :prerelease, :bootstrap_version, :template_file,
36
+ ].each do |name|
37
+ option name, Chef::Knife::Bootstrap.options[name]
38
+ end
39
+
40
+ option :dry_run,
41
+ :long => "--dry-run",
42
+ :description => "Don't really run, just use mock calls",
43
+ :boolean => true,
44
+ :default => false
45
+ option :force,
46
+ :long => "--force",
47
+ :description => "Perform launch operations even if it may not be safe to do so. Default false",
48
+ :boolean => true,
49
+ :default => false
50
+
51
+ option :bootstrap,
52
+ :long => "--[no-]bootstrap",
53
+ :description => "Also bootstrap the launched node (default is NOT to bootstrap)",
54
+ :boolean => true,
55
+ :default => false
56
+ option :bootstrap_runs_chef_client,
57
+ :long => "--[no-]bootstrap-runs-chef-client",
58
+ :description => "If bootstrap is invoked, the bootstrap script causes an initial run of chef-client (default true).",
59
+ :boolean => true,
60
+ :default => true
61
+
62
+ def run
63
+ load_cluster_chef
64
+ die(banner) if @name_args.empty?
65
+ configure_dry_run
66
+
67
+ #
68
+ # Load the facet
69
+ #
70
+ full_target = get_slice(*@name_args)
71
+ display(full_target)
72
+ target = full_target.select(&:launchable?)
73
+
74
+ warn_or_die_on_bogus_servers(full_target) unless full_target.bogus_servers.empty?
75
+
76
+ die("", "#{ui.color("All servers are running -- not launching any.",:blue)}", "", 1) if target.empty?
77
+
78
+ # Pre-populate information in chef
79
+ section("Sync'ing to chef and cloud")
80
+ target.sync_to_cloud
81
+ target.sync_to_chef
82
+
83
+ # Make security groups
84
+ section("Making security groups")
85
+ full_target.security_groups.each{|name,group| group.run }
86
+
87
+ # Launch servers
88
+ section("Launching machines", :green)
89
+ target.create_servers
90
+
91
+ ui.info("")
92
+ display(target)
93
+
94
+ # As each server finishes, configure it
95
+ watcher_threads = target.parallelize do |svr|
96
+ perform_after_launch_tasks(svr)
97
+ end
98
+
99
+ progressbar_for_threads(watcher_threads)
100
+
101
+ display(target)
102
+ end
103
+
104
+ def display(target)
105
+ super(target, ["Name", "InstanceID", "State", "Flavor", "Image", "AZ", "Public IP", "Private IP", "Created At", 'Volumes', 'Elastic IP']) do |svr|
106
+ { 'launchable?' => (svr.launchable? ? "[blue]#{svr.launchable?}[reset]" : '-' ), }
107
+ end
108
+ end
109
+
110
+ def perform_after_launch_tasks(server)
111
+ # Wait for node creation on amazon side
112
+ server.fog_server.wait_for{ ready? }
113
+
114
+ # Attach volumes, etc
115
+ server.sync_to_cloud
116
+
117
+ # Try SSH
118
+ unless config[:dry_run]
119
+ nil until tcp_test_ssh(server.fog_server.dns_name){ sleep @initial_sleep_delay ||= 10 }
120
+ end
121
+
122
+ # Run Bootstrap
123
+ if config[:bootstrap]
124
+ run_bootstrap(server, server.fog_server.dns_name)
125
+ end
126
+ end
127
+
128
+ def tcp_test_ssh(hostname)
129
+ tcp_socket = TCPSocket.new(hostname, 22)
130
+ readable = IO.select([tcp_socket], nil, nil, 5)
131
+ if readable
132
+ Chef::Log.debug("sshd accepting connections on #{hostname}, banner is #{tcp_socket.gets}")
133
+ yield
134
+ true
135
+ else
136
+ false
137
+ end
138
+ rescue Errno::ETIMEDOUT
139
+ false
140
+ rescue Errno::ECONNREFUSED
141
+ sleep 2
142
+ false
143
+ ensure
144
+ tcp_socket && tcp_socket.close
145
+ end
146
+
147
+ def warn_or_die_on_bogus_servers(target)
148
+ ui.info("")
149
+ ui.info "Cluster has servers in a transitional or undefined state (shown as 'bogus'):"
150
+ ui.info("")
151
+ display(target)
152
+ ui.info("")
153
+ unless config[:force]
154
+ die(
155
+ "Launch operations may be unpredictable under these circumstances.",
156
+ "You should wait for the cluster to stabilize, fix the undefined server problems",
157
+ "(run \"knife cluster show CLUSTER\" to see what the problems are), or launch",
158
+ "the cluster anyway using the --force option.", "", -2)
159
+ end
160
+ ui.info("")
161
+ ui.info "--force specified"
162
+ ui.info "Proceeding to launch anyway. This may produce undesired results."
163
+ ui.info("")
164
+ end
165
+
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,50 @@
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
+
21
+ class Chef
22
+ class Knife
23
+ class ClusterList < Knife
24
+ include ClusterChef::KnifeCommon
25
+
26
+ deps do
27
+ ClusterChef::KnifeCommon.load_deps
28
+ end
29
+
30
+ banner "knife cluster list (options)"
31
+
32
+ def run
33
+ load_cluster_chef
34
+ configure_dry_run
35
+
36
+ hash = ClusterChef.cluster_filenames
37
+
38
+ table = []
39
+ hash.keys.sort.each do |key|
40
+ table.push( { :cluster => key, :path => hash[key] } )
41
+ end
42
+
43
+ ui.info "Cluster Path: #{ ClusterChef.cluster_path.join ", " }"
44
+
45
+ Formatador.display_compact_table(table, [:cluster,:path])
46
+
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,118 @@
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_ssh.rb")
21
+ require File.expand_path(File.dirname(__FILE__)+"/generic_command.rb")
22
+
23
+ class Chef
24
+ class Knife
25
+ #
26
+ # Runs the ssh command to open a SOCKS proxy to the given host, and writes a
27
+ # PAC (automatic proxy config) file to
28
+ # /tmp/cluster_chef_proxy-YOURNAME.pac. Only the first host is used, even if
29
+ # multiple match.
30
+ #
31
+ # Why not use Net::Ssh directly? The SOCKS proxy support was pretty
32
+ # bad. Though ugly, exec'ing the command works.
33
+ #
34
+ class ClusterProxy < ClusterChef::Script
35
+
36
+ import_banner_and_options(Chef::Knife::ClusterSsh, :except => [:concurrency, ])
37
+ banner 'knife cluster proxy "CLUSTER [FACET [INDEXES]]" (options) - Runs the ssh command to open a SOCKS proxy to the given host, and writes a PAC (automatic proxy config) file to /tmp/cluster_chef_proxy-YOURNAME.pac. Only the first host is used, even if multiple match.'
38
+
39
+ option :background,
40
+ :long => "--[no-]background",
41
+ :description => "Requests ssh to go to background after setting up the proxy",
42
+ :boolean => true,
43
+ :default => true
44
+
45
+ option :socks_port,
46
+ :long => '--socks-port',
47
+ :short => '-D',
48
+ :description => 'Port to listen on for SOCKS5 proxy',
49
+ :default => '6666'
50
+
51
+ def relevant?(server)
52
+ server.sshable?
53
+ end
54
+
55
+ def perform_execution(target)
56
+ svr = target.first
57
+ cmd = command_for_target(svr)
58
+
59
+ dump_proxy_pac
60
+ exec(*cmd)
61
+ end
62
+
63
+ def command_for_target(svr)
64
+ config[:attribute] ||= Chef::Config[:knife][:ssh_address_attribute] || "fqdn"
65
+ config[:ssh_user] ||= Chef::Config[:knife][:ssh_user]
66
+ config[:identity_file] ||= svr.cloud.ssh_identity_file
67
+
68
+ if (svr.cloud.public_ip) then address = svr.cloud.public_ip ; end
69
+ if (not address) && (svr.chef_node) then address = format_for_display( svr.chef_node )[config[:attribute]] ; end
70
+ if (not address) && (svr.fog_server) then address = svr.fog_server.public_ip_address ; end
71
+
72
+ cmd = [ 'ssh', '-N' ]
73
+ cmd += [ '-D', config[:socks_port].to_s ]
74
+ cmd += [ '-i', config[:identity_file] ] if config[:identity_file].present?
75
+ cmd += [ '-p', config[:port].to_s ] if config[:port].present?
76
+ cmd << '-f' if config[:background]
77
+ cmd << "-#{'v' * config[:verbosity]}" if (config[:verbosity] > 0)
78
+ cmd += %w[ -o StrictHostKeyChecking=no ] if config[:no_host_key_verify]
79
+ cmd += %w[ -o ConnectTimeout=10 -o ServerAliveInterval=60 -o ControlPath=none ]
80
+ cmd << (config[:ssh_user] ? "#{config[:ssh_user]}@#{address}" : address)
81
+
82
+ Chef::Log.debug("Cluster proxy config: #{config.inspect}")
83
+ Chef::Log.debug("Cluster proxy command: #{cmd.inspect}")
84
+ ui.info(["SOCKS Proxy on",
85
+ "local port", ui.color(config[:socks_port], :cyan),
86
+ "for", ui.color(svr.name, :cyan),
87
+ "(#{address})"
88
+ ].join(" "))
89
+ cmd
90
+ end
91
+
92
+ #
93
+ # Write a .pac (automatic proxy configuration) file
94
+ # to /etc/cluster_chef_proxy-YOURNAME.pac
95
+ #
96
+ def dump_proxy_pac
97
+ pac_filename = File.expand_path(File.join('/tmp', "cluster_chef_proxy-#{ENV['USER']}.pac"))
98
+ ui.info("point your browser at PAC (automatic proxy config file) #{pac_filename}")
99
+ File.open(pac_filename, 'w') do |f|
100
+ f.print %Q{function FindProxyForURL(url, host) {
101
+ if ((shExpMatch(host, "*ec2*.amazonaws.com" )) ||
102
+ (shExpMatch(host, "*ec2.internal*" )) ||
103
+ (shExpMatch(host, "*compute-*.amazonaws.com" )) ||
104
+ (shExpMatch(host, "*compute-*.internal*" )) ||
105
+ (shExpMatch(host, "*domu*.internal*" )) ||
106
+ (shExpMatch(host, "10.*" ))
107
+ ) {
108
+ return "SOCKS5 localhost:#{config[:socks_port]}";
109
+ }
110
+ return "DIRECT";
111
+ }
112
+ }
113
+ end
114
+ end
115
+
116
+ end
117
+ end
118
+ end