summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Lewis <nick@puppetlabs.com>2011-07-20 16:35:46 -0700
committerNick Lewis <nick@puppetlabs.com>2011-07-20 16:35:46 -0700
commitba6230b6039d62b0713c9d5e3ff61a68f70ef723 (patch)
tree41523b6f3a3e5fbc83f33784de408f1d5dd71825
parente8a2287cdac5dbf086b60af65e301f3e2360ee2b (diff)
parent8820a78b5793ba6266b3974ac90a9405d73b8343 (diff)
downloadpuppet-ba6230b6039d62b0713c9d5e3ff61a68f70ef723.tar.gz
puppet-ba6230b6039d62b0713c9d5e3ff61a68f70ef723.tar.xz
puppet-ba6230b6039d62b0713c9d5e3ff61a68f70ef723.zip
Merge branch '2.7.x'
-rw-r--r--acceptance/tests/jeff_append_to_array.rb9
-rw-r--r--acceptance/tests/puppet_apply_a_file_should_create_a_file_and_report_the_md5.rb9
-rw-r--r--acceptance/tests/puppet_apply_basics.rb8
-rw-r--r--acceptance/tests/puppet_apply_should_show_a_notice.rb8
-rwxr-xr-xacceptance/tests/resource/service/ticket_4123_should_list_all_running_redhat.rb3
-rwxr-xr-xacceptance/tests/resource/service/ticket_4124_should_list_all_disabled.rb2
-rw-r--r--acceptance/tests/ticket_3172_puppet_kick_with_hostnames_on_the_command_line.rb8
-rw-r--r--acceptance/tests/ticket_4059_ralsh_can_change_settings.rb7
-rw-r--r--acceptance/tests/ticket_4110_puppet_apply_should_not_create_a_user_that_already_exists.rb6
-rw-r--r--acceptance/tests/ticket_4233_resource_with_a_newline.rb7
-rw-r--r--acceptance/tests/ticket_4285_file_resource_fail_when_name_defined_instead_of_path.rb6
-rw-r--r--acceptance/tests/ticket_4287_undefined_method_evaluate_match_when_function_call_used_in_an_if_statement.rb7
-rw-r--r--acceptance/tests/ticket_4289_facter_should_recognize_OEL_operatingsystemrelease.rb2
-rw-r--r--acceptance/tests/ticket_4293_define_and_use_a_define_within_a_class.rb7
-rw-r--r--acceptance/tests/ticket_5477_master_not_dectect_sitepp.rb7
-rw-r--r--acceptance/tests/ticket_6541_invalid_filebucket_files.rb21
-rw-r--r--acceptance/tests/ticket_6734_6256_5530_5503.rb2
-rw-r--r--lib/puppet/application/agent.rb8
-rw-r--r--lib/puppet/application/apply.rb7
-rw-r--r--lib/puppet/application/ca.rb5
-rw-r--r--lib/puppet/application/device.rb8
-rw-r--r--lib/puppet/defaults.rb2
-rw-r--r--lib/puppet/face/ca.rb233
-rw-r--r--lib/puppet/interface.rb5
-rw-r--r--lib/puppet/interface/action.rb3
-rw-r--r--lib/puppet/interface/face_collection.rb49
-rw-r--r--lib/puppet/interface/option_manager.rb3
-rw-r--r--lib/puppet/module.rb5
-rw-r--r--lib/puppet/ssl/inventory.rb2
-rwxr-xr-xlib/puppet/type/file/source.rb2
-rw-r--r--lib/puppet/util.rb1
-rw-r--r--lib/puppet/util/settings.rb2
-rw-r--r--lib/semver.rb65
-rwxr-xr-xspec/integration/defaults_spec.rb2
-rwxr-xr-xspec/shared_behaviours/things_that_declare_options.rb2
-rwxr-xr-xspec/unit/face/ca_spec.rb355
-rwxr-xr-xspec/unit/indirector/certificate_status/file_spec.rb4
-rwxr-xr-xspec/unit/interface/action_spec.rb10
-rwxr-xr-xspec/unit/interface/face_collection_spec.rb40
-rwxr-xr-xspec/unit/interface_spec.rb8
-rwxr-xr-xspec/unit/module_spec.rb47
-rw-r--r--spec/unit/semver_spec.rb187
-rwxr-xr-xspec/unit/util/settings_spec.rb11
43 files changed, 1028 insertions, 157 deletions
diff --git a/acceptance/tests/jeff_append_to_array.rb b/acceptance/tests/jeff_append_to_array.rb
index 415d59fe8..20f43665e 100644
--- a/acceptance/tests/jeff_append_to_array.rb
+++ b/acceptance/tests/jeff_append_to_array.rb
@@ -12,8 +12,9 @@ manifest = %q{
include parent::child
}
-apply_manifest_on(agents, manifest) do
- stdout =~ /notice: parent array element/ or fail_test("parent missing")
- stdout =~ /notice: child array element/ or fail_test("child missing")
+agents.each do |host|
+ apply_manifest_on(host, manifest) do
+ assert_match(/notice: parent array element/, stdout, "#{host}: parent missing")
+ assert_match(/notice: child array element/, stdout, "#{host}: child missing")
+ end
end
-
diff --git a/acceptance/tests/puppet_apply_a_file_should_create_a_file_and_report_the_md5.rb b/acceptance/tests/puppet_apply_a_file_should_create_a_file_and_report_the_md5.rb
index abb06fbaf..44338520a 100644
--- a/acceptance/tests/puppet_apply_a_file_should_create_a_file_and_report_the_md5.rb
+++ b/acceptance/tests/puppet_apply_a_file_should_create_a_file_and_report_the_md5.rb
@@ -6,10 +6,11 @@ manifest = "file{'#{file}': content => 'test'}"
step "clean up #{file} for testing"
on agents, "rm -f #{file}"
-step "run the manifest and verify MD5 was printed"
-apply_manifest_on(agents, manifest) do
- fail_test "didn't find the content MD5 on output" unless
- stdout.include? "defined content as '{md5}098f6bcd4621d373cade4e832627b4f6'"
+step "Run the manifest and verify MD5 was printed"
+agents.each do |host|
+ apply_manifest_on(host, manifest) do
+ assert_match(/defined content as '{md5}098f6bcd4621d373cade4e832627b4f6'/, stdout, "#{host}: didn't find the content MD5 on output")
+ end
end
step "clean up #{file} after testing"
diff --git a/acceptance/tests/puppet_apply_basics.rb b/acceptance/tests/puppet_apply_basics.rb
index bbbdefc15..23c57d84d 100644
--- a/acceptance/tests/puppet_apply_basics.rb
+++ b/acceptance/tests/puppet_apply_basics.rb
@@ -5,11 +5,13 @@
test_name "Trivial puppet tests"
step "check that puppet apply displays notices"
-apply_manifest_on(agents, "notice 'Hello World'") do
- stdout =~ /notice:.*Hello World/ or fail_test("missing notice!")
+agents.each do |host|
+ apply_manifest_on(host, "notice 'Hello World'") do
+ assert_match(/notice:.*Hello World/, stdout, "#{host}: missing notice!")
+ end
end
step "verify help displays something for puppet master"
on master, puppet_master("--help") do
- stdout =~ /puppet master/ or fail_test("improper help output")
+ assert_match(/puppet master/, stdout, "improper help output")
end
diff --git a/acceptance/tests/puppet_apply_should_show_a_notice.rb b/acceptance/tests/puppet_apply_should_show_a_notice.rb
index af6f41ca7..757d29bbf 100644
--- a/acceptance/tests/puppet_apply_should_show_a_notice.rb
+++ b/acceptance/tests/puppet_apply_should_show_a_notice.rb
@@ -1,5 +1,7 @@
test_name "puppet apply should show a notice"
-apply_manifest_on(agents, "notice 'Hello World'") do
- fail_test "the notice didn't show" unless
- stdout =~ /notice: .*: Hello World/
+
+agents.each do |host|
+ apply_manifest_on(host, "notice 'Hello World'") do
+ assert_match(/notice: .*: Hello World/, stdout, "#{host}: the notice didn't show")
+ end
end
diff --git a/acceptance/tests/resource/service/ticket_4123_should_list_all_running_redhat.rb b/acceptance/tests/resource/service/ticket_4123_should_list_all_running_redhat.rb
index 127e943a9..9f0fdc5c7 100755
--- a/acceptance/tests/resource/service/ticket_4123_should_list_all_running_redhat.rb
+++ b/acceptance/tests/resource/service/ticket_4123_should_list_all_running_redhat.rb
@@ -4,8 +4,7 @@ step "Validate services running agreement ralsh vs. OS service count"
# ticket_4123_should_list_all_running_redhat.sh
hosts.each do |host|
- if host['platform'].include?('centos') or host['platform'].include?('redhat')
- puts "XXX #{host['platform']}"
+ if host['platform'].include?('centos') or host['platform'].include?('rhel')
run_script_on(host,'acceptance-tests/tests/resource/service/ticket_4123_should_list_all_running_redhat.sh')
else
skip_test "Test not supported on this plaform"
diff --git a/acceptance/tests/resource/service/ticket_4124_should_list_all_disabled.rb b/acceptance/tests/resource/service/ticket_4124_should_list_all_disabled.rb
index db96ad91c..13ad5ceac 100755
--- a/acceptance/tests/resource/service/ticket_4124_should_list_all_disabled.rb
+++ b/acceptance/tests/resource/service/ticket_4124_should_list_all_disabled.rb
@@ -4,7 +4,7 @@ step "Validate disabled services agreement ralsh vs. OS service count"
# ticket_4124_should_list_all_disabled.sh
hosts.each do |host|
- unless host['platform'].include? 'centos' or host['platform'].include? 'redhat'
+ unless host['platform'].include? 'centos' or host['platform'].include? 'rhel'
skip_test "Test not supported on this plaform"
else
run_script_on(host,'acceptance-tests/tests/resource/service/ticket_4124_should_list_all_disabled.sh')
diff --git a/acceptance/tests/ticket_3172_puppet_kick_with_hostnames_on_the_command_line.rb b/acceptance/tests/ticket_3172_puppet_kick_with_hostnames_on_the_command_line.rb
index 436ce29fe..24dd7256b 100644
--- a/acceptance/tests/ticket_3172_puppet_kick_with_hostnames_on_the_command_line.rb
+++ b/acceptance/tests/ticket_3172_puppet_kick_with_hostnames_on_the_command_line.rb
@@ -2,6 +2,8 @@ test_name "#3172: puppet kick with hostnames on the command line"
step "verify that we trigger our host"
target = 'working.example.org'
-on(agents, puppet_kick(target), :acceptable_exit_codes => [3]) {
- fail_test "didn't trigger #{target}" unless stdout.include? "Triggering #{target}"
-}
+agents.each do |host|
+ on(host, puppet_kick(target), :acceptable_exit_codes => [3]) {
+ assert_match(/Triggering #{target}/, stdout, "didn't trigger #{target} on #{host}" )
+ }
+end
diff --git a/acceptance/tests/ticket_4059_ralsh_can_change_settings.rb b/acceptance/tests/ticket_4059_ralsh_can_change_settings.rb
index c97bbdbe6..83f5899f2 100644
--- a/acceptance/tests/ticket_4059_ralsh_can_change_settings.rb
+++ b/acceptance/tests/ticket_4059_ralsh_can_change_settings.rb
@@ -11,9 +11,10 @@ on(agents, puppet_resource(content)) do
stdout.index('Host[example.com]/ensure: created') or
fail_test("missing notice about host record creation")
end
-on(agents, "cat #{target}") do
- stdout =~ /^127\.0\.0\.1\s+example\.com/ or
- fail_test("missing host record in #{target}")
+agents.each do |host|
+ on(host, "cat #{target}") do
+ assert_match(/^127\.0\.0\.1\s+example\.com/, stdout, "missing host record in #{target} on #{host}")
+ end
end
step "cleanup at the end of the test"
diff --git a/acceptance/tests/ticket_4110_puppet_apply_should_not_create_a_user_that_already_exists.rb b/acceptance/tests/ticket_4110_puppet_apply_should_not_create_a_user_that_already_exists.rb
index 9704250d9..147857362 100644
--- a/acceptance/tests/ticket_4110_puppet_apply_should_not_create_a_user_that_already_exists.rb
+++ b/acceptance/tests/ticket_4110_puppet_apply_should_not_create_a_user_that_already_exists.rb
@@ -1,5 +1,7 @@
test_name "#4110: puppet apply should not create a user that already exists"
-apply_manifest_on(agents, "user { 'root': ensure => 'present' }") do
- fail_test("we tried to create root on this host") if stdout =~ /created/
+agents.each do |host|
+ apply_manifest_on(host, "user { 'root': ensure => 'present' }") do
+ assert_no_match(/created/, stdout, "we tried to create root on #{host}" )
+ end
end
diff --git a/acceptance/tests/ticket_4233_resource_with_a_newline.rb b/acceptance/tests/ticket_4233_resource_with_a_newline.rb
index 7bb7dc3c3..11924b550 100644
--- a/acceptance/tests/ticket_4233_resource_with_a_newline.rb
+++ b/acceptance/tests/ticket_4233_resource_with_a_newline.rb
@@ -8,6 +8,9 @@ test_name "#4233: resource with a newline"
# and 2.6.0 final to not return an error line.
# Look for the line in the output and fail the test
# if we find it.
-apply_manifest_on(agents, 'exec { \'/bin/echo -e "\nHello World\n"\': }') do
- stdout =~ /err:/ and fail_test("error report in output, sorry")
+
+agents.each do |host|
+ apply_manifest_on(host, 'exec { \'/bin/echo -e "\nHello World\n"\': }') do
+ assert_no_match(/err:/, stdout, "error report in output on #{host}")
+ end
end
diff --git a/acceptance/tests/ticket_4285_file_resource_fail_when_name_defined_instead_of_path.rb b/acceptance/tests/ticket_4285_file_resource_fail_when_name_defined_instead_of_path.rb
index d2297fbc4..c1cdb0b9d 100644
--- a/acceptance/tests/ticket_4285_file_resource_fail_when_name_defined_instead_of_path.rb
+++ b/acceptance/tests/ticket_4285_file_resource_fail_when_name_defined_instead_of_path.rb
@@ -12,6 +12,8 @@ manifest = %q{
}
}
-apply_manifest_on(agents, manifest) do
- fail_test "found the bug report output" if stdout =~ /Cannot alias/
+agents.each do |host|
+ apply_manifest_on(host, manifest) do
+ assert_no_match(/Cannot alias/, stdout, "#{host}: found the bug report output")
+ end
end
diff --git a/acceptance/tests/ticket_4287_undefined_method_evaluate_match_when_function_call_used_in_an_if_statement.rb b/acceptance/tests/ticket_4287_undefined_method_evaluate_match_when_function_call_used_in_an_if_statement.rb
index e9a17df36..f5a1c1685 100644
--- a/acceptance/tests/ticket_4287_undefined_method_evaluate_match_when_function_call_used_in_an_if_statement.rb
+++ b/acceptance/tests/ticket_4287_undefined_method_evaluate_match_when_function_call_used_in_an_if_statement.rb
@@ -7,7 +7,8 @@ manifest = %q{
}
}
-apply_manifest_on(agents, manifest) do
- fail_test "didn't get the expected notice" unless
- stdout.include? 'notice: No issue here...'
+agents.each do |host|
+ apply_manifest_on(host, manifest) do
+ assert_match(/notice: No issue here.../, stdout, "didn't get the expected notice on #{host}")
+ end
end
diff --git a/acceptance/tests/ticket_4289_facter_should_recognize_OEL_operatingsystemrelease.rb b/acceptance/tests/ticket_4289_facter_should_recognize_OEL_operatingsystemrelease.rb
index 653fcb274..cacb7db65 100644
--- a/acceptance/tests/ticket_4289_facter_should_recognize_OEL_operatingsystemrelease.rb
+++ b/acceptance/tests/ticket_4289_facter_should_recognize_OEL_operatingsystemrelease.rb
@@ -16,6 +16,6 @@ agents.each do |host|
if stdout =~ /oel/i then
step "test operatingsystemrelease fact on OEL host #{host}"
on host, facter("operatingsystemrelease")
- stdout =~ /^\d\.\d$/ or fail_test "operatingsystemrelease not as expected"
+ assert_match(/^\d\.\d$/, stdout, "operatingsystemrelease not as expected on #{host}")
end
end
diff --git a/acceptance/tests/ticket_4293_define_and_use_a_define_within_a_class.rb b/acceptance/tests/ticket_4293_define_and_use_a_define_within_a_class.rb
index 830da99b4..aa42fd401 100644
--- a/acceptance/tests/ticket_4293_define_and_use_a_define_within_a_class.rb
+++ b/acceptance/tests/ticket_4293_define_and_use_a_define_within_a_class.rb
@@ -16,7 +16,8 @@ class foo {
include foo
PP
-apply_manifest_on(agents, manifest) do
- stdout =~ /notice.*?Foo::Do_notify.*?a_message_for_you/ or
- fail_test("the notification didn't show up in stdout")
+agents.each do |host|
+ apply_manifest_on(host, manifest) do
+ assert_match(/notice.*?Foo::Do_notify.*?a_message_for_you/, stdout, "the notification didn't show up in stdout on #{host}")
+ end
end
diff --git a/acceptance/tests/ticket_5477_master_not_dectect_sitepp.rb b/acceptance/tests/ticket_5477_master_not_dectect_sitepp.rb
index d8723b2ec..f774eca05 100644
--- a/acceptance/tests/ticket_5477_master_not_dectect_sitepp.rb
+++ b/acceptance/tests/ticket_5477_master_not_dectect_sitepp.rb
@@ -24,7 +24,10 @@ with_master_running_on(master, "--manifest #{manifest_file} --certdnsnames=\"pup
sleep 3
step "Agent: puppet agent --test"
- on agents, puppet_agent("--test --server #{master}"), :acceptable_exit_codes => [2] do
- fail_test "Site.pp not detect at Master?" unless stdout.include? 'ticket_5477_notify'
+
+ agents.each do |host|
+ on(host, puppet_agent("--test --server #{master}"), :acceptable_exit_codes => [2]) do
+ assert_match(/ticket_5477_notify/, stdout, "#{host}: Site.pp not detected on Puppet Master")
+ end
end
end
diff --git a/acceptance/tests/ticket_6541_invalid_filebucket_files.rb b/acceptance/tests/ticket_6541_invalid_filebucket_files.rb
index 25bcff452..33b985b67 100644
--- a/acceptance/tests/ticket_6541_invalid_filebucket_files.rb
+++ b/acceptance/tests/ticket_6541_invalid_filebucket_files.rb
@@ -4,23 +4,26 @@ apply_manifest_on(agents, manifest)
test_name "verify invalid hashes should not change the file"
manifest = "file { '/tmp/6541': content => '{md5}notahash' }"
-apply_manifest_on(agents, manifest) do
- fail_test "shouldn't have overwrote the file" if
- stdout =~ /content changed/
+agents.each do |host|
+ apply_manifest_on(host, manifest) do
+ assert_no_match(/content changed/, stdout, "#{host}: shouldn't have overwrote the file")
+ end
end
test_name "verify valid but unbucketed hashes should not change the file"
manifest = "file { '/tmp/6541': content => '{md5}13ad7345d56b566a4408ffdcd877bc78' }"
-apply_manifest_on(agents, manifest) do
- fail_test "shouldn't have overwrote the file" if
- stdout =~ /content changed/
+agents.each do |host|
+ apply_manifest_on(host, manifest) do
+ assert_no_match(/content changed/, stdout, "#{host}: shouldn't have overwrote the file")
+ end
end
on(agents, puppet_filebucket("backup -l /dev/null") )
test_name "verify that an empty file can be retrieved from the filebucket"
manifest = "file { '/tmp/6541': content => '{md5}d41d8cd98f00b204e9800998ecf8427e' }"
-apply_manifest_on(agents, manifest) do
- fail_test "shouldn't have overwrote the file" unless
- stdout =~ /content changed '\{md5\}552e21cd4cd9918678e3c1a0df491bc3' to '\{md5\}d41d8cd98f00b204e9800998ecf8427e'/
+agents.each do |host|
+ apply_manifest_on(host, manifest) do
+ assert_match(/content changed '\{md5\}552e21cd4cd9918678e3c1a0df491bc3' to '\{md5\}d41d8cd98f00b204e9800998ecf8427e'/, stdout, "#{host}: shouldn't have overwrote the file")
+ end
end
diff --git a/acceptance/tests/ticket_6734_6256_5530_5503.rb b/acceptance/tests/ticket_6734_6256_5530_5503.rb
index 72bb592d8..b5d7aaaf3 100644
--- a/acceptance/tests/ticket_6734_6256_5530_5503.rb
+++ b/acceptance/tests/ticket_6734_6256_5530_5503.rb
@@ -7,6 +7,6 @@ test_name "Tickets 6734 6256 5530 5503i Puppet Master fails to start"
with_master_running_on(master) do
step "Check permissions on puppet/rrd/"
on master, "ls -l /var/lib/puppet | grep rrd | awk '{print $3\" \"$4}'" do
- fail_test "puppet/rrd does not exist/wrong permission" unless stdout.include? 'puppet puppet'
+ assert_match(/puppet puppet/, stdout, "puppet/rrd does not exist/wrong permissions")
end
end
diff --git a/lib/puppet/application/agent.rb b/lib/puppet/application/agent.rb
index f0442648b..ea7cbdfb5 100644
--- a/lib/puppet/application/agent.rb
+++ b/lib/puppet/application/agent.rb
@@ -187,10 +187,10 @@ configuration options can also be generated by running puppet agent with
should always at least contain MD5, MD2, SHA1 and SHA256.
* --detailed-exitcodes:
- Provide transaction information via exit codes. If this is enabled, an
- exit code of '2' means there were changes, and an exit code of '4'
- means that there were failures during the transaction. This option
- only makes sense in conjunction with --onetime.
+ Provide transaction information via exit codes. If this is enabled, an exit
+ code of '2' means there were changes, an exit code of '4' means there were
+ failures during the transaction, and an exit code of '6' means there were both
+ changes and failures.
* --disable:
Disable working on the local system. This puts a lock file in place,
diff --git a/lib/puppet/application/apply.rb b/lib/puppet/application/apply.rb
index 5562a9b09..200309b7d 100644
--- a/lib/puppet/application/apply.rb
+++ b/lib/puppet/application/apply.rb
@@ -82,9 +82,10 @@ configuration options can also be generated by running puppet with
Enable full debugging.
* --detailed-exitcodes:
- Provide transaction information via exit codes. If this is enabled, an
- exit code of '2' means there were changes, and an exit code of '4'
- means that there were failures during the transaction.
+ Provide transaction information via exit codes. If this is enabled, an exit
+ code of '2' means there were changes, an exit code of '4' means there were
+ failures during the transaction, and an exit code of '6' means there were both
+ changes and failures.
* --help:
Print this help message
diff --git a/lib/puppet/application/ca.rb b/lib/puppet/application/ca.rb
new file mode 100644
index 000000000..d1ec2502e
--- /dev/null
+++ b/lib/puppet/application/ca.rb
@@ -0,0 +1,5 @@
+require 'puppet/application/face_base'
+
+class Puppet::Application::Ca < Puppet::Application::FaceBase
+ run_mode :master
+end
diff --git a/lib/puppet/application/device.rb b/lib/puppet/application/device.rb
index 3e2dec98c..977c5c023 100644
--- a/lib/puppet/application/device.rb
+++ b/lib/puppet/application/device.rb
@@ -113,10 +113,10 @@ parameter, so you can specify '--server <servername>' as an argument.
Enable full debugging.
* --detailed-exitcodes:
- Provide transaction information via exit codes. If this is enabled, an
- exit code of '2' means there were changes, and an exit code of '4' means
- that there were failures during the transaction. This option only makes
- sense in conjunction with --onetime.
+ Provide transaction information via exit codes. If this is enabled, an exit
+ code of '2' means there were changes, an exit code of '4' means there were
+ failures during the transaction, and an exit code of '6' means there were both
+ changes and failures.
* --help:
Print this help message
diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb
index e6beb512e..637ee8fdd 100644
--- a/lib/puppet/defaults.rb
+++ b/lib/puppet/defaults.rb
@@ -472,7 +472,7 @@ module Puppet
:desc => "The directory in which to store reports
received from the client. Each client gets a separate
subdirectory."},
- :reporturl => ["http://localhost:3000/reports",
+ :reporturl => ["http://localhost:3000/reports/upload",
"The URL used by the http reports processor to send reports"],
:fileserverconfig => ["$confdir/fileserver.conf", "Where the fileserver configuration is stored."],
:strict_hostname_checking => [false, "Whether to only search for the complete
diff --git a/lib/puppet/face/ca.rb b/lib/puppet/face/ca.rb
new file mode 100644
index 000000000..e643530f0
--- /dev/null
+++ b/lib/puppet/face/ca.rb
@@ -0,0 +1,233 @@
+require 'puppet/face'
+
+Puppet::Face.define(:ca, '0.1.0') do
+ copyright "Puppet Labs", 2011
+ license "Apache 2 license; see COPYING"
+
+ summary "Local Puppet Certificate Authority management."
+
+ description <<TEXT
+This provides local management of the Puppet Certificate Authority.
+
+You can use this subcommand to sign outstanding certificate requests, list
+and manage local certificates, and inspect the state of the CA.
+TEXT
+
+ action :list do
+ summary "List certificates and/or certificate requests."
+
+ description <<-end
+This will list the current certificates and certificate signing requests
+in the Puppet CA. You will also get the fingerprint, and any certificate
+verification failure reported.
+ end
+
+ option "--[no-]all" do
+ summary "Include all certificates and requests."
+ end
+
+ option "--[no-]pending" do
+ summary "Include pending certificate signing requests."
+ end
+
+ option "--[no-]signed" do
+ summary "Include signed certificates."
+ end
+
+ option "--subject PATTERN" do
+ summary "Only list if the subject matches PATTERN."
+
+ description <<TEXT
+Only include certificates or requests where subject matches PATTERN.
+
+PATTERN is interpreted as a regular expression, allowing complex
+filtering of the content.
+TEXT
+ end
+
+ when_invoked do |options|
+ raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
+ unless ca = Puppet::SSL::CertificateAuthority.instance
+ raise "Unable to fetch the CA"
+ end
+
+ pattern = options[:subject].nil? ? nil :
+ Regexp.new(options[:subject], Regexp::IGNORECASE)
+
+ pending = options[:pending].nil? ? options[:all] : options[:pending]
+ signed = options[:signed].nil? ? options[:all] : options[:signed]
+
+ # By default we list pending, so if nothing at all was requested...
+ unless pending or signed then pending = true end
+
+ hosts = []
+
+ pending and hosts += ca.waiting?
+ signed and hosts += ca.list
+
+ pattern and hosts = hosts.select {|hostname| pattern.match hostname }
+
+ hosts.sort.map {|host| Puppet::SSL::Host.new(host) }
+ end
+
+ when_rendering :console do |hosts|
+ unless ca = Puppet::SSL::CertificateAuthority.instance
+ raise "Unable to fetch the CA"
+ end
+
+ length = hosts.map{|x| x.name.length }.max + 1
+
+ hosts.map do |host|
+ name = host.name.ljust(length)
+ if host.certificate_request then
+ " #{name} (#{host.certificate_request.fingerprint})"
+ else
+ begin
+ ca.verify(host.certificate)
+ "+ #{name} (#{host.certificate.fingerprint})"
+ rescue Puppet::SSL::CertificateAuthority::CertificateVerificationError => e
+ "- #{name} (#{host.certificate.fingerprint}) (#{e.to_s})"
+ end
+ end
+ end.join("\n")
+ end
+ end
+
+ action :destroy do
+ when_invoked do |host, options|
+ raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
+ unless ca = Puppet::SSL::CertificateAuthority.instance
+ raise "Unable to fetch the CA"
+ end
+
+ ca.destroy host
+ end
+ end
+
+ action :revoke do
+ when_invoked do |host, options|
+ raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
+ unless ca = Puppet::SSL::CertificateAuthority.instance
+ raise "Unable to fetch the CA"
+ end
+
+ begin
+ ca.revoke host
+ rescue ArgumentError => e
+ # This is a bit naff, but it makes the behaviour consistent with the
+ # destroy action. The underlying tools could be nicer for that sort
+ # of thing; they have fairly inconsistent reporting of failures.
+ raise unless e.to_s =~ /Could not find a serial number for /
+ "Nothing was revoked"
+ end
+ end
+ end
+
+ action :generate do
+ when_invoked do |host, options|
+ raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
+ unless ca = Puppet::SSL::CertificateAuthority.instance
+ raise "Unable to fetch the CA"
+ end
+
+ begin
+ ca.generate host
+ rescue RuntimeError => e
+ if e.to_s =~ /already has a requested certificate/
+ "#{host} already has a certificate request; use sign instead"
+ else
+ raise
+ end
+ rescue ArgumentError => e
+ if e.to_s =~ /A Certificate already exists for /
+ "#{host} already has a certificate"
+ else
+ raise
+ end
+ end
+ end
+ end
+
+ action :sign do
+ when_invoked do |host, options|
+ raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
+ unless ca = Puppet::SSL::CertificateAuthority.instance
+ raise "Unable to fetch the CA"
+ end
+
+ begin
+ ca.sign host
+ rescue ArgumentError => e
+ if e.to_s =~ /Could not find certificate request/
+ e.to_s
+ else
+ raise
+ end
+ end
+ end
+ end
+
+ action :print do
+ when_invoked do |host, options|
+ raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
+ unless ca = Puppet::SSL::CertificateAuthority.instance
+ raise "Unable to fetch the CA"
+ end
+
+ ca.print host
+ end
+ end
+
+ action :fingerprint do
+ option "--digest ALGORITHM" do
+ summary "The hash algorithm to use when displaying the fingerprint"
+ end
+
+ when_invoked do |host, options|
+ raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
+ unless ca = Puppet::SSL::CertificateAuthority.instance
+ raise "Unable to fetch the CA"
+ end
+
+ begin
+ # I want the default from the CA, not to duplicate it, but passing
+ # 'nil' explicitly means that we don't get that. This works...
+ if options.has_key? :digest
+ ca.fingerprint host, options[:digest]
+ else
+ ca.fingerprint host
+ end
+ rescue ArgumentError => e
+ raise unless e.to_s =~ /Could not find a certificate or csr for/
+ nil
+ end
+ end
+ end
+
+ action :verify do
+ when_invoked do |host, options|
+ raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
+ unless ca = Puppet::SSL::CertificateAuthority.instance
+ raise "Unable to fetch the CA"
+ end
+
+ begin
+ ca.verify host
+ { :host => host, :valid => true }
+ rescue ArgumentError => e
+ raise unless e.to_s =~ /Could not find a certificate for/
+ { :host => host, :valid => false, :error => e.to_s }
+ rescue Puppet::SSL::CertificateAuthority::CertificateVerificationError => e
+ { :host => host, :valid => false, :error => e.to_s }
+ end
+ end
+
+ when_rendering :console do |value|
+ if value[:valid]
+ nil
+ else
+ "Could not verify #{value[:host]}: #{value[:error]}"
+ end
+ end
+ end
+end
diff --git a/lib/puppet/interface.rb b/lib/puppet/interface.rb
index 6be8b6930..6c288f3c0 100644
--- a/lib/puppet/interface.rb
+++ b/lib/puppet/interface.rb
@@ -2,6 +2,7 @@ require 'puppet'
require 'puppet/util/autoload'
require 'puppet/interface/documentation'
require 'prettyprint'
+require 'semver'
class Puppet::Interface
include FullDocs
@@ -84,12 +85,12 @@ class Puppet::Interface
attr_reader :name, :version
def initialize(name, version, &block)
- unless Puppet::Interface::FaceCollection.validate_version(version)
+ unless SemVer.valid?(version)
raise ArgumentError, "Cannot create face #{name.inspect} with invalid version number '#{version}'!"
end
@name = Puppet::Interface::FaceCollection.underscorize(name)
- @version = version
+ @version = SemVer.new(version)
# The few bits of documentation we actually demand. The default license
# is a favour to our end users; if you happen to get that in a core face
diff --git a/lib/puppet/interface/action.rb b/lib/puppet/interface/action.rb
index 185302b07..fe77a9658 100644
--- a/lib/puppet/interface/action.rb
+++ b/lib/puppet/interface/action.rb
@@ -227,8 +227,9 @@ WRAPPER
end
end
+ @options << option.name
+
option.aliases.each do |name|
- @options << name
@options_hash[name] = option
end
diff --git a/lib/puppet/interface/face_collection.rb b/lib/puppet/interface/face_collection.rb
index 12d3c56b1..4522824fd 100644
--- a/lib/puppet/interface/face_collection.rb
+++ b/lib/puppet/interface/face_collection.rb
@@ -1,8 +1,6 @@
require 'puppet/interface'
module Puppet::Interface::FaceCollection
- SEMVER_VERSION = /^(\d+)\.(\d+)\.(\d+)([A-Za-z][0-9A-Za-z-]*|)$/
-
@faces = Hash.new { |hash, key| hash[key] = {} }
def self.faces
@@ -17,55 +15,18 @@ module Puppet::Interface::FaceCollection
@faces.keys.select {|name| @faces[name].length > 0 }
end
- def self.validate_version(version)
- !!(SEMVER_VERSION =~ version.to_s)
- end
-
- def self.semver_to_array(v)
- parts = SEMVER_VERSION.match(v).to_a[1..4]
- parts[0..2] = parts[0..2].map { |e| e.to_i }
- parts
- end
-
- def self.cmp_semver(a, b)
- a, b = [a, b].map do |x| semver_to_array(x) end
-
- cmp = a[0..2] <=> b[0..2]
- if cmp == 0
- cmp = a[3] <=> b[3]
- cmp = +1 if a[3].empty? && !b[3].empty?
- cmp = -1 if b[3].empty? && !a[3].empty?
- end
- cmp
- end
-
- def self.prefix_match?(desired, target)
- # Can't meaningfully do a prefix match with current on either side.
- return false if desired == :current
- return false if target == :current
-
- # REVISIT: Should probably fail if the matcher is not valid.
- prefix = desired.split('.').map {|x| x =~ /^\d+$/ and x.to_i }
- have = semver_to_array(target)
-
- while want = prefix.shift do
- return false unless want == have.shift
- end
- return true
- end
-
def self.[](name, version)
name = underscorize(name)
get_face(name, version) or load_face(name, version)
end
# get face from memory, without loading.
- def self.get_face(name, desired_version)
+ def self.get_face(name, pattern)
return nil unless @faces.has_key? name
+ return @faces[name][:current] if pattern == :current
- return @faces[name][:current] if desired_version == :current
-
- found = @faces[name].keys.select {|v| prefix_match?(desired_version, v) }.sort.last
+ versions = @faces[name].keys - [ :current ]
+ found = SemVer.find_matching(pattern, versions)
return @faces[name][found]
end
@@ -108,7 +69,7 @@ module Puppet::Interface::FaceCollection
# versions here and return the last item in that set.
#
# --daniel 2011-04-06
- latest_ver = @faces[name].keys.sort {|a, b| cmp_semver(a, b) }.last
+ latest_ver = @faces[name].keys.sort.last
@faces[name][:current] = @faces[name][latest_ver]
end
rescue LoadError => e
diff --git a/lib/puppet/interface/option_manager.rb b/lib/puppet/interface/option_manager.rb
index 326a91d92..a1f300e8e 100644
--- a/lib/puppet/interface/option_manager.rb
+++ b/lib/puppet/interface/option_manager.rb
@@ -26,8 +26,9 @@ module Puppet::Interface::OptionManager
end
end
+ @options << option.name
+
option.aliases.each do |name|
- @options << name
@options_hash[name] = option
end
diff --git a/lib/puppet/module.rb b/lib/puppet/module.rb
index 059591ed8..00468df96 100644
--- a/lib/puppet/module.rb
+++ b/lib/puppet/module.rb
@@ -42,7 +42,10 @@ class Puppet::Module
def has_metadata?
return false unless metadata_file
- FileTest.exist?(metadata_file)
+ return false unless FileTest.exist?(metadata_file)
+
+ metadata = PSON.parse File.read(metadata_file)
+ return metadata.is_a?(Hash) && !metadata.keys.empty?
end
def initialize(name, environment = nil)
diff --git a/lib/puppet/ssl/inventory.rb b/lib/puppet/ssl/inventory.rb
index e094da100..c210fdc35 100644
--- a/lib/puppet/ssl/inventory.rb
+++ b/lib/puppet/ssl/inventory.rb
@@ -48,5 +48,7 @@ class Puppet::SSL::Inventory
return Integer($1)
end
+
+ return nil
end
end
diff --git a/lib/puppet/type/file/source.rb b/lib/puppet/type/file/source.rb
index 76c646baf..49e885865 100755
--- a/lib/puppet/type/file/source.rb
+++ b/lib/puppet/type/file/source.rb
@@ -42,7 +42,7 @@ module Puppet
on the local host, whereas `agent` will connect to the
puppet server that it received the manifest from.
- See the [fileserver configuration documentation](http://projects.puppetlabs.com/projects/puppet/wiki/File_Serving_Configuration) for information on how to configure
+ See the [fileserver configuration documentation](http://docs.puppetlabs.com/guides/file_serving.html) for information on how to configure
and use file services within Puppet.
If you specify multiple file sources for a file, then the first
diff --git a/lib/puppet/util.rb b/lib/puppet/util.rb
index ce9d4642b..ff09221a2 100644
--- a/lib/puppet/util.rb
+++ b/lib/puppet/util.rb
@@ -30,7 +30,6 @@ module Util
end
end
-
def self.synchronize_on(x,type)
sync_object,users = 0,1
begin
diff --git a/lib/puppet/util/settings.rb b/lib/puppet/util/settings.rb
index f243b8691..4559e9af3 100644
--- a/lib/puppet/util/settings.rb
+++ b/lib/puppet/util/settings.rb
@@ -721,7 +721,7 @@ if @config.include?(:run_mode)
end
Puppet::Util::SUIDManager.asuser(*chown) do
- mode = obj.mode || 0640
+ mode = obj.mode ? obj.mode.to_i : 0640
args << "w" if args.empty?
args << mode
diff --git a/lib/semver.rb b/lib/semver.rb
new file mode 100644
index 000000000..ef9435abd
--- /dev/null
+++ b/lib/semver.rb
@@ -0,0 +1,65 @@
+class SemVer
+ VERSION = /^v?(\d+)\.(\d+)\.(\d+)([A-Za-z][0-9A-Za-z-]*|)$/
+ SIMPLE_RANGE = /^v?(\d+|[xX])(?:\.(\d+|[xX])(?:\.(\d+|[xX]))?)?$/
+
+ include Comparable
+
+ def self.valid?(ver)
+ VERSION =~ ver
+ end
+
+ def self.find_matching(pattern, versions)
+ versions.select { |v| v.matched_by?("#{pattern}") }.sort.last
+ end
+
+ attr_reader :major, :minor, :tiny, :special
+
+ def initialize(ver)
+ unless SemVer.valid?(ver)
+ raise ArgumentError.new("Invalid version string '#{ver}'!")
+ end
+
+ @major, @minor, @tiny, @special = VERSION.match(ver).captures.map do |x|
+ # Because Kernel#Integer tries to interpret hex and octal strings, which
+ # we specifically do not want, and which cannot be overridden in 1.8.7.
+ Float(x).to_i rescue x
+ end
+ end
+
+ def <=>(other)
+ other = SemVer.new("#{other}") unless other.is_a? SemVer
+ return self.major <=> other.major unless self.major == other.major
+ return self.minor <=> other.minor unless self.minor == other.minor
+ return self.tiny <=> other.tiny unless self.tiny == other.tiny
+
+ return 0 if self.special == other.special
+ return 1 if self.special == ''
+ return -1 if other.special == ''
+
+ return self.special <=> other.special
+ end
+
+ def matched_by?(pattern)
+ # For the time being, this is restricted to exact version matches and
+ # simple range patterns. In the future, we should implement some or all of
+ # the comparison operators here:
+ # https://github.com/isaacs/node-semver/blob/d474801/semver.js#L340
+
+ case pattern
+ when SIMPLE_RANGE
+ pattern = SIMPLE_RANGE.match(pattern).captures
+ pattern[1] = @minor unless pattern[1] && pattern[1] !~ /x/i
+ pattern[2] = @tiny unless pattern[2] && pattern[2] !~ /x/i
+ [@major, @minor, @tiny] == pattern.map { |x| x.to_i }
+ when VERSION
+ self == SemVer.new(pattern)
+ else
+ false
+ end
+ end
+
+ def inspect
+ "v#{@major}.#{@minor}.#{@tiny}#{@special}"
+ end
+ alias :to_s :inspect
+end
diff --git a/spec/integration/defaults_spec.rb b/spec/integration/defaults_spec.rb
index a165838c3..84297e8f9 100755
--- a/spec/integration/defaults_spec.rb
+++ b/spec/integration/defaults_spec.rb
@@ -275,7 +275,7 @@ describe "Puppet defaults" do
describe "reporturl" do
subject { Puppet.settings[:reporturl] }
- it { should == "http://localhost:3000/reports" }
+ it { should == "http://localhost:3000/reports/upload" }
end
describe "when configuring color" do
diff --git a/spec/shared_behaviours/things_that_declare_options.rb b/spec/shared_behaviours/things_that_declare_options.rb
index ebf1b2071..19bba66c1 100755
--- a/spec/shared_behaviours/things_that_declare_options.rb
+++ b/spec/shared_behaviours/things_that_declare_options.rb
@@ -43,7 +43,7 @@ shared_examples_for "things that declare options" do
option "-f"
option "--baz"
end
- thing.options.should == [:foo, :bar, :b, :q, :quux, :f, :baz]
+ thing.options.should == [:foo, :bar, :quux, :f, :baz]
end
it "should detect conflicts in long options" do
diff --git a/spec/unit/face/ca_spec.rb b/spec/unit/face/ca_spec.rb
new file mode 100755
index 000000000..b8c82ce99
--- /dev/null
+++ b/spec/unit/face/ca_spec.rb
@@ -0,0 +1,355 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+require 'puppet/face'
+
+describe Puppet::Face[:ca, '0.1.0'] do
+ include PuppetSpec::Files
+
+ before :each do
+ Puppet.run_mode.stubs(:master?).returns(true)
+ Puppet[:ca] = true
+ Puppet[:ssldir] = tmpdir("face-ca-ssldir")
+
+ Puppet::SSL::Host.ca_location = :only
+ Puppet[:certificate_revocation] = true
+
+ # This is way more intimate than I want to be with the implementation, but
+ # there doesn't seem any other way to test this. --daniel 2011-07-18
+ Puppet::SSL::CertificateAuthority.stubs(:instance).returns(
+ # ...and this actually does the directory creation, etc.
+ Puppet::SSL::CertificateAuthority.new
+ )
+ end
+
+ def make_certs(csr_names, crt_names)
+ Array(csr_names).map do |name|
+ Puppet::SSL::Host.new(name).generate_certificate_request
+ end
+
+ Array(crt_names).map do |name|
+ Puppet::SSL::Host.new(name).generate
+ end
+ end
+
+ context "#verify" do
+ let :action do Puppet::Face[:ca, '0.1.0'].get_action(:verify) end
+
+ it "should not explode if there is no certificate" do
+ expect {
+ subject.verify('random-host').should == {
+ :host => 'random-host', :valid => false,
+ :error => 'Could not find a certificate for random-host'
+ }
+ }.should_not raise_error
+ end
+
+ it "should not explode if there is only a CSR" do
+ make_certs('random-host', [])
+ expect {
+ subject.verify('random-host').should == {
+ :host => 'random-host', :valid => false,
+ :error => 'Could not find a certificate for random-host'
+ }
+ }.should_not raise_error
+ end
+
+ it "should verify a signed certificate" do
+ make_certs([], 'random-host')
+ subject.verify('random-host').should == {
+ :host => 'random-host', :valid => true
+ }
+ end
+
+ it "should not verify a revoked certificate" do
+ make_certs([], 'random-host')
+ subject.revoke('random-host')
+
+ expect {
+ subject.verify('random-host').should == {
+ :host => 'random-host', :valid => false,
+ :error => 'certificate revoked'
+ }
+ }.should_not raise_error
+ end
+
+ it "should verify a revoked certificate if CRL use was turned off" do
+ make_certs([], 'random-host')
+ subject.revoke('random-host')
+
+ Puppet[:certificate_revocation] = false
+ subject.verify('random-host').should == {
+ :host => 'random-host', :valid => true
+ }
+ end
+ end
+
+ context "#fingerprint" do
+ let :action do Puppet::Face[:ca, '0.1.0'].get_action(:fingerprint) end
+
+ it "should have a 'digest' option" do
+ action.should be_option :digest
+ end
+
+ it "should not explode if there is no certificate" do
+ expect {
+ subject.fingerprint('random-host').should be_nil
+ }.should_not raise_error
+ end
+
+ it "should fingerprint a CSR" do
+ make_certs('random-host', [])
+ expect {
+ subject.fingerprint('random-host').should =~ /^[0-9A-F:]+$/
+ }.should_not raise_error
+ end
+
+ it "should fingerprint a certificate" do
+ make_certs([], 'random-host')
+ subject.fingerprint('random-host').should =~ /^[0-9A-F:]+$/
+ end
+
+ %w{md5 MD5 sha1 ShA1 SHA1 RIPEMD160 sha256 sha512}.each do |digest|
+ it "should fingerprint with #{digest.inspect}" do
+ make_certs([], 'random-host')
+ subject.fingerprint('random-host', :digest => digest).should =~ /^[0-9A-F:]+$/
+ end
+
+ it "should fingerprint with #{digest.to_sym} as a symbol" do
+ make_certs([], 'random-host')
+ subject.fingerprint('random-host', :digest => digest.to_sym).
+ should =~ /^[0-9A-F:]+$/
+ end
+ end
+ end
+
+ context "#print" do
+ let :action do Puppet::Face[:ca, '0.1.0'].get_action(:print) end
+
+ it "should not explode if there is no certificate" do
+ expect {
+ subject.print('random-host').should be_nil
+ }.should_not raise_error
+ end
+
+ it "should return nothing if there is only a CSR" do
+ make_certs('random-host', [])
+ expect {
+ subject.print('random-host').should be_nil
+ }.should_not raise_error
+ end
+
+ it "should return the certificate content if there is a cert" do
+ make_certs([], 'random-host')
+ text = subject.print('random-host')
+ text.should be_an_instance_of String
+ text.should =~ /^Certificate:/
+ text.should =~ /Issuer: CN=Puppet CA: /
+ text.should =~ /Subject: CN=random-host$/
+ end
+ end
+
+ context "#sign" do
+ let :action do Puppet::Face[:ca, '0.1.0'].get_action(:sign) end
+
+ it "should not explode if there is no CSR" do
+ expect {
+ subject.sign('random-host').
+ should == 'Could not find certificate request for random-host'
+ }.should_not raise_error
+ end
+
+ it "should not explode if there is a signed cert" do
+ make_certs([], 'random-host')
+ expect {
+ subject.sign('random-host').
+ should == 'Could not find certificate request for random-host'
+ }.should_not raise_error
+ end
+
+ it "should sign a CSR if one exists" do
+ make_certs('random-host', [])
+ subject.sign('random-host').should be_an_instance_of Puppet::SSL::Certificate
+
+ list = subject.list(:signed => true)
+ list.length.should == 1
+ list.first.name.should == 'random-host'
+ end
+ end
+
+ context "#generate" do
+ let :action do Puppet::Face[:ca, '0.1.0'].get_action(:generate) end
+
+ it "should generate a certificate if requested" do
+ subject.list(:all => true).should == []
+
+ subject.generate('random-host')
+
+ list = subject.list(:signed => true)
+ list.length.should == 1
+ list.first.name.should == 'random-host'
+ end
+
+ it "should not explode if a CSR with that name already exists" do
+ make_certs('random-host', [])
+ expect {
+ subject.generate('random-host').should =~ /already has a certificate request/
+ }.should_not raise_error
+ end
+
+ it "should not explode if the certificate with that name already exists" do
+ make_certs([], 'random-host')
+ expect {
+ subject.generate('random-host').should =~ /already has a certificate/
+ }.should_not raise_error
+ end
+ end
+
+ context "#revoke" do
+ let :action do Puppet::Face[:ca, '0.1.0'].get_action(:revoke) end
+
+ it "should not explode when asked to revoke something that doesn't exist" do
+ expect { subject.revoke('nonesuch') }.should_not raise_error
+ end
+
+ it "should let the user know what went wrong" do
+ subject.revoke('nonesuch').should == 'Nothing was revoked'
+ end
+
+ it "should revoke a certificate" do
+ make_certs([], 'random-host')
+ found = subject.list(:all => true, :subject => 'random-host')
+ subject.get_action(:list).when_rendering(:console).call(found).
+ should =~ /^\+ random-host/
+
+ subject.revoke('random-host')
+
+ found = subject.list(:all => true, :subject => 'random-host')
+ subject.get_action(:list).when_rendering(:console).call(found).
+ should =~ /^- random-host \([:0-9A-F]+\) \(certificate revoked\)/
+ end
+ end
+
+ context "#destroy" do
+ let :action do Puppet::Face[:ca, '0.1.0'].get_action(:destroy) end
+
+ it "should not explode when asked to delete something that doesn't exist" do
+ expect { subject.destroy('nonesuch') }.should_not raise_error
+ end
+
+ it "should let the user know if nothing was deleted" do
+ subject.destroy('nonesuch').should == "Nothing was deleted"
+ end
+
+ it "should destroy a CSR, if we have one" do
+ make_certs('random-host', [])
+ subject.list(:pending => true, :subject => 'random-host').should_not == []
+
+ subject.destroy('random-host')
+
+ subject.list(:pending => true, :subject => 'random-host').should == []
+ end
+
+ it "should destroy a certificate, if we have one" do
+ make_certs([], 'random-host')
+ subject.list(:signed => true, :subject => 'random-host').should_not == []
+
+ subject.destroy('random-host')
+
+ subject.list(:signed => true, :subject => 'random-host').should == []
+ end
+
+ it "should tell the user something was deleted" do
+ make_certs([], 'random-host')
+ subject.list(:signed => true, :subject => 'random-host').should_not == []
+ subject.destroy('random-host').
+ should == "Deleted for random-host: Puppet::SSL::Certificate, Puppet::SSL::Key"
+ end
+ end
+
+ context "#list" do
+ let :action do Puppet::Face[:ca, '0.1.0'].get_action(:list) end
+
+ context "options" do
+ subject { Puppet::Face[:ca, '0.1.0'].get_action(:list) }
+ it { should be_option :pending }
+ it { should be_option :signed }
+ it { should be_option :all }
+ it { should be_option :subject }
+ end
+
+ context "with no hosts in CA" do
+ [:pending, :signed, :all].each do |type|
+ it "should return nothing for #{type}" do
+ subject.list(type => true).should == []
+ end
+
+ it "should not fail when a matcher is passed" do
+ expect {
+ subject.list(type => true, :subject => '.').should == []
+ }.should_not raise_error
+ end
+ end
+ end
+
+ context "with some hosts" do
+ csr_names = (1..3).map {|n| "csr-#{n}" }
+ crt_names = (1..3).map {|n| "crt-#{n}" }
+ all_names = csr_names + crt_names
+
+ {
+ {} => csr_names,
+ { :pending => true } => csr_names,
+
+ { :signed => true } => crt_names,
+
+ { :all => true } => all_names,
+ { :pending => true, :signed => true } => all_names,
+ }.each do |input, expect|
+ it "should map #{input.inspect} to #{expect.inspect}" do
+ make_certs(csr_names, crt_names)
+ subject.list(input).map(&:name).should =~ expect
+ end
+
+ ['', '.', '2', 'none'].each do |pattern|
+ filtered = expect.select {|x| Regexp.new(pattern).match(x) }
+
+ it "should filter all hosts matching #{pattern.inspect} to #{filtered.inspect}" do
+ make_certs(csr_names, crt_names)
+ subject.list(input.merge :subject => pattern).map(&:name).should =~ filtered
+ end
+ end
+ end
+
+ context "when_rendering :console" do
+ { [["csr1.local"], []] => '^ csr1.local ',
+ [[], ["crt1.local"]] => '^\+ crt1.local ',
+ [["csr2"], ["crt2"]] => ['^ csr2 ', '^\+ crt2 ']
+ }.each do |input, pattern|
+ it "should render #{input.inspect} to match #{pattern.inspect}" do
+ make_certs(*input)
+ text = action.when_rendering(:console).call(subject.list(:all => true))
+ Array(pattern).each do |item|
+ text.should =~ Regexp.new(item)
+ end
+ end
+ end
+ end
+ end
+ end
+
+ actions = %w{destroy list revoke generate sign print verify fingerprint}
+ actions.each do |action|
+ it { should be_action action }
+ it "should fail #{action} when not a CA" do
+ Puppet[:ca] = false
+ expect {
+ case subject.method(action).arity
+ when -1 then subject.send(action)
+ when -2 then subject.send(action, 'dummy')
+ else
+ raise "#{action} has arity #{subject.method(action).arity}"
+ end
+ }.should raise_error(/Not a CA/)
+ end
+ end
+end
diff --git a/spec/unit/indirector/certificate_status/file_spec.rb b/spec/unit/indirector/certificate_status/file_spec.rb
index 897fe0716..c5d4e283f 100755
--- a/spec/unit/indirector/certificate_status/file_spec.rb
+++ b/spec/unit/indirector/certificate_status/file_spec.rb
@@ -7,6 +7,10 @@ require 'tempfile'
describe "Puppet::Indirector::CertificateStatus::File", :fails_on_windows => true do
include PuppetSpec::Files
+ before :all do
+ Puppet::SSL::Host.configure_indirection(:file)
+ end
+
before do
Puppet::SSL::CertificateAuthority.stubs(:ca?).returns true
@terminus = Puppet::SSL::Host.indirection.terminus(:file)
diff --git a/spec/unit/interface/action_spec.rb b/spec/unit/interface/action_spec.rb
index cf8d61d51..23216e7b4 100755
--- a/spec/unit/interface/action_spec.rb
+++ b/spec/unit/interface/action_spec.rb
@@ -171,6 +171,16 @@ describe Puppet::Interface::Action do
face.get_action(:foo).options.should =~ [:bar]
end
+ it "should only list options and not aliases" do
+ face = Puppet::Interface.new(:action_level_options, '0.0.1') do
+ action :foo do
+ when_invoked do |options| true end
+ option "--bar", "-b", "--foo-bar"
+ end
+ end
+ face.get_action(:foo).options.should =~ [:bar]
+ end
+
describe "with both face and action options" do
let :face do
Puppet::Interface.new(:action_level_options, '0.0.1') do
diff --git a/spec/unit/interface/face_collection_spec.rb b/spec/unit/interface/face_collection_spec.rb
index 4ad8787c5..98887a778 100755
--- a/spec/unit/interface/face_collection_spec.rb
+++ b/spec/unit/interface/face_collection_spec.rb
@@ -25,39 +25,9 @@ describe Puppet::Interface::FaceCollection do
@original_required.each {|f| $".push f unless $".include? f }
end
- describe "::prefix_match?" do
- # want have
- { ['1.0.0', '1.0.0'] => true,
- ['1.0', '1.0.0'] => true,
- ['1', '1.0.0'] => true,
- ['1.0.0', '1.1.0'] => false,
- ['1.0', '1.1.0'] => false,
- ['1', '1.1.0'] => true,
- ['1.0.1', '1.0.0'] => false,
- }.each do |data, result|
- it "should return #{result.inspect} for prefix_match?(#{data.join(', ')})" do
- subject.prefix_match?(*data).should == result
- end
- end
- end
-
- describe "::validate_version" do
- { '10.10.10' => true,
- '1.2.3.4' => false,
- '10.10.10beta' => true,
- '10.10' => false,
- '123' => false,
- 'v1.1.1' => false,
- }.each do |input, result|
- it "should#{result ? '' : ' not'} permit #{input.inspect}" do
- subject.validate_version(input).should(result ? be_true : be_false)
- end
- end
- end
-
describe "::[]" do
before :each do
- subject.instance_variable_get("@faces")[:foo]['0.0.1'] = 10
+ subject.instance_variable_get("@faces")[:foo][SemVer.new('0.0.1')] = 10
end
it "should return the face with the given name" do
@@ -75,13 +45,13 @@ describe Puppet::Interface::FaceCollection do
end
it "should return true if the face specified is registered" do
- subject.instance_variable_get("@faces")[:foo]['0.0.1'] = 10
+ subject.instance_variable_get("@faces")[:foo][SemVer.new('0.0.1')] = 10
subject["foo", '0.0.1'].should == 10
end
it "should attempt to require the face if it is not registered" do
subject.expects(:require).with do |file|
- subject.instance_variable_get("@faces")[:bar]['0.0.1'] = true
+ subject.instance_variable_get("@faces")[:bar][SemVer.new('0.0.1')] = true
file == 'puppet/face/bar'
end
subject["bar", '0.0.1'].should be_true
@@ -131,7 +101,9 @@ describe Puppet::Interface::FaceCollection do
it "should store the face by name" do
face = Puppet::Face.new(:my_face, '0.0.1')
subject.register(face)
- subject.instance_variable_get("@faces").should == {:my_face => {'0.0.1' => face}}
+ subject.instance_variable_get("@faces").should == {
+ :my_face => { face.version => face }
+ }
end
end
diff --git a/spec/unit/interface_spec.rb b/spec/unit/interface_spec.rb
index 8bbbcc857..4cb1f8743 100755
--- a/spec/unit/interface_spec.rb
+++ b/spec/unit/interface_spec.rb
@@ -174,6 +174,14 @@ describe Puppet::Interface do
face.get_action(:foo).options.should =~ [:quux]
face.get_action(:bar).options.should =~ [:quux]
end
+
+ it "should only list options and not aliases" do
+ face = subject.new(:face_options, '0.0.1') do
+ option "--bar", "-b", "--foo-bar"
+ end
+ face.options.should =~ [:bar]
+ end
+
end
describe "with inherited options" do
diff --git a/spec/unit/module_spec.rb b/spec/unit/module_spec.rb
index d1d01a1aa..a0f64c6d3 100755
--- a/spec/unit/module_spec.rb
+++ b/spec/unit/module_spec.rb
@@ -505,12 +505,38 @@ describe Puppet::Module do
mod.metadata_file.should == mod.metadata_file
end
- it "should know if it has a metadata file" do
+ it "should have metadata if it has a metadata file and its data is not empty" do
FileTest.expects(:exist?).with(@module.metadata_file).returns true
+ File.stubs(:read).with(@module.metadata_file).returns "{\"foo\" : \"bar\"}"
@module.should be_has_metadata
end
+ it "should have metadata if it has a metadata file and its data is not empty" do
+ FileTest.expects(:exist?).with(@module.metadata_file).returns true
+ File.stubs(:read).with(@module.metadata_file).returns "{\"foo\" : \"bar\"}"
+
+ @module.should be_has_metadata
+ end
+
+ it "should not have metadata if has a metadata file and its data is empty" do
+ FileTest.expects(:exist?).with(@module.metadata_file).returns true
+ File.stubs(:read).with(@module.metadata_file).returns "/*
++-----------------------------------------------------------------------+
+| |
+| ==> DO NOT EDIT THIS FILE! <== |
+| |
+| You should edit the `Modulefile` and run `puppet-module build` |
+| to generate the `metadata.json` file for your releases. |
+| |
++-----------------------------------------------------------------------+
+*/
+
+{}"
+
+ @module.should_not be_has_metadata
+ end
+
it "should know if it is missing a metadata file" do
FileTest.expects(:exist?).with(@module.metadata_file).returns false
@@ -528,16 +554,16 @@ describe Puppet::Module do
Puppet::Module.new("yay")
end
- describe "when loading the medatada file", :if => Puppet.features.json? do
+ describe "when loading the medatada file", :if => Puppet.features.pson? do
before do
@data = {
- :license => "GPL2",
- :author => "luke",
- :version => "1.0",
- :source => "http://foo/",
+ :license => "GPL2",
+ :author => "luke",
+ :version => "1.0",
+ :source => "http://foo/",
:puppetversion => "0.25"
}
- @text = @data.to_json
+ @text = @data.to_pson
@module = Puppet::Module.new("foo")
@module.stubs(:metadata_file).returns "/my/file"
@@ -552,9 +578,12 @@ describe Puppet::Module do
it "should fail if #{attr} is not present in the metadata file" do
@data.delete(attr.to_sym)
- @text = @data.to_json
+ @text = @data.to_pson
File.stubs(:read).with("/my/file").returns @text
- lambda { @module.load_metadata }.should raise_error(Puppet::Module::MissingMetadata)
+ lambda { @module.load_metadata }.should raise_error(
+ Puppet::Module::MissingMetadata,
+ "No #{attr} module metadata provided for foo"
+ )
end
end
diff --git a/spec/unit/semver_spec.rb b/spec/unit/semver_spec.rb
new file mode 100644
index 000000000..0e0457b6e
--- /dev/null
+++ b/spec/unit/semver_spec.rb
@@ -0,0 +1,187 @@
+require 'spec_helper'
+require 'semver'
+
+describe SemVer do
+ describe '::valid?' do
+ it 'should validate basic version strings' do
+ %w[ 0.0.0 999.999.999 v0.0.0 v999.999.999 ].each do |vstring|
+ SemVer.valid?(vstring).should be_true
+ end
+ end
+
+ it 'should validate special version strings' do
+ %w[ 0.0.0foo 999.999.999bar v0.0.0a v999.999.999beta ].each do |vstring|
+ SemVer.valid?(vstring).should be_true
+ end
+ end
+
+ it 'should fail to validate invalid version strings' do
+ %w[ nope 0.0foo 999.999 x0.0.0 z.z.z 1.2.3-beta 1.x.y ].each do |vstring|
+ SemVer.valid?(vstring).should be_false
+ end
+ end
+ end
+
+ describe '::find_matching' do
+ before :all do
+ @versions = %w[
+ 0.0.1
+ 0.0.2
+ 1.0.0rc1
+ 1.0.0rc2
+ 1.0.0
+ 1.0.1
+ 1.1.0
+ 1.1.1
+ 1.1.2
+ 1.1.3
+ 1.1.4
+ 1.2.0
+ 1.2.1
+ 2.0.0rc1
+ ].map { |v| SemVer.new(v) }
+ end
+
+ it 'should match exact versions by string' do
+ @versions.each do |version|
+ SemVer.find_matching(version, @versions).should == version
+ end
+ end
+
+ it 'should return nil if no versions match' do
+ %w[ 3.0.0 2.0.0rc2 1.0.0alpha ].each do |v|
+ SemVer.find_matching(v, @versions).should be_nil
+ end
+ end
+
+ it 'should find the greatest match for partial versions' do
+ SemVer.find_matching('1.0', @versions).should == 'v1.0.1'
+ SemVer.find_matching('1.1', @versions).should == 'v1.1.4'
+ SemVer.find_matching('1', @versions).should == 'v1.2.1'
+ SemVer.find_matching('2', @versions).should == 'v2.0.0rc1'
+ SemVer.find_matching('2.1', @versions).should == nil
+ end
+
+
+ it 'should find the greatest match for versions with placeholders' do
+ SemVer.find_matching('1.0.x', @versions).should == 'v1.0.1'
+ SemVer.find_matching('1.1.x', @versions).should == 'v1.1.4'
+ SemVer.find_matching('1.x', @versions).should == 'v1.2.1'
+ SemVer.find_matching('1.x.x', @versions).should == 'v1.2.1'
+ SemVer.find_matching('2.x', @versions).should == 'v2.0.0rc1'
+ SemVer.find_matching('2.x.x', @versions).should == 'v2.0.0rc1'
+ SemVer.find_matching('2.1.x', @versions).should == nil
+ end
+ end
+
+ describe 'instantiation' do
+ it 'should raise an exception when passed an invalid version string' do
+ expect { SemVer.new('invalidVersion') }.to raise_exception ArgumentError
+ end
+
+ it 'should populate the appropriate fields for a basic version string' do
+ version = SemVer.new('1.2.3')
+ version.major.should == 1
+ version.minor.should == 2
+ version.tiny.should == 3
+ version.special.should == ''
+ end
+
+ it 'should populate the appropriate fields for a special version string' do
+ version = SemVer.new('3.4.5beta6')
+ version.major.should == 3
+ version.minor.should == 4
+ version.tiny.should == 5
+ version.special.should == 'beta6'
+ end
+ end
+
+ describe '#matched_by?' do
+ subject { SemVer.new('v1.2.3beta') }
+
+ describe 'should match against' do
+ describe 'literal version strings' do
+ it { should be_matched_by('1.2.3beta') }
+
+ it { should_not be_matched_by('1.2.3alpha') }
+ it { should_not be_matched_by('1.2.4beta') }
+ it { should_not be_matched_by('1.3.3beta') }
+ it { should_not be_matched_by('2.2.3beta') }
+ end
+
+ describe 'partial version strings' do
+ it { should be_matched_by('1.2.3') }
+ it { should be_matched_by('1.2') }
+ it { should be_matched_by('1') }
+ end
+
+ describe 'version strings with placeholders' do
+ it { should be_matched_by('1.2.x') }
+ it { should be_matched_by('1.x.3') }
+ it { should be_matched_by('1.x.x') }
+ it { should be_matched_by('1.x') }
+ end
+ end
+ end
+
+ describe 'comparisons' do
+ describe 'against a string' do
+ it 'should just work' do
+ SemVer.new('1.2.3').should == '1.2.3'
+ end
+ end
+
+ describe 'against a symbol' do
+ it 'should just work' do
+ SemVer.new('1.2.3').should == :'1.2.3'
+ end
+ end
+
+ describe 'on a basic version (v1.2.3)' do
+ subject { SemVer.new('v1.2.3') }
+
+ it { should == SemVer.new('1.2.3') }
+
+ # Different major versions
+ it { should > SemVer.new('0.2.3') }
+ it { should < SemVer.new('2.2.3') }
+
+ # Different minor versions
+ it { should > SemVer.new('1.1.3') }
+ it { should < SemVer.new('1.3.3') }
+
+ # Different tiny versions
+ it { should > SemVer.new('1.2.2') }
+ it { should < SemVer.new('1.2.4') }
+
+ # Against special versions
+ it { should > SemVer.new('1.2.3beta') }
+ it { should < SemVer.new('1.2.4beta') }
+ end
+
+ describe 'on a special version (v1.2.3beta)' do
+ subject { SemVer.new('v1.2.3beta') }
+
+ it { should == SemVer.new('1.2.3beta') }
+
+ # Same version, final release
+ it { should < SemVer.new('1.2.3') }
+
+ # Different major versions
+ it { should > SemVer.new('0.2.3') }
+ it { should < SemVer.new('2.2.3') }
+
+ # Different minor versions
+ it { should > SemVer.new('1.1.3') }
+ it { should < SemVer.new('1.3.3') }
+
+ # Different tiny versions
+ it { should > SemVer.new('1.2.2') }
+ it { should < SemVer.new('1.2.4') }
+
+ # Against special versions
+ it { should > SemVer.new('1.2.3alpha') }
+ it { should < SemVer.new('1.2.3beta2') }
+ end
+ end
+end
diff --git a/spec/unit/util/settings_spec.rb b/spec/unit/util/settings_spec.rb
index efe2be443..f7cb19936 100755
--- a/spec/unit/util/settings_spec.rb
+++ b/spec/unit/util/settings_spec.rb
@@ -1,5 +1,6 @@
#!/usr/bin/env rspec
require 'spec_helper'
+require 'ostruct'
describe Puppet::Util::Settings do
include PuppetSpec::Files
@@ -1108,4 +1109,14 @@ describe Puppet::Util::Settings do
it "should cache the result"
end
+
+ describe "#writesub" do
+ it "should only pass valid arguments to File.open" do
+ settings = Puppet::Util::Settings.new
+ settings.stubs(:get_config_file_default).with(:privatekeydir).returns(OpenStruct.new(:mode => "750"))
+
+ File.expects(:open).with("/path/to/keydir", "w", 750).returns true
+ settings.writesub(:privatekeydir, "/path/to/keydir")
+ end
+ end
end