knife-server 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.cane +1 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +3 -0
  5. data/.travis.yml +12 -8
  6. data/CHANGELOG.md +32 -1
  7. data/Gemfile +9 -4
  8. data/Guardfile +28 -0
  9. data/README.md +28 -5
  10. data/Rakefile +31 -10
  11. data/knife-server.gemspec +18 -8
  12. data/lib/chef/knife/bootstrap/_omnibus.sh +63 -10
  13. data/lib/chef/knife/bootstrap/chef10/rhel.erb +2 -0
  14. data/lib/chef/knife/bootstrap/chef11/omnibus.erb +4 -1
  15. data/lib/chef/knife/bootstrap/chef11/rhel.erb +2 -0
  16. data/lib/chef/knife/server_backup.rb +24 -10
  17. data/lib/chef/knife/server_bootstrap_base.rb +68 -23
  18. data/lib/chef/knife/server_bootstrap_ec2.rb +33 -20
  19. data/lib/chef/knife/server_bootstrap_linode.rb +20 -13
  20. data/lib/chef/knife/server_bootstrap_openstack.rb +128 -0
  21. data/lib/chef/knife/server_bootstrap_standalone.rb +28 -16
  22. data/lib/chef/knife/server_restore.rb +23 -9
  23. data/lib/knife-server.rb +1 -0
  24. data/lib/knife/server/credentials.rb +78 -42
  25. data/lib/knife/server/ec2_security_group.rb +24 -21
  26. data/lib/knife/server/ssh.rb +54 -18
  27. data/lib/knife/server/version.rb +2 -1
  28. data/spec/chef/knife/server_backup_spec.rb +58 -44
  29. data/spec/chef/knife/server_bootstrap_ec2_spec.rb +108 -80
  30. data/spec/chef/knife/server_bootstrap_linode_spec.rb +93 -64
  31. data/spec/chef/knife/server_bootstrap_openstack_spec.rb +305 -0
  32. data/spec/chef/knife/server_bootstrap_standalone_spec.rb +113 -76
  33. data/spec/chef/knife/server_restore_spec.rb +38 -37
  34. data/spec/knife/server/credientials_spec.rb +248 -51
  35. data/spec/knife/server/ec2_security_group_spec.rb +76 -68
  36. data/spec/knife/server/ssh_spec.rb +138 -22
  37. metadata +107 -31
@@ -174,6 +174,8 @@ configure_firewall() {
174
174
  /usr/sbin/lokkit -p 4040:tcp
175
175
  # ssl proxy to chef-server-api
176
176
  /usr/sbin/lokkit -p 443:tcp
177
+ # SSH port
178
+ /usr/sbin/lokkit -p 22:tcp
177
179
  }
178
180
 
179
181
  setup
@@ -22,6 +22,7 @@ set -e
22
22
  export hostname="<%= @config[:chef_node_name] %>"
23
23
  export version="<%= @config[:bootstrap_version] %>"
24
24
  export prerelease="<%= @config[:prerelease] == true %>"
25
+ export url="<%= @chef_config[:knife][:server_package_url] %>"
25
26
  export webui_enable="<%= @chef_config[:knife][:webui_enable] == true %>"
26
27
  export webui_password="<%= ENV['WEBUI_PASSWORD'] %>"
27
28
  export amqp_password="<%= ENV['AMQP_PASSWORD'] %>"
@@ -55,9 +56,11 @@ tmp_dir=$(mktemp -d -t tmp.XXXXXXXX || echo "/tmp")
55
56
  set_hostname_for_${platform}
56
57
  download_package
57
58
  install_package
59
+ detect_info
60
+ patch_knife_code
58
61
  prepare_chef_server_rb
59
- symlink_binaries
60
62
  reconfigure_chef_server
63
+ symlink_binaries
61
64
  if [ ! -n "$no_test"]
62
65
  then
63
66
  test_chef_server
