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.
- checksums.yaml +4 -4
- data/.cane +1 -0
- data/.rspec +1 -0
- data/.rubocop.yml +3 -0
- data/.travis.yml +12 -8
- data/CHANGELOG.md +32 -1
- data/Gemfile +9 -4
- data/Guardfile +28 -0
- data/README.md +28 -5
- data/Rakefile +31 -10
- data/knife-server.gemspec +18 -8
- data/lib/chef/knife/bootstrap/_omnibus.sh +63 -10
- data/lib/chef/knife/bootstrap/chef10/rhel.erb +2 -0
- data/lib/chef/knife/bootstrap/chef11/omnibus.erb +4 -1
- data/lib/chef/knife/bootstrap/chef11/rhel.erb +2 -0
- data/lib/chef/knife/server_backup.rb +24 -10
- data/lib/chef/knife/server_bootstrap_base.rb +68 -23
- data/lib/chef/knife/server_bootstrap_ec2.rb +33 -20
- data/lib/chef/knife/server_bootstrap_linode.rb +20 -13
- data/lib/chef/knife/server_bootstrap_openstack.rb +128 -0
- data/lib/chef/knife/server_bootstrap_standalone.rb +28 -16
- data/lib/chef/knife/server_restore.rb +23 -9
- data/lib/knife-server.rb +1 -0
- data/lib/knife/server/credentials.rb +78 -42
- data/lib/knife/server/ec2_security_group.rb +24 -21
- data/lib/knife/server/ssh.rb +54 -18
- data/lib/knife/server/version.rb +2 -1
- data/spec/chef/knife/server_backup_spec.rb +58 -44
- data/spec/chef/knife/server_bootstrap_ec2_spec.rb +108 -80
- data/spec/chef/knife/server_bootstrap_linode_spec.rb +93 -64
- data/spec/chef/knife/server_bootstrap_openstack_spec.rb +305 -0
- data/spec/chef/knife/server_bootstrap_standalone_spec.rb +113 -76
- data/spec/chef/knife/server_restore_spec.rb +38 -37
- data/spec/knife/server/credientials_spec.rb +248 -51
- data/spec/knife/server/ec2_security_group_spec.rb +76 -68
- data/spec/knife/server/ssh_spec.rb +138 -22
- metadata +107 -31
@@ -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
|
@@ -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
|
20
|
-
require
|
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
|
28
|
-
require
|
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" => {
|
64
|
-
|
65
|
-
|
66
|
-
|
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,
|
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,
|
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
|
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
|
30
|
-
require
|
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
|
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
|
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,
|
47
|
-
|
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,
|
57
|
-
|
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,
|
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
|
74
|
-
|
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
|
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,
|
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
|
-
|
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
|
-
|
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(
|
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
|
159
|
-
raise "Could not determine the OS running the target for
|
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
|
-
|
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
|
-
|
168
|
-
config
|
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
|
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
|
31
|
-
require
|
32
|
-
require
|
32
|
+
require "knife/server/ssh"
|
33
|
+
require "knife/server/credentials"
|
34
|
+
require "knife/server/ec2_security_group"
|
33
35
|
|
34
36
|
begin
|
35
|
-
require
|
36
|
-
require
|
37
|
+
require "chef/knife/ec2_server_create"
|
38
|
+
require "fog"
|
37
39
|
Chef::Knife::Ec2ServerCreate.load_deps
|
38
40
|
|
39
|
-
current_options =
|
41
|
+
current_options = options
|
40
42
|
self.options = Chef::Knife::Ec2ServerCreate.options.dup
|
41
|
-
|
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 =>
|
60
|
+
:proc => proc { |groups| groups.split(",") }
|
59
61
|
|
60
62
|
def run
|
61
|
-
|
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
|
-
|
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
|
-
|
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 =>
|
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[
|
95
|
-
s.tags[
|
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
|
-
|
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(
|
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
|
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
|
31
|
-
require
|
32
|
+
require "knife/server/ssh"
|
33
|
+
require "knife/server/credentials"
|
32
34
|
|
33
35
|
begin
|
34
|
-
require
|
35
|
-
require
|
36
|
+
require "chef/knife/linode_server_create"
|
37
|
+
require "fog"
|
36
38
|
Chef::Knife::LinodeServerCreate.load_deps
|
37
39
|
|
38
|
-
current_options =
|
40
|
+
current_options = options
|
39
41
|
self.options = Chef::Knife::LinodeServerCreate.options.dup
|
40
|
-
|
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
|
-
|
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[
|
62
|
-
ENV[
|
63
|
-
ENV[
|
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
|
-
|
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 =>
|
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
|