knife-server 0.3.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -22,61 +22,33 @@ class Chef
22
22
  class Knife
23
23
  class ServerBootstrapEc2 < Knife
24
24
 
25
+ banner "knife server bootstrap ec2 (options)"
26
+
25
27
  include Knife::ServerBootstrapBase
26
28
 
27
29
  deps do
28
30
  require 'knife/server/ssh'
29
31
  require 'knife/server/credentials'
30
32
  require 'knife/server/ec2_security_group'
31
- require 'chef/knife/ec2_server_create'
32
- require 'fog'
33
- Chef::Knife::Ec2ServerCreate.load_deps
34
- end
35
-
36
- banner "knife server bootstrap ec2 (options)"
37
33
 
38
- option :aws_access_key_id,
39
- :short => "-A ID",
40
- :long => "--aws-access-key-id KEY",
41
- :description => "Your AWS Access Key ID",
42
- :proc => Proc.new { |key| Chef::Config[:knife][:aws_access_key_id] = key }
43
-
44
- option :aws_secret_access_key,
45
- :short => "-K SECRET",
46
- :long => "--aws-secret-access-key SECRET",
47
- :description => "Your AWS API Secret Access Key",
48
- :proc => Proc.new { |key| Chef::Config[:knife][:aws_secret_access_key] = key }
49
- option :region,
50
- :long => "--region REGION",
51
- :description => "Your AWS region",
52
- :default => "us-east-1",
53
- :proc => Proc.new { |key| Chef::Config[:knife][:region] = key }
54
-
55
- option :ssh_key_name,
56
- :short => "-S KEY",
57
- :long => "--ssh-key KEY",
58
- :description => "The AWS SSH key id",
59
- :proc => Proc.new { |key| Chef::Config[:knife][:aws_ssh_key_id] = key }
60
-
61
- option :flavor,
62
- :short => "-f FLAVOR",
63
- :long => "--flavor FLAVOR",
64
- :description => "The flavor of server (m1.small, m1.medium, etc)",
65
- :proc => Proc.new { |f| Chef::Config[:knife][:flavor] = f },
66
- :default => "m1.small"
67
-
68
- option :image,
69
- :short => "-I IMAGE",
70
- :long => "--image IMAGE",
71
- :description => "The AMI for the server",
72
- :proc => Proc.new { |i| Chef::Config[:knife][:image] = i }
73
-
74
- option :availability_zone,
75
- :short => "-Z ZONE",
76
- :long => "--availability-zone ZONE",
77
- :description => "The Availability Zone",
78
- :default => "us-east-1b",
79
- :proc => Proc.new { |key| Chef::Config[:knife][:availability_zone] = key }
34
+ begin
35
+ require 'chef/knife/ec2_server_create'
36
+ require 'fog'
37
+ Chef::Knife::Ec2ServerCreate.load_deps
38
+
39
+ current_options = self.options
40
+ self.options = Chef::Knife::Ec2ServerCreate.options.dup
41
+ self.options.merge!(current_options)
42
+ rescue LoadError => ex
43
+ ui.error [
44
+ "Knife plugin knife-ec2 could not be loaded.",
45
+ "Please add the knife-ec2 gem to your Gemfile or",
46
+ "install the gem manually with `gem install knife-ec2'.",
47
+ "(#{ex.message})"
48
+ ].join(" ")
49
+ exit 1
50
+ end
51
+ end
80
52
 
81
53
  option :security_groups,
82
54
  :short => "-G X,Y,Z",
@@ -85,20 +57,6 @@ class Chef
85
57
  :default => ["infrastructure"],
86
58
  :proc => Proc.new { |groups| groups.split(',') }
87
59
 
88
- option :tags,
89
- :short => "-T T=V[,T=V,...]",
90
- :long => "--tags Tag=Value[,Tag=Value...]",
91
- :description => "The tags for this server",
92
- :proc => Proc.new { |tags| tags.split(',') }
93
-
94
- option :ebs_size,
95
- :long => "--ebs-size SIZE",
96
- :description => "The size of the EBS volume in GB, for EBS-backed instances"
97
-
98
- option :ebs_no_delete_on_term,
99
- :long => "--ebs-no-delete-on-term",
100
- :description => "Do not delete EBS volumn on instance termination"
101
-
102
60
  def run
103
61
  validate!
