Skip to content

Commit

Permalink
feat: add user_role module
Browse files Browse the repository at this point in the history
  • Loading branch information
lowlydba committed Dec 15, 2024
1 parent b704ebb commit 835a244
Show file tree
Hide file tree
Showing 8 changed files with 321 additions and 1 deletion.
2 changes: 1 addition & 1 deletion galaxy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace: lowlydba
name: sqlserver
version: 2.3.6
version: 2.4.0
readme: README.md
authors:
- John McCall (github.com/lowlydba)
Expand Down
123 changes: 123 additions & 0 deletions plugins/modules/user_role.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#!powershell
# -*- coding: utf-8 -*-

# (c) 2022, John McCall (@lowlydba)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

#AnsibleRequires -CSharpUtil Ansible.Basic
#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="2.0.0" }

$ErrorActionPreference = "Stop"

$spec = @{
supports_check_mode = $true
options = @{
database = @{type = 'str'; required = $true }
username = @{type = 'str'; required = $true }
role = @{type = 'str'; required = $true }
state = @{type = 'str'; required = $false; default = 'present'; choices = @('present', 'absent') }
}
}

$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
$username = $module.Params.username
$database = $module.Params.database
$role = $module.Params.role
$state = $module.Params.state
$checkMode = $module.CheckMode

$module.Result.changed = $false

$getUserSplat = @{
SqlInstance = $sqlInstance
SqlCredential = $sqlCredential
Database = $database
User = $username
EnableException = $true
}
$getRoleSplat = @{
SqlInstance = $sqlInstance
SqlCredential = $sqlCredential
Database = $database
Role = $role
EnableException = $true
}
$getRoleMemberSplat = @{
SqlInstance = $sqlInstance
SqlCredential = $sqlCredential
Database = $database
Role = $role
IncludeSystemUser = $true
EnableException = $true
}

# Verify user and role exist, DBATools currently fails silently
$existingUser = Get-DbaDbUser @getUserSplat
if ($null -eq $existingUser) {
$module.FailJson("User [$username] does not exist in database [$database].")
}
$existingRole = Get-DbaDbRole @getRoleSplat
if ($null -eq $existingRole) {
$module.FailJson("Role [$role] does not exist in database [$database].")
}

# Get role members
$existingRoleMembers = Get-DbaDbRoleMember @getRoleMemberSplat

if ($state -eq "absent") {
if ($existingRoleMembers.username -contains $username) {
try {
$removeRoleMemberSplat = @{
SqlInstance = $sqlInstance
SqlCredential = $sqlCredential
User = $username
Database = $database
Role = $role
EnableException = $true
WhatIf = $checkMode
Force = $true
Confirm = $false
}
$output = Remove-DbaDbRoleMember @removeRoleMemberSplat
$module.Result.changed = $true
}
catch {
$module.FailJson("Removing user [$username] from database role [$role] failed: $($_.Exception.Message)", $_)
}
}
}
elseif ($state -eq "present") {
# Add user to role
if ($existingRoleMembers.username -notcontains $username) {
try {
$addRoleMemberSplat = @{
SqlInstance = $sqlInstance
SqlCredential = $sqlCredential
User = $username
Database = $database
Role = $role
EnableException = $true
WhatIf = $checkMode
Force = $true
Confirm = $false
}
$output = Add-DbaDbRoleMember @addRoleMemberSplat
$module.Result.changed = $true
}
catch {
$module.FailJson("Adding user [$username] to database role [$role] failed: $($_.Exception.Message)", $_)
}
}
}
try {
if ($null -ne $output) {
$resultData = ConvertTo-SerializableObject -InputObject $output
$module.Result.data = $resultData
}
$module.ExitJson()
}
catch {
$module.FailJson("Failure: $($_.Exception.Message)", $_)
}
70 changes: 70 additions & 0 deletions plugins/modules/user_role.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

# (c) 2022, John McCall (@lowlydba)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

DOCUMENTATION = r'''
---
module: user_role
short_description: Configures a user's role in a database.
description:
- Adds or removes a user's role in a database.
version_added: 2.4.0
options:
database:
description:
- Database for the user.
type: str
required: true
username:
description:
- Name of the user.
type: str
required: true
role:
description:
- The database role for the user to be modified.
type: str
required: true
author: "John McCall (@lowlydba)"
requirements:
- L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
extends_documentation_fragment:
- lowlydba.sqlserver.sql_credentials
- lowlydba.sqlserver.attributes.check_mode
- lowlydba.sqlserver.attributes.platform_all
- lowlydba.sqlserver.state
'''

