Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 29 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
workflow_dispatch:

env:
SERVICE_URL: https://facade-maint-config-windows-use-ssh-6f3kfepqcq-ew.a.run.app/v1/provision
SERVICE_URL: https://facade-release-6f3kfepqcq-ew.a.run.app/v1/provision
PUPPET_FORGE_TOKEN: ${{ secrets.PUPPET_FORGE_TOKEN || secrets.PUPPET_FORGE_TOKEN_PUBLIC }}
BUNDLE_RUBYGEMS___PUPPETCORE__PUPPET__COM: "forge-key:${{ secrets.PUPPET_FORGE_TOKEN || secrets.PUPPET_FORGE_TOKEN_PUBLIC }}"

Expand Down Expand Up @@ -72,6 +72,24 @@ jobs:
with:
service-key: ${{ secrets.TWINGATE_PUBLIC_REPO_KEY }}

- name: Fix DNS
run: |
echo "=== Remove Azure DNS from eth0 interface ==="
sudo resolvectl dns eth0 ""

echo "=== Configure Twingate DNS properly ==="
sudo resolvectl dns sdwan0 100.95.0.251 100.95.0.252
sudo resolvectl domain sdwan0 delivery.puppetlabs.net

echo "=== Flush DNS cache ==="
sudo resolvectl flush-caches

echo "=== Check new configuration ==="
resolvectl status

echo "=== Test DNS resolution ==="
nslookup artifactory.delivery.puppetlabs.net

- name: Checkout
uses: actions/checkout@v3
with:
Expand Down Expand Up @@ -106,24 +124,29 @@ jobs:
run: |
bundle exec rake 'litmus:install_module'

- name: Install Chocolatey and MSOLEDBSQL driver
run: |
bundle exec bolt command run "Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))" --targets all --inventoryfile spec/fixtures/litmus_inventory.yaml
bundle exec bolt command run "choco install msoledbsql -y --force" --targets all --inventoryfile spec/fixtures/litmus_inventory.yaml

- name: Authenticate with GCP
run: |
echo '${{ secrets.GCP_CONNECTION }}' >> creds.json
bundle exec bolt file upload creds.json C:\\creds.json --targets ssh_nodes --inventoryfile spec/fixtures/litmus_inventory.yaml
bundle exec bolt command run "gcloud auth activate-service-account --key-file C:\\creds.json" --targets ssh_nodes --inventoryfile spec/fixtures/litmus_inventory.yaml
bundle exec bolt file upload creds.json C:\\creds.json --targets all --inventoryfile spec/fixtures/litmus_inventory.yaml
bundle exec bolt command run "gcloud auth activate-service-account --key-file C:\\creds.json" --targets all --inventoryfile spec/fixtures/litmus_inventory.yaml

- name: Download OS ISO
run: |
bundle exec bolt command run 'gsutil -q cp gs://artifactory-modules/windows/en_windows_server_2019_updated_july_2020_x64_dvd_94453821.iso C:\\' --targets ssh_nodes --inventoryfile spec/fixtures/litmus_inventory.yaml
bundle exec bolt command run 'gsutil -q cp gs://artifactory-modules/windows/en_windows_server_2019_updated_july_2020_x64_dvd_94453821.iso C:\\' --targets all --inventoryfile spec/fixtures/litmus_inventory.yaml

- name: Download SQLServer ISO
run: |
bundle exec bolt command run 'gsutil -q cp gs://artifactory-modules/puppetlabs-sqlserver/SQLServer2019CTP2.4-x64-ENU.iso C:\\' --targets ssh_nodes --inventoryfile spec/fixtures/litmus_inventory.yaml
bundle exec bolt command run 'gsutil -q cp gs://artifactory-modules/puppetlabs-sqlserver/SQLServer2019CTP2.4-x64-ENU.iso C:\\' --targets all --inventoryfile spec/fixtures/litmus_inventory.yaml

- name: Set Environment Variable
run: |
pass=`grep -oP '(?<=password: ).*' spec/fixtures/litmus_inventory.yaml`
bundle exec bolt command run "[Environment]::SetEnvironmentVariable('pass', '$pass', 'Machine')" --targets ssh_nodes --inventoryfile spec/fixtures/litmus_inventory.yaml
bundle exec bolt command run "[Environment]::SetEnvironmentVariable('pass', '$pass', 'Machine')" --targets all --inventoryfile spec/fixtures/litmus_inventory.yaml

