chef-config 13.6.4 → 13.7.16
Sign up to get free protection for your applications and to get access to all the features.
- 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
|