104
62
  config_security_group
@@ -112,7 +70,9 @@ class Chef
112
70
  ENV['WEBUI_PASSWORD'] = config[:webui_password]
113
71
  ENV['AMQP_PASSWORD'] = config[:amqp_password]
114
72
  bootstrap = Chef::Knife::Ec2ServerCreate.new
115
- bootstrap.config.merge!(config)
73
+ Chef::Knife::Ec2ServerCreate.options.keys.each do |attr|
74
+ bootstrap.config[attr] = config_val(attr)
75
+ end
116
76
  bootstrap.config[:tags] = bootstrap_tags
117
77
  bootstrap.config[:distro] = bootstrap_distro
118
78
  bootstrap
@@ -121,16 +81,16 @@ class Chef
121
81
  def ec2_connection
122
82
  @ec2_connection ||= Fog::Compute.new(
123
83
  :provider => 'AWS',
124
- :aws_access_key_id => Chef::Config[:knife][:aws_access_key_id],
125
- :aws_secret_access_key => Chef::Config[:knife][:aws_secret_access_key],
126
- :region => Chef::Config[:knife][:region]
84
+ :aws_access_key_id => config_val(:aws_access_key_id),
85
+ :aws_secret_access_key => config_val(:aws_secret_access_key),
86
+ :region => config_val(:region)
127
87
  )
128
88
  end
129
89
 
130
90
  def server_dns_name
131
91
  server = ec2_connection.servers.find do |s|
132
92
  s.state == "running" &&
133
- s.tags['Name'] == config[:chef_node_name] &&
93
+ s.tags['Name'] == config_val(:chef_node_name) &&
134
94
  s.tags['Role'] == 'chef_server'
135
95
  end
136
96
 
@@ -144,25 +104,37 @@ class Chef
144
104
  ui.error "You did not provide a valid --node-name value."
145
105
  exit 1
146
106
  end
107
+ if config_val(:platform) == "auto"
108
+ ui.error "Auto platform mode cannot be used with knife-ec2 plugin"
109
+ exit 1
110
+ end
147
111
  end
148
112
 
149
- def config_security_group(name = config[:security_groups].first)
113
+ def config_security_group(name = nil)
114
+ name = config_val(:security_groups).first if name.nil?
115
+
150
116
  ::Knife::Server::Ec2SecurityGroup.new(ec2_connection, ui).
151
117
  configure_chef_server_group(name, :description => "#{name} group")
152
118
  end
153
119
 
154
120
  def bootstrap_tags
155
- Hash[Array(config[:tags]).map { |t| t.split('=') }].
121
+ Hash[Array(config_val(:tags)).map { |t| t.split('=') }].
156
122
  merge({"Role" => "chef_server"}).map { |k,v| "#{k}=#{v}" }
157
123
  end
158
124
 
159
125
  def ssh_connection
160
- ::Knife::Server::SSH.new(
126
+ opts = {
161
127
  :host => server_dns_name,
162
- :user => config[:ssh_user],
163
- :port => config[:ssh_port],
164
- :keys => [config[:identity_file]]
165
- )
128
+ :user => config_val(:ssh_user),
129
+ :port => config_val(:ssh_port),
130
+ :keys => [config_val(:identity_file)].compact
131
+ }
132
+ if config_val(:host_key_verify) == false
133
+ opts[:user_known_hosts_file] = "/dev/null"
134
+ opts[:paranoid] = false
135
+ end
136
+
137
+ ::Knife::Server::SSH.new(opts)
166
138
  end
167
139
  end
168
140
  end
@@ -22,6 +22,8 @@ class Chef
22
22
  class Knife
23
23
  class ServerBootstrapStandalone < Knife
24
24
 
25
+ banner "knife server bootstrap standalone (options)"
26
+
25
27
  include Knife::ServerBootstrapBase
26
28
 
27
29
  deps do
@@ -29,20 +31,17 @@ class Chef
29
31
  require 'knife/server/credentials'
30
32
  require 'chef/knife/bootstrap'
31
33
  Chef::Knife::Bootstrap.load_deps
32
- end
33
34
 
34
- banner "knife server bootstrap standalone (options)"
35
+ current_options = self.options
36
+ self.options = Chef::Knife::Bootstrap.options.dup
37
+ self.options.merge!(current_options)
38
+ end
35
39
 
