ssp 0.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/ssp +1 -1
- data/lib/ssp/app.rb +11 -0
- data/lib/ssp/application/node.rb +15 -2
- data/lib/ssp/application/office_node.rb +180 -0
- data/lib/ssp/version.rb +1 -1
- metadata +5 -4
data/bin/ssp
CHANGED
data/lib/ssp/app.rb
CHANGED
@@ -2,7 +2,15 @@ require 'thor'
|
|
2
2
|
require 'thor/group'
|
3
3
|
|
4
4
|
module SSP
|
5
|
+
module ThorExtensions
|
6
|
+
def banner(task, namespace = nil, subcommand = false)
|
7
|
+
"#{File.basename($0)} #{task.formatted_usage(self, $thor_runner, subcommand)}"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
5
11
|
class App < Thor
|
12
|
+
extend ThorExtensions
|
13
|
+
|
6
14
|
namespace :app
|
7
15
|
map "-T" => :list
|
8
16
|
|
@@ -61,6 +69,9 @@ module SSP
|
|
61
69
|
unless @_commands_initialized
|
62
70
|
Dir[File.join(File.dirname(__FILE__), "application", "*.rb")].each do |command|
|
63
71
|
require(command)
|
72
|
+
klass_name = Thor::Util.camel_case(File.basename(command).sub(/\.rb$/, ''))
|
73
|
+
klass = SSP::App.const_get(klass_name)
|
74
|
+
klass.extend(ThorExtensions)
|
64
75
|
end
|
65
76
|
@_commands_initialized = true
|
66
77
|
end
|
data/lib/ssp/application/node.rb
CHANGED
@@ -24,8 +24,8 @@ class SSP::App::Node < Thor
|
|
24
24
|
:desc => "Sets the flavor of the server (1: 256MB, 2: 512MB, 3: 1024MB, ...)",
|
25
25
|
:default => 2
|
26
26
|
method_option :image, :aliases => "-i", :type => :numeric,
|
27
|
-
:desc => "Sets the image to be used (49: Ubuntu 10.04,
|
28
|
-
:default =>
|
27
|
+
:desc => "Sets the image to be used (49: Ubuntu 10.04, 4256704: chef-node)",
|
28
|
+
:default => 4256704
|
29
29
|
def create(fqdn, *roles)
|
30
30
|
server = connection.servers.new
|
31
31
|
|
@@ -110,6 +110,19 @@ validation_client_name "#{chef_config[:validation_client_name]}"
|
|
110
110
|
ssh.run
|
111
111
|
end
|
112
112
|
|
113
|
+
desc "list", "Lists available servers on Rackspace"
|
114
|
+
def list
|
115
|
+
server_list = [ ["ID", "Name", "Public IP", "Private IP", "Flavor ID"].map {|t| shell.set_color(t, :bold)} ]
|
116
|
+
server_list += connection.servers.all.map do |server|
|
117
|
+
[
|
118
|
+
server.id.to_s, server.name,
|
119
|
+
server.addresses["public"][0], server.addresses["private"][0],
|
120
|
+
server.flavor_id.to_s
|
121
|
+
]
|
122
|
+
end
|
123
|
+
print_table(server_list)
|
124
|
+
end
|
125
|
+
|
113
126
|
protected
|
114
127
|
def connection
|
115
128
|
@connection ||= Fog::Rackspace::Servers.new(
|
@@ -0,0 +1,180 @@
|
|
1
|
+
require 'chef/config'
|
2
|
+
require 'chef/knife/ssh'
|
3
|
+
require 'ssp/config'
|
4
|
+
|
5
|
+
class SSP::App::OfficeNode < Thor
|
6
|
+
namespace :officenode
|
7
|
+
|
8
|
+
class_option :ssh_user,
|
9
|
+
:desc => "The ssh username",
|
10
|
+
:default => "root"
|
11
|
+
|
12
|
+
class_option :ssh_password,
|
13
|
+
:desc => "The ssh password",
|
14
|
+
:default => SSP::Config[:vanilla][:root_password]
|
15
|
+
|
16
|
+
class_option :chef_config, :aliases => "-c",
|
17
|
+
:desc => "Location of the chef configuration file",
|
18
|
+
:default => File.join(ENV['HOME'], '.chef', 'knife.rb')
|
19
|
+
|
20
|
+
|
21
|
+
desc "create FQDN [ROLES...]", "Creates a new chef client on Vanilla"
|
22
|
+
method_option :memory, :aliases => "-m", :type => :numeric,
|
23
|
+
:desc => "Sets the memory size for the node in MB",
|
24
|
+
:default => 512
|
25
|
+
method_option :iplastpart, :aliases => "-i", :type => :numeric,
|
26
|
+
:desc => "Sets the last part of the node's IP",
|
27
|
+
:required => true
|
28
|
+
def create(fqdn, *roles)
|
29
|
+
ip = "192.168.1.#{options[:iplastpart]}"
|
30
|
+
disk_size = options[:memory] * 20 / 1024
|
31
|
+
hostname = fqdn.split(".").first
|
32
|
+
|
33
|
+
# Convert roles array to proper run list
|
34
|
+
run_list = roles.map { |r| r =~ /recipe\[(.*)\]/ ? $1 : "role[#{r}]" }
|
35
|
+
|
36
|
+
# Always include the chef-client role in the run list
|
37
|
+
unless run_list.include? "role[chef-client]"
|
38
|
+
run_list.unshift "role[chef-client]"
|
39
|
+
end
|
40
|
+
|
41
|
+
vncpass = pwgen
|
42
|
+
rootpass = pwgen
|
43
|
+
|
44
|
+
say_status "Name: ", fqdn, :cyan
|
45
|
+
say_status "Memory: ", "#{options[:memory]}MB", :cyan
|
46
|
+
say_status "Disk: ", "#{disk_size}GB", :cyan
|
47
|
+
say_status "IP: ", ip, :cyan
|
48
|
+
say_status "VNC password: ", vncpass, :cyan
|
49
|
+
say_status "root password: ", rootpass, :cyan
|
50
|
+
|
51
|
+
say "\nRequesting server", :magenta
|
52
|
+
|
53
|
+
command = <<EOH
|
54
|
+
bash -c '
|
55
|
+
/root/bin/mkdomu.sh -m #{options[:memory]} -d #{disk_size} -v #{vncpass} -p #{rootpass} #{hostname} #{options[:iplastpart]}
|
56
|
+
xm create /etc/xen/#{hostname}.cfg
|
57
|
+
'
|
58
|
+
EOH
|
59
|
+
|
60
|
+
ssh_run "vanilla", command
|
61
|
+
|
62
|
+
say "\nServer ready, waiting 15 seconds to bootstrap."
|
63
|
+
sleep 15
|
64
|
+
|
65
|
+
say "\nBootstrapping #{shell.set_color(fqdn, :bold)}..."
|
66
|
+
|
67
|
+
command = <<EOH
|
68
|
+
bash -c '
|
69
|
+
mkdir -p /etc/chef
|
70
|
+
|
71
|
+
(
|
72
|
+
cat <<'EOP'
|
73
|
+
127.0.0.1 localhost localhost.localdomain
|
74
|
+
#{ip} #{fqdn} #{fqdn.split(".").first}
|
75
|
+
|
76
|
+
192.168.1.82 basil basil.secretsaucepartners.com chef.secretsaucepartners.com
|
77
|
+
EOP
|
78
|
+
) > /etc/hosts
|
79
|
+
|
80
|
+
(
|
81
|
+
cat <<'EOP'
|
82
|
+
#{IO.read(chef_config[:validation_key])}
|
83
|
+
EOP
|
84
|
+
) > /tmp/validation.pem
|
85
|
+
awk NF /tmp/validation.pem > /etc/chef/validation.pem
|
86
|
+
rm /tmp/validation.pem
|
87
|
+
|
88
|
+
(
|
89
|
+
cat <<'EOP'
|
90
|
+
log_level :info
|
91
|
+
log_location STDOUT
|
92
|
+
chef_server_url "#{chef_config[:chef_server_url]}"
|
93
|
+
validation_client_name "#{chef_config[:validation_client_name]}"
|
94
|
+
EOP
|
95
|
+
) > /etc/chef/client.rb
|
96
|
+
|
97
|
+
(
|
98
|
+
cat <<'EOP'
|
99
|
+
#{{ "run_list" => run_list }.to_json}
|
100
|
+
EOP
|
101
|
+
) > /etc/chef/first-boot.json
|
102
|
+
|
103
|
+
apt-get -y update
|
104
|
+
apt-get -y upgrade
|
105
|
+
|
106
|
+
/usr/local/bin/chef-client -j /etc/chef/first-boot.json'
|
107
|
+
EOH
|
108
|
+
|
109
|
+
begin
|
110
|
+
ssh_run ip, command, "root", rootpass
|
111
|
+
rescue Net::SSH::HostKeyMismatch => key_ex
|
112
|
+
key_ex.remember_host!
|
113
|
+
retry
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
desc "list", "Lists available servers on Vanilla"
|
118
|
+
def list
|
119
|
+
ssh_run "vanilla", "xm list"
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
desc "destroy FQDN", "Removes a chef client and also destorys the Xen guest on Vanilla"
|
124
|
+
def destroy(fqdn)
|
125
|
+
hostname = fqdn.split(".").first
|
126
|
+
|
127
|
+
if ask("Are you sure you want to destroy the `#{fqdn}' node? [yes/no]").downcase != "yes"
|
128
|
+
raise Thor::Error, "Aborting."
|
129
|
+
end
|
130
|
+
|
131
|
+
command = <<EOH
|
132
|
+
bash -c '
|
133
|
+
xm shutdown #{hostname}
|
134
|
+
sleep 3
|
135
|
+
rm /etc/xen/#{hostname}.cfg
|
136
|
+
lvremove -f vg/#{hostname}-{root,swap}'
|
137
|
+
EOH
|
138
|
+
|
139
|
+
ssh_run "vanilla", command
|
140
|
+
|
141
|
+
say %x{knife node delete #{fqdn} -y -c #{options[:chef_config]} 2>/dev/null}
|
142
|
+
say %x{knife client delete #{fqdn} -y -c #{options[:chef_config]} 2>/dev/null}
|
143
|
+
end
|
144
|
+
|
145
|
+
protected
|
146
|
+
def chef_config
|
147
|
+
unless defined?(@_chef_config_loaded)
|
148
|
+
Chef::Config.from_file(options[:chef_config])
|
149
|
+
@_chef_config_loaded = true
|
150
|
+
end
|
151
|
+
Chef::Config
|
152
|
+
end
|
153
|
+
|
154
|
+
def ssh_run(host, command, user = options[:ssh_user], pass = options[:ssh_password])
|
155
|
+
ssh = Chef::Knife::Ssh.new
|
156
|
+
ssh.name_args = [ host, command ]
|
157
|
+
ssh.config[:ssh_user] = user
|
158
|
+
ssh.config[:password] = pass
|
159
|
+
ssh.config[:manual] = true
|
160
|
+
|
161
|
+
begin
|
162
|
+
ssh.run
|
163
|
+
rescue Net::SSH::AuthenticationFailed
|
164
|
+
unless config[:ssh_password]
|
165
|
+
puts "Failed to authenticate #{config[:ssh_user]} - trying password auth"
|
166
|
+
ssh = Chef::Knife::Ssh.new
|
167
|
+
ssh.name_args = [ host, command ]
|
168
|
+
ssh.config[:ssh_user] = user
|
169
|
+
ssh.config[:manual] = true
|
170
|
+
ssh.config[:password] = ssh.get_password
|
171
|
+
ssh.run
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def pwgen(length = 16)
|
177
|
+
chars = (('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a) - %w(i o 0 1 l I O)
|
178
|
+
(1..length).collect {|a| chars[rand(chars.size)]}.join
|
179
|
+
end
|
180
|
+
end
|
data/lib/ssp/version.rb
CHANGED
metadata
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ssp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: "0.
|
8
|
+
- 2
|
9
|
+
version: "0.2"
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- !binary |
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-
|
19
|
+
date: 2010-07-05 00:00:00 +02:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
@@ -64,6 +64,7 @@ files:
|
|
64
64
|
- lib/ssp/app.rb
|
65
65
|
- lib/ssp/application/bags.rb
|
66
66
|
- lib/ssp/application/node.rb
|
67
|
+
- lib/ssp/application/office_node.rb
|
67
68
|
- lib/ssp/application/pair.rb
|
68
69
|
- lib/ssp/config.rb
|
69
70
|
- lib/ssp/version.rb
|