@@ -129,6 +129,8 @@ configure_firewall() {
129
129
  /usr/sbin/lokkit -p 4040:tcp
130
130
  # ssl proxy to chef-server-api
131
131
  /usr/sbin/lokkit -p 443:tcp
132
+ # SSH port
133
+ /usr/sbin/lokkit -p 22:tcp
132
134
  }
133
135
 
134
136
  setup
@@ -1,3 +1,4 @@
1
+ # -*- encoding: utf-8 -*-
1
2
  #
2
3
  # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
3
4
  # Copyright:: Copyright (c) 2012 Fletcher Nichol
@@ -16,16 +17,17 @@
16
17
  # limitations under the License.
17
18
  #
18
19
 
19
- require 'chef/knife'
20
- require 'chef/node'
20
+ require "chef/knife"
21
+ require "chef/node"
21
22
 
22
23
  class Chef
23
24
  class Knife
25
+ # Backs up a Chef server component.
24
26
  class ServerBackup < Knife
25
27
 
26
28
  deps do
27
- require 'fileutils'
28
- require 'uri'
29
+ require "fileutils"
30
+ require "uri"
29
31
  end
30
32
 
31
33
  banner "knife server backup COMPONENT[ COMPONENT ...] (options)"
@@ -60,10 +62,22 @@ class Chef
60
62
  private
61
63
 
62
64
  COMPONENTS = {
63
- "nodes" => { :singular => "node", :klass => Chef::Node },
64
- "roles" => { :singular => "role", :klass => Chef::Role },
65
- "environments" => { :singular => "environment", :klass => Chef::Environment },
66
- "data_bags" => { :singular => "data_bag", :klass => Chef::DataBag },
65
+ "nodes" => {
66
+ :singular => "node",
67
+ :klass => Chef::Node
68
+ },
69
+ "roles" => {
70
+ :singular => "role",
71
+ :klass => Chef::Role
72
+ },
73
+ "environments" => {
74
+ :singular => "environment",
75
+ :klass => Chef::Environment
76
+ },
77
+ "data_bags" => {
78
+ :singular => "data_bag",
79
+ :klass => Chef::DataBag
80
+ }
67
81
  }
68
82
 
69
83
  def validate!
@@ -80,7 +94,7 @@ class Chef
80
94
  ui.msg "Creating #{c[:singular]} backups in #{dir_path}"
81
95
  FileUtils.mkdir_p(dir_path)
82
96
 
83
- Array(c[:klass].list).each do |name, url|
97
+ Array(c[:klass].list).each do |name, _url|
84
98
  next if component == "environments" && name == "_default"
85
99
 
86
100
  case component
@@ -108,7 +122,7 @@ class Chef
108
122
  item_path = ::File.join(dir_path, name)
109
123
  FileUtils.mkdir_p(item_path)
110
124
 
111
- Array(c[:klass].load(name)).each do |item_name, url|
125
+ Array(c[:klass].load(name)).each do |item_name, _url|
112
126
  obj = Chef::DataBagItem.load(name, item_name)
113
127
  ui.msg "Backing up #{c[:singular]}[#{name}][#{item_name}]"
114
128
  ::File.open(::File.join(item_path, "#{item_name}.json"), "wb") do |f|
@@ -1,3 +1,4 @@
1
+ # -*- encoding: utf-8 -*-
1
2
  #
2
3
  # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
3
4
  # Copyright:: Copyright (c) 2012 Fletcher Nichol
@@ -16,35 +17,39 @@
16
17
  # limitations under the License.
17
18
  #
18
19
 
19
- require 'chef/knife'
20
+ require "chef/knife"
20
21
 
21
22
  class Chef
22
23
  class Knife
24
+ # Common behavior for server bootstrapping.
23
25
  module ServerBootstrapBase
24
26
 
25
- def self.included(included_class)
27
+ def self.included(included_class) # rubocop:disable Metrics/MethodLength
26
28
  included_class.class_eval do
27
29
 
28
30
  deps do
29
- require 'chef/knife/ssh'
30
- require 'net/ssh'
31
+ require "chef/knife/ssh"
32
+ require "net/ssh"
31
33
  end
32
34
 
33
35
  option :platform,