- name: Run acceptance tests
run: |
Expand Down
35 changes: 29 additions & 6 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
- cron: '0 0 * * *'

env:
SERVICE_URL: https://facade-maint-config-windows-use-ssh-6f3kfepqcq-ew.a.run.app/v1/provision
SERVICE_URL: https://facade-release-6f3kfepqcq-ew.a.run.app/v1/provision
PUPPET_FORGE_TOKEN: ${{ secrets.PUPPET_FORGE_TOKEN || secrets.PUPPET_FORGE_TOKEN_PUBLIC }}
BUNDLE_RUBYGEMS___PUPPETCORE__PUPPET__COM: "forge-key:${{ secrets.PUPPET_FORGE_TOKEN || secrets.PUPPET_FORGE_TOKEN_PUBLIC }}"

Expand Down Expand Up @@ -69,6 +69,24 @@ jobs:
with:
service-key: ${{ secrets.TWINGATE_PUBLIC_REPO_KEY }}

- name: Fix DNS
run: |
echo "=== Remove Azure DNS from eth0 interface ==="
sudo resolvectl dns eth0 ""

echo "=== Configure Twingate DNS properly ==="
sudo resolvectl dns sdwan0 100.95.0.251 100.95.0.252
sudo resolvectl domain sdwan0 delivery.puppetlabs.net

echo "=== Flush DNS cache ==="
sudo resolvectl flush-caches

echo "=== Check new configuration ==="
resolvectl status

echo "=== Test DNS resolution ==="
nslookup artifactory.delivery.puppetlabs.net

- name: Checkout
uses: actions/checkout@v3
with:
Expand Down Expand Up @@ -103,24 +121,29 @@ jobs:
run: |
bundle exec rake 'litmus:install_module'

- name: Install Chocolatey and MSOLEDBSQL driver
run: |
bundle exec bolt command run "Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))" --targets all --inventoryfile spec/fixtures/litmus_inventory.yaml
bundle exec bolt command run "choco install msoledbsql -y --force" --targets all --inventoryfile spec/fixtures/litmus_inventory.yaml

- name: Authenitcate with GCP
run: |
echo '${{ secrets.GCP_CONNECTION }}' >> creds.json
bundle exec bolt file upload creds.json C:\\creds.json --targets ssh_nodes --inventoryfile spec/fixtures/litmus_inventory.yaml
bundle exec bolt command run "gcloud auth activate-service-account --key-file C:\\creds.json" --targets ssh_nodes --inventoryfile spec/fixtures/litmus_inventory.yaml
bundle exec bolt file upload creds.json C:\\creds.json --targets all --inventoryfile spec/fixtures/litmus_inventory.yaml
bundle exec bolt command run "gcloud auth activate-service-account --key-file C:\\creds.json" --targets all --inventoryfile spec/fixtures/litmus_inventory.yaml

- name: Download OS ISO
run: |
bundle exec bolt command run 'gsutil -q cp gs://artifactory-modules/windows/en_windows_server_2019_updated_july_2020_x64_dvd_94453821.iso C:\\' --targets ssh_nodes --inventoryfile spec/fixtures/litmus_inventory.yaml
bundle exec bolt command run 'gsutil -q cp gs://artifactory-modules/windows/en_windows_server_2019_updated_july_2020_x64_dvd_94453821.iso C:\\' --targets all --inventoryfile spec/fixtures/litmus_inventory.yaml

- name: Download SQLServer ISO
run: |
bundle exec bolt command run 'gsutil -q cp gs://artifactory-modules/puppetlabs-sqlserver/SQLServer2019CTP2.4-x64-ENU.iso C:\\' --targets ssh_nodes --inventoryfile spec/fixtures/litmus_inventory.yaml
bundle exec bolt command run 'gsutil -q cp gs://artifactory-modules/puppetlabs-sqlserver/SQLServer2019CTP2.4-x64-ENU.iso C:\\' --targets all --inventoryfile spec/fixtures/litmus_inventory.yaml

