diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..c4e52ff --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +# https://EditorConfig.org +# top-most EditorConfig file +root=true + +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 +charset = utf-8 +trim_trailing_whitespace = true diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..7353614 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +* text=auto +* text eol=lf diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 0000000..e69de29 diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml new file mode 100644 index 0000000..f6eba26 --- /dev/null +++ b/.github/workflows/cd.yml @@ -0,0 +1,13 @@ +--- +on: + push: + branches: + - main + +jobs: + supermarket-deploy: + uses: Stromweld/github-workflows/.github/workflows/cookbook-supermarket-deploy.yml@main + secrets: inherit + with: + SUPERMARKET_USER: "stromweld" + SUPERMARKET_URL: "https://supermarket.chef.io" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..7fb1c7f --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,76 @@ +--- +on: + pull_request: + +jobs: + markdownlint: + uses: Stromweld/github-workflows/.github/workflows/markdown-lint.yml@main + + yamllint: + uses: Stromweld/github-workflows/.github/workflows/yaml-lint.yml@main + + jsonlint: + uses: Stromweld/github-workflows/.github/workflows/json-lint.yml@main + + cookstylelint: + uses: Stromweld/github-workflows/.github/workflows/cookstyle-lint.yml@main + + integration: + runs-on: ubuntu-latest + strategy: + matrix: + os: + - centos-7 + - almalinux-8 + - almalinux-9 + - rockylinux-8 + - rockylinux-9 + - ubuntu-2004 + - ubuntu-2204 + suite: + - server + - automate + - supermarket + fail-fast: false + steps: + - name: Check out code + uses: actions/checkout@main + - name: Install Vagrant + run: | + sudo apt-get update + sudo apt-get install -y vagrant virtualbox + - name: Install Chef + uses: actionshub/chef-install@main + - name: Test-Kitchen Converge + uses: actionshub/test-kitchen@main + with: + suite: ${{ matrix.suite }} + os: ${{ matrix.os }} + action: converge + env: + CHEF_LICENSE: accept-no-persist + - name: Test-Kitchen Verify + uses: actionshub/test-kitchen@main + with: + suite: ${{ matrix.suite }} + os: ${{ matrix.os }} + action: verify + env: + CHEF_LICENSE: accept-no-persist + + check: + if: always() + needs: + - markdownlint + - yamllint + - jsonlint + - cookstylelint + - integration + runs-on: Ubuntu-latest + steps: + - name: Decide whether the needed jobs succeeded or failed + uses: re-actors/alls-green@main + with: + allowed-failures: + allowed-skips: + jobs: ${{ toJSON(needs) }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9abf29f --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +.vagrant +*~ +*# +.#* +\#*# +.*.sw[a-z] +*.un~ + +# Bundler +Gemfile.lock +gems.locked +bin/* +.bundle/* + +# test kitchen +.kitchen/ +kitchen.local.yml + +# Chef +Berksfile.lock +.zero-knife.rb +Policyfile.lock.json diff --git a/.mdlrc b/.mdlrc new file mode 100755 index 0000000..f3b5506 --- /dev/null +++ b/.mdlrc @@ -0,0 +1 @@ +rules "~MD013", "~MD034" diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..c891beb --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,61 @@ +# chef_software CHANGELOG + +This file is used to list changes made in each version of the chef_software cookbook. + +## 2.2.0 (2024-03-02) + +- [Corey Hemminger] - Moved iam_policy and iam_user creation to resources + +## 2.1.2 (2023-03-31) + +- [Corey Hemminger] - Hacky way of adding idempotency to chef-server org admin association + +## 2.1.1 (2023-03-20) + +- [Corey Hemminger] - Add safe navigation to .include method for automatev2 recipe + +## 2.1.0 (20232-03-17) + +- [Corey Hemminger] - Add Integrated Infra-Server user and org config to automate recipe + +## 2.0.2 (2022-09-29) + +- [Corey Hemminger] - Removed chef-ingredient reference to fork from policyfile + +## 2.0.1 (2022-08-12) + +- [Corey Hemminger] - Update changelog + +## 2.0.0 (2022-08-12) + +- [Corey Hemminger] - Update chef_automatev2 recipe to use iamv2 for user and policy creation +- [Corey Hemminger] - update chef_server to run chef-server-ctl upgrade vs chef-server-ctl reconfigure + +## 1.1.1 (2022-08-02) + +- [Corey Hemminger] - Fix server and supermarket's to run reconfigure after an update +- [Corey Hemminger] - Add github actions CI/CD pipelines and testing + +## 1.1.0 (2020-08-07) + +- [Corey Hemminger] - Modernize cookbook with policy file and other skeleton files + +## 1.0.4 (2019-04-01) + +- [Corey Hemminger] - Work around to make org admins idempotent + +## 1.0.3 (2019-03-11) + +- [Corey Hemminger] - Make description the same as long description + +## 1.0.2 (2019-03-11) + +- [Corey Hemminger] - Updated metadata description + +## 1.0.1 (2019-01-14) + +- [Corey Hemminger] - Updated readme and .kitchen.yml + +## 1.0.0 (2018-12-21) + +- [Corey Hemminger] - Initial Release diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..cd21578 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1 @@ +Please refer to diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8dada3e --- /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/Policyfile.rb b/Policyfile.rb new file mode 100644 index 0000000..4f97262 --- /dev/null +++ b/Policyfile.rb @@ -0,0 +1,19 @@ +# Policyfile.rb - Describe how you want Chef Infra Client to build your system. +# +# For more information on the Policyfile feature, visit +# https://docs.chef.io/policyfile/ + +# A name that describes what the system you're building with Chef does. +name 'chef_software' + +# Where to find external cookbooks: +default_source :supermarket + +# run_list: chef-client will run these recipes in the order specified. +run_list 'chef_software::default' +named_run_list :chef_automatev2, 'chef_software::chef_automatev2' +named_run_list :chef_server, 'chef_software::chef_server' +named_run_list :chef_supermarket, 'chef_software::chef_supermarket' + +# Specify a custom source for a single cookbook: +cookbook 'chef_software', path: '.' diff --git a/README.md b/README.md new file mode 100644 index 0000000..69df256 --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +# chef_software + +This Cookbook wraps the chef-ingredient cookbook and will install and configure chef-server, chef-automatev2, and an internal chef-supermarket. Configuration is all attribute driven. + +## Requirements + +Please refer to the chef-ingredient cookbook for additional information on configuration options to add to the atribute hashes. + +### Platforms + +- Linux + +## Recipes + +### default recipe + +Recipe does nothing but log warning that it does nothing + +### chef_automatev2 + +Recipe to install chef-automatev2 + +### chef_server + +Recipe to install chef-server and manage users & organizations + +### chef_supermarket + +Recipe to install chef-supermarket + +## Usage + +1. Set attributes via wrapper cookbook, policy files, role or environment files. +1. Build chef-automatev2 server first. Create an admin token and update `automate_admin_token` attribute. +1. Build chef-server second. Update `chef_supermarket` attribute with the correct settings found on the chef server at `/etc/opscode/oc-id-applications/supermarket.json` +1. Build chef-supermarket third. diff --git a/TESTING.md b/TESTING.md new file mode 100644 index 0000000..359579c --- /dev/null +++ b/TESTING.md @@ -0,0 +1 @@ +Please refer to diff --git a/attributes/default.rb b/attributes/default.rb new file mode 100644 index 0000000..30e336a --- /dev/null +++ b/attributes/default.rb @@ -0,0 +1,110 @@ +# +# Cookbook:: chef_software +# Attributes:: default +# +# Copyright:: 2019, Corey Hemminger +# +# 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. + +default['chef_software']['chef_server_api_fqdn'] = 'chef-server.example.com' +default['chef_software']['chef_automate_api_fqdn'] = 'chef-automate.example.com' +default['chef_software']['chef_supermarket_api_fqdn'] = 'chef-supermarket.example.com' +default['chef_software']['automate_admin_token'] = nil + +default['chef_software']['chef_automatev2'] = { + products: %w(automate infra-server builder), + accept_license: true, + config: <<~EOC, + [global.v1] + fqdn = "#{node['chef_software']['chef_automate_api_fqdn']}" + EOC + +} + +default['chef_software']['automatev2_local_users'] = { + test1: { + user_json: { + id: 'test1', + name: 'Test 1', + password: 'Test1234!', + }, + }, +} + +default['chef_software']['automatev2_iam_policies'] = { + test1: { + policy_json: { + name: 'Test1', + id: 'test1', + projects: [], + members: ['user:local:test1'], + statements: [ + { + effect: 'ALLOW', + actions: ['*'], + projects: ['*'], + role: 'owner', + }, + ], + }, + }, +} + +default['chef_software']['chef_server'] = { + accept_license: true, + config: <<~EOC, + api_fqdn "#{node['chef_software']['chef_server_api_fqdn']}" + topology "standalone" + #{if node['chef_software']['chef_supermarket_api_fqdn'] + "oc_id['applications'] ||= {} + oc_id['applications']['supermarket'] = { + 'redirect_uri' => 'https://#{node['chef_software']['chef_supermarket_api_fqdn']}/auth/chef_oauth2/callback' + }" + end} + EOC + +} + +default['chef_software']['chef_user'] = { + test1: { + first_name: 'Test', + last_name: '1', + email: 'test1@example.com', + password: 'Test1234!', + }, +} + +default['chef_software']['chef_org'] = { + testing: { + org_full_name: 'Testing Chef Server', + admins: %w(test1), + users: %w(), + }, +} + +default['chef_software']['chef_supermarket'] = { + chef_server_url: "https://#{node['chef_software']['chef_server_api_fqdn']}", + chef_oauth2_app_id: 'GUID', + chef_oauth2_secret: 'GUID', + chef_oauth2_verify_ssl: false, + accept_license: true, + config: { + fqdn: node['chef_software']['chef_supermarket_api_fqdn'], + smtp_address: 'localhost', + smtp_port: 25, + from_email: 'chef-supermarket@example.com', + features: 'tools,gravatar,github,announcement,fieri', + fieri_key: 'randomstuff', + fieri_supermarket_endpoint: node['chef_software']['chef_supermarket_api_fqdn'], + }, +} diff --git a/chefignore b/chefignore new file mode 100644 index 0000000..cc170ea --- /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/kitchen.dokken.yml b/kitchen.dokken.yml new file mode 100755 index 0000000..904fdd9 --- /dev/null +++ b/kitchen.dokken.yml @@ -0,0 +1,83 @@ +--- +driver: + name: dokken + privileged: true # because Docker and SystemD/Upstart + +transport: + name: dokken + +provisioner: + name: dokken + deprecations_as_errors: true + always_update_cookbooks: true + chef_license: accept-no-persist + clean_dokken_sandbox: false + +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: 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: debian-10 + driver: + image: dokken/debian-10 + pid_one_command: /bin/systemd + intermediate_instructions: + - RUN /usr/bin/apt-get update + + - name: debian-11 + driver: + image: dokken/debian-11 + pid_one_command: /bin/systemd + intermediate_instructions: + - RUN /usr/bin/apt-get update + + - name: ubuntu-20.04 + driver: + image: dokken/ubuntu-20.04 + pid_one_command: /bin/systemd + intermediate_instructions: + - RUN /usr/bin/apt-get update + + - name: ubuntu-22.04 + driver: + image: dokken/ubuntu-22.04 + pid_one_command: /bin/systemd + intermediate_instructions: + - RUN /usr/bin/apt-get update diff --git a/kitchen.yml b/kitchen.yml new file mode 100755 index 0000000..03ddd9a --- /dev/null +++ b/kitchen.yml @@ -0,0 +1,63 @@ +--- +driver: + name: vagrant + box_auto_update: true + box_auto_prune: true + +provisioner: + name: chef_infra + retry_on_exit_code: + - 35 # 35 is the exit code signaling that the node is rebooting + product_name: chef + deprecations_as_errors: true + always_update_cookbooks: true + chef_license: accept-no-persist + +verifier: + name: inspec + +platforms: + - name: almalinux-8 + - name: almalinux-9 + - name: amazonlinux-2 + - name: rockylinux-8 + - name: rockylinux-9 + # - name: amazonlinux-2023 + - name: centos-7 + - name: centos-stream-8 + - name: centos-stream-9 + - name: debian-10 + - name: debian-11 + - name: ubuntu-20.04 + - name: ubuntu-22.04 + +suites: + - name: server + named_run_list: 'chef_server' + driver: + customize: + memory: 3328 + verifier: + inspec_tests: + - test/integration/default + - test/integration/chef_server + attributes: + - name: automate + named_run_list: 'chef_automatev2' + driver: + customize: + memory: 3072 + verifier: + inspec_tests: + - test/integration/default + - test/integration/chef_automate + attributes: + chef_software: + automate_admin_token: lazy { shell_out('chef-automate iam token create admin --admin').stdout.strip } + - name: supermarket + named_run_list: 'chef_supermarket' + verifier: + inspec_tests: + - test/integration/default + - test/integration/chef_supermarket + attributes: diff --git a/libraries/helpers.rb b/libraries/helpers.rb new file mode 100644 index 0000000..5f1f777 --- /dev/null +++ b/libraries/helpers.rb @@ -0,0 +1,13 @@ +module ChefSoftware + module Helpers + def get_iam_user(user) + Mash.new(JSON.parse(shell_out("curl --insecure -s -H \"api-token: #{node['chef_software']['automate_admin_token']}\" https://localhost/apis/iam/v2/users/#{user}").stdout)) + end + + def get_iam_policy(policy_name) + Mash.new(JSON.parse(shell_out("curl --insecure -s -H \"api-token: #{node['chef_software']['automate_admin_token']}\" https://localhost/apis/iam/v2/policies/#{policy_name}").stdout)) + end + end +end + +Chef::DSL::Universal.include(ChefSoftware::Helpers) diff --git a/metadata.rb b/metadata.rb new file mode 100644 index 0000000..ef270d1 --- /dev/null +++ b/metadata.rb @@ -0,0 +1,16 @@ +name 'chef_software' +maintainer 'Corey Hemminger' +maintainer_email 'hemminger@hotmail.com' +license 'Apache-2.0' +description 'Installs/Configures chef server, chef automate2, chef supermarket' +version '2.2.0' +chef_version '>= 16.4' + +issues_url 'https://github.com/Stromweld/chef_software/issues' +source_url 'https://github.com/Stromweld/chef_software' + +%w(centos redhat ubuntu).each do |os| + supports os +end + +depends 'chef-ingredient' diff --git a/recipes/chef_automatev2.rb b/recipes/chef_automatev2.rb new file mode 100644 index 0000000..75223f7 --- /dev/null +++ b/recipes/chef_automatev2.rb @@ -0,0 +1,64 @@ +# +# Cookbook:: chef_software +# Recipe:: chef_automatev2 +# +# Copyright:: 2019, Corey Hemminger +# +# 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. + +chef_automatev2 'Create Automate server' do + node['chef_software']['chef_automatev2']&.each do |key, value| + send(key, value) + end +end + +node['chef_software']['automatev2_local_users']&.each do |name, hash| + iam_user name do + user_hash hash['user_json'] + api_token lazy { node['chef_software']['automate_admin_token'] } + action :create + end +end + +node['chef_software']['automatev2_iam_policies']&.each do |name, hash| + iam_policy name do + policy_hash hash['policy_json'] + api_token lazy { node['chef_software']['automate_admin_token'] } + action :create + end +end + +if node['chef_software']['chef_automatev2']['products']&.include?('infra-server') + node['chef_software']['chef_user']&.each do |name, hash| + chef_user name do + hash&.each do |key, value| + send(key, value) + end + end + end + + node['chef_software']['chef_org']&.each do |name, hash| + template "#{Chef::Config[:file_cache_path]}/#{name}" do + source 'orgs.erb' + variables org_opts: hash + notifies :create, "chef_org[#{name}]", :immediately + end + + chef_org name do + hash&.each do |key, value| + send(key, value) + end + action :nothing + end + end +end diff --git a/recipes/chef_server.rb b/recipes/chef_server.rb new file mode 100644 index 0000000..4d85577 --- /dev/null +++ b/recipes/chef_server.rb @@ -0,0 +1,75 @@ +# +# Cookbook:: chef_software +# Recipe:: chef_server +# +# Copyright:: 2019, Corey Hemminger +# +# 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. + +chef_server 'chef-server' do + node['chef_software']['chef_server']&.each do |key, value| + send(key, value) + end + notifies :run, 'execute[reconfigure chef server]', :immediately +end + +execute 'reconfigure chef server' do + command 'chef-server-ctl stop && chef-server-ctl upgrade && chef-server-ctl start && chef-server-ctl cleanup && chef-server-ctl status' + live_stream true + action :nothing +end + +if node['chef_software']['chef_automate_api_fqdn'] && node['chef_software']['automate_admin_token'] + execute 'set data_collector token' do + command "chef-server-ctl set-secret data_collector token '#{node['chef_software']['automate_admin_token']}'" + not_if { shell_out('chef-server-ctl show-secret data_collector token').stdout.include?(node['chef_software']['automate_admin_token']) } + notifies :run, 'execute[chef-server-ctl restart nginx]', :immediately + notifies :run, 'execute[chef-server-ctl restart opscode-erchef]', :immediately + sensitive true + end + + execute 'chef-server-ctl restart nginx' do + action :nothing + end + + execute 'chef-server-ctl restart opscode-erchef' do + action :nothing + end +end + +ingredient_config 'chef-server' do + notifies :reconfigure, 'chef_server[chef-server]', :immediately +end + +node['chef_software']['chef_user']&.each do |name, hash| + chef_user name do + hash&.each do |key, value| + send(key, value) + end + end +end + +node['chef_software']['chef_org']&.each do |name, hash| + template "#{Chef::Config[:file_cache_path]}/#{name}" do + source 'orgs.erb' + variables org_opts: hash + notifies :create, "chef_org[#{name}]", :immediately + end + + chef_org name do + hash&.each do |key, value| + send(key, value) + end + action :nothing + end +end diff --git a/recipes/chef_supermarket.rb b/recipes/chef_supermarket.rb new file mode 100644 index 0000000..c48d9e9 --- /dev/null +++ b/recipes/chef_supermarket.rb @@ -0,0 +1,30 @@ +# +# Cookbook:: chef_software +# Recipe:: chef_supermarket +# +# Copyright:: 2019, Corey Hemminger +# +# 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. + +chef_supermarket 'supermarket' do + node['chef_software']['chef_supermarket']&.each do |key, value| + send(key, value) + end + notifies :run, 'execute[reconfigure chef supermarket]', :immediately +end + +execute 'reconfigure chef supermarket' do + command 'supermarket-ctl reconfigure && supermarket-ctl start && supermarket-ctl status' + live_stream true + action :nothing +end diff --git a/recipes/default.rb b/recipes/default.rb new file mode 100644 index 0000000..1a03dad --- /dev/null +++ b/recipes/default.rb @@ -0,0 +1,19 @@ +# +# Cookbook:: chef_software +# Recipe:: default +# +# Copyright:: 2019, Corey Hemminger +# +# 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. + +Chef::Log.warn('The chef_software::default recipe includes no resources and should not be included directly on nodes') diff --git a/resources/iam_policy.rb b/resources/iam_policy.rb new file mode 100644 index 0000000..caa43a6 --- /dev/null +++ b/resources/iam_policy.rb @@ -0,0 +1,104 @@ +# To learn more about Custom Resources, see https://docs.chef.io/custom_resources.html +# +# Author:: Corey Hemminger +# Cookbook:: chef_software +# Resource:: iam_policy +# +# Copyright:: 2024, Corey Hemminger +# +# 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. +unified_mode true +provides :iam_policy +resource_name :iam_policy + +description 'manage IAM policies' + +property :name, String, + name_property: true, + description: 'Name of the IAM policy' + +property :policy_hash, Hash, + required: true, + description: 'Policy json in ruby hash format' + +property :api_token, String, + required: true, + sensitive: true, + description: 'Automate API token' + +action :create do + description 'Create a new IAM user' + + name = new_resource.name + policy_hash = new_resource.policy_hash + policy_json = policy_hash.to_json + srv_policy = get_iam_policy(policy_json['id']) + http_request "create iam policy #{name}" do + headers({ 'api-token' => new_resource.api_token, 'Content-Type' => 'application/json' }) + message policy_json + url 'https://localhost/apis/iam/v2/policies' + action :post + sensitive true + only_if { + Chef::Log.warn(srv_policy['error'].inspect) + srv_policy['error'].eql?("no policy with ID \"#{policy_hash['id']}\" found") + } + end +end + +action :update do + name = new_resource.name + policy_hash = new_resource.policy_hash + policy_json = policy_hash.to_json + srv_policy = get_iam_policy(policy_json['id']) + Chef::Log.info("\nuserpolicy: #{policy_json.inspect}\nsrv_policy: #{srv_policy.inspect}\n") + # Test policy from server and desired policy match key by key from desired policy + test_result = if srv_policy['error'] + Chef::Log.warn(srv_policy['error'].inspect) + true + else + test = true + statement_test = true + unless srv_policy['error'] + policy_hash.each_key do |key| + if key.eql?('statements') + policy_hash['statements'].each_index do |i| + policy_hash['statements'][i].each_key do |statement_key| + test = policy_hash['statements'][i][statement_key].eql?(srv_policy['policy']['statements'][i][statement_key]) + break if statement_test.eql?(false) + end + break if statement_test.eql?(false) + end + break if statement_test.eql?(false) + + next + end + test = policy_hash[key].eql?(srv_policy['policy'][key]) + break if test.eql?(false) + end + end + if test && statement_test + true + else + false + end + end + http_request "update iam policy #{name}" do + headers({ 'api-token' => new_resource.api_token, 'Content-Type' => 'application/json' }) + message policy_json + url "https://localhost/apis/iam/v2/policies/#{policy_hash['id']}" + action :put + sensitive true + not_if { test_result } + end +end diff --git a/resources/iam_user.rb b/resources/iam_user.rb new file mode 100644 index 0000000..c30bea7 --- /dev/null +++ b/resources/iam_user.rb @@ -0,0 +1,79 @@ +# To learn more about Custom Resources, see https://docs.chef.io/custom_resources.html +# +# Author:: Corey Hemminger +# Cookbook:: chef_software +# Resource:: iam_user +# +# Copyright:: 2024, Corey Hemminger +# +# 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. +unified_mode true +provides :iam_user +resource_name :iam_user + +description 'manage IAM users' + +property :name, String, + name_property: true, + description: 'Name of the IAM user' + +property :user_hash, Hash, + required: true, + description: 'User json in ruby hash format' + +property :api_token, String, + required: true, + sensitive: true, + description: 'Automate API token' + +action :create do + description 'Create a new IAM user' + + name = new_resource.name + user_hash = new_resource.user_hash + user_json = user_hash.to_json + srv_user = get_iam_user(user_hash['id']) + http_request "create iam user #{name}" do + headers({ 'api-token' => new_resource.api_token, 'Content-Type' => 'application/json' }) + message user_json + url 'https://localhost/apis/iam/v2/users' + action :post + sensitive true + only_if { + Chef::Log.warn(srv_user['error'].inspect) + srv_user['error'].eql?('No user record found') + } + end +end + +action :update do + name = new_resource.name + user_hash = new_resource.user_hash + user_json = user_hash.to_json + test_user = get_iam_user(user_hash['id']) + # Test user from server and desired user match key by key from desired policy + test_result = if user_policy['error'] + Chef::Log.warn(user_policy['error'].inspect) + true + else + user_hash['id'].eql?(test_user['user']['id']) && user_hash['name'].eql?(test_user['user']['name']) + end + http_request "update iam user #{name}" do + headers({ 'api-token' => new_resource.api_token, 'Content-Type' => 'application/json' }) + message user_json + url "https://localhost/apis/iam/v2/users/#{user_hash['id']}" + action :put + sensitive true + not_if { test_result } + end +end diff --git a/templates/default/orgs.erb b/templates/default/orgs.erb new file mode 100644 index 0000000..c902ca4 --- /dev/null +++ b/templates/default/orgs.erb @@ -0,0 +1,3 @@ +<% @org_opts.each do |key, value| %> + <%= key %> => <%= value %> +<% end %> diff --git a/test/integration/chef_automate/test_chef_automatev2_spec.rb b/test/integration/chef_automate/test_chef_automatev2_spec.rb new file mode 100644 index 0000000..e2a527a --- /dev/null +++ b/test/integration/chef_automate/test_chef_automatev2_spec.rb @@ -0,0 +1,48 @@ +describe file('/usr/local/bin/chef-automate') do + it { should_not exist } +end + +bin_path = if os.debian? + '/bin/chef-automate' + else + '/usr/bin/chef-automate' + end + +describe file(bin_path) do + it { should exist } +end + +describe command('chef-automate version') do + its('exit_status') { should eq 0 } +end + +describe service('chef-automate') do + it { should be_installed } + it { should be_running } + it { should be_enabled } +end + +%w(80 443).each do |port| + describe port(port) do + it { should be_listening } + end +end + +# TODO: uncomment when resource are out of experimental +# describe habitat_packages do +# its('names') { should include 'automate-ui' } +# its('names') { should include 'automate-cs-oc-erchef' } +# its('names') { should include 'automate-builder-api' } +# its('names') { should include 'automate-postgresql' } +# its('names') { should include 'automate-opensearch' } +# its('names') { should include 'automate-load-balancer' } +# end +# +# describe habitat_services do +# its('names') { should include 'automate-ui' } +# its('names') { should include 'automate-cs-oc-erchef' } +# its('names') { should include 'automate-builder-api' } +# its('names') { should include 'automate-postgresql' } +# its('names') { should include 'automate-opensearch' } +# its('names') { should include 'automate-load-balancer' } +# end diff --git a/test/integration/chef_server/test_chef_server_spec.rb b/test/integration/chef_server/test_chef_server_spec.rb new file mode 100644 index 0000000..d785f87 --- /dev/null +++ b/test/integration/chef_server/test_chef_server_spec.rb @@ -0,0 +1,15 @@ +describe package('chef-server-core') do + it { should be_installed } +end + +describe service('private_chef-runsvdir-start') do + it { should be_installed } + it { should be_running } + it { should be_enabled } +end + +%w(80 443).each do |port| + describe port(port) do + it { should be_listening } + end +end diff --git a/test/integration/chef_supermarket/test_chef_supermarket_spec.rb b/test/integration/chef_supermarket/test_chef_supermarket_spec.rb new file mode 100644 index 0000000..e811289 --- /dev/null +++ b/test/integration/chef_supermarket/test_chef_supermarket_spec.rb @@ -0,0 +1,15 @@ +describe package('supermarket') do + it { should be_installed } +end + +describe service('supermarket-runsvdir-start') do + it { should be_installed } + it { should be_running } + it { should be_enabled } +end + +%w(80 443).each do |port| + describe port(port) do + it { should be_listening } + end +end diff --git a/test/integration/default/default_test.rb b/test/integration/default/default_test.rb new file mode 100644 index 0000000..d739df4 --- /dev/null +++ b/test/integration/default/default_test.rb @@ -0,0 +1,11 @@ +# InSpec test for recipe chef_automate + +# The InSpec reference, with examples and extensive documentation, can be +# found at https://www.inspec.io/docs/reference/resources/ + +# Listening port +%w(80 443).each do |port_num| + describe port(port_num) do + it { should be_listening } + end +end