r10k 2.2.2 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.mkd +25 -0
  3. data/Gemfile +1 -1
  4. data/doc/dynamic-environments/configuration.mkd +36 -11
  5. data/integration/tests/basic_functionality/proxy_with_pe_only_module.rb +128 -0
  6. data/lib/r10k/errors.rb +18 -0
  7. data/lib/r10k/forge/module_release.rb +3 -3
  8. data/lib/r10k/git.rb +53 -0
  9. data/lib/r10k/git/rugged/bare_repository.rb +16 -7
  10. data/lib/r10k/git/rugged/base_repository.rb +16 -2
  11. data/lib/r10k/git/rugged/credentials.rb +9 -0
  12. data/lib/r10k/git/rugged/working_repository.rb +18 -5
  13. data/lib/r10k/git/shellgit/bare_repository.rb +12 -3
  14. data/lib/r10k/git/shellgit/base_repository.rb +19 -3
  15. data/lib/r10k/git/shellgit/working_repository.rb +13 -3
  16. data/lib/r10k/initializers.rb +1 -0
  17. data/lib/r10k/settings.rb +41 -22
  18. data/lib/r10k/settings/collection.rb +25 -21
  19. data/lib/r10k/settings/definition.rb +14 -2
  20. data/lib/r10k/settings/helpers.rb +38 -0
  21. data/lib/r10k/settings/list.rb +107 -0
  22. data/lib/r10k/util/symbolize_keys.rb +6 -2
  23. data/lib/r10k/version.rb +1 -1
  24. data/r10k.gemspec +1 -1
  25. data/r10k.yaml.example +38 -12
  26. data/spec/shared-examples/git/bare_repository.rb +62 -0
  27. data/spec/shared-examples/git/working_repository.rb +57 -11
  28. data/spec/shared-examples/settings/ancestry.rb +44 -0
  29. data/spec/unit/forge/module_release_spec.rb +1 -1
  30. data/spec/unit/git/rugged/credentials_spec.rb +6 -0
  31. data/spec/unit/settings/collection_spec.rb +2 -1
  32. data/spec/unit/settings/definition_spec.rb +6 -5
  33. data/spec/unit/settings/inheritance_spec.rb +38 -0
  34. data/spec/unit/settings/list_spec.rb +88 -0
  35. data/spec/unit/settings_spec.rb +52 -23
  36. data/spec/unit/util/attempt_spec.rb +1 -1
  37. data/spec/unit/util/symbolize_keys_spec.rb +25 -9
  38. metadata +11 -4
@@ -21,8 +21,12 @@ module R10K
21
21
  end
22
22
 
23
23
  value = hash[key]
24
- if recurse && value.is_a?(Hash)
25
- symbolize_keys!(value, true)
24
+ if recurse
25
+ if value.is_a?(Hash)
26
+ symbolize_keys!(value, true)
27
+ elsif value.is_a?(Array)
28
+ value.map { |item| symbolize_keys!(item, true) if item.is_a?(Hash) }
29
+ end
26
30
  end
27
31
  end
28
32
  end
@@ -1,3 +1,3 @@
1
1
  module R10K
2
- VERSION = '2.2.2'
2
+ VERSION = '2.3.0'
3
3
  end
@@ -28,7 +28,7 @@ Gem::Specification.new do |s|
28
28
  s.add_dependency 'log4r', '1.1.10'
29
29
  s.add_dependency 'multi_json', '~> 1.10'
30
30
 
31
- s.add_dependency 'puppet_forge', '~> 2.1.5'
31
+ s.add_dependency 'puppet_forge', '~> 2.2'
32
32
  s.add_dependency 'semantic_puppet', '~> 0.1.0'
33
33
  s.add_dependency 'minitar'
34
34
 
@@ -9,18 +9,25 @@
9
9
  # be updated.
10
10
  #
11
11
  # The default value is "~/.r10k"
12
- cachedir: '/var/cache/r10k'
12
+ #cachedir: '/var/cache/r10k'
13
+
14
+ # The 'proxy' setting configures an HTTP proxy to use for all HTTP/HTTPS
15
+ # operations performed by r10k. This includes requests to the Puppet Forge
16
+ # as well as any Git operations performed against an HTTP/HTTPS remote.
17
+ # You can also configure specific proxies for only Git or Forge operations
18
+ # using settings below. Authenticated proxies can be configured by providing
19
+ # credentials in the URL, e.g. 'https://username:password@proxy.example.com:8888'
20
+ #proxy: 'https://proxy.example.com:8888'
13
21
 