36
40
  option :host,
37
41
  :short => "-H FQDN_OR_IP",
38
42
  :long => "--host FQDN_OR_IP",
39
43
  :description => "Hostname or IP address of host to bootstrap"
40
44
 
41
- option :ssh_password,
42
- :short => "-P PASSWORD",
43
- :long => "--ssh-password PASSWORD",
44
- :description => "The ssh password"
45
-
46
45
  def run
47
46
  validate!
48
47
  check_ssh_connection
@@ -57,10 +56,11 @@ class Chef
57
56
  ENV['AMQP_PASSWORD'] = config[:amqp_password]
58
57
  bootstrap = Chef::Knife::Bootstrap.new
59
58
  bootstrap.name_args = [ config[:host] ]
60
- [ :chef_node_name, :ssh_user, :ssh_password, :ssh_port, :identity_file
61
- ].each { |attr| bootstrap.config[attr] = config[attr] }
59
+ Chef::Knife::Bootstrap.options.keys.each do |attr|
60
+ bootstrap.config[attr] = config_val(attr)
61
+ end
62
62
  bootstrap.config[:distro] = bootstrap_distro
63
- bootstrap.config[:use_sudo] = true unless config[:ssh_user] == "root"
63
+ bootstrap.config[:use_sudo] = true unless config_val(:ssh_user) == "root"
64
64
  bootstrap
65
65
  end
66
66
 
@@ -80,21 +80,27 @@ class Chef
80
80
  def check_ssh_connection
81
81
  ssh_connection.exec! "hostname -f"
82
82
  rescue Net::SSH::AuthenticationFailed
83
- ui.warn("Failed to authenticate #{config[:ssh_user]} - " +
83
+ ui.warn("Failed to authenticate #{config_val(:ssh_user)} - " +
84
84
  "trying password auth")
85
85
  config[:ssh_password] = ui.ask(
86
- "Enter password for #{config[:ssh_user]}@#{config[:host]}: "
86
+ "Enter password for #{config_val(:ssh_user)}@#{config_val(:host)}: "
87
87
  ) { |q| q.echo = false }
88
88
  end
89
89
 
90
90
  def ssh_connection
91
- ::Knife::Server::SSH.new(
92
- :host => config[:host],
93
- :user => config[:ssh_user],
94
- :password => config[:ssh_password],
95
- :port => config[:ssh_port],
96
- :keys => [config[:identity_file]].compact
97
- )
91
+ opts = {
92
+ :host => config_val(:host),
93
+ :user => config_val(:ssh_user),
94
+ :password => config_val(:ssh_password),
95
+ :port => config_val(:ssh_port),
96
+ :keys => [config_val(:identity_file)].compact
97
+ }
98
+ if config_val(:host_key_verify) == false
99
+ opts[:user_known_hosts_file] = "/dev/null"
100
+ opts[:paranoid] = false
101
+ end
102
+
103
+ ::Knife::Server::SSH.new(opts)
98
104
  end
99
105
  end
100
106
  end
@@ -21,9 +21,10 @@ require 'fileutils'
21
21
  module Knife
22
22
  module Server
23
23
  class Credentials
24
- def initialize(ssh, validation_key_path)
24
+ def initialize(ssh, validation_key_path, options = {})
25
25
  @ssh = ssh
26
26
  @validation_key_path = validation_key_path
27
+ @omnibus = options[:omnibus]
27
28
  end
28
29
 
29
30
  def install_validation_key(suffix = Time.now.to_i)
@@ -32,20 +33,39 @@ module Knife
32
33
  backup_file_path(@validation_key_path, suffix))
33
34
  end
34
35
 
36
+ chef10_key = "/etc/chef/validation.pem"
37
+ omnibus_key = "/etc/chef-server/chef-validator.pem"
38
+
35
39
  File.open(@validation_key_path, "wb") do |f|
36
- f.write(@ssh.exec!("cat /etc/chef/validation.pem"))
40
+ f.write(@ssh.exec!("cat #{omnibus? ? omnibus_key : chef10_key}"))
37
41
  end
38
42
  end
39
43
 
40
44
  def create_root_client