- name: Set Environment Variable
run: |
pass=`grep -oP '(?<=password: ).*' spec/fixtures/litmus_inventory.yaml`
bundle exec bolt command run "[Environment]::SetEnvironmentVariable('pass', '$pass', 'Machine')" --targets ssh_nodes --inventoryfile spec/fixtures/litmus_inventory.yaml
bundle exec bolt command run "[Environment]::SetEnvironmentVariable('pass', '$pass', 'Machine')" --targets all --inventoryfile spec/fixtures/litmus_inventory.yaml

- name: Run acceptance tests
run: |
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

## Overview

The sqlserver module installs and manages Microsoft SQL Server 2014, 2016, 2017, 2019 and 2022 on Windows systems.
The sqlserver module installs and manages Microsoft SQL Server 2014, 2016, 2017, 2019, 2022 and 2025 on Windows systems.

## Module Description

Expand Down Expand Up @@ -273,11 +273,11 @@ For information on the classes and types, see the [REFERENCE.md](https://github.

## Limitations

SQL 2017, 2019 and 2022 detection support has been added. This support is limited to functionality already present for other versions.
SQL 2017, 2019, 2022 and 2025 detection support has been added. This support is limited to functionality already present for other versions.

The MSOLEDBSQL driver is now required to use this module. You can use this chocolatey [package](https://community.chocolatey.org/packages/msoledbsql) for installation. but it must version 18.x or earlier. (v19+ is not currently supported)
The MSOLEDBSQL driver is required to use this module. You can use this chocolatey [package](https://community.chocolatey.org/packages/msoledbsql) for installation.

This module can manage only a single version of SQL Server on a given host (one and only one of SQL Server 2014, 2016, 2017, 2019 or 2022). The module is able to manage multiple SQL Server instances of the same version.
This module can manage only a single version of SQL Server on a given host (one and only one of SQL Server 2014, 2016, 2017, 2019, 2022 or 2025). The module is able to manage multiple SQL Server instances of the same version.

This module cannot manage the SQL Server Native Client SDK (also known as SNAC_SDK). The SQL Server installation media can install the SDK, but it is not able to uninstall the SDK. Note that the 'sqlserver_features' fact detects the presence of the SDK.

Expand Down
16 changes: 10 additions & 6 deletions lib/puppet_x/sqlserver/features.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
SQL_2017 = 'SQL_2017'
SQL_2019 = 'SQL_2019'
SQL_2022 = 'SQL_2022'
SQL_2025 = 'SQL_2025'

ALL_SQL_VERSIONS = [SQL_2014, SQL_2016, SQL_2017, SQL_2019, SQL_2022].freeze
ALL_SQL_VERSIONS = [SQL_2014, SQL_2016, SQL_2017, SQL_2019, SQL_2022, SQL_2025].freeze

# rubocop:disable Style/ClassAndModuleChildren
module PuppetX
Expand All @@ -35,12 +36,15 @@ class Features # rubocop:disable Style/Documentation
major_version: 15,
registry_path: '150'
},
SQL_2022 => {
major_version: 16,
registry_path: '160'
}
SQL_2022 => {
major_version: 16,
registry_path: '160'
},
SQL_2025 => {
major_version: 17,
registry_path: '170'
}
}.freeze

SQL_REG_ROOT = 'Software\Microsoft\Microsoft SQL Server'
HKLM = 'HKEY_LOCAL_MACHINE'

Expand Down
1 change: 1 addition & 0 deletions lib/puppet_x/sqlserver/server_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def self.sql_version_from_install_source(source_dir)
ver = content.match('"(.+)"')
return nil if ver.nil?

return SQL_2025 if ver[1].start_with?('17.')
return SQL_2022 if ver[1].start_with?('16.')
return SQL_2019 if ver[1].start_with?('15.')
return SQL_2017 if ver[1].start_with?('14.')
Expand Down
3 changes: 2 additions & 1 deletion metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "puppetlabs-sqlserver",
"version": "5.0.5",
"author": "puppetlabs",
"summary": "The `sqlserver` module installs and manages MS SQL Server 2014, 2016, 2017, 2019 and 2022 on Windows systems.",
"summary": "The `sqlserver` module installs and manages MS SQL Server 2014, 2016, 2017, 2019, 2022 and 2025 on Windows systems.",
"license": "proprietary",
"source": "https://github.com/puppetlabs/puppetlabs-sqlserver",
"project_page": "https://github.com/puppetlabs/puppetlabs-sqlserver",
Expand Down Expand Up @@ -45,6 +45,7 @@
"sql2017",
"sql2019",
"sql2022",
"sql2025",
"tsql",
"database"
],
Expand Down
17 changes: 17 additions & 0 deletions spec/acceptance/manifests/install_oledb_driver.pp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

