Skip to content

Commit

Permalink
Move NOT EXISTS to the top for readability
Browse files Browse the repository at this point in the history
  • Loading branch information
spetrosi committed Apr 14, 2022
1 parent 43f0632 commit cc10e05
Show file tree
Hide file tree
Showing 14 changed files with 214 additions and 115 deletions.
33 changes: 24 additions & 9 deletions tasks/main.yml
Expand Up @@ -497,9 +497,10 @@

- name: Create and back up DBM certificate
vars:
__mssql_input_sql_file: create_and_back_up_dbm_cert.j2
__mssql_input_sql_file: create_and_back_up_cert.j2
include_tasks: input_sql_file.yml

# changed_when: false because the role removes cert files after using them
- name: Fetch DBM certificates from the primary node to the control node
fetch:
src: "{{ item.value}}"
Expand All @@ -508,10 +509,11 @@
with_dict:
cert: /var/opt/mssql/data/{{ mssql_ha_dbm_cert_name }}.cer
key: /var/opt/mssql/data/{{ mssql_ha_dbm_cert_name }}.pvk
changed_when: false

- name: Create database mirroring endpoints
vars:
__mssql_input_sql_file: create_endpoint.j2
__mssql_input_sql_file: configure_endpoint.j2
include_tasks: input_sql_file.yml

- name: Get mssql-server version to see if WRITE_LEASE_VALIDITY is available
Expand All @@ -525,7 +527,7 @@

- name: Create the {{ mssql_ha_ag_name }} availability group
vars:
__mssql_input_sql_file: create_ag.j2
__mssql_input_sql_file: configure_ag.j2
include_tasks: input_sql_file.yml

- name: Grant permissions to the {{ mssql_ha_login }} login
Expand All @@ -538,22 +540,24 @@
__mssql_input_sql_file: replicate_db.j2
include_tasks: input_sql_file.yml

# This is required because `any_errors_fatal: true` does not work within blocks
# that have the `always` section
# This is required because `any_errors_fatal: true` does not work within
# blocks that have rescue or always sections
- name: Set a fact to indicate successfull set up on the primary replica
delegate_to: localhost
set_fact:
__mssql_primary_successfull: true
run_once: true

rescue:
# changed_when: false because this task removes unused remnant of cert files
- name: Remove DBM certificates from the control node
delegate_to: localhost
file:
path: "{{ item }}"
state: absent
loop:
- cert
- key
changed_when: false

- name: Configure availability group on replicas
when:
Expand Down Expand Up @@ -612,12 +616,12 @@

- name: Restore DBM certificate
vars:
__mssql_input_sql_file: restore_dbm_cert.j2
__mssql_input_sql_file: restore_cert.j2
include_tasks: input_sql_file.yml

- name: Create database mirroring endpoints
vars:
__mssql_input_sql_file: create_endpoint.j2
__mssql_input_sql_file: configure_endpoint.j2
include_tasks: input_sql_file.yml

- name: Create the {{ mssql_ha_login }} login
Expand All @@ -640,15 +644,26 @@
__mssql_input_sql_file: verify_sql_cluster.j2
include_tasks: input_sql_file.yml
when: mssql_ha_replica_type != 'witness'

always:
# changed_when: false because this task removes unused remnant of cert files
- name: Remove DBM certificates from the control node
delegate_to: localhost
file:
path: "{{ item }}"
state: absent
loop:
- cert
- key
changed_when: false

- name: Remove replicas from an availability group
when:
- mssql_ha_configure is defined
- mssql_ha_configure | bool
- mssql_ha_replica_type == 'absent'
vars:
__mssql_input_sql_file: remove_from_ag.j2
include_tasks: input_sql_file.yml

