├── .README.html
├── .ansible-lint
├── .codespell_ignores
├── .codespellrc
├── .collection
├── README.md
└── galaxy.yml
├── .commitlintrc.js
├── .fmf
└── version
├── .github
├── CODEOWNERS
├── dependabot.yml
├── pull_request_template.md
└── workflows
│ ├── ansible-lint.yml
│ ├── ansible-managed-var-comment.yml
│ ├── ansible-test.yml
│ ├── build_docs.yml
│ ├── changelog_to_tag.yml
│ ├── codespell.yml
│ ├── markdownlint.yml
│ ├── pr-title-lint.yml
│ ├── qemu-kvm-integration-tests.yml
│ ├── test_converting_readme.yml
│ ├── tft.yml
│ ├── tft_citest_bad.yml
│ ├── weekly_ci.yml
│ └── woke.yml
├── .gitignore
├── .markdownlint.yaml
├── .ostree
├── README.md
└── get_ostree_data.sh
├── .packit.yaml
├── .pandoc_template.html5
├── .yamllint.yml
├── CHANGELOG.md
├── LICENSE
├── README-ansible.md
├── README-ostree.md
├── README.md
├── ansible_pytest_extra_requirements.txt
├── contributing.md
├── custom_requirements.txt
├── defaults
└── main.yml
├── files
└── ha_is_primary.sql
├── handlers
└── main.yml
├── meta
├── collection-requirements.yml
└── main.yml
├── molecule
└── default
│ ├── Dockerfile.j2
│ └── molecule.yml
├── molecule_extra_requirements.txt
├── plans
├── README-plans.md
├── mssql_ha.fmf
└── test_playbooks_parallel.fmf
├── pylint_extra_requirements.txt
├── pytest_extra_requirements.txt
├── tasks
├── configure_storage_paths.yml
├── input_sql_files.yml
├── main.yml
├── mssql_conf_setting.yml
├── set_vars.yml
├── sqlcmd_input_content.yml
├── sqlcmd_input_file.yml
└── verify_password.yml
├── templates
├── configure_ag.j2
├── configure_endpoint.j2
├── configure_listener.j2
├── create_and_back_up_cert.j2
├── create_ha_login.j2
├── create_master_key_encryption.j2
├── drop_cert.j2
├── enable_alwayson.j2
├── get_ansible_managed.j2
├── grant_permissions_to_ha_login.j2
├── join_to_ag.j2
├── replicate_db.j2
└── restore_cert.j2
├── tests
├── .fmf
│ └── version
├── collection-requirements.yml
├── files
│ ├── create_ExampleDB1.sql
│ ├── create_ExampleDB2.sql
│ ├── sql_script.sql
│ └── verify_fts.sql
├── no-vault-variables.txt
├── playbooks
│ ├── tests_ad_integration.yml
│ ├── tests_ad_integration_join_false.yml
│ └── tests_ad_integration_w_keytab.yml
├── provision.fmf
├── requirements.txt
├── roles
│ ├── caller
│ │ ├── tasks
│ │ │ └── main.yml
│ │ └── vars
│ │ │ └── main.yml
│ └── linux-system-roles.mssql
│ │ ├── defaults
│ │ ├── files
│ │ ├── handlers
│ │ ├── meta
│ │ ├── tasks
│ │ ├── templates
│ │ └── vars
├── setup-snapshot.yml
├── tasks
│ ├── assert_fail_on_unsupported_ver.yml
│ ├── check_header.yml
│ ├── cleanup.yml
│ ├── mssql-sever-increase-start-limit.yml
│ ├── mssql_conf_verify.yml
│ ├── snapshot_install_packages.yml
│ ├── tests_idempotency.yml
│ ├── tests_input_sql_file.yml
│ ├── tests_password.yml
│ ├── tests_tcp_firewall.yml
│ ├── tests_tls.yml
│ ├── upgrade_and_assert.yml
│ ├── verify_ad_auth.yml
│ ├── verify_package.yml
│ ├── verify_settings.yml
│ └── verify_tcp_port.yml
├── templates
│ ├── add_test_listener.j2
│ ├── alter_ag.j2
│ ├── alter_endpoint.j2
│ ├── configure_ag_cluster_type_none.j2
│ ├── create_example_db.j2
│ ├── disable_alwayson.j2
│ ├── drop_ag.j2
│ ├── drop_endpoint.j2
│ ├── get_ansible_managed.j2
│ ├── remove_listener.j2
│ ├── remove_sql_cert.j2
│ └── separate_from_ag.j2
├── tests_2019_upgrade.yml
├── tests_2022_upgrade.yml
├── tests_accept_eula.yml
├── tests_configure_ha_cluster_external.yml
├── tests_configure_ha_cluster_read_scale.yml
├── tests_default_2019.yml
├── tests_idempotency_2017.yml
├── tests_idempotency_2019.yml
├── tests_idempotency_2022.yml
├── tests_include_vars_from_parent.yml
├── tests_input_sql_file_2017.yml
├── tests_input_sql_file_2019.yml
├── tests_input_sql_file_2022.yml
├── tests_password_2017.yml
├── tests_password_2019.yml
├── tests_password_2022.yml
├── tests_selinux_enforcing_2022.yml
├── tests_tcp_firewall_2017.yml
├── tests_tcp_firewall_2019.yml
├── tests_tcp_firewall_2022.yml
├── tests_tls_2017.yml
├── tests_tls_2019.yml
├── tests_tls_2022.yml
├── vars
│ ├── rh_distros_vars.yml
│ └── vault-variables.yml
└── vault_pwd
├── tox.ini
└── vars
├── AlmaLinux_8.yml
├── CentOS_7.yml
├── CentOS_8.yml
├── RedHat.yml
├── RedHat_7.yml
├── RedHat_8.yml
├── Rocky_8.yml
├── Suse.yml
└── main.yml
/.ansible-lint:
--------------------------------------------------------------------------------
1 | ---
2 | profile: production
3 | kinds:
4 | - yaml: "**/meta/collection-requirements.yml"
5 | - playbook: "**/tests/get_coverage.yml"
6 | - yaml: "**/tests/collection-requirements.yml"
7 | - playbook: "**/tests/tests_*.yml"
8 | - playbook: "**/tests/setup-snapshot.yml"
9 | - tasks: "**/tests/*.yml"
10 | - playbook: "**/tests/playbooks/*.yml"
11 | - tasks: "**/tests/tasks/*.yml"
12 | - tasks: "**/tests/tasks/*/*.yml"
13 | - vars: "**/tests/vars/*.yml"
14 | - playbook: "**/examples/*.yml"
15 | skip_list:
16 | - fqcn-builtins
17 | - var-naming[no-role-prefix]
18 | - galaxy[no-changelog]
19 | - galaxy[no-runtime]
20 | exclude_paths:
21 | - tests/roles/
22 | - .github/
23 | - .markdownlint.yaml
24 | - examples/roles/
25 | mock_roles:
26 | - linux-system-roles.mssql
27 | supported_ansible_also:
28 | - "2.14.0"
29 |
--------------------------------------------------------------------------------
/.codespell_ignores:
--------------------------------------------------------------------------------
1 | passt
2 |
--------------------------------------------------------------------------------
/.codespellrc:
--------------------------------------------------------------------------------
1 | [codespell]
2 | check-hidden = true
3 | # Note that `-w` doesn't work when ignore-multiline-regex is set
4 | # https://github.com/codespell-project/codespell/issues/3642
5 | ignore-multiline-regex = codespell:ignore-begin.*codespell:ignore-end
6 | ignore-words = .codespell_ignores
7 | # skip-file is not available https://github.com/codespell-project/codespell/pull/2759
8 | # .pandoc_template.html5 contains a typo in Licence that we shouldn't edit
9 | # .README.html is generated from README.md automatically - no need to check spelling
10 | skip = .pandoc_template.html5,.README.html
11 |
--------------------------------------------------------------------------------
/.collection/README.md:
--------------------------------------------------------------------------------
1 | # Microsoft SQL Ansible Collection
2 |
3 | ## Description
4 |
5 | This collection contains a role for managing Microsoft SQL Server.
6 |
7 | ## Installation
8 |
9 | There are currently two ways to install this collection, using `ansible-galaxy` or RPM package.
10 |
11 | ### Installing with ansible-galaxy
12 |
13 | You can install the collection with `ansible-galaxy` by entering the following command:
14 |
15 | ```shell
16 | ansible-galaxy collection install microsoft.sql
17 | ```
18 |
19 | You can also include it in a requirements.yml file and install it with ansible-galaxy collection install -r requirements.yml, using the format:
20 |
21 | ```yaml
22 | collections:
23 | - name: microsoft.sql
24 | ```
25 |
26 | Note that if you install any collections from Ansible Galaxy, they will not be upgraded automatically when you upgrade the Ansible package.
27 | To upgrade the collection to the latest available version, run the following command:
28 |
29 | ```shell
30 | ansible-galaxy collection install microsoft.sql --upgrade
31 | ```
32 |
33 | You can also install a specific version of the collection, for example, if you need to downgrade when something is broken in the latest version (please report an issue in this repository). Use the following syntax to install version 1.0.0:
34 |
35 | ```shell
36 | ansible-galaxy collection install microsoft.sql:==1.0.0
37 | ```
38 |
39 | See [using Ansible collections](https://docs.ansible.com/ansible/devel/user_guide/collections_using.html) for more details.
40 |
41 | After the installation, you can call the server role from playbooks with `microsoft.sql.server`.
42 | When installing using `ansible-galaxy`, by default, you can find the role documentation at `~/.ansible/collections/ansible_collections/microsoft/sql/roles/server/README.md`.
43 |
44 | ### Installing using RPM package
45 |
46 | You can install the collection with the software package management tool `dnf` by running the following command:
47 |
48 | ```bash
49 | dnf install ansible-collection-microsoft-sql
50 | ```
51 |
52 | When installing using `dnf`, you can find the role documentation in markdown format at `/usr/share/doc/ansible-collection-microsoft-sql/microsoft.sql-server/README.md` and in HTML format at `/usr/share/doc/ansible-collection-microsoft-sql/microsoft.sql-server/README.html`.
53 |
54 | ## Use Cases
55 |
56 | The common use cases are the following
57 |
58 | * I want to install, configure, and manage SQL Server on one or more systems
59 | * I want to configure several systems with Always On Availability Groups
60 | * I want to configure SQL Server to authenticate with Active Directory Server
61 |
62 | For more scenarios and examples, see role's documentation.
63 |
64 | ## Contributing (Optional)
65 |
66 | If you wish to contribute to roles within this collection, feel free to open a pull request for the role's upstream repository at https://github.com/linux-system-roles/mssql.
67 |
68 | We recommend that prior to submitting a PR, you familiarize yourself with our [Contribution Guidelines](https://linux-system-roles.github.io/contribute.html).
69 |
70 | ## Support
71 |
72 | * Red Hat Enterprise Linux 7 (RHEL 7+)
73 | * Red Hat Enterprise Linux 8 (RHEL 8+)
74 | * Red Hat Enterprise Linux 9 (RHEL 9+)
75 | * Fedora
76 | * RHEL derivatives such as CentOS
77 | * Suse Linux Enterprise Server 15 (SLES 15)
78 | * OpenSUSE 15
79 |
80 | ## Release Notes and Roadmap
81 |
82 | For the list of versions and their changelog, see CHANGELOG.md within this collection.
83 |
84 | ## Related Information
85 |
86 | Where available, link to general how to use collections or other related documentation applicable to the technology/product this collection works with. Useful materials such as demos, case studies, etc. may be linked here as well.
87 |
88 | ## License Information
89 |
90 | - MIT
--------------------------------------------------------------------------------
/.collection/galaxy.yml:
--------------------------------------------------------------------------------
1 | ---
2 | namespace: "microsoft"
3 | name: "sql"
4 | version: "1.0.11"
5 | description: "The Ansible role that manages Microsoft SQL Server"
6 |
7 | authors:
8 | - "Sergei Petrosian "
9 |
10 | repository: "https://github.com/linux-system-roles/mssql"
11 | # yamllint disable-line rule:line-length
12 | documentation: "https://github.com/linux-system-roles/mssql/blob/main/README.md"
13 | issues: "https://github.com/linux-system-roles/mssql/issues"
14 |
15 | readme: "README.md"
16 |
17 | license:
18 | - MIT
19 |
20 | dependencies:
21 | "fedora.linux_system_roles": "*"
22 |
23 | tags:
24 | - "mssql"
25 | - "microsoft"
26 | - "sql"
27 | - "database"
28 |
--------------------------------------------------------------------------------
/.commitlintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | parserPreset: 'conventional-changelog-conventionalcommits',
3 | rules: {
4 | 'body-leading-blank': [1, 'always'],
5 | 'body-max-line-length': [2, 'always', 100],
6 | 'footer-leading-blank': [1, 'always'],
7 | 'footer-max-line-length': [2, 'always', 100],
8 | 'header-max-length': [2, 'always', 100],
9 | 'subject-case': [
10 | 2,
11 | 'never',
12 | ['start-case', 'pascal-case', 'upper-case'],
13 | ],
14 | 'subject-empty': [2, 'never'],
15 | 'subject-full-stop': [2, 'never', '.'],
16 | 'type-case': [2, 'always', 'lower-case'],
17 | 'type-empty': [2, 'never'],
18 | 'type-enum': [
19 | 2,
20 | 'always',
21 | [
22 | 'build',
23 | 'chore',
24 | 'ci',
25 | 'docs',
26 | 'feat',
27 | 'fix',
28 | 'perf',
29 | 'refactor',
30 | 'revert',
31 | 'style',
32 | 'test',
33 | 'tests',
34 | ],
35 | ],
36 | },
37 | prompt: {
38 | questions: {
39 | type: {
40 | description: "Select the type of change that you're committing",
41 | enum: {
42 | feat: {
43 | description: 'A new feature',
44 | title: 'Features',
45 | emoji: '✨',
46 | },
47 | fix: {
48 | description: 'A bug fix',
49 | title: 'Bug Fixes',
50 | emoji: '🐛',
51 | },
52 | docs: {
53 | description: 'Documentation only changes',
54 | title: 'Documentation',
55 | emoji: '📚',
56 | },
57 | style: {
58 | description:
59 | 'Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)',
60 | title: 'Styles',
61 | emoji: '💎',
62 | },
63 | refactor: {
64 | description:
65 | 'A code change that neither fixes a bug nor adds a feature',
66 | title: 'Code Refactoring',
67 | emoji: '📦',
68 | },
69 | perf: {
70 | description: 'A code change that improves performance',
71 | title: 'Performance Improvements',
72 | emoji: '🚀',
73 | },
74 | test: {
75 | description: 'Adding missing tests or correcting existing tests',
76 | title: 'Tests',
77 | emoji: '🚨',
78 | },
79 | tests: {
80 | description: 'Adding missing tests or correcting existing tests',
81 | title: 'Tests',
82 | emoji: '🚨',
83 | },
84 | build: {
85 | description:
86 | 'Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)',
87 | title: 'Builds',
88 | emoji: '🛠',
89 | },
90 | ci: {
91 | description:
92 | 'Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)',
93 | title: 'Continuous Integrations',
94 | emoji: '⚙️',
95 | },
96 | chore: {
97 | description: "Other changes that don't modify src or test files",
98 | title: 'Chores',
99 | emoji: '♻️',
100 | },
101 | revert: {
102 | description: 'Reverts a previous commit',
103 | title: 'Reverts',
104 | emoji: '🗑',
105 | },
106 | },
107 | },
108 | scope: {
109 | description:
110 | 'What is the scope of this change (e.g. component or file name)',
111 | },
112 | subject: {
113 | description:
114 | 'Write a short, imperative tense description of the change',
115 | },
116 | body: {
117 | description: 'Provide a longer description of the change',
118 | },
119 | isBreaking: {
120 | description: 'Are there any breaking changes?',
121 | },
122 | breakingBody: {
123 | description:
124 | 'A BREAKING CHANGE commit requires a body. Please enter a longer description of the commit itself',
125 | },
126 | breaking: {
127 | description: 'Describe the breaking changes',
128 | },
129 | isIssueAffected: {
130 | description: 'Does this change affect any open issues?',
131 | },
132 | issuesBody: {
133 | description:
134 | 'If issues are closed, the commit requires a body. Please enter a longer description of the commit itself',
135 | },
136 | issues: {
137 | description: 'Add issue references (e.g. "fix #123", "re #123".)',
138 | },
139 | },
140 | },
141 | };
142 |
--------------------------------------------------------------------------------
/.fmf/version:
--------------------------------------------------------------------------------
1 | 1
2 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # https://help.github.com/en/articles/about-code-owners
2 | # Default reviewers for everything
3 | * @spetrosi @richm
4 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | ---
2 | version: 2
3 | updates:
4 | - package-ecosystem: github-actions
5 | directory: /
6 | schedule:
7 | interval: monthly
8 | commit-message:
9 | prefix: ci
10 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | Enhancement:
2 |
3 | Reason:
4 |
5 | Result:
6 |
7 | Issue Tracker Tickets (Jira or BZ if any):
8 |
--------------------------------------------------------------------------------
/.github/workflows/ansible-lint.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: Ansible Lint
3 | on: # yamllint disable-line rule:truthy
4 | pull_request:
5 | merge_group:
6 | branches:
7 | - main
8 | types:
9 | - checks_requested
10 | push:
11 | branches:
12 | - main
13 | workflow_dispatch:
14 | env:
15 | LSR_ROLE2COLL_NAMESPACE: fedora
16 | LSR_ROLE2COLL_NAME: linux_system_roles
17 | permissions:
18 | contents: read
19 | jobs:
20 | ansible_lint:
21 | runs-on: ubuntu-latest
22 | steps:
23 | - name: Update pip, git
24 | run: |
25 | set -euxo pipefail
26 | sudo apt update
27 | sudo apt install -y git
28 |
29 | - name: Checkout repo
30 | uses: actions/checkout@v4
31 |
32 | - name: Install tox, tox-lsr
33 | run: |
34 | set -euxo pipefail
35 | pip3 install "git+https://github.com/linux-system-roles/tox-lsr@3.10.0"
36 |
37 | - name: Convert role to collection format
38 | id: collection
39 | run: |
40 | set -euxo pipefail
41 | TOXENV=collection lsr_ci_runtox
42 | coll_dir=".tox/ansible_collections/$LSR_ROLE2COLL_NAMESPACE/$LSR_ROLE2COLL_NAME"
43 | # cleanup after collection conversion
44 | rm -rf "$coll_dir/.ansible" .tox/ansible-plugin-scan
45 | # ansible-lint action requires a .git directory???
46 | # https://github.com/ansible/ansible-lint/blob/main/action.yml#L45
47 | mkdir -p "$coll_dir/.git"
48 | meta_req_file="${{ github.workspace }}/meta/collection-requirements.yml"
49 | test_req_file="${{ github.workspace }}/tests/collection-requirements.yml"
50 | if [ -f "$meta_req_file" ] && [ -f "$test_req_file" ]; then
51 | coll_req_file="${{ github.workspace }}/req.yml"
52 | python -c 'import sys; import yaml
53 | hsh1 = yaml.safe_load(open(sys.argv[1]))
54 | hsh2 = yaml.safe_load(open(sys.argv[2]))
55 | coll = {}
56 | for item in hsh1["collections"] + hsh2["collections"]:
57 | if isinstance(item, dict):
58 | name = item["name"]
59 | rec = item
60 | else:
61 | name = item # assume string
62 | rec = {"name": name}
63 | if name not in coll:
64 | coll[name] = rec
65 | hsh1["collections"] = list(coll.values())
66 | yaml.safe_dump(hsh1, open(sys.argv[3], "w"))' "$meta_req_file" "$test_req_file" "$coll_req_file"
67 | echo merged "$coll_req_file"
68 | cat "$coll_req_file"
69 | elif [ -f "$meta_req_file" ]; then
70 | coll_req_file="$meta_req_file"
71 | elif [ -f "$test_req_file" ]; then
72 | coll_req_file="$test_req_file"
73 | else
74 | coll_req_file=""
75 | fi
76 | echo "coll_req_file=$coll_req_file" >> $GITHUB_OUTPUT
77 |
78 | - name: Run ansible-lint
79 | uses: ansible/ansible-lint@v25
80 | with:
81 | working_directory: ${{ github.workspace }}/.tox/ansible_collections/${{ env.LSR_ROLE2COLL_NAMESPACE }}/${{ env.LSR_ROLE2COLL_NAME }}
82 | requirements_file: ${{ steps.collection.outputs.coll_req_file }}
83 | env:
84 | ANSIBLE_COLLECTIONS_PATH: ${{ github.workspace }}/.tox
85 |
--------------------------------------------------------------------------------
/.github/workflows/ansible-managed-var-comment.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: Check for ansible_managed variable use in comments
3 | on: # yamllint disable-line rule:truthy
4 | pull_request:
5 | merge_group:
6 | branches:
7 | - main
8 | types:
9 | - checks_requested
10 | push:
11 | branches:
12 | - main
13 | workflow_dispatch:
14 | permissions:
15 | contents: read
16 | jobs:
17 | ansible_managed_var_comment:
18 | runs-on: ubuntu-latest
19 | steps:
20 | - name: Update pip, git
21 | run: |
22 | set -euxo pipefail
23 | python3 -m pip install --upgrade pip
24 | sudo apt update
25 | sudo apt install -y git
26 |
27 | - name: Checkout repo
28 | uses: actions/checkout@v4
29 |
30 | - name: Install tox, tox-lsr
31 | run: |
32 | set -euxo pipefail
33 | pip3 install "git+https://github.com/linux-system-roles/tox-lsr@3.10.0"
34 |
35 | - name: Run ansible-plugin-scan
36 | run: |
37 | set -euxo pipefail
38 | TOXENV=ansible-managed-var-comment lsr_ci_runtox
39 |
--------------------------------------------------------------------------------
/.github/workflows/ansible-test.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: Ansible Test
3 | on: # yamllint disable-line rule:truthy
4 | pull_request:
5 | merge_group:
6 | branches:
7 | - main
8 | types:
9 | - checks_requested
10 | push:
11 | branches:
12 | - main
13 | workflow_dispatch:
14 | env:
15 | LSR_ROLE2COLL_NAMESPACE: fedora
16 | LSR_ROLE2COLL_NAME: linux_system_roles
17 | permissions:
18 | contents: read
19 | jobs:
20 | ansible_test:
21 | runs-on: ubuntu-latest
22 | steps:
23 | - name: Update pip, git
24 | run: |
25 | set -euxo pipefail
26 | python3 -m pip install --upgrade pip
27 | sudo apt update
28 | sudo apt install -y git
29 |
30 | - name: Checkout repo
31 | uses: actions/checkout@v4
32 |
33 | - name: Install tox, tox-lsr
34 | run: |
35 | set -euxo pipefail
36 | pip3 install "git+https://github.com/linux-system-roles/tox-lsr@3.10.0"
37 |
38 | - name: Convert role to collection format
39 | run: |
40 | set -euxo pipefail
41 | TOXENV=collection lsr_ci_runtox
42 |
43 | - name: Run ansible-test
44 | uses: ansible-community/ansible-test-gh-action@release/v1
45 | with:
46 | testing-type: sanity # wokeignore:rule=sanity
47 | ansible-core-version: stable-2.17
48 | collection-src-directory: ${{ github.workspace }}/.tox/ansible_collections/${{ env.LSR_ROLE2COLL_NAMESPACE }}/${{ env.LSR_ROLE2COLL_NAME }}
49 |
--------------------------------------------------------------------------------
/.github/workflows/build_docs.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # yamllint disable rule:line-length
3 | name: Convert README.md to HTML and push to docs branch
4 | on: # yamllint disable-line rule:truthy
5 | push:
6 | branches:
7 | - main
8 | paths:
9 | - README.md
10 | release:
11 | types:
12 | - published
13 | permissions:
14 | contents: read
15 | jobs:
16 | build_docs:
17 | runs-on: ubuntu-latest
18 | permissions:
19 | contents: write
20 | steps:
21 | - name: Update pip, git
22 | run: |
23 | set -euxo pipefail
24 | sudo apt update
25 | sudo apt install -y git
26 |
27 | - name: Check out code
28 | uses: actions/checkout@v4
29 | with:
30 | fetch-depth: 0
31 | - name: Ensure the docs branch
32 | run: |
33 | set -euxo pipefail
34 | branch=docs
35 | existed_in_remote=$(git ls-remote --heads origin $branch)
36 |
37 | if [ -z "${existed_in_remote}" ]; then
38 | echo "Creating $branch branch"
39 | git config --global user.name "${{ github.actor }}"
40 | git config --global user.email "${{ github.actor }}@users.noreply.github.com"
41 | git checkout --orphan $branch
42 | git reset --hard
43 | git commit --allow-empty -m "Initializing $branch branch"
44 | git push origin $branch
45 | echo "Created $branch branch"
46 | else
47 | echo "Branch $branch already exists"
48 | fi
49 |
50 | - name: Checkout the docs branch
51 | uses: actions/checkout@v4
52 | with:
53 | ref: docs
54 |
55 | - name: Fetch README.md and .pandoc_template.html5 template from the workflow branch
56 | uses: actions/checkout@v4
57 | with:
58 | sparse-checkout: |
59 | README.md
60 | .pandoc_template.html5
61 | sparse-checkout-cone-mode: false
62 | path: ref_branch
63 | - name: Set RELEASE_VERSION based on whether run on release or on push
64 | run: |
65 | set -euxo pipefail
66 | if [ ${{ github.event_name }} = release ]; then
67 | echo "RELEASE_VERSION=${{ github.event.release.tag_name }}" >> $GITHUB_ENV
68 | elif [ ${{ github.event_name }} = push ]; then
69 | echo "RELEASE_VERSION=latest" >> $GITHUB_ENV
70 | else
71 | echo Unsupported event
72 | exit 1
73 | fi
74 |
75 | - name: Ensure that version and docs directories exist
76 | run: mkdir -p ${{ env.RELEASE_VERSION }} docs
77 |
78 | - name: Remove badges from README.md prior to converting to HTML
79 | run: sed -i '1,8 {/^\[\!.*actions\/workflows/d}' ref_branch/README.md
80 |
81 | - name: Convert README.md to HTML and save to the version directory
82 | uses: docker://pandoc/core:latest
83 | with:
84 | args: >-
85 | --from gfm --to html5 --toc --shift-heading-level-by=-1
86 | --template ref_branch/.pandoc_template.html5
87 | --output ${{ env.RELEASE_VERSION }}/README.html ref_branch/README.md
88 |
89 | - name: Copy latest README.html to docs/index.html for GitHub pages
90 | if: env.RELEASE_VERSION == 'latest'
91 | run: cp ${{ env.RELEASE_VERSION }}/README.html docs/index.html
92 |
93 | - name: Upload README.html as an artifact
94 | uses: actions/upload-artifact@master
95 | with:
96 | name: README.html
97 | path: ${{ env.RELEASE_VERSION }}/README.html
98 |
99 | - name: Commit changes
100 | run: |
101 | git config --global user.name "${{ github.actor }}"
102 | git config --global user.email "${{ github.actor }}@users.noreply.github.com"
103 | git add ${{ env.RELEASE_VERSION }}/README.html docs/index.html
104 | git commit -m "Update README.html for ${{ env.RELEASE_VERSION }}"
105 |
106 | - name: Push changes
107 | uses: ad-m/github-push-action@master
108 | with:
109 | github_token: ${{ secrets.GITHUB_TOKEN }}
110 | branch: docs
111 |
--------------------------------------------------------------------------------
/.github/workflows/changelog_to_tag.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # yamllint disable rule:line-length
3 | name: Tag, release, and publish role based on CHANGELOG.md push
4 | on: # yamllint disable-line rule:truthy
5 | push:
6 | branches:
7 | - main
8 | paths:
9 | - CHANGELOG.md
10 | permissions:
11 | contents: read
12 | jobs:
13 | tag_release_publish:
14 | runs-on: ubuntu-latest
15 | permissions:
16 | contents: write
17 | steps:
18 | - name: Update pip, git
19 | run: |
20 | set -euxo pipefail
21 | sudo apt update
22 | sudo apt install -y git
23 |
24 | - name: checkout PR
25 | uses: actions/checkout@v4
26 |
27 | - name: Get tag and message from the latest CHANGELOG.md commit
28 | id: tag
29 | run: |
30 | set -euxo pipefail
31 | print=false
32 | while read -r line; do
33 | if [[ "$line" =~ ^\[([0-9]+\.[0-9]+\.[0-9]+)\]\ -\ [0-9-]+ ]]; then
34 | if [ "$print" = false ]; then
35 | _tagname="${BASH_REMATCH[1]}"
36 | echo "$line"
37 | print=true
38 | else
39 | break
40 | fi
41 | elif [ "$print" = true ]; then
42 | echo "$line"
43 | fi
44 | done < CHANGELOG.md > ./.tagmsg.txt
45 | git fetch --all --tags
46 | for t in $( git tag -l ); do
47 | if [ "$t" = "$_tagname" ]; then
48 | echo INFO: tag "$t" already exists
49 | exit 1
50 | fi
51 | done
52 | # Get name of the branch that the change was pushed to
53 | _branch="${GITHUB_REF_NAME:-}"
54 | if [ "$_branch" = master ] || [ "$_branch" = main ]; then
55 | echo Using branch name ["$_branch"] as push branch
56 | else
57 | echo WARNING: GITHUB_REF_NAME ["$_branch"] is not main or master
58 | _branch=$( git branch -r | grep -o 'origin/HEAD -> origin/.*$' | \
59 | awk -F'/' '{print $3}' || : )
60 | fi
61 | if [ -z "$_branch" ]; then
62 | _branch=$( git branch --points-at HEAD --no-color --format='%(refname:short)' )
63 | fi
64 | if [ -z "$_branch" ]; then
65 | echo ERROR: unable to determine push branch
66 | git branch -a
67 | exit 1
68 | fi
69 | echo "tagname=$_tagname" >> "$GITHUB_OUTPUT"
70 | echo "branch=$_branch" >> "$GITHUB_OUTPUT"
71 |
72 | - name: Install dependencies
73 | run: |
74 | set -euxo pipefail
75 | sudo apt-get update
76 | sudo apt install -y git
77 | pip install --upgrade pip galaxy-importer ansible-core 'pyyaml<6,>=5.4.1' ruamel_yaml
78 |
79 | - name: Setup Python
80 | uses: actions/setup-python@v5
81 |
82 | - name: checkout auto-maintenance
83 | uses: actions/checkout@v4
84 | with:
85 | repository: linux-system-roles/auto-maintenance
86 | path: auto-maintenance
87 |
88 | - name: checkout mssql into a separate directory
89 | uses: actions/checkout@v4
90 | with:
91 | path: mssql
92 | - name: Build and publish the collection
93 | shell: bash
94 | id: build
95 | run: |
96 | set -euxo pipefail
97 | tagname=${{ steps.tag.outputs.tagname }}
98 | rolename=mssql
99 | collection_namespace=microsoft
100 | collection_name=sql
101 | collection_rolename=server
102 | dest_path=/var/tmp/collection
103 | coll_path="$dest_path"/ansible_collections/"$collection_namespace"/"$collection_name"
104 |
105 | echo ::group::Update galaxy.yml
106 | sed -i "s/version: .*/version: \"$tagname\"/g" "$rolename"/.collection/galaxy.yml
107 | echo ::endgroup::
108 |
109 | echo ::group::Remove symlinks in tests/roles
110 | if [ -d "$rolename"/tests/roles ]; then
111 | find "$rolename"/tests/roles -type l -exec rm {} \;
112 | if [ -d "$rolename"/tests/roles/linux-system-roles."$rolename" ]; then
113 | rm -r "$rolename"/tests/roles/linux-system-roles."$rolename"
114 | fi
115 | fi
116 | echo ::endgroup::
117 |
118 | echo ::group::Build Collection
119 | # Ensure there is no dest_path before running release_collection.py
120 | rm -rf "$dest_path"
121 | python3 auto-maintenance/lsr_role2collection.py --role "$rolename" \
122 | --src-path "$rolename" \
123 | --src-owner linux-system-roles \
124 | --dest-path "$dest_path" \
125 | --readme "$rolename"/.collection/README.md \
126 | --namespace microsoft \
127 | --collection sql \
128 | --new-role server \
129 | --meta-runtime auto-maintenance/lsr_role2collection/runtime.yml
130 |
131 | # Replace remnants of "linux-system-roles.mssql" with collection FQDN
132 | find "$coll_path"/ -type f -exec \
133 | sed -e "s/linux-system-roles[.]%$rolename\\>/$collection_namespace.$collection_name.$collection_rolename/g" \
134 | -i {} \;
135 |
136 | # removing dot files/dirs
137 | rm -r "$coll_path"/.[A-Za-z]*
138 | rm -r "$coll_path"/tests/"$collection_rolename"/.[A-Za-z]*
139 |
140 | # Copy .ansible-lint to collection dir
141 | cp "$coll_path"/roles/"$collection_rolename"/.ansible-lint "$coll_path"
142 |
143 | # Copy CHANGELOG.md from collection role to parent collection dir
144 | cp "$coll_path"/roles/"$collection_rolename"/CHANGELOG.md \
145 | "$coll_path"
146 |
147 | # Copy galaxy.yml to the collection directory
148 | cp -p "$rolename"/.collection/galaxy.yml "$coll_path"
149 |
150 | pushd "$coll_path"
151 | ansible-galaxy collection build
152 | popd
153 | echo ::endgroup::
154 | _tarball="$coll_path"/microsoft-sql-$tagname.tar.gz
155 | if [ ! -f "${_tarball}" ]; then
156 | echo ::error::"Did not find tarball to publish: ${_tarball}"
157 | exit 1
158 | fi
159 |
160 | echo ::group::Run galaxy-importer against collection tarball
161 | GALAXY_IMPORTER_CONFIG=auto-maintenance/lsr_role2collection/galaxy-importer.cfg \
162 | python3 -m galaxy_importer.main \
163 | "$_tarball"
164 | echo ::endgroup::
165 |
166 | echo ::group::Publish Collection to Galaxy
167 | ansible-galaxy collection publish -vv --token "${{ secrets.GALAXY_API_KEY }}" "$_tarball"
168 | echo ::endgroup::
169 | echo ::info Done
170 |
171 | - name: Create tag
172 | uses: mathieudutour/github-tag-action@v6.2
173 | with:
174 | github_token: ${{ secrets.GITHUB_TOKEN }}
175 | custom_tag: ${{ steps.tag.outputs.tagname }}
176 | tag_prefix: ''
177 |
178 | - name: Create Release
179 | id: create_release
180 | uses: ncipollo/release-action@v1
181 | with:
182 | tag: ${{ steps.tag.outputs.tagname }}
183 | name: Version ${{ steps.tag.outputs.tagname }}
184 | bodyFile: ./.tagmsg.txt
185 | makeLatest: true
186 |
--------------------------------------------------------------------------------
/.github/workflows/codespell.yml:
--------------------------------------------------------------------------------
1 | # Codespell configuration is within .codespellrc
2 | ---
3 | name: Codespell
4 | on: # yamllint disable-line rule:truthy
5 | - pull_request
6 | permissions:
7 | contents: read
8 | jobs:
9 | codespell:
10 | name: Check for spelling errors
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: Checkout
14 | uses: actions/checkout@v4
15 |
16 | - name: Codespell
17 | uses: codespell-project/actions-codespell@v2
18 |
--------------------------------------------------------------------------------
/.github/workflows/markdownlint.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # yamllint disable rule:line-length
3 | name: Markdown Lint
4 | on: # yamllint disable-line rule:truthy
5 | pull_request:
6 | merge_group:
7 | branches:
8 | - main
9 | types:
10 | - checks_requested
11 | push:
12 | branches:
13 | - main
14 | workflow_dispatch:
15 | permissions:
16 | contents: read
17 | jobs:
18 | markdownlint:
19 | runs-on: ubuntu-latest
20 | steps:
21 | - name: Update pip, git
22 | run: |
23 | set -euxo pipefail
24 | sudo apt update
25 | sudo apt install -y git
26 |
27 | - name: Check out code
28 | uses: actions/checkout@v4
29 |
30 | # CHANGELOG.md is generated automatically from PR titles and descriptions
31 | # It might have issues but they are not critical
32 | - name: Lint all markdown files except for CHANGELOG.md
33 | uses: docker://avtodev/markdown-lint:master
34 | with:
35 | args: >-
36 | --ignore=CHANGELOG.md
37 | **/*.md
38 | config: .markdownlint.yaml
39 |
--------------------------------------------------------------------------------
/.github/workflows/pr-title-lint.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: PR Title Lint
3 | on: # yamllint disable-line rule:truthy
4 | pull_request:
5 | types:
6 | - opened
7 | - synchronize
8 | - reopened
9 | - edited
10 | merge_group:
11 | branches:
12 | - main
13 | types:
14 | - checks_requested
15 | permissions:
16 | contents: read
17 | jobs:
18 | commit-checks:
19 | runs-on: ubuntu-latest
20 | steps:
21 | - uses: actions/checkout@v4
22 | with:
23 | fetch-depth: 0
24 |
25 | - name: Install conventional-commit linter
26 | run: npm install @commitlint/config-conventional @commitlint/cli
27 |
28 | - name: Run commitlint on PR title
29 | env:
30 | PR_TITLE: ${{ github.event.pull_request.title }}
31 | # Echo from env variable to avoid bash errors with extra characters
32 | run: echo "$PR_TITLE" | npx commitlint --verbose
33 |
--------------------------------------------------------------------------------
/.github/workflows/test_converting_readme.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # yamllint disable rule:line-length
3 | name: Test converting README.md to README.html
4 | on: # yamllint disable-line rule:truthy
5 | pull_request:
6 | merge_group:
7 | branches:
8 | - main
9 | types:
10 | - checks_requested
11 | push:
12 | branches:
13 | - main
14 | permissions:
15 | contents: read
16 | jobs:
17 | test_converting_readme:
18 | runs-on: ubuntu-latest
19 | permissions:
20 | contents: write
21 | steps:
22 | - name: Update pip, git
23 | run: |
24 | set -euxo pipefail
25 | sudo apt update
26 | sudo apt install -y git
27 |
28 | - name: Check out code
29 | uses: actions/checkout@v4
30 |
31 | - name: Remove badges from README.md prior to converting to HTML
32 | run: sed -i '1,8 {/^\[\!.*actions\/workflows/d}' README.md
33 |
34 | - name: Convert README.md to HTML
35 | uses: docker://pandoc/core:latest
36 | with:
37 | args: >-
38 | --from gfm --to html5 --toc --shift-heading-level-by=-1
39 | --template .pandoc_template.html5
40 | --output README.html README.md
41 |
42 | - name: Upload README.html as an artifact
43 | uses: actions/upload-artifact@master
44 | with:
45 | name: README.html
46 | path: README.html
47 |
--------------------------------------------------------------------------------
/.github/workflows/tft_citest_bad.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: Re-run failed testing farm tests
3 | on:
4 | issue_comment:
5 | types:
6 | - created
7 | permissions:
8 | contents: read
9 | jobs:
10 | citest_bad_rerun:
11 | if: |
12 | github.event.issue.pull_request
13 | && contains(fromJson('["[citest_bad]", "[citest-bad]", "[citest bad]"]'), github.event.comment.body)
14 | && contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)
15 | permissions:
16 | actions: write # for re-running failed jobs: https://docs.github.com/en/rest/actions/workflow-runs?apiVersion=2022-11-28#re-run-a-job-from-a-workflow-run
17 | runs-on: ubuntu-latest
18 | steps:
19 | - name: Wait 10s until tft.yml workflow is created and skipped because new comment don't match [citest]
20 | run: sleep 10s
21 |
22 | - name: Re-run failed jobs for this PR
23 | env:
24 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
25 | REPO: ${{ github.repository }}
26 | PR_TITLE: ${{ github.event.issue.title }}
27 | run: |
28 | PENDING_RUN=$(gh api "repos/$REPO/actions/workflows/tft.yml/runs?event=issue_comment" \
29 | | jq -r "[.workflow_runs[] | select( .display_title == \"$PR_TITLE\") | \
30 | select(.status == \"pending\" or .status == \"queued\" or .status == \"in_progress\") | .id][0]")
31 | # if pending run don't exist, take the last run with failure state
32 | if [ "$PENDING_RUN" != "null" ]; then
33 | echo "The workflow $PENDING_RUN is still running, wait for it to finish to re-run"
34 | exit 1
35 | fi
36 | RUN_ID=$(gh api "repos/$REPO/actions/workflows/tft.yml/runs?event=issue_comment" \
37 | | jq -r "[.workflow_runs[] | select( .display_title == \"$PR_TITLE\" ) | select( .conclusion == \"failure\" ) | .id][0]")
38 | if [ "$RUN_ID" = "null" ]; then
39 | echo "Failed workflow not found, exiting"
40 | exit 1
41 | fi
42 | echo "Re-running workflow $RUN_ID"
43 | gh api --method POST repos/$REPO/actions/runs/$RUN_ID/rerun-failed-jobs
44 |
--------------------------------------------------------------------------------
/.github/workflows/weekly_ci.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # yamllint disable rule:line-length
3 | name: Weekly CI trigger
4 | on: # yamllint disable-line rule:truthy
5 | workflow_dispatch:
6 | schedule:
7 | - cron: 0 0 * * 6
8 | env:
9 | BRANCH_NAME: weekly-ci
10 | COMMIT_MESSAGE: "ci: This PR is to trigger periodic CI testing"
11 | BODY_MESSAGE: >-
12 | This PR is for the purpose of triggering periodic CI testing.
13 | We don't currently have a way to trigger CI without a PR,
14 | so this PR serves that purpose.
15 | COMMENT: "[citest]"
16 | permissions:
17 | contents: read
18 | jobs:
19 | weekly_ci:
20 | runs-on: ubuntu-latest
21 | permissions:
22 | issues: write
23 | pull-requests: write
24 | contents: write
25 | steps:
26 | - name: Update pip, git
27 | run: |
28 | set -euxo pipefail
29 | sudo apt update
30 | sudo apt install -y git
31 |
32 | - name: Checkout latest code
33 | uses: actions/checkout@v4
34 | with:
35 | fetch-depth: 0
36 | - name: Create or rebase commit, add dump_packages callback
37 | run: |
38 | set -euxo pipefail
39 |
40 | git config --global user.name "github-actions[bot]"
41 | git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
42 | git checkout ${{ env.BRANCH_NAME }} || git checkout -b ${{ env.BRANCH_NAME }}
43 | git rebase main
44 | if [ ! -d tests/callback_plugins ]; then
45 | mkdir -p tests/callback_plugins
46 | fi
47 | curl -L -s -o tests/callback_plugins/dump_packages.py https://raw.githubusercontent.com/linux-system-roles/auto-maintenance/main/callback_plugins/dump_packages.py
48 | git add tests/callback_plugins
49 | git commit --allow-empty -m "${{ env.COMMIT_MESSAGE }}"
50 | git push -f --set-upstream origin ${{ env.BRANCH_NAME }}
51 |
52 | - name: Create and comment pull request
53 | uses: actions/github-script@v7
54 | with:
55 | github-token: ${{ secrets.GH_PUSH_TOKEN }}
56 | script: |
57 | const head = [context.repo.owner, ":", "${{ env.BRANCH_NAME }}"].join("");
58 | const response = await github.rest.pulls.list({
59 | owner: context.repo.owner,
60 | repo: context.repo.repo,
61 | head: head,
62 | base: context.ref,
63 | state: "open"
64 | });
65 | let pr_number = '';
66 | if (response.data.length === 0) {
67 | pr_number = (await github.rest.pulls.create({
68 | owner: context.repo.owner,
69 | repo: context.repo.repo,
70 | title: "${{ env.COMMIT_MESSAGE }}",
71 | body: "${{ env.BODY_MESSAGE }}",
72 | head: "${{ env.BRANCH_NAME }}",
73 | base: context.ref,
74 | draft: true
75 | })).data.number;
76 | } else {
77 | pr_number = response.data[0].number;
78 | }
79 | github.rest.issues.createComment({
80 | owner: context.repo.owner,
81 | repo: context.repo.repo,
82 | issue_number: pr_number,
83 | body: "${{ env.COMMENT }}",
84 | });
85 |
--------------------------------------------------------------------------------
/.github/workflows/woke.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # yamllint disable rule:line-length
3 | name: Woke
4 | on: # yamllint disable-line rule:truthy
5 | - pull_request
6 | jobs:
7 | woke:
8 | name: Detect non-inclusive language
9 | runs-on: ubuntu-latest
10 | steps:
11 | - name: Checkout
12 | uses: actions/checkout@v4
13 |
14 | - name: Run lsr-woke-action
15 | # Originally, uses: get-woke/woke-action@v0
16 | uses: linux-system-roles/lsr-woke-action@main
17 | with:
18 | woke-args: "-c https://raw.githubusercontent.com/linux-system-roles/tox-lsr/main/src/tox_lsr/config_files/woke.yml --count-only-error-for-failure"
19 | # Cause the check to fail on any broke rules
20 | fail-on-error: true
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | passes.yml
2 | vault.yml
3 | *.pyc
4 | *.retry
5 | /tests/.coverage
6 | /tests/htmlcov*
7 | /.tox
8 | /venv*/
9 | /.venv/
10 | .vscode/
11 | artifacts/
12 | __pycache__/
13 | *~
14 | .pytest_cache/
15 |
--------------------------------------------------------------------------------
/.markdownlint.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # Default state for all rules
3 | default: true
4 |
5 | # Path to configuration file to extend
6 | extends: null
7 |
8 | # MD001/heading-increment/header-increment - Heading levels should only increment by one level at a time
9 | MD001: true
10 |
11 | # MD002/first-heading-h1/first-header-h1 - First heading should be a top-level heading
12 | MD002:
13 | # Heading level
14 | level: 1
15 |
16 | # MD003/heading-style/header-style - Heading style
17 | MD003:
18 | # Heading style
19 | style: "consistent"
20 |
21 | # MD004/ul-style - Unordered list style
22 | MD004:
23 | # List style
24 | style: "consistent"
25 |
26 | # MD005/list-indent - Inconsistent indentation for list items at the same level
27 | MD005: true
28 |
29 | # MD006/ul-start-left - Consider starting bulleted lists at the beginning of the line
30 | MD006: true
31 |
32 | # MD007/ul-indent - Unordered list indentation
33 | MD007:
34 | # Spaces for indent
35 | indent: 2
36 | # Whether to indent the first level of the list
37 | start_indented: false
38 | # Spaces for first level indent (when start_indented is set)
39 | start_indent: 2
40 |
41 | # MD009/no-trailing-spaces - Trailing spaces
42 | MD009:
43 | # Spaces for line break
44 | br_spaces: 2
45 | # Allow spaces for empty lines in list items
46 | list_item_empty_lines: false
47 | # Include unnecessary breaks
48 | strict: false
49 |
50 | # MD010/no-hard-tabs - Hard tabs
51 | MD010:
52 | # Include code blocks
53 | code_blocks: true
54 | # Fenced code languages to ignore
55 | ignore_code_languages: []
56 | # Number of spaces for each hard tab
57 | spaces_per_tab: 1
58 |
59 | # MD011/no-reversed-links - Reversed link syntax
60 | MD011: true
61 |
62 | # MD012/no-multiple-blanks - Multiple consecutive blank lines
63 | MD012:
64 | # Consecutive blank lines
65 | maximum: 1
66 |
67 | # Modified for LSR
68 | # GFM does not limit line length
69 | # MD013/line-length - Line length
70 | MD013: false
71 | # # Number of characters
72 | # # line_length: 80
73 | # line_length: 999
74 | # # Number of characters for headings
75 | # heading_line_length: 80
76 | # # Number of characters for code blocks
77 | # code_block_line_length: 80
78 | # # Include code blocks
79 | # code_blocks: true
80 | # # Include tables
81 | # tables: true
82 | # # Include headings
83 | # headings: true
84 | # # Include headings
85 | # headers: true
86 | # # Strict length checking
87 | # strict: false
88 | # # Stern length checking
89 | # stern: false
90 |
91 | # MD014/commands-show-output - Dollar signs used before commands without showing output
92 | MD014: true
93 |
94 | # MD018/no-missing-space-atx - No space after hash on atx style heading
95 | MD018: true
96 |
97 | # MD019/no-multiple-space-atx - Multiple spaces after hash on atx style heading
98 | MD019: true
99 |
100 | # MD020/no-missing-space-closed-atx - No space inside hashes on closed atx style heading
101 | MD020: true
102 |
103 | # MD021/no-multiple-space-closed-atx - Multiple spaces inside hashes on closed atx style heading
104 | MD021: true
105 |
106 | # MD022/blanks-around-headings/blanks-around-headers - Headings should be surrounded by blank lines
107 | MD022:
108 | # Blank lines above heading
109 | lines_above: 1
110 | # Blank lines below heading
111 | lines_below: 1
112 |
113 | # MD023/heading-start-left/header-start-left - Headings must start at the beginning of the line
114 | MD023: true
115 |
116 | # MD024/no-duplicate-heading/no-duplicate-header - Multiple headings with the same content
117 | MD024: true
118 |
119 | # MD025/single-title/single-h1 - Multiple top-level headings in the same document
120 | MD025:
121 | # Heading level
122 | level: 1
123 | # RegExp for matching title in front matter
124 | front_matter_title: "^\\s*title\\s*[:=]"
125 |
126 | # MD026/no-trailing-punctuation - Trailing punctuation in heading
127 | MD026:
128 | # Punctuation characters not allowed at end of headings
129 | punctuation: ".,;:!。,;:!"
130 |
131 | # MD027/no-multiple-space-blockquote - Multiple spaces after blockquote symbol
132 | MD027: true
133 |
134 | # MD028/no-blanks-blockquote - Blank line inside blockquote
135 | MD028: true
136 |
137 | # MD029/ol-prefix - Ordered list item prefix
138 | MD029:
139 | # List style
140 | style: "one_or_ordered"
141 |
142 | # MD030/list-marker-space - Spaces after list markers
143 | MD030:
144 | # Spaces for single-line unordered list items
145 | ul_single: 1
146 | # Spaces for single-line ordered list items
147 | ol_single: 1
148 | # Spaces for multi-line unordered list items
149 | ul_multi: 1
150 | # Spaces for multi-line ordered list items
151 | ol_multi: 1
152 |
153 | # MD031/blanks-around-fences - Fenced code blocks should be surrounded by blank lines
154 | MD031:
155 | # Include list items
156 | list_items: true
157 |
158 | # MD032/blanks-around-lists - Lists should be surrounded by blank lines
159 | MD032: true
160 |
161 | # MD033/no-inline-html - Inline HTML
162 | MD033:
163 | # Allowed elements
164 | allowed_elements: []
165 |
166 | # MD034/no-bare-urls - Bare URL used
167 | MD034: true
168 |
169 | # MD035/hr-style - Horizontal rule style
170 | MD035:
171 | # Horizontal rule style
172 | style: "consistent"
173 |
174 | # MD036/no-emphasis-as-heading/no-emphasis-as-header - Emphasis used instead of a heading
175 | MD036:
176 | # Punctuation characters
177 | punctuation: ".,;:!?。,;:!?"
178 |
179 | # MD037/no-space-in-emphasis - Spaces inside emphasis markers
180 | MD037: true
181 |
182 | # MD038/no-space-in-code - Spaces inside code span elements
183 | MD038: true
184 |
185 | # MD039/no-space-in-links - Spaces inside link text
186 | MD039: true
187 |
188 | # MD040/fenced-code-language - Fenced code blocks should have a language specified
189 | MD040:
190 | # List of languages
191 | allowed_languages: []
192 | # Require language only
193 | language_only: false
194 |
195 | # MD041/first-line-heading/first-line-h1 - First line in a file should be a top-level heading
196 | MD041:
197 | # Heading level
198 | level: 1
199 | # RegExp for matching title in front matter
200 | front_matter_title: "^\\s*title\\s*[:=]"
201 |
202 | # MD042/no-empty-links - No empty links
203 | MD042: true
204 |
205 | # Modified for LSR
206 | # Disabling, we do not need this
207 | # MD043/required-headings/required-headers - Required heading structure
208 | MD043: false
209 | # # List of headings
210 | # headings: []
211 | # # List of headings
212 | # headers: []
213 | # # Match case of headings
214 | # match_case: false
215 |
216 | # MD044/proper-names - Proper names should have the correct capitalization
217 | MD044:
218 | # List of proper names
219 | names: []
220 | # Include code blocks
221 | code_blocks: true
222 | # Include HTML elements
223 | html_elements: true
224 |
225 | # MD045/no-alt-text - Images should have alternate text (alt text)
226 | MD045: true
227 |
228 | # MD046/code-block-style - Code block style
229 | MD046:
230 | # Block style
231 | style: "consistent"
232 |
233 | # MD047/single-trailing-newline - Files should end with a single newline character
234 | MD047: true
235 |
236 | # MD048/code-fence-style - Code fence style
237 | MD048:
238 | # Code fence style
239 | style: "consistent"
240 |
241 | # MD049/emphasis-style - Emphasis style should be consistent
242 | MD049:
243 | # Emphasis style should be consistent
244 | style: "consistent"
245 |
246 | # MD050/strong-style - Strong style should be consistent
247 | MD050:
248 | # Strong style should be consistent
249 | style: "consistent"
250 |
251 | # MD051/link-fragments - Link fragments should be valid
252 | MD051: true
253 |
254 | # MD052/reference-links-images - Reference links and images should use a label that is defined
255 | MD052: true
256 |
257 | # MD053/link-image-reference-definitions - Link and image reference definitions should be needed
258 | MD053:
259 | # Ignored definitions
260 | ignored_definitions:
261 | - "//"
262 |
--------------------------------------------------------------------------------
/.ostree/README.md:
--------------------------------------------------------------------------------
1 | *NOTE*: The `*.txt` files are used by `get_ostree_data.sh` to create the lists
2 | of packages, and to find other system roles used by this role. DO NOT use them
3 | directly.
4 |
--------------------------------------------------------------------------------
/.ostree/get_ostree_data.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -euo pipefail
4 |
5 | ostree_dir="${OSTREE_DIR:-"$(dirname "$(realpath "$0")")"}"
6 |
7 | if [ -z "${4:-}" ] || [ "${1:-}" = help ] || [ "${1:-}" = -h ]; then
8 | cat <&2 echo ERROR - could not find role "$role" - please use ANSIBLE_COLLECTIONS_PATH
64 | exit 2
65 | }
66 |
67 | get_packages() {
68 | local ostree_dir pkgtype pkgfile rolefile
69 | ostree_dir="$1"
70 | for pkgtype in "${pkgtypes[@]}"; do
71 | for suff in "" "-$distro" "-${distro}-${major_ver}" "-${distro}-${ver}"; do
72 | pkgfile="$ostree_dir/packages-${pkgtype}${suff}.txt"
73 | if [ -f "$pkgfile" ]; then
74 | cat "$pkgfile"
75 | fi
76 | done
77 | rolefile="$ostree_dir/roles-${pkgtype}.txt"
78 | if [ -f "$rolefile" ]; then
79 | local roles role rolepath
80 | roles="$(cat "$rolefile")"
81 | for role in $roles; do
82 | rolepath="$(get_rolepath "$ostree_dir" "$role")"
83 | if [ -z "$rolepath" ]; then
84 | 1>&2 echo ERROR - could not find role "$role" - please use ANSIBLE_COLLECTIONS_PATH
85 | exit 2
86 | fi
87 | get_packages "$rolepath"
88 | done
89 | fi
90 | done | sort -u
91 | }
92 |
93 | format_packages_json() {
94 | local comma pkgs pkg
95 | comma=""
96 | pkgs="["
97 | while read -r pkg; do
98 | pkgs="${pkgs}${comma}\"${pkg}\""
99 | comma=,
100 | done
101 | pkgs="${pkgs}]"
102 | echo "$pkgs"
103 | }
104 |
105 | format_packages_raw() {
106 | cat
107 | }
108 |
109 | format_packages_yaml() {
110 | while read -r pkg; do
111 | echo "- $pkg"
112 | done
113 | }
114 |
115 | format_packages_toml() {
116 | while read -r pkg; do
117 | echo "[[packages]]"
118 | echo "name = \"$pkg\""
119 | echo "version = \"*\""
120 | done
121 | }
122 |
123 | distro="${distro_ver%%-*}"
124 | ver="${distro_ver##*-}"
125 | if [[ "$ver" =~ ^([0-9]*) ]]; then
126 | major_ver="${BASH_REMATCH[1]}"
127 | else
128 | echo ERROR: cannot parse major version number from version "$ver"
129 | exit 1
130 | fi
131 |
132 | "get_$category" "$ostree_dir" | "format_${category}_$format"
133 |
--------------------------------------------------------------------------------
/.packit.yaml:
--------------------------------------------------------------------------------
1 | downstream_package_name: ansible-collection-microsoft-sql
2 |
3 | specfile_path: ansible-collection-microsoft-sql.spec
4 |
5 | files_to_sync:
6 | - ansible-collection-microsoft-sql.spec
7 | - src: CHANGELOG.md
8 | dest: CHANGELOG.md
9 |
10 | upstream_project_url: https://github.com/linux-system-roles/mssql
11 |
12 | actions:
13 | post-upstream-clone:
14 | - "wget https://src.fedoraproject.org/rpms/ansible-collection-microsoft-sql/raw/rawhide/f/ansible-collection-microsoft-sql.spec -O ansible-collection-microsoft-sql.spec"
15 | - "wget https://src.fedoraproject.org/rpms/ansible-collection-microsoft-sql/raw/rawhide/f/ansible-packaging.inc -O ansible-packaging.inc"
16 | jobs:
17 | - job: propose_downstream
18 | trigger: release
19 | dist_git_branches:
20 | - fedora-all
21 |
--------------------------------------------------------------------------------
/.yamllint.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | ignore: |
4 | /.tox/
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2021 Red Hat, Inc.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README-ansible.md:
--------------------------------------------------------------------------------
1 | # Introduction to Ansible for Linux System Roles
2 |
3 | If you are not familiar with Ansible, please see
4 | [Introduction to Ansible for Linux System Roles](https://linux-system-roles.github.io/documentation/intro-to-ansible-for-system-roles.html),
5 | where many useful links are presented.
6 |
--------------------------------------------------------------------------------
/README-ostree.md:
--------------------------------------------------------------------------------
1 | # rpm-ostree
2 |
3 | The role supports running on [rpm-ostree](https://coreos.github.io/rpm-ostree/)
4 | systems. The primary issue is that the `/usr` filesystem is read-only, and the
5 | role cannot install packages. Instead, it will just verify that the necessary
6 | packages and any other `/usr` files are pre-installed. The role will change the
7 | package manager to one that is compatible with `rpm-ostree` systems.
8 |
9 | ## Building
10 |
11 | To build an ostree image for a particular operating system distribution and
12 | version, use the script `.ostree/get_ostree_data.sh` to get the list of
13 | packages. If the role uses other system roles, then the script will include the
14 | packages for the other roles in the list it outputs. The list of packages will
15 | be sorted in alphanumeric order.
16 |
17 | Usage:
18 |
19 | ```bash
20 | .ostree/get_ostree_data.sh packages runtime DISTRO-VERSION FORMAT
21 | ```
22 |
23 | `DISTRO-VERSION` is in the format that Ansible uses for `ansible_distribution`
24 | and `ansible_distribution_version` - for example, `Fedora-38`, `CentOS-8`,
25 | `RedHat-9.4`
26 |
27 | `FORMAT` is one of `toml`, `json`, `yaml`, `raw`
28 |
29 | * `toml` - each package in a TOML `[[packages]]` element
30 |
31 | ```toml
32 | [[packages]]
33 | name = "package-a"
34 | version = "*"
35 | [[packages]]
36 | name = "package-b"
37 | version = "*"
38 | ...
39 | ```
40 |
41 | * `yaml` - a YAML list of packages
42 |
43 | ```yaml
44 | - package-a
45 | - package-b
46 | ...
47 | ```
48 |
49 | * `json` - a JSON list of packages
50 |
51 | ```json
52 | ["package-a","package-b",...]
53 | ```
54 |
55 | * `raw` - a plain text list of packages, one per line
56 |
57 | ```bash
58 | package-a
59 | package-b
60 | ...
61 | ```
62 |
63 | What format you choose depends on which image builder you are using. For
64 | example, if you are using something based on
65 | [osbuild-composer](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html-single/composing_installing_and_managing_rhel_for_edge_images/index#creating-an-image-builder-blueprint-for-a-rhel-for-edge-image-using-the-command-line-interface_composing-a-rhel-for-edge-image-using-image-builder-command-line),
66 | you will probably want to use the `toml` output format.
67 |
--------------------------------------------------------------------------------
/ansible_pytest_extra_requirements.txt:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 |
3 | # ansible and dependencies for all supported platforms
4 | ansible ; python_version > "2.6"
5 | idna<2.8 ; python_version < "2.7"
6 | PyYAML<5.1 ; python_version < "2.7"
7 |
--------------------------------------------------------------------------------
/contributing.md:
--------------------------------------------------------------------------------
1 | # Contributing to the mssql Linux System Role
2 |
3 | ## Where to start
4 |
5 | The first place to go is [Contribute](https://linux-system-roles.github.io/contribute.html).
6 | This has all of the common information that all role developers need:
7 |
8 | * Role structure and layout
9 | * Development tools - How to run tests and checks
10 | * Ansible recommended practices
11 | * Basic git and github information
12 | * How to create git commits and submit pull requests
13 |
14 | **Bugs and needed implementations** are listed on
15 | [Github Issues](https://github.com/linux-system-roles/mssql/issues).
16 | Issues labeled with
17 | [**help wanted**](https://github.com/linux-system-roles/mssql/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22)
18 | are likely to be suitable for new contributors!
19 |
20 | **Code** is managed on [Github](https://github.com/linux-system-roles/mssql), using
21 | [Pull Requests](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests).
22 |
--------------------------------------------------------------------------------
/custom_requirements.txt:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 |
3 | # Write requirements for running your custom commands in tox here:
4 |
--------------------------------------------------------------------------------
/defaults/main.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | mssql_accept_microsoft_odbc_driver_for_sql_server_eula: false
4 | mssql_accept_microsoft_cli_utilities_for_sql_server_eula: false
5 | mssql_accept_microsoft_sql_server_standard_eula: false
6 | mssql_version: null
7 | mssql_upgrade: false
8 | mssql_password: null
9 | mssql_edition: null
10 | mssql_tools_versions: [18]
11 | mssql_tcp_port: 1433
12 | mssql_manage_firewall: false
13 | mssql_ip_address: null
14 | mssql_enable_sql_agent: null
15 | mssql_install_fts: null
16 | mssql_install_powershell: null
17 | mssql_tune_for_fua_storage: null
18 | mssql_datadir: null
19 | mssql_datadir_mode: '755'
20 | mssql_logdir: null
21 | mssql_logdir_mode: '755'
22 |
23 | mssql_pre_input_sql_file: []
24 | mssql_post_input_sql_file: []
25 | mssql_pre_input_sql_content: []
26 | mssql_post_input_sql_content: []
27 | mssql_debug: false
28 |
29 | mssql_tls_enable: null
30 | mssql_tls_cert: null
31 | mssql_tls_private_key: null
32 | mssql_tls_force: false
33 | mssql_tls_version: 1.2
34 | mssql_tls_remote_src: false
35 | mssql_tls_certificates: []
36 | mssql_tls_self_sign: false
37 |
38 | mssql_rpm_key: https://packages.microsoft.com/keys/microsoft.asc
39 | mssql_server_repository: "{{ __mssql_server_repository }}"
40 | mssql_client_repository: "{{ __mssql_client_repository }}"
41 |
42 | mssql_ha_configure: false
43 | mssql_ha_ag_cluster_type: external
44 | # mssql_ha_replica_type must be set per host in inventory. Setting it hear to
45 | # avoid "variable not defined" error in Ansible
46 | mssql_ha_replica_type: null
47 | mssql_ha_endpoint_port: 5022
48 | mssql_ha_cert_name: null
49 | mssql_ha_private_key_password: null
50 | mssql_ha_master_key_password: null
51 | mssql_ha_reset_cert: false
52 | mssql_ha_endpoint_name: null
53 | mssql_ha_ag_name: null
54 | mssql_ha_db_names: []
55 |
56 | mssql_ha_prep_for_pacemaker: "{{ mssql_ha_ag_cluster_type | lower != 'none' }}"
57 | mssql_ha_virtual_ip: null
58 | mssql_ha_login: null
59 | mssql_ha_login_password: null
60 | mssql_manage_ha_cluster: false
61 |
62 | mssql_ad_configure: false
63 | mssql_ad_join: true
64 | mssql_ad_sql_user: null
65 | mssql_ad_sql_password: null
66 | # Default to CN={{ mssql_ad_sql_user }},CN=Users,DC=DOMAIN,DC=SUBDOMAIN...
67 | mssql_ad_sql_user_dn: >-
68 | CN={{ mssql_ad_sql_user }},
69 | CN=Users,
70 | {{ ad_integration_realm.split(".")
71 | | map("regex_replace", "^", "DC=")
72 | | join(",") }}
73 | mssql_ad_keytab_file: null
74 | mssql_ad_keytab_remote_src: false
75 | mssql_ad_kerberos_user: >-
76 | {{ ad_integration_user if ad_integration_user is defined
77 | else mssql_ad_sql_user }}
78 | mssql_ad_kerberos_password: >-
79 | {{ ad_integration_password if ad_integration_user is defined
80 | else mssql_ad_sql_password }}
81 |
82 | mssql_run_selinux_confined: "{{ __mssql_confined_supported | d(false) }}"
83 | mssql_manage_selinux: false
84 |
--------------------------------------------------------------------------------
/files/ha_is_primary.sql:
--------------------------------------------------------------------------------
1 | IF EXISTS(
2 | SELECT role
3 | FROM sys.dm_hadr_availability_replica_states states
4 | JOIN sys.availability_replicas replicas
5 | ON states.replica_id = replicas.replica_id
6 | WHERE states.is_local = 1
7 | AND
8 | role = 1
9 | )
10 | BEGIN
11 | PRINT(1)
12 | END
13 | ELSE
14 | BEGIN
15 | PRINT(0)
16 | END
17 |
--------------------------------------------------------------------------------
/handlers/main.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Restart the mssql-server service
4 | service:
5 | name: mssql-server
6 | state: restarted
7 | when: __mssql_is_booted | bool
8 |
--------------------------------------------------------------------------------
/meta/collection-requirements.yml:
--------------------------------------------------------------------------------
1 | ---
2 | collections:
3 | - name: fedora.linux_system_roles
4 |
--------------------------------------------------------------------------------
/meta/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | galaxy_info:
3 | author: Sergei Petrosian
4 | description: This role installs and configures Microsoft SQL Server
5 | company: Red Hat, Inc.
6 | license: MIT
7 | min_ansible_version: "2.9"
8 | platforms:
9 | - name: Fedora
10 | versions:
11 | - all
12 | - name: EL
13 | versions:
14 | - "9"
15 | - "8"
16 | - "7"
17 | - name: SLES
18 | versions:
19 | - "15SP5"
20 | - name: opensuse
21 | versions:
22 | - "15.5"
23 | galaxy_tags:
24 | - centos
25 | - containerbuild
26 | - database
27 | - el7
28 | - el8
29 | - el9
30 | - fedora
31 | - microsoft
32 | - mssql
33 | - opensuse15dot5
34 | - rhel
35 | - sles15sp5
36 | - sql
37 | dependencies: []
38 |
--------------------------------------------------------------------------------
/molecule/default/Dockerfile.j2:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | # Molecule managed
3 |
4 | {% if item.registry is defined %}
5 | FROM {{ item.registry.url }}/{{ item.image }}
6 | {% else %}
7 | FROM {{ item.image }}
8 | {% endif %}
9 |
10 | RUN set -euo pipefail; \
11 | pkgs="python sudo yum-plugin-ovl bash"; \
12 | if grep 'CentOS release 6' /etc/centos-release > /dev/null 2>&1; then \
13 | for file in /etc/yum.repos.d/CentOS-*.repo; do \
14 | if ! grep '^baseurl=.*vault[.]centos[.]org' "$file"; then \
15 | sed -i -e 's,^mirrorlist,#mirrorlist,' \
16 | -e 's,^#baseurl=,baseurl=,' \
17 | -e 's,mirror.centos.org/centos/$releasever,vault.centos.org/6.10,' \
18 | "$file"; \
19 | fi; \
20 | done; \
21 | pkgs="$pkgs upstart chkconfig initscripts"; \
22 | fi; \
23 | if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \
24 | elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python3 sudo python3-devel python3-dnf bash && dnf clean all; \
25 | elif [ $(command -v yum) ]; then yum makecache fast && yum install -y $pkgs && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \
26 | elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml && zypper clean -a; \
27 | elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \
28 | elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates && xbps-remove -O; fi
29 |
--------------------------------------------------------------------------------
/molecule/default/molecule.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | dependency:
4 | name: galaxy
5 | driver:
6 | name: ${LSR_MOLECULE_DRIVER:-docker}
7 | platforms:
8 | - name: centos-6
9 | image: registry.centos.org/centos:6
10 | volumes:
11 | - /sys/fs/cgroup:/sys/fs/cgroup:ro
12 | privileged: true
13 | command: /sbin/init
14 | - name: centos-7
15 | image: registry.centos.org/centos/systemd:latest
16 | volumes:
17 | - /sys/fs/cgroup:/sys/fs/cgroup:ro
18 | privileged: true
19 | command: /usr/lib/systemd/systemd --system
20 | - name: centos-8
21 | image: registry.centos.org/centos:8
22 | volumes:
23 | - /sys/fs/cgroup:/sys/fs/cgroup:ro
24 | privileged: true
25 | command: /usr/lib/systemd/systemd --system
26 | provisioner:
27 | name: ansible
28 | log: true
29 | playbooks:
30 | converge: ../../tests/tests_default.yml
31 | scenario:
32 | name: default
33 | test_sequence:
34 | - destroy
35 | - create
36 | - converge
37 | - idempotence
38 | - check
39 | - destroy
40 |
--------------------------------------------------------------------------------
/molecule_extra_requirements.txt:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 |
3 | # Write extra requirements for running molecule here:
4 |
--------------------------------------------------------------------------------
/plans/README-plans.md:
--------------------------------------------------------------------------------
1 | # Introduction CI Testing Plans
2 |
3 | Linux System Roles CI runs [tmt](https://tmt.readthedocs.io/en/stable/index.html) test plans in [Testing farm](https://docs.testing-farm.io/Testing%20Farm/0.1/index.html) with the [tft.yml](https://github.com/linux-system-roles/mssql/blob/main/.github/workflows/tft.yml) GitHub workflow.
4 |
5 | The `plans/test_playbooks_parallel.fmf` plan is a test plan that runs test playbooks in parallel on multiple managed nodes.
6 | `plans/test_playbooks_parallel.fmf` is generated centrally from `https://github.com/linux-system-roles/.github/`.
7 | The automation calculates the number of managed nodes to provision with this formula:
8 |
9 | ```plain
10 | number-of-test-playbooks / 10 + 1
11 | ```
12 |
13 | The `plans/test_playbooks_parallel.fmf` plan does the following steps:
14 |
15 | 1. Provisions systems to be used as a control node and as managed nodes.
16 | 2. Does the required preparation on systems.
17 | 3. For the given role and the given PR, runs the general test from [test.sh](https://github.com/linux-system-roles/tft-tests/blob/main/tests/general/test.sh).
18 |
19 | The [tft.yml](https://github.com/linux-system-roles/mssql/blob/main/.github/workflows/tft.yml) workflow runs the above plan and uploads the results to our Fedora storage for public access.
20 | This workflow uses Testing Farm's Github Action [Schedule tests on Testing Farm](https://github.com/marketplace/actions/schedule-tests-on-testing-farm).
21 |
22 | ## Running Tests
23 |
24 | You can run tests locally with the `tmt try` cli or remotely in Testing Farm.
25 |
26 | ### Running Tests Locally
27 |
28 | 1. Install `tmt` as described in [Installation](https://tmt.readthedocs.io/en/stable/stories/install.html).
29 | 2. Change to the role repository directory.
30 | 3. Modify `plans/test_playbooks_parallel.fmf` to suit your requirements:
31 | 1. Due to [issue #3138](https://github.com/teemtee/tmt/issues/3138), comment out all managed nodes except for one.
32 | 2. Optionally modify environment variables to, e.g. run only specified test playbooks by modifying `SYSTEM_ROLES_ONLY_TESTS`.
33 | 4. Enter `tmt try -p plans/test_playbooks_parallel `.
34 | This command identifies the `plans/test_playbooks_parallel.fmf` plan and provisions local VMs, a control node and a managed node.
35 | 5. `tmt try` is in development and does not identify tests from URL automatically, so after provisioning the machines, you must type `t`, `p`, `t` from the interactive prompt to identify tests, run preparation steps, and run the tests.
36 |
37 | ### Running in Testing Farm
38 |
39 | 1. Install `testing-farm` as described in [Installation](https://gitlab.com/testing-farm/cli/-/blob/main/README.adoc#user-content-installation).
40 | 2. Change to the role repository directory.
41 | 3. If you want to run tests with edits in your branch, you need to commit and push changes first to some branch.
42 | 4. You can uncomment "Inject your ssh public key to test systems" discover step in the plan if you want to troubleshoot tests by SSHing into test systems in Testing Farm.
43 | 5. Enter `testing-farm request`.
44 | Edit to your needs.
45 |
46 | ```bash
47 | $ TESTING_FARM_API_TOKEN= \
48 | testing-farm request --pipeline-type="tmt-multihost" \
49 | --plan-filter="tag:playbooks_parallel" \
50 | --git-url "https://github.com//mssql" \
51 | --git-ref "" \
52 | --compose CentOS-Stream-9 \
53 | -e "SYSTEM_ROLES_ONLY_TESTS=tests_default.yml" \
54 | --no-wait
55 | ```
56 |
--------------------------------------------------------------------------------
/plans/mssql_ha.fmf:
--------------------------------------------------------------------------------
1 | summary: A general test for a system role
2 | tag: mssql
3 | provision:
4 | - name: control-node1
5 | role: control_node
6 | - name: managed-node1
7 | role: managed_node
8 | hardware:
9 | memory: ">= 4096 MB"
10 | # Provision all machines in the same AWS pool to ensure that they are in the same subnet
11 | pool: aws-testing-farm-09
12 | - name: managed-node2
13 | role: managed_node
14 | hardware:
15 | memory: ">= 4096 MB"
16 | pool: aws-testing-farm-09
17 | - name: managed-node3
18 | role: managed_node
19 | hardware:
20 | memory: ">= 4096 MB"
21 | pool: aws-testing-farm-09
22 | - name: virtualip-node1
23 | role: virtualip
24 | pool: aws-testing-farm-09
25 | environment:
26 | SR_ANSIBLE_VER: 2.17
27 | SR_PYTHON_VERSION: 3.12
28 | SR_REPO_NAME: mssql
29 | SR_ONLY_TESTS: "tests_configure_ha_cluster_external.yml tests_configure_ha_cluster_read_scale.yml"
30 | SR_TEST_LOCAL_CHANGES: false
31 | SR_PR_NUM: ""
32 | SR_LSR_USER: ""
33 | SR_LSR_DOMAIN: ""
34 | SR_LSR_SSH_KEY: ""
35 | SR_ARTIFACTS_DIR: ""
36 | SR_ARTIFACTS_URL: ""
37 | SR_TFT_DEBUG: false
38 | prepare:
39 | - name: Use vault.centos.org repos (CS 7, 8 EOL workaround)
40 | script: |
41 | if grep -q 'CentOS Stream release 8' /etc/redhat-release; then
42 | sed -i '/^mirror/d;s/#\(baseurl=http:\/\/\)mirror/\1vault/' /etc/yum.repos.d/*.repo
43 | fi
44 | if grep -q 'CentOS Linux release 7.9' /etc/redhat-release; then
45 | sed -i '/^mirror/d;s/#\?\(baseurl=http:\/\/\)mirror/\1vault/' /etc/yum.repos.d/*.repo
46 | fi
47 | # Replace with feature: epel: enabled once https://github.com/teemtee/tmt/pull/3128 is merged
48 | - name: Enable epel to install beakerlib
49 | script: |
50 | # CS 10 and Fedora doesn't require epel
51 | if grep -q -e 'CentOS Stream release 10' -e 'Fedora release' /etc/redhat-release; then
52 | exit 0
53 | fi
54 | yum install epel-release yum-utils -y
55 | yum-config-manager --enable epel epel-debuginfo epel-source
56 | discover:
57 | - name: Prepare managed nodes
58 | how: fmf
59 | where: managed_node
60 | filter: tag:prep_managed_node
61 | url: https://github.com/linux-system-roles/tft-tests
62 | ref: main
63 | - name: Run test playbooks from control_node
64 | how: fmf
65 | where: control_node
66 | filter: tag:mssql_ha
67 | url: https://github.com/linux-system-roles/tft-tests
68 | ref: main
69 | # Uncomment this step for troubleshooting
70 | # This is required because currently testing-farm cli doesn't support running multi-node plans
71 | # You can set ID_RSA_PUB in the environment section above to your public key to distribute it to nodes
72 | # - name: Inject your ssh public key to test systems
73 | # how: fmf
74 | # where: control_node
75 | # filter: tag:reserve_system
76 | execute:
77 | how: tmt
78 |
--------------------------------------------------------------------------------
/plans/test_playbooks_parallel.fmf:
--------------------------------------------------------------------------------
1 | summary: A general test for a system role
2 | tag: playbooks_parallel
3 | provision:
4 | # TF uses `how: artemis`, and `tmt try`` uses `how: virtual`.
5 | # Hence there is no need to define `how` explicitly.
6 | - name: control-node1
7 | role: control_node
8 | - name: managed-node1
9 | role: managed_node
10 | hardware:
11 | memory: '>= 4096 MB'
12 | - name: managed-node2
13 | role: managed_node
14 | hardware:
15 | memory: '>= 4096 MB'
16 | - name: managed-node3
17 | role: managed_node
18 | hardware:
19 | memory: '>= 4096 MB'
20 | environment:
21 | SR_ANSIBLE_VER: 2.17
22 | SR_REPO_NAME: mssql
23 | SR_PYTHON_VERSION: 3.12
24 | SR_ONLY_TESTS: "" # tests_default.yml
25 | SR_TEST_LOCAL_CHANGES: true
26 | SR_PR_NUM: ""
27 | SR_LSR_USER: ""
28 | SR_LSR_DOMAIN: ""
29 | SR_LSR_SSH_KEY: ""
30 | SR_ARTIFACTS_DIR: ""
31 | SR_ARTIFACTS_URL: ""
32 | SR_TFT_DEBUG: false
33 | prepare:
34 | - name: Use vault.centos.org repos (CS 7, 8 EOL workaround)
35 | script: |
36 | if grep -q 'CentOS Stream release 8' /etc/redhat-release; then
37 | sed -i '/^mirror/d;s/#\(baseurl=http:\/\/\)mirror/\1vault/' /etc/yum.repos.d/*.repo
38 | fi
39 | if grep -q 'CentOS Linux release 7.9' /etc/redhat-release; then
40 | sed -i '/^mirror/d;s/#\?\(baseurl=http:\/\/\)mirror/\1vault/' /etc/yum.repos.d/*.repo
41 | fi
42 | # Replace with feature: epel: enabled once https://github.com/teemtee/tmt/pull/3128 is merged
43 | - name: Enable epel to install beakerlib
44 | script: |
45 | # CS 10 and Fedora doesn't require epel
46 | if grep -q -e 'CentOS Stream release 10' -e 'Fedora release' /etc/redhat-release; then
47 | exit 0
48 | fi
49 | yum install epel-release yum-utils -y
50 | yum-config-manager --enable epel epel-debuginfo epel-source
51 | discover:
52 | - name: Prepare managed node
53 | how: fmf
54 | where: managed_node
55 | filter: tag:prep_managed_node
56 | url: https://github.com/linux-system-roles/tft-tests
57 | ref: main
58 | - name: Run test playbooks from control_node
59 | how: fmf
60 | where: control_node
61 | filter: tag:test_playbooks
62 | url: https://github.com/linux-system-roles/tft-tests
63 | ref: main
64 | # Uncomment this step for troubleshooting
65 | # This is required because currently testing-farm cli doesn't support running multi-node plans
66 | # You can set ID_RSA_PUB in the environment section above to your public key to distribute it to nodes
67 | # - name: Inject your ssh public key to test systems
68 | # how: fmf
69 | # where: control_node
70 | # filter: tag:reserve_system
71 | # url: https://github.com/linux-system-roles/tft-tests
72 | # ref: main
73 | execute:
74 | how: tmt
75 |
--------------------------------------------------------------------------------
/pylint_extra_requirements.txt:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 |
3 | # Write extra requirements for running pylint here:
4 |
--------------------------------------------------------------------------------
/pytest_extra_requirements.txt:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 |
3 | # Write extra requirements for running pytest here:
4 | # If you need ansible then uncomment the following line:
5 | #-ransible_pytest_extra_requirements.txt
6 | # If you need mock then uncomment the following line:
7 | #mock ; python_version < "3.0"
8 |
--------------------------------------------------------------------------------
/tasks/configure_storage_paths.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: >-
4 | Ensure the directory and permissions {{ __mssql_storage_path }}
5 | file:
6 | path: "{{ __mssql_storage_path }}"
7 | state: directory
8 | owner: mssql
9 | group: mssql
10 | mode: "{{ __mssql_storage_mode }}"
11 |
12 | - name: Append facts for the selinux role
13 | vars:
14 | selinux_fcontext:
15 | - target: "{{ __mssql_storage_path }}"
16 | setype: "{{ 'mssql_db_t' if __mssql_storage_setting == 'defaultlogdir'
17 | else 'mssql_var_t' }}"
18 | ftype: d
19 | state: present
20 | selinux_restore_dir:
21 | - "{{ __mssql_storage_path }}"
22 | set_fact:
23 | selinux_fcontexts: "{{
24 | (selinux_fcontexts | default([])) + selinux_fcontext }}"
25 | selinux_restore_dirs: "{{
26 | (selinux_restore_dirs | default([])) + selinux_restore_dir }}"
27 | when:
28 | - mssql_manage_selinux | bool
29 | - mssql_run_selinux_confined | bool
30 |
31 | - name: Configure the setting {{ __mssql_storage_setting }}
32 | include_tasks: mssql_conf_setting.yml
33 | vars:
34 | __mssql_conf_setting: filelocation {{ __mssql_storage_setting }}
35 | __mssql_conf_setting_value: "{{ __mssql_storage_path }}"
36 |
--------------------------------------------------------------------------------
/tasks/input_sql_files.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | # This task files inputs sql files into MSSQL.
3 | # This task takes a list of files.
4 | # If you feed a file with .j2 extension, it generates a template from it.
5 | # If you feed a file with other extension, it just copies the file and runs it.
6 | ---
7 | # This is required because in the case when a task that precedes the input
8 | # task fails, the print task prints a previous result
9 | - name: Unset the __mssql_sqlcmd_input variable
10 | set_fact:
11 | __mssql_sqlcmd_input: []
12 |
13 | - name: Verify that the mssql_password variable is defined
14 | assert:
15 | that:
16 | - mssql_password is not none
17 | fail_msg: >-
18 | You must define the mssql_password variable because MSSQL requires
19 | the sa user to authenticate to input SQL files.
20 |
21 | - name: Ensure that the mssql-server service is started
22 | service:
23 | name: mssql-server
24 | state: started
25 |
26 | - name: Wait for mssql-server to prepare for client connections
27 | wait_for:
28 | path: /var/opt/mssql/log/errorlog
29 | search_regex: SQL Server is now ready for client connections
30 | delay: 1
31 |
32 | - name: Prepare MSSQL and facts for logging in
33 | include_tasks: verify_password.yml
34 | when: >-
35 | (__mssql_sqlcmd_login_cmd is none) or
36 | (__mssql_sqlcmd_login_cmd is not defined)
37 |
38 | - name: Input SQL script files to MSSQL
39 | include_tasks: sqlcmd_input_file.yml
40 | loop: "{{ __mssql_sql_files_to_input }}"
41 | when: __mssql_sql_files_to_input is defined
42 |
43 | - name: Input SQL script contents to MSSQL
44 | include_tasks: sqlcmd_input_content.yml
45 | loop: "{{ __mssql_sql_content_to_input }}"
46 | when: __mssql_sql_content_to_input is defined
47 |
--------------------------------------------------------------------------------
/tasks/mssql_conf_setting.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Get the setting {{ __mssql_conf_setting }}
4 | # noqa jinja[spacing]
5 | command: >-
6 | grep '^{{ __mssql_conf_setting | regex_replace('^.*\s' ,'') }} = '
7 | {{ __mssql_conf_path }}
8 | changed_when: false
9 | failed_when: false
10 | register: __mssql_conf_get_setting
11 |
12 | - name: Configure the setting {{ __mssql_conf_setting }}
13 | # noqa jinja[spacing]
14 | command: >-
15 | {{ __mssql_conf_cli }} set {{ __mssql_conf_setting |
16 | regex_replace(' ','.') }} {{ __mssql_conf_setting_value | quote }}
17 | vars:
18 | __mssql_conf_get_value: >-
19 | {{ __mssql_conf_get_setting.stdout |
20 | regex_replace('^.*\s=\s', '') }}
21 | when: >-
22 | (__mssql_conf_setting_value != 'unset') and
23 | (("No setting for the given" in __mssql_conf_get_setting.stdout) or
24 | ((__mssql_conf_setting_value | type_debug != "bool") and
25 | (__mssql_conf_setting_value | string | lower not in
26 | __mssql_conf_get_value | lower)) or
27 | ((__mssql_conf_setting_value | type_debug == "bool") and
28 | (__mssql_conf_setting_value != __mssql_conf_get_value | bool)))
29 | register: __mssql_conf_set
30 | failed_when:
31 | - >-
32 | ("error" in __mssql_conf_set.stdout | lower) or
33 | (__mssql_conf_set is failed)
34 | - >-
35 | "is already in use. Please use another port" not in
36 | __mssql_conf_set.stdout
37 | changed_when: >-
38 | "SQL Server needs to be restarted in order to apply this setting." in
39 | __mssql_conf_set.stdout
40 | notify: Restart the mssql-server service
41 |
42 | - name: Unset the setting {{ __mssql_conf_setting }}
43 | command: >-
44 | {{ __mssql_conf_cli }} unset
45 | {{ __mssql_conf_setting | regex_replace('\s', '.') }}
46 | when:
47 | - __mssql_conf_setting_value == "unset"
48 | - '"No setting for the given" not in __mssql_conf_get_setting.stdout'
49 | register: __mssql_conf_unset
50 | failed_when: >-
51 | ("error" in __mssql_conf_unset.stdout | lower) or
52 | (__mssql_conf_unset is failed)
53 | notify: Restart the mssql-server service
54 | changed_when: true
55 |
--------------------------------------------------------------------------------
/tasks/set_vars.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Ensure ansible_facts used by role
4 | setup:
5 | gather_subset: "{{ __mssql_required_facts_subsets }}"
6 | when: __mssql_required_facts |
7 | difference(ansible_facts.keys() | list) | length > 0
8 |
9 | - name: Set platform/version specific variables
10 | include_vars: "{{ __mssql_vars_file }}"
11 | loop:
12 | - "{{ ansible_os_family }}.yml"
13 | - "{{ ansible_distribution }}.yml"
14 | - "{{ ansible_distribution }}_{{ ansible_distribution_major_version }}.yml"
15 | - "{{ ansible_distribution }}_{{ ansible_distribution_version }}.yml"
16 | vars:
17 | __mssql_vars_file: "{{ role_path }}/vars/{{ item }}"
18 | when: __mssql_vars_file is file
19 |
20 | - name: Determine if system is booted with systemd
21 | when: __mssql_is_booted is not defined
22 | block:
23 | - name: Run systemctl
24 | # noqa command-instead-of-module
25 | command: systemctl is-system-running
26 | register: __is_system_running
27 | changed_when: false
28 | failed_when: false
29 |
30 | - name: Require installed systemd
31 | fail:
32 | msg: "Error: This role requires systemd to be installed."
33 | when: '"No such file or directory" in __is_system_running.msg | d("")'
34 |
35 | - name: Set flag to indicate that systemd runtime operations are available
36 | set_fact:
37 | # see https://www.man7.org/linux/man-pages/man1/systemctl.1.html#:~:text=is-system-running%20output
38 | __mssql_is_booted: "{{ __is_system_running.stdout != 'offline' }}"
39 |
--------------------------------------------------------------------------------
/tasks/sqlcmd_input_content.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Input script content with sqlcmd
3 | block:
4 | - name: Input script content
5 | command: >-
6 | {{ __mssql_sqlcmd_login_cmd }} -Q {{ item | quote }} -b
7 | register: __mssql_sqlcmd_input
8 | changed_when: '"successfully" in __mssql_sqlcmd_input.stdout'
9 | no_log: true
10 | until: >-
11 | "TCP Provider: Error code 0x102" not in __mssql_sqlcmd_input.stdout and
12 | "TCP Provider: Error code 0x102" not in __mssql_sqlcmd_input.stderr and
13 | "TCP Provider: Error code 0x2749" not in __mssql_sqlcmd_input.stdout and
14 | "TCP Provider: Error code 0x2749" not in __mssql_sqlcmd_input.stderr
15 |
16 | always:
17 | # Role prints the output if the input succeeds, otherwise Ansible prints the
18 | # output from the failed input tasks
19 | - name: Print results and clean up after inputting script content
20 | when:
21 | - >-
22 | (mssql_debug | bool) or
23 | (__mssql_sqlcmd_input is failed)
24 | - __mssql_sqlcmd_loop | length > 0
25 | debug:
26 | var: __mssql_sqlcmd_loop
27 | loop:
28 | - "{{ __mssql_sqlcmd_input.stdout_lines }}"
29 | - "{{ __mssql_sqlcmd_input.stderr_lines }}"
30 | loop_control:
31 | loop_var: __mssql_sqlcmd_loop
32 |
--------------------------------------------------------------------------------
/tasks/sqlcmd_input_file.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Input with sqlcmd {{ item }}
3 | block:
4 | - name: Create a tempfile on the host for {{ item }}
5 | tempfile:
6 | state: file
7 | prefix: "{{ item | basename }}_"
8 | suffix: .sql
9 | register: __mssql_sql_tempfile
10 | changed_when: false
11 |
12 | - name: Copy the file to the host {{ item }}
13 | copy:
14 | src: "{{ item }}"
15 | dest: "{{ __mssql_sql_tempfile.path }}"
16 | mode: preserve
17 | when: item is not search(".*\.j2$")
18 | changed_when: false
19 |
20 | - name: Generate the template on the host for {{ item }}
21 | template:
22 | src: "{{ item }}"
23 | dest: "{{ __mssql_sql_tempfile.path }}"
24 | mode: preserve
25 | when: item is search(".*\.j2$")
26 | changed_when: false
27 |
28 | - name: Input with the sqlcmd command {{ item }}
29 | command: >-
30 | {{ __mssql_sqlcmd_login_cmd }} -i {{ __mssql_sql_tempfile.path }} -b
31 | register: __mssql_sqlcmd_input
32 | changed_when: '"successfully" in __mssql_sqlcmd_input.stdout'
33 | no_log: true
34 | until: >-
35 | "TCP Provider: Error code 0x68" not in __mssql_sqlcmd_input.stdout and
36 | "TCP Provider: Error code 0x68" not in __mssql_sqlcmd_input.stderr and
37 | "TCP Provider: Error code 0x102" not in __mssql_sqlcmd_input.stdout and
38 | "TCP Provider: Error code 0x102" not in __mssql_sqlcmd_input.stderr and
39 | "TCP Provider: Error code 0x2749" not in __mssql_sqlcmd_input.stdout and
40 | "TCP Provider: Error code 0x2749" not in __mssql_sqlcmd_input.stderr
41 | always:
42 | # Role prints the output if the input succeeds, otherwise Ansible prints the
43 | # output from the failed input tasks
44 | - name: Print file location and output from inputting {{ item }}
45 | when:
46 | - >-
47 | (mssql_debug | bool) or
48 | (__mssql_sqlcmd_input is failed)
49 | - __mssql_sqlcmd_loop | length > 0
50 | debug:
51 | var: __mssql_sqlcmd_loop
52 | loop:
53 | - "{{ __mssql_sql_tempfile.path }}"
54 | - "{{ __mssql_sqlcmd_input.stdout_lines }}"
55 | - "{{ __mssql_sqlcmd_input.stderr_lines }}"
56 | loop_control:
57 | loop_var: __mssql_sqlcmd_loop
58 |
59 | # Role keeps the file if the input failed
60 | - name: Remove the tempfile {{ item }}
61 | file:
62 | path: "{{ __mssql_sql_tempfile.path }}"
63 | state: absent
64 | when:
65 | - __mssql_sqlcmd_input is succeeded
66 | - not mssql_debug
67 | changed_when: false
68 |
--------------------------------------------------------------------------------
/tasks/verify_password.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Ensure that the mssql-server service is started
4 | service:
5 | name: mssql-server
6 | state: started
7 | when: __mssql_is_booted | bool
8 |
9 | - name: Check if a custom tcpport setting exist
10 | command: grep '^tcpport = ' {{ __mssql_conf_path }}
11 | failed_when: false
12 | changed_when: false
13 | register: __mssql_custom_tcp_port
14 |
15 | - name: Check if a custom ipaddress setting exist
16 | command: grep '^ipaddress = ' {{ __mssql_conf_path }}
17 | failed_when: false
18 | changed_when: false
19 | register: __mssql_custom_ip_address
20 |
21 | - name: Set a fact with a login command
22 | vars:
23 | __ipaddress: >-
24 | {{ __mssql_custom_ip_address.stdout |
25 | regex_search('[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}') }}
26 | __tcpport: >-
27 | {{ __mssql_custom_tcp_port.stdout | regex_search('[1-9][0-9]{0,4}') }}
28 | __s_arg: >-
29 | {{ (__ipaddress or __tcpport) | ternary('-S', '') }}
30 | __ipaddress_arg: >-
31 | {{ __ipaddress if __ipaddress else '127.0.0.1' if __tcpport else '' }}
32 | set_fact:
33 | __mssql_sqlcmd_login_cmd: >-
34 | {{ __sqlcmd_cli }}
35 | {{ __s_arg }}
36 | {{ __ipaddress_arg }}{{ ',' if __tcpport
37 | else '' }}{{ __tcpport if __tcpport else '' }}
38 | -U sa -P {{ mssql_password | quote }}
39 | no_log: true
40 |
--------------------------------------------------------------------------------
/templates/configure_endpoint.j2:
--------------------------------------------------------------------------------
1 | IF NOT EXISTS (
2 | SELECT name
3 | FROM sys.database_mirroring_endpoints
4 | WHERE name = '{{ mssql_ha_endpoint_name }}'
5 | )
6 | BEGIN
7 | PRINT 'Endpoint {{ mssql_ha_endpoint_name }} does not exist, creating';
8 | CREATE ENDPOINT {{ mssql_ha_endpoint_name }}
9 | STATE = STARTED
10 | AS TCP (LISTENER_PORT = {{ mssql_ha_endpoint_port }})
11 | FOR DATABASE_MIRRORING (
12 | ROLE = {{ __mssql_ha_endpoint_role }},
13 | AUTHENTICATION = CERTIFICATE {{ mssql_ha_cert_name }},
14 | ENCRYPTION = REQUIRED ALGORITHM AES
15 | );
16 | PRINT 'Endpoint {{ mssql_ha_endpoint_name }} created successfully'
17 | END
18 | ELSE
19 | BEGIN
20 | PRINT 'Verifying the existing endpoint {{ mssql_ha_endpoint_name }}';
21 | IF NOT EXISTS (
22 | SELECT name, port FROM sys.tcp_endpoints
23 | WHERE name = '{{ mssql_ha_endpoint_name }}' AND
24 | port = {{ mssql_ha_endpoint_port }}
25 | )
26 | BEGIN
27 | ALTER ENDPOINT {{ mssql_ha_endpoint_name }}
28 | AS TCP (LISTENER_PORT = {{ mssql_ha_endpoint_port }});
29 | PRINT 'The LISTENER_PORT setting for the {{ mssql_ha_endpoint_name }} \
30 | endpoint updated to {{ mssql_ha_endpoint_port }} successfully';
31 | END
32 | ELSE
33 | BEGIN
34 | PRINT 'The LISTENER_PORT setting for the {{ mssql_ha_endpoint_name }} \
35 | endpoint is already set to {{ mssql_ha_endpoint_port }}, skipping';
36 | END
37 | IF NOT EXISTS (
38 | SELECT name, role_desc FROM sys.database_mirroring_endpoints
39 | WHERE name = '{{ mssql_ha_endpoint_name }}' AND
40 | role_desc = '{{ __mssql_ha_endpoint_role }}'
41 | )
42 | BEGIN
43 | ALTER ENDPOINT {{ mssql_ha_endpoint_name }}
44 | FOR DATABASE_MIRRORING (ROLE = {{ __mssql_ha_endpoint_role }});
45 | PRINT 'The ROLE setting for the {{ mssql_ha_endpoint_name }} \
46 | endpoint updated to {{ __mssql_ha_endpoint_role }} successfully';
47 | END
48 | ELSE
49 | BEGIN
50 | PRINT 'The ROLE setting for the {{ mssql_ha_endpoint_name }} \
51 | endpoint is already set to {{ __mssql_ha_endpoint_role }}, skipping';
52 | END
53 | IF NOT EXISTS (
54 | SELECT endp.name as endpoint_name,
55 | cert.name as cert_name,
56 | cert.certificate_id cert_id
57 | FROM sys.certificates cert
58 | JOIN sys.database_mirroring_endpoints endp
59 | ON cert.certificate_id = endp.certificate_id
60 | WHERE endp.name = '{{ mssql_ha_endpoint_name }}' AND
61 | cert.name = '{{ mssql_ha_cert_name }}'
62 | )
63 | BEGIN
64 | ALTER ENDPOINT {{ mssql_ha_endpoint_name }}
65 | FOR DATABASE_MIRRORING (
66 | AUTHENTICATION = CERTIFICATE {{ mssql_ha_cert_name }}
67 | );
68 | PRINT 'The certificate for the {{ mssql_ha_endpoint_name }} \
69 | endpoint updated to {{ mssql_ha_cert_name }} successfully';
70 | END
71 | ELSE
72 | BEGIN
73 | PRINT 'The certificate for the {{ mssql_ha_endpoint_name }} \
74 | endpoint is already set to {{ mssql_ha_cert_name }}, skipping';
75 | END
76 | IF NOT EXISTS (
77 | SELECT name, encryption_algorithm_desc
78 | FROM sys.database_mirroring_endpoints
79 | WHERE name = '{{ mssql_ha_endpoint_name }}' AND
80 | encryption_algorithm_desc = 'AES'
81 | )
82 | BEGIN
83 | ALTER ENDPOINT {{ mssql_ha_endpoint_name }}
84 | FOR DATABASE_MIRRORING (ENCRYPTION = REQUIRED ALGORITHM AES);
85 | PRINT 'The ENCRYPTION setting for the {{ mssql_ha_endpoint_name }} \
86 | endpoint updated to AES successfully';
87 | END
88 | ELSE
89 | BEGIN
90 | PRINT 'The ENCRYPTION setting for the {{ mssql_ha_endpoint_name }} \
91 | endpoint is already set to AES, skipping';
92 | END
93 | IF NOT EXISTS (
94 | SELECT name, state
95 | FROM sys.tcp_endpoints
96 | WHERE name = '{{ mssql_ha_endpoint_name }}' AND
97 | state = 0
98 | )
99 | BEGIN
100 | PRINT 'Endpoint {{ mssql_ha_endpoint_name }} is not started, starting';
101 | ALTER ENDPOINT {{ mssql_ha_endpoint_name }} STATE = STARTED;
102 | PRINT 'Endpoint {{ mssql_ha_endpoint_name }} started successfully';
103 | END
104 | ELSE
105 | BEGIN
106 | PRINT 'Endpoint {{ mssql_ha_endpoint_name }} is already started, skipping';
107 | END
108 | END
109 |
--------------------------------------------------------------------------------
/templates/configure_listener.j2:
--------------------------------------------------------------------------------
1 | IF NOT EXISTS (
2 | SELECT dns_name
3 | FROM sys.availability_group_listeners
4 | )
5 | BEGIN
6 | PRINT 'Adding the {{ mssql_ha_ag_name }}-listener listener to the \
7 | {{ mssql_ha_ag_name }} availability group';
8 | ALTER AVAILABILITY GROUP {{ mssql_ha_ag_name }}
9 | ADD LISTENER '{{ mssql_ha_ag_name }}-listener' (
10 | WITH IP ( ('{{ mssql_ha_virtual_ip }}','255.255.255.0') ),
11 | PORT = {{ mssql_tcp_port }}
12 | );
13 | PRINT 'Added the {{ mssql_ha_ag_name }}-listener listener successfully';
14 | END
15 | ELSE
16 | BEGIN
17 | DECLARE @ListenerName VARCHAR(30) = (
18 | SELECT dns_name FROM sys.availability_group_listeners
19 | );
20 | PRINT 'Verifying the existing listener ' + CAST(@ListenerName AS VARCHAR);
21 | IF NOT EXISTS (
22 | SELECT port
23 | FROM sys.availability_group_listeners
24 | WHERE port = '{{ mssql_tcp_port }}'
25 | )
26 | BEGIN
27 | PRINT 'Modifying the listener port setting'
28 | EXEC (
29 | 'ALTER AVAILABILITY GROUP {{ mssql_ha_ag_name }}
30 | MODIFY LISTENER "'+@ListenerName+'" (
31 | PORT = {{ mssql_tcp_port }}
32 | )'
33 | );
34 | PRINT 'Set listener port to {{ mssql_tcp_port }} successfully'
35 | END
36 | ELSE
37 | BEGIN
38 | PRINT 'The port setting is already set correctly, skipping'
39 | END
40 | IF NOT EXISTS (
41 | SELECT listener_id
42 | FROM sys.availability_group_listener_ip_addresses
43 | WHERE ip_address = '{{ mssql_ha_virtual_ip }}' AND
44 | ip_subnet_mask = '255.255.255.0'
45 | )
46 | BEGIN
47 | PRINT 'Modifying the listener ip address setting'
48 | EXEC (
49 | 'ALTER AVAILABILITY GROUP {{ mssql_ha_ag_name }}
50 | MODIFY LISTENER "'+@ListenerName+'" (
51 | ADD IP ("{{ mssql_ha_virtual_ip }}","255.255.255.0")
52 | )'
53 | );
54 | PRINT 'Added listener ip address \
55 | {{ mssql_ha_virtual_ip}},255.255.255.0 successfully'
56 | END
57 | ELSE
58 | BEGIN
59 | PRINT 'The listener ip address setting is already set correctly, skipping'
60 | END
61 | END
62 |
--------------------------------------------------------------------------------
/templates/create_and_back_up_cert.j2:
--------------------------------------------------------------------------------
1 | -- Enabling NOCOUNT to suppress (1 rows affected) messages from DECLARE
2 | -- keywords on the output
3 | SET NOCOUNT ON;
4 |
5 | DECLARE @cerExists INT;
6 | EXEC master.dbo.xp_fileexist '{{ __mssql_ha_cert_dest }}', @cerExists OUTPUT;
7 | DECLARE @pvkExists INT;
8 | EXEC master.dbo.xp_fileexist '{{ __mssql_ha_private_key_dest }}',
9 | @pvkExists OUTPUT;
10 |
11 | IF NOT EXISTS(
12 | SELECT name
13 | FROM sys.certificates
14 | WHERE name = '{{ mssql_ha_cert_name }}'
15 | )
16 | BEGIN
17 | PRINT 'Certificate {{ mssql_ha_cert_name }} does not exist, creating';
18 | IF (@cerExists = 1 AND @pvkExists = 1) OR (@cerExists != @pvkExists)
19 | BEGIN
20 | THROW 51000, 'Certificate {{ mssql_ha_cert_name }} does not exist in \
21 | SQL Server, however, {{ __mssql_ha_cert_dest }} \
22 | and/or {{ __mssql_ha_private_key_dest }} files do exist. \
23 | You must either remove the files, or run the role with \
24 | `mssql_ha_reset_cert: true` to regenerate certificates. Ensure to read \
25 | carefully what `mssql_ha_reset_cert: true` does in the README.md file of the \
26 | role beforehand', 1;
27 | END
28 | ELSE
29 | BEGIN
30 | CREATE CERTIFICATE {{ mssql_ha_cert_name }}
31 | WITH SUBJECT = 'Managed by microsoft.sql.server';
32 | PRINT 'Certificate {{ mssql_ha_cert_name }} created successfully';
33 | END
34 | END
35 | ELSE
36 | BEGIN
37 | PRINT 'Certificate {{ mssql_ha_cert_name }} already exists, skipping';
38 | END
39 |
40 | IF @cerExists = 1 AND @pvkExists = 1
41 | BEGIN
42 | PRINT '{{ __mssql_ha_cert_dest }} and \
43 | {{ __mssql_ha_private_key_dest }} already exist, skipping';
44 | END
45 | ELSE IF @cerExists = 0 AND @pvkExists = 0
46 | BEGIN
47 | PRINT 'Exporting a certificate and private key to \
48 | {{ __mssql_ha_cert_dest }} and \
49 | {{ __mssql_ha_private_key_dest }}';
50 | BACKUP CERTIFICATE {{ mssql_ha_cert_name }}
51 | TO FILE = '{{ __mssql_ha_cert_dest }}'
52 | WITH PRIVATE KEY (
53 | FILE = '{{ __mssql_ha_private_key_dest }}',
54 | ENCRYPTION BY PASSWORD = '{{ mssql_ha_private_key_password }}'
55 | );
56 | PRINT 'Certificate and private key files \
57 | {{ __mssql_ha_cert_dest }} and \
58 | {{ __mssql_ha_private_key_dest }} exported successfully';
59 | END
60 | ELSE IF @cerExists = 1 AND @pvkExists = 0
61 | BEGIN
62 | PRINT '{{ __mssql_ha_private_key_dest }} does not exist \
63 | while {{ __mssql_ha_cert_dest }} exists. You must \
64 | either remove the files, or run the role with `mssql_ha_reset_cert: true` to \
65 | regenerate certificates.';
66 | END
67 | ELSE IF @cerExists = 0 AND @pvkExists = 1
68 | BEGIN
69 | PRINT '{{ __mssql_ha_cert_dest }} does not exist \
70 | while {{ __mssql_ha_private_key_dest }} exists. You must \
71 | either remove the files, or run the role with `mssql_ha_reset_cert: true` to \
72 | regenerate certificates.';
73 | END
74 |
--------------------------------------------------------------------------------
/templates/create_ha_login.j2:
--------------------------------------------------------------------------------
1 | USE master;
2 | IF NOT EXISTS (
3 | SELECT name FROM sys.server_principals
4 | WHERE name = '{{ mssql_ha_login }}'
5 | )
6 | BEGIN
7 | PRINT 'A {{ mssql_ha_login }} login does not exist, creating';
8 | CREATE LOGIN {{ mssql_ha_login }}
9 | WITH PASSWORD = N'{{ mssql_ha_login_password }}';
10 | PRINT 'The {{ mssql_ha_login }} login created successfully';
11 | END
12 | ELSE
13 | BEGIN
14 | PRINT 'A {{ mssql_ha_login }} login already exists, skipping'
15 | END
16 |
17 | IF IS_SRVROLEMEMBER ('sysadmin','{{ mssql_ha_login }}') = 1
18 | BEGIN
19 | PRINT '{{ mssql_ha_login }} is a member of sysadmin role, skipping';
20 | END
21 | ELSE
22 | BEGIN
23 | PRINT 'Adding {{ mssql_ha_login }} to the sysadmin server role';
24 | ALTER SERVER ROLE sysadmin ADD MEMBER {{ mssql_ha_login }};
25 | PRINT '{{ mssql_ha_login }} added to the sysadmin server role successfully';
26 | END
27 |
--------------------------------------------------------------------------------
/templates/create_master_key_encryption.j2:
--------------------------------------------------------------------------------
1 | IF NOT EXISTS (
2 | SELECT name
3 | FROM sys.symmetric_keys
4 | WHERE name LIKE '%databaseMasterkey%'
5 | )
6 | BEGIN
7 | PRINT 'Master key does not exist, creating';
8 | CREATE MASTER KEY ENCRYPTION BY PASSWORD =
9 | '{{ mssql_ha_master_key_password }}';
10 | PRINT 'Master key created successfully';
11 | END
12 | ELSE
13 | BEGIN
14 | PRINT 'Master key already exists, verifying the provided password against \
15 | the existing master key';
16 | BEGIN TRY
17 | OPEN MASTER KEY DECRYPTION BY PASSWORD =
18 | '{{ mssql_ha_master_key_password }}';
19 | PRINT 'The provided master key password is correct';
20 | END TRY
21 | BEGIN CATCH
22 | {% if not mssql_ha_reset_cert %}
23 | PRINT 'You provided an incorrect master key password with the \
24 | mssql_ha_master_key_password variable';
25 | THROW;
26 | {% elif mssql_ha_reset_cert %}
27 | PRINT 'Master key password provided with the \
28 | mssql_ha_master_key_password variable does not match the existing password, \
29 | dropping master key to re-create it';
30 | DROP MASTER KEY;
31 | PRINT 'Master key dropped successfully';
32 | CREATE MASTER KEY ENCRYPTION BY PASSWORD =
33 | '{{ mssql_ha_master_key_password }}';
34 | PRINT 'Master key created successfully';
35 | {% endif %}
36 | END CATCH
37 | END
38 |
--------------------------------------------------------------------------------
/templates/drop_cert.j2:
--------------------------------------------------------------------------------
1 | IF EXISTS(
2 | SELECT name
3 | FROM sys.certificates
4 | WHERE name = '{{ mssql_ha_cert_name }}'
5 | )
6 | BEGIN
7 | PRINT 'Certificate {{ mssql_ha_cert_name }} already exists, checking if \
8 | there is an endopint associated with this certificate';
9 | DECLARE @EndpointName VARCHAR(30) = (
10 | SELECT endp.name as endpoint_name
11 | FROM sys.certificates cert
12 | JOIN sys.database_mirroring_endpoints endp
13 | ON cert.certificate_id = endp.certificate_id
14 | WHERE cert.name = '{{ mssql_ha_cert_name }}'
15 | );
16 | IF @EndpointName IS NOT NULL
17 | BEGIN
18 | PRINT 'Removing the endpoint ' + CAST(@EndpointName AS VARCHAR) +
19 | ' to re-create it';
20 | EXEC ('DROP ENDPOINT ' +@EndpointName);
21 | PRINT 'The {{ mssql_ha_endpoint_name }} endpoint removed successfully';
22 | END
23 | ELSE
24 | BEGIN
25 | PRINT 'There is no endpoint associated with this certificate, skipping';
26 | END
27 | PRINT 'Removing the {{ mssql_ha_cert_name }} certificate to re-create it';
28 | DROP CERTIFICATE {{ mssql_ha_cert_name }};
29 | PRINT 'The {{ mssql_ha_cert_name }} certificate removed successfully'
30 | END
31 |
--------------------------------------------------------------------------------
/templates/enable_alwayson.j2:
--------------------------------------------------------------------------------
1 | IF NOT EXISTS (
2 | SELECT name, startup_state
3 | FROM sys.server_event_sessions WHERE
4 | name = 'AlwaysOn_health' and
5 | startup_state = 1
6 | )
7 | BEGIN
8 | PRINT 'AlwaysOn Health events are not enabled, enabling';
9 | ALTER EVENT SESSION AlwaysOn_health ON SERVER WITH (STARTUP_STATE=ON);
10 | PRINT 'AlwaysOn Health events enabled successfully';
11 | END
12 | ELSE
13 | BEGIN
14 | PRINT 'AlwaysOn Health events already enabled, skipping';
15 | END
16 |
--------------------------------------------------------------------------------
/templates/get_ansible_managed.j2:
--------------------------------------------------------------------------------
1 | {{ ansible_managed | comment }}
2 | {{ "system_role:mssql" | comment(prefix="", postfix="") }}
3 |
--------------------------------------------------------------------------------
/templates/grant_permissions_to_ha_login.j2:
--------------------------------------------------------------------------------
1 | -- Need to find how to add permissions idempotently
2 | PRINT 'Granting the required permissions to {{ mssql_ha_login }}';
3 | GRANT ALTER, CONTROL, VIEW DEFINITION ON
4 | AVAILABILITY GROUP::{{ mssql_ha_ag_name }}
5 | TO {{ mssql_ha_login }};
6 | GRANT VIEW SERVER STATE TO {{ mssql_ha_login }};
7 | PRINT 'Required permissions granted to {{ mssql_ha_login }}';
8 |
--------------------------------------------------------------------------------
/templates/join_to_ag.j2:
--------------------------------------------------------------------------------
1 | IF EXISTS (
2 | SELECT name
3 | FROM sys.availability_groups
4 | WHERE name = '{{ mssql_ha_ag_name }}'
5 | )
6 | AND NOT EXISTS (
7 | SELECT ag.name, replica.replica_server_name, replica.availability_mode_desc
8 | FROM sys.availability_groups ag
9 | JOIN sys.availability_replicas replica
10 | ON ag.group_id = replica.group_id
11 | WHERE ag.name = '{{ mssql_ha_ag_name }}' AND
12 | ag.cluster_type_desc = '{{ mssql_ha_ag_cluster_type }}' AND
13 | replica.replica_server_name = '{{ ansible_hostname }}' AND
14 | replica.availability_mode_desc = '{{ __mssql_ha_availability_mode }}'
15 | )
16 | BEGIN
17 | PRINT 'The existing availability group {{ mssql_ha_ag_name }} has \
18 | incorrect availability mode set for the {{ ansible_hostname }} replica, \
19 | removing this availability group to re-create it'
20 | DROP AVAILABILITY GROUP {{ mssql_ha_ag_name }};
21 | PRINT 'The availability group {{ mssql_ha_ag_name }} removed successfully'
22 | END
23 | ELSE IF EXISTS (
24 | SELECT name
25 | FROM sys.availability_groups
26 | WHERE name = '{{ mssql_ha_ag_name }}'
27 | )
28 | AND EXISTS (
29 | SELECT ag.name, replica.replica_server_name, replica.availability_mode_desc
30 | FROM sys.availability_groups ag
31 | JOIN sys.availability_replicas replica
32 | ON ag.group_id = replica.group_id
33 | WHERE ag.name = '{{ mssql_ha_ag_name }}' AND
34 | replica.replica_server_name = '{{ ansible_hostname }}' AND
35 | replica.availability_mode_desc = '{{ __mssql_ha_availability_mode }}'
36 | )
37 | BEGIN
38 | PRINT 'Already joined to the {{ mssql_ha_ag_name }} availability group, \
39 | skipping'
40 | END
41 |
42 | IF NOT EXISTS(
43 | SELECT name
44 | FROM sys.availability_groups
45 | WHERE name = '{{ mssql_ha_ag_name }}'
46 | )
47 | BEGIN
48 | PRINT 'Joining to the {{ mssql_ha_ag_name }} availability group';
49 | ALTER AVAILABILITY GROUP {{ mssql_ha_ag_name }}
50 | JOIN WITH (CLUSTER_TYPE = {{ mssql_ha_ag_cluster_type }});
51 | PRINT 'Joined to the {{ mssql_ha_ag_name }} availability group successfully';
52 | END
53 |
54 | {% if mssql_ha_replica_type in ['synchronous', 'asynchronous'] %}
55 | -- It is not possible to grant permissions fully idempotently
56 | ALTER AVAILABILITY GROUP {{ mssql_ha_ag_name }} GRANT CREATE ANY DATABASE;
57 | PRINT 'Granted the CREATE ANY DATABASE permission to the \
58 | {{ mssql_ha_ag_name }} availability group';
59 | {% endif %}
60 |
--------------------------------------------------------------------------------
/templates/replicate_db.j2:
--------------------------------------------------------------------------------
1 | {% if mssql_ha_db_names | length > 0 %}
2 | {% for item in mssql_ha_db_names %}
3 | {% set db_backup_path = "/var/opt/mssql/data/" + item %}
4 | IF NOT EXISTS (
5 | SELECT name, recovery_model_desc
6 | FROM sys.databases
7 | WHERE name = '{{ item }}' AND
8 | recovery_model_desc = 'FULL'
9 | )
10 | BEGIN
11 | PRINT 'Setting RECOVERY FULL on the {{ item }} database';
12 | ALTER DATABASE {{ item }} SET RECOVERY FULL;
13 | PRINT 'RECOVERY FULL on the {{ item }} database set successfully';
14 | END
15 | ELSE
16 | BEGIN
17 | PRINT 'RECOVERY FULL on the {{ item }} database is set, skipping';
18 | END
19 |
20 | IF NOT EXISTS (
21 | SELECT [database_name], backup_start_date, backup_finish_date, [type]
22 | FROM msdb.dbo.backupset
23 | WHERE [type]='D' AND
24 | [database_name]='{{ item }}' AND
25 | backup_finish_date >= DATEADD(hh, -3, GETDATE())
26 | )
27 | BEGIN
28 | PRINT 'Backing up the {{ item }} database to \
29 | {{ db_backup_path }}';
30 | BACKUP DATABASE {{ item }}
31 | TO DISK = N'{{ db_backup_path }}';
32 | PRINT 'The {{ item }} database backed up successfully';
33 | END
34 | ELSE
35 | BEGIN
36 | PRINT 'The {{ item }} database is already backed up, skipping';
37 | END
38 |
39 | IF NOT EXISTS (
40 | SELECT
41 | AG.name AS [AvailabilityGroupName],
42 | ISNULL(agstates.primary_replica, '') AS [PrimaryReplicaServerName],
43 | dbcs.database_name AS [DatabaseName],
44 | ISNULL(dbrs.synchronization_state, 0) AS [SynchronizationState],
45 | ISNULL(dbrs.is_suspended, 0) AS [IsSuspended],
46 | ISNULL(dbcs.is_database_joined, 0) AS [IsJoined]
47 | FROM master.sys.availability_groups AS AG
48 | LEFT OUTER JOIN master.sys.dm_hadr_availability_group_states as agstates
49 | ON AG.group_id = agstates.group_id
50 | INNER JOIN master.sys.availability_replicas AS AR
51 | ON AG.group_id = AR.group_id
52 | INNER JOIN master.sys.dm_hadr_availability_replica_states AS arstates
53 | ON AR.replica_id = arstates.replica_id AND arstates.is_local = 1
54 | INNER JOIN master.sys.dm_hadr_database_replica_cluster_states AS dbcs
55 | ON arstates.replica_id = dbcs.replica_id
56 | LEFT OUTER JOIN master.sys.dm_hadr_database_replica_states AS dbrs
57 | ON dbcs.replica_id = dbrs.replica_id
58 | AND dbcs.group_database_id = dbrs.group_database_id
59 | WHERE dbcs.database_name = '{{ item }}'
60 | )
61 | BEGIN
62 | PRINT 'Adding the {{ item }} database to the \
63 | {{ mssql_ha_ag_name }} availability group';
64 | ALTER AVAILABILITY GROUP {{ mssql_ha_ag_name }}
65 | ADD DATABASE {{ item }};
66 | PRINT 'The {{ item }} database added to the \
67 | {{ mssql_ha_ag_name }} availability group successfully';
68 | END
69 | ELSE
70 | BEGIN
71 | PRINT 'The {{ item }} database is already added to the \
72 | {{ mssql_ha_ag_name }} availability group, skipping';
73 | END
74 | {% endfor %}
75 | {% endif %}
76 |
--------------------------------------------------------------------------------
/templates/restore_cert.j2:
--------------------------------------------------------------------------------
1 | IF NOT EXISTS(
2 | SELECT name
3 | FROM sys.certificates
4 | WHERE name = '{{ mssql_ha_cert_name }}'
5 | )
6 | BEGIN
7 | PRINT 'Certificate {{ mssql_ha_cert_name }} does not exist, creating';
8 | CREATE CERTIFICATE {{ mssql_ha_cert_name }}
9 | FROM FILE = '{{ __mssql_ha_cert_dest }}'
10 | WITH PRIVATE KEY (
11 | FILE = '{{ __mssql_ha_private_key_dest }}',
12 | DECRYPTION BY PASSWORD = '{{ mssql_ha_private_key_password }}'
13 | );
14 | PRINT 'Certificate {{ mssql_ha_cert_name }} created successfully';
15 | END
16 | ELSE
17 | BEGIN
18 | PRINT 'Certificate {{ mssql_ha_cert_name }} already exists, skipping';
19 | END
20 |
--------------------------------------------------------------------------------
/tests/.fmf/version:
--------------------------------------------------------------------------------
1 | 1
2 |
--------------------------------------------------------------------------------
/tests/collection-requirements.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | collections:
4 | - name: ansible.windows
5 | - name: fedora.linux_system_roles
6 |
--------------------------------------------------------------------------------
/tests/files/create_ExampleDB1.sql:
--------------------------------------------------------------------------------
1 | IF NOT EXISTS(
2 | SELECT name
3 | FROM sys.databases
4 | WHERE name = 'ExampleDB1'
5 | )
6 | BEGIN
7 | PRINT 'Creating the ExampleDB1 database';
8 | CREATE DATABASE ExampleDB1;
9 | PRINT 'The ExampleDB1 database created successfully';
10 | END
11 | ELSE
12 | BEGIN
13 | PRINT 'The ExampleDB1 database already exists, skipping';
14 | END
15 | GO
16 |
17 | USE ExampleDB1;
18 | GO
19 |
20 | IF NOT EXISTS (
21 | SELECT name, xtype
22 | FROM sysobjects
23 | WHERE name='Inventory' and xtype='U'
24 | )
25 | BEGIN
26 | PRINT 'Adding the Inventory table to the ExampleDB1 database';
27 | CREATE TABLE Inventory (id INT, name NVARCHAR(50), quantity INT);
28 | INSERT INTO Inventory VALUES (1, 'apple', 100);
29 | INSERT INTO Inventory VALUES (2, 'orange', 150);
30 | INSERT INTO Inventory VALUES (3, 'banana', 154);
31 | INSERT INTO Inventory VALUES (4, N'バナナ', 170);
32 | PRINT 'The Inventory table created successfully';
33 | END
34 | ELSE
35 | BEGIN
36 | PRINT 'The Inventory table already exists, skipping';
37 | END
38 | GO
39 |
--------------------------------------------------------------------------------
/tests/files/create_ExampleDB2.sql:
--------------------------------------------------------------------------------
1 | IF NOT EXISTS(
2 | SELECT name
3 | FROM sys.databases
4 | WHERE name = 'ExampleDB2'
5 | )
6 | BEGIN
7 | PRINT 'Creating the ExampleDB2 database';
8 | CREATE DATABASE ExampleDB2;
9 | PRINT 'The ExampleDB2 database created successfully';
10 | END
11 | ELSE
12 | BEGIN
13 | PRINT 'The ExampleDB2 database already exists, skipping';
14 | END
15 | GO
16 |
17 | USE ExampleDB2;
18 | GO
19 |
20 | IF NOT EXISTS (
21 | SELECT name, xtype
22 | FROM sysobjects
23 | WHERE name='Inventory' and xtype='U'
24 | )
25 | BEGIN
26 | PRINT 'Adding the Inventory table to the ExampleDB2 database';
27 | CREATE TABLE Inventory (id INT, name NVARCHAR(50), quantity INT);
28 | INSERT INTO Inventory VALUES (1, 'pineapple', 100);
29 | INSERT INTO Inventory VALUES (2, 'grapefruit', 150);
30 | INSERT INTO Inventory VALUES (3, 'cucumber', 154);
31 | INSERT INTO Inventory VALUES (4, N'バナナ', 170);
32 | PRINT 'The Inventory table created successfully';
33 | END
34 | ELSE
35 | BEGIN
36 | PRINT 'The Inventory table already exists, skipping';
37 | END
38 | GO
39 |
--------------------------------------------------------------------------------
/tests/files/sql_script.sql:
--------------------------------------------------------------------------------
1 | IF NOT EXISTS (
2 | SELECT name
3 | FROM master.sys.server_principals
4 | WHERE name = 'MyLogin'
5 | )
6 | BEGIN
7 | PRINT 'Creating the MyLogin login';
8 | CREATE LOGIN MyLogin WITH PASSWORD = 'p@55w0rD'
9 | PRINT 'The MyLogin login created successfully';
10 | END
11 | ELSE
12 | BEGIN
13 | PRINT 'The MyLogin login already exists, skipping';
14 | END
15 |
16 | IF NOT EXISTS (
17 | SELECT name
18 | FROM sys.database_principals
19 | WHERE name = 'MyUser')
20 | BEGIN
21 | PRINT 'Creating the MyUser user';
22 | CREATE USER MyUser FOR LOGIN MyLogin
23 | PRINT 'The MyUser user created successfully';
24 | END
25 | ELSE
26 | BEGIN
27 | PRINT 'The MyUser user already exists, skipping';
28 | END
29 |
30 | IF NOT EXISTS(
31 | SELECT name
32 | FROM sys.databases
33 | WHERE name = 'ExampleDB'
34 | )
35 | BEGIN
36 | PRINT 'Creating the ExampleDB database';
37 | CREATE DATABASE ExampleDB;
38 | PRINT 'The ExampleDB database created successfully';
39 | END
40 | ELSE
41 | BEGIN
42 | PRINT 'The ExampleDB database already exists, skipping';
43 | END
44 | GO
45 |
46 | USE ExampleDB;
47 | GO
48 |
49 | IF NOT EXISTS (
50 | SELECT name, xtype
51 | FROM sysobjects
52 | WHERE name='Inventory' and xtype='U'
53 | )
54 | BEGIN
55 | PRINT 'Adding the Inventory table to the ExampleDB database';
56 | CREATE TABLE Inventory (id INT, name NVARCHAR(50), quantity INT);
57 | INSERT INTO Inventory VALUES (1, 'apple', 100);
58 | INSERT INTO Inventory VALUES (2, 'orange', 150);
59 | INSERT INTO Inventory VALUES (3, 'banana', 154);
60 | INSERT INTO Inventory VALUES (4, N'バナナ', 170);
61 | PRINT 'The Inventory table created successfully';
62 | END
63 | ELSE
64 | BEGIN
65 | PRINT 'The Inventory table already exists, skipping';
66 | END
67 | GO
--------------------------------------------------------------------------------
/tests/files/verify_fts.sql:
--------------------------------------------------------------------------------
1 | SELECT
2 | CASE FULLTEXTSERVICEPROPERTY('IsFullTextInstalled')
3 | WHEN 1 THEN 'Full-Text Search is enabled'
4 | ELSE 'Full-Text Search is not enabled'
5 | END
6 | ;
--------------------------------------------------------------------------------
/tests/no-vault-variables.txt:
--------------------------------------------------------------------------------
1 | tests_configure_ha_cluster.yml
2 | tests_idempotency_2017.yml
3 | tests_idempotency_2019.yml
4 | tests_idempotency_2022.yml
5 | tests_input_sql_file_2017.yml
6 | tests_input_sql_file_2019.yml
7 | tests_input_sql_file_2022.yml
8 | tests_password_2017.yml
9 | tests_password_2019.yml
10 | tests_password_2022.yml
11 |
--------------------------------------------------------------------------------
/tests/playbooks/tests_ad_integration.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | # To run this test, AD server must be configured and it's properties
4 | # provided with the following variables:
5 | # ad_integration_realm
6 | # ad_integration_user
7 | # ad_integration_password
8 | # Inventory must contain the client Linux node and the ad AD Server node like:
9 | # all:
10 | # hosts:
11 | # client:
12 | # ansible_connection: local
13 | # ansible_host: 127.0.0.1
14 | # ad:
15 | # ansible_host: 10.192.1.1
16 | # ad_fqdn: ad1.domain.com
17 | # ansible_connection: winrm
18 | # ansible_password: Secret123
19 | # ansible_port: 5986
20 | # ansible_user: Administrator
21 | # ansible_winrm_server_cert_validation: ignore
22 | - name: Test integration with AD server
23 | hosts: client
24 | vars:
25 | mssql_accept_microsoft_odbc_driver_for_sql_server_eula: true
26 | mssql_accept_microsoft_cli_utilities_for_sql_server_eula: true
27 | mssql_accept_microsoft_sql_server_standard_eula: true
28 | mssql_version: 2022
29 | mssql_password: "p@55w0rD"
30 | mssql_edition: Evaluation
31 | mssql_manage_firewall: true
32 | mssql_debug: true
33 | mssql_ad_configure: true
34 | mssql_ad_sql_user: sqluser
35 | mssql_ad_sql_password: "p@55w0rD1"
36 | ad_integration_realm: domain.com
37 | ad_integration_user: Administrator
38 | ad_integration_password: Secret123
39 | ad_integration_manage_dns: true
40 | ad_integration_dns_server: 1.1.1.1
41 | ad_integration_dns_connection_name: eth0
42 | ad_integration_dns_connection_type: ethernet
43 | # ad_integration_realm is randomized in IDM CI hence need to use variables
44 | # Cannot use variable for Administrator because test with
45 | # mssql_ad_join: false does ad_integration_user: null
46 | __mssql_ad_login: >-
47 | {{ ad_integration_realm.split('.') | first + '\Administrator' }}
48 | mssql_post_input_sql_content: |-
49 | USE master;
50 | IF NOT EXISTS (
51 | SELECT name FROM sys.server_principals
52 | WHERE name = '{{ __mssql_ad_login }}'
53 | )
54 | BEGIN
55 | PRINT 'A {{ __mssql_ad_login }} login does not exist, creating';
56 | CREATE LOGIN [{{ __mssql_ad_login }}] FROM WINDOWS;
57 | PRINT 'The {{ __mssql_ad_login }} login created successfully';
58 | END
59 | ELSE
60 | BEGIN
61 | PRINT 'A {{ __mssql_ad_login }} login already exists, skipping'
62 | END
63 |
64 | tasks:
65 | # Test general scenario
66 | - name: Set up MSSQL and configure AD authentication
67 | include_role:
68 | name: linux-system-roles.mssql
69 |
70 | - name: Test AD integration
71 | include_tasks: ../tasks/verify_ad_auth.yml
72 |
73 | # Test with mssql_ad_keytab_file
74 | - name: Fetch keytab file that was prepared above
75 | fetch:
76 | src: /var/opt/mssql/secrets/mssql.keytab
77 | dest: /tmp/mssql.keytab
78 | flat: true
79 | mode: preserve
80 | run_once: true
81 |
82 | - name: Clean up after the role invocation
83 | include_tasks: ../tasks/cleanup.yml
84 |
--------------------------------------------------------------------------------
/tests/playbooks/tests_ad_integration_join_false.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | # To run this test, AD server must be configured and it's properties
4 | # provided with the following variables:
5 | # ad_integration_realm
6 | # ad_integration_user
7 | # ad_integration_password
8 | # Inventory must contain the client Linux node and the ad AD Server node like:
9 | # all:
10 | # hosts:
11 | # client:
12 | # ansible_connection: local
13 | # ansible_host: 127.0.0.1
14 | # ad:
15 | # ansible_host: 10.192.1.1
16 | # ad_fqdn: ad1.domain.com
17 | # ansible_connection: winrm
18 | # ansible_password: Secret123
19 | # ansible_port: 5986
20 | # ansible_user: Administrator
21 | # ansible_winrm_server_cert_validation: ignore
22 | - name: Test integration with AD server
23 | hosts: client
24 | vars:
25 | mssql_accept_microsoft_odbc_driver_for_sql_server_eula: true
26 | mssql_accept_microsoft_cli_utilities_for_sql_server_eula: true
27 | mssql_accept_microsoft_sql_server_standard_eula: true
28 | mssql_version: 2022
29 | mssql_password: "p@55w0rD"
30 | mssql_edition: Evaluation
31 | mssql_manage_firewall: true
32 | mssql_debug: true
33 | mssql_ad_configure: true
34 | mssql_ad_sql_user: sqluser
35 | mssql_ad_sql_password: "p@55w0rD1"
36 | ad_integration_realm: domain.com
37 | ad_integration_user: Administrator
38 | ad_integration_password: Secret123
39 | ad_integration_manage_dns: true
40 | ad_integration_dns_server: 1.1.1.1
41 | ad_integration_dns_connection_name: eth0
42 | ad_integration_dns_connection_type: ethernet
43 | # ad_integration_realm is randomized in IDM CI hence need to use variables
44 | # Cannot use variable for Administrator because test with
45 | # mssql_ad_join: false does ad_integration_user: null
46 | __mssql_ad_login: >-
47 | {{ ad_integration_realm.split('.') | first + '\Administrator' }}
48 | mssql_post_input_sql_content: |-
49 | USE master;
50 | IF NOT EXISTS (
51 | SELECT name FROM sys.server_principals
52 | WHERE name = '{{ __mssql_ad_login }}'
53 | )
54 | BEGIN
55 | PRINT 'A {{ __mssql_ad_login }} login does not exist, creating';
56 | CREATE LOGIN [{{ __mssql_ad_login }}] FROM WINDOWS;
57 | PRINT 'The {{ __mssql_ad_login }} login created successfully';
58 | END
59 | ELSE
60 | BEGIN
61 | PRINT 'A {{ __mssql_ad_login }} login already exists, skipping'
62 | END
63 |
64 | tasks:
65 | # Test with mssql_ad_join: false
66 | - name: Authenticate to AD
67 | include_role:
68 | name: linux-system-roles.ad_integration
69 |
70 | - name: Set up MSSQL and configure AD authentication without joining to AD
71 | include_role:
72 | name: linux-system-roles.mssql
73 | vars:
74 | mssql_ad_join: false
75 | # Explicitly set kerberos vars, otherwise the value becomes null
76 | mssql_ad_kerberos_user: Administrator
77 | mssql_ad_kerberos_password: Secret123
78 | ad_integration_user: null
79 | ad_integration_password: null
80 | ad_integration_manage_dns: null
81 | ad_integration_dns_server: null
82 | ad_integration_dns_connection_name: null
83 | ad_integration_dns_connection_type: null
84 |
85 | - name: Test AD integration
86 | include_tasks: ../tasks/verify_ad_auth.yml
87 |
--------------------------------------------------------------------------------
/tests/playbooks/tests_ad_integration_w_keytab.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | # To run this test, AD server must be configured and it's properties
4 | # provided with the following variables:
5 | # ad_integration_realm
6 | # ad_integration_user
7 | # ad_integration_password
8 | # Inventory must contain the client Linux node and the ad AD Server node like:
9 | # all:
10 | # hosts:
11 | # client:
12 | # ansible_connection: local
13 | # ansible_host: 127.0.0.1
14 | # ad:
15 | # ansible_host: 10.192.1.1
16 | # ad_fqdn: ad1.domain.com
17 | # ansible_connection: winrm
18 | # ansible_password: Secret123
19 | # ansible_port: 5986
20 | # ansible_user: Administrator
21 | # ansible_winrm_server_cert_validation: ignore
22 | - name: Test integration with AD server
23 | hosts: client
24 | vars:
25 | mssql_accept_microsoft_odbc_driver_for_sql_server_eula: true
26 | mssql_accept_microsoft_cli_utilities_for_sql_server_eula: true
27 | mssql_accept_microsoft_sql_server_standard_eula: true
28 | mssql_version: 2022
29 | mssql_password: "p@55w0rD"
30 | mssql_edition: Evaluation
31 | mssql_manage_firewall: true
32 | mssql_debug: true
33 | mssql_ad_configure: true
34 | mssql_ad_sql_user: sqluser
35 | mssql_ad_sql_password: "p@55w0rD1"
36 | ad_integration_realm: domain.com
37 | ad_integration_user: Administrator
38 | ad_integration_password: Secret123
39 | ad_integration_manage_dns: true
40 | ad_integration_dns_server: 1.1.1.1
41 | ad_integration_dns_connection_name: eth0
42 | ad_integration_dns_connection_type: ethernet
43 | # ad_integration_realm is randomized in IDM CI hence need to use variables
44 | # Cannot use variable for Administrator because test with
45 | # mssql_ad_join: false does ad_integration_user: null
46 | __mssql_ad_login: >-
47 | {{ ad_integration_realm.split('.') | first + '\Administrator' }}
48 | mssql_post_input_sql_content: |-
49 | USE master;
50 | IF NOT EXISTS (
51 | SELECT name FROM sys.server_principals
52 | WHERE name = '{{ __mssql_ad_login }}'
53 | )
54 | BEGIN
55 | PRINT 'A {{ __mssql_ad_login }} login does not exist, creating';
56 | CREATE LOGIN [{{ __mssql_ad_login }}] FROM WINDOWS;
57 | PRINT 'The {{ __mssql_ad_login }} login created successfully';
58 | END
59 | ELSE
60 | BEGIN
61 | PRINT 'A {{ __mssql_ad_login }} login already exists, skipping'
62 | END
63 |
64 | tasks:
65 | - name: Set up MSSQL and configure AD authentication with keytab
66 | vars:
67 | # /tmp/mssql.keytab is created in tests_ad_integration.yml
68 | mssql_ad_keytab_file: /tmp/mssql.keytab
69 | mssql_ad_keytab_remote_src: false
70 | mssql_ad_sql_password: null
71 | include_role:
72 | name: linux-system-roles.mssql
73 |
74 | - name: Test AD integration
75 | include_tasks: ../tasks/verify_ad_auth.yml
76 |
77 | - name: Clean up after the role invocation
78 | include_tasks: ../tasks/cleanup.yml
79 |
--------------------------------------------------------------------------------
/tests/provision.fmf:
--------------------------------------------------------------------------------
1 | standard-inventory-qcow2:
2 | qemu:
3 | m: 4096
4 |
--------------------------------------------------------------------------------
/tests/requirements.txt:
--------------------------------------------------------------------------------
1 | # Python requirements for tests
2 | # Requirement for playbooks/tests_ad_integration.yml
3 | pywinrm==0.4.3
4 |
--------------------------------------------------------------------------------
/tests/roles/caller/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # tasks file for caller
3 |
4 | - name: Include role
5 | include_role:
6 | name: "{{ roletoinclude }}"
7 |
8 | - name: Test variable override
9 | assert:
10 | that: not __caller_override
11 |
--------------------------------------------------------------------------------
/tests/roles/caller/vars/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # vars file for caller
3 | __caller_override: false
4 |
--------------------------------------------------------------------------------
/tests/roles/linux-system-roles.mssql/defaults:
--------------------------------------------------------------------------------
1 | ../../../defaults
--------------------------------------------------------------------------------
/tests/roles/linux-system-roles.mssql/files:
--------------------------------------------------------------------------------
1 | ../../../files
--------------------------------------------------------------------------------
/tests/roles/linux-system-roles.mssql/handlers:
--------------------------------------------------------------------------------
1 | ../../../handlers
--------------------------------------------------------------------------------
/tests/roles/linux-system-roles.mssql/meta:
--------------------------------------------------------------------------------
1 | ../../../meta
--------------------------------------------------------------------------------
/tests/roles/linux-system-roles.mssql/tasks:
--------------------------------------------------------------------------------
1 | ../../../tasks
--------------------------------------------------------------------------------
/tests/roles/linux-system-roles.mssql/templates:
--------------------------------------------------------------------------------
1 | ../../../templates
--------------------------------------------------------------------------------
/tests/roles/linux-system-roles.mssql/vars:
--------------------------------------------------------------------------------
1 | ../../../vars
--------------------------------------------------------------------------------
/tests/setup-snapshot.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Setup snapshot
3 | hosts: all
4 | tasks:
5 | - name: Set facts used by role
6 | include_role:
7 | name: linux-system-roles.mssql
8 | tasks_from: set_vars.yml
9 | public: true
10 |
11 | - name: Deploy the GPG key for Microsoft repositories
12 | rpm_key:
13 | key: "{{ mssql_rpm_key }}"
14 | state: present
15 |
16 | # The tools repo is required for powershell
17 | - name: Configure the Microsoft SQL Server Tools repository
18 | yum_repository:
19 | name: packages-microsoft-com-prod
20 | description: Microsoft SQL Server Tools
21 | baseurl: "{{ mssql_client_repository }}"
22 | gpgcheck: true
23 |
24 | - name: Cache packages required for tests
25 | vars:
26 | __mssql_packages:
27 | - "{{ __mssql_server_packages }}"
28 | - "{{ __mssql_server_fts_packages }}"
29 | - "{{ __mssql_server_ha_packages }}"
30 | - "{{ __mssql_powershell_packages }}"
31 | mssql_version: "{{ item }}"
32 | include_tasks: tasks/snapshot_install_packages.yml
33 | loop: "{{ __mssql_supported_versions }}"
34 |
35 | - name: Remove the Microsoft SQL Server Tools repository
36 | yum_repository:
37 | name: packages-microsoft-com-prod
38 | state: absent
39 |
--------------------------------------------------------------------------------
/tests/tasks/assert_fail_on_unsupported_ver.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Ensure ansible_facts to get ansible_distribution
3 | setup:
4 | gather_subset: min
5 |
6 | - name: Assert fail on EL 7 with version = 2022 and EL 9 with version != 2022
7 | when: >-
8 | (ansible_distribution in ['CentOS', 'RedHat'] and
9 | ansible_distribution_major_version is version('7', '=') and
10 | mssql_version | int == 2022) or
11 | (((ansible_distribution in ['CentOS', 'RedHat'] and
12 | ansible_distribution_major_version is version('9', '=')) or
13 | (ansible_distribution in ['Fedora']))
14 | and
15 | mssql_version | int != 2022)
16 | block:
17 | - name: Run the role
18 | vars:
19 | mssql_password: "p@55w0rD"
20 | mssql_edition: Evaluation
21 | include_role:
22 | name: linux-system-roles.mssql
23 |
24 | - name: Unreachable task
25 | fail:
26 | msg: The above task must fail
27 | rescue:
28 | - name: Assert that the role failed with EL < 8 not supported
29 | assert:
30 | that: >-
31 | 'You must set the mssql_version variable to one of'
32 | in ansible_failed_result.msg
33 |
34 | - name: Clean up after the role invocation
35 | include_tasks: tasks/cleanup.yml
36 |
37 | # Putting end_host into a rescue block results in a failed task
38 | - name: End unsupported host
39 | meta: end_host
40 |
--------------------------------------------------------------------------------
/tests/tasks/check_header.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | # Find two words in ansible_managed and grep for them in the config file
4 | - name: Grep the ansible_managed header in {{ __mssql_conf_path }}
5 | vars:
6 | __mssql_conf_path: /var/opt/mssql/mssql.conf
7 | command: >-
8 | grep
9 | {{ lookup('template', 'get_ansible_managed.j2') |
10 | regex_search('(\b\w+\s){2}') | quote }}
11 | {{ __mssql_conf_path }}
12 | changed_when: false
13 |
--------------------------------------------------------------------------------
/tests/tasks/cleanup.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Gather package facts
3 | package_facts:
4 | no_log: true
5 |
6 | - name: Set role variables needed for cleanup
7 | include_role:
8 | name: linux-system-roles.mssql
9 | tasks_from: set_vars.yml
10 | public: true
11 |
12 | - name: Purge cluster configuration
13 | vars:
14 | ha_cluster_cluster_present: false
15 | ha_cluster_enable_repos: false
16 | include_role:
17 | name: fedora.linux_system_roles.ha_cluster
18 | when: ansible_facts.packages.pcs is defined
19 |
20 | - name: Debug ansible_python_version
21 | debug:
22 | var: ansible_python_version
23 |
24 | - name: Purge firewall configuration
25 | vars:
26 | firewall:
27 | - previous: replaced
28 | include_role:
29 | name: fedora.linux_system_roles.firewall
30 | when: ansible_facts.packages.firewalld is defined
31 |
32 | - name: Purge selinux configuration
33 | vars:
34 | selinux_all_purge: true
35 | include_role:
36 | name: fedora.linux_system_roles.selinux
37 | when: mssql_manage_selinux | d(false) | bool
38 |
39 | - name: Leave realm
40 | command: realm leave
41 | register: realm_leave
42 | failed_when: false
43 | changed_when: >-
44 | not "Couldn't find a configured realm" in realm_leave.stderr
45 | when: ansible_facts.packages.realmd is defined
46 |
47 | - name: Destroy Kerberos tickets # noqa no-changed-when
48 | command: kdestroy -A
49 | when: ansible_facts.packages["krb5-workstation"] is defined
50 |
51 | - name: Remove related packages
52 | package:
53 | name:
54 | - adutil
55 | - mssql-server*
56 | - mssql-tools*
57 | - unixODBC-devel
58 | - mssql-server-fts
59 | - mssql-server-ha
60 | - powershell
61 | state: absent
62 | autoremove: true
63 |
64 | - name: Remove related files
65 | shell: >-
66 | rm -rfv /var/opt/mssql*
67 | /opt/mssql*
68 | /var/log/pacemaker/pacemaker.log
69 | /etc/yum.repos.d/packages-microsoft-com-*
70 | /tmp/*.j2
71 | /tmp/mssql_data
72 | /tmp/mssql_log
73 | /etc/systemd/system/mssql-server.service.d
74 | /etc/systemd/system/multi-user.target.wants/mssql-server.service
75 | register: __mssql_cleanup_remove
76 | changed_when: "'removed' in __mssql_cleanup_remove.stdout"
77 |
78 | # On SQL Server 2017, 2019 the service remains after removing RPMs
79 | - name: Stop the mssql-server service # noqa command-instead-of-module
80 | shell: systemctl stop mssql-server || true
81 | changed_when: false
82 | when: __mssql_is_booted | bool
83 |
84 | - name: Get SELinux policy modules
85 | command: semodule -l
86 | changed_when: false
87 | register: __mssql_policy_loaded
88 |
89 | # not installed in Fedora by default
90 | - name: Ensure that semanage command is available
91 | package:
92 | name: policycoreutils-python-utils
93 | state: present
94 | when: "'mssql' in __mssql_policy_loaded.stdout_lines"
95 |
96 | # removing the mssql-server-selinux package fails to actually remove the
97 | # policy (and ignores the failure)
98 | - name: Hack around broken mssql SELinux profile and actually remove it
99 | shell: |-
100 | set -eux
101 | semanage fcontext -D
102 | semanage port -D
103 | semodule --priority=200 -r mssql
104 | changed_when: true
105 | when: "'mssql' in __mssql_policy_loaded.stdout_lines"
106 |
107 | - name: Check for leftover mssql processes
108 | command: pgrep -au mssql
109 | register: __mssql_processes
110 | changed_when: false
111 | # 0: found, 1: no processes, 2: user mssql does not exist
112 | failed_when: not __mssql_processes.rc in [0, 1, 2]
113 |
114 | - name: Kill leftover mssql processes
115 | command: pkill --signal KILL -e -u mssql
116 | changed_when: true
117 | when: __mssql_processes.rc == 0
118 |
119 | - name: Remove system user
120 | user:
121 | name: mssql
122 | state: absent
123 | remove: true
124 |
--------------------------------------------------------------------------------
/tests/tasks/mssql-sever-increase-start-limit.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Create service drop-in directory
4 | file:
5 | path: /etc/systemd/system/mssql-server.service.d
6 | state: directory
7 | owner: root
8 | group: root
9 | mode: "0755"
10 |
11 | - name: Modify the mssql-server service start limit interval and burst
12 | copy:
13 | dest: /etc/systemd/system/mssql-server.service.d/startlimit.conf
14 | content: |
15 | [Service]
16 | StartLimitInterval=0
17 | StartLimitBurst=0
18 | owner: root
19 | group: root
20 | mode: "0644"
21 | register: __mssql_modify_limit
22 |
23 | - name: Reload service daemon
24 | systemd: # noqa no-handler
25 | daemon_reload: true
26 | when:
27 | - __mssql_modify_limit is changed
28 | - __mssql_is_booted | d(true)
29 |
--------------------------------------------------------------------------------
/tests/tasks/mssql_conf_verify.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | # This tasks file verifies the value of a mssql-conf setting.
4 | # It takes two variables:
5 | # __mssql_conf_setting - the setting name
6 | # __mssql_conf_value - the setting value
7 | - name: Get the value of the setting {{ __mssql_conf_setting }}
8 | vars:
9 | __mssql_conf_path: /var/opt/mssql/mssql.conf
10 | shell: grep '^{{ __mssql_conf_setting }}' {{ __mssql_conf_path }} || true
11 | changed_when: false
12 | register: __mssql_conf_get_setting
13 |
14 | - name: Verify the setting when it is type str {{ __mssql_conf_setting }}
15 | vars:
16 | __mssql_conf_get_value: >-
17 | {{ __mssql_conf_get_setting.stdout |
18 | regex_replace('^.*\s=\s', '') | string }}
19 | assert:
20 | that: __mssql_conf_get_value == __mssql_conf_value | string
21 | when:
22 | - __mssql_conf_value | type_debug != 'bool'
23 | - __mssql_conf_setting != "tcpport"
24 |
25 | - name: Verify the setting when it is type bool {{ __mssql_conf_setting }}
26 | vars:
27 | __mssql_conf_get_value: >-
28 | {{ __mssql_conf_get_setting.stdout |
29 | regex_replace('^.*\s=\s', '') | bool }}
30 | assert:
31 | that: __mssql_conf_get_value == __mssql_conf_value
32 | when:
33 | - __mssql_conf_value | type_debug == 'bool'
34 | - __mssql_conf_setting != "tcpport"
35 |
36 | # Special case for tcpport because sqlcmd does not set tcpport to 1433
37 | # When you try to set tcpport to 1433, sqlcmd just keeps tcpport entry in
38 | # mssql.conf empty
39 | # Empty previous tcp port setting means that the port is default 1433
40 | - name: Verify that tcpport = {{ __mssql_conf_value }}
41 | vars:
42 | __mssql_conf_get_value: >-
43 | {{ __mssql_conf_get_setting.stdout | regex_search('[1-9][0-9]{0,4}')
44 | if __mssql_conf_get_setting.stdout
45 | else '1433' }}
46 | assert:
47 | that: __mssql_conf_get_value | int == __mssql_conf_value | int
48 | when:
49 | - __mssql_conf_setting == "tcpport"
50 |
--------------------------------------------------------------------------------
/tests/tasks/snapshot_install_packages.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Install packages but avoid installing sql-server 2022 on RHEL < 8
4 | block:
5 | - name: Configure the Microsoft SQL Server repository {{ mssql_version }}
6 | yum_repository:
7 | name: packages-microsoft-com-mssql-server-{{ mssql_version | int }}
8 | description: Microsoft SQL Server {{ mssql_version }}
9 | baseurl: "{{ mssql_server_repository }}"
10 | gpgcheck: true
11 |
12 | - name: Install required packages
13 | package:
14 | name: "{{ __mssql_packages }}"
15 | state: present
16 |
17 | # NOTE: Removed packages will still be in the local package cache
18 | # and when installed will be installed from the local disk
19 | - name: Remove mssql packages to keep them in cache only
20 | package:
21 | name: "{{ __mssql_packages }}"
22 | state: absent
23 | autoremove: true
24 |
25 | - name: Remove the Microsoft SQL Server repo version {{ mssql_version }}
26 | yum_repository:
27 | name: packages-microsoft-com-mssql-server-{{ mssql_version | int }}
28 | state: absent
29 |
--------------------------------------------------------------------------------
/tests/tasks/tests_idempotency.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Assert fail on EL 7 with version = 2022 and EL 9 with version != 2022
3 | include_tasks: assert_fail_on_unsupported_ver.yml
4 |
5 | - name: Run on a fresh host and set all parameters
6 | include_role:
7 | name: linux-system-roles.mssql
8 | vars:
9 | mssql_password: "p@55w0rD"
10 | mssql_edition: Evaluation
11 | mssql_tcp_port: 1433
12 | mssql_ip_address: 0.0.0.0
13 | mssql_enable_sql_agent: true
14 | mssql_install_fts: true
15 | mssql_tune_for_fua_storage: true
16 | mssql_install_powershell: true
17 | mssql_datadir: /tmp/mssql_data
18 | mssql_logdir: /tmp/mssql_log
19 |
20 | - name: Configure the mssql-server service start limit interval and burst
21 | include_tasks: mssql-sever-increase-start-limit.yml
22 |
23 | - name: Run again with the same settings - should report not changed
24 | include_role:
25 | name: linux-system-roles.mssql
26 | vars:
27 | mssql_password: "p@55w0rD"
28 | mssql_edition: Evaluation
29 | mssql_tcp_port: 1433
30 | mssql_ip_address: 0.0.0.0
31 | mssql_enable_sql_agent: true
32 | mssql_install_fts: true
33 | mssql_tune_for_fua_storage: true
34 | mssql_install_powershell: true
35 | mssql_datadir: /tmp/mssql_data
36 | mssql_logdir: /tmp/mssql_log
37 |
38 | - name: Verify settings
39 | include_tasks: verify_settings.yml
40 | vars:
41 | __verify_mssql_password: "p@55w0rD"
42 | __verify_mssql_edition: Evaluation
43 | __verify_mssql_tcp_port: 1433
44 | __verify_mssql_ip_address: 0.0.0.0
45 | __verify_mssql_agent_is_enabled: true
46 | __verify_mssql_fts_is_installed: true
47 | __verify_mssql_is_tuned_for_fua: true
48 | __verify_mssql_powershell_is_installed: true
49 | __verify_mssql_datadir: /tmp/mssql_data
50 | __verify_mssql_logdir: /tmp/mssql_log
51 |
52 | - name: Run to edit settings
53 | include_role:
54 | name: linux-system-roles.mssql
55 | vars:
56 | mssql_password: "p@55w0rD1"
57 | mssql_edition: Standard
58 | mssql_tcp_port: 1435
59 | mssql_ip_address: 127.0.0.1
60 | mssql_enable_sql_agent: false
61 | mssql_install_fts: false
62 | mssql_tune_for_fua_storage: false
63 | mssql_install_powershell: false
64 | mssql_datadir: /var/opt/mssql/data
65 | mssql_logdir: /var/opt/mssql/log
66 | mssql_datadir_mode: '755'
67 | mssql_logdir_mode: '755'
68 |
69 | - name: Run with the edited settings again - should report not changed
70 | include_role:
71 | name: linux-system-roles.mssql
72 | vars:
73 | mssql_password: "p@55w0rD1"
74 | mssql_edition: Standard
75 | mssql_tcp_port: 1435
76 | mssql_ip_address: 127.0.0.1
77 | mssql_enable_sql_agent: false
78 | mssql_install_fts: false
79 | mssql_tune_for_fua_storage: false
80 | mssql_install_powershell: false
81 | mssql_datadir: /var/opt/mssql/data
82 | mssql_logdir: /var/opt/mssql/log
83 |
84 | - name: Verify disabled settings
85 | include_tasks: verify_settings.yml
86 | vars:
87 | __verify_mssql_password: "p@55w0rD1"
88 | # package defaults to Evaluation, but the tests above change it to
89 | # 'Standard' in the case where the server actually runs
90 | __verify_mssql_edition: "{{ 'Standard' if __mssql_is_booted else 'Evaluation' }}"
91 | __verify_mssql_tcp_port: 1435
92 | __verify_mssql_ip_address: 127.0.0.1
93 | __verify_mssql_agent_is_enabled: false
94 | __verify_mssql_fts_is_installed: false
95 | __verify_mssql_ha_is_installed: false
96 | __verify_mssql_is_tuned_for_fua: false
97 | __verify_mssql_powershell_is_installed: false
98 | __verify_mssql_datadir: /var/opt/mssql/data
99 | __verify_mssql_logdir: /var/opt/mssql/log
100 | __verify_mssql_datadir_mode: '0755'
101 | __verify_mssql_logdir_mode: '0755'
102 |
103 | - name: Check the ansible_managed header in the configuration file
104 | include_tasks: check_header.yml
105 |
--------------------------------------------------------------------------------
/tests/tasks/tests_input_sql_file.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Assert fail on EL 7 with version = 2022 and EL 9 with version != 2022
3 | include_tasks: assert_fail_on_unsupported_ver.yml
4 |
5 | - name: Set up MSSQL and input sql files with pre_input
6 | include_role:
7 | name: linux-system-roles.mssql
8 | vars:
9 | mssql_pre_input_sql_file:
10 | - create_example_db.j2
11 | - create_example_db.j2
12 | mssql_password: "p@55w0rD"
13 | mssql_edition: Evaluation
14 | # Enable FTS in the beginning so that it works at the end
15 | # It takes some time for mssql-server to configure it after RPM is installed
16 | mssql_install_fts: true
17 | # noqa var-naming[no-role-prefix]
18 | __mssql_test_db_name: ExampleDB1
19 |
20 | - name: Assert the latest script invocation resulted in no changes
21 | assert:
22 | that:
23 | - >-
24 | 'The ExampleDB1 database already exists, skipping' in
25 | __mssql_sqlcmd_input.stdout
26 | - >-
27 | 'The Inventory table already exists, skipping' in
28 | __mssql_sqlcmd_input.stdout
29 |
30 | - name: Input sql files with post_input into custom storage directory
31 | include_role:
32 | name: linux-system-roles.mssql
33 | vars:
34 | mssql_datadir: /tmp/mssql_data
35 | mssql_logdir: /tmp/mssql_log
36 | mssql_datadir_mode: '0700'
37 | mssql_logdir_mode: '0700'
38 | mssql_post_input_sql_file:
39 | - sql_script.sql
40 | - sql_script.sql
41 | mssql_password: "p@55w0rD"
42 |
43 | - name: Assert the latest script invocation resulted in no changes
44 | assert:
45 | that:
46 | - >-
47 | 'The MyLogin login already exists, skipping'
48 | in __mssql_sqlcmd_input.stdout
49 | - >-
50 | 'The MyUser user already exists, skipping'
51 | in __mssql_sqlcmd_input.stdout
52 |
53 | - name: Verify custom storage
54 | include_tasks: verify_settings.yml
55 | vars:
56 | __verify_mssql_datadir: /tmp/mssql_data
57 | __verify_mssql_logdir: /tmp/mssql_log
58 | __verify_mssql_datadir_mode: '0700'
59 | __verify_mssql_logdir_mode: '0700'
60 |
61 | - name: Set up MSSQL and input sql content with pre_input
62 | include_role:
63 | name: linux-system-roles.mssql
64 | vars:
65 | mssql_pre_input_sql_content:
66 | - "{{ lookup('template', 'create_example_db.j2') }}"
67 | - "{{ lookup('template', 'create_example_db.j2') }}"
68 | __mssql_test_db_name: ExampleDB2
69 | mssql_password: "p@55w0rD"
70 | mssql_edition: Evaluation
71 |
72 | - name: Assert the latest script invocation resulted in no changes
73 | assert:
74 | that: >-
75 | 'The ExampleDB2 database already exists, skipping' in
76 | __mssql_sqlcmd_input.stdout
77 |
78 | - name: Set up MSSQL and input sql content with post_input
79 | include_role:
80 | name: linux-system-roles.mssql
81 | vars:
82 | mssql_post_input_sql_content:
83 | - "{{ lookup('file', 'sql_script.sql') }}"
84 | mssql_password: "p@55w0rD"
85 |
86 | - name: Assert the latest script invocation resulted in no changes
87 | assert:
88 | that: >-
89 | 'The MyLogin login already exists, skipping'
90 | in __mssql_sqlcmd_input.stdout
91 |
92 | - name: Verify the failure when the mssql_password var is not specified
93 | block:
94 | - name: Input the sql file without the mssql_password variable
95 | include_role:
96 | name: linux-system-roles.mssql
97 | vars:
98 | mssql_pre_input_sql_file: sql_script.sql
99 |
100 | - name: Unreachable task
101 | fail:
102 | msg: The above task must fail
103 |
104 | rescue:
105 | - name: Assert that the role failed with mssql_password not defined
106 | assert:
107 | that: >-
108 | 'You must define the mssql_password variable' in
109 | ansible_failed_result.msg
110 |
111 | - name: Verify the failure when the mssql_password var is not specified
112 | block:
113 | - name: Input the sql file without the mssql_password variable
114 | include_role:
115 | name: linux-system-roles.mssql
116 | vars:
117 | mssql_post_input_sql_file: sql_script.sql
118 |
119 | - name: Unreachable task
120 | fail:
121 | msg: The above task must fail
122 |
123 | rescue:
124 | - name: Assert that the role failed with mssql_password not defined
125 | assert:
126 | that: >-
127 | 'You must define the mssql_password variable' in
128 | ansible_failed_result.msg
129 |
130 | - name: Verify that FTS was enabled in the beginning of this test playbook
131 | include_role:
132 | name: linux-system-roles.mssql
133 | vars:
134 | mssql_post_input_sql_file: verify_fts.sql
135 | mssql_password: "p@55w0rD"
136 |
137 | - name: Assert the latest script invocation resulted in no changes
138 | assert:
139 | that:
140 | - >-
141 | 'Full-Text Search is enabled'
142 | in __mssql_sqlcmd_input.stdout
143 |
--------------------------------------------------------------------------------
/tests/tasks/tests_password.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Assert fail on EL 7 with version = 2022 and EL 9 with version != 2022
3 | include_tasks: assert_fail_on_unsupported_ver.yml
4 |
5 | # role does not run during bootc QEMU validation, thus _is_booted is undefined
6 | - name: Set __mssql_is_booted for bootc validation tests
7 | set_fact:
8 | __mssql_is_booted: true
9 | when: __bootc_validation | d(false)
10 |
11 | - name: Set up MSSQL
12 | include_role:
13 | name: linux-system-roles.mssql
14 | vars:
15 | mssql_password: "p@55w0rD"
16 | mssql_edition: Evaluation
17 | mssql_tools_versions: [17]
18 | when: not __bootc_validation | d(false)
19 |
20 | - name: Configure the mssql-server service start limit interval and burst
21 | include_tasks: tasks/mssql-sever-increase-start-limit.yml
22 | when: not __bootc_validation | d(false)
23 |
24 | - name: >-
25 | Change the password with default settings.
26 | Should report Changed.
27 | include_role:
28 | name: linux-system-roles.mssql
29 | vars:
30 | mssql_password: "p@55w0rD11"
31 | when: not __bootc_validation | d(false)
32 |
33 | - name: Verify settings
34 | include_tasks: tasks/verify_settings.yml
35 | vars:
36 | __verify_mssql_password: "p@55w0rD11"
37 | when: not __bootc_validation | d(false)
38 |
39 | - name: Verify the package {{ __mssql_verify_package_name }}
40 | include_tasks: verify_package.yml
41 | vars:
42 | __mssql_verify_package_name: mssql-tools
43 | __mssql_verify_package_installed: true
44 |
45 | - name: Change the IP address setting.
46 | include_role:
47 | name: linux-system-roles.mssql
48 | vars:
49 | mssql_ip_address: 127.0.0.1
50 | when: not __bootc_validation | d(false)
51 |
52 | - name: Create QEMU deployment during bootc end-to-end test
53 | delegate_to: localhost
54 | become: false
55 | command: "{{ lsr_scriptdir }}/bootc-buildah-qcow.sh {{ ansible_host }}"
56 | changed_when: true
57 | when: ansible_connection == "buildah"
58 |
59 | - name: >-
60 | Change the password with a custom IP address.
61 | Should report Changed.
62 | include_role:
63 | name: linux-system-roles.mssql
64 | vars:
65 | mssql_password: "p@55w0rD"
66 | mssql_tools_versions: [17, 18]
67 | when: not __bootc_validation | d(false)
68 |
69 | - name: Verify settings
70 | include_tasks: tasks/verify_settings.yml
71 | vars:
72 | __verify_mssql_password: "p@55w0rD"
73 | when: not __bootc_validation | d(false)
74 |
75 | - name: Verify the package {{ __mssql_verify_package_name }}
76 | include_tasks: verify_package.yml
77 | vars:
78 | __mssql_verify_package_name: mssql-tools18
79 | __mssql_verify_package_installed: true
80 |
81 | - name: Change the TCP port setting.
82 | include_role:
83 | name: linux-system-roles.mssql
84 | vars:
85 | mssql_tcp_port: 1432
86 | when: not __bootc_validation | d(false)
87 |
88 | - name: >-
89 | Change the password with a custom TCP port and IP address.
90 | Should report Changed.
91 | include_role:
92 | name: linux-system-roles.mssql
93 | vars:
94 | mssql_password: "p@55w0rD11"
95 | mssql_tools_versions: [18]
96 | when: not __bootc_validation | d(false)
97 |
98 | - name: Verify settings
99 | include_tasks: tasks/verify_settings.yml
100 | vars:
101 | __verify_mssql_password: "p@55w0rD11"
102 | when: not __bootc_validation | d(false)
103 |
104 | - name: Verify the package {{ __mssql_verify_package_name }}
105 | include_tasks: verify_package.yml
106 | vars:
107 | __mssql_verify_package_name: mssql-tools18
108 | __mssql_verify_package_installed: true
109 |
110 | - name: Check the ansible_managed header in the configuration file
111 | include_tasks: tasks/check_header.yml
112 |
--------------------------------------------------------------------------------
/tests/tasks/tests_tcp_firewall.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Assert fail on EL 7 with version = 2022 and EL 9 with version != 2022
3 | include_tasks: assert_fail_on_unsupported_ver.yml
4 |
5 | - name: Test while not settings mssql_tcp_port to default it to 1433
6 | vars:
7 | __mssql_test_port: 1433
8 | block:
9 | - name: Set up SQL Server
10 | include_role:
11 | name: linux-system-roles.mssql
12 | vars:
13 | mssql_password: "p@55w0rD"
14 | mssql_edition: Evaluation
15 |
16 | - name: >-
17 | Verify that the port is configured properly {{ __mssql_test_port }}
18 | include_tasks: tasks/verify_tcp_port.yml
19 | vars:
20 | __mssql_tcp_port_new: "{{ __mssql_test_port }}"
21 |
22 | - name: Configure the mssql-server service start limit interval and burst
23 | include_tasks: tasks/mssql-sever-increase-start-limit.yml
24 |
25 | - name: Test while settings mssql_tcp_port to to 1433
26 | vars:
27 | __mssql_test_port: 1433
28 | block:
29 | - name: Set up SQL Server
30 | include_role:
31 | name: linux-system-roles.mssql
32 | vars:
33 | mssql_password: "p@55w0rD"
34 | mssql_edition: Evaluation
35 | mssql_tcp_port: "{{ __mssql_test_port }}"
36 |
37 | - name: >-
38 | Verify that the port is configured properly {{ __mssql_test_port }}
39 | include_tasks: tasks/verify_tcp_port.yml
40 | vars:
41 | __mssql_tcp_port_new: "{{ __mssql_test_port }}"
42 |
43 | - name: Test with mssql_tcp_port changed to 1435
44 | vars:
45 | __mssql_test_port: 1435
46 | block:
47 | - name: Set up SQL Server
48 | include_role:
49 | name: linux-system-roles.mssql
50 | vars:
51 | mssql_password: "p@55w0rD"
52 | mssql_edition: Evaluation
53 | mssql_tcp_port: "{{ __mssql_test_port }}"
54 |
55 | - name: >-
56 | Verify that the port is configured properly {{ __mssql_test_port }}
57 | include_tasks: tasks/verify_tcp_port.yml
58 | vars:
59 | __mssql_tcp_port_new: "{{ __mssql_test_port }}"
60 | __mssql_tcp_port_previous: 1433
61 |
--------------------------------------------------------------------------------
/tests/tasks/tests_tls.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Assert fail on EL 7 with version = 2022 and EL 9 with version != 2022
3 | include_tasks: assert_fail_on_unsupported_ver.yml
4 |
5 | - name: Ensure the openssl package
6 | package:
7 | name: openssl
8 | state: present
9 | run_once: true
10 |
11 | - name: Create a tempfile for a certificate on hosts
12 | tempfile:
13 | state: file
14 | register: __mssql_cert_tempfile
15 | run_once: true
16 |
17 | - name: Create a tempfile for a private key on hosts
18 | tempfile:
19 | state: file
20 | register: __mssql_pvk_tempfile
21 | run_once: true
22 |
23 | - name: Generate a self-signed certificate and public key
24 | command: >-
25 | openssl req -x509 -nodes -newkey rsa:2048
26 | -subj "/CN={{ ansible_default_ipv4.address }}"
27 | -out {{ __mssql_cert_tempfile.path }}
28 | -keyout {{ __mssql_pvk_tempfile.path }} -days 365
29 | changed_when: true
30 | run_once: true
31 |
32 | - name: Copy certificate files to local tmp
33 | fetch:
34 | src: "{{ item }}"
35 | dest: "{{ item }}"
36 | flat: true
37 | mode: preserve
38 | run_once: true
39 | loop:
40 | - "{{ __mssql_cert_tempfile.path }}"
41 | - "{{ __mssql_pvk_tempfile.path }}"
42 |
43 | # Test relative and full path with mssql_tls_remote_src: false
44 | - name: Copy a private key to the playbook directory to test a relative path
45 | copy:
46 | src: "{{ __mssql_pvk_tempfile.path }}"
47 | dest: "{{ __mssql_pvk_tempfile.path | basename }}"
48 | mode: preserve
49 | delegate_to: localhost
50 | run_once: true
51 |
52 | - name: Set mssql_tls_cert and mssql_tls_private_key for the following test
53 | set_fact:
54 | mssql_tls_cert: "{{ __mssql_cert_tempfile.path }}"
55 | mssql_tls_private_key: "{{ __mssql_pvk_tempfile.path | basename }}"
56 |
57 | - name: Test relative and full path with certs on control node
58 | block:
59 | - name: Run role
60 | include_role:
61 | name: linux-system-roles.mssql
62 | public: true
63 | vars:
64 | mssql_tls_enable: true
65 | mssql_tls_cert: "{{ __mssql_cert_tempfile.path }}"
66 | mssql_tls_private_key: "{{ __mssql_pvk_tempfile.path | basename }}"
67 | always:
68 | - name: Remove a private key from the playbook directory
69 | file:
70 | path: "{{ __mssql_pvk_tempfile.path | basename }}"
71 | state: absent
72 | delegate_to: localhost
73 | run_once: true
74 |
75 | - name: Configure the mssql-server service start limit interval and burst
76 | include_tasks: tasks/mssql-sever-increase-start-limit.yml
77 |
78 | - name: Verify connectivity and settings
79 | include_tasks: tasks/verify_settings.yml
80 | vars:
81 | __verify_mssql_password: "p@55w0rD"
82 | __verify_mssql_is_tls_encrypted: true
83 |
84 | # Test disabling TLS encryption
85 | - name: Disable TLS encryption
86 | include_role:
87 | name: linux-system-roles.mssql
88 | public: true
89 | vars:
90 | mssql_tls_enable: false
91 |
92 | - name: Verify connectivity and settings
93 | include_tasks: tasks/verify_settings.yml
94 | vars:
95 | __verify_mssql_password: "p@55w0rD"
96 | __verify_mssql_is_tls_encrypted: false
97 |
98 | # Test mssql_tls_remote_src: true
99 | - name: Remove certificates from hosts
100 | file:
101 | path: "{{ item }}"
102 | state: absent
103 | loop:
104 | - /etc/pki/tls/certs/{{ __mssql_cert_tempfile.path | basename }}
105 | - /etc/pki/tls/private/{{ __mssql_pvk_tempfile.path | basename }}
106 |
107 | - name: Copy certificates to hosts
108 | copy:
109 | src: "{{ item }}"
110 | dest: "{{ item }}"
111 | mode: preserve
112 | loop:
113 | - "{{ __mssql_cert_tempfile.path }}"
114 | - "{{ __mssql_pvk_tempfile.path }}"
115 |
116 | - name: Set mssql_tls_cert and mssql_tls_private_key for the following test
117 | set_fact:
118 | mssql_tls_cert: "{{ __mssql_cert_tempfile.path }}"
119 | mssql_tls_private_key: "{{ __mssql_pvk_tempfile.path | basename }}"
120 |
121 | - name: Test with certs on managed nodes
122 | include_role:
123 | name: linux-system-roles.mssql
124 | public: true
125 | vars:
126 | mssql_tls_enable: true
127 | mssql_tls_cert: "{{ __mssql_cert_tempfile.path }}"
128 | mssql_tls_private_key: "{{ __mssql_pvk_tempfile.path }}"
129 | mssql_tls_remote_src: true
130 |
131 | - name: Verify connectivity and settings
132 | include_tasks: tasks/verify_settings.yml
133 | vars:
134 | __verify_mssql_password: "p@55w0rD"
135 | __verify_mssql_is_tls_encrypted: true
136 |
137 | - name: Check the ansible_managed header in the configuration file
138 | include_tasks: tasks/check_header.yml
139 |
140 | # Test disabling TLS encryption
141 | - name: Disable TLS encryption
142 | include_role:
143 | name: linux-system-roles.mssql
144 | vars:
145 | mssql_tls_enable: false
146 |
147 | - name: Verify connectivity and settings
148 | include_tasks: tasks/verify_settings.yml
149 | vars:
150 | __verify_mssql_password: "p@55w0rD"
151 | __verify_mssql_is_tls_encrypted: false
152 |
153 | # Test mssql_tls_certificates
154 | - name: Test with certs created by the certificate role
155 | include_role:
156 | name: linux-system-roles.mssql
157 | public: true
158 | vars:
159 | mssql_tls_enable: true
160 | mssql_tls_certificates:
161 | - name: mssql_2019_cert
162 | common_name: "{{ ansible_default_ipv4.address }}"
163 | ca: self-sign
164 |
165 | - name: Flush handlers
166 | meta: flush_handlers
167 |
168 | - name: Verify connectivity and settings
169 | include_tasks: tasks/verify_settings.yml
170 | vars:
171 | __verify_mssql_password: "p@55w0rD"
172 | __verify_mssql_is_tls_encrypted: true
173 |
174 | # Disable TLS encryption for future tests
175 | - name: Disable TLS encryption
176 | include_role:
177 | name: linux-system-roles.mssql
178 | vars:
179 | mssql_tls_enable: false
180 |
--------------------------------------------------------------------------------
/tests/tasks/upgrade_and_assert.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # With __mssql_version provide the version to upgrade to
3 | # With __mssql_prev_version provide the current version of SQL Server
4 | - name: Upgrade to a new version
5 | vars:
6 | mssql_upgrade: true
7 | mssql_version: "{{ __mssql_version }}"
8 | block:
9 | - name: Upgrade to {{ __mssql_version }}
10 | include_role:
11 | name: linux-system-roles.mssql
12 |
13 | - name: Upgrade again to test idempotency - should report not changed
14 | include_role:
15 | name: linux-system-roles.mssql
16 | rescue:
17 | - name: Assert that upgrading EL 7 to 2022 fails
18 | when:
19 | - __mssql_version == 2022
20 | - ansible_distribution in ['CentOS', 'RedHat']
21 | - ansible_distribution_version is version('8', '<')
22 | assert:
23 | that: >-
24 | 'SQL Server 2022 does not support EL 7 hosts'
25 | in ansible_failed_result.msg
26 | always:
27 | - name: Clean up EL 7 after the role invocation
28 | when:
29 | - __mssql_version == 2022
30 | - ansible_distribution in ['CentOS', 'RedHat']
31 | - ansible_distribution_version is version('8', '<')
32 | include_tasks: tasks/cleanup.yml
33 |
34 | # Putting end_host into a rescue block results in a failed task
35 | - name: End EL 7 host
36 | when:
37 | - __mssql_version == 2022
38 | - ansible_distribution in ['CentOS', 'RedHat']
39 | - ansible_distribution_version is version('8', '<')
40 | meta: end_host
41 |
42 | - name: >-
43 | Verify the failure when mssql_version < current version
44 | block:
45 | - name: >-
46 | Upgrade to new version on mssql
47 | new version {{ __mssql_prev_version }}
48 | include_role:
49 | name: linux-system-roles.mssql
50 | vars:
51 | mssql_version: "{{ __mssql_prev_version }}"
52 |
53 | - name: Unreachable task
54 | fail:
55 | msg: The above task must fail
56 | rescue:
57 | # Verify the error message
58 | # Verify that the error is returned only once in ansible_failed_result
59 | - name: Assert that the role failed with the correct message
60 | assert:
61 | that:
62 | - >-
63 | 'You set mssql_version to {{ __mssql_prev_version }}, but your SQL'
64 | in ansible_failed_result.results
65 | | selectattr('msg', 'defined')
66 | | map(attribute='msg')
67 | | join(' ')
68 | - ansible_failed_result.results | selectattr('msg', 'defined')
69 | | list
70 | | length == 1
71 |
--------------------------------------------------------------------------------
/tests/tasks/verify_ad_auth.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Test AD integration with keytab
4 | vars:
5 | __mssql_kinit_user: >-
6 | {{ ad_integration_user }}@{{ ad_integration_realm
7 | | upper }}
8 | block:
9 | - name: Install sshpass for use in the following task
10 | package:
11 | name: sshpass
12 | state: present
13 |
14 | - name: Print credential caches to check if AD principal exists
15 | command: klist -l
16 | register: __mssql_klist
17 | changed_when: false
18 | failed_when: false
19 |
20 | # Do not fail when there are no tickets
21 | - name: Print status of credential cache for {{ __mssql_kinit_user }}
22 | shell: >-
23 | set -euo pipefail;
24 | klist -l $(klist -l | grep {{ __mssql_kinit_user }}
25 | | awk '{print $2}')
26 | register: __mssql_klist_kinit_user
27 | when: __mssql_kinit_user in __mssql_klist.stdout
28 | changed_when: false
29 |
30 | - name: Obtain Kerberos ticket of the AD user {{ ad_integration_user }}
31 | shell: >-
32 | set -euo pipefail;
33 | echo {{ ad_integration_password | quote }}
34 | | kinit {{ __mssql_kinit_user }}
35 | when: >-
36 | (__mssql_kinit_user not in __mssql_klist.stdout)
37 | or
38 | ("(Expired)" in __mssql_klist_kinit_user.stdout | d())
39 | changed_when: true
40 |
41 | - name: SSH into AD, kinit as Administrator, verify authentication
42 | shell: >-
43 | set -euo pipefail;
44 | sshpass -p {{ mssql_ad_sql_password | quote }}
45 | ssh -o StrictHostKeyChecking=no
46 | -l {{ mssql_ad_sql_user }}@{{ ad_integration_realm }}
47 | {{ ansible_fqdn }}
48 | "echo {{ ad_integration_password | quote }}
49 | | kinit {{ __mssql_kinit_user }} &&
50 | /opt/mssql-tools18/bin/sqlcmd -S. -Q 'SELECT SYSTEM_USER'"
51 | register: __mssql_ad_test
52 | changed_when: false
53 | always:
54 | - name: Print test results
55 | debug:
56 | var: __mssql_ad_test.stdout_lines
57 |
58 | - name: Print test results
59 | debug:
60 | var: __mssql_ad_test.stderr_lines
61 |
--------------------------------------------------------------------------------
/tests/tasks/verify_package.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | # This tasks file verifies if the provided package is installed or not.
4 | # It takes to variables:
5 | # __mssql_verify_package - the package to verify
6 | # __mssql_verify_installed - boolean
7 | - name: Gather package facts
8 | package_facts:
9 | manager: auto
10 | no_log: true
11 |
12 | - name: Verify if the package is installed {{ __mssql_verify_package_name }}
13 | assert:
14 | that: __mssql_verify_package_name in ansible_facts.packages
15 | when: __mssql_verify_package_installed | bool
16 |
17 | - name: Verify if the package is not installed {{ __mssql_verify_package_name }}
18 | assert:
19 | that: __mssql_verify_package_name not in ansible_facts.packages
20 | when: not __mssql_verify_package_installed
21 |
--------------------------------------------------------------------------------
/tests/tasks/verify_tcp_port.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | # This task files verifies that the provided port is configured in SQL Server
3 | # and opened in firewall. It can verify if a port is closed too.
4 | # It takes the following variables:
5 | # __mssql_tcp_port_new - the configured port to verify
6 | # __mssql_tcp_port_previous - optional: the previous port to verify it is closed
7 | ---
8 | - name: List opened firewall ports
9 | command: firewall-cmd --list-ports
10 | register: __mssql_firewall_ports
11 | changed_when: false
12 |
13 | - name: Verify that the port is open in firewall {{ __mssql_tcp_port_new }}
14 | assert:
15 | that: >-
16 | '{{ __mssql_tcp_port_new }}/tcp' in __mssql_firewall_ports.stdout
17 | when: __mssql_tcp_port_new is defined
18 |
19 | - name: Verify that the firewall port is closed {{ __mssql_tcp_port_previous }}
20 | assert:
21 | that: >-
22 | '{{ __mssql_tcp_port_previous }}/tcp' not in
23 | __mssql_firewall_ports.stdout
24 | when: __mssql_tcp_port_previous is defined
25 |
26 | - name: >-
27 | Verify that the port is configured in SQL Server {{ __mssql_tcp_port_new }}
28 | include_tasks: tasks/verify_settings.yml
29 | vars:
30 | __mssql_tcp_port_matches: "{{ __mssql_tcp_port_new }}"
31 | when: __mssql_tcp_port_new is defined
32 |
--------------------------------------------------------------------------------
/tests/templates/add_test_listener.j2:
--------------------------------------------------------------------------------
1 | PRINT 'Adding the TEST-listener listener to the \
2 | {{ mssql_ha_ag_name }} availability group';
3 | ALTER AVAILABILITY GROUP {{ mssql_ha_ag_name }}
4 | ADD LISTENER 'TEST-listener' (
5 | WITH IP ( ('{{ mssql_ha_virtual_ip }}','255.255.255.0') ),
6 | PORT = {{ mssql_tcp_port }}
7 | );
8 |
--------------------------------------------------------------------------------
/tests/templates/alter_ag.j2:
--------------------------------------------------------------------------------
1 | IF EXISTS (
2 | SELECT name, cluster_type_desc
3 | FROM sys.availability_groups
4 | WHERE name = '{{ mssql_ha_ag_name }}'
5 | )
6 | BEGIN
7 | PRINT 'Altering the existing availability group {{ mssql_ha_ag_name }}'
8 | IF NOT EXISTS (
9 | SELECT name, db_failover
10 | FROM sys.availability_groups
11 | WHERE name = '{{ mssql_ha_ag_name }}' AND
12 | db_failover = 0
13 | )
14 | BEGIN
15 | ALTER AVAILABILITY GROUP {{ mssql_ha_ag_name }} SET (DB_FAILOVER = ON)
16 | PRINT 'Set DB_FAILOVER to ON succesfully'
17 | END
18 | ELSE
19 | BEGIN
20 | PRINT 'DB_FAILOVER = OFF is already set, skipping'
21 | END
22 | PRINT 'Altering replicas'
23 | {% for item in ansible_play_hosts %}
24 | {% if hostvars[item]['mssql_ha_replica_type'] != 'absent' %}
25 | IF EXISTS (
26 | SELECT replica_server_name
27 | FROM sys.availability_replicas
28 | WHERE replica_server_name = '{{ hostvars[item]['ansible_hostname'] }}'
29 | )
30 | BEGIN
31 | PRINT 'Verifying the existing replica {{ item }}';
32 | {% if (hostvars[item]['mssql_ha_replica_type'] == 'primary') or
33 | (hostvars[item]['mssql_ha_replica_type'] == 'synchronous') %}
34 | {% set ag_replica_settings = ({
35 | "endpoint_url":{
36 | "sql_setting_name":"ENDPOINT_URL",
37 | "sys_setting_name":"endpoint_url",
38 | "setting_value":"N'tcp://" + hostvars[item]['ansible_fqdn'] + ":" +
39 | "1234" + "'"
40 | },
41 | "failover_mode":{
42 | "sql_setting_name":"FAILOVER_MODE",
43 | "sys_setting_name":"failover_mode_desc",
44 | "setting_value":"EXTERNAL"
45 | },
46 | "seeding_mode":{
47 | "sql_setting_name":"SEEDING_MODE",
48 | "sys_setting_name":"seeding_mode_desc",
49 | "setting_value":"MANUAL"
50 | },
51 | "allow_connections":{
52 | "sql_setting_name": "SECONDARY_ROLE (ALLOW_CONNECTIONS = NO)",
53 | "sys_setting_name": "secondary_role_allow_connections_desc",
54 | "setting_value": "NO"
55 | }
56 | }) %}
57 | {% elif hostvars[item]['mssql_ha_replica_type'] == 'witness' %}
58 | {% set ag_replica_settings = ({
59 | "endpoint_url":{
60 | "sql_setting_name":"ENDPOINT_URL",
61 | "sys_setting_name":"endpoint_url",
62 | "setting_value":"N'tcp://" + hostvars[item]['ansible_fqdn'] + ":" +
63 | "1234" + "'"
64 | }
65 | }) %}
66 | {% endif %}
67 | {% for key, value in ag_replica_settings.items() %}
68 | IF NOT EXISTS (
69 | SELECT replica_server_name, {{ value.sys_setting_name }}
70 | FROM sys.availability_replicas
71 | WHERE replica_server_name = N'{{ hostvars[item]['ansible_hostname'] }}'
72 | AND
73 | {% if key == 'endpoint_url' %}
74 | {{ value.sys_setting_name }} = {{ value.setting_value }}
75 | {% else %}
76 | {{ value.sys_setting_name }} = '{{ value.setting_value }}'
77 | {% endif %}
78 | )
79 | BEGIN
80 | ALTER AVAILABILITY GROUP {{ mssql_ha_ag_name }} MODIFY REPLICA ON
81 | N'{{ hostvars[item]['ansible_hostname'] }}' WITH (
82 | {% if key == 'allow_connections' %}
83 | {{ value.sql_setting_name }}
84 | {% else %}
85 | {{ value.sql_setting_name }} = {{ value.setting_value }}
86 | {% endif %}
87 | );
88 | PRINT '{{ hostvars[item]['ansible_hostname'] }}: \
89 | The {{ value.sql_setting_name }} setting on this \
90 | {{ hostvars[item]['mssql_ha_replica_type'] }} replica configured successfully';
91 | END
92 | ELSE
93 | BEGIN
94 | PRINT '{{ hostvars[item]['ansible_hostname'] }}: \
95 | The {{ value.sql_setting_name }} setting on this \
96 | {{ hostvars[item]['mssql_ha_replica_type'] }} replica is already set \
97 | correctly, skipping';
98 | END
99 | {% endfor %}
100 | END
101 | {% endif %}
102 | {% endfor %}
103 | END
104 |
--------------------------------------------------------------------------------
/tests/templates/alter_endpoint.j2:
--------------------------------------------------------------------------------
1 | IF NOT EXISTS(
2 | SELECT name
3 | FROM sys.certificates
4 | WHERE name = 'test_cert'
5 | )
6 | BEGIN
7 | PRINT 'Certificate test_cert does not exist, creating';
8 | CREATE CERTIFICATE test_cert
9 | WITH SUBJECT = 'Test certificate';
10 | PRINT 'Certificate test_cert created successfully';
11 | END
12 | ELSE
13 | BEGIN
14 | PRINT 'Certificate test_cert already exists, skipping';
15 | END
16 |
17 | ALTER ENDPOINT {{ mssql_ha_endpoint_name }}
18 | STATE = STOPPED
19 | AS TCP (LISTENER_PORT = 1234)
20 | FOR DATABASE_MIRRORING (
21 | ROLE = PARTNER,
22 | AUTHENTICATION = CERTIFICATE test_cert,
23 | ENCRYPTION = REQUIRED ALGORITHM RC4
24 | );
25 |
--------------------------------------------------------------------------------
/tests/templates/configure_ag_cluster_type_none.j2:
--------------------------------------------------------------------------------
1 | CREATE AVAILABILITY GROUP {{ mssql_ha_ag_name }}
2 | WITH (CLUSTER_TYPE = NONE)
3 | FOR REPLICA ON
4 | N'{{ ansible_hostname }}' WITH (
5 | ENDPOINT_URL = N'tcp://{{ ansible_fqdn }}:{{ mssql_ha_endpoint_port }}',
6 | AVAILABILITY_MODE = SYNCHRONOUS_COMMIT,
7 | FAILOVER_MODE = MANUAL,
8 | SEEDING_MODE = AUTOMATIC,
9 | SECONDARY_ROLE (ALLOW_CONNECTIONS = ALL)
10 | );
11 |
--------------------------------------------------------------------------------
/tests/templates/create_example_db.j2:
--------------------------------------------------------------------------------
1 | IF NOT EXISTS(
2 | SELECT name
3 | FROM sys.databases
4 | WHERE name = '{{ __mssql_test_db_name }}'
5 | )
6 | BEGIN
7 | PRINT 'Creating the {{ __mssql_test_db_name }} database';
8 | CREATE DATABASE {{ __mssql_test_db_name }};
9 | PRINT 'The {{ __mssql_test_db_name }} database created successfully';
10 | END
11 | ELSE
12 | BEGIN
13 | PRINT 'The {{ __mssql_test_db_name }} database already exists, skipping';
14 | END
15 | GO
16 |
17 | USE {{ __mssql_test_db_name }};
18 | GO
19 |
20 | IF NOT EXISTS (
21 | SELECT name, xtype
22 | FROM sysobjects
23 | WHERE name='Inventory' and xtype='U'
24 | )
25 | BEGIN
26 | PRINT 'Adding the Inventory table to the {{ __mssql_test_db_name }} database';
27 | CREATE TABLE Inventory (id INT, name NVARCHAR(50), quantity INT);
28 | INSERT INTO Inventory VALUES (1, 'apple', 100);
29 | INSERT INTO Inventory VALUES (2, 'orange', 150);
30 | INSERT INTO Inventory VALUES (3, 'banana', 154);
31 | INSERT INTO Inventory VALUES (4, N'バナナ', 170);
32 | PRINT 'The Inventory table created successfully';
33 | END
34 | ELSE
35 | BEGIN
36 | PRINT 'The Inventory table already exists, skipping';
37 | END
38 | GO
39 |
--------------------------------------------------------------------------------
/tests/templates/disable_alwayson.j2:
--------------------------------------------------------------------------------
1 | ALTER EVENT SESSION AlwaysOn_health ON SERVER WITH (STARTUP_STATE=OFF);
2 |
--------------------------------------------------------------------------------
/tests/templates/drop_ag.j2:
--------------------------------------------------------------------------------
1 | IF EXISTS (
2 | SELECT name
3 | FROM sys.availability_groups
4 | WHERE name = '{{ mssql_ha_ag_name }}'
5 | )
6 | BEGIN
7 | DROP AVAILABILITY GROUP ag1;
8 | PRINT 'The {{ mssql_ha_ag_name }} availability group dropped successfully';
9 | END
10 | ELSE
11 | BEGIN
12 | PRINT 'The {{ mssql_ha_ag_name }} ag does not exist, skipping';
13 | END
14 |
--------------------------------------------------------------------------------
/tests/templates/drop_endpoint.j2:
--------------------------------------------------------------------------------
1 | PRINT 'Dropping the {{ mssql_ha_endpoint_name }} endpoint'
2 | IF NOT EXISTS (
3 | SELECT name
4 | FROM sys.database_mirroring_endpoints
5 | WHERE name = '{{ mssql_ha_endpoint_name }}'
6 | )
7 | BEGIN
8 | PRINT 'Endpoint {{ mssql_ha_endpoint_name }} does not exist, skipping'
9 | END
10 | ELSE
11 | BEGIN
12 | DROP ENDPOINT {{ mssql_ha_endpoint_name }};
13 | PRINT 'Endpoint {{ mssql_ha_endpoint_name }} dropped successfully'
14 | END
15 |
--------------------------------------------------------------------------------
/tests/templates/get_ansible_managed.j2:
--------------------------------------------------------------------------------
1 | {{ ansible_managed | comment }}
2 | {{ "system_role:mssql" | comment(prefix="", postfix="") }}
3 |
--------------------------------------------------------------------------------
/tests/templates/remove_listener.j2:
--------------------------------------------------------------------------------
1 | IF NOT EXISTS (
2 | SELECT dns_name
3 | FROM sys.availability_group_listeners
4 | )
5 | BEGIN
6 | PRINT 'Listeners do not exist, skipping'
7 | END
8 | ELSE
9 | BEGIN
10 | DECLARE @ListenerName VARCHAR(30) = (
11 | SELECT dns_name FROM sys.availability_group_listeners
12 | );
13 | PRINT 'Removing the listener ' + CAST(@ListenerName AS VARCHAR);
14 | EXEC (
15 | 'ALTER AVAILABILITY GROUP {{ mssql_ha_ag_name }}
16 | REMOVE LISTENER "'+@ListenerName+'"'
17 | );
18 | PRINT 'Removed the listener ' + CAST(@ListenerName AS VARCHAR) + ' successfully';
19 | END
20 |
--------------------------------------------------------------------------------
/tests/templates/remove_sql_cert.j2:
--------------------------------------------------------------------------------
1 | DROP CERTIFICATE {{ mssql_ha_cert_name }};
2 |
--------------------------------------------------------------------------------
/tests/templates/separate_from_ag.j2:
--------------------------------------------------------------------------------
1 | DROP DATABASE {{ __mssql_test_database }}
2 | DROP AVAILABILITY GROUP {{ mssql_ha_ag_name }}
3 |
--------------------------------------------------------------------------------
/tests/tests_2019_upgrade.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Ensure that the role installs version 2017 and upgrades to 2019
4 | hosts: all
5 | vars:
6 | mssql_accept_microsoft_odbc_driver_for_sql_server_eula: true
7 | mssql_accept_microsoft_cli_utilities_for_sql_server_eula: true
8 | mssql_accept_microsoft_sql_server_standard_eula: true
9 | __mssql_gather_facts_no_log: true
10 | tasks:
11 | - name: Assert fail on EL 7 with version=2022 and EL 9 with version!=2022
12 | include_tasks: tasks/assert_fail_on_unsupported_ver.yml
13 | vars:
14 | mssql_version: 2017
15 |
16 | - name: Run test in a block to clean up in always
17 | block:
18 | - name: Verify the failure when mssql_version is provided incorrectly
19 | block:
20 | - name: Run the role with incorrect mssql_version
21 | include_role:
22 | name: linux-system-roles.mssql
23 | public: true
24 | vars:
25 | mssql_version: 2018
26 |
27 | - name: Unreachable task
28 | fail:
29 | msg: The above task must fail
30 |
31 | rescue:
32 | - name: Assert that the role failed with the correct message
33 | assert:
34 | that: >-
35 | 'You must set the mssql_version variable to one of
36 | {{ __mssql_supported_versions | join(", ") }}'
37 | in ansible_failed_result.msg
38 |
39 | - name: Verify the failure when mssql_version is not provided
40 | block:
41 | - name: Run the role with incorrect mssql_version
42 | include_role:
43 | name: linux-system-roles.mssql
44 | public: true
45 |
46 | - name: Unreachable task
47 | fail:
48 | msg: The above task must fail
49 |
50 | rescue:
51 | - name: Assert that the role failed with the correct message
52 | assert:
53 | that: >-
54 | 'You must set the mssql_version variable to one of
55 | {{ __mssql_supported_versions | join(", ") }}'
56 | in ansible_failed_result.msg
57 |
58 | - name: Set up MSSQL 2017
59 | include_role:
60 | name: linux-system-roles.mssql
61 | vars:
62 | mssql_version: 2017
63 | mssql_password: "p@55w0rD"
64 | mssql_edition: Evaluation
65 |
66 | - name: Upgrade to 2019 and assert expected results
67 | include_tasks: tasks/upgrade_and_assert.yml
68 | vars:
69 | __mssql_version: 2019
70 | __mssql_prev_version: 2017
71 |
72 | - name: Check the ansible_managed header in the configuration file
73 | include_tasks: tasks/check_header.yml
74 | always:
75 | - name: Clean up after the role invocation
76 | include_tasks: tasks/cleanup.yml
77 |
--------------------------------------------------------------------------------
/tests/tests_2022_upgrade.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Ensure that the role installs version 2017 and upgrades to 2019
4 | hosts: all
5 | vars:
6 | mssql_accept_microsoft_odbc_driver_for_sql_server_eula: true
7 | mssql_accept_microsoft_cli_utilities_for_sql_server_eula: true
8 | mssql_accept_microsoft_sql_server_standard_eula: true
9 | __mssql_gather_facts_no_log: true
10 | tasks:
11 | - name: Assert fail on EL 7 with version=2022 and EL 9 with version!=2022
12 | include_tasks: tasks/assert_fail_on_unsupported_ver.yml
13 | vars:
14 | mssql_version: 2019
15 |
16 | - name: Run test in a block to clean up in always
17 | block:
18 | - name: Verify the failure when mssql_version is provided incorrectly
19 | block:
20 | - name: Run the role with incorrect mssql_version
21 | include_role:
22 | name: linux-system-roles.mssql
23 | public: true
24 | vars:
25 | mssql_version: 2018
26 |
27 | - name: Unreachable task
28 | fail:
29 | msg: The above task must fail
30 |
31 | rescue:
32 | - name: Assert that the role failed with the correct message
33 | assert:
34 | that: >-
35 | 'You must set the mssql_version variable to one of
36 | {{ __mssql_supported_versions | join(", ") }}'
37 | in ansible_failed_result.msg
38 |
39 | - name: Verify the failure when mssql_version is not provided
40 | block:
41 | - name: Run the role with incorrect mssql_version
42 | include_role:
43 | name: linux-system-roles.mssql
44 | public: true
45 |
46 | - name: Unreachable task
47 | fail:
48 | msg: The above task must fail
49 |
50 | rescue:
51 | - name: Assert that the role failed with the correct message
52 | assert:
53 | that: >-
54 | 'You must set the mssql_version variable to one of
55 | {{ __mssql_supported_versions | join(", ") }}'
56 | in ansible_failed_result.msg
57 |
58 | - name: Set up MSSQL 2019
59 | include_role:
60 | name: linux-system-roles.mssql
61 | vars:
62 | mssql_version: 2019
63 | mssql_password: "p@55w0rD"
64 | mssql_edition: Evaluation
65 |
66 | - name: Upgrade to 2022 and assert expected results
67 | include_tasks: tasks/upgrade_and_assert.yml
68 | vars:
69 | __mssql_version: 2022
70 | __mssql_prev_version: 2019
71 |
72 | - name: Check the ansible_managed header in the configuration file
73 | include_tasks: tasks/check_header.yml
74 | always:
75 | - name: Clean up after the role invocation
76 | include_tasks: tasks/cleanup.yml
77 |
--------------------------------------------------------------------------------
/tests/tests_accept_eula.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Ensure that the role runs when EULA are accepted
4 | hosts: all
5 | vars:
6 | mssql_accept_microsoft_odbc_driver_for_sql_server_eula: true
7 | mssql_accept_microsoft_cli_utilities_for_sql_server_eula: true
8 | mssql_accept_microsoft_sql_server_standard_eula: true
9 | mssql_version: "{{
10 | '2022' if (ansible_distribution_major_version is version('9', '>=') or
11 | ansible_distribution in ['Fedora'])
12 | else '2017' }}"
13 | __mssql_test_confined_supported: "{{
14 | ((ansible_distribution in ['CentOS', 'RedHat']) and
15 | (ansible_distribution_major_version is version('9', '>='))) or
16 | (ansible_distribution in ['Fedora']) }}"
17 | mssql_manage_selinux: "{{ __mssql_test_confined_supported }}"
18 | mssql_run_selinux_confined: "{{ __mssql_test_confined_supported }}"
19 | __mssql_gather_facts_no_log: true
20 | tasks:
21 | - name: Run test in a block to clean up in always
22 | block:
23 | - name: Verify the failure on a fresh host when required vars undefined
24 | block:
25 | - name: Run the role with default parameters
26 | include_role:
27 | name: linux-system-roles.mssql
28 |
29 | - name: Unreachable task
30 | fail:
31 | msg: The above task must fail
32 |
33 | rescue:
34 | - name: Assert that the role failed with variables undefined
35 | assert:
36 | that: >-
37 | 'You must define the following variables to set up MSSQL' in
38 | ansible_failed_result.msg.0
39 | always:
40 | - name: Clean up after the role invocation
41 | include_tasks: tasks/cleanup.yml
42 |
--------------------------------------------------------------------------------
/tests/tests_configure_ha_cluster_read_scale.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | # Example test inventory:
3 | # all:
4 | # hosts:
5 | # managed_host1:
6 | # ansible_host:
7 | # mssql_ha_replica_type: primary
8 | # managed_host2:
9 | # ansible_host:
10 | # mssql_ha_replica_type: synchronous
11 | # managed_host3:
12 | # ansible_host:
13 | # mssql_ha_replica_type: asynchronous
14 | ---
15 | - name: Verify HA functionality with read-scale clusters
16 | hosts: all
17 | vars:
18 | mssql_debug: true
19 | mssql_accept_microsoft_odbc_driver_for_sql_server_eula: true
20 | mssql_accept_microsoft_cli_utilities_for_sql_server_eula: true
21 | mssql_accept_microsoft_sql_server_standard_eula: true
22 | mssql_password: "p@55w0rD"
23 | mssql_edition: Evaluation
24 | mssql_version: 2022
25 | mssql_manage_firewall: true
26 | __mssql_gather_facts_no_log: true
27 | mssql_manage_selinux: false
28 | mssql_run_selinux_confined: false
29 | mssql_ha_configure: true
30 | mssql_ha_endpoint_port: 5022
31 | mssql_ha_cert_name: ExampleCert
32 | mssql_ha_master_key_password: "p@55w0rD1"
33 | mssql_ha_private_key_password: "p@55w0rD2"
34 | mssql_ha_reset_cert: false
35 | mssql_ha_endpoint_name: Example_Endpoint
36 | mssql_ha_ag_name: ExampleAG
37 | mssql_ha_db_names:
38 | - ExampleDB1
39 | - ExampleDB2
40 | mssql_ha_ag_cluster_type: none
41 | tasks:
42 | - name: Run test in a block to clean up in always
43 | when: ansible_play_hosts_all | length >= 3
44 | block:
45 | - name: Clusters of a read_scale type must not have a witness node
46 | meta: end_play
47 | when: ansible_play_hosts_all |
48 | map('extract', hostvars, 'mssql_ha_replica_type') |
49 | select('match', '^witness$') |
50 | list |
51 | length > 0
52 |
53 | - name: Verify that by default the role fails on EL < 8
54 | when:
55 | - ansible_distribution in ['CentOS', 'RedHat']
56 | - ansible_distribution_version is version('8', '<')
57 | block:
58 | - name: Run the role
59 | vars:
60 | mssql_ha_configure: true
61 | include_role:
62 | name: linux-system-roles.mssql
63 |
64 | - name: Unreachable task
65 | fail:
66 | msg: The above task must fail
67 | rescue:
68 | - name: Assert that the role failed with EL 7 not supported
69 | assert:
70 | that: >-
71 | 'mssql_ha_configure=true does not support running against EL 7
72 | hosts' in ansible_failed_result.msg
73 | always:
74 | - name: Clean up after the role invocation
75 | include_tasks: tasks/cleanup.yml
76 | when: ansible_play_hosts_all | length == 1
77 |
78 | # Putting end_host into a rescue block results in a failed task
79 | - name: End EL 7 host
80 | meta: end_host
81 |
82 | - name: Set facts to create test DBs on primary as a pre task
83 | set_fact:
84 | mssql_pre_input_sql_file:
85 | - create_ExampleDB1.sql
86 | - create_ExampleDB2.sql
87 | when: mssql_ha_replica_type == 'primary'
88 |
89 | - name: Run on all hosts to configure read-scale cluster
90 | include_role:
91 | name: linux-system-roles.mssql
92 |
93 | - name: Verify that the database exists on the secondary servers
94 | vars:
95 | __mssql_sql_content_to_input:
96 | - |-
97 | IF EXISTS(
98 | SELECT name
99 | FROM sys.databases
100 | WHERE name = 'ExampleDB1'
101 | )
102 | BEGIN
103 | PRINT 'SUCCESS, The database ExampleDB1 exists'
104 | END
105 | ELSE
106 | BEGIN
107 | PRINT 'FAIL, The database ExampleDB1 exists'
108 | END
109 | include_role:
110 | name: linux-system-roles.mssql
111 | tasks_from: input_sql_files.yml
112 |
113 | - name: Assert that the template reported changed state
114 | assert:
115 | that: >-
116 | "SUCCESS, The database ExampleDB1 exists" in
117 | __mssql_sqlcmd_input.stdout
118 | always:
119 | - name: Clean up after the role invocation
120 | include_tasks: tasks/cleanup.yml
121 |
--------------------------------------------------------------------------------
/tests/tests_default_2019.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Ensure that the role runs with default parameters
4 | hosts: all
5 | tasks:
6 | - name: Run test in a block to clean up in always
7 | block:
8 | - name: Verify that by default the role fails with EULA not accepted
9 | block:
10 | - name: Run the role with default parameters
11 | include_role:
12 | name: linux-system-roles.mssql
13 |
14 | - name: Unreachable task
15 | fail:
16 | msg: The above task must fail
17 |
18 | rescue:
19 | - name: Assert that the role failed with EULA not accepted
20 | assert:
21 | that: >-
22 | 'You must accept EULA' in ansible_failed_result.msg.0
23 | always:
24 | - name: Clean up after the role invocation
25 | include_tasks: tasks/cleanup.yml
26 |
--------------------------------------------------------------------------------
/tests/tests_idempotency_2017.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Ensure that the role is idempotent
4 | hosts: all
5 | gather_facts: false
6 | vars:
7 | mssql_accept_microsoft_odbc_driver_for_sql_server_eula: true
8 | mssql_accept_microsoft_cli_utilities_for_sql_server_eula: true
9 | mssql_accept_microsoft_sql_server_standard_eula: true
10 | mssql_version: 2017
11 | __mssql_gather_facts_no_log: true
12 | tasks:
13 | - name: Run test in a block to clean up in always
14 | block:
15 | - name: Run tests_idempotency with SQL Server {{ mssql_version }}
16 | include_tasks: tasks/tests_idempotency.yml
17 | always:
18 | - name: Clean up after the role invocation
19 | include_tasks: tasks/cleanup.yml
20 |
--------------------------------------------------------------------------------
/tests/tests_idempotency_2019.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Ensure that the role is idempotent
4 | hosts: all
5 | gather_facts: false
6 | vars:
7 | mssql_accept_microsoft_odbc_driver_for_sql_server_eula: true
8 | mssql_accept_microsoft_cli_utilities_for_sql_server_eula: true
9 | mssql_accept_microsoft_sql_server_standard_eula: true
10 | mssql_version: 2019
11 | __mssql_gather_facts_no_log: true
12 | tasks:
13 | - name: Run test in a block to clean up in always
14 | block:
15 | - name: Run tests_idempotency with SQL Server {{ mssql_version }}
16 | include_tasks: tasks/tests_idempotency.yml
17 | always:
18 | - name: Clean up after the role invocation
19 | include_tasks: tasks/cleanup.yml
20 |
--------------------------------------------------------------------------------
/tests/tests_idempotency_2022.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Ensure that the role is idempotent
4 | hosts: all
5 | gather_facts: false
6 | vars:
7 | mssql_accept_microsoft_odbc_driver_for_sql_server_eula: true
8 | mssql_accept_microsoft_cli_utilities_for_sql_server_eula: true
9 | mssql_accept_microsoft_sql_server_standard_eula: true
10 | mssql_version: 2022
11 | mssql_manage_selinux: "{{ mssql_run_selinux_confined }}"
12 | __mssql_gather_facts_no_log: true
13 | tasks:
14 | - name: Run test in a block to clean up in always
15 | block:
16 | - name: Run tests_idempotency with SQL Server {{ mssql_version }}
17 | include_tasks: tasks/tests_idempotency.yml
18 | always:
19 | - name: Clean up after the role invocation
20 | include_tasks: tasks/cleanup.yml
21 |
--------------------------------------------------------------------------------
/tests/tests_include_vars_from_parent.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test role include variable override
3 | hosts: all
4 | gather_facts: true
5 | tasks:
6 | - name: Run test in a block to clean up in always
7 | block:
8 | - name: >-
9 | Create var file in caller that can override the one in called role
10 | delegate_to: localhost
11 | copy:
12 | # usually the fake file will cause the called role to crash of
13 | # overriding happens, but if not, set a variable that will
14 | # allow to detect the bug
15 | content: "__caller_override: true"
16 | # XXX ugly, self-modifying code - changes the "caller" role on
17 | # the controller
18 | dest: "{{ playbook_dir }}/roles/caller/vars/{{ item }}.yml"
19 | mode: preserve
20 | loop: "{{ varfiles | unique }}"
21 | # In case the playbook is executed against multiple hosts, use
22 | # only the first one. Otherwise the hosts would stomp on each
23 | # other since they are changing files on the controller.
24 | when: inventory_hostname == ansible_play_hosts_all[0]
25 | vars:
26 | # change to hostvars['localhost']['ansible_facts'] to use the
27 | # information for localhost
28 | facts: "{{ ansible_facts }}"
29 | versions:
30 | - "{{ facts['distribution_version'] }}"
31 | - "{{ facts['distribution_major_version'] }}"
32 | separators: ["-", "_"]
33 | # create all variants like CentOS, CentOS_8.1, CentOS-8.1,
34 | # CentOS-8, CentOS-8.1
35 | # more formally:
36 | # {{ ansible_distribution }}-{{ ansible_distribution_version }}
37 | # {{ ansible_distribution }}-\
38 | # {{ ansible_distribution_major_version }}
39 | # {{ ansible_distribution }}
40 | # {{ ansible_os_family }}
41 | # and the same for _ as separator.
42 | varfiles: "{{ [facts['distribution']] | product(separators) |
43 | map('join') | product(versions) | map('join') | list +
44 | [facts['distribution'], facts['os_family']] }}"
45 | register: __varfiles_created
46 |
47 | - name: Import role
48 | import_role:
49 | name: caller
50 | vars:
51 | roletoinclude: linux-system-roles.mssql
52 | mssql_accept_microsoft_odbc_driver_for_sql_server_eula: true
53 | mssql_accept_microsoft_cli_utilities_for_sql_server_eula: true
54 | mssql_accept_microsoft_sql_server_standard_eula: true
55 | mssql_version: "{{
56 | '2022' if (ansible_distribution_major_version
57 | is version('9', '>=') or
58 | ansible_distribution in ['Fedora'])
59 | else '2017' }}"
60 | mssql_password: P@55w0rD
61 | mssql_edition: Evaluation
62 | __mssql_test_confined_supported: "{{
63 | ((ansible_distribution in ['CentOS', 'RedHat']) and
64 | (ansible_distribution_major_version is version('9', '>='))) or
65 | (ansible_distribution in ['Fedora']) }}"
66 | mssql_manage_selinux: "{{ __mssql_test_confined_supported }}"
67 | mssql_run_selinux_confined: "{{ __mssql_test_confined_supported }}"
68 | always:
69 | - name: Cleanup
70 | file:
71 | path: "{{ item.dest }}"
72 | state: absent
73 | loop: "{{ __varfiles_created.results }}"
74 | delegate_to: localhost
75 | when: inventory_hostname == ansible_play_hosts_all[0]
76 |
77 | - name: Clean up after the role invocation
78 | include_tasks: tasks/cleanup.yml
79 |
--------------------------------------------------------------------------------
/tests/tests_input_sql_file_2017.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Ensure that the role can input sql files to MSSQL
4 | hosts: all
5 | vars:
6 | mssql_accept_microsoft_odbc_driver_for_sql_server_eula: true
7 | mssql_accept_microsoft_cli_utilities_for_sql_server_eula: true
8 | mssql_accept_microsoft_sql_server_standard_eula: true
9 | mssql_debug: true
10 | mssql_version: 2017
11 | __mssql_gather_facts_no_log: true
12 | tasks:
13 | - name: Run test in a block to clean up in always
14 | block:
15 | - name: Run tests_input_sql_file with SQL Server {{ mssql_version }}
16 | include_tasks: tasks/tests_input_sql_file.yml
17 | always:
18 | - name: Clean up after the role invocation
19 | include_tasks: tasks/cleanup.yml
20 |
--------------------------------------------------------------------------------
/tests/tests_input_sql_file_2019.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Ensure that the role can input sql files to MSSQL
4 | hosts: all
5 | vars:
6 | mssql_accept_microsoft_odbc_driver_for_sql_server_eula: true
7 | mssql_accept_microsoft_cli_utilities_for_sql_server_eula: true
8 | mssql_accept_microsoft_sql_server_standard_eula: true
9 | mssql_debug: true
10 | mssql_version: 2019
11 | __mssql_gather_facts_no_log: true
12 | tasks:
13 | - name: Run test in a block to clean up in always
14 | block:
15 | - name: Run tests_input_sql_file with SQL Server {{ mssql_version }}
16 | include_tasks: tasks/tests_input_sql_file.yml
17 | always:
18 | - name: Clean up after the role invocation
19 | include_tasks: tasks/cleanup.yml
20 |
--------------------------------------------------------------------------------
/tests/tests_input_sql_file_2022.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Ensure that the role can input sql files to MSSQL
4 | hosts: all
5 | tags:
6 | # this test doesn't work in container builds
7 | - tests::booted
8 | vars:
9 | mssql_accept_microsoft_odbc_driver_for_sql_server_eula: true
10 | mssql_accept_microsoft_cli_utilities_for_sql_server_eula: true
11 | mssql_accept_microsoft_sql_server_standard_eula: true
12 | mssql_debug: true
13 | mssql_version: 2022
14 | mssql_manage_selinux: "{{ mssql_run_selinux_confined }}"
15 | __mssql_gather_facts_no_log: true
16 | tasks:
17 | - name: Run test in a block to clean up in always
18 | block:
19 | - name: Run tests_input_sql_file with SQL Server {{ mssql_version }}
20 | include_tasks: tasks/tests_input_sql_file.yml
21 | always:
22 | - name: Clean up after the role invocation
23 | include_tasks: tasks/cleanup.yml
24 |
--------------------------------------------------------------------------------
/tests/tests_password_2017.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Ensure that the role is idempotent when changing the sa user password
4 | hosts: all
5 | vars:
6 | mssql_accept_microsoft_odbc_driver_for_sql_server_eula: true
7 | mssql_accept_microsoft_cli_utilities_for_sql_server_eula: true
8 | mssql_accept_microsoft_sql_server_standard_eula: true
9 | mssql_version: 2017
10 | __mssql_gather_facts_no_log: true
11 | tasks:
12 | - name: Run test in a block to clean up in always
13 | block:
14 | - name: Run tests_password with SQL Server {{ mssql_version }}
15 | include_tasks: tasks/tests_password.yml
16 | always:
17 | - name: Clean up after the role invocation
18 | include_tasks: tasks/cleanup.yml
19 |
--------------------------------------------------------------------------------
/tests/tests_password_2019.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Ensure that the role is idempotent when changing the sa user password
4 | hosts: all
5 | vars:
6 | mssql_accept_microsoft_odbc_driver_for_sql_server_eula: true
7 | mssql_accept_microsoft_cli_utilities_for_sql_server_eula: true
8 | mssql_accept_microsoft_sql_server_standard_eula: true
9 | mssql_version: 2019
10 | __mssql_gather_facts_no_log: true
11 | tasks:
12 | - name: Run test in a block to clean up in always
13 | block:
14 | - name: Run tests_password with SQL Server {{ mssql_version }}
15 | include_tasks: tasks/tests_password.yml
16 | always:
17 | - name: Clean up after the role invocation
18 | include_tasks: tasks/cleanup.yml
19 |
--------------------------------------------------------------------------------
/tests/tests_password_2022.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Ensure that the role is idempotent when changing the sa user password
4 | hosts: all
5 | vars:
6 | mssql_accept_microsoft_odbc_driver_for_sql_server_eula: true
7 | mssql_accept_microsoft_cli_utilities_for_sql_server_eula: true
8 | mssql_accept_microsoft_sql_server_standard_eula: true
9 | mssql_version: 2022
10 | mssql_manage_selinux: "{{ mssql_run_selinux_confined }}"
11 | __mssql_gather_facts_no_log: true
12 | tasks:
13 | - name: Run test in a block to clean up in always
14 | block:
15 | - name: Run tests_password with SQL Server {{ mssql_version }}
16 | include_tasks: tasks/tests_password.yml
17 | always:
18 | - name: Clean up after the role invocation
19 | include_tasks: tasks/cleanup.yml
20 | when: not __bootc_validation | d(false)
21 |
--------------------------------------------------------------------------------
/tests/tests_selinux_enforcing_2022.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Test mssql_run_selinux_confined
4 | hosts: all
5 | gather_facts: false
6 | vars:
7 | mssql_accept_microsoft_odbc_driver_for_sql_server_eula: true
8 | mssql_accept_microsoft_cli_utilities_for_sql_server_eula: true
9 | mssql_accept_microsoft_sql_server_standard_eula: true
10 | mssql_version: 2022
11 | mssql_password: "p@55w0rD"
12 | mssql_edition: Evaluation
13 | __mssql_gather_facts_no_log: true
14 | tasks:
15 | - name: Assert expected failures on unsupported platforms
16 | include_tasks: tasks/assert_fail_on_unsupported_ver.yml
17 |
18 | - name: Check error message on not supported hosts and clean up
19 | when:
20 | - ansible_distribution in ['CentOS', 'RedHat']
21 | - ansible_distribution_major_version is version('9', '<')
22 | block:
23 | - name: Check error message on not supported hosts
24 | include_role:
25 | name: linux-system-roles.mssql
26 | vars:
27 | mssql_manage_selinux: true
28 | mssql_run_selinux_confined: true
29 | rescue:
30 | - name: Assert that the role failed with selinux_confined not supported
31 | assert:
32 | that: >-
33 | 'Variables mssql_run_selinux_confined and mssql_manage_selinux are
34 | supported only on RHEL 9' in ansible_failed_result.msg
35 | always:
36 | - name: Clean up after the role invocation
37 | include_tasks: tasks/cleanup.yml
38 |
39 | - name: End unsupported host
40 | meta: end_host
41 |
42 | - name: Run test in a block to clean up in always
43 | block:
44 | - name: Run with selinux_confined
45 | include_role:
46 | name: linux-system-roles.mssql
47 | vars:
48 | mssql_manage_selinux: true
49 | mssql_run_selinux_confined: true
50 |
51 | - name: Verify settings
52 | include_tasks: tasks/verify_settings.yml
53 | vars:
54 | __verify_mssql_password: "p@55w0rD"
55 | __verify_mssql_edition: Evaluation
56 | __verify_mssql_is_confined: true
57 |
58 | - name: Configure the mssql-server service start limit interval and burst
59 | include_tasks: tasks/mssql-sever-increase-start-limit.yml
60 |
61 | - name: Run without selinux_confined
62 | include_role:
63 | name: linux-system-roles.mssql
64 | vars:
65 | mssql_manage_selinux: false
66 | mssql_run_selinux_confined: false
67 |
68 | - name: Verify settings
69 | include_tasks: tasks/verify_settings.yml
70 | vars:
71 | __verify_mssql_password: "p@55w0rD"
72 | __verify_mssql_edition: Evaluation
73 | __verify_mssql_is_confined: false
74 | always:
75 | - name: Clean up after the role invocation
76 | include_tasks: tasks/cleanup.yml
77 |
--------------------------------------------------------------------------------
/tests/tests_tcp_firewall_2017.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Verify the use of the firewall role to configure SQL Server TCP ports
4 | hosts: all
5 | vars:
6 | mssql_accept_microsoft_odbc_driver_for_sql_server_eula: true
7 | mssql_accept_microsoft_cli_utilities_for_sql_server_eula: true
8 | mssql_accept_microsoft_sql_server_standard_eula: true
9 | mssql_manage_firewall: true
10 | mssql_version: 2017
11 | __mssql_gather_facts_no_log: true
12 | tasks:
13 | - name: Run test in a block to clean up in always
14 | block:
15 | - name: Run tests_tcp_firewall with SQL Server {{ mssql_version }}
16 | include_tasks: tasks/tests_tcp_firewall.yml
17 | always:
18 | - name: Clean up after the role invocation
19 | include_tasks: tasks/cleanup.yml
20 |
--------------------------------------------------------------------------------
/tests/tests_tcp_firewall_2019.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Verify the use of the firewall role to configure SQL Server TCP ports
4 | hosts: all
5 | vars:
6 | mssql_accept_microsoft_odbc_driver_for_sql_server_eula: true
7 | mssql_accept_microsoft_cli_utilities_for_sql_server_eula: true
8 | mssql_accept_microsoft_sql_server_standard_eula: true
9 | mssql_manage_firewall: true
10 | mssql_version: 2019
11 | __mssql_gather_facts_no_log: true
12 | tasks:
13 | - name: Run test in a block to clean up in always
14 | block:
15 | - name: Run tests_tcp_firewall with SQL Server {{ mssql_version }}
16 | include_tasks: tasks/tests_tcp_firewall.yml
17 | always:
18 | - name: Clean up after the role invocation
19 | include_tasks: tasks/cleanup.yml
20 |
--------------------------------------------------------------------------------
/tests/tests_tcp_firewall_2022.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Verify the use of the firewall role to configure SQL Server TCP ports
4 | hosts: all
5 | tags:
6 | # FIXME: firewall role does not currently work in container builds
7 | # https://issues.redhat.com/browse/RHEL-88425
8 | - tests::booted
9 | vars:
10 | mssql_accept_microsoft_odbc_driver_for_sql_server_eula: true
11 | mssql_accept_microsoft_cli_utilities_for_sql_server_eula: true
12 | mssql_accept_microsoft_sql_server_standard_eula: true
13 | mssql_manage_firewall: true
14 | mssql_version: 2022
15 | mssql_manage_selinux: "{{ mssql_run_selinux_confined }}"
16 | __mssql_gather_facts_no_log: true
17 | tasks:
18 | - name: Run test in a block to clean up in always
19 | block:
20 | - name: Run tests_tcp_firewall with SQL Server {{ mssql_version }}
21 | include_tasks: tasks/tests_tcp_firewall.yml
22 | always:
23 | - name: Clean up after the role invocation
24 | include_tasks: tasks/cleanup.yml
25 |
--------------------------------------------------------------------------------
/tests/tests_tls_2017.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Ensure that tls encryption configuration works
4 | hosts: all
5 | vars:
6 | mssql_accept_microsoft_odbc_driver_for_sql_server_eula: true
7 | mssql_accept_microsoft_cli_utilities_for_sql_server_eula: true
8 | mssql_accept_microsoft_sql_server_standard_eula: true
9 | mssql_password: "p@55w0rD"
10 | mssql_edition: Evaluation
11 | mssql_tcp_port: 1433
12 | mssql_version: 2017
13 | mssql_tls_self_sign: true
14 | __mssql_gather_facts_no_log: true
15 | tasks:
16 | - name: Run test in a block to clean up in always
17 | block:
18 | - name: Run tests_tls with SQL Server {{ mssql_version }}
19 | include_tasks: tasks/tests_tls.yml
20 | always:
21 | - name: Clean up after the role invocation
22 | include_tasks: tasks/cleanup.yml
23 |
--------------------------------------------------------------------------------
/tests/tests_tls_2019.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Ensure that tls encryption configuration works
4 | hosts: all
5 | vars:
6 | mssql_accept_microsoft_odbc_driver_for_sql_server_eula: true
7 | mssql_accept_microsoft_cli_utilities_for_sql_server_eula: true
8 | mssql_accept_microsoft_sql_server_standard_eula: true
9 | mssql_password: "p@55w0rD"
10 | mssql_edition: Evaluation
11 | mssql_tcp_port: 1433
12 | mssql_version: 2019
13 | mssql_tls_self_sign: true
14 | __mssql_gather_facts_no_log: true
15 | tasks:
16 | - name: Run test in a block to clean up in always
17 | block:
18 | - name: Run tests_tls with SQL Server {{ mssql_version }}
19 | include_tasks: tasks/tests_tls.yml
20 | always:
21 | - name: Clean up after the role invocation
22 | include_tasks: tasks/cleanup.yml
23 |
--------------------------------------------------------------------------------
/tests/tests_tls_2022.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | - name: Ensure that tls encryption configuration works
4 | hosts: all
5 | tags:
6 | # certificate role can not work in container builds
7 | - tests::booted
8 | vars:
9 | mssql_accept_microsoft_odbc_driver_for_sql_server_eula: true
10 | mssql_accept_microsoft_cli_utilities_for_sql_server_eula: true
11 | mssql_accept_microsoft_sql_server_standard_eula: true
12 | mssql_password: "p@55w0rD"
13 | mssql_edition: Evaluation
14 | mssql_tcp_port: 1433
15 | mssql_version: 2022
16 | mssql_tls_self_sign: true
17 | mssql_manage_selinux: "{{ mssql_run_selinux_confined }}"
18 | __mssql_gather_facts_no_log: true
19 | tasks:
20 | - name: Run test in a block to clean up in always
21 | block:
22 | - name: Run tests_tls with SQL Server {{ mssql_version }}
23 | include_tasks: tasks/tests_tls.yml
24 | always:
25 | - name: Clean up after the role invocation
26 | include_tasks: tasks/cleanup.yml
27 |
--------------------------------------------------------------------------------
/tests/vars/rh_distros_vars.yml:
--------------------------------------------------------------------------------
1 | # vars for handling conditionals for RedHat and clones
2 | # DO NOT EDIT - file is auto-generated
3 | # repo is https://github.com/linux-system-roles/.github
4 | # file is playbooks/templates/tests/vars/rh_distros_vars.yml
5 | ---
6 | # Ansible distribution identifiers that the role treats like RHEL
7 | __mssql_rh_distros:
8 | - AlmaLinux
9 | - CentOS
10 | - RedHat
11 | - Rocky
12 |
13 | # Same as above but includes Fedora
14 | __mssql_rh_distros_fedora: "{{ __mssql_rh_distros + ['Fedora'] }}"
15 |
16 | # Use this in conditionals to check if distro is Red Hat or clone
17 | __mssql_is_rh_distro: "{{ ansible_distribution in __mssql_rh_distros }}"
18 |
19 | # Use this in conditionals to check if distro is Red Hat or clone, or Fedora
20 | __mssql_is_rh_distro_fedora: "{{ ansible_distribution in __mssql_rh_distros_fedora }}"
21 |
--------------------------------------------------------------------------------
/tests/vars/vault-variables.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | mssql_password: !vault |
4 | $ANSIBLE_VAULT;1.1;AES256
5 | 66336361663164656232326461653662643537386337346563613939356466313835383235313234
6 | 3634333565616161316639666662613564353237653663610a616639306439653033386664303839
7 | 30663030636161326137656235636230356162373234386461363632353863393161353035316162
8 | 3664353366373231360a343334326337353861366233656330363634353164316434616561333161
9 | 3234
10 |
--------------------------------------------------------------------------------
/tests/vault_pwd:
--------------------------------------------------------------------------------
1 | password
2 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | [lsr_config]
3 | lsr_enable = true
4 |
5 | [lsr_ansible-lint]
6 | configfile = {toxinidir}/.ansible-lint
7 |
--------------------------------------------------------------------------------
/vars/AlmaLinux_8.yml:
--------------------------------------------------------------------------------
1 | RedHat_8.yml
--------------------------------------------------------------------------------
/vars/CentOS_7.yml:
--------------------------------------------------------------------------------
1 | RedHat_7.yml
--------------------------------------------------------------------------------
/vars/CentOS_8.yml:
--------------------------------------------------------------------------------
1 | RedHat_8.yml
--------------------------------------------------------------------------------
/vars/RedHat.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | __mssql_server_repository: >-
4 | https://packages.microsoft.com/rhel/9/mssql-server-{{ mssql_version | int }}/
5 | __mssql_client_repository: >-
6 | https://packages.microsoft.com/rhel/9/prod/
7 | __mssql_supported_versions:
8 | - 2022
9 | __mssql_confined_supported: true
10 | __mssql_tuned_supported: true
11 |
--------------------------------------------------------------------------------
/vars/RedHat_7.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | __mssql_server_repository: >-
4 | https://packages.microsoft.com/rhel/7/mssql-server-{{ mssql_version | int }}/
5 | __mssql_client_repository: >-
6 | https://packages.microsoft.com/rhel/7/prod/
7 | __mssql_supported_versions:
8 | - 2017
9 | - 2019
10 | __mssql_confined_supported: false
11 |
--------------------------------------------------------------------------------
/vars/RedHat_8.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | __mssql_server_repository: >-
4 | https://packages.microsoft.com/rhel/8/mssql-server-{{ mssql_version | int }}/
5 | __mssql_client_repository: >-
6 | https://packages.microsoft.com/rhel/8/prod/
7 | __mssql_supported_versions:
8 | - 2017
9 | - 2019
10 | - 2022
11 | __mssql_confined_supported: false
12 |
--------------------------------------------------------------------------------
/vars/Rocky_8.yml:
--------------------------------------------------------------------------------
1 | RedHat_8.yml
--------------------------------------------------------------------------------
/vars/Suse.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | __mssql_base_repository: "https://packages.microsoft.com/sles/{{ ansible_facts['distribution_major_version'] | int }}/"
4 | __mssql_server_repository: "{{ __mssql_base_repository }}mssql-server-{{ mssql_version | int }}/"
5 | __mssql_client_repository: "{{ __mssql_base_repository }}prod/"
6 | __mssql_client_packages: "mssql-tools{{ '' if __sqlcmd_ver == '17' else __sqlcmd_ver }}"
7 | __mssql_supported_versions:
8 | - 2019
9 | - 2022
10 | __mssql_confined_supported: false
11 | __mssql_tuned_supported: false
12 |
--------------------------------------------------------------------------------
/vars/main.yml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | ---
3 | __mssql_required_facts:
4 | - distribution
5 | - distribution_major_version
6 | - distribution_version
7 | - os_family
8 | # the subsets of ansible_facts that need to be gathered in case any of the
9 | # facts in required_facts is missing; see the documentation of
10 | # the 'gather_subset' parameter of the 'setup' module
11 | __mssql_required_facts_subsets: "{{ ['!all', '!min'] +
12 | __mssql_required_facts }}"
13 | __mssql_server_packages: mssql-server
14 | __mssql_server_selinux_packages: mssql-server-selinux
15 | __sqlcmd_ver: "{{ mssql_tools_versions | sort | last }}"
16 | __sqlcmd_cli: "{{
17 | '/opt/mssql-tools/bin/sqlcmd' if __sqlcmd_ver == '17'
18 | else '/opt/mssql-tools' + __sqlcmd_ver + '/bin/sqlcmd' }}"
19 | __mssql_client_packages:
20 | - mssql-tools{{ '' if __sqlcmd_ver == '17' else __sqlcmd_ver }}
21 | - unixODBC-devel
22 | __mssql_server_fts_packages: mssql-server-fts
23 | __mssql_server_ha_packages: mssql-server-ha
24 | __mssql_powershell_packages: powershell
25 | # Dicts define SQL Server version and the corresponding mssql-server version
26 | __mssql_version_package_mapping:
27 | - 2017: 14
28 | - 2019: 15
29 | - 2022: 16
30 | __mssql_keytab_path: /var/opt/mssql/secrets/mssql.keytab
31 | __mssql_conf_path: /var/opt/mssql/mssql.conf
32 | __mssql_conf_cli: /opt/mssql/bin/mssql-conf
33 | __mssql_ha_replica_types_all:
34 | - primary
35 | - synchronous
36 | - asynchronous
37 | - witness
38 | - absent
39 | __mssql_ha_replica_types_secondary:
40 | - synchronous
41 | - asynchronous
42 | - witness
43 | __mssql_ha_replica_types_external:
44 | - primary
45 | - synchronous
46 | - asynchronous
47 | __mssql_ha_endpoint_role: >-
48 | {%- if mssql_ha_replica_type in __mssql_ha_replica_types_external -%}
49 | ALL
50 | {%- elif mssql_ha_replica_type == 'witness' -%}
51 | WITNESS
52 | {%- else -%}
53 | null
54 | {%- endif -%}
55 | __mssql_ha_db_failover: >-
56 | {%- if mssql_ha_ag_cluster_type | lower == 'external' -%}
57 | ON
58 | {%- elif mssql_ha_ag_cluster_type | lower == 'none' -%}
59 | OFF
60 | {%- else -%}
61 | null
62 | {%- endif -%}
63 | __mssql_ha_cert_dest: /var/opt/mssql/data/{{ mssql_ha_cert_name }}.cer
64 | __mssql_ha_private_key_dest: /var/opt/mssql/data/{{ mssql_ha_cert_name }}.pvk
65 |
66 | __mssql_ad_kinit_user: >-
67 | {{ mssql_ad_kerberos_user }}@{{ ad_integration_realm | upper }}
68 |
69 | # BEGIN - DO NOT EDIT THIS BLOCK - rh distros variables
70 | # Ansible distribution identifiers that the role treats like RHEL
71 | __mssql_rh_distros:
72 | - AlmaLinux
73 | - CentOS
74 | - RedHat
75 | - Rocky
76 |
77 | # Same as above but includes Fedora
78 | __mssql_rh_distros_fedora: "{{ __mssql_rh_distros + ['Fedora'] }}"
79 |
80 | # Use this in conditionals to check if distro is Red Hat or clone
81 | __mssql_is_rh_distro: "{{ ansible_distribution in __mssql_rh_distros }}"
82 |
83 | # Use this in conditionals to check if distro is Red Hat or clone, or Fedora
84 | __mssql_is_rh_distro_fedora: "{{ ansible_distribution in __mssql_rh_distros_fedora }}"
85 | # END - DO NOT EDIT THIS BLOCK - rh distros variables
86 |
--------------------------------------------------------------------------------