diff --git a/.travis.yml b/.travis.yml index 242055a9..7cfecdf8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ --- +sudo: false language: ruby bundler_args: --without development script: "bundle exec rake spec SPEC_OPTS='--format documentation'" diff --git a/lib/puppet/provider/sqlserver.rb b/lib/puppet/provider/sqlserver.rb index ba788223..eabb84be 100644 --- a/lib/puppet/provider/sqlserver.rb +++ b/lib/puppet/provider/sqlserver.rb @@ -55,7 +55,10 @@ def self.run_authenticated_sqlcmd(query, opts) 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 debug("Return result #{result}") if opts[:failonfail] && result.match(/THROW CAUGHT/) - fail(result.gsub('THROW CAUGHT:','')) + fail(result.gsub('THROW CAUGHT:', '')) + end + if result.match(/Msg \d+, Level 16/) + fail(result) end return result ensure diff --git a/lib/puppet/templates/authenticated_query.ps1.erb b/lib/puppet/templates/authenticated_query.ps1.erb index 5e712d02..a66b62ce 100644 --- a/lib/puppet/templates/authenticated_query.ps1.erb +++ b/lib/puppet/templates/authenticated_query.ps1.erb @@ -34,6 +34,12 @@ $result = sqlcmd.exe -i '<%= input_file %>' -h-1 -W -s ',' <% if @instance != 'M Write-Error -Message ($result | where {$_ -match "Incorrect syntax"} | select -First 1) exit(10) } + if($result -match "Msg \d+, Level 16"){ + $msg = $result -join ' ' + Write-Host $msg + Write-Error -Message "ERROR: $msg" + exit(10) + } } catch{ Write-Host $_ diff --git a/manifests/user.pp b/manifests/user.pp index 08a3869f..68dd2df9 100644 --- a/manifests/user.pp +++ b/manifests/user.pp @@ -1,6 +1,38 @@ ## +# == Define Resource Type: sqlserver::user # +# === Requirement/Dependencies: # +# Requires defined type {sqlserver::config} in order to execute against the SQL Server instance +# +# === Examples +# +# sqlserver::user{'myUser': +# database => 'loggingDatabase', +# login => 'myUser', +# } +# +# === Parameters +# [user] +# The username you want to manage, defaults to the title +# +# [database] +# The database you want the user to be created as +# +# [ensure] +# Ensure present or absent +# +# [default_schema] +# SQL schema you would like to default to, typically 'dbo' +# +# [instance] +# The named instance you want to manage against +# +# [login] +# The login to associate the user with, by default SQL Server will assume user and login match if left empty +# +# [password] +# The password for the user, can only be used when the database is a contained database. # ## define sqlserver::user ( @@ -11,7 +43,6 @@ $instance = 'MSSQLSERVER', $login = undef, $password = undef, - $force_delete = false, ) { sqlserver_validate_instance_name($instance) @@ -19,12 +50,12 @@ $is_windows_user = sqlserver_is_domain_or_local_user($login) if $password { - validate_re($password, '^.{1,128}$', 'Password must be equal or less than 128 characters') + sqlserver_validate_range($password, 1, 128, 'Password must be equal or less than 128 characters') if $is_windows_user and $login != undef{ fail('Can not provide password when using a Windows Login') } } - validate_re($database, '^.{1,128}$','Database name must be between 1 and 128 characters') + sqlserver_validate_range($database, 1, 128, 'Database name must be between 1 and 128 characters') $create_delete = $ensure ? { present => 'create', diff --git a/spec/defines/user_spec.rb b/spec/defines/user_spec.rb index 95b7c591..33a67ba5 100644 --- a/spec/defines/user_spec.rb +++ b/spec/defines/user_spec.rb @@ -78,7 +78,7 @@ let(:additional_params) { {:user => 'myMachineName/myUser'} } let(:sqlserver_tsql_title) { 'user-MSSQLSERVER-myDatabase-myMachineName/myUser' } let(:should_contain_command) { [ - "USE [myDatabase]", + "USE [myDatabase];", 'CREATE USER [myMachineName/myUser]' ] } it_should_behave_like 'sqlserver_tsql command' @@ -93,9 +93,24 @@ ] } it_should_behave_like 'sqlserver_tsql command' end + describe 'have dependency on Sqlserver::Config[MSSQLSERVER]' do it 'should require ::config' do should contain_sqlserver_tsql(sqlserver_tsql_title).with_require('Sqlserver::Config[MSSQLSERVER]') end end + + describe 'when ensure => absent' do + let(:additional_params) { {:ensure => 'absent'} } + let(:sqlserver_contain_command) { [ + 'USE [loggingDb];\nDROP [loggingUser]', + "\nIF EXISTS(SELECT name FROM sys.database_principals WHERE name = 'loggingUser')\n THROW", + ] } + let(:sqlserver_contain_onlyif) { [ + "\nIF EXISTS(SELECT name FROM sys.database_principals WHERE type in ('U','S','G') AND name = 'loggingUser')\n", + ] } + it_should_behave_like 'sqlserver_tsql command' + it_should_behave_like 'sqlserver_tsql onlyif' + end + end diff --git a/templates/create/user.sql.erb b/templates/create/user.sql.erb index 765ea6db..b92616e3 100644 --- a/templates/create/user.sql.erb +++ b/templates/create/user.sql.erb @@ -1,8 +1,7 @@ --- Need to use exec instead of use statement as this will trigger try catch USE [<%= @database %>]; <% if @password %> IF EXISTS(select containment from sys.databases WHERE name = '<%= @database %>' AND containment = 0) - THROW 51000, 'Database must be contained in order to use passwords', 0 + THROW 51000, 'Database must be contained in order to use passwords', 10 <% end %> CREATE USER [<%= @user %>] <% if @login -%> diff --git a/templates/delete/user.sql.erb b/templates/delete/user.sql.erb new file mode 100644 index 00000000..fffdbe7d --- /dev/null +++ b/templates/delete/user.sql.erb @@ -0,0 +1,4 @@ +USE [<%= @database %>]; +DROP USER [<%= @user %>]; +IF EXISTS(SELECT name FROM sys.database_principals WHERE name = '<%= @user %>') + THROW 51000, 'Failed to drop user <%= @user %>', 10