mirror of
https://github.com/Microsoft/sql-server-samples.git
synced 2025-12-08 14:58:54 +00:00
Added sample Ansible playbook for installing SQL Server and creating a Pacemaker-managed AG.
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
This is a sample Ansible playbook that shows how to install SQL Server, create a Pacemaker cluster, and create an AG managed by the cluster on a set of Linux nodes.
|
||||
|
||||
|
||||
# Roles
|
||||
|
||||
- `pacemaker` - This role creates a Pacemaker cluster between the hosts.
|
||||
- `mssql-server` - This role installs SQL Server on the host, runs setup to set the SA password, and starts the service.
|
||||
- `mssql-server-ha` - This role enables support for HA and creates a DB Mirroring endpoint.
|
||||
- `mssql-server-ag-external` - This role installs the Pacemaker resource agents, creates an AG, an optional listener, and Pacemaker resources for both.
|
||||
|
||||
|
||||
# Try
|
||||
|
||||
1. Put the names of the Linux nodes in the `inventory` file
|
||||
|
||||
1. Configure the deployment in `play.yml`
|
||||
|
||||
1. Create a vault file named `vault.yml` using the template at the end of this README.
|
||||
|
||||
```sh
|
||||
ansible-vault create vault.yml
|
||||
```
|
||||
|
||||
1. Execute the playbook
|
||||
|
||||
```sh
|
||||
ansible-playbook ./play.yml -i ./inventory --ask-vault-pass -e 'ansible_user=username'
|
||||
```
|
||||
|
||||
|
||||
# Vault file template
|
||||
|
||||
```yaml
|
||||
---
|
||||
|
||||
ansible_ssh_pass: 'some password'
|
||||
|
||||
ansible_sudo_pass: 'some password'
|
||||
|
||||
# The password for the sa user. Only used if mssql-server needs to be installed.
|
||||
sa_password: 'some password'
|
||||
|
||||
# The password for the master key
|
||||
master_key_password: 'some password'
|
||||
|
||||
# The SQL password for the DBM endpoint user
|
||||
dbm_password: 'some password'
|
||||
|
||||
# The password for the DBM cert private key
|
||||
dbm_cert_password: 'some password'
|
||||
|
||||
# The password of the user that admins the pacemaker cluster (hacluster)
|
||||
pacemaker_cluster_password: 'some password'
|
||||
|
||||
# The SQL password for the pacemaker user
|
||||
pacemaker_password: 'some password'
|
||||
```
|
||||
@@ -0,0 +1,4 @@
|
||||
[servers]
|
||||
node1
|
||||
node2
|
||||
node3
|
||||
@@ -0,0 +1,253 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.1',
|
||||
'supported_by': 'community',
|
||||
'status': ['preview']
|
||||
}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: mssql_ag
|
||||
|
||||
short_description: Add or join availability groups on a SQL Server instance
|
||||
|
||||
description:
|
||||
- Add or join availability groups on a SQL Server instance.
|
||||
|
||||
version_added: "2.2"
|
||||
|
||||
author: Arnav Singh (@arsing)
|
||||
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- The name of the availability group to add
|
||||
required: true
|
||||
|
||||
state:
|
||||
description:
|
||||
- The state to set the local replica to
|
||||
choices: ["all_secondaries_or_unjoined", "all_joined_to_one_primary"]
|
||||
required: true
|
||||
|
||||
all_replicas:
|
||||
description:
|
||||
- A list of all the replicas of the AG
|
||||
required: false
|
||||
|
||||
primary:
|
||||
description:
|
||||
- The replica that should become the primary
|
||||
required: false
|
||||
|
||||
local_replica:
|
||||
description:
|
||||
- The name of the local replica
|
||||
required: false
|
||||
|
||||
dbm_endpoint_port:
|
||||
description:
|
||||
- The port of the DBM endpoint
|
||||
required: false
|
||||
|
||||
login_port:
|
||||
description:
|
||||
- The TDS port of the instance
|
||||
required: false
|
||||
default: 1433
|
||||
|
||||
login_name:
|
||||
description:
|
||||
- The name of the user to log in to the instance
|
||||
required: true
|
||||
|
||||
login_password:
|
||||
description:
|
||||
- The password of the user to log in to the instance
|
||||
required: true
|
||||
|
||||
notes:
|
||||
- Requires the mssql-tools package on the remote host.
|
||||
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- mssql-tools
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
EXAMPLES = '''
|
||||
# Set all replicas of AG foo to secondary
|
||||
- mssql_ag:
|
||||
name: foo
|
||||
state: all_secondaries_or_unjoined
|
||||
login_name: sa
|
||||
login_password: password
|
||||
|
||||
# Join all replicas of AG foo to primary on the first server in the group named servers
|
||||
- mssql_ag:
|
||||
name: foo
|
||||
state: all_joined_to_one_primary
|
||||
all_replicas: "{{ groups['servers'] }}"
|
||||
primary: "{{ groups['servers'][0] }}"
|
||||
local_replica: "{{ inventory_hostname }}"
|
||||
login_name: sa
|
||||
login_password: password
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
RETURN = '''
|
||||
name:
|
||||
description: The name of the AG that was created or joined
|
||||
returned: success
|
||||
type: string
|
||||
sample: foo
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
import subprocess
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
name = dict(required = True),
|
||||
state = dict(choices = ['all_secondaries_or_unjoined', 'all_joined_to_one_primary'], required = True),
|
||||
all_replicas = dict(type = 'list', required = False),
|
||||
primary = dict(required = False),
|
||||
local_replica = dict(required = False),
|
||||
dbm_endpoint_port = dict(required = False),
|
||||
login_port = dict(required = False, default = 1433),
|
||||
login_name = dict(required = True),
|
||||
login_password = dict(required = True, no_log = True)
|
||||
),
|
||||
required_if = [
|
||||
['state', 'all_joined_to_one_primary', ['all_replicas', 'primary', 'local_replica', 'dbm_endpoint_port']]
|
||||
]
|
||||
)
|
||||
|
||||
name = module.params['name']
|
||||
state = module.params['state']
|
||||
all_replicas = module.params['all_replicas']
|
||||
primary = module.params['primary']
|
||||
local_replica = module.params['local_replica']
|
||||
dbm_endpoint_port = module.params['dbm_endpoint_port']
|
||||
login_port = module.params['login_port']
|
||||
login_name = module.params['login_name']
|
||||
login_password = module.params['login_password']
|
||||
|
||||
if state == "all_secondaries_or_unjoined":
|
||||
sqlcmd(login_port, login_name, login_password, """
|
||||
IF EXISTS (
|
||||
SELECT * FROM sys.availability_groups WHERE name = {0}
|
||||
)
|
||||
ALTER AVAILABILITY GROUP {1} SET (ROLE = SECONDARY)
|
||||
;
|
||||
""".format(
|
||||
quoteName(name, "'"),
|
||||
quoteName(name, '[')
|
||||
))
|
||||
|
||||
elif primary == local_replica:
|
||||
def replica_spec(name, endpoint_port):
|
||||
return """
|
||||
{0} WITH (
|
||||
ENDPOINT_URL = {1},
|
||||
AVAILABILITY_MODE = SYNCHRONOUS_COMMIT,
|
||||
FAILOVER_MODE = EXTERNAL,
|
||||
SEEDING_MODE = AUTOMATIC
|
||||
)
|
||||
""".format(
|
||||
quoteName(name.split('.')[0], "'"),
|
||||
quoteName('tcp://{0}:{1}'.format(name, endpoint_port), "'")
|
||||
)
|
||||
|
||||
sqlcmd(login_port, login_name, login_password, """
|
||||
IF NOT EXISTS (
|
||||
SELECT * FROM sys.availability_groups WHERE name = {0}
|
||||
)
|
||||
CREATE AVAILABILITY GROUP {1}
|
||||
WITH (CLUSTER_TYPE = EXTERNAL, DB_FAILOVER = ON)
|
||||
FOR REPLICA ON {2}
|
||||
ELSE IF NOT EXISTS (
|
||||
SELECT *
|
||||
FROM sys.dm_hadr_availability_replica_states ars
|
||||
JOIN sys.availability_groups ag ON ars.group_id = ag.group_id
|
||||
WHERE ag.name = {0} AND ars.is_local = 1 AND ars.role = 1
|
||||
)
|
||||
BEGIN
|
||||
EXEC sp_set_session_context @key = N'external_cluster', @value = N'yes', @read_only = 1
|
||||
ALTER AVAILABILITY GROUP {1} FAILOVER
|
||||
END
|
||||
;
|
||||
|
||||
ALTER AVAILABILITY GROUP {1} GRANT CREATE ANY DATABASE
|
||||
;
|
||||
""".format(
|
||||
quoteName(name, "'"),
|
||||
quoteName(name, '['),
|
||||
replica_spec(primary, dbm_endpoint_port)
|
||||
))
|
||||
|
||||
for replica in all_replicas:
|
||||
if replica != primary:
|
||||
sqlcmd(login_port, login_name, login_password, """
|
||||
IF NOT EXISTS (
|
||||
SELECT *
|
||||
FROM sys.availability_replicas ar
|
||||
JOIN sys.availability_groups ag ON ar.group_id = ag.group_id
|
||||
WHERE ag.name = {0} AND ar.replica_server_name = {2}
|
||||
)
|
||||
ALTER AVAILABILITY GROUP {1}
|
||||
ADD REPLICA ON {3}
|
||||
;
|
||||
""".format(
|
||||
quoteName(name, "'"),
|
||||
quoteName(name, '['),
|
||||
quoteName(replica.split('.')[0], "'"),
|
||||
replica_spec(replica, dbm_endpoint_port)
|
||||
))
|
||||
|
||||
else:
|
||||
sqlcmd(login_port, login_name, login_password, """
|
||||
IF NOT EXISTS (
|
||||
SELECT * FROM sys.availability_groups WHERE name = {0}
|
||||
)
|
||||
ALTER AVAILABILITY GROUP {1} JOIN WITH (CLUSTER_TYPE = EXTERNAL)
|
||||
;
|
||||
|
||||
ALTER AVAILABILITY GROUP {1} GRANT CREATE ANY DATABASE
|
||||
;
|
||||
""".format(
|
||||
quoteName(name, "'"),
|
||||
quoteName(name, '[')
|
||||
))
|
||||
|
||||
module.exit_json(changed = True, name = name)
|
||||
|
||||
def sqlcmd(login_port, login_name, login_password, command):
|
||||
subprocess.check_call([
|
||||
'/opt/mssql-tools/bin/sqlcmd',
|
||||
'-S',
|
||||
"localhost,{0}".format(login_port),
|
||||
'-U',
|
||||
login_name,
|
||||
'-P',
|
||||
login_password,
|
||||
'-b',
|
||||
'-Q',
|
||||
command
|
||||
])
|
||||
|
||||
def quoteName(name, quote_char):
|
||||
if quote_char == '[' or quote_char == ']':
|
||||
(quote_start_char, quote_end_char) = ('[', ']')
|
||||
elif quote_char == "'":
|
||||
(quote_start_char, quote_end_char) = ("N'", "'")
|
||||
else:
|
||||
raise Exception("Unsupported quote_char {0}, must be [ or ] or '".format(quote_char))
|
||||
|
||||
return "{0}{1}{2}".format(quote_start_char, name.replace(quote_end_char, quote_end_char + quote_end_char), quote_end_char)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
+184
@@ -0,0 +1,184 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.1',
|
||||
'supported_by': 'community',
|
||||
'status': ['preview']
|
||||
}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: mssql_ag_listener
|
||||
|
||||
short_description: Create an availability group listener on a SQL Server instance
|
||||
|
||||
description:
|
||||
- Create an availability group listener on a SQL Server instance.
|
||||
|
||||
version_added: "2.2"
|
||||
|
||||
author: Arnav Singh (@arsing)
|
||||
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- The name of the listener to add
|
||||
required: true
|
||||
|
||||
ag_name:
|
||||
description:
|
||||
- The name of the availability group to add the listener to
|
||||
required: true
|
||||
|
||||
ip:
|
||||
description:
|
||||
- The IPs for the listener to bind to
|
||||
required: true
|
||||
|
||||
readonly_routing_replicas:
|
||||
description:
|
||||
- A list of all the replicas of the AG that should participate in read-only routing
|
||||
required: false
|
||||
|
||||
login_port:
|
||||
description:
|
||||
- The TDS port of the instance
|
||||
required: false
|
||||
default: 1433
|
||||
|
||||
login_name:
|
||||
description:
|
||||
- The name of the user to log in to the instance
|
||||
required: true
|
||||
|
||||
login_password:
|
||||
description:
|
||||
- The password of the user to log in to the instance
|
||||
required: true
|
||||
|
||||
notes:
|
||||
- Requires the mssql-tools package on the remote host.
|
||||
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- mssql-tools
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
EXAMPLES = '''
|
||||
# Creates an AG listener named foo for the AG named bar with IP 1.2.3.4, and have all replicas in the "servers" group participate in read-only routing
|
||||
- mssql_ag_listener:
|
||||
name: foo
|
||||
ag_name: bar
|
||||
ip:
|
||||
- '1.2.3.4'
|
||||
readonly_routing_replicas: "{{ groups['servers'] }}"
|
||||
login_name: sa
|
||||
login_password: password
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
RETURN = '''
|
||||
name:
|
||||
description: The name of the AG listener that was created
|
||||
returned: success
|
||||
type: string
|
||||
sample: foo
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
import subprocess
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
name = dict(required = True),
|
||||
ag_name = dict(required = True),
|
||||
ip = dict(type = 'list', required = True),
|
||||
readonly_routing_replicas = dict(type = 'list', required = True),
|
||||
login_port = dict(required = False, default = 1433),
|
||||
login_name = dict(required = True),
|
||||
login_password = dict(required = True, no_log = True)
|
||||
)
|
||||
)
|
||||
|
||||
name = module.params['name']
|
||||
ag_name = module.params['ag_name']
|
||||
ips = module.params['ip']
|
||||
readonly_routing_replicas = module.params['readonly_routing_replicas']
|
||||
login_port = module.params['login_port']
|
||||
login_name = module.params['login_name']
|
||||
login_password = module.params['login_password']
|
||||
|
||||
sqlcmd(login_port, login_name, login_password, """
|
||||
IF EXISTS (
|
||||
SELECT *
|
||||
FROM
|
||||
sys.availability_groups ag JOIN
|
||||
sys.availability_group_listeners agl ON ag.group_id = agl.group_id
|
||||
WHERE
|
||||
ag.name = {0} AND agl.dns_name = {2}
|
||||
)
|
||||
ALTER AVAILABILITY GROUP {1} REMOVE LISTENER {2}
|
||||
;
|
||||
|
||||
ALTER AVAILABILITY GROUP {1} ADD LISTENER {2} (WITH IP ({3}))
|
||||
""".format(
|
||||
quoteName(ag_name, "'"),
|
||||
quoteName(ag_name, '['),
|
||||
quoteName(name, "'"),
|
||||
', '.join("({0}, '255.255.255.255')".format(quoteName(ip, "'")) for ip in ips)
|
||||
))
|
||||
|
||||
for replica in readonly_routing_replicas:
|
||||
sqlcmd(login_port, login_name, login_password, """
|
||||
ALTER AVAILABILITY GROUP {0} MODIFY REPLICA ON {1} WITH (PRIMARY_ROLE (ALLOW_CONNECTIONS = READ_WRITE))
|
||||
;
|
||||
ALTER AVAILABILITY GROUP {0} MODIFY REPLICA ON {1} WITH (SECONDARY_ROLE (ALLOW_CONNECTIONS = READ_ONLY))
|
||||
;
|
||||
ALTER AVAILABILITY GROUP {0} MODIFY REPLICA ON {1} WITH (SECONDARY_ROLE (READ_ONLY_ROUTING_URL = {2}))
|
||||
;
|
||||
""".format(
|
||||
quoteName(ag_name, '['),
|
||||
quoteName(replica.split('.')[0], "'"),
|
||||
quoteName('tcp://{0}:{1}'.format(replica, login_port), "'")
|
||||
))
|
||||
|
||||
for replica in readonly_routing_replicas:
|
||||
sqlcmd(login_port, login_name, login_password, """
|
||||
ALTER AVAILABILITY GROUP {0} MODIFY REPLICA ON {1} WITH (PRIMARY_ROLE (READ_ONLY_ROUTING_LIST = ({2})))
|
||||
""".format(
|
||||
quoteName(ag_name, '['),
|
||||
quoteName(replica.split('.')[0], "'"),
|
||||
', '.join(quoteName(other_replica.split('.')[0], "'") for other_replica in readonly_routing_replicas if other_replica != replica)
|
||||
))
|
||||
|
||||
module.exit_json(changed = True, name = name)
|
||||
|
||||
def sqlcmd(login_port, login_name, login_password, command):
|
||||
subprocess.check_call([
|
||||
'/opt/mssql-tools/bin/sqlcmd',
|
||||
'-S',
|
||||
"localhost,{0}".format(login_port),
|
||||
'-U',
|
||||
login_name,
|
||||
'-P',
|
||||
login_password,
|
||||
'-b',
|
||||
'-Q',
|
||||
command
|
||||
])
|
||||
|
||||
def quoteName(name, quote_char):
|
||||
if quote_char == '[' or quote_char == ']':
|
||||
(quote_start_char, quote_end_char) = ('[', ']')
|
||||
elif quote_char == "'":
|
||||
(quote_start_char, quote_end_char) = ("N'", "'")
|
||||
else:
|
||||
raise Exception("Unsupported quote_char {0}, must be [ or ] or '".format(quote_char))
|
||||
|
||||
return "{0}{1}{2}".format(quote_start_char, name.replace(quote_end_char, quote_end_char + quote_end_char), quote_end_char)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.1',
|
||||
'supported_by': 'community',
|
||||
'status': ['preview']
|
||||
}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: mssql_certificate
|
||||
|
||||
short_description: Add certificates to a SQL Server instance
|
||||
|
||||
description:
|
||||
- Add certificates to a SQL Server instance.
|
||||
|
||||
version_added: "2.2"
|
||||
|
||||
author: Arnav Singh (@arsing)
|
||||
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- The name of the certificate to add
|
||||
required: true
|
||||
|
||||
authorization_username:
|
||||
description:
|
||||
- The name of the SQL user to authorize with this certificate
|
||||
required: false
|
||||
default: 0.0.0.0
|
||||
|
||||
pub_key_path:
|
||||
description:
|
||||
- The path of the public key of the certificate (in Windows form)
|
||||
required: true
|
||||
|
||||
priv_key_path:
|
||||
description:
|
||||
- The path of the private key of the certificate (in Windows form)
|
||||
required: true
|
||||
|
||||
priv_key_password:
|
||||
description:
|
||||
- The password to decrypt the private key of the certificate
|
||||
required: true
|
||||
|
||||
login_port:
|
||||
description:
|
||||
- The TDS port of the instance
|
||||
required: false
|
||||
default: 1433
|
||||
|
||||
login_name:
|
||||
description:
|
||||
- The name of the user to log in to the instance
|
||||
required: true
|
||||
|
||||
login_password:
|
||||
description:
|
||||
- The password of the user to log in to the instance
|
||||
required: true
|
||||
|
||||
notes:
|
||||
- Requires the mssql-tools package on the remote host.
|
||||
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- mssql-tools
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
EXAMPLES = '''
|
||||
- mssql_certificate:
|
||||
name: dbm_cert
|
||||
authorization_username: dbm_user
|
||||
pub_key_path: "C:\\var\\opt\\mssql\\secrets\\dbm_certificate.cer"
|
||||
priv_key_path: "C:\\var\\opt\\mssql\\secrets\\dbm_certificate.pvk"
|
||||
priv_key_password: password
|
||||
login_name: sa
|
||||
login_password: password
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
RETURN = '''
|
||||
name:
|
||||
description: The name of the certificate that was added
|
||||
returned: success
|
||||
type: string
|
||||
sample: foo
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
import subprocess
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
name = dict(required = True),
|
||||
authorization_username = dict(required = True),
|
||||
pub_key_path = dict(required = True),
|
||||
priv_key_path = dict(required = True),
|
||||
priv_key_password = dict(required = True, no_log = True),
|
||||
login_port = dict(required = False, default = 1433),
|
||||
login_name = dict(required = True),
|
||||
login_password = dict(required = True, no_log = True)
|
||||
)
|
||||
)
|
||||
|
||||
name = module.params['name']
|
||||
authorization_username = module.params['authorization_username']
|
||||
pub_key_path = module.params['pub_key_path']
|
||||
priv_key_path = module.params['priv_key_path']
|
||||
priv_key_password = module.params['priv_key_password']
|
||||
login_port = module.params['login_port']
|
||||
login_name = module.params['login_name']
|
||||
login_password = module.params['login_password']
|
||||
|
||||
sqlcmd(login_port, login_name, login_password, """
|
||||
IF NOT EXISTS(
|
||||
SELECT * FROM sys.certificates WHERE name = {0}
|
||||
)
|
||||
CREATE CERTIFICATE {1}
|
||||
AUTHORIZATION {2}
|
||||
FROM FILE = {3}
|
||||
WITH PRIVATE KEY (
|
||||
FILE = {4},
|
||||
DECRYPTION BY PASSWORD = {5}
|
||||
)
|
||||
;
|
||||
""".format(
|
||||
quoteName(name, "'"),
|
||||
quoteName(name, '['),
|
||||
quoteName(authorization_username, '['),
|
||||
quoteName(pub_key_path, "'"),
|
||||
quoteName(priv_key_path, "'"),
|
||||
quoteName(priv_key_password, "'")
|
||||
))
|
||||
|
||||
module.exit_json(changed = True, name = name)
|
||||
|
||||
def sqlcmd(login_port, login_name, login_password, command):
|
||||
subprocess.check_call([
|
||||
'/opt/mssql-tools/bin/sqlcmd',
|
||||
'-S',
|
||||
"localhost,{0}".format(login_port),
|
||||
'-U',
|
||||
login_name,
|
||||
'-P',
|
||||
login_password,
|
||||
'-b',
|
||||
'-Q',
|
||||
command
|
||||
])
|
||||
|
||||
def quoteName(name, quote_char):
|
||||
if quote_char == '[' or quote_char == ']':
|
||||
(quote_start_char, quote_end_char) = ('[', ']')
|
||||
elif quote_char == "'":
|
||||
(quote_start_char, quote_end_char) = ("N'", "'")
|
||||
else:
|
||||
raise Exception("Unsupported quote_char {0}, must be [ or ] or '".format(quote_char))
|
||||
|
||||
return "{0}{1}{2}".format(quote_start_char, name.replace(quote_end_char, quote_end_char + quote_end_char), quote_end_char)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,138 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.1',
|
||||
'supported_by': 'community',
|
||||
'status': ['preview']
|
||||
}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: mssql_conf
|
||||
|
||||
short_description: Set configuration settings for a SQL Server instance
|
||||
|
||||
description:
|
||||
- Set configuration settings for a SQL Server instance
|
||||
|
||||
version_added: "2.2"
|
||||
|
||||
author: Arnav Singh (@arsing)
|
||||
|
||||
options:
|
||||
setup_sa_password:
|
||||
description:
|
||||
- The password to set for the sa account in setup
|
||||
required: false
|
||||
|
||||
name:
|
||||
description:
|
||||
- The name of the setting
|
||||
required: false
|
||||
|
||||
value:
|
||||
description:
|
||||
- The value of the setting
|
||||
required: false
|
||||
|
||||
login_port:
|
||||
description:
|
||||
- The TDS port of the instance
|
||||
required: false
|
||||
default: 1433
|
||||
|
||||
|
||||
login_name:
|
||||
description:
|
||||
- The name of the user to log in to the instance
|
||||
required: true
|
||||
|
||||
login_password:
|
||||
description:
|
||||
- The password of the user to log in to the instance
|
||||
required: true
|
||||
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
EXAMPLES = '''
|
||||
# Enables HADRON
|
||||
- mssql_conf:
|
||||
name: hadr.hadrenabled
|
||||
value: 1
|
||||
login_name: sa
|
||||
login_password: password
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
RETURN = '''
|
||||
#
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
import os.path
|
||||
import subprocess
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
setup_sa_password = dict(required = False, no_log = True),
|
||||
setup_pid = dict(required = False),
|
||||
name = dict(required = False),
|
||||
value = dict(required = False),
|
||||
traceflags_on = dict(type = 'list', required = False),
|
||||
traceflags_off = dict(type = 'list', required = False),
|
||||
login_port = dict(required = False, default = 1433),
|
||||
login_name = dict(required = True),
|
||||
login_password = dict(required = True, no_log = True)
|
||||
),
|
||||
required_one_of = [
|
||||
['setup_sa_password', 'name', 'traceflags_on', 'traceflags_off']
|
||||
],
|
||||
mutually_exclusive = [
|
||||
['setup_sa_password', 'name', 'traceflags_on'],
|
||||
['setup_sa_password', 'name', 'traceflags_off'],
|
||||
],
|
||||
required_together = [
|
||||
['setup_sa_password', 'setup_pid'],
|
||||
['name', 'value']
|
||||
],
|
||||
)
|
||||
|
||||
setup_sa_password = module.params['setup_sa_password']
|
||||
setup_pid = module.params['setup_pid']
|
||||
name = module.params['name']
|
||||
value = module.params['value']
|
||||
traceflags_on = module.params['traceflags_on']
|
||||
traceflags_off = module.params['traceflags_off']
|
||||
login_port = module.params['login_port']
|
||||
login_name = module.params['login_name']
|
||||
login_password = module.params['login_password']
|
||||
|
||||
changed = True
|
||||
|
||||
if setup_sa_password is not None:
|
||||
if os.path.isfile('/var/opt/mssql/mssql.conf'):
|
||||
changed = False
|
||||
else:
|
||||
setup_env = os.environ.copy()
|
||||
subprocess.check_call(
|
||||
['/opt/mssql/bin/mssql-conf', '--noprompt', 'setup', 'accept-eula'],
|
||||
env = { 'MSSQL_SA_PASSWORD': setup_sa_password, 'MSSQL_PID': setup_pid })
|
||||
|
||||
if name is not None:
|
||||
subprocess.check_call(['/opt/mssql/bin/mssql-conf', '--noprompt', 'set', name, value])
|
||||
|
||||
if traceflags_on is not None:
|
||||
subprocess.check_call(['/opt/mssql/bin/mssql-conf', '--noprompt', 'traceflag'] + [str(traceflag) for traceflag in traceflags_on] + ['on'])
|
||||
|
||||
if traceflags_off is not None:
|
||||
subprocess.check_call(['/opt/mssql/bin/mssql-conf', '--noprompt', 'traceflag'] + [str(traceflag) for traceflag in traceflags_off] + ['off'])
|
||||
|
||||
module.exit_json(changed = changed)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,201 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.1',
|
||||
'supported_by': 'community',
|
||||
'status': ['preview']
|
||||
}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: mssql_login
|
||||
|
||||
short_description: Add endpoints to a SQL Server instance
|
||||
|
||||
description:
|
||||
- Add endpoints to a SQL Server instance.
|
||||
|
||||
version_added: "2.2"
|
||||
|
||||
author: Arnav Singh (@arsing)
|
||||
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- The name of the endpoint to add
|
||||
required: true
|
||||
|
||||
ip:
|
||||
description:
|
||||
- The IP to bind to
|
||||
required: false
|
||||
default: 0.0.0.0
|
||||
|
||||
port:
|
||||
description:
|
||||
- The port to bind to
|
||||
required: true
|
||||
|
||||
type:
|
||||
description:
|
||||
- The type of the endpoint
|
||||
required: true
|
||||
choices: ["DATA_MIRRORING"]
|
||||
|
||||
dbm_cert_name:
|
||||
description:
|
||||
- The name of the cert to use for the DATA_MIRRORING endpoint
|
||||
required: false
|
||||
default: []
|
||||
|
||||
state:
|
||||
description:
|
||||
- The state to set the endpoint to
|
||||
required: false
|
||||
choices:
|
||||
- started
|
||||
default: started
|
||||
|
||||
login_port:
|
||||
description:
|
||||
- The TDS port of the instance
|
||||
required: false
|
||||
default: 1433
|
||||
|
||||
login_name:
|
||||
description:
|
||||
- The name of the user to log in to the instance
|
||||
required: true
|
||||
|
||||
login_password:
|
||||
description:
|
||||
- The password of the user to log in to the instance
|
||||
required: true
|
||||
|
||||
notes:
|
||||
- Requires the mssql-tools package on the remote host.
|
||||
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- mssql-tools
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
EXAMPLES = '''
|
||||
# Create a DBM endpoint named 'foo' on port 5022 with authentication from the cert named 'bar'
|
||||
- mssql_endpoint:
|
||||
name: foo
|
||||
port: 5022
|
||||
type: DATA_MIRRORING
|
||||
dbm_cert_name: bar
|
||||
state: started
|
||||
login_name: sa
|
||||
login_password: password
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
RETURN = '''
|
||||
name:
|
||||
description: The name of the endpoint that was added
|
||||
returned: success
|
||||
type: string
|
||||
sample: foo
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
import subprocess
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
name = dict(required = True),
|
||||
ip = dict(required = False, default = "0.0.0.0"),
|
||||
port = dict(required = True),
|
||||
type = dict(choices = ['DATA_MIRRORING'], required = True),
|
||||
dbm_cert_name = dict(required = False),
|
||||
state = dict(choices = ['started'], required = False, default = 'started'),
|
||||
login_port = dict(required = False, default = 1433),
|
||||
login_name = dict(required = True),
|
||||
login_password = dict(required = True, no_log = True)
|
||||
),
|
||||
required_if = [
|
||||
['type', 'DATA_MIRRORING', ['dbm_cert_name']]
|
||||
]
|
||||
)
|
||||
|
||||
name = module.params['name']
|
||||
ip = module.params['ip']
|
||||
port = module.params['port']
|
||||
type = module.params['type']
|
||||
dbm_cert_name = module.params['dbm_cert_name']
|
||||
state = module.params['state']
|
||||
login_port = module.params['login_port']
|
||||
login_name = module.params['login_name']
|
||||
login_password = module.params['login_password']
|
||||
|
||||
if type == "DATA_MIRRORING":
|
||||
options = """
|
||||
ROLE = ALL,
|
||||
AUTHENTICATION = CERTIFICATE {0},
|
||||
ENCRYPTION = REQUIRED ALGORITHM AES
|
||||
""".format(
|
||||
quoteName(dbm_cert_name, '[')
|
||||
)
|
||||
|
||||
sqlcmd(login_port, login_name, login_password, """
|
||||
IF NOT EXISTS(
|
||||
SELECT * FROM sys.tcp_endpoints WHERE name = {0}
|
||||
)
|
||||
CREATE ENDPOINT {1}
|
||||
AS TCP (LISTENER_IP = ({2}), LISTENER_PORT = {3})
|
||||
FOR DATA_MIRRORING ({4})
|
||||
;
|
||||
""".format(
|
||||
quoteName(name, "'"),
|
||||
quoteName(name, '['),
|
||||
ip,
|
||||
port,
|
||||
options
|
||||
))
|
||||
|
||||
if state == 'started':
|
||||
sqlcmd(login_port, login_name, login_password, """
|
||||
IF NOT EXISTS(
|
||||
SELECT * FROM sys.tcp_endpoints WHERE name = {0} AND state = 0
|
||||
)
|
||||
ALTER ENDPOINT {1} STATE = STARTED
|
||||
;
|
||||
""".format(
|
||||
quoteName(name, "'"),
|
||||
quoteName(name, '[')
|
||||
))
|
||||
|
||||
module.exit_json(changed = True, name = name)
|
||||
|
||||
def sqlcmd(login_port, login_name, login_password, command):
|
||||
subprocess.check_call([
|
||||
'/opt/mssql-tools/bin/sqlcmd',
|
||||
'-S',
|
||||
"localhost,{0}".format(login_port),
|
||||
'-U',
|
||||
login_name,
|
||||
'-P',
|
||||
login_password,
|
||||
'-b',
|
||||
'-Q',
|
||||
command
|
||||
])
|
||||
|
||||
def quoteName(name, quote_char):
|
||||
if quote_char == '[' or quote_char == ']':
|
||||
(quote_start_char, quote_end_char) = ('[', ']')
|
||||
elif quote_char == "'":
|
||||
(quote_start_char, quote_end_char) = ("N'", "'")
|
||||
else:
|
||||
raise Exception("Unsupported quote_char {0}, must be [ or ] or '".format(quote_char))
|
||||
|
||||
return "{0}{1}{2}".format(quote_start_char, name.replace(quote_end_char, quote_end_char + quote_end_char), quote_end_char)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.1',
|
||||
'supported_by': 'community',
|
||||
'status': ['preview']
|
||||
}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: mssql_grant_endpoint
|
||||
|
||||
short_description: Grants permissions on endpoints of a SQL Server instance
|
||||
|
||||
description:
|
||||
- Grants permissions on endpoints of a SQL Server instance.
|
||||
|
||||
version_added: "2.2"
|
||||
|
||||
author: Arnav Singh (@arsing)
|
||||
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- The name of the endpoint
|
||||
required: true
|
||||
|
||||
permission:
|
||||
description:
|
||||
- The permission to grant on the endpoint
|
||||
required: true
|
||||
|
||||
principal:
|
||||
description:
|
||||
- The principal to grant the permission to
|
||||
required: true
|
||||
|
||||
login_port:
|
||||
description:
|
||||
- The TDS port of the instance
|
||||
required: false
|
||||
default: 1433
|
||||
|
||||
login_name:
|
||||
description:
|
||||
- The name of the user to log in to the instance
|
||||
required: true
|
||||
|
||||
login_password:
|
||||
description:
|
||||
- The password of the user to log in to the instance
|
||||
required: true
|
||||
|
||||
notes:
|
||||
- Requires the mssql-tools package on the remote host.
|
||||
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- mssql-tools
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
EXAMPLES = '''
|
||||
# Grants CONNECT permission on the DBM endpoint named 'foo' to the login 'bar'
|
||||
- mssql_endpoint:
|
||||
name: foo
|
||||
permission: CONNECT
|
||||
principal: bar
|
||||
login_name: sa
|
||||
login_password: password
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
RETURN = '''
|
||||
name:
|
||||
description: The name of the login that was added
|
||||
returned: success
|
||||
type: string
|
||||
sample: foo
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
import subprocess
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
name = dict(required = True),
|
||||
permission = dict(choices = ["CONNECT"], required = True),
|
||||
principal = dict(required = True),
|
||||
login_port = dict(required = False, default = 1433),
|
||||
login_name = dict(required = True),
|
||||
login_password = dict(required = True, no_log = True)
|
||||
)
|
||||
)
|
||||
|
||||
permission = module.params['permission']
|
||||
name = module.params['name']
|
||||
principal = module.params['principal']
|
||||
login_port = module.params['login_port']
|
||||
login_name = module.params['login_name']
|
||||
login_password = module.params['login_password']
|
||||
|
||||
sqlcmd(login_port, login_name, login_password, """
|
||||
GRANT {0} ON ENDPOINT::{1} TO {2}
|
||||
""".format(
|
||||
permission,
|
||||
quoteName(name, '['),
|
||||
quoteName(principal, '[')
|
||||
))
|
||||
|
||||
module.exit_json(changed = True, name = name)
|
||||
|
||||
def sqlcmd(login_port, login_name, login_password, command):
|
||||
subprocess.check_call([
|
||||
'/opt/mssql-tools/bin/sqlcmd',
|
||||
'-S',
|
||||
"localhost,{0}".format(login_port),
|
||||
'-U',
|
||||
login_name,
|
||||
'-P',
|
||||
login_password,
|
||||
'-b',
|
||||
'-Q',
|
||||
command
|
||||
])
|
||||
|
||||
def quoteName(name, quote_char):
|
||||
if quote_char == '[' or quote_char == ']':
|
||||
(quote_start_char, quote_end_char) = ('[', ']')
|
||||
elif quote_char == "'":
|
||||
(quote_start_char, quote_end_char) = ("N'", "'")
|
||||
else:
|
||||
raise Exception("Unsupported quote_char {0}, must be [ or ] or '".format(quote_char))
|
||||
|
||||
return "{0}{1}{2}".format(quote_start_char, name.replace(quote_end_char, quote_end_char + quote_end_char), quote_end_char)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,160 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.1',
|
||||
'supported_by': 'community',
|
||||
'status': ['preview']
|
||||
}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: mssql_login
|
||||
|
||||
short_description: Add logins to a SQL Server instance
|
||||
|
||||
description:
|
||||
- Add logins to a SQL Server instance.
|
||||
|
||||
version_added: "2.2"
|
||||
|
||||
author: Arnav Singh (@arsing)
|
||||
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- The name of the login to add
|
||||
required: true
|
||||
|
||||
password:
|
||||
description:
|
||||
- The password of the login
|
||||
required: true
|
||||
|
||||
roles:
|
||||
description:
|
||||
- The roles to add the login to
|
||||
required: false
|
||||
default: []
|
||||
|
||||
login_port:
|
||||
description:
|
||||
- The TDS port of the instance
|
||||
required: false
|
||||
default: 1433
|
||||
|
||||
login_name:
|
||||
description:
|
||||
- The name of the user to log in to the instance
|
||||
required: true
|
||||
|
||||
login_password:
|
||||
description:
|
||||
- The password of the user to log in to the instance
|
||||
required: true
|
||||
|
||||
notes:
|
||||
- Requires the mssql-tools package on the remote host.
|
||||
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- mssql-tools
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
EXAMPLES = '''
|
||||
# Create a login named 'foo' with password 'bar' and add it to sysadmin role
|
||||
- mssql_login:
|
||||
name: foo
|
||||
password: bar
|
||||
roles:
|
||||
- sysadmin
|
||||
login_name: sa
|
||||
login_password: password
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
RETURN = '''
|
||||
name:
|
||||
description: The name of the login that was added
|
||||
returned: success
|
||||
type: string
|
||||
sample: foo
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
import subprocess
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
name = dict(required = True),
|
||||
password = dict(required = True, no_log = True),
|
||||
roles = dict(type = 'list', required = False, default = []),
|
||||
login_port = dict(required = False, default = 1433),
|
||||
login_name = dict(required = True),
|
||||
login_password = dict(required = True, no_log = True)
|
||||
)
|
||||
)
|
||||
|
||||
name = module.params['name']
|
||||
password = module.params['password']
|
||||
roles = module.params['roles']
|
||||
login_port = module.params['login_port']
|
||||
login_name = module.params['login_name']
|
||||
login_password = module.params['login_password']
|
||||
|
||||
sqlcmd(login_port, login_name, login_password, """
|
||||
IF EXISTS(
|
||||
SELECT * FROM sys.sql_logins WHERE name = {0}
|
||||
)
|
||||
ALTER LOGIN {1} WITH PASSWORD = {2}
|
||||
ELSE
|
||||
CREATE LOGIN {1} WITH
|
||||
PASSWORD = {2},
|
||||
DEFAULT_DATABASE = [master],
|
||||
CHECK_EXPIRATION = OFF,
|
||||
CHECK_POLICY = OFF
|
||||
;
|
||||
""".format(
|
||||
quoteName(name, "'"),
|
||||
quoteName(name, '['),
|
||||
quoteName(password, "'")
|
||||
))
|
||||
|
||||
for role in roles:
|
||||
sqlcmd(login_port, login_name, login_password, """
|
||||
ALTER SERVER ROLE {0} ADD MEMBER {1}
|
||||
""".format(
|
||||
quoteName(role, '['),
|
||||
quoteName(name, '[')
|
||||
))
|
||||
|
||||
module.exit_json(changed = True, name = name)
|
||||
|
||||
def sqlcmd(login_port, login_name, login_password, command):
|
||||
subprocess.check_call([
|
||||
'/opt/mssql-tools/bin/sqlcmd',
|
||||
'-S',
|
||||
"localhost,{0}".format(login_port),
|
||||
'-U',
|
||||
login_name,
|
||||
'-P',
|
||||
login_password,
|
||||
'-b',
|
||||
'-Q',
|
||||
command
|
||||
])
|
||||
|
||||
def quoteName(name, quote_char):
|
||||
if quote_char == '[' or quote_char == ']':
|
||||
(quote_start_char, quote_end_char) = ('[', ']')
|
||||
elif quote_char == "'":
|
||||
(quote_start_char, quote_end_char) = ("N'", "'")
|
||||
else:
|
||||
raise Exception("Unsupported quote_char {0}, must be [ or ] or '".format(quote_char))
|
||||
|
||||
return "{0}{1}{2}".format(quote_start_char, name.replace(quote_end_char, quote_end_char + quote_end_char), quote_end_char)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.1',
|
||||
'supported_by': 'community',
|
||||
'status': ['preview']
|
||||
}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: mssql_master_key
|
||||
|
||||
short_description: Add master keys to a SQL Server instance
|
||||
|
||||
description:
|
||||
- Add master keys to a SQL Server instance.
|
||||
|
||||
version_added: "2.2"
|
||||
|
||||
author: Arnav Singh (@arsing)
|
||||
|
||||
options:
|
||||
password:
|
||||
description:
|
||||
- The password of the master key
|
||||
required: true
|
||||
|
||||
login_port:
|
||||
description:
|
||||
- The TDS port of the instance
|
||||
required: false
|
||||
default: 1433
|
||||
|
||||
login_name:
|
||||
description:
|
||||
- The name of the user to log in to the instance
|
||||
required: true
|
||||
|
||||
login_password:
|
||||
description:
|
||||
- The password of the user to log in to the instance
|
||||
required: true
|
||||
|
||||
notes:
|
||||
- Requires the mssql-tools package on the remote host.
|
||||
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- mssql-tools
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
EXAMPLES = '''
|
||||
# Create a master key with password 'foo'
|
||||
- mssql_master_key:
|
||||
password: foo
|
||||
login_name: sa
|
||||
login_password: password
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
RETURN = '''
|
||||
#
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
import subprocess
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
password = dict(required = True, no_log = True),
|
||||
login_port = dict(required = False, default = 1433),
|
||||
login_name = dict(required = True),
|
||||
login_password = dict(required = True, no_log = True)
|
||||
)
|
||||
)
|
||||
|
||||
password = module.params['password']
|
||||
login_port = module.params['login_port']
|
||||
login_name = module.params['login_name']
|
||||
login_password = module.params['login_password']
|
||||
|
||||
sqlcmd(login_port, login_name, login_password, """
|
||||
IF EXISTS (
|
||||
SELECT * FROM sys.symmetric_keys WHERE name = '##MS_DatabaseMasterKey##'
|
||||
)
|
||||
ALTER MASTER KEY REGENERATE WITH ENCRYPTION BY PASSWORD = {0}
|
||||
ELSE
|
||||
CREATE MASTER KEY ENCRYPTION BY PASSWORD = {0}
|
||||
""".format(
|
||||
quoteName(password, "'")
|
||||
))
|
||||
|
||||
module.exit_json(changed = True)
|
||||
|
||||
def sqlcmd(login_port, login_name, login_password, command):
|
||||
subprocess.check_call([
|
||||
'/opt/mssql-tools/bin/sqlcmd',
|
||||
'-S',
|
||||
"localhost,{0}".format(login_port),
|
||||
'-U',
|
||||
login_name,
|
||||
'-P',
|
||||
login_password,
|
||||
'-b',
|
||||
'-Q',
|
||||
command
|
||||
])
|
||||
|
||||
def quoteName(name, quote_char):
|
||||
if quote_char == '[' or quote_char == ']':
|
||||
(quote_start_char, quote_end_char) = ('[', ']')
|
||||
elif quote_char == "'":
|
||||
(quote_start_char, quote_end_char) = ("N'", "'")
|
||||
else:
|
||||
raise Exception("Unsupported quote_char {0}, must be [ or ] or '".format(quote_char))
|
||||
|
||||
return "{0}{1}{2}".format(quote_start_char, name.replace(quote_end_char, quote_end_char + quote_end_char), quote_end_char)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,136 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.1',
|
||||
'supported_by': 'community',
|
||||
'status': ['preview']
|
||||
}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: mssql_user
|
||||
|
||||
short_description: Add users to a SQL Server instance
|
||||
|
||||
description:
|
||||
- Add ysers to a SQL Server instance.
|
||||
|
||||
version_added: "2.2"
|
||||
|
||||
author: Arnav Singh (@arsing)
|
||||
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- The name of the user to add
|
||||
required: true
|
||||
|
||||
login:
|
||||
description:
|
||||
- The login name of the user to add
|
||||
required: true
|
||||
|
||||
login_port:
|
||||
description:
|
||||
- The TDS port of the instance
|
||||
required: false
|
||||
default: 1433
|
||||
|
||||
login_name:
|
||||
description:
|
||||
- The name of the user to log in to the instance
|
||||
required: true
|
||||
|
||||
login_password:
|
||||
description:
|
||||
- The password of the user to log in to the instance
|
||||
required: true
|
||||
|
||||
notes:
|
||||
- Requires the mssql-tools package on the remote host.
|
||||
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- mssql-tools
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
EXAMPLES = '''
|
||||
# Create a user named 'foo' for the login named 'bar'
|
||||
- mssql_user:
|
||||
name: foo
|
||||
login: bar
|
||||
login_name: sa
|
||||
login_password: password
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
RETURN = '''
|
||||
name:
|
||||
description: The name of the user that was added
|
||||
returned: success
|
||||
type: string
|
||||
sample: foo
|
||||
'''.replace('\t', ' ')
|
||||
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
import subprocess
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
name = dict(required = True),
|
||||
login = dict(required = True),
|
||||
login_port = dict(required = False, default = 1433),
|
||||
login_name = dict(required = True),
|
||||
login_password = dict(required = True, no_log = True)
|
||||
)
|
||||
)
|
||||
|
||||
name = module.params['name']
|
||||
login = module.params['login']
|
||||
login_port = module.params['login_port']
|
||||
login_name = module.params['login_name']
|
||||
login_password = module.params['login_password']
|
||||
|
||||
sqlcmd(login_port, login_name, login_password, """
|
||||
IF NOT EXISTS(
|
||||
SELECT * FROM sys.sysusers WHERE name = {0}
|
||||
)
|
||||
CREATE USER {1} FOR LOGIN {2}
|
||||
;
|
||||
""".format(
|
||||
quoteName(name, "'"),
|
||||
quoteName(name, '['),
|
||||
quoteName(login, '[')
|
||||
))
|
||||
|
||||
module.exit_json(changed = True, name = name)
|
||||
|
||||
def sqlcmd(login_port, login_name, login_password, command):
|
||||
subprocess.check_call([
|
||||
'/opt/mssql-tools/bin/sqlcmd',
|
||||
'-S',
|
||||
"localhost,{0}".format(login_port),
|
||||
'-U',
|
||||
login_name,
|
||||
'-P',
|
||||
login_password,
|
||||
'-b',
|
||||
'-Q',
|
||||
command
|
||||
])
|
||||
|
||||
def quoteName(name, quote_char):
|
||||
if quote_char == '[' or quote_char == ']':
|
||||
(quote_start_char, quote_end_char) = ('[', ']')
|
||||
elif quote_char == "'":
|
||||
(quote_start_char, quote_end_char) = ("N'", "'")
|
||||
else:
|
||||
raise Exception("Unsupported quote_char {0}, must be [ or ] or '".format(quote_char))
|
||||
|
||||
return "{0}{1}{2}".format(quote_start_char, name.replace(quote_end_char, quote_end_char + quote_end_char), quote_end_char)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,75 @@
|
||||
---
|
||||
|
||||
# Usage:
|
||||
# ansible-playbook ./play.yml -i ./inventory --ask-vault-pass -e 'ansible_user=<>'
|
||||
|
||||
- hosts: servers
|
||||
|
||||
vars:
|
||||
# The URL of the repo to fetch the mssql-server and mssql-server-ha packages from
|
||||
centos_server_repo_url: 'https://packages.microsoft.com/config/rhel/7/mssql-server.repo'
|
||||
ubuntu_server_repo_url: 'https://packages.microsoft.com/config/ubuntu/16.04/mssql-server.list'
|
||||
|
||||
# The URL of the repo to fetch the mssql-tools package from
|
||||
centos_tools_repo_url: 'https://packages.microsoft.com/config/rhel/7/prod.repo'
|
||||
ubuntu_tools_repo_url: 'https://packages.microsoft.com/config/ubuntu/16.04/prod.list'
|
||||
|
||||
# The sqlservr PID. Only used if mssql-server needs to be installed.
|
||||
pid: 'Developer'
|
||||
|
||||
# The port for the TSQL endpoint
|
||||
tsql_endpoint_port: 1433
|
||||
|
||||
# The name of the DBM endpoint
|
||||
dbm_endpoint_name: 'dbm_endpoint'
|
||||
|
||||
# The port for the DBM endpoint
|
||||
dbm_endpoint_port: 5022
|
||||
|
||||
# The SQL login and SQL username for the DBM endpoint user
|
||||
dbm_login: 'dbm_login'
|
||||
dbm_username: 'dbm_user'
|
||||
|
||||
# The name of the DBM cert
|
||||
dbm_cert_name: 'dbm_cert'
|
||||
|
||||
# The path of the DBM cert public key accessible *from the machine running this playbook*.
|
||||
# The path need not be accessible from the nodes that are being deployed to.
|
||||
dbm_cert_pub: /share/dbm_certificate.cer
|
||||
|
||||
# The path of the DBM cert private key accessible *from the machine running this playbook*.
|
||||
# The path need not be accessible from the nodes that are being deployed to.
|
||||
dbm_cert_priv: /share/dbm_certificate.pvk
|
||||
|
||||
# The filename to store the DBM cert public key as (/var/opt/mssql/data/<this value>)
|
||||
dbm_cert_pub_target: dbm_certificate.cer
|
||||
|
||||
# The filename to store the DBM cert private key as (/var/opt/mssql/data/<this value>)
|
||||
dbm_cert_priv_target: dbm_certificate.pvk
|
||||
|
||||
# The name of the AG and AG pacemaker resource
|
||||
ag_name: 'ag1'
|
||||
|
||||
# The IP of the AG listener
|
||||
ag_listener_ip: ''
|
||||
|
||||
# The NIC that the AG listener IP should be set on
|
||||
ag_listener_nic: 'eno1'
|
||||
|
||||
# The name of the pacemaker cluster
|
||||
pacemaker_cluster_name: 'mycluster'
|
||||
|
||||
# The SQL login for the pacemaker user
|
||||
pacemaker_login: 'pacemaker'
|
||||
|
||||
vars_files:
|
||||
- 'vault.yml'
|
||||
|
||||
become: yes
|
||||
become_user: root
|
||||
become_method: sudo
|
||||
any_errors_fatal: true
|
||||
max_fail_percentage: 0
|
||||
|
||||
roles:
|
||||
- mssql-server-ag-external
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
---
|
||||
|
||||
dependencies:
|
||||
- role: pacemaker
|
||||
- role: mssql-server-ha
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
---
|
||||
|
||||
# install pacemaker resource agents
|
||||
|
||||
- name: install mssql-server-ha package
|
||||
package:
|
||||
name: mssql-server-ha
|
||||
state: latest
|
||||
|
||||
|
||||
# create AG
|
||||
|
||||
- name: create AG with all replicas in secondary role
|
||||
mssql_ag:
|
||||
name: "{{ ag_name }}"
|
||||
state: all_secondaries_or_unjoined
|
||||
login_port: "{{ tsql_endpoint_port }}"
|
||||
login_name: 'sa'
|
||||
login_password: "{{ sa_password }}"
|
||||
|
||||
- name: promote one replica to AG primary and join others to it
|
||||
mssql_ag:
|
||||
name: "{{ ag_name }}"
|
||||
state: all_joined_to_one_primary
|
||||
all_replicas: "{{ groups['servers'] }}"
|
||||
primary: "{{ groups['servers'][0] }}"
|
||||
local_replica: "{{ inventory_hostname }}"
|
||||
dbm_endpoint_port: "{{ dbm_endpoint_port }}"
|
||||
login_port: "{{ tsql_endpoint_port }}"
|
||||
login_name: 'sa'
|
||||
login_password: "{{ sa_password }}"
|
||||
|
||||
|
||||
# create listener
|
||||
|
||||
- name: create listener
|
||||
mssql_ag_listener:
|
||||
name: "{{ ag_name }}_listener"
|
||||
ag_name: "{{ ag_name }}"
|
||||
ip:
|
||||
- "{{ ag_listener_ip }}"
|
||||
readonly_routing_replicas: "{{ groups['servers'] }}"
|
||||
login_port: "{{ tsql_endpoint_port }}"
|
||||
login_name: 'sa'
|
||||
login_password: "{{ sa_password }}"
|
||||
when: inventory_hostname == groups['servers'][0] and ag_listener_ip != ''
|
||||
|
||||
|
||||
# create pacemaker login
|
||||
|
||||
- name: create pacemaker login
|
||||
mssql_login:
|
||||
name: "{{ pacemaker_login }}"
|
||||
password: "{{ pacemaker_password }}"
|
||||
roles:
|
||||
- sysadmin
|
||||
login_port: "{{ tsql_endpoint_port }}"
|
||||
login_name: 'sa'
|
||||
login_password: "{{ sa_password }}"
|
||||
|
||||
- name: create pacemaker passwd file
|
||||
copy:
|
||||
content: |
|
||||
{{ pacemaker_login }}
|
||||
{{ pacemaker_password }}
|
||||
dest: /var/opt/mssql/secrets/passwd
|
||||
mode: 0400
|
||||
|
||||
|
||||
# create AG pacemaker resource
|
||||
|
||||
- name: create AG pacemaker resource
|
||||
shell: |
|
||||
pcs resource show '{{ ag_name }}' ||
|
||||
pcs resource create '{{ ag_name }}' ocf:mssql:ag \
|
||||
'ag_name={{ ag_name }}' \
|
||||
--master meta \
|
||||
master-max=1 master-node-max=1 clone-max={{ groups['servers']|length }} notify=true
|
||||
when: inventory_hostname == groups['servers'][0]
|
||||
|
||||
|
||||
# Create AG listener pacemaker resource
|
||||
|
||||
- name: create AG listener pacemaker resource
|
||||
shell: |
|
||||
pcs resource show '{{ ag_name }}_listener' || \
|
||||
pcs resource create '{{ ag_name }}_listener' ocf:heartbeat:IPaddr2 \
|
||||
'ip={{ ag_listener_ip }}' \
|
||||
'nic={{ ag_listener_nic }}'
|
||||
when: inventory_hostname == groups['servers'][0]
|
||||
|
||||
- name: colocate AG listener with AG primary
|
||||
command: pcs constraint colocation add '{{ ag_name }}_listener' with master '{{ ag_name }}'-master
|
||||
when: inventory_hostname == groups['servers'][0]
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
---
|
||||
|
||||
dependencies:
|
||||
- role: mssql-server
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
---
|
||||
|
||||
# enable HA
|
||||
|
||||
- name: check HA enabled
|
||||
command: /opt/mssql-tools/bin/sqlcmd -U sa -P '{{ sa_password }}' -b -Q "SELECT 'IsHadrEnabled = ' + CONVERT(NVARCHAR(100), SERVERPROPERTY('IsHadrEnabled'))"
|
||||
register: hadr_enabled
|
||||
|
||||
- name: enable HA
|
||||
mssql_conf:
|
||||
name: hadr.hadrenabled
|
||||
value: 1
|
||||
login_name: 'sa'
|
||||
login_password: "{{ sa_password }}"
|
||||
when: hadr_enabled.stdout.find('IsHadrEnabled = 1') == -1
|
||||
|
||||
- name: restart sqlservr to enable HA
|
||||
service:
|
||||
name: mssql-server
|
||||
state: restarted
|
||||
when: hadr_enabled.stdout.find('IsHadrEnabled = 1') == -1
|
||||
|
||||
|
||||
# DBM endpoint
|
||||
|
||||
- name: check if firewalld is installed (CentOS, RedHat)
|
||||
command: rpm -q firewalld
|
||||
register: firewalld_installed
|
||||
failed_when: false
|
||||
when: ansible_distribution in ['CentOS', 'RedHat']
|
||||
|
||||
- name: open DBM endpoint in firewall (CentOS, RedHat)
|
||||
firewalld:
|
||||
port: "{{ dbm_endpoint_port }}/tcp"
|
||||
state: enabled
|
||||
permanent: true
|
||||
when: (ansible_distribution in ['CentOS', 'RedHat']) and firewalld_installed.rc == 0
|
||||
|
||||
- name: reload firewall (CentOS, RedHat)
|
||||
command: firewall-cmd --reload
|
||||
when: (ansible_distribution in ['CentOS', 'RedHat']) and firewalld_installed.rc == 0
|
||||
|
||||
- name: open DBM endpoint in firewall (Ubuntu)
|
||||
ufw:
|
||||
port: "{{ dbm_endpoint_port }}"
|
||||
proto: tcp
|
||||
rule: allow
|
||||
when: ansible_distribution == 'Ubuntu'
|
||||
|
||||
- name: copy DBM cert public key
|
||||
copy:
|
||||
src: "{{ dbm_cert_pub }}"
|
||||
dest: "/var/opt/mssql/data/{{ dbm_cert_pub_target }}"
|
||||
owner: mssql
|
||||
group: mssql
|
||||
mode: 0444
|
||||
|
||||
- name: copy DBM cert private key
|
||||
copy:
|
||||
src: "{{ dbm_cert_priv }}"
|
||||
dest: "/var/opt/mssql/data/{{ dbm_cert_priv_target }}"
|
||||
owner: mssql
|
||||
group: mssql
|
||||
mode: 0400
|
||||
|
||||
- name: create master key
|
||||
mssql_master_key:
|
||||
password: "{{ master_key_password }}"
|
||||
login_port: "{{ tsql_endpoint_port }}"
|
||||
login_name: 'sa'
|
||||
login_password: "{{ sa_password }}"
|
||||
|
||||
- name: create DBM endpoint login
|
||||
mssql_login:
|
||||
name: "{{ dbm_login }}"
|
||||
password: "{{ dbm_password }}"
|
||||
login_port: "{{ tsql_endpoint_port }}"
|
||||
login_name: 'sa'
|
||||
login_password: "{{ sa_password }}"
|
||||
|
||||
- name: create DBM endpoint user
|
||||
mssql_user:
|
||||
name: "{{ dbm_username }}"
|
||||
login: "{{ dbm_login }}"
|
||||
login_port: "{{ tsql_endpoint_port }}"
|
||||
login_name: 'sa'
|
||||
login_password: "{{ sa_password }}"
|
||||
|
||||
- name: create DBM endpoint certificate
|
||||
mssql_certificate:
|
||||
name: "{{ dbm_cert_name }}"
|
||||
authorization_username: "{{ dbm_username }}"
|
||||
pub_key_path: "/var/opt/mssql/data/{{ dbm_cert_pub_target }}"
|
||||
priv_key_path: "/var/opt/mssql/data/{{ dbm_cert_priv_target }}"
|
||||
priv_key_password: "{{ dbm_cert_password }}"
|
||||
login_port: "{{ tsql_endpoint_port }}"
|
||||
login_name: 'sa'
|
||||
login_password: "{{ sa_password }}"
|
||||
|
||||
- name: create DBM endpoint
|
||||
mssql_endpoint:
|
||||
name: "{{ dbm_endpoint_name }}"
|
||||
port: "{{ dbm_endpoint_port }}"
|
||||
type: DATA_MIRRORING
|
||||
dbm_cert_name: "{{ dbm_cert_name }}"
|
||||
state: started
|
||||
login_port: "{{ tsql_endpoint_port }}"
|
||||
login_name: 'sa'
|
||||
login_password: "{{ sa_password }}"
|
||||
|
||||
- name: grant connect on DBM endpoint
|
||||
mssql_grant_endpoint:
|
||||
name: "{{ dbm_endpoint_name }}"
|
||||
permission: CONNECT
|
||||
principal: "{{ dbm_login }}"
|
||||
login_port: "{{ tsql_endpoint_port }}"
|
||||
login_name: 'sa'
|
||||
login_password: "{{ sa_password }}"
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
---
|
||||
|
||||
# install mssql-server package
|
||||
|
||||
- name: install mssql-server repo (CentOS, RedHat)
|
||||
get_url:
|
||||
url: "{{ centos_server_repo_url }}"
|
||||
dest: /etc/yum.repos.d/mssql-server.repo
|
||||
when: ansible_distribution in ['CentOS', 'RedHat']
|
||||
|
||||
- name: install mssql-server repo (Ubuntu)
|
||||
get_url:
|
||||
url: "{{ ubuntu_server_repo_url }}"
|
||||
dest: /etc/apt/sources.list.d/mssql-server.list
|
||||
when: ansible_distribution == 'Ubuntu'
|
||||
|
||||
- name: refresh apt-get cache for server repo (Ubuntu)
|
||||
command: apt-get update
|
||||
when: ansible_distribution == 'Ubuntu'
|
||||
|
||||
- name: install mssql-server package
|
||||
package:
|
||||
name: mssql-server
|
||||
state: latest
|
||||
|
||||
|
||||
# setup
|
||||
|
||||
- name: mssql-server setup
|
||||
mssql_conf:
|
||||
setup_sa_password: "{{ sa_password }}"
|
||||
setup_pid: "{{ pid }}"
|
||||
login_name: 'sa'
|
||||
login_password: "{{ sa_password }}"
|
||||
|
||||
|
||||
# TSQL endpoint
|
||||
|
||||
- name: set TSQL endpoint port
|
||||
mssql_conf:
|
||||
name: network.tcpport
|
||||
value: "{{ tsql_endpoint_port }}"
|
||||
login_name: 'sa'
|
||||
login_password: "{{ sa_password }}"
|
||||
|
||||
- name: check if firewalld is installed (CentOS, RedHat)
|
||||
command: rpm -q firewalld
|
||||
register: firewalld_installed
|
||||
failed_when: false
|
||||
when: ansible_distribution in ['CentOS', 'RedHat']
|
||||
|
||||
- name: open TSQL endpoint in firewall (CentOS, RedHat)
|
||||
firewalld:
|
||||
port: "{{ tsql_endpoint_port }}/tcp"
|
||||
state: enabled
|
||||
permanent: true
|
||||
when: (ansible_distribution in ['CentOS', 'RedHat']) and firewalld_installed.rc == 0
|
||||
|
||||
- name: reload firewall (CentOS, RedHat)
|
||||
command: firewall-cmd --reload
|
||||
when: (ansible_distribution in ['CentOS', 'RedHat']) and firewalld_installed.rc == 0
|
||||
|
||||
- name: open TSQL endpoint in firewall (Ubuntu)
|
||||
ufw:
|
||||
port: "{{ tsql_endpoint_port }}"
|
||||
proto: tcp
|
||||
rule: allow
|
||||
when: ansible_distribution == 'Ubuntu'
|
||||
|
||||
|
||||
# mssql-tools package
|
||||
|
||||
- name: install mssql-tools repo (CentOS, RedHat)
|
||||
get_url:
|
||||
url: "{{ centos_tools_repo_url }}"
|
||||
dest: /etc/yum.repos.d/mssql-tools.repo
|
||||
when: ansible_distribution in ['CentOS', 'RedHat']
|
||||
|
||||
- name: install mssql-tools repo (Ubuntu)
|
||||
get_url:
|
||||
url: "{{ ubuntu_tools_repo_url }}"
|
||||
dest: /etc/apt/sources.list.d/mssql-tools.list
|
||||
when: ansible_distribution == 'Ubuntu'
|
||||
|
||||
- name: refresh apt-get cache for tools repo (Ubuntu)
|
||||
command: apt-get update
|
||||
when: ansible_distribution == 'Ubuntu'
|
||||
|
||||
- name: install mssql-tools package
|
||||
package:
|
||||
name: mssql-tools
|
||||
state: latest
|
||||
environment:
|
||||
ACCEPT_EULA: 'y'
|
||||
|
||||
|
||||
# Start mssql-server service
|
||||
|
||||
- name: start sqlservr
|
||||
service:
|
||||
name: mssql-server
|
||||
state: started
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
---
|
||||
|
||||
# enable HA repo
|
||||
|
||||
- name: Enable HA repo (RedHat)
|
||||
command: subscription-manager repos --enable=rhel-ha-for-rhel-7-server-rpms
|
||||
when: ansible_distribution == 'RedHat'
|
||||
|
||||
|
||||
# install pacemaker
|
||||
|
||||
- name: ensure pacemaker is installed (CentOS, RedHat)
|
||||
package:
|
||||
name:
|
||||
- fence-agents-all
|
||||
- pacemaker
|
||||
- pcs
|
||||
- resource-agents
|
||||
state: latest
|
||||
when: ansible_distribution in ['CentOS', 'RedHat']
|
||||
|
||||
- name: ensure pacemaker is installed (Ubuntu)
|
||||
package:
|
||||
name:
|
||||
- fence-agents
|
||||
- pacemaker
|
||||
- pcs
|
||||
- resource-agents
|
||||
state: latest
|
||||
when: ansible_distribution == 'Ubuntu'
|
||||
|
||||
- name: check if firewalld is installed (CentOS, RedHat)
|
||||
command: rpm -q firewalld
|
||||
register: firewalld_installed
|
||||
failed_when: false
|
||||
when: ansible_distribution in ['CentOS', 'RedHat']
|
||||
|
||||
- name: open pacemaker in firewall (CentOS, RedHat)
|
||||
firewalld:
|
||||
service: high-availability
|
||||
state: enabled
|
||||
permanent: true
|
||||
immediate: true
|
||||
when: (ansible_distribution in ['CentOS', 'RedHat']) and firewalld_installed.rc == 0
|
||||
|
||||
- name: reload firewall (CentOS, RedHat)
|
||||
command: firewall-cmd --reload
|
||||
when: (ansible_distribution in ['CentOS', 'RedHat']) and firewalld_installed.rc == 0
|
||||
|
||||
- name: open pacemaker in firewall (TCP) (Ubuntu)
|
||||
ufw:
|
||||
port: "{{ item }}"
|
||||
proto: tcp
|
||||
rule: allow
|
||||
with_items:
|
||||
- 2224
|
||||
- 3121
|
||||
- 21064
|
||||
when: ansible_distribution == 'Ubuntu'
|
||||
|
||||
- name: open pacemaker in firewall (UDP) (Ubuntu)
|
||||
ufw:
|
||||
port: 5405
|
||||
proto: udp
|
||||
rule: allow
|
||||
when: ansible_distribution == 'Ubuntu'
|
||||
|
||||
- name: setup pacemaker admin user
|
||||
user:
|
||||
name: hacluster
|
||||
password: "{{ pacemaker_cluster_password|password_hash('sha512') }}"
|
||||
|
||||
- name: setup pcsd service
|
||||
service:
|
||||
name: pcsd
|
||||
state: started
|
||||
enabled: yes
|
||||
|
||||
- name: setup pacemaker service
|
||||
service:
|
||||
name: pacemaker
|
||||
enabled: yes
|
||||
|
||||
|
||||
# create pacemaker cluster
|
||||
|
||||
- name: create pacemaker cluster
|
||||
shell: |
|
||||
pcs cluster auth -u hacluster -p '{{ pacemaker_cluster_password }}' {% for server in groups['servers'] %} {{ server }} {% endfor %} &&
|
||||
pcs cluster setup --name '{{ pacemaker_cluster_name }}' {% for server in groups['servers'] %} {{ server }} {% endfor %} &&
|
||||
pcs cluster start --all &&
|
||||
pcs property set stonith-enabled=false &&
|
||||
pcs property set start-failure-is-fatal=false
|
||||
args:
|
||||
creates: /etc/corosync/corosync.conf
|
||||
when: inventory_hostname == groups['servers'][0]
|
||||
Reference in New Issue
Block a user