knife-server 1.1.0 → 1.2.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.
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