├── .github └── workflows │ ├── commitlint.yml │ └── kitchen.vagrant.yml ├── .gitignore ├── .gitlab-ci.yml ├── .pre-commit-config.yaml ├── .rstcheck.cfg ├── .rubocop.yml ├── .salt-lint ├── .travis.yml ├── .yamllint ├── AUTHORS.md ├── CHANGELOG.md ├── CODEOWNERS ├── FORMULA ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── bin ├── install-hooks └── kitchen ├── commitlint.config.js ├── docs ├── AUTHORS.rst ├── CHANGELOG.rst ├── README.rst └── TOFS_pattern.rst ├── kitchen.vagrant.yml ├── kitchen.yml ├── pillar.example ├── postgres ├── _mapdata │ ├── _mapdata.jinja │ └── init.sls ├── client │ ├── init.sls │ └── remove.sls ├── codenamemap.yaml ├── defaults.yaml ├── dev │ ├── init.sls │ └── remove.sls ├── dropped.sls ├── init.sls ├── libtofs.jinja ├── macos │ ├── init.sls │ └── postgresapp.sls ├── macros.jinja ├── manage.sls ├── map.jinja ├── osfamilymap.yaml ├── osmap.yaml ├── python.sls ├── repo.yaml ├── server │ ├── image.sls │ ├── init.sls │ └── remove.sls ├── templates │ ├── limit.maxfiles.plist │ ├── mac_shortcut.sh │ ├── pg_hba.conf.j2 │ ├── pg_ident.conf.j2 │ └── postgres.sh.j2 └── upstream.sls ├── pre-commit_semantic-release.sh ├── release-rules.js ├── release.config.js └── test ├── integration ├── default │ ├── README.md │ ├── controls │ │ ├── services.rb │ │ └── share.rb │ └── inspec.yml ├── repo │ ├── README.md │ ├── controls │ │ ├── repository.rb │ │ ├── services.rb │ │ └── share.rb │ └── inspec.yml └── share │ ├── README.md │ ├── controls │ ├── command.rb │ └── config.rb │ ├── inspec.yml │ └── libraries │ └── system.rb └── salt └── pillar ├── postgres.sls └── repo.sls /.github/workflows/commitlint.yml: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # vim: ft=yaml 3 | --- 4 | name: Commitlint 5 | 'on': [pull_request] 6 | 7 | jobs: 8 | lint: 9 | runs-on: ubuntu-latest 10 | env: 11 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 12 | steps: 13 | - uses: actions/checkout@v2 14 | with: 15 | fetch-depth: 0 16 | - uses: wagoid/commitlint-github-action@v1 17 | -------------------------------------------------------------------------------- /.github/workflows/kitchen.vagrant.yml: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # vim: ft=yaml 3 | --- 4 | name: 'Kitchen Vagrant (FreeBSD)' 5 | 'on': ['push', 'pull_request'] 6 | 7 | env: 8 | KITCHEN_LOCAL_YAML: 'kitchen.vagrant.yml' 9 | 10 | jobs: 11 | test: 12 | runs-on: 'macos-10.15' 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | instance: 17 | - default-freebsd-130-master-py3 18 | # - freebsd-130-master-py3 19 | - default-freebsd-123-master-py3 20 | # - freebsd-123-master-py3 21 | # - default-freebsd-130-3004-0-py3 22 | # - default-freebsd-123-3004-0-py3 23 | steps: 24 | - name: 'Check out code' 25 | uses: 'actions/checkout@v2' 26 | - name: 'Set up Bundler cache' 27 | uses: 'actions/cache@v1' 28 | with: 29 | path: 'vendor/bundle' 30 | key: "${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}" 31 | restore-keys: "${{ runner.os }}-gems-" 32 | - name: 'Run Bundler' 33 | run: | 34 | ruby --version 35 | bundle config path vendor/bundle 36 | bundle install --jobs 4 --retry 3 37 | - name: 'Run Test Kitchen' 38 | run: 'bundle exec kitchen verify ${{ matrix.instance }}' 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a packager 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .kitchen 49 | .kitchen.local.yml 50 | kitchen.local.yml 51 | junit-*.xml 52 | 53 | # Translations 54 | *.mo 55 | *.pot 56 | 57 | # Django stuff: 58 | *.log 59 | local_settings.py 60 | 61 | # Flask stuff: 62 | instance/ 63 | .webassets-cache 64 | 65 | # Scrapy stuff: 66 | .scrapy 67 | 68 | # Sphinx documentation 69 | docs/_build/ 70 | 71 | # PyBuilder 72 | target/ 73 | 74 | # Jupyter Notebook 75 | .ipynb_checkpoints 76 | 77 | # pyenv 78 | .python-version 79 | 80 | # celery beat schedule file 81 | celerybeat-schedule 82 | 83 | # SageMath parsed files 84 | *.sage.py 85 | 86 | # dotenv 87 | .env 88 | 89 | # virtualenv 90 | .venv 91 | venv/ 92 | ENV/ 93 | 94 | # visual studio 95 | .vs/ 96 | 97 | # Spyder project settings 98 | .spyderproject 99 | .spyproject 100 | 101 | # Rope project settings 102 | .ropeproject 103 | 104 | # mkdocs documentation 105 | /site 106 | 107 | # mypy 108 | .mypy_cache/ 109 | 110 | # Bundler 111 | .bundle/ 112 | 113 | # copied `.md` files used for conversion to `.rst` using `m2r` 114 | docs/*.md 115 | 116 | # Vim 117 | *.sw? 118 | 119 | ## Collected when centralising formulas (check and sort) 120 | # `collectd-formula` 121 | .pytest_cache/ 122 | /.idea/ 123 | Dockerfile.*_* 124 | ignore/ 125 | tmp/ 126 | 127 | # `salt-formula` -- Vagrant Specific files 128 | .vagrant 129 | top.sls 130 | !test/salt/pillar/top.sls 131 | 132 | # `suricata-formula` -- Platform binaries 133 | *.rpm 134 | *.deb 135 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # vim: ft=yaml 3 | --- 4 | ############################################################################### 5 | # Define all YAML node anchors 6 | ############################################################################### 7 | .node_anchors: 8 | # `only` (also used for `except` where applicable) 9 | only_branch_master_parent_repo: &only_branch_master_parent_repo 10 | - 'master@saltstack-formulas/postgres-formula' 11 | # `stage` 12 | stage_lint: &stage_lint 'lint' 13 | stage_release: &stage_release 'release' 14 | stage_test: &stage_test 'test' 15 | # `image` 16 | image_commitlint: &image_commitlint 'myii/ssf-commitlint:11' 17 | image_dindruby: &image_dindruby 'myii/ssf-dind-ruby:2.7.1-r3' 18 | image_precommit: &image_precommit 19 | name: 'myii/ssf-pre-commit:2.9.2' 20 | entrypoint: ['/bin/bash', '-c'] 21 | image_rubocop: &image_rubocop 'pipelinecomponents/rubocop:latest' 22 | image_semantic-release: &image_semanticrelease 'myii/ssf-semantic-release:15.14' 23 | # `services` 24 | services_docker_dind: &services_docker_dind 25 | - 'docker:dind' 26 | # `variables` 27 | # https://forum.gitlab.com/t/gitlab-com-ci-caching-rubygems/5627/3 28 | # https://bundler.io/v1.16/bundle_config.html 29 | variables_bundler: &variables_bundler 30 | BUNDLE_CACHE_PATH: '${CI_PROJECT_DIR}/.cache/bundler' 31 | BUNDLE_WITHOUT: 'production' 32 | # `cache` 33 | cache_bundler: &cache_bundler 34 | key: '${CI_JOB_STAGE}' 35 | paths: 36 | - '${BUNDLE_CACHE_PATH}' 37 | 38 | ############################################################################### 39 | # Define stages and global variables 40 | ############################################################################### 41 | stages: 42 | - *stage_lint 43 | - *stage_test 44 | - *stage_release 45 | variables: 46 | DOCKER_DRIVER: 'overlay2' 47 | 48 | ############################################################################### 49 | # `lint` stage: `commitlint`, `pre-commit` & `rubocop` (latest, failure allowed) 50 | ############################################################################### 51 | commitlint: 52 | stage: *stage_lint 53 | image: *image_commitlint 54 | script: 55 | # Add `upstream` remote to get access to `upstream/master` 56 | - 'git remote add upstream 57 | https://gitlab.com/saltstack-formulas/postgres-formula.git' 58 | - 'git fetch --all' 59 | # Set default commit hashes for `--from` and `--to` 60 | - 'export COMMITLINT_FROM="$(git merge-base upstream/master HEAD)"' 61 | - 'export COMMITLINT_TO="${CI_COMMIT_SHA}"' 62 | # `coqbot` adds a merge commit to test PRs on top of the latest commit in 63 | # the repo; amend this merge commit message to avoid failure 64 | - | 65 | if [ "${GITLAB_USER_LOGIN}" = "coqbot" ] \ 66 | && [ "${CI_COMMIT_BRANCH}" != "master" ]; then 67 | git commit --amend -m \ 68 | 'chore: reword coqbot merge commit message for commitlint' 69 | export COMMITLINT_TO=HEAD 70 | fi 71 | # Run `commitlint` 72 | - 'commitlint --from "${COMMITLINT_FROM}" 73 | --to "${COMMITLINT_TO}" 74 | --verbose' 75 | 76 | pre-commit: 77 | stage: *stage_lint 78 | image: *image_precommit 79 | # https://pre-commit.com/#gitlab-ci-example 80 | variables: 81 | PRE_COMMIT_HOME: '${CI_PROJECT_DIR}/.cache/pre-commit' 82 | cache: 83 | key: '${CI_JOB_NAME}' 84 | paths: 85 | - '${PRE_COMMIT_HOME}' 86 | script: 87 | - 'pre-commit run --all-files --color always --verbose' 88 | 89 | # Use a separate job for `rubocop` other than the one potentially run by `pre-commit` 90 | # - The `pre-commit` check will only be available for formulas that pass the default 91 | # `rubocop` check -- and must continue to do so 92 | # - This job is allowed to fail, so can be used for all formulas 93 | # - Furthermore, this job uses all of the latest `rubocop` features & cops, 94 | # which will help when upgrading the `rubocop` linter used in `pre-commit` 95 | rubocop: 96 | allow_failure: true 97 | stage: *stage_lint 98 | image: *image_rubocop 99 | script: 100 | - 'rubocop -d -P -S --enable-pending-cops' 101 | 102 | ############################################################################### 103 | # Define `test` template 104 | ############################################################################### 105 | .test_instance: &test_instance 106 | stage: *stage_test 107 | image: *image_dindruby 108 | services: *services_docker_dind 109 | variables: *variables_bundler 110 | cache: *cache_bundler 111 | before_script: 112 | # TODO: This should work from the env vars above automatically 113 | - 'bundle config set path "${BUNDLE_CACHE_PATH}"' 114 | - 'bundle config set without "${BUNDLE_WITHOUT}"' 115 | - 'bundle install' 116 | script: 117 | # Alternative value to consider: `${CI_JOB_NAME}` 118 | - 'bin/kitchen verify "${DOCKER_ENV_CI_JOB_NAME}"' 119 | 120 | ############################################################################### 121 | # Define `test` template (`allow_failure: true`) 122 | ############################################################################### 123 | .test_instance_failure_permitted: 124 | <<: *test_instance 125 | allow_failure: true 126 | 127 | ############################################################################### 128 | # `test` stage: each instance below uses the `test` template above 129 | ############################################################################### 130 | ## Define the rest of the matrix based on Kitchen testing 131 | # Make sure the instances listed below match up with 132 | # the `platforms` defined in `kitchen.yml` 133 | # yamllint disable rule:line-length 134 | # default-debian-11-tiamat-py3: {extends: '.test_instance'} 135 | # default-debian-10-tiamat-py3: {extends: '.test_instance'} 136 | # default-debian-9-tiamat-py3: {extends: '.test_instance'} 137 | # default-ubuntu-2204-tiamat-py3: {extends: '.test_instance_failure_permitted'} 138 | # default-ubuntu-2004-tiamat-py3: {extends: '.test_instance'} 139 | # default-ubuntu-1804-tiamat-py3: {extends: '.test_instance'} 140 | # default-centos-stream8-tiamat-py3: {extends: '.test_instance_failure_permitted'} 141 | # default-centos-7-tiamat-py3: {extends: '.test_instance'} 142 | # default-amazonlinux-2-tiamat-py3: {extends: '.test_instance'} 143 | # default-oraclelinux-8-tiamat-py3: {extends: '.test_instance'} 144 | # default-oraclelinux-7-tiamat-py3: {extends: '.test_instance'} 145 | # default-almalinux-8-tiamat-py3: {extends: '.test_instance'} 146 | # default-rockylinux-8-tiamat-py3: {extends: '.test_instance'} 147 | # default-debian-11-master-py3: {extends: '.test_instance'} 148 | # repo-debian-11-master-py3: {extends: '.test_instance'} 149 | debian-11-master-py3: {extends: '.test_instance'} 150 | # default-debian-10-master-py3: {extends: '.test_instance'} 151 | # repo-debian-10-master-py3: {extends: '.test_instance'} 152 | debian-10-master-py3: {extends: '.test_instance'} 153 | # default-debian-9-master-py3: {extends: '.test_instance'} 154 | # repo-debian-9-master-py3: {extends: '.test_instance'} 155 | debian-9-master-py3: {extends: '.test_instance'} 156 | # default-ubuntu-2204-master-py3: {extends: '.test_instance_failure_permitted'} 157 | # repo-ubuntu-2204-master-py3: {extends: '.test_instance_failure_permitted'} 158 | ubuntu-2204-master-py3: {extends: '.test_instance_failure_permitted'} 159 | # default-ubuntu-2004-master-py3: {extends: '.test_instance'} 160 | # repo-ubuntu-2004-master-py3: {extends: '.test_instance'} 161 | ubuntu-2004-master-py3: {extends: '.test_instance'} 162 | # default-ubuntu-1804-master-py3: {extends: '.test_instance'} 163 | # repo-ubuntu-1804-master-py3: {extends: '.test_instance'} 164 | ubuntu-1804-master-py3: {extends: '.test_instance'} 165 | # default-centos-stream8-master-py3: {extends: '.test_instance_failure_permitted'} 166 | # repo-centos-stream8-master-py3: {extends: '.test_instance_failure_permitted'} 167 | centos-stream8-master-py3: {extends: '.test_instance_failure_permitted'} 168 | # default-centos-7-master-py3: {extends: '.test_instance'} 169 | # repo-centos-7-master-py3: {extends: '.test_instance'} 170 | centos-7-master-py3: {extends: '.test_instance'} 171 | # default-fedora-36-master-py3: {extends: '.test_instance_failure_permitted'} 172 | # repo-fedora-36-master-py3: {extends: '.test_instance_failure_permitted'} 173 | fedora-36-master-py3: {extends: '.test_instance_failure_permitted'} 174 | # default-fedora-35-master-py3: {extends: '.test_instance'} 175 | # repo-fedora-35-master-py3: {extends: '.test_instance'} 176 | fedora-35-master-py3: {extends: '.test_instance'} 177 | # default-opensuse-leap-153-master-py3: {extends: '.test_instance'} 178 | # repo-opensuse-leap-153-master-py3: {extends: '.test_instance'} 179 | opensuse-leap-153-master-py3: {extends: '.test_instance'} 180 | default-opensuse-tmbl-latest-master-py3: {extends: '.test_instance_failure_permitted'} 181 | # opensuse-tmbl-latest-master-py3: {extends: '.test_instance_failure_permitted'} 182 | # default-amazonlinux-2-master-py3: {extends: '.test_instance'} 183 | # repo-amazonlinux-2-master-py3: {extends: '.test_instance'} 184 | amazonlinux-2-master-py3: {extends: '.test_instance'} 185 | # default-oraclelinux-8-master-py3: {extends: '.test_instance'} 186 | # repo-oraclelinux-8-master-py3: {extends: '.test_instance'} 187 | oraclelinux-8-master-py3: {extends: '.test_instance'} 188 | # default-oraclelinux-7-master-py3: {extends: '.test_instance'} 189 | # repo-oraclelinux-7-master-py3: {extends: '.test_instance'} 190 | oraclelinux-7-master-py3: {extends: '.test_instance'} 191 | default-arch-base-latest-master-py3: {extends: '.test_instance'} 192 | # arch-base-latest-master-py3: {extends: '.test_instance'} 193 | # default-gentoo-stage3-latest-master-py3: {extends: '.test_instance'} 194 | # gentoo-stage3-latest-master-py3: {extends: '.test_instance'} 195 | # default-gentoo-stage3-systemd-master-py3: {extends: '.test_instance'} 196 | # gentoo-stage3-systemd-master-py3: {extends: '.test_instance'} 197 | # default-almalinux-8-master-py3: {extends: '.test_instance'} 198 | # repo-almalinux-8-master-py3: {extends: '.test_instance'} 199 | almalinux-8-master-py3: {extends: '.test_instance'} 200 | # default-rockylinux-8-master-py3: {extends: '.test_instance'} 201 | # repo-rockylinux-8-master-py3: {extends: '.test_instance'} 202 | rockylinux-8-master-py3: {extends: '.test_instance'} 203 | # default-debian-11-3004-1-py3: {extends: '.test_instance'} 204 | # default-debian-10-3004-1-py3: {extends: '.test_instance'} 205 | # default-debian-9-3004-1-py3: {extends: '.test_instance'} 206 | # default-ubuntu-2204-3004-1-py3: {extends: '.test_instance_failure_permitted'} 207 | # default-ubuntu-2004-3004-1-py3: {extends: '.test_instance'} 208 | # default-ubuntu-1804-3004-1-py3: {extends: '.test_instance'} 209 | # default-centos-stream8-3004-1-py3: {extends: '.test_instance_failure_permitted'} 210 | # default-centos-7-3004-1-py3: {extends: '.test_instance'} 211 | # default-fedora-36-3004-1-py3: {extends: '.test_instance_failure_permitted'} 212 | # default-fedora-35-3004-1-py3: {extends: '.test_instance'} 213 | # default-amazonlinux-2-3004-1-py3: {extends: '.test_instance'} 214 | # default-oraclelinux-8-3004-1-py3: {extends: '.test_instance'} 215 | # default-oraclelinux-7-3004-1-py3: {extends: '.test_instance'} 216 | # default-arch-base-latest-3004-1-py3: {extends: '.test_instance'} 217 | # default-gentoo-stage3-latest-3004-1-py3: {extends: '.test_instance'} 218 | # default-gentoo-stage3-systemd-3004-1-py3: {extends: '.test_instance'} 219 | # default-almalinux-8-3004-1-py3: {extends: '.test_instance'} 220 | # default-rockylinux-8-3004-1-py3: {extends: '.test_instance'} 221 | # default-opensuse-leap-153-3004-0-py3: {extends: '.test_instance'} 222 | # default-opensuse-tmbl-latest-3004-0-py3: {extends: '.test_instance_failure_permitted'} 223 | # default-debian-10-3003-4-py3: {extends: '.test_instance'} 224 | # default-debian-9-3003-4-py3: {extends: '.test_instance'} 225 | # default-ubuntu-2004-3003-4-py3: {extends: '.test_instance'} 226 | # default-ubuntu-1804-3003-4-py3: {extends: '.test_instance'} 227 | # default-centos-stream8-3003-4-py3: {extends: '.test_instance_failure_permitted'} 228 | # default-centos-7-3003-4-py3: {extends: '.test_instance'} 229 | # default-amazonlinux-2-3003-4-py3: {extends: '.test_instance'} 230 | # default-oraclelinux-8-3003-4-py3: {extends: '.test_instance'} 231 | # default-oraclelinux-7-3003-4-py3: {extends: '.test_instance'} 232 | # default-almalinux-8-3003-4-py3: {extends: '.test_instance'} 233 | # yamllint enable rule:line-length 234 | 235 | ############################################################################### 236 | # `release` stage: `semantic-release` 237 | ############################################################################### 238 | semantic-release: 239 | only: *only_branch_master_parent_repo 240 | stage: *stage_release 241 | image: *image_semanticrelease 242 | variables: 243 | MAINTAINER_TOKEN: '${GH_TOKEN}' 244 | script: 245 | # Update `AUTHORS.md` 246 | - '${HOME}/go/bin/maintainer contributor' 247 | # Run `semantic-release` 248 | - 'semantic-release' 249 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # vim: ft=yaml 3 | --- 4 | # See https://pre-commit.com for more information 5 | # See https://pre-commit.com/hooks.html for more hooks 6 | ci: 7 | autofix_commit_msg: | 8 | ci(pre-commit.ci): apply auto fixes from pre-commit.com hooks 9 | 10 | For more information, see https://pre-commit.ci 11 | autofix_prs: true 12 | autoupdate_branch: '' 13 | autoupdate_commit_msg: | 14 | ci(pre-commit.ci): perform `pre-commit` autoupdate 15 | autoupdate_schedule: quarterly 16 | skip: [] 17 | submodules: false 18 | default_stages: [commit] 19 | repos: 20 | - repo: https://github.com/dafyddj/commitlint-pre-commit-hook 21 | rev: v2.3.0 22 | hooks: 23 | - id: commitlint 24 | name: Check commit message using commitlint 25 | description: Lint commit message against @commitlint/config-conventional rules 26 | stages: [commit-msg] 27 | additional_dependencies: ['@commitlint/config-conventional@8.3.4'] 28 | - id: commitlint-travis 29 | stages: [manual] 30 | additional_dependencies: ['@commitlint/config-conventional@8.3.4'] 31 | always_run: true 32 | - repo: https://github.com/rubocop-hq/rubocop 33 | rev: v1.30.1 34 | hooks: 35 | - id: rubocop 36 | name: Check Ruby files with rubocop 37 | args: [--debug] 38 | always_run: true 39 | pass_filenames: false 40 | - repo: https://github.com/shellcheck-py/shellcheck-py 41 | rev: v0.8.0.4 42 | hooks: 43 | - id: shellcheck 44 | name: Check shell scripts with shellcheck 45 | files: ^.*\.(sh|bash|ksh)$ 46 | types: [] 47 | - repo: https://github.com/adrienverge/yamllint 48 | rev: v1.26.3 49 | hooks: 50 | - id: yamllint 51 | name: Check YAML syntax with yamllint 52 | args: [--strict, '.'] 53 | always_run: true 54 | pass_filenames: false 55 | - repo: https://github.com/warpnet/salt-lint 56 | rev: v0.8.0 57 | hooks: 58 | - id: salt-lint 59 | name: Check Salt files using salt-lint 60 | files: ^.*\.(sls|jinja|j2|tmpl|tst)$ 61 | - repo: https://github.com/myint/rstcheck 62 | rev: 3f929574 63 | hooks: 64 | - id: rstcheck 65 | name: Check reST files using rstcheck 66 | exclude: 'docs/CHANGELOG.rst' 67 | - repo: https://github.com/saltstack-formulas/mirrors-rst-lint 68 | rev: v1.3.2 69 | hooks: 70 | - id: rst-lint 71 | name: Check reST files using rst-lint 72 | exclude: | 73 | (?x)^( 74 | docs/CHANGELOG.rst| 75 | docs/TOFS_pattern.rst| 76 | )$ 77 | additional_dependencies: [pygments==2.9.0] 78 | -------------------------------------------------------------------------------- /.rstcheck.cfg: -------------------------------------------------------------------------------- 1 | [rstcheck] 2 | report=info 3 | ignore_language=rst 4 | ignore_messages=(Duplicate (ex|im)plicit target.*|Hyperlink target ".*" is not referenced\.$) 5 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # vim: ft=yaml 3 | --- 4 | # General overrides used across formulas in the org 5 | Layout/LineLength: 6 | # Increase from default of `80` 7 | # Based on https://github.com/PyCQA/flake8-bugbear#opinionated-warnings (`B950`) 8 | Max: 88 9 | Metrics/BlockLength: 10 | IgnoredMethods: 11 | - control 12 | - describe 13 | # Increase from default of `25` 14 | Max: 30 15 | Security/YAMLLoad: 16 | Exclude: 17 | - test/integration/**/_mapdata.rb 18 | 19 | # General settings across all cops in this formula 20 | AllCops: 21 | NewCops: enable 22 | 23 | # Any offenses that should be fixed, e.g. collected via. `rubocop --auto-gen-config` 24 | -------------------------------------------------------------------------------- /.salt-lint: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # vim: ft=yaml 3 | --- 4 | exclude_paths: [] 5 | rules: {} 6 | skip_list: 7 | # Using `salt-lint` for linting other files as well, such as Jinja macros/templates 8 | - 205 # Use ".sls" as a Salt State file extension 9 | # Skipping `207` and `208` because `210` is sufficient, at least for the time-being 10 | # I.e. Allows 3-digit unquoted codes to still be used, such as `644` and `755` 11 | - 207 # File modes should always be encapsulated in quotation marks 12 | - 208 # File modes should always contain a leading zero 13 | tags: [] 14 | verbosity: 1 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # vim: ft=yaml 3 | --- 4 | ################################################################################ 5 | # NOTE: This file is UNMAINTAINED; it is provided for references purposes only. 6 | # No guarantees are tendered that this structure will work after 2020. 7 | ################################################################################ 8 | # * https://en.wikipedia.org/wiki/Travis_CI: 9 | # - "... free open-source plans were removed in [sic] the end of 2020" 10 | # - https://blog.travis-ci.com/2020-11-02-travis-ci-new-billing 11 | # - https://ropensci.org/technotes/2020/11/19/moving-away-travis/ 12 | ################################################################################ 13 | ## Machine config 14 | os: 'linux' 15 | arch: 'amd64' 16 | dist: 'bionic' 17 | version: '~> 1.0' 18 | 19 | ## Language and cache config 20 | language: 'ruby' 21 | cache: 'bundler' 22 | 23 | ## Services config 24 | services: 25 | - docker 26 | 27 | ## Script to run for the test stage 28 | script: 29 | - bin/kitchen verify "${INSTANCE}" 30 | 31 | ## Stages and jobs matrix 32 | stages: 33 | - test 34 | # # As part of the switch away from Travis CI, ensure that the `release` stage 35 | # # is not run inadvertently 36 | # - name: 'release' 37 | # if: 'branch = master AND type != pull_request' 38 | jobs: 39 | include: 40 | ## Define the test stage that runs the linters (and testing matrix, if applicable) 41 | 42 | # Run all of the linters in a single job 43 | - language: 'node_js' 44 | node_js: 'lts/*' 45 | env: 'Lint' 46 | name: 'Lint: salt-lint, yamllint, rubocop, shellcheck & commitlint' 47 | before_install: 'skip' 48 | script: 49 | # Install and run `salt-lint` 50 | - pip install --user salt-lint 51 | - git ls-files -- '*.sls' '*.jinja' '*.j2' '*.tmpl' '*.tst' 52 | | xargs salt-lint 53 | # Install and run `yamllint` 54 | # Need at least `v1.17.0` for the `yaml-files` setting 55 | - pip install --user yamllint>=1.17.0 56 | - yamllint -s . 57 | # Install and run `rubocop` 58 | - gem install rubocop 59 | - rubocop -d 60 | # Run `shellcheck` (already pre-installed in Travis) 61 | - shellcheck --version 62 | - git ls-files -- '*.sh' '*.bash' '*.ksh' 63 | | xargs shellcheck 64 | # Install and run `commitlint` 65 | - npm i -D @commitlint/config-conventional 66 | @commitlint/travis-cli 67 | - commitlint-travis 68 | 69 | # Run `pre-commit` linters in a single job 70 | - language: 'python' 71 | env: 'Lint_pre-commit' 72 | name: 'Lint: pre-commit' 73 | before_install: 'skip' 74 | cache: 75 | directories: 76 | - $HOME/.cache/pre-commit 77 | script: 78 | # Install and run `pre-commit` 79 | - pip install pre-commit==2.7.1 80 | - pre-commit run --all-files --color always --verbose 81 | - pre-commit run --color always --hook-stage manual --verbose commitlint-travis 82 | 83 | ## Define the rest of the matrix based on Kitchen testing 84 | # Make sure the instances listed below match up with 85 | # the `platforms` defined in `kitchen.yml` 86 | # - env: INSTANCE=default-debian-11-tiamat-py3 87 | # - env: INSTANCE=default-debian-10-tiamat-py3 88 | # - env: INSTANCE=default-debian-9-tiamat-py3 89 | # - env: INSTANCE=default-ubuntu-2204-tiamat-py3 90 | # - env: INSTANCE=default-ubuntu-2004-tiamat-py3 91 | # - env: INSTANCE=default-ubuntu-1804-tiamat-py3 92 | # - env: INSTANCE=default-centos-stream8-tiamat-py3 93 | # - env: INSTANCE=default-centos-7-tiamat-py3 94 | # - env: INSTANCE=default-amazonlinux-2-tiamat-py3 95 | # - env: INSTANCE=default-oraclelinux-8-tiamat-py3 96 | # - env: INSTANCE=default-oraclelinux-7-tiamat-py3 97 | # - env: INSTANCE=default-almalinux-8-tiamat-py3 98 | # - env: INSTANCE=default-rockylinux-8-tiamat-py3 99 | # - env: INSTANCE=default-debian-11-master-py3 100 | # - env: INSTANCE=repo-debian-11-master-py3 101 | - env: INSTANCE=debian-11-master-py3 102 | # - env: INSTANCE=default-debian-10-master-py3 103 | # - env: INSTANCE=repo-debian-10-master-py3 104 | - env: INSTANCE=debian-10-master-py3 105 | # - env: INSTANCE=default-debian-9-master-py3 106 | # - env: INSTANCE=repo-debian-9-master-py3 107 | - env: INSTANCE=debian-9-master-py3 108 | # - env: INSTANCE=default-ubuntu-2204-master-py3 109 | # - env: INSTANCE=repo-ubuntu-2204-master-py3 110 | - env: INSTANCE=ubuntu-2204-master-py3 111 | # - env: INSTANCE=default-ubuntu-2004-master-py3 112 | # - env: INSTANCE=repo-ubuntu-2004-master-py3 113 | - env: INSTANCE=ubuntu-2004-master-py3 114 | # - env: INSTANCE=default-ubuntu-1804-master-py3 115 | # - env: INSTANCE=repo-ubuntu-1804-master-py3 116 | - env: INSTANCE=ubuntu-1804-master-py3 117 | # - env: INSTANCE=default-centos-stream8-master-py3 118 | # - env: INSTANCE=repo-centos-stream8-master-py3 119 | - env: INSTANCE=centos-stream8-master-py3 120 | # - env: INSTANCE=default-centos-7-master-py3 121 | # - env: INSTANCE=repo-centos-7-master-py3 122 | - env: INSTANCE=centos-7-master-py3 123 | # - env: INSTANCE=default-fedora-36-master-py3 124 | # - env: INSTANCE=repo-fedora-36-master-py3 125 | - env: INSTANCE=fedora-36-master-py3 126 | # - env: INSTANCE=default-fedora-35-master-py3 127 | # - env: INSTANCE=repo-fedora-35-master-py3 128 | - env: INSTANCE=fedora-35-master-py3 129 | # - env: INSTANCE=default-opensuse-leap-153-master-py3 130 | # - env: INSTANCE=repo-opensuse-leap-153-master-py3 131 | - env: INSTANCE=opensuse-leap-153-master-py3 132 | - env: INSTANCE=default-opensuse-tmbl-latest-master-py3 133 | # - env: INSTANCE=opensuse-tmbl-latest-master-py3 134 | # - env: INSTANCE=default-amazonlinux-2-master-py3 135 | # - env: INSTANCE=repo-amazonlinux-2-master-py3 136 | - env: INSTANCE=amazonlinux-2-master-py3 137 | # - env: INSTANCE=default-oraclelinux-8-master-py3 138 | # - env: INSTANCE=repo-oraclelinux-8-master-py3 139 | - env: INSTANCE=oraclelinux-8-master-py3 140 | # - env: INSTANCE=default-oraclelinux-7-master-py3 141 | # - env: INSTANCE=repo-oraclelinux-7-master-py3 142 | - env: INSTANCE=oraclelinux-7-master-py3 143 | - env: INSTANCE=default-arch-base-latest-master-py3 144 | # - env: INSTANCE=arch-base-latest-master-py3 145 | # - env: INSTANCE=default-gentoo-stage3-latest-master-py3 146 | # - env: INSTANCE=gentoo-stage3-latest-master-py3 147 | # - env: INSTANCE=default-gentoo-stage3-systemd-master-py3 148 | # - env: INSTANCE=gentoo-stage3-systemd-master-py3 149 | # - env: INSTANCE=default-almalinux-8-master-py3 150 | # - env: INSTANCE=repo-almalinux-8-master-py3 151 | - env: INSTANCE=almalinux-8-master-py3 152 | # - env: INSTANCE=default-rockylinux-8-master-py3 153 | # - env: INSTANCE=repo-rockylinux-8-master-py3 154 | - env: INSTANCE=rockylinux-8-master-py3 155 | # - env: INSTANCE=default-debian-11-3004-1-py3 156 | # - env: INSTANCE=default-debian-10-3004-1-py3 157 | # - env: INSTANCE=default-debian-9-3004-1-py3 158 | # - env: INSTANCE=default-ubuntu-2204-3004-1-py3 159 | # - env: INSTANCE=default-ubuntu-2004-3004-1-py3 160 | # - env: INSTANCE=default-ubuntu-1804-3004-1-py3 161 | # - env: INSTANCE=default-centos-stream8-3004-1-py3 162 | # - env: INSTANCE=default-centos-7-3004-1-py3 163 | # - env: INSTANCE=default-fedora-36-3004-1-py3 164 | # - env: INSTANCE=default-fedora-35-3004-1-py3 165 | # - env: INSTANCE=default-amazonlinux-2-3004-1-py3 166 | # - env: INSTANCE=default-oraclelinux-8-3004-1-py3 167 | # - env: INSTANCE=default-oraclelinux-7-3004-1-py3 168 | # - env: INSTANCE=default-arch-base-latest-3004-1-py3 169 | # - env: INSTANCE=default-gentoo-stage3-latest-3004-1-py3 170 | # - env: INSTANCE=default-gentoo-stage3-systemd-3004-1-py3 171 | # - env: INSTANCE=default-almalinux-8-3004-1-py3 172 | # - env: INSTANCE=default-rockylinux-8-3004-1-py3 173 | # - env: INSTANCE=default-opensuse-leap-153-3004-0-py3 174 | # - env: INSTANCE=default-opensuse-tmbl-latest-3004-0-py3 175 | # - env: INSTANCE=default-debian-10-3003-4-py3 176 | # - env: INSTANCE=default-debian-9-3003-4-py3 177 | # - env: INSTANCE=default-ubuntu-2004-3003-4-py3 178 | # - env: INSTANCE=default-ubuntu-1804-3003-4-py3 179 | # - env: INSTANCE=default-centos-stream8-3003-4-py3 180 | # - env: INSTANCE=default-centos-7-3003-4-py3 181 | # - env: INSTANCE=default-amazonlinux-2-3003-4-py3 182 | # - env: INSTANCE=default-oraclelinux-8-3003-4-py3 183 | # - env: INSTANCE=default-oraclelinux-7-3003-4-py3 184 | # - env: INSTANCE=default-almalinux-8-3003-4-py3 185 | 186 | ## Define the release stage that runs `semantic-release` 187 | - stage: 'release' 188 | language: 'node_js' 189 | node_js: 'lts/*' 190 | env: 'Release' 191 | name: 'Run semantic-release inc. file updates to AUTHORS, CHANGELOG & FORMULA' 192 | before_install: 'skip' 193 | script: 194 | # Update `AUTHORS.md` 195 | - export MAINTAINER_TOKEN=${GH_TOKEN} 196 | - go get github.com/myii/maintainer 197 | - maintainer contributor 198 | 199 | # Install all dependencies required for `semantic-release` 200 | - npm i -D @semantic-release/changelog@3 201 | @semantic-release/exec@3 202 | @semantic-release/git@7 203 | deploy: 204 | provider: 'script' 205 | # Opt-in to `dpl v2` to complete the Travis build config validation (beta) 206 | # * https://docs.travis-ci.com/user/build-config-validation 207 | # Deprecated `skip_cleanup` can now be avoided, `cleanup: false` is by default 208 | edge: true 209 | # Run `semantic-release` 210 | script: 'npx semantic-release@15.14' 211 | 212 | # Notification options: `always`, `never` or `change` 213 | notifications: 214 | webhooks: 215 | if: 'repo = saltstack-formulas/postgres-formula' 216 | urls: 217 | - https://saltstack-formulas.zulipchat.com/api/v1/external/travis?api_key=HsIq3o5QmLxdnVCKF9is0FUIpkpAY79P&stream=CI&topic=saltstack-formulas%2Fpostgres-formula&ignore_pull_requests=true 218 | on_success: always # default: always 219 | on_failure: always # default: always 220 | on_start: always # default: never 221 | on_cancel: always # default: always 222 | on_error: always # default: always 223 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # vim: ft=yaml 3 | --- 4 | # Extend the `default` configuration provided by `yamllint` 5 | extends: 'default' 6 | 7 | # Files to ignore completely 8 | # 1. All YAML files under directory `.bundle/`, introduced if gems are installed locally 9 | # 2. All YAML files under directory `.cache/`, introduced during the CI run 10 | # 3. All YAML files under directory `.git/` 11 | # 4. All YAML files under directory `node_modules/`, introduced during the CI run 12 | # 5. Any SLS files under directory `test/`, which are actually state files 13 | # 6. Any YAML files under directory `.kitchen/`, introduced during local testing 14 | # 7. `kitchen.vagrant.yml`, which contains Embedded Ruby (ERB) template syntax 15 | # 8. All YAML files heavily reliant on Jinja; these can be tackled in a subsequent PR 16 | ignore: | 17 | .bundle/ 18 | .cache/ 19 | .git/ 20 | node_modules/ 21 | test/**/states/**/*.sls 22 | .kitchen/ 23 | kitchen.vagrant.yml 24 | pillar.example 25 | postgres/codenamemap.yaml 26 | postgres/osfamilymap.yaml 27 | postgres/osmap.yaml 28 | postgres/repo.yaml 29 | test/salt/pillar/postgres.sls 30 | 31 | yaml-files: 32 | # Default settings 33 | - '*.yaml' 34 | - '*.yml' 35 | - .salt-lint 36 | - .yamllint 37 | # SaltStack Formulas additional settings 38 | - '*.example' 39 | - test/**/*.sls 40 | 41 | rules: 42 | empty-values: 43 | forbid-in-block-mappings: true 44 | forbid-in-flow-mappings: true 45 | line-length: 46 | # Increase from default of `80` 47 | # Based on https://github.com/PyCQA/flake8-bugbear#opinionated-warnings (`B950`) 48 | max: 88 49 | octal-values: 50 | forbid-implicit-octal: true 51 | forbid-explicit-octal: true 52 | -------------------------------------------------------------------------------- /AUTHORS.md: -------------------------------------------------------------------------------- 1 | # Authors 2 | 3 | This list is sorted by the number of commits per contributor in _descending_ order. 4 | 5 | Avatar|Contributor|Contributions 6 | :-:|---|:-: 7 | @myii|[@myii](https://github.com/myii)|229 8 | @noelmcloughlin|[@noelmcloughlin](https://github.com/noelmcloughlin)|79 9 | @aboe76|[@aboe76](https://github.com/aboe76)|54 10 | @gravyboat|[@gravyboat](https://github.com/gravyboat)|41 11 | @javierbertoli|[@javierbertoli](https://github.com/javierbertoli)|24 12 | @nmadhok|[@nmadhok](https://github.com/nmadhok)|19 13 | @vutny|[@vutny](https://github.com/vutny)|18 14 | @puneetk|[@puneetk](https://github.com/puneetk)|11 15 | @EvaSDK|[@EvaSDK](https://github.com/EvaSDK)|9 16 | @dferramosi|[@dferramosi](https://github.com/dferramosi)|8 17 | @johnkeates|[@johnkeates](https://github.com/johnkeates)|8 18 | @litnialex|[@litnialex](https://github.com/litnialex)|8 19 | @whiteinge|[@whiteinge](https://github.com/whiteinge)|8 20 | @wolodjawentland|[@wolodjawentland](https://github.com/wolodjawentland)|8 21 | @iggy|[@iggy](https://github.com/iggy)|7 22 | @dynjnelson|[@dynjnelson](https://github.com/dynjnelson)|7 23 | @rominf|[@rominf](https://github.com/rominf)|7 24 | @alxwr|[@alxwr](https://github.com/alxwr)|5 25 | @audreyfeldroy|[@audreyfeldroy](https://github.com/audreyfeldroy)|5 26 | @blast-hardcheese|[@blast-hardcheese](https://github.com/blast-hardcheese)|5 27 | @gilou|[@gilou](https://github.com/gilou)|5 28 | @techhat|[@techhat](https://github.com/techhat)|5 29 | @t0fik|[@t0fik](https://github.com/t0fik)|5 30 | @stp-ip|[@stp-ip](https://github.com/stp-ip)|4 31 | @blbradley|[@blbradley](https://github.com/blbradley)|3 32 | @dafyddj|[@dafyddj](https://github.com/dafyddj)|3 33 | @abrefort|[@abrefort](https://github.com/abrefort)|3 34 | @renoirb|[@renoirb](https://github.com/renoirb)|3 35 | @Ken-2scientists|[@Ken-2scientists](https://github.com/Ken-2scientists)|2 36 | @madssj|[@madssj](https://github.com/madssj)|2 37 | @tgoodaire|[@tgoodaire](https://github.com/tgoodaire)|2 38 | @sticky-note|[@sticky-note](https://github.com/sticky-note)|2 39 | @durana|[@durana](https://github.com/durana)|1 40 | @bebosudo|[@bebosudo](https://github.com/bebosudo)|1 41 | @sarcastic-coder|[@sarcastic-coder](https://github.com/sarcastic-coder)|1 42 | @SuperTux88|[@SuperTux88](https://github.com/SuperTux88)|1 43 | @brot|[@brot](https://github.com/brot)|1 44 | @xbglowx|[@xbglowx](https://github.com/xbglowx)|1 45 | @cro|[@cro](https://github.com/cro)|1 46 | @campbellmc|[@campbellmc](https://github.com/campbellmc)|1 47 | @baby-gnu|[@baby-gnu](https://github.com/baby-gnu)|1 48 | @UtahDave|[@UtahDave](https://github.com/UtahDave)|1 49 | @fcrozat|[@fcrozat](https://github.com/fcrozat)|1 50 | @Laogeodritt|[@Laogeodritt](https://github.com/Laogeodritt)|1 51 | @itbabu|[@itbabu](https://github.com/itbabu)|1 52 | @mkotsbak|[@mkotsbak](https://github.com/mkotsbak)|1 53 | @mattysads|[@mattysads](https://github.com/mattysads)|1 54 | @mbrannigan|[@mbrannigan](https://github.com/mbrannigan)|1 55 | @n-rodriguez|[@n-rodriguez](https://github.com/n-rodriguez)|1 56 | @SamJoan|[@SamJoan](https://github.com/SamJoan)|1 57 | @rmoorman|[@rmoorman](https://github.com/rmoorman)|1 58 | @skurfer|[@skurfer](https://github.com/skurfer)|1 59 | @RobRuana|[@RobRuana](https://github.com/RobRuana)|1 60 | @sbrefort|[@sbrefort](https://github.com/sbrefort)|1 61 | @sbellem|[@sbellem](https://github.com/sbellem)|1 62 | @retrry|[@retrry](https://github.com/retrry)|1 63 | @thomasrossetto|[@thomasrossetto](https://github.com/thomasrossetto)|1 64 | @thatch45|[@thatch45](https://github.com/thatch45)|1 65 | @tobio|[@tobio](https://github.com/tobio)|1 66 | @XRasher|[@XRasher](https://github.com/XRasher)|1 67 | @YetAnotherMinion|[@YetAnotherMinion](https://github.com/YetAnotherMinion)|1 68 | @ek9|[@ek9](https://github.com/ek9)|1 69 | @Strade288|[@Strade288](https://github.com/Strade288)|1 70 | @daks|[@daks](https://github.com/daks)|1 71 | 72 | --- 73 | 74 | Auto-generated by a [forked version](https://github.com/myii/maintainer) of [gaocegege/maintainer](https://github.com/gaocegege/maintainer) on 2022-07-18. 75 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners 2 | 3 | # SECTION: Owner(s) for everything in the repo, unless a later match takes precedence 4 | # FILE PATTERN OWNER(S) 5 | * @vutny @myii 6 | 7 | # SECTION: Owner(s) for specific directories 8 | # FILE PATTERN OWNER(S) 9 | 10 | # SECTION: Owner(s) for files/directories related to `semantic-release` 11 | # FILE PATTERN OWNER(S) 12 | /.github/workflows/ @saltstack-formulas/ssf 13 | /bin/install-hooks @saltstack-formulas/ssf 14 | /bin/kitchen @saltstack-formulas/ssf 15 | /docs/AUTHORS.rst @saltstack-formulas/ssf 16 | /docs/CHANGELOG.rst @saltstack-formulas/ssf 17 | /docs/TOFS_pattern.rst @saltstack-formulas/ssf 18 | /*/_mapdata/ @saltstack-formulas/ssf 19 | /*/libsaltcli.jinja @saltstack-formulas/ssf 20 | /*/libtofs.jinja @saltstack-formulas/ssf 21 | /test/integration/**/_mapdata.rb @saltstack-formulas/ssf 22 | /test/integration/**/libraries/system.rb @saltstack-formulas/ssf 23 | /test/integration/**/inspec.yml @saltstack-formulas/ssf 24 | /test/integration/**/README.md @saltstack-formulas/ssf 25 | /test/salt/pillar/top.sls @saltstack-formulas/ssf 26 | /.gitignore @saltstack-formulas/ssf 27 | /.cirrus.yml @saltstack-formulas/ssf 28 | /.gitlab-ci.yml @saltstack-formulas/ssf 29 | /.pre-commit-config.yaml @saltstack-formulas/ssf 30 | /.rstcheck.cfg @saltstack-formulas/ssf 31 | /.rubocop.yml @saltstack-formulas/ssf 32 | /.salt-lint @saltstack-formulas/ssf 33 | /.travis.yml @saltstack-formulas/ssf 34 | /.yamllint @saltstack-formulas/ssf 35 | /AUTHORS.md @saltstack-formulas/ssf 36 | /CHANGELOG.md @saltstack-formulas/ssf 37 | /CODEOWNERS @saltstack-formulas/ssf 38 | /commitlint.config.js @saltstack-formulas/ssf 39 | /FORMULA @saltstack-formulas/ssf 40 | /Gemfile @saltstack-formulas/ssf 41 | /Gemfile.lock @saltstack-formulas/ssf 42 | /kitchen.yml @saltstack-formulas/ssf 43 | /kitchen.vagrant.yml @saltstack-formulas/ssf 44 | /kitchen.windows.yml @saltstack-formulas/ssf 45 | /pre-commit_semantic-release.sh @saltstack-formulas/ssf 46 | /release-rules.js @saltstack-formulas/ssf 47 | /release.config.js @saltstack-formulas/ssf 48 | 49 | # SECTION: Owner(s) for specific files 50 | # FILE PATTERN OWNER(S) 51 | -------------------------------------------------------------------------------- /FORMULA: -------------------------------------------------------------------------------- 1 | name: postgres 2 | os: Debian, Ubuntu, Raspbian, RedHat, Fedora, CentOS, Suse, openSUSE, Gentoo, Funtoo, Arch, Manjaro, Alpine, FreeBSD, OpenBSD, Solaris, SmartOS, Windows, MacOS 3 | os_family: Debian, RedHat, Suse, Gentoo, Arch, Alpine, FreeBSD, OpenBSD, Solaris, Windows, MacOS 4 | version: 0.45.0 5 | release: 1 6 | minimum_version: 2016.11 7 | summary: Postgres formula 8 | description: Formula to install and configure PostgreSQL 9 | top_level_dir: postgres 10 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source ENV.fetch('PROXY_RUBYGEMSORG', 'https://rubygems.org') 4 | 5 | # Install the `inspec` gem using `git` because versions after `4.22.22` 6 | # suppress diff output; this version fixes this for our uses. 7 | # rubocop:disable Layout/LineLength 8 | gem 'inspec', git: 'https://gitlab.com/saltstack-formulas/infrastructure/inspec', branch: 'ssf' 9 | # rubocop:enable Layout/LineLength 10 | 11 | # Install the `kitchen-docker` gem using `git` in order to gain a performance 12 | # improvement: avoid package installations which are already covered by the 13 | # `salt-image-builder` (i.e. the pre-salted images that we're using) 14 | # rubocop:disable Layout/LineLength 15 | gem 'kitchen-docker', git: 'https://gitlab.com/saltstack-formulas/infrastructure/kitchen-docker', branch: 'ssf' 16 | # rubocop:enable Layout/LineLength 17 | 18 | gem 'kitchen-inspec', '>= 2.5.0' 19 | gem 'kitchen-salt', '>= 0.7.2' 20 | 21 | group :vagrant do 22 | gem 'kitchen-vagrant' 23 | end 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2015 Salt Stack Formulas 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /bin/install-hooks: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | set -o nounset # Treat unset variables as an error and immediately exit 3 | set -o errexit # If a command fails exit the whole script 4 | 5 | if [ "${DEBUG:-false}" = "true" ]; then 6 | set -x # Run the entire script in debug mode 7 | fi 8 | 9 | if ! command -v pre-commit >/dev/null 2>&1; then 10 | echo "pre-commit not found: please install or check your PATH" >&2 11 | echo "See https://pre-commit.com/#installation" >&2 12 | exit 1 13 | fi 14 | 15 | pre-commit install --install-hooks 16 | pre-commit install --hook-type commit-msg --install-hooks 17 | -------------------------------------------------------------------------------- /bin/kitchen: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'kitchen' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require 'pathname' 12 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path('bundle', __dir__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort( 22 | 'Your `bin/bundle` was not generated by Bundler, ' \ 23 | 'so this binstub cannot run. Replace `bin/bundle` by running ' \ 24 | '`bundle binstubs bundler --force`, then run this command again.' 25 | ) 26 | end 27 | end 28 | 29 | require 'rubygems' 30 | require 'bundler/setup' 31 | 32 | load Gem.bin_path('test-kitchen', 'kitchen') 33 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'], 3 | rules: { 4 | 'body-max-line-length': [2, 'always', 120], 5 | 'footer-max-line-length': [2, 'always', 120], 6 | 'header-max-length': [2, 'always', 72], 7 | }, 8 | }; 9 | -------------------------------------------------------------------------------- /docs/AUTHORS.rst: -------------------------------------------------------------------------------- 1 | .. role:: raw-html-m2r(raw) 2 | :format: html 3 | 4 | 5 | Authors 6 | ======= 7 | 8 | This list is sorted by the number of commits per contributor in *descending* order. 9 | 10 | .. list-table:: 11 | :header-rows: 1 12 | 13 | * - Avatar 14 | - Contributor 15 | - Contributions 16 | * - :raw-html-m2r:`@myii` 17 | - `@myii `_ 18 | - 201 19 | * - :raw-html-m2r:`@noelmcloughlin` 20 | - `@noelmcloughlin `_ 21 | - 79 22 | * - :raw-html-m2r:`@aboe76` 23 | - `@aboe76 `_ 24 | - 54 25 | * - :raw-html-m2r:`@gravyboat` 26 | - `@gravyboat `_ 27 | - 41 28 | * - :raw-html-m2r:`@javierbertoli` 29 | - `@javierbertoli `_ 30 | - 24 31 | * - :raw-html-m2r:`@nmadhok` 32 | - `@nmadhok `_ 33 | - 19 34 | * - :raw-html-m2r:`@vutny` 35 | - `@vutny `_ 36 | - 18 37 | * - :raw-html-m2r:`@puneetk` 38 | - `@puneetk `_ 39 | - 11 40 | * - :raw-html-m2r:`@EvaSDK` 41 | - `@EvaSDK `_ 42 | - 9 43 | * - :raw-html-m2r:`@dferramosi` 44 | - `@dferramosi `_ 45 | - 8 46 | * - :raw-html-m2r:`@johnkeates` 47 | - `@johnkeates `_ 48 | - 8 49 | * - :raw-html-m2r:`@litnialex` 50 | - `@litnialex `_ 51 | - 8 52 | * - :raw-html-m2r:`@whiteinge` 53 | - `@whiteinge `_ 54 | - 8 55 | * - :raw-html-m2r:`@babilen` 56 | - `@babilen `_ 57 | - 8 58 | * - :raw-html-m2r:`@iggy` 59 | - `@iggy `_ 60 | - 7 61 | * - :raw-html-m2r:`@dynjnelson` 62 | - `@dynjnelson `_ 63 | - 7 64 | * - :raw-html-m2r:`@rominf` 65 | - `@rominf `_ 66 | - 7 67 | * - :raw-html-m2r:`@alxwr` 68 | - `@alxwr `_ 69 | - 5 70 | * - :raw-html-m2r:`@audreyfeldroy` 71 | - `@audreyfeldroy `_ 72 | - 5 73 | * - :raw-html-m2r:`@blast-hardcheese` 74 | - `@blast-hardcheese `_ 75 | - 5 76 | * - :raw-html-m2r:`@gilou` 77 | - `@gilou `_ 78 | - 5 79 | * - :raw-html-m2r:`@techhat` 80 | - `@techhat `_ 81 | - 5 82 | * - :raw-html-m2r:`@t0fik` 83 | - `@t0fik `_ 84 | - 5 85 | * - :raw-html-m2r:`@stp-ip` 86 | - `@stp-ip `_ 87 | - 4 88 | * - :raw-html-m2r:`@blbradley` 89 | - `@blbradley `_ 90 | - 3 91 | * - :raw-html-m2r:`@dafyddj` 92 | - `@dafyddj `_ 93 | - 3 94 | * - :raw-html-m2r:`@abrefort` 95 | - `@abrefort `_ 96 | - 3 97 | * - :raw-html-m2r:`@renoirb` 98 | - `@renoirb `_ 99 | - 3 100 | * - :raw-html-m2r:`@Ken-2scientists` 101 | - `@Ken-2scientists `_ 102 | - 2 103 | * - :raw-html-m2r:`@madssj` 104 | - `@madssj `_ 105 | - 2 106 | * - :raw-html-m2r:`@tgoodaire` 107 | - `@tgoodaire `_ 108 | - 2 109 | * - :raw-html-m2r:`@sticky-note` 110 | - `@sticky-note `_ 111 | - 2 112 | * - :raw-html-m2r:`@durana` 113 | - `@durana `_ 114 | - 1 115 | * - :raw-html-m2r:`@bebosudo` 116 | - `@bebosudo `_ 117 | - 1 118 | * - :raw-html-m2r:`@sarcastic-coder` 119 | - `@sarcastic-coder `_ 120 | - 1 121 | * - :raw-html-m2r:`@SuperTux88` 122 | - `@SuperTux88 `_ 123 | - 1 124 | * - :raw-html-m2r:`@brot` 125 | - `@brot `_ 126 | - 1 127 | * - :raw-html-m2r:`@xbglowx` 128 | - `@xbglowx `_ 129 | - 1 130 | * - :raw-html-m2r:`@cro` 131 | - `@cro `_ 132 | - 1 133 | * - :raw-html-m2r:`@campbellmc` 134 | - `@campbellmc `_ 135 | - 1 136 | * - :raw-html-m2r:`@baby-gnu` 137 | - `@baby-gnu `_ 138 | - 1 139 | * - :raw-html-m2r:`@UtahDave` 140 | - `@UtahDave `_ 141 | - 1 142 | * - :raw-html-m2r:`@fcrozat` 143 | - `@fcrozat `_ 144 | - 1 145 | * - :raw-html-m2r:`@Laogeodritt` 146 | - `@Laogeodritt `_ 147 | - 1 148 | * - :raw-html-m2r:`@itbabu` 149 | - `@itbabu `_ 150 | - 1 151 | * - :raw-html-m2r:`@mkotsbak` 152 | - `@mkotsbak `_ 153 | - 1 154 | * - :raw-html-m2r:`@mattysads` 155 | - `@mattysads `_ 156 | - 1 157 | * - :raw-html-m2r:`@mbrannigan` 158 | - `@mbrannigan `_ 159 | - 1 160 | * - :raw-html-m2r:`@n-rodriguez` 161 | - `@n-rodriguez `_ 162 | - 1 163 | * - :raw-html-m2r:`@SamJoan` 164 | - `@SamJoan `_ 165 | - 1 166 | * - :raw-html-m2r:`@rmoorman` 167 | - `@rmoorman `_ 168 | - 1 169 | * - :raw-html-m2r:`@skurfer` 170 | - `@skurfer `_ 171 | - 1 172 | * - :raw-html-m2r:`@RobRuana` 173 | - `@RobRuana `_ 174 | - 1 175 | * - :raw-html-m2r:`@sbrefort` 176 | - `@sbrefort `_ 177 | - 1 178 | * - :raw-html-m2r:`@sbellem` 179 | - `@sbellem `_ 180 | - 1 181 | * - :raw-html-m2r:`@retrry` 182 | - `@retrry `_ 183 | - 1 184 | * - :raw-html-m2r:`@thomasrossetto` 185 | - `@thomasrossetto `_ 186 | - 1 187 | * - :raw-html-m2r:`@thatch45` 188 | - `@thatch45 `_ 189 | - 1 190 | * - :raw-html-m2r:`@tobio` 191 | - `@tobio `_ 192 | - 1 193 | * - :raw-html-m2r:`@XRasher` 194 | - `@XRasher `_ 195 | - 1 196 | * - :raw-html-m2r:`@YetAnotherMinion` 197 | - `@YetAnotherMinion `_ 198 | - 1 199 | * - :raw-html-m2r:`@ek9` 200 | - `@ek9 `_ 201 | - 1 202 | * - :raw-html-m2r:`@Strade288` 203 | - `@Strade288 `_ 204 | - 1 205 | * - :raw-html-m2r:`@daks` 206 | - `@daks `_ 207 | - 1 208 | 209 | 210 | ---- 211 | 212 | Auto-generated by a `forked version `_ of `gaocegege/maintainer `_ on 2022-02-07. 213 | -------------------------------------------------------------------------------- /docs/README.rst: -------------------------------------------------------------------------------- 1 | postgres-formula 2 | ================ 3 | 4 | |img_travis| |img_sr| 5 | 6 | .. |img_travis| image:: https://travis-ci.com/saltstack-formulas/postgres-formula.svg?branch=master 7 | :alt: Travis CI Build Status 8 | :scale: 100% 9 | :target: https://travis-ci.com/saltstack-formulas/postgres-formula 10 | .. |img_sr| image:: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg 11 | :alt: Semantic Release 12 | :scale: 100% 13 | :target: https://github.com/semantic-release/semantic-release 14 | 15 | A formula to install and configure PostgreSQL server. 16 | 17 | .. contents:: **Table of Contents** 18 | 19 | General notes 20 | ------------- 21 | 22 | See the full `SaltStack Formulas installation and usage instructions 23 | `_. 24 | 25 | If you are interested in writing or contributing to formulas, please pay attention to the `Writing Formula Section 26 | `_. 27 | 28 | If you want to use this formula, please pay attention to the ``FORMULA`` file and/or ``git tag``, 29 | which contains the currently released version. This formula is versioned according to `Semantic Versioning `_. 30 | 31 | See `Formula Versioning Section `_ for more details. 32 | 33 | Contributing to this repo 34 | ------------------------- 35 | 36 | **Commit message formatting is significant!!** 37 | 38 | Please see `How to contribute `_ for more details. 39 | 40 | Available states 41 | ---------------- 42 | 43 | .. contents:: 44 | :local: 45 | 46 | ``postgres`` 47 | ^^^^^^^^^^^^ 48 | 49 | Installs and configures both PostgreSQL server and client with creation of various DB objects in 50 | the cluster. This state applies to both Linux and MacOS. 51 | 52 | ``postgres.client`` 53 | ^^^^^^^^^^^^^^^^^^^ 54 | 55 | Installs the PostgreSQL client binaries and libraries on Linux. 56 | 57 | ``postgres.manage`` 58 | ^^^^^^^^^^^^^^^^^^^ 59 | 60 | Creates such DB objects as: users, tablespaces, databases, schemas and extensions. 61 | See ``pillar.example`` file for details. 62 | 63 | ``postgres.python`` 64 | ^^^^^^^^^^^^^^^^^^^ 65 | 66 | Installs the PostgreSQL adapter for Python on Linux. 67 | 68 | ``postgres.server`` 69 | ^^^^^^^^^^^^^^^^^^^ 70 | 71 | Installs the PostgreSQL server package on Linux, prepares the DB cluster and starts the server using 72 | packaged init script, job or unit. 73 | 74 | 75 | .. note:: 76 | 77 | For PostgreSQL server before version 10 to work inside a **FreeBSD Jail** 78 | set ``sysvshm=new`` and ``sysvsem=new``. 79 | DO NOT SET ``allow.sysvipc=1``. It defeats the purpose of using Jails. 80 | 81 | Further information: https://blog.tyk.nu/blog/freebsd-jails-and-sysv-ipc/ 82 | 83 | 84 | **Running inside a container** (using Packer, Docker or similar tools), when OS ``init`` process 85 | is not available to start the service and enable it on "boot", set pillar value: 86 | 87 | .. code:: yaml 88 | 89 | postgres: 90 | bake_image: True 91 | 92 | This toggles starting PostgreSQL daemon by issuing raw ``pg_ctl`` or ``pg_ctlcluster`` command. 93 | 94 | ``postgres.upstream`` 95 | ^^^^^^^^^^^^^^^^^^^^^ 96 | 97 | Configures the PostgreSQL Official (upstream) repository on target system if 98 | applicable. 99 | 100 | The state relies on the ``postgres:use_upstream_repo`` Pillar value which could be set as following: 101 | 102 | * ``True`` (default): adds the upstream repository to install packages from 103 | * ``False``: makes sure that the repository configuration is absent 104 | * ``'postgresapp'`` (MacOS) uses upstream PostgresApp package repository. 105 | * ``'homebrew'`` (MacOS) uses Homebrew postgres 106 | 107 | The ``postgres:version`` Pillar controls which version of the PostgreSQL packages should be 108 | installed from the upstream Linux repository. Defaults to ``9.5``. 109 | 110 | 111 | Removal states 112 | -------------- 113 | 114 | ``postgres.dropped`` 115 | ^^^^^^^^^^^^^^^^^^^^ 116 | 117 | Meta state to remove Postgres software. By default the release installed by formula is targeted only. To target multiple releases, set pillar ``postgres.remove.multiple_releases: True``. 118 | 119 | ``postgres.server.remove`` 120 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ 121 | 122 | Remove server, lib, and contrib packages. The ``postgres.server.remove`` will retain data by default (no data loss) - set pillar ``postgres.remove.data: True`` to remove data and configuration directories also. 123 | 124 | ``postgres.client.remove`` 125 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ 126 | 127 | Remove client package. 128 | 129 | ``postgres.dev.remove`` 130 | ^^^^^^^^^^^^^^^^^^^^^^^ 131 | 132 | Remove development and python packages. 133 | 134 | 135 | Testing 136 | ------- 137 | 138 | Linux testing is done with ``kitchen-salt``. 139 | 140 | ``kitchen converge`` 141 | ^^^^^^^^^^^^^^^^^^^^ 142 | 143 | Creates the docker instance and runs the ``postgres`` main state, ready for testing. 144 | 145 | ``kitchen verify`` 146 | ^^^^^^^^^^^^^^^^^^ 147 | 148 | Runs the ``inspec`` tests on the actual instance. 149 | 150 | ``kitchen destroy`` 151 | ^^^^^^^^^^^^^^^^^^^ 152 | 153 | Removes the docker instance. 154 | 155 | ``kitchen test`` 156 | ^^^^^^^^^^^^^^^^ 157 | 158 | Runs all of the stages above in one go: i.e. ``destroy`` + ``converge`` + ``verify`` + ``destroy``. 159 | 160 | ``kitchen login`` 161 | ^^^^^^^^^^^^^^^^^ 162 | 163 | Gives you SSH access to the instance for manual testing. 164 | 165 | Testing with Vagrant 166 | -------------------- 167 | 168 | Windows/FreeBSD/OpenBSD testing is done with ``kitchen-salt``. 169 | 170 | Requirements 171 | ^^^^^^^^^^^^ 172 | 173 | * Ruby 174 | * Virtualbox 175 | * Vagrant 176 | 177 | Setup 178 | ^^^^^ 179 | 180 | .. code-block:: bash 181 | 182 | $ gem install bundler 183 | $ bundle install --with=vagrant 184 | $ bin/kitchen test [platform] 185 | 186 | Where ``[platform]`` is the platform name defined in ``kitchen.vagrant.yml``, 187 | e.g. ``windows-81-latest-py3``. 188 | 189 | Note 190 | ^^^^ 191 | 192 | When testing using Vagrant you must set the environment variable ``KITCHEN_LOCAL_YAML`` to ``kitchen.vagrant.yml``. For example: 193 | 194 | .. code-block:: bash 195 | 196 | $ KITCHEN_LOCAL_YAML=kitchen.vagrant.yml bin/kitchen test # Alternatively, 197 | $ export KITCHEN_LOCAL_YAML=kitchen.vagrant.yml 198 | $ bin/kitchen test 199 | 200 | Then run the following commands as needed. 201 | 202 | ``bin/kitchen converge`` 203 | ^^^^^^^^^^^^^^^^^^^^^^^^ 204 | 205 | Creates the Vagrant instance and runs the ``postgres`` main state, ready for testing. 206 | 207 | ``bin/kitchen verify`` 208 | ^^^^^^^^^^^^^^^^^^^^^^ 209 | 210 | Runs the ``inspec`` tests on the actual instance. 211 | 212 | ``bin/kitchen destroy`` 213 | ^^^^^^^^^^^^^^^^^^^^^^^ 214 | 215 | Removes the Vagrant instance. 216 | 217 | ``bin/kitchen test`` 218 | ^^^^^^^^^^^^^^^^^^^^ 219 | 220 | Runs all of the stages above in one go: i.e. ``destroy`` + ``converge`` + ``verify`` + ``destroy``. 221 | 222 | ``bin/kitchen login`` 223 | ^^^^^^^^^^^^^^^^^^^^^ 224 | 225 | Gives you RDP/SSH access to the instance for manual testing. 226 | 227 | .. vim: fenc=utf-8 spell spl=en cc=100 tw=99 fo=want sts=2 sw=2 et 228 | -------------------------------------------------------------------------------- /docs/TOFS_pattern.rst: -------------------------------------------------------------------------------- 1 | .. _tofs_pattern: 2 | 3 | TOFS: A pattern for using SaltStack 4 | =================================== 5 | 6 | .. list-table:: 7 | :name: tofs-authors 8 | :header-rows: 1 9 | :stub-columns: 1 10 | :widths: 2,2,3,2 11 | 12 | * - 13 | - Person 14 | - Contact 15 | - Date 16 | * - Authored by 17 | - Roberto Moreda 18 | - moreda@allenta.com 19 | - 29/12/2014 20 | * - Modified by 21 | - Daniel Dehennin 22 | - daniel.dehennin@baby-gnu.org 23 | - 07/02/2019 24 | * - Modified by 25 | - Imran Iqbal 26 | - https://github.com/myii 27 | - 23/02/2019 28 | 29 | All that follows is a proposal based on my experience with `SaltStack `_. The good thing of a piece of software like this is that you can "bend it" to suit your needs in many possible ways, and this is one of them. All the recommendations and thoughts are given "as it is" with no warranty of any type. 30 | 31 | .. contents:: **Table of Contents** 32 | 33 | Usage of values in pillar vs templates in ``file_roots`` 34 | -------------------------------------------------------- 35 | 36 | Among other functions, the *master* (or *salt-master*) serves files to the *minions* (or *salt-minions*). The `file_roots `_ is the list of directories used in sequence to find a file when a minion requires it: the first match is served to the minion. Those files could be `state files `_ or configuration templates, among others. 37 | 38 | Using SaltStack is a simple and effective way to implement configuration management, but even in a `non-multitenant `_ scenario, it is not a good idea to generally access some data (e.g. the database password in our `Zabbix `_ server configuration file or the private key of our `Nginx `_ TLS certificate). 39 | 40 | To avoid this situation we can use the `pillar mechanism `_, which is designed to provide controlled access to data from the minions based on some selection rules. As pillar data could be easily integrated in the `Jinja `_ templates, it is a good mechanism to store values to be used in the final rendering of state files and templates. 41 | 42 | There are a variety of approaches on the usage of pillar and templates as seen in the `saltstack-formulas `_' repositories. `Some `_ `developments `_ stress the initial purpose of pillar data into a storage for most of the possible variables for a determined system configuration. This, in my opinion, is shifting too much load from the original template files approach. Adding up some `non-trivial Jinja `_ code as essential part of composing the state file definitely makes SaltStack state files (hence formulas) more difficult to read. The extreme of this approach is that we could end up with a new render mechanism, implemented in Jinja, storing everything needed in pillar data to compose configurations. Additionally, we are establishing a strong dependency with the Jinja renderer. 43 | 44 | In opposition to the *put the code in file_roots and the data in pillars* approach, there is the *pillar as a store for a set of key-values* approach. A full-blown configuration file abstracted in pillar and jinja is complicated to develop, understand and maintain. I think a better and simpler approach is to keep a configuration file templated using just a basic (non-extensive but extensible) set of pillar values. 45 | 46 | On the reusability of SaltStack state files 47 | ------------------------------------------- 48 | 49 | There is a brilliant initiative of the SaltStack community called `salt-formulas `_. Their goal is to provide state files, pillar examples and configuration templates ready to be used for provisioning. I am a contributor for two small ones: `zabbix-formula `_ and `varnish-formula `_. 50 | 51 | The `design guidelines `_ for formulas are clear in many aspects and it is a recommended reading for anyone willing to write state files, even non-formulaic ones. 52 | 53 | In the next section, I am going to describe my proposal to extend further the reusability of formulas, suggesting some patterns of usage. 54 | 55 | The Template Override and Files Switch (TOFS) pattern 56 | ----------------------------------------------------- 57 | 58 | I understand a formula as a **complete, independent set of SaltStack state and configuration template files sufficient to configure a system**. A system could be something as simple as an NTP server or some other much more complex service that requires many state and configuration template files. 59 | 60 | The customization of a formula should be done mainly by providing pillar data used later to render either the state or the configuration template files. 61 | 62 | Example: NTP before applying TOFS 63 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 64 | 65 | Let's work with the NTP example. A basic formula that follows the `design guidelines `_ has the following files and directories tree: 66 | 67 | .. code-block:: console 68 | 69 | /srv/saltstack/salt-formulas/ntp-saltstack-formula/ 70 | ntp/ 71 | map.jinja 72 | init.sls 73 | conf.sls 74 | files/ 75 | default/ 76 | etc/ 77 | ntp.conf.jinja 78 | 79 | In order to use it, let's assume a `masterless configuration `_ and this relevant section of ``/etc/salt/minion``: 80 | 81 | .. code-block:: yaml 82 | 83 | pillar_roots: 84 | base: 85 | - /srv/saltstack/pillar 86 | file_client: local 87 | file_roots: 88 | base: 89 | - /srv/saltstack/salt 90 | - /srv/saltstack/salt-formulas/ntp-saltstack-formula 91 | 92 | .. code-block:: jinja 93 | 94 | {#- /srv/saltstack/salt-formulas/ntp-saltstack-formula/ntp/map.jinja #} 95 | {%- set ntp = salt['grains.filter_by']({ 96 | 'default': { 97 | 'pkg': 'ntp', 98 | 'service': 'ntp', 99 | 'config': '/etc/ntp.conf', 100 | }, 101 | }, merge=salt['pillar.get']('ntp:lookup')) %} 102 | 103 | In ``init.sls`` we have the minimal states required to have NTP configured. In many cases ``init.sls`` is almost equivalent to an ``apt-get install`` or a ``yum install`` of the package. 104 | 105 | .. code-block:: sls 106 | 107 | ## /srv/saltstack/salt-formulas/ntp-saltstack-formula/ntp/init.sls 108 | {%- from 'ntp/map.jinja' import ntp with context %} 109 | 110 | Install NTP: 111 | pkg.installed: 112 | - name: {{ ntp.pkg }} 113 | 114 | Enable and start NTP: 115 | service.running: 116 | - name: {{ ntp.service }} 117 | - enabled: True 118 | - require: 119 | - pkg: Install NTP package 120 | 121 | In ``conf.sls`` we have the configuration states. In most cases, that is just managing configuration file templates and making them to be watched by the service. 122 | 123 | .. code-block:: sls 124 | 125 | ## /srv/saltstack/salt-formulas/ntp-saltstack-formula/ntp/conf.sls 126 | include: 127 | - ntp 128 | 129 | {%- from 'ntp/map.jinja' import ntp with context %} 130 | 131 | Configure NTP: 132 | file.managed: 133 | - name: {{ ntp.config }} 134 | - template: jinja 135 | - source: salt://ntp/files/default/etc/ntp.conf.jinja 136 | - watch_in: 137 | - service: Enable and start NTP service 138 | - require: 139 | - pkg: Install NTP package 140 | 141 | Under ``files/default``, there is a structure that mimics the one in the minion in order to avoid clashes and confusion on where to put the needed templates. There you can find a mostly standard template for the configuration file. 142 | 143 | .. code-block:: jinja 144 | 145 | {#- /srv/saltstack/salt-formulas/ntp-saltstack-formula/ntp/files/default/etc/ntp.conf.jinja #} 146 | {#- Managed by saltstack #} 147 | {#- Edit pillars or override this template in saltstack if you need customization #} 148 | {%- set settings = salt['pillar.get']('ntp', {}) %} 149 | {%- set default_servers = ['0.ubuntu.pool.ntp.org', 150 | '1.ubuntu.pool.ntp.org', 151 | '2.ubuntu.pool.ntp.org', 152 | '3.ubuntu.pool.ntp.org'] %} 153 | 154 | driftfile /var/lib/ntp/ntp.drift 155 | statistics loopstats peerstats clockstats 156 | filegen loopstats file loopstats type day enable 157 | filegen peerstats file peerstats type day enable 158 | filegen clockstats file clockstats type day enable 159 | 160 | {%- for server in settings.get('servers', default_servers) %} 161 | server {{ server }} 162 | {%- endfor %} 163 | 164 | restrict -4 default kod notrap nomodify nopeer noquery 165 | restrict -6 default kod notrap nomodify nopeer noquery 166 | 167 | restrict 127.0.0.1 168 | restrict ::1 169 | 170 | With all this, it is easy to install and configure a simple NTP server by just running ``salt-call state.sls ntp.conf``: the package will be installed, the service will be running and the configuration should be correct for most of cases, even without pillar data. 171 | 172 | Alternatively, you can define a highstate in ``/srv/saltstack/salt/top.sls`` and run ``salt-call state.highstate``. 173 | 174 | .. code-block:: sls 175 | 176 | ## /srv/saltstack/salt/top.sls 177 | base: 178 | '*': 179 | - ntp.conf 180 | 181 | **Customizing the formula just with pillar data**, we have the option to define the NTP servers. 182 | 183 | .. code-block:: sls 184 | 185 | ## /srv/saltstack/pillar/top.sls 186 | base: 187 | '*': 188 | - ntp 189 | 190 | .. code-block:: sls 191 | 192 | ## /srv/saltstack/pillar/ntp.sls 193 | ntp: 194 | servers: 195 | - 0.ch.pool.ntp.org 196 | - 1.ch.pool.ntp.org 197 | - 2.ch.pool.ntp.org 198 | - 3.ch.pool.ntp.org 199 | 200 | Template Override 201 | ^^^^^^^^^^^^^^^^^ 202 | 203 | If the customization based on pillar data is not enough, we can override the template by creating a new one in ``/srv/saltstack/salt/ntp/files/default/etc/ntp.conf.jinja`` 204 | 205 | .. code-block:: jinja 206 | 207 | {#- /srv/saltstack/salt/ntp/files/default/etc/ntp.conf.jinja #} 208 | {#- Managed by saltstack #} 209 | {#- Edit pillars or override this template in saltstack if you need customization #} 210 | 211 | {#- Some bizarre configurations here #} 212 | {#- ... #} 213 | 214 | {%- for server in settings.get('servers', default_servers) %} 215 | server {{ server }} 216 | {%- endfor %} 217 | 218 | This way we are locally **overriding the template files** offered by the formula in order to make a more complex adaptation. Of course, this could be applied as well to any of the files, including the state files. 219 | 220 | Files Switch 221 | ^^^^^^^^^^^^ 222 | 223 | To bring some order into the set of template files included in a formula, as we commented, we suggest having a similar structure to a normal final file system under ``files/default``. 224 | 225 | We can make different templates coexist for different minions, classified by any `grain `_ value, by simply creating new directories under ``files``. This mechanism is based on **using values of some grains as a switch for the directories under** ``files/``. 226 | 227 | If we decide that we want ``os_family`` as switch, then we could provide the formula template variants for both the ``RedHat`` and ``Debian`` families. 228 | 229 | .. code-block:: console 230 | 231 | /srv/saltstack/salt-formulas/ntp-saltstack-formula/ntp/files/ 232 | default/ 233 | etc/ 234 | ntp.conf.jinja 235 | RedHat/ 236 | etc/ 237 | ntp.conf.jinja 238 | Debian/ 239 | etc/ 240 | ntp.conf.jinja 241 | 242 | To make this work we need a ``conf.sls`` state file that takes a list of possible files as the configuration template. 243 | 244 | .. code-block:: sls 245 | 246 | ## /srv/saltstack/salt-formulas/ntp-saltstack-formula/ntp/conf.sls 247 | include: 248 | - ntp 249 | 250 | {%- from 'ntp/map.jinja' import ntp with context %} 251 | 252 | Configure NTP: 253 | file.managed: 254 | - name: {{ ntp.config }} 255 | - template: jinja 256 | - source: 257 | - salt://ntp/files/{{ grains.get('os_family', 'default') }}/etc/ntp.conf.jinja 258 | - salt://ntp/files/default/etc/ntp.conf.jinja 259 | - watch_in: 260 | - service: Enable and start NTP service 261 | - require: 262 | - pkg: Install NTP package 263 | 264 | If we want to cover the possibility of a special template for a minion identified by ``node01`` then we could have a specific template in ``/srv/saltstack/salt/ntp/files/node01/etc/ntp.conf.jinja``. 265 | 266 | .. code-block:: jinja 267 | 268 | {#- /srv/saltstack/salt/ntp/files/node01/etc/ntp.conf.jinja #} 269 | {#- Managed by saltstack #} 270 | {#- Edit pillars or override this template in saltstack if you need customization #} 271 | 272 | {#- Some crazy configurations here for node01 #} 273 | {#- ... #} 274 | 275 | To make this work we could write a specially crafted ``conf.sls``. 276 | 277 | .. code-block:: sls 278 | 279 | ## /srv/saltstack/salt-formulas/ntp-saltstack-formula/ntp/conf.sls 280 | include: 281 | - ntp 282 | 283 | {%- from 'ntp/map.jinja' import ntp with context %} 284 | 285 | Configure NTP: 286 | file.managed: 287 | - name: {{ ntp.config }} 288 | - template: jinja 289 | - source: 290 | - salt://ntp/files/{{ grains.get('id') }}/etc/ntp.conf.jinja 291 | - salt://ntp/files/{{ grains.get('os_family') }}/etc/ntp.conf.jinja 292 | - salt://ntp/files/default/etc/ntp.conf.jinja 293 | - watch_in: 294 | - service: Enable and start NTP service 295 | - require: 296 | - pkg: Install NTP package 297 | 298 | Using the ``files_switch`` macro 299 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 300 | 301 | We can simplify the ``conf.sls`` with the new ``files_switch`` macro to use in the ``source`` parameter for the ``file.managed`` state. 302 | 303 | .. code-block:: sls 304 | 305 | ## /srv/saltstack/salt-formulas/ntp-saltstack-formula/ntp/conf.sls 306 | include: 307 | - ntp 308 | 309 | {%- set tplroot = tpldir.split('/')[0] %} 310 | {%- from 'ntp/map.jinja' import ntp with context %} 311 | {%- from 'ntp/libtofs.jinja' import files_switch %} 312 | 313 | Configure NTP: 314 | file.managed: 315 | - name: {{ ntp.config }} 316 | - template: jinja 317 | - source: {{ files_switch(['/etc/ntp.conf.jinja'], 318 | lookup='Configure NTP' 319 | ) 320 | }} 321 | - watch_in: 322 | - service: Enable and start NTP service 323 | - require: 324 | - pkg: Install NTP package 325 | 326 | 327 | * This uses ``config.get``, searching for ``ntp:tofs:source_files:Configure NTP`` to determine the list of template files to use. 328 | * If this returns a result, the default of ``['/etc/ntp.conf.jinja']`` will be appended to it. 329 | * If this does not yield any results, the default of ``['/etc/ntp.conf.jinja']`` will be used. 330 | 331 | In ``libtofs.jinja``, we define this new macro ``files_switch``. 332 | 333 | .. literalinclude:: ../template/libtofs.jinja 334 | :caption: /srv/saltstack/salt-formulas/ntp-saltstack-formula/ntp/libtofs.jinja 335 | :language: jinja 336 | 337 | How to customise the ``source`` further 338 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 339 | 340 | The examples below are based on an ``Ubuntu`` minion called ``theminion`` being configured via. pillar. 341 | 342 | Using the default settings of the ``files_switch`` macro above, 343 | the ``source`` will be: 344 | 345 | .. code-block:: sls 346 | 347 | - source: 348 | - salt://ntp/files/theminion/etc/ntp.conf.jinja 349 | - salt://ntp/files/Debian/etc/ntp.conf.jinja 350 | - salt://ntp/files/default/etc/ntp.conf.jinja 351 | 352 | Customise ``files`` 353 | ~~~~~~~~~~~~~~~~~~~ 354 | 355 | The ``files`` portion can be customised: 356 | 357 | .. code-block:: sls 358 | 359 | ntp: 360 | tofs: 361 | dirs: 362 | files: files_alt 363 | 364 | Resulting in: 365 | 366 | .. code-block:: sls 367 | 368 | - source: 369 | - salt://ntp/files_alt/theminion/etc/ntp.conf.jinja 370 | - salt://ntp/files_alt/Debian/etc/ntp.conf.jinja 371 | - salt://ntp/files_alt/default/etc/ntp.conf.jinja 372 | 373 | Customise the use of grains 374 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 375 | 376 | Grains can be customised and even arbitrary paths can be supplied: 377 | 378 | .. code-block:: sls 379 | 380 | ntp: 381 | tofs: 382 | files_switch: 383 | - any/path/can/be/used/here 384 | - id 385 | - os 386 | - os_family 387 | 388 | Resulting in: 389 | 390 | .. code-block:: sls 391 | 392 | - source: 393 | - salt://ntp/files/any/path/can/be/used/here/etc/ntp.conf.jinja 394 | - salt://ntp/files/theminion/etc/ntp.conf.jinja 395 | - salt://ntp/files/Ubuntu/etc/ntp.conf.jinja 396 | - salt://ntp/files/Debian/etc/ntp.conf.jinja 397 | - salt://ntp/files/default/etc/ntp.conf.jinja 398 | 399 | Customise the ``default`` path 400 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 401 | 402 | The ``default`` portion of the path can be customised: 403 | 404 | .. code-block:: sls 405 | 406 | ntp: 407 | tofs: 408 | dirs: 409 | default: default_alt 410 | 411 | Resulting in: 412 | 413 | .. code-block:: sls 414 | 415 | - source: 416 | ... 417 | - salt://ntp/files/default_alt/etc/ntp.conf.jinja 418 | 419 | Customise the list of ``source_files`` 420 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 421 | 422 | The list of ``source_files`` can be given: 423 | 424 | .. code-block:: sls 425 | 426 | ntp: 427 | tofs: 428 | source_files: 429 | Configure NTP: 430 | - '/etc/ntp.conf_alt.jinja' 431 | 432 | Resulting in: 433 | 434 | .. code-block:: sls 435 | 436 | - source: 437 | - salt://ntp/files/theminion/etc/ntp.conf_alt.jinja 438 | - salt://ntp/files/theminion/etc/ntp.conf.jinja 439 | - salt://ntp/files/Debian/etc/ntp.conf_alt.jinja 440 | - salt://ntp/files/Debian/etc/ntp.conf.jinja 441 | - salt://ntp/files/default/etc/ntp.conf_alt.jinja 442 | - salt://ntp/files/default/etc/ntp.conf.jinja 443 | 444 | Note: This does *not* override the default value. 445 | Rather, the value from the pillar/config is prepended to the default. 446 | 447 | Using sub-directories for ``components`` 448 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 449 | 450 | If your formula is composed of several components, you may prefer to provides files under sub-directories, like in the `systemd-formula `_. 451 | 452 | .. code-block:: console 453 | 454 | /srv/saltstack/systemd-formula/ 455 | systemd/ 456 | init.sls 457 | libtofs.jinja 458 | map.jinja 459 | networkd/ 460 | init.sls 461 | files/ 462 | default/ 463 | network/ 464 | 99-default.link 465 | resolved/ 466 | init.sls 467 | files/ 468 | default/ 469 | resolved.conf 470 | timesyncd/ 471 | init.sls 472 | files/ 473 | Arch/ 474 | resolved.conf 475 | Debian/ 476 | resolved.conf 477 | default/ 478 | resolved.conf 479 | Ubuntu/ 480 | resolved.conf 481 | 482 | For example, the following ``formula.component.config`` SLS: 483 | 484 | .. code-block:: sls 485 | 486 | {%- from "formula/libtofs.jinja" import files_switch with context %} 487 | 488 | formula configuration file: 489 | file.managed: 490 | - name: /etc/formula.conf 491 | - user: root 492 | - group: root 493 | - mode: 644 494 | - template: jinja 495 | - source: {{ files_switch(['formula.conf'], 496 | lookup='formula', 497 | use_subpath=True 498 | ) 499 | }} 500 | 501 | will be rendered on a ``Debian`` minion named ``salt-formula.ci.local`` as: 502 | 503 | .. code-block:: sls 504 | 505 | formula configuration file: 506 | file.managed: 507 | - name: /etc/formula.conf 508 | - user: root 509 | - group: root 510 | - mode: 644 511 | - template: jinja 512 | - source: 513 | - salt://formula/component/files/salt-formula.ci.local/formula.conf 514 | - salt://formula/component/files/Debian/formula.conf 515 | - salt://formula/component/files/default/formula.conf 516 | - salt://formula/files/salt-formula.ci.local/formula.conf 517 | - salt://formula/files/Debian/formula.conf 518 | - salt://formula/files/default/formula.conf 519 | -------------------------------------------------------------------------------- /kitchen.vagrant.yml: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # vim: ft=yaml 3 | --- 4 | driver: 5 | name: vagrant 6 | cache_directory: false 7 | customize: 8 | usbxhci: 'off' 9 | gui: false 10 | ssh: 11 | shell: /bin/sh 12 | linked_clone: true 13 | <% unless ENV['CI'] %> 14 | synced_folders: 15 | - - '.kitchen/kitchen-vagrant/%{instance_name}/vagrant' 16 | - '/vagrant' 17 | - 'create: true, disabled: false' 18 | <% end %> 19 | 20 | platforms: 21 | - name: freebsd-130-master-py3 22 | driver: 23 | box: myii/freebsd-13.0-master-py3 24 | - name: freebsd-123-master-py3 25 | driver: 26 | box: myii/freebsd-12.3-master-py3 27 | - name: freebsd-130-3004-0-py3 28 | driver: 29 | box: myii/freebsd-13.0-3004.0-py3 30 | - name: freebsd-123-3004-0-py3 31 | driver: 32 | box: myii/freebsd-12.3-3004.0-py3 33 | -------------------------------------------------------------------------------- /kitchen.yml: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # vim: ft=yaml 3 | --- 4 | # For help on this file's format, see https://kitchen.ci/ 5 | driver: 6 | name: docker 7 | use_sudo: false 8 | privileged: true 9 | run_command: /usr/lib/systemd/systemd 10 | 11 | provisioner: 12 | name: salt_solo 13 | log_level: debug 14 | salt_install: none 15 | require_chef: false 16 | formula: postgres 17 | salt_copy_filter: 18 | - .kitchen 19 | - .git 20 | 21 | platforms: 22 | ## SALT `tiamat` 23 | - name: debian-11-tiamat-py3 24 | driver: 25 | image: saltimages/salt-tiamat-py3:debian-11 26 | run_command: /lib/systemd/systemd 27 | - name: debian-10-tiamat-py3 28 | driver: 29 | image: saltimages/salt-tiamat-py3:debian-10 30 | run_command: /lib/systemd/systemd 31 | - name: debian-9-tiamat-py3 32 | driver: 33 | image: saltimages/salt-tiamat-py3:debian-9 34 | run_command: /lib/systemd/systemd 35 | - name: ubuntu-2204-tiamat-py3 36 | driver: 37 | image: saltimages/salt-tiamat-py3:ubuntu-22.04 38 | run_command: /lib/systemd/systemd 39 | - name: ubuntu-2004-tiamat-py3 40 | driver: 41 | image: saltimages/salt-tiamat-py3:ubuntu-20.04 42 | run_command: /lib/systemd/systemd 43 | - name: ubuntu-1804-tiamat-py3 44 | driver: 45 | image: saltimages/salt-tiamat-py3:ubuntu-18.04 46 | run_command: /lib/systemd/systemd 47 | - name: centos-stream8-tiamat-py3 48 | driver: 49 | image: saltimages/salt-tiamat-py3:centos-stream8 50 | - name: centos-7-tiamat-py3 51 | driver: 52 | image: saltimages/salt-tiamat-py3:centos-7 53 | - name: amazonlinux-2-tiamat-py3 54 | driver: 55 | image: saltimages/salt-tiamat-py3:amazonlinux-2 56 | - name: oraclelinux-8-tiamat-py3 57 | driver: 58 | image: saltimages/salt-tiamat-py3:oraclelinux-8 59 | - name: oraclelinux-7-tiamat-py3 60 | driver: 61 | image: saltimages/salt-tiamat-py3:oraclelinux-7 62 | - name: almalinux-8-tiamat-py3 63 | driver: 64 | image: saltimages/salt-tiamat-py3:almalinux-8 65 | - name: rockylinux-8-tiamat-py3 66 | driver: 67 | image: saltimages/salt-tiamat-py3:rockylinux-8 68 | 69 | ## SALT `master` 70 | - name: debian-11-master-py3 71 | driver: 72 | image: saltimages/salt-master-py3:debian-11 73 | run_command: /lib/systemd/systemd 74 | - name: debian-10-master-py3 75 | driver: 76 | image: saltimages/salt-master-py3:debian-10 77 | run_command: /lib/systemd/systemd 78 | - name: debian-9-master-py3 79 | driver: 80 | image: saltimages/salt-master-py3:debian-9 81 | run_command: /lib/systemd/systemd 82 | - name: ubuntu-2204-master-py3 83 | driver: 84 | image: saltimages/salt-master-py3:ubuntu-22.04 85 | run_command: /lib/systemd/systemd 86 | - name: ubuntu-2004-master-py3 87 | driver: 88 | image: saltimages/salt-master-py3:ubuntu-20.04 89 | run_command: /lib/systemd/systemd 90 | - name: ubuntu-1804-master-py3 91 | driver: 92 | image: saltimages/salt-master-py3:ubuntu-18.04 93 | run_command: /lib/systemd/systemd 94 | - name: centos-stream8-master-py3 95 | driver: 96 | image: saltimages/salt-master-py3:centos-stream8 97 | - name: centos-7-master-py3 98 | driver: 99 | image: saltimages/salt-master-py3:centos-7 100 | - name: fedora-36-master-py3 101 | driver: 102 | image: saltimages/salt-master-py3:fedora-36 103 | - name: fedora-35-master-py3 104 | driver: 105 | image: saltimages/salt-master-py3:fedora-35 106 | - name: opensuse-leap-153-master-py3 107 | driver: 108 | image: saltimages/salt-master-py3:opensuse-leap-15.3 109 | # Workaround to avoid intermittent failures on `opensuse-leap-15.3`: 110 | # => SCP did not finish successfully (255): (Net::SCP::Error) 111 | transport: 112 | max_ssh_sessions: 1 113 | - name: opensuse-tmbl-latest-master-py3 114 | driver: 115 | image: saltimages/salt-master-py3:opensuse-tumbleweed-latest 116 | # Workaround to avoid intermittent failures on `opensuse-tumbleweed`: 117 | # => SCP did not finish successfully (255): (Net::SCP::Error) 118 | transport: 119 | max_ssh_sessions: 1 120 | - name: amazonlinux-2-master-py3 121 | driver: 122 | image: saltimages/salt-master-py3:amazonlinux-2 123 | - name: oraclelinux-8-master-py3 124 | driver: 125 | image: saltimages/salt-master-py3:oraclelinux-8 126 | - name: oraclelinux-7-master-py3 127 | driver: 128 | image: saltimages/salt-master-py3:oraclelinux-7 129 | - name: arch-base-latest-master-py3 130 | driver: 131 | image: saltimages/salt-master-py3:arch-base-latest 132 | - name: gentoo-stage3-latest-master-py3 133 | driver: 134 | image: saltimages/salt-master-py3:gentoo-stage3-latest 135 | run_command: /sbin/init 136 | - name: gentoo-stage3-systemd-master-py3 137 | driver: 138 | image: saltimages/salt-master-py3:gentoo-stage3-systemd 139 | - name: almalinux-8-master-py3 140 | driver: 141 | image: saltimages/salt-master-py3:almalinux-8 142 | - name: rockylinux-8-master-py3 143 | driver: 144 | image: saltimages/salt-master-py3:rockylinux-8 145 | 146 | ## SALT `3004.1` 147 | - name: debian-11-3004-1-py3 148 | driver: 149 | image: saltimages/salt-3004.1-py3:debian-11 150 | run_command: /lib/systemd/systemd 151 | - name: debian-10-3004-1-py3 152 | driver: 153 | image: saltimages/salt-3004.1-py3:debian-10 154 | run_command: /lib/systemd/systemd 155 | - name: debian-9-3004-1-py3 156 | driver: 157 | image: saltimages/salt-3004.1-py3:debian-9 158 | run_command: /lib/systemd/systemd 159 | - name: ubuntu-2204-3004-1-py3 160 | driver: 161 | image: saltimages/salt-3004.1-py3:ubuntu-22.04 162 | run_command: /lib/systemd/systemd 163 | - name: ubuntu-2004-3004-1-py3 164 | driver: 165 | image: saltimages/salt-3004.1-py3:ubuntu-20.04 166 | run_command: /lib/systemd/systemd 167 | - name: ubuntu-1804-3004-1-py3 168 | driver: 169 | image: saltimages/salt-3004.1-py3:ubuntu-18.04 170 | run_command: /lib/systemd/systemd 171 | - name: centos-stream8-3004-1-py3 172 | driver: 173 | image: saltimages/salt-3004.1-py3:centos-stream8 174 | - name: centos-7-3004-1-py3 175 | driver: 176 | image: saltimages/salt-3004.1-py3:centos-7 177 | - name: fedora-36-3004-1-py3 178 | driver: 179 | image: saltimages/salt-3004.1-py3:fedora-36 180 | - name: fedora-35-3004-1-py3 181 | driver: 182 | image: saltimages/salt-3004.1-py3:fedora-35 183 | - name: amazonlinux-2-3004-1-py3 184 | driver: 185 | image: saltimages/salt-3004.1-py3:amazonlinux-2 186 | - name: oraclelinux-8-3004-1-py3 187 | driver: 188 | image: saltimages/salt-3004.1-py3:oraclelinux-8 189 | - name: oraclelinux-7-3004-1-py3 190 | driver: 191 | image: saltimages/salt-3004.1-py3:oraclelinux-7 192 | - name: arch-base-latest-3004-1-py3 193 | driver: 194 | image: saltimages/salt-3004.1-py3:arch-base-latest 195 | - name: gentoo-stage3-latest-3004-1-py3 196 | driver: 197 | image: saltimages/salt-3004.1-py3:gentoo-stage3-latest 198 | run_command: /sbin/init 199 | - name: gentoo-stage3-systemd-3004-1-py3 200 | driver: 201 | image: saltimages/salt-3004.1-py3:gentoo-stage3-systemd 202 | - name: almalinux-8-3004-1-py3 203 | driver: 204 | image: saltimages/salt-3004.1-py3:almalinux-8 205 | - name: rockylinux-8-3004-1-py3 206 | driver: 207 | image: saltimages/salt-3004.1-py3:rockylinux-8 208 | 209 | ## SALT `3004.0` 210 | - name: opensuse-leap-153-3004-0-py3 211 | driver: 212 | image: saltimages/salt-3004.0-py3:opensuse-leap-15.3 213 | # Workaround to avoid intermittent failures on `opensuse-leap-15.3`: 214 | # => SCP did not finish successfully (255): (Net::SCP::Error) 215 | transport: 216 | max_ssh_sessions: 1 217 | - name: opensuse-tmbl-latest-3004-0-py3 218 | driver: 219 | image: saltimages/salt-3004.0-py3:opensuse-tumbleweed-latest 220 | # Workaround to avoid intermittent failures on `opensuse-tumbleweed`: 221 | # => SCP did not finish successfully (255): (Net::SCP::Error) 222 | transport: 223 | max_ssh_sessions: 1 224 | 225 | ## SALT `3003.4` 226 | - name: debian-10-3003-4-py3 227 | driver: 228 | image: saltimages/salt-3003.4-py3:debian-10 229 | run_command: /lib/systemd/systemd 230 | - name: debian-9-3003-4-py3 231 | driver: 232 | image: saltimages/salt-3003.4-py3:debian-9 233 | run_command: /lib/systemd/systemd 234 | - name: ubuntu-2004-3003-4-py3 235 | driver: 236 | image: saltimages/salt-3003.4-py3:ubuntu-20.04 237 | run_command: /lib/systemd/systemd 238 | - name: ubuntu-1804-3003-4-py3 239 | driver: 240 | image: saltimages/salt-3003.4-py3:ubuntu-18.04 241 | run_command: /lib/systemd/systemd 242 | - name: centos-stream8-3003-4-py3 243 | driver: 244 | image: saltimages/salt-3003.4-py3:centos-stream8 245 | - name: centos-7-3003-4-py3 246 | driver: 247 | image: saltimages/salt-3003.4-py3:centos-7 248 | - name: amazonlinux-2-3003-4-py3 249 | driver: 250 | image: saltimages/salt-3003.4-py3:amazonlinux-2 251 | - name: oraclelinux-8-3003-4-py3 252 | driver: 253 | image: saltimages/salt-3003.4-py3:oraclelinux-8 254 | - name: oraclelinux-7-3003-4-py3 255 | driver: 256 | image: saltimages/salt-3003.4-py3:oraclelinux-7 257 | - name: almalinux-8-3003-4-py3 258 | driver: 259 | image: saltimages/salt-3003.4-py3:almalinux-8 260 | 261 | verifier: 262 | # https://www.inspec.io/ 263 | name: inspec 264 | sudo: true 265 | reporter: 266 | # cli, documentation, html, progress, json, json-min, json-rspec, junit 267 | - cli 268 | 269 | suites: 270 | - name: default 271 | provisioner: 272 | state_top: 273 | base: 274 | '*': 275 | - postgres._mapdata 276 | - postgres 277 | pillars: 278 | top.sls: 279 | base: 280 | '*': 281 | - postgres 282 | pillars_from_files: 283 | postgres.sls: test/salt/pillar/postgres.sls 284 | verifier: 285 | inspec_tests: 286 | - path: test/integration/default 287 | - name: repo 288 | includes: 289 | - debian-11-tiamat-py3 290 | - debian-10-tiamat-py3 291 | - debian-9-tiamat-py3 292 | - ubuntu-2204-tiamat-py3 293 | - ubuntu-2004-tiamat-py3 294 | - ubuntu-1804-tiamat-py3 295 | - centos-stream8-tiamat-py3 296 | - centos-7-tiamat-py3 297 | - amazonlinux-2-tiamat-py3 298 | - oraclelinux-8-tiamat-py3 299 | - oraclelinux-7-tiamat-py3 300 | - almalinux-8-tiamat-py3 301 | - rockylinux-8-tiamat-py3 302 | - debian-11-master-py3 303 | - debian-10-master-py3 304 | - debian-9-master-py3 305 | - ubuntu-2204-master-py3 306 | - ubuntu-2004-master-py3 307 | - ubuntu-1804-master-py3 308 | - centos-stream8-master-py3 309 | - centos-7-master-py3 310 | - fedora-36-master-py3 311 | - fedora-35-master-py3 312 | - opensuse-leap-153-master-py3 313 | - amazonlinux-2-master-py3 314 | - oraclelinux-8-master-py3 315 | - oraclelinux-7-master-py3 316 | - almalinux-8-master-py3 317 | - rockylinux-8-master-py3 318 | - debian-11-3004-1-py3 319 | - debian-10-3004-1-py3 320 | - debian-9-3004-1-py3 321 | - ubuntu-2204-3004-1-py3 322 | - ubuntu-2004-3004-1-py3 323 | - ubuntu-1804-3004-1-py3 324 | - centos-stream8-3004-1-py3 325 | - centos-7-3004-1-py3 326 | - fedora-36-3004-1-py3 327 | - fedora-35-3004-1-py3 328 | - amazonlinux-2-3004-1-py3 329 | - oraclelinux-8-3004-1-py3 330 | - oraclelinux-7-3004-1-py3 331 | - almalinux-8-3004-1-py3 332 | - rockylinux-8-3004-1-py3 333 | - opensuse-leap-153-3004-0-py3 334 | - debian-10-3003-4-py3 335 | - debian-9-3003-4-py3 336 | - ubuntu-2004-3003-4-py3 337 | - ubuntu-1804-3003-4-py3 338 | - centos-stream8-3003-4-py3 339 | - centos-7-3003-4-py3 340 | - amazonlinux-2-3003-4-py3 341 | - oraclelinux-8-3003-4-py3 342 | - oraclelinux-7-3003-4-py3 343 | - almalinux-8-3003-4-py3 344 | provisioner: 345 | state_top: 346 | base: 347 | '*': 348 | - postgres._mapdata 349 | - postgres 350 | pillars: 351 | top.sls: 352 | base: 353 | '*': 354 | - postgres 355 | - repo 356 | pillars_from_files: 357 | postgres.sls: test/salt/pillar/postgres.sls 358 | repo.sls: test/salt/pillar/repo.sls 359 | verifier: 360 | inspec_tests: 361 | - path: test/integration/repo 362 | -------------------------------------------------------------------------------- /pillar.example: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # vim: ft=yaml 3 | --- 4 | # Port to use for the cluster -- can be used to provide a non-standard port 5 | # NOTE: If already set in the minion config, that value takes priority 6 | postgres.port: '5432' 7 | 8 | postgres: 9 | # UPSTREAM REPO 10 | # Set true to configure upstream postgresql.org repository for YUM/APT/ZYPP 11 | use_upstream_repo: false 12 | # Version to install from upstream repository (if upstream_repo: true) 13 | version: '13' 14 | # Set true to add a file in /etc/profile.d adding the bin dir in $PATH 15 | # as packages from upstream put them somewhere like /usr/pgsql-10/bin 16 | add_profile: false 17 | # If automatic package installation fails, use `fromrepo` to specify the 18 | # upstream repo to install packages from [#133, #185] (if upstream_repo: true) 19 | fromrepo: 'jessie-pgdg' 20 | 21 | ### MACOS 22 | # Set to 'postgresapp' OR 'homebrew' for MacOS 23 | # use_upstream_repo: 'postgresapp' 24 | # use_upstream_repo: 'homebrew' 25 | 26 | # PACKAGE 27 | # These pillars are typically never required. 28 | # pkg: 'postgresql' 29 | # pkg_client: 'postgresql-client' 30 | # service: 31 | # name: 'postgresql' 32 | # flags: -w -s -m fast 33 | # sysrc: true 34 | pkgs_extra: 35 | {%- if grains.os_family not in ('FreeBSD',) %} 36 | - postgresql-contrib 37 | {%- endif %} 38 | - postgresql-plpython 39 | 40 | # CLUSTER 41 | # The default `encoding` is derived from the `locale` so not recommended 42 | # to provide a value for it unless necessary 43 | cluster: 44 | locale: en_US.UTF-8 45 | # encoding: UTF8 46 | 47 | # 'Alternatives system' priority incremental. 0 disables feature. 48 | linux: 49 | altpriority: 30 50 | 51 | # macos limits 52 | limits: 53 | soft: 64000 54 | hard: 128000 55 | 56 | # POSTGRES 57 | # Append the lines under this item to your postgresql.conf file. 58 | # Pay attention to indent exactly with 4 spaces for all lines. 59 | postgresconf: |- 60 | listen_addresses = '*' # listen on all interfaces 61 | 62 | # Path to the `pg_hba.conf` file Jinja template on Salt Fileserver 63 | pg_hba.conf: salt://postgres/templates/pg_hba.conf.j2 64 | 65 | # This section covers ACL management in the ``pg_hba.conf`` file. 66 | # acls list controls: which hosts are allowed to connect, how clients 67 | # are authenticated, which PostgreSQL user names they can use, which 68 | # databases they can access. Records take one of these forms: 69 | # 70 | # acls: 71 | # - ['local', 'DATABASE', 'USER', 'METHOD'] 72 | # - ['host', 'DATABASE', 'USER', 'ADDRESS', 'METHOD'] 73 | # - ['hostssl', 'DATABASE', 'USER', 'ADDRESS', 'METHOD'] 74 | # - ['hostnossl', 'DATABASE', 'USER', 'ADDRESS', 'METHOD'] 75 | # 76 | # The uppercase items must be replaced by actual values. 77 | # METHOD could be omitted, 'md5' will be appended by default. 78 | # 79 | # Postgres expect a valid CIDR for ADDRESS (not ipaddress) 80 | # 81 | # If ``acls`` item value is empty ('', [], null), then the contents of 82 | # ``pg_hba.conf`` file will not be touched at all. 83 | acls: 84 | - ['local', 'db0', 'connuser', 'peer map=users_as_appuser'] 85 | - ['local', 'db1', 'localUser'] 86 | - ['host', 'db2', 'remoteUser', '192.168.33.0/24'] 87 | - ['host', 'all', 'all', '127.0.0.1/32', 'md5'] 88 | 89 | identity_map: 90 | - ['users_as_appuser', 'jdoe', 'connuser'] 91 | - ['users_as_appuser', 'jsmith', 'connuser'] 92 | 93 | # Backup extension for configuration files, defaults to ``.bak``. 94 | # Set ``false`` to stop creation of backups when config files change. 95 | {%- if salt['status.time']|default(none) is callable %} 96 | config_backup: ".backup@{{ salt['status.time']('%y-%m-%d_%H:%M:%S') }}" 97 | {%- endif %} 98 | 99 | {%- if 'init' in grains and grains['init'] == 'unknown' %} 100 | 101 | # If Salt is unable to detect init system running in the scope of state run, 102 | # probably we are trying to bake a container/VM image with PostgreSQL. 103 | # Use ``bake_image`` setting to control how PostgreSQL will be started: if set 104 | # to ``true`` the raw ``pg_ctl`` will be utilized instead of packaged init 105 | # script, job or unit run with Salt ``service`` state. 106 | bake_image: true 107 | 108 | {%- endif %} 109 | 110 | # Create/remove users, tablespaces, databases, schema and extensions. 111 | # Each of these dictionaries contains PostgreSQL entities which 112 | # mapped to the ``postgres_*`` Salt states with arguments. See the Salt 113 | # documentation to get all supported argument for a particular state. 114 | # 115 | # Format is the following: 116 | # 117 | # : 118 | # NAME: 119 | # ensure: # 'present' is the default 120 | # ARGUMENT: VALUE 121 | # ... 122 | # 123 | # where 'NAME' is the state name, 'ARGUMENT' is the kwarg name, and 124 | # 'VALUE' is kwarg value. 125 | # 126 | # For example, the Pillar: 127 | # 128 | # users: 129 | # testUser: 130 | # password: test 131 | # 132 | # will render such state: 133 | # 134 | # postgres_user-testUser: 135 | # postgres_user.present: 136 | # - name: testUser 137 | # - password: test 138 | users: 139 | localUser: 140 | ensure: present 141 | password: '98ruj923h4rf' 142 | createdb: false 143 | createroles: false 144 | inherit: true 145 | replication: false 146 | 147 | remoteUser: 148 | ensure: present 149 | password: '98ruj923h4rf' 150 | createdb: false 151 | createroles: false 152 | inherit: true 153 | replication: false 154 | 155 | absentUser: 156 | ensure: absent 157 | 158 | # tablespaces to be created 159 | tablespaces: 160 | my_space: 161 | directory: /srv/my_tablespace 162 | owner: localUser 163 | 164 | # databases to be created 165 | databases: 166 | db1: 167 | owner: 'localUser' 168 | template: 'template0' 169 | lc_ctype: 'en_US.UTF-8' 170 | lc_collate: 'en_US.UTF-8' 171 | db2: 172 | owner: 'remoteUser' 173 | template: 'template0' 174 | lc_ctype: 'en_US.UTF-8' 175 | lc_collate: 'en_US.UTF-8' 176 | tablespace: 'my_space' 177 | # set custom schema 178 | schemas: 179 | public: 180 | owner: 'localUser' 181 | # enable per-db extension 182 | extensions: 183 | uuid-ossp: 184 | schema: 'public' 185 | 186 | # optional schemas to enable on database 187 | schemas: 188 | uuid-ossp: 189 | dbname: db1 190 | owner: localUser 191 | 192 | # optional extensions to install in schema 193 | extensions: 194 | # postgis: {} 195 | uuid-ossp: 196 | schema: uuid-ossp 197 | maintenance_db: db1 198 | 199 | remove: 200 | data: true 201 | multiple_releases: true 202 | releases: ['9.6', '10'] 203 | 204 | # vim: ft=yaml ts=2 sts=2 sw=2 et 205 | -------------------------------------------------------------------------------- /postgres/_mapdata/_mapdata.jinja: -------------------------------------------------------------------------------- 1 | # yamllint disable rule:indentation rule:line-length 2 | # {{ grains.get("osfinger", grains.os) }} 3 | --- 4 | {#- use salt.slsutil.serialize to avoid encoding errors on some platforms #} 5 | {{ salt["slsutil.serialize"]( 6 | "yaml", 7 | map, 8 | default_flow_style=False, 9 | allow_unicode=True, 10 | ) 11 | | regex_replace("^\s+'$", "'", multiline=True) 12 | | trim 13 | }} 14 | -------------------------------------------------------------------------------- /postgres/_mapdata/init.sls: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # vim: ft=sls 3 | --- 4 | {#- Get the `tplroot` from `tpldir` #} 5 | {%- set tplroot = tpldir.split("/")[0] %} 6 | {%- from tplroot ~ "/map.jinja" import postgres with context %} 7 | 8 | {%- set _mapdata = { 9 | "values": postgres, 10 | } %} 11 | {%- do salt["log.debug"]("### MAP.JINJA DUMP ###\n" ~ _mapdata | yaml(False)) %} 12 | 13 | {%- set output_dir = "/temp" if grains.os_family == "Windows" else "/tmp" %} 14 | {%- set output_file = output_dir ~ "/salt_mapdata_dump.yaml" %} 15 | 16 | {{ tplroot }}-mapdata-dump: 17 | file.managed: 18 | - name: {{ output_file }} 19 | - source: salt://{{ tplroot }}/_mapdata/_mapdata.jinja 20 | - template: jinja 21 | - context: 22 | map: {{ _mapdata | yaml }} 23 | -------------------------------------------------------------------------------- /postgres/client/init.sls: -------------------------------------------------------------------------------- 1 | {%- from salt.file.dirname(tpldir) ~ "/map.jinja" import postgres with context -%} 2 | 3 | {%- set pkgs = [] %} 4 | {%- for pkg in (postgres.pkg_client,) %} 5 | {%- if pkg %} 6 | {%- do pkgs.append(pkg) %} 7 | {%- endif %} 8 | {%- endfor %} 9 | 10 | {%- if postgres.use_upstream_repo == true %} 11 | include: 12 | - postgres.upstream 13 | {%- endif %} 14 | 15 | # Install PostgreSQL client and libraries 16 | postgresql-client-libs: 17 | pkg.installed: 18 | - pkgs: {{ pkgs | json }} 19 | {%- if 'pkg_repo' in postgres and postgres.use_upstream_repo == true %} 20 | - refresh: True 21 | - require: 22 | - pkgrepo: postgresql-repo 23 | {%- endif %} 24 | {%- if postgres.fromrepo %} 25 | - fromrepo: {{ postgres.fromrepo }} 26 | {%- endif %} 27 | 28 | # Alternatives system. Make client binaries available in $PATH 29 | {%- if 'bin_dir' in postgres and postgres.linux.altpriority %} 30 | {%- for bin in postgres.client_bins %} 31 | {%- set path = salt['file.join'](postgres.bin_dir, bin) %} 32 | 33 | postgresql-{{ bin }}-altinstall: 34 | alternatives.install: 35 | - name: {{ bin }} 36 | - link: {{ salt['file.join']('/usr/bin', bin) }} 37 | - path: {{ path }} 38 | - priority: {{ postgres.linux.altpriority }} 39 | - onlyif: test -f {{ path }} 40 | - require: 41 | - pkg: postgresql-client-libs 42 | {%- if grains['saltversioninfo'] < [2018, 11, 0, 0] %} 43 | - retry: 44 | attempts: 2 45 | until: True 46 | {%- endif %} 47 | 48 | {%- endfor %} 49 | {%- endif %} 50 | -------------------------------------------------------------------------------- /postgres/client/remove.sls: -------------------------------------------------------------------------------- 1 | {%- from salt.file.dirname(tpldir) ~ "/map.jinja" import postgres with context -%} 2 | 3 | #remove release installed by formula 4 | postgresql-client-removed: 5 | pkg.removed: 6 | - pkgs: 7 | {% if postgres.pkg_client %} 8 | - {{ postgres.pkg_client }} 9 | {% endif %} 10 | 11 | {%- if postgres.remove.multiple_releases %} 12 | #search for and cleandown multiple releases 13 | 14 | {% for release in postgres.remove.releases %} 15 | {% if 'bin_dir' in postgres %} 16 | {%- for bin in postgres.client_bins %} 17 | {% set path = '/usr/pgsql-' + release|string + '/bin/' + bin %} 18 | 19 | postgresql{{ release }}-client-{{ bin }}-alternative-remove: 20 | alternatives.remove: 21 | - name: {{ bin }} 22 | - path: {{ path }} 23 | {% if grains.os in ('Fedora', 'CentOS',) %} 24 | {# bypass bug #} 25 | - onlyif: alternatives --display {{ bin }} 26 | {% else %} 27 | - onlyif: test -f {{ path }} 28 | {% endif %} 29 | - require_in: 30 | - pkg: postgresql{{ release }}-client-pkgs-removed 31 | {%- endfor %} 32 | {%- endif %} 33 | 34 | postgresql{{ release }}-client-pkgs-removed: 35 | pkg.purged: 36 | - pkgs: 37 | - postgresql 38 | - postgresql-{{ release }} 39 | - postgresql-{{ release|replace('.', '') }} 40 | - postgresql{{ release }}-common 41 | - postgresql{{ release }}-jdbc 42 | 43 | {% endfor %} 44 | 45 | {%- endif %} 46 | -------------------------------------------------------------------------------- /postgres/codenamemap.yaml: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # vim: ft=yaml 3 | --- 4 | ### Set parameters based on PostgreSQL version supplied with particular distro 5 | 6 | {% import_yaml "postgres/repo.yaml" as repo %} 7 | 8 | {# Generate lookup dictionary map for OS and derivative distributions 9 | name: distro codename 10 | version: PostgreSQL release version 11 | codename: optional grain value if `name` does not match the one returned by `oscodename` grain 12 | #} 13 | 14 | {% macro debian_codename(name, version, codename=none) %} 15 | 16 | {% if repo.use_upstream_repo == true %} 17 | {% set version = repo.version %} 18 | {% set fromrepo = repo.fromrepo|default(name ~ '-pgdg', true) %} 19 | {% else %} 20 | {% set fromrepo = name %} 21 | {% endif %} 22 | {% set cluster_name = repo.cluster_name %} 23 | {% set conf_dir = '/etc/postgresql/{0}/{1}'.format(version, cluster_name) %} 24 | {% set data_dir = '/var/lib/postgresql/{0}/{1}'.format(version, cluster_name) %} 25 | 26 | {{ codename|default(name, true) }}: 27 | # PostgreSQL packages are mostly downloaded from `main` repo component 28 | conf_dir: {{ conf_dir }} 29 | data_dir: {{ data_dir }} 30 | fromrepo: {{ fromrepo }} 31 | pkg_repo: 32 | name: 'deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.gpg] http://apt.postgresql.org/pub/repos/apt {{ name }}-pgdg main' 33 | pkg: postgresql-{{ version }} 34 | pkg_client: postgresql-client-{{ version }} 35 | prepare_cluster: 36 | pgcommand: pg_createcluster {{ version }} {{ cluster_name }} -d 37 | user: root 38 | bake_image_run_cmd: pg_ctlcluster {{ version }} {{ cluster_name }} start 39 | 40 | {% endmacro %} 41 | 42 | 43 | {% macro fedora_codename(name, version, codename=none) %} 44 | 45 | {# use upstream version if configured #} 46 | {% if repo.use_upstream_repo == true %} 47 | {% set version = repo.version %} 48 | {% endif %} 49 | 50 | {{ codename|default(name, true) }}: 51 | # PostgreSQL packages are mostly downloaded from `main` repo component 52 | pkg_repo: 53 | baseurl: 'https://download.postgresql.org/pub/repos/yum/{{ version }}/fedora/fedora-$releasever-$basearch' 54 | 55 | {% endmacro %} 56 | 57 | ## Debian GNU/Linux (the second parameter refers to the postgresql package version, not the distro) 58 | # http://apt.postgresql.org/pub/repos/apt/dists/ 59 | # https://packages.debian.org/search?keywords=postgresql&searchon=names 60 | {{ debian_codename('jessie', '9.4') }} 61 | {{ debian_codename('stretch', '9.6') }} 62 | {{ debian_codename('buster', '11') }} 63 | {{ debian_codename('bullseye', '13') }} 64 | {{ debian_codename('bookworm', '15') }} 65 | 66 | # `oscodename` grain has long distro name 67 | # if `lsb-release` package not installed 68 | {{ debian_codename('jessie', '9.4', 'Debian GNU/Linux 8 (jessie)') }} 69 | {{ debian_codename('stretch', '9.6', 'Debian GNU/Linux 9 (stretch)') }} 70 | {{ debian_codename('buster', '11', 'Debian GNU/Linux 10 (buster)') }} 71 | {{ debian_codename('bullseye', '13', 'Debian GNU/Linux 11 (bullseye)') }} 72 | {{ debian_codename('bookworm', '15', 'Debian GNU/Linux 12 (bookworm)') }} 73 | 74 | ## Ubuntu 75 | # http://apt.postgresql.org/pub/repos/apt/dists/ 76 | # https://packages.ubuntu.com/search?keywords=postgresql&searchon=names 77 | {{ debian_codename('xenial', '9.5') }} 78 | {{ debian_codename('bionic', '10') }} 79 | {{ debian_codename('eoan', '11') }} 80 | {{ debian_codename('focal', '12') }} 81 | {{ debian_codename('jammy', '14') }} 82 | 83 | ## Fedora 84 | # https://download.postgresql.org/pub/repos/yum/13/fedora/ 85 | # https://apps.fedoraproject.org/packages/postgresql 86 | {{ fedora_codename('Fedora-34', '13') }} 87 | {{ fedora_codename('Fedora-33', '13') }} 88 | 89 | ## Amazon 90 | Amazon Linux 2: 91 | pkgs_deps: 92 | - libicu 93 | - systemd-sysv 94 | pkg_repo: 95 | baseurl: 'https://download.postgresql.org/pub/repos/yum/{{ repo.version }}/redhat/rhel-7-$basearch' 96 | 97 | # vim: ft=sls 98 | -------------------------------------------------------------------------------- /postgres/defaults.yaml: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # vim: ft=yaml 3 | --- 4 | # Default lookup dictionary 5 | 6 | postgres: 7 | use_upstream_repo: true 8 | add_profile: false # add bin_dir to $PATH, if installed from repos 9 | version: '13' 10 | pkg: postgresql 11 | pkgs_extra: [] 12 | pkgs_deps: [] 13 | pkg_client: postgresql-client 14 | pkg_dev: postgresql-devel 15 | pkg_dev_deps: [] 16 | pkg_libpq_dev: libpq-dev 17 | pkg_libs: postgresql-libs 18 | pkg_python: python-psycopg2 19 | userhomes: /home 20 | user: postgres 21 | group: postgres 22 | 23 | prepare_cluster: 24 | run: true 25 | pgcommand: initdb -D 26 | pgtestfile: PG_VERSION 27 | user: postgres 28 | env: [] 29 | 30 | cluster: 31 | name: main # Debian-based only 32 | locale: '' # Defaults to `C` 33 | encoding: '' # Defaults to `SQL_ASCII` if `locale` not provided 34 | 35 | conf_dir: /var/lib/pgsql/data 36 | data_dir: /var/lib/pgsql/data 37 | conf_dir_mode: '0700' 38 | postgresconf: "" 39 | 40 | macos: 41 | archive: postgres.dmg 42 | tmpdir: /tmp/postgrestmp 43 | postgresapp: 44 | # See: https://github.com/PostgresApp/PostgresApp/releases/ 45 | # yamllint disable-line rule:line-length 46 | url: https://github.com/PostgresApp/PostgresApp/releases/download/v2.1.1/Postgres-2.1.1.dmg 47 | sum: sha256=ac0656b522a58fd337931313f09509c09610c4a6078fe0b8e469e69af1e1750b 48 | homebrew: 49 | url: '' 50 | sum: '' 51 | dl: 52 | opts: -s -L 53 | interval: 60 54 | retries: 2 55 | 56 | pg_hba.conf: salt://postgres/templates/pg_hba.conf.j2 57 | acls: 58 | # "local" is for Unix domain socket connections only 59 | - ['local', 'all', 'all', 'peer'] 60 | # IPv4 local connections: 61 | - ['host', 'all', 'all', '127.0.0.1/32', 'md5'] 62 | # IPv6 local connections: 63 | - ['host', 'all', 'all', '::1/128', 'md5'] 64 | # Allow replication connections from localhost, by a user with the 65 | # replication privilege. 66 | - ['local', 'replication', 'all', 'peer'] 67 | - ['host', 'replication', 'all', '127.0.0.1/32', 'md5'] 68 | - ['host', 'replication', 'all', '::1/128', 'md5'] 69 | 70 | pg_ident.conf: salt://postgres/templates/pg_ident.conf.j2 71 | identity_map: [] 72 | 73 | config_backup: '.bak' 74 | 75 | service: 76 | name: postgresql 77 | sysrc: false 78 | 79 | bake_image: false 80 | bake_image_run_cmd: pg_ctl start 81 | 82 | fromrepo: '' 83 | 84 | users: {} 85 | tablespaces: {} 86 | databases: {} 87 | schemas: {} 88 | extensions: {} 89 | 90 | linux: 91 | # Alternatives system are disabled by a 'altpriority=0' pillar. 92 | altpriority: 0 93 | 94 | remove: 95 | data: false 96 | multiple_releases: false 97 | releases: ['9.2', '9.3', '9.4', '9.5', '9.6', '10'] 98 | -------------------------------------------------------------------------------- /postgres/dev/init.sls: -------------------------------------------------------------------------------- 1 | {%- from salt.file.dirname(tpldir) ~ "/map.jinja" import postgres with context -%} 2 | 3 | {% if grains.os not in ('Windows', 'MacOS',) %} 4 | {%- set pkgs = [postgres.pkg_dev, postgres.pkg_libpq_dev] + postgres.pkg_dev_deps %} 5 | 6 | {% if pkgs %} 7 | install-postgres-dev-packages: 8 | pkg.installed: 9 | - pkgs: {{ pkgs | json }} 10 | {% if postgres.fromrepo %} 11 | - fromrepo: {{ postgres.fromrepo }} 12 | {% endif %} 13 | {% endif %} 14 | 15 | # Alternatives system. Make devclient binaries available in $PATH 16 | {%- if 'bin_dir' in postgres and postgres.linux.altpriority %} 17 | {%- for bin in postgres.dev_bins %} 18 | {%- set path = salt['file.join'](postgres.bin_dir, bin) %} 19 | 20 | postgresql-{{ bin }}-altinstall: 21 | alternatives.install: 22 | - name: {{ bin }} 23 | - link: {{ salt['file.join']('/usr/bin', bin) }} 24 | - path: {{ path }} 25 | - priority: {{ postgres.linux.altpriority }} 26 | - onlyif: test -f {{ path }} 27 | {%- if grains['saltversioninfo'] < [2018, 11, 0, 0] %} 28 | - retry: 29 | attempts: 2 30 | until: True 31 | {%- endif %} 32 | 33 | {%- endfor %} 34 | {%- endif %} 35 | 36 | {% elif grains.os == 'MacOS' %} 37 | 38 | # Darwin maxfiles limits 39 | {% if postgres.limits.soft or postgres.limits.hard %} 40 | 41 | postgres_maxfiles_limits_conf: 42 | file.managed: 43 | - name: /Library/LaunchDaemons/limit.maxfiles.plist 44 | - source: salt://postgres/templates/limit.maxfiles.plist 45 | - template: jinja 46 | - context: 47 | soft_limit: {{ postgres.limits.soft }} 48 | hard_limit: {{ postgres.limits.hard }} 49 | - group: {{ postgres.group }} 50 | {% endif %} 51 | 52 | {% if postgres.use_upstream_repo == 'postgresapp' %} 53 | # Shortcut for PostgresApp 54 | postgres-desktop-shortcut-clean: 55 | file.absent: 56 | - name: '{{ postgres.userhomes }}/{{ postgres.user }}/Desktop/Postgres ({{ postgres.use_upstream_repo }})' 57 | - require_in: 58 | - file: postgres-desktop-shortcut-add 59 | 60 | postgres-desktop-shortcut-add: 61 | file.managed: 62 | - name: /tmp/mac_shortcut.sh 63 | - source: salt://postgres/templates/mac_shortcut.sh 64 | - mode: 755 65 | - template: jinja 66 | - context: 67 | user: {{ postgres.user }} 68 | homes: {{ postgres.userhomes }} 69 | cmd.run: 70 | - name: '/tmp/mac_shortcut.sh "Postgres ({{ postgres.use_upstream_repo }})"' 71 | - runas: {{ postgres.user }} 72 | - require: 73 | - file: postgres-desktop-shortcut-add 74 | {% endif %} 75 | 76 | {% endif %} 77 | -------------------------------------------------------------------------------- /postgres/dev/remove.sls: -------------------------------------------------------------------------------- 1 | {%- from salt.file.dirname(tpldir) ~ "/map.jinja" import postgres with context -%} 2 | 3 | # remove release installed by formula 4 | postgresql-devel-removed: 5 | pkg.removed: 6 | - pkgs: 7 | {% if postgres.pkg_dev %} 8 | - {{ postgres.pkg_dev }} 9 | {% endif %} 10 | {% if postgres.pkg_libpq_dev %} 11 | - {{ postgres.pkg_libpq_dev }} 12 | {% endif %} 13 | {% if postgres.pkg_python %} 14 | - {{ postgres.pkg_python }} 15 | {% endif %} 16 | 17 | {%- if postgres.remove.multiple_releases %} 18 | #search for and cleandown multiple releases 19 | 20 | {% for release in postgres.remove.releases %} 21 | {% if 'bin_dir' in postgres %} 22 | {%- for bin in postgres.dev_bins %} 23 | {% set path = '/usr/pgsql-' + release|string + '/bin/' + bin %} 24 | 25 | postgresql{{ release }}-devel-{{ bin }}-alternative-remove: 26 | alternatives.remove: 27 | - name: {{ bin }} 28 | - path: {{ path }} 29 | {% if grains.os in ('Fedora', 'CentOS',) %} 30 | {# bypass bug #} 31 | - onlyif: alternatives --display {{ bin }} 32 | {% else %} 33 | - onlyif: test -f {{ path }} 34 | {% endif %} 35 | - require_in: 36 | - pkg: postgresql{{ release }}-devel-pkgs-removed 37 | {%- endfor %} 38 | {%- endif %} 39 | 40 | postgresql{{ release }}-devel-pkgs-removed: 41 | pkg.purged: 42 | - pkgs: 43 | - postgresql-dev 44 | - postgresql-dev-{{ release|replace('.', '') }} 45 | - postgresql-server-dev 46 | - postgresql-server-dev-{{ release|replace('.', '') }} 47 | - postgresql{{ release }}-jdbc 48 | - postgresql{{ release|replace('.', '') }}-jdbc 49 | - postgresql-{{ release }} 50 | - postgresql-{{ release|replace('.', '') }} 51 | - {{ postgres.pkg_python or "postgresql-python" }} 52 | 53 | {% endfor %} 54 | 55 | {%- endif %} 56 | -------------------------------------------------------------------------------- /postgres/dropped.sls: -------------------------------------------------------------------------------- 1 | 2 | include: 3 | - postgres.server.remove 4 | - postgres.client.remove 5 | - postgres.dev.remove 6 | -------------------------------------------------------------------------------- /postgres/init.sls: -------------------------------------------------------------------------------- 1 | 2 | include: 3 | {% if grains.os == 'MacOS' %} 4 | - postgres.macos 5 | {% else %} 6 | - postgres.server 7 | - postgres.client 8 | - postgres.manage 9 | {% endif %} 10 | -------------------------------------------------------------------------------- /postgres/libtofs.jinja: -------------------------------------------------------------------------------- 1 | {%- macro files_switch( 2 | source_files, 3 | lookup=None, 4 | default_files_switch=["id", "os_family"], 5 | indent_width=6, 6 | use_subpath=False 7 | ) %} 8 | {#- 9 | Returns a valid value for the "source" parameter of a "file.managed" 10 | state function. This makes easier the usage of the Template Override and 11 | Files Switch (TOFS) pattern. 12 | Params: 13 | * source_files: ordered list of files to look for 14 | * lookup: key under ":tofs:source_files" to prepend to the 15 | list of source files 16 | * default_files_switch: if there's no config (e.g. pillar) 17 | ":tofs:files_switch" this is the ordered list of grains to 18 | use as selector switch of the directories under 19 | "/files" 20 | * indent_width: indentation of the result value to conform to YAML 21 | * use_subpath: defaults to `False` but if set, lookup the source file 22 | recursively from the current state directory up to `tplroot` 23 | Example (based on a `tplroot` of `xxx`): 24 | If we have a state: 25 | Deploy configuration: 26 | file.managed: 27 | - name: /etc/yyy/zzz.conf 28 | - source: {{ files_switch( 29 | ["/etc/yyy/zzz.conf", "/etc/yyy/zzz.conf.jinja"], 30 | lookup="Deploy configuration", 31 | ) }} 32 | - template: jinja 33 | In a minion with id=theminion and os_family=RedHat, it's going to be 34 | rendered as: 35 | Deploy configuration: 36 | file.managed: 37 | - name: /etc/yyy/zzz.conf 38 | - source: 39 | - salt://xxx/files/theminion/etc/yyy/zzz.conf 40 | - salt://xxx/files/theminion/etc/yyy/zzz.conf.jinja 41 | - salt://xxx/files/RedHat/etc/yyy/zzz.conf 42 | - salt://xxx/files/RedHat/etc/yyy/zzz.conf.jinja 43 | - salt://xxx/files/default/etc/yyy/zzz.conf 44 | - salt://xxx/files/default/etc/yyy/zzz.conf.jinja 45 | - template: jinja 46 | #} 47 | {#- Get the `tplroot` from `tpldir` #} 48 | {%- set tplroot = tpldir.split("/")[0] %} 49 | {%- set path_prefix = salt["config.get"](tplroot ~ ":tofs:path_prefix", tplroot) %} 50 | {%- set files_dir = salt["config.get"](tplroot ~ ":tofs:dirs:files", "files") %} 51 | {%- set files_switch_list = salt["config.get"]( 52 | tplroot ~ ":tofs:files_switch", default_files_switch 53 | ) %} 54 | {#- Lookup source_files (v2), files (v1), or fallback to an empty list #} 55 | {%- set src_files = salt["config.get"]( 56 | tplroot ~ ":tofs:source_files:" ~ lookup, 57 | salt["config.get"](tplroot ~ ":tofs:files:" ~ lookup, []), 58 | ) %} 59 | {#- Append the default source_files #} 60 | {%- set src_files = src_files + source_files %} 61 | {#- Only add to [""] when supporting older TOFS implementations #} 62 | {%- set path_prefix_exts = [""] %} 63 | {%- if use_subpath and tplroot != tpldir %} 64 | {#- Walk directory tree to find {{ files_dir }} #} 65 | {%- set subpath_parts = tpldir.lstrip(tplroot).lstrip("/").split("/") %} 66 | {%- for path in subpath_parts %} 67 | {%- set subpath = subpath_parts[0 : loop.index] | join("/") %} 68 | {%- do path_prefix_exts.append("/" ~ subpath) %} 69 | {%- endfor %} 70 | {%- endif %} 71 | {%- for path_prefix_ext in path_prefix_exts | reverse %} 72 | {%- set path_prefix_inc_ext = path_prefix ~ path_prefix_ext %} 73 | {#- For older TOFS implementation, use `files_switch` from the config #} 74 | {#- Use the default, new method otherwise #} 75 | {%- set fsl = salt["config.get"]( 76 | tplroot ~ path_prefix_ext | replace("/", ":") ~ ":files_switch", 77 | files_switch_list, 78 | ) %} 79 | {#- Append an empty value to evaluate as `default` in the loop below #} 80 | {%- if "" not in fsl %} 81 | {%- set fsl = fsl + [""] %} 82 | {%- endif %} 83 | {%- for fs in fsl %} 84 | {%- for src_file in src_files %} 85 | {%- if fs %} 86 | {%- set fs_dirs = salt["config.get"](fs, fs) %} 87 | {%- else %} 88 | {%- set fs_dirs = salt["config.get"]( 89 | tplroot ~ ":tofs:dirs:default", "default" 90 | ) %} 91 | {%- endif %} 92 | {#- Force the `config.get` lookup result as a list where necessary #} 93 | {#- since we need to also handle grains that are lists #} 94 | {%- if fs_dirs is string %} 95 | {%- set fs_dirs = [fs_dirs] %} 96 | {%- endif %} 97 | {%- for fs_dir in fs_dirs %} 98 | {#- strip empty elements by using a select #} 99 | {%- set url = ( 100 | [ 101 | "- salt:/", 102 | path_prefix_inc_ext.strip("/"), 103 | files_dir.strip("/"), 104 | fs_dir.strip("/"), 105 | src_file.strip("/"), 106 | ] 107 | | select 108 | | join("/") 109 | ) %} 110 | {{ url | indent(indent_width, true) }} 111 | {%- endfor %} 112 | {%- endfor %} 113 | {%- endfor %} 114 | {%- endfor %} 115 | {%- endmacro %} 116 | -------------------------------------------------------------------------------- /postgres/macos/init.sls: -------------------------------------------------------------------------------- 1 | {%- from salt.file.dirname(tpldir) ~ "/map.jinja" import postgres with context -%} 2 | 3 | include: 4 | {% if postgres.use_upstream_repo == 'postgresapp' %} 5 | - postgres.macos.postgresapp 6 | {% elif postgres.use_upstream_repo == 'homebrew' %} 7 | - postgres.server 8 | - postgres.client 9 | {% endif %} 10 | - postgres.dev 11 | -------------------------------------------------------------------------------- /postgres/macos/postgresapp.sls: -------------------------------------------------------------------------------- 1 | {%- from salt.file.dirname(tpldir) ~ "/map.jinja" import postgres as pg with context -%} 2 | 3 | pg-extract-dirs: 4 | file.directory: 5 | - names: 6 | - '{{ pg.macos.tmpdir }}' 7 | - makedirs: True 8 | - require_in: 9 | - pg-download-archive 10 | 11 | pg-download-archive: 12 | pkg.installed: 13 | - name: curl 14 | cmd.run: 15 | - name: curl {{ pg.macos.dl.opts }} -o {{ pg.macos.tmpdir }}/{{ pg.macos.archive }} {{ pg.macos.postgresapp.url }} 16 | - unless: test -f {{ pg.macos.tmpdir }}/{{ pg.macos.archive }} 17 | {% if grains['saltversioninfo'] >= [2017, 7, 0] %} 18 | - retry: 19 | attempts: {{ pg.macos.dl.retries }} 20 | interval: {{ pg.macos.dl.interval }} 21 | until: True 22 | splay: 10 23 | {% endif %} 24 | 25 | {%- if pg.macos.postgresapp.sum %} 26 | pg-check-archive-hash: 27 | module.run: 28 | - name: file.check_hash 29 | - path: '{{ pg.macos.tmpdir }}/{{ pg.macos.archive }}' 30 | - file_hash: {{ pg.macos.postgresapp.sum }} 31 | - require: 32 | - cmd: pg-download-archive 33 | - require_in: 34 | - archive: pg-package-install 35 | {%- endif %} 36 | 37 | pg-package-install: 38 | macpackage.installed: 39 | - name: '{{ pg.macos.tmpdir }}/{{ pg.macos.archive }}' 40 | - store: True 41 | - dmg: True 42 | - app: True 43 | - force: True 44 | - allow_untrusted: True 45 | - onchanges: 46 | - cmd: pg-download-archive 47 | - require_in: 48 | - file: pg-package-install 49 | file.append: 50 | - name: {{ pg.userhomes }}/{{ pg.user }}/.bash_profile 51 | - text: 'export PATH=$PATH:/Applications/Postgres.app/Contents/Versions/latest/bin' 52 | 53 | -------------------------------------------------------------------------------- /postgres/macros.jinja: -------------------------------------------------------------------------------- 1 | {%- from "postgres/map.jinja" import postgres with context -%} 2 | 3 | {%- macro format_kwargs(kwarg) -%} 4 | 5 | {%- filter indent(4) %} 6 | {%- for k, v in kwarg|dictsort() %} 7 | - {{ k }}: {{ v|yaml_dquote if v is string else v }} 8 | {%- endfor %} 9 | {%- endfilter %} 10 | 11 | {%- endmacro %} 12 | 13 | {%- macro format_state(name, state, kwarg) %} 14 | 15 | {%- if 'name' not in kwarg %} 16 | {%- do kwarg.update({'name': name}) %} 17 | {%- endif %} 18 | {%- if 'ensure' in kwarg %} 19 | {%- set ensure = kwarg.pop('ensure') %} 20 | {%- endif %} 21 | {%- set user_available = not (state == 'postgres_schema' and grains.saltversioninfo < [2018, 3]) %} 22 | {%- if 'user' not in kwarg and user_available %} 23 | {%- do kwarg.update({'user': postgres.user}) %} 24 | {%- endif -%} 25 | 26 | {{ state }}-{{ name }}: 27 | {{ state }}.{{ ensure|default('present') }}: 28 | {{- format_kwargs(kwarg) }} 29 | - onchanges: 30 | - test: postgres-reload-modules 31 | 32 | {%- endmacro %} 33 | 34 | # vim: ft=sls 35 | -------------------------------------------------------------------------------- /postgres/manage.sls: -------------------------------------------------------------------------------- 1 | {%- from tpldir + "/map.jinja" import postgres with context -%} 2 | {%- from tpldir + "/macros.jinja" import format_state with context -%} 3 | 4 | {%- if salt['postgres.user_create']|default(none) is not callable %} 5 | 6 | # Salt states for managing PostgreSQL is not available, 7 | # need to provision client binaries first 8 | 9 | include: 10 | - postgres.client 11 | {%- if 'server_bins' in postgres and grains['saltversion'] == '2016.11.0' %} 12 | # FIXME: Salt v2016.11.0 bug https://github.com/saltstack/salt/issues/37935 13 | - postgres.server 14 | {%- endif %} 15 | 16 | {%- endif %} 17 | 18 | # Ensure that Salt is able to use postgres modules 19 | 20 | postgres-reload-modules: 21 | test.succeed_with_changes: 22 | - reload_modules: True 23 | 24 | # User states 25 | 26 | {%- for name, user in postgres.users|dictsort() %} 27 | 28 | {{ format_state(name, 'postgres_user', user) }} 29 | 30 | {%- endfor %} 31 | 32 | # Tablespace states 33 | 34 | {%- for name, tblspace in postgres.tablespaces|dictsort() %} 35 | 36 | {{ format_state(name, 'postgres_tablespace', tblspace) }} 37 | {%- if 'owner' in tblspace %} 38 | - require: 39 | - postgres_user: postgres_user-{{ tblspace.owner }} 40 | {%- endif %} 41 | 42 | {%- endfor %} 43 | 44 | # Database states 45 | 46 | {%- for name, db in postgres.databases|dictsort() %} 47 | {%- if 'extensions' in db %} 48 | {%- for ext_name, extension in db.pop('extensions')|dictsort() %} 49 | {%- do extension.update({'name': ext_name, 'maintenance_db': name}) %} 50 | 51 | {{ format_state( name + '-' + ext_name, 'postgres_extension', extension) }} 52 | - require: 53 | - postgres_database: postgres_database-{{ name }} 54 | {%- if 'schema' in extension and 'schemas' in postgres %} 55 | - postgres_schema: postgres_schema-{{ name }}-{{ extension.schema }} 56 | {%- endif %} 57 | 58 | {%- endfor %} 59 | {%- endif %} 60 | {%- if 'schemas' in db %} 61 | {%- for schema_name, schema in db.pop('schemas')|dictsort() %} 62 | {%- do schema.update({'name': schema_name, 'dbname': name }) %} 63 | 64 | {{ format_state( name + '-' + schema_name, 'postgres_schema', schema) }} 65 | - require: 66 | - postgres_database: postgres_database-{{ name }} 67 | 68 | {%- endfor %} 69 | {%- endif %} 70 | 71 | {{ format_state(name, 'postgres_database', db) }} 72 | {%- if 'owner' in db or 'tablespace' in db %} 73 | - require: 74 | {%- endif %} 75 | {%- if 'owner' in db %} 76 | - postgres_user: postgres_user-{{ db.owner }} 77 | {%- endif %} 78 | {%- if 'tablespace' in db %} 79 | - postgres_tablespace: postgres_tablespace-{{ db.tablespace }} 80 | {%- endif %} 81 | 82 | {%- endfor %} 83 | 84 | # Schema states 85 | 86 | {%- for name, schema in postgres.schemas|dictsort() %} 87 | 88 | {{ format_state(name, 'postgres_schema', schema) }} 89 | - require: 90 | - postgres_database-{{ schema.dbname }} 91 | {%- if 'owner' in schema %} 92 | - postgres_user: postgres_user-{{ schema.owner }} 93 | {%- endif %} 94 | 95 | {%- endfor %} 96 | 97 | # Extension states 98 | 99 | {%- for name, extension in postgres.extensions|dictsort() %} 100 | 101 | {{ format_state(name, 'postgres_extension', extension) }} 102 | {%- if 'maintenance_db' in extension or 'schema' in extension %} 103 | - require: 104 | {%- endif %} 105 | {%- if 'maintenance_db' in extension %} 106 | - postgres_database: postgres_database-{{ extension.maintenance_db }} 107 | {%- endif %} 108 | {%- if 'schema' in extension %} 109 | - postgres_schema: postgres_schema-{{ extension.schema }} 110 | {%- endif %} 111 | 112 | {%- endfor %} 113 | -------------------------------------------------------------------------------- /postgres/map.jinja: -------------------------------------------------------------------------------- 1 | {% import_yaml "postgres/defaults.yaml" as defaults %} 2 | {% import_yaml "postgres/osfamilymap.yaml" as osfamilymap %} 3 | {% import_yaml "postgres/osmap.yaml" as osmap %} 4 | {% import_yaml "postgres/codenamemap.yaml" as oscodenamemap %} 5 | 6 | {% set postgres = salt['grains.filter_by']( 7 | defaults, 8 | merge=salt['grains.filter_by']( 9 | osfamilymap, 10 | grain='os_family', 11 | merge=salt['grains.filter_by']( 12 | osmap, 13 | grain='os', 14 | merge=salt['grains.filter_by']( 15 | oscodenamemap, 16 | grain='oscodename', 17 | merge=salt['pillar.get']('postgres', {}), 18 | ), 19 | ), 20 | ), 21 | base='postgres', 22 | ) %} 23 | 24 | {# Concatenate the cluster preparation command and then append it to the `postgres` dict #} 25 | {% set pc_cmd = '{0} {1}'.format(postgres.prepare_cluster.pgcommand, postgres.data_dir) %} 26 | {% if postgres.cluster.locale %} 27 | {% set pc_cmd = '{0} --locale={1}'.format(pc_cmd, postgres.cluster.locale) %} 28 | {% endif %} 29 | {% if postgres.cluster.encoding %} 30 | {% set pc_cmd = '{0} --encoding={1}'.format(pc_cmd, postgres.cluster.encoding) %} 31 | {% endif %} 32 | {% do postgres.update({'prepare_cluster_cmd': pc_cmd}) %} 33 | -------------------------------------------------------------------------------- /postgres/osfamilymap.yaml: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # vim: ft=yaml 3 | --- 4 | {% import_yaml "postgres/repo.yaml" as repo %} 5 | 6 | {% set release = repo.version|replace('.', '') %} 7 | 8 | Arch: 9 | use_upstream_repo: false 10 | conf_dir: /var/lib/postgres/data 11 | data_dir: /var/lib/postgres/data 12 | pkg_client: postgresql-libs 13 | pkg_dev: postgresql 14 | 15 | Debian: 16 | pkgs_deps: ['python3-apt'] 17 | pkg_repo: 18 | humanname: PostgreSQL Official Repository 19 | file: /etc/apt/sources.list.d/pgdg.list 20 | pkg_repo_keyring: 'https://download.postgresql.org/pub/repos/apt/pool/main/p/pgdg-keyring/pgdg-keyring_2018.2_all.deb' 21 | pkg_repo_keyid: ACCC4CF8 22 | {% if repo.use_upstream_repo == true %} 23 | pkg_dev: '' 24 | {% else %} 25 | pkg_dev: postgresql-server-dev-all 26 | {% endif %} 27 | 28 | FreeBSD: 29 | {% if repo.version|float >= 9.6 %} 30 | user: &freebsd-user postgres 31 | group: &freebsd-group postgres 32 | conf_dir: {{ '/var/db/postgres/data' ~ release }} 33 | data_dir: {{ '/var/db/postgres/data' ~ release }} 34 | {% else %} 35 | user: &freebsd-user pgsql 36 | group: &freebsd-group pgsql 37 | conf_dir: /usr/local/pgsql/data 38 | data_dir: /usr/local/pgsql/data 39 | {% endif %} 40 | pkg_libpq_dev: null #not in freebsd 41 | pkg_client: postgresql{{ release }}-client 42 | pkg: postgresql{{ release }}-server 43 | prepare_cluster: 44 | user: *freebsd-user 45 | group: *freebsd-group 46 | service: 47 | flags: -w -s -m fast 48 | sysrc: True 49 | 50 | OpenBSD: 51 | conf_dir: /var/postgresql/data 52 | data_dir: /var/postgresql/data 53 | user: _postgresql 54 | service: 55 | flags: -w -s -m fast 56 | sysrc: True 57 | 58 | RedHat: 59 | pkg_repo: 60 | name: pgdg{{ release }} 61 | humanname: PostgreSQL {{ repo.version }} $releasever - $basearch 62 | gpgcheck: 1 63 | gpgkey: 'https://download.postgresql.org/pub/repos/yum/RPM-GPG-KEY-PGDG-{{ release }}' 64 | baseurl: 'https://download.postgresql.org/pub/repos/yum/{{ repo.version }}/redhat/rhel-$releasever-$basearch' 65 | 66 | pkgs_deps: 67 | - libicu 68 | {%- if grains.get('osmajorrelease', 0) == 7 %} 69 | - systemd-sysv 70 | {%- endif %} 71 | pkg_python: python3-psycopg2 72 | 73 | {% if repo.use_upstream_repo == true %} 74 | {% set data_dir = '/var/lib/pgsql/' ~ repo.version ~ '/data' %} 75 | 76 | fromrepo: pgdg{{ release }} 77 | pkg: postgresql{{ release }}-server 78 | pkg_client: postgresql{{ release }} 79 | pkg_libs: postgresql{{ release }}-libs 80 | pkg_dev: postgresql{{ release }}-devel 81 | conf_dir: {{ data_dir }} 82 | data_dir: {{ data_dir }} 83 | service: 84 | name: postgresql-{{ repo.version }} 85 | 86 | # Alternatives system 87 | linux: 88 | altpriority: 30 89 | 90 | # directory containing PostgreSQL client executables 91 | bin_dir: /usr/pgsql-{{ repo.version }}/bin 92 | dev_bins: 93 | - ecg 94 | client_bins: 95 | - clusterdb 96 | - createdb 97 | - createlang 98 | - createuser 99 | - dropdb 100 | - droplang 101 | - dropuser 102 | - pg_archivecleanup 103 | - pg_basebackup 104 | - pg_config 105 | - pg_dump 106 | - pg_dumpall 107 | - pg_isready 108 | - pg_receivexlog 109 | - pg_restore 110 | - pg_rewind 111 | - pg_test_fsync 112 | - pg_test_timing 113 | - pg_upgrade 114 | - pg_xlogdump 115 | - pgbench 116 | - psql 117 | - reindexdb 118 | - vacuumdb 119 | server_bins: 120 | - initdb 121 | - pg_controldata 122 | - pg_ctl 123 | - pg_resetxlog 124 | - postgres 125 | - postgresql{{ release }}-check-db-dir 126 | - postgresql{{ release }}-setup 127 | - postmaster 128 | 129 | {% else %} 130 | 131 | pkg: postgresql-server 132 | pkg_client: postgresql 133 | 134 | {% endif %} 135 | pkg_libpq_dev: libpqxx-devel 136 | pkg_dev_deps: 137 | - perl-Time-HiRes 138 | - libicu-devel 139 | - perl-IPC-Run 140 | - perl-Test-Simple 141 | 142 | Suse: 143 | pkg_repo: 144 | name: pgdg-sles-{{ release }} 145 | humanname: PostgreSQL {{ repo.version }} $releasever - $basearch 146 | # works for postgres 11 onwards 147 | baseurl: 'https://download.postgresql.org/pub/repos/zypp/{{ repo.version }}/suse/sles-$releasever-$basearch' 148 | gpgkey: 'https://download.postgresql.org/pub/repos/zypp/{{ repo.version }}/suse/sles-$releasever-$basearch/repodata/repomd.xml.key' 149 | gpgcheck: 1 150 | gpgautoimport: True 151 | 152 | {% if repo.use_upstream_repo == true %} 153 | {% set data_dir = '/var/lib/pgsql/' ~ repo.version ~ '/data' %} 154 | 155 | fromrepo: pgdg-sles-{{ release }} 156 | pkg: postgresql{{ release }}-server 157 | pkg_client: postgresql{{ release }} 158 | pkg_dev: postgresql{{ release }}-devel 159 | pkg_libs: postgresql{{ release }}-libs 160 | conf_dir: {{ data_dir }} 161 | data_dir: {{ data_dir }} 162 | service: 163 | name: postgresql-{{ repo.version }} 164 | 165 | # Alternatives system 166 | linux: 167 | altpriority: 30 168 | 169 | # directory containing PostgreSQL client executables 170 | bin_dir: /usr/pgsql-{{ repo.version }}/bin 171 | dev_bins: 172 | - ecg 173 | client_bins: 174 | - pg_archivecleanup 175 | - pg_config 176 | - pg_isready 177 | - pg_receivexlog 178 | - pg_rewind 179 | - pg_test_fsync 180 | - pg_test_timing 181 | - pg_upgrade 182 | - pg_xlogdump 183 | - pgbench 184 | server_bins: 185 | - initdb 186 | - pg_controldata 187 | - pg_ctl 188 | - pg_resetxlog 189 | - postgres 190 | - postgresql{{ release }}-check-db-dir 191 | - postgresql{{ release }}-setup 192 | - postmaster 193 | 194 | {% else %} 195 | 196 | pkg: postgresql-server 197 | pkg_client: postgresql 198 | 199 | {% endif %} 200 | pkg_libpq_dev: libpqxx 201 | 202 | {%- if grains.os == 'MacOS' %} 203 | ## jinja check avoids rendering noise/failure on Linux 204 | MacOS: 205 | {%- if repo.use_upstream_repo == 'homebrew' %} 206 | service: 207 | name: homebrew.mxcl.postgresql 208 | {%- elif repo.use_upstream_repo == 'postgresapp' %} 209 | service: 210 | name: com.postgresapp.Postgres2 211 | {%- endif %} 212 | pkg: postgresql 213 | pkg_client: 214 | pkg_libpq_dev: 215 | userhomes: /Users 216 | user: {{ repo.user }} 217 | group: {{ repo.group }} 218 | conf_dir: /Users/{{ repo.user }}/Library/AppSupport/postgres_{{ repo.use_upstream_repo }} 219 | data_dir: /Users/{{ repo.user }}/Library/AppSupport/postgres_{{ repo.use_upstream_repo }} 220 | prepare_cluster: 221 | user: {{ repo.user }} 222 | group: {{ repo.group }} 223 | # macos limits 224 | limits: 225 | soft: 64000 226 | hard: 64000 227 | {%- endif %} 228 | 229 | # vim: ft=sls 230 | -------------------------------------------------------------------------------- /postgres/osmap.yaml: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # vim: ft=yaml 3 | --- 4 | {% import_yaml "postgres/repo.yaml" as repo %} 5 | 6 | Fedora: 7 | pkg_repo: 8 | # yamllint disable-line rule:line-length 9 | baseurl: 'https://download.postgresql.org/pub/repos/yum/{{ repo.version }}/fedora/fedora-$releasever-$basearch' 10 | remove: 11 | releases: ['9.4', '9.5', '9.6', '10'] 12 | -------------------------------------------------------------------------------- /postgres/python.sls: -------------------------------------------------------------------------------- 1 | {% from tpldir + "/map.jinja" import postgres with context %} 2 | 3 | include: 4 | - postgres.upstream 5 | 6 | postgresql-python: 7 | pkg.installed: 8 | - name: {{ postgres.pkg_python }} 9 | {% if postgres.fromrepo %} 10 | - fromrepo: {{ postgres.fromrepo }} 11 | {% endif %} 12 | {% if 'pkg_repo' in postgres and postgres.use_upstream_repo == true %} 13 | - refresh: True 14 | - require: 15 | - pkgrepo: postgresql-repo 16 | {% endif %} 17 | -------------------------------------------------------------------------------- /postgres/repo.yaml: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # vim: ft=yaml 3 | --- 4 | # This file allows to get PostgreSQL version and upstream repo settings 5 | # early from Pillar to set correct lookup dictionaty items 6 | 7 | {% import_yaml "postgres/defaults.yaml" as defaults %} 8 | 9 | use_upstream_repo: {{ salt['pillar.get']('postgres:use_upstream_repo', defaults.postgres.use_upstream_repo) }} 10 | version: {{ salt['pillar.get']('postgres:version', defaults.postgres.version) }} 11 | fromrepo: {{ salt['pillar.get']('postgres:fromrepo', defaults.postgres.fromrepo) }} 12 | cluster_name: {{ salt['pillar.get']('postgres:cluster:name', defaults.postgres.cluster.name) }} 13 | 14 | #Early lookup for system user on MacOS 15 | {% if grains.os == 'MacOS' %} 16 | {% set sysuser = salt['pillar.get']('postgres:user', salt['cmd.run']("stat -f '%Su' /dev/console")) %} 17 | {% set sysgroup = salt['pillar.get']('postgres:group', salt['cmd.run']("stat -f '%Sg' /dev/console")) %} 18 | user: {{ sysuser }} 19 | group: {{ sysgroup }} 20 | {% endif %} 21 | 22 | # vim: ft=sls 23 | -------------------------------------------------------------------------------- /postgres/server/image.sls: -------------------------------------------------------------------------------- 1 | {%- from salt.file.dirname(tpldir) ~ "/map.jinja" import postgres with context -%} 2 | 3 | # This state is used to launch PostgreSQL with ``pg_ctl`` command and enable it 4 | # on "boot" during an image (Docker, Virtual Appliance, AMI) preparation 5 | 6 | {%- if postgres.bake_image %} 7 | 8 | # An attempt to start PostgreSQL with `pg_ctl` 9 | postgresql-running: 10 | cmd.run: 11 | - name: {{ postgres.bake_image_run_cmd }} 12 | - runas: {{ postgres.user }} 13 | - unless: 14 | - ps -p $(head -n 1 {{ postgres.data_dir }}/postmaster.pid) 2>/dev/null 15 | - require: 16 | - file: postgresql-pg_hba 17 | 18 | postgresql-service-reload: 19 | module.run: 20 | - name: test.true 21 | - require: 22 | - cmd: postgresql-running 23 | 24 | # Try to enable PostgreSQL in "manual" way 25 | 26 | postgresql-enable: 27 | cmd.run: 28 | {%- if salt['file.file_exists']('/bin/systemctl') %} 29 | - name: systemctl enable {{ postgres.service.name }} 30 | {%- elif salt['cmd.which']('chkconfig') %} 31 | - name: chkconfig {{ postgres.service.name }} on 32 | {%- elif salt['file.file_exists']('/usr/sbin/update-rc.d') %} 33 | - name: update-rc.d {{ postgres.service.name }} defaults 34 | {%- else %} 35 | # Nothing to do 36 | - name: 'true' 37 | {%- endif %} 38 | - require: 39 | - cmd: postgresql-running 40 | 41 | {%- endif %} 42 | -------------------------------------------------------------------------------- /postgres/server/init.sls: -------------------------------------------------------------------------------- 1 | {%- from salt.file.dirname(tpldir) ~ "/map.jinja" import postgres with context -%} 2 | 3 | {%- set includes = [] %} 4 | {%- if postgres.bake_image %} 5 | {%- do includes.append('postgres.server.image') %} 6 | {%- endif %} 7 | {%- if postgres.use_upstream_repo == true -%} 8 | {%- do includes.append('postgres.upstream') %} 9 | {%- endif %} 10 | 11 | {%- if includes -%} 12 | include: 13 | {{ includes|yaml(false)|indent(2) }} 14 | {%- endif %} 15 | 16 | {%- set pkgs = [postgres.pkg] + postgres.pkgs_extra %} 17 | # Install, configure and start PostgreSQL server 18 | postgresql-server: 19 | pkg.installed: 20 | - pkgs: {{ pkgs | json }} 21 | {%- if 'pkg_repo' in postgres and postgres.use_upstream_repo == true %} 22 | - refresh: True 23 | - require: 24 | - pkgrepo: postgresql-repo 25 | {%- endif %} 26 | {%- if postgres.fromrepo %} 27 | - fromrepo: {{ postgres.fromrepo }} 28 | {%- endif %} 29 | {%- if grains.os == 'MacOS' %} 30 | #Register as Launchd LaunchAgent for system users 31 | - require_in: 32 | - file: postgresql-server 33 | file.managed: 34 | - name: /Library/LaunchAgents/{{ postgres.service.name }}.plist 35 | - source: /usr/local/opt/postgres/{{ postgres.service.name }}.plist 36 | - group: wheel 37 | - require_in: 38 | - service: postgresql-running 39 | 40 | 41 | # Alternatives system. Make server binaries available in $PATH 42 | {%- elif 'bin_dir' in postgres and postgres.linux.altpriority %} 43 | {%- for bin in postgres.server_bins %} 44 | {%- set path = salt['file.join'](postgres.bin_dir, bin) %} 45 | 46 | postgresql-{{ bin }}-altinstall: 47 | alternatives.install: 48 | - name: {{ bin }} 49 | - link: {{ salt['file.join']('/usr/bin', bin) }} 50 | - path: {{ path }} 51 | - priority: {{ postgres.linux.altpriority }} 52 | - onlyif: test -f {{ path }} 53 | - require: 54 | - pkg: postgresql-server 55 | - require_in: 56 | - cmd: postgresql-cluster-prepared 57 | {%- if grains['saltversioninfo'] < [2018, 11, 0, 0] %} 58 | - retry: 59 | attempts: 2 60 | until: True 61 | {%- endif %} 62 | 63 | {%- endfor %} 64 | {%- endif %} 65 | 66 | postgresql-cluster-prepared: 67 | file.directory: 68 | - name: {{ postgres.data_dir }} 69 | - user: {{ postgres.user }} 70 | - group: {{ postgres.group }} 71 | - makedirs: True 72 | - recurse: 73 | - user 74 | - group 75 | {%- if postgres.prepare_cluster.run %} 76 | cmd.run: 77 | {%- if postgres.prepare_cluster.command is defined %} 78 | {# support for depreciated 'prepare_cluster.command' pillar #} 79 | - name: {{ postgres.prepare_cluster.command }} 80 | - unless: {{ postgres.prepare_cluster.test }} 81 | {%- else %} 82 | - name: {{ postgres.prepare_cluster_cmd }} 83 | - unless: test -f {{ postgres.data_dir }}/{{ postgres.prepare_cluster.pgtestfile }} 84 | {%- endif %} 85 | - cwd: / 86 | - env: {{ postgres.prepare_cluster.env }} 87 | - runas: {{ postgres.prepare_cluster.user }} 88 | - require: 89 | - pkg: postgresql-server 90 | - file: postgresql-cluster-prepared 91 | - watch_in: 92 | - service: postgresql-running 93 | {%- endif %} 94 | 95 | postgresql-config-dir: 96 | file.directory: 97 | - names: 98 | - {{ postgres.data_dir }} 99 | - {{ postgres.conf_dir }} 100 | - user: {{ postgres.user }} 101 | - group: {{ postgres.group }} 102 | - dir_mode: {{ postgres.conf_dir_mode }} 103 | - force: True 104 | - recurse: 105 | - mode 106 | - ignore_files 107 | - makedirs: True 108 | - require: 109 | {%- if postgres.prepare_cluster.run %} 110 | - cmd: postgresql-cluster-prepared 111 | {%- else %} 112 | - file: postgresql-cluster-prepared 113 | {%- endif %} 114 | 115 | {%- set db_port = salt['config.option']('postgres.port') %} 116 | {%- if db_port %} 117 | 118 | postgresql-conf-comment-port: 119 | file.comment: 120 | - name: {{ postgres.conf_dir }}/postgresql.conf 121 | - regex: ^port\s*=.+ 122 | - require: 123 | - file: postgresql-config-dir 124 | 125 | {%- endif %} 126 | 127 | {%- if postgres.postgresconf or db_port %} 128 | 129 | postgresql-conf: 130 | file.blockreplace: 131 | - name: {{ postgres.conf_dir }}/postgresql.conf 132 | - marker_start: "# Managed by SaltStack: listen_addresses: please do not edit" 133 | - marker_end: "# Managed by SaltStack: end of salt managed zone --" 134 | - content: | 135 | {%- if postgres.postgresconf %} 136 | {{ postgres.postgresconf|indent(8) }} 137 | {%- endif %} 138 | {%- if db_port %} 139 | port = {{ db_port }} 140 | {%- endif %} 141 | - show_changes: True 142 | - append_if_not_found: True 143 | {#- Detect empty values (none, '') in the config_backup #} 144 | - backup: {{ postgres.config_backup|default(false, true) }} 145 | - require: 146 | - file: postgresql-config-dir 147 | {%- if db_port %} 148 | - file: postgresql-conf-comment-port 149 | {%- endif %} 150 | - watch_in: 151 | - service: postgresql-running 152 | 153 | {%- endif %} 154 | 155 | {%- set pg_hba_path = salt['file.join'](postgres.conf_dir, 'pg_hba.conf') %} 156 | 157 | postgresql-pg_hba: 158 | file.managed: 159 | - name: {{ pg_hba_path }} 160 | - user: {{ postgres.user }} 161 | - group: {{ postgres.group }} 162 | - mode: 600 163 | {%- if postgres.acls %} 164 | - source: {{ postgres['pg_hba.conf'] }} 165 | - template: jinja 166 | - defaults: 167 | acls: {{ postgres.acls|yaml() }} 168 | {%- if postgres.config_backup %} 169 | # Create the empty file before managing to overcome the limitation of check_cmd 170 | - onlyif: test -f {{ pg_hba_path }} || touch {{ pg_hba_path }} 171 | # Make a local backup before the file modification 172 | - check_cmd: >- 173 | salt-call --local file.copy 174 | {{ pg_hba_path }} {{ pg_hba_path ~ postgres.config_backup }} remove_existing=true 175 | {%- endif %} 176 | {%- else %} 177 | - replace: False 178 | {%- endif %} 179 | - require: 180 | - file: postgresql-config-dir 181 | - watch_in: 182 | - service: postgresql-running 183 | 184 | {%- set pg_ident_path = salt['file.join'](postgres.conf_dir, 'pg_ident.conf') %} 185 | 186 | postgresql-pg_ident: 187 | file.managed: 188 | - name: {{ pg_ident_path }} 189 | - user: {{ postgres.user }} 190 | - group: {{ postgres.group }} 191 | - mode: 600 192 | {%- if postgres.identity_map %} 193 | - source: {{ postgres['pg_ident.conf'] }} 194 | - template: jinja 195 | - defaults: 196 | mappings: {{ postgres.identity_map|yaml() }} 197 | {%- if postgres.config_backup %} 198 | # Create the empty file before managing to overcome the limitation of check_cmd 199 | - onlyif: test -f {{ pg_ident_path }} || touch {{ pg_ident_path }} 200 | # Make a local backup before the file modification 201 | - check_cmd: >- 202 | salt-call --local file.copy 203 | {{ pg_ident_path }} {{ pg_ident_path ~ postgres.config_backup }} remove_existing=true 204 | {%- endif %} 205 | {%- else %} 206 | - replace: False 207 | {%- endif %} 208 | - require: 209 | - file: postgresql-config-dir 210 | {%- if postgres.prepare_cluster.run %} 211 | - cmd: postgresql-cluster-prepared 212 | {%- else %} 213 | - file: postgresql-cluster-prepared 214 | {%- endif %} 215 | - watch_in: 216 | {%- if grains.os not in ('MacOS',) %} 217 | - module: postgresql-service-reload 218 | {%- else %} 219 | - service: postgresql-running 220 | {%- endif %} 221 | 222 | {%- for name, tblspace in postgres.tablespaces|dictsort() %} 223 | 224 | postgresql-tablespace-dir-{{ name }}: 225 | file.directory: 226 | - name: {{ tblspace.directory }} 227 | - user: {{ postgres.user }} 228 | - group: {{ postgres.group }} 229 | - mode: 700 230 | - makedirs: True 231 | - recurse: 232 | - user 233 | - group 234 | - require: 235 | - pkg: postgresql-server 236 | 237 | {%- if "selinux" in grains and grains.selinux.enabled %} 238 | 239 | pkg.installed: 240 | - names: 241 | - policycoreutils-python 242 | - selinux-policy-targeted 243 | - refresh: True 244 | selinux.fcontext_policy_present: 245 | - name: '{{ tblspace.directory }}(/.*)?' 246 | - sel_type: postgresql_db_t 247 | - require: 248 | - file: postgresql-tablespace-dir-{{ name }} 249 | - pkg: postgresql-tablespace-dir-{{ name }} 250 | 251 | postgresql-tablespace-dir-{{ name }}-fcontext: 252 | selinux.fcontext_policy_applied: 253 | - name: {{ tblspace.directory }} 254 | - recursive: True 255 | - require: 256 | - selinux: postgresql-tablespace-dir-{{ name }} 257 | 258 | {%- endif %} 259 | 260 | {%- endfor %} 261 | 262 | {%- if not postgres.bake_image %} 263 | 264 | # Workaround for FreeBSD minion undefinitely hanging on service start 265 | # cf. https://github.com/saltstack/salt/issues/44848 266 | {% if postgres.service.sysrc %} 267 | posgresql-rc-flags: 268 | sysrc.managed: 269 | - name: {{ postgres.service.name }}_flags 270 | - value: "{{ postgres.service.flags }} > /dev/null 2>&1" 271 | - watch_in: 272 | - service: postgresql-running 273 | {% endif %} 274 | 275 | # Start PostgreSQL server using OS init 276 | # Note: This is also the target for numerous `watch_in` requisites above, used 277 | # for the necessary service restart after changing the relevant configuration files 278 | postgresql-running: 279 | service.running: 280 | - name: {{ postgres.service.name }} 281 | - enable: True 282 | 283 | # Reload the service for changes made to `pg_ident.conf`, except for `MacOS` 284 | # which is handled by `postgresql-running` above. 285 | {%- if grains.os not in ('MacOS',) %} 286 | postgresql-service-reload: 287 | module.wait: 288 | - name: service.reload 289 | - m_name: {{ postgres.service.name }} 290 | - require: 291 | - service: postgresql-running 292 | {%- endif %} 293 | 294 | {%- endif %} 295 | -------------------------------------------------------------------------------- /postgres/server/remove.sls: -------------------------------------------------------------------------------- 1 | {%- from salt.file.dirname(tpldir) ~ "/map.jinja" import postgres with context -%} 2 | 3 | postgresql-dead: 4 | service.dead: 5 | - name: {{ postgres.service.name }} 6 | - enable: False 7 | 8 | postgresql-repo-removed: 9 | pkgrepo.absent: 10 | - name: {{ postgres.pkg_repo.name }} 11 | {%- if 'pkg_repo_keyid' in postgres %} 12 | - keyid: {{ postgres.pkg_repo_keyid }} 13 | {%- endif %} 14 | 15 | {% if grains.os_family == 'Debian' %} 16 | postgresql-repo-keyring-removed: 17 | pkg.removed: 18 | - name: pgdg-keyring 19 | {%- endif -%} 20 | 21 | #remove release installed by formula 22 | postgresql-server-removed: 23 | pkg.removed: 24 | - pkgs: 25 | {% if postgres.pkg %} 26 | - {{ postgres.pkg }} 27 | {% endif %} 28 | {% if postgres.pkgs_extra %} 29 | {% for pkg in postgres.pkgs_extra %} 30 | - {{ pkg }} 31 | {% endfor %} 32 | {% endif %} 33 | file.absent: 34 | - names: 35 | - /var/run/postgresql 36 | 37 | {%- if postgres.remove.multiple_releases %} 38 | #search for and cleandown multiple releases 39 | 40 | {% for release in postgres.remove.releases %} 41 | postgresql{{ release }}-server-pkgs-removed: 42 | pkg.purged: 43 | - pkgs: 44 | - {{ postgres.pkg if postgres.pkg else "postgresql" }} 45 | - postgresql-server 46 | - postgresql-libs 47 | - postgresql-contrib 48 | - postgresql-server-{{ release }} 49 | - postgresql-libs-{{ release }} 50 | - postgresql-contrib-{{ release }} 51 | - postgresql{{ release }}-contrib 52 | - postgresql{{ release }}-server 53 | - postgresql{{ release }}-libs 54 | - postgresql{{ release }}-contrib 55 | - postgresql{{ release|replace('.', '') }}-contrib 56 | - postgresql{{ release|replace('.', '') }}-server 57 | - postgresql{{ release|replace('.', '') }}-libs 58 | - postgresql{{ release|replace('.', '') }}-contrib 59 | 60 | {% if 'bin_dir' in postgres %} 61 | {% for bin in postgres.server_bins %} 62 | {% set path = '/usr/pgsql-' + release|string + '/bin/' + bin %} 63 | 64 | postgresql{{ release }}-server-{{ bin }}-alternative-remove: 65 | alternatives.remove: 66 | - name: {{ bin }} 67 | - path: {{ path }} 68 | {% if grains.os in ('Fedora', 'CentOS',) %} 69 | {# bypass bug #} 70 | - onlyif: alternatives --display {{ bin }} 71 | {% else %} 72 | - onlyif: test -f {{ path }} 73 | {% endif %} 74 | 75 | {% endfor %} 76 | {% endif %} 77 | 78 | {%- if postgres.remove.data %} 79 | #allow data loss? default is no 80 | postgresql{{ release }}-dataconf-removed: 81 | file.absent: 82 | - names: 83 | - {{ postgres.conf_dir }} 84 | - {{ postgres.data_dir }} 85 | - /var/lib/postgresql 86 | - /var/lib/pgsql 87 | 88 | {% for name, tblspace in postgres.tablespaces|dictsort() %} 89 | postgresql{{ release }}-tablespace-dir-{{ name }}-removed: 90 | file.absent: 91 | - name: {{ tblspace.directory }} 92 | - require: 93 | - file: postgresql{{ release }}-dataconf-removed 94 | {% endfor %} 95 | {% endif %} 96 | 97 | {% endfor %} 98 | {%- endif %} 99 | -------------------------------------------------------------------------------- /postgres/templates/limit.maxfiles.plist: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | Label 7 | limit.maxfiles 8 | ProgramArguments 9 | 10 | /bin/launchctl 11 | limit 12 | maxfiles 13 | {{ soft_limit }} 14 | {{ hard_limit }} 15 | 16 | RunAtLoad 17 | 18 | ServiceIPC 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /postgres/templates/mac_shortcut.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | shortcutName="${1}" 4 | app="postgres.app" 5 | Source="/Applications/$app" 6 | Destination="{{ homes }}/{{ user }}/Desktop/${shortcutName}" 7 | /usr/bin/osascript -e "tell application \"Finder\" to make alias file to POSIX file \"$Source\" at POSIX file \"$Destination\"" 8 | -------------------------------------------------------------------------------- /postgres/templates/pg_hba.conf.j2: -------------------------------------------------------------------------------- 1 | ###################################################################### 2 | # ATTENTION! Managed by SaltStack. # 3 | # DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN! # 4 | ###################################################################### 5 | # 6 | # PostgreSQL Client Authentication Configuration File 7 | # =================================================== 8 | # 9 | # Refer to the "Client Authentication" section in the PostgreSQL 10 | # documentation for a complete description of this file. 11 | 12 | # DO NOT DISABLE! 13 | # If you change this first entry you will need to make sure that the 14 | # database superuser can access the database using some other method. 15 | # Noninteractive access to all databases is required during automatic 16 | # maintenance (custom daily cronjobs, replication, and similar tasks). 17 | 18 | # Database administrative login by Unix domain socket 19 | local all postgres peer 20 | 21 | # TYPE DATABASE USER ADDRESS METHOD 22 | 23 | {% for acl in acls %} 24 | {%- if acl|first() == 'local' %} 25 | 26 | {%- if acl|length() == 3 %} 27 | {%- do acl.extend(['', 'md5']) %} 28 | {%- elif acl|length() == 4 %} 29 | {%- do acl.insert(3, '') %} 30 | {%- endif %} 31 | 32 | {%- else %} 33 | 34 | {%- if acl|length() == 4 %} 35 | {%- do acl.append('md5') %} 36 | {%- endif %} 37 | 38 | {%- endif %} 39 | {{ '{0:<7} {1:<15} {2:<15} {3:<23} {4}'.format(*acl) }} 40 | {% endfor %} 41 | -------------------------------------------------------------------------------- /postgres/templates/pg_ident.conf.j2: -------------------------------------------------------------------------------- 1 | ###################################################################### 2 | # ATTENTION! Managed by SaltStack. # 3 | # DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN! # 4 | ###################################################################### 5 | # 6 | # PostgreSQL User Name Maps 7 | # ========================= 8 | # 9 | # Refer to the PostgreSQL documentation, chapter "Client 10 | # Authentication" for a complete description. A short synopsis 11 | # follows. 12 | # 13 | # This file controls PostgreSQL user name mapping. It maps external 14 | # user names to their corresponding PostgreSQL user names. Records 15 | # are of the form: 16 | # 17 | # MAPNAME SYSTEM-USERNAME PG-USERNAME 18 | # 19 | # (The uppercase quantities must be replaced by actual values.) 20 | # 21 | # MAPNAME is the (otherwise freely chosen) map name that was used in 22 | # pg_hba.conf. SYSTEM-USERNAME is the detected user name of the 23 | # client. PG-USERNAME is the requested PostgreSQL user name. The 24 | # existence of a record specifies that SYSTEM-USERNAME may connect as 25 | # PG-USERNAME. 26 | # 27 | # If SYSTEM-USERNAME starts with a slash (/), it will be treated as a 28 | # regular expression. Optionally this can contain a capture (a 29 | # parenthesized subexpression). The substring matching the capture 30 | # will be substituted for \1 (backslash-one) if present in 31 | # PG-USERNAME. 32 | # 33 | # Multiple maps may be specified in this file and used by pg_hba.conf. 34 | # 35 | # No map names are defined in the default configuration. If all 36 | # system user names and PostgreSQL user names are the same, you don't 37 | # need anything in this file. 38 | # 39 | # This file is read on server startup and when the postmaster receives 40 | # a SIGHUP signal. If you edit the file on a running system, you have 41 | # to SIGHUP the postmaster for the changes to take effect. You can 42 | # use "pg_ctl reload" to do that. 43 | 44 | # Put your actual configuration here 45 | # ---------------------------------- 46 | 47 | # MAPNAME SYSTEM-USERNAME PG-USERNAME 48 | 49 | {%- for mapping in mappings %} 50 | {{ '{0:<15} {1:<22} {2}'.format(*mapping) -}} 51 | {% endfor %} 52 | -------------------------------------------------------------------------------- /postgres/templates/postgres.sh.j2: -------------------------------------------------------------------------------- 1 | ###################################################################### 2 | # ATTENTION! Managed by SaltStack. # 3 | # DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN! # 4 | ###################################################################### 5 | 6 | if ! echo $PATH | grep -q {{ bin_dir }} ; then 7 | export PATH=$PATH:{{ bin_dir }} 8 | fi 9 | -------------------------------------------------------------------------------- /postgres/upstream.sls: -------------------------------------------------------------------------------- 1 | {%- from tpldir + "/map.jinja" import postgres with context -%} 2 | {%- from tpldir + "/macros.jinja" import format_kwargs with context -%} 3 | 4 | {%- if 'pkg_repo' in postgres -%} 5 | {% set pg_common_version = salt['pkg.version']('postgresql-common') %} 6 | 7 | {%- if postgres.use_upstream_repo == true -%} 8 | 9 | {%- if postgres.add_profile -%} 10 | postgresql-profile: 11 | file.managed: 12 | - name: /etc/profile.d/postgres.sh 13 | - user: root 14 | - group: root 15 | - mode: 644 16 | - template: jinja 17 | - source: salt://postgres/templates/postgres.sh.j2 18 | - defaults: 19 | bin_dir: {{ postgres.bin_dir }} 20 | {%- endif %} 21 | 22 | postgresql-pkg-deps: 23 | pkg.installed: 24 | - pkgs: {{ postgres.pkgs_deps | json }} 25 | 26 | # Add upstream repository for your distro 27 | {% if grains.os_family == 'Debian' %} 28 | {% if salt['pkg.version_cmp'](pg_common_version, '246') <= 0 %} 29 | postgresql-repo-keyring: 30 | pkg.installed: 31 | - sources: 32 | - pgdg-keyring: {{ postgres.pkg_repo_keyring }} 33 | - require_in: 34 | - pkgrepo: postgresql-repo 35 | {%- endif %} 36 | {%- endif %} 37 | 38 | postgresql-repo: 39 | pkgrepo.managed: 40 | {{- format_kwargs(postgres.pkg_repo) }} 41 | - require: 42 | - pkg: postgresql-pkg-deps 43 | 44 | {%- else -%} 45 | 46 | # Remove the repo configuration (and GnuPG key) as requested 47 | postgresql-repo: 48 | pkgrepo.absent: 49 | - name: {{ postgres.pkg_repo.name }} 50 | {%- if 'pkg_repo_keyid' in postgres %} 51 | - keyid: {{ postgres.pkg_repo_keyid }} 52 | {%- endif %} 53 | 54 | {% if grains.os_family == 'Debian' %} 55 | postgresql-repo-keyring: 56 | pkg.removed: 57 | - name: pgdg-keyring 58 | {%- endif -%} 59 | 60 | {%- endif -%} 61 | 62 | {%- elif grains.os not in ('Windows', 'MacOS',) %} 63 | 64 | postgresql-repo: 65 | test.show_notification: 66 | - text: | 67 | PostgreSQL does not provide package repository for {{ salt['grains.get']('osfinger', grains.os) }} 68 | 69 | {%- endif %} 70 | -------------------------------------------------------------------------------- /pre-commit_semantic-release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ############################################################################### 4 | # (A) Update `FORMULA` with `${nextRelease.version}` 5 | ############################################################################### 6 | sed -i -e "s_^\(version:\).*_\1 ${1}_" FORMULA 7 | 8 | 9 | ############################################################################### 10 | # (B) Use `m2r2` to convert automatically produced `.md` docs to `.rst` 11 | ############################################################################### 12 | 13 | # Install `m2r2` 14 | pip3 install m2r2 15 | 16 | # Copy and then convert the `.md` docs 17 | cp ./*.md docs/ 18 | cd docs/ || exit 19 | m2r2 --overwrite ./*.md 20 | 21 | # Change excess `H1` headings to `H2` in converted `CHANGELOG.rst` 22 | sed -i -e '/^=.*$/s/=/-/g' CHANGELOG.rst 23 | sed -i -e '1,4s/-/=/g' CHANGELOG.rst 24 | 25 | # Use for debugging output, when required 26 | # cat AUTHORS.rst 27 | # cat CHANGELOG.rst 28 | 29 | # Return back to the main directory 30 | cd .. 31 | -------------------------------------------------------------------------------- /release-rules.js: -------------------------------------------------------------------------------- 1 | // No release is triggered for the types commented out below. 2 | // Commits using these types will be incorporated into the next release. 3 | // 4 | // NOTE: Any changes here must be reflected in `CONTRIBUTING.md`. 5 | module.exports = [ 6 | {breaking: true, release: 'major'}, 7 | // {type: 'build', release: 'patch'}, 8 | // {type: 'chore', release: 'patch'}, 9 | // {type: 'ci', release: 'patch'}, 10 | {type: 'docs', release: 'patch'}, 11 | {type: 'feat', release: 'minor'}, 12 | {type: 'fix', release: 'patch'}, 13 | {type: 'perf', release: 'patch'}, 14 | {type: 'refactor', release: 'patch'}, 15 | {type: 'revert', release: 'patch'}, 16 | {type: 'style', release: 'patch'}, 17 | {type: 'test', release: 'patch'}, 18 | ]; 19 | -------------------------------------------------------------------------------- /release.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | branch: 'master', 3 | repositoryUrl: 'https://github.com/saltstack-formulas/postgres-formula', 4 | plugins: [ 5 | ['@semantic-release/commit-analyzer', { 6 | preset: 'angular', 7 | releaseRules: './release-rules.js', 8 | }], 9 | '@semantic-release/release-notes-generator', 10 | ['@semantic-release/changelog', { 11 | changelogFile: 'CHANGELOG.md', 12 | changelogTitle: '# Changelog', 13 | }], 14 | ['@semantic-release/exec', { 15 | prepareCmd: 'sh ./pre-commit_semantic-release.sh ${nextRelease.version}', 16 | }], 17 | ['@semantic-release/git', { 18 | assets: ['*.md', 'docs/*.rst', 'FORMULA'], 19 | }], 20 | '@semantic-release/github', 21 | ], 22 | generateNotes: { 23 | preset: 'angular', 24 | writerOpts: { 25 | // Required due to upstream bug preventing all types being displayed. 26 | // Bug: https://github.com/conventional-changelog/conventional-changelog/issues/317 27 | // Fix: https://github.com/conventional-changelog/conventional-changelog/pull/410 28 | transform: (commit, context) => { 29 | const issues = [] 30 | 31 | commit.notes.forEach(note => { 32 | note.title = `BREAKING CHANGES` 33 | }) 34 | 35 | // NOTE: Any changes here must be reflected in `CONTRIBUTING.md`. 36 | if (commit.type === `feat`) { 37 | commit.type = `Features` 38 | } else if (commit.type === `fix`) { 39 | commit.type = `Bug Fixes` 40 | } else if (commit.type === `perf`) { 41 | commit.type = `Performance Improvements` 42 | } else if (commit.type === `revert`) { 43 | commit.type = `Reverts` 44 | } else if (commit.type === `docs`) { 45 | commit.type = `Documentation` 46 | } else if (commit.type === `style`) { 47 | commit.type = `Styles` 48 | } else if (commit.type === `refactor`) { 49 | commit.type = `Code Refactoring` 50 | } else if (commit.type === `test`) { 51 | commit.type = `Tests` 52 | } else if (commit.type === `build`) { 53 | commit.type = `Build System` 54 | // } else if (commit.type === `chore`) { 55 | // commit.type = `Maintenance` 56 | } else if (commit.type === `ci`) { 57 | commit.type = `Continuous Integration` 58 | } else { 59 | return 60 | } 61 | 62 | if (commit.scope === `*`) { 63 | commit.scope = `` 64 | } 65 | 66 | if (typeof commit.hash === `string`) { 67 | commit.shortHash = commit.hash.substring(0, 7) 68 | } 69 | 70 | if (typeof commit.subject === `string`) { 71 | let url = context.repository 72 | ? `${context.host}/${context.owner}/${context.repository}` 73 | : context.repoUrl 74 | if (url) { 75 | url = `${url}/issues/` 76 | // Issue URLs. 77 | commit.subject = commit.subject.replace(/#([0-9]+)/g, (_, issue) => { 78 | issues.push(issue) 79 | return `[#${issue}](${url}${issue})` 80 | }) 81 | } 82 | if (context.host) { 83 | // User URLs. 84 | commit.subject = commit.subject.replace(/\B@([a-z0-9](?:-?[a-z0-9/]){0,38})/g, (_, username) => { 85 | if (username.includes('/')) { 86 | return `@${username}` 87 | } 88 | 89 | return `[@${username}](${context.host}/${username})` 90 | }) 91 | } 92 | } 93 | 94 | // remove references that already appear in the subject 95 | commit.references = commit.references.filter(reference => { 96 | if (issues.indexOf(reference.issue) === -1) { 97 | return true 98 | } 99 | 100 | return false 101 | }) 102 | 103 | return commit 104 | }, 105 | }, 106 | }, 107 | }; 108 | -------------------------------------------------------------------------------- /test/integration/default/README.md: -------------------------------------------------------------------------------- 1 | # InSpec Profile: `default` 2 | 3 | This shows the implementation of the `default` InSpec [profile](https://github.com/inspec/inspec/blob/master/docs/profiles.md). 4 | 5 | ## Verify a profile 6 | 7 | InSpec ships with built-in features to verify a profile structure. 8 | 9 | ```bash 10 | $ inspec check default 11 | Summary 12 | ------- 13 | Location: default 14 | Profile: profile 15 | Controls: 4 16 | Timestamp: 2019-06-24T23:09:01+00:00 17 | Valid: true 18 | 19 | Errors 20 | ------ 21 | 22 | Warnings 23 | -------- 24 | ``` 25 | 26 | ## Execute a profile 27 | 28 | To run all **supported** controls on a local machine use `inspec exec /path/to/profile`. 29 | 30 | ```bash 31 | $ inspec exec default 32 | .. 33 | 34 | Finished in 0.0025 seconds (files took 0.12449 seconds to load) 35 | 8 examples, 0 failures 36 | ``` 37 | 38 | ## Execute a specific control from a profile 39 | 40 | To run one control from the profile use `inspec exec /path/to/profile --controls name`. 41 | 42 | ```bash 43 | $ inspec exec default --controls package 44 | . 45 | 46 | Finished in 0.0025 seconds (files took 0.12449 seconds to load) 47 | 1 examples, 0 failures 48 | ``` 49 | 50 | See an [example control here](https://github.com/inspec/inspec/blob/master/examples/profile/controls/example.rb). 51 | -------------------------------------------------------------------------------- /test/integration/default/controls/services.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | service_name = 'postgresql' 4 | 5 | pg_port = 6 | case platform[:family] 7 | when 'debian', 'suse' 8 | 5433 9 | else 10 | 5432 11 | end 12 | 13 | control 'Postgres service' do 14 | impact 0.5 15 | title 'should be installed, enabled and running' 16 | 17 | describe service(service_name) do 18 | it { should be_installed } 19 | it { should be_enabled } 20 | it { should be_running } 21 | end 22 | 23 | describe port(pg_port) do 24 | it { should be_listening } 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /test/integration/default/controls/share.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # https://docs.chef.io/inspec/profiles/#including-all-controls-from-a-profile 4 | # Could use `include_controls` in this scenario 5 | # include_controls 'share' 6 | 7 | # https://docs.chef.io/inspec/profiles/#selectively-including-controls-from-a-profile 8 | # However, using `require_controls` for more clarity 9 | require_controls 'share' do 10 | control 'Postgres command' 11 | control 'Postgres configuration' 12 | # control 'Postgres service' 13 | end 14 | -------------------------------------------------------------------------------- /test/integration/default/inspec.yml: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # vim: ft=yaml 3 | --- 4 | name: default 5 | title: postgres formula 6 | maintainer: SaltStack Formulas 7 | license: Apache-2.0 8 | summary: Verify that the postgres formula is setup and configured correctly 9 | depends: 10 | - name: share 11 | path: test/integration/share 12 | supports: 13 | - platform-name: debian 14 | - platform-name: ubuntu 15 | - platform-name: centos 16 | - platform-name: fedora 17 | - platform-name: opensuse 18 | - platform-name: suse 19 | - platform-name: freebsd 20 | - platform-name: openbsd 21 | - platform-name: amazon 22 | - platform-name: oracle 23 | - platform-name: arch 24 | - platform-name: gentoo 25 | - platform-name: almalinux 26 | - platform-name: rocky 27 | - platform-name: mac_os_x 28 | - platform: windows 29 | -------------------------------------------------------------------------------- /test/integration/repo/README.md: -------------------------------------------------------------------------------- 1 | # InSpec Profile: `repo` 2 | 3 | This shows the implementation of the `repo` InSpec [profile](https://github.com/inspec/inspec/blob/master/docs/profiles.md). 4 | 5 | ## Verify a profile 6 | 7 | InSpec ships with built-in features to verify a profile structure. 8 | 9 | ```bash 10 | $ inspec check repo 11 | Summary 12 | ------- 13 | Location: repo 14 | Profile: profile 15 | Controls: 4 16 | Timestamp: 2019-06-24T23:09:01+00:00 17 | Valid: true 18 | 19 | Errors 20 | ------ 21 | 22 | Warnings 23 | -------- 24 | ``` 25 | 26 | ## Execute a profile 27 | 28 | To run all **supported** controls on a local machine use `inspec exec /path/to/profile`. 29 | 30 | ```bash 31 | $ inspec exec repo 32 | .. 33 | 34 | Finished in 0.0025 seconds (files took 0.12449 seconds to load) 35 | 8 examples, 0 failures 36 | ``` 37 | 38 | ## Execute a specific control from a profile 39 | 40 | To run one control from the profile use `inspec exec /path/to/profile --controls name`. 41 | 42 | ```bash 43 | $ inspec exec repo --controls package 44 | . 45 | 46 | Finished in 0.0025 seconds (files took 0.12449 seconds to load) 47 | 1 examples, 0 failures 48 | ``` 49 | 50 | See an [example control here](https://github.com/inspec/inspec/blob/master/examples/profile/controls/example.rb). 51 | -------------------------------------------------------------------------------- /test/integration/repo/controls/repository.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | case platform.family 4 | when 'redhat', 'fedora', 'suse' 5 | os_name_repo_file = { 6 | 'opensuse' => '/etc/zypp/repos.d/pgdg-sles-13.repo' 7 | } 8 | os_name_repo_file.default = '/etc/yum.repos.d/pgdg13.repo' 9 | 10 | os_name_repo_url = { 11 | 'amazon' => 'https://download.postgresql.org/pub/repos/yum/13/redhat/rhel-7-$basearch', 12 | 'fedora' => 'https://download.postgresql.org/pub/repos/yum/13/fedora/fedora-$releasever-$basearch', 13 | 'opensuse' => 'https://download.postgresql.org/pub/repos/zypp/13/suse/sles-$releasever-$basearch' 14 | } 15 | os_name_repo_url.default = 'https://download.postgresql.org/pub/repos/yum/13/redhat/rhel-$releasever-$basearch' 16 | 17 | repo_url = os_name_repo_url[platform.name] 18 | repo_file = os_name_repo_file[platform.name] 19 | 20 | when 'debian' 21 | repo_keyring = '/usr/share/postgresql-common/pgdg/apt.postgresql.org.gpg' 22 | repo_file = '/etc/apt/sources.list.d/pgdg.list' 23 | # rubocop:disable Layout/LineLength 24 | repo_url = "deb [signed-by=#{repo_keyring}] http://apt.postgresql.org/pub/repos/apt #{system.platform[:codename]}-pgdg main" 25 | # rubocop:enable Layout/LineLength 26 | end 27 | 28 | control 'Postgresql repository keyring' do 29 | title 'should be installed' 30 | 31 | only_if('Requirement for Debian family') do 32 | os.debian? 33 | end 34 | 35 | describe package('pgdg-keyring') do 36 | it { should be_installed } 37 | end 38 | 39 | describe file(repo_keyring) do 40 | it { should exist } 41 | it { should be_owned_by 'root' } 42 | it { should be_grouped_into 'root' } 43 | its('mode') { should cmp '0644' } 44 | end 45 | end 46 | 47 | control 'Postgresql repository' do 48 | impact 1 49 | title 'should be configured' 50 | describe file(repo_file) do 51 | its('content') { should include repo_url } 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /test/integration/repo/controls/services.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | service_name = 4 | case platform[:family] 5 | when 'redhat', 'fedora', 'suse' 6 | case system.platform[:release] 7 | when 'tumbleweed' 8 | 'postgresql' 9 | else 10 | 'postgresql-13' 11 | end 12 | else 13 | 'postgresql' 14 | end 15 | 16 | pg_port = 17 | case platform[:family] 18 | when 'debian', 'suse' 19 | 5433 20 | else 21 | 5432 22 | end 23 | 24 | control 'Postgres service' do 25 | impact 0.5 26 | title 'should be installed, enabled and running' 27 | 28 | describe service(service_name) do 29 | it { should be_installed } 30 | it { should be_enabled } 31 | it { should be_running } 32 | end 33 | 34 | describe port(pg_port) do 35 | it { should be_listening } 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /test/integration/repo/controls/share.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # https://docs.chef.io/inspec/profiles/#including-all-controls-from-a-profile 4 | # Could use `include_controls` in this scenario 5 | # include_controls 'share' 6 | 7 | # https://docs.chef.io/inspec/profiles/#selectively-including-controls-from-a-profile 8 | # However, using `require_controls` for more clarity 9 | require_controls 'share' do 10 | control 'Postgres command' 11 | control 'Postgres configuration' 12 | # control 'Postgres service' 13 | end 14 | -------------------------------------------------------------------------------- /test/integration/repo/inspec.yml: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # vim: ft=yaml 3 | --- 4 | name: repo 5 | title: postgres formula 6 | maintainer: SaltStack Formulas 7 | license: Apache-2.0 8 | # yamllint disable-line rule:line-length 9 | summary: Verify that the postgres formula is setup and configured correctly (when installing from the upstream repo) 10 | depends: 11 | - name: share 12 | path: test/integration/share 13 | supports: 14 | - platform-name: debian 15 | - platform-name: ubuntu 16 | - platform-name: centos 17 | - platform-name: fedora 18 | - platform-name: opensuse 19 | - platform-name: suse 20 | - platform-name: freebsd 21 | - platform-name: openbsd 22 | - platform-name: amazon 23 | - platform-name: oracle 24 | - platform-name: arch 25 | - platform-name: gentoo 26 | - platform-name: almalinux 27 | - platform-name: rocky 28 | - platform-name: mac_os_x 29 | - platform: windows 30 | -------------------------------------------------------------------------------- /test/integration/share/README.md: -------------------------------------------------------------------------------- 1 | # InSpec Profile: `share` 2 | 3 | This shows the implementation of the `share` InSpec [profile](https://github.com/inspec/inspec/blob/master/docs/profiles.md). 4 | 5 | Its goal is to share the libraries between all profiles. 6 | 7 | ## Libraries 8 | 9 | ### `system` 10 | 11 | The `system` library provides easy access to system dependent information: 12 | 13 | - `system.platform`: based on `inspec.platform`, modify to values that are more consistent from a SaltStack perspective 14 | - `system.platform[:family]` provide a family name for Arch and Gentoo 15 | - `system.platform[:name]` append `linux` to both `amazon` and `oracle`; ensure Windows platforms are resolved as simply `windows` 16 | - `system.platform[:release]` tweak Arch, Amazon Linux, Gentoo, openSUSE and Windows: 17 | - `Arch` is always `base-latest` 18 | - `Amazon Linux` release `2018` is resolved as `1` 19 | - `Gentoo` release is trimmed to its major version number and then the init system is appended (i.e. `sysv` or `sysd`) 20 | - `openSUSE` is resolved as `tumbleweed` if the `platform[:release]` is in date format 21 | - `Windows` uses the widely-used release number (e.g. `8.1` or `2019-server`) in place of the actual system release version 22 | - `system.platform[:finger]` is the concatenation of the name and the major release number (except for Ubuntu, which gives `ubuntu-20.04` for example) 23 | -------------------------------------------------------------------------------- /test/integration/share/controls/command.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Overide by Platform 4 | pg_port = '5432' 5 | pg_port = '5433' if (platform[:family] == 'debian') || (platform[:family] == 'suse') 6 | 7 | control 'Postgres command' do 8 | title 'should match desired lines' 9 | 10 | # Can't use `%Q` here due to the `\` 11 | describe command("su - postgres -c 'psql -p#{pg_port} -qtc \"\\l+ db2\"'") do 12 | its(:stdout) do 13 | should match( 14 | /db2.*remoteUser.*UTF8.*en_US.UTF-8.*en_US.UTF-8.*my_space/ 15 | ) 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /test/integration/share/controls/config.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | control 'Postgres configuration' do 4 | title 'should include the directory' 5 | 6 | describe file('/srv/my_tablespace') do 7 | it { should be_directory } 8 | it { should be_owned_by 'postgres' } 9 | it { should be_grouped_into 'postgres' } 10 | its('mode') { should cmp '0700' } 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /test/integration/share/inspec.yml: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # vim: ft=yaml 3 | --- 4 | name: share 5 | title: InSpec shared resources 6 | maintainer: SaltStack Formulas 7 | license: Apache-2.0 8 | summary: shared resources 9 | supports: 10 | - platform-name: debian 11 | - platform-name: ubuntu 12 | - platform-name: centos 13 | - platform-name: fedora 14 | - platform-name: opensuse 15 | - platform-name: suse 16 | - platform-name: freebsd 17 | - platform-name: openbsd 18 | - platform-name: amazon 19 | - platform-name: oracle 20 | - platform-name: arch 21 | - platform-name: gentoo 22 | - platform-name: almalinux 23 | - platform-name: rocky 24 | - platform-name: mac_os_x 25 | - platform: windows 26 | -------------------------------------------------------------------------------- /test/integration/share/libraries/system.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # system.rb -- InSpec resources for system values 4 | # Author: Daniel Dehennin 5 | # Copyright (C) 2020 Daniel Dehennin 6 | 7 | # rubocop:disable Metrics/ClassLength 8 | class SystemResource < Inspec.resource(1) 9 | name 'system' 10 | 11 | attr_reader :platform 12 | 13 | def initialize 14 | super 15 | @platform = build_platform 16 | end 17 | 18 | private 19 | 20 | def build_platform 21 | { 22 | family: build_platform_family, 23 | name: build_platform_name, 24 | release: build_platform_release, 25 | finger: build_platform_finger, 26 | codename: build_platform_codename 27 | } 28 | end 29 | 30 | def build_platform_family 31 | case inspec.platform[:name] 32 | when 'arch', 'gentoo' 33 | inspec.platform[:name] 34 | else 35 | inspec.platform[:family] 36 | end 37 | end 38 | 39 | def build_platform_name 40 | case inspec.platform[:name] 41 | when 'amazon', 'oracle', 'rocky' 42 | "#{inspec.platform[:name]}linux" 43 | when /^windows_/ 44 | inspec.platform[:family] 45 | else 46 | inspec.platform[:name] 47 | end 48 | end 49 | 50 | # rubocop:disable Metrics/MethodLength,Metrics/AbcSize,Metrics/CyclomaticComplexity 51 | def build_platform_release 52 | case inspec.platform[:name] 53 | when 'amazon' 54 | # `2018` relase is named `1` in `kitchen.yml` 55 | inspec.platform[:release].gsub(/2018.*/, '1') 56 | when 'arch' 57 | 'base-latest' 58 | when 'gentoo' 59 | "#{inspec.platform[:release].split('.')[0]}-#{derive_gentoo_init_system}" 60 | when 'mac_os_x' 61 | inspec.command('sw_vers -productVersion').stdout.to_s 62 | when 'opensuse' 63 | # rubocop:disable Style/NumericLiterals,Layout/LineLength 64 | inspec.platform[:release].to_i > 20210101 ? 'tumbleweed' : inspec.platform[:release] 65 | # rubocop:enable Style/NumericLiterals,Layout/LineLength 66 | when 'windows_8.1_pro' 67 | '8.1' 68 | when 'windows_server_2022_datacenter' 69 | '2022-server' 70 | when 'windows_server_2019_datacenter' 71 | '2019-server' 72 | when 'windows_server_2016_datacenter' 73 | '2016-server' 74 | else 75 | inspec.platform[:release] 76 | end 77 | end 78 | # rubocop:enable Metrics/MethodLength,Metrics/AbcSize,Metrics/CyclomaticComplexity 79 | 80 | def derive_gentoo_init_system 81 | inspec.command('systemctl').exist? ? 'sysd' : 'sysv' 82 | end 83 | 84 | def build_platform_finger 85 | "#{build_platform_name}-#{build_finger_release}" 86 | end 87 | 88 | def build_finger_release 89 | case inspec.platform[:name] 90 | when 'ubuntu' 91 | build_platform_release.split('.').slice(0, 2).join('.') 92 | else 93 | build_platform_release.split('.')[0] 94 | end 95 | end 96 | 97 | # rubocop:disable Metrics/MethodLength,Metrics/CyclomaticComplexity 98 | def build_platform_codename 99 | case build_platform_finger 100 | when 'ubuntu-22.04' 101 | 'jammy' 102 | when 'ubuntu-20.04' 103 | 'focal' 104 | when 'ubuntu-18.04' 105 | 'bionic' 106 | when 'debian-11' 107 | 'bullseye' 108 | when 'debian-10' 109 | 'buster' 110 | when 'debian-9' 111 | 'stretch' 112 | when 'almalinux-8' 113 | "AlmaLinux #{build_platform_release} (Arctic Sphynx)" 114 | when 'amazonlinux-2' 115 | 'Amazon Linux 2' 116 | when 'arch-base-latest' 117 | 'Arch Linux' 118 | when 'centos-7' 119 | 'CentOS Linux 7 (Core)' 120 | when 'centos-8' 121 | 'CentOS Stream 8' 122 | when 'opensuse-tumbleweed' 123 | 'openSUSE Tumbleweed' 124 | when 'opensuse-15' 125 | "openSUSE Leap #{build_platform_release}" 126 | when 'oraclelinux-8', 'oraclelinux-7' 127 | "Oracle Linux Server #{build_platform_release}" 128 | when 'gentoo-2-sysd', 'gentoo-2-sysv' 129 | 'Gentoo/Linux' 130 | when 'rockylinux-8' 131 | "Rocky Linux #{build_platform_release} (Green Obsidian)" 132 | else 133 | '' 134 | end 135 | end 136 | # rubocop:enable Metrics/MethodLength,Metrics/CyclomaticComplexity 137 | end 138 | # rubocop:enable Metrics/ClassLength 139 | -------------------------------------------------------------------------------- /test/salt/pillar/postgres.sls: -------------------------------------------------------------------------------- 1 | # Port to use for the cluster -- can be used to provide a non-standard port 2 | # NOTE: If already set in the minion config, that value takes priority 3 | 4 | {%- if grains.os_family not in ['Debian', 'Suse'] %} 5 | postgres.port: '5432' 6 | {%- else %} 7 | postgres.port: '5433' 8 | {%- endif %} 9 | 10 | postgres: 11 | use_upstream_repo: false 12 | 13 | # ### MACOS 14 | # # Set to 'postgresapp' OR 'homebrew' for MacOS 15 | # # use_upstream_repo: 'postgresapp' 16 | # # use_upstream_repo: 'homebrew' 17 | 18 | # # PACKAGE 19 | # # These pillars are typically never required. 20 | # # pkg: 'postgresql' 21 | # # pkg_client: 'postgresql-client' 22 | # # service: postgresql 23 | # pkgs_extra: 24 | # - postgresql-contrib 25 | # - postgresql-plpython 26 | 27 | # CLUSTER 28 | # The default `encoding` is derived from the `locale` so not recommended 29 | # to provide a value for it unless necessary 30 | cluster: 31 | locale: en_US.UTF-8 32 | # encoding: UTF8 33 | 34 | # #'Alternatives system' priority incremental. 0 disables feature. 35 | # linux: 36 | # altpriority: 30 37 | # 38 | # # macos limits 39 | # limits: 40 | # soft: 64000 41 | # hard: 128000 42 | 43 | # POSTGRES 44 | # Append the lines under this item to your postgresql.conf file. 45 | # Pay attention to indent exactly with 4 spaces for all lines. 46 | postgresconf: |- 47 | listen_addresses = '*' # listen on all interfaces 48 | 49 | # Path to the `pg_hba.conf` file Jinja template on Salt Fileserver 50 | pg_hba.conf: salt://postgres/templates/pg_hba.conf.j2 51 | 52 | # This section covers ACL management in the ``pg_hba.conf`` file. 53 | # acls list controls: which hosts are allowed to connect, how clients 54 | # are authenticated, which PostgreSQL user names they can use, which 55 | # databases they can access. Records take one of these forms: 56 | # 57 | # acls: 58 | # - ['local', 'DATABASE', 'USER', 'METHOD'] 59 | # - ['host', 'DATABASE', 'USER', 'ADDRESS', 'METHOD'] 60 | # - ['hostssl', 'DATABASE', 'USER', 'ADDRESS', 'METHOD'] 61 | # - ['hostnossl', 'DATABASE', 'USER', 'ADDRESS', 'METHOD'] 62 | # 63 | # The uppercase items must be replaced by actual values. 64 | # METHOD could be omitted, 'md5' will be appended by default. 65 | # 66 | # If ``acls`` item value is empty ('', [], null), then the contents of 67 | # ``pg_hba.conf`` file will not be touched at all. 68 | acls: 69 | - ['local', 'db0', 'connuser', 'peer map=users_as_appuser'] 70 | - ['local', 'db1', 'localUser'] 71 | - ['host', 'db2', 'remoteUser', '192.168.33.0/24'] 72 | 73 | identity_map: 74 | - ['users_as_appuser', 'jdoe', 'connuser'] 75 | - ['users_as_appuser', 'jsmith', 'connuser'] 76 | 77 | # Backup extension for configuration files, defaults to ``.bak``. 78 | # Set ``False`` to stop creation of backups when config files change. 79 | {%- if salt['status.time']|default(none) is callable %} 80 | config_backup: ".backup@{{ salt['status.time']('%y-%m-%d_%H:%M:%S') }}" 81 | {%- endif %} 82 | 83 | {# {%- if grains['init'] == 'unknown' %} #} 84 | {# #} 85 | {# # If Salt is unable to detect init system running in the scope of state run, #} 86 | {# # probably we are trying to bake a container/VM image with PostgreSQL. #} 87 | {# # Use ``bake_image`` setting to control how PostgreSQL will be started: if set #} 88 | {# # to ``True`` the raw ``pg_ctl`` will be utilized instead of packaged init #} 89 | {# # script, job or unit run with Salt ``service`` state. #} 90 | {# bake_image: True #} 91 | {# #} 92 | {# {%- endif %} #} 93 | 94 | # Create/remove users, tablespaces, databases, schema and extensions. 95 | # Each of these dictionaries contains PostgreSQL entities which 96 | # mapped to the ``postgres_*`` Salt states with arguments. See the Salt 97 | # documentation to get all supported argument for a particular state. 98 | # 99 | # Format is the following: 100 | # 101 | #: 102 | # NAME: 103 | # ensure: # 'present' is the default 104 | # ARGUMENT: VALUE 105 | # ... 106 | # 107 | # where 'NAME' is the state name, 'ARGUMENT' is the kwarg name, and 108 | # 'VALUE' is kwarg value. 109 | # 110 | # For example, the Pillar: 111 | # 112 | # users: 113 | # testUser: 114 | # password: test 115 | # 116 | # will render such state: 117 | # 118 | # postgres_user-testUser: 119 | # postgres_user.present: 120 | # - name: testUser 121 | # - password: test 122 | users: 123 | localUser: 124 | ensure: present 125 | password: '98ruj923h4rf' 126 | createdb: False 127 | createroles: False 128 | inherit: True 129 | replication: False 130 | 131 | remoteUser: 132 | ensure: present 133 | password: '98ruj923h4rf' 134 | createdb: False 135 | createroles: False 136 | inherit: True 137 | replication: False 138 | 139 | absentUser: 140 | ensure: absent 141 | 142 | # tablespaces to be created 143 | tablespaces: 144 | my_space: 145 | directory: /srv/my_tablespace 146 | owner: localUser 147 | 148 | # databases to be created 149 | databases: 150 | db1: 151 | owner: localUser 152 | template: template0 153 | lc_ctype: en_US.UTF-8 154 | lc_collate: en_US.UTF-8 155 | db2: 156 | owner: remoteUser 157 | template: template0 158 | lc_ctype: en_US.UTF-8 159 | lc_collate: en_US.UTF-8 160 | tablespace: my_space 161 | # set custom schema 162 | schemas: 163 | public: 164 | owner: localUser 165 | # enable per-db extension 166 | {#- TODO: Find a way to only disable this for the `default` suite, since it works with the `repo` suite #} 167 | {%- if grains.os_family == 'Debian' and salt['grains.get']('osfinger') != 'Debian-9' %} 168 | extensions: 169 | uuid-ossp: 170 | schema: 'public' 171 | {%- endif %} 172 | 173 | # optional schemas to enable on database 174 | schemas: 175 | uuid-ossp: 176 | dbname: db1 177 | owner: localUser 178 | 179 | # optional extensions to install in schema 180 | {#- TODO: Find a way to only disable this for the `default` suite, since it works with the `repo` suite #} 181 | {%- if grains.os_family == 'Debian' and salt['grains.get']('osfinger') != 'Debian-9' %} 182 | extensions: 183 | uuid-ossp: 184 | schema: uuid-ossp 185 | maintenance_db: db1 186 | # postgis: {} 187 | {%- endif %} 188 | 189 | # remove: 190 | # data: True 191 | # multiple_releases: True 192 | # releases: ['9.6', '10',] 193 | 194 | # vim: ft=yaml ts=2 sts=2 sw=2 et 195 | -------------------------------------------------------------------------------- /test/salt/pillar/repo.sls: -------------------------------------------------------------------------------- 1 | --- 2 | postgres: 3 | use_upstream_repo: true 4 | version: '13' 5 | --------------------------------------------------------------------------------