cluster_chef-knife 3.0.5

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 (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