diff --git a/.gitignore b/.gitignore index 7bed114..024f1e1 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ pkg/ Berksfile.lock # Bundler +Gemfile.lock bin/* .bundle/* diff --git a/.kitchen.cloud.yml b/.kitchen.cloud.yml deleted file mode 100644 index f56be17..0000000 --- a/.kitchen.cloud.yml +++ /dev/null @@ -1,49 +0,0 @@ ---- -driver: - name: ec2 - access_key_id: "<%= ENV['AWS_ACCESS_KEY_ID'] %>" - secret_access_key: "<%= ENV['AWS_SECRET_ACCESS_KEY'] %>" - aws_ssh_key_id: travis-ci-aws-frank - security_group_ids: ["sg-2dc50845"] - region: eu-central-1 - require_chef_omnibus: 12 - instance_type: t2.micro - tags: - Name: travis-ci - -transport: - ssh_key: '.travis/travis-ci-aws-frank.pem' - connection_timeout: 10 - connection_retries: 5 - -platforms: - - name: ubuntu-14.04 - driver: - image_id: ami-6bee0004 - transport: - username: ubuntu - - name: ubuntu-16.04 - driver: - image_id: ami-f9e30f96 - transport: - username: ubuntu - -provisioner: - name: chef_solo - -suites: - - name: pg-91 - run_list: - - recipe[apt] - - recipe[pgtest::test_9_1] - - name: pg-94 - run_list: - - recipe[apt] - - recipe[pgtest::test_9_4] - - name: pg-94-chef11 - run_list: - - recipe[apt] - - recipe[pgtest::test_9_4] - provisioner: - name: chef_zero - require_chef_omnibus: 11.14.2 diff --git a/.kitchen.docker.yml b/.kitchen.docker.yml new file mode 100644 index 0000000..97aa379 --- /dev/null +++ b/.kitchen.docker.yml @@ -0,0 +1,357 @@ +--- +driver: + name: docker + use_sudo: false + privileged: true + +provisioner: + product_name: chef + chef_license: accept + +verifier: + name: inspec + inspec_tests: + - path: test/integration/postgresql_lwrp_test + +platforms: + - name: debian-8-docker + driver_config: + image: debian:8 + disable_upstart: false + run_command: '/sbin/init' + provision_command: + # For postgreqsl + - echo "en_US.UTF-8 UTF-8" > /etc/locale.gen + - apt-get install -y locales && locale-gen en_US.UTF-8 + # Netstat for Serverspec + - apt-get install -y net-tools + + - name: debian-9-docker + driver_config: + image: debian:9 + disable_upstart: false + run_command: '/lib/systemd/systemd' + provision_command: + # For postgreqsl + - echo "en_US.UTF-8 UTF-8" > /etc/locale.gen + - apt-get install -y locales && locale-gen en_US.UTF-8 + # Netstat for Serverspec + - apt-get install -y net-tools + # gnupg for Chef + - apt-get install -y gnupg + + - name: ubuntu-14.04-docker + driver_config: + image: ubuntu-upstart:14.04 + disable_upstart: false + run_command: '/sbin/init' + provision_command: + # Netstat for Serverspec + - apt-get install -y net-tools + + + - name: ubuntu-16.04-docker + driver_config: + image: ubuntu:16.04 + run_command: '/sbin/init' + provision_command: + # For systemd + - systemctl set-default multi-user.target + # For postgreqsl + - apt-get install -y locales && locale-gen en_US.UTF-8 + # Netstat for Serverspec + - apt-get install -y net-tools + + - name: ubuntu-18.04-docker + driver_config: + image: ubuntu:18.04 + run_command: '/sbin/init' + provision_command: + - apt-get install -y locales && locale-gen en_US.UTF-8 + # For systemd + - systemctl set-default multi-user.target + # Netstat for Inspec + - apt-get install -y net-tools + # gnupg for Chef + - apt-get install -y gnupg + +suites: + - name: pg-96-chef13 + provisioner: + product_name: chef + product_version: 13 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.6' + verifier: + attributes: + pg_version: 9.6 + + - name: pg-10-chef13 + provisioner: + product_name: chef + product_version: 13 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '10' + verifier: + attributes: + pg_version: 10 + + - name: pg-11-chef13 + provisioner: + product_name: chef + product_version: 13 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '11' + verifier: + attributes: + pg_version: 11 + + - name: pg-91-chef14 + provisioner: + product_name: chef + product_version: 14 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.1' + verifier: + attributes: + pg_version: 9.1 + excludes: + # There is no official postgresql-9.1 package for Debian 9 & Ubuntu 18.04 + - debian-9-docker + - ubuntu-18.04-docker + + - name: pg-92-chef14 + provisioner: + product_name: chef + product_version: 14 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.2' + verifier: + attributes: + pg_version: 9.2 + excludes: + # There is no official postgresql-9.2 package for Ubuntu 18.04 + - ubuntu-18.04-docker + + - name: pg-93-chef14 + provisioner: + product_name: chef + product_version: 14 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.3' + verifier: + attributes: + pg_version: 9.3 + + - name: pg-94-chef14 + provisioner: + product_name: chef + product_version: 14 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.4' + verifier: + attributes: + pg_version: 9.4 + + - name: pg-95-chef14 + provisioner: + product_name: chef + product_version: 14 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.5' + verifier: + attributes: + pg_version: 9.5 + + - name: pg-96-chef14 + provisioner: + product_name: chef + product_version: 14 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.6' + verifier: + attributes: + pg_version: 9.6 + + - name: pg-10-chef14 + provisioner: + product_name: chef + product_version: 14 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '10' + verifier: + attributes: + pg_version: 10 + + - name: pg-11-chef14 + provisioner: + product_name: chef + product_version: 14 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '11' + verifier: + attributes: + pg_version: 11 + + - name: pg-91-chef15 + provisioner: + product_name: chef + product_version: 15 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.1' + verifier: + attributes: + pg_version: 9.1 + excludes: + # There is no official postgresql-9.1 package for Debian 9 & Ubuntu 18.04 + - debian-9-docker + - ubuntu-18.04-docker + + - name: pg-92-chef15 + provisioner: + product_name: chef + product_version: 15 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.2' + verifier: + attributes: + pg_version: 9.2 + excludes: + # There is no official postgresql-9.2 package for Ubuntu 18.04 + - ubuntu-18.04-docker + + - name: pg-93-chef15 + provisioner: + product_name: chef + product_version: 15 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.3' + verifier: + attributes: + pg_version: 9.3 + + - name: pg-94-chef15 + provisioner: + product_name: chef + product_version: 15 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.4' + verifier: + attributes: + pg_version: 9.4 + + - name: pg-95-chef15 + provisioner: + product_name: chef + product_version: 15 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.5' + verifier: + attributes: + pg_version: 9.5 + + - name: pg-96-chef15 + provisioner: + product_name: chef + product_version: 15 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.6' + verifier: + attributes: + pg_version: 9.6 + + - name: pg-10-chef15 + provisioner: + product_name: chef + product_version: 15 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '10' + verifier: + attributes: + pg_version: 10 + + - name: pg-11-chef15 + provisioner: + product_name: chef + product_version: 15 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '11' + verifier: + attributes: + pg_version: 11 diff --git a/.kitchen.yml b/.kitchen.yml index 391e260..7adabfa 100644 --- a/.kitchen.yml +++ b/.kitchen.yml @@ -3,49 +3,304 @@ driver_plugin: vagrant provisioner: name: chef_zero - require_chef_omnibus: 12 + chef_license: accept + +verifier: + name: inspec + inspec_tests: + - path: test/integration/postgresql_lwrp_test platforms: - - name: ubuntu-12.04 - driver: - box: express42/ubuntu12.04-chef11 - name: ubuntu-14.04 driver: - box: express42/ubuntu-14.04 + box: bento/ubuntu-14.04 - name: ubuntu-16.04 driver: - box: express42/ubuntu-16.04 - - name: debian-7.9 - - name: debian-8.4 + box: bento/ubuntu-16.04 + - name: ubuntu-18.04 + driver: + box: bento/ubuntu-18.04 + - name: debian-9 + driver: + box: bento/debian-9 suites: - - name: pg-90 + - name: pg-96-chef13 + provisioner: + product_name: chef + product_version: 13 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.6' + verifier: + attributes: + pg_version: 9.6 + + - name: pg-10-chef13 + provisioner: + product_name: chef + product_version: 13 run_list: - recipe[apt] - - recipe[pgtest::test_9_0] + - recipe[pgtest::test] + attributes: + pgtest: + version: '10' + verifier: + attributes: + pg_version: 10 + + - name: pg-11-chef13 + provisioner: + product_name: chef + product_version: 13 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '11' + verifier: + attributes: + pg_version: 11 + + - name: pg-91-chef14 + provisioner: + product_name: chef + product_version: 14 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.1' + verifier: + attributes: + pg_version: 9.1 excludes: - - ubuntu-16.04 - - debian-8.4 - - name: pg-91 + # There is no official postgresql-9.1 package for Debian 9 & Ubuntu 18.04 + - debian-9 + - ubuntu-18.04 + + - name: pg-92-chef14 + provisioner: + product_name: chef + product_version: 14 run_list: - recipe[apt] - - recipe[pgtest::test_9_1] - - name: pg-92 + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.2' + verifier: + attributes: + pg_version: 9.2 + excludes: + # There is no official postgresql-9.2 package for Ubuntu 18.04 + - ubuntu-18.04 + + - name: pg-93-chef14 + provisioner: + product_name: chef + product_version: 14 run_list: - recipe[apt] - - recipe[pgtest::test_9_2] - - name: pg-93 + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.3' + verifier: + attributes: + pg_version: 9.3 + + - name: pg-94-chef14 + provisioner: + product_name: chef + product_version: 14 run_list: - recipe[apt] - - recipe[pgtest::test_9_3] - - name: pg-94 + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.4' + verifier: + attributes: + pg_version: 9.4 + + - name: pg-95-chef14 + provisioner: + product_name: chef + product_version: 14 run_list: - recipe[apt] - - recipe[pgtest::test_9_4] - - name: pg-94-chef11 + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.5' + verifier: + attributes: + pg_version: 9.5 + + - name: pg-96-chef14 + provisioner: + product_name: chef + product_version: 14 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.6' + verifier: + attributes: + pg_version: 9.6 + + - name: pg-10-chef14 + provisioner: + product_name: chef + product_version: 14 run_list: - recipe[apt] - - recipe[pgtest::test_9_4] + - recipe[pgtest::test] + attributes: + pgtest: + version: '10' + verifier: + attributes: + pg_version: 10 + + - name: pg-11-chef14 provisioner: - name: chef_zero - require_chef_omnibus: 11.14.2 + product_name: chef + product_version: 14 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '11' + verifier: + attributes: + pg_version: 11 + + - name: pg-91-chef15 + provisioner: + product_name: chef + product_version: 15 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.1' + verifier: + attributes: + pg_version: 9.1 + excludes: + # There is no official postgresql-9.1 package for Debian 9 & Ubuntu 18.04 + - debian-9 + - ubuntu-18.04 + + - name: pg-92-chef15 + provisioner: + product_name: chef + product_version: 15 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.2' + verifier: + attributes: + pg_version: 9.2 + excludes: + # There is no official postgresql-9.2 package for Ubuntu 18.04 + - ubuntu-18.04 + + - name: pg-93-chef15 + provisioner: + product_name: chef + product_version: 15 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.3' + verifier: + attributes: + pg_version: 9.3 + + - name: pg-94-chef15 + provisioner: + product_name: chef + product_version: 15 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.4' + verifier: + attributes: + pg_version: 9.4 + + - name: pg-95-chef15 + provisioner: + product_name: chef + product_version: 15 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.5' + verifier: + attributes: + pg_version: 9.5 + + - name: pg-96-chef15 + provisioner: + product_name: chef + product_version: 15 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '9.6' + verifier: + attributes: + pg_version: 9.6 + + - name: pg-10-chef15 + provisioner: + product_name: chef + product_version: 15 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '10' + verifier: + attributes: + pg_version: 10 + + - name: pg-11-chef15 + provisioner: + product_name: chef + product_version: 15 + run_list: + - recipe[apt] + - recipe[pgtest::test] + attributes: + pgtest: + version: '11' + verifier: + attributes: + pg_version: 11 diff --git a/.rspec b/.rspec deleted file mode 100644 index 1020571..0000000 --- a/.rspec +++ /dev/null @@ -1 +0,0 @@ ---color --format progress diff --git a/.rubocop.yml b/.rubocop.yml index ee7a80e..195f4d7 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,18 +1,3 @@ -LineLength: +--- +Naming/PredicateName: Enabled: false -SingleSpaceBeforeFirstArg: - Exclude: - - '**/metadata.rb' -MethodLength: - Exclude: - - 'test/**/spec_helper.rb' - - 'libraries/helpers.rb' -AbcSize: - Exclude: - - 'libraries/helpers.rb' - - 'test/**/spec_helper.rb' -Documentation: - Enabled: false -CyclomaticComplexity: - Exclude: - - 'libraries/helpers.rb' diff --git a/.travis.yml b/.travis.yml index 0de8447..cec61f0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,35 +1,86 @@ +services: + - docker + language: ruby cache: bundler sudo: false rvm: -- 2.2.2 -bundler_args: "--without kitchen_vagrant" +- 2.6.3 +bundler_args: "--without kitchen_vagrant kitchen_cloud aws" + before_install: -- openssl aes-256-cbc -K $encrypted_b45d6f20bf91_key -iv $encrypted_b45d6f20bf91_iv - -in .travis/secret_keys.tar.enc -out .travis/secret_keys.tar -d -- tar xf .travis/secret_keys.tar -C .travis -- mv .travis/travis_rsa ~/.ssh/id_rsa -script: -- bundle exec rubocop -- bundle exec foodcritic -f any . -- bundle exec rspec -- bundle exec kitchen test -c 10 -d always -deploy: - edge: - source: Artemmkin/dpl - branch: master - provider: chef-supermarket - user_id: express42 - client_key: ".travis/express42.pem" - cookbook_category: Databases - skip_cleanup: true - on: - tags: true -notifications: - slack: - secure: M7REbNB5Wf6eMBxQijnquWw4KlBbrw5zLM6fWqB1CjA3IF7DbYFUgvBTeUAxTFE9P2KEahYydPRkhzDtQ49PpE31g93yfy1yqQ/1rBHuzmZztR1hpwzYAhzGg4cak/47LQPaHx6Y9Pa83N8BPwpE4t9936wB3gXBlQERQdGdmoE= + - gem update --system + - gem install bundler + +script: "bundle exec kitchen test ${INSTANCE} --destroy=always" + env: global: - - KITCHEN_YAML=.kitchen.cloud.yml + - KITCHEN_YAML=.kitchen.docker.yml - secure: Ag8Zn5lQxHrj+Xi79FAKiyq1mJxos+eQe6rL3xrk0aDL10YuAbbYz32jOce1MlIvTsEl4uaVQXQXIJmHjbCqzf5m61FYqRMqVhQ8B+Sh3AYiGe1MYpl9KJSYleyJPqJBDBZ/xfLpDKX7PoUCgXpHm2ZION2YFBHdRx3tN/lejoU= - secure: FAO//JQqC+rY3ce19GjA/KWpNskY2nT+8i83WyueHZ20zIc6FMdkWOs+WcEcnfcXDG8GBCqiIG+wF1GajUWirWo+aEIjIguADJhZwuLqD4g6KDmRW9p1MB2b3XDvAbvzze7yy6uG9GcuhiKo+J3S33YugFD59UHGa7hCGeEukAo= + matrix: + - INSTANCE=pg-11-chef15-ubuntu-1604 + - INSTANCE=pg-11-chef15-debian-9 + - INSTANCE=pg-11-chef15-debian-8 + - INSTANCE=pg-10-chef15-ubuntu-1604 + - INSTANCE=pg-10-chef15-debian-9 + - INSTANCE=pg-10-chef15-debian-8 + - INSTANCE=pg-96-chef15-ubuntu-1604 + - INSTANCE=pg-96-chef15-ubuntu-1404 + - INSTANCE=pg-96-chef15-debian-9 + - INSTANCE=pg-96-chef15-debian-8 + - INSTANCE=pg-93-chef14-ubuntu-1404 + - INSTANCE=pg-93-chef14-ubuntu-1604 + - INSTANCE=pg-93-chef14-debian-8 + - INSTANCE=pg-93-chef14-debian-9 + - INSTANCE=pg-94-chef14-ubuntu-1604 + - INSTANCE=pg-94-chef14-debian-8 + - INSTANCE=pg-94-chef14-debian-9 + - INSTANCE=pg-95-chef14-ubuntu-1604 + - INSTANCE=pg-95-chef14-debian-8 + - INSTANCE=pg-95-chef14-debian-9 + - INSTANCE=pg-96-chef14-ubuntu-1404 + - INSTANCE=pg-96-chef14-ubuntu-1604 + - INSTANCE=pg-96-chef14-debian-8 + - INSTANCE=pg-96-chef14-debian-9 + - INSTANCE=pg-10-chef14-ubuntu-1604 + - INSTANCE=pg-10-chef14-debian-8 + - INSTANCE=pg-10-chef14-debian-9 + - INSTANCE=pg-11-chef14-ubuntu-1604 + - INSTANCE=pg-11-chef14-ubuntu-1604 + - INSTANCE=pg-11-chef14-debian-8 + - INSTANCE=pg-11-chef14-debian-9 + - INSTANCE=pg-96-chef13-ubuntu-1404 + - INSTANCE=pg-96-chef13-ubuntu-1604 + - INSTANCE=pg-96-chef13-debian-8 + - INSTANCE=pg-96-chef13-debian-9 + - INSTANCE=pg-10-chef13-ubuntu-1604 + - INSTANCE=pg-10-chef13-debian-8 + - INSTANCE=pg-10-chef13-debian-9 + - INSTANCE=pg-11-chef13-ubuntu-1404 + - INSTANCE=pg-11-chef13-ubuntu-1604 + - INSTANCE=pg-11-chef13-debian-8 + - INSTANCE=pg-11-chef13-debian-9 + +jobs: + include: + - stage: lint + script: + - bundle exec cookstyle --version + - bundle exec cookstyle + - bundle exec foodcritic --version + - bundle exec foodcritic --contex --epic-fail any . + + - stage: deploy + if: tag =~ ^[0-9]\.[0-9]\.[0-9]$ + script: + - openssl aes-256-cbc -K $encrypted_b45d6f20bf91_key -iv $encrypted_b45d6f20bf91_iv + -in .travis/secret_keys.tar.enc -out .travis/secret_keys.tar -d + - tar xf .travis/secret_keys.tar -C .travis + - bundle exec stove login --username express42 --key .travis/express42.pem + - bundle exec stove --no-git + +notifications: + slack: + secure: M7REbNB5Wf6eMBxQijnquWw4KlBbrw5zLM6fWqB1CjA3IF7DbYFUgvBTeUAxTFE9P2KEahYydPRkhzDtQ49PpE31g93yfy1yqQ/1rBHuzmZztR1hpwzYAhzGg4cak/47LQPaHx6Y9Pa83N8BPwpE4t9936wB3gXBlQERQdGdmoE= diff --git a/Berksfile b/Berksfile index b2faf8a..1d21b60 100644 --- a/Berksfile +++ b/Berksfile @@ -3,12 +3,12 @@ source 'https://supermarket.chef.io' metadata group :integration do - cookbook 'sysctl', '<0.8.0' + cookbook 'sysctl' cookbook 'pgtest', path: 'test/fixtures/cookbooks/pgtest' end group :compat do - cookbook 'build-essential', '<4.0' - cookbook 'apt', '<4.0' - cookbook 'ohai', '=3.0.1' + cookbook 'build-essential' + cookbook 'apt' + cookbook 'ohai' end diff --git a/CHANGELOG.md b/CHANGELOG.md index 2569855..2d127ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,106 @@ +## 1.6.3 (Aug 19, 2019) + +* (New) wal-g version 0.2.11 +* (New) bundle update + +## 1.6.2 (Aug 05, 2019) + +* (Fix) more typos in attributes + +## 1.6.1 (Jul 30, 2019) + +* (Fix) typos in attributes. + +## 1.6.0 (Jul 03, 2019) + +* (Deprecation) `postgresql_cloud_backup` attribute `protocol` was removed. It was used only for a partial env vars validation. + +## 1.5.4 (Jun 28, 2019) + +* Travis config: tests for Ubuntu 18.04 were removed again. Run local ones. + +## 1.5.3 (Jun 27, 2019) + +* (New) WAL-G version 0.2.9 +* (New) `wal-g wal-push` fix by injecting the `PATH` variable into the envdir +* (New) ruby 2.6.3 for TravisCI +* (New) Test Kitchen suites for Chef 15 + +## 1.5.2 (Feb 25, 2019) + +* (New) tests for PostgreSQL 9.1 & 9.2 were dropped from TravisCI configuration +* (New) WAL-G version 0.2.6 which has new GPG support implementation + +## 1.5.1 (Feb 17, 2019) + +* (Fix) envdir's files should be marked as sensitive. +* (Fix) Set PGHOST environment variable to `/var/run/postgresql` for wal-g if unset. + +## 1.5.0 (Feb 16, 2019) + +* (New) PostgreSQL 11 tests +* (New) wal-g support for cloud backup +* (New) Ruby 2.6.0 for TravisCI tests +* (New) Inspec configuration to test running PostgreSQL configuration +* (Fix) pip version 18.0 was pinned as the newer fails to install to sandbox +* (Fix) Some minor ruby style fixes +* (Fix) Other pg extension should be installed during integration tests + +## 1.4.2 (May 22, 2018) + +* (New) Ubuntu 18.04 tests +* (New) Test Kitchen configuration for AWS cloud was removed +* (Fix) cookbook `poise-python` version was restricted again `>= 1.7.0` +* (Fix) Some minor Test Kitchen configuration improvements + +## 1.4.1 (May 15, 2018) + +* (Fix) Unpin `poise-python` cookbook version + +## 1.4.0 (Apr 10, 2018) + +* (New) Chef 14 support & tests +* (New) LWRP-defined resources were rewritten using the new custom resource style +* (Fix) TravisCI: all Chef 13 test were enabled + +## 1.3.1 (Apr 03, 2018) +* (Fix) TravisCI build method. Now using `sethvargo/stove` gem instead of `dpl` + +## 1.3.0 (Apr 03, 2018) +* (New) Chef 12 test were dropped. (Chef 12 reaches EOL at the and of April 2018) +* (New) Chef 13 full support; +* (New) WAL-E version 1.1.0; +* (New) `poise-python` cookbook is used instead of outdated `python`; +* (Fix) TravisCI configuration was updated to test against more OSes and to use Chef 13; +* (Fix) Berksfile version pins were removed; + +## 1.2.4 (Mar 12, 2018) +* (Fix) Rename `params` method in `postgresql_cloud_backup` for compatibility with Chef 13 + +## 1.2.3 (Jan 31, 2018) +* (Fix) Resource `postgresql` PostgreSQL version validation. +* (Fix) Use resource attributes to set PostgreSQL version for test purposes. + +## 1.2.2 (Jan 16, 2018) +* (New) PostgreSQL 10 support. +* (New) Integration tests were migrated to InSpec. +* (New) InSpec resources: postgres_database +* (Fix) InSpec resources: `postgres_cluster`, `postgres_extension` & `postgres_user` were refactored. +* (Fix) Test Kitchen: use one test recipe instead of one-recipe-per-pg-version. +* (Fix) Test Kitchen: use only official images. +* (Fix) Test Kitchen: tests for Chef 11 support were removed, as outdated. +* (Fix) Test Kitchen: Test for Postgresql 9.0 were removed; there is PostgreSQL 9.0 package on modern systems. +* (Fix) [postgresql] fix ruby_block notifications. +* (Fix) [pgtest] user creation should be invoked using `encrypted_password` attribute for better compatibility. + +## 1.2.1 (Dec 15, 2016) +* (New) Autoremove checkpoint_segments from configuration if pg > 9.4 + ## 1.2.0 (Jul 22, 2016) * (New) Add extension lwrp to install extensions from postgresql-contrib subpackage, which comes installed * (New) Add pgxn extension lwrp to install extensions from pgxn.org website, using pgxn client * (New) Add test recipes for installing extensions with newly introduced resources - ## 1.1.15 (Sep 24, 2015) * (Fix) [postgresql] Fix initial slave creation on 9.1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..5aa3471 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,10 @@ +If you wish to contribute, please follow these steps: + +1. Fork this repository on GitHub. +2. Create a new branch. +3. Write your code. +4. Write new tests. +5. Run tests from [TESTING.md](https://github.com/express42/postgresql_lwrp/blob/master/TESTING.md). +6. If everythig is Ok, commit and create a pull request. + +Thank you! \ No newline at end of file diff --git a/Gemfile b/Gemfile index 2351c96..da46501 100644 --- a/Gemfile +++ b/Gemfile @@ -5,9 +5,16 @@ end group :unit do gem 'chefspec' end +group :inspec do + gem 'inspec', '~>4.7.24' + gem 'kitchen-inspec' +end group :lint do gem 'foodcritic' - gem 'rubocop' + gem 'cookstyle' +end +group :kitchen_docker do + gem 'kitchen-docker' end group :kitchen_common do gem 'test-kitchen' @@ -15,10 +22,6 @@ end group :kitchen_vagrant do gem 'kitchen-vagrant' end -group :kitchen_cloud do - gem 'kitchen-digitalocean' - gem 'kitchen-ec2' -end -group :aws do - gem 'aws-sdk', '2.2.34' +group :deploy do + gem 'stove' end diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index 715ff50..0000000 --- a/Gemfile.lock +++ /dev/null @@ -1,322 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - activesupport (4.1.9) - i18n (~> 0.6, >= 0.6.9) - json (~> 1.7, >= 1.7.7) - minitest (~> 5.1) - thread_safe (~> 0.1) - tzinfo (~> 1.1) - addressable (2.3.7) - artifactory (2.3.2) - ast (2.0.0) - astrolabe (1.3.0) - parser (>= 2.2.0.pre.3, < 3.0) - aws-sdk (2.2.34) - aws-sdk-resources (= 2.2.34) - aws-sdk-core (2.2.34) - jmespath (~> 1.0) - aws-sdk-resources (2.2.34) - aws-sdk-core (= 2.2.34) - axiom-types (0.1.1) - descendants_tracker (~> 0.0.4) - ice_nine (~> 0.11.0) - thread_safe (~> 0.3, >= 0.3.1) - berkshelf (3.2.3) - addressable (~> 2.3.4) - berkshelf-api-client (~> 1.2) - buff-config (~> 1.0) - buff-extensions (~> 1.0) - buff-shell_out (~> 0.1) - celluloid (~> 0.16.0) - celluloid-io (~> 0.16.1) - cleanroom (~> 1.0) - faraday (~> 0.9.0) - minitar (~> 0.5.4) - octokit (~> 3.0) - retryable (~> 2.0) - ridley (~> 4.0) - solve (~> 1.1) - thor (~> 0.19) - berkshelf-api-client (1.2.1) - faraday (~> 0.9.0) - buff-config (1.0.1) - buff-extensions (~> 1.0) - varia_model (~> 0.4) - buff-extensions (1.0.0) - buff-ignore (1.1.1) - buff-ruby_engine (0.1.0) - buff-shell_out (0.2.0) - buff-ruby_engine (~> 0.1.0) - builder (3.2.2) - celluloid (0.16.0) - timers (~> 4.0.0) - celluloid-io (0.16.2) - celluloid (>= 0.16.0) - nio4r (>= 1.1.0) - chef (12.4.0) - chef-config (= 12.4.0) - chef-zero (~> 4.2, >= 4.2.2) - diff-lcs (~> 1.2, >= 1.2.4) - erubis (~> 2.7) - ffi-yajl (~> 2.2) - highline (~> 1.6, >= 1.6.9) - mixlib-authentication (~> 1.3) - mixlib-cli (~> 1.4) - mixlib-log (~> 1.3) - mixlib-shellout (>= 2.0.0.rc.0, < 3.0) - net-ssh (~> 2.6) - net-ssh-multi (~> 1.1) - ohai (~> 8.0) - plist (~> 3.1.0) - pry (~> 0.9) - rspec-core (~> 3.2) - rspec-expectations (~> 3.2) - rspec-mocks (~> 3.2) - rspec_junit_formatter (~> 0.2.0) - serverspec (~> 2.7) - specinfra (~> 2.10) - syslog-logger (~> 1.6) - chef-config (12.4.0) - mixlib-config (~> 2.0) - mixlib-shellout (~> 2.0) - chef-zero (4.2.3) - ffi-yajl (>= 1.1, < 3.0) - hashie (~> 2.0) - mixlib-log (~> 1.3) - rack - uuidtools (~> 2.1) - chefspec (4.2.0) - chef (>= 11.14) - fauxhai (~> 2.0) - rspec (~> 3.0) - cleanroom (1.0.0) - coderay (1.1.0) - coercible (1.0.0) - descendants_tracker (~> 0.0.1) - dep-selector-libgecode (1.0.2) - dep_selector (1.0.3) - dep-selector-libgecode (~> 1.0) - ffi (~> 1.9) - descendants_tracker (0.0.4) - thread_safe (~> 0.3, >= 0.3.1) - diff-lcs (1.2.5) - droplet_kit (1.1.3) - activesupport (~> 4.1.6) - faraday (~> 0.9.1) - kartograph (~> 0.2.0) - resource_kit (~> 0.1.1) - virtus (~> 1.0.3) - equalizer (0.0.9) - erubis (2.7.0) - excon (0.49.0) - faraday (0.9.1) - multipart-post (>= 1.2, < 3) - fauxhai (2.3.0) - net-ssh - ohai - ffi (1.9.9) - ffi-yajl (2.2.0) - libyajl2 (~> 1.2) - foodcritic (4.0.0) - erubis - gherkin (~> 2.11) - nokogiri (~> 1.5) - rake - rufus-lru (~> 1.0) - treetop (~> 1.4) - yajl-ruby (~> 1.1) - gherkin (2.12.2) - multi_json (~> 1.3) - hashie (2.1.2) - highline (1.7.2) - hitimes (1.2.2) - i18n (0.7.0) - ice_nine (0.11.1) - ipaddress (0.8.3) - jmespath (1.2.4) - json_pure (>= 1.8.1) - json (1.8.2) - json_pure (1.8.3) - kartograph (0.2.0) - kitchen-digitalocean (0.8.3) - droplet_kit (~> 1.0) - test-kitchen (~> 1.2) - kitchen-ec2 (1.0.0) - aws-sdk (~> 2) - excon - multi_json - retryable (~> 2.0) - test-kitchen (~> 1.4, >= 1.4.1) - kitchen-vagrant (0.15.0) - test-kitchen (~> 1.0) - libyajl2 (1.2.0) - method_source (0.8.2) - mime-types (2.6.1) - mini_portile2 (2.0.0) - minitar (0.5.4) - minitest (5.5.1) - mixlib-authentication (1.3.0) - mixlib-log - mixlib-cli (1.5.0) - mixlib-config (2.2.1) - mixlib-install (1.0.12) - artifactory - mixlib-shellout - mixlib-versioning - mixlib-log (1.6.0) - mixlib-shellout (2.2.6) - mixlib-versioning (1.1.0) - multi_json (1.12.1) - multipart-post (2.0.0) - net-http-persistent (2.9.4) - net-scp (1.2.1) - net-ssh (>= 2.6.5) - net-ssh (2.9.4) - net-ssh-gateway (1.2.0) - net-ssh (>= 2.6.5) - net-ssh-multi (1.2.1) - net-ssh (>= 2.6.5) - net-ssh-gateway (>= 1.2.0) - net-telnet (0.1.1) - nio4r (1.1.0) - nokogiri (1.6.7.2) - mini_portile2 (~> 2.0.0.rc2) - octokit (3.8.0) - sawyer (~> 0.6.0, >= 0.5.3) - ohai (8.5.0) - ffi (~> 1.9) - ffi-yajl (~> 2.2) - ipaddress - mime-types (~> 2.0) - mixlib-cli - mixlib-config (~> 2.0) - mixlib-log - mixlib-shellout (~> 2.0) - rake (~> 10.1) - systemu (~> 2.6.4) - wmi-lite (~> 1.0) - parser (2.2.0.3) - ast (>= 1.1, < 3.0) - plist (3.1.0) - polyglot (0.3.5) - powerpack (0.1.0) - pry (0.10.1) - coderay (~> 1.1.0) - method_source (~> 0.8.1) - slop (~> 3.4) - rack (1.6.4) - rainbow (2.0.0) - rake (10.4.2) - resource_kit (0.1.2) - addressable (~> 2.3.6) - retryable (2.0.1) - ridley (4.1.2) - addressable - buff-config (~> 1.0) - buff-extensions (~> 1.0) - buff-ignore (~> 1.1) - buff-shell_out (~> 0.1) - celluloid (~> 0.16.0) - celluloid-io (~> 0.16.1) - erubis - faraday (~> 0.9.0) - hashie (>= 2.0.2, < 3.0.0) - json (>= 1.7.7) - mixlib-authentication (>= 1.3.0) - net-http-persistent (>= 2.8) - retryable (>= 2.0.0) - semverse (~> 1.1) - varia_model (~> 0.4) - rspec (3.4.0) - rspec-core (~> 3.4.0) - rspec-expectations (~> 3.4.0) - rspec-mocks (~> 3.4.0) - rspec-core (3.4.4) - rspec-support (~> 3.4.0) - rspec-expectations (3.4.0) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.4.0) - rspec-its (1.2.0) - rspec-core (>= 3.0.0) - rspec-expectations (>= 3.0.0) - rspec-mocks (3.4.1) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.4.0) - rspec-support (3.4.1) - rspec_junit_formatter (0.2.3) - builder (< 4) - rspec-core (>= 2, < 4, != 2.12.0) - rubocop (0.29.1) - astrolabe (~> 1.3) - parser (>= 2.2.0.1, < 3.0) - powerpack (~> 0.1) - rainbow (>= 1.99.1, < 3.0) - ruby-progressbar (~> 1.4) - ruby-progressbar (1.7.1) - rufus-lru (1.0.5) - safe_yaml (1.0.4) - sawyer (0.6.0) - addressable (~> 2.3.5) - faraday (~> 0.8, < 0.10) - semverse (1.2.1) - serverspec (2.36.0) - multi_json - rspec (~> 3.0) - rspec-its - specinfra (~> 2.53) - sfl (2.2) - slop (3.6.0) - solve (1.2.1) - dep_selector (~> 1.0) - semverse (~> 1.1) - specinfra (2.58.0) - net-scp - net-ssh (>= 2.7, < 4.0) - net-telnet - sfl - syslog-logger (1.6.8) - systemu (2.6.5) - test-kitchen (1.9.1) - mixlib-install (~> 1.0, >= 1.0.4) - mixlib-shellout (>= 1.2, < 3.0) - net-scp (~> 1.1) - net-ssh (>= 2.9, < 4.0) - safe_yaml (~> 1.0) - thor (~> 0.18) - thor (0.19.1) - thread_safe (0.3.4) - timers (4.0.1) - hitimes - treetop (1.5.3) - polyglot (~> 0.3) - tzinfo (1.2.2) - thread_safe (~> 0.1) - uuidtools (2.1.5) - varia_model (0.4.0) - buff-extensions (~> 1.0) - hashie (>= 2.0.2, < 3.0.0) - virtus (1.0.4) - axiom-types (~> 0.1) - coercible (~> 1.0) - descendants_tracker (~> 0.0, >= 0.0.3) - equalizer (~> 0.0, >= 0.0.9) - wmi-lite (1.0.0) - yajl-ruby (1.2.1) - -PLATFORMS - ruby - -DEPENDENCIES - aws-sdk (= 2.2.34) - berkshelf - chefspec - foodcritic - kitchen-digitalocean - kitchen-ec2 - kitchen-vagrant - rubocop - test-kitchen - -BUNDLED WITH - 1.10.6 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e927ea3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2014 Express 42 public cookbooks + +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. diff --git a/MAINTAINERS b/MAINTAINERS index e346b99..ee3aad6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4,3 +4,4 @@ ikurochkin serjs osminog evtuhovich +dragonsmith diff --git a/README.md b/README.md index ce888a0..55db1d1 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,36 @@ -[![Chef cookbook](https://img.shields.io/cookbook/v/postgresql_lwrp.svg)](https://github.com/express42-cookbooks/postgresql_lwrp) -[![Code Climate](https://codeclimate.com/github/express42-cookbooks/postgresql_lwrp/badges/gpa.svg)](https://codeclimate.com/github/express42-cookbooks/postgresql_lwrp) -[![Build Status](https://travis-ci.org/express42-cookbooks/postgresql_lwrp.svg)](https://travis-ci.org/express42-cookbooks/postgresql_lwrp) +[![Chef cookbook](https://img.shields.io/cookbook/v/postgresql_lwrp.svg)](https://github.com/express42/postgresql_lwrp) +[![Code Climate](https://codeclimate.com/github/express42/postgresql_lwrp/badges/gpa.svg)](https://codeclimate.com/github/express42/postgresql_lwrp) +[![Build Status](https://travis-ci.org/express42/postgresql_lwrp.svg)](https://travis-ci.org/express42/postgresql_lwrp) Description =========== -This cookbook includes recipes and providers to install and configure postgresql database. This cookbook was tested with Postgresql 9.0, 9.1, 9.2, 9.3. Version 9.0 is supported with limitations: creating users and databases are not working, also 9.0 not supported in Ubuntu 16.04 and Debian Jessie. -Supported platforms: Debian Squeeze/Wheezy/Jessie and Ubuntu 12.04/14.04/16.04. +This cookbook includes recipes and providers to install and configure postgresql database. This cookbook was tested with Postgresql 9.1, 9.2, 9.3, 9.4, 9.5, 9.6 & 10. + +Supported platforms: + +* Debian 8 +* Debian 9 +* Ubuntu 14.04 +* Ubuntu 16.04 +* Ubuntu 18.04 + +*Note: TravisCI tests for Ubuntu 18.04 are omitted now because they somehow hang. Local Vagrant & Docker-based tests are succesfull. This will be investigated further.* Changelog ========= -See CHANGELOG.md +See [CHANGELOG.md](https://github.com/express42/postgresql_lwrp/blob/master/CHANGELOG.md) Requirements ============ -Minimal chef-client version is 11.14.2. + +The minimal recommended version of chef-client is `13.0.113`. It may still work on version `12.5.1` and older, but no tests are made starting from version `1.3.0` of this cookbook as Chef 12 is reaching its EOL in the April, 2018 Dependencies ============ -Postgresql cookbook depends on apt cookbook. + +* apt +* cron +* poise-python Attributes ========== @@ -159,15 +172,15 @@ Example full daily database backup ```ruby postgresql_cloud_backup 'main' do + utility 'wal-g' in_version '9.3' in_cluster 'main' full_backup_time weekday: '*', month: '*', day: '*', hour: '3', minute: '0' # Data bag item should contain following keys for S3 protocol: # aws_access_key_id, aws_secret_access_key, wale_s3_prefix - params Chef::EncryptedDataBagItem.load('s3', 'secrets').to_hash.select {|i| i != "id"} + parameters Chef::EncryptedDataBagItem.load('s3', 'secrets').to_hash.select {|i| i != "id"} # Or just a hash, if you don't use data bags: - params { aws_access_key_id: 'access_key', aws_secret_access_key: 'secret_key', wale_s3_prefix: 's3_prefix' } - protocol 's3' + parameters { aws_access_key_id: 'access_key', aws_secret_access_key: 'secret_key', walg_s3_prefix: 's3_prefix' } # In case you need to prepend wal-e with, for example, traffic limiter # you can use following method: command_prefix 'trickle -s -u 1024' @@ -184,7 +197,7 @@ $ /opt/wal-e/bin/postgresql_cloud_backup_helper.sh main 9.3 count 31 ``` -Example of how to install extensions from postgresql-contrib +Example of how to install extensions from postgresql-contrib NOTE: schema and version are optional parameters, but others are required ```ruby @@ -195,7 +208,7 @@ postgresql_extension 'cube' do schema 'public' end ``` -Example of how to install extensions from http://pgxn.org/ +Example of how to install extensions from http://pgxn.org/ NOTE: schema is an optional parameter, but others are required ```ruby @@ -209,22 +222,10 @@ end ``` +# License and Maintainer +Maintainer:: LLC Express 42 () +Source:: https://github.com/express42/postgresql_lwrp +Issues:: https://github.com/express42/postgresql_lwrp/issues -License and Author -================== - -Author:: Nikita Borzykh () - -Copyright (C) 2012-2016 LLC Express 42 - -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. +License:: MIT diff --git a/TESTING.md b/TESTING.md new file mode 100644 index 0000000..8165334 --- /dev/null +++ b/TESTING.md @@ -0,0 +1,11 @@ +## Testing + +To run all tests execute: + +```shell +bundle install + +bundle exec cookstyle && \ + bundle exec foodcritic --contex --epic-fail any . && \ + bundle exec kitchen test +``` diff --git a/attributes/cloud_backup.rb b/attributes/cloud_backup.rb deleted file mode 100644 index 68372a5..0000000 --- a/attributes/cloud_backup.rb +++ /dev/null @@ -1,6 +0,0 @@ -default['postgresql']['cloud_backup']['packages'] = %w(daemontools gcc lzop mbuffer pv python-dev libffi-dev) -default['postgresql']['cloud_backup']['install_source'] = 'pypi' -default['postgresql']['cloud_backup']['version'] = '0.7.3' -default['postgresql']['cloud_backup']['wal_e_bin'] = '/opt/wal-e/bin/wal-e' -default['postgresql']['cloud_backup']['wal_e_path'] = '/opt/wal-e' -default['postgresql']['cloud_backup']['github_repo'] = 'https://github.com/wal-e/wal-e' diff --git a/attributes/cloud_backup_wal_e.rb b/attributes/cloud_backup_wal_e.rb new file mode 100644 index 0000000..e0cd725 --- /dev/null +++ b/attributes/cloud_backup_wal_e.rb @@ -0,0 +1,22 @@ +# https://github.com/poise/poise-python/issues/133 +default['poise-python']['options']['pip_version'] = '18.0' + +default['postgresql']['cloud_backup']['wal_e']['packages'] = %w( + gcc + lzop + mbuffer + pv + python3-dev + libffi-dev + libssl-dev +) + +default['postgresql']['cloud_backup']['wal_e']['pypi_packages'] = %w( + boto +) + +default['postgresql']['cloud_backup']['wal_e']['install_source'] = 'pypi' +default['postgresql']['cloud_backup']['wal_e']['version'] = '1.1.0' +default['postgresql']['cloud_backup']['wal_e']['bin'] = '/opt/wal-e/bin/wal-e' +default['postgresql']['cloud_backup']['wal_e']['path'] = '/opt/wal-e' +default['postgresql']['cloud_backup']['wal_e']['github_repo'] = 'https://github.com/wal-e/wal-e' diff --git a/attributes/cloud_backup_wal_g.rb b/attributes/cloud_backup_wal_g.rb new file mode 100644 index 0000000..e6df278 --- /dev/null +++ b/attributes/cloud_backup_wal_g.rb @@ -0,0 +1,7 @@ +default['postgresql']['cloud_backup']['wal_g']['packages'] = %w( +) + +default['postgresql']['cloud_backup']['wal_g']['version'] = 'v0.2.11' +default['postgresql']['cloud_backup']['wal_g']['url'] = "https://github.com/wal-g/wal-g/releases/download/#{node['postgresql']['cloud_backup']['wal_g']['version']}/wal-g.linux-amd64.tar.gz" +default['postgresql']['cloud_backup']['wal_g']['checksum'] = '313a617311ad58005c407c2e9b06b3556785559b051e5fae5d147c17ba36f2bc' +default['postgresql']['cloud_backup']['wal_g']['bin'] = '/usr/local/bin/wal-g' diff --git a/attributes/server.rb b/attributes/server.rb index b022d3b..576e1fe 100644 --- a/attributes/server.rb +++ b/attributes/server.rb @@ -1,59 +1,61 @@ default['postgresql']['defaults']['server']['version'] = '9.2' -default['postgresql']['defaults']['server']['configuration']['listen_addresses'] = 'localhost' -default['postgresql']['defaults']['server']['configuration']['port'] = 5432 -default['postgresql']['defaults']['server']['configuration']['max_connections'] = 100 -default['postgresql']['defaults']['server']['configuration']['shared_buffers'] = '100MB' -default['postgresql']['defaults']['server']['configuration']['temp_buffers'] = '8MB' -default['postgresql']['defaults']['server']['configuration']['max_prepared_transactions'] = 0 -default['postgresql']['defaults']['server']['configuration']['work_mem'] = '2MB' -default['postgresql']['defaults']['server']['configuration']['maintenance_work_mem'] = '64MB' -default['postgresql']['defaults']['server']['configuration']['max_stack_depth'] = '2MB' -default['postgresql']['defaults']['server']['configuration']['max_files_per_process'] = '1000' -default['postgresql']['defaults']['server']['configuration']['vacuum_cost_delay'] = 0 -default['postgresql']['defaults']['server']['configuration']['wal_level'] = 'hot_standby' -default['postgresql']['defaults']['server']['configuration']['fsync'] = 'on' -default['postgresql']['defaults']['server']['configuration']['synchronous_commit'] = 'on' -default['postgresql']['defaults']['server']['configuration']['checkpoint_segments'] = '64' -default['postgresql']['defaults']['server']['configuration']['wal_sync_method'] = 'fsync' -default['postgresql']['defaults']['server']['configuration']['checkpoint_completion_target'] = '0.9' -default['postgresql']['defaults']['server']['configuration']['effective_cache_size'] = node['memory']['total'].to_i / 2 -default['postgresql']['defaults']['server']['configuration']['log_destination'] = 'stderr' -default['postgresql']['defaults']['server']['configuration']['syslog_ident'] = 'postgres' -default['postgresql']['defaults']['server']['configuration']['log_min_duration_statement'] = 200 -default['postgresql']['defaults']['server']['configuration']['log_truncate_on_rotation'] = 'on' -default['postgresql']['defaults']['server']['configuration']['log_rotation_age'] = '1d' -default['postgresql']['defaults']['server']['configuration']['log_rotation_size'] = 0 -default['postgresql']['defaults']['server']['configuration']['log_line_prefix'] = '%t [%p]: [%l-1]' -default['postgresql']['defaults']['server']['configuration']['track_activities'] = 'on' -default['postgresql']['defaults']['server']['configuration']['track_counts'] = 'on' -default['postgresql']['defaults']['server']['configuration']['autovacuum'] = 'on' -default['postgresql']['defaults']['server']['configuration']['autovacuum_naptime'] = '1min' -default['postgresql']['defaults']['server']['configuration']['archive_mode'] = 'off' -default['postgresql']['defaults']['server']['configuration']['max_wal_senders'] = 5 -default['postgresql']['defaults']['server']['configuration']['wal_keep_segments'] = 32 -default['postgresql']['defaults']['server']['configuration']['hot_standby'] = 'off' -default['postgresql']['defaults']['server']['configuration']['max_standby_archive_delay'] = '30s' -default['postgresql']['defaults']['server']['configuration']['max_standby_streaming_delay'] = '30s' -default['postgresql']['defaults']['server']['configuration']['wal_receiver_status_interval'] = '10s' -default['postgresql']['defaults']['server']['configuration']['hot_standby_feedback'] = 'on' -default['postgresql']['defaults']['server']['configuration']['extra_float_digits'] = 0 -default['postgresql']['defaults']['server']['configuration']['client_encoding'] = 'UTF8' -default['postgresql']['defaults']['server']['configuration']['ssl'] = true -default['postgresql']['defaults']['server']['configuration']['ssl_cert_file'] = '/etc/ssl/certs/ssl-cert-snakeoil.pem' -default['postgresql']['defaults']['server']['configuration']['ssl_key_file'] = '/etc/ssl/private/ssl-cert-snakeoil.key' -default['postgresql']['defaults']['server']['configuration']['ssl_renegotiation_limit'] = 0 -default['postgresql']['defaults']['server']['configuration']['lc_messages'] = 'en_US.UTF-8' -default['postgresql']['defaults']['server']['configuration']['lc_monetary'] = 'en_US.UTF-8' -default['postgresql']['defaults']['server']['configuration']['lc_numeric'] = 'en_US.UTF-8' -default['postgresql']['defaults']['server']['configuration']['lc_time'] = 'en_US.UTF-8' -default['postgresql']['defaults']['server']['configuration']['default_text_search_config'] = 'pg_catalog.russian' - +default['postgresql']['defaults']['server']['configuration'] = { + listen_addresses: 'localhost', + port: 5432, + max_connections: 100, + shared_buffers: '100MB', + temp_buffers: '8MB', + max_prepared_transactions: 0, + work_mem: '2MB', + maintenance_work_mem: '64MB', + max_stack_depth: '2MB', + max_files_per_process: '1000', + vacuum_cost_delay: 0, + wal_level: 'hot_standby', + fsync: 'on', + synchronous_commit: 'on', + checkpoint_segments: '64', + wal_sync_method: 'fsync', + checkpoint_completion_target: '0.9', + effective_cache_size: "#{(node['memory']['total'].to_i / (2 * 1024))}MB", + log_destination: 'stderr', + syslog_ident: 'postgres', + log_min_duration_statement: 200, + log_truncate_on_rotation: 'on', + log_rotation_age: '1d', + log_rotation_size: 0, + log_line_prefix: '%t [%p]: [%l-1]', + track_activities: 'on', + track_counts: 'on', + autovacuum: 'on', + autovacuum_naptime: '1min', + archive_mode: 'off', + max_wal_senders: 5, + wal_keep_segments: 32, + hot_standby: 'off', + max_standby_archive_delay: '30s', + max_standby_streaming_delay: '30s', + wal_receiver_status_interval: '10s', + hot_standby_feedback: 'on', + extra_float_digits: 0, + client_encoding: 'UTF8', + ssl: true, + ssl_cert_file: '/etc/ssl/certs/ssl-cert-snakeoil.pem', + ssl_key_file: '/etc/ssl/private/ssl-cert-snakeoil.key', + ssl_renegotiation_limit: 0, + lc_messages: 'en_US.UTF-8', + lc_monetary: 'en_US.UTF-8', + lc_numeric: 'en_US.UTF-8', + lc_time: 'en_US.UTF-8', + default_text_search_config: 'pg_catalog.russian', +} default['postgresql']['defaults']['server']['ident_configuration'] = [] default['postgresql']['defaults']['server']['hba_configuration'] = [ { type: 'local', database: 'all', user: 'postgres', address: '', method: 'peer' }, { type: 'local', database: 'all', user: 'all', address: '', method: 'peer' }, { type: 'host', database: 'all', user: 'all', address: '127.0.0.1/32', method: 'md5' }, - { type: 'host', database: 'all', user: 'all', address: '::1/128', method: 'md5' } + { type: 'host', database: 'all', user: 'all', address: '::1/128', method: 'md5' }, ] +default['postgresql']['defaults']['server']['replication'] = {} diff --git a/libraries/helpers.rb b/libraries/helpers.rb index 48f89c6..7b64143 100644 --- a/libraries/helpers.rb +++ b/libraries/helpers.rb @@ -33,21 +33,15 @@ module Helpers def pg_installed?(pkg_name) dpkg_status = Mixlib::ShellOut.new("dpkg-query -W -f='${Status}\n' #{pkg_name} 2>/dev/null | grep -c -q 'ok installed'") dpkg_status.run_command - if dpkg_status.exitstatus == 0 - false - else - true - end + return false if dpkg_status.exitstatus == 0 + true end def systemd_used? systemd_checker = Mixlib::ShellOut.new('file /sbin/init') systemd_checker.run_command - if systemd_checker.stdout =~ /systemd/ - return true - else - return false - end + return true if systemd_checker.stdout =~ /systemd/ + false end def exec_in_pg_cluster(cluster_version, cluster_name, *cluster_database, sql) @@ -65,11 +59,8 @@ def get_pg_port(cluster_version, cluster_name) end def need_to_restart?(allow_restart_cluster, first_time) - if allow_restart_cluster == :first - return first_time - elsif allow_restart_cluster == :always - return true - end + return first_time if allow_restart_cluster == :first + return true if allow_restart_cluster == :always false end @@ -77,65 +68,58 @@ def pg_running?(cluster_version, cluster_name) pg_status = Mixlib::ShellOut.new("su -c '/usr/lib/postgresql/#{cluster_version}/bin/pg_ctl \ -D /var/lib/postgresql/#{cluster_version}/#{cluster_name} status' postgres") pg_status.run_command - if pg_status.stdout =~ /server\ is\ running/ - return true - else - return false - end + return true if pg_status.stdout =~ /server\ is\ running/ + false end def create_user(cluster_version, cluster_name, cluster_user, options) stdout, stderr = exec_in_pg_cluster(cluster_version, cluster_name, 'SELECT usename FROM pg_user') - fail "postgresql create_user: can't get users list\nSTDOUT: #{stdout}\nSTDERR: #{stderr}" unless stderr.empty? + raise "postgresql create_user: can't get users list\nSTDOUT: #{stdout}\nSTDERR: #{stderr}" unless stderr.empty? if stdout.include? cluster_user - log("postgresql create_user: user '#{cluster_user}' already exists, skiping") + Chef::Log.info("postgresql create_user: user '#{cluster_user}' already exists, skiping") return nil - else stdout, stderr = exec_in_pg_cluster(cluster_version, cluster_name, "CREATE USER \\\"#{cluster_user}\\\" #{options.map { |t| t.join(' ') }.join(' ')}") - fail "postgresql create_user: can't create user #{cluster_user}\nSTDOUT: #{stdout}\nSTDERR: #{stderr}" unless stdout.include?("CREATE ROLE\n") - log("postgresql create_user: user '#{cluster_user}' created") + raise "postgresql create_user: can't create user #{cluster_user}\nSTDOUT: #{stdout}\nSTDERR: #{stderr}" unless stdout.include?("CREATE ROLE\n") + Chef::Log.info("postgresql create_user: user '#{cluster_user}' created") end end def create_database(cluster_version, cluster_name, cluster_database, options) stdout, stderr = exec_in_pg_cluster(cluster_version, cluster_name, 'SELECT datname FROM pg_database') - fail "postgresql create_database: can't get database list\nSTDOUT: #{stdout}\nSTDERR: #{stderr}" unless stderr.empty? + raise "postgresql create_database: can't get database list\nSTDOUT: #{stdout}\nSTDERR: #{stderr}" unless stderr.empty? if stdout.gsub(/\s+/, ' ').split(' ').include? cluster_database - log("postgresql create_database: database '#{cluster_database}' already exists, skiping") + Chef::Log.info("postgresql create_database: database '#{cluster_database}' already exists, skiping") return nil else stdout, stderr = exec_in_pg_cluster(cluster_version, cluster_name, "CREATE DATABASE \\\"#{cluster_database}\\\" #{options.map { |t| t.join(' ') }.join(' ')}") - fail "postgresql create_database: can't create database #{cluster_database}\nSTDOUT: #{stdout}\nSTDERR: #{stderr}" unless stdout.include?("CREATE DATABASE\n") - log("postgresql create_database: database '#{cluster_database}' created") + raise "postgresql create_database: can't create database #{cluster_database}\nSTDOUT: #{stdout}\nSTDERR: #{stderr}" unless stdout.include?("CREATE DATABASE\n") + Chef::Log.info("postgresql create_database: database '#{cluster_database}' created") end end def extension_available?(cluster_version, cluster_name, extension) stdout, _stderr = exec_in_pg_cluster(cluster_version, cluster_name, 'SELECT name FROM pg_available_extensions') - if stdout.include? extension - return true - else - return false - end + return true if stdout.include? extension + false end def install_extension(cluster_version, cluster_name, cluster_database, extension, options) - fail "extension '#{extension}' is not available, please use \'pgxn_extension\' resource to install the extention" unless extension_available?(cluster_version, cluster_name, extension) + raise "extension '#{extension}' is not available, please use \'pgxn_extension\' resource to install the extention" unless extension_available?(cluster_version, cluster_name, extension) stdout, stderr = exec_in_pg_cluster(cluster_version, cluster_name, cluster_database, 'SELECT extname FROM pg_extension') - fail "postgresql install_extension: can't get extensions list\nSTDOUT: #{stdout}\nSTDERR: #{stderr}" unless stderr.empty? + raise "postgresql install_extension: can't get extensions list\nSTDOUT: #{stdout}\nSTDERR: #{stderr}" unless stderr.empty? if stdout.include? extension - log("postgresql install: extension '#{extension}' already installed, skiping") + Chef::Log.info("postgresql install: extension '#{extension}' already installed, skiping") return nil else stdout, stderr = exec_in_pg_cluster(cluster_version, cluster_name, cluster_database, "CREATE EXTENSION \\\"#{extension}\\\" #{options.map { |t| t.join(' ') }.join(' ')}") - fail "postgresql install_extension: can't install extension #{extension}\nSTDOUT: #{stdout}\nSTDERR: #{stderr}" unless stdout.include?("CREATE EXTENSION\n") - log("postgresql install_extension: extension '#{extension}' installed") + raise "postgresql install_extension: can't install extension #{extension}\nSTDOUT: #{stdout}\nSTDERR: #{stderr}" unless stdout.include?("CREATE EXTENSION\n") + Chef::Log.info("postgresql install_extension: extension '#{extension}' installed") end end @@ -144,16 +128,16 @@ def pgxn_install_extension(cluster_version, cluster_name, params, options) pgxn_status.run_command stdout, stderr = exec_in_pg_cluster(cluster_version, cluster_name, params[:db], 'SELECT extname FROM pg_extension') - fail "postgresql install_extension: can't get extensions list\nSTDOUT: #{stdout}\nSTDERR: #{stderr}" unless stderr.empty? + raise "postgresql install_extension: can't get extensions list\nSTDOUT: #{stdout}\nSTDERR: #{stderr}" unless stderr.empty? if stdout.include? params[:name].downcase - log("postgresql install: extension '#{params[:name]}' already installed, skipping") + Chef::Log.info("postgresql install: extension '#{params[:name]}' already installed, skipping") return nil else pgxn_status = Mixlib::ShellOut.new("sudo -u postgres pgxn load '#{params[:name]}'='#{params[:version]}' -d #{params[:db]} --#{params[:stage]} #{options.map { |t| t.join(' ') }.join(' ')}") pgxn_status.run_command - fail "postgresql install_extension: can't install extension #{params[:name]}\nSTDOUT: #{pgxn_status.stdout}\nSTDERR: #{pgxn_status.stderr}" unless pgxn_status.stdout.include?('CREATE EXTENSION') - log("postgresql install_extension: extension '#{params[:name]}' installed") + raise "postgresql install_extension: can't install extension #{params[:name]}\nSTDOUT: #{pgxn_status.stdout}\nSTDERR: #{pgxn_status.stderr}" unless pgxn_status.stdout.include?('CREATE EXTENSION') + Chef::Log.info("postgresql install_extension: extension '#{params[:name]}' installed") end end @@ -163,23 +147,6 @@ def configuration_hacks(configuration, cluster_version) configuration.delete('wal_receiver_status_interval') if cluster_version.to_f < 9.1 configuration.delete('hot_standby_feedback') if cluster_version.to_f < 9.1 end - - def cloud_backup_configuration_hacks(configuration, cluster_name, cluster_version, wal_e_bin) - configuration['archive_command'] = "envdir /etc/wal-e.d/#{cluster_name}-#{cluster_version}/env/ #{wal_e_bin} wal-push %p" - end - - def params_validation(provider, credentials) - case provider - when 's3' - required_params = [:AWS_ACCESS_KEY_ID, :AWS_SECRET_ACCESS_KEY, :WALE_S3_PREFIX] - when 'swift' - required_params = [:SWIFT_AUTHURL, :SWIFT_TENANT, :SWIFT_USER, :SWIFT_PASSWORD, :WALE_SWIFT_PREFIX] - when 'azure' - required_params = [:WABS_ACCOUNT_NAME, :WABS_ACCESS_KEY, :WALE_WABS_PREFIX] - end - - required_params - credentials.keys.map { |key| key.upcase.to_sym } - end end end end diff --git a/metadata.rb b/metadata.rb index b015e06..39fad01 100644 --- a/metadata.rb +++ b/metadata.rb @@ -4,17 +4,17 @@ license 'MIT' description 'Installs and configures postgresql for clients or servers' long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) -version '1.2.0' +version '1.6.3' +chef_version '>= 12.5' if respond_to?(:chef_version) +source_url 'https://github.com/express42/postgresql_lwrp' if respond_to?(:source_url) +issues_url 'https://github.com/express42/postgresql_lwrp/issues' if respond_to?(:issues_url) recipe 'postgresql_lwrp::default', 'Installs postgresql client packages' recipe 'postgresql_lwrp::apt_official_repository', 'Setup official apt repository' -recipe 'postgresql_lwrp::cloud_backup', 'Setup cloud backup via wal-e utility' depends 'apt' -depends 'python' +depends 'poise-python', '>= 1.7.0' depends 'cron' supports 'debian' supports 'ubuntu' - -conflicts 'database' diff --git a/providers/cloud_backup.rb b/providers/cloud_backup.rb deleted file mode 100644 index 3f04ac8..0000000 --- a/providers/cloud_backup.rb +++ /dev/null @@ -1,115 +0,0 @@ -# -# Cookbook Name:: postgresql_lwrp -# Provider:: cloud_backup -# -# Author:: LLC Express 42 (info@express42.com) -# -# Copyright (C) 2014 LLC Express 42 -# -# 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. -# -# - -use_inline_resources - -include Chef::Postgresql::Helpers - -provides :postgresql_cloud_backup if defined? provides - -action :schedule do - postgresql_version = new_resource.in_version - postgresql_instance_name = new_resource.in_cluster - postgresql_name_version = "#{postgresql_instance_name}-#{postgresql_version}" - postgresql_path = "/var/lib/postgresql/#{postgresql_version}/#{postgresql_instance_name}" - wal_e_bin = node['postgresql']['cloud_backup']['wal_e_bin'] - command_prefix = new_resource.command_prefix - envdir_params = new_resource.params - full_backup_time = new_resource.full_backup_time - - unsetted_required_params = params_validation(new_resource.protocol, envdir_params) - fail "Key(s) '#{unsetted_required_params.join(', ')}' missing for protocol '#{new_resource.protocol}'" unless unsetted_required_params.empty? - - # Add libpq PGPORT variable to envdir_params - envdir_params['PGPORT'] = get_pg_port(postgresql_version, postgresql_instance_name).to_s - - # Create wal-e root directory - directory "/etc/wal-e.d/#{postgresql_name_version}/env" do - recursive true - mode '0750' - owner 'root' - group 'postgres' - end - - # We may use custom temp dir - directory 'WAL-E temp directory' do - path envdir_params['tmpdir'] - recursive true - mode '0750' - owner 'postgres' - group 'postgres' - only_if { envdir_params.key? 'tmpdir' } - end - - # Create all param files in wal-e.d/env directory - envdir_params.each do |key, val| - file "/etc/wal-e.d/#{postgresql_name_version}/env/#{key.upcase}" do - mode 0640 - owner 'root' - group 'postgres' - content val - backup false - end - end - - # Remove unused - ruby_block 'Remove unused variables' do - block do - unused_variables = ::Dir["/etc/wal-e.d/#{postgresql_name_version}/env/*"] - envdir_params.keys.map { |key| "/etc/wal-e.d/#{postgresql_name_version}/env/#{key.upcase}" } - unused_variables.each { |var| ::File.delete var } - end - end - - # Create crontask via cron cookbook - cron_d "backup_postgresql_cluster_#{postgresql_name_version.sub('.', '-')}" do - command "#{command_prefix} envdir /etc/wal-e.d/#{postgresql_name_version}/env #{wal_e_bin} backup-push #{postgresql_path}" - user 'postgres' - minute full_backup_time[:minute] - hour full_backup_time[:hour] - day full_backup_time[:day] - month full_backup_time[:month] - weekday full_backup_time[:weekday] - end - - if new_resource.retain - num_to_retain = new_resource.retain - cron_d "remove_old_backups_postgresql_cluster_#{postgresql_name_version.sub('.', '-')}" do - command "#{command_prefix} envdir /etc/wal-e.d/#{postgresql_name_version}/env #{wal_e_bin} delete --confirm retain #{num_to_retain}" - user 'postgres' - minute full_backup_time[:minute] - hour full_backup_time[:hour] - day full_backup_time[:day] - month full_backup_time[:month] - weekday full_backup_time[:weekday] - end - else - cron_d "remove_old_backups_postgresql_cluster_#{postgresql_name_version.sub('.', '-')}" do - action :delete - end - end -end diff --git a/providers/database.rb b/providers/database.rb deleted file mode 100644 index 2c2c3fc..0000000 --- a/providers/database.rb +++ /dev/null @@ -1,45 +0,0 @@ -# -# Cookbook Name:: postgresql_lwrp -# Provider:: database -# -# Author:: LLC Express 42 (info@express42.com) -# -# Copyright (C) 2014 LLC Express 42 -# -# 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. -# -# - -include Chef::Postgresql::Helpers - -provides :postgresql_database if defined? provides - -action :create do - options = {} - - options['OWNER'] = "\\\"#{new_resource.owner}\\\"" if new_resource.owner - options['TABLESPACE'] = "'#{new_resource.tablespace}'" if new_resource.tablespace - options['TEMPLATE'] = "'#{new_resource.template}'" if new_resource.template - options['ENCODING'] = "'#{new_resource.encoding}'" if new_resource.encoding - options['CONNECTION LIMIT'] = new_resource.connection_limit if new_resource.connection_limit - - if create_database(new_resource.in_version, new_resource.in_cluster, new_resource.name, options) - new_resource.updated_by_last_action(true) - end -end diff --git a/providers/default.rb b/providers/default.rb deleted file mode 100644 index a34e914..0000000 --- a/providers/default.rb +++ /dev/null @@ -1,260 +0,0 @@ -# -# Cookbook Name:: postgresql_lwrp -# Provider:: default -# -# Author:: LLC Express 42 (info@express42.com) -# -# Copyright (C) 2012-2014 LLC Express 42 -# -# 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. -# - -use_inline_resources - -include Chef::Postgresql::Helpers - -provides :postgresql if defined? provides - -action :create do - configuration = Chef::Mixin::DeepMerge.merge(node['postgresql']['defaults']['server']['configuration'].to_hash, new_resource.configuration) - hba_configuration = node['postgresql']['defaults']['server']['hba_configuration'] | new_resource.hba_configuration - ident_configuration = node['postgresql']['defaults']['server']['ident_configuration'] | new_resource.ident_configuration - - cluster_name = new_resource.name - cluster_version = (!new_resource.cluster_version.empty? && new_resource.cluster_version) || node['postgresql']['defaults']['server']['version'] - service_name = "postgresql_#{cluster_version}_#{cluster_name}" - - allow_restart_cluster = new_resource.allow_restart_cluster - - replication = new_resource.replication - replication_file = "/var/lib/postgresql/#{cluster_version}/#{cluster_name}/recovery.conf" - replication_start_slave = new_resource.replication_start_slave - replication_initial_copy = new_resource.replication_initial_copy - - wal_e_bin = node['postgresql']['cloud_backup']['wal_e_bin'] - - cluster_options = Mash.new(new_resource.cluster_create_options) - parsed_cluster_options = [] - - first_time = pg_installed?("postgresql-#{cluster_version}") - - %w(locale lc-collate lc-ctype lc-messages lc-monetary lc-numeric lc-time).each do |option| - parsed_cluster_options << "--#{option} #{cluster_options[:locale]}" if cluster_options[option] - end - - # Locale hack - if new_resource.cluster_create_options.key?('locale') && !new_resource.cluster_create_options['locale'].empty? - system_lang = ENV['LANG'] - ENV['LANG'] = new_resource.cluster_create_options['locale'] - end - - # Configuration hacks - configuration_hacks(configuration, cluster_version) - - # Backups hacks - if configuration['archive_command'] == 'cloud_auto'.downcase.to_sym - cloud_backup_configuration_hacks(configuration, cluster_name, cluster_version, wal_e_bin) - end - - # Install postgresql-common package - package 'postgresql-common' - - file '/etc/postgresql-common/createcluster.conf' do - content "create_main_cluster = false\n" - only_if { cluster_version.to_f >= 9.2 } - end - - # Install postgresql server packages - %W(postgresql-#{cluster_version} postgresql-contrib-#{cluster_version} postgresql-server-dev-#{cluster_version}).each do |pkg| - package pkg - end - - # Install pgxn client to download custom extensions - package 'pgxnclient' - package 'build-essential' - - # Return locale - if new_resource.cluster_create_options.key?('locale') && !new_resource.cluster_create_options['locale'].empty? - ENV['LANG'] = system_lang - end - - # Systemd not working with cluster names with dashes - # see http://comments.gmane.org/gmane.comp.db.postgresql.debian/346 - if systemd_used? && cluster_name.include?('-') - fail "Sorry, systemd not support cluster names with dashes ('-'), use underscore ('_') instead" - end - - # Create postgresql cluster directories - %W(/etc/postgresql /etc/postgresql/#{cluster_version} /etc/postgresql/#{cluster_version}/#{cluster_name}).each do |dir| - directory dir do - owner 'postgres' - group 'postgres' - end - end - - %W(/var/lib/postgresql /var/lib/postgresql/#{cluster_version}).each do |dir| - directory dir do - owner 'postgres' - group 'postgres' - end - end - - directory "/var/lib/postgresql/#{cluster_version}/#{cluster_name}" do - mode '0700' - owner 'postgres' - group 'postgres' - end - - # Exec pg_cluster create - execute 'Exec pg_createcluster' do - command "pg_createcluster #{parsed_cluster_options.join(' ')} #{cluster_version} #{cluster_name}" - not_if { ::File.exist?("/etc/postgresql/#{cluster_version}/#{cluster_name}/postgresql.conf") || !replication.empty? } - end - - # Define postgresql service - postgresql_service = service service_name do - action :nothing - provider Chef::Provider::Service::Simple - start_command "pg_ctlcluster #{cluster_version} #{cluster_name} start" - stop_command "pg_ctlcluster #{cluster_version} #{cluster_name} stop" - reload_command "pg_ctlcluster #{cluster_version} #{cluster_name} reload" - restart_command "pg_ctlcluster #{cluster_version} #{cluster_name} restart" - status_command "su -c '/usr/lib/postgresql/#{cluster_version}/bin/pg_ctl \ - -D /var/lib/postgresql/#{cluster_version}/#{cluster_name} status' postgres" - supports status: true, restart: true, reload: true - end - - # Ruby block for postgresql smart restart - ruby_block "restart_service_#{service_name}" do - action :nothing - block do - if !replication.empty? && !replication_start_slave - run_context.notifies_delayed(Chef::Resource::Notification.new(postgresql_service, :reload, self)) - elsif need_to_restart?(allow_restart_cluster.to_sym, first_time) - run_context.notifies_delayed(Chef::Resource::Notification.new(postgresql_service, :restart, self)) - else - run_context.notifies_delayed(Chef::Resource::Notification.new(postgresql_service, :reload, self)) - end - end - end - - # Configuration templates - - main_configuration = configuration.dup - main_configuration.delete('ssl_cert_file') if cluster_version.to_f < 9.2 - main_configuration.delete('ssl_key_file') if cluster_version.to_f < 9.2 - - template "/etc/postgresql/#{cluster_version}/#{cluster_name}/postgresql.conf" do - source 'postgresql.conf.erb' - owner 'postgres' - group 'postgres' - mode 0644 - variables configuration: main_configuration, cluster_name: cluster_name, cluster_version: cluster_version - cookbook new_resource.cookbook - notifies :create, "ruby_block[restart_service_#{service_name}]", :delayed - end - - template "/etc/postgresql/#{cluster_version}/#{cluster_name}/pg_hba.conf" do - source 'pg_hba.conf.erb' - owner 'postgres' - group 'postgres' - mode 0644 - variables configuration: hba_configuration - cookbook new_resource.cookbook - notifies :create, "ruby_block[restart_service_#{service_name}]", :delayed - end - - template "/etc/postgresql/#{cluster_version}/#{cluster_name}/pg_ident.conf" do - source 'pg_ident.conf.erb' - owner 'postgres' - group 'postgres' - mode 0644 - variables configuration: ident_configuration - cookbook new_resource.cookbook - notifies :create, "ruby_block[restart_service_#{service_name}]", :delayed - end - - file "/etc/postgresql/#{cluster_version}/#{cluster_name}/start.conf" do - content "auto\n" - end - - # Replication - if !replication.empty? - - if replication_initial_copy - pg_basebackup_path = "/usr/lib/postgresql/#{cluster_version}/bin/pg_basebackup" - pg_data_directory = "/var/lib/postgresql/#{cluster_version}/#{cluster_name}" - - BASEBACKUP_PARAMS = { - 'host' => '-h', - 'port' => '-p', - 'user' => '-U', - 'password' => '-W' - } - - conninfo_hash = Hash[*replication[:primary_conninfo].scan(/\w+=[^\s]+/).map { |x| x.split('=', 2) }.flatten] - - basebackup_conninfo_hash = conninfo_hash.map do |key, val| - "#{BASEBACKUP_PARAMS[key.to_s]} #{val}" if BASEBACKUP_PARAMS[key.to_s] - end.compact - - execute 'Make basebackup' do - command "#{pg_basebackup_path} -D #{pg_data_directory} -F p -x -c fast #{basebackup_conninfo_hash.join(' ')}" - user 'postgres' - not_if { ::File.exist?("/var/lib/postgresql/#{cluster_version}/#{cluster_name}/base") } - timeout 604_800 - end - end - - link "/var/lib/postgresql/#{cluster_version}/#{cluster_name}/server.key" do - to configuration['ssl_key_file'] - not_if { cluster_version.to_f > 9.1 && ::File.exist?("/var/lib/postgresql/#{cluster_version}/#{cluster_name}/server.key") } - end - - link "/var/lib/postgresql/#{cluster_version}/#{cluster_name}/server.crt" do - to configuration['ssl_cert_file'] - not_if { cluster_version.to_f > 9.1 && ::File.exist?("/var/lib/postgresql/#{cluster_version}/#{cluster_name}/server.crt") } - end - - template "/var/lib/postgresql/#{cluster_version}/#{cluster_name}/recovery.conf" do - source 'recovery.conf.erb' - owner 'postgres' - group 'postgres' - mode 0644 - variables replication: replication - cookbook new_resource.cookbook - notifies :create, "ruby_block[restart_service_#{service_name}]", :delayed - end - - else - - file replication_file do - action :delete - notifies :create, "ruby_block[restart_service_#{service_name}]", :delayed - end - end - - # Start postgresql - ruby_block "start_service_#{service_name}]" do - block do - run_context.notifies_delayed(Chef::Resource::Notification.new(postgresql_service, :start, self)) - end - not_if { pg_running?(cluster_version, cluster_name) || (!replication.empty? && !replication_start_slave) } - end -end diff --git a/providers/extension.rb b/providers/extension.rb deleted file mode 100644 index 8095b56..0000000 --- a/providers/extension.rb +++ /dev/null @@ -1,43 +0,0 @@ -# -# Cookbook Name:: postgresql_lwrp -# Provider:: extension -# -# Author:: LLC Express 42 (info@express42.com) -# -# Copyright (C) 2016 LLC Express 42 -# -# 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. -# -# - -use_inline_resources - -include Chef::Postgresql::Helpers - -provides :postgresql_extension if defined? provides - -action :install do - options = {} - options['SCHEMA'] = new_resource.schema.to_s if new_resource.schema - options['VERSION'] = "'#{new_resource.version}'" if new_resource.version - - if install_extension(new_resource.in_version, new_resource.in_cluster, new_resource.db, new_resource.name, options) - new_resource.updated_by_last_action(true) - end -end diff --git a/providers/pgxn_extension.rb b/providers/pgxn_extension.rb deleted file mode 100644 index 07c984a..0000000 --- a/providers/pgxn_extension.rb +++ /dev/null @@ -1,47 +0,0 @@ -# -# Cookbook Name:: postgresql_lwrp -# Provider:: pgxn_extension -# -# Author:: LLC Express 42 (info@express42.com) -# -# Copyright (C) 2016 LLC Express 42 -# -# 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. -# -# - -use_inline_resources - -include Chef::Postgresql::Helpers - -provides :pgxn_extension if defined? provides - -action :install do - options = {} - options['--schema'] = new_resource.schema.to_s if new_resource.schema - params = {} - params[:name] = new_resource.name.to_s if new_resource.name - params[:stage] = new_resource.stage.to_s if new_resource.stage - params[:version] = new_resource.version.to_s if new_resource.version - params[:db] = new_resource.db.to_s if new_resource.db - - if pgxn_install_extension(new_resource.in_version, new_resource.in_cluster, params, options) - new_resource.updated_by_last_action(true) - end -end diff --git a/providers/user.rb b/providers/user.rb deleted file mode 100644 index 2eba0e5..0000000 --- a/providers/user.rb +++ /dev/null @@ -1,57 +0,0 @@ -# -# Cookbook Name:: postgresql_lwrp -# Provider:: user -# -# Author:: LLC Express 42 (info@express42.com) -# -# Copyright (C) 2014 LLC Express 42 -# -# 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. -# -# - -use_inline_resources - -include Chef::Postgresql::Helpers - -provides :postgresql_user if defined? provides - -action :create do - options = new_resource.advanced_options.clone - - if new_resource.replication == true - options['REPLICATION'] = nil - elsif new_resource.replication == false - options['NOREPLICATION'] = nil - end - - if new_resource.superuser == true - options['SUPERUSER'] = nil - elsif new_resource.superuser == false - options['NOSUPERUSER'] = nil - end - - options['ENCRYPTED PASSWORD'] = "'#{new_resource.encrypted_password}'" if new_resource.encrypted_password - - options['UNENCRYPTED PASSWORD'] = "'#{new_resource.unencrypted_password}'" if new_resource.unencrypted_password - - if create_user(new_resource.in_version, new_resource.in_cluster, new_resource.name, options) - new_resource.updated_by_last_action(true) - end -end diff --git a/recipes/cloud_backup.rb b/recipes/cloud_backup.rb index 5b0aae9..510e6e0 100644 --- a/recipes/cloud_backup.rb +++ b/recipes/cloud_backup.rb @@ -25,34 +25,6 @@ # SOFTWARE. # -include_recipe 'python' +# Install packages -# Install packages and pips -node['postgresql']['cloud_backup']['packages'].each do |pkg| - package pkg -end - -python_virtualenv node['postgresql']['cloud_backup']['wal_e_path'] - -case node['postgresql']['cloud_backup']['install_source'] -when 'github' - archive_url = "#{node['postgresql']['cloud_backup']['github_repo']}/archive/#{node['postgresql']['cloud_backup']['version']}.zip" - python_pip 'wal-e' do - package_name archive_url - virtualenv node['postgresql']['cloud_backup']['wal_e_path'] - end -when 'pypi' - python_pip 'wal-e' do - version node['postgresql']['cloud_backup']['version'] - virtualenv node['postgresql']['cloud_backup']['wal_e_path'] - end -end - -template 'postgresql cloud backup' do - path "#{node['postgresql']['cloud_backup']['wal_e_path']}/bin/postgresql_cloud_backup_helper.sh" - source 'postgresql_cloud_backup_helper.sh.erb' - mode '0755' - variables( - wal_e_bin: node['postgresql']['cloud_backup']['wal_e_bin'] - ) -end +Chef::Log.warn('recipe[postgresql_lwrp::cloud_backup] is no longer necessary to use the postgresql_cloud_backup resource. Please update your cookbooks or remove this recipe from your runlist.') diff --git a/resources/cloud_backup.rb b/resources/cloud_backup.rb index f236ccb..d2135c8 100644 --- a/resources/cloud_backup.rb +++ b/resources/cloud_backup.rb @@ -28,23 +28,195 @@ provides :postgresql_cloud_backup resource_name :postgresql_cloud_backup -actions :schedule default_action :schedule -attribute :name, kind_of: String, required: true -attribute :in_version, kind_of: String, required: true -attribute :in_cluster, kind_of: String, required: true -attribute :protocol, kind_of: String, - required: true, - callbacks: { - 'is not allowed! Allowed providers: s3, swift or azure' => proc do |value| - !value.to_sym.match(/^(s3|swift|azure)$/).nil? - end - } -attribute :params, kind_of: Hash, required: true - -# Crontab command prefix to use with wal-e -# e.g. for speed limit by trickle like `trickle -s -u 1024 envdir /etc/wal-e.d/...` -attribute :command_prefix, kind_of: String, required: false -attribute :full_backup_time, kind_of: Hash, default: { minute: '0', hour: '3', day: '*', month: '*', weekday: '*' } -attribute :retain, kind_of: Integer, required: false +property :utility, String, + default: 'wal-e', + equal_to: %w(wal-e wal_e wal-g wal_g) +property :in_version, String, required: true +property :in_cluster, String, required: true +property :parameters, Hash, required: true + +# Crontab command prefix to use with wal-e, e.g. for speed limit by trickle +# like `trickle -s -u 1024 envdir /etc/wal-e.d/...` +property :command_prefix, String, required: false +property :full_backup_time, Hash, + default: { + minute: '0', + hour: '3', + day: '*', + month: '*', + weekday: '*', + } +property :retain, Integer, required: false + +action_class do + include Chef::Postgresql::Helpers + + def install_wal_e + wal_e_attributes = node['postgresql']['cloud_backup']['wal_e'] + + python_runtime '3' do + provider :system + options package_name: 'python3' + end + + python_virtualenv wal_e_attributes['path'] do + python '3' + end + + python_package wal_e_attributes['pypi_packages'] do + virtualenv wal_e_attributes['path'] + end + + wal_e_repo = wal_e_attributes['github_repo'] + wal_e_version = wal_e_attributes['version'] + case wal_e_attributes['install_source'] + when 'github' + archive_url = "#{wal_e_repo}/archive/#{wal_e_version}.zip" + python_package 'wal-e' do + package_name archive_url + virtualenv wal_e_attributes['path'] + end + when 'pypi' + python_package 'wal-e' do + version wal_e_version + virtualenv wal_e_attributes['path'] + end + end + + template 'postgresql cloud backup' do + path "#{wal_e_attributes['path']}/bin/postgresql_cloud_backup_helper.sh" + source 'postgresql_cloud_backup_helper.sh.erb' + cookbook 'postgresql_lwrp' + mode '0755' + variables( + wal_e_bin: wal_e_attributes['bin'] + ) + end + end + + def install_wal_g + remote_file 'wal-g' do + path "#{Chef::Config[:file_cache_path]}/wal-g.linux-amd64.tar.gz" + owner 'root' + group 'root' + mode '0644' + source node['postgresql']['cloud_backup']['wal_g']['url'] + checksum node['postgresql']['cloud_backup']['wal_g']['checksum'] + end + + dirname = ::File.dirname node['postgresql']['cloud_backup']['wal_g']['bin'] + bash 'untar wal-g' do + code "tar -xzf #{Chef::Config[:file_cache_path]}/wal-g.linux-amd64.tar.gz -C #{dirname}" + action :nothing + subscribes :run, 'remote_file[wal-g]', :immediately + end + end +end + +action :install do + backup_utility = new_resource.utility.sub('_', '-') + + package node['postgresql']['cloud_backup'][backup_utility.sub('-', '_')]['packages'] + + ['daemontools'] + + case backup_utility + when 'wal-e' + install_wal_e + when 'wal-g' + install_wal_g + end +end + +action :schedule do + action_install + + postgresql_version = new_resource.in_version + postgresql_instance_name = new_resource.in_cluster + postgresql_name_version = "#{postgresql_instance_name}-#{postgresql_version}" + postgresql_path = "/var/lib/postgresql/#{postgresql_version}/#{postgresql_instance_name}" + + backup_utility = new_resource.utility.sub('_', '-') + backup_utility_bin = node['postgresql']['cloud_backup'][backup_utility.sub('-', '_')]['bin'] + command_prefix = new_resource.command_prefix + envdir_params = new_resource.parameters + full_backup_time = new_resource.full_backup_time + + # Add libpq PGPORT variable to envdir_params + envdir_params['PGPORT'] = get_pg_port(postgresql_version, postgresql_instance_name).to_s + + # wal-g needs a default PGHOST variable to connect via UNIX socket + if backup_utility == 'wal-g' && + !envdir_params.key?('PGHOST') + envdir_params['PGHOST'] = '/var/run/postgresql' + envdir_params['PATH'] = '/bin:/sbin:/usr/bin:/usr/sbin' + end + + # Create environment directory + directory "/etc/#{backup_utility}.d/#{postgresql_name_version}/env" do + recursive true + mode '0750' + owner 'root' + group 'postgres' + end + + if envdir_params.key? 'tmpdir' + # We may use custom temp dir + directory "#{backup_utility.upcase} temp directory" do + path envdir_params['tmpdir'] + recursive true + mode '0750' + owner 'postgres' + group 'postgres' + end + end + + # Create all param files in directory + envdir_params.each do |key, val| + file "/etc/#{backup_utility}.d/#{postgresql_name_version}/env/#{key.upcase}" do + mode '0640' + owner 'root' + group 'postgres' + content val + sensitive true + backup false + end + end + + # Remove unused + ruby_block 'Remove unused variables' do + block do + unused_variables = ::Dir["/etc/#{backup_utility}.d/#{postgresql_name_version}/env/*"] - envdir_params.keys.map { |key| "/etc/#{backup_utility}.d/#{postgresql_name_version}/env/#{key.upcase}" } + unused_variables.each { |var| ::File.delete var } + end + end + + # Create crontask via cron cookbook + cron_d "backup_postgresql_cluster_#{postgresql_name_version.sub('.', '-')}" do + command "#{command_prefix} envdir /etc/#{backup_utility}.d/#{postgresql_name_version}/env #{backup_utility_bin} backup-push #{postgresql_path}" + user 'postgres' + minute full_backup_time[:minute] + hour full_backup_time[:hour] + day full_backup_time[:day] + month full_backup_time[:month] + weekday full_backup_time[:weekday] + end + + if new_resource.retain + num_to_retain = new_resource.retain + cron_d "remove_old_backups_postgresql_cluster_#{postgresql_name_version.sub('.', '-')}" do + command "#{command_prefix} envdir /etc/#{backup_utility}.d/#{postgresql_name_version}/env #{backup_utility_bin} delete --confirm retain #{num_to_retain}" + user 'postgres' + minute full_backup_time[:minute] + hour full_backup_time[:hour] + day full_backup_time[:day] + month full_backup_time[:month] + weekday full_backup_time[:weekday] + end + else + cron_d "remove_old_backups_postgresql_cluster_#{postgresql_name_version.sub('.', '-')}" do + action :delete + end + end +end diff --git a/resources/database.rb b/resources/database.rb index 430f9ba..490c7a0 100644 --- a/resources/database.rb +++ b/resources/database.rb @@ -25,17 +25,30 @@ # SOFTWARE. # +include Chef::Postgresql::Helpers + provides :postgresql_database resource_name :postgresql_database -actions :create default_action :create -attribute :name, kind_of: String, required: true -attribute :in_version, kind_of: String, required: true -attribute :in_cluster, kind_of: String, required: true -attribute :owner, kind_of: String -attribute :tablespace, kind_of: String -attribute :template, kind_of: String -attribute :encoding, kind_of: String -attribute :connection_limit, kind_of: Integer +property :in_version, String, required: true +property :in_cluster, String, required: true +property :owner, String +property :tablespace, String +property :template, String +property :encoding, String +property :connection_limit, Integer + +action :create do + options = {} + + options['OWNER'] = "\\\"#{new_resource.owner}\\\"" if new_resource.owner + options['TABLESPACE'] = "'#{new_resource.tablespace}'" if new_resource.tablespace + options['TEMPLATE'] = "'#{new_resource.template}'" if new_resource.template + options['ENCODING'] = "'#{new_resource.encoding}'" if new_resource.encoding + options['CONNECTION LIMIT'] = new_resource.connection_limit if new_resource.connection_limit + converge_by "create database #{new_resource.name}" do + create_database(new_resource.in_version, new_resource.in_cluster, new_resource.name, options) + end +end diff --git a/resources/default.rb b/resources/default.rb index ab00471..76a6c93 100644 --- a/resources/default.rb +++ b/resources/default.rb @@ -25,24 +25,278 @@ # SOFTWARE. # +include Chef::Postgresql::Helpers + provides :postgresql resource_name :postgresql -actions :create default_action :create -attribute :cluster_name, kind_of: String, required: true -attribute :cluster_version, kind_of: String, regex: [/\A(|\d.\d)\Z\z/], default: '' -attribute :cookbook, kind_of: String, default: 'postgresql_lwrp' -attribute :cluster_create_options, kind_of: Hash, default: {} -attribute :configuration, kind_of: Hash, default: {} -attribute :hba_configuration, kind_of: Array, default: [] -attribute :ident_configuration, kind_of: Array, default: [] -attribute :replication, kind_of: Hash, default: {} -attribute :replication_initial_copy, kind_of: [TrueClass, FalseClass], default: false -attribute :replication_start_slave, kind_of: [TrueClass, FalseClass], default: false -attribute :allow_restart_cluster, default: :none, callbacks: { +property :cluster_name, String, required: true +property :cluster_version, String, regex: [/\A(1\d|9\.[1-6])\Z\z/] +property :cookbook, String, default: 'postgresql_lwrp' +property :cluster_create_options, Hash, default: {} +property :configuration, Hash, default: {} +property :hba_configuration, Array, default: [] +property :ident_configuration, Array, default: [] +property :replication, Hash, default: {} +property :replication_initial_copy, [TrueClass, FalseClass], default: false +property :replication_start_slave, [TrueClass, FalseClass], default: false +property :allow_restart_cluster, default: :none, callbacks: { 'is not allowed! Allowed params for allow_restart_cluster: first, always or none' => proc do |value| !value.to_sym.match(/^(first|always|none)$/).nil? - end + end, } + +action :create do + configuration = Chef::Mixin::DeepMerge.merge(node['postgresql']['defaults']['server']['configuration'].to_hash, new_resource.configuration) + hba_configuration = node['postgresql']['defaults']['server']['hba_configuration'] | new_resource.hba_configuration + ident_configuration = node['postgresql']['defaults']['server']['ident_configuration'] | new_resource.ident_configuration + + cluster_name = new_resource.name + cluster_version = (!new_resource.cluster_version.empty? && new_resource.cluster_version) || node['postgresql']['defaults']['server']['version'] + service_name = "postgresql_#{cluster_version}_#{cluster_name}" + + allow_restart_cluster = new_resource.allow_restart_cluster + + replication = Chef::Mixin::DeepMerge.merge(node['postgresql']['defaults']['server']['replication'].to_hash, new_resource.replication) + replication_file = "/var/lib/postgresql/#{cluster_version}/#{cluster_name}/recovery.conf" + replication_start_slave = new_resource.replication_start_slave + replication_initial_copy = new_resource.replication_initial_copy + + cluster_options = Mash.new(new_resource.cluster_create_options) + parsed_cluster_options = [] + + first_time = pg_installed?("postgresql-#{cluster_version}") + + %w(locale lc-collate lc-ctype lc-messages lc-monetary lc-numeric lc-time).each do |option| + parsed_cluster_options << "--#{option} #{cluster_options[:locale]}" if cluster_options[option] + end + + # Locale hack + if new_resource.cluster_create_options.key?('locale') && !new_resource.cluster_create_options['locale'].empty? + system_lang = ENV['LANG'] + ENV['LANG'] = new_resource.cluster_create_options['locale'] + end + + # Configuration hacks + configuration_hacks(configuration, cluster_version) + + # Install postgresql-common package + package 'postgresql-common' + + file '/etc/postgresql-common/createcluster.conf' do + content "create_main_cluster = false\n" + only_if { cluster_version.to_f >= 9.2 } + end + + # Install postgresql server packages + %W(postgresql-#{cluster_version} postgresql-contrib-#{cluster_version} postgresql-server-dev-#{cluster_version}).each do |pkg| + package pkg + end + + # Install pgxn client to download custom extensions + package 'pgxnclient' + package 'build-essential' + + # Return locale + if new_resource.cluster_create_options.key?('locale') && !new_resource.cluster_create_options['locale'].empty? + ENV['LANG'] = system_lang + end + + # Systemd not working with cluster names with dashes + # see http://comments.gmane.org/gmane.comp.db.postgresql.debian/346 + if systemd_used? && cluster_name.include?('-') + raise "Sorry, systemd not support cluster names with dashes ('-'), use underscore ('_') instead" + end + + # Create postgresql cluster directories + %W( + /etc/postgresql + /etc/postgresql/#{cluster_version} + /etc/postgresql/#{cluster_version}/#{cluster_name} + /var/lib/postgresql + /var/lib/postgresql/#{cluster_version} + ).each do |dir| + directory dir do + owner 'postgres' + group 'postgres' + end + end + + directory "/var/lib/postgresql/#{cluster_version}/#{cluster_name}" do + mode '0700' + owner 'postgres' + group 'postgres' + end + + # Exec pg_cluster create + execute 'Exec pg_createcluster' do + command "pg_createcluster #{parsed_cluster_options.join(' ')} #{cluster_version} #{cluster_name}" + not_if do + ::File.exist?("/etc/postgresql/#{cluster_version}/#{cluster_name}/postgresql.conf") || + !replication.empty? + end + end + + # Define postgresql service + postgresql_service = service service_name do + action :nothing + provider Chef::Provider::Service::Simple + start_command "pg_ctlcluster #{cluster_version} #{cluster_name} start" + stop_command "pg_ctlcluster #{cluster_version} #{cluster_name} stop" + reload_command "pg_ctlcluster #{cluster_version} #{cluster_name} reload" + restart_command "pg_ctlcluster #{cluster_version} #{cluster_name} restart" + status_command "su -c '/usr/lib/postgresql/#{cluster_version}/bin/pg_ctl \ + -D /var/lib/postgresql/#{cluster_version}/#{cluster_name} status' postgres" + supports status: true, restart: true, reload: true + end + + # Ruby block for postgresql smart restart + ruby_block "restart_service_#{service_name}" do + action :nothing + block do + if !replication.empty? && !replication_start_slave + run_context.notifies_delayed(Chef::Resource::Notification.new(postgresql_service, :reload, self)) + elsif need_to_restart?(allow_restart_cluster.to_sym, first_time) + run_context.notifies_delayed(Chef::Resource::Notification.new(postgresql_service, :restart, self)) + else + run_context.notifies_delayed(Chef::Resource::Notification.new(postgresql_service, :reload, self)) + end + end + end + + # Configuration templates + + main_configuration = configuration.dup + main_configuration.delete('ssl_cert_file') if cluster_version.to_f < 9.2 + main_configuration.delete('ssl_key_file') if cluster_version.to_f < 9.2 + main_configuration.delete('checkpoint_segments') if cluster_version.to_f > 9.4 + + # Backu hack: + # Set `archive_command` option automatically according to the tool of the + # choise in `postgresql_cloud_backup` resource assosiated with this PG + # instance if `archive command` config option is set to `:cloud_auto` + with_run_context :root do + t = run_context.resource_collection.select do |res| + res.resource_name == :postgresql_cloud_backup && + res.in_cluster == cluster_name && + res.in_version == cluster_version + end + + if !t.empty? && + main_configuration['archive_command'] == :cloud_auto + backup_utility = t.first.utility + backup_utility_bin = node['postgresql']['cloud_backup'][backup_utility.sub('-', '_')]['bin'] + main_configuration['archive_command'] = "envdir /etc/#{backup_utility}.d/#{cluster_name}-#{cluster_version}/env/ #{backup_utility_bin} wal-push %p" + end + end + + template "/etc/postgresql/#{cluster_version}/#{cluster_name}/postgresql.conf" do + source 'postgresql.conf.erb' + owner 'postgres' + group 'postgres' + mode '0644' + variables( + configuration: main_configuration, + cluster_name: cluster_name, + cluster_version: cluster_version + ) + cookbook new_resource.cookbook + notifies :run, "ruby_block[restart_service_#{service_name}]", :delayed + end + + template "/etc/postgresql/#{cluster_version}/#{cluster_name}/pg_hba.conf" do + source 'pg_hba.conf.erb' + owner 'postgres' + group 'postgres' + mode '0644' + variables configuration: hba_configuration + cookbook new_resource.cookbook + notifies :run, "ruby_block[restart_service_#{service_name}]", :delayed + end + + template "/etc/postgresql/#{cluster_version}/#{cluster_name}/pg_ident.conf" do + source 'pg_ident.conf.erb' + owner 'postgres' + group 'postgres' + mode '0644' + variables configuration: ident_configuration + cookbook new_resource.cookbook + notifies :run, "ruby_block[restart_service_#{service_name}]", :delayed + end + + file "/etc/postgresql/#{cluster_version}/#{cluster_name}/start.conf" do + content "auto\n" + end + + # Replication + if !replication.empty? + + if replication_initial_copy + pg_basebackup_path = "/usr/lib/postgresql/#{cluster_version}/bin/pg_basebackup" + pg_data_directory = "/var/lib/postgresql/#{cluster_version}/#{cluster_name}" + + BASEBACKUP_PARAMS = { + 'host' => '-h', + 'port' => '-p', + 'user' => '-U', + 'password' => '-W', + }.freeze + + conninfo_hash = Hash[*replication[:primary_conninfo].scan(/\w+=[^\s]+/).map { |x| x.split('=', 2) }.flatten] + + basebackup_conninfo_hash = conninfo_hash.map do |key, val| + "#{BASEBACKUP_PARAMS[key.to_s]} #{val}" if BASEBACKUP_PARAMS[key.to_s] + end.compact + + fetch_wal_logs = if cluster_version.to_i >= 10 + '-X fetch' + else + '-x' + end + + execute 'Make basebackup' do + command "#{pg_basebackup_path} -D #{pg_data_directory} -F p #{fetch_wal_logs} -c fast #{basebackup_conninfo_hash.join(' ')}" + user 'postgres' + not_if { ::File.exist?("/var/lib/postgresql/#{cluster_version}/#{cluster_name}/base") } + timeout 604_800 + end + end + + link "/var/lib/postgresql/#{cluster_version}/#{cluster_name}/server.key" do + to configuration['ssl_key_file'] + not_if { cluster_version.to_f > 9.1 && ::File.exist?("/var/lib/postgresql/#{cluster_version}/#{cluster_name}/server.key") } + end + + link "/var/lib/postgresql/#{cluster_version}/#{cluster_name}/server.crt" do + to configuration['ssl_cert_file'] + not_if { cluster_version.to_f > 9.1 && ::File.exist?("/var/lib/postgresql/#{cluster_version}/#{cluster_name}/server.crt") } + end + + template "/var/lib/postgresql/#{cluster_version}/#{cluster_name}/recovery.conf" do + source 'recovery.conf.erb' + owner 'postgres' + group 'postgres' + mode '0644' + variables replication: replication + cookbook new_resource.cookbook + notifies :run, "ruby_block[restart_service_#{service_name}]", :delayed + end + + else + + file replication_file do + action :delete + notifies :run, "ruby_block[restart_service_#{service_name}]", :delayed + end + end + + # Start postgresql + ruby_block "start_service_#{service_name}]" do + block do + run_context.notifies_delayed(Chef::Resource::Notification.new(postgresql_service, :start, self)) + end + not_if { pg_running?(cluster_version, cluster_name) || (!replication.empty? && !replication_start_slave) } + end +end diff --git a/resources/extension.rb b/resources/extension.rb index e42be94..23ef264 100644 --- a/resources/extension.rb +++ b/resources/extension.rb @@ -25,15 +25,25 @@ # SOFTWARE. # +include Chef::Postgresql::Helpers + provides :postgresql_extension resource_name :postgresql_extension -actions :install default_action :install -attribute :name, kind_of: String, name_attribute: true, required: true -attribute :in_version, kind_of: String, required: true -attribute :in_cluster, kind_of: String, required: true -attribute :db, kind_of: String, required: true -attribute :schema, kind_of: String -attribute :version, kind_of: String +property :in_version, String, required: true +property :in_cluster, String, required: true +property :db, String, required: true +property :schema, String +property :version, String + +action :install do + options = {} + options['SCHEMA'] = new_resource.schema.to_s if new_resource.schema + options['VERSION'] = "'#{new_resource.version}'" if new_resource.version + + converge_by 'install extension new_resource.name' do + install_extension(new_resource.in_version, new_resource.in_cluster, new_resource.db, new_resource.name, options) + end +end diff --git a/resources/pgxn_extension.rb b/resources/pgxn_extension.rb index 976de65..421f1eb 100644 --- a/resources/pgxn_extension.rb +++ b/resources/pgxn_extension.rb @@ -25,16 +25,29 @@ # SOFTWARE. # +include Chef::Postgresql::Helpers + provides :pgxn_extension resource_name :pgxn_extension -actions :install default_action :install -attribute :name, kind_of: String, name_attribute: true, required: true -attribute :in_version, kind_of: String, required: true -attribute :in_cluster, kind_of: String, required: true -attribute :db, kind_of: String, required: true -attribute :schema, kind_of: String -attribute :version, kind_of: String, required: true -attribute :stage, kind_of: String, required: true +property :in_version, String, required: true +property :in_cluster, String, required: true +property :db, String, required: true +property :schema, String +property :version, String, required: true +property :stage, String, required: true + +action :install do + options = {} + options['--schema'] = new_resource.schema.to_s if new_resource.schema + params = {} + params[:name] = new_resource.name.to_s if new_resource.name + params[:stage] = new_resource.stage.to_s if new_resource.stage + params[:version] = new_resource.version.to_s if new_resource.version + params[:db] = new_resource.db.to_s if new_resource.db + converge_by 'install pgxn extension' do + pgxn_install_extension(new_resource.in_version, new_resource.in_cluster, params, options) + end +end diff --git a/resources/user.rb b/resources/user.rb index f2e461c..f2de56e 100644 --- a/resources/user.rb +++ b/resources/user.rb @@ -25,17 +25,40 @@ # SOFTWARE. # +include Chef::Postgresql::Helpers + provides :postgresql_user resource_name :postgresql_user -actions :create default_action :create -attribute :name, kind_of: String, required: true -attribute :in_version, kind_of: String, required: true -attribute :in_cluster, kind_of: String, required: true -attribute :unencrypted_password, kind_of: String -attribute :encrypted_password, kind_of: String -attribute :replication, kind_of: [TrueClass, FalseClass] -attribute :superuser, kind_of: [TrueClass, FalseClass] -attribute :advanced_options, kind_of: Hash, default: {} +property :in_version, String, required: true +property :in_cluster, String, required: true +property :unencrypted_password, String +property :encrypted_password, String +property :replication, [TrueClass, FalseClass] +property :superuser, [TrueClass, FalseClass] +property :advanced_options, Hash, default: {} + +action :create do + options = new_resource.advanced_options.dup + + if new_resource.replication == true + options['REPLICATION'] = nil + elsif new_resource.replication == false + options['NOREPLICATION'] = nil + end + + if new_resource.superuser == true + options['SUPERUSER'] = nil + elsif new_resource.superuser == false + options['NOSUPERUSER'] = nil + end + + options['ENCRYPTED PASSWORD'] = "'#{new_resource.encrypted_password}'" if new_resource.encrypted_password + + options['UNENCRYPTED PASSWORD'] = "'#{new_resource.unencrypted_password}'" if new_resource.unencrypted_password + converge_by "create user #{new_resource.name}" do + create_user(new_resource.in_version, new_resource.in_cluster, new_resource.name, options) + end +end diff --git a/templates/default/recovery.conf.erb b/templates/default/recovery.conf.erb index 45ab459..2f1eff9 100644 --- a/templates/default/recovery.conf.erb +++ b/templates/default/recovery.conf.erb @@ -1,5 +1,8 @@ -<%= "standby_mode = '#{@replication[:standby_mode]}'" if @replication[:standby_mode] %> -<%= "primary_conninfo = '#{@replication[:primary_conninfo]}'" if @replication[:primary_conninfo] %> -<%= "trigger_file = '#{@replication[:trigger_file]}'" if @replication[:trigger_file] %> -<%= "restore_command = '#{@replication[:restore_command]}'" if @replication[:restore_command] %> -<%= "primary_slot_name = '#{@replication[:primary_slot_name]}'" if @replication[:primary_slot_name] %> +# +## Generated by Chef for <%= node['fqdn'] %>. +## Local modifications will be overwritten. +# + +<% @replication.each do |parameter, value| %> +<%= parameter %> = '<%= value %>' +<% end %> diff --git a/test/fixtures/cookbooks/pgtest/recipes/cloud_backup.rb b/test/fixtures/cookbooks/pgtest/recipes/cloud_backup.rb index 349384b..eec3ce3 100644 --- a/test/fixtures/cookbooks/pgtest/recipes/cloud_backup.rb +++ b/test/fixtures/cookbooks/pgtest/recipes/cloud_backup.rb @@ -1 +1,22 @@ -include_recipe 'postgresql_lwrp::cloud_backup' +postgresql_cloud_backup 'test-wal-e' do + in_version node['pgtest']['version'] + in_cluster 'main' + parameters( + 'PGPORT' => '5432', + 'AWS_ACCESS_KEY_ID' => 'example', + 'AWS_SECRET_ACCESS_KEY' => 'example', + 'WALE_S3_PREFIX' => 'example' + ) +end + +postgresql_cloud_backup 'test-wal-g' do + utility 'wal-g' + in_version node['pgtest']['version'] + in_cluster 'walg' + parameters( + 'PGPORT' => '5432', + 'AWS_ACCESS_KEY_ID' => 'example', + 'AWS_SECRET_ACCESS_KEY' => 'example', + 'WALG_S3_PREFIX' => 'example' + ) +end diff --git a/test/fixtures/cookbooks/pgtest/recipes/create_database.rb b/test/fixtures/cookbooks/pgtest/recipes/create_database.rb index 8a5bb2b..098a93b 100644 --- a/test/fixtures/cookbooks/pgtest/recipes/create_database.rb +++ b/test/fixtures/cookbooks/pgtest/recipes/create_database.rb @@ -1,13 +1,13 @@ include_recipe 'postgresql_lwrp::default' postgresql_database 'test01' do - in_version node['postgresql']['defaults']['server']['version'] + in_version node['pgtest']['version'] in_cluster 'main' owner 'test01' end postgresql_database 'test-02' do - in_version node['postgresql']['defaults']['server']['version'] + in_version node['pgtest']['version'] in_cluster 'main' owner 'test-02' end diff --git a/test/fixtures/cookbooks/pgtest/recipes/create_user.rb b/test/fixtures/cookbooks/pgtest/recipes/create_user.rb index 87412b0..32fe3c4 100644 --- a/test/fixtures/cookbooks/pgtest/recipes/create_user.rb +++ b/test/fixtures/cookbooks/pgtest/recipes/create_user.rb @@ -1,15 +1,15 @@ include_recipe 'postgresql_lwrp::default' postgresql_user 'test01' do - in_version node['postgresql']['defaults']['server']['version'] + in_version node['pgtest']['version'] in_cluster 'main' - unencrypted_password 'test01' + encrypted_password 'test01' replication true end postgresql_user 'test-02' do - in_version node['postgresql']['defaults']['server']['version'] + in_version node['pgtest']['version'] in_cluster 'main' - unencrypted_password 'test-02' + encrypted_password 'test-02' superuser true end diff --git a/test/fixtures/cookbooks/pgtest/recipes/install_ext.rb b/test/fixtures/cookbooks/pgtest/recipes/install_ext.rb index 645ac1b..ae05371 100644 --- a/test/fixtures/cookbooks/pgtest/recipes/install_ext.rb +++ b/test/fixtures/cookbooks/pgtest/recipes/install_ext.rb @@ -1,15 +1,16 @@ include_recipe 'postgresql_lwrp::default' postgresql_extension 'cube' do - in_version node['postgresql']['defaults']['server']['version'] + in_version node['pgtest']['version'] in_cluster 'main' db 'test01' end -pgxn_extension 'count_distinct' do - in_version node['postgresql']['defaults']['server']['version'] +pgxn_extension 'semver' do + in_version node['pgtest']['version'] in_cluster 'main' db 'test01' - version '1.3.2' + version '0.20.3' stage 'stable' + only_if { node['pgtest']['version'].to_f > 9.1 } end diff --git a/test/fixtures/cookbooks/pgtest/recipes/master.rb b/test/fixtures/cookbooks/pgtest/recipes/master.rb index a099b26..431c8d4 100644 --- a/test/fixtures/cookbooks/pgtest/recipes/master.rb +++ b/test/fixtures/cookbooks/pgtest/recipes/master.rb @@ -8,12 +8,13 @@ postgresql 'main' do cluster_create_options('locale' => 'en_US.UTF-8') + cluster_version node['pgtest']['version'] configuration( + archive_command: :cloud_auto, listen_addresses: '*', max_connections: 300, ssl_renegotiation_limit: 0, archive_mode: 'on', - archive_command: 'exit 0', shared_buffers: '64MB', maintenance_work_mem: '8MB', work_mem: '2MB', @@ -22,7 +23,7 @@ hba_configuration( [ { type: 'host', database: 'all', user: 'all', address: '0.0.0.0/0', method: 'md5' }, - { type: 'host', database: 'replication', user: 'postgres', address: '127.0.0.1/32', method: 'trust' } + { type: 'host', database: 'replication', user: 'postgres', address: '127.0.0.1/32', method: 'trust' }, ] ) end diff --git a/test/fixtures/cookbooks/pgtest/recipes/master_for_walg.rb b/test/fixtures/cookbooks/pgtest/recipes/master_for_walg.rb new file mode 100644 index 0000000..3736a55 --- /dev/null +++ b/test/fixtures/cookbooks/pgtest/recipes/master_for_walg.rb @@ -0,0 +1,30 @@ +include_recipe 'postgresql_lwrp::apt_official_repository' +include_recipe 'postgresql_lwrp::default' +include_recipe 'sysctl::default' + +sysctl_param 'kernel.shmmax' do + value 68_719_476_736 +end + +postgresql 'walg' do + cluster_create_options('locale' => 'en_US.UTF-8') + cluster_version node['pgtest']['version'] + configuration( + archive_command: :cloud_auto, + port: 5435, + listen_addresses: '*', + max_connections: 100, + ssl_renegotiation_limit: 0, + archive_mode: 'on', + shared_buffers: '64MB', + maintenance_work_mem: '8MB', + work_mem: '2MB', + effective_cache_size: '200MB' + ) + hba_configuration( + [ + { type: 'host', database: 'all', user: 'all', address: '0.0.0.0/0', method: 'md5' }, + { type: 'host', database: 'replication', user: 'postgres', address: '127.0.0.1/32', method: 'trust' }, + ] + ) +end diff --git a/test/fixtures/cookbooks/pgtest/recipes/slave.rb b/test/fixtures/cookbooks/pgtest/recipes/slave.rb index ea77bf2..fbb1de0 100644 --- a/test/fixtures/cookbooks/pgtest/recipes/slave.rb +++ b/test/fixtures/cookbooks/pgtest/recipes/slave.rb @@ -1,6 +1,9 @@ include_recipe 'postgresql_lwrp::apt_official_repository' include_recipe 'postgresql_lwrp::default' -include_recipe 'sysctl::default' + +service 'postgresql' do + action :restart +end sysctl_param 'kernel.shmmax' do value 68_719_476_736 @@ -8,8 +11,10 @@ postgresql 'slave' do cluster_create_options('locale' => 'en_US.UTF-8') + cluster_version node['pgtest']['version'] configuration( port: '5433', + hot_standby: 'on', listen_addresses: '*', max_connections: 300, ssl_renegotiation_limit: 0, @@ -20,7 +25,7 @@ ) hba_configuration( [ - { type: 'host', database: 'all', user: 'all', address: '0.0.0.0/0', method: 'md5' } + { type: 'host', database: 'all', user: 'all', address: '0.0.0.0/0', method: 'md5' }, ] ) replication( diff --git a/test/fixtures/cookbooks/pgtest/recipes/slave_init_nostart.rb b/test/fixtures/cookbooks/pgtest/recipes/slave_init_nostart.rb index d48122f..e3b5d9f 100644 --- a/test/fixtures/cookbooks/pgtest/recipes/slave_init_nostart.rb +++ b/test/fixtures/cookbooks/pgtest/recipes/slave_init_nostart.rb @@ -1,6 +1,5 @@ include_recipe 'postgresql_lwrp::apt_official_repository' include_recipe 'postgresql_lwrp::default' -include_recipe 'sysctl::default' sysctl_param 'kernel.shmmax' do value 68_719_476_736 @@ -8,6 +7,7 @@ postgresql 'slave2' do cluster_create_options('locale' => 'ru_RU.UTF-8') + cluster_version node['pgtest']['version'] configuration( port: '5434', listen_addresses: '*', @@ -20,7 +20,7 @@ ) hba_configuration( [ - { type: 'host', database: 'all', user: 'all', address: '0.0.0.0/0', method: 'md5' } + { type: 'host', database: 'all', user: 'all', address: '0.0.0.0/0', method: 'md5' }, ] ) replication( diff --git a/test/fixtures/cookbooks/pgtest/recipes/test_9_4.rb b/test/fixtures/cookbooks/pgtest/recipes/test.rb similarity index 67% rename from test/fixtures/cookbooks/pgtest/recipes/test_9_4.rb rename to test/fixtures/cookbooks/pgtest/recipes/test.rb index 7a00057..c3e083c 100644 --- a/test/fixtures/cookbooks/pgtest/recipes/test_9_4.rb +++ b/test/fixtures/cookbooks/pgtest/recipes/test.rb @@ -1,6 +1,7 @@ -node.default['postgresql']['defaults']['server']['version'] = '9.4' -node.default['postgresql']['client']['version'] = '9.4' +node.default['postgresql']['client']['version'] = node['pgtest']['version'] + include_recipe 'pgtest::master' +include_recipe 'pgtest::master_for_walg' include_recipe 'pgtest::create_user' include_recipe 'pgtest::create_database' include_recipe 'pgtest::install_ext' diff --git a/test/fixtures/cookbooks/pgtest/recipes/test_9_0.rb b/test/fixtures/cookbooks/pgtest/recipes/test_9_0.rb deleted file mode 100644 index 5808618..0000000 --- a/test/fixtures/cookbooks/pgtest/recipes/test_9_0.rb +++ /dev/null @@ -1,8 +0,0 @@ -node.default['postgresql']['defaults']['server']['version'] = '9.0' -node.override['postgresql']['defaults']['server']['hba_configuration'] = [ - { type: 'local', database: 'all', user: 'postgres', address: '', method: 'ident' }, - { type: 'local', database: 'all', user: 'all', address: '', method: 'ident' }, - { type: 'host', database: 'all', user: 'all', address: '127.0.0.1/32', method: 'md5' }, - { type: 'host', database: 'all', user: 'all', address: '::1/128', method: 'md5' } -] -include_recipe 'pgtest::master' diff --git a/test/fixtures/cookbooks/pgtest/recipes/test_9_1.rb b/test/fixtures/cookbooks/pgtest/recipes/test_9_1.rb deleted file mode 100644 index 9d76df1..0000000 --- a/test/fixtures/cookbooks/pgtest/recipes/test_9_1.rb +++ /dev/null @@ -1,7 +0,0 @@ -node.default['postgresql']['defaults']['server']['version'] = '9.1' -node.default['postgresql']['client']['version'] = '9.1' -include_recipe 'pgtest::master' -include_recipe 'pgtest::create_user' -include_recipe 'pgtest::create_database' -include_recipe 'pgtest::install_ext' -include_recipe 'pgtest::cloud_backup' diff --git a/test/fixtures/cookbooks/pgtest/recipes/test_9_2.rb b/test/fixtures/cookbooks/pgtest/recipes/test_9_2.rb deleted file mode 100644 index 6d5b08d..0000000 --- a/test/fixtures/cookbooks/pgtest/recipes/test_9_2.rb +++ /dev/null @@ -1,9 +0,0 @@ -node.default['postgresql']['defaults']['server']['version'] = '9.2' -node.default['postgresql']['client']['version'] = '9.2' -include_recipe 'pgtest::master' -include_recipe 'pgtest::create_user' -include_recipe 'pgtest::create_database' -include_recipe 'pgtest::install_ext' -include_recipe 'pgtest::slave' -include_recipe 'pgtest::slave_init_nostart' -include_recipe 'pgtest::cloud_backup' diff --git a/test/fixtures/cookbooks/pgtest/recipes/test_9_3.rb b/test/fixtures/cookbooks/pgtest/recipes/test_9_3.rb deleted file mode 100644 index 2e0d527..0000000 --- a/test/fixtures/cookbooks/pgtest/recipes/test_9_3.rb +++ /dev/null @@ -1,9 +0,0 @@ -node.default['postgresql']['defaults']['server']['version'] = '9.3' -node.default['postgresql']['client']['version'] = '9.3' -include_recipe 'pgtest::master' -include_recipe 'pgtest::create_user' -include_recipe 'pgtest::create_database' -include_recipe 'pgtest::install_ext' -include_recipe 'pgtest::slave' -include_recipe 'pgtest::slave_init_nostart' -include_recipe 'pgtest::cloud_backup' diff --git a/test/integration/pg-90/serverspec/postgresql_spec.rb b/test/integration/pg-90/serverspec/postgresql_spec.rb deleted file mode 100644 index 53a910e..0000000 --- a/test/integration/pg-90/serverspec/postgresql_spec.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'spec_helper' - -master_tests('9.0') diff --git a/test/integration/pg-90/serverspec/spec_helper.rb b/test/integration/pg-90/serverspec/spec_helper.rb deleted file mode 120000 index 9b53bb7..0000000 --- a/test/integration/pg-90/serverspec/spec_helper.rb +++ /dev/null @@ -1 +0,0 @@ -../../spec_helper.rb \ No newline at end of file diff --git a/test/integration/pg-91/serverspec/postgresql_spec.rb b/test/integration/pg-91/serverspec/postgresql_spec.rb deleted file mode 100644 index adb3c30..0000000 --- a/test/integration/pg-91/serverspec/postgresql_spec.rb +++ /dev/null @@ -1,7 +0,0 @@ -require 'spec_helper' - -master_tests('9.1') -create_users_tests('9.1') -create_database_tests('9.1') -install_extension_tests('9.1') -cloud_backup_tests diff --git a/test/integration/pg-91/serverspec/spec_helper.rb b/test/integration/pg-91/serverspec/spec_helper.rb deleted file mode 120000 index 9b53bb7..0000000 --- a/test/integration/pg-91/serverspec/spec_helper.rb +++ /dev/null @@ -1 +0,0 @@ -../../spec_helper.rb \ No newline at end of file diff --git a/test/integration/pg-92/serverspec/postgresql_spec.rb b/test/integration/pg-92/serverspec/postgresql_spec.rb deleted file mode 100644 index d4105b5..0000000 --- a/test/integration/pg-92/serverspec/postgresql_spec.rb +++ /dev/null @@ -1,8 +0,0 @@ -require 'spec_helper' - -master_tests('9.2') -create_users_tests('9.2') -create_database_tests('9.2') -install_extension_tests('9.2') -slave_tests('9.2') -cloud_backup_tests diff --git a/test/integration/pg-92/serverspec/spec_helper.rb b/test/integration/pg-92/serverspec/spec_helper.rb deleted file mode 120000 index 9b53bb7..0000000 --- a/test/integration/pg-92/serverspec/spec_helper.rb +++ /dev/null @@ -1 +0,0 @@ -../../spec_helper.rb \ No newline at end of file diff --git a/test/integration/pg-93/serverspec/postgresql_spec.rb b/test/integration/pg-93/serverspec/postgresql_spec.rb deleted file mode 100644 index d1a332e..0000000 --- a/test/integration/pg-93/serverspec/postgresql_spec.rb +++ /dev/null @@ -1,8 +0,0 @@ -require 'spec_helper' - -master_tests('9.3') -create_users_tests('9.3') -create_database_tests('9.3') -install_extension_tests('9.3') -slave_tests('9.3') -cloud_backup_tests diff --git a/test/integration/pg-93/serverspec/spec_helper.rb b/test/integration/pg-93/serverspec/spec_helper.rb deleted file mode 120000 index 9b53bb7..0000000 --- a/test/integration/pg-93/serverspec/spec_helper.rb +++ /dev/null @@ -1 +0,0 @@ -../../spec_helper.rb \ No newline at end of file diff --git a/test/integration/pg-94-chef11/serverspec/postgresql_spec.rb b/test/integration/pg-94-chef11/serverspec/postgresql_spec.rb deleted file mode 100644 index 6f27471..0000000 --- a/test/integration/pg-94-chef11/serverspec/postgresql_spec.rb +++ /dev/null @@ -1,8 +0,0 @@ -require 'spec_helper' - -master_tests('9.4') -create_users_tests('9.4') -create_database_tests('9.4') -install_extension_tests('9.4') -slave_tests('9.4') -cloud_backup_tests diff --git a/test/integration/pg-94-chef11/serverspec/spec_helper.rb b/test/integration/pg-94-chef11/serverspec/spec_helper.rb deleted file mode 120000 index 9b53bb7..0000000 --- a/test/integration/pg-94-chef11/serverspec/spec_helper.rb +++ /dev/null @@ -1 +0,0 @@ -../../spec_helper.rb \ No newline at end of file diff --git a/test/integration/pg-94/serverspec/postgresql_spec.rb b/test/integration/pg-94/serverspec/postgresql_spec.rb deleted file mode 100644 index 6f27471..0000000 --- a/test/integration/pg-94/serverspec/postgresql_spec.rb +++ /dev/null @@ -1,8 +0,0 @@ -require 'spec_helper' - -master_tests('9.4') -create_users_tests('9.4') -create_database_tests('9.4') -install_extension_tests('9.4') -slave_tests('9.4') -cloud_backup_tests diff --git a/test/integration/pg-94/serverspec/spec_helper.rb b/test/integration/pg-94/serverspec/spec_helper.rb deleted file mode 120000 index 9b53bb7..0000000 --- a/test/integration/pg-94/serverspec/spec_helper.rb +++ /dev/null @@ -1 +0,0 @@ -../../spec_helper.rb \ No newline at end of file diff --git a/test/integration/postgresql_lwrp_test/inspec/controls/default.rb b/test/integration/postgresql_lwrp_test/inspec/controls/default.rb new file mode 100644 index 0000000..ba9e84b --- /dev/null +++ b/test/integration/postgresql_lwrp_test/inspec/controls/default.rb @@ -0,0 +1,154 @@ +# # encoding: utf-8 + +# Inspec default test + +# The Inspec reference, with examples and extensive documentation, can be +# found at http://inspec.io/docs/reference/resources/ + +pg_version = attribute('pg_version', default: nil, description: 'Set postgresql version') + +control 'postgres users' do + title 'Users should be configured' + + describe postgres_user(pg_version, 'main', 'test01', 'test01') do + it { should have_login } + it { should have_privilege('rolreplication') } + it { should_not have_privilege('rolsuper') } + end + + describe postgres_user(pg_version, 'main', 'test-02', 'test-02') do + it { should have_login } + it { should have_privilege('rolsuper') } + end +end + +control 'postgres master' do + title 'Postgres cluster' + + describe package("postgresql-#{pg_version}") do + it { should be_installed } + end + + # Chef 14 resource service is broken on a first run on Ubuntu 14. + if os.name == 'ubuntu' && os.release.to_f > 14.04 + describe service('postgresql') do + it { should be_enabled } + end + end + + describe postgres_cluster(pg_version, 'main') do + it { should be_running } + end + + describe port(5432) do + it { should be_listening } + end +end + +control 'postgres databases' do + title 'Check postgres databases' + + describe postgres_database(pg_version, 'main', 'test01') do + it { should be_created } + it { should have_owner('test01') } + end + + describe postgres_database(pg_version, 'main', 'test-02') do + it { should be_created } + it { should have_owner('test-02') } + it { should_not have_owner('test01') } + end + + describe postgres_database(pg_version, 'main', 'test-03') do + it { should_not be_created } + end +end + +control 'postgres extensions' do + title 'Check postgres extensions' + describe postgres_extension(pg_version, 'main', 'cube', 'test01') do + it { should be_installed } + end + + if pg_version.to_f > 9.1 + describe postgres_extension(pg_version, 'main', 'semver', 'test01') do + it { should be_installed } + end + end +end + +control 'postgres slave' do + title 'Postgres cluster' + # Chef 14 resource service is broken on a first run on Ubuntu 14. + if os.name == 'ubuntu' && os.release.to_f > 14.04 + describe service('postgresql') do + it { should be_enabled } + end + end + + describe postgres_cluster(pg_version, 'slave') do + it { should be_running } + end + + describe postgres_cluster(pg_version, 'slave2') do + it { should be_stopped } + end + + describe port(5433) do + it { should be_listening } + end + + describe port(5434) do + it { should_not be_listening } + end +end + +control 'WAL-E cloud backup' do + title 'Check WAL-E cloud backup installation' + + %w( + daemontools + lzop + mbuffer + pv + python3-dev + ).each do |pkg| + describe package(pkg) do + it { should be_installed } + end + end + + %w( + wal-e + boto + ).each do |pip_package| + describe pip(pip_package, '/opt/wal-e/bin/pip') do + it { should be_installed } + end + end + + describe postgres_cluster(pg_version, 'main') do + its('archive_command') do + should match(%r{envdir /etc/wal-e.d/main-#{pg_version}/env/ /opt/wal-e/bin/wal-e wal-push %p}s) + end + end +end + +control 'WAL-G cloud backup' do + title 'Check WAL-G cloud backup installation' + describe file('/usr/local/bin/wal-g') do + it { should exist } + it { should be_executable } + end + + describe file("/etc/wal-g.d/walg-#{pg_version}/env/PGHOST") do + it { should exist } + its('content') { should match(%r{/var/run/postgresql}) } + end + + describe postgres_cluster(pg_version, 'walg') do + its('archive_command') do + should match(%r{envdir /etc/wal-g.d/walg-#{pg_version}/env/ /usr/local/bin/wal-g wal-push %p}s) + end + end +end diff --git a/test/integration/postgresql_lwrp_test/inspec/inspec.yml b/test/integration/postgresql_lwrp_test/inspec/inspec.yml new file mode 100644 index 0000000..4eecc77 --- /dev/null +++ b/test/integration/postgresql_lwrp_test/inspec/inspec.yml @@ -0,0 +1,5 @@ +name: inspec-test-fixtures +title: InSpec Profile +maintainer: LLC Express 42 +license: MIT +version: 0.1.0 diff --git a/test/integration/postgresql_lwrp_test/inspec/libraries/postgres_cluster.rb b/test/integration/postgresql_lwrp_test/inspec/libraries/postgres_cluster.rb new file mode 100644 index 0000000..db0eced --- /dev/null +++ b/test/integration/postgresql_lwrp_test/inspec/libraries/postgres_cluster.rb @@ -0,0 +1,110 @@ +# author: Dmitry Mischenko + +class PostgresCluster < Inspec.resource(1) + name 'postgres_cluster' + desc 'Use the postgres_cluster InSpec audit resource to test PostgreSQL database cluster status' + example " + describe postgres_cluster('9.6', 'slave') do + it { should be_running } + end + + describe postgres_cluster('9.6', 'slave2') do + it { should be_stopped } + end + " + + def initialize(version, name = 'main') + @name = name + @version = version + @port = get_port(version, name) + @running = 0 + @stopping = define_stopping_code(version) + + @params = SimpleConfig.new( + running_configuration, + assignment_regex: /^\s*([^=\|]*?)\s*\|\s*(.*?)\s*$/ + ) + end + + def running? + cmd = "/usr/lib/postgresql/#{@version}/bin/pg_ctl" + cmd += " -D /var/lib/postgresql/#{@version}/#{@name} status" + full_cmd = su_wrapper(cmd) + return true if inspec.command(full_cmd).exit_status == @running + false + end + + def stopped? + cmd = "/usr/lib/postgresql/#{@version}/bin/pg_ctl" + cmd += " -D /var/lib/postgresql/#{@version}/#{@name} status" + full_cmd = su_wrapper(cmd) + return true if inspec.command(full_cmd).exit_status == @stopping + false + end + + def to_s + "Cluster #{@name}" + end + + # Expose all parameters of the configuration file. + def method_missing(name) + @params.params[name.to_s] || super + end + + def respond_to_missing?(method_name, include_private = false) + @params.params.include?(method_name.to_s) || super + end + + private + + def running_configuration + c = query('SELECT name, setting FROM pg_settings') + c + end + + def query(query) + psql_cmd = create_psql_cmd(query, 'postgres') + cmd = inspec.command(psql_cmd) + out = cmd.stdout + "\n" + cmd.stderr + + if cmd.exit_status != 0 || + out =~ /could not connect to .*/ || + out.downcase =~ /^error:.*/ + nil + else + cmd.stdout.strip + end + end + + def escaped_query(query) + Shellwords.escape(query) + end + + def su_wrapper(psql_cmd) + "su postgres -c \"#{psql_cmd}\"" + end + + def create_psql_cmd(query, database) + cmd = '/usr/bin/psql' + cmd += " -d #{database}" + cmd += " -p #{@port}" + cmd += ' -q -A -t' + cmd += " -c #{escaped_query(query)}" + su_wrapper(cmd) + end + + def get_port(version, cluster) + pid_file_name = "/var/lib/postgresql/#{version}/#{cluster}/postmaster.pid" + postmaster_content = inspec.command("cat #{pid_file_name}").stdout.split + postmaster_content[3].to_i + end + + def define_stopping_code(version) + case version.to_s + when '9.1' + 1 + else + 3 + end + end +end diff --git a/test/integration/postgresql_lwrp_test/inspec/libraries/postgres_database.rb b/test/integration/postgresql_lwrp_test/inspec/libraries/postgres_database.rb new file mode 100644 index 0000000..8d709a0 --- /dev/null +++ b/test/integration/postgresql_lwrp_test/inspec/libraries/postgres_database.rb @@ -0,0 +1,61 @@ +# encoding: utf-8 +# author: Kirill Kuznetsov + +class PostgresDatabase < Inspec.resource(1) + name 'postgres_database' + desc 'Use the postgres_database InSpec audit resource to test PostgreSQL cluster databases.' + example " + describe postgres_database('9.6', 'main', 'test01') do + it { should be_created } + it { should have_owner('test01')} + end + " + + def initialize(version, cluster, name) + @name = name + @version = version + @cluster = cluster + @port = get_port(version, cluster) + end + + def created? + return true if query("SELECT datname FROM pg_database where datname='#{@name}'") == @name + false + end + + def has_owner?(owner) + return true if query("SELECT pg_get_userbyid(datdba) FROM pg_database where datname='#{@name}'") == owner + false + end + + def to_s + "Database #{@name}" + end + + private + + def query(query) + psql_cmd = create_psql_cmd(query, 'postgres') + cmd = inspec.command(psql_cmd) + out = cmd.stdout + "\n" + cmd.stderr + if cmd.exit_status != 0 || out =~ /could not connect to .*/ || out.downcase =~ /^error:.*/ + false + else + cmd.stdout.strip + end + end + + def escaped_query(query) + Shellwords.escape(query) + end + + def create_psql_cmd(query, database) + "su postgres -c \"psql -d #{database} -p #{@port} -q -t -c #{escaped_query(query)}\"" + end + + def get_port(version, cluster) + pid_file_name = "/var/lib/postgresql/#{version}/#{cluster}/postmaster.pid" + postmaster_content = inspec.command("cat #{pid_file_name}").stdout.split + postmaster_content[3].to_i + end +end diff --git a/test/integration/postgresql_lwrp_test/inspec/libraries/postgres_extension.rb b/test/integration/postgresql_lwrp_test/inspec/libraries/postgres_extension.rb new file mode 100644 index 0000000..7de8e0f --- /dev/null +++ b/test/integration/postgresql_lwrp_test/inspec/libraries/postgres_extension.rb @@ -0,0 +1,54 @@ +# encoding: utf-8 +# author: Dmitry Mischenko + +class PostgresExtension < Inspec.resource(1) + name 'postgres_extension' + desc 'Use the postgres_extension InSpec audit resource to test installation of PostgreSQL database extensions' + example " + describe postgres_extension('9.6', 'main', 'cube', 'test01') do + it { should be_installed } + end + " + + def initialize(version, cluster, name, db = 'postgres') + @name = name + @db = db + @port = get_port(version, cluster) + end + + def installed? + return true if query('SELECT extname FROM pg_extension').include? @name + false + end + + def to_s + "Extension #{@name}" + end + + private + + def query(query) + psql_cmd = create_psql_cmd(query, @db) + cmd = inspec.command(psql_cmd) + out = cmd.stdout + "\n" + cmd.stderr + if cmd.exit_status != 0 || out =~ /could not connect to .*/ || out.downcase =~ /^error:.*/ + false + else + cmd.stdout.strip + end + end + + def escaped_query(query) + Shellwords.escape(query) + end + + # TODO: You cannot specify multiple DBs + def create_psql_cmd(query, db) + "su postgres -c \"psql -d #{db} -p #{@port} -q -t -c #{escaped_query(query)}\"" + end + + def get_port(version, cluster) + postmaster_content = inspec.command("cat /var/lib/postgresql/#{version}/#{cluster}/postmaster.pid").stdout.split + postmaster_content[3].to_i + end +end diff --git a/test/integration/postgresql_lwrp_test/inspec/libraries/postgres_user.rb b/test/integration/postgresql_lwrp_test/inspec/libraries/postgres_user.rb new file mode 100644 index 0000000..cf84e3b --- /dev/null +++ b/test/integration/postgresql_lwrp_test/inspec/libraries/postgres_user.rb @@ -0,0 +1,61 @@ +# encoding: utf-8 +# author: Dmitry Mischenko + +class PostgresUser < Inspec.resource(1) + name 'postgres_user' + desc 'Use the postgres_user InSpec audit resource to test PostgreSQL database user options' + example " + describe postgres_user('9.6', 'main', 'test-02', 'test-02') do + it { should have_login } + it { should have_privilege('rolsuper') } + end + " + + def initialize(version, cluster, user, pass, db = 'postgres') + @user = user || 'postgres' + @pass = pass + @host = 'localhost' + @db = db + @port = get_port(version, cluster) + end + + def has_privilege?(priv) + return true if query("SELECT #{priv} FROM pg_roles where rolname='#{@user}'") == 't' + false + end + + def has_login? + return true if query('SELECT 1') + false + end + + def to_s + "User #{@user}" + end + + private + + def query(query) + psql_cmd = create_psql_cmd(query, @db) + cmd = inspec.command(psql_cmd) + out = cmd.stdout + "\n" + cmd.stderr + if cmd.exit_status != 0 || out =~ /could not connect to .*/ || out.downcase =~ /^error:.*/ + false + else + cmd.stdout.strip + end + end + + def escaped_query(query) + Shellwords.escape(query) + end + + def create_psql_cmd(query, db) + "PGPASSWORD='#{@pass}' psql -U #{@user} -d #{db} -h #{@host} -p #{@port} -A -t -c #{escaped_query(query)}" + end + + def get_port(version, cluster) + postmaster_content = inspec.command("cat /var/lib/postgresql/#{version}/#{cluster}/postmaster.pid").stdout.split + postmaster_content[3].to_i + end +end diff --git a/test/integration/spec_helper.rb b/test/integration/spec_helper.rb index 8e3837c..6bfb2f4 100644 --- a/test/integration/spec_helper.rb +++ b/test/integration/spec_helper.rb @@ -39,11 +39,8 @@ def postgresql_check_login(version, name, user, password) def postgresql_extension_installed?(version, name, database, extension) pg_port = get_port(version, name) psql_out = command("echo -n \"SELECT extname FROM pg_extension\"| sudo -u postgres psql -t -p \"#{pg_port}\" \"#{database}\" 2>/dev/null") - if psql_out.stdout.include? extension - return true - else - return false - end + return true if psql_out.stdout.include? extension + false end def master_tests(pg_version)