34
36
  :short => "-P PLATFORM",
35
37
  :long => "--platform PLATFORM",
36
- :description => "The platform type that will be bootstrapped (omnibus)",
38
+ :description => "The platform type that will be bootstrapped, "\
39
+ "default is 'omnibus'",
37
40
  :default => "omnibus"
38
41
 
39
42
  option :distro,
40
43
  :short => "-d DISTRO",
41
44
  :long => "--distro DISTRO",
42
- :description => "Bootstrap a distro using a template; default is 'chef11/omnibus'"
45
+ :description => "Bootstrap a distro using a template, " \
46
+ "default is 'chef11/omnibus'"
43
47
 
44
48
  option :bootstrap_version,
45
49
  :long => "--bootstrap-version VERSION",
46
- :description => "The version of Chef Server to install, default is latest release",
47
- :proc => Proc.new { |v| Chef::Config[:knife][:bootstrap_version] = v },
50
+ :description => "The version of Chef Server to install, " \
51
+ "default is latest release",
52
+ :proc => proc { |v| Chef::Config[:knife][:bootstrap_version] = v },
48
53
  :default => nil
49
54
 
50
55
  option :prerelease,
@@ -53,13 +58,15 @@ class Chef
53
58
 
54
59
  option :webui_enable,
55
60
  :long => "--[no-]webui-enable",
56
- :description => "Whether or not to enable the webui, default is false",
57
- :proc => Proc.new { |v| Chef::Config[:knife][:webui_enable] = v },
61
+ :description => "Whether or not to enable the webui, " \
62
+ "default is false",
63
+ :proc => proc { |v| Chef::Config[:knife][:webui_enable] = v },
58
64
  :default => false
59
65
 
60
66
  option :webui_password,
61
67
  :long => "--webui-password SECRET",
62
- :description => "Initial password for WebUI admin account, default is 'chefchef'",
68
+ :description => "Initial password for WebUI admin account, " \
69
+ "default is 'chefchef'",
63
70
  :default => "chefchef"
64
71
 
65
72
  option :amqp_password,
@@ -70,19 +77,47 @@ class Chef
70
77
  option :log_level,
71
78
  :short => "-l LEVEL",
72
79
  :long => "--log-level LEVEL",
73
- :description => "Set the log level (debug, info, warn, error, fatal)",
74
- :proc => Proc.new { |v| Chef::Config[:knife][:log_level] = v.to_sym },
80
+ :description => "Set the log level " \
81
+ "(debug, info, warn, error, fatal), default is error",
82
+ :proc => proc { |v| Chef::Config[:knife][:log_level] = v.to_sym },
75
83
  :default => :error
76
84
 
77
85
  option :no_test,
78
86
  :short => "-n",
79
87
  :long => "--no-test",
80
- :description => "Do not run opscode pedant as a part of the omnibus installation"
88
+ :description => "Do not run opscode pedant as a part of the " \
89
+ "omnibus installation"
90
+
91
+ option :url,
92
+ :long => "--url URL",
93
+ :description => "URL to specfic package release",
94
+ :proc => proc { |u| Chef::Config[:knife][:server_package_url] = u }
81
95
  end
82
96
  end
83
97
 
98
+ def run
99
+ validate!
100
+ end
101
+
84
102
  private
85
103
 
104
+ def validate!
105
+ knife_fail = "You did not set {{KEY}} in your knife.rb, which is a " \
106
+ "required setting. Please generate an initial knife.rb or read " \
107
+ "the setup instructions at http://fnichol.github.io/knife-server/"
108
+
109
+ # rubocop:disable Style/DeprecatedHashMethods
110
+ if Chef::Config[:node_name].nil?
111
+ ui.error knife_fail.gsub(/{{KEY}}/, "node_name")
112
+ exit 1
113
+ end
114
+ if Chef::Config[:client_key].nil?
115
+ ui.error knife_fail.gsub(/{{KEY}}/, "client_key")
116
+ exit 1
117
+ end
118
+ # rubocop:enable Style/DeprecatedHashMethods
119
+ end
120
+
86
121
  def fetch_validation_key
