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.
- data/.gitignore +51 -0
- data/.rspec +3 -0
- data/CHANGELOG.md +63 -0
- data/Gemfile +18 -0
- data/LICENSE +201 -0
- data/README.md +332 -0
- data/Rakefile +92 -0
- data/TODO.md +8 -0
- data/VERSION +1 -0
- data/chefignore +41 -0
- data/cluster_chef-knife.gemspec +111 -0
- data/clusters/website_demo.rb +65 -0
- data/config/client.rb +59 -0
- data/lib/chef/knife/bootstrap/ubuntu10.04-basic.erb +78 -0
- data/lib/chef/knife/bootstrap/ubuntu10.04-cluster_chef.erb +139 -0
- data/lib/chef/knife/bootstrap/ubuntu11.10-cluster_chef.erb +128 -0
- data/lib/chef/knife/cluster_bootstrap.rb +69 -0
- data/lib/chef/knife/cluster_kick.rb +86 -0
- data/lib/chef/knife/cluster_kill.rb +73 -0
- data/lib/chef/knife/cluster_launch.rb +168 -0
- data/lib/chef/knife/cluster_list.rb +50 -0
- data/lib/chef/knife/cluster_proxy.rb +118 -0
- data/lib/chef/knife/cluster_show.rb +56 -0
- data/lib/chef/knife/cluster_ssh.rb +94 -0
- data/lib/chef/knife/cluster_start.rb +32 -0
- data/lib/chef/knife/cluster_stop.rb +37 -0
- data/lib/chef/knife/cluster_sync.rb +76 -0
- data/lib/chef/knife/generic_command.rb +66 -0
- data/lib/chef/knife/knife_common.rb +199 -0
- data/notes/aws_console_screenshot.jpg +0 -0
- data/rspec.watchr +29 -0
- data/spec/cluster_chef/cluster_spec.rb +13 -0
- data/spec/cluster_chef/facet_spec.rb +70 -0
- data/spec/cluster_chef/server_slice_spec.rb +19 -0
- data/spec/cluster_chef/server_spec.rb +112 -0
- data/spec/cluster_chef_spec.rb +193 -0
- data/spec/spec_helper/dummy_chef.rb +25 -0
- data/spec/spec_helper.rb +50 -0
- data/spec/test_config.rb +20 -0
- data/tasks/chef_config.rb +38 -0
- data/tasks/jeweler_use_alt_branch.rb +47 -0
- 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
|