Skip to content

Commit 58be6dd

Browse files
committed
Merge pull request #68 from cyberious/FM1900
FM-1900 Add User defined type
2 parents ac27cfc + 6056a42 commit 58be6dd

File tree

7 files changed

+169
-3
lines changed

7 files changed

+169
-3
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ script: "bundle exec rake spec SPEC_OPTS='--format documentation'"
55
rvm:
66
- 1.9.3
77
- 2.0.0
8+
- 2.1.5
89
env:
910
matrix:
1011
- PUPPET_GEM_VERSION="~> 3.7.1"

Gemfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ group :development, :test do
44
gem 'nokogiri'
55
gem 'mime-types', '<2.0', :require => false
66
gem 'rake', :require => false
7-
gem 'rspec-puppet', :require => false
7+
gem 'rspec-puppet', '~>1.0', :require => false
88
gem 'puppetlabs_spec_helper', :require => false
99
gem 'puppet-lint', :require => false
1010
gem 'simplecov', :require => false

lib/puppet/provider/sqlserver.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ def self.run_authenticated_sqlcmd(query, opts)
5454
#We want to not fail the exec but fail the overall process once we get the clean result back, otherwise we report the temp file which is meaningless
5555
result = Puppet::Util::Execution.execute(['powershell.exe', '-noprofile', '-executionpolicy', 'unrestricted', temp_ps1.path], {:failonfail => false}) #We expect some things to fail in order to run as an only if
5656
debug("Return result #{result}")
57-
if opts[:failonfail] && result.match(/ERROR/)
58-
fail(result)
57+
if opts[:failonfail] && result.match(/THROW CAUGHT/)
58+
fail(result.gsub('THROW CAUGHT:',''))
5959
end
6060
return result
6161
ensure

manifests/user.pp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
##
2+
#
3+
#
4+
#
5+
##
6+
define sqlserver::user (
7+
$database,
8+
$ensure = 'present',
9+
$user = $title,
10+
$default_schema = undef,
11+
$instance = 'MSSQLSERVER',
12+
$login = undef,
13+
$password = undef,
14+
$force_delete = false,
15+
)
16+
{
17+
sqlserver_validate_instance_name($instance)
18+
19+
$is_windows_user = sqlserver_is_domain_or_local_user($login)
20+
21+
if $password {
22+
validate_re($password, '^.{1,128}$', 'Password must be equal or less than 128 characters')
23+
if $is_windows_user and $login != undef{
24+
fail('Can not provide password when using a Windows Login')
25+
}
26+
}
27+
validate_re($database, '^.{1,128}$','Database name must be between 1 and 128 characters')
28+
29+
$create_delete = $ensure ? {
30+
present => 'create',
31+
absent => 'delete',
32+
}
33+
34+
sqlserver_tsql{ "user-${instance}-${database}-${user}":
35+
instance => $instance,
36+
command => template("sqlserver/${create_delete}/user.sql.erb"),
37+
onlyif => template('sqlserver/query/user_exists.sql.erb'),
38+
require => Sqlserver::Config[$instance]
39+
}
40+
41+
}