87
122
  credentials_client.install_validation_key
88
123
  end
@@ -100,7 +135,7 @@ class Chef
100
135
  config_val(:platform) == "auto"
101
136
  end
102
137
 
103
- def distro_auto_map(platform, platform_version)
138
+ def distro_auto_map(platform, _platform_version)
104
139
  # NOTE this logic is shared with chef/knife/bootstrap/auto.sh, which is
105
140
  # run on the server side.
106
141
  # XXX we don't actually use the platform_version stuff, just included
@@ -120,7 +155,7 @@ class Chef
120
155
  "suse"
121
156
  end
122
157
 
123
- return construct_distro(normal)
158
+ construct_distro(normal)
124
159
  end
125
160
 
126
161
  def construct_distro(platform)
@@ -136,7 +171,8 @@ class Chef
136
171
  def bootstrap_distro
137
172
  return config_val(:distro) if config_val(:distro)
138
173
  return determine_platform if config_val(:platform) == "auto"
139
- return construct_distro(config_val(:platform))
174
+
175
+ construct_distro(config_val(:platform))
140
176
  end
141
177
 
142
178
  def credentials_client
@@ -149,23 +185,32 @@ class Chef
149
185
  def determine_platform
150
186
  return nil unless bootstrap_auto?
151
187
 
152
- script = File.binread(File.expand_path("bootstrap/auto.sh", File.dirname(__FILE__)))
188
+ script = File.binread(
189
+ File.expand_path("bootstrap/auto.sh", File.dirname(__FILE__))
190
+ )
153
191
 
154
192
  # result is expected to be two lines, first being the platform name,
155
193
  # second being the platform version.
156
194
  result, exit_status = ssh_connection.run_script(script)
157
195
 
158
- if exit_status != 0 or !result or result.strip.empty?
159
- raise "Could not determine the OS running the target for the chef server. Please specify --platform."
196
+ if exit_status != 0 || !result || result.strip.empty?
197
+ raise "Could not determine the OS running the target for " \
198
+ "the chef server. Please specify --platform."
160
199
  end
161
200
 
162
- return distro_auto_map(*result.split(/\n/).compact[0..1])
201
+ distro_auto_map(*result.split(/\n/).compact[0..1])
163
202
  end
164
203
 
165
204
  def config_val(key)
166
205
  key = key.to_sym
167
- default_value = options[key] && options[key][:default]
168
- config.fetch(key, Chef::Config[:knife].fetch(key, default_value))
206
+ case
207
+ when !config[key].nil?
208
+ config[key]
209
+ when !Chef::Config[:knife][key].nil?
210
+ Chef::Config[:knife][key]
211
+ else
212
+ options[key] && options[key][:default]
213
+ end
169
214
  end
170
215
  end
171
216
  end
@@ -1,3 +1,4 @@
1
+ # -*- encoding: utf-8 -*-
1
2
  #
2
3
  # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
3
4
  # Copyright:: Copyright (c) 2012 Fletcher Nichol
@@ -16,10 +17,11 @@
16
17
  # limitations under the License.
17
18
  #
18
19
 
19
- require 'chef/knife/server_bootstrap_base'
20
+ require "chef/knife/server_bootstrap_base"
20
21
 
21
22
  class Chef
22
23
  class Knife
24
+ # Provisions an EC2 instance and sets up an Open Source Chef Server.
23
25
  class ServerBootstrapEc2 < Knife
24
26
 
25
27
  banner "knife server bootstrap ec2 (options)"
@@ -27,18 +29,18 @@ class Chef
27
29
  include Knife::ServerBootstrapBase
28
30
 
29
31
  deps do
30
- require 'knife/server/ssh'
31
- require 'knife/server/credentials'
32
- require 'knife/server/ec2_security_group'
32
+ require "knife/server/ssh"
33
+ require "knife/server/credentials"
34
+ require "knife/server/ec2_security_group"
33
35
 
34
36
  begin