- name: Ensure the ansible_managed header in /var/opt/mssql/mssql.conf
vars:
Expand Down
172 changes: 94 additions & 78 deletions templates/create_ag.j2 → templates/configure_ag.j2
@@ -1,10 +1,57 @@
IF EXISTS (
IF NOT EXISTS (
SELECT * FROM sys.availability_groups
WHERE name = '{{ mssql_ha_ag_name }}' AND
cluster_type_desc = 'external'
)
BEGIN
PRINT 'Creating the {{ mssql_ha_ag_name }} availability group';
CREATE AVAILABILITY GROUP {{ mssql_ha_ag_name }}
{% if ansible_os_family == 'RedHat' and
ansible_distribution_version | float < 8.3 %}
WITH (DB_FAILOVER = ON, CLUSTER_TYPE = EXTERNAL)
{% else %}
WITH (DB_FAILOVER = ON, CLUSTER_TYPE = EXTERNAL, WRITE_LEASE_VALIDITY=20)
{% endif %}
FOR REPLICA ON
N'{{ ansible_hostname }}' WITH (
ENDPOINT_URL = N'tcp://{{ ansible_fqdn }}:{{ mssql_ha_listener_port }}',
AVAILABILITY_MODE = SYNCHRONOUS_COMMIT,
FAILOVER_MODE = EXTERNAL,
SEEDING_MODE = AUTOMATIC
{% for item in ansible_play_hosts %}
{% if hostvars[item]['mssql_ha_replica_type'] == 'synchronous' %}
),
N'{{ hostvars[item]['ansible_hostname'] }}' WITH (
ENDPOINT_URL = N'tcp://{{
hostvars[item]['ansible_fqdn'] }}:{{ mssql_ha_listener_port }}',
AVAILABILITY_MODE = {{ hostvars[item]['__mssql_ha_availability_mode'] }},
FAILOVER_MODE = {{ hostvars[item]['__mssql_ha_failover_mode'] }},
SEEDING_MODE = {{ hostvars[item]['__mssql_ha_seeding_mode'] }}
{% elif hostvars[item]['mssql_ha_replica_type'] == 'witness' %}
),
N'{{ hostvars[item]['ansible_hostname'] }}' WITH (
ENDPOINT_URL = N'tcp://{{
hostvars[item]['ansible_fqdn'] }}:{{ mssql_ha_listener_port }}',
AVAILABILITY_MODE = {{ hostvars[item]['__mssql_ha_availability_mode'] }}
{% endif %}
{% endfor %}
);
PRINT 'The {{ mssql_ha_ag_name }} availability group created successfully';
END
ELSE
BEGIN
PRINT 'Verifying the existing availability group {{ mssql_ha_ag_name }}'
IF EXISTS (
SELECT * FROM sys.availability_groups
WHERE name = '{{ mssql_ha_ag_name }}' AND
cluster_type_desc != 'external'
)
BEGIN
PRINT 'The existing {{ mssql_ha_ag_name }} availability group has \
incorrect cluster type set, dropping the groupt to re-create it';
DROP AVAILABILITY GROUP ag1;
PRINT 'The {{ mssql_ha_ag_name }} availability group dropped successfully';
END
IF NOT EXISTS (
SELECT * FROM sys.availability_groups
WHERE name = '{{ mssql_ha_ag_name }}' AND
Expand All @@ -19,12 +66,50 @@ BEGIN
PRINT 'DB_FAILOVER = ON is already set, skipping'
END
PRINT 'Verifying replicas'
{% for item in ansible_play_hosts_all %}
{% for item in ansible_play_hosts %}
{% if hostvars[item]['mssql_ha_replica_type'] != 'absent' %}
IF EXISTS (
SELECT * FROM sys.availability_replicas
WHERE replica_server_name = '{{ hostvars[item]['ansible_hostname'] }}' AND
availability_mode_desc !=
'{{ hostvars[item]['__mssql_ha_availability_mode'] }}'
)
BEGIN
PRINT '{{ hostvars[item]['ansible_hostname'] }}: The availability mode \
of this availability replica does not match the required availability mode, \
removing this replica re-create it';
ALTER AVAILABILITY GROUP {{ mssql_ha_ag_name }} REMOVE REPLICA ON
N'{{ hostvars[item]['ansible_hostname'] }}'
PRINT '{{ hostvars[item]['ansible_hostname'] }}: Removed successfully'
END
IF NOT EXISTS (
SELECT * FROM sys.availability_replicas
WHERE replica_server_name = '{{ hostvars[item]['ansible_hostname'] }}'
)
BEGIN
PRINT 'Adding the {{ hostvars[item]['ansible_hostname'] }} \
{{ hostvars[item]['mssql_ha_replica_type'] }} replica';
{% if hostvars[item]['mssql_ha_replica_type'] == 'synchronous' %}
ALTER AVAILABILITY GROUP {{ mssql_ha_ag_name }} ADD REPLICA ON
N'{{ hostvars[item]['ansible_hostname'] }}' WITH (
ENDPOINT_URL = N'tcp://{{
hostvars[item]['ansible_fqdn'] }}:{{ mssql_ha_listener_port }}',
AVAILABILITY_MODE = {{ hostvars[item]['__mssql_ha_availability_mode'] }},
FAILOVER_MODE = {{ hostvars[item]['__mssql_ha_failover_mode'] }},
SEEDING_MODE = {{ hostvars[item]['__mssql_ha_seeding_mode'] }}
);
{% elif hostvars[item]['mssql_ha_replica_type'] == 'witness' %}
ALTER AVAILABILITY GROUP {{ mssql_ha_ag_name }} ADD REPLICA ON
N'{{ hostvars[item]['ansible_hostname'] }}' WITH (
ENDPOINT_URL = N'tcp://{{ hostvars[item]['ansible_fqdn'] }}:{{ mssql_ha_listener_port }}',
AVAILABILITY_MODE = {{ hostvars[item]['__mssql_ha_availability_mode'] }}
);
{% endif %}
PRINT 'The {{ hostvars[item]['ansible_hostname'] }} \
{{ hostvars[item]['mssql_ha_replica_type'] }} replica added successfully';
END
{% if hostvars[item]['mssql_ha_replica_type'] != 'primary' %}
ELSE
BEGIN
PRINT 'Verifying the existing replica {{ item }}';
{% if (hostvars[item]['mssql_ha_replica_type'] == 'primary') or
Expand Down Expand Up @@ -57,7 +142,8 @@ BEGIN
{% for key, value in ag_replica_settings.items() %}
IF NOT EXISTS (
SELECT * FROM sys.availability_replicas
WHERE replica_server_name = N'{{ hostvars[item]['ansible_hostname'] }}' AND
WHERE replica_server_name = N'{{ hostvars[item]['ansible_hostname'] }}'
AND
{% if key == 'endpoint_url' %}
{{ value.sys_setting_name }} = {{ value.setting_value }}
{% else %}
Expand All @@ -82,95 +168,25 @@ correctly, skipping';
END
{% endfor %}
END
{% if hostvars[item]['mssql_ha_replica_type'] != 'primary' %}
ELSE
BEGIN
PRINT 'Adding the {{ hostvars[item]['ansible_hostname'] }} \
{{ hostvars[item]['mssql_ha_replica_type'] }} replica';
{% if hostvars[item]['mssql_ha_replica_type'] == 'synchronous' %}
ALTER AVAILABILITY GROUP {{ mssql_ha_ag_name }} ADD REPLICA ON
N'{{ hostvars[item]['ansible_hostname'] }}' WITH (
ENDPOINT_URL = N'tcp://{{
hostvars[item]['ansible_fqdn'] }}:{{ mssql_ha_listener_port }}',
AVAILABILITY_MODE = {{ hostvars[item]['__mssql_ha_availability_mode'] }},
FAILOVER_MODE = {{ hostvars[item]['__mssql_ha_failover_mode'] }},
SEEDING_MODE = {{ hostvars[item]['__mssql_ha_seeding_mode'] }}
);
{% elif hostvars[item]['mssql_ha_replica_type'] == 'witness' %}
ALTER AVAILABILITY GROUP {{ mssql_ha_ag_name }} ADD REPLICA ON
N'{{ hostvars[item]['ansible_hostname'] }}' WITH (
ENDPOINT_URL = N'tcp://{{ hostvars[item]['ansible_fqdn'] }}:{{ mssql_ha_listener_port }}',
AVAILABILITY_MODE = {{ hostvars[item]['__mssql_ha_availability_mode'] }}
);
{% endif %}
PRINT 'The {{ hostvars[item]['ansible_hostname'] }} \
{{ hostvars[item]['mssql_ha_replica_type'] }} replica added successfully';
END
{% endif %}
{% elif hostvars[item]['mssql_ha_replica_type'] == 'absent' %}
IF EXISTS (
IF NOT EXISTS (
SELECT * FROM sys.availability_replicas
WHERE replica_server_name = '{{ hostvars[item]['ansible_hostname'] }}'
)
BEGIN
PRINT '{{ item }}: this replica is already removed, skipping';
END
ELSE
BEGIN
PRINT '{{ item }}: Removing this replica';
ALTER AVAILABILITY GROUP {{ mssql_ha_ag_name }}
REMOVE REPLICA ON N'{{ hostvars[item]['ansible_hostname'] }}';
PRINT '{{ item }}: This replica is removed successfully';
END
ELSE
BEGIN
PRINT '{{ item }}: this replica is already removed, skipping';
END
{% endif %}
{% endfor %}
END
ELSE
BEGIN
IF EXISTS (
SELECT * FROM sys.availability_groups
WHERE name = '{{ mssql_ha_ag_name }}' AND
cluster_type_desc != 'external'
)
BEGIN
PRINT 'The existing {{ mssql_ha_ag_name }} availability group has \
incorrect cluster type set, dropping the groupt to re-create it';
DROP AVAILABILITY GROUP ag1;
PRINT 'The {{ mssql_ha_ag_name }} availability group dropped successfully';
END
PRINT 'Creating the {{ mssql_ha_ag_name }} availability group';
CREATE AVAILABILITY GROUP {{ mssql_ha_ag_name }}
{% if ansible_os_family == 'RedHat' and ansible_distribution_version | float < 8.3 %}
WITH (DB_FAILOVER = ON, CLUSTER_TYPE = EXTERNAL)
{% else %}
WITH (DB_FAILOVER = ON, CLUSTER_TYPE = EXTERNAL, WRITE_LEASE_VALIDITY=20)
{% endif %}
FOR REPLICA ON
N'{{ ansible_hostname }}' WITH (
ENDPOINT_URL = N'tcp://{{ ansible_fqdn }}:{{ mssql_ha_listener_port }}',
AVAILABILITY_MODE = SYNCHRONOUS_COMMIT,
FAILOVER_MODE = EXTERNAL,
SEEDING_MODE = AUTOMATIC
{% for item in ansible_play_hosts_all %}
{% if hostvars[item]['mssql_ha_replica_type'] == 'synchronous' %}
),
N'{{ hostvars[item]['ansible_hostname'] }}' WITH (
ENDPOINT_URL = N'tcp://{{
hostvars[item]['ansible_fqdn'] }}:{{ mssql_ha_listener_port }}',
AVAILABILITY_MODE = {{ hostvars[item]['__mssql_ha_availability_mode'] }},
FAILOVER_MODE = {{ hostvars[item]['__mssql_ha_failover_mode'] }},
SEEDING_MODE = {{ hostvars[item]['__mssql_ha_seeding_mode'] }}
{% elif hostvars[item]['mssql_ha_replica_type'] == 'witness' %}
),
N'{{ hostvars[item]['ansible_hostname'] }}' WITH (
ENDPOINT_URL = N'tcp://{{
hostvars[item]['ansible_fqdn'] }}:{{ mssql_ha_listener_port }}',
AVAILABILITY_MODE = {{ hostvars[item]['__mssql_ha_availability_mode'] }}
{% endif %}
{% endfor %}
);
PRINT 'The {{ mssql_ha_ag_name }} availability group created successfully';
END

