knife-clodo 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *~
@@ -0,0 +1,14 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = 'knife-clodo'
3
+ spec.version = '0.1.0'
4
+ spec.summary = 'Clodo.Ru knife plugin'
5
+ spec.add_dependency('fog', '>= 0.10.0')
6
+ spec.description = <<-EOF
7
+ Knife plugin for Clodo.Ru cloud provider.
8
+ EOF
9
+ spec.author = 'Stepan G. Fedorov'
10
+ spec.email = 'sf@clodo.ru'
11
+ spec.homepage = 'http://clodo.ru/'
12
+ spec.files = `git ls-files`.split "\n"
13
+ spec.require_paths = ["lib"]
14
+ end
@@ -0,0 +1,51 @@
1
+ bash -c '
2
+ <%= "export http_proxy=\"#{knife_config[:bootstrap_proxy]}\"" if knife_config[:bootstrap_proxy] -%>
3
+
4
+ if [ ! -f /usr/bin/chef-client ]; then
5
+ echo "chef chef/chef_server_url string <%= @chef_config[:chef_server_url] %>" | debconf-set-selections
6
+ [ -f /etc/apt/sources.list.d/opscode.list ] || echo "deb http://apt.opscode.com <%= chef_version.to_f == 0.10 ? "squeeze-0.10" : "squeeze" %> main" > /etc/apt/sources.list.d/opscode.list
7
+ wget <%= "--proxy=on " if knife_config[:bootstrap_proxy] %>-O- http://apt.opscode.com/packages@opscode.com.gpg.key | apt-key add -
8
+ fi
9
+
10
+ export DEBIAN_FRONTEND=noninteractive
11
+
12
+ apt-get update
13
+ apt-get install -y ucf chef
14
+
15
+ (
16
+ cat <<'EOP'
17
+ log_level :info
18
+ log_location STDOUT
19
+ ssl_verufy_mode :verify_none
20
+ chef_server_url "<%= @chef_config[:chef_server_url] %>"
21
+ EOP
22
+ ) > /etc/chef/client.rb
23
+
24
+ (
25
+ cat <<'EOP'
26
+ <%= validation_key %>
27
+ EOP
28
+ ) > /tmp/validation.pem
29
+ awk NF /tmp/validation.pem > /etc/chef/validation.pem
30
+ rm /tmp/validation.pem
31
+
32
+ <% unless @chef_config[:validation_client_name] == "chef-validator" -%>
33
+ [ `grep -qx "validation_client_name \"<%= @chef_config[:validation_client_name] %>\"" /etc/chef/client.rb` ] || echo "validation_client_name \"<%= @chef_config[:validation_client_name] %>\"" >> /etc/chef/client.rb
34
+ <% end -%>
35
+
36
+ <% if @config[:chef_node_name] %>
37
+ [ `grep -qx "node_name \"<%= @config[:chef_node_name] %>\"" /etc/chef/client.rb` ] || echo "node_name \"<%= @config[:chef_node_name] %>\"" >> /etc/chef/client.rb
38
+ <% end -%>
39
+
40
+ <% if knife_config[:bootstrap_proxy] %>
41
+ echo 'http_proxy "knife_config[:bootstrap_proxy]"' >> /etc/chef/client.rb
42
+ echo 'https_proxy "knife_config[:bootstrap_proxy]"' >> /etc/chef/client.rb
43
+ <% end -%>
44
+
45
+ (
46
+ cat <<'EOP'
47
+ <%= { "run_list" => @run_list }.to_json %>
48
+ EOP
49
+ ) > /etc/chef/first-boot.json
50
+
51
+ <%= start_chef %>'
@@ -0,0 +1,61 @@
1
+ require 'chef/knife'
2
+
3
+ class Chef
4
+ class Knife
5
+ module ClodoBase
6
+
7
+ # I don't know what this means, so just copy it from Rackspace
8
+ def self.included(includer)
9
+ includer.class_eval do
10
+
11
+ deps do
12
+ require 'fog'
13
+ require 'net/ssh/multi'
14
+ require 'readline'
15
+ require 'chef/json_compat'
16
+ end
17
+
18
+ option :clodo_api_key,
19
+ :short => "-K KEY",
20
+ :long => "--clodo-api-key KEY",
21
+ :description => "Your clodo.ru API key",
22
+ :proc => Proc.new { |key| Chef::Config[:knife][:clodo_api_key] = key }
23
+
24
+ option :clodo_username,
25
+ :short => "-A USERNAME",
26
+ :long => "--clodo-username USERNAME",
27
+ :description => "Your clodo.ru API username",
28
+ :proc => Proc.new { |username| Chef::Config[:knife][:clodo_username] = username }
29
+
30
+ option :clodo_api_auth_url,
31
+ :long => "--clodo-api-auth-url URL",
32
+ :description => "Your clodo.ru API auth url",
33
+ :default => "api.clodo.ru",
34
+ :proc => Proc.new { |url| Chef::Config[:knife][:clodo_api_auth_url] = url }
35
+ end
36
+
37
+ def connection
38
+ @connection ||= Fog::Compute::Clodo.new({
39
+ :clodo_api_key => Chef::Config[:knife][:clodo_api_key],
40
+ :clodo_username => (Chef::Config[:knife][:clodo_username] || Chef::Config[:knife][:clodo_api_username]),
41
+ :clodo_auth_url => Chef::Config[:knife][:clodo_api_auth_url] || config[:clodo_api_auth_url]})
42
+ end
43
+
44
+ def locate_config_value(key)
45
+ key = key.to_sym
46
+ Chef::Config[:knife][key] || config[key]
47
+ end
48
+
49
+ def public_dns_name(server)
50
+ @public_dns_name ||= begin
51
+ Resolv.getname(server.public_ip_address)
52
+ rescue
53
+ "#{server.public_ip_address.gsub('.','-')}.clodo.ru"
54
+ end
55
+ end
56
+
57
+ end
58
+
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,216 @@
1
+ require 'chef/knife/clodo_base'
2
+
3
+ class Chef
4
+ class Knife
5
+ class ClodoServerCreate < Knife
6
+
7
+ include Knife::ClodoBase
8
+
9
+ deps do
10
+ require 'fog'
11
+ require 'readline'
12
+ require 'chef/json_compat'
13
+ require 'chef/knife/bootstrap'
14
+ Chef::Knife::Bootstrap.load_deps
15
+ end
16
+
17
+ banner "knife clodo.ru server create (options)"
18
+
19
+ option :image,
20
+ :short => "-I IMAGE",
21
+ :long => "--image IMAGE",
22
+ :description => "The image of server; default is 541 (Debian 6 amd64 Scale)",
23
+ :proc => Proc.new { |f| Chef::Config[:knife][:image] = f.to_i },
24
+ :default => 541
25
+
26
+ option :server_name,
27
+ :short => "-N NAME",
28
+ :long => "--server-name NAME",
29
+ :description => "The title for your server"
30
+
31
+ option :server_type,
32
+ :long => "--server-type TYPE",
33
+ :description => "Type of the server - static or scale (default scale)",
34
+ :proc => Proc.new {|f| Chef::Config[:knife][:server_type] = f=="static"?"VirtualServer":"ScaleServer"},
35
+ :default => "ScaleServer"
36
+
37
+ option :server_memory,
38
+ :long => "--server-memory MB",
39
+ :description => "For static server is an amount of memory in megabytes, for scale server is a low limit in megabytes. (default is 512MB)",
40
+ :proc => Proc.new {|m| Chef::Config[:knife][:server_memory] = m.to_i},
41
+ :default => 512
42
+
43
+ option :server_memory_max,
44
+ :long => "--server-memory-max MB",
45
+ :description => "For static server is ignored, for scale server is a high limit in megabytes. (default is 4096MB)",
46
+ :proc => Proc.new {|m| Chef::Config[:knife][:server_memory_max] = m.to_i},
47
+ :default => 4096
48
+
49
+ option :server_disk,
50
+ :long => "--server-disk GB",
51
+ :description => "Server's disk size in gigabytes. (default 10GB)",
52
+ :proc => Proc.new {|d| Chef::Config[:knife][:server_disk] = d.to_i},
53
+ :default => 10
54
+
55
+ option :server_support_level,
56
+ :long => "--server-support-level LEVEL",
57
+ :description => "Support level for this server. Default is always 1. You can also choose from 2 and 3",
58
+ :proc => Proc.new {|s| Chef::Config[:knife][:server_support_level] = s.to_i},
59
+ :default => 1
60
+
61
+ option :chef_node_name,
62
+ :long => "--node-name NAME",
63
+ :description => "The Chef node name for your new node"
64
+
65
+ option :ssh_user,
66
+ :short => "-x USERNAME",
67
+ :long => "--ssh-user USERNAME",
68
+ :description => "The ssh username; default is 'root'",
69
+ :default => "root"
70
+
71
+ option :ssh_password,
72
+ :short => "-P PASSWORD",
73
+ :long => "--ssh-password PASSWORD",
74
+ :description => "The ssh password"
75
+
76
+ option :identity_file,
77
+ :short => "-i IDENTITY_FILE",
78
+ :long => "--identity-file IDENTITY_FILE",
79
+ :description => "The SSH identity file used for authentication"
80
+
81
+ option :prerelease,
82
+ :long => "--prerelease",
83
+ :description => "Install the pre-release chef gems"
84
+
85
+ option :bootstrap_version,
86
+ :long => "--bootstrap-version VERSION",
87
+ :description => "The version of Chef to install",
88
+ :proc => Proc.new { |v| Chef::Config[:knife][:bootstrap_version] = v }
89
+ option :prerelease,
90
+ :long => "--prerelease",
91
+ :description => "Install the pre-release chef gems"
92
+
93
+ option :bootstrap_version,
94
+ :long => "--bootstrap-version VERSION",
95
+ :description => "The version of Chef to install",
96
+ :proc => Proc.new { |v| Chef::Config[:knife][:bootstrap_version] = v }
97
+
98
+ option :distro,
99
+ :short => "-d DISTRO",
100
+ :long => "--distro DISTRO",
101
+ :description => "Bootstrap a distro using a template; default is 'debian6apt'",
102
+ :proc => Proc.new { |d| Chef::Config[:knife][:distro] = d },
103
+ :default => "debian6apt"
104
+
105
+ option :template_file,
106
+ :long => "--template-file TEMPLATE",
107
+ :description => "Full path to location of template to use",
108
+ :proc => Proc.new { |t| Chef::Config[:knife][:template_file] = t },
109
+ :default => false
110
+
111
+ option :run_list,
112
+ :short => "-r RUN_LIST",
113
+ :long => "--run-list RUN_LIST",
114
+ :description => "Comma separated list of roles/recipes to apply",
115
+ :proc => lambda { |o| o.split(/[\s,]+/) },
116
+ :default => []
117
+
118
+ def tcp_test_ssh(hostname)
119
+ tcp_socket = TCPSocket.new(hostname, 22)
120
+ readable = IO.select([tcp_socket], nil, nil, 5)
121
+ if readable
122
+ Chef::Log.debug("sshd accepting connections on #{hostname}, banner is #{tcp_socket.gets}")
123
+ yield
124
+ true
125
+ else
126
+ false
127
+ end
128
+ rescue Errno::ETIMEDOUT
129
+ false
130
+ rescue Errno::EPERM
131
+ false
132
+ rescue Errno::ECONNREFUSED
133
+ sleep 2
134
+ false
135
+ rescue Errno::EHOSTUNREACH
136
+ sleep 2
137
+ false
138
+ ensure
139
+ tcp_socket && tcp_socket.close
140
+ end
141
+
142
+
143
+ def run
144
+ $stdout.sync = true
145
+
146
+ unless Chef::Config[:knife][:image]
147
+ ui.error("You have not provided a valid image value. Please note the short option for this value recently changed from '-i' to '-I'.")
148
+ exit 1
149
+ end
150
+
151
+ options = {
152
+ :vps_type => Chef::Config[:knife][:server_type],
153
+ :vps_memory => Chef::Config[:knife][:server_memory],
154
+ :vps_memory_max => Chef::Config[:knife][:server_memory_max],
155
+ :vps_hdd => Chef::Config[:knife][:server_disk],
156
+ :vps_admin => Chef::Config[:knife][:server_support_level],
157
+ :vps_os => Chef::Config[:knife][:image]
158
+ }
159
+
160
+ options[:name] = config[:server_name] if config[:server_name]
161
+
162
+ server = connection.servers.create(options)
163
+
164
+ puts "#{ui.color("ID", :cyan)}: #{server.id}"
165
+ puts "#{ui.color("Name", :cyan)}: #{server.name}"
166
+ puts "#{ui.color("Image", :cyan)}: #{server.image}"
167
+ puts "#{ui.color("IP", :cyan)}: #{server.public_ip_address}"
168
+ puts "#{ui.color("root password", :red)}: #{server.password}"
169
+
170
+ print "\n#{ui.color("Waiting server", :magenta)}"
171
+
172
+ # wait for it to be ready to do stuff
173
+ server.wait_for { print "."; ready? }
174
+
175
+ puts("\n")
176
+
177
+ puts "#{ui.color("Public DNS Name", :cyan)}: #{public_dns_name(server)}"
178
+ puts "#{ui.color("Public IP Address", :cyan)}: #{server.public_ip_address}"
179
+ puts "#{ui.color("Password", :cyan)}: #{server.password}"
180
+
181
+ print "\n#{ui.color("Waiting for sshd", :magenta)}"
182
+
183
+ print(".") until tcp_test_ssh(server.public_ip_address) { sleep @initial_sleep_delay ||= 10; puts("done") }
184
+
185
+ bootstrap_for_node(server).run
186
+
187
+ puts "\n"
188
+ puts "#{ui.color("Instance ID", :cyan)}: #{server.id}"
189
+ puts "#{ui.color("Name", :cyan)}: #{server.name}"
190
+ puts "#{ui.color("Image", :cyan)}: #{server.image}"
191
+ puts "#{ui.color("Public DNS Name", :cyan)}: #{public_dns_name(server)}"
192
+ puts "#{ui.color("Public IP Address", :cyan)}: #{server.public_ip_address}"
193
+ puts "#{ui.color("Password", :cyan)}: #{server.password}"
194
+ puts "#{ui.color("Environment", :cyan)}: #{config[:environment] || '_default'}"
195
+ puts "#{ui.color("Run List", :cyan)}: #{config[:run_list].join(', ')}"
196
+ end
197
+
198
+ def bootstrap_for_node(server)
199
+ bootstrap = Chef::Knife::Bootstrap.new
200
+ bootstrap.name_args = [public_dns_name(server)]
201
+ bootstrap.config[:run_list] = config[:run_list]
202
+ bootstrap.config[:ssh_user] = config[:ssh_user] || "root"
203
+ bootstrap.config[:ssh_password] = server.password
204
+ bootstrap.config[:identity_file] = config[:identity_file]
205
+ bootstrap.config[:chef_node_name] = config[:chef_node_name] || server.id
206
+ bootstrap.config[:prerelease] = config[:prerelease]
207
+ bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
208
+ # bootstrap will run as root...sudo (by default) also messes up Ohai on CentOS boxes
209
+ bootstrap.config[:use_sudo] = true unless config[:ssh_user] == 'root'
210
+ bootstrap.config[:environment] = config[:environment]
211
+ bootstrap
212
+ end
213
+
214
+ end
215
+ end
216
+ end
@@ -0,0 +1,48 @@
1
+ require 'chef/knife/clodo_base'
2
+
3
+ class Chef
4
+ class Knife
5
+ class ClodoServerList < Knife
6
+
7
+ include Knife::ClodoBase
8
+
9
+ banner "knife clodo server list (options)"
10
+
11
+ def run
12
+ $stdout.sync = true
13
+
14
+ server_list = [
15
+ ui.color('ID', :bold),
16
+ ui.color('Name', :bold),
17
+ ui.color('Public IP', :bold),
18
+ ui.color('Root pass', :bold),
19
+ ui.color('VNC', :bold),
20
+ ui.color('VNC pass', :bold),
21
+ ui.color('State', :bold)
22
+ ]
23
+
24
+ connection.servers.each do |server|
25
+ server_list << server.id.to_s
26
+ server_list << server.name
27
+ server_list << (server.public_ip_address ? server.public_ip_address : "")
28
+ server_list << server.password
29
+ server_list << server.vps_vnc
30
+ server_list << server.vps_vnc_pass
31
+ server_list << case server.state.downcase
32
+ when 'is_suspended'
33
+ ui.color(server.state.downcase, :red)
34
+ when 'is_disabled', 'is_request'
35
+ ui.color(server.state.downcase, :cyan)
36
+ when 'is_install'
37
+ ui.color(server.state.downcase, :yellow)
38
+ when 'is_running'
39
+ ui.color(server.state.downcase, :green)
40
+ else
41
+ ui.color(server.state.upcase, :red)
42
+ end
43
+ end
44
+ puts ui.list(server_list, :columns_across, 7)
45
+ end
46
+ end
47
+ end
48
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: knife-clodo
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Stepan G. Fedorov
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-09-24 00:00:00 +04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: fog
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 55
30
+ segments:
31
+ - 0
32
+ - 10
33
+ - 0
34
+ version: 0.10.0
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ description: "\tKnife plugin for Clodo.Ru cloud provider.\n"
38
+ email: sf@clodo.ru
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ extra_rdoc_files: []
44
+
45
+ files:
46
+ - .gitignore
47
+ - knife-clodo.gemspec
48
+ - lib/chef/knife/bootstrap/debian6apt.erb
49
+ - lib/chef/knife/clodo_base.rb
50
+ - lib/chef/knife/clodo_server_create.rb
51
+ - lib/chef/knife/clodo_server_list.rb
52
+ has_rdoc: true
53
+ homepage: http://clodo.ru/
54
+ licenses: []
55
+
56
+ post_install_message:
57
+ rdoc_options: []
58
+
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ hash: 3
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ hash: 3
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ requirements: []
80
+
81
+ rubyforge_project:
82
+ rubygems_version: 1.3.7
83
+ signing_key:
84
+ specification_version: 3
85
+ summary: Clodo.Ru knife plugin
86
+ test_files: []
87
+