# Download and install the Microsoft OLE DB Driver for SQL Server
# Using individual PowerShell commands to avoid quote escaping issues

exec { 'download_oledb_driver':
command => 'powershell.exe -Command "Invoke-WebRequest -Uri https://go.microsoft.com/fwlink/?linkid=2274906 -OutFile C:\\Windows\\Temp\\msoledbsql.msi -UseBasicParsing"',
creates => 'C:/Windows/Temp/msoledbsql.msi',
timeout => 300,
}

exec { 'install_oledb_driver':
command => 'powershell.exe -Command "Start-Process msiexec.exe -ArgumentList \'/i\', \'C:\\Windows\\Temp\\msoledbsql.msi\', \'/quiet\', \'/norestart\' -Wait"',
require => Exec['download_oledb_driver'],
unless => 'powershell.exe -Command "if (Test-Path \'HKLM:\\SOFTWARE\\Microsoft\\Microsoft SQL Server\\*\\OLE DB Provider for SQL Server\') { exit 0 } else { exit 1 }"',
timeout => 600,
}
43 changes: 21 additions & 22 deletions spec/acceptance/sqlserver_role_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@
require 'securerandom'
require 'erb'

hostname = Helper.instance.run_shell('hostname').stdout.upcase.strip

# database name
db_name = "DB#{SecureRandom.hex(4)}".upcase
LOGIN1 = "Login1_#{SecureRandom.hex(2)}".freeze
LOGIN2 = "Login2_#{SecureRandom.hex(2)}".freeze
LOGIN3 = "Login3_#{SecureRandom.hex(2)}".freeze
Expand Down Expand Up @@ -47,8 +43,11 @@ def ensure_sqlserver_logins_users(db_name)

context 'Start testing sqlserver::role' do
before(:all) do
# Initialize hostname and db_name once per context
@hostname = Helper.instance.run_shell('hostname').stdout.upcase.strip
@db_name = "DB#{SecureRandom.hex(4)}".upcase
# Create database users
ensure_sqlserver_logins_users(db_name)
ensure_sqlserver_logins_users(@db_name)
end

before(:each) do
Expand Down Expand Up @@ -76,7 +75,7 @@ def ensure_sqlserver_logins_users(db_name)
admin_pass => 'Pupp3t1@',
}
sqlserver::user{'#{USER1}':
database => '#{db_name}',
database => '#{@db_name}',
ensure => 'absent',
}
MANIFEST
Expand All @@ -100,25 +99,25 @@ def ensure_sqlserver_logins_users(db_name)
apply_manifest(pp, catch_failures: true)

# validate that the database-specific role '#{@role}' is successfully created with specified permissions':
query = "USE #{db_name};
query = "USE #{@db_name};
SELECT spr.principal_id, spr.name,
spe.state_desc, spe.permission_name
FROM sys.server_principals AS spr
JOIN sys.server_permissions AS spe
ON spe.grantee_principal_id = spr.principal_id
WHERE spr.name = '#{@role}';"

run_sql_query(query:, server: hostname, expected_row_count: 2)
run_sql_query(query:, server: @hostname, expected_row_count: 2)

# validate that the database-specific role '#{@role}' has correct authorization #{LOGIN1}
query = "USE #{db_name};
query = "USE #{@db_name};
SELECT spr.name, sl.name
FROM sys.server_principals AS spr
JOIN sys.sql_logins AS sl
ON spr.owning_principal_id = sl.principal_id
WHERE sl.name = '#{LOGIN1}';"

run_sql_query(query:, server: hostname, expected_row_count: 1)
run_sql_query(query:, server: @hostname, expected_row_count: 1)
end