14
22
  # The 'sources' setting determines what repositories r10k will use when creating
15
23
  # Puppet environments.
16
24
  sources:
17
25
  # Each source should have a unique name, and preferrably should only use
18
26
  # alphanumeric characters and underscores.
19
- operations:
20
-
27
+ #operations:
21
28
  # The 'remote' setting determines the location of the VCS repository used
22
29
  # for creating environments.
23
- remote: 'git@github.com:my-org/org-operations-modules'
30
+ #remote: 'git@github.com:my-org/org-operations-modules'
24
31
 
25
32
  # The 'basedir' setting specifies where environments will be created for
26
33
  # this source. This setting should match the Puppet 'environmentpath'
@@ -28,19 +35,19 @@ sources:
28
35
  #
29
36
  # See http://docs.puppetlabs.com/references/latest/configuration.html#environmentpath
30
37
  # for more information about the Puppet 'environmentpath' setting.
31
- basedir: '/etc/puppetlabs/puppet/environments'
38
+ #basedir: '/etc/puppetlabs/puppet/environments'
32
39
 
33
40
  # One or more sources can be specified; each source is simple another entry
34
41
  # in the sources map.
35
- qa:
36
- remote: 'git@github.com:my-org/org-qa-modules'
42
+ #qa:
43
+ #remote: 'git@github.com:my-org/org-qa-modules'
37
44
 
38
45
  # Multiple sources can have the same 'basedir' setting, in case there is a
39
46
  # reason to push different sets of environments to the same Puppet master.
40
47
  # If two different sources have the same basedir care should be exercised
41
48
  # to make sure that two sources don't try create multiple environments with
42
49
  # the same name. See the 'prefix' setting for more information.
43
- basedir: '/etc/puppetlabs/puppet/environments'
50
+ #basedir: '/etc/puppetlabs/puppet/environments'
44
51
 
45
52
  # Sources can use the 'prefix' setting to avoid collisions between multiple
46
53
  # sources being created in the same directory. Setting prefix to true
@@ -49,7 +56,7 @@ sources:
49
56
  # branch.
50
57
  #
51
58
  # The default value is 'false'.
52
- prefix: true
59
+ #prefix: true
53
60
 
54
61
  # Additional configuration can be supplied to configure how r10k uses Git
55
62
  # and what version of Git it uses.
@@ -58,7 +65,7 @@ git:
58
65
  # As of 1.5.0 r10k can interact with Git repositories in two ways - by
59
66
  # shelling out to the 'git' executable, and by using libgit2 through the
60
67
  # 'rugged' library.
61
- provider: 'shellgit' # Either 'shellgit' or 'rugged', defaults to 'shellgit'
68
+ #provider: 'shellgit' # Either 'shellgit' or 'rugged', defaults to 'shellgit'
62
69
 
63
70
  # The 'private_key' setting sets the the SSH private key to use for remote
64
71
  # Git repositories accessed over SSH.
@@ -73,8 +80,27 @@ git:
73
80
  # The 'username' setting is only used by the 'rugged' Git provider.
74
81
  #username: 'git'
75
82
 
83
+ # The 'proxy' setting configures an HTTP proxy to use for all Git sources
84
+ # that have an HTTP/HTTPS remote URL. This can be overridden on a
85
+ # per-repository basis using the 'repositories' setting below.
86
+ #proxy: 'https://proxy.example.com:8888'
87
+
88
+ # The 'repositories' setting allows other git related settings to be
89
+ # configured for each remote repository individually. The value of
90
+ # this setting should be a list of repositories with a 'remote' key
91
+ # to identify the specific repository to be configured.
92
+ #repositories:
93
+ # - remote: "ssh://tessier-ashpool.freeside/protected-repo.git"
94
+ # private_key: "/etc/puppetlabs/r10k/ssh/id_rsa-protected-repo-deploy-key"
95
+ # proxy: 'https://proxy.example.com:8888'
96
+
76
97
  # Configuration options for downloading modules from the Puppet Forge
77
98
  forge:
78
99
  # The 'proxy' setting specifies an optional HTTP proxy to use when making