41
- @ssh.exec!([
45
+ chef10_cmd = [
42
46
  "knife configure",
43
47
  "--initial",
44
48
  "--server-url http://127.0.0.1:4000",
45
49
  "--user root",
46
50
  '--repository ""',
47
51
  "--defaults --yes"
48
- ].join(" "))
52
+ ].join(" ")
53
+
54
+ omnibus_cmd = [
55
+ "echo '#{ENV['WEBUI_PASSWORD']}' |",
56
+ "knife configure",
57
+ "--initial",
58
+ "--server-url http://127.0.0.1:8000",
59
+ "--user root",
60
+ '--repository ""',
61
+ "--admin-client-name chef-webui",
62
+ "--admin-client-key /etc/chef-server/chef-webui.pem",
63
+ "--validation-client-name chef-validator",
64
+ "--validation-key /etc/chef-server/chef-validator.pem",
65
+ "--defaults --yes"
66
+ ].join(" ")
67
+
68
+ @ssh.exec!(omnibus? ? omnibus_cmd : chef10_cmd)
49
69
  end
50
70
 
51
71
  def install_client_key(user, client_key_path, suffix = Time.now.to_i)
@@ -65,17 +85,34 @@ module Knife
65
85
 
66
86
  private
67
87
 
88
+ def omnibus?
89
+ @omnibus
90
+ end
91
+
68
92
  def backup_file_path(file_path, suffix)
69
93
  parts = file_path.rpartition(".")
70
94
  "#{parts[0]}.#{suffix}.#{parts[2]}"
71
95
  end
72
96
 
73
97
  def create_user_client(user)
74
- @ssh.exec!([
98
+ chef10_cmd = [
75
99
  "knife client create",
76
100
  user,
77
- "--admin --file /tmp/chef-client-#{user}.pem --disable-editing"
78
- ].join(" "))
101
+ "--admin",
102
+ "--file /tmp/chef-client-#{user}.pem",
103
+ "--disable-editing"
104
+ ].join(" ")
105
+
106
+ omnibus_cmd = [
107
+ "knife user create",
108
+ user,
109
+ "--admin",
110
+ "--file /tmp/chef-client-#{user}.pem",
111
+ "--disable-editing",
112
+ "--password #{ENV['WEBUI_PASSWORD']}"
113
+ ].join(" ")
114
+
115
+ @ssh.exec!(omnibus? ? omnibus_cmd : chef10_cmd)
79
116
  end
80
117
  end
81
118
  end
@@ -22,6 +22,7 @@ module Knife
22
22
  module Server
23
23
  class SSH
24
24
  DEFAULT_OPTIONS = { :user => "root", :port => "22" }.freeze
25
+ USER_SWITCH_COMMAND = %[sudo USER=root HOME="$(getent passwd root | cut -d : -f 6)"]
25
26
 
26
27
  def initialize(params)
27
28
  options = DEFAULT_OPTIONS.merge(params)
@@ -36,7 +37,7 @@ module Knife
36
37
  full_cmd = cmd
37
38
  else
38
39
  full_cmd = [
39
- %[sudo USER=root HOME="$(getent passwd root | cut -d : -f 6)"],
40
+ USER_SWITCH_COMMAND,
40
41
  %[bash -c '#{cmd}']
41
42
  ].join(" ")
42
43
  end
@@ -47,6 +48,61 @@ module Knife
47
48
  end
48
49
  result
49
50
  end
51
+
52
+ # runs a script on the target host by passing it to the stdin of a sh
53
+ # process. returns stdout and the exit status. does not care about stderr.
54
+ def run_script(content)
55
+ user_switch = ""
56
+
57
+ unless @user == "root"
58
+ user_switch = USER_SWITCH_COMMAND
59
+ end
60
+
61
+ wrapper = <<-EOF
62
+ if [ -e /dev/fd/0 ]
63
+ then
64
+ #{user_switch} /bin/sh /dev/fd/0
65
+ elif [ -e /dev/stdin ]
66
+ then
67
+ #{user_switch} /bin/sh /dev/stdin
68
+ else
69
+ echo "Cannot find method of communicating with the shell via stdin"
70
+ exit 1
71
+ fi
72
+ EOF
73
+
74
+ result = ""
75
+ exit_status = nil
76
+
77
+ Net::SSH.start(@host, @user, @options) do |ssh|
78
+ ssh.open_channel do |ch|
79
+ ch.on_open_failed do |ch, code, desc|
80
+ raise "Connection Error to #{ip}: #{desc}"
81
+ end
82
+
83
+ ch.exec(wrapper) do |channel, type, data|
84
+ # spit out the shell script and close stdin so sh can do its magic.
85
+ channel.send_data(content)
86
+ channel.eof!
87
+
88
+ # then we just wait for sweet, sweet output.
89
+ channel.on_data do |ch2, data|
90
+ result << data
91
+ end
92
+
93
+ channel.on_request("exit-status") do |ch2, data|
94
+ exit_status = data.read_long
95
+ end
96
+ end
97
+
98
+ ch.wait
99
+ end
100
+
101
+ ssh.loop
102
+ end
103
+
104
+ return result, exit_status
105
+ end
50
106
  end