it "Create database-specific role #{@role}" do
Expand All @@ -130,23 +129,23 @@ def ensure_sqlserver_logins_users(db_name)
sqlserver::role{'DatabaseRole':
ensure => 'present',
role => '#{@role}',
database => '#{db_name}',
database => '#{@db_name}',
permissions => {'GRANT' => ['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'CONTROL', 'ALTER']},
type => 'DATABASE',
}
MANIFEST
apply_manifest(pp, catch_failures: true)

# validate that the database-specific role '#{@role}' is successfully created with specified permissions':
query = "USE #{db_name};
query = "USE #{@db_name};
SELECT pr.principal_id, pr.name, pr.type_desc,
pr.authentication_type_desc, pe.state_desc, pe.permission_name
FROM sys.database_principals AS pr
JOIN sys.database_permissions AS pe
ON pe.grantee_principal_id = pr.principal_id
WHERE pr.name = '#{@role}';"

run_sql_query(query:, server: hostname, expected_row_count: 6)
run_sql_query(query:, server: @hostname, expected_row_count: 6)
end

it 'Create a database-specific role with the same name on two databases' do
Expand All @@ -158,7 +157,7 @@ def ensure_sqlserver_logins_users(db_name)
sqlserver::role{'DatabaseRole_1':
ensure => 'present',
role => '#{@role}',
database => '#{db_name}',
database => '#{@db_name}',
permissions => {'GRANT' => ['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'CONTROL', 'ALTER']},
type => 'DATABASE',
}
Expand All @@ -180,11 +179,11 @@ def ensure_sqlserver_logins_users(db_name)
FROM sys.database_principals AS pr
JOIN sys.database_permissions AS pe
ON pe.grantee_principal_id = pr.principal_id
JOIN #{db_name}.sys.database_principals as dbpr
JOIN #{@db_name}.sys.database_principals as dbpr
on pr.name = dbpr.name
WHERE pr.name = '#{@role}';"

run_sql_query(query:, server: hostname, expected_row_count: 6)
run_sql_query(query:, server: @hostname, expected_row_count: 6)
end

it "Create server role #{@role} with optional members and optional members-purge" do
Expand All @@ -205,18 +204,18 @@ def ensure_sqlserver_logins_users(db_name)
apply_manifest(pp, catch_failures: true)

# validate that the server role '#{@role}' is successfully created with specified permissions':
query = "USE #{db_name};
query = "USE #{@db_name};
SELECT spr.principal_id AS ID, spr.name AS Server_Role,
spe.state_desc, spe.permission_name
FROM sys.server_principals AS spr
JOIN sys.server_permissions AS spe
ON spe.grantee_principal_id = spr.principal_id
WHERE spr.name = '#{@role}';"

run_sql_query(query:, server: hostname, expected_row_count: 2)
run_sql_query(query:, server: @hostname, expected_row_count: 2)

# validate that the t server role '#{@role}' has correct members (Login1, 2, 3)
query = "USE #{db_name};
query = "USE #{@db_name};
SELECT spr.principal_id AS ID, spr.name AS ServerRole
FROM sys.server_principals AS spr
JOIN sys.server_role_members m
Expand All @@ -226,7 +225,7 @@ def ensure_sqlserver_logins_users(db_name)
OR spr.name = '#{LOGIN3}'
OR spr.name = 'LOGIN4';"

run_sql_query(query:, server: hostname, expected_row_count: 3)
run_sql_query(query:, server: @hostname, expected_row_count: 3)

puts "Create server role #{@role} with optional members_purge:"
pp = <<-MANIFEST
Expand All @@ -247,7 +246,7 @@ def ensure_sqlserver_logins_users(db_name)
apply_manifest(pp, catch_failures: true)

# validate that the t server role '#{@role}' has correct members (only Login3)
query = "USE #{db_name};
query = "USE #{@db_name};
SELECT spr.principal_id AS ID, spr.name AS ServerRole
FROM sys.server_principals AS spr
JOIN sys.server_role_members m
Expand All @@ -256,7 +255,7 @@ def ensure_sqlserver_logins_users(db_name)
OR spr.name = '#{LOGIN2}'
OR spr.name = '#{LOGIN3}';"

run_sql_query(query:, server: hostname, expected_row_count: 1)
run_sql_query(query:, server: @hostname, expected_row_count: 1)
end
end
end
Loading
Loading