79
- # requests to the Puppet Forge.
80
- proxy: 'http://my.site.proxy:3128'
100
+ # requests to the Puppet Forge. This will override the top level 'proxy'
101
+ # option or any proxy related environment variables when configured.
102
+ #proxy: 'https://proxy.example.com:8888'
103
+
104
+ # The 'baseurl' setting indicates where Forge modules should be installed
105
+ # from. This defaults to 'https://forgeapi.puppetlabs.com'
106
+ #baseurl: 'https://forgemirror.example.com'
@@ -17,6 +17,37 @@ RSpec.shared_examples "a git bare repository" do
17
17
  config = File.read(File.join(basedir, dirname, 'config'))
18
18
  expect(config).to match(remote)
19
19
  end
20
+
21
+ context "without a proxy" do
22
+ before(:each) do
23
+ allow(R10K::Git).to receive(:get_proxy_for_remote).with(remote).and_return(nil)
24
+ end
25
+
26
+ it 'does not change proxy ENV' do
27
+ expect(ENV).to_not receive(:[]=)
28
+ expect(ENV).to_not receive(:update)
29
+
30
+ subject.clone(remote)
31
+ end
32
+ end
33
+
34
+ context "with a proxy" do
35
+ before(:each) do
36
+ allow(R10K::Git).to receive(:get_proxy_for_remote).with(remote).and_return('http://proxy.example.com:3128')
37
+ end
38
+
39
+ it "manages proxy-related ENV vars" do
40
+ # Sets proxy settings.
41
+ ['HTTPS_PROXY', 'https_proxy', 'HTTP_PROXY', 'http_proxy'].each do |var|
42
+ expect(ENV).to receive(:[]=).with(var, 'http://proxy.example.com:3128')
43
+ end
44
+
45
+ # Resets proxy settings when done.
46
+ expect(ENV).to receive(:update).with(hash_including('HTTPS_PROXY' => nil))
47
+
48
+ subject.clone(remote)
49
+ end
50
+ end
20
51
  end
21
52
 
22
53
  describe "updating the repo" do
@@ -34,6 +65,37 @@ RSpec.shared_examples "a git bare repository" do
34
65
  subject.fetch
35
66
  expect(subject.tags).to include('0.9.0')
36
67
  end
68
+
69
+ context "without a proxy" do
70
+ before(:each) do
71
+ allow(R10K::Git).to receive(:get_proxy_for_remote).with(remote).and_return(nil)
72
+ end
73
+
74
+ it 'does not change proxy ENV' do
75
+ expect(ENV).to_not receive(:[]=)
76
+ expect(ENV).to_not receive(:update)
77
+
78
+ subject.fetch
79
+ end
80
+ end
81
+
82
+ context "with a proxy" do
83
+ before(:each) do
84
+ allow(R10K::Git).to receive(:get_proxy_for_remote).with(remote).and_return('http://proxy.example.com:3128')
85
+ end
86
+
87
+ it "manages proxy-related ENV vars" do
88
+ # Sets proxy settings.
89
+ ['HTTPS_PROXY', 'https_proxy', 'HTTP_PROXY', 'http_proxy'].each do |var|
90
+ expect(ENV).to receive(:[]=).with(var, 'http://proxy.example.com:3128')
91
+ end
92
+
93
+ # Resets proxy settings when done.
94
+ expect(ENV).to receive(:update).with(hash_including('HTTPS_PROXY' => nil))
95
+
96
+ subject.fetch
97
+ end
98
+ end
37
99
  end
38
100
 
39
101
  describe "listing branches" do
@@ -57,21 +57,36 @@ RSpec.shared_examples "a git working repository" do
57
57
  expect(alternates[0]).to match_realpath File.join(remote, 'objects')
58
58
  end
59
59
  end
60
- end
61
60
 
62
- describe "updating the repo" do
63
- let(:tag_090) { subject.git_dir + 'refs' + 'tags' + '0.9.0' }
64
- let(:packed_refs) { subject.git_dir + 'packed-refs' }
61
+ context "without a proxy" do
62
+ before(:each) do
63
+ allow(R10K::Git).to receive(:get_proxy_for_remote).with(remote).and_return(nil)
64
+ end
65
65
 
66
- before do
67
- subject.clone(remote)
68
- tag_090.delete if tag_090.exist?
69
- packed_refs.delete if packed_refs.exist?
66
+ it 'does not change proxy ENV' do
67
+ expect(ENV).to_not receive(:[]=)
68
+ expect(ENV).to_not receive(:update)
69
+
70
+ subject.clone(remote)
71
+ end
70
72
  end
71
73
 
