diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fb2d9db --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.vscode/ +.venv/ diff --git a/CHANGELOG.rst b/CHANGELOG.rst new file mode 100644 index 0000000..40301cd --- /dev/null +++ b/CHANGELOG.rst @@ -0,0 +1,19 @@ +========================== +msvsphere.ci Release Notes +========================== + +.. contents:: Topics + + +v0.1.0 +====== + +Release Summary +--------------- + +Initial msvsphere.ci collection release. + +New Roles +--------- + +- msvsphere.ci.postgresql_server - A role that installs and configures a PostgreSQL server diff --git a/LICENSE b/LICENSE index 2071b23..54edc7a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) +Copyright (c) 2023 Eugene Zamriy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/README.md b/README.md index fa5bd87..f5caaf5 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,79 @@ -# ansible-msvsphere.ci +# Ansible Collection - msvsphere.ci -Ansible collection for MSVSphere OS CI. \ No newline at end of file +The MSVSphere OS CI/CD collection. + +## Roles + +* [postgresql_server](roles/postgresql_server/README.md) + +## Documentation + +All bundled roles have a corresponding README.md file located at +`roles/ROLE_NAME/README.md`. + +You can also use the `ansible-doc` command, for example: + +```shell +$ ansible-doc --type role postgresql_server +``` + +## Development + +### Development environment configuration + +You must use a specific directory layout +`collections/ansible_collections/msvsphere/ci` to make molecule work. +For example: + +``` +$ mkdir -p ~/work/collections/ansible_collections/msvsphere/ci +$ git clone https://git.inferitos.ru/msvsphere/ansible-msvsphere.ci.git \ + ~/work/collections/ansible_collections/msvsphere/ci +``` + +In order to create and initialize a Python virtual environment run the +following commands in the project root: + +```shell +$ virtualenv .venv +$ . .venv/bin/activate +$ pip install -r requirements-devel.txt +``` + +### Testing + +Use the following commands to run molecule tests: + +```shell +# run all available test scenarios +$ molecule test --all + +# run the "postgresql_server-13" test scenario +$ molecule test -s postgresql_server-13 +``` + +### Releasing + +Update changelog entries: + +```shell +$ antsibull-changelog release +``` + +Build a release tarball: + +```shell +$ ansible-galaxy collection build +``` + +## License + +MIT. + +## Authors + +* [Eugene Zamriy](mailto:ezamriy@msvsphere-os.ru) + +## References + +* [Ansible Molecule](https://ansible.readthedocs.io/projects/molecule/) diff --git a/changelogs/.plugin-cache.yaml b/changelogs/.plugin-cache.yaml new file mode 100644 index 0000000..0b9486a --- /dev/null +++ b/changelogs/.plugin-cache.yaml @@ -0,0 +1,23 @@ +objects: + role: + postgresql_server: + description: A role that installs and configures a PostgreSQL server + name: postgresql_server + version_added: 0.1.0 +plugins: + become: {} + cache: {} + callback: {} + cliconf: {} + connection: {} + filter: {} + httpapi: {} + inventory: {} + lookup: {} + module: {} + netconf: {} + shell: {} + strategy: {} + test: {} + vars: {} +version: 0.1.0 diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml new file mode 100644 index 0000000..e240d74 --- /dev/null +++ b/changelogs/changelog.yaml @@ -0,0 +1,13 @@ +ancestor: null +releases: + 0.1.0: + changes: + release_summary: Initial msvsphere.ci collection release. + fragments: + - 0-initial-release.yml + objects: + role: + - description: A role that installs and configures a PostgreSQL server + name: postgresql_server + namespace: null + release_date: '2023-12-12' diff --git a/changelogs/config.yaml b/changelogs/config.yaml new file mode 100644 index 0000000..687a2f7 --- /dev/null +++ b/changelogs/config.yaml @@ -0,0 +1,33 @@ +changelog_filename_template: ../CHANGELOG.rst +changelog_filename_version_depth: 0 +changes_file: changelog.yaml +changes_format: combined +ignore_other_fragment_extensions: true +keep_fragments: false +archive_path_template: changelogs/fragments-archive +mention_ancestor: true +new_plugins_after_name: removed_features +notesdir: fragments +prelude_section_name: release_summary +prelude_section_title: Release Summary +sanitize_changelog: true +sections: +- - major_changes + - Major Changes +- - minor_changes + - Minor Changes +- - breaking_changes + - Breaking Changes / Porting Guide +- - deprecated_features + - Deprecated Features +- - removed_features + - Removed Features (previously deprecated) +- - security_fixes + - Security Fixes +- - bugfixes + - Bugfixes +- - known_issues + - Known Issues +title: msvsphere.ci +trivial_section_name: trivial +use_fqcn: true diff --git a/changelogs/fragments-archive/0-initial-release.yml b/changelogs/fragments-archive/0-initial-release.yml new file mode 100644 index 0000000..e11f845 --- /dev/null +++ b/changelogs/fragments-archive/0-initial-release.yml @@ -0,0 +1,2 @@ +--- +release_summary: Initial msvsphere.ci collection release. diff --git a/galaxy.yml b/galaxy.yml new file mode 100644 index 0000000..8698c1b --- /dev/null +++ b/galaxy.yml @@ -0,0 +1,18 @@ +namespace: msvsphere +name: ci +version: 0.1.0 +readme: README.md +authors: + - Eugene Zamriy +description: MSVSphere OS CI/CD collection +license_file: LICENSE +tags: + - linux + - msvsphere +dependencies: {} +repository: https://git.inferitos.ru/msvsphere/ansible-msvsphere.ci +homepage: https://git.inferitos.ru/msvsphere/ansible-msvsphere.ci +issues: https://git.inferitos.ru/msvsphere/ansible-msvsphere.ci/issues +build_ignore: + - .gitignore + - .vscode diff --git a/meta/runtime.yml b/meta/runtime.yml new file mode 100644 index 0000000..5c6fd35 --- /dev/null +++ b/meta/runtime.yml @@ -0,0 +1,2 @@ +--- +requires_ansible: '>=2.13' diff --git a/molecule/postgresql_server-13/molecule.yml b/molecule/postgresql_server-13/molecule.yml new file mode 100644 index 0000000..2144449 --- /dev/null +++ b/molecule/postgresql_server-13/molecule.yml @@ -0,0 +1,19 @@ +--- +driver: + name: vagrant + +platforms: + - name: msvsphere-9 + box: msvsphere/9 + memory: 1024 + cpus: 1 + +provisioner: + name: ansible + inventory: + group_vars: + all: + postgresql_major_version: '13' + playbooks: + converge: ../resources/tests/postgresql_server/playbooks/converge.yml + verify: ../resources/tests/postgresql_server/playbooks/verify.yml diff --git a/molecule/postgresql_server-15/molecule.yml b/molecule/postgresql_server-15/molecule.yml new file mode 100644 index 0000000..f426bf3 --- /dev/null +++ b/molecule/postgresql_server-15/molecule.yml @@ -0,0 +1,20 @@ +--- +driver: + name: vagrant + +platforms: + - name: msvsphere-9 + box: msvsphere/9 + memory: 1024 + cpus: 1 + +provisioner: + name: ansible + inventory: + group_vars: + all: + postgresql_major_version: '15' + postgresql_max_connections: 333 + playbooks: + converge: ../resources/tests/postgresql_server/playbooks/converge.yml + verify: ../resources/tests/postgresql_server/playbooks/verify.yml diff --git a/molecule/resources/tests/common/tasks/package_installed.yml b/molecule/resources/tests/common/tasks/package_installed.yml new file mode 100644 index 0000000..cd416d0 --- /dev/null +++ b/molecule/resources/tests/common/tasks/package_installed.yml @@ -0,0 +1,10 @@ +--- +- name: Collect installed packages facts + ansible.builtin.package_facts: + manager: rpm + +- name: Assert that package is installed + ansible.builtin.assert: + that: "'{{ package_name }}' in ansible_facts.packages|list" + fail_msg: "{{ package_name }} is not installed" + success_msg: "{{ package_name }} is installed" diff --git a/molecule/resources/tests/common/tasks/service_enabled_and_running.yml b/molecule/resources/tests/common/tasks/service_enabled_and_running.yml new file mode 100644 index 0000000..56ef196 --- /dev/null +++ b/molecule/resources/tests/common/tasks/service_enabled_and_running.yml @@ -0,0 +1,15 @@ +--- +- name: Collect service facts + ansible.builtin.service_facts: + +- name: Assert that service is enabled + ansible.builtin.assert: + that: "'enabled' in ansible_facts.services['{{ service_name }}.service'].status" + fail_msg: "{{ service_name }} is not enabled" + success_msg: "{{ service_name }} is enabled" + +- name: Assert that service is running + ansible.builtin.assert: + that: "'running' in ansible_facts.services['{{ service_name}}.service'].state" + fail_msg: "{{ service_name }} is not running" + success_msg: "{{ service_name }} is running" diff --git a/molecule/resources/tests/postgresql_server/playbooks/converge.yml b/molecule/resources/tests/postgresql_server/playbooks/converge.yml new file mode 100644 index 0000000..8b85841 --- /dev/null +++ b/molecule/resources/tests/postgresql_server/playbooks/converge.yml @@ -0,0 +1,11 @@ +--- +- name: Converge + hosts: all + gather_facts: true + become: true + + tasks: + - name: Test postgresql_server role + ansible.builtin.include_role: + name: msvsphere.ci.postgresql_server + rolespec_validate: true diff --git a/molecule/resources/tests/postgresql_server/playbooks/verify.yml b/molecule/resources/tests/postgresql_server/playbooks/verify.yml new file mode 100644 index 0000000..836fb6c --- /dev/null +++ b/molecule/resources/tests/postgresql_server/playbooks/verify.yml @@ -0,0 +1,54 @@ +--- +- name: Verify + hosts: all + become: true + tasks: + - include_tasks: ../../common/tasks/package_installed.yml + vars: + package_name: postgresql-server + + - name: Verify postgresql-server package version + ansible.builtin.assert: + that: | + (ansible_facts.packages['postgresql-server'][0]['version'] | split('.'))[0] == '{{ postgresql_major_version }}' + fail_msg: "installed postgresql-server major version is not '{{ postgresql_major_version }}'" + success_msg: "installed postgresql-server major version is '{{ postgresql_major_version }}'" + + - include_tasks: ../../common/tasks/service_enabled_and_running.yml + vars: + service_name: postgresql + + - name: Get postgresql service status + ansible.builtin.systemd_service: + name: postgresql + state: started + register: postgresql_service + + - name: Assert that postgresql service is starting after network-online.target + ansible.builtin.assert: + that: | + not postgresql_service.changed and + 'network-online.target' in (postgresql_service['status']['After'] | split) + fail_msg: 'postgresql service should be starting after network-online.target' + success_msg: 'postgresql service is starting after network-online.target' + + - name: Collect /var/lib/pgsql/data/pg_hba.conf file stats + ansible.builtin.stat: + path: /var/lib/pgsql/data/pg_hba.conf + register: pg_hba + + - name: Verify /var/lib/pgsql/data/pg_hba.conf stats + ansible.builtin.assert: + that: | + pg_hba.stat.exists and + pg_hba.stat.mode == '0600' and + pg_hba.stat.pw_name == 'postgres' and + pg_hba.stat.gr_name == 'postgres' + fail_msg: '/var/lib/pgsql/data/pg_hba.conf does not exist or has incorrect permissions' + success_msg: '/var/lib/pgsql/data/pg_hba.conf is verified' + + - include_tasks: ../../postgresql_server/tasks/postgresql_setting.yml + vars: + postgresql_setting_name: max_connections + postgresql_setting_value: "{{ postgresql_max_connections }}" + when: postgresql_max_connections is defined diff --git a/molecule/resources/tests/postgresql_server/tasks/postgresql_setting.yml b/molecule/resources/tests/postgresql_server/tasks/postgresql_setting.yml new file mode 100644 index 0000000..77ee333 --- /dev/null +++ b/molecule/resources/tests/postgresql_server/tasks/postgresql_setting.yml @@ -0,0 +1,15 @@ +--- +- name: Get postgresql configuration setting + ansible.builtin.command: "psql -t -A -c 'SHOW {{ postgresql_setting_name }}'" + become: true + become_user: postgres + register: postgresql_setting_rslt + +- name: Verify postgresql configuration setting + ansible.builtin.assert: + that: "postgresql_setting_rslt.stdout == '{{ postgresql_setting_value }}'" + fail_msg: > + postgresql setting {{ postgresql_setting_name }} value {{ postgresql_setting_rslt.stdout }} + does not match expected {{ postgresql_setting_value }} + success_msg: > + postgresql setting {{ postgresql_setting_name }} value is {{ postgresql_setting_value }} diff --git a/requirements-devel.txt b/requirements-devel.txt new file mode 100644 index 0000000..be9395d --- /dev/null +++ b/requirements-devel.txt @@ -0,0 +1,5 @@ +ansible-core==2.14.9 +antsibull-changelog==0.23.0 +molecule==6.0.2 +molecule-plugins==23.5.0 +molecule-plugins[vagrant]==23.5.0 diff --git a/roles/postgresql_server/README.md b/roles/postgresql_server/README.md new file mode 100644 index 0000000..afaced5 --- /dev/null +++ b/roles/postgresql_server/README.md @@ -0,0 +1,32 @@ +# msvsphere.ci.postgresql_server + +An Ansible role that installs and configures a PostgreSQL server. + +## Variables + +| Variable | Default value | Type | Description | Required | +| -------- | ------------- | ---- |----------- | -------- | +| postgresql_major_version | "13" | string | PostgreSQL major version. For MSVSphere 9.x possible values are "13" and "15". | no | +| postgresql_listen_address | | string | TCP/IP address(es) on which the server is to listen for connections. | no | +| postgresql_max_connections | | integer | Maximum number of concurrent connections. | no | +| postgresql_password_encryption | | string | Password encryption algorithm. Possible values are: `scram-sha-256` and `md5`. | no | + + +## Example playbook + +```yaml +--- +- hosts: all + roles: + - role: msvsphere.ci.postgresql_server + postgresql_major_version: '15' + postgresql_max_connections: 500 +``` + +## License + +MIT. + +## Authors + +* [Eugene Zamriy](mailto:ezamriy@msvsphere-os.ru) diff --git a/roles/postgresql_server/defaults/main.yml b/roles/postgresql_server/defaults/main.yml new file mode 100644 index 0000000..0d0a5c4 --- /dev/null +++ b/roles/postgresql_server/defaults/main.yml @@ -0,0 +1,4 @@ +--- +postgresql_major_version: '13' +postgresql_listen_address: '' +postgresql_password_encryption: '' diff --git a/roles/postgresql_server/files/10-after-network-online.conf b/roles/postgresql_server/files/10-after-network-online.conf new file mode 100644 index 0000000..758b827 --- /dev/null +++ b/roles/postgresql_server/files/10-after-network-online.conf @@ -0,0 +1,2 @@ +[Unit] +After=network-online.target diff --git a/roles/postgresql_server/handlers/main.yml b/roles/postgresql_server/handlers/main.yml new file mode 100644 index 0000000..29d7b69 --- /dev/null +++ b/roles/postgresql_server/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: restart postgresql + ansible.builtin.service: + name: postgresql + state: restarted diff --git a/roles/postgresql_server/meta/argument_specs.yml b/roles/postgresql_server/meta/argument_specs.yml new file mode 100644 index 0000000..7deb316 --- /dev/null +++ b/roles/postgresql_server/meta/argument_specs.yml @@ -0,0 +1,35 @@ +--- +argument_specs: + main: + short_description: A role that installs and configures a PostgreSQL server + author: Eugene Zamriy + version_added: '0.1.0' + options: + postgresql_major_version: + description: PostgreSQL major version. For MSVSphere 9.x possible values are "13" and "15". + default: '13' + choices: + - '13' + - '15' + type: 'str' + required: false + + postgresql_listen_address: + description: TCP/IP address(es) on which the server is to listen for connections. + type: 'str' + required: false + + postgresql_max_connections: + description: Maximum number of concurrent connections. + type: 'int' + required: false + + postgresql_password_encryption: + description: Password encryption algorithm. + default: '' + choices: + - '' + - scram-sha-256 + - md5 + type: 'str' + required: false diff --git a/roles/postgresql_server/meta/main.yml b/roles/postgresql_server/meta/main.yml new file mode 100644 index 0000000..cf23f32 --- /dev/null +++ b/roles/postgresql_server/meta/main.yml @@ -0,0 +1,15 @@ +--- +galaxy_info: + author: Eugene Zamriy + description: A role that installs and configures a PostgreSQL server. + company: Softline PJSC + license: MIT + min_ansible_version: 2.13 + platforms: + - name: EL + versions: + - "9" + galaxy_tags: + - postgresql + +dependencies: [] diff --git a/roles/postgresql_server/tasks/main.yml b/roles/postgresql_server/tasks/main.yml new file mode 100644 index 0000000..f5f9c19 --- /dev/null +++ b/roles/postgresql_server/tasks/main.yml @@ -0,0 +1,34 @@ +--- +- name: Install PostgreSQL server + ansible.builtin.dnf: + name: "{{ (postgresql_major_version == '13') | ternary('postgresql-server', '@postgresql:15/server') }}" + state: present + +- name: Init PostgreSQL database + ansible.builtin.command: postgresql-setup --initdb + args: + creates: /var/lib/pgsql/data/pg_hba.conf + +- name: Create /etc/systemd/system/postgresql.service.d directory + ansible.builtin.file: + path: /etc/systemd/system/postgresql.service.d + state: directory + owner: root + group: root + mode: '0755' + +- name: Configure PostgreSQL service to start after network is online + ansible.builtin.copy: + src: 10-after-network-online.conf + dest: /etc/systemd/system/postgresql.service.d/10-after-network-online.conf + owner: root + group: root + mode: '0644' + +- include_tasks: postgresql_conf.yml + +- name: Enable and start postgresql service + ansible.builtin.service: + name: postgresql + enabled: true + state: started diff --git a/roles/postgresql_server/tasks/postgresql_conf.yml b/roles/postgresql_server/tasks/postgresql_conf.yml new file mode 100644 index 0000000..494fcfc --- /dev/null +++ b/roles/postgresql_server/tasks/postgresql_conf.yml @@ -0,0 +1,30 @@ +--- +- name: Configure listen on IP addresses + ansible.builtin.lineinfile: + path: /var/lib/pgsql/data/postgresql.conf + regexp: '^\s*listen_addresses\s*=' + insertafter: '#\s*listen_addresses\s*=' + line: "listen_addresses = 'localhost, {{ postgresql_listen_address }}'" + when: postgresql_listen_address | trim != '' + notify: + - restart postgresql + +- name: Configure max connections number + ansible.builtin.lineinfile: + path: /var/lib/pgsql/data/postgresql.conf + regexp: '^\s*max_connections\s*=' + insertafter: '#\s*max_connections\s*=' + line: "max_connections = {{ postgresql_max_connections }}" + when: postgresql_max_connections is defined + notify: + - restart postgresql + +- name: Configure password encryption algorithm + ansible.builtin.lineinfile: + path: /var/lib/pgsql/data/postgresql.conf + regexp: '^\s*password_encryption\s*=' + insertafter: '#\s*password_encryption\s*=' + line: "password_encryption = {{ postgresql_password_encryption }}" + when: postgresql_password_encryption in ('scram-sha-256', 'md5') + notify: + - restart postgresql