diff --git a/Berksfile b/Berksfile index 2ff3ac2..04f18ed 100644 --- a/Berksfile +++ b/Berksfile @@ -30,7 +30,7 @@ cookbook 'nginx', '= 9.0.0' # part of Chef 14 (https://docs.chef.io/resource_build_essential.html) cookbook 'build-essential', '~> 8.2.1' cookbook 'mysql', '~> 8.5.1' -cookbook 'postgresql', '= 7.1.4' +cookbook 'postgresql', '= 7.1.8' cookbook 'apt', '~> 7.0.0' cookbook 'git', '= 6.0.0' cookbook 'hostsfile', '= 2.4.5' diff --git a/Berksfile.lock b/Berksfile.lock index 0c074ae..271a16b 100644 --- a/Berksfile.lock +++ b/Berksfile.lock @@ -44,7 +44,7 @@ DEPENDENCIES poise-ruby-build (~> 1.1.0) poise-service (~> 1.5.2) postfix (= 5.0.2) - postgresql (= 7.1.4) + postgresql (= 7.1.8) redis git: https://github.com/phlipper/chef-redis.git revision: 7476279fc9c8727f082b8d77b5e1922dc2ef437b @@ -154,7 +154,7 @@ GRAPH poise-service (1.5.2) poise (~> 2.0) postfix (5.0.2) - postgresql (7.1.4) + postgresql (7.1.8) redis (0.5.6) apt (>= 0.0.0) seven_zip (3.1.1) diff --git a/cookbooks/postgresql/CHANGELOG.md b/cookbooks/postgresql/CHANGELOG.md index 95af871..ce810eb 100644 --- a/cookbooks/postgresql/CHANGELOG.md +++ b/cookbooks/postgresql/CHANGELOG.md @@ -2,34 +2,52 @@ This file is used to list changes made in the last 3 major versions of the postgresql cookbook. -## Unreleased +## v7.1.8 (2020-02-22) -## v7.1.4 (28-03-2019) +- Fix incorrect ubuntu platform family value in `postgresql_server_install` +- Re-add unit tests that were skipped + +## v7.1.7 (2020-02-21) + +- Correctly configure postgres-common on Ubuntu hosts (fixes #596) + +## v7.1.6 (2020-02-20) + +- Remove unnecessary nil default in resource properties +- Migrate to GitHub Actions for testing + +## v7.1.5 (2019-11-18) + +- Allow to install extensions with hyphens, ex: `postgresql_extension '"uuid-ossp"'` +- Update Circle CI config to match sous-chefs defaults #617 +- Remove Fedora testing from CI, not an official supported OS by sous-chefs, PR welcome #617 + +## v7.1.4 (2019-03-28) - Fix installation of extensions. -## v7.1.3 (15-01-2019) +## v7.1.3 (2019-01-15) - Added support for dash in database role name. -## v7.1.2 (06-01-2019) +## v7.1.2 (2019-06-01) - Cleanup and update the user resource documentation and code. Removed extraneous 'sensitive' property which is a common property in all Chef resources. - Change default permissions on the postgres.conf to be world readable so that psql can work. -## v7.1.1 (26-09-2018) +## v7.1.1 (2018-09-26) - Rename slave to follower - Use CircleCI for testing - Simplyfy extension resource -## v7.1.0 (22-06-2018) +## v7.1.0 (2018-06-22) - Update the `initdb` script to use initdb rather than a service. #542 - Refactor database commands to use the common connect method. #535 - Increase the unit test coverage. -## v7.0.0 (25-05-2018) +## v7.0.0 (2018-05-25) _Breaking Change_ Please see UPGRADING.md and the README.md for information how to use. @@ -57,7 +75,7 @@ _Breaking Change_ Please see UPGRADING.md and the README.md for information how ## v6.1.2 (2018-04-16) -**this will be the last release of the 6.0 series before all recipes are removed from the cookbook** +this will be the last release of the 6.0 series before all recipes are removed from the cookbook - Deprecate all recipes diff --git a/cookbooks/postgresql/README.md b/cookbooks/postgresql/README.md index d25d75e..d8ebb76 100644 --- a/cookbooks/postgresql/README.md +++ b/cookbooks/postgresql/README.md @@ -2,10 +2,16 @@ [![Cookbook Version](https://img.shields.io/cookbook/v/postgresql.svg)](https://supermarket.chef.io/cookbooks/postgresql) [![Build Status](https://img.shields.io/circleci/project/github/sous-chefs/postgresql/master.svg)](https://circleci.com/gh/sous-chefs/postgresql) -[![pullreminders](https://pullreminders.com/badge.svg)](https://pullreminders.com?ref=badge) +[![OpenCollective](https://opencollective.com/sous-chefs/backers/badge.svg)](#backers) +[![OpenCollective](https://opencollective.com/sous-chefs/sponsors/badge.svg)](#sponsors) +[![License](https://img.shields.io/badge/License-Apache%202.0-green.svg)](https://opensource.org/licenses/Apache-2.0) Installs and configures PostgreSQL as a client or a server. +## Maintainers + +This cookbook is maintained by the Sous Chefs. The Sous Chefs are a community of Chef cookbook maintainers working together to maintain important cookbooks. If you’d like to know more please visit [sous-chefs.org](https://sous-chefs.org/) or come chat with us on the Chef Community Slack in [#sous-chefs](https://chefcommunity.slack.com/messages/C2V7B88SF). + ## Upgrading If you are wondering where all the recipes went in v7.0+, or how on earth I use this new cookbook please see upgrading.md for a full description. @@ -18,7 +24,6 @@ If you are wondering where all the recipes went in v7.0+, or how on earth I use - Debian 7+ - Ubuntu 14.04+ - Red Hat/CentOS/Scientific 6+ -- Fedora ### PostgreSQL version @@ -51,7 +56,7 @@ Name | Types | Description `hba_file` | String | | `#{conf_dir}/main/pg_hba.conf` | no `ident_file` | String | | `#{conf_dir}/main/pg_ident.conf` | no `external_pid_file` | String | | `/var/run/postgresql/#{version}-main.pid` | no -`password` | String, nil | Pass in a password, or have the cookbook generate one for you | | no +`password` | String, nil | Pass in a password, or have the cookbook generate one for you | random string | no #### Examples @@ -211,14 +216,14 @@ end This generates the following line in the `pg_hba.conf`: -``` +```config # Local postgres superuser access local all postgres ident ``` **Note**: The template by default generates a local access for Unix domain sockets only to support running the SQL execute resources. In Postgres version 9.1 and higher, the method is 'peer' instead of 'ident' which is identical. It looks like this: -``` +```config # "local" is for Unix domain socket connections only local all all peer ``` @@ -257,7 +262,7 @@ end This generates the following line in the `pg_ident.conf`: -``` +```config # MAPNAME SYSTEM-USERNAME PG-USERNAME # John Mapping @@ -279,7 +284,7 @@ end This generates the following line in the `pg_hba.conf`: -``` +```config # Local postgres superuser access host all foo 127.0.0.1/32 ident ``` @@ -400,34 +405,27 @@ postgresql_server_conf 'PostgreSQL Config' do end ``` -## Contributing +## Contributors -Please refer to each project's style guidelines and guidelines for submitting patches and additions. In general, we follow the "fork-and-pull" Git workflow. +This project exists thanks to all the people who [contribute.](https://opencollective.com/sous-chefs/contributors.svg?width=890&button=false) -1. **Fork** the repo on GitHub -2. **Clone** the project to your own machine -3. **Commit** changes to your own branch -4. **Push** your work back up to your fork -5. Submit a **Pull request** so that we can review your changes +### Backers -NOTE: Be sure to merge the latest from "upstream" before making a pull request! +Thank you to all our backers! -[Contribution informations for this project](CONTRIBUTING.md) +![https://opencollective.com/sous-chefs#backers](https://opencollective.com/sous-chefs/backers.svg?width=600&avatarHeight=40) -## License +### Sponsors -Copyright 2010-2017, Chef Software, Inc. +Support this project by becoming a sponsor. Your logo will show up here with a link to your website. -```text -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. -``` +![https://opencollective.com/sous-chefs/sponsor/0/website](https://opencollective.com/sous-chefs/sponsor/0/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/1/website](https://opencollective.com/sous-chefs/sponsor/1/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/2/website](https://opencollective.com/sous-chefs/sponsor/2/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/3/website](https://opencollective.com/sous-chefs/sponsor/3/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/4/website](https://opencollective.com/sous-chefs/sponsor/4/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/5/website](https://opencollective.com/sous-chefs/sponsor/5/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/6/website](https://opencollective.com/sous-chefs/sponsor/6/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/7/website](https://opencollective.com/sous-chefs/sponsor/7/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/8/website](https://opencollective.com/sous-chefs/sponsor/8/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/9/website](https://opencollective.com/sous-chefs/sponsor/9/avatar.svg?avatarHeight=100) diff --git a/cookbooks/postgresql/libraries/helpers.rb b/cookbooks/postgresql/libraries/helpers.rb index 431d5dd..b8d2a2b 100644 --- a/cookbooks/postgresql/libraries/helpers.rb +++ b/cookbooks/postgresql/libraries/helpers.rb @@ -22,7 +22,7 @@ module PostgresqlCookbook require 'securerandom' def psql_command_string(new_resource, query, grep_for: nil, value_only: false) - cmd = "/usr/bin/psql -c \"#{query}\"" + cmd = %(/usr/bin/psql -c "#{query}") cmd << " -d #{new_resource.database}" if new_resource.database cmd << " -U #{new_resource.user}" if new_resource.user cmd << " --host #{new_resource.host}" if new_resource.host @@ -35,12 +35,12 @@ module PostgresqlCookbook def execute_sql(new_resource, query) # If we don't pass in a user to the resource # default to the postgres user - user = new_resource.user ? new_resource.user : 'postgres' + user = new_resource.user || 'postgres' # Query could be a String or an Array of Strings statement = query.is_a?(String) ? query : query.join("\n") - cmd = shell_out(statement, user: user) + cmd = shell_out(statement, user: user, environment: psql_environment) # Pass back cmd so we can decide what to do with it in the calling method. cmd @@ -81,7 +81,7 @@ module PostgresqlCookbook end def create_extension_sql(new_resource) - sql = "CREATE EXTENSION IF NOT EXISTS #{new_resource.extension}" + sql = %(CREATE EXTENSION IF NOT EXISTS #{new_resource.extension}) sql << " FROM \"#{new_resource.old_version}\"" if new_resource.old_version psql_command_string(new_resource, sql) @@ -213,6 +213,7 @@ module PostgresqlCookbook "/usr/pgsql-#{new_resource.version}/bin/initdb" end cmd << " --locale '#{new_resource.initdb_locale}'" if new_resource.initdb_locale + cmd << " -E '#{new_resource.initdb_encoding}'" if new_resource.initdb_encoding cmd << " -D '#{data_dir(new_resource.version)}'" end @@ -239,6 +240,12 @@ module PostgresqlCookbook platform?('amazon') ? '6' : '$releasever' end + # Fedora doesn't seem to know the right symbols for psql + def psql_environment + return {} unless platform?('fedora') + { LD_LIBRARY_PATH: '/usr/lib64' } + end + # Generate a password if the value is set to generate. def postgres_password(new_resource) new_resource.password == 'generate' ? secure_random : new_resource.password diff --git a/cookbooks/postgresql/metadata.json b/cookbooks/postgresql/metadata.json index 52a549a..74f89dd 100644 --- a/cookbooks/postgresql/metadata.json +++ b/cookbooks/postgresql/metadata.json @@ -1 +1 @@ -{"name":"postgresql","version":"7.1.4","description":"Installs and configures postgresql for clients or servers","long_description":"# PostgreSQL cookbook\n\n[![Cookbook Version](https://img.shields.io/cookbook/v/postgresql.svg)](https://supermarket.chef.io/cookbooks/postgresql)\n[![Build Status](https://img.shields.io/circleci/project/github/sous-chefs/postgresql/master.svg)](https://circleci.com/gh/sous-chefs/postgresql)\n[![pullreminders](https://pullreminders.com/badge.svg)](https://pullreminders.com?ref=badge)\n\nInstalls and configures PostgreSQL as a client or a server.\n\n## Upgrading\n\nIf you are wondering where all the recipes went in v7.0+, or how on earth I use this new cookbook please see upgrading.md for a full description.\n\n## Requirements\n\n### Platforms\n\n- Amazon Linux\n- Debian 7+\n- Ubuntu 14.04+\n- Red Hat/CentOS/Scientific 6+\n- Fedora\n\n### PostgreSQL version\n\nWe follow the currently supported versions listed on \n\n### Chef\n\n- Chef 13.8+\n\n### Cookbook Dependencies\n\nNone.\n\n## Resources\n\n### postgresql_client_install\n\nThis resource installs PostgreSQL client packages.\n\n#### Actions\n\n- `install` - (default) Install client packages\n\n#### Properties\n\nName | Types | Description | Default | Required?\n------------------- | ----------------- | ------------------------------------------------------------- | ----------------------------------------- | ---------\n`version` | String | Version of PostgreSQL to install | '9.6' | no\n`setup_repo` | Boolean | Define if you want to add the PostgreSQL repo | true | no\n`hba_file` | String | | `#{conf_dir}/main/pg_hba.conf` | no\n`ident_file` | String | | `#{conf_dir}/main/pg_ident.conf` | no\n`external_pid_file` | String | | `/var/run/postgresql/#{version}-main.pid` | no\n`password` | String, nil | Pass in a password, or have the cookbook generate one for you | | no\n\n#### Examples\n\nTo install version 9.5:\n\n```ruby\npostgresql_client_install 'My PostgreSQL Client install' do\n version '9.5'\nend\n```\n\n### postgresql_server_install\n\nThis resource installs PostgreSQL client and server packages.\n\n#### Actions\n\n- `install` - (default) Install client and server packages\n- `create` - Initialize the database\n\n#### Properties\n\nName | Types | Description | Default | Required?\n------------------- | --------------- | --------------------------------------------- | -------------------------------------------------- | ---------\n`version` | String | Version of PostgreSQL to install | '9.6' | no\n`setup_repo` | Boolean | Define if you want to add the PostgreSQL repo | true | no\n`hba_file` | String | Path of pg_hba.conf file | `/pg_hba.conf'` | no\n`ident_file` | String | Path of pg_ident.conf file | `/pg_ident.conf` | no\n`external_pid_file` | String | Path of PID file | `/var/run/postgresql/-main.pid` | no\n`password` | String, nil | Set PostgreSQL user password | 'generate' | no\n`port` | Integer | Set listen port of PostgreSQL service | 5432 | no\n`initdb_locale` | String | Locale to initialise the database with | 'C' | no\n\n#### Examples\n\nTo install PostgreSQL server, set your own postgres password using non-default service port.\n\n```ruby\npostgresql_server_install 'My PostgreSQL Server install' do\n action :install\nend\n\npostgresql_server_install 'Setup my PostgreSQL 9.6 server' do\n password 'MyP4ssw0rd'\n port 5433\n action :create\nend\n```\n\n#### Known issues\n\nOn some platforms (e.g. Ubuntu 18.04), your `initdb_locale` should be set to the\nsame as the template database [GH-555](https://github.com/sous-chefs/postgresql/issues/555).\n\n### postgresql_server_conf\n\nThis resource manages postgresql.conf configuration file.\n\n#### Actions\n\n- `modify` - (default) Manager PostgreSQL configuration file (postgresql.conf)\n\n#### Properties\n\nName | Types | Description | Default | Required?\n---------------------- | ------- | --------------------------------------- | --------------------------------------------------- | ---------\n`version` | String | Version of PostgreSQL to install | '9.6' | no\n`data_directory` | String | Path of PostgreSQL data directory | `` | no\n`hba_file` | String | Path of pg_hba.conf file | `/pg_hba.conf` | no\n`ident_file` | String | Path of pg_ident.conf file | `/pg_ident.conf` | no\n`external_pid_file` | String | Path of PID file | `/var/run/postgresql/-main.pid` | no\n`stats_temp_directory` | String | Path of stats file | `/var/run/postgresql/version>-main.pg_stat_tmp` | no\n`port` | Integer | Set listen port of PostgreSQL service | 5432 | no\n`additional_config` | Hash | Extra configuration for the config file | {} | no\n\n#### Examples\n\nTo setup your PostgreSQL configuration with a specific data directory. If you have installed a specific version of PostgreSQL (different from 9.6), you must specify version in this resource too.\n\n```ruby\npostgresql_server_conf 'My PostgreSQL Config' do\n version '9.5'\n data_directory '/data/postgresql/9.5/main'\n notifies :reload, 'service[postgresql]'\nend\n```\n\n### postgresql_extension\n\nThis resource manages PostgreSQL extensions for a given database.\n\n#### Actions\n\n- `create` - (default) Creates an extension in a given database\n- `drop` - Drops an extension from the database\n\n#### Properties\n\nName | Types | Description | Default | Required?\n------------- | ------ | -------------------------------------------------------------------------------- | ---------------- | ---------\n`database` | String | Name of the database to install the extension into | | yes\n`extension` | String | Name of the extension to install the database | Name of resource | yes\n`version` | String | Version of the extension to install | | no\n`old_version` | String | Older module name for new extension replacement. Appends FROM to extension query | | no\n\n#### Examples\n\nTo install the `adminpack` extension:\n\n```ruby\n# Add the contrib package in Ubuntu/Debian\npackage 'postgresql-contrib-9.6'\n\n# Install adminpack extension\npostgresql_extension 'postgres adminpack' do\n database 'postgres'\n extension 'adminpack'\nend\n```\n\n### postgresql_access\n\nThis resource uses the accumulator pattern to build up the `pg_hba.conf` file via chef resources instead of piling on a mountain of chef attributes to make this cookbook more reusable. It directly mirrors the configuration options of the postgres hba file in the resource and by default notifies the server with a reload to avoid a full restart, causing a potential outage of service. To revoke access, simply remove the resource and the access change won't be computed into the final `pg_hba.conf`\n\n#### Actions\n\n- `grant` - (default) Creates an access line inside of `pg_hba.conf`\n\n#### Properties\n\nName | Types | Description | Default | Required?\n--------------- | ------ | ----------------------------------------------------------------------------------------- | ----------------- | ---------\n`name` | String | Name of the access resource, this is left as a comment inside the `pg_hba` config | Resource name | yes\n`source` | String | The cookbook template filename if you want to use your own custom template | 'pg_hba.conf.erb' | yes\n`cookbook` | String | The cookbook to look in for the template source | 'postgresql' | yes\n`comment` | String | A comment to leave above the entry in `pg_hba` | nil | no\n`access_type` | String | The type of access, e.g. local or host | 'local' | yes\n`access_db` | String | The database to access. Can use 'all' for all databases | 'all' | yes\n`access_user` | String | The user accessing the database. Can use 'all' for any user | 'all' | yes\n`access_addr` | String | The address(es) allowed access. Can be nil if method ident is used since it is local then | nil | no\n`access_method` | String | Authentication method to use | 'ident' | yes\n\n#### Examples\n\nTo grant access to the PostgreSQL user with ident authentication:\n\n```ruby\npostgresql_access 'local_postgres_superuser' do\n comment 'Local postgres superuser access'\n access_type 'local'\n access_db 'all'\n access_user 'postgres'\n access_addr nil\n access_method 'ident'\nend\n```\n\nThis generates the following line in the `pg_hba.conf`:\n\n```\n# Local postgres superuser access\nlocal all postgres ident\n```\n\n**Note**: The template by default generates a local access for Unix domain sockets only to support running the SQL execute resources. In Postgres version 9.1 and higher, the method is 'peer' instead of 'ident' which is identical. It looks like this:\n\n```\n# \"local\" is for Unix domain socket connections only\nlocal all all peer\n```\n\n### postgresql_ident\n\nThis resource generate `pg_ident.conf` configuration file to manage user mapping between system and PostgreSQL users.\n\n#### Actions\n\n- `create` - (default) Creates an mapping line inside of `pg_ident.conf`\n\n#### Properties\n\nName | Types | Description | Default | Required?\n-------------- | ----------- | -------------------------------------------------------------------------- | ------------------- | ---------\n`mapname` | String | Name of the user mapping | Resource name | yes\n`source` | String | The cookbook template filename if you want to use your own custom template | 'pg_ident.conf.erb' | no\n`cookbook` | String | The cookbook to look in for the template source | 'postgresql' | no\n`comment` | String, nil | A comment to leave above the entry in `pg_ident` | nil | no\n`system_user` | String | System user or regexp used for the mapping | None | yes\n`pg_user` | String | Pg user or regexp used for the mapping | None | yes\n\n#### Examples\n\nCreates a `mymapping` mapping that map `john` system user to `user1` PostgreSQL user:\n\n```ruby\npostgresql_ident 'Map john to user1' do\n comment 'John Mapping'\n mapname 'mymapping'\n system_user 'john'\n pg_user 'user1'\nend\n```\n\nThis generates the following line in the `pg_ident.conf`:\n\n```\n# MAPNAME SYSTEM-USERNAME PG-USERNAME\n\n# John Mapping\nmymapping john user1\n```\n\nTo grant access to the foo user with password authentication:\n\n```ruby\npostgresql_access 'local_foo_user' do\n comment 'Foo user access'\n access_type 'host'\n access_db 'all'\n access_user 'foo'\n access_addr '127.0.0.1/32'\n access_method 'md5'\nend\n```\n\nThis generates the following line in the `pg_hba.conf`:\n\n```\n# Local postgres superuser access\nhost all foo 127.0.0.1/32 ident\n```\n\n### postgresql_database\n\nThis resource manages PostgreSQL databases.\n\n#### Actions\n\n- `create` - (default) Creates the given database.\n- `drop` - Drops the given database.\n\n#### Properties\n\nName | Types | Description | Default | Required?\n---------- | ------- | ------------------------------------------------------------------- | ------------------- | ---------\n`database` | String | Name of the database to create | Resource name | yes\n`user` | String | User which run psql command | 'postgres' | no\n`template` | String | Template used to create the new database | 'template1' | no\n`host` | String | Define the host server where the database creation will be executed | Not set (localhost) | no\n`port` | Integer | Define the port of PostgreSQL server | 5432 | no\n`encoding` | String | Define database encoding | 'UTF-8' | no\n`locale` | String | Define database locale | 'en_US.UTF-8' | no\n`owner` | String | Define the owner of the database | Not set | no\n\n#### Examples\n\nTo create database named 'my_app' with owner 'user1':\n\n```ruby\npostgresql_database 'my_app' do\n owner 'user1'\nend\n```\n\n#### Known issues\n\nOn some platforms (e.g. Ubuntu 18.04), your `initdb_locale` should be set to the\nsame as the template database [GH-555](https://github.com/sous-chefs/postgresql/issues/555).\n\n### postgresql_user\n\nThis resource manage PostgreSQL users.\n\n#### Actions\n\n- `create` - (default) Creates the given user with default or given privileges.\n- `update` - Update user privilieges.\n- `drop` - Deletes the given user.\n\n#### Properties\n\nName | Types | Description | Default | Required?\n-------------------- | ------- | ----------------------------------------------- | -------- | ---------\n`create_user` | String | User to create (defaults to the resource name) | | Yes\n`superuser` | Boolean | Define if user needs superuser role | false | no\n`createdb` | Boolean | Define if user needs createdb role | false | no\n`createrole` | Boolean | Define if user needs createrole role | false | no\n`inherit` | Boolean | Define if user inherits the privileges of roles | true | no\n`replication` | Boolean | Define if user needs replication role | false | no\n`login` | Boolean | Define if user can login | true | no\n`password` | String | Set user's password | | no\n`encrypted_password` | String | Set user's password with an hashed password | | no\n`valid_until` | String | Define an account expiration date | | no\n`attributes` | Hash | Additional attributes for :update action | {} | no\n`user` | String | User for command | postgres | no\n`database` | String | Database for command | | no\n`host` | String | Hostname for command | | no\n`port` | Integer | Port number to connect to postgres | 5432 | no\n\n#### Examples\n\nCreate a user `user1` with a password, with `createdb` role and set an expiration date to 2018, Dec 21.\n\n```ruby\npostgresql_user 'user1' do\n password 'UserP4ssword'\n createdb true\n valid_until '2018-12-31'\nend\n```\n\nCreate a user `user1` with a password, with `createdb` role and set an expiration date to 2018, Dec 21.\n\n```ruby\npostgresql_user 'user1' do\n password 'UserP4ssword'\n createdb true\n valid_until '2018-12-31'\nend\n```\n\n## Usage\n\nTo install and configure your PostgreSQL instance you need to create your own cookbook and call needed resources with your own parameters.\n\nMore examples can be found in `test/cookbooks/test/recipes`\n\n## Example Usage\n\n```ruby\n# cookbooks/my_postgresql/recipes/default.rb\n\npostgresql_client_install 'PostgreSQL Client' do\n setup_repo false\n version '10.6'\nend\n\npostgresql_server_install 'PostgreSQL Server' do\n version '10.6'\n setup_repo false\n password 'P0stgresP4ssword'\nend\n\npostgresql_server_conf 'PostgreSQL Config' do\n notifies :reload, 'service[postgresql]'\nend\n```\n\n## Contributing\n\nPlease refer to each project's style guidelines and guidelines for submitting patches and additions. In general, we follow the \"fork-and-pull\" Git workflow.\n\n1. **Fork** the repo on GitHub\n2. **Clone** the project to your own machine\n3. **Commit** changes to your own branch\n4. **Push** your work back up to your fork\n5. Submit a **Pull request** so that we can review your changes\n\nNOTE: Be sure to merge the latest from \"upstream\" before making a pull request!\n\n[Contribution informations for this project](CONTRIBUTING.md)\n\n## License\n\nCopyright 2010-2017, Chef Software, Inc.\n\n```text\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n","maintainer":"Sous Chefs","maintainer_email":"help@sous-chefs.org","license":"Apache-2.0","platforms":{"ubuntu":">= 0.0.0","debian":">= 0.0.0","fedora":">= 0.0.0","amazon":">= 0.0.0","redhat":">= 0.0.0","centos":">= 0.0.0","scientific":">= 0.0.0","oracle":">= 0.0.0"},"dependencies":{},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{},"source_url":"https://github.com/sous-chefs/postgresql","issues_url":"https://github.com/sous-chefs/postgresql/issues","chef_version":[[">= 13.8"]],"ohai_version":[]} \ No newline at end of file +{"name":"postgresql","version":"7.1.8","description":"Installs and configures postgresql for clients or servers","long_description":"","maintainer":"Sous Chefs","maintainer_email":"help@sous-chefs.org","license":"Apache-2.0","platforms":{"ubuntu":">= 0.0.0","debian":">= 0.0.0","fedora":">= 0.0.0","amazon":">= 0.0.0","redhat":">= 0.0.0","centos":">= 0.0.0","scientific":">= 0.0.0","oracle":">= 0.0.0"},"dependencies":{},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{},"source_url":"https://github.com/sous-chefs/postgresql","issues_url":"https://github.com/sous-chefs/postgresql/issues","chef_version":[[">= 13.8"]],"ohai_version":[]} \ No newline at end of file diff --git a/cookbooks/postgresql/metadata.rb b/cookbooks/postgresql/metadata.rb index 9fb54ac..b4b193b 100644 --- a/cookbooks/postgresql/metadata.rb +++ b/cookbooks/postgresql/metadata.rb @@ -4,8 +4,7 @@ maintainer 'Sous Chefs' maintainer_email 'help@sous-chefs.org' license 'Apache-2.0' description 'Installs and configures postgresql for clients or servers' -long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) -version '7.1.4' +version '7.1.8' source_url 'https://github.com/sous-chefs/postgresql' issues_url 'https://github.com/sous-chefs/postgresql/issues' chef_version '>= 13.8' diff --git a/cookbooks/postgresql/resources/access.rb b/cookbooks/postgresql/resources/access.rb index 56d69cc..8c5ba63 100644 --- a/cookbooks/postgresql/resources/access.rb +++ b/cookbooks/postgresql/resources/access.rb @@ -16,12 +16,12 @@ # limitations under the License. # -property :access_type, String, required: true, default: 'local' -property :access_db, String, required: true, default: 'all' -property :access_user, String, required: true, default: 'postgres' -property :access_method, String, required: true, default: 'ident' -property :cookbook, String, default: 'postgresql' -property :source, String, default: 'pg_hba.conf.erb' +property :access_type, String, default: 'local' +property :access_db, String, default: 'all' +property :access_user, String, default: 'postgres' +property :access_method, String, default: 'ident' +property :cookbook, String, default: 'postgresql' +property :source, String, default: 'pg_hba.conf.erb' property :access_addr, String property :comment, String diff --git a/cookbooks/postgresql/resources/database.rb b/cookbooks/postgresql/resources/database.rb index be2a813..f4f0377 100644 --- a/cookbooks/postgresql/resources/database.rb +++ b/cookbooks/postgresql/resources/database.rb @@ -23,7 +23,7 @@ property :owner, String # Connection prefernces property :user, String, default: 'postgres' property :database, String, name_property: true -property :host, [String, nil], default: nil +property :host, String property :port, Integer, default: 5432 action :create do diff --git a/cookbooks/postgresql/resources/extension.rb b/cookbooks/postgresql/resources/extension.rb index fb104dd..f8987b6 100644 --- a/cookbooks/postgresql/resources/extension.rb +++ b/cookbooks/postgresql/resources/extension.rb @@ -30,6 +30,7 @@ action :create do code create_extension_sql(new_resource) user 'postgres' action :run + environment(psql_environment) not_if { follower? || extension_installed?(new_resource) } end end @@ -39,6 +40,7 @@ action :drop do code psql_command_string(new_resource, "DROP EXTENSION IF EXISTS \"#{new_resource.extension}\"") user 'postgres' action :run + environment(psql_environment) not_if { follower? } only_if { extension_installed?(new_resource) } end diff --git a/cookbooks/postgresql/resources/ident.rb b/cookbooks/postgresql/resources/ident.rb index ba677f0..52fdec3 100644 --- a/cookbooks/postgresql/resources/ident.rb +++ b/cookbooks/postgresql/resources/ident.rb @@ -21,11 +21,11 @@ property :source, String, default: 'pg_ident.conf.erb' property :cookbook, String, default: 'postgresql' property :system_user, String, required: true property :pg_user, String, required: true -property :comment, [String, nil], default: nil +property :comment, String action :create do ident_resource = new_resource - with_run_context :root do # ~FC037 + with_run_context :root do edit_resource(:template, "#{conf_dir}/pg_ident.conf") do |new_resource| source new_resource.source cookbook new_resource.cookbook diff --git a/cookbooks/postgresql/resources/server_install.rb b/cookbooks/postgresql/resources/server_install.rb index 3c66c67..290713b 100644 --- a/cookbooks/postgresql/resources/server_install.rb +++ b/cookbooks/postgresql/resources/server_install.rb @@ -1,4 +1,3 @@ -# frozen_string_literal: true # # Cookbook:: postgresql # Resource:: server_install @@ -26,6 +25,7 @@ property :external_pid_file, String, default: lazy { "/var/run/postgresql/#{vers property :password, [String, nil], default: 'generate' # Set to nil if we do not want to set a password property :port, Integer, default: 5432 property :initdb_locale, String +property :initdb_encoding, String # Connection preferences property :user, String, default: 'postgres' @@ -41,6 +41,23 @@ action :install do setup_repo new_resource.setup_repo end + # First install the postgresql-common package + if platform_family?('debian') + package 'postgresql-common' + + initdb_options = '' + initdb_options << "--locale #{new_resource.initdb_locale}" if new_resource.initdb_locale + initdb_options << " -E #{new_resource.initdb_encoding}" if new_resource.initdb_encoding + + template '/etc/postgresql-common/createcluster.conf' do + source 'createcluster.conf.erb' + cookbook 'postgresql' + variables( + initdb_options: initdb_options + ) + end + end + package server_pkg_name end diff --git a/cookbooks/postgresql/resources/user.rb b/cookbooks/postgresql/resources/user.rb index 05da73b..17b8b18 100644 --- a/cookbooks/postgresql/resources/user.rb +++ b/cookbooks/postgresql/resources/user.rb @@ -40,6 +40,7 @@ action :create do user 'postgres' command create_user_sql(new_resource) sensitive new_resource.sensitive + environment(psql_environment) not_if { follower? || user_exists?(new_resource) } end end @@ -49,6 +50,7 @@ action :update do execute "update postgresql user #{new_resource.create_user}" do user 'postgres' command update_user_sql(new_resource) + environment(psql_environment) sensitive true not_if { follower? } only_if { user_exists?(new_resource) } @@ -64,6 +66,7 @@ action :update do execute "Update postgresql user #{new_resource.create_user} to set #{attr}" do user 'postgres' command update_user_with_attributes_sql(new_resource, v) + environment(psql_environment) sensitive true not_if { follower? } only_if { user_exists?(new_resource) } @@ -76,6 +79,7 @@ action :drop do execute "drop postgresql user #{new_resource.create_user}" do user 'postgres' command drop_user_sql(new_resource) + environment(psql_environment) sensitive true not_if { follower? } only_if { user_exists?(new_resource) } diff --git a/cookbooks/postgresql/templates/createcluster.conf.erb b/cookbooks/postgresql/templates/createcluster.conf.erb new file mode 100644 index 0000000..b85e2b5 --- /dev/null +++ b/cookbooks/postgresql/templates/createcluster.conf.erb @@ -0,0 +1,41 @@ +# Default values for pg_createcluster(8) +# Occurrences of '%v' are replaced by the major version number, +# and '%c' by the cluster name. Use '%%' for a literal '%'. + +# Create a "main" cluster when a new postgresql-x.y server package is installed +#create_main_cluster = true + +# Default start.conf value, must be one of "auto", "manual", and "disabled". +# See pg_createcluster(8) for more documentation. +#start_conf = 'auto' + +# Default data directory. +#data_directory = '/var/lib/postgresql/%v/%c' + +# Default directory for transaction logs +# Unset by default, i.e. transaction logs remain in the data directory. +#waldir = '/var/lib/postgresql/wal/%v/%c/pg_wal' + +# Options to pass to initdb. +initdb_options = '<%= @initdb_options %>' + +# The following options are copied into the new cluster's postgresql.conf: + +# Enable SSL by default (using the "snakeoil" certificates installed by the +# ssl-cert package, unless configured otherwise here) +ssl = on + +# Show cluster name in process title +cluster_name = '%v/%c' + +# Put stats_temp_directory on tmpfs +stats_temp_directory = '/var/run/postgresql/%v-%c.pg_stat_tmp' + +# Add prefix to log lines +log_line_prefix = '%%m [%%p] %%q%%u@%%d ' + +# Add "include_dir" in postgresql.conf +add_include_dir = 'conf.d' + +# Directory for additional createcluster config +include_dir '/etc/postgresql-common/createcluster.d' diff --git a/data_bags/credentials/postgresql.json b/data_bags/credentials/postgresql.json index 886b65a..8c2fecc 100644 --- a/data_bags/credentials/postgresql.json +++ b/data_bags/credentials/postgresql.json @@ -1,23 +1,51 @@ { "id": "postgresql", "ejabberd_user_password": { - "encrypted_data": "s31aNIv9ZTlU8cVXMDUB79Iv+EozZS1NSZVU5ey9xpBf2WYohpSqni/5Wg==\n", - "iv": "a3LWKNYmUZfSMc1Y\n", - "auth_tag": "3P+WFcDw/R1d983g7YoFUw==\n", + "encrypted_data": "hz0xHS2wl66X6xxqLE5/6apQb8SvIR7r8hCd9ZzEcHf7VaWoFMNLmrmwqw==\n", + "iv": "PfEp9Jhqfp0o7Cje\n", + "auth_tag": "ckEADxPfymTvSVLLXUxTWA==\n", "version": 3, "cipher": "aes-256-gcm" }, "server_password": { - "encrypted_data": "w7zghEF+DjUhS59cze+qviqDcy8mQpIgW6olHabas1IH4t0z+IQ7\n", - "iv": "ppqOzJGczWtwGRnX\n", - "auth_tag": "2Lhqw7Rhm35HcltsDtaJIw==\n", + "encrypted_data": "9aV4IykJB3lISayq/crmowTjrQjwSWSrh7+O9LMq0IgZaWZ6Bk6R\n", + "iv": "XFeNPuZAh4nCX9NU\n", + "auth_tag": "LoAIWrqSAmcuA+r3nyHu2Q==\n", "version": 3, "cipher": "aes-256-gcm" }, "mastodon_user_password": { - "encrypted_data": "84UPPmtNh/5MH6u4svMPhRHBGK1GFnP4G2tk/a+wQLNxSB8FlDsTuqSC2A==\n", - "iv": "UBl2ILWCc2WKcN6d\n", - "auth_tag": "NF/xcK0tmvbBo1dDFhOf7w==\n", + "encrypted_data": "LGU8N2C9Ax17QvFCWNV9m1rbRpBT9YH1qVn/Cmz0/p+1aUcOUN8rzxb57Q==\n", + "iv": "FiYQKLmfJ/CYO50H\n", + "auth_tag": "t3NwAMqoGCJ/c/5H2KjQ+Q==\n", + "version": 3, + "cipher": "aes-256-gcm" + }, + "replication_password": { + "encrypted_data": "6UildEd3UactuYufRp+UjHFlK3zLZ8Vmggfc8URBRNVfWHs=\n", + "iv": "e4SpyAt32vXuX4un\n", + "auth_tag": "AkCEvuEnb+E5jTC84tC8NA==\n", + "version": 3, + "cipher": "aes-256-gcm" + }, + "ssl_cert": { + "encrypted_data": "loF7NMyOJXr8PfxsuN6zvp86hIqWYoGFiGq+ldirctWnmkeDmaROgzDW1oQp\nAubnEHZNx7IFRn/FGpGhhbX/DGjbL6EK0bSE6x6uzOEhpaFDAqmzzEfMXCMj\nDIsrM5WSmP1WBFd6g+/zk3EAXHeekOlLBEj13zzSJVj4piLFERKZRTgix0eP\nOmH+lGBoxy4hXKfa9ru7c5h4vLVQHSlHjrrsyeKdumbmXWSb3IJWtEsNQRqu\nKu6DZ+IRC8fH+DBs8/32dTbJ6uR29kbKfZrWTrpOKXWJLnT1snuiTMeRbTcO\nVbS1ZSeGcpGMFFayAui4KgPaDK8vT/mXcd2P3+c85GZtmmvIKfloIRmtb4in\nleUx3z70BxPFRg5wYfSiP/xJMpjJrh5/6P+96iMkgmU+wuXT+95yf4Agz7G5\n0gObs/sJCAV9qOoWIXSU3jyNvaYsZMPj8FHXlpnCXojHJ2WnqLCAPeVWYHbd\nvNSEOvmCN07xK1PkGZT9NGfPzRcZxqop5gJ3qP9Km33Z06SNF+28i2d4lpy+\n1oWqg5ow2CBhRrb0Bx8FplQug4EXCV7Sni4mc0jSX90rBv+e65Em+33x0A27\nPrp7lfcv+7ridU5AZXifFZSuIJF6LMXz+ji2zC2JMjS4xQ8/KXBd8E5/fRJH\nI18X+t/xx8gakmaDrz/3+4i8TVt1I8pIpN/SaAXTZqgme1QoISymf6LQzFxW\ns1kQGOwbtgx60+2BG7kF9XRRZJay8P1uxmVgjHWbqyL0KbYTlU2zTLuRs3ez\n+rPEsxB/hNfUeB9guALFLtvlkAob1Fh/Za6aukaFlaVJHbHoXehH/aXBPAVK\n0ld+3fql5Ib/OAD7prWaUCZ/tP357RWwCxz+ECjtJhFdREx8fT1aZGvmJ0yx\nESNhSjrn+b+rVc+HiD4hAytW+QP2yNqfKO9YzxXYfN5BBTxh/fvO2qVtQmSf\n+u9iatEaico44E7MX1ZOYAclTA289dwyu6R9PRa1p0zral5b+vJAOx1iH1uq\nzHUKTiRCRAcWrcciL8PH8MRXdcHSxmfyBSBbcz+dh/MURyQMx/LOQ31gYuYq\nzlgbJNsVl6V9rl9x2SargwJrD1WM863oyQumZc/M42GX0z9PilIhLQbF26MN\n2tUf5IDK7d42Z5A6ATxR+0qKh2/WvDXDbNHy+cuAjRJRX9vTgNqpR5qCOyT5\nIxA55rLvHYxbnqic124I1EdXGtoEXqsxt1YAq3ho9QCQz1t5Z/AP63oUEuLr\np4WIeo44fqZzjprRFEE3KbCGlUDx56xLg4a84JF1rMU0ce11BUtEEtRF2p4X\noecU8Z5vvhvsqXxYko6aFNcAvxO2FdZmC76lilNsHgH9VS02ctjOT7Mvi2XP\n3QEVOg==\n", + "iv": "v+wkuXO+2VZHRkOu\n", + "auth_tag": "C56+Qe/UNzR8k9HizIFyMA==\n", + "version": 3, + "cipher": "aes-256-gcm" + }, + "ssl_key": { + "encrypted_data": "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\n", + "iv": "sPYjnXdqpABH9wrl\n", + "auth_tag": "F5ajYZMx+6r333stbQ0E1Q==\n", + "version": 3, + "cipher": "aes-256-gcm" + }, + "ssl_root_cert": { + "encrypted_data": "hwwHOg/kuJxMEOLpDC2zCrIRoWkbcNzui849HEtootXsL8YPFMIo0wKzC4JS\nc5R5A7MOqgoijjrhymMKkWZ4nqdx0ZVjlLQoBpFd2D6OYmomID/e4Qi2fR4Q\nZ9eS1xoPi0cAcKKML83yHJ3bRkZhqcZLIauqm3N+pAwEdYjHo9HrNPs9stqL\noSyLIG5IwNvwh8DJMb9XU5tBlMOpI0eUDRptBHjecAdmSv59jxse7dSHVove\ndsooWNdsz48318QMG3e2ALRIWZHFb0t2C/01wYqk9PrazIX9upC1BHZ7f4XZ\nAOkukFD/uVa3wLrzQnGhh8bLxZmsRaKaGlY79vg6HgYqUoqmEuB6FHVRX7xb\nh4zt3CcWQMwU0r+Po1a2Qo5HT9xP40QgrHwtJwlpLgIP/9yxhTjpb2qdJzY3\n88MI/wZLvyezTZwMmZikE9+IlwfUBBmsSJVHOtKlPQ27YAHXmALczQUPrYG9\nqWLnWoqmyYFMpPF4u7QQUXNjde+z5sZb2gELRy1nBtHGPEZQY/Ji9P4AT0jW\n3tTidly4yYa0sXLGFH/ZbePRwrUX1qd7RalOLWUYkPwEUVcO5FzzWvCr58S0\n570VoHhyTrYWwaRfiEhEsOV/aSrVERa7T89NvDGpaKQmzpWCF1uGbnmRUI+a\nyYhSzgXaFiKiE8JFvev83slqRpsxF2z2bdHEBvSIce69pzC5VjWKVuHG/Lf8\nVseTapbVXNptMTgm+ToZHcbtBFdWlh3rpyaAKj5uKkKenY0n/R7s4M0GFviY\nj+zLQhHGYXNCybKTfguDfcKe6XiktguwXTCaXo8HpaZr49i2HsAYmSEHw4oE\nYKoYUfm9v1n6O6uxWXV92OIpRS0bkb4hUMWY9K6oG/hbUCupX/RWnBZW4wAS\nvh561oz1Ef1NVI85l2DDG++oCgXgiqzulIQxyNFOyofX5KLmJ8/nLSUc2R3E\nITPaqEG/5NUSyeQMPbIVRN4bsXcogWB/779QiXP6nDEuucNH6kpesiDbEmxC\n5J9i3xKI97zDL8HEmT7Tgp5Tu9FOyOA36qS14cMo8Ue4MWDGV1NrnbWf7LvE\nnx65h8tk1LzimnTE/NqhrYgodylUnNf6c76CaHUhqBDi3JUMF9O/IwRuYH7w\nTvOGphtyix7Lph3wCJJf/VVgK4jy2erq9+mr82dKBBCynEbUJVhpVlAkdKqX\n44LC+KIvJBb4UPerutEYmOOy2Ha1elQyFebSgUR6bxxG9JvZEOYY+UCdeRnz\nQTCQYEvUO7nHSI1uKDW2/BC0f6vzQxYWBT1XgWt5D+wlqz3ysW2AKCK2j4xL\nEFZEQF4ibX0Acm/dp/BVztq8ymhTtqW7pMPHbub0/Q4kgFiPq66FHxJdQU4Q\nuS9w2ciiPGbCbgdww3RfEU3c0kTieyHRcL/pU3aaO6RTA3SeGRX6DqXX3Si3\npkLiyuXBBIskbn0RiBn1SXYMJ17Vaye4BvFlDc2PywhEsXkRGn6Ad1gLOkyZ\nycLnXizhLX0kePSgyn/0N9RI067dlv2lzdaVuheQQEX7efrFCC2zMzvdgP8=\n", + "iv": "TrPuASVYx7D2onkS\n", + "auth_tag": "Gzn4kJCs87LK3ZKJxCHAnw==\n", "version": 3, "cipher": "aes-256-gcm" } diff --git a/nodes/andromeda.kosmos.org.json b/nodes/andromeda.kosmos.org.json index fc8ce4d..08697e1 100644 --- a/nodes/andromeda.kosmos.org.json +++ b/nodes/andromeda.kosmos.org.json @@ -24,6 +24,7 @@ "ipaddress": "46.4.18.160", "roles": [ "base", + "postgresql_primary", "mastodon", "ejabberd" ], @@ -73,7 +74,6 @@ "nginx::commons_dir", "nginx::commons_script", "nginx::commons_conf", - "build-essential::default", "ark::default", "composer::default", "composer::install", @@ -107,7 +107,8 @@ "tor-full::default", "kosmos-base::letsencrypt", "git::default", - "git::package" + "git::package", + "build-essential::default" ], "platform": "ubuntu", "platform_version": "18.04", @@ -128,7 +129,7 @@ "recipe[kosmos-base::andromeda_firewall]", "recipe[kosmos-ipfs]", "recipe[kosmos-ipfs::public_gateway]", - "recipe[kosmos-postgresql]", + "role[postgresql_primary]", "recipe[kosmos-mediawiki]", "recipe[kosmos-btcpayserver::proxy]", "role[mastodon]", diff --git a/roles/postgresql_primary.rb b/roles/postgresql_primary.rb new file mode 100644 index 0000000..0cb0ccd --- /dev/null +++ b/roles/postgresql_primary.rb @@ -0,0 +1,5 @@ +name "postgresql_primary" + +run_list %w( + kosmos-postgresql::default +) diff --git a/roles/postgresql_replica.rb b/roles/postgresql_replica.rb new file mode 100644 index 0000000..8ee5100 --- /dev/null +++ b/roles/postgresql_replica.rb @@ -0,0 +1,5 @@ +name "postgresql_replica" + +run_list %w( + kosmos-postgresql::replica +) diff --git a/site-cookbooks/kosmos-postgresql/README.md b/site-cookbooks/kosmos-postgresql/README.md index 9521928..2541424 100644 --- a/site-cookbooks/kosmos-postgresql/README.md +++ b/site-cookbooks/kosmos-postgresql/README.md @@ -1,4 +1,57 @@ # kosmos-postgresql -TODO: Enter the cookbook description here. +## Usage +### On the primary: + +Set the `postgresql_primary` role on the node + +### On the replica: + +Add the `postgresql_replica` role to the node's run list. Run Chef on the node +a first time. +After the initial Chef run on the replica, run Chef on the primary to add the +firewall rules and PostgreSQL access rules, then run Chef again on the replica +to set up replication. + +## Caveat + +[`firewall_rules`](https://github.com/chef-cookbooks/firewall/issues/134) and +[`postgresql_access`](https://github.com/sous-chefs/postgresql/issues/648) are +declared in recipes, not resources because of the way custom resources +work currently in Chef. See the `default.rb` and `replica.rb` recipes. + +The primary gives access to the `replication` db to the `replication` user +connecting from a replica, and replicas to the primary. For more information +about PostgreSQL client authentication, see the +[official docs](https://www.postgresql.org/docs/12/auth-pg-hba-conf.html) + +The primary opens up the PostgreSQL port (5432 TCP) to replicas, and replicas +to the primary. + +## TLS self-signed certificate + +A wildcard (`*.kosmos.org` certificate) was generated with the following +commands: + +``` +openssl req -new -nodes -text -out root.csr -keyout root.key \ + -subj "/CN=root.kosmos.org" +chmod og-rwx root.key +openssl x509 -req -in root.csr -text -days 3650 \ + -extfile /etc/ssl/openssl.cnf -extensions v3_ca \ + -signkey root.key -out root.crt +openssl req -new -nodes -text -out server.csr \ + -keyout server.key -subj "/CN=*.kosmos.org" +chmod og-rwx server.key +openssl x509 -req -in server.csr -text -days 1825 \ + -CA root.crt -CAkey root.key -CAcreateserial \ + -out server.crt +``` + +It is valid until May 12 2025. + +The content of `server.crt`, `server.key` and `root.crt` an stored in the +`postgresql` encrypted data bag. The root key is stored in LastPass +("Self-signed TLS root certificate"). `server.crt` & `server.key` are used by +the PostgreSQL server. diff --git a/site-cookbooks/kosmos-postgresql/attributes/default.rb b/site-cookbooks/kosmos-postgresql/attributes/default.rb new file mode 100644 index 0000000..dec530f --- /dev/null +++ b/site-cookbooks/kosmos-postgresql/attributes/default.rb @@ -0,0 +1,3 @@ +# This is set to false by default, and set to true in the server resource +# for replicas. +node.default['kosmos-postgresql']['ready_to_set_up_replica'] = false diff --git a/site-cookbooks/kosmos-postgresql/libraries/helpers.rb b/site-cookbooks/kosmos-postgresql/libraries/helpers.rb new file mode 100644 index 0000000..a3331b6 --- /dev/null +++ b/site-cookbooks/kosmos-postgresql/libraries/helpers.rb @@ -0,0 +1,33 @@ +class Chef + class Recipe + def postgresql_primary + postgresql_primary = search(:node, "role:postgresql_primary AND chef_environment:#{node.chef_environment}").first + + unless postgresql_primary.nil? + primary_ip = ip_for(postgresql_primary) + + { hostname: postgresql_primary[:hostname], ipaddress: primary_ip } + end + end + + def postgresql_replicas + postgresql_replicas = [] + + search(:node, "role:postgresql_replica AND chef_environment:#{node.chef_environment}").each do |replica| + replica_ip = ip_for(replica) + + postgresql_replicas << { hostname: replica[:hostname], ipaddress: replica_ip } + end + + postgresql_replicas + end + + def ip_for(server_node) + if node.chef_environment == "development" + server_node['network']['interfaces']['eth1']['routes'].first['src'] + else + server_node['ipaddress'] + end + end + end +end diff --git a/site-cookbooks/kosmos-postgresql/recipes/default.rb b/site-cookbooks/kosmos-postgresql/recipes/default.rb index 8e48c3a..d4bef39 100644 --- a/site-cookbooks/kosmos-postgresql/recipes/default.rb +++ b/site-cookbooks/kosmos-postgresql/recipes/default.rb @@ -24,28 +24,49 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -return if platform?('ubuntu') && node[:platform_version].to_f < 18.04 +postgresql_version = "12" +postgresql_service = "postgresql@#{postgresql_version}-main" -node.override['build-essential']['compile_time'] = true -include_recipe 'build-essential::default' - -package("libpq-dev") { action :nothing }.run_action(:install) - -chef_gem 'pg' do - compile_time true +postgresql_custom_server postgresql_version do + role "primary" end -postgresql_data_bag_item = data_bag_item('credentials', 'postgresql') - -postgresql_server_install "main" do - version "10" - setup_repo false - password postgresql_data_bag_item['server_password'] - action :install +service postgresql_service do + supports restart: true, status: true, reload: true + action [:enable] end -postgresql_client_install "main" do - version "10" - setup_repo false - action :install +# This will only be run once, if the /var/lib/postgresql/10/main directory +# exists. The old data directory is then moved. +execute "upgrade postgresql to 12" do + command <<-EOF +systemctl stop postgresql@12-main +systemctl stop postgresql@10-main +su - postgres -c "/usr/lib/postgresql/12/bin/pg_upgrade --old-bindir=/usr/lib/postgresql/10/bin/ --new-bindir=/usr/lib/postgresql/12/bin/ --old-datadir=/etc/postgresql/10/main/ --new-datadir=/etc/postgresql/12/main/" +mv /var/lib/postgresql/10/main /var/lib/postgresql/10/main.old +systemctl start postgresql@12-main + EOF + only_if { ::File.exist? "/var/lib/postgresql/10/main" } +end + +postgresql_replicas.each do |replica| + postgresql_access "#{replica[:hostname]} replication" do + access_type "host" + access_db "replication" + access_user "replication" + access_addr "#{replica[:ipaddress]}/32" + access_method "md5" + notifies :reload, "service[#{postgresql_service}]", :immediately + end + + unless node.chef_environment == "development" + include_recipe "firewall" + + firewall_rule "postgresql" do + port 5432 + protocol :tcp + command :allow + destination replica[:ipaddress] + end + end end diff --git a/site-cookbooks/kosmos-postgresql/recipes/replica.rb b/site-cookbooks/kosmos-postgresql/recipes/replica.rb new file mode 100644 index 0000000..6bbcb75 --- /dev/null +++ b/site-cookbooks/kosmos-postgresql/recipes/replica.rb @@ -0,0 +1,82 @@ +# +# Cookbook:: kosmos-postgresql +# Recipe:: replica +# +# The MIT License (MIT) +# +# Copyright:: 2019, Kosmos Developers +# +# 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: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +postgresql_version = "12" +postgresql_service = "postgresql@#{postgresql_version}-main" + +postgresql_custom_server postgresql_version do + role "replica" +end + +service postgresql_service do + supports restart: true, status: true, reload: true + action [:enable] +end + +postgresql_data_bag_item = data_bag_item('credentials', 'postgresql') + +primary = postgresql_primary + +unless primary.nil? + postgresql_data_dir = "/var/lib/postgresql/#{postgresql_version}/main" + + if node['kosmos-postgresql']['ready_to_set_up_replica'] + execute "set up replication" do + command <<-EOF +systemctl stop #{postgresql_service} +mv #{postgresql_data_dir} #{postgresql_data_dir}.old +PGPASSWORD=#{postgresql_data_bag_item['replication_password']} pg_basebackup -h #{primary[:ipaddress]} -U replication -D #{postgresql_data_dir} -R +chown -R postgres:postgres #{postgresql_data_dir} +systemctl start #{postgresql_service} + EOF + sensitive true + not_if { ::File.exist? "#{postgresql_data_dir}/standby.signal" } + end + end + + postgresql_access "replication" do + access_type "host" + access_db "replication" + access_user "replication" + access_addr "#{primary[:ipaddress]}/32" + access_method "md5" + notifies :reload, "service[#{postgresql_service}]", :immediately + end + + # On the next Chef run the replica will be set up + node.normal['kosmos-postgresql']['ready_to_set_up_replica'] = true + + unless node.chef_environment == "development" + include_recipe "firewall" + + firewall_rule "postgresql" do + port 5432 + protocol :tcp + command :allow + destination primary[:ipaddress] + end + end +end diff --git a/site-cookbooks/kosmos-postgresql/resources/server.rb b/site-cookbooks/kosmos-postgresql/resources/server.rb new file mode 100644 index 0000000..b6919e8 --- /dev/null +++ b/site-cookbooks/kosmos-postgresql/resources/server.rb @@ -0,0 +1,102 @@ +resource_name :postgresql_custom_server + +property :postgresql_version, String, required: true, name_property: true +property :role, String, required: true # Can be primary or replica + +action :create do + postgresql_version = new_resource.postgresql_version + postgresql_data_dir = data_dir(postgresql_version) + postgresql_service = "postgresql@#{postgresql_version}-main" + + node.override['build-essential']['compile_time'] = true + include_recipe 'build-essential::default' + + package("libpq-dev") { action :nothing }.run_action(:install) + + chef_gem 'pg' do + compile_time true + end + + postgresql_data_bag_item = data_bag_item('credentials', 'postgresql') + + postgresql_server_install "main" do + version postgresql_version + setup_repo true + password postgresql_data_bag_item['server_password'] + action :install + end + + service postgresql_service do + supports restart: true, status: true, reload: true + # action [:enable, :start] + end + + postgresql_client_install "main" do + version postgresql_version + setup_repo true + action :install + end + + postgresql_user "replication" do + action :create + replication true + password postgresql_data_bag_item['replication_password'] + end + + shared_buffers = if node['memory']['total'].to_i / 1024 < 1024 # > 1GB RAM + "128MB" + else # >= 1GB RAM, use 25% of total RAM + "#{node['memory']['total'].to_i / 1024 / 4}MB" + end + + additional_config = { + max_connections: 100, # default + shared_buffers: shared_buffers, + unix_socket_directories: "/var/run/postgresql", + dynamic_shared_memory_type: "posix", + timezone: "UTC", # default is GMT + listen_addresses: "0.0.0.0", + } + + if new_resource.role == "replica" + additional_config[:promote_trigger_file] = "#{postgresql_data_dir}/failover.trigger" + end + + ssl_cert = postgresql_data_bag_item['ssl_cert'] + ssl_cert_path = "#{postgresql_data_dir}/server.crt" + ssl_key = postgresql_data_bag_item['ssl_key'] + ssl_key_path = "#{postgresql_data_dir}/server.key" + + file ssl_cert_path do + content ssl_cert + owner "postgres" + group "postgres" + mode "0640" + sensitive true + end + + file ssl_key_path do + content ssl_key + owner "postgres" + group "postgres" + mode "0600" + sensitive true + end + + additional_config[:ssl] = "on" + additional_config[:ssl_cert_file] = ssl_cert_path + additional_config[:ssl_key_file] = ssl_key_path + # ejabberd does not support 1.3 yet + additional_config[:ssl_min_protocol_version] = "TLSv1.2" + + postgresql_server_conf "main" do + version postgresql_version + additional_config additional_config + notifies :reload, "service[#{postgresql_service}]" + end +end + +action_class do + # to use the data_dir helper + include PostgresqlCookbook::Helpers +end