72
- it "fetches objects from the remote" do
73
- subject.fetch
74
- expect(subject.tags).to include('0.9.0')
74
+ context "with a proxy" do
75
+ before(:each) do
76
+ allow(R10K::Git).to receive(:get_proxy_for_remote).with(remote).and_return('http://proxy.example.com:3128')
77
+ end
78
+
79
+ it "manages proxy-related ENV vars" do
80
+ # Sets proxy settings.
81
+ ['HTTPS_PROXY', 'https_proxy', 'HTTP_PROXY', 'http_proxy'].each do |var|
82
+ expect(ENV).to receive(:[]=).with(var, 'http://proxy.example.com:3128')
83
+ end
84
+
85
+ # Resets proxy settings when done.
86
+ expect(ENV).to receive(:update).with(hash_including('HTTPS_PROXY' => nil))
87
+
88
+ subject.clone(remote)
89
+ end
75
90
  end
76
91
  end
77
92
 
@@ -90,6 +105,37 @@ RSpec.shared_examples "a git working repository" do
90
105
  subject.fetch
91
106
  expect(subject.tags).to include('0.9.0')
92
107
  end
108
+
109
+ context "without a proxy" do
110
+ before(:each) do
111
+ allow(R10K::Git).to receive(:get_proxy_for_remote).with(remote).and_return(nil)
112
+ end
113
+
114
+ it 'does not change proxy ENV' do
115
+ expect(ENV).to_not receive(:[]=)
116
+ expect(ENV).to_not receive(:update)
117
+
118
+ subject.fetch
119
+ end
120
+ end
121
+
122
+ context "with a proxy" do
123
+ before(:each) do
124
+ allow(R10K::Git).to receive(:get_proxy_for_remote).with(remote).and_return('http://proxy.example.com:3128')
125
+ end
126
+
127
+ it "manages proxy-related ENV vars" do
128
+ # Sets proxy settings.
129
+ ['HTTPS_PROXY', 'https_proxy', 'HTTP_PROXY', 'http_proxy'].each do |var|
130
+ expect(ENV).to receive(:[]=).with(var, 'http://proxy.example.com:3128')
131
+ end
132
+
133
+ # Resets proxy settings when done.
134
+ expect(ENV).to receive(:update).with(hash_including('HTTPS_PROXY' => nil))
135
+
136
+ subject.fetch
137
+ end
138
+ end
93
139
  end
94
140
 
95
141
  describe "listing branches" do
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ require 'r10k/settings/collection'
4
+ require 'r10k/settings/list'
5
+
6
+ shared_examples_for "a setting with ancestors" do
7
+ describe '#parent=' do
8
+ it "allows assignment to a collection" do
9
+ parent = R10K::Settings::Collection.new(:parent, [])
10
+
11
+ subject.parent = parent
12
+
13
+ expect(subject.parent).to eq parent
14
+ end
15
+
16
+ it "allows assignment to a list" do
17
+ parent = R10K::Settings::List.new(:parent, [])
18
+
19
+ subject.parent = parent
20
+
21
+ expect(subject.parent).to eq parent
22
+ end
23
+
24
+ it "rejects assignment when argument is not a settings collection or list" do
25
+ parent = Hash.new
26
+
27
+ expect { subject.parent = parent }.to raise_error do |error|
28
+ expect(error.message).to match /may only belong to a settings collection or list/i
29
+ end
30
+ end
31
+
32
+ it "rejects re-assignment" do
33
+ parent = R10K::Settings::Collection.new(:parent, [])
34
+ step_parent = R10K::Settings::Collection.new(:step_parent, [])
35
+
36
+ subject.parent = parent
37
+
38
+ expect { subject.parent = step_parent }.to raise_error do |error|
39
+ expect(error.message).to match /cannot be reassigned.*new parent/i
40
+ end
41
+ end
42
+ end
43
+ end
44
+
@@ -27,7 +27,7 @@ describe R10K::Forge::ModuleRelease do
27
27
 
28
28
  describe '#verify' do
29
29
  it "verifies the module checksum based on the Forge file checksum" do
30
- allow(subject.forge_release).to receive(:data).and_return('file_md5' => 'something')
30
+ allow(subject.forge_release).to receive(:file_md5).and_return('something')
31
31
  expect(subject.forge_release).to receive(:verify).with(download_path)
32
32
  subject.verify
33
33
  end
@@ -99,5 +99,11 @@ describe R10K::Git::Rugged::Credentials, :unless => R10K::Util::Platform.jruby?
99
99
  it "creates default credentials when no other types are allowed" do
100
100
  expect(subject.call("https://tessier-ashpool.freeside/repo.git", nil, [])).to be_a_kind_of(Rugged::Credentials::Default)