-- It is not possible to grant permissions fully idempotently
ALTER AVAILABILITY GROUP {{ mssql_ha_ag_name }} GRANT CREATE ANY DATABASE;
Expand Up @@ -102,4 +102,4 @@ endpoint is already correct, skipping';
BEGIN
PRINT 'Endpoint {{ mssql_ha_endpoint_name }} is already started, skipping';
END
END
END
@@ -1,20 +1,27 @@
-- Enabling NOCOUNT to suppress (1 rows affected) messages on the output
-- Enabling NOCOUNT to suppress (1 rows affected) messages from DECLARE
-- keywordss on the output
SET NOCOUNT ON;

DECLARE @cerExists INT;
exec master.dbo.xp_fileexist '/var/opt/mssql/data/{{ mssql_ha_dbm_cert_name }}.cer', @cerExists OUTPUT;
exec master.dbo.xp_fileexist
'/var/opt/mssql/data/{{ mssql_ha_dbm_cert_name }}.cer', @cerExists OUTPUT;
DECLARE @pvkExists INT;
exec master.dbo.xp_fileexist '/var/opt/mssql/data/{{ mssql_ha_dbm_cert_name }}.pvk', @pvkExists OUTPUT;
IF NOT EXISTS(SELECT * FROM sys.certificates WHERE name = '{{ mssql_ha_dbm_cert_name }}')
exec master.dbo.xp_fileexist
'/var/opt/mssql/data/{{ mssql_ha_dbm_cert_name }}.pvk', @pvkExists OUTPUT;
IF NOT EXISTS(
SELECT *
FROM sys.certificates
WHERE name = '{{ mssql_ha_dbm_cert_name }}'
)
BEGIN
PRINT 'Certificate {{ mssql_ha_dbm_cert_name }} does not exist, creating';
IF (@cerExists = 1 AND @pvkExists = 1) OR (@cerExists != @pvkExists)
BEGIN
THROW 51000, 'Certificate {{ mssql_ha_dbm_cert_name }} does not exist in SQL \
Server, however, /var/opt/mssql/data/{{ mssql_ha_dbm_cert_name }}.cer and/or \
/var/opt/mssql/data/{{ mssql_ha_dbm_cert_name }}.pvk files do exist. You must \
either remove the files, or run the role with `mssql_ha_reset_cert: true` \
to regenerate certificates.', 1;
THROW 51000, 'Certificate {{ mssql_ha_dbm_cert_name }} does not exist in \
SQL Server, however, /var/opt/mssql/data/{{ mssql_ha_dbm_cert_name }}.cer \
and/or /var/opt/mssql/data/{{ mssql_ha_dbm_cert_name }}.pvk files do exist. \
You must either remove the files, or run the role with \
`mssql_ha_reset_cert: true` to regenerate certificates.', 1;
END
ELSE
BEGIN
Expand Down
8 changes: 5 additions & 3 deletions templates/create_master_key_encryption.j2
Expand Up @@ -4,20 +4,22 @@ IF NOT EXISTS (
)
BEGIN
PRINT 'Master key does not exist, creating';
CREATE MASTER KEY ENCRYPTION BY PASSWORD = '{{ mssql_ha_master_key_password }}';
CREATE MASTER KEY ENCRYPTION BY PASSWORD =
'{{ mssql_ha_master_key_password }}';
PRINT 'Master key created successfully';
END
ELSE
BEGIN
PRINT 'Master key already exists, verifying the provided password against \
the existing master key';
BEGIN TRY
OPEN MASTER KEY DECRYPTION BY PASSWORD = '{{ mssql_ha_master_key_password }}';
OPEN MASTER KEY DECRYPTION BY PASSWORD =
'{{ mssql_ha_master_key_password }}';
PRINT 'The provided master key password is correct';
END TRY
BEGIN CATCH
PRINT 'You provided an incorrect master key password with the \
mssql_ha_master_key_password variable';
THROW;
END CATCH
END
END

0 comments on commit cc10e05

Please sign in to comment.