aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--acceptance/tests/resource/mailalias/create.rb32
-rw-r--r--acceptance/tests/resource/mailalias/destroy.rb41
-rw-r--r--acceptance/tests/resource/mailalias/modify.rb41
-rw-r--r--acceptance/tests/resource/mailalias/query.rb35
-rw-r--r--lib/puppet/provider/mailalias/aliases.rb50
-rw-r--r--lib/puppet/type/mailalias.rb46
-rw-r--r--spec/fixtures/integration/provider/mailalias/aliases/test131
-rw-r--r--spec/integration/provider/mailalias/aliases_spec.rb10
-rw-r--r--spec/unit/type/mailalias_spec.rb49
9 files changed, 335 insertions, 0 deletions
diff --git a/acceptance/tests/resource/mailalias/create.rb b/acceptance/tests/resource/mailalias/create.rb
new file mode 100644
index 0000000..e1d40b9
--- /dev/null
+++ b/acceptance/tests/resource/mailalias/create.rb
@@ -0,0 +1,32 @@
+test_name "should create an email alias"
+
+confine :except, :platform => 'windows'
+
+tag 'audit:low',
+ 'audit:refactor', # Use block style `test_name`
+ 'audit:acceptance' # Could be done at the integration (or unit) layer though
+ # actual changing of resources could irreparably damage a
+ # host running this, or require special permissions.
+
+name = "pl#{rand(999999).to_i}"
+agents.each do |agent|
+ teardown do
+ #(teardown) restore the alias file
+ on(agent, "mv /tmp/aliases /etc/aliases", :acceptable_exit_codes => [0,1])
+ end
+
+ #------- SETUP -------#
+ step "(setup) backup alias file"
+ on(agent, "cp /etc/aliases /tmp/aliases", :acceptable_exit_codes => [0,1])
+
+ #------- TESTS -------#
+ step "create a mailalias with puppet"
+ args = ['ensure=present',
+ 'recipient="foo,bar,baz"']
+ on(agent, puppet_resource('mailalias', name, args))
+
+ step "verify the alias exists"
+ on(agent, "cat /etc/aliases") do |res|
+ assert_match(/#{name}:.*foo,bar,baz/, res.stdout, "mailalias not in aliases file")
+ end
+end
diff --git a/acceptance/tests/resource/mailalias/destroy.rb b/acceptance/tests/resource/mailalias/destroy.rb
new file mode 100644
index 0000000..63bc3d0
--- /dev/null
+++ b/acceptance/tests/resource/mailalias/destroy.rb
@@ -0,0 +1,41 @@
+test_name "should delete an email alias"
+
+confine :except, :platform => 'windows'
+
+tag 'audit:low',
+ 'audit:refactor', # Use block style `test_name`
+ 'audit:acceptance' # Could be done at the integration (or unit) layer though
+ # actual changing of resources could irreparably damage a
+ # host running this, or require special permissions.
+
+name = "pl#{rand(999999).to_i}"
+agents.each do |agent|
+ teardown do
+ #(teardown) restore the alias file
+ on(agent, "mv /tmp/aliases /etc/aliases", :acceptable_exit_codes => [0,1])
+ end
+
+ #------- SETUP -------#
+ step "(setup) backup alias file"
+ on(agent, "cp /etc/aliases /tmp/aliases", :acceptable_exit_codes => [0,1])
+
+ step "(setup) create a mailalias"
+ on(agent, "echo '#{name}: foo,bar,baz' >> /etc/aliases")
+
+ step "(setup) verify the alias exists"
+ on(agent, "cat /etc/aliases") do |res|
+ assert_match(/#{name}:.*foo,bar,baz/, res.stdout, "mailalias not in aliases file")
+ end
+
+ #------- TESTS -------#
+ step "delete the aliases database with puppet"
+ args = ['ensure=absent',
+ 'recipient="foo,bar,baz"']
+ on(agent, puppet_resource('mailalias', name, args))
+
+
+ step "verify the alias is absent"
+ on(agent, "cat /etc/aliases") do |res|
+ assert_no_match(/#{name}:.*foo,bar,baz/, res.stdout, "mailalias was not removed from aliases file")
+ end
+end
diff --git a/acceptance/tests/resource/mailalias/modify.rb b/acceptance/tests/resource/mailalias/modify.rb
new file mode 100644
index 0000000..832043b
--- /dev/null
+++ b/acceptance/tests/resource/mailalias/modify.rb
@@ -0,0 +1,41 @@
+test_name "should modify an email alias"
+
+confine :except, :platform => 'windows'
+
+tag 'audit:low',
+ 'audit:refactor', # Use block style `test_name`
+ 'audit:acceptance' # Could be done at the integration (or unit) layer though
+ # actual changing of resources could irreparably damage a
+ # host running this, or require special permissions.
+
+name = "pl#{rand(999999).to_i}"
+agents.each do |agent|
+ teardown do
+ #(teardown) restore the alias file
+ on(agent, "mv /tmp/aliases /etc/aliases", :acceptable_exit_codes => [0,1])
+ end
+
+ #------- SETUP -------#
+ step "(setup) backup alias file"
+ on(agent, "cp /etc/aliases /tmp/aliases", :acceptable_exit_codes => [0,1])
+
+ step "(setup) create a mailalias"
+ on(agent, "echo '#{name}: foo,bar,baz' >> /etc/aliases")
+
+ step "(setup) verify the alias exists"
+ on(agent, "cat /etc/aliases") do |res|
+ assert_match(/#{name}:.*foo,bar,baz/, res.stdout, "mailalias not in aliases file")
+ end
+
+ #------- TESTS -------#
+ step "modify the aliases database with puppet"
+ args = ['ensure=present',
+ 'recipient="foo,bar,baz,blarvitz"']
+ on(agent, puppet_resource('mailalias', name, args))
+
+
+ step "verify the updated alias is present"
+ on(agent, "cat /etc/aliases") do |res|
+ assert_match(/#{name}:.*foo,bar,baz,blarvitz/, res.stdout, "updated mailalias not in aliases file")
+ end
+end
diff --git a/acceptance/tests/resource/mailalias/query.rb b/acceptance/tests/resource/mailalias/query.rb
new file mode 100644
index 0000000..40e495a
--- /dev/null
+++ b/acceptance/tests/resource/mailalias/query.rb
@@ -0,0 +1,35 @@
+test_name "should be able to find an exisitng email alias"
+
+confine :except, :platform => 'windows'
+
+tag 'audit:low',
+ 'audit:refactor', # Use block style `test_name`
+ 'audit:acceptance' # Could be done at the integration (or unit) layer though
+ # actual changing of resources could irreparably damage a
+ # host running this, or require special permissions.
+
+name = "pl#{rand(999999).to_i}"
+agents.each do |agent|
+ teardown do
+ #(teardown) restore the alias file
+ on(agent, "mv /tmp/aliases /etc/aliases", :acceptable_exit_codes => [0,1])
+ end
+
+ #------- SETUP -------#
+ step "(setup) backup alias file"
+ on(agent, "cp /etc/aliases /tmp/aliases", :acceptable_exit_codes => [0,1])
+
+ step "(setup) create a mailalias"
+ on(agent, "echo '#{name}: foo,bar,baz' >> /etc/aliases")
+
+ step "(setup) verify the alias exists"
+ on(agent, "cat /etc/aliases") do |res|
+ assert_match(/#{name}:.*foo,bar,baz/, res.stdout, "mailalias not in aliases file")
+ end
+
+ #------- TESTS -------#
+ step "query for the mail alias with puppet"
+ on(agent, puppet_resource('mailalias', name)) do
+ fail_test "didn't find the scheduled_task #{name}" unless stdout.include? 'present'
+ end
+end
diff --git a/lib/puppet/provider/mailalias/aliases.rb b/lib/puppet/provider/mailalias/aliases.rb
new file mode 100644
index 0000000..038d450
--- /dev/null
+++ b/lib/puppet/provider/mailalias/aliases.rb
@@ -0,0 +1,50 @@
+require 'puppet/provider/parsedfile'
+
+Puppet::Type.type(:mailalias).provide(
+ :aliases,
+ :parent => Puppet::Provider::ParsedFile,
+ :default_target => "/etc/aliases",
+ :filetype => :flat
+) do
+ text_line :comment, :match => /^#/
+ text_line :blank, :match => /^\s*$/
+
+ record_line :aliases, :fields => %w{name recipient}, :separator => /\s*:\s*/, :block_eval => :instance do
+ def post_parse(record)
+ if record[:recipient]
+ record[:recipient] = record[:recipient].split(/\s*,\s*/).collect { |d| d.gsub(/^['"]|['"]$/, '') }
+ end
+ record
+ end
+
+ def process(line)
+ ret = {}
+ records = line.split(':',4)
+ ret[:name] = records[0].strip
+ if records.length == 4 and records[2].strip == 'include'
+ ret[:file] = records[3].strip
+ else
+ records = line.split(':',2)
+ ret[:recipient] = records[1].strip
+ end
+ ret
+ end
+
+ def to_line(record)
+ if record[:recipient]
+ dest = record[:recipient].collect do |d|
+ # Quote aliases that have non-alpha chars
+ if d =~ /[^-+\w@.]/
+ '"%s"' % d
+ else
+ d
+ end
+ end.join(",")
+ "#{record[:name]}: #{dest}"
+ elsif record[:file]
+ "#{record[:name]}: :include: #{record[:file]}"
+ end
+ end
+ end
+end
+
diff --git a/lib/puppet/type/mailalias.rb b/lib/puppet/type/mailalias.rb
new file mode 100644
index 0000000..b5df7b8
--- /dev/null
+++ b/lib/puppet/type/mailalias.rb
@@ -0,0 +1,46 @@
+module Puppet
+ Type.newtype(:mailalias) do
+ @doc = "Creates an email alias in the local alias database."
+
+ ensurable
+
+ newparam(:name, :namevar => true) do
+ desc "The alias name."
+ end
+
+ newproperty(:recipient, :array_matching => :all) do
+ desc "Where email should be sent. Multiple values
+ should be specified as an array. The file and the
+ recipient entries are mutually exclusive."
+ end
+
+ newproperty(:file) do
+ desc "A file containing the alias's contents. The file and the
+ recipient entries are mutually exclusive."
+
+ validate do |value|
+ unless Puppet::Util.absolute_path?(value)
+ fail Puppet::Error, _("File paths must be fully qualified, not '%{value}'") % { value: value }
+ end
+ end
+ end
+
+ newproperty(:target) do
+ desc "The file in which to store the aliases. Only used by
+ those providers that write to disk."
+
+ defaultto { if @resource.class.defaultprovider.ancestors.include?(Puppet::Provider::ParsedFile)
+ @resource.class.defaultprovider.default_target
+ else
+ nil
+ end
+ }
+ end
+
+ validate do
+ if self[:recipient] && self[:file]
+ self.fail _("You cannot specify both a recipient and a file")
+ end
+ end
+ end
+end
diff --git a/spec/fixtures/integration/provider/mailalias/aliases/test1 b/spec/fixtures/integration/provider/mailalias/aliases/test1
new file mode 100644
index 0000000..a69be8a
--- /dev/null
+++ b/spec/fixtures/integration/provider/mailalias/aliases/test1
@@ -0,0 +1,31 @@
+# Basic system aliases -- these MUST be present
+MAILER-DAEMON: postmaster
+postmaster: root
+
+# General redirections for pseudo accounts
+bin: root
+daemon: root
+named: root
+nobody: root
+uucp: root
+www: root
+ftp-bugs: root
+postfix: root
+
+# Put your local aliases here.
+
+# Well-known aliases
+manager: root
+dumper: root
+operator: root
+abuse: postmaster
+
+# trap decode to catch security attacks
+decode: root
+
+# Other tests
+anothertest: "|/path/to/rt-mailgate --queue 'another test' --action correspond --url http://my.com/"
+test: "|/path/to/rt-mailgate --queue 'test' --action correspond --url http://my.com/"
+
+# Included file
+incfile: :include: /tmp/somefile
diff --git a/spec/integration/provider/mailalias/aliases_spec.rb b/spec/integration/provider/mailalias/aliases_spec.rb
new file mode 100644
index 0000000..64cef1c
--- /dev/null
+++ b/spec/integration/provider/mailalias/aliases_spec.rb
@@ -0,0 +1,10 @@
+#! /usr/bin/env ruby
+require 'spec_helper'
+require 'shared_behaviours/all_parsedfile_providers'
+
+provider_class = Puppet::Type.type(:mailalias).provider(:aliases)
+
+describe provider_class do
+ # #1560, in which we corrupt the format of complex mail aliases.
+ it_should_behave_like "all parsedfile providers", provider_class
+end
diff --git a/spec/unit/type/mailalias_spec.rb b/spec/unit/type/mailalias_spec.rb
new file mode 100644
index 0000000..eb701c6
--- /dev/null
+++ b/spec/unit/type/mailalias_spec.rb
@@ -0,0 +1,49 @@
+#! /usr/bin/env ruby
+require 'spec_helper'
+
+describe Puppet::Type.type(:mailalias) do
+ include PuppetSpec::Files
+
+ let :tmpfile_path do tmpfile('afile') end
+ let :target do tmpfile('mailalias') end
+ let :recipient_resource do
+ described_class.new(:name => "luke", :recipient => "yay", :target => target)
+ end
+
+ let :file_resource do
+ described_class.new(:name => "lukefile", :file => tmpfile_path, :target => target)
+ end
+
+ it "should be initially absent as a recipient" do
+ expect(recipient_resource.retrieve_resource[:recipient]).to eq(:absent)
+ end
+
+ it "should be initially absent as an included file" do
+ expect(file_resource.retrieve_resource[:file]).to eq(:absent)
+ end
+
+ it "should try and set the recipient when it does the sync" do
+ expect(recipient_resource.retrieve_resource[:recipient]).to eq(:absent)
+ recipient_resource.property(:recipient).expects(:set).with(["yay"])
+ recipient_resource.property(:recipient).sync
+ end
+
+ it "should try and set the included file when it does the sync" do
+ expect(file_resource.retrieve_resource[:file]).to eq(:absent)
+ file_resource.property(:file).expects(:set).with(tmpfile_path)
+ file_resource.property(:file).sync
+ end
+
+ it "should fail when file is not an absolute path" do
+ expect {
+ Puppet::Type.type(:mailalias).new(:name => 'x', :file => 'afile')
+ }.to raise_error Puppet::Error, /File paths must be fully qualified/
+ end
+
+ it "should fail when both file and recipient are specified" do
+ expect {
+ Puppet::Type.type(:mailalias).new(:name => 'x', :file => tmpfile_path,
+ :recipient => 'foo@example.com')
+ }.to raise_error Puppet::Error, /cannot specify both a recipient and a file/
+ end
+end