Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(#11046) improve freebsd user and group providers #338

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
34 changes: 24 additions & 10 deletions lib/puppet/provider/group/pw.rb
@@ -1,34 +1,48 @@
require 'puppet/provider/nameservice/pw'

Puppet::Type.type(:group).provide :pw, :parent => Puppet::Provider::NameService::PW do
desc "Group management via `pw`.
desc "Group management via `pw` on FreeBSD."

Only works on FreeBSD.
commands :pw => "pw"
has_features :manages_members

"

commands :pw => "/usr/sbin/pw"
defaultfor :operatingsystem => :freebsd

options :members, :flag => "-M", :method => :mem

verify :gid, "GID must be an integer" do |value|
value.is_a? Integer
end

def addcmd
cmd = [command(:pw), "groupadd", @resource[:name]]

if gid = @resource.should(:gid)
unless gid == :absent
cmd << flag(:gid) << gid
end
end

# Apparently, contrary to the man page, groupadd does
# not accept -o.
#if @parent[:allowdupe] == :true
# cmd << "-o"
#end
if members = @resource.should(:members)
unless members == :absent
if members.is_a?(Array)
members = members.join(",")
end
cmd << "-M" << members
end
end

cmd << "-o" if @resource.allowdupe?

cmd
end

def modifycmd(param, value)
# members may be an array, need a comma separated list
if param == :members and value.is_a?(Array)
value = value.join(",")
end
super(param, value)
end
end

58 changes: 56 additions & 2 deletions lib/puppet/provider/user/pw.rb
@@ -1,16 +1,18 @@
require 'puppet/provider/nameservice/pw'
require 'open3'

Puppet::Type.type(:user).provide :pw, :parent => Puppet::Provider::NameService::PW do
desc "User management via `pw` on FreeBSD."

commands :pw => "pw"
has_features :manages_homedir, :allows_duplicates
has_features :manages_homedir, :allows_duplicates, :manages_passwords, :manages_expiry

defaultfor :operatingsystem => :freebsd

options :home, :flag => "-d", :method => :dir
options :comment, :method => :gecos
options :groups, :flag => "-G"
options :expiry, :method => :expire

verify :gid, "GID must be an integer" do |value|
value.is_a? Integer
Expand All @@ -23,10 +25,14 @@
def addcmd
cmd = [command(:pw), "useradd", @resource[:name]]
@resource.class.validproperties.each do |property|
next if property == :ensure
next if property == :ensure or property == :password
# the value needs to be quoted, mostly because -c might
# have spaces in it
if value = @resource.should(property) and value != ""
if property == :expiry
# FreeBSD uses DD-MM-YYYY rather than YYYY-MM-DD
value = value.split("-").reverse.join("-")
end
cmd << flag(property) << value
end
end
Expand All @@ -37,5 +43,53 @@ def addcmd

cmd
end

def modifycmd(param, value)
if param == :expiry
# FreeBSD uses DD-MM-YYYY rather than YYYY-MM-DD
value = value.split("-").reverse.join("-")
end
cmd = super(param, value)
cmd << "-m" if @resource.managehome?
cmd
end

def create
super

# Set the password after create if given
self.password = @resource[:password] if @resource[:password]
end

# use pw to update password hash
def password=(cryptopw)
Puppet.debug "change password for user '#{@resource[:name]}' method called with hash '#{cryptopw}'"
stdin, stdout, stderr = Open3.popen3("pw user mod #{@resource[:name]} -H 0")
stdin.puts(cryptopw)
stdin.close
Puppet.debug "finished password for user '#{@resource[:name]}' method called with hash '#{cryptopw}'"
end

# get password from /etc/master.passwd
def password
Puppet.debug "checking password for user '#{@resource[:name]}' method called"
current_passline = `getent passwd #{@resource[:name]}`
current_password = current_passline.chomp.split(':')[1] if current_passline
Puppet.debug "finished password for user '#{@resource[:name]}' method called : '#{current_password}'"
current_password
end

# Get expiry from system and convert to Puppet-style date
def expiry
expiry = self.get(:expiry)
expiry = :absent if expiry == 0

if expiry != :absent
t = Time.at(expiry)
expiry = "%4d-%02d-%02d" % [t.year, t.month, t.mday]
end

expiry
end
end

81 changes: 81 additions & 0 deletions spec/unit/provider/group/pw_spec.rb
@@ -0,0 +1,81 @@
#!/usr/bin/env rspec
require 'spec_helper'

provider_class = Puppet::Type.type(:group).provider(:pw)

describe provider_class do
let :resource do
Puppet::Type.type(:group).new(:name => "testgroup", :provider => :pw)
end

let :provider do
resource.provider
end

describe "when creating groups" do
let :provider do
prov = resource.provider
prov.expects(:exists?).returns nil
prov
end

it "should run pw with no additional flags when no properties are given" do
provider.addcmd.must == [provider_class.command(:pw), "groupadd", "testgroup"]
provider.expects(:execute).with([provider_class.command(:pw), "groupadd", "testgroup"])
provider.create
end

it "should use -o when allowdupe is enabled" do
resource[:allowdupe] = true
provider.expects(:execute).with(includes("-o"))
provider.create
end

it "should use -g with the correct argument when the gid property is set" do
resource[:gid] = 12345
provider.expects(:execute).with(all_of(includes("-g"), includes(12345)))
provider.create
end

it "should use -M with the correct argument when the members property is set" do
resource[:members] = "user1"
provider.expects(:execute).with(all_of(includes("-M"), includes("user1")))
provider.create
end

it "should use -M with all the given users when the members property is set to an array" do
resource[:members] = ["user1", "user2"]
provider.expects(:execute).with(all_of(includes("-M"), includes("user1,user2")))
provider.create
end
end

describe "when deleting groups" do
it "should run pw with no additional flags" do
provider.expects(:exists?).returns true
provider.deletecmd.must == [provider_class.command(:pw), "groupdel", "testgroup"]
provider.expects(:execute).with([provider_class.command(:pw), "groupdel", "testgroup"])
provider.delete
end
end

describe "when modifying groups" do
it "should run pw with the correct arguments" do
provider.modifycmd("gid", 12345).must == [provider_class.command(:pw), "groupmod", "testgroup", "-g", 12345]
provider.expects(:execute).with([provider_class.command(:pw), "groupmod", "testgroup", "-g", 12345])
provider.gid = 12345
end

it "should use -M with the correct argument when the members property is changed" do
resource[:members] = "user1"
provider.expects(:execute).with(all_of(includes("-M"), includes("user2")))
provider.members = "user2"
end

it "should use -M with all the given users when the members property is changed with an array" do
resource[:members] = ["user1", "user2"]
provider.expects(:execute).with(all_of(includes("-M"), includes("user3,user4")))
provider.members = ["user3", "user4"]
end
end
end