knife-server 0.3.3 → 1.0.0

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.
@@ -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