101
101
  end
102
+
103
+ it "refuses to generate credentials more than 50 times" do
104
+ (1..50).each { subject.call("https://tessier-ashpool.freeside/repo.git", nil, [:plaintext]) }
105
+
106
+ expect { subject.call("https://tessier-ashpool.freeside/repo.git", nil, [:plaintext]) }.to raise_error(R10K::Git::GitError, /authentication failed/i)
107
+ end
102
108
  end
103
109
  end
@@ -11,6 +11,8 @@ describe R10K::Settings::Collection do
11
11
  described_class.new(:collection, [symbol_defn, default_defn])
12
12
  end
13
13
 
14
+ it_behaves_like "a setting with ancestors"
15
+
14
16
  describe "#evaluate" do
15
17
  it "assigns values, validates them, and resolves a final value" do
16
18
  expect(subject).to receive(:assign).with({:default_defn => :squid})
@@ -20,7 +22,6 @@ describe R10K::Settings::Collection do
20
22
  end
21
23
  end
22
24
 
23
-
24
25
  describe '#assign' do
25
26
  it "assigns values to the appropriate setting" do
26
27
  subject.assign({:symbol_defn => :hello})
@@ -1,10 +1,15 @@
1
1
  require 'spec_helper'
2
2
  require 'r10k/settings/definition'
3
+ require 'r10k/settings/collection'
4
+ require 'r10k/settings/list'
3
5
 
4
6
  describe R10K::Settings::Definition do
7
+ subject { described_class.new(:setting) }
8
+
9
+ it_behaves_like "a setting with ancestors"
10
+
5
11
  describe "#evaluate" do
6
12
  it "assigns a value, validates it, and resolves a final value" do
7
- subject = described_class.new(:setting)
8
13
  expect(subject).to receive(:assign).with("myvalue")
9
14
  expect(subject).to receive(:validate)
10
15
  expect(subject).to receive(:resolve)
@@ -14,7 +19,6 @@ describe R10K::Settings::Definition do
14
19
 
15
20
  describe "#assign" do
16
21
  it 'stores the provided value' do
17
- subject = described_class.new(:setting)
18
22
  subject.assign("I'm the value")
19
23
  expect(subject.value).to eq "I'm the value"
20
24
  end
@@ -33,7 +37,6 @@ describe R10K::Settings::Definition do
33
37
  end
34
38
 
35
39
  it "does nothing if a validate hook has not been assigned" do
36
- subject = described_class.new(:setting)
37
40
  subject.assign("I'm the value")
38
41
  subject.validate
39
42
  end
@@ -55,7 +58,6 @@ describe R10K::Settings::Definition do
55
58
 
56
59
  describe "#resolve" do
57
60
  it "returns the value when the value has been given" do
58
- subject = described_class.new(:setting)
59
61
  subject.assign("Mun")
60
62
  expect(subject.resolve).to eq "Mun"
61
63
  end
@@ -71,7 +73,6 @@ describe R10K::Settings::Definition do
71
73
  end
72
74
 
73
75
  it "returns nil when there is no value nor default" do
74
- subject = described_class.new(:setting)
75
76
  expect(subject.resolve).to be_nil
76
77
  end
77
78
  end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+ require 'r10k/settings/collection'
3
+ require 'r10k/settings/definition'
4
+
5
+ RSpec.describe 'R10K::Settings inheritance' do
6
+ subject do
7
+ R10K::Settings::Collection.new(:parent_settings, [
8
+ R10K::Settings::Definition.new(:banana, {
9
+ :default => 'cavendish',
10
+ }),
11
+
12
+ R10K::Settings::Collection.new(:child_settings, [
13
+ R10K::Settings::Definition.new(:banana, {
14
+ :default => :inherit,
15
+ }),
16
+ ]),
17
+ ])
18
+ end
19
+
20
+ describe "child settings" do
21
+ let(:setting) { subject[:child_settings][:banana] }
22
+
23
+ context "when child value is not set" do
24
+ it "should resolve to default value from parent" do
25
+ expect(setting.value).to be_nil
26
+ expect(setting.resolve).to eq 'cavendish'
27
+ end
28
+ end
29
+
30
+ context "when child value is set" do
31
+ before(:each) { setting.assign('gros michel') }
32
+
33
+ it "should resolve to child value" do
34
+ expect(setting.resolve).to eq 'gros michel'
35
+ end
36
+ end
37
+ end
38
+ end