EXAMPLES = r'''
- name: Add a user to a fixed db role
lowlydba.sqlserver.user_role:
sql_instance: sql-01.myco.io
username: TheIntern
database: InternProject1
role: db_owner
- name: Remove a user from a fixed db role
lowlydba.sqlserver.login:
sql_instance: sql-01.myco.io
username: TheIntern
database: InternProject1
role: db_owner
state: absent
- name: Add a user to a custom db role
lowlydba.sqlserver.login:
sql_instance: sql-01.myco.io
username: TheIntern
database: InternProject1
role: db_intern
state: absent
'''

RETURN = r'''
data:
description: Output from the C(Remove-DbaDbRoleMember), (Get-DbaDbRoleMember), or C(Add-DbaDbRoleMember) functions.
returned: success, but not in check_mode.
type: dict
'''
2 changes: 2 additions & 0 deletions tests/integration/targets/user_role/aliases
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
context/target
setup/once/setup_sqlserver
3 changes: 3 additions & 0 deletions tests/integration/targets/user_role/meta/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
dependencies:
- setup_sqlserver_test_plugins
114 changes: 114 additions & 0 deletions tests/integration/targets/user_role/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
---
- name: Var block
vars:
login_name: "PhillipJFry"
plain_password: "P0pS3cret!23$%"
password_expiration_enabled: false
password_policy_enforced: false
password_must_change: false
enabled: false
default_database: "master"
language: "us_english"
default_schema: "dbo"
username: "PhillipJFry"
database: "master"
role: "db_owner"
module_defaults:
lowlydba.sqlserver.login:
sql_instance: "{{ sqlserver_instance }}"
sql_username: "{{ sqlserver_username }}"
sql_password: "{{ sqlserver_password }}"
default_database: "{{ default_database }}"
login: "{{ login_name }}"
password: "{{ plain_password }}"
password_expiration_enabled: "{{ password_expiration_enabled }}"
password_must_change: "{{ password_must_change }}"
enabled: "{{ enabled }}"
language: "{{ language }}"
state: present
lowlydba.sqlserver.user:
sql_instance: "{{ sqlserver_instance }}"
sql_username: "{{ sqlserver_username }}"
sql_password: "{{ sqlserver_password }}"
database: "{{ database }}"
login: "{{ login_name }}"
username: "{{ username }}"
default_schema: "{{ default_schema }}"
state: present
lowlydba.sqlserver.user_role:
sql_instance: "{{ sqlserver_instance }}"
sql_username: "{{ sqlserver_username }}"
sql_password: "{{ sqlserver_password }}"
database: "{{ database }}"
username: "{{ username }}"
role: "{{ role }}"
state: present
tags: ["sqlserver.user"]
block:
- name: Create login
lowlydba.sqlserver.login:
register: result
- assert:
that:
- result.data != None

- name: Create user
lowlydba.sqlserver.user:
register: result
- assert:
that:
- result.data != None
- result.data.ComputerName != None
- result.data.InstanceName != None
- result.data.SqlInstance != None
- result.data.Database == "{{ database }}"
- result.data.DefaultSchema == "{{ default_schema }}"
- result.data.Login == "{{ login_name }}"
- result.data.Name == "{{ username }}"

- name: Add user to database role
lowlydba.sqlserver.user_role:
register: result
- assert:
that:
- result is changed

- name: Add user to non-existent database role
lowlydba.sqlserver.user_role:
role: db_IMadeThisOneUp
register: result
- assert:
that:
- result.failed == true
- "'Role [db_IMadeThisOneUp] does not exist in database' in result.msg"

- name: Add non-existent user to database role
lowlydba.sqlserver.user_role:
username: NewUserWhoThis
register: result
- assert:
that:
- result.failed == true
- "'User [NewUserWhoThis] does not exist in database' in result.msg"

- name: Add user again to database role
lowlydba.sqlserver.user_role:
register: result
- assert:
that:
- result is not changed

- name: Remove user from database role
lowlydba.sqlserver.user_role:
register: result
- assert:
that:
- result is changed

always:
- name: Drop user
lowlydba.sqlserver.user:
state: "absent"
- name: Drop login
lowlydba.sqlserver.login:
state: "absent"
5 changes: 5 additions & 0 deletions tests/integration/targets/win_user_role/aliases
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
windows/all
windows/group/1
context/target
setup/once/setup_win_sqlserver
needs/target/user_role
3 changes: 3 additions & 0 deletions tests/integration/targets/win_user_role/meta/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
dependencies:
- user_role

0 comments on commit 835a244

Please sign in to comment.