Skip to content

Commit

Permalink
(#12460) use replace_file for the .k5login file
Browse files Browse the repository at this point in the history
Previously this hand-coded replacing the .k5login file; Replacing that with
the standard API ensures consistent, safe, and atomic updates of the target
file.

It also reduces the cognitive burden of the provider, since the semantics of
the standard method are clearer than the semantics of the type.

Finally, this commit adds some tests for the type, and the inline provider, to
help ensure that the type continues to work into the future.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
  • Loading branch information
Daniel Pittman authored and haus committed Feb 20, 2012
1 parent 7900a66 commit 0c96703
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 2 deletions.
5 changes: 3 additions & 2 deletions lib/puppet/type/k5login.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Plug-in type for handling k5login files
require 'puppet/util'

Puppet::Type.newtype(:k5login) do
@doc = "Manage the `.k5login` file for a user. Specify the full path to
Expand Down Expand Up @@ -79,8 +80,8 @@ def mode=(value)

private
def write(value)
Puppet::Util.secure_open(@resource[:name], "w") do |f|
f.puts value.join("\n")
Puppet::Util.replace_file(@resource[:name], 0644) do |f|
f.puts value
end
end
end
Expand Down
115 changes: 115 additions & 0 deletions spec/unit/type/k5login_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#!/usr/bin/env ruby
require 'spec_helper'
require 'fileutils'
require 'puppet/type'

describe Puppet::Type.type(:k5login) do
include PuppetSpec::Files

context "the type class" do
subject { described_class }
it { should be_validattr :ensure }
it { should be_validattr :path }
it { should be_validattr :principals }
it { should be_validattr :mode }
# We have one, inline provider implemented.
it { should be_validattr :provider }
end

let(:path) { tmpfile('k5login') }

def resource(attrs = {})
attrs = {
:ensure => 'present',
:path => path,
:principals => 'fred@EXAMPLE.COM'
}.merge(attrs)

if content = attrs.delete(:content)
File.open(path, 'w') { |f| f.print(content) }
end

resource = described_class.new(attrs)
resource
end

before :each do
FileUtils.touch(path)
end

context "the provider" do
context "when the file is missing" do
it "should initially be absent" do
File.delete(path)
resource.retrieve[:ensure].must == :absent
end

it "should create the file when synced" do
resource(:ensure => 'present').parameter(:ensure).sync
File.should be_exist path
end
end

context "when the file is present" do
context "retrieved initial state" do
subject { resource.retrieve }

it "should retrieve its properties correctly with zero principals" do
subject[:ensure].should == :present
subject[:principals].should == []
# We don't really care what the mode is, just that it got it
subject[:mode].should_not be_nil
end

context "with one principal" do
subject { resource(:content => "daniel@EXAMPLE.COM\n").retrieve }

it "should retrieve its principals correctly" do
subject[:principals].should == ["daniel@EXAMPLE.COM"]
end
end

context "with two principals" do
subject do
content = ["daniel@EXAMPLE.COM", "george@EXAMPLE.COM"].join("\n")
resource(:content => content).retrieve
end

it "should retrieve its principals correctly" do
subject[:principals].should == ["daniel@EXAMPLE.COM", "george@EXAMPLE.COM"]
end
end
end

it "should remove the file ensure is absent" do
resource(:ensure => 'absent').property(:ensure).sync
File.should_not be_exist path
end

it "should write one principal to the file" do
File.read(path).should == ""
resource(:principals => ["daniel@EXAMPLE.COM"]).property(:principals).sync
File.read(path).should == "daniel@EXAMPLE.COM\n"
end

it "should write multiple principals to the file" do
content = ["daniel@EXAMPLE.COM", "george@EXAMPLE.COM"]

File.read(path).should == ""
resource(:principals => content).property(:principals).sync
File.read(path).should == content.join("\n") + "\n"
end

describe "when setting the mode", :unless => Puppet.features.microsoft_windows? do
# The defined input type is "mode, as an octal string"
["400", "600", "700", "644", "664"].each do |mode|
it "should update the mode to #{mode}" do
resource(:mode => mode).property(:mode).sync

(File.stat(path).mode & 07777).to_s(8).should == mode
end
end
end
end
end
end

0 comments on commit 0c96703

Please sign in to comment.