Skip to content
This repository has been archived by the owner on Jun 18, 2019. It is now read-only.

Commit

Permalink
New helper for fixing user/group properties on Windows and FreeBSD.
Browse files Browse the repository at this point in the history
This feels like it should be okay for all existing code I think.
  • Loading branch information
coderanger committed Apr 9, 2016
1 parent d37378d commit 6d40cfc
Show file tree
Hide file tree
Showing 6 changed files with 292 additions and 0 deletions.
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,6 @@ end
dev_gem 'halite'
dev_gem 'poise-boiler'
dev_gem 'poise-profiler'

# Pending https://github.com/customink/fauxhai/commit/d89f1e2de609478046e7a387f2b8d97729a68983
gem 'fauxhai', github: 'customink/fauxhai'
1 change: 1 addition & 0 deletions lib/poise/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ module Helpers
autoload :ResourceSubclass, 'poise/helpers/resource_subclass'
autoload :Subresources, 'poise/helpers/subresources'
autoload :TemplateContent, 'poise/helpers/template_content'
autoload :Win32User, 'poise/helpers/win32_user'
end
end
60 changes: 60 additions & 0 deletions lib/poise/helpers/win32_user.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#
# Copyright 2013-2016, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

require 'chef/mash'

require 'poise/error'
require 'poise/utils/win32'


module Poise
module Helpers
# A resource mixin to intercept properties named `user`, `group`, or `owner`,
# if their default value is `'root'` and make it work on Windows (and
# FreeBSD, AIX).
#
# @since 2.7.0
# @example
# class MyResource < Chef::Resource
# include Poise::Helpers::Win32User
# attribute(:user, default: 'root')
# attribute(:group, default: 'root')
# end
# @example Avoiding automatic translation
# class MyResource < Chef::Resource
# include Poise::Helpers::Win32User
# attribute(:user, default: lazy { 'root' })
# attribute(:group, default: lazy { 'root' })
# end
module Win32User
USER_PROPERTIES = ['user', :user, 'owner', :owner]
GROUP_PROPERTIES = ['group', :group]

def set_or_return(symbol, arg, options={})
if options && options[:default] == 'root'
if USER_PROPERTIES.include?(symbol) && node.platform_family?('windows')
options = options.dup
options[:default] = Poise::Utils::Win32.admin_user
elsif GROUP_PROPERTIES.include?(symbol)
options = options.dup
options[:default] = node['root_group']
end
end
super(symbol, arg, options)
end
end
end
end
1 change: 1 addition & 0 deletions lib/poise/resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ module Resource
include Poise::Helpers::ResourceName
include Poise::Helpers::ResourceSubclass
include Poise::Helpers::TemplateContent
include Poise::Helpers::Win32User # Must be after LazyDefault.
include Poise::Utils::ShellOut

# @!classmethods
Expand Down
50 changes: 50 additions & 0 deletions lib/poise/utils/win32.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#
# Copyright 2016, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#


module Poise
module Utils
module Win32
extend self

# Code borrowed from https://github.com/chef-cookbooks/chef-client/blob/master/libraries/helpers.rb
# Used under the terms of the Apache v2 license.
# Copyright 2012-2016, John Dewey

# Run a WMI query and extracts a property. This assumes Chef has already
# loaded the win32 libraries.
#
# @api private
# @param wmi_property [Symbol] Property to extract.
# @param wmi_query [String] Query to run.
# @return [String]
def wmi_property_from_query(wmi_property, wmi_query)
@wmi = ::WIN32OLE.connect('winmgmts://')
result = @wmi.ExecQuery(wmi_query)
return nil unless result.each.count > 0
result.each.next.send(wmi_property)
end

# Find the name of the Administrator user, give or take localization.
#
# @return [String]
def admin_user
wmi_property_from_query(:name, "select * from Win32_UserAccount where sid like 'S-1-5-21-%-500' and LocalAccount=True")
end

end
end
end
177 changes: 177 additions & 0 deletions test/spec/helpers/win32_user_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
#
# Copyright 2016, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

require 'spec_helper'

describe Poise::Helpers::Win32User do
let(:chefspec_options) { {platform: 'ubuntu', version: '14.04'} }
provider(:poise_test)
before do
allow(Poise::Utils::Win32).to receive(:admin_user).and_return('Administrator')
end

context 'user property' do
resource(:poise_test) do
include Poise::Helpers::LWRPPolyfill
include described_class
attribute(:user, default: 'root')
end

context 'with a default' do
recipe do
poise_test 'test'
end

