diff --git a/roles/postgresql_server/README.md b/roles/postgresql_server/README.md new file mode 100644 index 00000000..c924e05c --- /dev/null +++ b/roles/postgresql_server/README.md @@ -0,0 +1,131 @@ +# postgresql_server + +Install PostgreSQL server for Cloudera Manager + +This role installs and configures a PostgreSQL server, primarily for use as a backend database for Cloudera Manager. It sets up the necessary packages, manages the PostgreSQL repository, configures essential database settings (e.g., `postgresql.conf`), and defines host-based authentication rules (`pg_hba.conf`). The role can also optionally create a database superuser and enable TLS for secure connections. It will also ensure the `psycopg2` (or `psycopg3`) Python client library is available. + +The role will: +- Optionally enable or disable the PostgreSQL package repository setup. +- Install PostgreSQL server packages, including client libraries and utilities. +- Ensure the `psycopg2` (or `psycopg3`) Python package is installed, which is often required for Ansible's PostgreSQL modules. +- Create a dedicated database superuser account if `create_database_admin_user` is `true`. +- Configure global PostgreSQL server settings by managing the `postgresql.conf` file. +- Configure host-based authentication (HBA) rules by managing the `pg_hba.conf` file, controlling client access. +- Optionally, enable and configure TLS for secure client-server connections, utilizing specified certificate, key, and CA files. +- Start and enable the PostgreSQL service. + +# Requirements + +- Target host must have internet access to download PostgreSQL packages and repository data. +- Root or `sudo` privileges are required to manage packages, services, and system configuration files. +- If `postgresql_tls_enabled` is `true`, ensure that the certificate, key, and CA files specified (`postgresql_tls_cert_path`, `postgresql_tls_key_path`, `postgresql_tls_ca_path`) are present on the target host prior to execution. + +# Dependencies + +- `community.general` +- `community.postgresql` + +In addition, the following role(s) are required: + +- `geerlingguy.postgres` + + +# Parameters + +| Variable | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `create_database_admin_user` | `bool` | `False` | `false` | Flag to specify if a database superuser should be created by this role. If `true`, `database_admin_user` and `database_admin_password` must be provided. | +| `database_admin_user` | `str` | `True` if `create_database_admin_user` is `true` | | Username for the database superuser account to be created. | +| `database_admin_password` | `str` | `True` if `create_database_admin_user` is `true` | | Password for the database superuser account to be created. | +| `postgresql_version` | `int` | `False` | `14` | PostgreSQL version to install (e.g., 12, 14, 16). | +| `postgresql_packages` | `list` of `str` | `False` | `[defaults based on OS]` | List of packages to install for the PostgreSQL server. If not defined, the role will use default package names specific to the OS distribution and PostgreSQL version. | +| `postgresql_repo_enabled` | `bool` | `False` | `true` | Flag enabling the setup and teardown of the PostgreSQL package repository. If `false`, the role will assume existing repositories are configured and will not modify them. | +| `postgresql_tls_enabled` | `bool` | `False` | `false` | Flag enabling TLS connections for the PostgreSQL server. | +| `postgresql_tls_cert_path` | `path` | `False` | `$PGDATA/server.crt` | Path to the TLS certificate file on the PostgreSQL server. If not specified, PostgreSQL typically uses a default path (e.g., `$PGDATA/server.crt`). | +| `postgresql_tls_key_path` | `path` | `False` | `$PGDATA/server.key` | Path to the TLS private key file on the PostgreSQL server. If not specified, PostgreSQL typically uses a default path (e.g., `$PGDATA/server.key`). | +| `postgresql_tls_ca_path` | `path` | `False` | `None` | Path to the TLS Certificate Authority (CA) file on the PostgreSQL server. If not specified, PostgreSQL will typically not use a CA file, impacting client certificate validation. | +| `postgresql_config_options` | `list` of `dict` | `False` | `[]` | List of global configuration entries for the `postgresql.conf` file. Each dictionary requires an `option` (parameter name) and a `value`. | +|     `option` | `str` | `True` | | Name of the PostgreSQL configuration parameter (e.g., `listen_addresses`). | +|     `value` | `str` | `True` | | Value of the PostgreSQL configuration parameter (e.g., `'*'`). | +| `postgresql_access_entries` | `list` of `dict` | `False` | `[]` | List of host-based authentication (HBA) entries for the `pg_hba.conf` file. Each dictionary requires `type`, `database`, `user`, and `auth_method`. `address` is optional. | +|     `type` | `str` | `True` | | Authentication scope type (e.g., `host`, `local`). | +|     `database` | `str` | `True` | | Database target for the HBA rule (e.g., `all`, `scm`). | +|     `user` | `str` | `True` | | User or user type for the HBA rule (e.g., `all`, `scm_user`). | +|     `address` | `str` | `False` | | Networking scope (e.g., `10.0.0.0/24`, `::1/128`). Required for `host` type. | +|     `auth_method` | `str` | `True` | | Authentication method (e.g., `md5`, `scram-sha-256`, `trust`). | + +# Example Playbook + +```yaml +- hosts: db_servers + tasks: + - name: Install PostgreSQL server with default settings + ansible.builtin.import_role: + name: cloudera.exe.postgresql_server + # Uses PostgreSQL 14, default packages, no admin user, no TLS, default configs. + + - name: Install PostgreSQL 16 with custom admin user and basic HBA + ansible.builtin.import_role: + name: cloudera.exe.postgresql_server + vars: + postgresql_version: 16 + create_database_admin_user: true + database_admin_user: "cm_admin" + database_admin_password: "MySuperSecurePassword" + postgresql_access_entries: + - type: host + database: all + user: all + address: 0.0.0.0/0 + auth_method: md5 + - type: host + database: all + user: all + address: ::/0 + auth_method: md5 + + - name: Install PostgreSQL with TLS enabled and custom configs + ansible.builtin.import_role: + name: cloudera.exe.postgresql_server + vars: + postgresql_version: 14 + postgresql_tls_enabled: true + postgresql_tls_cert_path: "/etc/pki/tls/certs/server.crt" + postgresql_tls_key_path: "/etc/pki/tls/private/server.key" + postgresql_tls_ca_path: "/etc/pki/tls/certs/ca.crt" + postgresql_config_options: + - option: ssl + value: on + - option: ssl_cert_file + value: "/etc/pki/tls/certs/server.crt" + - option: ssl_key_file + value: "/etc/pki/tls/private/server.key" + - option: ssl_ca_file + value: "/etc/pki/tls/certs/ca.crt" + - option: listen_addresses + value: "'*'" + postgresql_access_entries: + - type: hostssl # Enforce SSL for this rule + database: all + user: all + address: 0.0.0.0/0 + auth_method: scram-sha-256 +``` + +# License + +``` +Copyright 2024 Cloudera, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +``` diff --git a/roles/postgresql_server/defaults/main.yml b/roles/postgresql_server/defaults/main.yml new file mode 100644 index 00000000..0de36922 --- /dev/null +++ b/roles/postgresql_server/defaults/main.yml @@ -0,0 +1,31 @@ +--- +# Copyright 2024 Cloudera, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +postgresql_version: 14 + +postgresql_repo_enabled: true +# postgresql_packages: [] + +postgresql_tls_enabled: false +# postgresql_tls_cert_path: +# postgresql_tls_key_path: +# postgresql_tls_ca_path: + +# postgresql_config_options: [] +# postgresql_access_entries: [] + +create_database_admin_user: false +# database_admin_user: +# database_admin_password: diff --git a/roles/postgresql_server/files/utf8-template.sql b/roles/postgresql_server/files/utf8-template.sql new file mode 100644 index 00000000..614fcfc8 --- /dev/null +++ b/roles/postgresql_server/files/utf8-template.sql @@ -0,0 +1,24 @@ +-- Copyright 2024 Cloudera, Inc. +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. + +-- If unable to set encoding via /etc/locale.conf and LC_ALL="en_US.UTF-8" + +update pg_database set datallowconn = TRUE where datname = 'template0'; +\c template0 +update pg_database set datistemplate = FALSE where datname = 'template1'; +drop database template1; +create database template1 with template = template0 encoding = 'UTF8'; +update pg_database set datistemplate = TRUE where datname = 'template1'; +\c template1 +update pg_database set datallowconn = FALSE where datname = 'template0'; diff --git a/roles/postgresql_server/handlers/main.yml b/roles/postgresql_server/handlers/main.yml new file mode 100644 index 00000000..2c7d87a3 --- /dev/null +++ b/roles/postgresql_server/handlers/main.yml @@ -0,0 +1,24 @@ +--- +# Copyright 2024 Cloudera, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- name: Clean YUM metadata + ansible.builtin.command: yum clean metadata + changed_when: false + tags: molecule-idempotence-notest + +- name: Clean DNF metadata + ansible.builtin.command: dnf clean metadata + changed_when: false + tags: molecule-idempotence-notest diff --git a/roles/postgresql_server/meta/argument_specs.yml b/roles/postgresql_server/meta/argument_specs.yml new file mode 100644 index 00000000..ed5753dc --- /dev/null +++ b/roles/postgresql_server/meta/argument_specs.yml @@ -0,0 +1,116 @@ +--- +# Copyright 2024 Cloudera, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +argument_specs: + main: + short_description: Install PostgreSQL server for Cloudera Manager + description: + - Install and configure PostgreSQL server, including required users, for Cloudera Manager. + - Will install C(psycopg2) (or C(psycopg3)). + - Optionally, will enable TLS. + - Optionally, will create a database superuser. + author: Cloudera Labs + version_added: "5.0.0" + options: + create_database_admin_user: + description: + - Flag to specify if a database superuser should be created + type: bool + default: false + database_admin_user: + description: + - Username for database superuser account + type: str + required: false + database_admin_password: + description: + - Password for database superuser account + type: str + required: false + postgresql_version: + description: + - PostgreSQL version to install. + default: 14 + postgresql_packages: + description: + - List of packages for the PostgreSQL installation. + - If not defined, defaults are specified by OS distribution. + type: list + elements: str + postgresql_repo_enabled: + description: + - Flag enabling the setup and teardown of the PostgreSQL repository. + - If I(postgresql_repo_enable=no), then any existing repositories will be employed. + type: bool + default: true + postgresql_tls_enabled: + description: + - Flag enabling TLS connections. + type: bool + default: false + postgresql_tls_cert_path: + description: + - Path to the TLS certificate file. + - If not specified, the PostgreSQL server will employ its default, typically C($PGDATA/server.crt). + type: path + postgresql_tls_key_path: + description: + - Path to the TLS private key file. + - If not specified, the PostgreSQL server will employ its default, typically C($PGDATA/server.key). + type: path + postgresql_tls_ca_path: + description: + - Path to the TLS certificate authority (CA) file. + - If not specified, the PostgreSQL server will employ its default, typically C(None), i.e. empty. + type: path + postgresql_config_options: + description: + - List of global configuration entries for PostgreSQL server, i.e. C(postgres.conf) file. + type: list + elements: dict + options: + option: + description: + - Name of the parameter. + required: true + value: + description: + - Value of the parameter. + required: true + postgresql_access_entries: + description: + - List of host-based authentication (HBA) entries for PostgreSQL server, i.e. C(pg_hba.conf) file. + type: list + elements: dict + options: + type: + description: + - Authentication scope (type). + required: true + database: + description: + - Database target. + required: true + user: + description: + - User or user type. + required: true + address: + description: + - Networking scope. + auth_method: + description: + - Authentication method. + required: true diff --git a/roles/postgresql_server/molecule/default/converge.yml b/roles/postgresql_server/molecule/default/converge.yml new file mode 100644 index 00000000..3e10c8cc --- /dev/null +++ b/roles/postgresql_server/molecule/default/converge.yml @@ -0,0 +1,27 @@ +--- +# Copyright 2024 Cloudera, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- name: Converge + hosts: all + gather_facts: true + become: true + tasks: + - name: Install PostgreSQL + ansible.builtin.import_role: + name: cloudera.exe.postgresql_server + vars: + create_database_admin_user: true + database_admin_user: molecule + database_admin_password: molecule diff --git a/roles/postgresql_server/molecule/default/create.yml b/roles/postgresql_server/molecule/default/create.yml new file mode 100644 index 00000000..41583e5e --- /dev/null +++ b/roles/postgresql_server/molecule/default/create.yml @@ -0,0 +1,336 @@ +--- +# Copyright 2024 Cloudera, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- name: Create + hosts: localhost + connection: local + gather_facts: false + no_log: "{{ molecule_no_log }}" + vars: + # Run config handling + default_run_id: "{{ lookup('password', '/dev/null chars=ascii_lowercase length=5') }}" + default_run_config: + run_id: "{{ default_run_id }}" + + run_config_path: "{{ lookup('env', 'MOLECULE_EPHEMERAL_DIRECTORY') }}/run-config.yml" + run_config_from_file: "{{ (lookup('file', run_config_path, errors='ignore') or '{}') | from_yaml }}" + run_config: "{{ default_run_config | combine(run_config_from_file) }}" + + # Platform settings handling + default_assign_public_ip: true + default_aws_profile: "{{ lookup('env', 'AWS_PROFILE') }}" + default_boot_wait_seconds: 120 + default_instance_type: t3a.medium + default_key_inject_method: cloud-init # valid values: [cloud-init, ec2] + default_key_name: "molecule-{{ run_config.run_id }}" + default_private_key_path: "{{ lookup('env', 'MOLECULE_EPHEMERAL_DIRECTORY') }}/id_rsa" + default_public_key_path: "{{ default_private_key_path }}.pub" + default_ssh_user: ansible + default_ssh_port: 22 + default_user_data: "" + + default_security_group_name: "molecule-{{ run_config.run_id }}" + default_security_group_description: Ephemeral security group for Molecule instances + default_security_group_rules: + - proto: tcp + from_port: "{{ default_ssh_port }}" + to_port: "{{ default_ssh_port }}" + cidr_ip: "0.0.0.0/0" + - proto: icmp + from_port: 8 + to_port: -1 + cidr_ip: "0.0.0.0/0" + default_security_group_rules_egress: + - proto: -1 + from_port: 0 + to_port: 0 + cidr_ip: "0.0.0.0/0" + + platform_defaults: + assign_public_ip: "{{ default_assign_public_ip }}" + aws_profile: "{{ default_aws_profile }}" + boot_wait_seconds: "{{ default_boot_wait_seconds }}" + instance_type: "{{ default_instance_type }}" + key_inject_method: "{{ default_key_inject_method }}" + key_name: "{{ default_key_name }}" + private_key_path: "{{ default_private_key_path }}" + public_key_path: "{{ default_public_key_path }}" + security_group_name: "{{ default_security_group_name }}" + security_group_description: "{{ default_security_group_description }}" + security_group_rules: "{{ default_security_group_rules }}" + security_group_rules_egress: "{{ default_security_group_rules_egress }}" + ssh_user: "{{ default_ssh_user }}" + ssh_port: "{{ default_ssh_port }}" + cloud_config: {} + image: "" + image_name: "" + image_owner: [self] + name: "" + region: "" + security_groups: [] + tags: {} + volumes: [] + vpc_id: "" + vpc_subnet_id: "" + + # Merging defaults into a list of dicts is, it turns out, not straightforward + platforms: >- + {{ [platform_defaults | dict2items] + | product(molecule_yml.platforms | map('dict2items') | list) + | map('flatten', levels=1) + | list + | map('items2dict') + | list }} + pre_tasks: + - name: Validate platform configurations + ansible.builtin.assert: + that: + - platforms | length > 0 + - platform.name is string and platform.name | length > 0 + - platform.assign_public_ip is boolean + - platform.aws_profile is string + - platform.boot_wait_seconds is integer and platform.boot_wait_seconds >= 0 + - platform.cloud_config is mapping + - platform.image is string + - platform.image_name is string + - platform.image_owner is sequence or (platform.image_owner is string and platform.image_owner | length > 0) + - platform.instance_type is string and platform.instance_type | length > 0 + - platform.key_inject_method is in ["cloud-init", "ec2"] + - platform.key_name is string and platform.key_name | length > 0 + - platform.private_key_path is string and platform.private_key_path | length > 0 + - platform.public_key_path is string and platform.public_key_path | length > 0 + - platform.region is string + - platform.security_group_name is string and platform.security_group_name | length > 0 + - platform.security_group_description is string and platform.security_group_description | length > 0 + - platform.security_group_rules is sequence + - platform.security_group_rules_egress is sequence + - platform.security_groups is sequence + - platform.ssh_user is string and platform.ssh_user | length > 0 + - platform.ssh_port is integer and platform.ssh_port in range(1, 65536) + - platform.tags is mapping + - platform.volumes is sequence + - platform.vpc_id is string + - platform.vpc_subnet_id is string and platform.vpc_subnet_id | length > 0 + quiet: true + loop: "{{ platforms }}" + loop_control: + loop_var: platform + label: "{{ platform.name }}" + tasks: + - name: Write run config to file + ansible.builtin.copy: + dest: "{{ run_config_path }}" + content: "{{ run_config | to_yaml }}" + mode: "0600" + + - name: Generate local key pairs + community.crypto.openssh_keypair: + path: "{{ item.private_key_path }}" + type: rsa + size: 2048 + regenerate: never + loop: "{{ platforms }}" + loop_control: + label: "{{ item.name }}" + register: local_keypairs + + - name: Look up EC2 AMI(s) by owner and name (if image not set) + amazon.aws.ec2_ami_info: + owners: "{{ item.image_owner }}" + filters: "{{ item.image_filters | default({}) | combine(image_name_map) }}" + vars: + image_name_map: "{% if item.image_name is defined and item.image_name | length > 0 %}{{ {'name': item.image_name} }}{% else %}{}{% endif %}" + loop: "{{ platforms }}" + loop_control: + label: "{{ item.name }}" + when: not item.image + register: ami_info + + - name: Look up subnets to determine VPCs (if needed) + amazon.aws.ec2_vpc_subnet_info: + subnet_ids: "{{ item.vpc_subnet_id }}" + loop: "{{ platforms }}" + loop_control: + label: "{{ item.name }}" + when: not item.vpc_id + register: subnet_info + + - name: Validate discovered information + ansible.builtin.assert: + that: + - platform.image or (ami_info.results[index].images | length > 0) + - platform.vpc_id or (subnet_info.results[index].subnets | length > 0) + quiet: true + loop: "{{ platforms }}" + loop_control: + loop_var: platform + index_var: index + label: "{{ platform.name }}" + + - name: Create ephemeral EC2 keys (if needed) + amazon.aws.ec2_key: + profile: "{{ item.aws_profile | default(omit) }}" + region: "{{ item.region | default(omit) }}" + name: "{{ item.key_name }}" + key_material: "{{ local_keypair.public_key }}" + vars: + local_keypair: "{{ local_keypairs.results[index] }}" + loop: "{{ platforms }}" + loop_control: + index_var: index + label: "{{ item.name }}" + when: item.key_inject_method == "ec2" + register: ec2_keys + + - name: Create ephemeral security groups (if needed) + amazon.aws.ec2_security_group: + profile: "{{ item.aws_profile | default(omit) }}" + iam_instance_profile: "{{ item.iam_instance_profile | default(omit) }}" + region: "{{ item.region | default(omit) }}" + vpc_id: "{{ item.vpc_id or vpc_subnet.vpc_id }}" + name: "{{ item.security_group_name }}" + description: "{{ item.security_group_description }}" + rules: "{{ item.security_group_rules }}" + rules_egress: "{{ item.security_group_rules_egress }}" + vars: + vpc_subnet: "{{ subnet_info.results[index].subnets[0] }}" + loop: "{{ platforms }}" + loop_control: + index_var: index + label: "{{ item.name }}" + when: item.security_groups | length == 0 + + - name: Create ephemeral EC2 instance(s) + amazon.aws.ec2_instance: + profile: "{{ item.aws_profile | default(omit) }}" + region: "{{ item.region | default(omit) }}" + filters: "{{ platform_filters }}" + instance_type: "{{ item.instance_type }}" + image_id: "{{ platform_image_id }}" + vpc_subnet_id: "{{ item.vpc_subnet_id }}" + security_groups: "{{ platform_security_groups }}" + network: + assign_public_ip: "{{ item.assign_public_ip }}" + volumes: "{{ item.volumes }}" + key_name: "{{ (item.key_inject_method == 'ec2') | ternary(item.key_name, omit) }}" + tags: "{{ platform_tags }}" + user_data: "{{ platform_user_data }}" + state: "running" + wait: true + vars: + platform_security_groups: "{{ item.security_groups or [item.security_group_name] }}" + platform_generated_image_id: "{{ (ami_info.results[index].images | sort(attribute='creation_date', reverse=True))[0].image_id }}" + platform_image_id: "{{ item.image or platform_generated_image_id }}" + + platform_generated_cloud_config: + users: + - name: "{{ item.ssh_user }}" + ssh_authorized_keys: + - "{{ local_keypairs.results[index].public_key }}" + sudo: "ALL=(ALL) NOPASSWD:ALL" + platform_cloud_config: >- + {{ (item.key_inject_method == 'cloud-init') + | ternary((item.cloud_config | combine(platform_generated_cloud_config)), item.cloud_config) }} + platform_user_data: |- + #cloud-config + {{ platform_cloud_config | to_yaml }} + + platform_generated_tags: + instance: "{{ item.name }}" + "molecule-run-id": "{{ run_config.run_id }}" + platform_tags: "{{ (item.tags or {}) | combine(platform_generated_tags) }}" + platform_filter_keys: "{{ platform_generated_tags.keys() | map('regex_replace', '^(.+)$', 'tag:\\1') }}" + platform_filters: "{{ dict(platform_filter_keys | zip(platform_generated_tags.values())) }}" + loop: "{{ platforms }}" + loop_control: + index_var: index + label: "{{ item.name }}" + register: ec2_instances_async + async: 7200 + poll: 0 + + - name: Instance boot block + when: ec2_instances_async is changed + block: + - name: Wait for instance creation to complete + ansible.builtin.async_status: + jid: "{{ item.ansible_job_id }}" + loop: "{{ ec2_instances_async.results }}" + loop_control: + index_var: index + label: "{{ platforms[index].name }}" + register: ec2_instances + until: ec2_instances is finished + retries: 300 + + - name: Collect instance configs + ansible.builtin.set_fact: + instance_config: + instance: "{{ item.name }}" + address: "{{ item.assign_public_ip | ternary(instance.public_ip_address, instance.private_ip_address) }}" + user: "{{ item.ssh_user }}" + port: "{{ item.ssh_port }}" + identity_file: "{{ item.private_key_path }}" + instance_ids: + - "{{ instance.instance_id }}" + vars: + instance: "{{ ec2_instances.results[index].instances[0] }}" + loop: "{{ platforms }}" + loop_control: + index_var: index + label: "{{ item.name }}" + register: instance_configs + + - name: Write Molecule instance configs + ansible.builtin.copy: + dest: "{{ molecule_instance_config }}" + content: >- + {{ instance_configs.results + | map(attribute='ansible_facts.instance_config') + | list + | to_json + | from_json + | to_yaml }} + mode: "0600" + + - name: Start SSH pollers + ansible.builtin.wait_for: + host: "{{ item.address }}" + port: "{{ item.port }}" + search_regex: SSH + delay: 10 + timeout: 320 + loop: "{{ instance_configs.results | map(attribute='ansible_facts.instance_config') | list }}" + loop_control: + label: "{{ item.instance }}" + register: ssh_wait_async + async: 300 + poll: 0 + + - name: Wait for SSH + ansible.builtin.async_status: + jid: "{{ item.ansible_job_id }}" + loop: "{{ ssh_wait_async.results }}" + loop_control: + index_var: index + label: "{{ platforms[index].name }}" + register: ssh_wait + until: ssh_wait is finished + retries: 300 + delay: 1 + + - name: Wait for boot process to finish + ansible.builtin.pause: + seconds: "{{ platforms | map(attribute='boot_wait_seconds') | max }}" diff --git a/roles/postgresql_server/molecule/default/destroy.yml b/roles/postgresql_server/molecule/default/destroy.yml new file mode 100644 index 00000000..a090fe0b --- /dev/null +++ b/roles/postgresql_server/molecule/default/destroy.yml @@ -0,0 +1,157 @@ +--- +# Copyright 2024 Cloudera, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- name: Destroy + hosts: localhost + connection: local + gather_facts: false + no_log: "{{ molecule_no_log }}" + vars: + # Run config handling + default_run_id: "{{ lookup('password', '/dev/null chars=ascii_lowercase length=5') }}" + default_run_config: + run_id: "{{ default_run_id }}" + + run_config_path: "{{ lookup('env', 'MOLECULE_EPHEMERAL_DIRECTORY') }}/run-config.yml" + run_config_from_file: "{{ (lookup('file', run_config_path, errors='ignore') or '{}') | from_yaml }}" + run_config: "{{ default_run_config | combine(run_config_from_file) }}" + + # Platform settings handling + default_aws_profile: "{{ lookup('env', 'AWS_PROFILE') }}" + default_key_inject_method: cloud-init # valid values: [cloud-init, ec2] + default_key_name: "molecule-{{ run_config.run_id }}" + default_security_group_name: "molecule-{{ run_config.run_id }}" + + platform_defaults: + aws_profile: "{{ default_aws_profile }}" + key_inject_method: "{{ default_key_inject_method }}" + key_name: "{{ default_key_name }}" + region: "" + security_group_name: "{{ default_security_group_name }}" + security_groups: [] + vpc_id: "" + vpc_subnet_id: "" + + # Merging defaults into a list of dicts is, it turns out, not straightforward + platforms: >- + {{ [platform_defaults | dict2items] + | product(molecule_yml.platforms | map('dict2items') | list) + | map('flatten', levels=1) + | list + | map('items2dict') + | list }} + + # Stored instance config + instance_config: "{{ (lookup('file', molecule_instance_config, errors='ignore') or '{}') | from_yaml }}" + pre_tasks: + - name: Validate platform configurations + ansible.builtin.assert: + that: + - platforms | length > 0 + - platform.name is string and platform.name | length > 0 + - platform.aws_profile is string + - platform.key_inject_method is in ["cloud-init", "ec2"] + - platform.key_name is string and platform.key_name | length > 0 + - platform.region is string + - platform.security_group_name is string and platform.security_group_name | length > 0 + - platform.security_groups is sequence + - platform.vpc_id is string + - platform.vpc_subnet_id is string and platform.vpc_subnet_id | length > 0 + quiet: true + loop: "{{ platforms }}" + loop_control: + loop_var: platform + label: "{{ platform.name }}" + tasks: + - name: Look up subnets to determine VPCs (if needed) + amazon.aws.ec2_vpc_subnet_info: + profile: "{{ item.aws_profile | default(omit) }}" + region: "{{ item.region | default(omit) }}" + subnet_ids: "{{ item.vpc_subnet_id }}" + loop: "{{ platforms }}" + loop_control: + label: "{{ item.name }}" + when: not item.vpc_id + register: subnet_info + + - name: Validate discovered information + ansible.builtin.assert: + that: platform.vpc_id or (subnet_info.results[index].subnets | length > 0) + quiet: true + loop: "{{ platforms }}" + loop_control: + loop_var: platform + index_var: index + label: "{{ platform.name }}" + + - name: Destroy resources + when: instance_config | length != 0 + block: + - name: Destroy ephemeral EC2 instances + amazon.aws.ec2_instance: + profile: "{{ item.aws_profile | default(omit) }}" + region: "{{ item.region | default(omit) }}" + instance_ids: "{{ instance_config | map(attribute='instance_ids') | flatten }}" + vpc_subnet_id: "{{ item.vpc_subnet_id }}" + state: absent + loop: "{{ platforms }}" + loop_control: + label: "{{ item.name }}" + register: ec2_instances_async + async: 7200 + poll: 0 + + - name: Wait for instance destruction to complete + ansible.builtin.async_status: + jid: "{{ item.ansible_job_id }}" + loop: "{{ ec2_instances_async.results }}" + loop_control: + index_var: index + label: "{{ platforms[index].name }}" + register: ec2_instances + until: ec2_instances is finished + retries: 300 + + - name: Destroy ephemeral security groups (if needed) + amazon.aws.ec2_security_group: + profile: "{{ item.aws_profile | default(omit) }}" + region: "{{ item.region | default(omit) }}" + vpc_id: "{{ item.vpc_id or vpc_subnet.vpc_id }}" + name: "{{ item.security_group_name }}" + state: absent + vars: + vpc_subnet: "{{ subnet_info.results[index].subnets[0] }}" + loop: "{{ platforms }}" + loop_control: + index_var: index + label: "{{ item.name }}" + when: item.security_groups | length == 0 + + - name: Destroy ephemeral keys (if needed) + amazon.aws.ec2_key: + profile: "{{ item.aws_profile | default(omit) }}" + region: "{{ item.region | default(omit) }}" + name: "{{ item.key_name }}" + state: absent + loop: "{{ platforms }}" + loop_control: + index_var: index + label: "{{ item.name }}" + when: item.key_inject_method == "ec2" + + - name: Write Molecule instance configs + ansible.builtin.copy: + dest: "{{ molecule_instance_config }}" + content: "{{ {} | to_yaml }}" diff --git a/roles/postgresql_server/molecule/default/molecule.yml b/roles/postgresql_server/molecule/default/molecule.yml new file mode 100644 index 00000000..ad4bfc84 --- /dev/null +++ b/roles/postgresql_server/molecule/default/molecule.yml @@ -0,0 +1,53 @@ +--- +# Copyright 2024 Cloudera, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Requires a preexisting AWS VPC and subnet, the latter referenced by the +# environment variable, ROLE_SUBNET_ID, typically set in the Molecule ENV file +# which is /.env.yml + +# Requires AWS credentials, including region + +# Requires the following Python libraries on localhost +# - netattr +# - boto3 + +driver: + name: ec2 +platforms: + # RHEL 9.4 + - name: rhel9-4.molecule.internal + image_owner: "309956199498" + image_name: RHEL-9.4.0_HVM-* + instance_type: t3.medium + boot_wait_seconds: 15 + vpc_subnet_id: ${TEST_VPC_SUBNET_ID} + tags: + Name: molecule-postgresql_server-rhel9-4 + Project: Molecule testing for postgresql_server +# Ubuntu 20.04 +# - name: ubuntu20.04.molecule.internal +# image_owner: "099720109477" +# image_name: ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-* +# instance_type: t3.medium +# boot_wait_seconds: 15 +# vpc_subnet_id: ${TEST_VPC_SUBNET_ID} +# tags: +# Name: molecule-postgresql_server-ubuntu20-04 +# Project: Molecule testing for postgresql_server +provisioner: + name: ansible + # inventory: + # group_vars: + # all: diff --git a/roles/postgresql_server/molecule/default/requirements.yml b/roles/postgresql_server/molecule/default/requirements.yml new file mode 100644 index 00000000..02259c56 --- /dev/null +++ b/roles/postgresql_server/molecule/default/requirements.yml @@ -0,0 +1,23 @@ +--- +# Copyright 2024 Cloudera, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +collections: + - community.crypto + - amazon.aws + - ansible.utils + - community.general + - community.postgresql +roles: + - geerlingguy.postgresql diff --git a/roles/postgresql_server/molecule/default/side_effect.yml b/roles/postgresql_server/molecule/default/side_effect.yml new file mode 100644 index 00000000..8300df0c --- /dev/null +++ b/roles/postgresql_server/molecule/default/side_effect.yml @@ -0,0 +1,43 @@ +--- +# Copyright 2024 Cloudera, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- name: Add test users to PostgreSQL + hosts: all + gather_facts: true + become: true + tasks: + - name: Create test database + community.postgresql.postgresql_db: + name: test + become: true + become_user: postgres + + - name: Add authorized user + community.postgresql.postgresql_user: + db: test + name: user_one + password: authorized + comment: Authorized User + become: true + become_user: postgres + + - name: Add non-authorized user + community.postgresql.postgresql_user: + db: test + name: user_two + password: "" + comment: Unauthorized User + become: true + become_user: postgres diff --git a/roles/postgresql_server/molecule/default/verify.yml b/roles/postgresql_server/molecule/default/verify.yml new file mode 100644 index 00000000..ad1f17b2 --- /dev/null +++ b/roles/postgresql_server/molecule/default/verify.yml @@ -0,0 +1,58 @@ +--- +# Copyright 2024 Cloudera, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- name: Confirm local database access + hosts: all + gather_facts: false + tasks: + - name: Ping database locally + community.postgresql.postgresql_ping: + become: true + become_user: postgres + register: postgres_user + failed_when: not postgres_user.is_available + + - name: Confirm server encoding + community.postgresql.postgresql_query: + db: postgres + query: SHOW SERVER_ENCODING + become: true + become_user: postgres + register: postgres_encoding + failed_when: postgres_encoding.query_result | map(attribute="server_encoding") | first != "UTF8" + +- name: Confirm external database access + hosts: all + gather_facts: false + tasks: + - name: Ping database as authorized user + community.postgresql.postgresql_ping: + login_host: "0.0.0.0" + port: 5432 + db: test + login_user: user_one + login_password: authorized + register: authorized_user + failed_when: not authorized_user.is_available + + - name: Ping database as non-authorized user + community.postgresql.postgresql_ping: + login_host: "0.0.0.0" + port: 5432 + db: test + login_user: user_two + login_password: no_password_is_set + register: not_authorized_user + failed_when: not_authorized_user.is_available diff --git a/roles/postgresql_server/tasks/RedHat_post.yml b/roles/postgresql_server/tasks/RedHat_post.yml new file mode 100644 index 00000000..154f9200 --- /dev/null +++ b/roles/postgresql_server/tasks/RedHat_post.yml @@ -0,0 +1,39 @@ +--- +# Copyright 2024 Cloudera, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- name: Remove repositories and clean metadata + when: postgresql_repo_enabled + ansible.builtin.yum_repository: + name: "{{ repo }}" + state: absent + loop: + - pgdg-common + - pgdg + loop_control: + loop_var: repo + tags: molecule-idempotence-notest + notify: Clean YUM metadata + +# - name: Install psycopg2 build prerequisites +# when: ansible_distribution_major_version == "8" +# ansible.builtin.package: +# name: +# - gcc +# - libpq-devel + +# # This fails if the PSQL repositories are not removed +# - name: Install psycopg2 library +# ansible.builtin.pip: +# name: psycopg2-binary diff --git a/roles/postgresql_server/tasks/RedHat_pre.yml b/roles/postgresql_server/tasks/RedHat_pre.yml new file mode 100644 index 00000000..206aeae3 --- /dev/null +++ b/roles/postgresql_server/tasks/RedHat_pre.yml @@ -0,0 +1,57 @@ +--- +# Copyright 2024 Cloudera, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- name: Install PostgreSQL common repository + when: postgresql_repo_enabled + ansible.builtin.yum_repository: + name: pgdg-common + description: PostgreSQL common for RHEL/CentOS + baseurl: "https://download.postgresql.org/pub/repos/yum/common/redhat/rhel-$releasever-$basearch" + gpgkey: >- + https://download.postgresql.org/pub/repos/yum/keys/PGDG-RPM-GPG-KEY- + {{ (ansible_architecture in ['aarch64', 'arm64']) | ternary('AARCH64-', '') }} + RHEL + tags: molecule-idempotence-notest + +- name: Install PostgreSQL version repository + when: postgresql_repo_enabled + ansible.builtin.yum_repository: + name: pgdg + description: PostgreSQL {{ postgresql_version }} for RHEL/CentOS + baseurl: "https://download.postgresql.org/pub/repos/yum/{{ postgresql_version }}/redhat/rhel-$releasever-$basearch" + gpgkey: >- + https://download.postgresql.org/pub/repos/yum/keys/PGDG-RPM-GPG-KEY- + {{ (ansible_architecture in ['aarch64', 'arm64']) | ternary('AARCH64-', '') }} + RHEL + tags: molecule-idempotence-notest + +- name: Disable default Postgres module in RHEL 8 or greater + when: ansible_distribution_major_version | int >= 8 + ansible.builtin.command: dnf module disable -qy postgresql + register: __postgres_module_result + changed_when: + - '"Disabling modules" in __postgres_module_result.stdout' + failed_when: + - __postgres_module_result.rc != 0 and __postgres_module_result.rc != 1 + +- name: Set UTF-8 as default locale for database encoding + ansible.builtin.lineinfile: + path: /etc/locale.conf + line: 'LC_ALL="en_US.UTF-8"' + regexp: "^(#\\s+)LC_ALL=" + create: true + owner: root + group: root + mode: "0644" diff --git a/roles/postgresql_server/tasks/default.yml b/roles/postgresql_server/tasks/default.yml new file mode 100644 index 00000000..a60ed6e5 --- /dev/null +++ b/roles/postgresql_server/tasks/default.yml @@ -0,0 +1,15 @@ +# Copyright 2024 Cloudera, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# no-op diff --git a/roles/postgresql_server/tasks/main.yml b/roles/postgresql_server/tasks/main.yml new file mode 100644 index 00000000..06753da5 --- /dev/null +++ b/roles/postgresql_server/tasks/main.yml @@ -0,0 +1,84 @@ +--- +# Copyright 2024 Cloudera, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- name: Check superuser parameters + when: create_database_admin_user + ansible.builtin.assert: + that: + - database_admin_user is defined + - database_admin_password is defined + quiet: true + fail_msg: "Missing superuser parameters." + +- name: Load PostgreSQL variables for OS + ansible.builtin.include_vars: "{{ item }}" + with_first_found: + - "{{ ansible_facts['distribution'] }}-{{ ansible_facts['distribution_version'] }}.yml" + - "{{ ansible_facts['distribution'] }}-{{ ansible_facts['distribution_major_version'] }}.yml" + - "{{ ansible_facts['distribution'] }}.yml" + - "{{ ansible_facts['os_family'] }}-{{ ansible_facts['distribution_version'] }}.yml" + - "{{ ansible_facts['os_family'] }}-{{ ansible_facts['distribution_major_version'] }}.yml" + - "{{ ansible_facts['os_family'] }}.yml" + - "default.yml" + +- name: Execute pre-install tasks for OS + ansible.builtin.include_tasks: "{{ item }}" + with_first_found: + - "{{ ansible_facts['distribution'] }}-{{ ansible_facts['distribution_version'] }}_pre.yml" + - "{{ ansible_facts['distribution'] }}-{{ ansible_facts['distribution_major_version'] }}_pre.yml" + - "{{ ansible_facts['distribution'] }}_pre.yml" + - "{{ ansible_facts['os_family'] }}-{{ ansible_facts['distribution_version'] }}_pre.yml" + - "{{ ansible_facts['os_family'] }}-{{ ansible_facts['distribution_major_version'] }}_pre.yml" + - "{{ ansible_facts['os_family'] }}_pre.yml" + - "default.yml" + +- name: Install PostgreSQL server + ansible.builtin.include_role: + name: geerlingguy.postgresql + vars: + postgresql_global_config_options: "{{ postgresql_config_options | default(__postgresql_global_config_options) | union(postgresql_ssl_options) | union(postgresql_cldr_options) + }}" + postgresql_hba_entries: "{{ postgresql_access_entries | default(__postgresql_hba_entries) }}" + +- name: Set local user ACLs on TLS entities + ansible.builtin.import_role: + name: cloudera.exe.prereq_tls_acls + vars: + acl_user_accounts: "{{ postgresql_local_accounts | community.general.keep_keys(target=target_keys) | list }}" + target_keys: + - user + - key_acl + - key_password_acl + - keystore_acl + - unencrypted_key_acl + +- name: Execute post-install tasks for OS + ansible.builtin.include_tasks: "{{ item }}" + with_first_found: + - "{{ ansible_facts['distribution'] }}-{{ ansible_facts['distribution_version'] }}_post.yml" + - "{{ ansible_facts['distribution'] }}-{{ ansible_facts['distribution_major_version'] }}_post.yml" + - "{{ ansible_facts['distribution'] }}_post.yml" + - "{{ ansible_facts['os_family'] }}-{{ ansible_facts['distribution_version'] }}_post.yml" + - "{{ ansible_facts['os_family'] }}-{{ ansible_facts['distribution_major_version'] }}_post.yml" + - "{{ ansible_facts['os_family'] }}_post.yml" + - "default.yml" + +- name: Create superuser + when: create_database_admin_user + community.postgresql.postgresql_user: + role_attr_flags: SUPERUSER + name: "{{ database_admin_user }}" + password: "{{ database_admin_password }}" + become_user: postgres diff --git a/roles/postgresql_server/vars/RedHat-8.yml b/roles/postgresql_server/vars/RedHat-8.yml new file mode 100644 index 00000000..b62296cd --- /dev/null +++ b/roles/postgresql_server/vars/RedHat-8.yml @@ -0,0 +1,27 @@ +--- +# Copyright 2025 Cloudera, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +postgresql_data_dir: /var/lib/pgsql/{{ postgresql_version }}/data +postgresql_bin_path: /usr/pgsql-{{ postgresql_version }}/bin +postgresql_config_path: /var/lib/pgsql/{{ postgresql_version }}/data +postgresql_daemon: postgresql-{{ postgresql_version }}.service +# Removed devel package as avoids dependency on perl-IPC-run in pg 12+ +postgresql_packages: + - postgresql{{ postgresql_version | regex_replace('\.', '') }} + - postgresql{{ postgresql_version | regex_replace('\.', '') }}-server + - postgresql{{ postgresql_version | regex_replace('\.', '') }}-libs + - postgresql{{ postgresql_version | regex_replace('\.', '') }}-contrib +# - postgresql{{ postgresql_version | regex_replace('\.', '') }}-devel +postgresql_python_library: python-psycopg2 diff --git a/roles/postgresql_server/vars/RedHat-9.yml b/roles/postgresql_server/vars/RedHat-9.yml new file mode 100644 index 00000000..a028a586 --- /dev/null +++ b/roles/postgresql_server/vars/RedHat-9.yml @@ -0,0 +1,27 @@ +--- +# Copyright 2024 Cloudera, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +postgresql_data_dir: /var/lib/pgsql/{{ postgresql_version }}/data +postgresql_bin_path: /usr/pgsql-{{ postgresql_version }}/bin +postgresql_config_path: /var/lib/pgsql/{{ postgresql_version }}/data +postgresql_daemon: postgresql-{{ postgresql_version }}.service +# Removed devel package as avoids dependency on perl-IPC-run in pg 12+ +postgresql_packages: + - postgresql{{ postgresql_version | regex_replace('\.', '') }} + - postgresql{{ postgresql_version | regex_replace('\.', '') }}-server + - postgresql{{ postgresql_version | regex_replace('\.', '') }}-libs + - postgresql{{ postgresql_version | regex_replace('\.', '') }}-contrib +# - postgresql{{ postgresql_version | regex_replace('\.', '') }}-devel +postgresql_python_library: python-psycopg2 diff --git a/roles/postgresql_server/vars/default.yml b/roles/postgresql_server/vars/default.yml new file mode 100644 index 00000000..a60ed6e5 --- /dev/null +++ b/roles/postgresql_server/vars/default.yml @@ -0,0 +1,15 @@ +# Copyright 2024 Cloudera, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# no-op diff --git a/roles/postgresql_server/vars/main.yml b/roles/postgresql_server/vars/main.yml new file mode 100644 index 00000000..3564858f --- /dev/null +++ b/roles/postgresql_server/vars/main.yml @@ -0,0 +1,90 @@ +--- +# Copyright 2024 Cloudera, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +postgresql_ssl_options: + - option: ssl + value: "{{ postgresql_tls_enabled | ternary('on', 'off') }}" + - option: ssl_cert_file + value: "{{ postgresql_tls_enabled | ternary(postgresql_tls_cert_path, None) }}" + - option: ssl_key_file + value: "{{ postgresql_tls_enabled | ternary(postgresql_tls_key_path, None) }}" + - option: ssl_ca_file + value: "{{ postgresql_tls_enabled | ternary(postgresql_tls_ca_path, None) }}" + +postgresql_cldr_options: + - option: password_encryption + value: "scram-sha-256" + +__postgresql_global_config_options: + - option: shared_buffers + value: "256MB" + - option: wal_buffers + value: "8MB" + - option: max_wal_size + value: "768MB" + - option: checkpoint_completion_target + value: 0.9 + - option: log_directory + value: "log" + - option: listen_addresses + value: "*" + - option: max_connections + value: 300 + +__postgresql_hba_entries: + - type: local + database: all + user: postgres + auth_method: peer + - type: local + database: all + user: all + auth_method: peer + - type: host + database: all + user: all + address: "127.0.0.1/32" + auth_method: scram-sha-256 + - type: host + database: all + user: all + address: "127.0.0.1/32" + auth_method: md5 + - type: host + database: all + user: all + address: "::1/128" + auth_method: md5 + - type: host + database: all + user: all + address: "samenet" + auth_method: scram-sha-256 + - type: host + database: all + user: all + address: "samenet" + auth_method: md5 + +postgresql_locales: + - "en_US.UTF-8" + +postgresql_local_accounts: + - user: postgres + # home: /var/lib/pgsql + # comment: PostgreSQL Server + # mode: "700" + # shell: /bin/bash + unencrypted_key_acl: true