diff --git a/.editorconfig b/.editorconfig new file mode 100755 index 00000000..cc21b046 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ +# https://EditorConfig.org + +# top-most EditorConfig file +root=true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true + +# 2 space indentation +indent_style = space +indent_size = 2 + +# Avoid issues parsing cookbook files later +charset = utf-8 + +# Avoid cookstyle warnings +trim_trailing_whitespace = true diff --git a/.envrc b/.envrc new file mode 100644 index 00000000..6ed589ea --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use chefworkstation diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..6313b56c --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..7cc52a97 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @sous-chefs/maintainers diff --git a/.github/lock.yml b/.github/lock.yml new file mode 100644 index 00000000..8344a7b3 --- /dev/null +++ b/.github/lock.yml @@ -0,0 +1,8 @@ +--- +daysUntilLock: 365 +exemptLabels: [] +lockLabel: false +lockComment: > + This thread has been automatically locked since there has not been + any recent activity after it was closed. Please open a new issue for + related bugs. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..570fe5c1 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,78 @@ +--- +name: ci + +"on": + pull_request: + push: + branches: + - main + +jobs: + lint-unit: + uses: sous-chefs/.github/.github/workflows/lint-unit.yml@2.0.6 + permissions: + actions: write + checks: write + pull-requests: write + statuses: write + issues: write + + integration: + needs: lint-unit + runs-on: ubuntu-latest + strategy: + matrix: + os: + - almalinux-8 + - almalinux-9 + - centos-7 + - centos-stream-8 + - centos-stream-9 + - debian-10 + - debian-11 + - ubuntu-1804 + - ubuntu-2004 + - ubuntu-2204 + suite: + - client-57 + - client-80 + - devel-57 + - devel-80 + - server-57 + - server-80 + - source-57 + - source-80 + - replication-57 + - replication-80 + - resources-57 + - resources-80 + fail-fast: false + + steps: + - name: Check out code + uses: actions/checkout@v4 + - name: Install Chef + uses: actionshub/chef-install@2.0.4 + # https://github.com/actions/virtual-environments/issues/181#issuecomment-610874237 + - name: Disable apparmor for mysqld + run: | + set -x + sudo apt-get -y remove mysql-server --purge + sudo apt-get -y install apparmor-profiles + sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld + - name: Dokken + uses: actionshub/test-kitchen@2.1.0 + env: + CHEF_LICENSE: accept-no-persist + KITCHEN_LOCAL_YAML: kitchen.dokken.yml + with: + suite: ${{ matrix.suite }} + os: ${{ matrix.os }} + - name: Print debug output on failure + if: failure() + run: | + set -x + sudo journalctl -l --since today + sudo docker version + sudo docker info + KITCHEN_LOCAL_YAML=kitchen.dokken.yml /usr/bin/kitchen exec ${{ matrix.suite }}-${{ matrix.os }} -c "journalctl -l" diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 00000000..4bb59c62 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,25 @@ +--- +name: Mark stale issues and pull requests + +"on": + schedule: [cron: "0 0 * * *"] + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v8 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + close-issue-message: > + Closing due to inactivity. + If this is still an issue please reopen or open another issue. + Alternatively drop by the #sous-chefs channel on the [Chef Community Slack](http://community-slack.chef.io/) and we'll be happy to help! + Thanks, Sous-Chefs. + days-before-close: 7 + days-before-stale: 365 + stale-issue-message: > + Marking stale due to inactivity. + Remove stale label or comment or this will be closed in 7 days. + Alternatively drop by the #sous-chefs channel on the [Chef Community Slack](http://community-slack.chef.io/) and we'll be happy to help! + Thanks, Sous-Chefs. diff --git a/.gitignore b/.gitignore index c2ee49a2..be3b9a8b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,49 @@ -cookbooks/* +*.rbc +.config +InstalledFiles +pkg +test/tmp +test/version_tmp tmp -.librarian/ -.kitchen/ -.kitchen.local.yml +_Store +*~ +*# +.#* +\#*# +*.un~ +*.tmp +*.bk +*.bkup + +# editor files +.idea +.*.sw[a-z] + +# ruby/bundler/rspec files +.ruby-version +.ruby-gemset +.rvmrc Gemfile.lock +.bundle +*.gem +coverage +spec/reports + +# YARD / rdoc artifacts +.yardoc +_yardoc +doc/ +rdoc + +# chef infra stuff +Berksfile.lock +.kitchen +kitchen.local.yml +vendor/ +.coverage/ +.zero-knife.rb +Policyfile.lock.json + +# vagrant stuff +.vagrant/ +.vagrant.d/ diff --git a/.kitchen.yml b/.kitchen.yml deleted file mode 100644 index 154dfc50..00000000 --- a/.kitchen.yml +++ /dev/null @@ -1,48 +0,0 @@ -#<% require "kitchen-sync" %> ---- -driver: - name: docker - require_chef_omnibus: <%= ENV.fetch("CHEF_VERSION", "true") %> - -provisioner: - name: chef_zero - -platforms: - - name: amazon-2015 - driver_config: - image: ambakshi/amazon-linux - platform: rhel - - name: centos-6.6 - - name: centos-7.1 - - name: debian-7.8 - - name: debian-8.0 - - name: ubuntu-12.04 - - name: ubuntu-14.04 - -suites: - <% %w[5.5 5.6].each do |version| %> - - name: client_<%= version.tr(".", "") %> - attributes: - percona: - apt: - keyserver: hkp://pgp.mit.edu:80 - version: "<%= version %>" - run_list: - - recipe[percona::client] - - recipe[percona::toolkit] - - - name: server_<%= version.tr(".", "") %> - attributes: - percona: - apt: - keyserver: hkp://pgp.mit.edu:80 - version: "<%= version %>" - server: - datadir: /tmp/mysql - debian_password: d3b1an - jemalloc: true - root_password: r00t - run_list: - - recipe[percona::server] - - recipe[percona::backup] - <% end %> diff --git a/.markdownlint-cli2.yaml b/.markdownlint-cli2.yaml new file mode 100644 index 00000000..6fa8e776 --- /dev/null +++ b/.markdownlint-cli2.yaml @@ -0,0 +1,5 @@ +config: + ul-indent: false # MD007 + line-length: false # MD013 + no-duplicate-heading: false # MD024 + reference-links-images: false # MD052 diff --git a/.mdlrc b/.mdlrc new file mode 100644 index 00000000..ebeef65e --- /dev/null +++ b/.mdlrc @@ -0,0 +1 @@ +rules "~MD013", "~MD024" diff --git a/.overcommit.yml b/.overcommit.yml new file mode 100644 index 00000000..0e89a3c1 --- /dev/null +++ b/.overcommit.yml @@ -0,0 +1,24 @@ +--- +PreCommit: + TrailingWhitespace: + enabled: true + YamlLint: + enabled: true + required_executable: "yamllint" + ChefSpec: + enabled: true + required_executable: "chef" + command: ["chef", "exec", "rspec"] + Cookstyle: + enabled: true + required_executable: "cookstyle" + command: ["cookstyle"] + MarkdownLint: + enabled: false + required_executable: "npx" + command: ["npx", "markdownlint-cli2", "'**/*.md'"] + include: ["**/*.md"] + +CommitMsg: + HardTabs: + enabled: true diff --git a/.rubocop.yml b/.rubocop.yml index cac7b3be..d88ffa9f 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,29 +1,4 @@ +--- AllCops: Exclude: - - ".bundle/**/*" - - ".kitchen/**/*" - - "vendor/**/*" - -LineLength: - Max: 80 - Exclude: - - "**/attributes/*.rb" - - "**/metadata.rb" - -StringLiterals: - EnforcedStyle: double_quotes - -StringLiteralsInInterpolation: - EnforcedStyle: double_quotes - -PercentLiteralDelimiters: - PreferredDelimiters: - "%r": "()" - "%w": "[]" # Arrays use brackets - "%W": "[]" # Arrays use brackets - -SingleSpaceBeforeFirstArg: - Enabled: false # too strict about metadata and certain formatting - -inherit_from: test/support/rubocop/enabled.yml -inherit_from: test/support/rubocop/disabled.yml + - 'Dangerfile' diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b9bb1a16..00000000 --- a/.travis.yml +++ /dev/null @@ -1,24 +0,0 @@ -language: ruby -bundler_args: --jobs 4 --without integration -rvm: - - 2.0 - - 2.1 - - 2.2 -cache: bundler -sudo: false # travis docker container -env: - matrix: - - CHEF_VERSION=11.18.0 - - CHEF_VERSION=12.0.0 - - CHEF_VERSION=12.1.0 - - CHEF_VERSION=12.2.0 - - CHEF_VERSION=12.3.0 -before_script: - - "gem install bundler-audit --no-rdoc --no-ri && bundle-audit update" -script: - - bundle-audit check --ignore OSVDB-117461 CVE-2015-1820 - - bundle exec rake license_finder - - bundle exec rake rubocop - - bundle exec rake foodcritic - - bundle exec rake chefspec - - bundle exec rake kitchen:all diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..51d0ae7a --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "chef-software.chef", + "rebornix.ruby", + "editorconfig.editorconfig", + "DavidAnson.vscode-markdownlint" + ] +} diff --git a/.yamllint b/.yamllint new file mode 100644 index 00000000..0046b237 --- /dev/null +++ b/.yamllint @@ -0,0 +1,15 @@ +--- +extends: default +rules: + line-length: + max: 256 + level: warning + document-start: disable + braces: + forbid: false + min-spaces-inside: 0 + max-spaces-inside: 1 + min-spaces-inside-empty: -1 + max-spaces-inside-empty: -1 + comments: + min-spaces-from-content: 1 diff --git a/Berksfile b/Berksfile index 967b9a78..e09849c7 100644 --- a/Berksfile +++ b/Berksfile @@ -1,3 +1,7 @@ -source "https://supermarket.chef.io" +source 'https://supermarket.chef.io' metadata + +group :integration do + cookbook 'test', path: 'test/fixtures/cookbooks/test' +end diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..08d39dfb --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,225 @@ +# percona Cookbook CHANGELOG + +This file is used to list changes made in each version of the percona cookbook. + +## Unreleased + +## 3.4.4 - *2023-09-28* + +## 3.4.3 - *2023-09-04* + +## 3.4.2 - *2023-07-10* + +## 3.4.1 - *2023-06-14* + +- Fix adjustment of open files limit within systemd unit + +## 3.4.0 - *2023-06-07* + +- Avoid changing the perms on /tmp +- Remove duplicate configuration line +- Avoid duplicating mysqld configuration section in my.cnf +- Remove the open file limit from the systemd unit since it is already set in my.cnf anyway + +## 3.3.1 - *2023-05-17* + +## 3.3.0 - *2023-04-25* + +- Fixed the user key in the ctrl_hash for the run_query method in the mysql_user custom resource +- Updated ctrl_hash (now user_hash) parameters to validate if a user can login using username@host instead of username@ctrl_host +- Wrapped password substring in single quotes to protect from special characters in sql_command_string helper method +- Updated default encoding and collate in 8.0 to `utf8mb4` and `utf8mb4_0900_ai_ci` respectively +- Fixed 8.0 client rpm dependency conflict on centos 7 +- Stop running tests for Server and Client 5.6 +- Change test behaviour to not enable jemalloc on RHEL 9. + +## 3.2.11 - *2023-04-25* + +Standardise files with files in sous-chefs/repo-management + +## 3.2.10 - *2023-04-07* + +Standardise files with files in sous-chefs/repo-management + +## 3.2.9 - *2023-04-01* + +Standardise files with files in sous-chefs/repo-management + +## 3.2.8 - *2023-04-01* + +Standardise files with files in sous-chefs/repo-management + +## 3.2.7 - *2023-04-01* + +Standardise files with files in sous-chefs/repo-management + +## 3.2.6 - *2023-03-20* + +Standardise files with files in sous-chefs/repo-management + +## 3.2.5 - *2023-03-15* + +Standardise files with files in sous-chefs/repo-management + +## 3.2.4 - *2023-02-23* + +Standardise files with files in sous-chefs/repo-management + +## 3.2.3 - *2023-02-14* + +Standardise files with files in sous-chefs/repo-management + +## 3.2.2 - *2023-02-14* + +Standardise files with files in sous-chefs/repo-management + +## 3.2.1 - *2022-12-08* + +Standardise files with files in sous-chefs/repo-management + +## 3.2.0 - *2022-08-18* + +- Remove `myisam_repair_threads` for < 5.7 as it's been deprecated +- Remove delivery and move to calling RSpec directly via a reusable workflow +- Update tested platforms +- Add support to Alma Linux & Rocky Linux +- Update default encoding when using 8.0 to `utf8mb3` to fix idempotency issues +- Fix management of server `my.cnf` +- Set `manage_symlink_source` to `false` and set `force_unlink` to `true` to fix idempotency on Debian based systems +- Fix issue when testing on Debian dokken images by removing mailutils (and thus mysql-common) + +## 3.1.3 - *2022-02-17* + +- Standardise files with files in sous-chefs/repo-management + +## 3.1.2 - *2022-02-08* + +- Remove delivery folder + +## 3.1.1 - *2022-01-03* + +- Fix root password setting for version >= 5.7 + +## 3.1.0 - *2021-10-04* + +- Use `dnf_module` resource from `yum` cookbook instead of manually disabling module + +## 3.0.0 - *2021-09-17* + +- Chef 17 updates: enable `unified_mode` on all resources +- Remove dependency on openssl cookbook and create `percona_secure_random` method to replace that functionality +- Remove dependency on chef-vault cookbook and require Chef >= 16 +- Use full gpg key id for apt repos and switch to using keyserver.ubuntu.com +- Move mysql dnf module disabling to before yum repos + +## 2.1.2 - *2021-08-30* + +- Standardise files with files in sous-chefs/repo-management + +## 2.1.1 - *2021-06-01* + +- Standardise files with files in sous-chefs/repo-management + +## 2.1.0 - *2021-01-19* + +- Fix error when granting multi-word privileges (ex. `REPLICATION CLIENT`) to users through `percona_mysql_user` +- Remove support for Ubuntu 16.04 + +## 2.0.1 - *2020-12-15* + +- Fix links to resources in README + +## 2.0.0 - 2020-10-23 + +- Add `percona_mysql_database` resource for creating, querying and removing databases +- Add `percona_mysql_user` resource for creating, modifying and removing database users + +- Remove `mysql_chef_gem` and `mysql2_chef_gem` providers in favor of the `percona_mysql_database` and `percona_mysql_user` resources + +## 1.1.1 - 2020-09-16 + +- resolved cookstyle error: libraries/helpers.rb:125:1 refactor: `ChefCorrectness/IncorrectLibraryInjection` + +## 1.1.0 - 2020-08-20 + +- Add devel package attribute to client recipe + +## 1.0.0 - 2020-08-14 + +- Add support for Debian 10 for 5.7 only +- Add support for Ubuntu 20.04 for 5.7 only +- Add support for CentOS 8 +- Add cluster suite and tests to test cluster recipe +- Add support for Percona 8.0 and default to that version +- Re-add ChefSpec tests +- Add ssl suite and tests for ssl recipe +- Add master suite and tests for testing the replication recipe +- Suite to test compatibility with Chef 13 +@2.0.1 + +- Update apt gpg key +- Fixes for supporting 5.7 +- Fix manage_symlink_source warning with template[/etc/mysql/my.cnf] +- Don't remove mysql-libs on RHEL +- jemalloc package installation and path setup for all platforms +- Fixed enabled ChefSpec tests +- Use the correct syntax on 8.0 for SSL replication +- Use correct cert path for master/slave +- Fix issue when trying to set node['percona']['version'] in a recipe + +- Convert to InSpec tests and refactor test cookbook recipes +- Don't install abi_version packages on Debian/Ubuntu +- Standardise files with files in sous-chefs/repo-management +- Move client package installation for cluster to cluster recipe + +- Remove support for Amazon Linux +- Remove support for OpenSUSE +- Remove support for Debian 8 (EOL) +- Remove support for Fedora / Scientific +- Remove support for CentOS 6 +- Remove references to EOL 5.5 release + +### Deprecated + +- Deprecate monitoring recipe +- Use new inclusive terminology and add deprecation warning for old terms + +## 0.17.2 - 2020-08-06 + +@2.0.1 + +- Fix debian_password as a string for testing +- Fix idempotency issues with find_password method + +## 0.17.1 - 2020-05-14 + +- resolved cookstyle error: recipes/access_grants.rb:28:40 convention: `Layout/TrailingWhitespace` +- resolved cookstyle error: recipes/access_grants.rb:28:41 refactor: `ChefModernize/FoodcriticComments` +- resolved cookstyle error: recipes/configure_server.rb:102:25 convention: `Layout/TrailingWhitespace` +- resolved cookstyle error: recipes/configure_server.rb:102:26 refactor: `ChefModernize/FoodcriticComments` +- resolved cookstyle error: recipes/configure_server.rb:170:42 convention: `Layout/TrailingWhitespace` +- resolved cookstyle error: recipes/configure_server.rb:170:43 refactor: `ChefModernize/FoodcriticComments` +- resolved cookstyle error: recipes/replication.rb:28:35 convention: `Layout/TrailingWhitespace` +- resolved cookstyle error: recipes/replication.rb:28:36 refactor: `ChefModernize/FoodcriticComments` + +## 0.17.0 - 2020-05-05 + +- resolved cookstyle error: attributes/default.rb:8:16 warning: `Lint/SendWithMixinArgument` +- resolved cookstyle error: libraries/passwords.rb:23:16 refactor: `ChefModernize/DatabagHelpers` +- resolved cookstyle error: recipes/ssl.rb:17:9 refactor: `ChefModernize/DatabagHelpers` +- Removed unused use_inline_resources and whyrun_supported? methods from the resources +- Removed unused long_description metadata from metadata.rb +- Simplify platform checks inn only_if checks +- Remove the unused .foodcritic file +- Update metadata to point to Sous Chefs +- Migrate to github actions for testing + +## [0.16.5] + +- Use latest percona GPG keys for yum repo. See [New Percona Package Signing Key Requires Update on RHEL and CentOS](https://www.percona.com/blog/2019/02/05/new-percona-package-signing-key-requires-update-on-rhel-and-centos/) + +## [0.16.1] - 2015-06-03 + +- Many changes + +[0.16.1]: https://github.com/sous-chefs/percona/compare/v0.16.0...v0.16.1 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..20b4adbd --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,3 @@ +# Community Guidelines + +This project follows the Chef Community Guidelines diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..a946aea1 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,4 @@ +# Contributing + +Please refer to +[https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD](https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD) diff --git a/Dangerfile b/Dangerfile new file mode 100644 index 00000000..bc08b7ae --- /dev/null +++ b/Dangerfile @@ -0,0 +1,47 @@ +# Reference: http://danger.systems/reference.html + +# A pull request summary is required. Add a description of the pull request purpose. +# Changelog must be updated for each pull request that changes code. +# Warnings will be issued for: +# Pull request with more than 400 lines of code changed +# Pull reqest that change more than 5 lines without test changes +# Failures will be issued for: +# Pull request without summary +# Pull requests with code changes without changelog entry + +def code_changes? + code = %w(libraries attributes recipes resources files templates) + code.each do |location| + return true unless git.modified_files.grep(/#{location}/).empty? + end + false +end + +def test_changes? + tests = %w(spec test kitchen.yml kitchen.dokken.yml) + tests.each do |location| + return true unless git.modified_files.grep(/#{location}/).empty? + end + false +end + +failure 'Please provide a summary of your Pull Request.' if github.pr_body.length < 10 + +warn 'This is a big Pull Request.' if git.lines_of_code > 400 + +warn 'This is a Table Flip.' if git.lines_of_code > 2000 + +# Require a CHANGELOG entry for non-test changes. +if !git.modified_files.include?('CHANGELOG.md') && code_changes? + failure 'Please include a CHANGELOG entry.' +end + +# Require Major Minor Patch version labels +unless github.pr_labels.grep /minor|major|patch/i + warn 'Please add a release label to this pull request' +end + +# A sanity check for tests. +if git.lines_of_code > 5 && code_changes? && !test_changes? + warn 'This Pull Request is probably missing tests.' +end diff --git a/Gemfile b/Gemfile deleted file mode 100644 index 7a6aeaeb..00000000 --- a/Gemfile +++ /dev/null @@ -1,21 +0,0 @@ -source "https://rubygems.org" - -chef_version = ENV.fetch("CHEF_VERSION", "12.3.0") - -gem "chef", "~> #{chef_version}" -gem "chefspec", "~> 4.2.0" -gem "chef-vault", "~> 2.6.0" - -gem "berkshelf", "~> 3.2.4" -gem "foodcritic", "~> 4.0.0" -gem "license_finder", "~> 2.0.4" -gem "rake", "~> 10.4.2" -gem "rubocop", "~> 0.31.0" -gem "serverspec", "~> 2.17.0" - -group :integration do - gem "busser-serverspec", "~> 0.5.6" - gem "kitchen-docker", "~> 2.1.0" - gem "kitchen-sync", "~> 1.0.1" - gem "test-kitchen", "~> 1.4.0" -end diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..8dada3ed --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index b3d06e01..00000000 --- a/LICENSE.txt +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) -Copyright (c) 2012-2015 Phil Cohen - -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/README.md b/README.md index e8b50a5e..30d43ece 100644 --- a/README.md +++ b/README.md @@ -1,103 +1,88 @@ -# chef-percona - -## Flair +# Percona Cookbook [![Cookbook Version](https://img.shields.io/cookbook/v/percona.svg)](https://supermarket.chef.io/cookbooks/percona) -[![License](https://img.shields.io/badge/license-MIT-blue.svg)](http://phlipper.mit-license.org/2012-2015/license.html) -[![Build Status](http://img.shields.io/travis-ci/phlipper/chef-percona.png)](https://travis-ci.org/phlipper/chef-percona) -[![Code Climate](https://codeclimate.com/github/phlipper/chef-percona.png)](https://codeclimate.com/github/phlipper/chef-percona) -[![Gitter](https://img.shields.io/badge/Gitter%2Eim-Join_Chat_→-yellow.svg)](https://gitter.im/phlipper/chef-percona) -![It Works On My Machine™](https://img.shields.io/badge/It_Works-On_My_Machine%E2%84%A2-orange.svg) -[![Tip](http://img.shields.io/gratipay/phlipper.png)](https://gratipay.com/phlipper/) -[![Endorse](http://api.coderwall.com/phlipper/endorsecount.png)](http://coderwall.com/phlipper) +[![OpenCollective](https://opencollective.com/sous-chefs/backers/badge.svg)](#backers) +[![OpenCollective](https://opencollective.com/sous-chefs/sponsors/badge.svg)](#sponsors) +[![License](https://img.shields.io/badge/License-Apache%202.0-green.svg)](https://opensource.org/licenses/Apache-2.0) ## Description -Installs the [Percona -MySQL](http://www.percona.com/software/percona-server) client and/or -server components. (We are attempting to leverage the official Opscode +Installs the [Percona MySQL](http://www.percona.com/software/percona-server) client and/or +server components. (We are attempting to leverage the Sous-Chefs MySQL cookbook as much as possible.) Optionally installs: -* [XtraBackup](http://www.percona.com/software/percona-xtrabackup/) hot backup software -* [Percona Toolkit](http://www.percona.com/software/percona-toolkit/) advanced command-line tools -* [XtraDB -Cluster](http://www.percona.com/software/percona-xtradb-cluster/) high -availability and high scalability solution for MySQL. -* [Percona Monitoring Plugins](http://www.percona.com/software/percona-monitoring-plugins) various Nagios plugins for monitoring MySQL +- [XtraBackup](https://www.percona.com/software/mysql-database/percona-xtrabackup) hot backup software +- [Percona Toolkit](https://www.percona.com/software/database-tools/percona-toolkit) advanced command-line tools +- [XtraDB Cluster](https://www.percona.com/software/mysql-database/percona-xtradb-cluster) high availability and high scalability solution for MySQL. -## Requirements +## Maintainers -### Supported Platforms +This cookbook is maintained by the Sous Chefs. The Sous Chefs are a community of Chef cookbook maintainers working together to maintain important cookbooks. If you’d like to know more please visit [sous-chefs.org](https://sous-chefs.org/) or come chat with us on the Chef Community Slack in [#sous-chefs](https://chefcommunity.slack.com/messages/C2V7B88SF). -We provide an expanding set of tests against the following 64-bit platforms: +## Requirements -* Amazon 2014.03 -* CentOS 6.5 -* CentOS 7.0 -* Debian 7.8 -* Ubuntu 12.04 LTS -* Ubuntu 14.04 LTS +### Supported Platforms -Although we don't test against all possible platform verions, we expect -the following to be supported. Please submit an issue if this is not the -cause, and we'll make reasonable efforts to improve support: +We provide an expanding set of tests against the following 64-bit platforms which match what upstream supports: -* Ubuntu -* Debian -* Amazon Linux AMI -* CentOS -* Red Hat -* Scientific -* Fedora +- CentOS 7+ +- Debian 10+ +- Ubuntu 18.04+ LTS ### Cookbooks -* [apt](https://supermarket.getchef.com/cookbooks/apt) Chef LWRP Cookbook -* [openssl](https://supermarket.getchef.com/cookbooks/openssl) Chef Cookbook -* [yum](https://supermarket.getchef.com/cookbooks/yum) Chef LWRP Cookbook -* [yum-epel](https://supermarket.getchef.com/cookbooks/yum-epel) Chef LWRP Cookbook +- [yum-epel](https://supermarket.chef.io/cookbooks/yum-epel) +- [line](https://supermarket.chef.io/cookbooks/line) ### Chef -This cookbook requires Chef >= 11.14.2 due to the use of the `sensitive` attribute for some resources. +This cookbook requires Chef >= 16. -We aim to test the most recent releases of Chef. You can view -the [currently tested versions](https://github.com/phlipper/chef-percona/blob/master/.travis.yml). -(Feel free to submit a pull request if they're out of date!) +## Recipes +- `percona` - The default which includes the client recipe. +- `percona::package_repo` - Sets up the package repository and installs common packages. +- `percona::client` - Installs the Percona MySQL client libraries. +- `percona::server` - Installs and configures the Percona MySQL server daemon. +- `percona::backup` - Installs and configures the Percona XtraBackup hot backup software. +- `percona::toolkit` - Installs the Percona Toolkit software +- `percona::cluster` - Installs the Percona XtraDB Cluster server components +- `percona::configure_server` - Used internally to manage the server configuration. +- `percona::replication` - Used internally to grant permissions for replication. +- `percona::access_grants` - Used internally to grant permissions for recipes. +- `percona::ssl` - Used internally to setup ssl certificates for server/client. -## Recipes +## Resources -* `percona` - The default no-op recipe. -* `percona::package_repo` - Sets up the package repository and installs common packages. -* `percona::client` - Installs the Percona MySQL client libraries. -* `percona::server` - Installs and configures the Percona MySQL server daemon. -* `percona::backup` - Installs and configures the Percona XtraBackup hot backup software. -* `percona::toolkit` - Installs the Percona Toolkit software -* `percona::cluster` - Installs the Percona XtraDB Cluster server components -* `percona::configure_server` - Used internally to manage the server configuration. -* `percona::replication` - Used internally to grant permissions for replication. -* `percona::access_grants` - Used internally to grant permissions for recipes. -* `percona::monitoring` - Installs Percona monitoring plugins for Nagios +- [`percona_mysql_user`](https://github.com/sous-chefs/percona/blob/master/documentation/resource_percona_mysql_user.md) +- [`percona_mysql_database`](https://github.com/sous-chefs/percona/blob/master/documentation/resource_percona_mysql_database.md) ## Usage -This cookbook installs the Percona MySQL components if not present, and pulls updates if they are installed on the system. +This cookbook installs the Percona MySQL components if not present, and pulls updates if they are installed on the +system. + +This cookbook uses inclusion terminology where applicable replacing terms such as ``master/slave`` to ``source/replica`` +which matches the [terminology decided upstream](https://mysqlhighavailability.com/mysql-terminology-updates/). Older +releases of Percona still use the terms in their configuration so those will remain, however we will be using the newer +terms with attributes, property and variable names. Currently both terms should work however the next major release of +this cookbook will only use the new terminology. ### Encrypted Passwords -This cookbook requires [Encrypted Data Bags](http://wiki.opscode.com/display/chef/Encrypted+Data+Bags). If you forget to use them or do not use a node attribute to overwrite them empty passwords will be used. +This cookbook requires [Encrypted Data Bags](https://docs.chef.io/secrets/#encrypt-a-data-bag-item). If you forget to use them or do not use a node attribute to overwrite them empty passwords will be used. -To use encrypted passwords, you must create an encrypted data bag. This cookbook assumes a data bag named `passwords`, but you can override the name using the `node[:percona][:encrypted_data_bag]` attribute. You can also optionally specify a data bag secret file to be loaded for the secret key using the `node[:percona][:encrypted_data_bag_secret_file]` attribute. +To use encrypted passwords, you must create an encrypted data bag. This cookbook assumes a data bag named `passwords`, but you can override the name using the `node['percona']['encrypted_data_bag']` attribute. You can also optionally specify a data bag secret file to be loaded for the secret key using the `node['percona']['encrypted_data_bag_secret_file']` attribute. This cookbook expects a `mysql` item and a `system` item. Please refer to the official documentation on how to get this setup. It actually uses a MySQL example so it can be mostly copied. Ensure you cover the data bag items as described below. -You also may set expected item names via attributes `node["percona"]["encrypted_data_bag_item_mysql"]` and `node["percona"]["encrypted_data_bag_item_system"]`. +You also may set expected item names via attributes `node['percona']['encrypted_data_bag_item_mysql']` and `node['percona']['encrypted_data_bag_item_system']`. ### Skip passwords -Set the `["percona"]["skip_passwords"]` attribute to skip setting up passwords. Removes the need for the encrypted data bag if using chef-solo. Is useful for setting up development and ci environments where you just want to use the root user with no password. If you are doing this you may want to set `[:percona][:server][:debian_username]` to be `"root"` also. + +Set the `['percona']['skip_passwords']` attribute to skip setting up passwords. Removes the need for the encrypted data bag if using chef-solo. Is useful for setting up development and ci environments where you just want to use the root user with no password. If you are doing this you may want to set `['percona']['server']['debian_username']` to be `"root"` also. ### Skip Configure @@ -109,9 +94,9 @@ The mysql item should contain entries for root, backup, and replication. If no v #### system item -The "system" item should contain an entry for the debian system user as specified in the `node[:percona][:server][:debian_username]` attribute. If no such entry is found, the cookbook will fall back to the default non-encrypted password. +The "system" item should contain an entry for the debian system user as specified in the `node['percona']['server']['debian_username']` attribute. If no such entry is found, the cookbook will fall back to the default non-encrypted password. -Example: "passwords" data bag - this example assumes that `node[:percona][:server][:debian_username] = spud` +Example: "passwords" data bag - this example assumes that `node['percona']['server']['debian_username'] = spud` ```javascript { @@ -130,9 +115,14 @@ Example: "passwords" data bag - this example assumes that `node[:percona][:serve Above shows the encrypted password in the data bag. Check out the `encrypted_data_bag_secret` setting in `knife.rb` to setup your data bag secret during bootstrapping. +### Install client development package + +To install the package including header files needed to compile software using the client library (`percona-server-devel` on Centos and `libperconaserverclient-dev` on Debian), set `node['percona']['client']['install_devel_package']` to `true`. This will add those packages to the list to be installed when running the `percona::client` recipe. This attribute is disabled by default. + ### Replication over SSL -To enable SSL based replication, you will need to flip the attribute `node[:percona][:server][:replication][:ssl_enabled]` to `true` and add a new data_bag item -to the percona encrypted data_bag (see`node[:percona][:encrypted_data_bag]` attribute) with the id `ssl_replication` ( see `node["percona"]["encrypted_data_bag_item_ssl_replication"]` attribute) that contains this data: + +To enable SSL based replication, you will need to flip the attribute `node['percona']['server']['replication']['ssl_enabled']` to `true` and add a new data\_bag item +to the percona encrypted data\_bag (see`node['percona']['encrypted_data_bag']` attribute) with the id `ssl_replication` ( see `node['percona']['encrypted_data_bag_item_ssl_replication']` attribute) that contains this data: ```javascript { @@ -148,12 +138,13 @@ to the percona encrypted data_bag (see`node[:percona][:encrypted_data_bag]` attr } } ``` -All certificates and keys have to be converted to a string (easiest way is to use ruby: */usr/bin/env ruby -e 'p ARGF.read'* **filename**) and placed + +All certificates and keys have to be converted to a string (easiest way is to use ruby: `/usr/bin/env ruby -e 'p ARGF.read' `) and placed instead of CA_CERTIFICATE_STRING, SERVER_CERTIFICATE_STRING, SERVER_KEY_STRING, CLIENT_CERTIFICATE_STRING, CLIENT_KEY_STRING. ### Percona XtraDB Cluster -Below is a minimal example setup to bootstrap a Percona XtraDB Cluster. Please see the [official documentation](http://www.percona.com/doc/percona-xtradb-cluster/5.6/index.html) for more information. This is not a perfect example. It is just a sample to get you started. +Below is a minimal example setup to bootstrap a Percona XtraDB Cluster. Please see the [official documentation](https://www.percona.com/doc/percona-xtradb-cluster/8.0/index.html) for more information. This is not a perfect example. It is just a sample to get you started. Wrapper recipe recipes/percona.rb: @@ -190,8 +181,8 @@ end cluster_address = "gcomm://#{cluster_ips.join(',')}" Chef::Log.info "Using Percona XtraDB cluster address of: #{cluster_address}" -node.override["percona"]["cluster"]["wsrep_cluster_address"] = cluster_address -node.override["percona"]["cluster"]["wsrep_node_name"] = node['hostname'] +node.override['percona']['cluster']['wsrep_cluster_address'] = cluster_address +node.override['percona']['cluster']['wsrep_node_name'] = node['hostname'] include_recipe 'percona::cluster' include_recipe 'percona::backup' @@ -223,279 +214,19 @@ default_attributes( Now you need to bring three servers up one at a time with the percona role applied to them. By default the servers will sync up via rsync server state transfer (SST) -## Attributes - -```ruby -default["percona"]["version"] = "5.6" -version = node["percona"]["version"] - -# Always restart percona on configuration changes -default["percona"]["auto_restart"] = true - -case node["platform_family"] -when "debian" - default["percona"]["server"]["socket"] = "/var/run/mysqld/mysqld.sock" - default["percona"]["server"]["default_storage_engine"] = "InnoDB" - default["percona"]["server"]["includedir"] = "/etc/mysql/conf.d/" - default["percona"]["server"]["pidfile"] = "/var/run/mysqld/mysqld.pid" - default["percona"]["server"]["package"] = "percona-server-server-#{version}" -when "rhel" - default["percona"]["server"]["socket"] = "/var/lib/mysql/mysql.sock" - default["percona"]["server"]["default_storage_engine"] = "innodb" - default["percona"]["server"]["includedir"] = "" - default["percona"]["server"]["pidfile"] = "/var/lib/mysql/mysqld.pid" - default["percona"]["server"]["package"] = "Percona-Server-server-#{version.tr(".", "")}" - default["percona"]["server"]["shared_pkg"] = "Percona-Server-shared-#{version.tr(".", "")}" -end - -# Cookbook Settings -default["percona"]["main_config_file"] = value_for_platform_family( - "debian" => "/etc/mysql/my.cnf", - "rhel" => "/etc/my.cnf" -) -default["percona"]["apt"]["keyserver"] = "hkp://keys.gnupg.net:80" -default["percona"]["encrypted_data_bag"] = "passwords" -default["percona"]["encrypted_data_bag_secret_file"] = "" -default["percona"]["use_chef_vault"] = false -default["percona"]["skip_passwords"] = false -default["percona"]["skip_configure"] = false - -# Start percona server on boot -default["percona"]["server"]["enable"] = true - -# install vs. upgrade packages -default["percona"]["server"]["package_action"] = "install" - -# Basic Settings -default["percona"]["server"]["role"] = ["standalone"] -default["percona"]["server"]["username"] = "mysql" -default["percona"]["server"]["datadir"] = "/var/lib/mysql" -default["percona"]["server"]["logdir"] = "/var/log/mysql" -default["percona"]["server"]["tmpdir"] = "/tmp" -default["percona"]["server"]["slave_load_tmpdir"] = "/tmp" -default["percona"]["server"]["debian_username"] = "debian-sys-maint" -default["percona"]["server"]["jemalloc"] = false -default["percona"]["server"]["jemalloc_lib"] = value_for_platform_family( - "debian" => value_for_platform( - "ubuntu" => { - "trusty" => "/usr/lib/x86_64-linux-gnu/libjemalloc.so.1", - "precise" => "/usr/lib/libjemalloc.so.1" - } - ), - "rhel" => "/usr/lib64/libjemalloc.so.1" -) -default["percona"]["server"]["nice"] = 0 -default["percona"]["server"]["open_files_limit"] = 16_384 -default["percona"]["server"]["hostname"] = "localhost" -default["percona"]["server"]["basedir"] = "/usr" -default["percona"]["server"]["port"] = 3306 -default["percona"]["server"]["language"] = "/usr/share/mysql/english" -default["percona"]["server"]["character_set"] = "utf8" -default["percona"]["server"]["collation"] = "utf8_unicode_ci" -default["percona"]["server"]["skip_name_resolve"] = false -default["percona"]["server"]["skip_external_locking"] = true -default["percona"]["server"]["net_read_timeout"] = 120 -default["percona"]["server"]["connect_timeout"] = 10 -default["percona"]["server"]["wait_timeout"] = 28_800 -default["percona"]["server"]["old_passwords"] = 0 -default["percona"]["server"]["bind_address"] = "127.0.0.1" -default["percona"]["server"]["federated"] = false - -%w[debian_password root_password].each do |attribute| - next if attribute?(node["percona"]["server"][attribute]) - default["percona"]["server"][attribute] = secure_password -end - -# Fine Tuning -default["percona"]["server"]["key_buffer_size"] = "16M" -default["percona"]["server"]["max_allowed_packet"] = "64M" -default["percona"]["server"]["thread_stack"] = "192K" -default["percona"]["server"]["query_alloc_block_size"] = "16K" -default["percona"]["server"]["memlock"] = false -default["percona"]["server"]["transaction_isolation"] = "REPEATABLE-READ" -default["percona"]["server"]["tmp_table_size"] = "64M" -default["percona"]["server"]["max_heap_table_size"] = "64M" -default["percona"]["server"]["sort_buffer_size"] = "8M" -default["percona"]["server"]["join_buffer_size"] = "8M" -default["percona"]["server"]["thread_cache_size"] = 16 -default["percona"]["server"]["back_log"] = 50 -default["percona"]["server"]["max_connections"] = 30 -default["percona"]["server"]["max_connect_errors"] = 9_999_999 -default["percona"]["server"]["sql_modes"] = [] -default["percona"]["server"]["table_cache"] = 8192 -default["percona"]["server"]["group_concat_max_len"] = 4096 -default["percona"]["server"]["expand_fast_index_creation"] = false -default["percona"]["server"]["read_rnd_buffer_size"] = 262_144 - -# Query Cache Configuration -default["percona"]["server"]["query_cache_size"] = "64M" -default["percona"]["server"]["query_cache_limit"] = "2M" - -# Logging and Replication -default["percona"]["server"]["sync_binlog"] = (node["percona"]["server"]["role"] == "cluster" ? 0 : 1) -default["percona"]["server"]["slow_query_log"] = 1 -default["percona"]["server"]["slow_query_logdir"] = "/var/log/mysql" -default["percona"]["server"]["slow_query_log_file"] = "#{node["percona"]["server"]["slow_query_logdir"]}/mysql-slow.log" -default["percona"]["server"]["long_query_time"] = 2 -default["percona"]["server"]["server_id"] = 1 -default["percona"]["server"]["binlog_do_db"] = [] -default["percona"]["server"]["binlog_ignore_db"] = [] -default["percona"]["server"]["expire_logs_days"] = 10 -default["percona"]["server"]["max_binlog_size"] = "100M" -default["percona"]["server"]["binlog_cache_size"] = "1M" -default["percona"]["server"]["binlog_space_limit"] = 0 -default["percona"]["server"]["binlog_format"] = "MIXED" -default["percona"]["server"]["log_bin"] = "master-bin" -default["percona"]["server"]["relay_log"] = "slave-relay-bin" -default["percona"]["server"]["log_slave_updates"] = false -default["percona"]["server"]["log_warnings"] = true -default["percona"]["server"]["log_long_format"] = false -default["percona"]["server"]["bulk_insert_buffer_size"] = "64M" - -# MyISAM Specific -default["percona"]["server"]["myisam_recover_options"] = "BACKUP" -default["percona"]["server"]["myisam_sort_buffer_size"] = "128M" -default["percona"]["server"]["myisam_max_sort_file_size"] = "10G" -default["percona"]["server"]["myisam_repair_threads"] = 1 -default["percona"]["server"]["read_buffer_size"] = "8M" - -# InnoDB Specific -default["percona"]["server"]["skip_innodb"] = false -default["percona"]["server"]["innodb_additional_mem_pool_size"] = "32M" -default["percona"]["server"]["innodb_buffer_pool_size"] = "128M" -default["percona"]["server"]["innodb_data_file_path"] = "ibdata1:10M:autoextend" -default["percona"]["server"]["innodb_autoextend_increment"] = "128M" -default["percona"]["server"]["innodb_open_files"] = 2000 -default["percona"]["server"]["innodb_file_per_table"] = true -default["percona"]["server"]["innodb_file_format"] = "Antelope" -default["percona"]["server"]["innodb_data_home_dir"] = "" -default["percona"]["server"]["innodb_thread_concurrency"] = 16 -default["percona"]["server"]["innodb_flush_log_at_trx_commit"] = 1 -default["percona"]["server"]["innodb_fast_shutdown"] = false -default["percona"]["server"]["innodb_log_buffer_size"] = "64M" -default["percona"]["server"]["innodb_log_file_size"] = "5M" -default["percona"]["server"]["innodb_log_files_in_group"] = 2 -default["percona"]["server"]["innodb_max_dirty_pages_pct"] = 80 -default["percona"]["server"]["innodb_flush_method"] = "O_DIRECT" -default["percona"]["server"]["innodb_lock_wait_timeout"] = 120 -default["percona"]["server"]["innodb_import_table_from_xtrabackup"] = 0 - -# Performance Schema -default["percona"]["server"]["performance_schema"] = false - -# Replication Settings -default["percona"]["server"]["replication"]["read_only"] = false -default["percona"]["server"]["replication"]["host"] = "" -default["percona"]["server"]["replication"]["username"] = "" -default["percona"]["server"]["replication"]["password"] = "" -default["percona"]["server"]["replication"]["port"] = 3306 -default["percona"]["server"]["replication"]["ignore_db"] = [] -default["percona"]["server"]["replication"]["ignore_table"] = [] -default["percona"]["server"]["replication"]["ssl_enabled"] = false -default["percona"]["server"]["replication"]["suppress_1592"] = false -default["percona"]["server"]["replication"]["skip_slave_start"] = false -default["percona"]["server"]["replication"]["slave_transaction_retries"] = 10 - -# XtraBackup Settings -default["percona"]["backup"]["configure"] = false -default["percona"]["backup"]["username"] = "backup" -unless attribute?(node["percona"]["backup"]["password"]) - default["percona"]["backup"]["password"] = secure_password -end - -# XtraDB Cluster Settings -default["percona"]["cluster"]["package"] = value_for_platform_family( - "debian" => "percona-xtradb-cluster-#{version.tr(".", "")}", - "rhel" => "Percona-XtraDB-Cluster-#{version.tr(".", "")}" -) -default["percona"]["cluster"]["binlog_format"] = "ROW" -default["percona"]["cluster"]["wsrep_provider"] = value_for_platform_family( - "debian" => "/usr/lib/libgalera_smm.so", - "rhel" => "/usr/lib64/libgalera_smm.so" -) -default["percona"]["cluster"]["wsrep_retry_autocommit"] = 1 -default["percona"]["cluster"]["wsrep_provider_options"] = "" -default["percona"]["cluster"]["wsrep_cluster_address"] = "" -default["percona"]["cluster"]["wsrep_slave_threads"] = 2 -default["percona"]["cluster"]["wsrep_cluster_name"] = "" -default["percona"]["cluster"]["wsrep_sst_method"] = "rsync" -default["percona"]["cluster"]["wsrep_node_name"] = "" -default["percona"]["cluster"]["wsrep_notify_cmd"] = "" -default["percona"]["cluster"]["wsrep_sst_auth"] = "" - -# These both are used to build wsrep_sst_receive_address -default["percona"]["cluster"]["wsrep_sst_receive_interface"] = nil # Works like node["percona"]["server"]["bind_to"] -default["percona"]["cluster"]["wsrep_sst_receive_port"] = "4444" - -default["percona"]["cluster"]["innodb_locks_unsafe_for_binlog"] = 1 -default["percona"]["cluster"]["innodb_autoinc_lock_mode"] = 2 -``` - -### client.rb - -```ruby -# install vs. upgrade packages -default["percona"]["client"]["package_action"] = "install" - -version = value_for_platform_family( - "debian" => node["percona"]["version"], - "rhel" => node["percona"]["version"].tr(".", "") -) - -case node["platform_family"] -when "debian" - abi_version = case version - when "5.5" then "18" - when "5.6" then "18.1" - else "" - end - - default["percona"]["client"]["packages"] = %W[ - libperconaserverclient#{abi_version}-dev percona-server-client-#{version} - ] -when "rhel" - if Array(node["percona"]["server"]["role"]).include?("cluster") - default["percona"]["client"]["packages"] = %W[ - Percona-XtraDB-Cluster-devel-#{version} Percona-XtraDB-Cluster-client-#{version} - ] - else - default["percona"]["client"]["packages"] = %W[ - Percona-Server-devel-#{version} Percona-Server-client-#{version} - ] - end -end -``` - -### monitoring.rb - -```ruby -default["percona"]["plugins_version"] = "1.1.3" -default["percona"]["plugins_packages"] = %w[percona-nagios-plugins percona-zabbix-templates percona-cacti-templates] -``` - -### package_repo.rb - -```ruby -default["percona"]["yum"]["description"] = "Percona Packages" -default["percona"]["yum"]["baseurl"] = "http://repo.percona.com/centos/#{pversion}/os/#{arch}/" -default["percona"]["yum"]["gpgkey"] = "http://www.percona.com/downloads/RPM-GPG-KEY-percona" -default["percona"]["yum"]["gpgcheck"] = true -default["percona"]["yum"]["sslverify"] = true -``` - ## Explicit my.cnf templating -In some situation it is preferable to explicitly define the attributes needed in a `my.cnf` file. This is enabled by adding categories to the `node[:percona][:conf]` attributes. All keys found in the `node[:percona][:conf]` map will represent categories in the `my.cnf` file. Each category contains a map of attributes that will be written to the `my.cnf` file for that category. See the example for more details. +In some situations it is preferable to explicitly define the attributes needed in a `my.cnf` file. This is enabled by adding categories to the `node['percona']['conf']` attributes. All keys found in the `node['percona']['conf']` map will represent categories in the `my.cnf` file. Each category contains a map of attributes that will be written to the `my.cnf` file for that category. See the example for more details. -### Example: +### Example ```ruby -node["percona"]["conf"]["mysqld"]["slow_query_log_file"] = "/var/lib/mysql/data/mysql-slow.log" +node['percona']['conf']['mysqld']['slow_query_log_file'] = "/var/lib/mysql/data/mysql-slow.log" ``` This configuration would write the `mysqld` category to the `my.cnf` file and have an attribute `slow_query_log_file` whose value would be `/var/lib/mysql/data/mysql-slow.log`. -### Example output (my.cnf): +### Example output (my.cnf) ```ini [mysqld] @@ -504,258 +235,55 @@ slow_query_log_file = /var/lib/mysql/data/mysql-slow.log ## Dynamically setting the bind address -There's a special attribute `node["percona"]["server"]["bind_to"]` that allows you to dynamically set the bind address. This attribute accepts the values `"public_ip"`, `"private_ip"`, `"loopback"`, or and interface name like `"eth0"`. Based on this, the recipe will find a corresponding ipv4 address, and override the `node["percona"]["server"]["bind_address"]` attribute. +There's a special attribute `node['percona']['server']['bind_to']` that allows you to dynamically set the bind address. This attribute accepts the values `"public_ip"`, `"private_ip"`, `"loopback"`, or and interface name like `"eth0"`. Based on this, the recipe will find a corresponding ipv4 address, and override the `node['percona']['server']['bind_address']` attribute. -## MySQL Gems +## Goals -This cookbook provides a MySQL and MySQL2 gem installer specifically designed for -use with Percona. Since they share namespaces with other providers you most -likely want to call them directly targeting the provider, example provided below: +In no particular order: -```ruby -mysql2_chef_gem 'default' do - provider Chef::Provider::Mysql2ChefGem::Percona - action :install -end +- Be the most flexible way to setup a MySQL distribution through Chef + - Support for Chef Solo + - Support for Chef Server +- Support the following common database infrastructures: + - Single server instance + - Traditional Source/Replica replication + - Multi-source cluster replication +- Support the most recent Chef runtime environments +- Be the easiest way to setup a MySQL distribution through Chef -mysql_chef_gem 'default' do - provider Chef::Provider::MysqlChefGem::Percona - action :install -end -``` +## TODO -Also keep in mind that since these providers are subclasses of the mysql_chef_gem -and mysql2_chef_gem cookbooks they need to be added to your metadata.rb file as -depends to ensure they pull in the needed resource files. +- Fully support all of the standard Chef-supported distributions -## Goals +## Contributing -In no particular order: +- Fork it +- Create your feature branch (`git checkout -b my-new-feature`) +- Commit your changes (`git commit -am 'Added some feature'`) +- Push to the branch (`git push origin my-new-feature`) +- Create new Pull Request -* Be the most flexible way to setup a MySQL distribution through Chef - * Support for Chef Solo - * Support for Chef Server -* Support the following common database infrastructures: - * Single server instance - * Traditional Master/Slave replication - * Multi-master cluster replication -* Support the most recent Chef runtime environments -* Be the easiest way to setup a MySQL distribution through Chef +## Contributors +This project exists thanks to all the people who [contribute.](https://opencollective.com/sous-chefs/contributors.svg?width=890&button=false) -## TODO +### Backers -* Fully support all of the standard Chef-supported distributions +Thank you to all our backers! +![https://opencollective.com/sous-chefs#backers](https://opencollective.com/sous-chefs/backers.svg?width=600&avatarHeight=40) -## Contributing - -1. Fork it -2. Create your feature branch (`git checkout -b my-new-feature`) -3. Commit your changes (`git commit -am 'Added some feature'`) -4. Push to the branch (`git push origin my-new-feature`) -5. Create new Pull Request +### Sponsors -## Contributors +Support this project by becoming a sponsor. Your logo will show up here with a link to your website. -Many thanks go to the following [contributors](https://github.com/phlipper/chef-percona/graphs/contributors) who have helped to make this cookbook even better: - -* **[@jagcrete](https://github.com/jagcrete)** - * configurable keyserver - * encrypted password data bag - * custom `my.cnf` file -* **[@pwelch](https://github.com/pwelch)** - * ensure cookbook dependencies are loaded - * [Foodcritic](http://acrmp.github.com/foodcritic/) compliance updates - * various minor patches and updates -* **[@masv](https://github.com/masv)** - * compatibility updates for 5.5 -* **[@stottsan](https://github.com/stottsan)** - * config cleanup to prevent service restarts on chef run -* **[@abecciu](https://github.com/abecciu)** - * auto-generate secure passwords by default - * add ability to dynamically set the bind address - * add support for `main_config_file` attribute -* **[@patcon](https://github.com/patcon)** - * add `yum` support for `centos`, `amazon`, `scientific`, `fedora`, and `redhat` distributions -* **[@psi](https://github.com/psi)** - * fixes required for RedHat platforms -* **[@TheSerapher](https://github.com/TheSerapher)** - * improvements for master/slave replication setup - * updates and clarifications to the README - * add attribute to control server restart on config changes -* **[@bensomers](https://github.com/bensomers)** - * minor fixes to `replication.sql` - * fix a very dangerous bug around binlog-do-db setting for slave servers - * fix slow query log setting for 5.5 -* **[@tdg5](https://github.com/tdg5)** - * avoid use of `set_unless` for chef-solo, workaround for CHEF-2945 -* **[@gpendler](https://github.com/gpendler)** - * avoid re-installation of packages RedHat platforms -* **[@vinu](https://github.com/vinu)** - * pin the percona apt repo with high priority -* **[@ckuttruff](https://github.com/ckuttruff)** - * improve security on debian-based systems by changing config file permissions - * don't pass mysql root password in plaintext commands - * fix issue with -p flag when setting initial password -* **[@srodrig0209](https://github.com/srodrig0209)** - * add the `monitoring` recipe -* **[@jesseadams](https://github.com/jesseadams)** - * fixes for custom datadir setting use case - * add more Percona XtraDB cluster options - * XtraDB cluster support for replication over ssl -* **[@see0](https://github.com/see0)** - * fix incorrect root password reference -* **[@baldur](https://github.com/baldur)** - * _(honorable mention)_ fix incorrect root password reference - * fix typo in attribute for server username -* **[@chrisroberts](https://github.com/chrisroberts)** - * _(honorable mention)_ fix issue with -p flag when setting initial password -* **[@aaronjensen](https://github.com/aaronjensen)** - * allow server to not be started on startup -* **[@pioneerit](https://github.com/pioneerit)** - * add sections to `.my.cnf` for `mysqladmin` and `mysqldump` -* **[@AndreyChernyh](https://github.com/AndreyChernyh)** - * use resources helper to support newer chef versions -* **[@avit](https://github.com/avit)** - * add default utf8 character set option - * cleanup replication support - * remove dependency on opscode/mysql cookbook - * fix permissions for configuration files -* **[@alexzorin](https://github.com/alexzorin)** - * add support for `skip-name-resolve` option -* **[@jyotty](https://github.com/jyotty)** - * specify `binlog_format` in master and slave roles -* **[@adamdunkley](https://github.com/adamdunkley)** - * fix `table_cache` variable for mysql versions 5.6 and above - * remove unnecessary rewind, perform it directly -* **[@freerobby](https://github.com/freerobby)** - * add requirements to `Berksfile` - * more flexible apt dependency version to minimize conflicts -* **[@spovich](https://github.com/spovich)** - * disable `old_passwords` support by default - * force version 5.5 on Debian family to maintain consistency with RHEL family -* **[@v1nc3ntlaw](https://github.com/v1nc3ntlaw)** - * add attribute `innodb_file_format` - * add attribute `ignore_db` for slave template -* **[@joegaudet](https://github.com/joegaudet)** - * add attribute `group_concat_max_len` -* **[@mikesmullin](https://github.com/mikesmullin)** - * accumulating patches from multiple sources - * tempdir fixes -* **[@totally](https://github.com/totally)** - * support `yum` cookbook v3.0 - * use attributes for package names -* **[@sapunoff](https://github.com/sapunoff)** - * initial implementation of using attributes for package names -* **[@errm](https://github.com/errm)** - * add attribute `skip_passwords` -* **[@ewr](https://github.com/ewr)** - * fix mysql calls when there is no root password -* **[@jharley](https://github.com/jharley)** - * make `connect_timeout` configurable - * add cluster support for `wsrep_sst_auth` configuration - * update default for `wsrep_provider` on Debian - * enable InnoDB tuning for standalone and cluster - * set proper `my.cnf` location based on platform family - * add missing tunables to 'cluster' `my.cnf` template - * fix regression in cluster configuration template - * centralize `jemalloc` configuration for cluster and server configurations - * sync cluster configuration file with main configuration - * add `innodb_autoextend_increment` and `innodb_open_files` attributes - * fix cluster template regression -* **[@achied](https://github.com/achied)** - * fix setting passwords if attribute not defined -* **[@akshah123](https://github.com/akshah123)** - * force client packages to install version 5.5 -* **[@tkuhlman](https://github.com/tkuhlman)** - * re-add cluster support -* **[@mancdaz](https://github.com/mancdaz)** - * install monitoring plugins from package instead of tarball -* **[@iancoffey](https://github.com/iancoffey)** - * set debian-sys-maint password after grant - * add attribute `skip_configure` -* **[@notnmeyer](https://github.com/notnmeyer)** - * fix `access_grants` guards for `cluster` and `backup` recipes -* **[@odacrem](https://github.com/odacrem)** - * use correct replication username in `replication.sql` -* **[@g3kk0](https://github.com/g3kk0)** - * fix missing mysql log directory - * add attribute `wait_timeout` - * data-drive percona yum repository - * add support for `jemalloc` - * fix idempotency with chef-solo and `skip_password` attribute - * add attribute `expand_fast_index_creation` -* **[@gfloyd](https://github.com/gfloyd)** - * honor `skip_configure` attribute in cluster recipe -* **[@paustin01](https://github.com/paustin01)** - * add `encrypted_data_bag_secret_file` attribute -* **[@ajardan](https://github.com/ajardan)** - * support master-master replication in the `replication_master.sql` template - * extend master-master capabilities and add ssl support -* **[@realloc](https://github.com/realloc)** - * add `mysql2` gem provider - * add ability to set data bag item names using attributes -* **[@tbunnyman](https://github.com/tbunnyman)** - * make `ignore_db` attribute into an array & add matching `ignore_table` attribute - * add `suppress_1592` replication attribute - * add `sql_modes` attribute -* **[@mzdrale](https://github.com/mzdrale)** - * fix cluster package name on RHEL systems -* **[@Sauraus](https://github.com/Sauraus)** - * fix cluster dependency package installation on RHEL systems - * fix `slow_query_logdir` path creation -* **[@jim80net](https://github.com/jim80net)** - * fix toolkit installation for version 5.6 on RHEL systems -* **[@helgi](https://github.com/helgi)** - * use `mysql` command vs. a file to check the root password - * generate configuration file before setting up data directory - * ensure `includedir` is created if provided - * add attribute `performance_schema` - * fix mysql root password update check -* **[@arnesund](https://github.com/arnesund)** - * fix package list for clusters based on CentOS - * avoid uninstall of `mysql-libs` when not needed - * fix XtraDB Cluster 5.6 installation on CentOS 7 - * add support for `chef-vault` -* **[@n3bulous](https://github.com/n3bulous)** - * add `federated` and `read_rnd_buffer_size` attributes -* **[@runwaldarshu](https://github.com/runwaldarshu)** - * add `sensitive` attribute for resources -* **[@vermut](https://github.com/vermut)** - * fix `ConfigHelper` definitions to make them available from `module_function` -* **[@dng-dev](https://github.com/dng-dev)** - * add `innodb_import_table_from_xtrabackup` attribute -* **[@washingtoneg](https://github.com/washingtoneg)** - * add `myisam_read_buffer_size` attribute -* **[@cmjosh](https://github.com/cmjosh)** - * fix version-dependent package attribute issues -* **[@cybermerc](https://github.com/cybermerc)** - * fix provider superclass mismatch -* **[@drywheat](https://github.com/drywheat)** - * add `skip_slave_start` attribute -* **[@joelhandwell](https://github.com/joelhandwell)** - * fix duplication of slow query log directory creation - * suppress warning CHEF-3694 for log dir -* **[@bitpusher-real](https://github.com/bitpusher-real)** - * add `binlog_ignore_db` attribute - * add version restrictions on three MySQL directives - * only set `old_passwords` only when a value defined - * add `slave_transaction_retries` attribute - * add `slave_load_tmpdir` attribute -* **[@cyberflow](https://github.com/cyberflow)** - * add `replication_sql` attribute -* **[@jklare](https://github.com/jklare)** - * fix cluster specific settings for `my.cnf` and client packages -* **[@whiteley](https://github.com/whiteley)** - * remove duplicated attributes - * namespace apt attributes following yum example - - -## License - -**chef-percona** - -* Freely distributable and licensed under the [MIT license](http://phlipper.mit-license.org/2012-2015/license.html). -* Copyright (c) 2012-2015 Phil Cohen (github@phlippers.net) -* http://phlippers.net/ +![https://opencollective.com/sous-chefs/sponsor/0/website](https://opencollective.com/sous-chefs/sponsor/0/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/1/website](https://opencollective.com/sous-chefs/sponsor/1/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/2/website](https://opencollective.com/sous-chefs/sponsor/2/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/3/website](https://opencollective.com/sous-chefs/sponsor/3/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/4/website](https://opencollective.com/sous-chefs/sponsor/4/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/5/website](https://opencollective.com/sous-chefs/sponsor/5/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/6/website](https://opencollective.com/sous-chefs/sponsor/6/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/7/website](https://opencollective.com/sous-chefs/sponsor/7/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/8/website](https://opencollective.com/sous-chefs/sponsor/8/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/9/website](https://opencollective.com/sous-chefs/sponsor/9/avatar.svg?avatarHeight=100) diff --git a/Rakefile b/Rakefile deleted file mode 100644 index af455346..00000000 --- a/Rakefile +++ /dev/null @@ -1,38 +0,0 @@ -task default: "test" - -desc "Run all tests except `kitchen`" -task test: [:rubocop, :foodcritic, :chefspec] - -desc "Run all tests" -task all_tests: [ - :license_finder, :rubocop, :foodcritic, :chefspec, "kitchen:all" -] - -# license finder -task :license_finder do - sh "bundle exec license_finder --quiet" -end - -# rubocop style checker -require "rubocop/rake_task" -RuboCop::RakeTask.new - -# foodcritic chef lint -require "foodcritic" -FoodCritic::Rake::LintTask.new do |t| - t.options = { fail_tags: ["any"] } -end - -# chefspec unit tests -require "rspec/core/rake_task" -RSpec::Core::RakeTask.new(:chefspec) do |t| - t.rspec_opts = "--color --format progress" -end - -# test-kitchen integration tests -begin - require "kitchen/rake_tasks" - Kitchen::RakeTasks.new -rescue LoadError - task("kitchen:all") { puts "Unable to run `test-kitchen`" } -end diff --git a/TESTING.md b/TESTING.md new file mode 100644 index 00000000..920e381f --- /dev/null +++ b/TESTING.md @@ -0,0 +1,3 @@ +# Testing + +Please refer to [the community cookbook documentation on testing](https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/TESTING.MD). diff --git a/attributes/client.rb b/attributes/client.rb index 6b55105e..0cba4134 100644 --- a/attributes/client.rb +++ b/attributes/client.rb @@ -1,41 +1,9 @@ # -# Cookbook Name:: percona +# Cookbook:: percona # Attributes:: client # # install vs. upgrade packages -default["percona"]["client"]["package_action"] = "install" - -version = value_for_platform_family( - "debian" => node["percona"]["version"], - "rhel" => node["percona"]["version"].tr(".", "") -) - -case node["platform_family"] -when "debian" - abi_version = case version - when "5.5" then "18" - when "5.6" then "18.1" - else "" - end - - if Array(node["percona"]["server"]["role"]).include?("cluster") - default["percona"]["client"]["packages"] = %W[ - libperconaserverclient#{abi_version}-dev percona-xtradb-cluster-client-#{version} - ] - else - default["percona"]["client"]["packages"] = %W[ - libperconaserverclient#{abi_version}-dev percona-server-client-#{version} - ] - end -when "rhel" - if Array(node["percona"]["server"]["role"]).include?("cluster") - default["percona"]["client"]["packages"] = %W[ - Percona-XtraDB-Cluster-devel-#{version} Percona-XtraDB-Cluster-client-#{version} - ] - else - default["percona"]["client"]["packages"] = %W[ - Percona-Server-devel-#{version} Percona-Server-client-#{version} - ] - end -end +default['percona']['client']['package_action'] = 'install' +default['percona']['client']['packages'] = [] +default['percona']['client']['install_devel_package'] = false diff --git a/attributes/default.rb b/attributes/default.rb index 20fad103..906956c5 100644 --- a/attributes/default.rb +++ b/attributes/default.rb @@ -1,218 +1,225 @@ # -# Cookbook Name:: percona +# Cookbook:: percona # Attributes:: default # -# include the openssl cookbook password library -if defined?(::OpenSSLCookbook::RandomPassword) - ::Chef::Node.send(:include, ::OpenSSLCookbook::RandomPassword) -elsif defined?(::Opscode::OpenSSL::Password) - ::Chef::Node.send(:include, ::Opscode::OpenSSL::Password) -elsif defined?(::Chef::OpenSSL::Password) - ::Chef::Node.send(:include, ::Chef::OpenSSL::Password) -end +# include the percona_secure_random method +::Chef::Node.include ::Percona::Cookbook::Helpers -default["percona"]["version"] = "5.7" +default['percona']['version'] = '8.0' # Always restart percona on configuration changes -default["percona"]["auto_restart"] = true - -case node["platform_family"] -when "debian" - default["percona"]["server"]["socket"] = "/var/run/mysqld/mysqld.sock" - default["percona"]["server"]["default_storage_engine"] = "InnoDB" - default["percona"]["server"]["includedir"] = "/etc/mysql/conf.d/" - default["percona"]["server"]["pidfile"] = "/var/run/mysqld/mysqld.pid" -when "rhel" - default["percona"]["server"]["socket"] = "/var/lib/mysql/mysql.sock" - default["percona"]["server"]["default_storage_engine"] = "innodb" - default["percona"]["server"]["includedir"] = "" - default["percona"]["server"]["pidfile"] = "/var/lib/mysql/mysqld.pid" +default['percona']['auto_restart'] = true + +# SELinux module URL +# If interested, use "https://github.com/gguillen/selinux_percona-pxc-56-cluster/raw/master/percona-pxc-56-cluster.pp" +default['percona']['selinux_module_url'] = '' + +case node['platform_family'] +when 'debian' + default['percona']['server']['socket'] = '/var/run/mysqld/mysqld.sock' + default['percona']['server']['default_storage_engine'] = 'InnoDB' + default['percona']['server']['includedir'] = '/etc/mysql/conf.d/' + default['percona']['server']['pidfile'] = '/var/run/mysqld/mysqld.pid' +when 'rhel' + default['percona']['server']['socket'] = '/var/lib/mysql/mysql.sock' + default['percona']['server']['default_storage_engine'] = 'innodb' + default['percona']['server']['includedir'] = '' + default['percona']['server']['pidfile'] = '/var/lib/mysql/mysqld.pid' end # Cookbook Settings -default["percona"]["main_config_file"] = value_for_platform_family( - "debian" => "/etc/mysql/my.cnf", - "rhel" => "/etc/my.cnf" +default['percona']['main_config_file'] = value_for_platform_family( + 'debian' => '/etc/mysql/my.cnf', + 'rhel' => '/etc/my.cnf' ) -default["percona"]["encrypted_data_bag"] = "passwords" -default["percona"]["encrypted_data_bag_secret_file"] = "" -default["percona"]["encrypted_data_bag_item_mysql"] = "mysql" -default["percona"]["encrypted_data_bag_item_system"] = "system" -default["percona"]["encrypted_data_bag_item_ssl_replication"] = "ssl_replication" -default["percona"]["use_chef_vault"] = false -default["percona"]["skip_passwords"] = false -default["percona"]["skip_configure"] = false +default['percona']['main_config_template']['cookbook'] = 'percona' +default['percona']['main_config_template']['source']['default'] = 'my.cnf.main.erb' +default['percona']['main_config_template']['source']['cluster'] = 'my.cnf.cluster.erb' +default['percona']['encrypted_data_bag'] = 'passwords' +default['percona']['encrypted_data_bag_secret_file'] = '' +default['percona']['encrypted_data_bag_item_mysql'] = 'mysql' +default['percona']['encrypted_data_bag_item_system'] = 'system' +default['percona']['encrypted_data_bag_item_ssl_replication'] = 'ssl_replication' +default['percona']['use_chef_vault'] = false +default['percona']['skip_passwords'] = false +default['percona']['skip_configure'] = false # Start percona server on boot -default["percona"]["server"]["enable"] = true +default['percona']['server']['enable'] = true # install vs. upgrade packages -default["percona"]["server"]["package_action"] = "install" +default['percona']['server']['package_action'] = 'install' # Basic Settings -default["percona"]["server"]["role"] = ["standalone"] -default["percona"]["server"]["username"] = "mysql" -default["percona"]["server"]["datadir"] = "/var/lib/mysql" -default["percona"]["server"]["logdir"] = "/var/log/mysql" -default["percona"]["server"]["tmpdir"] = "/tmp" -default["percona"]["server"]["slave_load_tmpdir"] = "/tmp" -default["percona"]["server"]["debian_username"] = "debian-sys-maint" -default["percona"]["server"]["jemalloc"] = false -default["percona"]["server"]["jemalloc_lib"] = value_for_platform_family( - "debian" => value_for_platform( - "ubuntu" => { - "trusty" => "/usr/lib/x86_64-linux-gnu/libjemalloc.so.1", - "precise" => "/usr/lib/libjemalloc.so.1" - } - ), - "rhel" => "/usr/lib64/libjemalloc.so.1" -) -default["percona"]["server"]["nice"] = 0 -default["percona"]["server"]["open_files_limit"] = 16_384 -default["percona"]["server"]["hostname"] = "localhost" -default["percona"]["server"]["basedir"] = "/usr" -default["percona"]["server"]["port"] = 3306 -default["percona"]["server"]["language"] = "/usr/share/mysql/english" -default["percona"]["server"]["character_set"] = "utf8" -default["percona"]["server"]["collation"] = "utf8_unicode_ci" -default["percona"]["server"]["skip_name_resolve"] = false -default["percona"]["server"]["skip_external_locking"] = true -default["percona"]["server"]["net_read_timeout"] = 120 -default["percona"]["server"]["connect_timeout"] = 10 -default["percona"]["server"]["wait_timeout"] = 28_800 -default["percona"]["server"]["old_passwords"] = 0 -default["percona"]["server"]["bind_address"] = "127.0.0.1" -default["percona"]["server"]["federated"] = false - -%w[debian_password root_password].each do |attribute| - next if attribute?(node["percona"]["server"][attribute]) - - default["percona"]["server"][attribute] = random_password +default['percona']['server']['role'] = ['standalone'] +default['percona']['server']['package'] = [] +default['percona']['server']['username'] = 'mysql' +default['percona']['server']['datadir'] = '/var/lib/mysql' +default['percona']['server']['logdir'] = '/var/log/mysql' +default['percona']['server']['tmpdir'] = '/tmp' +default['percona']['server']['slave_load_tmpdir'] = '/tmp' +default['percona']['server']['debian_username'] = 'debian-sys-maint' +default['percona']['server']['jemalloc'] = false +default['percona']['server']['nice'] = 0 +default['percona']['server']['open_files_limit'] = 16_384 +default['percona']['server']['hostname'] = 'localhost' +default['percona']['server']['basedir'] = '/usr' +default['percona']['server']['port'] = 3306 +default['percona']['server']['language'] = '/usr/share/mysql/english' +default['percona']['server']['character_set'] = 'utf8' +default['percona']['server']['collation'] = 'utf8_unicode_ci' +default['percona']['server']['skip_name_resolve'] = false +default['percona']['server']['skip_external_locking'] = true +default['percona']['server']['net_read_timeout'] = 120 +default['percona']['server']['connect_timeout'] = 10 +default['percona']['server']['wait_timeout'] = 28_800 +default['percona']['server']['old_passwords'] = 0 +default['percona']['server']['bind_address'] = '127.0.0.1' +default['percona']['server']['federated'] = false +default['percona']['server']['report_host'] = '' + +%w(debian_password root_password).each do |attribute| + next if attribute?(node['percona']['server'][attribute]) + default['percona']['server'][attribute] = percona_secure_random end # Fine Tuning -default["percona"]["server"]["key_buffer_size"] = "16M" -default["percona"]["server"]["max_allowed_packet"] = "64M" -default["percona"]["server"]["thread_stack"] = "192K" -default["percona"]["server"]["query_alloc_block_size"] = "16K" -default["percona"]["server"]["memlock"] = false -default["percona"]["server"]["transaction_isolation"] = "REPEATABLE-READ" -default["percona"]["server"]["tmp_table_size"] = "64M" -default["percona"]["server"]["max_heap_table_size"] = "64M" -default["percona"]["server"]["sort_buffer_size"] = "8M" -default["percona"]["server"]["join_buffer_size"] = "8M" -default["percona"]["server"]["thread_cache_size"] = 16 -default["percona"]["server"]["back_log"] = 50 -default["percona"]["server"]["max_connections"] = 30 -default["percona"]["server"]["max_connect_errors"] = 9_999_999 -default["percona"]["server"]["sql_modes"] = [] -default["percona"]["server"]["table_cache"] = 8192 -default["percona"]["server"]["group_concat_max_len"] = 4096 -default["percona"]["server"]["expand_fast_index_creation"] = false -default["percona"]["server"]["read_rnd_buffer_size"] = 262_144 +default['percona']['server']['key_buffer_size'] = '16M' +default['percona']['server']['max_allowed_packet'] = '64M' +default['percona']['server']['thread_stack'] = '192K' +default['percona']['server']['query_alloc_block_size'] = '16K' +default['percona']['server']['memlock'] = false +default['percona']['server']['transaction_isolation'] = 'REPEATABLE-READ' +default['percona']['server']['tmp_table_size'] = '64M' +default['percona']['server']['max_heap_table_size'] = '64M' +default['percona']['server']['sort_buffer_size'] = '8M' +default['percona']['server']['join_buffer_size'] = '8M' +default['percona']['server']['thread_cache_size'] = 16 +default['percona']['server']['back_log'] = -1 # <5.6.6, use 50 +default['percona']['server']['max_connections'] = 30 +default['percona']['server']['max_connect_errors'] = 9_999_999 +default['percona']['server']['sql_modes'] = [] +default['percona']['server']['table_cache'] = 8172 +default['percona']['server']['table_definition_cache'] = '-1' # <5.6, use 4096 +default['percona']['server']['group_concat_max_len'] = 4096 +default['percona']['server']['expand_fast_index_creation'] = false +default['percona']['server']['read_rnd_buffer_size'] = 262_144 +default['percona']['server']['sysdate_is_now'] = false # Query Cache Configuration -default["percona"]["server"]["query_cache_size"] = "64M" -default["percona"]["server"]["query_cache_limit"] = "2M" +default['percona']['server']['query_cache_size'] = '64M' +default['percona']['server']['query_cache_limit'] = '2M' +default['percona']['server']['query_cache_type'] = '1' # Logging and Replication -default["percona"]["server"]["sync_binlog"] = (node["percona"]["server"]["role"] == "cluster" ? 0 : 1) -default["percona"]["server"]["slow_query_log"] = 1 -default["percona"]["server"]["slow_query_logdir"] = "/var/log/mysql" -default["percona"]["server"]["slow_query_log_file"] = "#{node["percona"]["server"]["slow_query_logdir"]}/mysql-slow.log" -default["percona"]["server"]["long_query_time"] = 2 -default["percona"]["server"]["server_id"] = 1 -default["percona"]["server"]["binlog_do_db"] = [] -default["percona"]["server"]["binlog_ignore_db"] = [] -default["percona"]["server"]["expire_logs_days"] = 10 -default["percona"]["server"]["max_binlog_size"] = "100M" -default["percona"]["server"]["binlog_space_limit"] = 0 -default["percona"]["server"]["binlog_cache_size"] = "1M" -default["percona"]["server"]["binlog_format"] = "MIXED" -default["percona"]["server"]["log_bin"] = "master-bin" -default["percona"]["server"]["relay_log"] = "slave-relay-bin" -default["percona"]["server"]["log_slave_updates"] = false -default["percona"]["server"]["log_warnings"] = true -default["percona"]["server"]["log_long_format"] = false -default["percona"]["server"]["bulk_insert_buffer_size"] = "64M" +default['percona']['server']['sync_binlog'] = (node['percona']['server']['role'] == 'cluster' ? 0 : 1) +default['percona']['server']['slow_query_log'] = 1 +default['percona']['server']['slow_query_logdir'] = '/var/log/mysql' +default['percona']['server']['slow_query_log_file'] = "#{node['percona']['server']['slow_query_logdir']}/mysql-slow.log" +default['percona']['server']['long_query_time'] = 2 +default['percona']['server']['log_queries_not_using_indexes'] = 0 +default['percona']['server']['server_id'] = 1 +default['percona']['server']['binlog_rows_query_log_events'] = false +default['percona']['server']['binlog_do_db'] = [] +default['percona']['server']['binlog_ignore_db'] = [] +default['percona']['server']['expire_logs_days'] = 10 +default['percona']['server']['gtid_mode'] = 'OFF' +default['percona']['server']['enforce_gtid_consistency'] = false +default['percona']['server']['max_binlog_size'] = '100M' +default['percona']['server']['binlog_cache_size'] = '1M' +default['percona']['server']['binlog_format'] = 'ROW' # Alt. MIXED +default['percona']['server']['binlog_checksum'] = 'CRC32' +default['percona']['server']['log_bin'] = 1 # enable/disable bin log +default['percona']['server']['log_bin_basename'] = 'master-bin' # 5.6~> default: datadir + '/' + hostname + '-bin' +default['percona']['server']['relay_log'] = 'slave-relay-bin' +default['percona']['server']['log_slave_updates'] = false +default['percona']['server']['log_warnings'] = node['percona']['version'].to_i < 8 +default['percona']['server']['log_long_format'] = false +default['percona']['server']['bulk_insert_buffer_size'] = '64M' +default['percona']['server']['sync_master_info'] = false +default['percona']['server']['sync_relay_log'] = false +default['percona']['server']['sync_relay_log_info'] = false +default['percona']['server']['master_verify_checksum'] = false +default['percona']['server']['slave_net_timeout'] = 3600 +default['percona']['server']['slave_sql_verify_checksum'] = false # MyISAM Specific -default["percona"]["server"]["myisam_recover_options"] = "BACKUP" -default["percona"]["server"]["myisam_sort_buffer_size"] = "128M" -default["percona"]["server"]["myisam_max_sort_file_size"] = "10G" -default["percona"]["server"]["myisam_repair_threads"] = 1 -default["percona"]["server"]["read_buffer_size"] = "8M" +default['percona']['server']['myisam_recover_options'] = 'BACKUP' +default['percona']['server']['myisam_sort_buffer_size'] = '128M' +default['percona']['server']['myisam_max_sort_file_size'] = '10G' +default['percona']['server']['myisam_repair_threads'] = 1 +default['percona']['server']['read_buffer_size'] = '8M' # InnoDB Specific -default["percona"]["server"]["skip_innodb"] = false -default["percona"]["server"]["innodb_additional_mem_pool_size"] = "32M" -default["percona"]["server"]["innodb_buffer_pool_size"] = "128M" -default["percona"]["server"]["innodb_data_file_path"] = "ibdata1:10M:autoextend" -default["percona"]["server"]["innodb_autoextend_increment"] = "128M" -default["percona"]["server"]["innodb_open_files"] = 2000 -default["percona"]["server"]["innodb_file_per_table"] = true -default["percona"]["server"]["innodb_file_format"] = "Antelope" -default["percona"]["server"]["innodb_data_home_dir"] = "" -default["percona"]["server"]["innodb_thread_concurrency"] = 16 -default["percona"]["server"]["innodb_flush_log_at_trx_commit"] = 1 -default["percona"]["server"]["innodb_fast_shutdown"] = false -default["percona"]["server"]["innodb_log_buffer_size"] = "64M" -default["percona"]["server"]["innodb_log_file_size"] = "5M" -default["percona"]["server"]["innodb_log_files_in_group"] = 2 -default["percona"]["server"]["innodb_max_dirty_pages_pct"] = 80 -default["percona"]["server"]["innodb_flush_method"] = "O_DIRECT" -default["percona"]["server"]["innodb_lock_wait_timeout"] = 120 -default["percona"]["server"]["innodb_import_table_from_xtrabackup"] = 0 +default['percona']['server']['skip_innodb'] = false +default['percona']['server']['innodb_additional_mem_pool_size'] = '32M' +default['percona']['server']['innodb_buffer_pool_size'] = '128M' +default['percona']['server']['innodb_buffer_pool_instances'] = 8 +default['percona']['server']['innodb_buffer_pool_populate'] = 0 # Introduced: MariaDB 5.5 / XtraDB 5.5.28-29.1 +default['percona']['server']['innodb_data_file_path'] = 'ibdata1:10M:autoextend' +default['percona']['server']['innodb_autoextend_increment'] = '128M' +default['percona']['server']['innodb_open_files'] = 2000 +default['percona']['server']['innodb_file_per_table'] = true +default['percona']['server']['innodb_file_format'] = 'Antelope' +default['percona']['server']['innodb_data_home_dir'] = '' +default['percona']['server']['innodb_thread_concurrency'] = 16 +default['percona']['server']['innodb_flush_log_at_trx_commit'] = 1 +default['percona']['server']['innodb_fast_shutdown'] = false +default['percona']['server']['innodb_log_buffer_size'] = '64M' +default['percona']['server']['innodb_log_file_size'] = '5M' +default['percona']['server']['innodb_log_files_in_group'] = 2 +default['percona']['server']['innodb_max_dirty_pages_pct'] = 80 +default['percona']['server']['innodb_flush_method'] = 'O_DIRECT' +default['percona']['server']['innodb_lock_wait_timeout'] = 120 +default['percona']['server']['innodb_import_table_from_xtrabackup'] = 0 +default['percona']['server']['innodb_numa_interleave'] = 0 # Performance Schema -default["percona"]["server"]["performance_schema"] = false +default['percona']['server']['performance_schema'] = false # Replication Settings -default["percona"]["server"]["replication"]["read_only"] = false -default["percona"]["server"]["replication"]["host"] = "" -default["percona"]["server"]["replication"]["username"] = "" -default["percona"]["server"]["replication"]["password"] = "" -default["percona"]["server"]["replication"]["port"] = 3306 -default["percona"]["server"]["replication"]["ignore_db"] = [] -default["percona"]["server"]["replication"]["ignore_table"] = [] -default["percona"]["server"]["replication"]["replicate_do_db"] = [] -default["percona"]["server"]["replication"]["replicate_do_table"] = [] -default["percona"]["server"]["replication"]["ssl_enabled"] = false -default["percona"]["server"]["replication"]["suppress_1592"] = false -default["percona"]["server"]["replication"]["skip_slave_start"] = false -default["percona"]["server"]["replication"]["replication_sql"] = "/etc/mysql/replication.sql" -default["percona"]["server"]["replication"]["slave_transaction_retries"] = 10 -default["percona"]["server"]["replication"]["enforce_gtid_consistency"] = "OFF" -default["percona"]["server"]["replication"]["gtid_mode"] = "OFF" -default["percona"]["server"]["replication"]["slave_exec_mode"] = "IDEMPOTENT" +default['percona']['server']['replication']['read_only'] = false +default['percona']['server']['replication']['host'] = '' +default['percona']['server']['replication']['username'] = '' +default['percona']['server']['replication']['password'] = '' +default['percona']['server']['replication']['port'] = 3306 +default['percona']['server']['replication']['ignore_db'] = [] +default['percona']['server']['replication']['ignore_table'] = [] +default['percona']['server']['replication']['ssl_enabled'] = false +default['percona']['server']['replication']['suppress_1592'] = false +default['percona']['server']['replication']['skip_slave_start'] = false +default['percona']['server']['replication']['replication_sql'] = '/etc/mysql/replication.sql' +default['percona']['server']['replication']['slave_transaction_retries'] = 10 + +# Mysqld_safe +default['percona']['server']['skip_syslog'] = false # XtraBackup Settings -default["percona"]["backup"]["configure"] = false -default["percona"]["backup"]["username"] = "backup" -unless attribute?(node["percona"]["backup"]["password"]) - default["percona"]["backup"]["password"] = random_password +default['percona']['backup']['configure'] = false +default['percona']['backup']['username'] = 'backup' +unless attribute?(node['percona']['backup']['password']) + default['percona']['backup']['password'] = percona_secure_random end # XtraDB Cluster Settings -default["percona"]["cluster"]["binlog_format"] = "ROW" -default["percona"]["cluster"]["wsrep_provider"] = value_for_platform_family( - "debian" => "/usr/lib/libgalera_smm.so", - "rhel" => "/usr/lib64/libgalera_smm.so" +default['percona']['cluster']['binlog_format'] = 'ROW' +default['percona']['cluster']['wsrep_provider'] = value_for_platform_family( + 'debian' => '/usr/lib/libgalera_smm.so', + 'rhel' => '/usr/lib64/libgalera_smm.so' ) -default["percona"]["cluster"]["wsrep_provider_options"] = "" -default['percona']['cluster']['wsrep_retry_autocommit'] = 1 -default["percona"]["cluster"]["wsrep_cluster_address"] = "" -default["percona"]["cluster"]["wsrep_slave_threads"] = 2 -default["percona"]["cluster"]["wsrep_cluster_name"] = "" -default["percona"]["cluster"]["wsrep_sst_method"] = "rsync" -default["percona"]["cluster"]["wsrep_node_name"] = "" -default["percona"]["cluster"]["wsrep_notify_cmd"] = "" -default["percona"]["cluster"]["wsrep_sst_auth"] = "" +default['percona']['cluster']['wsrep_provider_options'] = '' +default['percona']['cluster']['wsrep_cluster_address'] = '' +default['percona']['cluster']['wsrep_slave_threads'] = 2 +default['percona']['cluster']['wsrep_cluster_name'] = '' +default['percona']['cluster']['wsrep_sst_method'] = 'rsync' +default['percona']['cluster']['wsrep_node_name'] = '' +default['percona']['cluster']['wsrep_notify_cmd'] = '' +default['percona']['cluster']['wsrep_sst_auth'] = '' # These both are used to build wsrep_sst_receive_address -default["percona"]["cluster"]["wsrep_sst_receive_interface"] = nil # Works like node["percona"]["server"]["bind_to"] -default["percona"]["cluster"]["wsrep_sst_receive_port"] = "4444" +default['percona']['cluster']['wsrep_sst_receive_interface'] = nil # Works like node["percona"]["server"]["bind_to"] +default['percona']['cluster']['wsrep_sst_receive_port'] = '4444' -default["percona"]["cluster"]["innodb_locks_unsafe_for_binlog"] = 1 -default["percona"]["cluster"]["innodb_autoinc_lock_mode"] = 2 +default['percona']['cluster']['innodb_locks_unsafe_for_binlog'] = 1 +default['percona']['cluster']['innodb_autoinc_lock_mode'] = 2 diff --git a/attributes/monitoring.rb b/attributes/monitoring.rb deleted file mode 100644 index b3033f53..00000000 --- a/attributes/monitoring.rb +++ /dev/null @@ -1,7 +0,0 @@ -# -# Cookbook Name:: percona -# Attributes:: monitoring -# - -default["percona"]["plugins_version"] = "1.1.3" -default["percona"]["plugins_packages"] = %w[percona-nagios-plugins percona-zabbix-templates percona-cacti-templates] diff --git a/attributes/package_repo.rb b/attributes/package_repo.rb index cc0ccbb7..3956f25f 100644 --- a/attributes/package_repo.rb +++ b/attributes/package_repo.rb @@ -1,25 +1,20 @@ # -# Cookbook Name:: percona +# Cookbook:: percona # Attributes:: package_repo # -default["percona"]["use_percona_repos"] = true - -arch = node["kernel"]["machine"] == "x86_64" ? "x86_64" : "i386" -pversion = value_for_platform( - "amazon" => { "default" => "latest" }, - "default" => node["platform_version"].to_i -) - -default["percona"]["apt"]["key"] = "0x1C4CBDCDCD2EFD2A" -default["percona"]["apt"]["keyserver"] = "hkp://keys.gnupg.net:80" -default["percona"]["apt"]["uri"] = "http://repo.percona.com/apt" - -default["percona"]["yum"]["description"] = "Percona Packages" -default["percona"]["yum"]["baseurl"] = "http://repo.percona.com/yum/release/$releasever/RPMS/$basearch" +default['percona']['use_percona_repos'] = true +# From 8.0 onward, Percona has split up each product into individual repositories +# See https://www.percona.com/doc/percona-repo-config/index.html for more information +default['percona']['repositories'] = %w(ps-80) +default['percona']['apt']['key'] = '9334A25F8507EFA5' +default['percona']['apt']['keyserver'] = 'keyserver.ubuntu.com' +default['percona']['apt']['uri'] = 'http://repo.percona.com/apt' +default['percona']['yum']['description'] = 'Percona Packages' +default['percona']['yum']['baseurl'] = 'http://repo.percona.com/yum/release/$releasever/RPMS' default['percona']['yum']['gpgkey'] = [ 'https://repo.percona.com/yum/PERCONA-PACKAGING-KEY', 'https://repo.percona.com/yum/RPM-GPG-KEY-Percona', ] -default["percona"]["yum"]["gpgcheck"] = true -default["percona"]["yum"]["sslverify"] = true +default['percona']['yum']['gpgcheck'] = true +default['percona']['yum']['sslverify'] = true diff --git a/chefignore b/chefignore new file mode 100644 index 00000000..a27b0b25 --- /dev/null +++ b/chefignore @@ -0,0 +1,115 @@ +# Put files/directories that should be ignored in this file when uploading +# to a Chef Infra Server or Supermarket. +# Lines that start with '# ' are comments. + +# OS generated files # +###################### +.DS_Store +ehthumbs.db +Icon? +nohup.out +Thumbs.db +.envrc + +# EDITORS # +########### +.#* +.project +.settings +*_flymake +*_flymake.* +*.bak +*.sw[a-z] +*.tmproj +*~ +\#* +REVISION +TAGS* +tmtags +.vscode +.editorconfig + +## COMPILED ## +############## +*.class +*.com +*.dll +*.exe +*.o +*.pyc +*.so +*/rdoc/ +a.out +mkmf.log + +# Testing # +########### +.circleci/* +.codeclimate.yml +.delivery/* +.foodcritic +.kitchen* +.mdlrc +.overcommit.yml +.rspec +.rubocop.yml +.travis.yml +.watchr +.yamllint +azure-pipelines.yml +Dangerfile +examples/* +features/* +Guardfile +kitchen*.yml +mlc_config.json +Procfile +Rakefile +spec/* +test/* + +# SCM # +####### +.git +.gitattributes +.gitconfig +.github/* +.gitignore +.gitkeep +.gitmodules +.svn +*/.bzr/* +*/.git +*/.hg/* +*/.svn/* + +# Berkshelf # +############# +Berksfile +Berksfile.lock +cookbooks/* +tmp + +# Bundler # +########### +vendor/* +Gemfile +Gemfile.lock + +# Policyfile # +############## +Policyfile.rb +Policyfile.lock.json + +# Documentation # +############# +CODE_OF_CONDUCT* +CONTRIBUTING* +documentation/* +TESTING* +UPGRADING* + +# Vagrant # +########### +.vagrant +Vagrantfile diff --git a/config/license_finder.yml b/config/license_finder.yml deleted file mode 100644 index 63102a94..00000000 --- a/config/license_finder.yml +++ /dev/null @@ -1,12 +0,0 @@ ---- -whitelist: -- Apache 2.0 -- Apache v2 -- BSD -- BSD-3 -- GPLv3 -- ISC -- MIT -- Ruby -dependencies_file_dir: doc/license_finder -project_name: chef-percona diff --git a/doc/dependency_decisions.yml b/doc/dependency_decisions.yml deleted file mode 100644 index 1f819d69..00000000 --- a/doc/dependency_decisions.yml +++ /dev/null @@ -1,51 +0,0 @@ ---- -- - :whitelist - - MIT - - :who: Phil Cohen - :why: - :when: 2015-05-14 00:42:25.278199000 Z -- - :whitelist - - Apache 2.0 - - :who: Phil Cohen - :why: - :when: 2015-05-14 00:43:06.845446000 Z -- - :whitelist - - BSD - - :who: Phil Cohen - :why: - :when: 2015-05-14 00:43:37.398031000 Z -- - :whitelist - - ruby - - :who: Phil Cohen - :why: - :when: 2015-05-14 00:43:44.294826000 Z -- - :approve - - bundler - - :who: Phil Cohen - :why: - :when: 2015-05-14 01:49:37.564892000 Z -- - :approve - - chef-vault - - :who: Phil Cohen - :why: - :when: 2015-05-14 01:49:57.039089000 Z -- - :approve - - dep_selector - - :who: Phil Cohen - :why: - :when: 2015-05-14 01:50:07.679660000 Z -- - :approve - - hitimes - - :who: Phil Cohen - :why: - :when: 2015-05-14 01:50:17.333700000 Z -- - :approve - - minitar - - :who: Phil Cohen - :why: - :when: 2015-05-14 01:50:27.059127000 Z -- - :approve - - rake - - :who: Phil Cohen - :why: - :when: 2015-05-14 01:50:31.944663000 Z diff --git a/documentation/.gitkeep b/documentation/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/documentation/resource_percona_mysql_database.md b/documentation/resource_percona_mysql_database.md new file mode 100644 index 00000000..52ac3155 --- /dev/null +++ b/documentation/resource_percona_mysql_database.md @@ -0,0 +1,49 @@ +# percona\_mysql\_database + +Manage Percona MySQL databases and execute SQL queries on them. It works by establishing a control connection to the Percona server using the percona client (be sure it is installed before using this resource). + +## Actions + +- create - (default) to create a named database +- drop - to drop a named database +- query - to execute a SQL query + +## Properties + +Name | Types | Description | Default | Required? +----------------- | ----------------- | ------------------------------------------------------------ | ----------------------------------------- | --------- +`user` | String | the username of the control connection | `root` | no +`password` | String | password of the user used to connect to | | no +`host` | String | host to connect to | `localhost` | no +`port` | String | port of the host to connect to | `3306` | no +`database_name` | String | the name of the database to manage | `name` if not specified | no +`encoding` | String | | `utf8` | no +`collation` | String | | `utf8_general_ci` | no +`sql` | String | the SQL query to execute | | no + +When `host` has the value `localhost`, it will try to connect using a Unix socket, or TCP/IP if no socket is defined. + +### Examples + +```ruby +# Create a database +percona_mysql_database 'wordpress-cust01' do + host '127.0.0.1' + user 'root' + password node['wordpress-cust01']['mysql']['initial_root_password'] + action :create +end + +# Drop a database +percona_mysql_database 'baz' do + action :drop +end + +# Query a database +percona_mysql_database 'flush the privileges' do + sql 'flush privileges' + action :query +end +``` + +**The `query` action will NOT select a database before running the query, nor return the actual results from the SQL query.** diff --git a/documentation/resource_percona_mysql_user.md b/documentation/resource_percona_mysql_user.md new file mode 100644 index 00000000..241fe760 --- /dev/null +++ b/documentation/resource_percona_mysql_user.md @@ -0,0 +1,63 @@ +# percona\_mysql\_user + +Manage Percona MySQL users and grant them privileges on database objects. + +## Actions + +- create - (default) to create a user +- drop - to drop a user +- grant - to grant privileges to a user +- revoke - to revoke privileges from a user + +## Properties + +Name | Types | Description | Default | Required? +----------------- | ---------------------- | ------------------------------------------------------------ | ----------------------------------------- | --------- +`ctrl_user` | String | the username of the control connection | `root` | no +`ctrl_password` | String | password of the user used to connect to | | no +`ctrl_host` | String | host to connect to | `localhost` | no +`ctrl_port` | String | port of the host to connect to | `3306` | no +`username` | String | The database user to be managed | `name` if not defined | no +`host` | String | The host from which the user is allowed to connect | `localhost` | no +`password` | String, HashedPassword | password the user will be asked for to connect | | yes +`privileges` | Array | | `[:all]` | no +`database_name` | String | | | no +`table` | String | | | no +`grant_option` | true/false | | `false` | no +`require_ssl` | true/false | | `false` | no +`require_x509` | true/false | | `false` | no +`use_native_auth` | true/false | if using percona >8, use `mysql_native_password` for auth | `true` | no + +### `use_native_auth` + +This property should be set to `false` if the user is local (host of `localhost`) to provide better security. The property still works for remote users but does not provide any idempotency guarantees. `use_native_auth` has no effect for percona <8. + +## Examples + +```ruby +# Create an user but grant no privileges +percona_mysql_user 'disenfranchised' do + password 'super_secret' + action :create +end + +# Create an user using a hashed password string instead of plain text one +percona_mysql_user 'disenfranchised' do + password hashed_password('md5eacdbf8d9847a76978bd515fae200a2a') + action :create +end + +# Drop a user +percona_mysql_user 'foo_user' do + action :drop +end + +# Grant SELECT, UPDATE, and INSERT privileges to all tables in foo db from all hosts +percona_mysql_user 'foo_user' do + password 'super_secret' + database_name 'foo' + host '%' + privileges [:select,:update,:insert] + action :grant +end +``` diff --git a/kitchen.dokken.yml b/kitchen.dokken.yml new file mode 100644 index 00000000..47eff95d --- /dev/null +++ b/kitchen.dokken.yml @@ -0,0 +1,113 @@ +driver: + name: dokken + privileged: true + chef_version: <%= ENV['CHEF_VERSION'] || 'current' %> + +transport: { name: dokken } +provisioner: { name: dokken } + +platforms: + - name: almalinux-8 + driver: + image: dokken/almalinux-8 + pid_one_command: /usr/lib/systemd/systemd + + - name: almalinux-9 + driver: + image: dokken/almalinux-9 + pid_one_command: /usr/lib/systemd/systemd + + - name: amazonlinux-2023 + driver: + image: dokken/amazonlinux-2023 + pid_one_command: /usr/lib/systemd/systemd + + - name: centos-7 + driver: + image: dokken/centos-7 + pid_one_command: /usr/lib/systemd/systemd + + - name: centos-stream-8 + driver: + image: dokken/centos-stream-8 + pid_one_command: /usr/lib/systemd/systemd + + - name: centos-stream-9 + driver: + image: dokken/centos-stream-9 + pid_one_command: /usr/lib/systemd/systemd + + - name: debian-9 + driver: + image: dokken/debian-9 + pid_one_command: /bin/systemd + + - name: debian-10 + driver: + image: dokken/debian-10 + pid_one_command: /bin/systemd + + - name: debian-11 + driver: + image: dokken/debian-11 + pid_one_command: /bin/systemd + + - name: debian-12 + driver: + image: dokken/debian-12 + pid_one_command: /bin/systemd + + - name: fedora-latest + driver: + image: dokken/fedora-latest + pid_one_command: /usr/lib/systemd/systemd + + - name: opensuse-leap-15 + driver: + image: dokken/opensuse-leap-15 + pid_one_command: /usr/lib/systemd/systemd + + - name: oraclelinux-7 + driver: + image: dokken/oraclelinux-7 + pid_one_command: /usr/lib/systemd/systemd + + - name: oraclelinux-8 + driver: + image: dokken/oraclelinux-8 + pid_one_command: /usr/lib/systemd/systemd + + - name: oraclelinux-9 + driver: + image: dokken/oraclelinux-9 + pid_one_command: /usr/lib/systemd/systemd + + - name: rockylinux-8 + driver: + image: dokken/rockylinux-8 + pid_one_command: /usr/lib/systemd/systemd + + - name: rockylinux-9 + driver: + image: dokken/rockylinux-9 + pid_one_command: /usr/lib/systemd/systemd + + - name: ubuntu-18.04 + driver: + image: dokken/ubuntu-18.04 + pid_one_command: /bin/systemd + + - name: ubuntu-20.04 + driver: + image: dokken/ubuntu-20.04 + pid_one_command: /bin/systemd + + - name: ubuntu-22.04 + driver: + image: dokken/ubuntu-22.04 + pid_one_command: /bin/systemd + + - name: ubuntu-23.04 + driver: + image: dokken/ubuntu-23.04 + pid_one_command: /bin/systemd diff --git a/kitchen.exec.yml b/kitchen.exec.yml new file mode 100644 index 00000000..ba7b2a96 --- /dev/null +++ b/kitchen.exec.yml @@ -0,0 +1,7 @@ +--- +driver: { name: exec } +transport: { name: exec } + +platforms: + - name: macos-latest + - name: windows-latest diff --git a/kitchen.global.yml b/kitchen.global.yml new file mode 100644 index 00000000..a382fcd0 --- /dev/null +++ b/kitchen.global.yml @@ -0,0 +1,38 @@ +--- +provisioner: + name: chef_infra + product_name: chef + product_version: <%= ENV['CHEF_VERSION'] || 'latest' %> + channel: stable + install_strategy: once + chef_license: accept + enforce_idempotency: <%= ENV['ENFORCE_IDEMPOTENCY'] || true %> + multiple_converge: <%= ENV['MULTIPLE_CONVERGE'] || 2 %> + deprecations_as_errors: true + log_level: <%= ENV['CHEF_LOG_LEVEL'] || 'auto' %> + +verifier: + name: inspec + +platforms: + - name: almalinux-8 + - name: almalinux-9 + - name: amazonlinux-2023 + - name: centos-7 + - name: centos-stream-8 + - name: centos-stream-9 + - name: debian-9 + - name: debian-10 + - name: debian-11 + - name: debian-12 + - name: fedora-latest + - name: opensuse-leap-15 + - name: oraclelinux-7 + - name: oraclelinux-8 + - name: oraclelinux-9 + - name: rockylinux-8 + - name: rockylinux-9 + - name: ubuntu-18.04 + - name: ubuntu-20.04 + - name: ubuntu-22.04 + - name: ubuntu-23.04 diff --git a/kitchen.yml b/kitchen.yml new file mode 100644 index 00000000..c3fe8600 --- /dev/null +++ b/kitchen.yml @@ -0,0 +1,366 @@ +--- +driver: + name: vagrant + +provisioner: + name: chef_solo + enforce_idempotency: true + multiple_converge: 2 + deprecations_as_errors: true + data_bags_path: test/integration/data_bags + +verifier: + name: inspec + inspec_tests: + - path: test/integration/inspec + +platforms: + - name: almalinux-8 + - name: centos-7 + - name: centos-stream-8 + - name: debian-10 + - name: debian-11 + - name: rockylinux-8 + - name: ubuntu-18.04 + - name: ubuntu-20.04 + +suites: + - name: client-56 + run_list: + - recipe[test::client] + attributes: + percona: + version: '5.6' + verifier: + controls: + - client + - toolkit + inputs: + version: '5.6' + excludes: + - almalinux-8 + - centos-stream-8 + - debian-10 + - debian-11 + - rockylinux-8 + - ubuntu-20.04 + + - name: client-57 + run_list: + - recipe[test::client] + attributes: + percona: + version: '5.7' + verifier: + controls: + - client + - toolkit + inputs: + version: '5.7' + + - name: client-80 + run_list: + - recipe[test::client] + attributes: + percona: + version: '8.0' + verifier: + controls: + - client + - toolkit + inputs: + version: '8.0' + + - name: devel-56 + run_list: + - recipe[test::client] + attributes: + percona: + version: '5.6' + client: + install_devel_package: true + verifier: + controls: + - client + - toolkit + inputs: + version: '5.6' + devel: true + excludes: + - almalinux-8 + - centos-stream-8 + - debian-10 + - debian-11 + - rockylinux-8 + - ubuntu-20.04 + + - name: devel-57 + run_list: + - recipe[test::client] + attributes: + percona: + version: '5.7' + client: + install_devel_package: true + verifier: + controls: + - client + - toolkit + inputs: + version: '5.7' + devel: true + + - name: devel-80 + run_list: + - recipe[test::client] + attributes: + percona: + version: '8.0' + client: + install_devel_package: true + verifier: + controls: + - client + - toolkit + inputs: + version: '8.0' + devel: true + + - name: server-56 + run_list: + - recipe[test::server] + attributes: + percona: + version: '5.6' + excludes: + - almalinux-8 + - centos-stream-8 + - debian-10 + - debian-11 + - rockylinux-8 + - ubuntu-20.04 + verifier: + controls: + - client + - server + inputs: + version: '5.6' + + - name: server-57 + run_list: + - recipe[test::server] + attributes: + percona: + version: '5.7' + verifier: + controls: + - client + - server + inputs: + version: '5.7' + + - name: server-80 + run_list: + - recipe[test::server] + attributes: + percona: + version: '8.0' + verifier: + controls: + - client + - server + inputs: + version: '8.0' + + - name: source-56 + run_list: + - recipe[test::source] + attributes: + percona: + version: '5.6' + excludes: + - almalinux-8 + - centos-stream-8 + - debian-10 + - debian-11 + - rockylinux-8 + - ubuntu-20.04 + verifier: + controls: + - client + - server + inputs: + version: '5.6' + type: 'source' + + - name: source-57 + run_list: + - recipe[test::source] + attributes: + percona: + version: '5.7' + verifier: + controls: + - client + - server + inputs: + version: '5.7' + type: 'source' + + - name: source-80 + run_list: + - recipe[test::source] + attributes: + percona: + version: '8.0' + verifier: + controls: + - client + - server + inputs: + version: '8.0' + type: 'source' + + - name: cluster-56 + run_list: + - recipe[test::cluster] + attributes: + percona: + version: '5.6' + excludes: + - almalinux-8 + - centos-stream-8 + - debian-10 + - debian-11 + - rockylinux-8 + - ubuntu-20.04 + verifier: + controls: + - client + - server + inputs: + version: '5.6' + type: 'cluster' + + - name: cluster-57 + run_list: + - recipe[test::cluster] + attributes: + percona: + version: '5.7' + verifier: + controls: + - client + - server + inputs: + version: '5.7' + type: 'cluster' + + - name: cluster-80 + run_list: + - recipe[test::cluster] + attributes: + percona: + version: '8.0' + verifier: + controls: + - client + - server + inputs: + version: '8.0' + type: 'cluster' + + - name: replication-56 + run_list: + - recipe[test::replication] + attributes: + percona: + version: '5.6' + excludes: + - almalinux-8 + - centos-stream-8 + - debian-10 + - debian-11 + - rockylinux-8 + - ubuntu-20.04 + verifier: + controls: + - client + - server + inputs: + version: '5.6' + type: 'replication' + + - name: replication-57 + run_list: + - recipe[test::replication] + attributes: + percona: + version: '5.7' + verifier: + controls: + - client + - server + inputs: + version: '5.7' + type: 'replication' + + - name: replication-80 + run_list: + - recipe[test::replication] + attributes: + percona: + version: '8.0' + verifier: + controls: + - client + - server + inputs: + version: '8.0' + type: 'replication' + + - name: resources-56 + run_list: + - recipe[test::user_database] + attributes: + percona: + version: '5.6' + excludes: + - almalinux-8 + - centos-stream-8 + - debian-10 + - debian-11 + - rockylinux-8 + - ubuntu-20.04 + verifier: + controls: + - percona_database + - percona_user + inputs: + version: '5.6' + + - name: resources-57 + run_list: + - recipe[test::user_database] + attributes: + percona: + version: '5.7' + verifier: + controls: + - percona_database + - percona_user + inputs: + version: '5.8' + + - name: resources-80 + run_list: + - recipe[test::user_database] + attributes: + percona: + version: '8.0' + verifier: + controls: + - percona_database + - percona_user + inputs: + version: '8.0' diff --git a/libraries/config_helper.rb b/libraries/config_helper.rb index de8966fe..5472d950 100644 --- a/libraries/config_helper.rb +++ b/libraries/config_helper.rb @@ -1,4 +1,4 @@ -require "ipaddr" +require 'ipaddr' module Percona # Public: This module provides a helper method for returning a "scope" for a @@ -7,21 +7,23 @@ module IPScope def for(ipaddress) address = IPAddr.new(ipaddress) - case - when private?(address) then :private - when loopback?(address) then :loopback - else :public + if private?(address) + :private + elsif loopback?(address) + :loopback + else + :public end end module_function :for def loopback?(address) - IPAddr.new("0.0.0.0/8").include?(address) + IPAddr.new('127.0.0.0/8').include?(address) end module_function :loopback? def private?(address) - [IPAddr.new("10.0.0.0/8"), IPAddr.new("192.168.0.0/16")].any? do |range| + [IPAddr.new('10.0.0.0/8'), IPAddr.new('172.16.0.0/12'), IPAddr.new('192.168.0.0/16')].any? do |range| range.include?(address) end end @@ -33,31 +35,29 @@ def private?(address) module ConfigHelper def bind_to(node, interface) case interface - when "public_ip" then find_public_ip(node) - when "private_ip" then find_private_ip(node) - when "loopback" then find_loopback_ip(node) + when 'public_ip' then find_public_ip(node) + when 'private_ip' then find_private_ip(node) + when 'loopback' then find_loopback_ip(node) else find_interface_ip(node, interface) end end module_function :bind_to - private - def self.find_public_ip(node) - if node["cloud"] && node["cloud"]["public_ipv4"] - node["cloud"]["public_ipv4"] + if node['cloud'] && node['cloud']['public_ipv4'] + node['cloud']['public_ipv4'] else find_ip(node, :private) end end def self.find_private_ip(node) - if node["cloud"] && node["cloud"]["local_ipv4"] - node["cloud"]["local_ipv4"] - elsif node["cloud"] && node["cloud"]["private_ipv4"] - node["cloud"]["private_ipv4"] - elsif node["privateaddress"] - node["privateaddress"] + if node['cloud'] && node['cloud']['local_ipv4'] + node['cloud']['local_ipv4'] + elsif node['cloud'] && node['cloud']['private_ipv4'] + node['cloud']['private_ipv4'] + elsif node['privateaddress'] + node['privateaddress'] else find_ip(node, :private) end @@ -68,20 +68,20 @@ def self.find_loopback_ip(node) end def self.find_ip(node, scope) - node["network"]["interfaces"].each do |_, attrs| - next unless attrs["addresses"] - attrs["addresses"].each do |addr, data| - next unless data["family"] == "inet" + node['network']['interfaces'].each do |_, attrs| + next unless attrs['addresses'] + attrs['addresses'].each do |addr, data| + next unless data['family'] == 'inet' return addr if IPScope.for(addr) == scope end end end def find_interface_ip(node, interface) - interfaces = node["network"]["interfaces"] + interfaces = node['network']['interfaces'] return unless interfaces[interface] - addr = interfaces[interface]["addresses"].find do |_, attrs| - attrs["family"] == "inet" + addr = interfaces[interface]['addresses'].find do |_, attrs| + attrs['family'] == 'inet' end addr && addr[0] end diff --git a/libraries/hashed_passwords.rb b/libraries/hashed_passwords.rb new file mode 100644 index 00000000..2b725590 --- /dev/null +++ b/libraries/hashed_passwords.rb @@ -0,0 +1,45 @@ +# +# Author:: Maksim Horbul () +# Cookbook:: mariadb +# Library:: hashed_password +# +# Copyright:: 2016-2020, Eligible, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +module Percona + module Cookbook + class HashedPassword + # Initializes an object of the MysqlPassword type + # @param [String] hashed_password mysql native hashed password + # @return [MysqlPassword] + def initialize(hashed_password) + @hashed_password = hashed_password + end + + # String representation of the object + # @return [String] hashed password string + def to_s + @hashed_password + end + + module Helper + # helper method wrappers the string into a MysqlPassword object + # @param [String] hashed_password mysql native hashed password + # @return [MysqlPassword] object + def hashed_password(hashed_password) + HashedPassword.new hashed_password + end + end + end + end +end diff --git a/libraries/helpers.rb b/libraries/helpers.rb new file mode 100644 index 00000000..befea141 --- /dev/null +++ b/libraries/helpers.rb @@ -0,0 +1,227 @@ +module Percona + module Cookbook + module Helpers + def percona_version + case node['platform_family'] + when 'debian' + node['percona']['version'] + when 'rhel' + node['percona']['version'].tr('.', '') + end + end + + def percona_client_packages + case node['platform_family'] + when 'debian' + if node['percona']['version'].to_i >= 8 + %w(percona-server-client) + else + %W(percona-server-client-#{percona_version}) + end + when 'rhel' + if node['percona']['version'].to_i >= 8 + %w(percona-server-client) + else + %W(Percona-Server-client-#{percona_version}) + end + end + end + + def percona_devel_package + case node['platform_family'] + when 'rhel' + if node['percona']['version'].to_i >= 8 + 'percona-server-devel' + else + "Percona-Server-devel-#{percona_version}" + end + when 'debian' + if node['percona']['version'].to_i >= 8 + 'libperconaserverclient21-dev' + elsif node['percona']['version'] == '5.7' + 'libperconaserverclient20-dev' + elsif node['percona']['version'] == '5.6' + 'libperconaserverclient18.1-dev' + end + end + end + + def percona_server_package + if node['percona']['version'].to_i >= 8 + 'percona-server-server' + elsif platform_family?('debian') + "percona-server-server-#{percona_version}" + else + "Percona-Server-server-#{percona_version}" + end + end + + def percona_cluster_client_package + case node['platform_family'] + when 'debian' + if node['percona']['version'].to_i >= 8 + %w(percona-xtradb-cluster-client) + else + %W(percona-xtradb-cluster-client-#{percona_version}) + end + when 'rhel' + if node['percona']['version'].to_i >= 8 + %w(percona-xtradb-cluster-client) + else + %W(Percona-XtraDB-Cluster-client-#{percona_version}) + end + end + end + + def percona_cluster_package + if node['percona']['version'].to_i >= 8 + 'percona-xtradb-cluster-server' + elsif platform_family?('rhel') + "Percona-XtraDB-Cluster-#{percona_version}" + else + "percona-xtradb-cluster-#{percona_version}" + end + end + + def percona_backup_package + case node['platform_family'] + when 'debian' + case node['platform'] + when 'debian' + node['platform_version'].to_i >= 10 ? 'percona-xtrabackup-80' : 'xtrabackup' + when 'ubuntu' + node['platform_version'].to_f >= 20.04 ? 'percona-xtrabackup-80' : 'xtrabackup' + end + when 'rhel' + node['platform_version'].to_i >= 8 ? 'percona-xtrabackup-80' : 'percona-xtrabackup' + end + end + + def percona_jemalloc_package + case node['platform'] + when 'debian' + node['platform_version'].to_i >= 10 ? 'libjemalloc2' : 'libjemalloc1' + when 'ubuntu' + node['platform_version'].to_f >= 20.04 ? 'libjemalloc2' : 'libjemalloc1' + when 'centos', 'redhat', 'almalinux', 'rocky' + 'jemalloc' + end + end + + def percona_jemalloc_lib + case node['platform'] + when 'debian' + node['platform_version'].to_i >= 10 ? '/usr/lib/x86_64-linux-gnu/libjemalloc.so.2' : '/usr/lib/x86_64-linux-gnu/libjemalloc.so.1' + when 'ubuntu' + node['platform_version'].to_f >= 20.04 ? '/usr/lib/x86_64-linux-gnu/libjemalloc.so.2' : '/usr/lib/x86_64-linux-gnu/libjemalloc.so.1' + when 'centos', 'redhat', 'almalinux', 'rocky' + node['platform_version'].to_i >= 8 ? '/usr/lib64/libjemalloc.so.2' : '/usr/lib64/libjemalloc.so.1' + end + end + + def percona_default_encoding + node['percona']['version'].to_i >= 8 ? 'utf8mb4' : 'utf8' + end + + def percona_default_collate + node['percona']['version'].to_i >= 8 ? 'utf8mb4_0900_ai_ci' : 'utf8_general_ci' + end + + include Chef::Mixin::ShellOut + require 'securerandom' + ####### + # Function to execute an SQL statement + # Input: + # query : Query could be a single String or an Array of String. + # database : a string containing the name of the database to query in, nil if no database choosen + # ctrl : a Hash which could contain: + # - user : String or nil + # - password : String or nil + # - host : String or nil + # - port : String or Integer or nil + # - socket : String or nil + # Output: A String with cmd to execute the query (but do not execute it!) + # + def sql_command_string(query, database, ctrl, grep_for = nil) + raw_query = query.is_a?(String) ? query : query.join(";\n") + Chef::Log.debug("Control Hash: [#{ctrl.to_json}]\n") + cmd = "/usr/bin/mysql -B -e \"#{raw_query}\"" + cmd << " --user=#{ctrl[:user]}" if ctrl && ctrl.key?(:user) && !ctrl[:user].nil? + cmd << " -p'#{ctrl[:password]}'" if ctrl && ctrl.key?(:password) && !ctrl[:password].nil? + cmd << " -h #{ctrl[:host]}" if ctrl && ctrl.key?(:host) && !ctrl[:host].nil? && ctrl[:host] != 'localhost' + cmd << " -P #{ctrl[:port]}" if ctrl && ctrl.key?(:port) && !ctrl[:port].nil? && ctrl[:host] != 'localhost' + cmd << " -S #{default_socket}" if ctrl && ctrl.key?(:host) && !ctrl[:host].nil? && ctrl[:host] == 'localhost' + cmd << " #{database}" unless database.nil? + cmd << " | grep #{grep_for}" if grep_for + Chef::Log.debug("Executing this command: [#{cmd}]\n") + cmd + end + + ####### + # Function to execute an SQL statement in the default database. + # Input: Query could be a single String or an Array of String. + # Output: A String with -separated columns and \n-separated rows. + # This is easiest for 1-field (1-row, 1-col) results, otherwise + # it will be complex to parse the results. + def execute_sql(query, db_name, ctrl) + cmd = shell_out(sql_command_string(query, db_name, ctrl), + user: 'root') + if cmd.exitstatus != 0 + Chef::Log.fatal("mysql failed executing this SQL statement:\n#{query}") + Chef::Log.fatal(cmd.stderr) + raise 'SQL ERROR' + end + cmd.stdout + end + + # Returns status code of sql query + def execute_sql_exitstatus(query, ctrl) + shell_out(sql_command_string(query, nil, ctrl), user: 'root').exitstatus + end + + def parse_one_row(row, titles) + return_hash = {} + index = 0 + row.split("\t").each do |column| + return_hash[titles[index]] = column + index += 1 + end + return_hash + end + + def parse_mysql_batch_result(mysql_batch_result) + results = mysql_batch_result.split("\n") + titles = [] + index = 0 + return_array = [] + results.each do |row| + if index == 0 + titles = row.split("\t") + else + return_array[index - 1] = parse_one_row(row, titles) + end + index += 1 + end + return_array + end + + def default_socket + case node['platform_family'] + when 'rhel', 'fedora', 'amazon' + '/var/lib/mysql/mysql.sock' + when 'debian' + '/var/run/mysqld/mysqld.sock' + end + end + + def percona_secure_random + r = SecureRandom.hex + Chef::Log.debug "Generated password: #{r}" + r + end + end + end +end + +Chef::DSL::Recipe.include ::Percona::Cookbook::Helpers +Chef::Resource.include ::Percona::Cookbook::Helpers diff --git a/libraries/passwords.rb b/libraries/passwords.rb index 5a883bb0..14cc750f 100644 --- a/libraries/passwords.rb +++ b/libraries/passwords.rb @@ -4,74 +4,68 @@ class Chef class EncryptedPasswords attr_accessor :node, :bag, :secret_file - def initialize(node, bag = "passwords") + def initialize(node, bag = 'passwords') @node = node @bag = bag - @secret_file = node["percona"]["encrypted_data_bag_secret_file"] - @mysql_item = node["percona"]["encrypted_data_bag_item_mysql"] - @system_item = node["percona"]["encrypted_data_bag_item_system"] + @secret_file = node['percona']['encrypted_data_bag_secret_file'] + @mysql_item = node['percona']['encrypted_data_bag_item_mysql'] + @system_item = node['percona']['encrypted_data_bag_item_system'] end # helper for passwords def find_password(item, user, default = nil) begin # attribute that controls use of chef-vault or encrypted data bags - vault = node["percona"]["use_chef_vault"] + vault = node['percona']['use_chef_vault'] # load password from the vault pwds = ChefVault::Item.load(bag, item) if vault # load the encrypted data bag item, using a secret if specified - pwds = Chef::EncryptedDataBagItem.load(@bag, item, secret) unless vault + pwds = Chef::EncryptedDataBagItem.load(@bag, item, secret) unless vault # rubocop:disable Chef/Modernize/DatabagHelpers # now, let's look for the user password password = pwds[user] - rescue Chef::Exceptions::ValidationFailed => e - raise "Validation failed loading data bag '#{@bag}/#{item}'." - rescue Net::HTTPServerException => e - raise "Validation failed loading data bag '#{@bag}/#{item}'." rescue Chef::Log.info("Unable to load password for #{user}, #{item},"\ - "fall back to non-encrypted password") + 'fall back to non-encrypted password') end - # Avoid generating random password if _somehow_ data bag fails to load. - unless password - Chef::Log.info("Dumping passwords from '#{@bag}/#{item}': #{pwds}") - end - + # password will be nil if no encrypted data bag was loaded + # fall back to the attribute on this node password || default end # mysql root def root_password - find_password @mysql_item, "root", node_server["root_password"] + find_password @mysql_item, 'root', node_server['root_password'] end # debian script user password def debian_password - nil + find_password( + @system_item, node_server['debian_username'], + node_server['debian_password'] + ) end # ? def old_passwords - find_password @mysql_item, "old_passwords", node_server["old_passwords"] + find_password @mysql_item, 'old_passwords', node_server['old_passwords'] end - # password for user responsbile for replicating in master/slave environment + # password for user responsbile for replicating in source/replica environment def replication_password - find_password( - @mysql_item, "replication", node_server["replication"]["password"] - ) + find_password @mysql_item, node_server['replication']['username'], node_server['replication']['password'] end # password for user responsbile for running xtrabackup def backup_password - backup = node["percona"]["backup"] - find_password @mysql_item, backup["username"], backup["password"] + backup = node['percona']['backup'] + find_password @mysql_item, backup['username'], backup['password'] end private # helper def node_server - @node["percona"]["server"] + @node['percona']['server'] end def data_bag_secret_file diff --git a/libraries/provider_mysql2_chef_gem.rb b/libraries/provider_mysql2_chef_gem.rb deleted file mode 100644 index 4849e9c8..00000000 --- a/libraries/provider_mysql2_chef_gem.rb +++ /dev/null @@ -1,33 +0,0 @@ -class Chef - class Provider - class Mysql2ChefGem - # Provider to install MySQL2 gem on systems using Percona databases - class Percona < Chef::Provider::LWRPBase - use_inline_resources if defined?(use_inline_resources) - - def whyrun_supported? - true - end - - def action_install - converge_by "install mysql2 chef_gem and dependencies" do - recipe_eval do - run_context.include_recipe "build-essential" - run_context.include_recipe "percona::client" - end - - chef_gem "mysql2" do - action :install - end - end - end - - def action_remove - chef_gem "mysql2" do - action :remove - end - end - end - end - end -end diff --git a/libraries/provider_mysql_chef_gem.rb b/libraries/provider_mysql_chef_gem.rb deleted file mode 100644 index 63623c29..00000000 --- a/libraries/provider_mysql_chef_gem.rb +++ /dev/null @@ -1,33 +0,0 @@ -class Chef - class Provider - class MysqlChefGem - # Provider to install MySQL gem on systems using Percona databases - class Percona < Chef::Provider::LWRPBase - use_inline_resources if defined?(use_inline_resources) - - def whyrun_supported? - true - end - - def action_install - converge_by "install mysql chef_gem and dependencies" do - recipe_eval do - run_context.include_recipe "build-essential" - run_context.include_recipe "percona::client" - end - - chef_gem "mysql" do - action :install - end - end - end - - def action_remove - chef_gem "mysql" do - action :remove - end - end - end - end - end -end diff --git a/metadata.rb b/metadata.rb index 212501a9..da13cdc7 100644 --- a/metadata.rb +++ b/metadata.rb @@ -1,33 +1,18 @@ -name "percona" -maintainer "Phil Cohen" -maintainer_email "github@phlippers.net" -license "MIT" -description "Installs Percona MySQL client and server" -long_description "Please refer to README.md" -version "5.11.21" +name 'percona' +maintainer 'Sous Chefs' +maintainer_email 'help@sous-chefs.org' +license 'Apache-2.0' +description 'Installs Percona MySQL client and server' +source_url 'https://github.com/sous-chefs/percona' +issues_url 'https://github.com/sous-chefs/percona/issues' +version '3.4.4' +chef_version '>= 16.0' -recipe "percona", "Includes the client recipe to configure a client" -recipe "percona::package_repo", "Sets up the package repository and installs dependent packages" -recipe "percona::client", "Installs client libraries" -recipe "percona::server", "Installs the server daemon" -recipe "percona::backup", "Installs the XtraBackup hot backup software" -recipe "percona::toolkit", "Installs the Percona Toolkit software" -recipe "percona::cluster", "Installs the Percona XtraDB Cluster server components" -recipe "percona::configure_server", "Used internally to manage the server configuration." -recipe "percona::replication", "Used internally to grant permissions for replication." -recipe "percona::access_grants", "Used internally to grant permissions for recipes" -recipe "percona::monitoring", "Installs Percona monitoring plugins for Nagios" +depends 'yum' +depends 'yum-epel' +depends 'line' -depends "apt", ">= 2.7.0" -depends "build-essential" -depends "openssl" -depends "yum-epel" -depends "chef-vault" - -supports "debian" -supports "ubuntu" -supports "centos" -supports "amazon" -supports "scientific" -supports "fedora" -supports "redhat" +supports 'centos' +supports 'debian' +supports 'redhat' +supports 'ubuntu' diff --git a/recipes/access_grants.rb b/recipes/access_grants.rb index d008d4e4..d681de1b 100644 --- a/recipes/access_grants.rb +++ b/recipes/access_grants.rb @@ -1,42 +1,42 @@ # -# Cookbook Name:: percona +# Cookbook:: percona # Recipe:: access_grants # -passwords = EncryptedPasswords.new(node, node["percona"]["encrypted_data_bag"]) +passwords = EncryptedPasswords.new(node, node['percona']['encrypted_data_bag']) # define access grants -template "/etc/mysql/grants.sql" do - source "grants.sql.erb" +template '/etc/mysql/grants.sql' do + source 'grants.sql.erb' variables( root_password: passwords.root_password, - debian_user: node["percona"]["server"]["debian_username"], + debian_user: node['percona']['server']['debian_username'], debian_password: passwords.debian_password, backup_password: passwords.backup_password ) - owner "root" - group "root" - mode "0600" + owner 'root' + group 'root' + mode '0600' sensitive true end # execute access grants if passwords.root_password && !passwords.root_password.empty? # Intent is to check whether the root_password works, and use it to - # load the grants if so. If not, try loading without a password + # load the grants if so. If not, try loading without a password # and see if we get lucky - execute "mysql-install-privileges" do # ~FC009 - `sensitive` - command "/usr/bin/mysql -p'#{passwords.root_password}' -e '' &> /dev/null > /dev/null &> /dev/null ; if [ $? -eq 0 ] ; then /usr/bin/mysql -p'#{passwords.root_password}' < /etc/mysql/grants.sql ; else /usr/bin/mysql < /etc/mysql/grants.sql ; fi ;" # rubocop:disable LineLength + execute 'mysql-install-privileges' do + command "/usr/bin/mysql -p'#{passwords.root_password}' -e '' &> /dev/null > /dev/null &> /dev/null ; if [ $? -eq 0 ] ; then /usr/bin/mysql -p'#{passwords.root_password}' < /etc/mysql/grants.sql ; else /usr/bin/mysql < /etc/mysql/grants.sql ; fi ;" action :nothing - subscribes :run, resources("template[/etc/mysql/grants.sql]"), :immediately + subscribes :run, resources('template[/etc/mysql/grants.sql]'), :immediately sensitive true end else - # Simpler path... just try running the grants command - execute "mysql-install-privileges" do - command "/usr/bin/mysql < /etc/mysql/grants.sql" + # Simpler path... just try running the grants command + execute 'mysql-install-privileges' do + command '/usr/bin/mysql < /etc/mysql/grants.sql' action :nothing - subscribes :run, resources("template[/etc/mysql/grants.sql]"), :immediately + subscribes :run, resources('template[/etc/mysql/grants.sql]'), :immediately sensitive true end end diff --git a/recipes/backup.rb b/recipes/backup.rb index d4a827b0..b0204a4a 100644 --- a/recipes/backup.rb +++ b/recipes/backup.rb @@ -1,21 +1,15 @@ # -# Cookbook Name:: percona +# Cookbook:: percona # Recipe:: backup # -node.normal["percona"]["backup"]["configure"] = true +node.default['percona']['backup']['configure'] = true -include_recipe "percona::package_repo" +include_recipe 'percona::package_repo' -case node["platform_family"] -when "debian" - package "xtrabackup" do - options "--force-yes" - end -when "rhel" - package "percona-xtrabackup" unless node['percona']['version'] == '5.7' - package "percona-xtrabackup-24" if node['percona']['version'] == '5.7' +package 'xtrabackup' do + package_name percona_backup_package end # access grants -include_recipe "percona::access_grants" unless node["percona"]["skip_passwords"] +include_recipe 'percona::access_grants' unless node['percona']['skip_passwords'] diff --git a/recipes/client.rb b/recipes/client.rb index 9fb8861b..5e7b5c1c 100644 --- a/recipes/client.rb +++ b/recipes/client.rb @@ -1,12 +1,13 @@ # -# Cookbook Name:: percona +# Cookbook:: percona # Recipe:: client # -include_recipe "percona::package_repo" +include_recipe 'percona::package_repo' -node["percona"]["client"]["packages"].each do |percona_client_pkg| - package percona_client_pkg do - action node["percona"]["client"]["package_action"].to_sym - end +pkgs = node['percona']['client']['packages'].empty? ? percona_client_packages : node['percona']['client']['packages'] +pkgs << percona_devel_package if node['percona']['client']['install_devel_package'] + +package pkgs do + action node['percona']['client']['package_action'].to_sym end diff --git a/recipes/cluster.rb b/recipes/cluster.rb index 8afb22d6..bb5162a2 100644 --- a/recipes/cluster.rb +++ b/recipes/cluster.rb @@ -1,51 +1,33 @@ # -# Cookbook Name:: percona +# Cookbook:: percona # Recipe:: cluster # -include_recipe "percona::package_repo" +node.default['percona']['repositories'] = %w(pxc-80) +node.default['percona']['client']['packages'] = percona_cluster_client_package + +include_recipe 'percona::package_repo' +include_recipe 'percona::client' # Determine and set wsrep_sst_receive_address -if node["percona"]["cluster"]["wsrep_sst_receive_interface"] - sst_interface = node["percona"]["cluster"]["wsrep_sst_receive_interface"] - sst_port = node["percona"]["cluster"]["wsrep_sst_receive_port"] +if node['percona']['cluster']['wsrep_sst_receive_interface'] + sst_interface = node['percona']['cluster']['wsrep_sst_receive_interface'] + sst_port = node['percona']['cluster']['wsrep_sst_receive_port'] ip = Percona::ConfigHelper.bind_to(node, sst_interface) address = "#{ip}:#{sst_port}" - node.set["percona"]["cluster"]["wsrep_sst_receive_address"] = address + node.default['percona']['cluster']['wsrep_sst_receive_address'] = address end -# set default package attributes -version = node["percona"]["version"] -node.default["percona"]["cluster"]["package"] = value_for_platform_family( - "debian" => "percona-xtradb-cluster-#{version.tr(".", "")}", - "rhel" => "Percona-XtraDB-Cluster-#{version.tr(".", "")}" -) +# This is required for `socat` per: +# www.percona.com/doc/percona-xtradb-cluster/5.6/installation/yum_repo.html +include_recipe 'yum-epel' if platform_family?('rhel') # install packages -case node["platform_family"] -when "debian" - package node["percona"]["cluster"]["package"] do - # The package starts up immediately, then additional config is added and the - # restart command fails to work. Instead, stop the database before changing - # the configuration. - notifies :stop, "service[mysql]", :immediately - end -when "rhel" - package "mysql-libs" do - action :remove - not_if "rpm -qa | grep -q '#{node["percona"]["cluster"]["package"]}'" - end - - # This is required for `socat` per: - # www.percona.com/doc/percona-xtradb-cluster/5.6/installation/yum_repo.html - include_recipe "yum-epel" - - package node["percona"]["cluster"]["package"] -end +package percona_cluster_package -unless node["percona"]["skip_configure"] - include_recipe "percona::configure_server" +unless node['percona']['skip_configure'] + include_recipe 'percona::configure_server' end # access grants -include_recipe "percona::access_grants" unless node["percona"]["skip_passwords"] +include_recipe 'percona::access_grants' unless node['percona']['skip_passwords'] diff --git a/recipes/configure_server.rb b/recipes/configure_server.rb index 218b9e66..72e10285 100644 --- a/recipes/configure_server.rb +++ b/recipes/configure_server.rb @@ -1,63 +1,75 @@ # -# Cookbook Name:: percona +# Cookbook:: percona # Recipe:: configure_server # -percona = node["percona"] -server = percona["server"] -conf = percona["conf"] -mysqld = (conf && conf["mysqld"]) || {} +percona = node['percona'] +server = percona['server'] +conf = percona['conf'] +mysqld = (conf && conf['mysqld']) || {} -# install chef-vault if needed -include_recipe "chef-vault" if node["percona"]["use_chef_vault"] +if node['percona']['server']['role'].include?('master') || node['percona']['server']['role'].include?('slave') + Chef::Log.warn('Please use source/replica instead of master/slave for the role name. The next major release of the percona cookbook will only support the new terms.') +end -# construct an encrypted passwords helper -- giving it the node and bag name -passwords = EncryptedPasswords.new(node, percona["encrypted_data_bag"]) +# setup SELinux if needed +unless node['percona']['selinux_module_url'].nil? || node['percona']['selinux_module_url'] == '' + semodule_filename = node['percona']['selinux_module_url'].split('/')[-1] + semodule_filepath = "#{Chef::Config[:file_cache_path]}/#{semodule_filename}" + remote_file semodule_filepath do + source node['percona']['selinux_module_url'] + only_if { semodule_filename && platform_family?('rhel') } + end -if node["percona"]["server"]["jemalloc"] - package_name = value_for_platform_family( - "debian" => "libjemalloc1", - "rhel" => "jemalloc" - ) + execute "semodule-install-#{semodule_filename}" do + command "/usr/sbin/semodule -i #{semodule_filepath}" + only_if { semodule_filename && platform_family?('rhel') } + only_if { shell_out("/usr/sbin/semodule -l | grep '^#{semodule_filename.split('.')[0..-2]}\\s'").stdout == '' } + end +end + +# construct an encrypted passwords helper -- giving it the node and bag name +passwords = EncryptedPasswords.new(node, percona['encrypted_data_bag']) - package package_name +if node['percona']['server']['jemalloc'] + package percona_jemalloc_package end -template "/root/.my.cnf" do +template '/root/.my.cnf' do variables(root_password: passwords.root_password) - owner "root" - group "root" - mode "0600" - source "my.cnf.root.erb" + owner 'root' + group 'root' + mode '0600' + source 'my.cnf.root.erb' sensitive true - not_if { node["percona"]["skip_passwords"] } + not_if { node['percona']['skip_passwords'] } end -if server["bind_to"] - ipaddr = Percona::ConfigHelper.bind_to(node, server["bind_to"]) - if ipaddr && server["bind_address"] != ipaddr - node.override["percona"]["server"]["bind_address"] = ipaddr - node.save unless Chef::Config[:solo] +if server['bind_to'] + ipaddr = Percona::ConfigHelper.bind_to(node, server['bind_to']) + if ipaddr && server['bind_address'] != ipaddr + node.override['percona']['server']['bind_address'] = ipaddr + node.save unless Chef::Config[:solo] # rubocop:disable Chef/Correctness/CookbookUsesNodeSave end - log "Can't find ip address for #{server["bind_to"]}" do + log "Can't find ip address for #{server['bind_to']}" do level :warn only_if { ipaddr.nil? } end end -datadir = mysqld["datadir"] || server["datadir"] -logdir = mysqld["logdir"] || server["logdir"] -tmpdir = mysqld["tmpdir"] || server["tmpdir"] -includedir = mysqld["includedir"] || server["includedir"] -user = mysqld["username"] || server["username"] -slow_query_logdir = mysqld["slow_query_logdir"] || server["slow_query_logdir"] +datadir = mysqld['datadir'] || server['datadir'] +logdir = mysqld['logdir'] || server['logdir'] +tmpdir = mysqld['tmpdir'] || server['tmpdir'] +includedir = mysqld['includedir'] || server['includedir'] +user = mysqld['username'] || server['username'] +slow_query_logdir = mysqld['slow_query_logdir'] || server['slow_query_logdir'] # this is where we dump sql templates for replication, etc. -directory "/etc/mysql" do - owner "root" - group "root" - mode "0755" +directory '/etc/mysql' do + owner 'root' + group 'root' + mode '0755' end # setup the data directory @@ -68,7 +80,7 @@ end # setup the log directory -directory "log directory" do +directory 'log directory' do path logdir owner user group user @@ -80,10 +92,11 @@ owner user group user recursive true + not_if { tmpdir == '/tmp' } end # setup the configuration include directory -unless includedir.empty? # ~FC023 +unless includedir.empty? directory includedir do # don't evaluate an empty `directory` resource owner user group user @@ -92,7 +105,7 @@ end # setup slow_query_logdir directory -directory "slow query log directory" do +directory 'slow query log directory' do path slow_query_logdir owner user group user @@ -101,70 +114,84 @@ end # define the service -service "mysql" do +service 'mysql' do supports restart: true - action server["enable"] ? :enable : :disable + action server['enable'] ? :enable : :disable end -initialize_mysqld = "mysql_install_db --defaults-file=#{percona["main_config_file"]} --user=#{user}" -initialize_mysqld = "mysqld --defaults-file=#{percona["main_config_file"]} --initialize-insecure --user=#{user}" if percona["version"] == "5.7" # rubocop:disable LineLength # install db to the data directory -execute "setup mysql datadir" do - command initialize_mysqld - not_if "test -f #{datadir}/mysql/user.frm" +execute 'setup mysql datadir' do + if node['percona']['version'].to_f >= 5.7 + command "mysqld --defaults-file=#{percona['main_config_file']} --user=#{user} --initialize-insecure" + else + command "mysql_install_db --defaults-file=#{percona['main_config_file']} --user=#{user}" + end + not_if { ::File.exist?("#{datadir}/mysql/user.frm") || ::File.exist?("#{datadir}/mysql.ibd") } action :nothing end -execute "setup mysql datadir" do - command "mysqld --defaults-file=#{percona["main_config_file"]} --initialize-insecure --user=#{user}" # rubocop:disable LineLength - not_if "test -f #{datadir}/mysql/user.frm" - only_if { percona["version"] == "5.7" } - action :nothing +# install SSL certificates before config phase +if node['percona']['server']['replication']['ssl_enabled'] + include_recipe 'percona::ssl' end -# install SSL certificates before config phase -if node["percona"]["server"]["replication"]["ssl_enabled"] - include_recipe "percona::ssl" +if Array(server['role']).include?('cluster') + wsrep_sst_auth = if node['percona']['cluster']['wsrep_sst_auth'] == '' + "#{node['percona']['backup']['username']}:#{passwords.backup_password}" + else + node['percona']['cluster']['wsrep_sst_auth'] + end end # setup the main server config file -template percona["main_config_file"] do - if Array(server["role"]).include?("cluster") - source "my.cnf.cluster.erb" +template percona['main_config_file'] do + if Array(server['role']).include?('cluster') + source node['percona']['main_config_template']['source']['cluster'] else - source "my.cnf.main.erb" + source node['percona']['main_config_template']['source']['default'] end - owner "root" - group "root" - mode "0644" + cookbook node['percona']['main_config_template']['cookbook'] + owner 'root' + group 'root' + mode '0644' sensitive true - notifies :run, "execute[setup mysql datadir]", :immediately - if node["percona"]["auto_restart"] - notifies :restart, "service[mysql]", :immediately + manage_symlink_source false + force_unlink true + variables( + jemalloc_lib: percona_jemalloc_lib, + wsrep_sst_auth: wsrep_sst_auth + ) + notifies :run, 'execute[setup mysql datadir]', :immediately + if node['percona']['auto_restart'] + notifies :restart, 'service[mysql]', :immediately end end # now let's set the root password only if this is the initial install -unless node["percona"]["skip_passwords"] +unless node['percona']['skip_passwords'] root_pw = passwords.root_password - execute "Update MySQL root password" do # ~FC009 - `sensitive` - command "mysqladmin --user=root --password='' password '#{root_pw}'" + execute 'Update MySQL root password' do + if node['percona']['version'].to_f < 5.7 + command "mysqladmin --user=root --password='' password '#{root_pw}'" + else + command "mysql --user=root --password='' -e \"ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '#{root_pw}';\"" + end only_if "mysqladmin --user=root --password='' version" sensitive true end end # setup the debian system user config -template "/etc/mysql/debian.cnf" do - source "debian.cnf.erb" +template '/etc/mysql/debian.cnf' do + source 'debian.cnf.erb' variables(debian_password: passwords.debian_password) - owner "root" - group "root" - mode "0640" + owner 'root' + group 'root' + mode '0640' sensitive true - if node["percona"]["auto_restart"] - notifies :restart, "service[mysql]", :immediately + if node['percona']['auto_restart'] + notifies :restart, 'service[mysql]', :immediately end - only_if { platform_family?("debian") } + only_if { platform_family?('debian') } end diff --git a/recipes/default.rb b/recipes/default.rb index 7f9a15b2..f29ad761 100644 --- a/recipes/default.rb +++ b/recipes/default.rb @@ -1,6 +1,6 @@ # -# Cookbook Name:: percona +# Cookbook:: percona # Recipe:: default # -include_recipe "percona::client" +include_recipe 'percona::client' diff --git a/recipes/monitoring.rb b/recipes/monitoring.rb deleted file mode 100644 index 53f72f4a..00000000 --- a/recipes/monitoring.rb +++ /dev/null @@ -1,10 +0,0 @@ -# -# Cookbook Name:: percona -# Recipe:: monitoring -# - -node["percona"]["plugins_packages"].each do |pkg| - package pkg do - version node["percona"]["plugins_version"] - end -end diff --git a/recipes/package_repo.rb b/recipes/package_repo.rb index e3b5a044..a27d4e56 100644 --- a/recipes/package_repo.rb +++ b/recipes/package_repo.rb @@ -1,37 +1,68 @@ # -# Cookbook Name:: percona +# Cookbook:: percona # Recipe:: package_repo # -return unless node["percona"]["use_percona_repos"] - -case node["platform_family"] -when "debian" - include_recipe "apt" +return unless node['percona']['use_percona_repos'] +case node['platform_family'] +when 'debian' # Pin this repo as to avoid upgrade conflicts with distribution repos. - apt_preference "00percona" do - glob "*" - pin "release o=Percona Development Team" - pin_priority "1001" + apt_preference '00percona' do + glob '*' + pin 'release o=Percona Development Team' + pin_priority '1001' + end + + apt_repository 'percona' do + uri node['percona']['apt']['uri'] + components ['main'] + keyserver node['percona']['apt']['keyserver'] + key node['percona']['apt']['key'] + end + + if node['percona']['version'].to_i >= 8 + node['percona']['repositories'].each do |repo| + apt_repository "percona-#{repo}" do + uri "http://repo.percona.com/#{repo}/apt" + components ['main'] + keyserver node['percona']['apt']['keyserver'] + key node['percona']['apt']['key'] + end + end + end + +when 'rhel' + dnf_module 'mysql' do + action :disable + only_if { node['platform_version'].to_i == 8 } end - apt_repository "percona" do - uri node["percona"]["apt"]["uri"] - distribution node["lsb"]["codename"] - components ["main"] - keyserver node["percona"]["apt"]["keyserver"] - key node["percona"]["apt"]["key"] + yum_repository 'percona' do + description node['percona']['yum']['description'] + baseurl "#{node['percona']['yum']['baseurl']}/$basearch" + gpgkey node['percona']['yum']['gpgkey'] + gpgcheck node['percona']['yum']['gpgcheck'] + sslverify node['percona']['yum']['sslverify'] end -when "rhel" - include_recipe "yum" + if node['percona']['version'].to_i >= 8 + node['percona']['repositories'].each do |repo| + yum_repository "percona-#{repo}" do + description node['percona']['yum']['description'] + ' - ' + repo + baseurl "http://repo.percona.com/#{repo}/yum/release/$releasever/RPMS/$basearch" + gpgkey node['percona']['yum']['gpgkey'] + gpgcheck node['percona']['yum']['gpgcheck'] + sslverify node['percona']['yum']['sslverify'] + end + end + end - yum_repository "percona" do - description node["percona"]["yum"]["description"] - baseurl node["percona"]["yum"]["baseurl"] - gpgkey node["percona"]["yum"]["gpgkey"] - gpgcheck node["percona"]["yum"]["gpgcheck"] - sslverify node["percona"]["yum"]["sslverify"] + yum_repository 'percona-noarch' do + description node['percona']['yum']['description'] + ' - noarch' + baseurl "#{node['percona']['yum']['baseurl']}/noarch" + gpgkey node['percona']['yum']['gpgkey'] + gpgcheck node['percona']['yum']['gpgcheck'] + sslverify node['percona']['yum']['sslverify'] end end diff --git a/recipes/replication.rb b/recipes/replication.rb index d485f33f..dab2401b 100644 --- a/recipes/replication.rb +++ b/recipes/replication.rb @@ -1,31 +1,31 @@ # -# Cookbook Name:: percona +# Cookbook:: percona # Recipe:: replication # -require "shellwords" +require 'shellwords' -passwords = EncryptedPasswords.new(node, node["percona"]["encrypted_data_bag"]) -server = node["percona"]["server"] -replication_sql = server["replication"]["replication_sql"] +passwords = EncryptedPasswords.new(node, node['percona']['encrypted_data_bag']) +server = node['percona']['server'] +replication_sql = server['replication']['replication_sql'] # define access grants template replication_sql do - source "replication.sql.erb" + source 'replication.sql.erb' variables(replication_password: passwords.replication_password) - owner "root" - group "root" - mode "0600" + owner 'root' + group 'root' + mode '0600' sensitive true only_if do - server["replication"]["host"] != "" || server["role"].include?("master") + (server['replication']['host'] != '' || server['role'].include?('source') || server['role'].include?('master')) && !::File.exist?(replication_sql) end end root_pass = passwords.root_password.to_s -root_pass = Shellwords.escape(root_pass).prepend("-p") unless root_pass.empty? +root_pass = Shellwords.escape(root_pass).prepend('-p') unless root_pass.empty? -execute "mysql-set-replication" do # ~FC009 - `sensitive` +execute 'mysql-set-replication' do command "/usr/bin/mysql #{root_pass} < #{replication_sql}" action :nothing subscribes :run, resources("template[#{replication_sql}]"), :immediately diff --git a/recipes/server.rb b/recipes/server.rb index fd4fb8eb..9dca37e6 100644 --- a/recipes/server.rb +++ b/recipes/server.rb @@ -1,45 +1,46 @@ # -# Cookbook Name:: percona +# Cookbook:: percona # Recipe:: server # -include_recipe "percona::package_repo" +include_recipe 'percona::package_repo' +include_recipe 'percona::client' -version = node["percona"]["version"] +pkg = node['percona']['server']['package'].empty? ? percona_server_package : node['percona']['server']['package'] -# install packages -case node["platform_family"] -when "debian" - node.default["percona"]["server"]["package"] = "percona-server-server-#{version}" # rubocop:disable LineLength - - package node["percona"]["server"]["package"] do - options "--force-yes" - action node["percona"]["server"]["package_action"].to_sym - end -when "rhel" - node.default["percona"]["server"]["package"] = "Percona-Server-server-#{version.tr(".", "")}" # rubocop:disable LineLength - node.default["percona"]["server"]["shared_pkg"] = "Percona-Server-shared-#{version.tr(".", "")}" # rubocop:disable LineLength - - # Need to remove this to avoid conflicts - package "mysql-libs" do - action :remove - not_if "rpm -qa | grep #{node["percona"]["server"]["shared_pkg"]}" - end - - # we need mysqladmin - include_recipe "percona::client" +package pkg do + action node['percona']['server']['package_action'].to_sym +end - package node["percona"]["server"]["package"] do - action node["percona"]["server"]["package_action"].to_sym +# install packages +if platform_family?('rhel') + # Work around issue with 5.7 on RHEL + if node['percona']['version'].to_f >= 5.7 + execute 'systemctl daemon-reload' do + action :nothing + end + + delete_lines 'remove PIDFile from systemd.service' do + path '/usr/lib/systemd/system/mysqld.service' + pattern /^PIDFile=.*/ + notifies :run, 'execute[systemctl daemon-reload]', :immediately + end + + replace_or_add 'configure LimitNOFILE in systemd.service' do + path '/usr/lib/systemd/system/mysqld.service' + pattern /^LimitNOFILE =.*/ + line "LimitNOFILE = #{node['percona']['server']['open_files_limit']}" + notifies :run, 'execute[systemctl daemon-reload]', :immediately + end end end -unless node["percona"]["skip_configure"] - include_recipe "percona::configure_server" +unless node['percona']['skip_configure'] + include_recipe 'percona::configure_server' end # access grants -unless node["percona"]["skip_passwords"] - include_recipe "percona::access_grants" - include_recipe "percona::replication" +unless node['percona']['skip_passwords'] + include_recipe 'percona::access_grants' + include_recipe 'percona::replication' end diff --git a/recipes/ssl.rb b/recipes/ssl.rb index e9cf1d5d..69edabe3 100644 --- a/recipes/ssl.rb +++ b/recipes/ssl.rb @@ -1,41 +1,41 @@ # -# Cookbook Name:: percona +# Cookbook:: percona # Recipe:: ssl # -certs_path = "/etc/mysql/ssl" -server = node["percona"]["server"] -data_bag = node["percona"]["encrypted_data_bag"] +certs_path = '/etc/mysql/ssl' +server = node['percona']['server'] +data_bag = node['percona']['encrypted_data_bag'] directory certs_path do - owner node["percona"]["server"]["username"] - mode "0700" + owner node['percona']['server']['username'] + mode '0700' end -certs = Chef::EncryptedDataBagItem.load( +certs = data_bag_item( data_bag, - node["percona"]["encrypted_data_bag_item_ssl_replication"] + node['percona']['encrypted_data_bag_item_ssl_replication'] ) -# place the CA certificate, it should be present on both master and slave +# place the CA certificate, it should be present on both source and replica file "#{certs_path}/cacert.pem" do - content certs["ca-cert"] + content certs['ca-cert'] sensitive true end -%w[cert key].each do |file| - # place certificate and key for master +%w(cert key).each do |file| + # place certificate and key for source file "#{certs_path}/server-#{file}.pem" do - content certs["server"]["server-#{file}"] + content certs['server']["server-#{file}"] sensitive true - only_if { server["role"].include?("master") } + only_if { server['role'].include?('source') || server['role'].include?('master') } end - # because in a master-master setup a master could also be a slave - # place slave certificate and key + # because in a source-source setup a source could also be a replica + # place replica certificate and key file "#{certs_path}/client-#{file}.pem" do - content certs["client"]["client-#{file}"] + content certs['client']["client-#{file}"] sensitive true - only_if { server["role"].include?("slave") } + only_if { server['role'].include?('replica') || server['role'].include?('slave') } end end diff --git a/recipes/toolkit.rb b/recipes/toolkit.rb index fcced0fa..01ae45c9 100644 --- a/recipes/toolkit.rb +++ b/recipes/toolkit.rb @@ -1,17 +1,10 @@ # -# Cookbook Name:: percona +# Cookbook:: percona # Recipe:: toolkit # -include_recipe "percona::package_repo" +include_recipe 'percona::package_repo' -# Workaround a bug in the RPM packaging of percona-toolkit. Otherwise, it'll -# try to pull in Percona-Server-shared-51, which will conflict with 5.5. -# https://bugs.launchpad.net/percona-toolkit/+bug/1031427 -if platform_family?("rhel") && node["percona"]["version"].match(/5\.[15]/) - package "Percona-Server-shared-compat" -end - -package "percona-toolkit" do - options "--force-yes" if platform_family?("debian") +unless node['percona']['version'].to_i >= 8 && platform_family?('rhel') && node['platform_version'].to_i >= 8 + package 'percona-toolkit' end diff --git a/renovate.json b/renovate.json new file mode 100644 index 00000000..7e7a8bad --- /dev/null +++ b/renovate.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": ["config:base"], + "packageRules": [{ + "groupName": "Actions", + "matchUpdateTypes": ["patch", "pin", "digest"], + "automerge": true, + "addLabels": ["Release: Patch", "Skip: Announcements"] + }, + { + "groupName": "Actions", + "matchUpdateTypes": ["major"], + "automerge": false, + "addLabels": ["Release: Patch", "Skip: Announcements"] + } + ] +} diff --git a/resources/mysql_database.rb b/resources/mysql_database.rb new file mode 100644 index 00000000..d47d0d4f --- /dev/null +++ b/resources/mysql_database.rb @@ -0,0 +1,89 @@ +# +# Cookbook:: percona +# Resource:: database +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +provides :percona_mysql_database +unified_mode true + +include Percona::Cookbook::Helpers +include Percona::Cookbook + +property :database_name, String, name_property: true +property :host, [String, nil], default: 'localhost', desired_state: false +property :port, [Integer, nil], default: 3306, desired_state: false +property :user, [String, nil], default: 'root', desired_state: false +property :socket, [String, nil], desired_state: false +property :password, [String, nil], sensitive: true, desired_state: false +property :encoding, String, default: lazy { percona_default_encoding } +property :collation, String, default: lazy { percona_default_collate } +property :sql, String + +action :create do + if current_resource.nil? + converge_by "Creating database '#{new_resource.database_name}'" do + create_sql = "CREATE DATABASE IF NOT EXISTS \\`#{new_resource.database_name}\\`" + create_sql << " CHARACTER SET = #{new_resource.encoding}" if new_resource.encoding + create_sql << " COLLATE = #{new_resource.collation}" if new_resource.collation + run_query(create_sql, nil) + end + else + converge_if_changed :encoding do + run_query("ALTER SCHEMA \\`#{new_resource.database_name}\\` CHARACTER SET #{new_resource.encoding}", nil) + end + converge_if_changed :collation do + run_query("ALTER SCHEMA \\`#{new_resource.database_name}\\` COLLATE #{new_resource.collation}", nil) + end + end +end + +action :drop do + return if current_resource.nil? + converge_by "Dropping database '#{new_resource.database_name}'" do + run_query("DROP DATABASE IF EXISTS \\`#{new_resource.database_name}\\`", nil) + end +end + +action :query do + run_query(new_resource.sql, nil) +end + +load_current_value do + lsocket = (host == 'localhost') ? default_socket : nil + ctrl = { user: user, password: password + }.merge!(lsocket.nil? ? { host: host, port: port } : { socket: lsocket }) + query = "SHOW DATABASES LIKE '#{database_name}'" + results = execute_sql(query, nil, ctrl).split("\n") + current_value_does_not_exist! if results.count == 0 + + results = execute_sql("SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = '#{database_name}'", nil, ctrl) + results.split("\n").each do |row| + columns = row.split("\t") + if columns[0] != 'DEFAULT_CHARACTER_SET_NAME' + encoding columns[0] + collation columns[1] + end + end +end + +action_class do + include Percona::Cookbook::Helpers + + def run_query(query, database) + socket = (new_resource.socket && new_resource.host == 'localhost') ? new_resource.socket : nil + ctrl_hash = { host: new_resource.host, port: new_resource.port, user: new_resource.user, password: new_resource.password, socket: socket } + Chef::Log.debug("#{@new_resource}: Performing query [#{query}]") + execute_sql(query, database, ctrl_hash) + end +end diff --git a/resources/mysql_user.rb b/resources/mysql_user.rb new file mode 100644 index 00000000..13c7d0fd --- /dev/null +++ b/resources/mysql_user.rb @@ -0,0 +1,320 @@ +# +# Cookbook:: percona +# Resource:: user +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +provides :percona_mysql_user +unified_mode true + +include Percona::Cookbook::Helpers +include Percona::Cookbook + +property :username, String, name_property: true +property :password, [String, HashedPassword, NilClass], default: nil, sensitive: true +property :host, String, default: 'localhost', desired_state: false +property :database_name, String +property :table, String +property :privileges, Array, default: [:all] +property :grant_option, [true, false], default: false +property :require_ssl, [true, false], default: false +property :require_x509, [true, false], default: false +property :use_native_auth, [true, false], default: true +# Credentials used for control connection +property :ctrl_user, [String, NilClass], default: 'root', desired_state: false +property :ctrl_password, [String, NilClass], sensitive: true, desired_state: false +property :ctrl_host, [String, NilClass], default: 'localhost', desired_state: false +property :ctrl_port, [Integer, NilClass], default: 3306, desired_state: false + +action :create do + if current_resource.nil? + converge_by "Creating user '#{new_resource.username}'@'#{new_resource.host}'" do + create_sql = "CREATE USER '#{new_resource.username}'@'#{new_resource.host}'" + unless database_has_password_column + create_sql << ' REQUIRE SSL' if new_resource.require_ssl + create_sql << ' REQUIRE X509' if new_resource.require_x509 + create_sql << ' WITH GRANT OPTION' if new_resource.grant_option + end + run_query create_sql + update_user_password if new_resource.password + end + elsif !test_user_password + update_user_password + end +end + +load_current_value do + socket = ctrl_host == 'localhost' ? default_socket : nil + ctrl = { user: ctrl_user, password: ctrl_password + }.merge!(socket.nil? ? { host: ctrl_host, port: ctrl_port.to_s } : { socket: socket }) + query = "SELECT User,Host FROM mysql.user WHERE User='#{username}' AND Host='#{host}';" + results = execute_sql(query, nil, ctrl) + current_value_does_not_exist! if results.split("\n").count <= 1 +end + +action_class do + include Percona::Cookbook::Helpers + + def run_query(query) + socket = new_resource.ctrl_host == 'localhost' ? default_socket : nil + ctrl_hash = { user: new_resource.ctrl_user, password: new_resource.ctrl_password }.merge!(socket.nil? ? { host: new_resource.ctrl_host, port: new_resource.ctrl_port } : { socket: socket }) + Chef::Log.debug("#{@new_resource}: Performing query [#{query}]") + execute_sql(query, nil, ctrl_hash) + end + + def database_has_password_column + begin + result = run_query("SHOW COLUMNS FROM mysql.user WHERE Field='Password';") + rescue + return false + end + result.split("\n").count > 1 + end + + def redact_password(query, password) + if password.nil? || password == '' + query + else + query.gsub(password.to_s, 'REDACTED') + end + end + + def test_user_password + if database_has_password_column + test_sql = 'SELECT User,Host,Password FROM mysql.user ' \ + "WHERE User='#{new_resource.username}' AND Host='#{new_resource.host}' " + test_sql << if new_resource.password.is_a? HashedPassword + "AND Password='#{new_resource.password}'" + else + "AND Password=PASSWORD('#{new_resource.password}')" + end + run_query(test_sql).split("\n").count > 1 + else # Works for any authentication method as long as the host is localhost + test_sql = "SELECT 'user can login'" + socket = new_resource.host == 'localhost' ? default_socket : nil + # Passing host instead of ctrl_host to validate the user@scope login instead of user@ctrl_host + user_hash = { user: new_resource.username, password: new_resource.password }.merge!(socket.nil? ? { host: new_resource.host, port: new_resource.ctrl_port } : { socket: socket }) + Chef::Log.debug("#{@new_resource}: Performing query [#{test_sql}]") + + if execute_sql_exitstatus(test_sql, user_hash) == 0 + true + else # handles mysql_native_password authentication method + test_sql = 'SELECT User,Host,authentication_string FROM mysql.user ' \ + "WHERE User='#{new_resource.username}' AND Host='#{new_resource.host}' " # \ + test_sql << if new_resource.password.is_a? HashedPassword + "AND authentication_string='#{new_resource.password}'" + elsif new_resource.password != '' + # This is the password auth algorithm implmented by PASSWORD() which no longer exists on mysql 8 + "AND authentication_string=CONCAT('*', UPPER(SHA1(UNHEX(SHA1('#{new_resource.password}')))))" + else + "AND authentication_string=''" + end + run_query(test_sql).split("\n").count > 1 + end + end + end + + def update_user_password + converge_by "Update password for user '#{new_resource.username}'@'#{new_resource.host}'" do + if database_has_password_column + password_sql = "SET PASSWORD FOR '#{new_resource.username}'@'#{new_resource.host}' = " + password_sql << if new_resource.password.is_a? HashedPassword + "'#{new_resource.password}'" + else + " PASSWORD('#{new_resource.password}')" + end + else + # "ALTER USER is now the preferred statement for assigning passwords." + # http://dev.mysql.com/doc/refman/5.7/en/set-password.html + password_sql = "ALTER USER '#{new_resource.username}'@'#{new_resource.host}' " + password_sql << if new_resource.password.is_a? HashedPassword + "IDENTIFIED WITH mysql_native_password AS '#{new_resource.password}'" + elsif new_resource.use_native_auth + "IDENTIFIED WITH mysql_native_password BY '#{new_resource.password}'" + else + "IDENTIFIED BY '#{new_resource.password}'" + end + end + run_query password_sql + end + end + + def desired_privs + possible_global_privs = [ + :select, + :insert, + :update, + :delete, + :create, + :drop, + :references, + :index, + :alter, + :create_tmp_table, + :lock_tables, + :create_view, + :show_view, + :create_routine, + :alter_routine, + :execute, + :event, + :trigger, + :reload, + :shutdown, + :process, + :file, + :show_db, + :super, + :repl_slave, + :repl_client, + :create_user, + ] + possible_db_privs = [ + :select, + :insert, + :update, + :delete, + :create, + :drop, + :references, + :index, + :alter, + :create_tmp_table, + :lock_tables, + :create_view, + :show_view, + :create_routine, + :alter_routine, + :execute, + :event, + :trigger, + ] + + # convert :all to the individual db or global privs + if new_resource.privileges == [:all] && new_resource.database_name + possible_db_privs + elsif new_resource.privileges == [:all] + possible_global_privs + else + new_resource.privileges + end + end + + def revokify_key(key) + return '' if key.nil? + + # Some keys need to be translated as outlined by the table found here: + # https://dev.mysql.com/doc/refman/5.7/en/privileges-provided.html + result = key.to_s.downcase.tr('_', ' ').gsub('repl ', 'replication ').gsub('create tmp table', 'create temporary tables').gsub('show db', 'show databases') + result.gsub(/ priv$/, '') + end +end + +action :drop do + return if current_resource.nil? + converge_by "Dropping user '#{new_resource.username}'@'#{new_resource.host}'" do + drop_sql = 'DROP USER' + drop_sql << " '#{new_resource.username}'@'#{new_resource.host}'" + run_query drop_sql + end +end + +action :grant do + db_name = new_resource.database_name ? "\\`#{new_resource.database_name}\\`" : '*' + tbl_name = new_resource.table || '*' + test_table = new_resource.database_name ? 'mysql.db' : 'mysql.user' + + # Test + incorrect_privs = nil + test_sql = "SELECT * from #{test_table}" + test_sql << " WHERE User='#{new_resource.username}'" + test_sql << " AND Host='#{new_resource.host}'" + test_sql << " AND Db='#{new_resource.database_name}'" if new_resource.database_name + test_sql_results = run_query test_sql + + incorrect_privs = true if test_sql_results.split("\n").count == 0 + # These should all be 'Y' + unless test_sql_results.split("\n").count <= 1 + parsed_result = parse_mysql_batch_result(test_sql_results) + Chef::Log.debug(parsed_result) + parsed_result.each do |r| + desired_privs.each do |p| + key = p.to_s.capitalize.tr(' ', '_').gsub('Replication_', 'Repl_').gsub('Create_temporary_tables', 'Create_tmp_table').gsub('Show_databases', 'Show_db') + key = "#{key}_priv" + incorrect_privs = true if r[key] != 'Y' + end + end + end + + password_up_to_date = incorrect_privs || test_user_password + + # Repair + if incorrect_privs + converge_by "Granting privs for '#{new_resource.username}'@'#{new_resource.host}'" do + formatted_privileges = new_resource.privileges.map do |p| + p.to_s.upcase.tr('_', ' ').gsub('REPL ', 'REPLICATION ').gsub('CREATE TMP TABLE', 'CREATE TEMPORARY TABLES').gsub('SHOW DB', 'SHOW DATABASES') + end + repair_sql = "GRANT #{formatted_privileges.join(',')}" + repair_sql << " ON #{db_name}.#{tbl_name}" + repair_sql << " TO '#{new_resource.username}'@'#{new_resource.host}'" + if database_has_password_column + repair_sql << ' REQUIRE SSL' if new_resource.require_ssl + repair_sql << ' REQUIRE X509' if new_resource.require_x509 + repair_sql << ' WITH GRANT OPTION' if new_resource.grant_option + end + + redacted_sql = redact_password(repair_sql, new_resource.password) + Chef::Log.debug("#{@new_resource}: granting with sql [#{redacted_sql}]") + run_query(repair_sql) + run_query('FLUSH PRIVILEGES') + end + else + # The grants are correct, but perhaps the password needs updating? + update_user_password unless password_up_to_date + end +end + +action :revoke do + db_name = new_resource.database_name ? "\\`#{new_resource.database_name}\\`" : '*' + tbl_name = new_resource.table || '*' + test_table = new_resource.database_name ? 'mysql.db' : 'mysql.user' + + privs_to_revoke = [] + test_sql = "SELECT * from #{test_table}" + test_sql << " WHERE User='#{new_resource.username}'" + test_sql << " AND Host='#{new_resource.host}'" + test_sql << " AND Db='#{new_resource.database_name}'" if new_resource.database_name + test_sql_results = run_query test_sql + + # These should all be 'N' + test_sql_results.each do |r| + desired_privs.each do |p| + key = p.to_s.capitalize.tr(' ', '_').gsub('Replication_', 'Repl_').gsub('Create_temporary_tables', 'Create_tmp_table').gsub('Show_databases', 'Show_db') + key = "#{key}_priv" + privs_to_revoke << revokify_key(p) if r[key] != 'N' + end + end + + # Repair + unless privs_to_revoke.empty? + converge_by "Revoking privs for '#{new_resource.username}'@'#{new_resource.host}'" do + revoke_statement = "REVOKE #{privs_to_revoke.join(',')}" + revoke_statement << " ON #{db_name}.#{tbl_name}" + revoke_statement << " FROM \\`#{new_resource.username}\\`@\\`#{new_resource.host}\\` " + + Chef::Log.debug("#{@new_resource}: revoking access with statement [#{revoke_statement}]") + run_query revoke_statement + run_query 'FLUSH PRIVILEGES' + end + end +end diff --git a/spec/access_grants_spec.rb b/spec/access_grants_spec.rb index 1f6b7d97..babf97ae 100644 --- a/spec/access_grants_spec.rb +++ b/spec/access_grants_spec.rb @@ -1,42 +1,59 @@ -require "spec_helper" +require 'spec_helper' + +describe 'percona::access_grants' do + platform 'ubuntu' -describe "percona::access_grants" do let(:grant_file) do - "/etc/mysql/grants.sql" + '/etc/mysql/grants.sql' end - let(:chef_run) do - ChefSpec::SoloRunner.new do |node| - node.set["percona"]["server"]["root_password"] = "s3kr1t" - end.converge(described_recipe) - end + override_attributes['percona']['server']['root_password'] = 's3kr1t' + override_attributes['percona']['server']['debian_password'] = 's3kr1t' + override_attributes['percona']['backup']['password'] = 's3kr1t' - it "writes the `grants.sql` file" do + it 'writes the `grants.sql` file' do expect(chef_run).to create_template(grant_file).with( - owner: "root", - group: "root", - mode: "0600", - sensitive: true + owner: 'root', + group: 'root', + mode: '0600', + sensitive: true, + variables: { + root_password: 's3kr1t', + debian_password: 's3kr1t', + backup_password: 's3kr1t', + debian_user: 'debian-sys-maint', + } ) end - it "adds the root password to `grants.sql`" do + it 'adds the root password to `grants.sql`' do expect(chef_run).to render_file(grant_file).with_content( - "SET PASSWORD FOR 'root'@'localhost' = PASSWORD('s3kr1t')" + "ALTER USER 'root'@'localhost' IDENTIFIED BY 's3kr1t';" ) end - it "executes the `install privileges` command" do - expect(chef_run).to_not run_execute("mysql-install-privileges") + context 'Percona < 8.0' do + override_attributes['percona']['version'] = '5.7' + override_attributes['percona']['server']['root_password'] = 's3kr1t' + it 'adds the root password to `grants.sql`' do + expect(chef_run).to render_file(grant_file).with_content( + "SET PASSWORD FOR 'root'@'localhost' = PASSWORD('s3kr1t');" + ) + end + end + + it 'executes the `install privileges` command' do + expect(chef_run).to nothing_execute('mysql-install-privileges') + .with(command: "/usr/bin/mysql -p's3kr1t' -e '' &> /dev/null > /dev/null &> /dev/null ; if [ $? -eq 0 ] ; then /usr/bin/mysql -p's3kr1t' < /etc/mysql/grants.sql ; else /usr/bin/mysql < /etc/mysql/grants.sql ; fi ;") - exec_resource = chef_run.execute("mysql-install-privileges") + exec_resource = chef_run.execute('mysql-install-privileges') expect(exec_resource).to( subscribe_to("template[#{grant_file}]").on(:run).immediately ) tmpl_resource = chef_run.template(grant_file) expect(tmpl_resource).to( - notify("execute[mysql-install-privileges]").to(:run).immediately + notify('execute[mysql-install-privileges]').to(:run).immediately ) end end diff --git a/spec/backup_spec.rb b/spec/backup_spec.rb index 8b2ff5f2..84e2f396 100644 --- a/spec/backup_spec.rb +++ b/spec/backup_spec.rb @@ -1,24 +1,38 @@ -require "spec_helper" +require 'spec_helper' -describe "percona::backup" do - describe "Ubuntu" do - let(:chef_run) do - ChefSpec::SoloRunner.new.converge(described_recipe) +describe 'percona::backup' do + context 'Ubuntu' do + platform 'ubuntu' + + it { expect(chef_run).to include_recipe('percona::package_repo') } + it { expect(chef_run).to install_package('xtrabackup') } + it { expect(chef_run).to include_recipe('percona::access_grants') } + + context 'Ubuntu 20.04' do + platform 'ubuntu', '20.04' + it { expect(chef_run).to install_package('percona-xtrabackup-80') } end - it { expect(chef_run).to include_recipe("percona::package_repo") } - it { expect(chef_run).to install_package("xtrabackup") } - it { expect(chef_run).to include_recipe("percona::access_grants") } + context 'Debian 10' do + platform 'debian', '10' + it { expect(chef_run).to install_package('percona-xtrabackup-80') } + end end - describe "CentOS" do - let(:chef_run) do - env_options = { platform: "centos", version: "6.5" } - ChefSpec::SoloRunner.new(env_options).converge(described_recipe) + context 'CentOS' do + platform 'centos' + + before do + stub_command('dnf module list mysql | grep -q "^mysql.*\\[x\\]"') end - it { expect(chef_run).to include_recipe("percona::package_repo") } - it { expect(chef_run).to install_package("percona-xtrabackup") } - it { expect(chef_run).to include_recipe("percona::access_grants") } + it { expect(chef_run).to include_recipe('percona::package_repo') } + it { expect(chef_run).to install_package('xtrabackup') } + it { expect(chef_run).to include_recipe('percona::access_grants') } + + context 'CentOS 8' do + platform 'centos', '8' + it { expect(chef_run).to install_package('percona-xtrabackup-80') } + end end end diff --git a/spec/client_spec.rb b/spec/client_spec.rb index a4963c76..8d90283b 100644 --- a/spec/client_spec.rb +++ b/spec/client_spec.rb @@ -1,56 +1,100 @@ -require "spec_helper" +require 'spec_helper' -describe "percona::client" do - describe "when `package_action` is `install`" do - describe "Ubuntu" do - let(:chef_run) do - ChefSpec::SoloRunner.new.converge(described_recipe) +describe 'percona::client' do + before do + stub_command('dnf module list mysql | grep -q "^mysql.*\\[x\\]"') + end + + describe 'when `package_action` is `install`' do + context 'Ubuntu' do + platform 'ubuntu' + + it do + expect(chef_run).to install_package 'percona-server-client' + end + + it do + expect(chef_run).to_not install_package 'libperconaserverclient21-dev' end - specify do - expect(chef_run).to install_package "libperconaserverclient18.1-dev" - expect(chef_run).to install_package "percona-server-client-5.6" + context 'version 5.7' do + override_attributes['percona']['version'] = '5.7' + it do + expect(chef_run).to install_package 'percona-server-client-5.7' + end + end + + context 'version 5.6' do + override_attributes['percona']['version'] = '5.6' + it do + expect(chef_run).to install_package 'percona-server-client-5.6' + end end end - describe "CentOS" do - let(:chef_run) do - env_options = { platform: "centos", version: "6.5" } - ChefSpec::SoloRunner.new(env_options).converge(described_recipe) + context 'CentOS' do + platform 'centos' + + it do + expect(chef_run).to install_package 'percona-server-client' + end + + it do + expect(chef_run).to_not install_package 'percona-server-devel' end - specify do - expect(chef_run).to install_package "Percona-Server-devel-56" - expect(chef_run).to install_package "Percona-Server-client-56" + context 'version 5.7' do + override_attributes['percona']['version'] = '5.7' + it do + expect(chef_run).to install_package 'Percona-Server-client-57' + end + end + + context 'version 5.6' do + override_attributes['percona']['version'] = '5.6' + it do + expect(chef_run).to install_package 'Percona-Server-client-56' + end end end end - describe "when `package_action` is `upgrade`" do - describe "Ubuntu" do - let(:chef_run) do - ChefSpec::SoloRunner.new do |node| - node.set["percona"]["client"]["package_action"] = "upgrade" - end.converge(described_recipe) + describe 'when `package_action` is `upgrade`' do + context 'Ubuntu' do + platform 'ubuntu' + override_attributes['percona']['client']['package_action'] = 'upgrade' + + it do + expect(chef_run).to upgrade_package 'percona-server-client' end + end + + context 'CentOS' do + platform 'centos' + override_attributes['percona']['client']['package_action'] = 'upgrade' - specify do - expect(chef_run).to upgrade_package "libperconaserverclient18.1-dev" - expect(chef_run).to upgrade_package "percona-server-client-5.6" + it do + expect(chef_run).to upgrade_package 'percona-server-client' end end + end + + describe 'when `install_devel_package` is `true`' do + context 'Ubuntu' do + platform 'ubuntu' + override_attributes['percona']['client']['install_devel_package'] = true - describe "CentOS" do - let(:chef_run) do - env_options = { platform: "centos", version: "6.5" } - ChefSpec::SoloRunner.new(env_options) do |node| - node.set["percona"]["client"]["package_action"] = "upgrade" - end.converge(described_recipe) + it do + expect(chef_run).to install_package %w(percona-server-client libperconaserverclient21-dev) end + end + + context 'CentOS' do + platform 'centos' + override_attributes['percona']['client']['install_devel_package'] = true - specify do - expect(chef_run).to upgrade_package "Percona-Server-devel-56" - expect(chef_run).to upgrade_package "Percona-Server-client-56" + it do + expect(chef_run).to install_package %w(percona-server-client percona-server-devel) end end end diff --git a/spec/cluster_spec.rb b/spec/cluster_spec.rb index 88fed1f8..40387ca2 100644 --- a/spec/cluster_spec.rb +++ b/spec/cluster_spec.rb @@ -1,116 +1,113 @@ -require "spec_helper" +require 'spec_helper' -describe "percona::cluster" do - let(:chef_run) do - ChefSpec::SoloRunner.new.converge(described_recipe) - end +describe 'percona::cluster' do + platform 'ubuntu' before do - stub_command("test -f /var/lib/mysql/mysql/user.frm").and_return(true) - stub_command("mysqladmin --user=root --password='' version") - .and_return(true) - end - - specify do - expect(chef_run).to include_recipe "percona::package_repo" - expect(chef_run).to include_recipe "percona::configure_server" - expect(chef_run).to include_recipe "percona::access_grants" - - expect(chef_run).to_not include_recipe "yum-epel" + stub_command('test -f /var/lib/mysql/mysql/user.frm').and_return(true) + stub_command("mysqladmin --user=root --password='' version").and_return(true) + stub_command('dnf module list mysql | grep -q "^mysql.*\\[x\\]"') end - describe "version 5.5" do - let(:chef_run) do - ChefSpec::SoloRunner.new do |node| - node.set["percona"]["version"] = "5.5" - end.converge(described_recipe) + %w( + percona::package_repo + percona::client + percona::configure_server + percona::access_grants + ).each do |r| + it do + expect(chef_run).to include_recipe r end + end - let(:centos_cluster_package) do - "Percona-XtraDB-Cluster-55" - end + it do + expect(chef_run).to_not include_recipe 'yum-epel' + end - let(:ubuntu_cluster_package) do - "percona-xtradb-cluster-55" - end + describe 'version 5.6' do + override_attributes['percona']['version'] = '5.6' - describe "Ubuntu" do - specify do - expect(chef_run).to install_package(ubuntu_cluster_package) + describe 'Ubuntu' do + it do + expect(chef_run).to install_package 'percona-xtradb-cluster-5.6' + end - expect(chef_run.package(ubuntu_cluster_package)).to( - notify("service[mysql]").to(:stop).immediately - ) + it do + expect(chef_run).to install_package 'percona-xtradb-cluster-client-5.6' end end - describe "CentOS" do - let(:chef_run) do - env_options = { platform: "centos", version: "6.5" } - ChefSpec::SoloRunner.new(env_options) do |node| - node.set["percona"]["version"] = "5.5" - end.converge(described_recipe) - end + describe 'CentOS' do + platform 'centos' - before do - stub_command("rpm -qa | grep -q 'Percona-XtraDB-Cluster-55'") - .and_return(false) + it do + expect(chef_run).to include_recipe 'yum-epel' end - specify do - expect(chef_run).to remove_package "mysql-libs" - - expect(chef_run).to include_recipe "yum-epel" + it do + expect(chef_run).to install_package 'Percona-XtraDB-Cluster-56' + end - expect(chef_run).to install_package centos_cluster_package + it do + expect(chef_run).to install_package 'Percona-XtraDB-Cluster-client-56' end end end + describe 'version 5.7' do + override_attributes['percona']['version'] = '5.7' - describe "version 5.6" do - let(:chef_run) do - ChefSpec::SoloRunner.new do |node| - node.set["percona"]["version"] = "5.6" - end.converge(described_recipe) - end + describe 'Ubuntu' do + it do + expect(chef_run).to install_package 'percona-xtradb-cluster-5.7' + end - let(:centos_cluster_package) do - "Percona-XtraDB-Cluster-56" + it do + expect(chef_run).to install_package 'percona-xtradb-cluster-client-5.7' + end end - let(:ubuntu_cluster_package) do - "percona-xtradb-cluster-56" - end + describe 'CentOS' do + platform 'centos' + + it do + expect(chef_run).to include_recipe 'yum-epel' + end - describe "Ubuntu" do - specify do - expect(chef_run).to install_package(ubuntu_cluster_package) + it do + expect(chef_run).to install_package 'Percona-XtraDB-Cluster-57' + end - expect(chef_run.package(ubuntu_cluster_package)).to( - notify("service[mysql]").to(:stop).immediately - ) + it do + expect(chef_run).to install_package 'Percona-XtraDB-Cluster-client-57' end end + end + describe 'version 8.0' do + override_attributes['percona']['version'] = '8.0' - describe "CentOS" do - let(:chef_run) do - env_options = { platform: "centos", version: "6.5" } - ChefSpec::SoloRunner.new(env_options) do |node| - node.set["percona"]["version"] = "5.6" - end.converge(described_recipe) + describe 'Ubuntu' do + it do + expect(chef_run).to install_package 'percona-xtradb-cluster-server' end - before do - stub_command("rpm -qa | grep -q 'Percona-XtraDB-Cluster-56'") - .and_return(false) + it do + expect(chef_run).to install_package 'percona-xtradb-cluster-client' end + end - specify do - expect(chef_run).to remove_package "mysql-libs" + describe 'CentOS' do + platform 'centos' - expect(chef_run).to include_recipe "yum-epel" + it do + expect(chef_run).to include_recipe 'yum-epel' + end + + it do + expect(chef_run).to install_package 'percona-xtradb-cluster-server' + end - expect(chef_run).to install_package centos_cluster_package + it do + expect(chef_run).to install_package 'percona-xtradb-cluster-client' end end end diff --git a/spec/configure_server_spec.rb b/spec/configure_server_spec.rb index cb801809..dce8b322 100644 --- a/spec/configure_server_spec.rb +++ b/spec/configure_server_spec.rb @@ -1,271 +1,361 @@ -require "spec_helper" - -describe "percona::configure_server" do - describe "first run" do - let(:chef_run) do - ChefSpec::SoloRunner.new.converge(described_recipe) - end +require 'spec_helper' +describe 'percona::configure_server' do + platform 'ubuntu' + describe 'first run' do before do - stub_command("test -f /var/lib/mysql/mysql/user.frm").and_return(false) - stub_command("mysqladmin --user=root --password='' version") - .and_return(true) - end - - it "does not include the `chef-vault` recipe" do - expect(chef_run).to_not include_recipe "chef-vault" - end - - it "creates the main server config file" do - expect(chef_run).to create_template("/etc/mysql/my.cnf").with( - owner: "root", - group: "root", - mode: "0644" + allow(File).to receive(:exist?).and_call_original + allow(File).to receive(:exist?).with('var/lib/mysql/mysql/user.frm').and_return(false) + allow(File).to receive(:exist?).with('/var/lib/mysql.ibd').and_return(false) + stub_command("mysqladmin --user=root --password='' version").and_return(true) + end + + describe 'inclusion tests' do + context 'role master' do + override_attributes['percona']['server']['role'] = %w(master) + it do + expect(Chef::Log).to receive(:warn).with('Please use source/replica instead of master/slave for the role name. The next major release of the percona cookbook will only support the new terms.') + chef_run + end + end + context 'role slave' do + override_attributes['percona']['server']['role'] = %w(slave) + it do + expect(Chef::Log).to receive(:warn).with('Please use source/replica instead of master/slave for the role name. The next major release of the percona cookbook will only support the new terms.') + chef_run + end + end + end + + it 'creates the main server config file' do + expect(chef_run).to create_template('/etc/mysql/my.cnf').with( + owner: 'root', + group: 'root', + mode: '0644', + cookbook: 'percona', + source: 'my.cnf.main.erb', + manage_symlink_source: false, + force_unlink: true ) - expect(chef_run).to render_file("/etc/mysql/my.cnf").with_content( - "performance_schema=OFF" + expect(chef_run).to render_file('/etc/mysql/my.cnf').with_content( + 'performance_schema=OFF' ) - resource = chef_run.template("/etc/mysql/my.cnf") - expect(resource).to notify("execute[setup mysql datadir]").to(:run).immediately # rubocop:disable LineLength - expect(resource).to notify("service[mysql]").to(:restart).immediately + resource = chef_run.template('/etc/mysql/my.cnf') + expect(resource).to notify('execute[setup mysql datadir]').to(:run).immediately + expect(resource).to notify('service[mysql]').to(:restart).immediately end - it "creates the data directory" do - expect(chef_run).to create_directory("/var/lib/mysql").with( - owner: "mysql", - group: "mysql", + it 'creates the data directory' do + expect(chef_run).to create_directory('/var/lib/mysql').with( + owner: 'mysql', + group: 'mysql', recursive: true ) end - it "defines the setup for the data directory" do - resource = chef_run.execute("setup mysql datadir") - expect(resource).to do_nothing + it 'defines the setup for the data directory' do + expect(chef_run).to nothing_execute('setup mysql datadir').with(command: 'mysqld --defaults-file=/etc/mysql/my.cnf --user=mysql --initialize-insecure') end - it "creates the log directory" do - expect(chef_run).to create_directory("log directory").with( - path: "/var/log/mysql", - owner: "mysql", - group: "mysql", - recursive: true - ) + context 'version < 5.7' do + override_attributes['percona']['version'] = '5.6' + it 'defines the setup for the data directory' do + expect(chef_run).to nothing_execute('setup mysql datadir').with(command: 'mysql_install_db --defaults-file=/etc/mysql/my.cnf --user=mysql') + end end - it "do not create duplicated slow query log directory" do - expect(chef_run).to_not create_directory("slow query log directory").with( - path: "/var/log/mysql", - owner: "mysql", - group: "mysql", + it 'creates the log directory' do + expect(chef_run).to create_directory('log directory').with( + path: '/var/log/mysql', + owner: 'mysql', + group: 'mysql', recursive: true ) end - it "creates the temporary directory" do - expect(chef_run).to create_directory("/tmp").with( - owner: "mysql", - group: "mysql", + it 'do not create duplicated slow query log directory' do + expect(chef_run).to_not create_directory('slow query log directory').with( + path: '/var/log/mysql', + owner: 'mysql', + group: 'mysql', recursive: true ) end - it "creates the configuration include directory" do - expect(chef_run).to create_directory("/etc/mysql/conf.d/").with( - owner: "mysql", - group: "mysql", + it 'does not create temporary directory since it is /tmp' do + expect(chef_run).to_not create_directory('/tmp') + end + + it 'creates the configuration include directory' do + expect(chef_run).to create_directory('/etc/mysql/conf.d/').with( + owner: 'mysql', + group: 'mysql', recursive: true ) end - it "updates the root user password" do - expect(chef_run).to run_execute("Update MySQL root password") + it 'updates the root user password' do + expect(chef_run).to run_execute('Update MySQL root password') end end - describe "subsequent runs" do - let(:chef_run) do - ChefSpec::SoloRunner.new do |node| - node.set["percona"]["main_config_file"] = "/mysql/my.cnf" - node.set["percona"]["server"]["root_password"] = "s3kr1t" - node.set["percona"]["server"]["debian_password"] = "d3b1an" - node.set["percona"]["server"]["performance_schema"] = true - node.set["percona"]["conf"]["mysqld"]["datadir"] = "/mysql/data" - node.set["percona"]["conf"]["mysqld"]["tmpdir"] = "/mysql/tmp" - node.set["percona"]["conf"]["mysqld"]["includedir"] = "/mysql/conf.d" - end.converge(described_recipe) - end + describe 'subsequent runs' do + override_attributes['percona']['main_config_file'] = '/mysql/my.cnf' + override_attributes['percona']['server']['root_password'] = 's3kr1t' + override_attributes['percona']['server']['debian_password'] = 'd3b1an' + override_attributes['percona']['server']['performance_schema'] = true + override_attributes['percona']['conf']['mysqld']['datadir'] = '/mysql/data' + override_attributes['percona']['conf']['mysqld']['tmpdir'] = '/mysql/tmp' + override_attributes['percona']['conf']['mysqld']['includedir'] = '/mysql/conf.d' before do - stub_command("test -f /mysql/data/mysql/user.frm").and_return(true) - stub_command("mysqladmin --user=root --password='' version") - .and_return(false) + allow(File).to receive(:exist?).and_call_original + allow(File).to receive(:exist?).with('var/lib/mysql/mysql/user.frm').and_return(true) + allow(File).to receive(:exist?).with('/var/lib/mysql.ibd').and_return(true) + stub_command("mysqladmin --user=root --password='' version").and_return(false) end - it "creates a `.my.cnf` file for root" do - expect(chef_run).to create_template("/root/.my.cnf").with( - owner: "root", - group: "root", - mode: "0600", + it 'creates a `.my.cnf` file for root' do + expect(chef_run).to create_template('/root/.my.cnf').with( + owner: 'root', + group: 'root', + mode: '0600', sensitive: true ) - expect(chef_run).to render_file("/root/.my.cnf").with_content("s3kr1t") + expect(chef_run).to render_file('/root/.my.cnf').with_content('s3kr1t') end - it "creates the configuration directory" do - expect(chef_run).to create_directory("/etc/mysql").with( - owner: "root", - group: "root", - mode: "0755" + it 'creates the configuration directory' do + expect(chef_run).to create_directory('/etc/mysql').with( + owner: 'root', + group: 'root', + mode: '0755' ) end - it "creates the data directory" do - expect(chef_run).to create_directory("/mysql/data").with( - owner: "mysql", - group: "mysql", + it 'creates the data directory' do + expect(chef_run).to create_directory('/mysql/data').with( + owner: 'mysql', + group: 'mysql', recursive: true ) end - it "creates the temporary directory" do - expect(chef_run).to create_directory("/mysql/tmp").with( - owner: "mysql", - group: "mysql", + it 'creates the temporary directory' do + expect(chef_run).to create_directory('/mysql/tmp').with( + owner: 'mysql', + group: 'mysql', recursive: true ) end - it "creates the configuration include directory" do - expect(chef_run).to create_directory("/mysql/conf.d").with( - owner: "mysql", - group: "mysql", + it 'creates the configuration include directory' do + expect(chef_run).to create_directory('/mysql/conf.d').with( + owner: 'mysql', + group: 'mysql', recursive: true ) end - it "creates the slow query log directory" do - expect(chef_run).to create_directory("/var/log/mysql").with( - owner: "mysql", - group: "mysql", + it 'creates the slow query log directory' do + expect(chef_run).to create_directory('/var/log/mysql').with( + owner: 'mysql', + group: 'mysql', recursive: true ) end - it "manages the `mysql` service" do - expect(chef_run).to enable_service("mysql") + it 'manages the `mysql` service' do + expect(chef_run).to enable_service('mysql') end - it "defines the setup for the data directory" do - resource = chef_run.execute("setup mysql datadir") - expect(resource).to do_nothing + it 'defines the setup for the data directory' do + expect(chef_run).to nothing_execute('setup mysql datadir') end - it "creates the main server config file" do - expect(chef_run).to create_template("/mysql/my.cnf").with( - owner: "root", - group: "root", - mode: "0644", - sensitive: true + it 'creates the main server config file' do + expect(chef_run).to create_template('/mysql/my.cnf').with( + owner: 'root', + group: 'root', + mode: '0644', + sensitive: true, + cookbook: 'percona', + source: 'my.cnf.main.erb' ) - expect(chef_run).to render_file("/mysql/my.cnf").with_content( - "performance_schema=ON" + expect(chef_run).to render_file('/mysql/my.cnf').with_content( + 'performance_schema=ON' ) - resource = chef_run.template("/mysql/my.cnf") - expect(resource).to notify("execute[setup mysql datadir]").to(:run).immediately # rubocop:disable LineLength - expect(resource).to notify("service[mysql]").to(:restart).immediately + resource = chef_run.template('/mysql/my.cnf') + expect(resource).to notify('execute[setup mysql datadir]').to(:run).immediately + expect(resource).to notify('service[mysql]').to(:restart).immediately end - it "does not update the root user password" do - expect(chef_run).to_not run_execute("Update MySQL root password") + it 'does not update the root user password' do + expect(chef_run).to_not run_execute('Update MySQL root password') end - it "creates the debian system user config file" do - debian_cnf = "/etc/mysql/debian.cnf" + it 'creates the debian system user config file' do + debian_cnf = '/etc/mysql/debian.cnf' expect(chef_run).to create_template(debian_cnf).with( - owner: "root", - group: "root", - mode: "0640", + owner: 'root', + group: 'root', + mode: '0640', sensitive: true ) - expect(chef_run).to render_file(debian_cnf).with_content("d3b1an") + expect(chef_run).to render_file(debian_cnf).with_content('d3b1an') resource = chef_run.template(debian_cnf) - expect(resource).to notify("service[mysql]").to(:restart).immediately + expect(resource).to notify('service[mysql]').to(:restart).immediately end end - describe "custom slow query log directory" do - let(:chef_run) do - ChefSpec::SoloRunner.new do |node| - node.set["percona"]["server"]["slow_query_logdir"] = "/var/log/slowq" - end.converge(described_recipe) - end + describe 'custom slow query log directory' do + override_attributes['percona']['server']['slow_query_logdir'] = '/var/log/slowq' before do - stub_command("mysqladmin --user=root --password='' version") - .and_return(true) + stub_command("mysqladmin --user=root --password='' version").and_return(true) end - it "creates the slow query log directory" do - expect(chef_run).to create_directory("/var/log/slowq").with( - owner: "mysql", - group: "mysql", + it 'creates the slow query log directory' do + expect(chef_run).to create_directory('/var/log/slowq').with( + owner: 'mysql', + group: 'mysql', recursive: true ) end end - describe "`rhel` platform family" do - let(:chef_run) do - env_options = { platform: "centos", version: "6.5" } - ChefSpec::SoloRunner.new(env_options).converge(described_recipe) + describe 'jemalloc enabled' do + before do + stub_command("mysqladmin --user=root --password='' version").and_return(true) end - before do - stub_command("test -f /var/lib/mysql/mysql/user.frm").and_return(false) - stub_command("mysqladmin --user=root --password='' version") - .and_return(true) + override_attributes['percona']['server']['jemalloc'] = true + + context 'Debian 10' do + platform 'debian', '10' + + it do + expect(chef_run).to install_package 'libjemalloc2' + end + + it 'sets the correct malloc-lib path' do + expect(chef_run).to render_file('/etc/mysql/my.cnf').with_content( + %r{^malloc-lib.*= /usr/lib/x86_64-linux-gnu/libjemalloc.so.2} + ) + end end + context 'Debian 11' do + platform 'debian', '11' - it "creates the main server config file" do - expect(chef_run).to create_template("/etc/my.cnf").with( - owner: "root", - group: "root", - mode: "0644", - sensitive: true - ) + it do + expect(chef_run).to install_package 'libjemalloc2' + end + + it 'sets the correct malloc-lib path' do + expect(chef_run).to render_file('/etc/mysql/my.cnf').with_content( + %r{^malloc-lib.*= /usr/lib/x86_64-linux-gnu/libjemalloc.so.2} + ) + end + end + context 'Ubuntu 20.04' do + platform 'ubuntu', '20.04' + + it do + expect(chef_run).to install_package 'libjemalloc2' + end + + it 'sets the correct malloc-lib path' do + expect(chef_run).to render_file('/etc/mysql/my.cnf').with_content( + %r{^malloc-lib.*= /usr/lib/x86_64-linux-gnu/libjemalloc.so.2} + ) + end + end + context 'Ubuntu 18.04' do + platform 'ubuntu', '18.04' + + it do + expect(chef_run).to install_package 'libjemalloc1' + end - resource = chef_run.template("/etc/my.cnf") - expect(resource).to notify("execute[setup mysql datadir]").to(:run).immediately # rubocop:disable LineLength - expect(resource).to notify("service[mysql]").to(:restart).immediately + it 'sets the correct malloc-lib path' do + expect(chef_run).to render_file('/etc/mysql/my.cnf').with_content( + %r{^malloc-lib.*= /usr/lib/x86_64-linux-gnu/libjemalloc.so.1} + ) + end end + context 'CentOS 8' do + platform 'centos', '8' + + it do + expect(chef_run).to install_package 'jemalloc' + end - it "does not create the configuration include directory" do - expect(chef_run).to_not create_directory("/mysql/conf.d") + it 'sets the correct malloc-lib path' do + expect(chef_run).to render_file('/etc/my.cnf').with_content( + %r{^malloc-lib.*= /usr/lib64/libjemalloc.so.2} + ) + end + end + context 'CentOS 7' do + platform 'centos', '7' + + it do + expect(chef_run).to install_package 'jemalloc' + end + + it 'sets the correct malloc-lib path' do + expect(chef_run).to render_file('/etc/my.cnf').with_content( + %r{^malloc-lib.*= /usr/lib64/libjemalloc.so.1} + ) + end end end - describe "`chef-vault` support" do - let(:chef_run) do - ChefSpec::SoloRunner.new do |node| - node.set["percona"]["use_chef_vault"] = true - end.converge(described_recipe) + context '`rhel` platform family' do + platform 'centos' + + before do + stub_command("mysqladmin --user=root --password='' version").and_return(true) + stub_command('dnf module list mysql | grep -q "^mysql.*\\[x\\]"') + end + + it 'creates the main server config file' do + expect(chef_run).to create_template('/etc/my.cnf').with( + owner: 'root', + group: 'root', + mode: '0644', + sensitive: true, + cookbook: 'percona', + source: 'my.cnf.main.erb' + ) + + resource = chef_run.template('/etc/my.cnf') + expect(resource).to notify('execute[setup mysql datadir]').to(:run).immediately + expect(resource).to notify('service[mysql]').to(:restart).immediately end + it 'does not create the configuration include directory' do + expect(chef_run).to_not create_directory('/mysql/conf.d') + end + end + + describe '`chef-vault` support' do + override_attributes['percona']['use_chef_vault'] = true + before do - stub_command("mysqladmin --user=root --password='' version") - .and_return(false) + stub_command("mysqladmin --user=root --password='' version").and_return(false) end - it "includes the `chef-vault` recipe" do - expect(chef_run).to include_recipe "chef-vault" + it 'converges successfully' do + expect { chef_run }.to_not raise_error end end end diff --git a/spec/default_spec.rb b/spec/default_spec.rb index a5a3236d..ed9447ec 100644 --- a/spec/default_spec.rb +++ b/spec/default_spec.rb @@ -1,9 +1,9 @@ -require "spec_helper" +require 'spec_helper' -describe "percona::default" do - let(:chef_run) do - ChefSpec::SoloRunner.new.converge(described_recipe) - end +describe 'percona::default' do + platform 'ubuntu' - it { expect(chef_run).to include_recipe("percona::client") } + it do + expect(chef_run).to include_recipe('percona::client') + end end diff --git a/spec/monitoring_spec.rb b/spec/monitoring_spec.rb deleted file mode 100644 index 8a76dded..00000000 --- a/spec/monitoring_spec.rb +++ /dev/null @@ -1,11 +0,0 @@ -require "spec_helper" - -describe "percona::monitoring" do - let(:chef_run) do - ChefSpec::SoloRunner.new.converge(described_recipe) - end - - it { expect(chef_run).to install_package("percona-nagios-plugins") } - it { expect(chef_run).to install_package("percona-zabbix-templates") } - it { expect(chef_run).to install_package("percona-cacti-templates") } -end diff --git a/spec/package_repo_spec.rb b/spec/package_repo_spec.rb index 83e98ac5..ac68c2b8 100644 --- a/spec/package_repo_spec.rb +++ b/spec/package_repo_spec.rb @@ -1,28 +1,96 @@ -require "spec_helper" +require 'spec_helper' -describe "percona::package_repo" do - describe "Ubuntu" do - let(:chef_run) do - ChefSpec::SoloRunner.new.converge(described_recipe) +describe 'percona::package_repo' do + context 'ubuntu' do + platform 'ubuntu' + + it do + expect(chef_run).to add_apt_repository('percona').with( + uri: 'http://repo.percona.com/apt', + components: %w(main), + keyserver: 'keyserver.ubuntu.com', + key: %w(9334A25F8507EFA5) + ) + end + + it do + expect(chef_run).to add_apt_preference('00percona').with( + glob: '*', + pin: 'release o=Percona Development Team', + pin_priority: '1001' + ) end - it "sets up an apt repository for `percona`" do - expect(chef_run).to add_apt_repository("percona") + it do + expect(chef_run).to add_apt_repository('percona-ps-80').with( + uri: 'http://repo.percona.com/ps-80/apt', + components: %w(main), + keyserver: 'keyserver.ubuntu.com', + key: %w(9334A25F8507EFA5) + ) end - it "sets up an apt preference" do - expect(chef_run).to add_apt_preference("00percona") + context 'version < 8.0' do + override_attributes['percona']['version'] = '5.7' + + it do + expect(chef_run).to_not add_apt_repository('percona-ps-80') + end end end - describe "CentOS" do - let(:chef_run) do - env_options = { platform: "centos", version: "6.5" } - ChefSpec::SoloRunner.new(env_options).converge(described_recipe) + context 'centos' do + platform 'centos' + + it do + expect(chef_run).to disable_dnf_module('mysql') + end + + it do + expect(chef_run).to create_yum_repository('percona').with( + description: 'Percona Packages', + baseurl: 'http://repo.percona.com/yum/release/$releasever/RPMS/$basearch', + gpgkey: [ + 'https://repo.percona.com/yum/PERCONA-PACKAGING-KEY', + 'https://repo.percona.com/yum/RPM-GPG-KEY-Percona', + ], + gpgcheck: true, + sslverify: true + ) + end + + it do + expect(chef_run).to create_yum_repository('percona-noarch').with( + description: 'Percona Packages - noarch', + baseurl: 'http://repo.percona.com/yum/release/$releasever/RPMS/noarch', + gpgkey: [ + 'https://repo.percona.com/yum/PERCONA-PACKAGING-KEY', + 'https://repo.percona.com/yum/RPM-GPG-KEY-Percona', + ], + gpgcheck: true, + sslverify: true + ) end - it "sets up a yum repository for `percona`" do - expect(chef_run).to create_yum_repository("percona") + it do + expect(chef_run).to create_yum_repository('percona-ps-80').with( + description: 'Percona Packages - ps-80', + baseurl: 'http://repo.percona.com/ps-80/yum/release/$releasever/RPMS/$basearch', + gpgkey: [ + 'https://repo.percona.com/yum/PERCONA-PACKAGING-KEY', + 'https://repo.percona.com/yum/RPM-GPG-KEY-Percona', + ], + gpgcheck: true, + sslverify: true + ) + end + + context 'version < 8.0' do + override_attributes['percona']['version'] = '5.7' + + it do + expect(chef_run).to_not create_yum_repository('percona-ps-80') + end end end end diff --git a/spec/replication_spec.rb b/spec/replication_spec.rb index b309f458..90d153e7 100644 --- a/spec/replication_spec.rb +++ b/spec/replication_spec.rb @@ -1,50 +1,147 @@ -require "spec_helper" +require 'spec_helper' -describe "percona::replication" do +describe 'percona::replication' do + platform 'ubuntu' let(:replication_sql) do - "/etc/mysql/replication.sql" + '/etc/mysql/replication.sql' end - describe "without replication configured" do - let(:chef_run) do - ChefSpec::SoloRunner.new do |node| - node.set["percona"]["server"]["role"] = [] - node.set["percona"]["server"]["replication"]["host"] = "" - end.converge(described_recipe) - end + describe 'without replication configured' do + override_attributes['percona']['server']['role'] = [] + override_attributes['percona']['server']['replication']['host'] = '' - it "does not create a replication template" do + it 'does not create a replication template' do expect(chef_run).to_not create_template(replication_sql) end - it "does not execute the replication sql" do - expect(chef_run).to_not run_execute("mysql-set-replication") + it 'does not execute the replication sql' do + expect(chef_run).to_not run_execute('mysql-set-replication') - resource = chef_run.execute("mysql-set-replication") + resource = chef_run.execute('mysql-set-replication') expect(resource).to do_nothing end end - describe "with replication configured" do - let(:chef_run) do - ChefSpec::SoloRunner.new do |node| - node.set["percona"]["server"]["role"] = ["master"] - node.set["percona"]["server"]["replication"]["password"] = "s3kr1t" - end.converge(described_recipe) - end + describe 'with replication configured' do + override_attributes['percona']['server']['role'] = %w(source) + override_attributes['percona']['server']['root_password'] = 's3kr1t' + override_attributes['percona']['server']['replication']['password'] = 's3kr1t' + override_attributes['percona']['server']['replication']['username'] = 'replication' + override_attributes['percona']['server']['replication']['host'] = 'master-host' - it "creates a replication template" do + it 'creates a replication template' do expect(chef_run).to create_template(replication_sql).with( - owner: "root", - group: "root", - mode: "0600", + owner: 'root', + group: 'root', + mode: '0600', sensitive: true ) - expect(chef_run).to render_file(replication_sql).with_content("s3kr1t") + [ + /CREATE USER IF NOT EXISTS 'replication'@'%' IDENTIFIED BY 's3kr1t';/, + /GRANT REPLICATION SLAVE ON \*\.\* TO 'replication'@'%';/, + /MASTER_HOST='master-host'/, + /MASTER_USER='replication'/, + /MASTER_PASSWORD='s3kr1t'/, + ].each do |line| + expect(chef_run).to render_file(replication_sql).with_content(line) + end + end + + context 'role master' do + override_attributes['percona']['server']['role'] = %w(master) + it 'creates a replication template' do + expect(chef_run).to create_template(replication_sql).with( + owner: 'root', + group: 'root', + mode: '0600', + sensitive: true + ) + [ + /CREATE USER IF NOT EXISTS 'replication'@'%' IDENTIFIED BY 's3kr1t';/, + /GRANT REPLICATION SLAVE ON \*\.\* TO 'replication'@'%';/, + /MASTER_HOST='master-host'/, + /MASTER_USER='replication'/, + /MASTER_PASSWORD='s3kr1t'/, + ].each do |line| + expect(chef_run).to render_file(replication_sql).with_content(line) + end + end end - it "executes the replication sql" do - resource = chef_run.execute("mysql-set-replication") + context 'version 5.7' do + override_attributes['percona']['version'] = '5.7' + it do + [ + /GRANT REPLICATION SLAVE ON \*\.\* TO 'replication'@'%' IDENTIFIED BY 's3kr1t';/, + /MASTER_HOST='master-host'/, + /MASTER_USER='replication'/, + /MASTER_PASSWORD='s3kr1t'/, + ].each do |line| + expect(chef_run).to render_file(replication_sql).with_content(line) + end + end + end + + context 'ssl enabled' do + override_attributes['percona']['server']['replication']['ssl_enabled'] = true + it do + [ + /ALTER USER 'replication'@'%' REQUIRE SSL;/, + /MASTER_SSL=1/, + %r{MASTER_SSL_CA='/etc/mysql/ssl/cacert.pem'}, + %r{MASTER_SSL_CERT='/etc/mysql/ssl/server-cert.pem'}, + %r{MASTER_SSL_KEY='/etc/mysql/ssl/server-key.pem'}, + ].each do |line| + expect(chef_run).to render_file(replication_sql).with_content(line) + end + end + + context 'version 5.7' do + override_attributes['percona']['version'] = '5.7' + it do + [ + /GRANT REPLICATION SLAVE ON *.* TO 'replication'@'%' IDENTIFIED BY 's3kr1t' REQUIRE SSL;/, + /MASTER_SSL=1/, + %r{MASTER_SSL_CA='/etc/mysql/ssl/cacert.pem'}, + %r{MASTER_SSL_CERT='/etc/mysql/ssl/server-cert.pem'}, + %r{MASTER_SSL_KEY='/etc/mysql/ssl/server-key.pem'}, + ].each do |line| + expect(chef_run).to render_file(replication_sql).with_content(line) + end + end + end + + context 'role replica' do + override_attributes['percona']['server']['role'] = %w(replica) + it do + [ + %r{MASTER_SSL_CERT='/etc/mysql/ssl/client-cert.pem'}, + %r{MASTER_SSL_KEY='/etc/mysql/ssl/client-key.pem'}, + ].each do |line| + expect(chef_run).to render_file(replication_sql).with_content(line) + end + end + end + + context 'role slave' do + override_attributes['percona']['server']['role'] = %w(slave) + it do + [ + %r{MASTER_SSL_CERT='/etc/mysql/ssl/client-cert.pem'}, + %r{MASTER_SSL_KEY='/etc/mysql/ssl/client-key.pem'}, + ].each do |line| + expect(chef_run).to render_file(replication_sql).with_content(line) + end + end + end + end + + it 'executes the replication sql' do + resource = chef_run.execute('mysql-set-replication') + expect(chef_run).to nothing_execute('mysql-set-replication').with( + command: '/usr/bin/mysql -ps3kr1t < /etc/mysql/replication.sql', + sensitive: true + ) expect(resource).to( subscribe_to("template[#{replication_sql}]").on(:run).immediately ) diff --git a/spec/server_spec.rb b/spec/server_spec.rb index 8f1d728f..492b43ee 100644 --- a/spec/server_spec.rb +++ b/spec/server_spec.rb @@ -1,101 +1,113 @@ -require "spec_helper" +require 'spec_helper' -describe "percona::server" do - let(:chef_run) do - ChefSpec::SoloRunner.new.converge(described_recipe) - end +describe 'percona::server' do + platform 'ubuntu' before do - stub_command("test -f /var/lib/mysql/mysql/user.frm").and_return(true) - stub_command("mysqladmin --user=root --password='' version") - .and_return(true) + stub_command("mysqladmin --user=root --password='' version").and_return(true) + stub_command('dnf module list mysql | grep -q "^mysql.*\\[x\\]"') end - it { expect(chef_run).to include_recipe("percona::package_repo") } - it { expect(chef_run).to include_recipe("percona::configure_server") } - it { expect(chef_run).to include_recipe("percona::access_grants") } - it { expect(chef_run).to include_recipe("percona::replication") } + it { expect(chef_run).to include_recipe('percona::client') } + + describe 'Ubuntu' do + platform 'ubuntu' + + it { expect(chef_run).to include_recipe('percona::package_repo') } + it { expect(chef_run).to include_recipe('percona::configure_server') } + it { expect(chef_run).to include_recipe('percona::access_grants') } + it { expect(chef_run).to include_recipe('percona::replication') } + it { expect(chef_run).to install_package('percona-server-server') } + + context 'version 5.7' do + override_attributes['percona']['version'] = '5.7' + it do + expect(chef_run).to install_package 'percona-server-server-5.7' + end + end - describe "Ubuntu" do - it { expect(chef_run).to install_package("percona-server-server-5.6") } + context 'version 5.6' do + override_attributes['percona']['version'] = '5.6' + it do + expect(chef_run).to install_package 'percona-server-server-5.6' + end + end end - describe "CentOS" do - let(:shared_pkg) do - "Percona-Server-shared-56" + context 'CentOS' do + platform 'centos' + + it { expect(chef_run).to install_package('percona-server-server') } + + it do + expect(chef_run).to nothing_execute('systemctl daemon-reload') end - let(:chef_run) do - env_options = { platform: "centos", version: "6.5" } - ChefSpec::SoloRunner.new(env_options).converge(described_recipe) + it do + expect(chef_run).to edit_delete_lines('remove PIDFile from systemd.service').with( + path: '/usr/lib/systemd/system/mysqld.service' + # pattern: /^PIDFile=.*/ TODO: this errors out with + ) end - before do - stub_command("rpm -qa | grep #{shared_pkg}").and_return(false) + it do + expect(chef_run.delete_lines('remove PIDFile from systemd.service')).to \ + notify('execute[systemctl daemon-reload]').to(:run).immediately end - describe "without percona server shared package" do - it { expect(chef_run).to remove_package("mysql-libs") } + it do + expect(chef_run).to edit_replace_or_add('configure LimitNOFILE in systemd.service').with( + path: '/usr/lib/systemd/system/mysqld.service', + line: 'LimitNOFILE = 16384' + # pattern: /^LimitNOFILE =.*/ TODO: this errors out with + ) end - describe "with percona server shared package" do - before do - stub_command("rpm -qa | grep #{shared_pkg}").and_return(true) - end + it do + expect(chef_run.replace_or_add('configure LimitNOFILE in systemd.service')).to \ + notify('execute[systemctl daemon-reload]').to(:run).immediately + end - it { expect(chef_run).to_not remove_package("mysql-libs") } + context 'version 5.7' do + override_attributes['percona']['version'] = '5.7' + it do + expect(chef_run).to install_package 'Percona-Server-server-57' + end end - it { expect(chef_run).to include_recipe("percona::client") } - it { expect(chef_run).to install_package("Percona-Server-server-56") } + context 'version 5.6' do + override_attributes['percona']['version'] = '5.6' + it do + expect(chef_run).to install_package 'Percona-Server-server-56' + end + end end - describe "when `skip_configure` is true" do - let(:chef_run) do - ChefSpec::SoloRunner.new do |node| - node.set["percona"]["skip_configure"] = true - end.converge(described_recipe) - end + describe 'when `skip_configure` is true' do + override_attributes['percona']['skip_configure'] = true - it { expect(chef_run).to_not include_recipe("percona::configure_server") } + it { expect(chef_run).to_not include_recipe('percona::configure_server') } end - describe "when `skip_passwords` is true" do - let(:chef_run) do - ChefSpec::SoloRunner.new do |node| - node.set["percona"]["skip_passwords"] = true - end.converge(described_recipe) - end + describe 'when `skip_passwords` is true' do + override_attributes['percona']['skip_passwords'] = true - it { expect(chef_run).to_not include_recipe("percona::access_grants") } - it { expect(chef_run).to_not include_recipe("percona::replication") } + it { expect(chef_run).to_not include_recipe('percona::access_grants') } + it { expect(chef_run).to_not include_recipe('percona::replication') } end - describe "when `package_action` is `upgrade`" do - describe "Ubuntu" do - let(:chef_run) do - ChefSpec::SoloRunner.new do |node| - node.set["percona"]["server"]["package_action"] = "upgrade" - end.converge(described_recipe) - end + describe 'when `package_action` is `upgrade`' do + describe 'Ubuntu' do + override_attributes['percona']['server']['package_action'] = 'upgrade' - it { expect(chef_run).to upgrade_package("percona-server-server-5.6") } + it { expect(chef_run).to upgrade_package('percona-server-server') } end - describe "CentOS" do - let(:chef_run) do - env_options = { platform: "centos", version: "6.5" } - ChefSpec::SoloRunner.new(env_options) do |node| - node.set["percona"]["server"]["package_action"] = "upgrade" - end.converge(described_recipe) - end - - before do - stub_command("rpm -qa | grep Percona-Server-shared-56") - .and_return(false) - end + context 'CentOS' do + platform 'centos' + override_attributes['percona']['server']['package_action'] = 'upgrade' - it { expect(chef_run).to upgrade_package("Percona-Server-server-56") } + it { expect(chef_run).to upgrade_package('percona-server-server') } end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 2c6540ae..5d94fb35 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,24 +1,7 @@ -begin - require "chefspec" - require "chefspec/berkshelf" -rescue LoadError - puts "Unable to run `chefspec`" - exit -end +require 'chefspec' +require 'chefspec/berkshelf' RSpec.configure do |config| - config.platform = "ubuntu" - config.version = "12.04" - config.log_level = :error - config.raise_errors_for_deprecations! -end - -def add_apt_repository(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:apt_repository, :add, resource_name) + config.formatter = :documentation + config.color = true end - -def add_apt_preference(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:apt_preference, :add, resource_name) -end - -at_exit { ChefSpec::Coverage.report! } diff --git a/spec/ssl_spec.rb b/spec/ssl_spec.rb index 83e73dd6..b223dd73 100644 --- a/spec/ssl_spec.rb +++ b/spec/ssl_spec.rb @@ -1,67 +1,62 @@ -require "spec_helper" +require 'spec_helper' -describe "percona::ssl" do - let(:chef_run) do - ChefSpec::SoloRunner.new do |node| - node.set["percona"]["encrypted_data_bag"] = "test-bag" - node.set["percona"]["server"]["role"] = %w[master slave] - end.converge(described_recipe) - end +describe 'percona::ssl' do + platform 'ubuntu' + override_attributes['percona']['encrypted_data_bag'] = 'test-bag' + override_attributes['percona']['server']['role'] = %w(master slave) before do - expect(Chef::EncryptedDataBagItem).to( - receive(:load).with("test-bag", "ssl_replication").and_return( - "ca-cert" => "test-ca-cert", - "client" => { - "client-cert" => "test-client-cert", - "client-key" => "test-client-key" - }, - "server" => { - "server-cert" => "test-server-cert", - "server-key" => "test-server-key" - } - ) + stub_data_bag_item('test-bag', 'ssl_replication').and_return( + 'ca-cert' => 'test-ca-cert', + 'client' => { + 'client-cert' => 'test-client-cert', + 'client-key' => 'test-client-key', + }, + 'server' => { + 'server-cert' => 'test-server-cert', + 'server-key' => 'test-server-key', + } ) end - it "creates the certificate directory" do - expect(chef_run).to create_directory("/etc/mysql/ssl").with( - user: "mysql", - mode: "0700" + it 'creates the certificate directory' do + expect(chef_run).to create_directory('/etc/mysql/ssl').with( + user: 'mysql', + mode: '0700' ) end - it "creates the CA certificate" do - expect(chef_run).to create_file("/etc/mysql/ssl/cacert.pem").with( - content: "test-ca-cert", + it 'creates the CA certificate' do + expect(chef_run).to create_file('/etc/mysql/ssl/cacert.pem').with( + content: 'test-ca-cert', sensitive: true ) end - it "creates the server key" do - expect(chef_run).to create_file("/etc/mysql/ssl/server-key.pem").with( - content: "test-server-key", + it 'creates the server key' do + expect(chef_run).to create_file('/etc/mysql/ssl/server-key.pem').with( + content: 'test-server-key', sensitive: true ) end - it "creates the server certificate" do - expect(chef_run).to create_file("/etc/mysql/ssl/server-cert.pem").with( - content: "test-server-cert", + it 'creates the server certificate' do + expect(chef_run).to create_file('/etc/mysql/ssl/server-cert.pem').with( + content: 'test-server-cert', sensitive: true ) end - it "creates the client key" do - expect(chef_run).to create_file("/etc/mysql/ssl/client-key.pem").with( - content: "test-client-key", + it 'creates the client key' do + expect(chef_run).to create_file('/etc/mysql/ssl/client-key.pem').with( + content: 'test-client-key', sensitive: true ) end - it "creates the client certificate" do - expect(chef_run).to create_file("/etc/mysql/ssl/client-cert.pem").with( - content: "test-client-cert", + it 'creates the client certificate' do + expect(chef_run).to create_file('/etc/mysql/ssl/client-cert.pem').with( + content: 'test-client-cert', sensitive: true ) end diff --git a/spec/toolkit_spec.rb b/spec/toolkit_spec.rb index c6ed13c0..55469dfd 100644 --- a/spec/toolkit_spec.rb +++ b/spec/toolkit_spec.rb @@ -1,53 +1,29 @@ -require "spec_helper" +require 'spec_helper' -describe "percona::toolkit" do - let(:centos_package) do - "Percona-Server-shared-compat" - end - - let(:toolkit_package) do - "percona-toolkit" - end - - describe "Ubuntu" do - let(:chef_run) do - ChefSpec::SoloRunner.new.converge(described_recipe) - end - - specify do - expect(chef_run).to_not install_package(centos_package) +describe 'percona::toolkit' do + describe 'Ubuntu' do + platform 'ubuntu' - expect(chef_run).to install_package(toolkit_package) + it do + expect(chef_run).to install_package('percona-toolkit') end end - describe "CentOS" do - describe "when `version` is 5.5" do - let(:chef_run) do - env_options = { platform: "centos", version: "6.5" } - ChefSpec::SoloRunner.new(env_options) do |node| - node.set["percona"]["version"] = "5.5" - end.converge(described_recipe) - end + describe 'CentOS' do + platform 'centos', '7' - specify do - expect(chef_run).to install_package(centos_package) - expect(chef_run).to install_package(toolkit_package) - end + before do + stub_command('dnf module list mysql | grep -q "^mysql.*\\[x\\]"') end - describe "when `version` is 5.6" do - let(:chef_run) do - env_options = { platform: "centos", version: "6.5" } - ChefSpec::SoloRunner.new(env_options) do |node| - node.set["percona"]["version"] = "5.6" - end.converge(described_recipe) - end - - specify do - expect(chef_run).to_not install_package(centos_package) - - expect(chef_run).to install_package(toolkit_package) + it do + expect(chef_run).to install_package('percona-toolkit') + end + context 'CentOS 8 & Percona 8.0' do + platform 'centos', '8' + override_attributes['percona']['version'] = '8.0' + it do + expect(chef_run).to_not install_package('percona-toolkit') end end end diff --git a/templates/default/debian.cnf.erb b/templates/debian.cnf.erb similarity index 100% rename from templates/default/debian.cnf.erb rename to templates/debian.cnf.erb diff --git a/templates/default/replication.sql.erb b/templates/default/replication.sql.erb deleted file mode 100644 index 19283e10..00000000 --- a/templates/default/replication.sql.erb +++ /dev/null @@ -1,21 +0,0 @@ --- Generated by Chef for <%= node["hostname"] %>. --- Local modifications will be overwritten. - -GRANT REPLICATION SLAVE ON *.* TO '<%=node["percona"]["server"]["replication"]["username"]%>'@'%' - IDENTIFIED BY '<%= @replication_password %>' <% if node["percona"]["server"]["replication"]["ssl_enabled"] %>REQUIRE SSL<% end %>; -FLUSH PRIVILEGES; - -<% unless node["percona"]["server"]["replication"]["host"].empty? %> -CHANGE MASTER TO - MASTER_HOST='<%= node["percona"]["server"]["replication"]["host"] %>', - MASTER_PORT=<%= node["percona"]["server"]["replication"]["port"] %>, - MASTER_USER='<%= node["percona"]["server"]["replication"]["username"] %>', - <% if node["percona"]["server"]["replication"]["ssl_enabled"] %> - MASTER_SSL=1, - MASTER_SSL_CA='/etc/mysql/ssl/cacert.pem', - MASTER_SSL_CERT='/etc/mysql/ssl/client-cert.pem', - MASTER_SSL_KEY='/etc/mysql/ssl/client-key.pem', - <% end %> - MASTER_PASSWORD='<%= @replication_password %>'; -START SLAVE; -<% end %> diff --git a/templates/default/grants.sql.erb b/templates/grants.sql.erb similarity index 60% rename from templates/default/grants.sql.erb rename to templates/grants.sql.erb index 2152565d..5002bf80 100644 --- a/templates/default/grants.sql.erb +++ b/templates/grants.sql.erb @@ -1,25 +1,34 @@ # Generated by Chef for <%= node["fqdn"] %>. # Local modifications will be overwritten. -<% if node["platform_family"] == "debian" -%> +<% if node["platform_family"] == "debian" && node["percona"]["version"].to_f < 5.7 -%> # debian-sys-maint user for administration <% [['SELECT', 'mysql.user'], ['SHUTDOWN', '*.*']].each do |priv, loc| %> <%= "GRANT #{priv} ON #{loc} TO '#{@debian_user}'@'localhost';" %> <% end -%> SET PASSWORD FOR '<%= @debian_user %>'@'localhost' = PASSWORD('<%= @debian_password %>'); -<% end -%> - +<% end -%> <% if node["percona"]["backup"]["configure"] %> # Grant permissions for the XtraBackup user # Ensure the user exists, then revoke all grants, then re-grant specific permissions +<% if node["percona"]["version"].to_i >= 8 %> +CREATE USER IF NOT EXISTS '<%= node["percona"]["backup"]["username"] %>'@'localhost' IDENTIFIED BY '<%= @backup_password %>'; +GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO '<%= node["percona"]["backup"]["username"] %>'@'localhost'; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM '<%= node["percona"]["backup"]["username"] %>'@'localhost'; +GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO '<%= node["percona"]["backup"]["username"] %>'@'localhost'; +<% else -%> GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO '<%= node["percona"]["backup"]["username"] %>'@'localhost' IDENTIFIED BY '<%= @backup_password %>'; REVOKE ALL PRIVILEGES, GRANT OPTION FROM '<%= node["percona"]["backup"]["username"] %>'@'localhost'; GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO '<%= node["percona"]["backup"]["username"] %>'@'localhost' IDENTIFIED BY '<%= @backup_password %>'; <% end -%> +<% end -%> # Set the server root password. This should be preseeded by the package installation. +<% if node["percona"]["version"].to_i >= 8 %> +ALTER USER 'root'@'localhost' IDENTIFIED BY '<%= @root_password %>'; +<% else -%> SET PASSWORD FOR 'root'@'localhost' = PASSWORD('<%= @root_password %>'); - +<% end -%> FLUSH PRIVILEGES; diff --git a/templates/default/my.cnf.cluster.erb b/templates/my.cnf.cluster.erb similarity index 83% rename from templates/default/my.cnf.cluster.erb rename to templates/my.cnf.cluster.erb index 04be4487..0863409b 100644 --- a/templates/default/my.cnf.cluster.erb +++ b/templates/my.cnf.cluster.erb @@ -30,7 +30,10 @@ socket = <%= node["percona"]["server"]["socket"] %> nice = <%= node["percona"]["server"]["nice"] %> open-files-limit = <%= node["percona"]["server"]["open_files_limit"] %> <% if node["percona"]["server"]["jemalloc"] %> -malloc-lib = <%= node["percona"]["server"]["jemalloc_lib"] %> +malloc-lib = <%= @jemalloc_lib %> +<% end %> +<% if node["percona"]["server"]["skip_syslog"] %> +skip-syslog <% end %> # *** Application-specific options follow here *** @@ -43,7 +46,6 @@ malloc-lib = <%= node["percona"]["server"]["jemalloc_lib"] %> # # * Basic Settings # -server-id = <%= node["percona"]["server"]["server_id"] %> user = <%= node["percona"]["server"]["username"] %> pid-file = <%= node["percona"]["server"]["pidfile"] %> socket = <%= node["percona"]["server"]["socket"] %> @@ -56,6 +58,10 @@ slave_load_tmpdir = <%= node["percona"]["server"]["slave_load_tmpdir"] %> character_set_server = <%= node["percona"]["server"]["character_set"] %> collation_server = <%= node["percona"]["server"]["collation"] %> +<% unless node["percona"]["server"]["report_host"].empty? %> +report-host = <%= node["percona"]["server"]["report_host"] %> +<% end %> + <% if node["percona"]["server"]["federated"] %> federated <% end %> @@ -78,7 +84,6 @@ wait_timeout = <%= node["percona"]["server"]["wait_timeout"] %> binlog_format = <%= node["percona"]["cluster"]["binlog_format"] %> wsrep_provider = <%= node["percona"]["cluster"]["wsrep_provider"] %> wsrep_provider_options = <%= node["percona"]["cluster"]["wsrep_provider_options"] %> -wsrep_retry_autocommit = <%= node["percona"]["cluster"]["wsrep_retry_autocommit"] %> wsrep_cluster_address = <%= node["percona"]["cluster"]["wsrep_cluster_address"] %> wsrep_slave_threads = <%= node["percona"]["cluster"]["wsrep_slave_threads"] %> wsrep_cluster_name = <%= node["percona"]["cluster"]["wsrep_cluster_name"] %> @@ -86,11 +91,8 @@ wsrep_sst_method = <%= node["percona"]["cluster"]["wsrep_sst_metho wsrep_node_name = <%= node["percona"]["cluster"]["wsrep_node_name"] %> wsrep_notify_cmd = <%= node["percona"]["cluster"]["wsrep_notify_cmd"] %> wsrep_sst_receive_address = <%= node["percona"]["cluster"]["wsrep_sst_receive_address"] %> -<% if node["percona"]["cluster"]["wsrep_dirty_reads"] %> -wsrep_dirty_reads = ON -<% end %> -<% unless node["percona"]["cluster"]["wsrep_sst_auth"].empty? -%> -wsrep_sst_auth = <%= node["percona"]["cluster"]["wsrep_sst_auth"] %> +<% unless @wsrep_sst_auth.empty? -%> +wsrep_sst_auth = "<%= @wsrep_sst_auth %>" <% end -%> innodb_locks_unsafe_for_binlog = <%= node["percona"]["cluster"]["innodb_locks_unsafe_for_binlog"] %> innodb_autoinc_lock_mode = <%= node["percona"]["cluster"]["innodb_autoinc_lock_mode"] %> @@ -110,11 +112,9 @@ old_passwords = <%= @old_passwords %> bind-address = <%= node["percona"]["server"]["bind_address"] %> <% end %> -<%- if node["percona"]["version"] >= "5.5" %> # As of 5.6.6 performance_schema is enabled by default. This allows it to be # explicitly turned on or off as needed across all mysql versions performance_schema=<%= node["percona"]["server"]["performance_schema"] ? "ON" : "OFF" %> -<% end %> # # * Fine Tuning @@ -206,11 +206,7 @@ thread_cache_size = <%= node["percona"]["server"]["thread_cache_size"] %> # This replaces the startup script and checks MyISAM tables if needed # the first time they are touched -<%- if node["percona"]["version"] < "5.5" %> -myisam-recover = <%= node["percona"]["server"]["myisam_recover_options"] %> -<% else %> myisam-recover-options = <%= node["percona"]["server"]["myisam_recover_options"] %> -<% end %> # back_log is the number of connections the operating system can keep in @@ -236,20 +232,30 @@ sql-mode = <%= node["percona"]["server"]["sql_modes"].join(",") %> # The number of open tables for all threads. # make sure that the open file limit is at least twice this in the # mysqld_safe section -<%- if node["percona"]["version"] >= "5.6" %> +<%- if node["percona"]["version"].to_f >= 5.6 %> table_open_cache = <%= node["percona"]["server"]["table_cache"] %> +table_definition_cache = <%= node["percona"]["server"]["table_definition_cache"] %> <%- else %> -table_cache = <%= node["percona"]["server"]["table_cache"] %> +table_open_cache = <%= node["percona"]["server"]["table_cache"] %> + <%- unless node["percona"]["server"]["table_definition_cache"].to_i.eql?(-1) %> + <%# for <= 5.6.7, keep in mind MIN/MAX values. The -1 is the default value %> +table_definition_cache = <%= node["percona"]["server"]["table_definition_cache"] %> + <%- end %> <%- end %> +table_definition_cache = <%= node["percona"]["server"]["table_definition_cache"] %> + #thread_concurrency = 10 +<%- if node["percona"]["version"].to_i < 8 %> # # # * Query Cache Configuration # query_cache_limit = <%= node["percona"]["server"]["query_cache_limit"] %> query_cache_size = <%= node["percona"]["server"]["query_cache_size"] %> +query_cache_type = <%= node["percona"]["server"]["query_cache_type"] %> +<%- end %> # # * Logging and Replication # @@ -262,7 +268,7 @@ query_cache_size = <%= node["percona"]["server"]["query_cache_size"] %> # sync_binlog ensures that all writes to the binary log are immediately # flushed to disk. This is important, especially for replication, because # if the server crashes and has not written all of the binary log to disk (and flushed it) -# then some rows will not make it to the slave +# then some rows will not make it to the replica sync_binlog = <%= node["percona"]["server"]["sync_binlog"] %> # @@ -283,27 +289,29 @@ slow_query_log_file = <%= node["percona"]["server"]["slow_query_log_file"] %> # currently measures time with second accuracy only). long_query_time = <%= node["percona"]["server"]["long_query_time"] %> -# log-queries-not-using-indexes -# +<% if node["percona"]["server"]["log_queries_not_using_indexes"] %> +log-queries-not-using-indexes = <%= node["percona"]["server"]["log_queries_not_using_indexes"] %> +<% end %> + # The following can be used as easy to replay backup logs or for replication. -# note: if you are setting up a replication slave, see README.Debian about +# note: if you are setting up a replication replica, see README.Debian about # other settings you may need to change. # Unique server identification number between 1 and 2^32-1. This value -# is required for both master and slave hosts. It defaults to 1 if -# "master-host" is not set, but will MySQL will not function as a master +# is required for both source and replica hosts. It defaults to 1 if +# "master-host" is not set, but will MySQL will not function as a source # if it is omitted. -#server-id = 1 +# server-id = <%= node["percona"]["server"]["server_id"] %> <% unless node["percona"]["server"]["replication"]["ignore_db"].empty? %> -# Tells the slave SQL thread not to replicate any statement where the default database is. +# Tells the replica SQL thread not to replicate any statement where the default database is. <% Array(node["percona"]["server"]["replication"]["ignore_db"]).each do |ignore_db| -%> replicate-ignore-db = <%= ignore_db %> <% end -%> <% end -%> <% unless node["percona"]["server"]["replication"]["ignore_table"].empty? %> -# Creates a replication filter by telling the slave SQL thread not to replicate any statement that updates the specified table, even if any other tables might be updated by the same statement. +# Creates a replication filter by telling the replica SQL thread not to replicate any statement that updates the specified table, even if any other tables might be updated by the same statement. <% node["percona"]["server"]["replication"]["ignore_table"].each do |ignore_table| -%> replicate-ignore-table = <%= ignore_table %> <% end -%> @@ -312,36 +320,62 @@ replicate-ignore-table = <%= ignore_table %> <% if node["percona"]["server"]["replication"]["suppress_1592"] %> #turns off this statement is unsafe in statement-based replication -<% if node["percona"]["version"] < "5.5" -%> -suppress_log_warning_1592 -<% else %> log_warnings_suppress=1592 <% end %> -<% end %> -# Make the slave read-only. Only users with the SUPER privilege and the -# replication slave thread will be able to modify data on it. You can +# Make the replica read-only. Only users with the SUPER privilege and the +# replication replica thread will be able to modify data on it. You can # use this to ensure that no applications will accidently modify data on -# the slave instead of the master +# the replica instead of the source <% if node["percona"]["server"]["replication"]["read_only"] %> read_only <% end %> -# Tells the slave server not to start the slave threads when the server starts. +# Tells the replica server not to start the replica threads when the server starts. # This will allow you to tweak system and/or server settings prior to starting # replication. <% if node["percona"]["server"]["replication"]["skip_slave_start"] %> skip-slave-start <% end %> -# Number of times the slave SQL thread will retry a transaction in case it +# Number of times the replica SQL thread will retry a transaction in case it # failed with a deadlock or elapsed lock wait timeout, before giving up and # stopping. slave_transaction_retries = <%= node["percona"]["server"]["replication"]["slave_transaction_retries"] %> -log_bin = <%= node["percona"]["server"]["datadir"] %>/mysql-bin.log +# Enable binary logging. This is required for acting as a MASTER in a +# replication configuration. You also need the binary log if you need +# the ability to do point in time recovery from your latest backup. +# +# Bin log basename +# https://dev.mysql.com/doc/refman/5.6/en/replication-options-binary-log.html#sysvar_log_bin_basename +# it is recommened to specify a filename for the binary log, hopefully +# something that is not host specific. I've chosen master-bin. +<%- if node["percona"]["version"].to_f >= 5.6 and node["percona"]["server"].key?('log_bin_basename') and !node["percona"]["server"]["log_bin_basename"].empty? %> +log_bin = <%= node["percona"]["server"]["log_bin_basename"] %> +<%- end %> + +<% unless node["percona"]["server"]["relay_log"].empty? %> +relay-log = <%= node["percona"]["server"]["relay_log"] %> +<% end %> + expire_logs_days = <%= node["percona"]["server"]["expire_logs_days"] %> max_binlog_size = <%= node["percona"]["server"]["max_binlog_size"] %> +binlog_format = <%= node["percona"]["server"]["binlog_format"] %> +slave_net_timeout = <%= node["percona"]["server"]["slave_net_timeout"] %> +<%- if node["percona"]["version"].to_f >= 5.6 %> +binlog_checksum = <%= node["percona"]["server"]["binlog_checksum"] %> +<% if node["percona"]["server"]["master_verify_checksum"] %> +master_verify_checksum = <%= node["percona"]["server"]["master_verify_checksum"] %> +<% end %> +<% if node["percona"]["server"]["slave_sql_verify_checksum"] %> +slave_sql_verify_checksum = <%= node["percona"]["server"]["master_verify_checksum"] %> +<% end %> +<% end %> + +<% if node["percona"]["server"]["binlog_rows_query_log_events"] %> +binlog_rows_query_log_events +<% end %> <% node["percona"]["server"]["binlog_do_db"].each do |db_name| %> binlog-do-db = <%= db_name %> @@ -349,6 +383,25 @@ binlog-do-db = <%= db_name %> <% node["percona"]["server"]["binlog_ignore_db"].each do |db_name| %> binlog-ignore-db = <%= db_name %> +<% end -%> + +<%- if node["percona"]["version"].to_f >= 5.6 %> +gtid_mode = <%= node["percona"]["server"]["gtid_mode"] %> +<% if node["percona"]["server"]["enforce_gtid_consistency"] %> +enforce_gtid_consistency = <%= node["percona"]["server"]["enforce_gtid_consistency"] %> +<% end %> +<% end %> + +<% if node["percona"]["server"]["sync_master_info"] %> +sync_master_info = <%= node["percona"]["server"]["sync_master_info"] %> +<% end %> + + +<% if node["percona"]["server"]["sync_relay_log"] %> +sync_relay_log = <%= node["percona"]["server"]["sync_relay_log"] %> +<% end %> +<% if node["percona"]["server"]["sync_relay_log_info"] %> +sync_relay_log_info = <%= node["percona"]["server"]["sync_relay_log_info"] %> <% end %> # The size of the cache to hold the SQL statements for the binary log @@ -423,18 +476,22 @@ myisam_recover skip-innodb <% end %> +<%- if node["percona"]["version"].to_f < 5.7 %> # Additional memory pool that is used by InnoDB to store metadata # information. If InnoDB requires more memory for this purpose it will # start to allocate it from the OS. As this is fast enough on most # recent operating systems, you normally do not need to change this # value. SHOW INNODB STATUS will display the current amount used. -<% unless node["percona"]["version"] == "5.7" %> innodb_additional_mem_pool_size = <%= node["percona"]["server"]["innodb_additional_mem_pool_size"] %> -<% end %> +<%- end %> # This config file assumes a main memory of at least 8G innodb_buffer_pool_size = <%= node["percona"]["server"]["innodb_buffer_pool_size"] %> +innodb_buffer_pool_instances = <%= node["percona"]["server"]["innodb_buffer_pool_instances"] %> + +innodb_buffer_pool_populate = <%= node["percona"]["server"]["innodb_buffer_pool_populate"] %> + # InnoDB stores data in one or more data files forming the tablespace. # If you have a single logical drive for your data, a single # autoextending file would be good enough. In other cases, a single file @@ -454,12 +511,14 @@ innodb_autoextend_increment = <%= node["percona"]["server"]["innodb_autoextend_i <% if node["percona"]["server"]["innodb_file_per_table"] %> innodb_file_per_table <% end %> +<%- if node["percona"]["version"].to_i < 8 %> # The file format to use for new InnoDB tables. # Currently Antelope and Barracuda are supported. # This applies only for tables that have their own tablespace, # so for it to have an effect innodb_file_per_table must be enabled. innodb_file_format = <%= node["percona"]["server"]["innodb_file_format"] %> +<% end %> # Set this option if you would like the InnoDB tablespace files to be # stored in another location. By default this is the MySQL datadir. @@ -552,6 +611,10 @@ innodb_commit_concurrency=0 innodb_open_files=<%= node["percona"]["server"]["innodb_open_files"] %> +<%- if node["percona"]["version"].to_f >= 5.6 %> +innodb_numa_interleave=<%= node["percona"]["server"]["innodb_numa_interleave"] %> +<%- end %> + # # * Security Features # @@ -596,3 +659,5 @@ key_buffer_size = <%= node["percona"]["server"]["key_buffer_size"] %> <% if !node["percona"]["server"]["includedir"].empty? %> !includedir <%= node["percona"]["server"]["includedir"] %> <% end %> + +# vim: ts=1 sts=2 diff --git a/templates/default/my.cnf.main.erb b/templates/my.cnf.main.erb similarity index 85% rename from templates/default/my.cnf.main.erb rename to templates/my.cnf.main.erb index c6e72890..23a19d5a 100644 --- a/templates/default/my.cnf.main.erb +++ b/templates/my.cnf.main.erb @@ -33,7 +33,10 @@ socket = <%= node["percona"]["server"]["socket"] %> nice = <%= node["percona"]["server"]["nice"] %> open-files-limit = <%= node["percona"]["server"]["open_files_limit"] %> <% if node["percona"]["server"]["jemalloc"] %> -malloc-lib = <%= node["percona"]["server"]["jemalloc_lib"] %> +malloc-lib = <%= @jemalloc_lib %> +<% end %> +<% if node["percona"]["server"]["skip_syslog"] %> +skip-syslog <% end %> # *** Application-specific options follow here *** @@ -58,6 +61,10 @@ slave_load_tmpdir = <%= node["percona"]["server"]["slave_load_tmpdir"] %> character_set_server = <%= node["percona"]["server"]["character_set"] %> collation_server = <%= node["percona"]["server"]["collation"] %> +<% unless node["percona"]["server"]["report_host"].empty? %> +report-host = <%= node["percona"]["server"]["report_host"] %> +<% end %> + <% if node["percona"]["server"]["federated"] %> federated <% end %> @@ -89,14 +96,15 @@ bind-address = <%= node["percona"]["server"]["bind_address"] %> <% end %> # -<%- if node["percona"]["version"] >= "5.5" %> # As of 5.6.6 performance_schema is enabled by default. This allows it to be # explicitly turned on or off as needed across all mysql versions performance_schema=<%= node["percona"]["server"]["performance_schema"] ? "ON" : "OFF" %> -<% end %> # * Fine Tuning # + +sysdate_is_now = <%= node["percona"]["server"]["sysdate_is_now"] %> + key_buffer_size = <%= node["percona"]["server"]["key_buffer_size"] %> # The maximum size of a query packet the server can handle as well as @@ -137,14 +145,6 @@ query_alloc_block_size = <%= node["percona"]["server"]["query_alloc_block_size"] memlock <% end %> -<% if node["percona"]["server"]["max_statement_time"] %> -<% if node["percona"]["version"] == "5.7" %> -max_execution_time = <%= node["percona"]["server"]["max_statement_time"] %> -<% else %> -max_statement_time = <%= node["percona"]["server"]["max_statement_time"] %> -<% end %> -<% end %> - # Set the default transaction isolation level. Levels available are: # READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, SERIALIZABLE @@ -192,11 +192,7 @@ thread_cache_size = <%= node["percona"]["server"]["thread_cache_size"] %> # This replaces the startup script and checks MyISAM tables if needed # the first time they are touched -<%- if node["percona"]["version"] < "5.5" %> -myisam-recover = <%= node["percona"]["server"]["myisam_recover_options"] %> -<% else %> myisam-recover-options = <%= node["percona"]["server"]["myisam_recover_options"] %> -<% end %> # back_log is the number of connections the operating system can keep in # the listen queue, before the MySQL connection manager thread has @@ -208,6 +204,7 @@ myisam-recover-options = <%= node["percona"]["server"]["myisam_recover_options"] back_log = <%= node["percona"]["server"]["back_log"] %> max_connections = <%= node["percona"]["server"]["max_connections"] %> + # I don't know why 0 doesn't disable max_connect_errors checking # but it doesn't, so set it to a high value to prevent MySQL from # refusing to accept connections from a flaky host, especially if you @@ -221,13 +218,20 @@ sql-mode = <%= node["percona"]["server"]["sql_modes"].join(",") %> # The number of open tables for all threads. # make sure that the open file limit is at least twice this in the # mysqld_safe section -<%- if node["percona"]["version"] >= "5.6" %> +<%- if node["percona"]["version"].to_f >= 5.6 %> table_open_cache = <%= node["percona"]["server"]["table_cache"] %> +table_definition_cache = <%= node["percona"]["server"]["table_definition_cache"] %> <%- else %> table_cache = <%= node["percona"]["server"]["table_cache"] %> +<%# for <= 5.6.7, keep in mind MIN/MAX values. The -1 is the default value %> + <%- unless node["percona"]["server"]["table_definition_cache"].to_i.eql?(-1) %> +table_definition_cache = <%= node["percona"]["server"]["table_definition_cache"] %> + <%- end %> <%- end %> #thread_concurrency = 10 +<%- if node["percona"]["version"].to_i < 8 %> +# # # * Query Cache Configuration # @@ -248,6 +252,10 @@ query_cache_size = <%= node["percona"]["server"]["query_cache_size"] %> # other query results. query_cache_limit = <%= node["percona"]["server"]["query_cache_limit"] %> +query_cache_type = <%= node["percona"]["server"]["query_cache_type"] %> + + +<%- end %> # # * Logging and Replication # @@ -260,7 +268,7 @@ query_cache_limit = <%= node["percona"]["server"]["query_cache_limit"] %> # sync_binlog ensures that all writes to the binary log are immediately # flushed to disk. This is important, especially for replication, because # if the server crashes and has not written all of the binary log to disk (and flushed it) -# then some rows will not make it to the slave +# then some rows will not make it to the replica sync_binlog = <%= node["percona"]["server"]["sync_binlog"] %> # @@ -281,39 +289,29 @@ slow_query_log_file = <%= node["percona"]["server"]["slow_query_log_file"] %> # currently measures time with second accuracy only). long_query_time = <%= node["percona"]["server"]["long_query_time"] %> -# log-queries-not-using-indexes -# +<% if node["percona"]["server"]["log_queries_not_using_indexes"] %> +log-queries-not-using-indexes = <%= node["percona"]["server"]["log_queries_not_using_indexes"] %> +<% end %> + # The following can be used as easy to replay backup logs or for replication. -# note: if you are setting up a replication slave, see README.Debian about +# note: if you are setting up a replication replica, see README.Debian about # other settings you may need to change. # Unique server identification number between 1 and 2^32-1. This value -# is required for both master and slave hosts. It defaults to 1 if -# "master-host" is not set, but will MySQL will not function as a master +# is required for both source and replica hosts. It defaults to 1 if +# "master-host" is not set, but will MySQL will not function as a source # if it is omitted. server-id = <%= node["percona"]["server"]["server_id"] %> <% unless node["percona"]["server"]["replication"]["ignore_db"].empty? %> -# Tells the slave SQL thread not to replicate any statement where the default database is. +# Tells the replica SQL thread not to replicate any statement where the default database is. <% Array(node["percona"]["server"]["replication"]["ignore_db"]).each do |ignore_db| -%> replicate-ignore-db = <%= ignore_db %> <% end -%> <% end -%> -<% unless node["percona"]["server"]["replication"]["replicate_do_db"].empty? %> -<% Array(node["percona"]["server"]["replication"]["replicate_do_db"]).each do |db| -%> -replicate-do-db = <%= db %> -<% end -%> -<% end -%> - -<% unless node["percona"]["server"]["replication"]["replicate_do_table"].empty? %> -<% Array(node["percona"]["server"]["replication"]["replicate_do_table"]).each do |table| -%> -replicate-do-table = <%= table %> -<% end -%> -<% end -%> - <% unless node["percona"]["server"]["replication"]["ignore_table"].empty? %> -# Creates a replication filter by telling the slave SQL thread not to replicate any statement that updates the specified table, even if any other tables might be updated by the same statement. +# Creates a replication filter by telling the replica SQL thread not to replicate any statement that updates the specified table, even if any other tables might be updated by the same statement. <% node["percona"]["server"]["replication"]["ignore_table"].each do |ignore_table| -%> replicate-ignore-table = <%= ignore_table %> <% end -%> @@ -322,42 +320,63 @@ replicate-ignore-table = <%= ignore_table %> <% if node["percona"]["server"]["replication"]["suppress_1592"] %> #turns off this statement is unsafe in statement-based replication -<% if node["percona"]["version"] < "5.5" -%> -suppress_log_warning_1592 -<% else %> log_warnings_suppress=1592 <% end %> -<% end %> -# Make the slave read-only. Only users with the SUPER privilege and the -# replication slave thread will be able to modify data on it. You can +# Make the replica read-only. Only users with the SUPER privilege and the +# replication replica thread will be able to modify data on it. You can # use this to ensure that no applications will accidently modify data on -# the slave instead of the master +# the replica instead of the source <% if node["percona"]["server"]["replication"]["read_only"] %> read_only <% end %> -# Tells the slave server not to start the slave threads when the server starts. +# Tells the replica server not to start the replica threads when the server starts. # This will allow you to tweak system and/or server settings prior to starting # replication. <% if node["percona"]["server"]["replication"]["skip_slave_start"] %> skip-slave-start <% end %> -slave_exec_mode = <%= node["percona"]["server"]["replication"]["slave_exec_mode"] %> - -# Number of times the slave SQL thread will retry a transaction in case it +# Number of times the replica SQL thread will retry a transaction in case it # failed with a deadlock or elapsed lock wait timeout, before giving up and # stopping. slave_transaction_retries = <%= node["percona"]["server"]["replication"]["slave_transaction_retries"] %> -log_bin = <%= node["percona"]["server"]["datadir"] %>/mysql-bin.log + +# Enable binary logging. This is required for acting as a MASTER in a +# replication configuration. You also need the binary log if you need +# the ability to do point in time recovery from your latest backup. +# +# Bin log basename +# https://dev.mysql.com/doc/refman/5.6/en/replication-options-binary-log.html#sysvar_log_bin_basename +# it is recommened to specify a filename for the binary log, hopefully +# something that is not host specific. I've chosen master-bin. +<%- if node["percona"]["version"].to_f >= 5.6 and node["percona"]["server"].key?('log_bin_basename') and !node["percona"]["server"]["log_bin_basename"].empty? %> +log_bin = <%= node["percona"]["server"]["log_bin_basename"] %> +<%- end %> + +<% unless node["percona"]["server"]["relay_log"].empty? %> +relay-log = <%= node["percona"]["server"]["relay_log"] %> +<% end %> + expire_logs_days = <%= node["percona"]["server"]["expire_logs_days"] %> max_binlog_size = <%= node["percona"]["server"]["max_binlog_size"] %> binlog_format = <%= node["percona"]["server"]["binlog_format"] %> -<%- if node["percona"]["version"] > "5.6" %> -binlog_space_limit = <%= node["percona"]["server"]["binlog_space_limit"] %> -<%- end %> +slave_net_timeout = <%= node["percona"]["server"]["slave_net_timeout"] %> +<%- if node["percona"]["version"].to_f >= 5.6 %> +binlog_checksum = <%= node["percona"]["server"]["binlog_checksum"] %> +<% if node["percona"]["server"]["master_verify_checksum"] %> +master_verify_checksum = <%= node["percona"]["server"]["master_verify_checksum"] %> +<% end %> +<% if node["percona"]["server"]["slave_sql_verify_checksum"] %> +slave_sql_verify_checksum = <%= node["percona"]["server"]["master_verify_checksum"] %> +<% end %> +<% end %> + +<% if node["percona"]["server"]["binlog_rows_query_log_events"] %> +binlog_rows_query_log_events +<% end %> <% node["percona"]["server"]["binlog_do_db"].each do |db_name| %> binlog-do-db = <%= db_name %> @@ -365,11 +384,24 @@ binlog-do-db = <%= db_name %> <% node["percona"]["server"]["binlog_ignore_db"].each do |db_name| %> binlog-ignore-db = <%= db_name %> +<% end -%> + +<%- if node["percona"]["version"].to_f >= 5.6 %> +gtid_mode = <%= node["percona"]["server"]["gtid_mode"] %> +<% if node["percona"]["server"]["enforce_gtid_consistency"] %> +enforce_gtid_consistency = <%= node["percona"]["server"]["enforce_gtid_consistency"] %> +<% end %> <% end %> -# GTID -enforce_gtid_consistency = <%= node["percona"]["server"]["replication"]["enforce_gtid_consistency"] %> -gtid_mode = <%= node["percona"]["server"]["replication"]["gtid_mode"] %> +<% if node["percona"]["server"]["sync_master_info"] %> +sync_master_info = <%= node["percona"]["server"]["sync_master_info"] %> +<% end %> +<% if node["percona"]["server"]["sync_relay_log"] %> +sync_relay_log = <%= node["percona"]["server"]["sync_relay_log"] %> +<% end %> +<% if node["percona"]["server"]["sync_relay_log_info"] %> +sync_relay_log_info = <%= node["percona"]["server"]["sync_relay_log_info"] %> +<% end %> # The size of the cache to hold the SQL statements for the binary log # during a transaction. If you often use big, multi-statement @@ -381,24 +413,9 @@ gtid_mode = <%= node["percona"]["server"]["replication"][" # statement in transaction binlog_cache_size = <%= node["percona"]["server"]["binlog_cache_size"] %> -# Enable binary logging. This is required for acting as a MASTER in a -# replication configuration. You also need the binary log if you need -# the ability to do point in time recovery from your latest backup. - -# it is recommened to specify a filename for the binary log, hopefully -# something that is not host specific. I've chosen master-bin. -<% unless node["percona"]["server"]["log_bin"].empty? %> -log-bin = <%= node["percona"]["server"]["log_bin"] %> -<% end %> - -<% unless node["percona"]["server"]["relay_log"].empty? %> -relay-log = <%= node["percona"]["server"]["relay_log"] %> -<% end %> - - -# If you're using replication with chained slaves (A->B->C), you need to +# If you're using replication with chained replicas (A->B->C), you need to # enable this option on server B. It enables logging of updates done by -# the slave thread into the slave's binary log. +# the replica thread into the replica's binary log. <% if node["percona"]["server"]["log_slave_updates"] %> log_slave_updates <% end %> @@ -478,18 +495,20 @@ myisam_recover skip-innodb <% end %> +<%- if node["percona"]["version"].to_f < 5.7 %> # Additional memory pool that is used by InnoDB to store metadata # information. If InnoDB requires more memory for this purpose it will # start to allocate it from the OS. As this is fast enough on most # recent operating systems, you normally do not need to change this # value. SHOW INNODB STATUS will display the current amount used. -<% unless node["percona"]["version"] == "5.7" %> innodb_additional_mem_pool_size = <%= node["percona"]["server"]["innodb_additional_mem_pool_size"] %> -<% end %> +<%- end %> # This config file assumes a main memory of at least 8G innodb_buffer_pool_size = <%= node["percona"]["server"]["innodb_buffer_pool_size"] %> +innodb_buffer_pool_instances = <%= node["percona"]["server"]["innodb_buffer_pool_instances"] %> + # InnoDB stores data in one or more data files forming the tablespace. # If you have a single logical drive for your data, a single # autoextending file would be good enough. In other cases, a single file @@ -509,12 +528,14 @@ innodb_autoextend_increment = <%= node["percona"]["server"]["innodb_autoextend_i <% if node["percona"]["server"]["innodb_file_per_table"] %> innodb_file_per_table <% end %> +<%- if node["percona"]["version"].to_i < 8 %> # The file format to use for new InnoDB tables. # Currently Antelope and Barracuda are supported. # This applies only for tables that have their own tablespace, # so for it to have an effect innodb_file_per_table must be enabled. innodb_file_format = <%= node["percona"]["server"]["innodb_file_format"] %> +<% end %> # Set this option if you would like the InnoDB tablespace files to be # stored in another location. By default this is the MySQL datadir. @@ -607,10 +628,9 @@ innodb_commit_concurrency=0 innodb_open_files=<%= node["percona"]["server"]["innodb_open_files"] %> -<% if node["percona"]["version"] == "5.5" %> -# set this to 1 if you like to import single tables from xtrabackup snapshot -innodb_import_table_from_xtrabackup = <%= node["percona"]["server"]["innodb_import_table_from_xtrabackup"] %> -<% end %> +<%- if node["percona"]["version"].to_f >= 5.6 %> +innodb_numa_interleave=<%= node["percona"]["server"]["innodb_numa_interleave"] %> +<%- end %> # # * Security Features @@ -626,6 +646,11 @@ innodb_import_table_from_xtrabackup = <%= node["percona"]["server"]["innodb_impo ssl-key=/etc/mysql/ssl/server-key.pem <% end %> +<% unless node["percona"]["conf"].nil? or node["percona"]["conf"]["mysqld"].nil? %> +<% node["percona"]["conf"]["mysqld"].keys.each do |key| %> + <%= "#{key} = #{node["percona"]["conf"]["mysqld"][key]}" %> +<% end %> +<% end %> [mysqldump] quick @@ -641,18 +666,16 @@ key_buffer_size = <%= node["percona"]["server"]["key_buffer_size"] %> ##### custom configurations go here <% unless node["percona"]["conf"].nil? or node["percona"]["conf"].empty? %> <% node["percona"]["conf"].keys.each do |category| %> +<% unless category == 'mysqld' %> <%= "[#{category}]" %> <% node["percona"]["conf"][category].keys.each do |key| %> - <% if node["percona"]["conf"][category][key].is_a?(String) && node["percona"]["conf"][category][key].empty? %> - <%= key %> - <% else %> - <%= "#{key} = #{node["percona"]["conf"][category][key]}" %> - <% end %> + <%= "#{key} = #{node["percona"]["conf"][category][key]}" %> <% end %> <% end %> <% end %> +<% end %> # # * IMPORTANT: Additional settings that can override those from this file! diff --git a/templates/default/my.cnf.root.erb b/templates/my.cnf.root.erb similarity index 100% rename from templates/default/my.cnf.root.erb rename to templates/my.cnf.root.erb diff --git a/templates/replication.sql.erb b/templates/replication.sql.erb new file mode 100644 index 00000000..b1aa1477 --- /dev/null +++ b/templates/replication.sql.erb @@ -0,0 +1,32 @@ +-- Generated by Chef for <%= node["hostname"] %>. +-- Local modifications will be overwritten. +<% if node["percona"]["version"].to_i >= 8 %> +CREATE USER IF NOT EXISTS '<%=node["percona"]["server"]["replication"]["username"]%>'@'%' IDENTIFIED BY '<%= @replication_password %>'; +GRANT REPLICATION SLAVE ON *.* TO '<%=node["percona"]["server"]["replication"]["username"]%>'@'%'; +<% if node["percona"]["server"]["replication"]["ssl_enabled"] -%> +ALTER USER '<%=node["percona"]["server"]["replication"]["username"]%>'@'%' REQUIRE SSL; +<% end -%> +<% else -%> +GRANT REPLICATION SLAVE ON *.* TO '<%=node["percona"]["server"]["replication"]["username"]%>'@'%' IDENTIFIED BY '<%= @replication_password %>'<% if node["percona"]["server"]["replication"]["ssl_enabled"] %> REQUIRE SSL<% end %>; +<% end -%> +FLUSH PRIVILEGES; +<% unless node["percona"]["server"]["replication"]["host"].empty? %> + +CHANGE MASTER TO + MASTER_HOST='<%= node["percona"]["server"]["replication"]["host"] %>', + MASTER_PORT=<%= node["percona"]["server"]["replication"]["port"] %>, + MASTER_USER='<%= node["percona"]["server"]["replication"]["username"] %>', + <% if node["percona"]["server"]["replication"]["ssl_enabled"] %> + MASTER_SSL=1, + MASTER_SSL_CA='/etc/mysql/ssl/cacert.pem', + <% if node['percona']['server']['role'].include?('replica') || node['percona']['server']['role'].include?('slave') %> + MASTER_SSL_CERT='/etc/mysql/ssl/client-cert.pem', + MASTER_SSL_KEY='/etc/mysql/ssl/client-key.pem', + <% elsif node['percona']['server']['role'].include?('source') || node['percona']['server']['role'].include?('master') %> + MASTER_SSL_CERT='/etc/mysql/ssl/server-cert.pem', + MASTER_SSL_KEY='/etc/mysql/ssl/server-key.pem', + <% end %> + <% end %> + MASTER_PASSWORD='<%= @replication_password %>'; +START SLAVE; +<% end %> diff --git a/test/.chef/knife.rb b/test/.chef/knife.rb deleted file mode 100644 index bfc8607d..00000000 --- a/test/.chef/knife.rb +++ /dev/null @@ -1,2 +0,0 @@ -cache_type "BasicFile" -cache_options(:path => "#{ENV["HOME"]}/.chef/checksums") diff --git a/test/fixtures/cookbooks/test/metadata.rb b/test/fixtures/cookbooks/test/metadata.rb new file mode 100644 index 00000000..61911d19 --- /dev/null +++ b/test/fixtures/cookbooks/test/metadata.rb @@ -0,0 +1,7 @@ +name 'test' +maintainer 'Sous Chefs' +maintainer_email 'help@sous-chefs.org' +license 'Apache-2.0' +description 'Testing cookbook' +version '0.0.1' +depends 'percona' diff --git a/test/fixtures/cookbooks/test/recipes/_remove_mariadb_libs.rb b/test/fixtures/cookbooks/test/recipes/_remove_mariadb_libs.rb new file mode 100644 index 00000000..643ce357 --- /dev/null +++ b/test/fixtures/cookbooks/test/recipes/_remove_mariadb_libs.rb @@ -0,0 +1,6 @@ +# If we are installing 8.0 on a Centos 7 instance we need to remove the existing +# mariadb-libs rpm to avoid a dependency conflict. +package 'mariadb-libs' do + action :remove + only_if { platform_family?('rhel') && node['platform_version'].to_i == 7 && node['percona']['version'].to_i >= 8 } +end diff --git a/test/fixtures/cookbooks/test/recipes/_remove_mysql_common.rb b/test/fixtures/cookbooks/test/recipes/_remove_mysql_common.rb new file mode 100644 index 00000000..f21b61b3 --- /dev/null +++ b/test/fixtures/cookbooks/test/recipes/_remove_mysql_common.rb @@ -0,0 +1,11 @@ +# mailutils pulls in mysql-common which breaks initial installation on dokken based images. This doesn't seem to happen +# in a non-container system so let's have this here for now +if platform_family?('debian') + execute 'remove mysql-common' do + command <<~EOF + apt-get -y remove mailutils mailutils-common + apt-get -y autoremove + EOF + only_if { ::File.exist?('/usr/share/doc/mailutils-common/copyright') } + end +end diff --git a/test/fixtures/cookbooks/test/recipes/client.rb b/test/fixtures/cookbooks/test/recipes/client.rb new file mode 100644 index 00000000..0ad9ef54 --- /dev/null +++ b/test/fixtures/cookbooks/test/recipes/client.rb @@ -0,0 +1,3 @@ +include_recipe 'test::_remove_mariadb_libs' +include_recipe 'percona::client' +include_recipe 'percona::toolkit' diff --git a/test/fixtures/cookbooks/test/recipes/cluster.rb b/test/fixtures/cookbooks/test/recipes/cluster.rb new file mode 100644 index 00000000..5b6f7043 --- /dev/null +++ b/test/fixtures/cookbooks/test/recipes/cluster.rb @@ -0,0 +1,16 @@ +node.default['percona']['server']['datadir'] = '/tmp/mysql' +node.default['percona']['server']['debian_password'] = '0kb)F?Zj' +node.default['percona']['server']['root_password'] = '7tCk(V5I' +node.default['percona']['backup']['password'] = 'I}=sJ2bS' + +node.default['percona']['server']['jemalloc'] = if platform_family?('rhel') && node['platform_version'] >= '9' + false + else + true + end + +# Install postfix on RHEL to ensure we don't properly break mysql-libs compatibility +package 'postfix' if platform_family?('rhel') + +include_recipe 'test::_remove_mysql_common' +include_recipe 'percona::cluster' diff --git a/test/fixtures/cookbooks/test/recipes/replication.rb b/test/fixtures/cookbooks/test/recipes/replication.rb new file mode 100644 index 00000000..dc0df703 --- /dev/null +++ b/test/fixtures/cookbooks/test/recipes/replication.rb @@ -0,0 +1,7 @@ +node.default['percona']['server']['role'] = %w(source) +node.default['percona']['server']['replication']['host'] = 'source-host' +node.default['percona']['server']['replication']['username'] = 'replication' +node.default['percona']['server']['replication']['password'] = ')6$W2M{/' +node.default['percona']['server']['replication']['ssl_enabled'] = true + +include_recipe 'test::server' diff --git a/test/fixtures/cookbooks/test/recipes/server.rb b/test/fixtures/cookbooks/test/recipes/server.rb new file mode 100644 index 00000000..3bd49adb --- /dev/null +++ b/test/fixtures/cookbooks/test/recipes/server.rb @@ -0,0 +1,17 @@ +node.default['percona']['server']['datadir'] = '/tmp/mysql' +node.default['percona']['server']['debian_password'] = '0kb)F?Zj' +node.default['percona']['server']['root_password'] = '7tCk(V5I' +node.default['percona']['backup']['password'] = 'I}=sJ2bS' +node.default['percona']['server']['jemalloc'] = if platform_family?('rhel') && node['platform_version'] >= '9' + false + else + true + end + +include_recipe 'test::_remove_mariadb_libs' +include_recipe 'test::_remove_mysql_common' +include_recipe 'percona::server' +include_recipe 'percona::backup' + +# Install postfix on RHEL to ensure we don't properly break mysql-libs compatibility +package 'postfix' if platform_family?('rhel') diff --git a/test/fixtures/cookbooks/test/recipes/source.rb b/test/fixtures/cookbooks/test/recipes/source.rb new file mode 100644 index 00000000..07756daf --- /dev/null +++ b/test/fixtures/cookbooks/test/recipes/source.rb @@ -0,0 +1,6 @@ +node.default['percona']['server']['role'] = %w(source) +node.default['percona']['server']['replication']['host'] = 'source-host' +node.default['percona']['server']['replication']['username'] = 'replication' +node.default['percona']['server']['replication']['password'] = ')6$W2M{/' + +include_recipe 'test::server' diff --git a/test/fixtures/cookbooks/test/recipes/user_database.rb b/test/fixtures/cookbooks/test/recipes/user_database.rb new file mode 100644 index 00000000..2effa520 --- /dev/null +++ b/test/fixtures/cookbooks/test/recipes/user_database.rb @@ -0,0 +1,229 @@ +::Chef::DSL::Recipe.include Percona::Cookbook::HashedPassword::Helper + +node.default['percona']['skip_passwords'] = true +node.default['percona']['server']['debian_username'] = 'root' +node.default['percona']['server']['debian_password'] = '' +include_recipe 'test::_remove_mysql_common' +include_recipe 'percona::server' + +# Create a schema to test mysql_database :drop against +bash 'create datatrout' do + code <<-EOF + echo 'CREATE SCHEMA datatrout;' | /usr/bin/mysql -u root; + touch /tmp/troutmarker + EOF + not_if { ::File.exist?('/tmp/troutmarker') } + action :run +end + +# Create a database for testing existing grant operations +bash 'create datasalmon' do + code <<-EOF + echo 'CREATE SCHEMA datasalmon;' | /usr/bin/mysql -u root; + touch /tmp/salmonmarker + EOF + not_if { ::File.exist?('/tmp/salmonmarker') } + action :run +end + +# Create a user to test mysql_database_user :drop against +bash 'create kermit' do + code <<-EOF + echo "CREATE USER 'kermit'@'localhost';" | /usr/bin/mysql -u root; + touch /tmp/kermitmarker + EOF + not_if { ::File.exist?('/tmp/kermitmarker') } + action :run +end + +# Create a user to test mysql_database_user password update via :create +bash 'create rowlf' do + code <<-EOF + echo "CREATE USER 'rowlf'@'localhost' IDENTIFIED BY 'hunter2';" | /usr/bin/mysql -u root; + touch /tmp/rowlfmarker + EOF + not_if { ::File.exist?('/tmp/rowlfmarker') } + action :run +end + +# Create a user to test mysql_database_user password update via :create using a password hash +bash 'create statler' do + code <<-EOF + echo "CREATE USER 'statler'@'localhost' IDENTIFIED BY 'hunter2';" | /usr/bin/mysql -u root; + touch /tmp/statlermarker + EOF + not_if { ::File.exist?('/tmp/statlermarker') } + action :run +end + +# Create a user to test mysql_database_user password update via :grant +bash 'create rizzo' do + code <<-EOF + echo "CREATE USER 'rizzo'@'127.0.0.1' IDENTIFIED BY 'hunter2'; GRANT SELECT ON datasalmon.* TO 'rizzo'@'127.0.0.1';" | /usr/bin/mysql -u root; + touch /tmp/rizzomarker + EOF + not_if { ::File.exist?('/tmp/rizzomarker') } + action :run +end + +# Create a user to test ctrl_user, ctrl_password, and ctrl_host +bash 'create beauregard' do + code <<-EOF + echo "CREATE USER 'beauregard'@'localhost' IDENTIFIED BY '>mupp3ts'; GRANT ALL PRIVILEGES ON *.* TO 'beauregard'@'localhost' WITH GRANT OPTION; FLUSH PRIVILEGES;" | /usr/bin/mysql -u root; + touch /tmp/beauregardmarker + EOF + not_if { ::File.exist?('/tmp/beauregardmarker') } + action :run +end + +# Create a user to test mysql_database_user password update via :create and non-root user +bash 'create waldorf@localhost' do + code <<-EOF + echo "CREATE USER 'waldorf'@'localhost' IDENTIFIED BY 'balcony';" | /usr/bin/mysql -u root; + touch /tmp/waldorf_localhostmarker + EOF + not_if { ::File.exist?('/tmp/waldorf_localhostmarker') } + action :run +end + +# Create a user to test mysql_database_user password update via :create and non-root user +bash 'create waldorf' do + code <<-EOF + echo "CREATE USER 'waldorf'@'127.0.0.1' IDENTIFIED BY 'boxseat';" | /usr/bin/mysql -u root; + touch /tmp/waldorf_127marker + EOF + not_if { ::File.exist?('/tmp/waldorf_127marker') } + action :run +end + +## Resources we're testing +percona_mysql_database 'databass' do + action :create + password '' +end + +percona_mysql_database 'datatrout' do + action :drop + password '' +end + +percona_mysql_user 'piggy' do + action :create + ctrl_password '' +end + +percona_mysql_user 'kermit' do + action :drop + ctrl_password '' +end + +percona_mysql_user 'rowlf' do + password '123456' # hashed: *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 + ctrl_password '' + action :create +end + +percona_mysql_user 'gonzo' do + password 'abcdef' + ctrl_password '' + host '10.10.10.%' + action :create +end + +# create gonzo again to ensure the create action is idempotent +percona_mysql_user 'gonzo' do + password 'abcdef' + ctrl_password '' + host '10.10.10.%' + action :create +end + +hash = hashed_password('*2027D9391E714343187E07ACB41AE8925F30737E'); # 'l33t' + +percona_mysql_user 'statler' do + password hash + ctrl_password '' + action :create +end + +# test global permissions +percona_mysql_user 'camilla' do + password 'bokbokbok' + privileges [:select, :repl_client, :create_tmp_table, :show_db] + require_ssl true + ctrl_password '' + action [:create, :grant] +end + +percona_mysql_user 'fozzie' do + database_name 'databass' + password 'wokkawokka' + host 'mars' + privileges [:select, :update, :insert] + require_ssl true + ctrl_password '' + action [:create, :grant] +end + +hash2 = hashed_password('*F798E7C0681068BAE3242AA2297D2360DBBDA62B'); # 'zokkazokka' + +percona_mysql_user 'moozie' do + database_name 'databass' + password hash2 + ctrl_password '' + host '127.0.0.1' + privileges [:select, :update, :insert] + require_ssl false + action [:create, :grant] +end + +# all the grants exist ('Granting privs' should not show up), but the password is different +# and should get updated +percona_mysql_user 'rizzo' do + database_name 'datasalmon' + password 'salmon' + ctrl_password '' + host '127.0.0.1' + privileges [:select] + require_ssl false + action :grant +end + +# Should converge normally for all versions +# Checks to insure SHA2 password algo works for percona 8 +# with the host set to localhost +percona_mysql_user 'beaker' do + password 'meep' + host 'localhost' + ctrl_password '' + use_native_auth false + action :create +end + +# Create new user with a ctrl_user as non-root to test ctrl_hash and validate ctrl_password with special character +percona_mysql_user 'bunsen' do + database_name 'datasalmon' + password 'honeydont' + ctrl_user 'beauregard' + ctrl_password '>mupp3ts' + ctrl_host '127.0.0.1' + host 'localhost' + privileges [:select] + action [:create, :grant] +end + +percona_mysql_user 'waldorf' do + password 'balcony' + ctrl_user 'beauregard' + ctrl_password '>mupp3ts' + ctrl_host '127.0.0.1' + host '127.0.0.1' + action :create +end + +percona_mysql_database 'flush privileges' do + database_name 'databass' + password '' + sql 'flush privileges' + action :query +end diff --git a/test/integration/client_55/serverspec/localhost/client_55_spec.rb b/test/integration/client_55/serverspec/localhost/client_55_spec.rb deleted file mode 100644 index b5c14352..00000000 --- a/test/integration/client_55/serverspec/localhost/client_55_spec.rb +++ /dev/null @@ -1,54 +0,0 @@ -require "serverspec" - -set :backend, :exec - -def ubuntu? - os[:family] == "ubuntu" -end - -def redhat? - os[:family] == "redhat" -end - -describe "Ubuntu package installation", if: ubuntu? do - describe file("/etc/apt/sources.list.d/percona.list") do - it { should be_a_file } - its(:content) { should match "http://repo.percona.com/apt" } - end - - describe file("/etc/apt/preferences.d/00percona.pref") do - it { should be_a_file } - its(:content) { should match "release o=Percona Development Team" } - end - - describe package("libperconaserverclient18-dev") do - it { should be_installed } - end - - describe package("percona-server-client-5.5") do - it { should be_installed } - end - - describe package("percona-toolkit") do - it { should be_installed } - end -end - -describe "Red Hat package installation", if: redhat? do - describe yumrepo("percona") do - it { should exist } - it { should be_enabled } - end - - describe package("Percona-Server-devel-55") do - it { should be_installed } - end - - describe package("Percona-Server-client-55") do - it { should be_installed } - end - - describe package("percona-toolkit") do - it { should be_installed } - end -end diff --git a/test/integration/client_56/serverspec/localhost/client_56_spec.rb b/test/integration/client_56/serverspec/localhost/client_56_spec.rb deleted file mode 100644 index 20369d14..00000000 --- a/test/integration/client_56/serverspec/localhost/client_56_spec.rb +++ /dev/null @@ -1,54 +0,0 @@ -require "serverspec" - -set :backend, :exec - -def ubuntu? - os[:family] == "ubuntu" -end - -def redhat? - os[:family] == "redhat" -end - -describe "Ubuntu package installation" do - describe file("/etc/apt/sources.list.d/percona.list"), if: ubuntu? do - it { should be_a_file } - its(:content) { should match "http://repo.percona.com/apt" } - end - - describe file("/etc/apt/preferences.d/00percona.pref"), if: ubuntu? do - it { should be_a_file } - its(:content) { should match "release o=Percona Development Team" } - end - - describe package("libperconaserverclient18.1-dev"), if: ubuntu? do - it { should be_installed } - end - - describe package("percona-server-client-5.6"), if: ubuntu? do - it { should be_installed } - end - - describe package("percona-toolkit") do - it { should be_installed } - end -end - -describe "Red Hat package installation" do - describe yumrepo("percona"), if: redhat? do - it { should exist } - it { should be_enabled } - end - - describe package("Percona-Server-devel-56"), if: redhat? do - it { should be_installed } - end - - describe package("Percona-Server-client-56"), if: redhat? do - it { should be_installed } - end - - describe package("percona-toolkit") do - it { should be_installed } - end -end diff --git a/test/integration/data_bags/passwords/ssl_replication.json b/test/integration/data_bags/passwords/ssl_replication.json new file mode 100644 index 00000000..2974bacc --- /dev/null +++ b/test/integration/data_bags/passwords/ssl_replication.json @@ -0,0 +1,12 @@ +{ + "id": "ssl_replication", + "ca-cert": "-----BEGIN CERTIFICATE-----\nMIIDXTCCAkWgAwIBAgIJAM9aDRBDRsKlMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV\nBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX\naWRnaXRzIFB0eSBMdGQwHhcNMjAwODA4MDYwMTM0WhcNMzAwODA2MDYwMTM0WjBF\nMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50\nZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\nCgKCAQEA2ZQtSKPHkGVD5zy57IYf6E5DA0BKZpQ1DhvzIyaCF54AVWa+N+NaUgy/\n/NRr0cwPBM9uJ/nBCN/dRo1Uj8jAuJ4PS9YwOIfmhR+y/Z3DfBDnZVChmiydwlqR\nTNr8DNnCaU+mveHEdWcdUdXiun5XnSXYmS0mH/YirjM/vDPxVQ3n5Je4dolxte0W\nf9j3UdJ4/56VfQX+OpimlsUyJMuKVhBPtZfpIOAKWNinkhkzwdb+a6aT0qX360QU\n5cRrohQBbSn0imO28hM7d8fNHBLF+1IpTH5yVRdl5MnlDxeAh3Zcs0QQUtb8OUm5\nz/13YgceOCN5WiNghT0J+ah8orpvQwIDAQABo1AwTjAdBgNVHQ4EFgQUw64btZuh\nQLLRX11laapMdeWIPM0wHwYDVR0jBBgwFoAUw64btZuhQLLRX11laapMdeWIPM0w\nDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAZcHA5bt0WyabgVqyvE2Q\nuTjBjYMNuEPtSHqWNm3uW+trck+nMY4jq9hnJULOHR24r5s5Xxd0MI5PZiChmVME\nVbnhu9eA1L3fVLOyDWCd4VewY1CYnPPB8duCSd81Ldzq/WREeVidfa5XYChHAj+J\n+oHxqIea0+qeQvPrS89QVrlSgSTbBBcmuOJUidMiJgrsaGVJJIXpEsqxYm2bdI6l\nIV/QShSVK/KFEdc3oS4Noywvm1iPovU9BzFOW7JduKCH07s64Nbd3i7YpNKpxxNP\nyWvqG+p/t9rP04C/1mxxi/fy4R5U4jeSaX9SmwXwNkIZLoeX4q03sEzl9vRDJrpz\nHw==\n-----END CERTIFICATE-----\n", + "server": { + "server-cert": "-----BEGIN CERTIFICATE-----\nMIIC/jCCAeYCAQEwDQYJKoZIhvcNAQELBQAwRTELMAkGA1UEBhMCQVUxEzARBgNV\nBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0\nZDAeFw0yMDA4MDgwNjA0MjBaFw0zMDA4MDYwNjA0MjBaMEUxCzAJBgNVBAYTAkFV\nMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRz\nIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPq0DpvTBS\nrbHHLFESQDHF2gQbnS6/10fmjq3bMlWrOqrhyG5leH1m/G3hpcpuFTkxItWkc7vn\nPOFZAeOnxpu0OgIgOPbSz51E5CxNNY3JPrTLIHxLtS/U2IkBa23ZBU34wJbl6Vo2\nSc1PlI6ixikvR9XDEPNKBRIeUsq9rQyEX2ipL3HKoZ/lXklVjACB7y8z+DtkEiHj\n2KrZ45ytCyg7xwh/gBPp4NNr3vOE4ZQABiPIWR7FDGyMWz6fbHqbw/nwEY5A14bM\nYhvQDzto8KR0TpRqFOhFiLiXymrOI7ehHg2Y04FLObRcImDQfgc+ApXvNaN2JvaC\nqOjJ8JDyKDW1AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAG4uGCh1xbQSYwOoYEMG\nLEDVm0IlgGMIndAbAIeq3mrCtI2EJ4cscs9lkMNmGgSGaTxDWR35y6Xam3PRnYa3\nYm4K2ZMGRnKYDSRlLZKSiQAh7AS1BeLZ9PQ2G8r/K/Ta6uJuDSXVFokjex7hFe5P\nxqu1ytcxY055nzOXm3LLncznsmMtZt2iW2W4blPPQvu2u6NYgtzqEiRgtaZkLWA+\nmWxUtnpD4PBi8YnJV/wf4bMvQT8gccvtG36sXACtiQBlMHAt6EDRjE84+WS3GEF2\nTVpRluiIO0dBYqLz4faP395e7mefLK1mu0OX0Hb1J8XmWmoK224YWEv3wKeLZWzf\n7YY=\n-----END CERTIFICATE-----\n", + "server-key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDPq0DpvTBSrbHH\nLFESQDHF2gQbnS6/10fmjq3bMlWrOqrhyG5leH1m/G3hpcpuFTkxItWkc7vnPOFZ\nAeOnxpu0OgIgOPbSz51E5CxNNY3JPrTLIHxLtS/U2IkBa23ZBU34wJbl6Vo2Sc1P\nlI6ixikvR9XDEPNKBRIeUsq9rQyEX2ipL3HKoZ/lXklVjACB7y8z+DtkEiHj2KrZ\n45ytCyg7xwh/gBPp4NNr3vOE4ZQABiPIWR7FDGyMWz6fbHqbw/nwEY5A14bMYhvQ\nDzto8KR0TpRqFOhFiLiXymrOI7ehHg2Y04FLObRcImDQfgc+ApXvNaN2JvaCqOjJ\n8JDyKDW1AgMBAAECggEBALAnHPXoA+Bt87n2LoKjr1SbnRZrWydhjlzUtEaVyLNp\nHWBN6s7pyL2d6/sW7cI5AH1chgpsHXyFWMVuY9SCFLto5Tq99yhU8ZtpTOblQXLu\nXN9cm/KAK6WJU5W/sbr/0+boPlehfGNGcQBLDD6ohnDTp1BCxYwJBxhvtAf2jQKO\ngIQw8GlMGG57Gs5WwskQ+Y7nMO1SAHbRT7MyyCTd/4br9khkhwW1G79iuoSlkZ3K\nF3IdvrHe+tqyyuZQqaXNPz3XpwBStvUOzGiRmoNlPq4jYhs8MlrLUWPO92Ua0pcf\nBcOiQPeC8oXNwTS/WEN6RDcX9JMgAFTfDfqyu6gqDgECgYEA6HayzEgm5CYyK0CV\nIMt9UF4qCyDl8aLMTVEoG5rQ4jszWGSVixHWtyJcukYOMv1C+hKHkTlG9t/kGn5I\nxMwIrm568eCFGzG2sJEggUcZ83KeGu3oVS8W/1uPo4YUXZvfYNR81qyH4c0ADv+U\nqA66fqVGsQPOqs5wyPZp4Fsn0oECgYEA5LHknxbR6JCvtd809ELhwukf88I8Xfgp\nEPtYebDfEYFCLWhBIquZnIDsfr0Zx6kblWmXEJzHgW1jCrkLSP3f9KUmK3XTBR6c\nQJeQ6+09oMbPCYdOyZawAGfqiyOYmQNtd6m3csQktG8XPDPC5qz3Eig4DKFzuKtn\nQy4zfQ9HITUCgYBWgIzqDVNDhJ8YjzCvAmnANToJ6BUIxJ6nirKVCxf9hzAFDXDE\nTkAK56N/wT/ZY3q/2ZNOy/SHOysDXMixSodUeVIQnY6KXwZvT6G72XxjpdwFg0/4\nGszA+w5JOERtzOnje051B8CMmp8R9bMYklp9c/0JM7R8xNMdROyDCwiXgQKBgFZ2\n06M6c35kRaqTi2fWaZjRnx0AEObOTmh3PwozTwNFRYn5YrcC/f7n14JLaJXOX/lr\nhIvpWpyaiNmjAJtGMQhD8Fx6HaBP5G+fXlF0ztockGZf2+/nov9kSo70lFs1qouV\nhSBE/EOjxLskLsocFwWsYxSTbjchxtblft4HirMJAoGBALI2RqQX3USRcAuIbImd\nGFyltGN7r83Kb/5VuT8DVuyRZ4S1225m21jgrB8K0F+Px1GctbHdMLUU+MqNrwjT\nmpxvcwFLMGkeCKdchOjkIQEPZHS3oNvKBARarIX8ghBkDXj6ysGGDZOYK/08xuHc\nhcmvInxofp3bonuTL3f0cVWv\n-----END PRIVATE KEY-----\n" + }, + "client": { + "client-cert": "-----BEGIN CERTIFICATE-----\nMIIC/jCCAeYCAQEwDQYJKoZIhvcNAQELBQAwRTELMAkGA1UEBhMCQVUxEzARBgNV\nBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0\nZDAeFw0yMDA4MDgwNjA0MzJaFw0zMDA4MDYwNjA0MzJaMEUxCzAJBgNVBAYTAkFV\nMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRz\nIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCb87YqyPRG\nEL+gyT0EpfPqVk85MIPPIu9NgEwxvZNBHCeUlRMMPLaj78tCsO6gm2LuvJUDSiwq\nEdcqIg4ggwhGn4C/29EOJkF8bRbzoGUnOezJT/50BscZu0aaQ1qjjU1d3AXnILBu\nplroe7Gs9Vjs26hUclYMMI/zz1MjZCm0EAGDDxWbMHm+RLjZEK6S8PoOrD4lHsLh\nlUqmUlRGvSJNul6F/v6DckY84gPCL8kI1TwoO4ZBElX7CcesYYMXfCcVQEe7sqVs\nNEg43kOZvTlEnCqjPbFbux6vZF5QKAkKHAy9nOSoFu67NH3U0mdBdI029cGME/G/\nPm6FCsrkq9pNAgMBAAEwDQYJKoZIhvcNAQELBQADggEBANjt0N6kHuqqiKZ1eSm4\nLZH9hDFb+MBBbftefkJwHj1NF4y0jUL5qhsWfCwOxt1JX/4psESwYMuPjMjjJfQE\necfke9DozfEfQllaAsn+GNlpGVQ9BUGOP7YXXZa8mG8nybiVHcN5fIRntBBWpWvm\nI7/dtkzMpt5I94VhC51wNuIhmyBPlOLLvZ0V7kevtjXDjrIza7PeGVlUXYmHHFs/\njLghv7sKMwWt7tI2Wpo0yas6zaZZS/fSySoBa9yUPcWgKRY+Xtbv6wnOYD6QYOsN\ns2mD7P2eCPGbRwlMm7JRBpEdq8XX5mHWrRmes+7yBF7WkV/qGf4yqGFPTWucc+d8\n0Es=\n-----END CERTIFICATE-----\n", + "client-key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCb87YqyPRGEL+g\nyT0EpfPqVk85MIPPIu9NgEwxvZNBHCeUlRMMPLaj78tCsO6gm2LuvJUDSiwqEdcq\nIg4ggwhGn4C/29EOJkF8bRbzoGUnOezJT/50BscZu0aaQ1qjjU1d3AXnILBuplro\ne7Gs9Vjs26hUclYMMI/zz1MjZCm0EAGDDxWbMHm+RLjZEK6S8PoOrD4lHsLhlUqm\nUlRGvSJNul6F/v6DckY84gPCL8kI1TwoO4ZBElX7CcesYYMXfCcVQEe7sqVsNEg4\n3kOZvTlEnCqjPbFbux6vZF5QKAkKHAy9nOSoFu67NH3U0mdBdI029cGME/G/Pm6F\nCsrkq9pNAgMBAAECggEANp53maqB6xwokT6J0Vvx/ou1+XilYWGB4GnjxbP4o+Ah\neKdxYWLOMMJmNPhUywlA8A46Pkm3CBDxg78jpX1e46UvaYKqSENbwiFO3Yq6gq+F\n38fVfXt2NeviQVr/nrJ5ezr5EkbfpBE9W5ke1E2llGcmIFVfD6vebuyY2JdXB8nb\nU33WLVda7ARrG+7e9tNismEbYnEFQfKv2vDMoEi7LslGdZ8rG1WUDW4sHKuVBFNv\nxMA/duhHdNGW/fv1lyBtZSeOTbJrgHkAuWPf3QQD2BypAQ+Mz9DlmbmUHua7W05n\nreCfsmqZ1xnLZH0vxc9f7UJ3XDEBXrVNb0chhn0vIQKBgQDK9A3H17Cw8caKhsTy\nlilwOyw4Xo34mMvsZ9v+SKxdtoR8PMxRIbT8GbKt2/iSNPgcVcj6rTMMdD57USnd\n98VfQv3pDKUdQRJ1wRwmOLzOzGQBXrbc8vX+gTTetqd17XDbET35IqqyHp4hXON4\nMPln0ZBaDaNIL0fB/lCqSaL/yQKBgQDEtrhMZqddPnx5HG/nx0Mqg2k0qF6Jft6E\nUGlhdP/gchZibS6y111mp/kDZo8sCESJNPD/g4CMMw4haPVsAdtKV05/3KDGSwwJ\npktDXjb07KGRrRfYa5svV4R0S8nIFAcTENMTDxVwgs4fMINE0lKNIAp8xzBB4pn6\nVfss2E1wZQKBgQCr8gEK4u5Lu0seaffKHvaUo01fpJxblfiPHZ8A3MlLzCqKp2fj\nBM+1FoCPU+JQ3JeoSfWwi7TIRGP7TlROPnD1uGguXgw1sL/XC/ixWTh9bCT+FCSR\nJTbMnOMSHWXbP4Nx1jXPMVO0/MO0OGJvne5vytilsxA3Q/djn/bvjtuOIQKBgFmm\nnJ/VOPl5/OiFWUrcuXOqqEvjYBJxy5+pth1AYU09MY5yDBJdrKeYbhhqqV179yBB\nDISmvfMnYY1AdHlg7zwWRiRnvK4ijb3oF+0ABzPglFH7/R4ZDISq8ia+U5vn5MF/\nrXLGMRMxyhbU2T6ITC8dJypu7UNZrqs0fGCXw9MxAoGBAKNmWmECNrws3BirKpxK\n9JeYHM7nwUu8hWf8nO6FtCa2vB3DEMpseSK7PHi0JCHylEy0PaivBmjHrl5/LD80\n8h6x48HbclHOJKgMbe0X7y9rqF5BQNTTkFmxYc65Sj221ABK16e9f4wsUB4TmKSb\nqir5oop2mZmGHIrhAws9Ey7/\n-----END PRIVATE KEY-----\n" + } +} diff --git a/test/integration/inspec/controls/client_spec.rb b/test/integration/inspec/controls/client_spec.rb new file mode 100644 index 00000000..88a755d9 --- /dev/null +++ b/test/integration/inspec/controls/client_spec.rb @@ -0,0 +1,145 @@ +version = input('version') +type = input('type') +devel = input('devel') + +control 'client' do + desc 'Ensure Percona clients are installed.' + impact 1.0 + + if os.family == 'debian' + describe apt 'http://repo.percona.com/apt' do + it { should exist } + it { should be_enabled } + end + + if type == 'cluster' && version.to_i >= 8 + describe apt 'http://repo.percona.com/pxc-80/apt' do + it { should exist } + it { should be_enabled } + end + elsif version.to_i >= 8 + describe apt 'http://repo.percona.com/ps-80/apt' do + it { should exist } + it { should be_enabled } + end + else + describe apt 'http://repo.percona.com/ps-80/apt' do + it { should_not exist } + it { should_not be_enabled } + end + end + + describe file '/etc/apt/preferences.d/00percona.pref' do + it { should be_a_file } + its('content') { should match 'release o=Percona Development Team' } + end + + if type == 'cluster' && version.to_i >= 8 + describe package 'percona-xtradb-cluster-client' do + it { should be_installed } + its('version') { should >= '1:8' } + end + elsif type == 'cluster' + describe package "percona-xtradb-cluster-client-#{version}" do + it { should be_installed } + end + elsif version.to_i >= 8 + describe package 'percona-server-client' do + it { should be_installed } + its('version') { should >= '8' } + end + else + describe package "percona-server-client-#{version}" do + it { should be_installed } + end + end + + if devel == true + if version.to_i >= 8 + describe package 'libperconaserverclient21-dev' do + it { should be_installed } + end + elsif version == '5.7' + describe package 'libperconaserverclient20-dev' do + it { should be_installed } + end + elsif version == '5.6' + describe package 'libperconaserverclient18.1-dev' do + it { should be_installed } + end + end + elsif version.to_i >= 8 + describe package 'libperconaserverclient21-dev' do + it { should_not be_installed } + end + elsif version == '5.7' + describe package 'libperconaserverclient20-dev' do + it { should_not be_installed } + end + elsif version == '5.6' + describe package 'libperconaserverclient18.1-dev' do + it { should_not be_installed } + end + end + + else + describe yum.repo 'percona' do + it { should exist } + it { should be_enabled } + end + + describe yum.repo 'percona-noarch' do + it { should exist } + it { should be_enabled } + end + + if type == 'cluster' && version.to_i >= 8 + describe package 'percona-xtradb-cluster-client' do + it { should be_installed } + its('version') { should >= '8' } + end + elsif type == 'cluster' + describe package "Percona-XtraDB-Cluster-client-#{version.tr('.', '')}" do + it { should be_installed } + end + elsif version.to_i >= 8 + describe package 'percona-server-client' do + it { should be_installed } + its('version') { should >= '8' } + end + else + describe package "Percona-Server-client-#{version.tr('.', '')}" do + it { should be_installed } + end + end + + if devel == true + if version.to_i >= 8 + describe package 'percona-server-devel' do + it { should be_installed } + end + else + describe package "Percona-Server-devel-#{version.tr('.', '')}" do + it { should be_installed } + end + end + else + describe package "Percona-Server-devel-#{version.tr('.', '')}" do + it { should_not be_installed } + end + describe package 'percona-server-devel' do + it { should_not be_installed } + end + end + + end + + describe command 'mysql --version' do + its('exit_status') { should eq 0 } + if version.to_i >= 8 + its('stdout') { should match /Ver #{version.tr('.', '\.')}.+/ } + else + its('stdout') { should match /Distrib #{version.tr('.', '\.')}.+/ } + end + end +end diff --git a/test/integration/inspec/controls/resources_spec.rb b/test/integration/inspec/controls/resources_spec.rb new file mode 100644 index 00000000..b38f625b --- /dev/null +++ b/test/integration/inspec/controls/resources_spec.rb @@ -0,0 +1,60 @@ +control 'percona_database' do + impact 1.0 + title 'test creation and removal of databases' + + sql = mysql_session('root', '') + + describe sql.query('show databases') do + its(:stdout) { should match(/databass/) } + its(:stdout) { should_not match(/datatrout/) } + end +end + +control 'percona_user' do + impact 1.0 + title 'test creation, granting and removal of users' + + version = input('version') + password_column = version.to_f >= 5.7 ? 'authentication_string' : 'password' + + sql = mysql_session('root', '') + + describe sql.query('select User,Host from mysql.user') do + its(:stdout) { should match(/fozzie/) } + its(:stdout) { should_not match(/kermit/) } + end + + describe sql.query("SELECT #{password_column} FROM mysql.user WHERE user='fozzie' AND host='mars'") do + its(:stdout) { should include '*EF112B3D562CB63EA3275593C10501B59C4A390D' } + end + + describe sql.query("SELECT #{password_column} FROM mysql.user WHERE user='moozie' AND host='127.0.0.1'") do + its(:stdout) { should include '*F798E7C0681068BAE3242AA2297D2360DBBDA62B' } + end + + sql2 = mysql_session('moozie', 'zokkazokka', '127.0.0.1') + + describe sql2.query('show tables from databass') do + its(:exit_status) { should eq 0 } + end + + describe sql.query("SELECT #{password_column} FROM mysql.user WHERE user='rowlf' AND host = 'localhost'") do + its(:stdout) { should include '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' } + end + + describe sql.query("SELECT #{password_column} FROM mysql.user WHERE user='statler' AND host='localhost'") do + its(:stdout) { should include '*2027D9391E714343187E07ACB41AE8925F30737E' } + end + + describe sql.query('select Host from mysql.user where User like \'gonzo\'') do + its(:stdout) { should include '10.10.10.%' } + end + + describe sql.query("SELECT #{password_column} FROM mysql.user WHERE user='rizzo' AND host='127.0.0.1'") do + its(:stdout) { should include '*125EA03B506F7C876D9321E9055F37601461E970' } + end + + describe sql.query('select User,Host from mysql.user') do + its(:stdout) { should match(/bunsen/) } + end +end diff --git a/test/integration/inspec/controls/server_spec.rb b/test/integration/inspec/controls/server_spec.rb new file mode 100644 index 00000000..fd267814 --- /dev/null +++ b/test/integration/inspec/controls/server_spec.rb @@ -0,0 +1,253 @@ +version = input('version') +type = input('type') + +control 'server' do + desc 'Ensure server is installed' + impact 1.0 + + if os.family == 'debian' + case type + when 'server' + if version.to_i >= 8 + describe package 'percona-server-server' do + it { should be_installed } + its('version') { should >= '8.0' } + end + else + describe package "percona-server-server-#{version}" do + it { should be_installed } + end + end + when 'cluster' + if version.to_i >= 8 + describe package 'percona-xtradb-cluster-server' do + it { should be_installed } + its('version') { should >= '1:8.0' } + end + else + describe package "percona-xtradb-cluster-server-#{version}" do + it { should be_installed } + end + end + end + + xtrabackup_pkg = + if type == 'cluster' + if version.to_f < 5.7 + 'percona-xtrabackup' + else + 'percona-xtrabackup-24' + end + elsif (os.name == 'debian' && os.release.to_i >= 10) || (os.name == 'ubuntu' && os.release.to_f >= 20.04) + 'percona-xtrabackup-80' + else + 'xtrabackup' + end + + describe package xtrabackup_pkg do + if version.to_i >= 8 && type == 'cluster' + it { should_not be_installed } + else + it { should be_installed } + end + end + + jemalloc_pkg = + case os.name + when 'debian' + os.release.to_i >= 10 ? 'libjemalloc2' : 'libjemalloc1' + when 'ubuntu' + os.release.to_f >= 20.04 ? 'libjemalloc2' : 'libjemalloc1' + when 'centos' + os.release.to_i >= 8 ? 'libjemalloc2' : 'libjemalloc1' + end + + describe package jemalloc_pkg do + it { should be_installed } + end + + describe file '/etc/mysql/my.cnf' do + it { should be_a_file } + its('owner') { should cmp 'root' } + its('group') { should cmp 'root' } + its('mode') { should cmp '0644' } + end + + if version.to_f < 5.7 + describe file '/etc/mysql/grants.sql' do + its('content') { should match 'debian-sys-maint' } + its('content') { should match /0kb\)F\?Zj/ } + end + end + + describe file '/etc/mysql/debian.cnf' do + it { should be_a_file } + its('owner') { should cmp 'root' } + its('group') { should cmp 'root' } + its('mode') { should cmp '0640' } + its('content') { should match /0kb\)F\?Zj/ } + end + end + + if os.family == 'rhel' + + # postfix on RHEL depends on mysql-libs, ensure it still exists when using percona + describe package 'postfix' do + it { should be_installed } + end + + ver = version.tr('.', '') + describe package "Percona-Server-devel-#{ver}" do + it { should be_installed } + end + + if os.release.to_i >= 8 + describe package 'percona-xtrabackup-80' do + it { should be_installed } + end + else + describe package 'xtrabackup' do + it { should be_installed } + end + end + + describe package "Percona-Server-client-#{ver}" do + it { should be_installed } + end + + describe package "Percona-Server-server-#{ver}" do + it { should be_installed } + end + + describe package 'jemalloc' do + it { should be_installed } + end + + describe file '/etc/my.cnf' do + it { should be_a_file } + its('owner') { should cmp 'root' } + its('group') { should cmp 'root' } + its('mode') { should cmp '0644' } + end + end + + describe file '/root/.my.cnf' do + it { should be_a_file } + its('owner') { should cmp 'root' } + its('group') { should cmp 'root' } + its('mode') { should cmp '0600' } + its('content') { should match /7tCk\(V5I/ } + end + + describe file '/etc/mysql' do + it { should be_a_directory } + its('owner') { should cmp 'root' } + its('group') { should cmp 'root' } + its('mode') { should cmp '0755' } + end + + describe file '/var/lib/mysql' do + it { should be_a_directory } + its('owner') { should cmp 'mysql' } + its('group') { should cmp 'mysql' } + end + + describe file '/var/log/mysql' do + it { should be_a_directory } + its('owner') { should cmp 'mysql' } + its('group') { should cmp 'mysql' } + end + + describe service 'mysql' do + it { should be_enabled } + it { should be_running } + end + + describe processes('mysqld') do + it { should exist } + its('users') { should include 'mysql' } + end + + describe port 3306 do + it { should be_listening } + end + + describe file '/etc/mysql/grants.sql' do + it { should be_a_file } + its('owner') { should cmp 'root' } + its('group') { should cmp 'root' } + its('mode') { should cmp '0600' } + its('content') { should match /7tCk\(V5I/ } + end + + if type == 'source' + describe file '/etc/mysql/replication.sql' do + it { should be_a_file } + its('owner') { should cmp 'root' } + its('group') { should cmp 'root' } + its('mode') { should cmp '0600' } + its('content') { should match %r{\)6\$W2M\{/} } + its('content') { should match /TO 'replication'@'%'/ } + its('content') { should match /MASTER_HOST='source-host'/ } + its('content') { should match /MASTER_USER='replication'/ } + its('content') { should match %r{MASTER_PASSWORD='\)6\$W2M\{/'} } + end + elsif type == 'replication' + describe file '/etc/mysql/replication.sql' do + it { should be_a_file } + its('owner') { should cmp 'root' } + its('group') { should cmp 'root' } + its('mode') { should cmp '0600' } + if version.to_i >= 8 + its('content') { should match %r{CREATE USER IF NOT EXISTS 'replication'@'%' IDENTIFIED BY '\)6\$W2M\{\/';} } + its('content') { should match /GRANT REPLICATION SLAVE ON \*\.\* TO 'replication'@'%';/ } + its('content') { should match /ALTER USER 'replication'@'%' REQUIRE SSL;/ } + else + its('content') { should match %r{GRANT REPLICATION SLAVE ON \*\.\* TO 'replication'@'%' IDENTIFIED BY '\)6\$W2M\{/' REQUIRE SSL;} } + end + its('content') { should match /MASTER_HOST='source-host'/ } + its('content') { should match /MASTER_USER='replication'/ } + its('content') { should match %r{MASTER_PASSWORD='\)6\$W2M\{/'} } + its('content') { should match /MASTER_SSL=1/ } + its('content') { should match %r{MASTER_SSL_CA='/etc/mysql/ssl/cacert.pem'} } + its('content') { should match %r{MASTER_SSL_CERT='/etc/mysql/ssl/server-cert.pem'} } + its('content') { should match %r{MASTER_SSL_KEY='/etc/mysql/ssl/server-key.pem'} } + end + else + describe file '/etc/mysql/replication.sql' do + it { should_not be_a_file } + end + end + + describe file '/tmp/mysql' do + it { should be_a_directory } + its('owner') { should cmp 'mysql' } + its('group') { should cmp 'mysql' } + end + + mysql_file = version.to_i >= 8 ? '/tmp/mysql/mysql.ibd' : '/tmp/mysql/mysql/user.frm' + mysql_mode = version.to_f < 5.7 ? '0660' : '0640' + + describe file '/tmp/mysql/ibdata1' do + it { should be_a_file } + its('owner') { should cmp 'mysql' } + its('group') { should cmp 'mysql' } + its('mode') { should cmp mysql_mode } + end + + describe file mysql_file do + it { should be_a_file } + its('owner') { should cmp 'mysql' } + its('group') { should cmp 'mysql' } + its('mode') { should cmp mysql_mode } + end + + describe command "mysqladmin --user='root' --password='7tCk(V5I' variables" do + its('stdout') { should match %r{datadir\s+\| /tmp/mysql/} } + its('stdout') { should match %r{general_log_file\s+\| /tmp/mysql/} } + its('stdout') { should match /max_connections\s+\| 30/ } + its('stdout') { should match /table_open_cache\s+\| 8172/ } unless os.family == 'debian' # (open_files_limit - 10 - max_connections) / 2 + its('stdout') { should match /open_files_limit\s+\| 16384/ } unless os.family == 'debian' + its('exit_status') { should eq 0 } + end +end diff --git a/test/integration/inspec/controls/toolkit_spec.rb b/test/integration/inspec/controls/toolkit_spec.rb new file mode 100644 index 00000000..9d0ca652 --- /dev/null +++ b/test/integration/inspec/controls/toolkit_spec.rb @@ -0,0 +1,16 @@ +version = input('version') + +control 'toolkit' do + desc 'Ensure Percona toolkit are installed.' + impact 1.0 + + if version.to_i >= 8 && os.family == 'redhat' && os.release.to_i >= 8 + describe package 'percona-toolkit' do + it { should_not be_installed } + end + else + describe package 'percona-toolkit' do + it { should be_installed } + end + end +end diff --git a/test/integration/inspec/inspec.yml b/test/integration/inspec/inspec.yml new file mode 100644 index 00000000..98f89868 --- /dev/null +++ b/test/integration/inspec/inspec.yml @@ -0,0 +1,12 @@ +--- +name: percona +title: Integration tests for the Percona Cookbook +version: 0.1.0 +inputs: + - name: version + type: Numeric + required: true + - name: type + value: 'server' +supports: + - os-family: linux diff --git a/test/integration/server_55/serverspec/localhost/server_55_spec.rb b/test/integration/server_55/serverspec/localhost/server_55_spec.rb deleted file mode 100644 index f8d8363d..00000000 --- a/test/integration/server_55/serverspec/localhost/server_55_spec.rb +++ /dev/null @@ -1,168 +0,0 @@ -require "serverspec" - -set :backend, :exec - -def ubuntu? - os[:family] == "ubuntu" -end - -def redhat? - os[:family] == "redhat" -end - -describe "Ubuntu package installation", if: ubuntu? do - describe package("percona-server-server-5.5") do - it { should be_installed } - end - - describe package("libjemalloc1") do - it { should be_installed } - end -end - -describe "Red Hat package installation", if: redhat? do - describe package("Percona-Server-devel-55") do - it { should be_installed } - end - - describe package("Percona-Server-client-55") do - it { should be_installed } - end - - describe package("Percona-Server-server-55") do - it { should be_installed } - end - - describe package("jemalloc") do - it { should be_installed } - end -end - -describe "Service configuration" do - describe file("/root/.my.cnf") do - it { should be_a_file } - it { should be_owned_by "root" } - it { should be_grouped_into "root" } - it { should be_mode 600 } - its(:content) { should match "r00t" } - end - - describe file("/etc/mysql") do - it { should be_a_directory } - it { should be_owned_by "root" } - it { should be_grouped_into "root" } - it { should be_mode 755 } - end - - describe file("/var/lib/mysql") do - it { should be_a_directory } - it { should be_owned_by "mysql" } - it { should be_grouped_into "mysql" } - end - - describe file("/var/log/mysql") do - it { should be_a_directory } - it { should be_owned_by "mysql" } - it { should be_grouped_into "mysql" } - end - - describe file("/tmp") do - it { should be_a_directory } - it { should be_owned_by "mysql" } - it { should be_grouped_into "mysql" } - end - - describe service("mysql") do - it { should be_enabled } - it { should be_running } - end - - describe command("pgrep mysql") do - its(:stdout) { should match(/\d+/) } - its(:exit_status) { should eq 0 } - end - - describe port(3306) do - it { should be_listening } - end - - describe file("/var/lib/mysql/mysql/user.frm") do - it { should be_a_file } - it { should be_owned_by "mysql" } - it { should be_grouped_into "mysql" } - end - - describe file("/etc/mysql/my.cnf"), if: ubuntu? do - it { should be_a_file } - it { should be_owned_by "root" } - it { should be_grouped_into "root" } - it { should be_mode 644 } - end - - describe file("/etc/my.cnf"), if: redhat? do - it { should be_a_file } - it { should be_owned_by "root" } - it { should be_grouped_into "root" } - it { should be_mode 644 } - end - - describe file("/etc/mysql/grants.sql") do - it { should be_a_file } - it { should be_owned_by "root" } - it { should be_grouped_into "root" } - it { should be_mode 600 } - its(:content) { should match "r00t" } - end - - describe file("/etc/mysql/grants.sql"), if: ubuntu? do - its(:content) { should match "debian-sys-maint" } - its(:content) { should match "d3b1an" } - end - - describe file("/etc/mysql/debian.cnf"), if: ubuntu? do - it { should be_a_file } - it { should be_owned_by "root" } - it { should be_grouped_into "root" } - it { should be_mode 640 } - its(:content) { should match "d3b1an" } - end - - describe file("/etc/mysql/replication.sql") do - it { should_not be_a_file } - end - - describe "Custom data directory" do - describe file("/tmp/mysql") do - it { should be_a_directory } - it { should be_owned_by "mysql" } - it { should be_grouped_into "mysql" } - end - - describe file("/tmp/mysql/ibdata1") do - it { should be_a_file } - it { should be_owned_by "mysql" } - it { should be_grouped_into "mysql" } - it { should be_mode 660 } - end - - describe file("/tmp/mysql/ibdata1") do - it { should be_a_file } - it { should be_owned_by "mysql" } - it { should be_grouped_into "mysql" } - it { should be_mode 660 } - end - - describe file("/tmp/mysql/mysql/user.frm") do - it { should be_a_file } - it { should be_owned_by "mysql" } - it { should be_grouped_into "mysql" } - it { should be_mode 660 } - end - - describe command("mysqladmin --user='root' --password='r00t' variables") do - its(:stdout) { should match %r(datadir\s+| /tmp/mysql/) } - its(:stdout) { should match %r(general_log_file\s+| /tmp/mysql/) } - its(:exit_status) { should eq 0 } - end - end -end diff --git a/test/integration/server_56/serverspec/localhost/server_56_spec.rb b/test/integration/server_56/serverspec/localhost/server_56_spec.rb deleted file mode 100644 index a542617a..00000000 --- a/test/integration/server_56/serverspec/localhost/server_56_spec.rb +++ /dev/null @@ -1,168 +0,0 @@ -require "serverspec" - -set :backend, :exec - -def ubuntu? - os[:family] == "ubuntu" -end - -def redhat? - os[:family] == "redhat" -end - -describe "Ubuntu package installation", if: ubuntu? do - describe package("percona-server-server-5.6") do - it { should be_installed } - end - - describe package("libjemalloc1") do - it { should be_installed } - end -end - -describe "Red Hat package installation", if: redhat? do - describe package("Percona-Server-devel-56") do - it { should be_installed } - end - - describe package("Percona-Server-client-56") do - it { should be_installed } - end - - describe package("Percona-Server-server-56") do - it { should be_installed } - end - - describe package("jemalloc") do - it { should be_installed } - end -end - -describe "Service configuration" do - describe file("/root/.my.cnf") do - it { should be_a_file } - it { should be_owned_by "root" } - it { should be_grouped_into "root" } - it { should be_mode 600 } - its(:content) { should match "r00t" } - end - - describe file("/etc/mysql") do - it { should be_a_directory } - it { should be_owned_by "root" } - it { should be_grouped_into "root" } - it { should be_mode 755 } - end - - describe file("/var/lib/mysql") do - it { should be_a_directory } - it { should be_owned_by "mysql" } - it { should be_grouped_into "mysql" } - end - - describe file("/var/log/mysql") do - it { should be_a_directory } - it { should be_owned_by "mysql" } - it { should be_grouped_into "mysql" } - end - - describe file("/tmp") do - it { should be_a_directory } - it { should be_owned_by "mysql" } - it { should be_grouped_into "mysql" } - end - - describe service("mysql") do - it { should be_enabled } - it { should be_running } - end - - describe command("pgrep mysql") do - its(:stdout) { should match(/\d+/) } - its(:exit_status) { should eq 0 } - end - - describe port(3306) do - it { should be_listening } - end - - describe file("/var/lib/mysql/mysql/user.frm") do - it { should be_a_file } - it { should be_owned_by "mysql" } - it { should be_grouped_into "mysql" } - end - - describe file("/etc/mysql/my.cnf"), if: ubuntu? do - it { should be_a_file } - it { should be_owned_by "root" } - it { should be_grouped_into "root" } - it { should be_mode 644 } - end - - describe file("/etc/my.cnf"), if: redhat? do - it { should be_a_file } - it { should be_owned_by "root" } - it { should be_grouped_into "root" } - it { should be_mode 644 } - end - - describe file("/etc/mysql/grants.sql") do - it { should be_a_file } - it { should be_owned_by "root" } - it { should be_grouped_into "root" } - it { should be_mode 600 } - its(:content) { should match "r00t" } - end - - describe file("/etc/mysql/grants.sql"), if: ubuntu? do - its(:content) { should match "debian-sys-maint" } - its(:content) { should match "d3b1an" } - end - - describe file("/etc/mysql/debian.cnf"), if: ubuntu? do - it { should be_a_file } - it { should be_owned_by "root" } - it { should be_grouped_into "root" } - it { should be_mode 640 } - its(:content) { should match "d3b1an" } - end - - describe file("/etc/mysql/replication.sql") do - it { should_not be_a_file } - end - - describe "Custom data directory" do - describe file("/tmp/mysql") do - it { should be_a_directory } - it { should be_owned_by "mysql" } - it { should be_grouped_into "mysql" } - end - - describe file("/tmp/mysql/ibdata1") do - it { should be_a_file } - it { should be_owned_by "mysql" } - it { should be_grouped_into "mysql" } - it { should be_mode 660 } - end - - describe file("/tmp/mysql/ibdata1") do - it { should be_a_file } - it { should be_owned_by "mysql" } - it { should be_grouped_into "mysql" } - it { should be_mode 660 } - end - - describe file("/tmp/mysql/mysql/user.frm") do - it { should be_a_file } - it { should be_owned_by "mysql" } - it { should be_grouped_into "mysql" } - it { should be_mode 660 } - end - - describe command("mysqladmin --user='root' --password='r00t' variables") do - its(:stdout) { should match %r(datadir\s+| /tmp/mysql/) } - its(:stdout) { should match %r(general_log_file\s+| /tmp/mysql/) } - its(:exit_status) { should eq 0 } - end - end -end diff --git a/test/support/Gemfile.lock b/test/support/Gemfile.lock deleted file mode 100644 index 26653614..00000000 --- a/test/support/Gemfile.lock +++ /dev/null @@ -1,203 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - activesupport (3.2.13) - i18n (= 0.6.1) - multi_json (~> 1.0) - addressable (2.3.4) - akami (1.2.0) - gyoku (>= 0.4.0) - nokogiri (>= 1.4.0) - berkshelf (2.0.3) - activesupport (>= 3.2.0) - addressable (~> 2.3.4) - celluloid (>= 0.14.0) - chozo (>= 0.6.1) - faraday (>= 0.8.5) - hashie (>= 2.0.2) - minitar (~> 0.5.4) - retryable (~> 1.3.3) - ridley (~> 1.0.2) - solve (>= 0.4.4) - test-kitchen (>= 1.0.0.alpha7) - thor (~> 0.18.0) - builder (3.2.2) - bunny (0.7.9) - celluloid (0.14.1) - timers (>= 1.0.0) - celluloid-io (0.14.1) - celluloid (>= 0.14.1) - nio4r (>= 0.4.5) - chef (10.16.6) - bunny (>= 0.6.0, < 0.8.0) - erubis - highline (>= 1.6.9) - json (>= 1.4.4, <= 1.6.1) - mixlib-authentication (>= 1.3.0) - mixlib-cli (>= 1.1.0) - mixlib-config (>= 1.1.2) - mixlib-log (>= 1.3.0) - mixlib-shellout - moneta (< 0.7.0) - net-ssh (~> 2.2.2) - net-ssh-multi (~> 1.1.0) - ohai (>= 0.6.0) - rest-client (>= 1.0.4, < 1.7.0) - treetop (~> 1.4.9) - uuidtools - yajl-ruby (~> 1.1) - chozo (0.6.1) - activesupport (>= 3.2.0) - hashie (>= 2.0.2) - multi_json (>= 1.3.0) - coderay (1.0.9) - erubis (2.7.0) - excon (0.24.0) - faraday (0.8.7) - multipart-post (~> 1.1) - ffi (1.9.0) - fog (1.9.0) - builder - excon (~> 0.14) - formatador (~> 0.2.0) - mime-types - multi_json (~> 1.0) - net-scp (~> 1.0.4) - net-ssh (>= 2.1.3) - nokogiri (~> 1.5.0) - ruby-hmac - foodcritic (2.1.0) - erubis - gherkin (~> 2.11.7) - nokogiri (~> 1.5.4) - rak (~> 1.4) - treetop (~> 1.4.10) - yajl-ruby (~> 1.1.0) - formatador (0.2.4) - gherkin (2.11.8) - multi_json (~> 1.3) - gssapi (1.0.3) - ffi (>= 1.0.1) - gyoku (1.0.0) - builder (>= 2.1.2) - hashie (2.0.5) - highline (1.6.19) - httpclient (2.2.0.2) - httpi (0.9.7) - rack - i18n (0.6.1) - ipaddress (0.8.0) - json (1.6.1) - kitchen-ec2 (0.5.1) - fog - test-kitchen (~> 1.0.0.alpha.7) - little-plugger (1.1.3) - logging (1.6.2) - little-plugger (>= 1.1.3) - method_source (0.8.1) - mime-types (1.23) - minitar (0.5.4) - mixlib-authentication (1.3.0) - mixlib-log - mixlib-cli (1.3.0) - mixlib-config (1.1.2) - mixlib-log (1.6.0) - mixlib-shellout (1.1.0) - moneta (0.6.0) - multi_json (1.7.7) - multipart-post (1.2.0) - net-http-persistent (2.8) - net-scp (1.0.4) - net-ssh (>= 1.99.1) - net-ssh (2.2.2) - net-ssh-gateway (1.1.0) - net-ssh (>= 1.99.1) - net-ssh-multi (1.1) - net-ssh (>= 2.1.4) - net-ssh-gateway (>= 0.99.0) - nio4r (0.4.6) - nokogiri (1.5.10) - nori (1.1.5) - ohai (6.16.0) - ipaddress - mixlib-cli - mixlib-config - mixlib-log - mixlib-shellout - systemu - yajl-ruby - polyglot (0.3.3) - pry (0.9.12.2) - coderay (~> 1.0.5) - method_source (~> 0.8) - slop (~> 3.4) - rack (1.5.2) - rak (1.4) - rake (10.0.4) - rest-client (1.6.7) - mime-types (>= 1.16) - retryable (1.3.3) - ridley (1.0.2) - addressable - celluloid (~> 0.14.0) - celluloid-io (~> 0.14.0) - chozo (>= 0.6.0) - erubis - faraday (>= 0.8.4) - hashie (>= 2.0.2) - mixlib-authentication (>= 1.3.0) - net-http-persistent (>= 2.8) - net-ssh - retryable - solve (>= 0.4.4) - winrm (~> 1.1.0) - ruby-hmac (0.4.0) - rubyntlm (0.1.1) - safe_yaml (0.9.3) - savon (0.9.5) - akami (~> 1.0) - builder (>= 2.1.2) - gyoku (>= 0.4.0) - httpi (~> 0.9) - nokogiri (>= 1.4.0) - nori (~> 1.0) - wasabi (~> 1.0) - slop (3.4.5) - solve (0.5.0) - systemu (2.5.2) - test-kitchen (1.0.0.alpha.7) - celluloid - mixlib-shellout - net-scp - net-ssh - pry - safe_yaml - thor - thor (0.18.1) - timers (1.1.0) - treetop (1.4.14) - polyglot - polyglot (>= 0.3.1) - uuidtools (2.1.4) - wasabi (1.0.0) - nokogiri (>= 1.4.0) - winrm (1.1.2) - gssapi (~> 1.0.0) - httpclient (~> 2.2.0.2) - logging (~> 1.6.1) - nokogiri (~> 1.5.0) - rubyntlm (~> 0.1.1) - savon (= 0.9.5) - uuidtools (~> 2.1.2) - yajl-ruby (1.1.0) - -PLATFORMS - ruby - -DEPENDENCIES - berkshelf - chef (~> 10.16.4) - foodcritic - kitchen-ec2 - moneta (< 0.7.0) - rake diff --git a/test/support/keys/README.md b/test/support/keys/README.md deleted file mode 100644 index 47c0ccf9..00000000 --- a/test/support/keys/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Insecure Keypair - -These keys are the "insecure" public/private keypair we offer to -[base box creators](http://docs.vagrantup.com/v1/docs/base_boxes.html) for use in their base boxes so that -vagrant installations can automatically SSH into the boxes. - -If you're working with a team or company or with a custom box and -you want more secure SSH, you should create your own keypair -and configure the private key in the Vagrantfile with -`config.ssh.private_key_path` - -# Putty - -If you are using Vagrant on windows, the .ppk file contained here, in the keys directory, -has been generated from the private key and should be used to connect Putty to any VMs that -are leveraging the default key pair. See [guide](http://docs.vagrantup.com/v1/docs/getting-started/ssh.html) -in the documentation for more details on using Putty with Vagrant. diff --git a/test/support/keys/vagrant b/test/support/keys/vagrant deleted file mode 100644 index 7d6a0839..00000000 --- a/test/support/keys/vagrant +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzI -w+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoP -kcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2 -hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NO -Td0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcW -yLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQIBIwKCAQEA4iqWPJXtzZA68mKd -ELs4jJsdyky+ewdZeNds5tjcnHU5zUYE25K+ffJED9qUWICcLZDc81TGWjHyAqD1 -Bw7XpgUwFgeUJwUlzQurAv+/ySnxiwuaGJfhFM1CaQHzfXphgVml+fZUvnJUTvzf -TK2Lg6EdbUE9TarUlBf/xPfuEhMSlIE5keb/Zz3/LUlRg8yDqz5w+QWVJ4utnKnK -iqwZN0mwpwU7YSyJhlT4YV1F3n4YjLswM5wJs2oqm0jssQu/BT0tyEXNDYBLEF4A -sClaWuSJ2kjq7KhrrYXzagqhnSei9ODYFShJu8UWVec3Ihb5ZXlzO6vdNQ1J9Xsf -4m+2ywKBgQD6qFxx/Rv9CNN96l/4rb14HKirC2o/orApiHmHDsURs5rUKDx0f9iP -cXN7S1uePXuJRK/5hsubaOCx3Owd2u9gD6Oq0CsMkE4CUSiJcYrMANtx54cGH7Rk -EjFZxK8xAv1ldELEyxrFqkbE4BKd8QOt414qjvTGyAK+OLD3M2QdCQKBgQDtx8pN -CAxR7yhHbIWT1AH66+XWN8bXq7l3RO/ukeaci98JfkbkxURZhtxV/HHuvUhnPLdX -3TwygPBYZFNo4pzVEhzWoTtnEtrFueKxyc3+LjZpuo+mBlQ6ORtfgkr9gBVphXZG -YEzkCD3lVdl8L4cw9BVpKrJCs1c5taGjDgdInQKBgHm/fVvv96bJxc9x1tffXAcj -3OVdUN0UgXNCSaf/3A/phbeBQe9xS+3mpc4r6qvx+iy69mNBeNZ0xOitIjpjBo2+ -dBEjSBwLk5q5tJqHmy/jKMJL4n9ROlx93XS+njxgibTvU6Fp9w+NOFD/HvxB3Tcz -6+jJF85D5BNAG3DBMKBjAoGBAOAxZvgsKN+JuENXsST7F89Tck2iTcQIT8g5rwWC -P9Vt74yboe2kDT531w8+egz7nAmRBKNM751U/95P9t88EDacDI/Z2OwnuFQHCPDF -llYOUI+SpLJ6/vURRbHSnnn8a/XG+nzedGH5JGqEJNQsz+xT2axM0/W/CRknmGaJ -kda/AoGANWrLCz708y7VYgAtW2Uf1DPOIYMdvo6fxIB5i9ZfISgcJ/bbCUkFrhoH -+vq/5CIWxCPp0f85R4qxxQ5ihxJ0YDQT9Jpx4TMss4PSavPaBH3RXow5Ohe+bYoQ -NE5OgEXk2wVfZczCZpigBKbKZHNYcelXtTt/nP3rsCuGcM4h53s= ------END RSA PRIVATE KEY----- diff --git a/test/support/keys/vagrant.pub b/test/support/keys/vagrant.pub deleted file mode 100644 index 18a9c00f..00000000 --- a/test/support/keys/vagrant.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key diff --git a/test/support/rubocop/disabled.yml b/test/support/rubocop/disabled.yml deleted file mode 100644 index b4fd70ad..00000000 --- a/test/support/rubocop/disabled.yml +++ /dev/null @@ -1,25 +0,0 @@ -Encoding: - Description: 'Use UTF-8 as the source file encoding.' - Enabled: false - -SymbolArray: - Description: 'Use %i or %I for arrays of symbols.' - Enabled: false - -##################### Rails ################################## - -DefaultScope: - Description: 'Checks if the argument passed to default_scope is a block.' - Enabled: false - -HasAndBelongsToMany: - Description: 'Prefer has_many :through to has_and_belongs_to_many.' - Enabled: false - -Output: - Description: 'Checks for calls to puts, print, etc.' - Enabled: false - -Validation: - Description: 'Use sexy validations.' - Enabled: false diff --git a/test/support/rubocop/enabled.yml b/test/support/rubocop/enabled.yml deleted file mode 100644 index df712be3..00000000 --- a/test/support/rubocop/enabled.yml +++ /dev/null @@ -1,652 +0,0 @@ -# These are all the cops that are enabled in the default configuration. - -AccessModifierIndentation: - Description: Check indentation of private/protected visibility modifiers. - Enabled: true - -AccessorMethodName: - Description: Check the naming of accessor methods for get_/set_. - Enabled: true - -Alias: - Description: 'Use alias_method instead of alias.' - Enabled: true - -AlignArray: - Description: >- - Align the elements of an array literal if they span more than - one line. - Enabled: true - -AlignHash: - Description: >- - Align the elements of a hash literal if they span more than - one line. - Enabled: true - -AlignParameters: - Description: >- - Align the parameters of a method call if they span more - than one line. - Enabled: true - -AndOr: - Description: 'Use &&/|| instead of and/or.' - Enabled: true - -AsciiComments: - Description: 'Use only ascii symbols in comments.' - Enabled: true - -AsciiIdentifiers: - Description: 'Use only ascii symbols in identifiers.' - Enabled: true - -Attr: - Description: 'Checks for uses of Module#attr.' - Enabled: true - -BeginBlock: - Description: 'Avoid the use of BEGIN blocks.' - Enabled: true - -BlockComments: - Description: 'Do not use block comments.' - Enabled: true - -BlockNesting: - Description: 'Avoid excessive block nesting' - Enabled: true - -Blocks: - Description: >- - Avoid using {...} for multi-line blocks (multiline chaining is - always ugly). - Prefer {...} over do...end for single-line blocks. - Enabled: true - -BracesAroundHashParameters: - Description: 'Enforce braces style inside hash parameters.' - Enabled: true - -CaseEquality: - Description: 'Avoid explicit use of the case equality operator(===).' - Enabled: true - -CaseIndentation: - Description: 'Indentation of when in a case/when/[else/]end.' - Enabled: true - -CharacterLiteral: - Description: 'Checks for uses of character literals.' - Enabled: true - -ClassAndModuleCamelCase: - Description: 'Use CamelCase for classes and modules.' - Enabled: true - -ClassLength: - Description: 'Avoid classes longer than 100 lines of code.' - Enabled: true - -ClassMethods: - Description: 'Use self when defining module/class methods.' - Enabled: true - -ClassVars: - Description: 'Avoid the use of class variables.' - Enabled: true - -CollectionMethods: - Description: 'Preferred collection methods.' - Enabled: true - -ColonMethodCall: - Description: 'Do not use :: for method call.' - Enabled: true - -CommentAnnotation: - Description: >- - Checks formatting of special comments - (TODO, FIXME, OPTIMIZE, HACK, REVIEW). - Enabled: true - -ConstantName: - Description: 'Constants should use SCREAMING_SNAKE_CASE.' - Enabled: true - -CyclomaticComplexity: - Description: 'Avoid complex methods.' - Enabled: true - -DefWithParentheses: - Description: 'Use def with parentheses when there are arguments.' - Enabled: true - -Documentation: - Description: 'Document classes and non-namespace modules.' - Enabled: true - -DotPosition: - Description: 'Checks the position of the dot in multi-line method calls.' - Enabled: true - -EmptyLineBetweenDefs: - Description: 'Use empty lines between defs.' - Enabled: true - -EmptyLines: - Description: "Don't use several empty lines in a row." - Enabled: true - -EmptyLinesAroundAccessModifier: - Description: "Keep blank lines around access modifiers." - Enabled: true - -EmptyLinesAroundBody: - Description: "Keeps track of empty lines around expression bodies." - Enabled: true - -EmptyLiteral: - Description: 'Prefer literals to Array.new/Hash.new/String.new.' - Enabled: true - -EndBlock: - Description: 'Avoid the use of END blocks.' - Enabled: true - -EndOfLine: - Description: 'Use Unix-style line endings.' - Enabled: true - -EvenOdd: - Description: 'Favor the use of Fixnum#even? && Fixnum#odd?' - Enabled: true - -FavorJoin: - Description: 'Use Array#join instead of Array#*.' - Enabled: true - -FavorUnlessOverNegatedIf: - Description: >- - Favor unless over if for negative conditions - (or control flow or). - Enabled: true - -FavorUntilOverNegatedWhile: - Description: 'Favor until over while for negative conditions.' - Enabled: true - -FileName: - Description: 'Use snake_case for source file names.' - Enabled: true - -FinalNewline: - Description: 'Checks for a final newline in a source file.' - Enabled: true - -FlipFlop: - Description: 'Checks for flip flops' - Enabled: true - -For: - Description: 'Checks use of for or each in multiline loops.' - Enabled: true - -FormatString: - Description: 'Enforce the use of Kernel#sprintf, Kernel#format or String#%.' - Enabled: true - -GlobalVars: - Description: 'Do not introduce global variables.' - Enabled: true - -HashMethods: - Description: 'Checks for use of deprecated Hash methods.' - Enabled: true - -HashSyntax: - Description: >- - Prefer Ruby 1.9 hash syntax { a: 1, b: 2 } over 1.8 syntax - { :a => 1, :b => 2 }. - Enabled: true - -IfUnlessModifier: - Description: >- - Favor modifier if/unless usage when you have a - single-line body. - Enabled: true - -IfWithSemicolon: - Description: 'Never use if x; .... Use the ternary operator instead.' - Enabled: true - -IndentationConsistency: - Description: 'Keep indentation straight.' - Enabled: true - -IndentationWidth: - Description: 'Use 2 spaces for indentation.' - Enabled: true - -IndentArray: - Description: >- - Checks the indentation of the first element in an array - literal. - Enabled: true - -IndentHash: - Description: 'Checks the indentation of the first key in a hash literal.' - Enabled: true - -Lambda: - Description: 'Use the new lambda literal syntax for single-line blocks.' - Enabled: true - -LambdaCall: - Description: 'Use lambda.call(...) instead of lambda.(...).' - Enabled: true - -LeadingCommentSpace: - Description: 'Comments should start with a space.' - Enabled: true - -LineEndConcatenation: - Description: 'Use \\ instead of + to concatenate two string literals at line end.' - Enabled: true - -LineLength: - Description: 'Limit lines to 79 characters.' - Enabled: true - -MethodCalledOnDoEndBlock: - Description: 'Avoid chaining a method call on a do...end block.' - Enabled: true - -MethodCallParentheses: - Description: 'Do not use parentheses for method calls with no arguments.' - Enabled: true - -MethodDefParentheses: - Description: >- - Checks if the method definitions have or don't have - parentheses. - Enabled: true - -MethodLength: - Description: 'Avoid methods longer than 10 lines of code.' - Enabled: true - -MethodName: - Description: 'Use the configured style when naming methods.' - Enabled: true - -ModuleFunction: - Description: 'Checks for usage of `extend self` in modules.' - Enabled: true - -MultilineBlockChain: - Description: 'Avoid multi-line chains of blocks.' - Enabled: true - -MultilineIfThen: - Description: 'Never use then for multi-line if/unless.' - Enabled: true - -MultilineTernaryOperator: - Description: >- - Avoid multi-line ?: (the ternary operator); - use if/unless instead. - Enabled: true - -NestedTernaryOperator: - Description: 'Use one expression per branch in a ternary operator.' - Enabled: true - -NilComparison: - Description: 'Prefer x.nil? to x == nil.' - Enabled: true - -Not: - Description: 'Use ! instead of not.' - Enabled: true - -NumericLiterals: - Description: >- - Add underscores to large numeric literals to improve their - readability. - Enabled: true - -OneLineConditional: - Description: >- - Favor the ternary operator(?:) over - if/then/else/end constructs. - Enabled: true - -OpMethod: - Description: 'When defining binary operators, name the argument other.' - Enabled: true - -ParameterLists: - Description: 'Avoid parameter lists longer than three or four parameters.' - Enabled: true - -ParenthesesAroundCondition: - Description: >- - Don't use parentheses around the condition of an - if/unless/while. - Enabled: true - -PerlBackrefs: - Description: 'Avoid Perl-style regex back references.' - Enabled: true - -PredicateName: - Description: 'Check the names of predicate methods.' - Enabled: true - -Proc: - Description: 'Use proc instead of Proc.new.' - Enabled: true - -RaiseArgs: - Description: 'Checks the arguments passed to raise/fail.' - Enabled: true - -RedundantBegin: - Description: "Don't use begin blocks when they are not needed." - Enabled: true - -RedundantException: - Description: "Checks for an obsolete RuntimeException argument in raise/fail." - Enabled: true - -RedundantReturn: - Description: "Don't use return where it's not required." - Enabled: true - -RedundantSelf: - Description: "Don't use self where it's not needed." - Enabled: true - -RegexpLiteral: - Description: >- - Use %r for regular expressions matching more than - `MaxSlashes` '/' characters. - Use %r only for regular expressions matching more than - `MaxSlashes` '/' character. - Enabled: true - -RescueModifier: - Description: 'Avoid using rescue in its modifier form.' - Enabled: true - -Semicolon: - Description: "Don't use semicolons to terminate expressions." - Enabled: true - -SignalException: - Description: 'Checks for proper usage of fail and raise.' - Enabled: true - -SingleLineBlockParams: - Description: 'Enforces the names of some block params.' - Enabled: true - -SingleLineMethods: - Description: 'Avoid single-line methods.' - Enabled: true - -SpaceAfterColon: - Description: 'Use spaces after colons.' - Enabled: true - -SpaceAfterComma: - Description: 'Use spaces after commas.' - Enabled: true - -SpaceAfterControlKeyword: - Description: 'Use spaces after if/elsif/unless/while/until/case/when.' - Enabled: true - -SpaceAfterMethodName: - Description: >- - Never put a space between a method name and the opening - parenthesis. - Enabled: true - -SpaceAfterNot: - Description: Tracks redundant space after the ! operator. - Enabled: true - -SpaceAfterSemicolon: - Description: 'Use spaces after semicolons.' - Enabled: true - -SpaceAroundBlockBraces: - Description: >- - Checks that block braces have or don't have surrounding space. - For blocks taking parameters, checks that the left brace has - or doesn't have trailing space. - Enabled: true - -SpaceAroundEqualsInParameterDefault: - Description: >- - Use spaces around the = operator when assigning default - values in def params. - Enabled: true - -SpaceAroundOperators: - Description: 'Use spaces around operators.' - Enabled: true - -SpaceBeforeModifierKeyword: - Description: 'Put a space before the modifier keyword.' - Enabled: true - -SpaceInsideBrackets: - Description: 'No spaces after [ or before ].' - Enabled: true - -SpaceInsideHashLiteralBraces: - Description: "Use spaces inside hash literal braces - or don't." - Enabled: true - -SpaceInsideParens: - Description: 'No spaces after ( or before ).' - Enabled: true - -SpecialGlobalVars: - Description: 'Avoid Perl-style global variables.' - Enabled: true - -StringLiterals: - Description: 'Checks if uses of quotes match the configured preference.' - Enabled: true - -Tab: - Description: 'No hard tabs.' - Enabled: true - -TrailingBlankLines: - Description: 'Checks for superfluous trailing blank lines.' - Enabled: true - -TrailingComma: - Description: 'Checks for trailing comma in parameter lists and literals.' - Enabled: true - -TrailingWhitespace: - Description: 'Avoid trailing whitespace.' - Enabled: true - -TrivialAccessors: - Description: 'Prefer attr_* methods to trivial readers/writers.' - Enabled: true - -UnlessElse: - Description: >- - Never use unless with else. Rewrite these with the positive - case first. - Enabled: true - -VariableInterpolation: - Description: >- - Don't interpolate global, instance and class variables - directly in strings. - Enabled: true - -VariableName: - Description: 'Use the configured style when naming variables.' - Enabled: true - -WhenThen: - Description: 'Use when x then ... for one-line cases.' - Enabled: true - -WhileUntilDo: - Description: 'Checks for redundant do after while or until.' - Enabled: true - -WhileUntilModifier: - Description: >- - Favor modifier while/until usage when you have a - single-line body. - Enabled: true - -WordArray: - Description: 'Use %w or %W for arrays of words.' - Enabled: true - -#################### Lint ################################ -### Warnings - -AmbiguousOperator: - Description: >- - Checks for ambiguous operators in the first argument of a - method invocation without parentheses. - Enabled: true - -AmbiguousRegexpLiteral: - Description: >- - Checks for ambiguous regexp literals in the first argument of - a method invocation without parenthesis. - Enabled: true - -AssignmentInCondition: - Description: "Don't use assignment in conditions." - Enabled: true - -BlockAlignment: - Description: 'Align block ends correctly.' - Enabled: true - -ConditionPosition: - Description: 'Checks for condition placed in a confusing position relative to the keyword.' - Enabled: true - -Debugger: - Description: 'Check for debugger calls.' - Enabled: true - -DeprecatedClassMethods: - Description: 'Check for deprecated class method calls.' - Enabled: true - -ElseLayout: - Description: 'Check for odd code arrangement in an else block.' - Enabled: true - -EmptyEnsure: - Description: 'Checks for empty ensure block.' - Enabled: true - -EndAlignment: - Description: 'Align ends correctly.' - Enabled: true - -EndInMethod: - Description: 'END blocks should not be placed inside method definitions.' - Enabled: true - -EnsureReturn: - Description: 'Never use return in an ensure block.' - Enabled: true - -Eval: - Description: 'The use of eval represents a serious security risk.' - Enabled: true - -HandleExceptions: - Description: "Don't suppress exception." - Enabled: true - -InvalidCharacterLiteral: - Description: >- - Checks for invalid character literals with a non-escaped - whitespace character. - Enabled: true - -LiteralInCondition: - Description: 'Checks of literals used in conditions.' - Enabled: true - -LiteralInInterpolation: - Description: 'Checks for literals used in interpolation.' - Enabled: true - -Loop: - Description: >- - Use Kernel#loop with break rather than begin/end/until or - begin/end/while for post-loop tests. - Enabled: true - -ParenthesesAsGroupedExpression: - Description: >- - Checks for method calls with a space before the opening - parenthesis. - Enabled: true - -RequireParentheses: - Description: >- - Use parentheses in the method call to avoid confusion - about precedence. - Enabled: true - -RescueException: - Description: 'Avoid rescuing the Exception class.' - Enabled: true - -ShadowingOuterLocalVariable: - Description: >- - Do not use the same name as outer local variable - for block arguments or block local variables. - Enabled: true - -StringConversionInInterpolation: - Description: 'Checks for Object#to_s usage in string interpolation.' - Enabled: true - -UnreachableCode: - Description: 'Unreachable code.' - Enabled: true - -UselessAssignment: - Description: 'Checks for useless assignment to a local variable.' - Enabled: true - -UselessComparison: - Description: 'Checks for comparison of something with itself.' - Enabled: true - -UselessElseWithoutRescue: - Description: 'Checks for useless `else` in `begin..end` without `rescue`.' - Enabled: true - -UselessSetterCall: - Description: 'Checks for useless setter call to a local variable.' - Enabled: true - -Void: - Description: 'Possible use of operator/literal/variable in void context.' - Enabled: true