51
107
  end
52
108
  end
@@ -18,6 +18,6 @@
18
18
 
19
19
  module Knife
20
20
  module Server
21
- VERSION = "0.3.3"
21
+ VERSION = "1.0.0"
22
22
  end
23
23
  end
@@ -33,6 +33,8 @@ describe Chef::Knife::ServerBootstrapEc2 do
33
33
  @stderr = StringIO.new
34
34
  @knife.ui.stub!(:stderr).and_return(@stderr)
35
35
  @knife.config[:chef_node_name] = "yakky"
36
+ @knife.config[:platform] = "omnibus"
37
+ @knife.config[:ssh_user] = "root"
36
38
  end
37
39
 
38
40
  let(:connection) { mock(Fog::Compute::AWS) }
@@ -102,17 +104,25 @@ describe Chef::Knife::ServerBootstrapEc2 do
102
104
  bootstrap.config[:distro].should eq("distro-praha")
103
105
  end
104
106
 
105
- it "configs the bootstrap's distro to chef-server-debian by default" do
107
+ it "configs the bootstrap's distro to chef11/omnibus by default" do
106
108
  @knife.config.delete(:distro)
107
109
 
108
- bootstrap.config[:distro].should eq("chef-server-debian")
110
+ bootstrap.config[:distro].should eq("chef11/omnibus")
109
111
  end
110
112
 
111
113
  it "configs the bootstrap's distro value driven off platform value" do
112
114
  @knife.config.delete(:distro)
113
115
  @knife.config[:platform] = "freebsd"
114
116
 
115
- bootstrap.config[:distro].should eq("chef-server-freebsd")
117
+ bootstrap.config[:distro].should eq("chef11/freebsd")
118
+ end
119
+
120
+ it "configs the bootstrap's distro based on bootstrap_version and platform" do
121
+ @knife.config.delete(:distro)
122
+ @knife.config[:platform] = "freebsd"
123
+ @knife.config[:bootstrap_version] = "10"
124
+
125
+ bootstrap.config[:distro].should eq("chef10/freebsd")
116
126
  end
117
127
 
118
128
  it "configs the bootstrap's ENV with the webui password" do
@@ -251,13 +261,26 @@ describe Chef::Knife::ServerBootstrapEc2 do
251
261
  @knife.run
252
262
  end
253
263
 
254
- it "installs a new validation.pem key from the server" do
264
+ it "installs a new validation.pem key from the chef 10 server" do
265
+ @knife.config[:bootstrap_version] = "10"
266
+ Knife::Server::SSH.should_receive(:new).with({
267
+ :host => "grapes.wrath", :user => "root",
268
+ :port => "2345", :keys => ["~/.ssh/mykey_dsa"]
269
+ })
270
+ Knife::Server::Credentials.should_receive(:new).
271
+ with(ssh, "/etc/chef/validation.pem", {})
272
+ credentials.should_receive(:install_validation_key)
273
+
274
+ @knife.run
275
+ end
276
+
277
+ it "installs a new validation.pem key from the omnibus server" do
255
278
  Knife::Server::SSH.should_receive(:new).with({
256
279
  :host => "grapes.wrath", :user => "root",
257
280
  :port => "2345", :keys => ["~/.ssh/mykey_dsa"]
258
281
  })
259
282
  Knife::Server::Credentials.should_receive(:new).
260
- with(ssh, "/etc/chef/validation.pem")
283
+ with(ssh, "/etc/chef/validation.pem", {:omnibus => true})
261
284
  credentials.should_receive(:install_validation_key)
262
285
 
263
286
  @knife.run