35
- require 'chef/knife/ec2_server_create'
36
- require 'fog'
37
+ require "chef/knife/ec2_server_create"
38
+ require "fog"
37
39
  Chef::Knife::Ec2ServerCreate.load_deps
38
40
 
39
- current_options = self.options
41
+ current_options = options
40
42
  self.options = Chef::Knife::Ec2ServerCreate.options.dup
41
- self.options.merge!(current_options)
43
+ options.merge!(current_options)
42
44
  rescue LoadError => ex
43
45
  ui.error [
44
46
  "Knife plugin knife-ec2 could not be loaded.",
@@ -55,10 +57,10 @@ class Chef
55
57
  :long => "--groups X,Y,Z",
56
58
  :description => "The security groups for this server",
57
59
  :default => ["infrastructure"],
58
- :proc => Proc.new { |groups| groups.split(',') }
60
+ :proc => proc { |groups| groups.split(",") }
59
61
 
60
62
  def run
61
- validate!
63
+ super
62
64
  config_security_group
63
65
  ec2_bootstrap.run
64
66
  fetch_validation_key
@@ -67,12 +69,13 @@ class Chef
67
69
  end
68
70
 
69
71
  def ec2_bootstrap
70
- ENV['WEBUI_PASSWORD'] = config_val(:webui_password)
71
- ENV['AMQP_PASSWORD'] = config_val(:amqp_password)
72
- ENV['NO_TEST'] = "1" if config[:no_test]
72
+ setup_environment
73
73
  bootstrap = Chef::Knife::Ec2ServerCreate.new
74
74
  Chef::Knife::Ec2ServerCreate.options.keys.each do |attr|
75
- bootstrap.config[attr] = config_val(attr)
75
+ val = config_val(attr)
76
+ next if val.nil?
77
+
78
+ bootstrap.config[attr] = val
76
79
  end
77
80
  bootstrap.config[:tags] = bootstrap_tags
78
81
  bootstrap.config[:distro] = bootstrap_distro
@@ -81,7 +84,7 @@ class Chef
81
84
 
82
85
  def ec2_connection
83
86
  @ec2_connection ||= Fog::Compute.new(
84
- :provider => 'AWS',
87
+ :provider => "AWS",
85
88
  :aws_access_key_id => config_val(:aws_access_key_id),
86
89
  :aws_secret_access_key => config_val(:aws_secret_access_key),
87
90
  :region => config_val(:region)
@@ -91,8 +94,8 @@ class Chef
91
94
  def server_dns_name
92
95
  server = ec2_connection.servers.find do |s|
93
96
  s.state == "running" &&
94
- s.tags['Name'] == config_val(:chef_node_name) &&
95
- s.tags['Role'] == 'chef_server'
97
+ s.tags["Name"] == config_val(:chef_node_name) &&
98
+ s.tags["Role"] == "chef_server"
96
99
  end
97
100
 
98
101
  server && server.dns_name
@@ -101,6 +104,8 @@ class Chef
101
104
  private
102
105
 
103
106
  def validate!
107
+ super
108
+
104
109
  if config[:chef_node_name].nil?
105
110
  ui.error "You did not provide a valid --node-name value."
106
111
  exit 1
@@ -111,8 +116,16 @@ class Chef
111
116
  end
112
117
  end
113
118
 
119
+ def setup_environment
120
+ ENV["WEBUI_PASSWORD"] = config_val(:webui_password)
121
+ ENV["AMQP_PASSWORD"] = config_val(:amqp_password)
122
+ ENV["NO_TEST"] = "1" if config[:no_test]
123
+ end
124
+
114
125
  def config_security_group(name = nil)
115
- if config[:security_group_ids].nil? || config[:security_group_ids].empty?
126
+ ids = config[:security_group_ids]
127
+
128
+ if ids.nil? || ids.empty?
116
129
  name = config_val(:security_groups).first if name.nil?
117
130
  ::Knife::Server::Ec2SecurityGroup.new(ec2_connection, ui).
118
131
  configure_chef_server_group(name, :description => "#{name} group")
@@ -122,8 +135,8 @@ class Chef
122
135
  end
123
136
 
124
137
  def bootstrap_tags
125
- Hash[Array(config_val(:tags)).map { |t| t.split('=') }].
126
- merge({"Role" => "chef_server"}).map { |k,v| "#{k}=#{v}" }
138
+ Hash[Array(config_val(:tags)).map { |t| t.split("=") }].
139
+ merge("Role" => "chef_server").map { |k, v| "#{k}=#{v}" }
127
140
  end
128
141
 
129
142
  def ssh_connection
@@ -1,3 +1,4 @@
1
+ # -*- encoding: utf-8 -*-
1
2
  #
2
3
  # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
3
4
  # Copyright:: Copyright (c) 2013 Fletcher Nichol
@@ -16,10 +17,11 @@
16
17
  # limitations under the License.
17
18
  #
18
19
 
19
- require 'chef/knife/server_bootstrap_base'
20
+ require "chef/knife/server_bootstrap_base"
20
21
 
21
22
  class Chef
22
23
  class Knife
24
+ # Provisions a Linode instance and sets up an Open Source Chef Server.
23
25
  class ServerBootstrapLinode < Knife
24
26
 
25
27
  banner "knife server bootstrap linode (options)"
@@ -27,17 +29,17 @@ class Chef
27
29
  include Knife::ServerBootstrapBase
28
30
 
29
31
  deps do
30
- require 'knife/server/ssh'
31
- require 'knife/server/credentials'
32
+ require "knife/server/ssh"
33
+ require "knife/server/credentials"
32
34
 
33
35
  begin
34
- require 'chef/knife/linode_server_create'
35
- require 'fog'
36
+ require "chef/knife/linode_server_create"
37
+ require "fog"
36
38
  Chef::Knife::LinodeServerCreate.load_deps
37
39
 
38
- current_options = self.options
40
+ current_options = options
39
41
  self.options = Chef::Knife::LinodeServerCreate.options.dup
40
- self.options.merge!(current_options)
42
+ options.merge!(current_options)
41
43
  rescue LoadError => ex
42
44
  ui.error [
43
45
  "Knife plugin knife-linode could not be loaded.",
@@ -50,7 +52,7 @@ class Chef
50
52
  end
51
53
 
52
54
  def run
53
- validate!
55
+ super
54
56
  linode_bootstrap.run
55
57
  fetch_validation_key
56
58
  create_root_client
@@ -58,12 +60,15 @@ class Chef
58
60
  end
59
61
 
60
62
  def linode_bootstrap
61
- ENV['WEBUI_PASSWORD'] = config_val(:webui_password)
62
- ENV['AMQP_PASSWORD'] = config_val(:amqp_password)
63
- ENV['NO_TEST'] = "1" if config[:no_test]
63
+ ENV["WEBUI_PASSWORD"] = config_val(:webui_password)
64
+ ENV["AMQP_PASSWORD"] = config_val(:amqp_password)
65
+ ENV["NO_TEST"] = "1" if config[:no_test]
64
66
  bootstrap = Chef::Knife::LinodeServerCreate.new
65
67
  Chef::Knife::LinodeServerCreate.options.keys.each do |attr|
66
- bootstrap.config[attr] = config_val(attr)
68
+ val = config_val(attr)
69
+ next if val.nil?
70
+
71
+ bootstrap.config[attr] = val
67
72
  end
68
73
  bootstrap.config[:distro] = bootstrap_distro
69
74
  bootstrap
@@ -71,7 +76,7 @@ class Chef
71
76
 
72
77
  def linode_connection
73
78
  @linode_connection ||= Fog::Compute.new(
74
- :provider => 'Linode',
79
+ :provider => "Linode",
75
80
  :linode_api_key => config_val(:linode_api_key)
76
81
  )
77
82
  end
@@ -87,6 +92,8 @@ class Chef
87
92
  private
88
93
 
89
94
  def validate!
95
+ super
96
+
90
97
  if config[:chef_node_name].nil?
91
98
  ui.error "You did not provide a valid --node-name value."
92
99
  exit 1