spec/defines/user_spec.rb

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
require 'spec_helper'
2+
require File.expand_path(File.join(File.dirname(__FILE__), 'manifest_shared_examples.rb'))
3+
4+
RSpec.describe 'sqlserver::user', :type => :define do
5+
include_context 'manifests' do
6+
let(:title) { 'loggingUser' }
7+
let(:sqlserver_tsql_title) { 'user-MSSQLSERVER-myDatabase-loggingUser' }
8+
let(:params) { {:user => 'loggingUser', :database => 'myDatabase'} }
9+
end
10+
11+
describe 'should fail when password above 128 characters' do
12+
o = [('a'..'z'), ('A'..'Z'), (0..9)].map { |i| i.to_a }.flatten
13+
string = (0...129).map { o[rand(o.length)] }.join
14+
let(:additional_params) { {:password => string} }
15+
let(:raise_error_check) { 'Password must be equal or less than 128 characters' }
16+
it_should_behave_like 'validation error'
17+
end
18+
19+
describe 'should fail when database above 128 characters' do
20+
o = [('a'..'z'), ('A'..'Z'), (0..9)].map { |i| i.to_a }.flatten
21+
string = (0...129).map { o[rand(o.length)] }.join
22+
let(:additional_params) { {:database => string} }
23+
let(:raise_error_check) { 'Database name must be between 1 and 128 characters' }
24+
let(:sqlserver_tsql_title) { "user-MSSQLSERVER-#{string}-loggingUser" }
25+
it_should_behave_like 'validation error'
26+
end
27+
28+
describe 'should contain correct sql syntax for check' do
29+
let(:should_contain_onlyif) { [
30+
"USE [myDatabase]",
31+
"\nIF NOT EXISTS(SELECT name FROM sys.database_principals WHERE type in ('U','S','G') AND name = 'loggingUser')\n",
32+
"THROW 51000, 'User [loggingUser] does not exist for database [myDatabase]', 10\n"
33+
] }
34+
let(:should_contain_command) { [
35+
"USE [myDatabase]",
36+
/CREATE USER \[loggingUser\]\n\s+FROM LOGIN \[mySysLogin\]/
37+
] }
38+
let(:should_not_contain_command) { [
39+
'PASSWORD',
40+
'DEFAULT_SCHEMA',
41+
'WITH'
42+
] }
43+
let(:additional_params) { {:login => 'mySysLogin'} }
44+
it_should_behave_like 'sqlserver_tsql onlyif'
45+
it_should_behave_like 'sqlserver_tsql command'
46+
it_should_behave_like 'sqlserver_tsql without_command'
47+
end
48+
49+
describe 'when a password is specified' do
50+
password = 'Pupp3t1@'
51+
let(:additional_params) { {:password => password} }
52+
let(:should_contain_command) { [
53+
"USE [myDatabase];",
54+
/CREATE USER \[loggingUser\]\n\s+WITH PASSWORD = '#{password}'/
55+
] }
56+
let(:should_not_contain_command) { [
57+
'DEFAULT_SCHEMA',
58+
] }
59+
it_should_behave_like 'sqlserver_tsql onlyif'
60+
it_should_behave_like 'sqlserver_tsql command'
61+
it_should_behave_like 'sqlserver_tsql without_command'
62+
end
63+
64+
describe 'when a default_schema is specified' do
65+
let(:additional_params) { {:default_schema => 'dbo'} }
66+
let(:should_contain_command) { [
67+
"USE [myDatabase]",
68+
/CREATE USER \[loggingUser\]\n\s+WITH\s+DEFAULT_SCHEMA = dbo/
69+
] }
70+
let(:should_not_contain_command) { [
71+
'PASSWORD',
72+
] }
73+
it_should_behave_like 'sqlserver_tsql command'
74+
it_should_behave_like 'sqlserver_tsql without_command'
75+
end
76+
77+
describe 'when providing windows user' do
78+
let(:additional_params) { {:user => 'myMachineName/myUser'} }
79+
let(:sqlserver_tsql_title) { 'user-MSSQLSERVER-myDatabase-myMachineName/myUser' }
80+
let(:should_contain_command) { [
81+
"USE [myDatabase]",
82+
'CREATE USER [myMachineName/myUser]'
83+
] }
84+
it_should_behave_like 'sqlserver_tsql command'
85+
end
86+
87+
describe 'when providing a windows user and login' do
88+
let(:additional_params) { {:user => 'myMachineName/myUser', :login => 'myMachineName/myUser'} }
89+
let(:sqlserver_tsql_title) { 'user-MSSQLSERVER-myDatabase-myMachineName/myUser' }
90+
let(:should_contain_command) { [
91+
"USE [myDatabase]",
92+
/CREATE USER \[myMachineName\/myUser\]\n\s+FROM LOGIN \[myMachineName\/myUser\]/
93+
] }
94+
it_should_behave_like 'sqlserver_tsql command'
95+
end
96+
describe 'have dependency on Sqlserver::Config[MSSQLSERVER]' do
97+
it 'should require ::config' do
98+
should contain_sqlserver_tsql(sqlserver_tsql_title).with_require('Sqlserver::Config[MSSQLSERVER]')
99+
end
100+
end
101+
end

templates/create/user.sql.erb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
-- Need to use exec instead of use statement as this will trigger try catch
2+
USE [<%= @database %>];
3+
<% if @password %>
4+
IF EXISTS(select containment from sys.databases WHERE name = '<%= @database %>' AND containment = 0)
5+
THROW 51000, 'Database must be contained in order to use passwords', 0
6+
<% end %>
7+
CREATE USER [<%= @user %>]
8+
<% if @login -%>
9+
FROM LOGIN [<%= @login %>]
10+
<% else -%>
11+
<% if @password -%>
12+
WITH PASSWORD = '<%= @password %>'
13+
<% end -%>
14+
<% end -%>
15+
<% if @default_schema -%>
16+
<% if @password -%>,<% else -%>
17+
WITH <% end -%>
18+
DEFAULT_SCHEMA = <%= @default_schema %>
19+
<% end -%>

templates/query/user_exists.sql.erb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- Need to use exec instead of use statement as this will trigger try catch
2+
USE [<%= @database %>];
3+
IF <% if @ensure == 'present' %>NOT<% end %> EXISTS(SELECT name FROM sys.database_principals WHERE type in ('U','S','G') AND name = '<%= @user %>')
4+
THROW 51000, 'User [<%= @user %>] does not exist for database [<%= @database %>]', 10

0 commit comments

Comments
 (0)