chef-config 13.6.4 → 13.7.16
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/chef-config.gemspec +1 -0
- data/lib/chef-config/config.rb +10 -0
- data/lib/chef-config/mixin/credentials.rb +57 -0
- data/lib/chef-config/path_helper.rb +1 -1
- data/lib/chef-config/version.rb +1 -1
- data/lib/chef-config/workstation_config_loader.rb +42 -2
- data/spec/unit/workstation_config_loader_spec.rb +144 -0
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c1d509df602bb95a13b5ac06864f420dd0ae1fcf
|
4
|
+
data.tar.gz: 4924ec21b6dc5c39efd835550d022df3555e0625
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c2fbec33c4d7f638e18f55021bb13f9accfe0e5dfedd1c25b0c0cf7f9d04518949ba1ea39ac48422eb00fd8cbfad91661e7704b457aba4c2ebaf0988cc76e58e
|
7
|
+
data.tar.gz: 279f3af2f42c46c910215a5580032e7c90edde23ee9af3bc017ae58b66596fe3c160e3f222d29c27d16b133f4d38d36da5bdbe73762672a19f4e8e0c1ba70f18
|
data/chef-config.gemspec
CHANGED
data/lib/chef-config/config.rb
CHANGED
@@ -592,6 +592,12 @@ module ChefConfig
|
|
592
592
|
# If chef-zero is enabled, this defaults to nil (no authentication).
|
593
593
|
default(:client_key) { chef_zero.enabled ? nil : platform_specific_path("/etc/chef/client.pem") }
|
594
594
|
|
595
|
+
# A credentials file may contain a complete client key, rather than the path
|
596
|
+
# to one.
|
597
|
+
#
|
598
|
+
# We'll use this preferentially.
|
599
|
+
default :client_key_contents, nil
|
600
|
+
|
595
601
|
# When registering the client, should we allow the client key location to
|
596
602
|
# be a symlink? eg: /etc/chef/client.pem -> /etc/chef/prod-client.pem
|
597
603
|
# If the path of the key goes through a directory like /tmp this should
|
@@ -631,6 +637,7 @@ module ChefConfig
|
|
631
637
|
default(:validation_key) { chef_zero.enabled ? nil : platform_specific_path("/etc/chef/validation.pem") }
|
632
638
|
default :validation_client_name, "chef-validator"
|
633
639
|
|
640
|
+
default :validation_key_contents, nil
|
634
641
|
# When creating a new client via the validation_client account, Chef 11
|
635
642
|
# servers allow the client to generate a key pair locally and send the
|
636
643
|
# public key to the server. This is more secure and helps offload work from
|
@@ -691,6 +698,9 @@ module ChefConfig
|
|
691
698
|
# on running chef-client
|
692
699
|
default :count_log_resource_updates, true
|
693
700
|
|
701
|
+
# The selected profile when using credentials.
|
702
|
+
default :profile, nil
|
703
|
+
|
694
704
|
# knife configuration data
|
695
705
|
config_context :knife do
|
696
706
|
# XXX: none of these default values are applied to knife (and would create a backcompat
|
@@ -0,0 +1,57 @@
|
|
1
|
+
#
|
2
|
+
# Copyright:: Copyright 2017, Chef Software, Inc.
|
3
|
+
# License:: Apache License, Version 2.0
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
18
|
+
require "tomlrb"
|
19
|
+
require "chef-config/path_helper"
|
20
|
+
|
21
|
+
module ChefConfig
|
22
|
+
module Mixin
|
23
|
+
module Credentials
|
24
|
+
|
25
|
+
def load_credentials(profile = nil)
|
26
|
+
credentials_file = PathHelper.home(".chef", "credentials").freeze
|
27
|
+
context_file = PathHelper.home(".chef", "context").freeze
|
28
|
+
|
29
|
+
return unless File.file?(credentials_file)
|
30
|
+
|
31
|
+
context = File.read(context_file) if File.file?(context_file)
|
32
|
+
|
33
|
+
environment = ENV.fetch("CHEF_PROFILE", nil)
|
34
|
+
|
35
|
+
profile = if !profile.nil?
|
36
|
+
profile
|
37
|
+
elsif !environment.nil?
|
38
|
+
environment
|
39
|
+
elsif !context.nil?
|
40
|
+
context
|
41
|
+
else
|
42
|
+
"default"
|
43
|
+
end
|
44
|
+
|
45
|
+
config = Tomlrb.load_file(credentials_file)
|
46
|
+
apply_credentials(config[profile], profile)
|
47
|
+
rescue ChefConfig::ConfigurationError
|
48
|
+
raise
|
49
|
+
rescue => e
|
50
|
+
# TOML's error messages are mostly rubbish, so we'll just give a generic one
|
51
|
+
message = "Unable to parse Credentials file: #{credentials_file}\n"
|
52
|
+
message << e.message
|
53
|
+
raise ChefConfig::ConfigurationError, message
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -235,7 +235,7 @@ module ChefConfig
|
|
235
235
|
paths = paths.map { |home_path| home_path.gsub(path_separator, ::File::SEPARATOR) if home_path }
|
236
236
|
|
237
237
|
# Filter out duplicate paths and paths that don't exist.
|
238
|
-
valid_paths = paths.select { |home_path| home_path && Dir.
|
238
|
+
valid_paths = paths.select { |home_path| home_path && Dir.exist?(home_path.force_encoding("utf-8")) }
|
239
239
|
valid_paths = valid_paths.uniq
|
240
240
|
|
241
241
|
# Join all optional path elements at the end.
|
data/lib/chef-config/version.rb
CHANGED
@@ -22,24 +22,31 @@ require "chef-config/logger"
|
|
22
22
|
require "chef-config/path_helper"
|
23
23
|
require "chef-config/windows"
|
24
24
|
require "chef-config/mixin/dot_d"
|
25
|
+
require "chef-config/mixin/credentials"
|
25
26
|
|
26
27
|
module ChefConfig
|
27
28
|
class WorkstationConfigLoader
|
28
29
|
include ChefConfig::Mixin::DotD
|
30
|
+
include ChefConfig::Mixin::Credentials
|
29
31
|
|
30
32
|
# Path to a config file requested by user, (e.g., via command line option). Can be nil
|
31
33
|
attr_accessor :explicit_config_file
|
34
|
+
# The name of a credentials profile. Can be nil
|
35
|
+
attr_accessor :profile
|
36
|
+
attr_reader :credentials_found
|
32
37
|
|
33
38
|
# TODO: initialize this with a logger for Chef and Knife
|
34
|
-
def initialize(explicit_config_file, logger = nil)
|
39
|
+
def initialize(explicit_config_file, logger = nil, profile: nil)
|
35
40
|
@explicit_config_file = explicit_config_file
|
36
41
|
@chef_config_dir = nil
|
37
42
|
@config_location = nil
|
43
|
+
@profile = profile
|
38
44
|
@logger = logger || NullLogger.new
|
45
|
+
@credentials_found = false
|
39
46
|
end
|
40
47
|
|
41
48
|
def no_config_found?
|
42
|
-
config_location.nil?
|
49
|
+
config_location.nil? && !credentials_found
|
43
50
|
end
|
44
51
|
|
45
52
|
def config_location
|
@@ -62,6 +69,7 @@ module ChefConfig
|
|
62
69
|
end
|
63
70
|
|
64
71
|
def load
|
72
|
+
load_credentials(profile)
|
65
73
|
# Ignore it if there's no explicit_config_file and can't find one at a
|
66
74
|
# default path.
|
67
75
|
if !config_location.nil?
|
@@ -138,6 +146,38 @@ module ChefConfig
|
|
138
146
|
a
|
139
147
|
end
|
140
148
|
|
149
|
+
def apply_credentials(creds, profile)
|
150
|
+
Config.profile ||= profile
|
151
|
+
if creds.key?("node_name") && creds.key?("client_name")
|
152
|
+
raise ChefConfig::ConfigurationError, "Do not specify both node_name and client_name. You should prefer client_name."
|
153
|
+
end
|
154
|
+
Config.node_name = creds.fetch("node_name") if creds.key?("node_name")
|
155
|
+
Config.node_name = creds.fetch("client_name") if creds.key?("client_name")
|
156
|
+
Config.chef_server_url = creds.fetch("chef_server_url") if creds.key?("chef_server_url")
|
157
|
+
Config.validation_client_name = creds.fetch("validation_client_name") if creds.key?("validation_client_name")
|
158
|
+
|
159
|
+
extract_key(creds, "validation_key", :validation_key, :validation_key_contents)
|
160
|
+
extract_key(creds, "validator_key", :validation_key, :validation_key_contents)
|
161
|
+
extract_key(creds, "client_key", :client_key, :client_key_contents)
|
162
|
+
@credentials_found = true
|
163
|
+
end
|
164
|
+
|
165
|
+
def extract_key(creds, name, config_path, config_contents)
|
166
|
+
return unless creds.has_key?(name)
|
167
|
+
|
168
|
+
val = creds.fetch(name)
|
169
|
+
if val.start_with?("-----BEGIN RSA PRIVATE KEY-----")
|
170
|
+
Config.send(config_contents, val)
|
171
|
+
else
|
172
|
+
abs_path = Pathname.new(val).expand_path(home_chef_dir)
|
173
|
+
Config.send(config_path, abs_path)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def home_chef_dir
|
178
|
+
@home_chef_dir ||= PathHelper.home(".chef")
|
179
|
+
end
|
180
|
+
|
141
181
|
def apply_config(config_content, config_file_path)
|
142
182
|
Config.from_string(config_content, config_file_path)
|
143
183
|
rescue SignalException
|
@@ -38,6 +38,7 @@ RSpec.describe ChefConfig::WorkstationConfigLoader do
|
|
38
38
|
before do
|
39
39
|
# We set this to nil so that a dev workstation will
|
40
40
|
# not interfere with the tests.
|
41
|
+
ChefConfig::Config.reset
|
41
42
|
ChefConfig::Config[:config_d_dir] = nil
|
42
43
|
end
|
43
44
|
|
@@ -363,4 +364,147 @@ RSpec.describe ChefConfig::WorkstationConfigLoader do
|
|
363
364
|
end
|
364
365
|
end
|
365
366
|
end
|
367
|
+
|
368
|
+
describe "when loading a credentials file" do
|
369
|
+
if ChefConfig.windows?
|
370
|
+
let(:home) { "C:/Users/example.user" }
|
371
|
+
else
|
372
|
+
let(:home) { "/Users/example.user" }
|
373
|
+
end
|
374
|
+
let(:credentials_file) { "#{home}/.chef/credentials" }
|
375
|
+
let(:context_file) { "#{home}/.chef/context" }
|
376
|
+
|
377
|
+
before do
|
378
|
+
allow(ChefConfig::PathHelper).to receive(:home).with(".chef").and_return(File.join(home, ".chef"))
|
379
|
+
allow(ChefConfig::PathHelper).to receive(:home).with(".chef", "credentials").and_return(credentials_file)
|
380
|
+
allow(ChefConfig::PathHelper).to receive(:home).with(".chef", "context").and_return(context_file)
|
381
|
+
allow(File).to receive(:file?).with(context_file).and_return false
|
382
|
+
end
|
383
|
+
|
384
|
+
context "when the file exists" do
|
385
|
+
before do
|
386
|
+
expect(File).to receive(:read).with(credentials_file, { encoding: "utf-8" }).and_return(content)
|
387
|
+
allow(File).to receive(:file?).with(credentials_file).and_return true
|
388
|
+
end
|
389
|
+
|
390
|
+
context "and has a default profile" do
|
391
|
+
let(:content) do
|
392
|
+
content = <<EOH
|
393
|
+
[default]
|
394
|
+
node_name = 'barney'
|
395
|
+
client_key = "barney_rubble.pem"
|
396
|
+
chef_server_url = "https://api.chef.io/organizations/bedrock"
|
397
|
+
EOH
|
398
|
+
content
|
399
|
+
end
|
400
|
+
|
401
|
+
it "applies the expected config" do
|
402
|
+
expect { config_loader.load_credentials }.not_to raise_error
|
403
|
+
expect(ChefConfig::Config.chef_server_url).to eq("https://api.chef.io/organizations/bedrock")
|
404
|
+
expect(ChefConfig::Config.client_key.to_s).to eq("#{home}/.chef/barney_rubble.pem")
|
405
|
+
expect(ChefConfig::Config.profile.to_s).to eq("default")
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
context "and has a profile containing a full key" do
|
410
|
+
let(:content) do
|
411
|
+
content = <<EOH
|
412
|
+
[default]
|
413
|
+
client_key = """
|
414
|
+
-----BEGIN RSA PRIVATE KEY-----
|
415
|
+
foo
|
416
|
+
"""
|
417
|
+
EOH
|
418
|
+
content
|
419
|
+
end
|
420
|
+
|
421
|
+
it "applies the expected config" do
|
422
|
+
expect { config_loader.load_credentials }.not_to raise_error
|
423
|
+
expect(ChefConfig::Config.client_key_contents).to eq(<<EOH
|
424
|
+
-----BEGIN RSA PRIVATE KEY-----
|
425
|
+
foo
|
426
|
+
EOH
|
427
|
+
)
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
context "and has several profiles" do
|
432
|
+
let(:content) do
|
433
|
+
content = <<EOH
|
434
|
+
[default]
|
435
|
+
client_name = "default"
|
436
|
+
[environment]
|
437
|
+
client_name = "environment"
|
438
|
+
[explicit]
|
439
|
+
client_name = "explicit"
|
440
|
+
[context]
|
441
|
+
client_name = "context"
|
442
|
+
EOH
|
443
|
+
content
|
444
|
+
end
|
445
|
+
|
446
|
+
let(:env) { {} }
|
447
|
+
before do
|
448
|
+
stub_const("ENV", env)
|
449
|
+
end
|
450
|
+
|
451
|
+
it "selects the correct profile explicitly" do
|
452
|
+
expect { config_loader.load_credentials("explicit") }.not_to raise_error
|
453
|
+
expect(ChefConfig::Config.node_name).to eq("explicit")
|
454
|
+
end
|
455
|
+
|
456
|
+
context "with an environment variable" do
|
457
|
+
let(:env) { { "CHEF_PROFILE" => "environment" } }
|
458
|
+
|
459
|
+
it "selects the correct profile" do
|
460
|
+
expect { config_loader.load_credentials }.not_to raise_error
|
461
|
+
expect(ChefConfig::Config.node_name).to eq("environment")
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
465
|
+
it "selects the correct profile with a context file" do
|
466
|
+
allow(File).to receive(:file?).with(context_file).and_return true
|
467
|
+
expect(File).to receive(:read).with(context_file).and_return "context"
|
468
|
+
expect { config_loader.load_credentials }.not_to raise_error
|
469
|
+
expect(ChefConfig::Config.node_name).to eq("context")
|
470
|
+
end
|
471
|
+
|
472
|
+
it "falls back to the default" do
|
473
|
+
expect { config_loader.load_credentials }.not_to raise_error
|
474
|
+
expect(ChefConfig::Config.node_name).to eq("default")
|
475
|
+
end
|
476
|
+
end
|
477
|
+
|
478
|
+
context "and contains both node_name and client_name" do
|
479
|
+
let(:content) do
|
480
|
+
content = <<EOH
|
481
|
+
[default]
|
482
|
+
node_name = 'barney'
|
483
|
+
client_name = 'barney'
|
484
|
+
EOH
|
485
|
+
content
|
486
|
+
end
|
487
|
+
|
488
|
+
it "raises a ConfigurationError" do
|
489
|
+
expect { config_loader.load_credentials }.to raise_error(ChefConfig::ConfigurationError)
|
490
|
+
end
|
491
|
+
end
|
492
|
+
|
493
|
+
context "and has a syntax error" do
|
494
|
+
let(:content) { "<<<<<" }
|
495
|
+
|
496
|
+
it "raises a ConfigurationError" do
|
497
|
+
expect { config_loader.load_credentials }.to raise_error(ChefConfig::ConfigurationError)
|
498
|
+
end
|
499
|
+
end
|
500
|
+
end
|
501
|
+
|
502
|
+
context "when the file does not exist" do
|
503
|
+
it "does not load anything" do
|
504
|
+
allow(File).to receive(:file?).with(credentials_file).and_return false
|
505
|
+
expect(Tomlrb).not_to receive(:load_file)
|
506
|
+
config_loader.load_credentials
|
507
|
+
end
|
508
|
+
end
|
509
|
+
end
|
366
510
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chef-config
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 13.
|
4
|
+
version: 13.7.16
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Jacob
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-01-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mixlib-shellout
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: tomlrb
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.2'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.2'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: rake
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -138,6 +152,7 @@ files:
|
|
138
152
|
- lib/chef-config/exceptions.rb
|
139
153
|
- lib/chef-config/fips.rb
|
140
154
|
- lib/chef-config/logger.rb
|
155
|
+
- lib/chef-config/mixin/credentials.rb
|
141
156
|
- lib/chef-config/mixin/dot_d.rb
|
142
157
|
- lib/chef-config/mixin/fuzzy_hostname_matcher.rb
|
143
158
|
- lib/chef-config/package_task.rb
|