context 'on Linux' do
it { is_expected.to run_poise_test('test').with(user: 'root') }
end # /context on Linux

context 'on Windows' do
let(:chefspec_options) { {platform: 'windows', version: '2012r2'} }
it { is_expected.to run_poise_test('test').with(user: 'Administrator') }
end # /context on Windows
end # /context with a default

context 'with a value' do
recipe do
poise_test 'test' do
user 'other'
end
end

context 'on Linux' do
it { is_expected.to run_poise_test('test').with(user: 'other') }
end # /context on Linux

context 'on Windows' do
let(:chefspec_options) { {platform: 'windows', version: '2012r2'} }
it { is_expected.to run_poise_test('test').with(user: 'other') }
end # /context on Windows
end # /context with a value
end # /context user property

context 'owner property' do
resource(:poise_test) do
include Poise::Helpers::LWRPPolyfill
include described_class
attribute(:owner, default: 'root')
end

context 'with a default' do
recipe do
poise_test 'test'
end

context 'on Linux' do
it { is_expected.to run_poise_test('test').with(owner: 'root') }
end # /context on Linux

context 'on Windows' do
let(:chefspec_options) { {platform: 'windows', version: '2012r2'} }
it { is_expected.to run_poise_test('test').with(owner: 'Administrator') }
end # /context on Windows
end # /context with a default

context 'with a value' do
recipe do
poise_test 'test' do
owner 'other'
end
end

context 'on Linux' do
it { is_expected.to run_poise_test('test').with(owner: 'other') }
end # /context on Linux

context 'on Windows' do
let(:chefspec_options) { {platform: 'windows', version: '2012r2'} }
it { is_expected.to run_poise_test('test').with(owner: 'other') }
end # /context on Windows
end # /context with a value
end # /context owner property

context 'group property' do
resource(:poise_test) do
include Poise::Helpers::LWRPPolyfill
include described_class
attribute(:group, default: 'root')
end

context 'with a default' do
recipe do
poise_test 'test'
end

context 'on Linux' do
it { is_expected.to run_poise_test('test').with(group: 'root') }
end # /context on Linux

context 'on Windows' do
let(:chefspec_options) { {platform: 'windows', version: '2012r2'} }
# This test is written to be silly because Fauxhai doesn't have
# root_group data for Windows.
it { is_expected.to run_poise_test('test').with(group: chef_run.node['root_group']) }
end # /context on Windows

context 'on AIX' do
let(:chefspec_options) { {platform: 'aix', version: '6.1'} }
it { is_expected.to run_poise_test('test').with(group: 'system') }
end # /context on AIX
end # /context with a default

context 'with a value' do
recipe do
poise_test 'test' do
group 'other'
end
end

context 'on Linux' do
it { is_expected.to run_poise_test('test').with(group: 'other') }
end # /context on Linux

context 'on Windows' do
let(:chefspec_options) { {platform: 'windows', version: '2012r2'} }
it { is_expected.to run_poise_test('test').with(group: 'other') }
end # /context on Windows
end # /context with a value
end # /context group property

describe 'interaction with lazy defaults' do
let(:chefspec_options) { {platform: 'windows', version: '2012r2'} }
recipe do
poise_test 'test'
end

context 'with a non-lazy default' do
resource(:poise_test) do
include Poise::Resource
attribute(:user, default: 'root')
end

it { is_expected.to run_poise_test('test').with(user: 'Administrator') }
end # /context with a non-lazy default

context 'with a lazy default' do
resource(:poise_test) do
include Poise::Resource
attribute(:user, default: lazy { 'root' })
end

it { is_expected.to run_poise_test('test').with(user: 'root') }
end # /context with a lazy default
end # /describe interaction with lazy defaults
end

2 comments on commit 6d40cfc

@coderanger
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ping @lamont-granquist @jkeiser for feedbacks. Should make it easier to build resources that JFW on Windows and FreeBSD without a metric ass-ton of if windows. I don't know a ton about Windows though, this might be a terrible idea.

@lamont-granquist
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hrm...

you might want to look at reviving chef/ohai#698 with your #admin_user code. your code smells a bit better to me, but i still don't know enough about windows to really gauge it...

if the hardcoded System/Administrator thing was dealt with then i could see the utility of node['root_user'] added there to node['root_group'] which would give a cross platform way to express what you're trying to do.

then i sorta can see a role for monkeypatching that in automagically since most cookbook code hardcodes 'root' and will break on windows but it should probably be opt-in. not positive you're monkeypatching in the right spot, but i haven't dug into FAC/SAC in awhile...

Please sign in to comment.