From 631d9b82d61cd8515e3fd48785176a05ef6f090c Mon Sep 17 00:00:00 2001 From: noelmcloughlin Date: Tue, 3 Nov 2020 00:00:54 +0000 Subject: [PATCH] refactor(rewrite): modernize formula and fresh start - align tom template formula - fix bugs - add Windows support - Add saltstack dockercompose module support - Get rid of confusing old legacy spagetti jinja conditionals - Travis CI (package/archive) is passing - Windows is passing - Fixes/obsoletes: #252, #249, #243, #236, #234, #219, #202, #191 - Fixes/obsoletes: #190, #160, #95, #85, #74 - Includes #251 and #253 - Add Swarm support BREAKING CHANGE: This version is not backwards compatible. Update your states and pillar data to align with new formula. - MacOS was not tested in this PR but hopefully no regression. - docker.containers: sls was simplified (raise PR if regression) --- .travis.yml | 76 ++- docker/clean.sls | 54 +- docker/codenamemap.yaml | 39 +- docker/compose-ng.sls | 130 ----- docker/compose.sls | 25 - docker/compose/build.sls | 22 + docker/compose/clean.sls | 5 + docker/compose/get.sls | 19 + docker/compose/init.sls | 5 + docker/compose/kill.sls | 22 + docker/compose/networks/clean.sls | 22 + docker/compose/networks/init.sls | 5 + docker/compose/networks/install.sls | 22 + docker/compose/ng.sls | 137 +++++ docker/compose/pause.sls | 22 + docker/compose/ps.sls | 19 + docker/compose/pull.sls | 22 + docker/compose/restart.sls | 22 + docker/compose/rm.sls | 22 + docker/compose/service_create.sls | 25 + docker/compose/service_remove.sls | 22 + docker/compose/service_set_tag.sls | 25 + docker/compose/service_upsert.sls | 25 + .../compose/software/alternatives/clean.sls | 18 + docker/compose/software/alternatives/init.sls | 5 + .../compose/software/alternatives/install.sls | 44 ++ docker/compose/software/binary/clean.sls | 25 + docker/compose/software/binary/init.sls | 5 + docker/compose/software/binary/install.sls | 64 +++ docker/compose/software/clean.sls | 7 + docker/compose/software/init.sls | 7 + docker/compose/software/package/clean.sls | 24 + docker/compose/software/package/init.sls | 5 + docker/compose/software/package/install.sls | 40 ++ docker/compose/start.sls | 22 + docker/compose/stop.sls | 22 + docker/compose/unpause.sls | 22 + docker/compose/up.sls | 22 + docker/containers.sls | 45 -- docker/containers/absent.sls | 22 + docker/containers/clean.sls | 6 + docker/containers/init.sls | 5 + docker/containers/running.sls | 20 + docker/containers/stopped.sls | 17 + docker/cpuarchmap.yaml | 18 + docker/defaults.yaml | 149 +++-- docker/files/composetest/Dockerfile | 11 + docker/files/composetest/app.py | 23 + docker/files/composetest/docker-compose.yml | 13 + docker/files/composetest/requirements.txt | 3 + docker/files/config | 24 - docker/files/default/config.sh.jinja | 6 + docker/files/default/systemd.ini.jinja | 19 + docker/files/macros.jinja | 16 + docker/files/service_file.jinja | 20 - docker/files/systemd.conf | 28 - docker/files/upstart.conf | 37 -- docker/files/upstart.conf.deprecated.registry | 30 - docker/init.sls | 9 +- docker/install.sls | 134 ----- docker/kernel.sls | 31 -- docker/libtofs.jinja | 101 ++++ docker/macosapp/init.sls | 11 - docker/macosapp/install.sls | 60 -- docker/map.jinja | 124 +++-- docker/osarchmap.yaml | 72 +++ docker/osfamilymap.yaml | 139 +++-- docker/osfingermap.yaml | 35 ++ docker/osmap.yaml | 28 +- docker/registry.sls | 26 - docker/remove.sls | 8 - docker/repo.sls | 59 -- docker/software/alternatives/clean.sls | 18 + docker/software/alternatives/init.sls | 5 + docker/software/alternatives/install.sls | 44 ++ docker/software/archive/clean.sls | 25 + docker/software/archive/init.sls | 5 + docker/software/archive/install.sls | 105 ++++ docker/software/clean.sls | 10 + docker/software/config/clean.sls | 18 + docker/software/config/file.sls | 36 ++ docker/software/config/init.sls | 5 + docker/software/desktop/clean.sls | 13 + docker/software/desktop/init.sls | 5 + docker/software/desktop/install.sls | 63 +++ docker/software/init.sls | 10 + docker/software/package/clean.sls | 47 ++ docker/software/package/init.sls | 5 + docker/software/package/install.sls | 62 +++ docker/software/package/repo/clean.sls | 12 + docker/software/package/repo/init.sls | 5 + docker/software/package/repo/install.sls | 19 + docker/software/service/clean.sls | 26 + docker/software/service/init.sls | 5 + docker/software/service/running.sls | 78 +++ docker/swarm/clean.sls | 5 + docker/swarm/create_service.sls | 16 + docker/swarm/init.sls | 5 + docker/swarm/joinswarm.sls | 16 + docker/swarm/leaveswarm.sls | 15 + docker/swarm/node_ls.sls | 16 + docker/swarm/remove_node.sls | 16 + docker/swarm/remove_service.sls | 16 + docker/swarm/swarm_init.sls | 16 + docker/swarm/swarm_service_info.sls | 16 + docker/swarm/swarm_tokens.sls | 14 + docker/swarm/update_node.sls | 16 + docs/CONTRIBUTING.rst | 186 +++++++ docs/CONTRIBUTING_DOCS.rst | 96 ++++ docs/README.rst | 313 ++++++----- docs/TOFS_pattern.rst | 518 ++++++++++++++++++ docs/_static/css/custom.css | 21 + docs/conf.py | 173 ++++++ docs/index.rst | 20 + kitchen.yml | 235 ++++++-- pillar.example | 285 +++++----- .../{default => archive}/README.md | 12 +- .../archive/controls/archive_spec.rb | 94 ++++ .../{default => archive}/controls/config.rb | 2 +- test/integration/archive/controls/package.rb | 5 + .../{default => archive}/controls/service.rb | 4 +- .../{default => archive}/inspec.yml | 2 +- test/integration/clean/README.md | 50 ++ .../clean/controls/archive_spec.rb | 15 + test/integration/clean/controls/config.rb | 9 + test/integration/clean/controls/package.rb | 21 + test/integration/clean/controls/service.rb | 14 + test/integration/clean/inspec.yml | 18 + test/integration/default/controls/package.rb | 21 - test/integration/package/README.md | 50 ++ .../package/controls/archive_spec.rb | 26 + test/integration/package/controls/config.rb | 14 + test/integration/package/controls/package.rb | 21 + test/integration/package/controls/service.rb | 10 + test/integration/package/inspec.yml | 18 + test/salt/pillar/archive.sls | 1 + test/salt/pillar/package.sls | 161 ++++++ 137 files changed, 4388 insertions(+), 1283 deletions(-) delete mode 100644 docker/compose-ng.sls delete mode 100644 docker/compose.sls create mode 100644 docker/compose/build.sls create mode 100644 docker/compose/clean.sls create mode 100644 docker/compose/get.sls create mode 100644 docker/compose/init.sls create mode 100644 docker/compose/kill.sls create mode 100644 docker/compose/networks/clean.sls create mode 100644 docker/compose/networks/init.sls create mode 100644 docker/compose/networks/install.sls create mode 100644 docker/compose/ng.sls create mode 100644 docker/compose/pause.sls create mode 100644 docker/compose/ps.sls create mode 100644 docker/compose/pull.sls create mode 100644 docker/compose/restart.sls create mode 100644 docker/compose/rm.sls create mode 100644 docker/compose/service_create.sls create mode 100644 docker/compose/service_remove.sls create mode 100644 docker/compose/service_set_tag.sls create mode 100644 docker/compose/service_upsert.sls create mode 100644 docker/compose/software/alternatives/clean.sls create mode 100644 docker/compose/software/alternatives/init.sls create mode 100644 docker/compose/software/alternatives/install.sls create mode 100644 docker/compose/software/binary/clean.sls create mode 100644 docker/compose/software/binary/init.sls create mode 100644 docker/compose/software/binary/install.sls create mode 100644 docker/compose/software/clean.sls create mode 100644 docker/compose/software/init.sls create mode 100644 docker/compose/software/package/clean.sls create mode 100644 docker/compose/software/package/init.sls create mode 100644 docker/compose/software/package/install.sls create mode 100644 docker/compose/start.sls create mode 100644 docker/compose/stop.sls create mode 100644 docker/compose/unpause.sls create mode 100644 docker/compose/up.sls delete mode 100644 docker/containers.sls create mode 100644 docker/containers/absent.sls create mode 100644 docker/containers/clean.sls create mode 100644 docker/containers/init.sls create mode 100644 docker/containers/running.sls create mode 100644 docker/containers/stopped.sls create mode 100644 docker/cpuarchmap.yaml create mode 100644 docker/files/composetest/Dockerfile create mode 100644 docker/files/composetest/app.py create mode 100644 docker/files/composetest/docker-compose.yml create mode 100644 docker/files/composetest/requirements.txt delete mode 100644 docker/files/config create mode 100644 docker/files/default/config.sh.jinja create mode 100644 docker/files/default/systemd.ini.jinja create mode 100644 docker/files/macros.jinja delete mode 100644 docker/files/service_file.jinja delete mode 100644 docker/files/systemd.conf delete mode 100644 docker/files/upstart.conf delete mode 100644 docker/files/upstart.conf.deprecated.registry delete mode 100644 docker/install.sls delete mode 100644 docker/kernel.sls create mode 100644 docker/libtofs.jinja delete mode 100644 docker/macosapp/init.sls delete mode 100644 docker/macosapp/install.sls create mode 100644 docker/osarchmap.yaml create mode 100644 docker/osfingermap.yaml delete mode 100644 docker/registry.sls delete mode 100644 docker/remove.sls delete mode 100644 docker/repo.sls create mode 100644 docker/software/alternatives/clean.sls create mode 100644 docker/software/alternatives/init.sls create mode 100644 docker/software/alternatives/install.sls create mode 100644 docker/software/archive/clean.sls create mode 100644 docker/software/archive/init.sls create mode 100644 docker/software/archive/install.sls create mode 100644 docker/software/clean.sls create mode 100644 docker/software/config/clean.sls create mode 100644 docker/software/config/file.sls create mode 100644 docker/software/config/init.sls create mode 100644 docker/software/desktop/clean.sls create mode 100644 docker/software/desktop/init.sls create mode 100644 docker/software/desktop/install.sls create mode 100644 docker/software/init.sls create mode 100644 docker/software/package/clean.sls create mode 100644 docker/software/package/init.sls create mode 100644 docker/software/package/install.sls create mode 100644 docker/software/package/repo/clean.sls create mode 100644 docker/software/package/repo/init.sls create mode 100644 docker/software/package/repo/install.sls create mode 100644 docker/software/service/clean.sls create mode 100644 docker/software/service/init.sls create mode 100644 docker/software/service/running.sls create mode 100644 docker/swarm/clean.sls create mode 100644 docker/swarm/create_service.sls create mode 100644 docker/swarm/init.sls create mode 100644 docker/swarm/joinswarm.sls create mode 100644 docker/swarm/leaveswarm.sls create mode 100644 docker/swarm/node_ls.sls create mode 100644 docker/swarm/remove_node.sls create mode 100644 docker/swarm/remove_service.sls create mode 100644 docker/swarm/swarm_init.sls create mode 100644 docker/swarm/swarm_service_info.sls create mode 100644 docker/swarm/swarm_tokens.sls create mode 100644 docker/swarm/update_node.sls create mode 100644 docs/CONTRIBUTING.rst create mode 100644 docs/CONTRIBUTING_DOCS.rst create mode 100644 docs/TOFS_pattern.rst create mode 100644 docs/_static/css/custom.css create mode 100644 docs/conf.py create mode 100644 docs/index.rst rename test/integration/{default => archive}/README.md (81%) create mode 100644 test/integration/archive/controls/archive_spec.rb rename test/integration/{default => archive}/controls/config.rb (91%) create mode 100644 test/integration/archive/controls/package.rb rename test/integration/{default => archive}/controls/service.rb (72%) rename test/integration/{default => archive}/inspec.yml (96%) create mode 100644 test/integration/clean/README.md create mode 100644 test/integration/clean/controls/archive_spec.rb create mode 100644 test/integration/clean/controls/config.rb create mode 100644 test/integration/clean/controls/package.rb create mode 100644 test/integration/clean/controls/service.rb create mode 100644 test/integration/clean/inspec.yml delete mode 100644 test/integration/default/controls/package.rb create mode 100644 test/integration/package/README.md create mode 100644 test/integration/package/controls/archive_spec.rb create mode 100644 test/integration/package/controls/config.rb create mode 100644 test/integration/package/controls/package.rb create mode 100644 test/integration/package/controls/service.rb create mode 100644 test/integration/package/inspec.yml create mode 120000 test/salt/pillar/archive.sls create mode 100644 test/salt/pillar/package.sls diff --git a/.travis.yml b/.travis.yml index 691efa1b..c73727c4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,12 +11,22 @@ version: '~> 1.0' language: 'ruby' cache: 'bundler' +env: + global: + - CHANGE_MINIKUBE_NONE_USER=true + - MINIKUBE_WANTUPDATENOTIFICATION=false + - MINIKUBE_WANTREPORTERRORPROMPT=false + - MINIKUBE_HOME=$HOME + - CHANGE_MINIKUBE_NONE_USER=true + - KUBECONFIG=$HOME/.kube/config + ## Services config services: - docker ## Script to run for the test stage script: + - env - bin/kitchen verify "${INSTANCE}" ## Stages and jobs matrix @@ -72,35 +82,43 @@ jobs: ## Define the rest of the matrix based on Kitchen testing # Make sure the instances listed below match up with # the `platforms` defined in `kitchen.yml` - - env: INSTANCE=default-debian-10-master-py3 - # - env: INSTANCE=default-ubuntu-1804-master-py3 - # - env: INSTANCE=default-centos-8-master-py3 - # - env: INSTANCE=default-fedora-31-master-py3 - # - env: INSTANCE=default-opensuse-leap-151-master-py3 - # - env: INSTANCE=default-amazonlinux-2-master-py3 - # - env: INSTANCE=default-debian-10-2019-2-py3 - - env: INSTANCE=default-debian-9-2019-2-py3 - - env: INSTANCE=default-ubuntu-1804-2019-2-py3 - # - env: INSTANCE=default-centos-8-2019-2-py3 - # - env: INSTANCE=default-fedora-31-2019-2-py3 - # - env: INSTANCE=default-opensuse-leap-151-2019-2-py3 - # - env: INSTANCE=default-centos-7-2019-2-py2 - # - env: INSTANCE=default-amazonlinux-2-2019-2-py3 - - env: INSTANCE=default-arch-base-latest-2019-2-py2 - # - env: INSTANCE=default-fedora-30-2018-3-py3 - - env: INSTANCE=default-debian-9-2018-3-py2 - # - env: INSTANCE=default-ubuntu-1604-2018-3-py2 - # - env: INSTANCE=default-centos-7-2018-3-py2 - # - env: INSTANCE=default-opensuse-leap-151-2018-3-py2 - # - env: INSTANCE=default-amazonlinux-1-2018-3-py2 - # - env: INSTANCE=default-arch-base-latest-2018-3-py2 - # - env: INSTANCE=default-debian-8-2017-7-py2 - - env: INSTANCE=default-ubuntu-1604-2017-7-py2 - # - env: INSTANCE=default-centos-6-2017-7-py2 - # - env: INSTANCE=default-fedora-30-2017-7-py2 - # - env: INSTANCE=default-opensuse-leap-151-2017-7-py2 - # - env: INSTANCE=default-amazonlinux-1-2017-7-py2 - # - env: INSTANCE=default-arch-base-latest-2017-7-py2 + # env: INSTANCE=archive-debian-10-master-py3 + - env: INSTANCE=package-debian-10-master-py3 + - env: INSTANCE=archive-ubuntu-1804-master-py3 + - env: INSTANCE=clean-ubuntu-1804-master-py3 + - env: INSTANCE=package-ubuntu-1804-master-py3 + - env: INSTANCE=archive-centos-8-master-py3 + - env: INSTANCE=package-centos-8-master-py3 + # env: INSTANCE=archive-fedora-31-master-py3 + - env: INSTANCE=package-fedora-31-master-py3 + - env: INSTANCE=archive-opensuse-leap-151-master-py3 + - env: INSTANCE=package-opensuse-leap-151-master-py3 + - env: INSTANCE=archive-amazonlinux-2-master-py3 + # env: INSTANCE=package-amazonlinux-2-master-py3 + # - env: INSTANCE=archive-debian-10-3000-2-py3 + # - env: INSTANCE=archive-debian-9-3000-2-py3 + # - env: INSTANCE=archive-ubuntu-1804-3000-2-py3 + # - env: INSTANCE=archive-centos-8-3000-2-py3 + # - env: INSTANCE=archive-centos-7-3000-2-py3 + # - env: INSTANCE=archive-fedora-31-3000-2-py3 + # - env: INSTANCE=archive-opensuse-leap-151-3000-2-py3 + # - env: INSTANCE=archive-amazonlinux-2-3000-2-py3 + # - env: INSTANCE=archive-ubuntu-1804-3000-2-py2 + # - env: INSTANCE=archive-ubuntu-1604-3000-2-py2 + # - env: INSTANCE=archive-archive-base-latest-3000-2-py2 + # - env: INSTANCE=archive-debian-10-2019-2-py3 + # - env: INSTANCE=archive-debian-9-2019-2-py3 + # - env: INSTANCE=archive-ubuntu-1804-2019-2-py3 + # - env: INSTANCE=archive-ubuntu-1604-2019-2-py3 + # - env: INSTANCE=archive-centos-8-2019-2-py3 + # - env: INSTANCE=archive-centos-7-2019-2-py3 + # - env: INSTANCE=archive-fedora-31-2019-2-py3 + # env: INSTANCE=archive-opensuse-leap-151-2019-2-py3 + # - env: INSTANCE=archive-amazonlinux-2-2019-2-py3 + # - env: INSTANCE=archive-centos-6-2019-2-py2 + # - env: INSTANCE=archive-amazonlinux-1-2019-2-py2 + - env: INSTANCE=archive-arch-base-latest-2019-2-py2 + - env: INSTANCE=package-arch-base-latest-2019-2-py2 ## Define the release stage that runs `semantic-release` - stage: 'release' diff --git a/docker/clean.sls b/docker/clean.sls index 87fd167f..fbe4a05c 100644 --- a/docker/clean.sls +++ b/docker/clean.sls @@ -1,53 +1,7 @@ # -*- coding: utf-8 -*- # vim: ft=sls -{% from "docker/map.jinja" import docker with context %} -docker-packages-cleaned-service-dead: - service.dead: - - name: docker - {% if "process_signature" in docker %} - - sig: {{ docker.process_signature }} - - onlyif: ps -ef | grep "{{ docker.process_signature }}" ##stop stderr from sig - {% endif %} - - require_in: - - pkg: docker-packages-cleaned - -docker-packages-cleaned: - pkg.removed: - - pkgs: - - {{ docker.pkg.old_name if docker.use_old_repo else docker.pkg.name }} - - docker - - docker.io - - docker-client - - docker-client-latest - - docker-common - - docker-latest - - docker-latest-logrotate - - docker-logrotate - - docker-selinux - - docker-engine-selinux - - docker-engine - -{# remove pip packages installed by formula #} - -docker-pips-removed: - pip.removed: - - onlyif: python -m pip --version >/dev/null 2>&1 - - names: - {% if docker.compose_version -%} - - docker-compose == {{ docker.compose_version }} - {% else -%} - - docker-compose - {% endif -%} - {% if docker.install_docker_py -%} - {% if "python_package" in docker -%} - - {{ docker.python_package }} - {% elif "pip_version" in docker -%} - - docker-py {{ docker.pip_version }} - {% else -%} - - docker-py - {%- endif -%} - {% endif %} - {%- if docker.proxy %} - - proxy: {{ docker.proxy }} - {%- endif %} +include: + # .containers.clean + - .compose.clean + - .software.clean diff --git a/docker/codenamemap.yaml b/docker/codenamemap.yaml index fa180304..3895f452 100644 --- a/docker/codenamemap.yaml +++ b/docker/codenamemap.yaml @@ -2,42 +2,31 @@ # vim: ft=yaml --- wheezy: - kernel: - pkg: + pkg: + deps: name: linux-image-amd64 - fromrepo: wheezy-backports - pkgrepo: - name: deb http://http.debian.net/debian wheezy-backports main - humanname: Wheezy Backports - dist: wheezy-backports - pkgs: [] jessie: - kernel: - pkg: + pkg: + deps: name: linux-image-amd64 - fromrepo: jessie-backports - pkgrepo: - name: deb http://http.debian.net/debian jessie-backports main - humanname: Jessie Backports - dist: jessie-backports - pkgs: [] trusty: - kernel: - pkgs: + pkg: + deps: - linux-image-extra-virtual - linux-image-extra-{{ grains.kernelrelease }} precise: - kernel: - pkgs: + pkg: + deps: - linux-image-generic-lts-raring - linux-headers-generic-lts-raring CentOS Linux 7 (Core): - pkgs: - - yum-plugin-versionlock - - python2-pip - # python-docker - - rpmdevtools + pkg: + deps: + - yum-plugin-versionlock + - python2-pip + - python-docker-py + - rpmdevtools diff --git a/docker/compose-ng.sls b/docker/compose-ng.sls deleted file mode 100644 index 7a77163a..00000000 --- a/docker/compose-ng.sls +++ /dev/null @@ -1,130 +0,0 @@ -{#- Get the `tplroot` from `tpldir` #} -{%- set tplroot = tpldir.split('/')[0] %} -{%- from tplroot ~ "/map.jinja" import docker with context %} -{%- from tplroot ~ "/map.jinja" import compose with context %} - -include: - - docker.compose - -{%- for name, container in compose.items() %} - {%- set id = container.container_name|d(name) %} - {%- set required_containers = [] %} - {%- if grains['saltversioninfo'] >= [2017, 7, 0] %} -{{ id }}: - docker_image.present: - - force: {{ docker.containers.force_present }} - {%- else %} -{{ id }} image: - docker.pulled: - {%- endif %} - {%- if ':' in container.image %} - {%- set image = container.image.split(':',1) %} - - name: {{ image[0] }} - - tag: {{ image[1] }} - {%- else %} - - name: {{ container.image }} - {%- endif %} - -{{ id }} container: - {%- if grains['saltversioninfo'] >= [2017, 7, 0] %} - docker_container.running: - - skip_translate: {{ docker.containers.skip_translate }} - - force: {{ docker.containers.force_running }} - - privileged: {{ container.privileged|default(False) }} - {%- else %} - {%- if 'dvc' in container and container.dvc %} - docker.installed: - {%- else %} - docker.running: - {%- endif %} - {%- endif %} - - name: {{ id }} - - image: {{ container.image }} - {%- if 'command' in container %} - - command: {{ container.command }} - {%- endif %} - {%- if 'working_dir' in container %} - - working_dir: {{ container.working_dir }} - {%- endif %} - {%- if 'volume_driver' in container %} - - volume_driver: {{ container.volume_driver }} - {%- endif %} - {%- if 'userns_mode' in container %} - - userns_mode: {{ container.userns_mode }} - {%- endif %} - {%- if 'user' in container %} - - user: {{ container.user }} - {%- endif %} - {%- if 'environment' in container and container.environment is iterable %} - - environment: - {%- for variable, value in container.environment.items() %} - - {{ variable }}: {{ value }} - {%- endfor %} - {%- endif %} - {%- if 'ports' in container and container.ports is iterable %} - - port_bindings: - {%- for port_mapping in container.ports %} - {%- if port_mapping is string %} - {%- set mapping = port_mapping.split(':',2) %} - {%- if mapping|length < 2 %} - - "{{ mapping[0] }}" - {%- elif mapping|length > 2 %} - - "{{ mapping[0] }}:{{ mapping[1] }}:{{ mapping[-1] }}" - {%- else %} - - "{{ mapping[0] }}:{{ mapping[-1] }}" - {%- endif %} - {%- elif port_mapping is mapping %} - - {{ port_mapping }} - {%- endif %} - {%- endfor %} - {%- endif %} - {%- if 'volumes' in container %} - - binds: - {%- for bind in container.volumes %} - {%- set mapping = bind.rsplit(':', 1) %} - {%- if mapping|length > 1 %} - - "{{ mapping[0] }}:{{ mapping[-1] }}" - {%- else %} - - "{{ mapping[0] }}" - {%- endif %} - {%- endfor %} - {%- endif %} - {%- if 'volumes_from' in container %} - - volumes_from: - {%- for volume in container.volumes_from %} - {%- do required_containers.append(volume) %} - - {{ volume }} - {%- endfor %} - {%- endif %} - {%- if 'links' in container %} - - links: - {%- for link in container.links %} - {%- set name, alias = link.split(':',1) %} - {%- do required_containers.append(name) %} - {{ name }}: {{ alias }} - {%- endfor %} - {%- endif %} - {%- if 'restart' in container %} - {%- set policy = container.restart.split(':',1) %} - {%- if policy|length < 2 %} - - restart_policy: {{ policy[0] }} - {%- else %} - - restart_policy: {{ policy[0] }}:{{ policy[-1] }} - {%- endif %} - {%- endif %} - - require: - {%- if grains['saltversioninfo'] >= [2017, 7, 0] %} - - docker_image: {{ id }} - {%- else %} - - docker: {{ id }} image - {%- endif %} - {%- if required_containers is defined %} - {%- for containerid in required_containers %} - {%- if grains['saltversioninfo'] >= [2017, 7, 0] %} - - docker_image: {{ containerid }} - {%- else %} - - docker: {{ containerid }} - {%- endif %} - {%- endfor %} - {%- endif %} -{% endfor %} diff --git a/docker/compose.sls b/docker/compose.sls deleted file mode 100644 index 4f173c19..00000000 --- a/docker/compose.sls +++ /dev/null @@ -1,25 +0,0 @@ -{#- Get the `tplroot` from `tpldir` #} -{%- set tplroot = tpldir.split('/')[0] %} -{%- from tplroot ~ "/map.jinja" import docker with context %} - -include: - - docker - -docker-compose: - {%- if grains.os_family in ('Suse',) %} ##workaround https://github.com/saltstack-formulas/docker-formula/issues/198 - cmd.run: - - name: /usr/bin/pip install docker-compose - {%- else %} - pip.installed: - {%- if 'compose_version' in docker and docker.compose_version %} - - name: docker-compose == {{ docker.compose_version }} - {%- else %} - - name: docker-compose - {%- endif %} - {%- if docker.proxy %} - - proxy: {{ docker.proxy }} - {%- endif %} - - reload_modules: True - {%- endif %} - - require: - - pkg: docker-package-dependencies diff --git a/docker/compose/build.sls b/docker/compose/build.sls new file mode 100644 index 00000000..7742784a --- /dev/null +++ b/docker/compose/build.sls @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'applications' in d.compose and d.compose.applications %} + {%- for service in d.compose.applications|unique %} + {%- if 'path' in d.compose[service] and d.compose[service]['path'] %} + +{{ formula }}-compose-{{ service }}-build: + module.run: + - name: dockercompose.build + - path: {{ d.compose[service]['path'] }} + {%- if 'services_names' in d.compose[service] and d.compose[service]['service_names'] is iterable %} + - service_names: {{ d.compose[service]['service_names'] }} + {%- endif %} + + {% endif %} + {%- endfor %} + {%- endif %} diff --git a/docker/compose/clean.sls b/docker/compose/clean.sls new file mode 100644 index 00000000..93e4e478 --- /dev/null +++ b/docker/compose/clean.sls @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +include: + - .software.clean diff --git a/docker/compose/get.sls b/docker/compose/get.sls new file mode 100644 index 00000000..b4ceff4e --- /dev/null +++ b/docker/compose/get.sls @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'applications' in d.compose and d.compose.applications %} + {%- for service in d.compose.applications|unique %} + {%- if 'path' in d.compose[service] and d.compose[service]['path'] %} + +{{ formula }}-compose-{{ service }}-get: + module.run: + - name: dockercompose.get + - path: {{ d.compose[service]['path'] }} + + {% endif %} + {%- endfor %} + {%- endif %} diff --git a/docker/compose/init.sls b/docker/compose/init.sls new file mode 100644 index 00000000..d7ecdeb2 --- /dev/null +++ b/docker/compose/init.sls @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +include: + - .software diff --git a/docker/compose/kill.sls b/docker/compose/kill.sls new file mode 100644 index 00000000..d3ae2867 --- /dev/null +++ b/docker/compose/kill.sls @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'applications' in d.compose and d.compose.applications %} + {%- for service in d.compose.applications|unique %} + {%- if 'path' in d.compose[service] and d.compose[service]['path'] %} + +{{ formula }}-compose-{{ service }}-kill: + module.run: + - name: dockercompose.kill + - path: {{ d.compose[service]['path'] }} + {%- if 'services_names' in d.compose[service] and d.compose[service]['service_names'] is iterable %} + - service_names: {{ d.compose[service]['service_names'] }} + {%- endif %} + + {% endif %} + {%- endfor %} + {%- endif %} diff --git a/docker/compose/networks/clean.sls b/docker/compose/networks/clean.sls new file mode 100644 index 00000000..e507f5fc --- /dev/null +++ b/docker/compose/networks/clean.sls @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'networks' in d and d.networks %} + {%- set sls_archive = tplroot ~ '.software.archive.install' %} + {%- set sls_desktop = tplroot ~ '.software.desktop.install' %} + {%- set sls_package = tplroot ~ '.software.package.install' %} + +include: + - {{ sls_archive if d.pkg.docker.use_upstream == 'archive' else sls_desktop if d.pkg.docker.use_upstream == 'desktop' else sls_package }} + + {%- for name in docker.networks %} + +{{ formula }}-network-{{ name }}-absent: + docker_network.absent: + - name: {{ name }} + + {%- endfor %} diff --git a/docker/compose/networks/init.sls b/docker/compose/networks/init.sls new file mode 100644 index 00000000..d3e55181 --- /dev/null +++ b/docker/compose/networks/init.sls @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +include: + - .install diff --git a/docker/compose/networks/install.sls b/docker/compose/networks/install.sls new file mode 100644 index 00000000..73c8593a --- /dev/null +++ b/docker/compose/networks/install.sls @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'networks' in d and d.networks %} + {%- set sls_archive = tplroot ~ '.software.archive.install' %} + {%- set sls_desktop = tplroot ~ '.software.desktop.install' %} + {%- set sls_package = tplroot ~ '.software.package.install' %} + +include: + - {{ sls_archive if d.pkg.docker.use_upstream == 'archive' else sls_desktop if d.pkg.docker.use_upstream == 'desktop' else sls_package }} + + {%- for name in docker.networks %} + +{{ formula }}-network-{{ name }}-present: + docker_network.present: + - name: {{ name }} + + {%- endfor %} diff --git a/docker/compose/ng.sls b/docker/compose/ng.sls new file mode 100644 index 00000000..55c69f08 --- /dev/null +++ b/docker/compose/ng.sls @@ -0,0 +1,137 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls +# formerly compose-ng state + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + +include: + - {{ formula }}.compose.software + - {{ formula }}.compose.networks + + {%- for name, container in d.compose.ng.items() %} + {%- set id = container.container_name|d(name) %} + {%- set required_containers = [] %} + {%- set required_networks = [] %} + +{{ formula }}-compose-ng-{{ id }}-present: + {%- if 'deps' in d.pkg and d.pkg.deps %} + pkg.installed: + - names: {{ d.pkg.deps|json }} + - reload_modules: {{ d.misc.reload or true }} + - require_in: + - docker_image: {{ formula }}-compose-ng-{{ id }}-present + {%- endif %} + docker_image.present: + - force: {{ d.misc.force_present }} + {%- if ':' in container.image %} + {%- set image = container.image.split(':',1) %} + - name: {{ image[0] }} + - tag: {{ image[1] }} + {%- else %} + - name: {{ container.image }} + {%- endif %} + +{{ formula }}-compose-ng-{{ id }}-running: + docker_container.running: + - name: {{ id }} + - image: {{ container.image }} + - skip_translate: {{ d.misc.skip_translate }} + - force: {{ d.misc.force_running }} + - privileged: {{ container.privileged|default(False) }} + - interactive: {{ container.stdin_open|default(False) }} + - tty: {{ container.tty|default(False) }} + {%- if 'command' in container %} + - command: {{ container.command }} + {%- endif %} + {%- if 'working_dir' in container %} + - working_dir: {{ container.working_dir }} + {%- endif %} + {%- if 'volume_driver' in container %} + - volume_driver: {{ container.volume_driver }} + {%- endif %} + {%- if 'userns_mode' in container %} + - userns_mode: {{ container.userns_mode }} + {%- endif %} + {%- if 'user' in container %} + - user: {{ container.user }} + {%- endif %} + {%- if 'environment' in container and container.environment is iterable %} + - environment: + {%- for variable, value in container.environment.items() %} + - {{ variable }}: {{ value }} + {%- endfor %} + {%- endif %} + {%- if 'ports' in container and container.ports is iterable %} + - port_bindings: + {%- for port_mapping in container.ports %} + {%- if port_mapping is string %} + {%- set mapping = port_mapping.split(':',2) %} + {%- if mapping|length < 2 %} + - "{{ mapping[0] }}" + {%- elif mapping|length > 2 %} + - "{{ mapping[0] }}:{{ mapping[1] }}:{{ mapping[-1] }}" + {%- else %} + - "{{ mapping[0] }}:{{ mapping[-1] }}" + {%- endif %} + {%- elif port_mapping is mapping %} + - {{ port_mapping }} + {%- endif %} + {%- endfor %} + {%- endif %} + {%- if 'volumes' in container %} + - binds: + {%- for bind in container.volumes %} + {%- set mapping = bind.rsplit(':', 1) %} + {%- if mapping|length > 1 %} + - "{{ mapping[0] }}:{{ mapping[-1] }}" + {%- else %} + - "{{ mapping[0] }}" + {%- endif %} + {%- endfor %} + {%- endif %} + {%- if 'volumes_from' in container %} + - volumes_from: + {%- for volume in container.volumes_from %} + {%- do required_containers.append(volume) %} + - {{ volume }} + {%- endfor %} + {%- endif %} + {%- if 'links' in container %} + - links: + {%- for link in container.links %} + {%- set name, alias = link.split(':',1) %} + {%- do required_containers.append(name) %} + {{ name }}: {{ alias }} + {%- endfor %} + {%- endif %} + {%- if 'networks' in container %} + - networks: + {%- for network in container.networks %} + {%- do required_networks.append(network) %} + - {{ network }} + {%- endfor %} + {%- endif %} + {%- if 'restart' in container %} + {%- set policy = container.restart.split(':',1) %} + {%- if policy|length < 2 %} + - restart_policy: {{ policy[0] }} + {%- else %} + - restart_policy: {{ policy[0] }}:{{ policy[-1] }} + {%- endif %} + {%- endif %} + - require: + - docker_image: {{ formula }}-compose-ng-{{ id }}-present + {%- if required_containers is defined %} + {%- for containerid in required_containers %} + - docker_image: {{ formula }}-compose-ng-{{ id }}-present + {%- endfor %} + {%- endif %} + {%- if required_networks is defined %} + {%- for networkid in required_networks %} + - docker_network: {{ networkid }} + {%- endfor %} + {%- endif %} + + {% endfor %} diff --git a/docker/compose/pause.sls b/docker/compose/pause.sls new file mode 100644 index 00000000..fa5bde25 --- /dev/null +++ b/docker/compose/pause.sls @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'applications' in d.compose and d.compose.applications %} + {%- for service in d.compose.applications|unique %} + {%- if 'path' in d.compose[service] and d.compose[service]['path'] %} + +{{ formula }}-compose-{{ service }}-pause: + module.run: + - name: dockercompose.pause + - path: {{ d.compose[service]['path'] }} + {%- if 'services_names' in d.compose[service] and d.compose[service]['service_names'] is iterable %} + - service_names: {{ d.compose[service]['service_names'] }} + {%- endif %} + + {% endif %} + {%- endfor %} + {%- endif %} diff --git a/docker/compose/ps.sls b/docker/compose/ps.sls new file mode 100644 index 00000000..a03e07af --- /dev/null +++ b/docker/compose/ps.sls @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'applications' in d.compose and d.compose.applications %} + {%- for service in d.compose.applications|unique %} + {%- if 'path' in d.compose[service] and d.compose[service]['path'] %} + +{{ formula }}-compose-{{ service }}-ps: + module.run: + - name: dockercompose.ps + - path: {{ d.compose[service]['path'] }} + + {% endif %} + {%- endfor %} + {%- endif %} diff --git a/docker/compose/pull.sls b/docker/compose/pull.sls new file mode 100644 index 00000000..1f83a1f3 --- /dev/null +++ b/docker/compose/pull.sls @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'applications' in d.compose and d.compose.applications %} + {%- for service in d.compose.applications|unique %} + {%- if 'path' in d.compose[service] and d.compose[service]['path'] %} + +{{ formula }}-compose-{{ service }}-pull: + module.run: + - name: dockercompose.pull + - path: {{ d.compose[service]['path'] }} + {%- if 'services_names' in d.compose[service] and d.compose[service]['service_names'] is iterable %} + - service_names: {{ d.compose[service]['service_names'] }} + {%- endif %} + + {% endif %} + {%- endfor %} + {%- endif %} diff --git a/docker/compose/restart.sls b/docker/compose/restart.sls new file mode 100644 index 00000000..6505747d --- /dev/null +++ b/docker/compose/restart.sls @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'applications' in d.compose and d.compose.applications %} + {%- for service in d.compose.applications|unique %} + {%- if 'path' in d.compose[service] and d.compose[service]['path'] %} + +{{ formula }}-compose-{{ service }}-restart: + module.run: + - name: dockercompose.restart + - path: {{ d.compose[service]['path'] }} + {%- if 'services_names' in d.compose[service] and d.compose[service]['service_names'] is iterable %} + - service_names: {{ d.compose[service]['service_names'] }} + {%- endif %} + + {% endif %} + {%- endfor %} + {%- endif %} diff --git a/docker/compose/rm.sls b/docker/compose/rm.sls new file mode 100644 index 00000000..ac725386 --- /dev/null +++ b/docker/compose/rm.sls @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'applications' in d.compose and d.compose.applications %} + {%- for service in d.compose.applications|unique %} + {%- if 'path' in d.compose[service] and d.compose[service]['path'] %} + +{{ formula }}-compose-{{ service }}-rm: + module.run: + - name: dockercompose.rm + - path: {{ d.compose[service]['path'] }} + {%- if 'services_names' in d.compose[service] and d.compose[service]['service_names'] is iterable %} + - service_names: {{ d.compose[service]['service_names'] }} + {%- endif %} + + {% endif %} + {%- endfor %} + {%- endif %} diff --git a/docker/compose/service_create.sls b/docker/compose/service_create.sls new file mode 100644 index 00000000..86fa2f88 --- /dev/null +++ b/docker/compose/service_create.sls @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'applications' in d.compose and d.compose.applications %} + {%- for service in d.compose.applications|unique %} + {%- if 'path' in d.compose[service] and d.compose[service]['path'] %} + {%- if 'service_name' in d.compose[service] and d.compose[service]['service_name'] %} + {%- if 'definition' in d.compose[service] and d.compose[service]['definition'] %} + +{{ formula }}-compose-{{ service }}-service_create: + module.run: + - name: dockercompose.service_create + - path: {{ d.compose[service]['path'] }} + - service_name: {{ d.compose[service]['service_name'] }} + - definition: {{ d.compose[service]['definition'] }} + + {% endif %} + {% endif %} + {% endif %} + {%- endfor %} + {%- endif %} diff --git a/docker/compose/service_remove.sls b/docker/compose/service_remove.sls new file mode 100644 index 00000000..d8cc0133 --- /dev/null +++ b/docker/compose/service_remove.sls @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'applications' in d.compose and d.compose.applications %} + {%- for service in d.compose.applications|unique %} + {%- if 'path' in d.compose[service] and d.compose[service]['path'] %} + {%- if 'service_name' in d.compose[service] and d.compose[service]['service_name'] %} + +{{ formula }}-compose-{{ service }}-service_remove: + module.run: + - name: dockercompose.service_remove + - path: {{ d.compose[service]['path'] }} + - service_name: {{ d.compose[service]['service_name'] }} + + {% endif %} + {% endif %} + {%- endfor %} + {%- endif %} diff --git a/docker/compose/service_set_tag.sls b/docker/compose/service_set_tag.sls new file mode 100644 index 00000000..c3941c3c --- /dev/null +++ b/docker/compose/service_set_tag.sls @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'applications' in d.compose and d.compose.applications %} + {%- for service in d.compose.applications|unique %} + {%- if 'path' in d.compose[service] and d.compose[service]['path'] %} + {%- if 'service_name' in d.compose[service] and d.compose[service]['service_name'] %} + {%- if 'tag' in d.compose[service] and d.compose[service]['tag'] %} + +{{ formula }}-compose-{{ service }}-service_set_tag-{{ d.compose[service]['tag'] }}: + module.run: + - name: dockercompose.service_set_tag + - path: {{ d.compose[service]['path'] }} + - service_name: {{ d.compose[service]['service_name'] }} + - tag: {{ d.compose[service]['tag'] }} + + {% endif %} + {% endif %} + {% endif %} + {%- endfor %} + {%- endif %} diff --git a/docker/compose/service_upsert.sls b/docker/compose/service_upsert.sls new file mode 100644 index 00000000..0c48c3ca --- /dev/null +++ b/docker/compose/service_upsert.sls @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'applications' in d.compose and d.compose.applications %} + {%- for service in d.compose.applications|unique %} + {%- if 'path' in d.compose[service] and d.compose[service]['path'] %} + {%- if 'service_name' in d.compose[service] and d.compose[service]['service_name'] %} + {%- if 'definition' in d.compose[service] and d.compose[service]['definition'] %} + +{{ formula }}-compose-{{ service }}-service_upsert: + module.run: + - name: dockercompose.service_upsert + - path: {{ d.compose[service]['path'] }} + - service_name: {{ d.compose[service]['service_name'] }} + - definition: {{ d.compose[service]['definition'] }} + + {% endif %} + {% endif %} + {% endif %} + {%- endfor %} + {%- endif %} diff --git a/docker/compose/software/alternatives/clean.sls b/docker/compose/software/alternatives/clean.sls new file mode 100644 index 00000000..9515b9fa --- /dev/null +++ b/docker/compose/software/alternatives/clean.sls @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if d.linux.altpriority|int > 0 and grains.kernel == 'Linux' and grains.os_family not in ('Arch',) %} + {%- for cmd in d.pkg.compose.commands|unique %} + +{{ formula }}-docker-compose-alternatives-clean-{{ cmd }}: + alternatives.remove: + - name: link-k8s-docker-compose-{{ cmd }} + - path: {{ d.pkg.compose.path }}/bin/{{ cmd }} + - onlyif: update-alternatives --list |grep ^link-k8s-docker-compose-{{ cmd }} + + {%- endfor %} + {%- endif %} diff --git a/docker/compose/software/alternatives/init.sls b/docker/compose/software/alternatives/init.sls new file mode 100644 index 00000000..d3e55181 --- /dev/null +++ b/docker/compose/software/alternatives/init.sls @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +include: + - .install diff --git a/docker/compose/software/alternatives/install.sls b/docker/compose/software/alternatives/install.sls new file mode 100644 index 00000000..d6dc5d29 --- /dev/null +++ b/docker/compose/software/alternatives/install.sls @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if d.linux.altpriority|int > 0 and grains.kernel == 'Linux' and grains.os_family not in ('Arch',) %} + {%- set sls_binary_install = tplroot ~ '.compose.software.binary.install' %} + +include: + - {{ sls_binary_install }} + + {%- for cmd in d.pkg.compose.commands|unique %} +{{ formula }}-docker-compose-alternatives-install-bin-{{ cmd }}: + {%- if grains.os_family not in ('Suse', 'Arch') %} + alternatives.install: + - name: link-docker-compose-{{ cmd }} + - link: /usr/local/bin/{{ cmd }} + - order: 10 + - path: {{ d.pkg.compose['path'] }}/bin/{{ cmd }} + - priority: {{ d.linux.altpriority }} + {%- else %} + cmd.run: + - name: update-alternatives --install /usr/local/bin/{{ cmd }} link-docker-compose-{{ cmd }} {{ d.pkg.compose['path'] }}/bin/{{ cmd }} {{ d.linux.altpriority }} # noqa 204 + {%- endif %} + + - onlyif: + - test -f {{ d.pkg.compose['path'] }}/bin/{{ cmd }} + - unless: update-alternatives --list |grep ^link-docker-compose-{{ cmd }} || false + - require: + - sls: {{ sls_binary_install }} + - require_in: + - alternatives: {{ formula }}-docker-compose-alternatives-set-bin-{{ cmd }} + +{{ formula }}-docker-compose-alternatives-set-bin-{{ cmd }}: + alternatives.set: + - unless: {{ grains.os_family in ('Suse', 'Arch') }} || false + - name: link-docker-compose-{{ cmd }} + - path: {{ d.pkg.compose.path }}/bin/{{ cmd }} + - onlyif: test -f {{ d.pkg.compose['path'] }}/bin/{{ cmd }} + + {%- endfor %} + {%- endif %} diff --git a/docker/compose/software/binary/clean.sls b/docker/compose/software/binary/clean.sls new file mode 100644 index 00000000..91e248e3 --- /dev/null +++ b/docker/compose/software/binary/clean.sls @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if grains.kernel|lower in ('linux',) %} + {%- set sls_alternatives_clean = tplroot ~ '.software.alternatives.clean' %} + +include: + - {{ sls_alternatives_clean }} + +{{ formula }}-docker-compose-archive-absent: + file.absent: + - names: + - {{ d.dir.tmp }}/docker-compose + - {{ d.pkg.compose.path }} + {%- if d.linux.altpriority|int == 0 or grains.os_family in ('Arch', 'MacOS') %} + {%- for cmd in d.pkg.compose.commands|unique %} + - /usr/local/bin/{{ cmd }} + {%- endfor %} + {%- endif %} + + {%- endif %} diff --git a/docker/compose/software/binary/init.sls b/docker/compose/software/binary/init.sls new file mode 100644 index 00000000..051d698c --- /dev/null +++ b/docker/compose/software/binary/init.sls @@ -0,0 +1,5 @@ +#.-*- coding: utf-8 -*- +# vim: ft=sls + +include: + - .install diff --git a/docker/compose/software/binary/install.sls b/docker/compose/software/binary/install.sls new file mode 100644 index 00000000..441251d4 --- /dev/null +++ b/docker/compose/software/binary/install.sls @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if grains.kernel|lower in ('linux',) %} + {%- from tplroot ~ "/files/macros.jinja" import format_kwargs with context %} + {%- if d.pkg.compose.use_upstream == 'binary' and 'binary' in d.pkg.compose %} + +{{ formula }}-compose-software-binary-install: + {%- if 'deps' in d.pkg and d.pkg.deps %} + pkg.installed: + - names: {{ d.pkg.deps|json }} + - reload_modules: {{ d.misc.reload or true }} + - require_in: + - file: {{ formula }}-compose-software-binary-install + {%- endif %} + file.managed: + - unless: test -x {{ d.pkg.compose.path }}/docker-compose + - name: {{ d.pkg.compose.path }}/docker-compose + - source: {{ d.pkg.compose.binary.source }} + - clean: {{ d.misc.clean }} + {%- if 'source_hash' in d.pkg.compose.binary and d.pkg.compose.binary.source_hash %} + - source_hash: {{ d.pkg.compose.binary.source_hash }} + {%- else %} + - skip_verify: True + {%- endif %} + - makedirs: True + - retry: {{ d.retry_option|json }} + - mode: '0755' + - user: {{ d.identity.rootuser }} + - group: {{ d.identity.rootgroup }} + - recurse: + - user + - group + - mode + + {%- if d.linux.altpriority|int == 0 or grains.os_family in ('Arch', 'MacOS') %} + {%- for cmd in d.pkg.compose.commands|unique %} + +{{ formula }}-compose-software-binary-install-symlink-{{ cmd }}: + file.symlink: + - name: /usr/local/bin/{{ cmd }} + - target: {{ d.pkg.compose.path }}/{{ cmd }} + - force: True + - onchanges: + - file: {{ formula }}-compose-software-binary-install + - require: + - file: {{ formula }}-compose-software-binary-install + + {%- endfor %} + {%- endif %} + {%- endif %} + {%- else %} + +{{ formula }}-compose-software-binary-install-other: + test.show_notification: + - text: | + The docker-compose binary is unavailable/unselected for {{ salt['grains.get']('finger', grains.os_family) }} + + {%- endif %} + diff --git a/docker/compose/software/clean.sls b/docker/compose/software/clean.sls new file mode 100644 index 00000000..4d9da707 --- /dev/null +++ b/docker/compose/software/clean.sls @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +include: + - .package.clean + - .binary.clean + - .alternatives.clean diff --git a/docker/compose/software/init.sls b/docker/compose/software/init.sls new file mode 100644 index 00000000..ee5cf5cd --- /dev/null +++ b/docker/compose/software/init.sls @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +include: + - .package + - .binary + - .alternatives diff --git a/docker/compose/software/package/clean.sls b/docker/compose/software/package/clean.sls new file mode 100644 index 00000000..d906f6e4 --- /dev/null +++ b/docker/compose/software/package/clean.sls @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if d.pkg.compose.use_upstream in ('package', 'repo') %} + {%- if grains.os_family|lower in ('redhat', 'debian') %} + {%- set sls_repo_clean = tplroot ~ '.software.package.repo.clean' %} +include: + - {{ sls_repo_clean }} + {%- endif %} + +{{ formula }}-docker-compose-package-clean-pkgs: + pkg.removed: + - name: {{ d.pkg.compose.name }} + - reload_modules: true + {%- if grains.os_family|lower in ('redhat', 'debian') %} + - require: + - pkgrepo: {{ formula }}-software-package-repo-absent + {%- endif %} + + {%- endif %} diff --git a/docker/compose/software/package/init.sls b/docker/compose/software/package/init.sls new file mode 100644 index 00000000..d3e55181 --- /dev/null +++ b/docker/compose/software/package/init.sls @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +include: + - .install diff --git a/docker/compose/software/package/install.sls b/docker/compose/software/package/install.sls new file mode 100644 index 00000000..ac19755b --- /dev/null +++ b/docker/compose/software/package/install.sls @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if d.pkg.compose.use_upstream in ('package', 'repo') %} + {%- if grains.os_family in ('RedHat', 'Debian') %} + {%- set sls_repo_install = tplroot ~ '.software.package.repo.install' %} + +include: + - {{ sls_repo_install }} + + {%- endif %} + +{{ formula }}-docker-compose-package-install-deps: + pkg.installed: + - names: {{ d.pkg.deps|json }} + - require_in: + - pkg: {{ formula }}-docker-compose-package-install-pkgs + +{{ formula }}-docker-compose-package-install-pkgs: + pkg.installed: + - names: {{ d.pkg.compose.commands|unique|json }} + - runas: {{ d.identity.rootuser }} + - reload_modules: true + {%- if grains.os_family in ('RedHat', 'Debian') %} + - require: + - pkgrepo: {{ formula }}-software-package-repo-managed + {%- endif %} + + {%- else %} + +{{ formula }}-docker-compose-package-install-other: + test.show_notification: + - text: | + The docker compose package is unavailable/unselected for {{ salt['grains.get']('finger', grains.os_family) }} + + {%- endif %} diff --git a/docker/compose/start.sls b/docker/compose/start.sls new file mode 100644 index 00000000..01e1cf06 --- /dev/null +++ b/docker/compose/start.sls @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'applications' in d.compose and d.compose.applications %} + {%- for service in d.compose.applications|unique %} + {%- if 'path' in d.compose[service] and d.compose[service]['path'] %} + +{{ formula }}-compose-{{ service }}-start: + module.run: + - name: dockercompose.start + - path: {{ d.compose[service]['path'] }} + {%- if 'services_names' in d.compose[service] and d.compose[service]['service_names'] is iterable %} + - service_names: {{ d.compose[service]['service_names'] }} + {%- endif %} + + {% endif %} + {%- endfor %} + {%- endif %} diff --git a/docker/compose/stop.sls b/docker/compose/stop.sls new file mode 100644 index 00000000..0e38e8b8 --- /dev/null +++ b/docker/compose/stop.sls @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'applications' in d.compose and d.compose.applications %} + {%- for service in d.compose.applications|unique %} + {%- if 'path' in d.compose[service] and d.compose[service]['path'] %} + +{{ formula }}-compose-{{ service }}-stop: + module.run: + - name: dockercompose.stop + - path: {{ d.compose[service]['path'] }} + {%- if 'services_names' in d.compose[service] and d.compose[service]['service_names'] is iterable %} + - service_names: {{ d.compose[service]['service_names'] }} + {%- endif %} + + {% endif %} + {%- endfor %} + {%- endif %} diff --git a/docker/compose/unpause.sls b/docker/compose/unpause.sls new file mode 100644 index 00000000..ccd1829a --- /dev/null +++ b/docker/compose/unpause.sls @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'applications' in d.compose and d.compose.applications %} + {%- for service in d.compose.applications|unique %} + {%- if 'path' in d.compose[service] and d.compose[service]['path'] %} + +{{ formula }}-compose-{{ service }}-unpause: + module.run: + - name: dockercompose.unpause + - path: {{ d.compose[service]['path'] }} + {%- if 'services_names' in d.compose[service] and d.compose[service]['service_names'] is iterable %} + - service_names: {{ d.compose[service]['service_names'] }} + {%- endif %} + + {% endif %} + {%- endfor %} + {%- endif %} diff --git a/docker/compose/up.sls b/docker/compose/up.sls new file mode 100644 index 00000000..107ca913 --- /dev/null +++ b/docker/compose/up.sls @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'applications' in d.compose and d.compose.applications %} + {%- for service in d.compose.applications|unique %} + {%- if 'path' in d.compose[service] and d.compose[service]['path'] %} + +{{ formula }}-compose-{{ service }}-up: + module.run: + - name: dockercompose.up + - path: {{ d.compose[service]['path'] }} + {%- if 'services_names' in d.compose[service] and d.compose[service]['service_names'] is iterable %} + - service_names: {{ d.compose[service]['service_names'] }} + {%- endif %} + + {% endif %} + {%- endfor %} + {%- endif %} diff --git a/docker/containers.sls b/docker/containers.sls deleted file mode 100644 index e0e7b94a..00000000 --- a/docker/containers.sls +++ /dev/null @@ -1,45 +0,0 @@ -{#- Get the `tplroot` from `tpldir` #} -{%- set tplroot = tpldir.split('/')[0] %} -{%- from tplroot ~ "/map.jinja" import containers with context %} - -include: - - docker - -{% for name, container in containers.items() %} -docker-image-{{ name }}: - cmd.run: - - name: docker pull {{ container.image }} | grep "Image is up to date" >/dev/null 2>&1 || echo "changed=yes comment='Image updated'" - - stateful: True - - require: - - service: docker-service - -{# TODO: SysV init script #} -{# Use grains instead of command to get init system #} -{%- set init_system = grains['init'] %} - -docker-container-startup-config-{{ name }}: - file.managed: -{%- if init_system == "systemd" %} - - name: /etc/systemd/system/docker-{{ name }}.service - - mode: 644 -{%- elif init_system == "upstart" %} - - name: /etc/init/docker-{{ name }}.conf - - mode: 700 -{%- endif %} - - source: salt://docker/files/service_file.jinja - - user: root - - template: jinja - - defaults: - name: {{ name | json }} - container: {{ container | json }} - - require: - - cmd: docker-image-{{ name }} - -docker-container-service-{{ name }}: - service.running: - - name: docker-{{ name }} - - enable: True - - watch: - - cmd: docker-image-{{ name }} - - file: docker-container-startup-config-{{ name }} -{% endfor %} diff --git a/docker/containers/absent.sls b/docker/containers/absent.sls new file mode 100644 index 00000000..704ebc69 --- /dev/null +++ b/docker/containers/absent.sls @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} +{%- from tplroot ~ "/files/macros.jinja" import format_kwargs with context %} + + {%- if 'running' in d.containers and d.containers.running %} + {%- set sls_stopped = tplroot ~ '.containers.stopped' %} + +include: + - {{ sls_stopped }} + + +{{ formula }}-containers-absent: + docker_container.absent: + - names: {{ d.containers.running|unique|json }} + - require: + - sls: {{ sls_stopped }} + + {%- endif %} diff --git a/docker/containers/clean.sls b/docker/containers/clean.sls new file mode 100644 index 00000000..0cf1e0a5 --- /dev/null +++ b/docker/containers/clean.sls @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +include: + - .stopped + - .absent diff --git a/docker/containers/init.sls b/docker/containers/init.sls new file mode 100644 index 00000000..6fe4d1a3 --- /dev/null +++ b/docker/containers/init.sls @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +include: + - .running diff --git a/docker/containers/running.sls b/docker/containers/running.sls new file mode 100644 index 00000000..a8e19723 --- /dev/null +++ b/docker/containers/running.sls @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} +{%- from tplroot ~ "/files/macros.jinja" import format_kwargs with context %} + + {%- if 'running' in d.containers and d.containers.running %} + {%- for c in d.containers.running|unique %} + {%- if c in d.containers and d.containers[c] %} + +{{ formula }}-containers-{{ c }}-running: + docker_container.running: + - name: {{ c if 'name' not in d.containers[c] else d.containers[c]['name'] }} + {{- format_kwargs(d.containers[c]) }} + + {% endif %} + {%- endfor %} + {%- endif %} diff --git a/docker/containers/stopped.sls b/docker/containers/stopped.sls new file mode 100644 index 00000000..cb4acd68 --- /dev/null +++ b/docker/containers/stopped.sls @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'running' in d.containers and d.containers.running %} + {%- for c in d.containers.running|unique %} + +{{ formula }}-containers-{{ c }}-stopped: + docker_container.stopped: + - name: {{ c }} + - onlyif: docker container inspect {{ c }} + + {%- endfor %} + {%- endif %} diff --git a/docker/cpuarchmap.yaml b/docker/cpuarchmap.yaml new file mode 100644 index 00000000..57724e80 --- /dev/null +++ b/docker/cpuarchmap.yaml @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# vim: ft=yaml +# +# Setup variables using grains['cuparch'] based logic. +# You just need to add the key:values for an `osarch` that differ +# from `defaults.yaml` + `os_family.yaml`. +# Only add an `cpuarch` which is/will be supported by the formula +# +# If you do not need to provide defaults via the `cpuarch` grain, +# you will need to provide at least an empty dict in this file, e.g. +# cpuarch: {} +--- +# Windows has no 'osarch' grain +Default: + dingdong: null + +AMD64: + arch: amd64 diff --git a/docker/defaults.yaml b/docker/defaults.yaml index 84a9ec3b..cd00e158 100644 --- a/docker/defaults.yaml +++ b/docker/defaults.yaml @@ -2,45 +2,130 @@ # vim: ft=yaml --- docker: - process_signature: '/usr/bin/docker' - install_docker_py: true - python_package: docker - refresh_repo: true - configfile: /etc/default/docker - config: [] - daemon_config: {} - version: '' - rootuser: root - - use_upstream_repo: true - use_old_repo: false - proxy: false - - pkgs: - - iptables - - ca-certificates + div: '/' + formula: docker + supported: + - docker + - compose + - swarm + wanted: + - docker + - compose pkg: + version: 'latest' # linux native package version name: docker-ce - old_name: docker-engine - # For backward compatibility, this will be overriden by docker:version, if defined - version: latest - allow_updates: false - hold: false - use_upstream_app: false # macos + old: + - docker + - docker-client + - docker-client-latest + - docker-common + - docker-latest + - docker-latest-logrotate + - docker-logrotate + - docker-engine + - docker.io + - containerd + - runc + - docker-selinux + - docker-engine-selinux - pip: - install_pypi_pip: false - upgrade: false + docker: + version: '19.03.9' # archive package version + config_file: /etc/default/docker + config: {} + name: docker-ce + service: + name: dockerd + suffix: tgz + commands: + - docker + - docker-init + - runc + - docker-proxy + - containerd + - ctr + - dockerd + - containerd-shim + use_upstream: archive + uri_a: 'https://download.docker.com/linux/static/stable' + archive: + options: '--strip-components=1' + source_hash: '1c03c78be198d9085e7dd6806fc5d93264baaf0c7ea17f584d00af48eae508ee' + desktop: {} # macos/windows + repo: + comments: + - installed by salt + enabled: 1 + gpgcheck: 1 + firewall: + ports: + - 2375 + - 2376 - compose_version: '' + compose: + version: 'latest' + name: docker-compose + suffix: '' + commands: + - docker-compose + use_upstream: binary + binary: + options: '' + # yamllint disable-line rule:line-length + source: 'https://dl.bintray.com/docker-compose/master/docker-compose-Linux-x86_64' + source_hash: '3c96b57ea8e0027aee7e1a3023f7599bcecae54e77bcfd5f4e65a59672637e54' + networks: {} containers: - skip_translate: None + running: [] + compose: + applications: [] + ng: {} + swarm: + joinswarm: {} + leave_swarm: false + node_ls: {} + remove_node: {} + remove_service: {} + service_create: {} + swarm_init: {} + service_info: {} + swarm_tokens: true + update_node: {} + + dir: + base: /usr/local + source: /usr/local/src/docker/libs + service: /usr/lib/systemd/system + tmp: /tmp/saltstack-formulas-docker-tmp + lib: /var/lib/docker + linux: + altpriority: 0 + identity: + rootuser: root + rootgroup: root + arch: '' + + misc: + force_absent: false force_present: false force_running: false + skip_translate: None + clean: false + reload: true + refresh: true + firewall: false + hold: false - kernel: - pkg: - fromrepo: '' - pkgs: [] + retry_option: + # https://docs.saltstack.com/en/latest/ref/states/requisites.html#retrying-states + attempts: 3 + until: true + interval: 60 + splay: 10 + + # Just here for testing + added_in_defaults: defaults_value + winner: defaults + version: '' diff --git a/docker/files/composetest/Dockerfile b/docker/files/composetest/Dockerfile new file mode 100644 index 00000000..eb6dac80 --- /dev/null +++ b/docker/files/composetest/Dockerfile @@ -0,0 +1,11 @@ +# https://docs.docker.com/compose/gettingstarted/ +FROM python:3.7-alpine +WORKDIR /code +ENV FLASK_APP=app.py +ENV FLASK_RUN_HOST=0.0.0.0 +RUN apk add --no-cache gcc musl-dev linux-headers +COPY requirements.txt requirements.txt +RUN pip install -r requirements.txt +EXPOSE 5000 +COPY . . +CMD ["flask", "run"] diff --git a/docker/files/composetest/app.py b/docker/files/composetest/app.py new file mode 100644 index 00000000..b707ffc7 --- /dev/null +++ b/docker/files/composetest/app.py @@ -0,0 +1,23 @@ +# https://docs.docker.com/compose/gettingstarted/ +import time +import redis +from flask import Flask + +app = Flask(__name__) +cache = redis.Redis(host='redis', port=6379) + +def get_hit_count(): + retries = 5 + while True: + try: + return cache.incr('hits') + except redis.exceptions.ConnectionError as exc: + if retries == 0: + raise exc + retries -= 1 + time.sleep(0.5) + +@app.route('/') +def hello(): + count = get_hit_count() + return 'Hello World! I have been seen {} times.\n'.format(count) diff --git a/docker/files/composetest/docker-compose.yml b/docker/files/composetest/docker-compose.yml new file mode 100644 index 00000000..dd02d7a0 --- /dev/null +++ b/docker/files/composetest/docker-compose.yml @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +# vim: ft=yaml +--- +# https://docs.docker.com/compose/gettingstarted + +version: "3.8" +services: + web: + build: . + ports: + - "5000:5000" + redis: + image: "redis:alpine" diff --git a/docker/files/composetest/requirements.txt b/docker/files/composetest/requirements.txt new file mode 100644 index 00000000..a7e46f63 --- /dev/null +++ b/docker/files/composetest/requirements.txt @@ -0,0 +1,3 @@ +# https://docs.docker.com/compose/gettingstarted/ +flask +redis diff --git a/docker/files/config b/docker/files/config deleted file mode 100644 index d84dca4b..00000000 --- a/docker/files/config +++ /dev/null @@ -1,24 +0,0 @@ -# Docker Upstart and SysVinit configuration file - -# -# THIS FILE DOES NOT APPLY TO SYSTEMD -# -# Please see the documentation for "systemd drop-ins": -# https://docs.docker.com/engine/articles/systemd/ -# - -# Customize location of Docker binary (especially for development testing). -#DOCKERD="/usr/local/bin/dockerd" - -# Use DOCKER_OPTS to modify the daemon startup options. -#DOCKER_OPTS="--dns 8.8.8.8 --dns 8.8.4.4" - -# If you need Docker to use an HTTP proxy, it can also be specified here. -#export http_proxy="http://127.0.0.1:3128/" - -# This is also a handy place to tweak where Docker's temporary files go. -#export TMPDIR="/mnt/bigdrive/docker-tmp" - -{% for line in config %} -{{ line }} -{% endfor %} diff --git a/docker/files/default/config.sh.jinja b/docker/files/default/config.sh.jinja new file mode 100644 index 00000000..5c601d1f --- /dev/null +++ b/docker/files/default/config.sh.jinja @@ -0,0 +1,6 @@ +######################################################################## +# File managed by Salt at <{{ source }}>. +# Your changes may be overwritten. +######################################################################## + +{{ config|yaml(False) }} diff --git a/docker/files/default/systemd.ini.jinja b/docker/files/default/systemd.ini.jinja new file mode 100644 index 00000000..959ad17a --- /dev/null +++ b/docker/files/default/systemd.ini.jinja @@ -0,0 +1,19 @@ +######################################################### +# File managed by Salt. Changes risk being overwritten. +######################################################### +[Unit] +Description={{ desc }} +Wants=network-online.target +After= +Documentation=https://github.com/saltstack-formulas/prometheus-formula + +[Service] +User={{ user }} +Group={{ group }} +WorkingDirectory={{ workdir }} +ExecStart={{ start }} +ExecStop={{ stop }} +PIDFile=/var/run/{{ name }}.pid + +[Install] +WantedBy=multi-user.target diff --git a/docker/files/macros.jinja b/docker/files/macros.jinja new file mode 100644 index 00000000..0ae45e4e --- /dev/null +++ b/docker/files/macros.jinja @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# vim: ft=jinja +# +# Collection of common macros + +{%- macro format_kwargs(kwarg) -%} + {%- if kwarg and kwarg is mapping %} + + {%- filter indent(4) %} + {%- for k, v in kwarg|dictsort() %} +- {{ k }}: {{ v }} + {%- endfor %} + {%- endfilter %} + + {%- endif %} +{%- endmacro %} diff --git a/docker/files/service_file.jinja b/docker/files/service_file.jinja deleted file mode 100644 index c30c0318..00000000 --- a/docker/files/service_file.jinja +++ /dev/null @@ -1,20 +0,0 @@ -{#- Ugly, but covers the cases where variable evaluates to false, is empty, or non-existent #} -{%- set runoptions = container.get("runoptions") or [] %} -{%- set stopoptions = container.get("stopoptions") or [] %} -{%- set cmd = container.get("cmd") or "" %} -{%- set args = container.get("args") or [] %} - -{%- set runoptions = runoptions|join(' ') %} -{%- set stopoptions = stopoptions|join(' ') %} -{%- set args = args|join(' ') %} - -{%- set docker_prestart_remove_command = "rm -f %s"|format(name) %} -{%- set docker_start_command = "run %s --name=%s %s %s %s"|format(runoptions, name, container.image, cmd, args) %} -{%- set docker_stop_command = "stop %s %s"|format(stopoptions, name) %} -{%- set docker_poststop_command = "rm -f %s"|format(name) %} - -{%- if grains['init'] == 'systemd' %} -{%- include 'docker/files/systemd.conf' %} -{%- elif grains['init'] == 'upstart' %} -{%- include 'docker/files/upstart.conf' %} -{%- endif %} diff --git a/docker/files/systemd.conf b/docker/files/systemd.conf deleted file mode 100644 index 587ebae1..00000000 --- a/docker/files/systemd.conf +++ /dev/null @@ -1,28 +0,0 @@ -[Unit] -Description=Docker container for {{ name }} -Requires=docker.service -After=docker.service - -{%- set remove_on_stop = container.get("remove_on_stop", False) %} -{%- set pull_before_start = container.get("pull_before_start") or False %} -{%- set remove_before_start = container.get("remove_before_start") or False %} - -[Service] -Restart=always -{%- if pull_before_start %} -ExecStartPre=/usr/bin/docker pull {{ container.image }} -{%- endif %} - -{%- if remove_before_start %} -ExecStartPre=-/usr/bin/docker {{ docker_prestart_remove_command }} -{%- endif %} -ExecStart=/usr/bin/docker {{ docker_start_command }} -ExecStop=/usr/bin/docker {{ docker_stop_command }} -{%- if remove_on_stop %} -ExecStopPost=/usr/bin/docker {{ docker_poststop_command }} -{%- endif %} - -StandardOutput=null - -[Install] -WantedBy=multi-user.target diff --git a/docker/files/upstart.conf b/docker/files/upstart.conf deleted file mode 100644 index defd6868..00000000 --- a/docker/files/upstart.conf +++ /dev/null @@ -1,37 +0,0 @@ -description "Docker container for {{ name }}" -start on filesystem and started docker -stop on runlevel [06] -respawn - - -{#- Ugly, but covers the cases where variable evaluates to false, is empty, or non-existent #} -{%- set runoptions = container.get("runoptions", []) %} -{%- set stopoptions = container.get("stopoptions", []) %} -{%- set remove_on_stop = container.get("remove_on_stop", False) %} -{%- set cmd = container.get("cmd", "") %} - -{%- set pull_before_start = container.get("pull_before_start") or False %} -{%- set remove_before_start = container.get("remove_before_start") or False %} - -{%- if pull_before_start or remove_before_start -%} -pre-start script -{%- if pull_before_start %} - /usr/bin/docker pull {{ container.image }} -{%- endif %} - -{%- if remove_before_start %} - /usr/bin/docker rm -f {{ name }} -{%- endif %} -end script -{%- endif %} - -script - exec docker {{ docker_start_command }} -end script - -pre-stop script - /usr/bin/docker stop {%- for option in stopoptions %} {{ option }} {%- endfor %} {{ name }} - {%- if remove_on_stop %} - /usr/bin/docker rm -f {{ name }} - {%- endif %} -end script diff --git a/docker/files/upstart.conf.deprecated.registry b/docker/files/upstart.conf.deprecated.registry deleted file mode 100644 index 65f495c6..00000000 --- a/docker/files/upstart.conf.deprecated.registry +++ /dev/null @@ -1,30 +0,0 @@ -{#- Get the `tplroot` from `tpldir` #} -{%- set tplroot = tpldir.split('/')[0] %} -{%- from tplroot ~ "/map.jinja" import registry with context %} -{%- from tplroot ~ "/map.jinja" import amazon with context %} - -description "{{ registry.description }}" -start on runlevel [2345] -stop on runlevel [06] - -{# as of now docker registry has 'latest' pointing to 0.9.1, instead of 2.x #} -{% if registry.version != 'latest' %} -exec docker run \ -{%- for option in registry.runoptions %} - {{ option }} \ -{%- endfor %} - -p {{ registry.port }}:{{ registry.port }} \ - --restart="{{ registry.restart }}" \ - registry:{{ registry.version }} -{% else %} -exec docker run \ - -e SETTINGS_FLAVOR={{ amazon.settings_flavor }} \ - -e AWS_BUCKET={{ amazon.aws_bucket }} \ - -e AWS_KEY={{ amazon.aws_key }} \ - -e AWS_SECRET={{ amazon.aws_secret }} \ - -e STORAGE_PATH={{ amazon.storage_path }} \ - -e SEARCH_BACKEND={{ registry.search_backend }} \ - -p {{ registry.port }}:5000 \ - --restart="{{ registry.restart }}" \ - registry -{% endif %} diff --git a/docker/init.sls b/docker/init.sls index e32220e2..4a0744bd 100644 --- a/docker/init.sls +++ b/docker/init.sls @@ -1,10 +1,7 @@ # -*- coding: utf-8 -*- # vim: ft=sls -{#- Get the `tplroot` from `tpldir` #} -{%- set tplroot = tpldir.split('/')[0] %} -{%- from tplroot ~ "/map.jinja" import docker with context %} -{%- set sls_package_install = tplroot ~ '.install' %} -{%- set sls_macapp_install = tplroot ~ '.macosapp' %} include: - - {{ sls_package_install if not docker.pkg.use_upstream_app else sls_macapp_install }} + - .software + - .compose + # .containers diff --git a/docker/install.sls b/docker/install.sls deleted file mode 100644 index 6590a41b..00000000 --- a/docker/install.sls +++ /dev/null @@ -1,134 +0,0 @@ -{% from "docker/map.jinja" import docker with context %} - -{%- set docker_pkg_name = docker.pkg.old_name if docker.use_old_repo else docker.pkg.name %} -{%- set docker_pkg_version = docker.version | default(docker.pkg.version) %} -{%- set docker_packages = docker.kernel.pkgs + docker.pkgs %} - -include: - - .kernel - - .repo - -docker-package-dependencies: - pkg.installed: - - pkgs: - {%- for pkgname in docker_packages %} - - {{ pkgname }} - {%- endfor %} - {%- if "pip" in docker and "pkgname" in docker.pip %} - - {{ docker.pip.pkgname }} - {%- endif %} - - unless: test "`uname`" = "Darwin" - - refresh: {{ docker.refresh_repo }} - -docker-package: - pkg.installed: - - name: {{ docker_pkg_name }} - - version: {{ docker_pkg_version or 'latest' }} - - refresh: {{ docker.refresh_repo }} - - require: - - pkg: docker-package-dependencies - {%- if grains['os']|lower not in ('amazon', 'fedora', 'suse',) %} - - pkgrepo: docker-package-repository - {%- endif %} - {%- if grains['os']|lower not in ('suse',) %} - - allow_updates: {{ docker.pkg.allow_updates }} - - hold: {{ docker.pkg.hold }} - {%- endif %} - {%- if grains.os_family in ('Suse',) %} ##workaround https://github.com/saltstack-formulas/docker-formula/issues/198 - cmd.run: - - name: /usr/bin/pip install {{ '--upgrade' if docker.pip.upgrade else '' }} pip - {%- elif docker.pip.install_pypi_pip %} ##onlyif you really need pypi pip instead of using official distro pip - pip.installed: - - name: pip - - reload_modules: true - - upgrade: {{ docker.pip.upgrade }} - {%- endif %} - - require: - - pkg: docker-package-dependencies - - {%- if grains.os != 'MacOS' %} -docker-config: - file.managed: - - name: {{ docker.configfile }} - - source: salt://docker/files/config - - template: jinja - - mode: 644 - - user: root - - context: - config: {{ docker.config | json }} - - require: - - pkg: docker-package - - watch_in: - - service: docker-service - {%- endif %} - - {% if docker.daemon_config %} -docker-daemon-dir: - file.directory: - - name: /etc/docker - - user: root - - group: root - - mode: 755 - -docker-daemon-config: - file.serialize: - - name: /etc/docker/daemon.json - - user: root - - group: root - - mode: 644 - - dataset: - {{ docker.daemon_config | yaml() | indent(8) }} - - formatter: json - {% endif %} - -docker-service: - service.running: - - name: docker - - enable: True - - watch: - - pkg: docker-package - {% if docker.daemon_config %} - - file: docker-daemon-config - {% endif %} - {% if "process_signature" in docker %} - - sig: {{ docker.process_signature }} - {% endif %} - -docker-install-docker-service-not-running-notify: - test.show_notification: - - text: | - In certain circumstances the docker service will not start. - Your kernel is missing some modules, or not in ideal state. - See https://github.com/moby/moby/blob/master/contrib/check-config.sh - Rebooting your host may fix docker service failure! - - onfail: - - service: docker-service - - unless: {{ grains.os_family in ('MacOS', 'Windows') }} #maybe not needed? - service.enabled: - - name: docker - - onfail: - - service: docker-service - - unless: {{ grains.os_family in ('MacOS', 'Windows') }} #maybe not needed? - -{% if docker.install_docker_py %} -docker-py: - {%- if grains.os_family in ('Suse',) %} ##workaround https://github.com/saltstack-formulas/docker-formula/issues/198 - cmd.run: - - name: /usr/bin/pip install {{ docker.python_package }} - {%- else %} - pip.installed: - {%- if "python_package" in docker and docker.python_package %} - - name: {{ docker.python_package }} - {%- elif "pip_version" in docker and docker.pip_version %} - - name: docker-py {{ docker.pip_version }} - {%- else %} - - name: docker-py - {%- endif %} - - reload_modules: true - {%- if docker.proxy %} - - proxy: {{ docker.proxy }} - {%- endif %} - - require: - - pkg: docker-package-dependencies - {%- endif %} -{% endif %} diff --git a/docker/kernel.sls b/docker/kernel.sls deleted file mode 100644 index 9f6c467f..00000000 --- a/docker/kernel.sls +++ /dev/null @@ -1,31 +0,0 @@ -{#- Get the `tplroot` from `tpldir` #} -{%- set tplroot = tpldir.split('/')[0] %} -{%- from tplroot ~ "/map.jinja" import docker with context %} - -{%- if docker.kernel is defined and grains['os_family']|lower == 'debian' %} -pkgrepo-dependencies: - pkg.installed: - - name: python-apt - - {% if "pkgrepo" in docker.kernel %} -{{ grains["oscodename"]|lower }}-backports-repo: - pkgrepo.managed: - {% for key, value in docker.kernel.pkgrepo.items() %} - - {{ key }}: {{ value }} - {% endfor %} - - require: - - pkg: python-apt - - onlyif: dpkg --compare-versions {{ grains["kernelrelease"] }} lt 3.8 - {% endif %} - - {% if "pkg" in docker.kernel %} -docker-dependencies-kernel: - pkg.installed: - {% for key, value in docker.kernel.pkg.items() %} - - {{ key }}: {{ value }} - {% endfor %} - - require_in: - - pkg: docker-package - - onlyif: dpkg --compare-versions {{ grains["kernelrelease"] }} lt 3.8 - {% endif %} -{% endif %} diff --git a/docker/libtofs.jinja b/docker/libtofs.jinja new file mode 100644 index 00000000..da656a5e --- /dev/null +++ b/docker/libtofs.jinja @@ -0,0 +1,101 @@ +{%- macro files_switch(source_files, + lookup=None, + default_files_switch=['id', 'os_family'], + indent_width=6, + v1_path_prefix='') %} + {#- + Returns a valid value for the "source" parameter of a "file.managed" + state function. This makes easier the usage of the Template Override and + Files Switch (TOFS) pattern. + + Params: + * source_files: ordered list of files to look for + * lookup: key under ':tofs:source_files' to override + list of source files + * default_files_switch: if there's no config (e.g. pillar) + ':tofs:files_switch' this is the ordered list of grains to + use as selector switch of the directories under + "/files" + * indent_witdh: indentation of the result value to conform to YAML + * v1_path_prefix: (deprecated) only used for injecting a path prefix into + the source, to support older TOFS configs + + Example (based on a `tplroot` of `xxx`): + + If we have a state: + + Deploy configuration: + file.managed: + - name: /etc/yyy/zzz.conf + - source: {{ files_switch(['/etc/yyy/zzz.conf', '/etc/yyy/zzz.conf.jinja'], + lookup='Deploy configuration' + ) }} + - template: jinja + + In a minion with id=theminion and os_family=RedHat, it's going to be + rendered as: + + Deploy configuration: + file.managed: + - name: /etc/yyy/zzz.conf + - source: + - salt://xxx/files/theminion/etc/yyy/zzz.conf + - salt://xxx/files/theminion/etc/yyy/zzz.conf.jinja + - salt://xxx/files/RedHat/etc/yyy/zzz.conf + - salt://xxx/files/RedHat/etc/yyy/zzz.conf.jinja + - salt://xxx/files/default/etc/yyy/zzz.conf + - salt://xxx/files/default/etc/yyy/zzz.conf.jinja + - template: jinja + #} + {#- Get the `tplroot` from `tpldir` #} + {%- set tplroot = tpldir.split('/')[0] %} + {%- set path_prefix = salt['config.get'](tplroot ~ ':tofs:path_prefix', tplroot) %} + {%- set files_dir = salt['config.get'](tplroot ~ ':tofs:dirs:files', 'files') %} + {%- set files_switch_list = salt['config.get']( + tplroot ~ ':tofs:files_switch', + default_files_switch + ) %} + {#- Lookup source_files (v2), files (v1), or fallback to source_files parameter #} + {%- set src_files = salt['config.get']( + tplroot ~ ':tofs:source_files:' ~ lookup, + salt['config.get']( + tplroot ~ ':tofs:files:' ~ lookup, + source_files + ) + ) %} + {#- Only add to [''] when supporting older TOFS implementations #} + {%- set path_prefix_exts = [''] %} + {%- if v1_path_prefix != '' %} + {%- do path_prefix_exts.append(v1_path_prefix) %} + {%- endif %} + {%- for path_prefix_ext in path_prefix_exts %} + {%- set path_prefix_inc_ext = path_prefix ~ path_prefix_ext %} + {#- For older TOFS implementation, use `files_switch` from the config #} + {#- Use the default, new method otherwise #} + {%- set fsl = salt['config.get']( + tplroot ~ path_prefix_ext|replace('/', ':') ~ ':files_switch', + files_switch_list + ) %} + {#- Append an empty value to evaluate as `default` in the loop below #} + {%- if '' not in fsl %} + {%- do fsl.append('') %} + {%- endif %} + {%- for fs in fsl %} + {%- for src_file in src_files %} + {%- if fs %} + {%- set fs_dir = salt['config.get'](fs, fs) %} + {%- else %} + {%- set fs_dir = salt['config.get'](tplroot ~ ':tofs:dirs:default', 'default') %} + {%- endif %} + {%- set url = [ + '- salt:/', + path_prefix_inc_ext.strip('/'), + files_dir.strip('/'), + fs_dir.strip('/'), + src_file.strip('/'), + ] | select | join('/') %} +{{ url | indent(indent_width, true) }} + {%- endfor %} + {%- endfor %} + {%- endfor %} +{%- endmacro %} diff --git a/docker/macosapp/init.sls b/docker/macosapp/init.sls deleted file mode 100644 index b16d0683..00000000 --- a/docker/macosapp/init.sls +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# vim: ft=sls - -{#- Get the `tplroot` from `tpldir` #} -{%- set tplroot = tpldir.split('/')[0] %} -{%- from tplroot ~ "/map.jinja" import docker with context %} -{%- set sls_package_install = tplroot ~ '.install' %} -{%- set sls_macapp_install = tplroot ~ '.macosapp.install' %} - -include: - - {{ sls_macapp_install if docker.pkg.use_upstream_app else sls_package_install }} diff --git a/docker/macosapp/install.sls b/docker/macosapp/install.sls deleted file mode 100644 index ce5a5d3d..00000000 --- a/docker/macosapp/install.sls +++ /dev/null @@ -1,60 +0,0 @@ -# -*- coding: utf-8 -*- -# vim: ft=sls - -{#- Get the `tplroot` from `tpldir` #} -{%- set tplroot = tpldir.split('/')[0] %} -{%- from tplroot ~ "/map.jinja" import docker with context %} - - {%- if grains.os == 'MacOS' %} - -docker-macos-app-install-file-directory: - file.directory: - - name: /tmp/salt-docker-formula - - makedirs: True - - require_in: - - pkg: docker-macos-app-install-cmd-run - - cmd: docker-macos-app-install-cmd-run - -docker-macos-app-install-cmd-run: - pkg.installed: - - name: curl - cmd.run: - - name: curl -Lo /tmp/salt-docker-formula/{{ docker.pkg.app.name }} {{ docker.pkg.app.source }} - - unless: test -f /tmp/salt-docker-formula/{{ docker.pkg.app.name }} - - retry: - attempts: 3 - interval: 60 - until: True - splay: 10 - - {%- if docker.pkg.app.source_hash %} - -docker-macos-app-install-app-hash-module-run: - module.run: - - name: file.check_hash - - path: /tmp/salt-docker-formula/{{ docker.pkg.app.name }} - - file_hash: {{ docker.pkg.app.source_hash }} - - require: - - cmd: docker-macos-app-install-cmd-run - - require_in: - - macpackage: docker-macos-app-install-macpackage-installed - - {%- endif %} - -docker-macos-app-install-macpackage-installed: - macpackage.installed: - - name: /tmp/salt-docker-formula/{{ docker.pkg.app.name }} - - store: True - - dmg: True - - app: True - - force: True - - allow_untrusted: True - - onchanges: - - cmd: docker-macos-app-install-cmd-run - file.append: - - name: /Users/{{ docker.rootuser }}/.bash_profile - - text: 'export PATH=$PATH:/Applications/Docker.app/Contents/Versions/latest/bin' - - require: - - macpackage: docker-macos-app-install-macpackage-installed - - {%- endif %} diff --git a/docker/map.jinja b/docker/map.jinja index 5d057f5b..037d03cd 100644 --- a/docker/map.jinja +++ b/docker/map.jinja @@ -1,49 +1,91 @@ -{# vi: set ft=jinja: #} -{% set containers = salt['grains.filter_by']({ - 'default': {} - }, - merge=salt['pillar.get']('docker-containers:lookup')) -%} - -{% set registry = salt['grains.filter_by']({ - 'default': { - 'description': 'Docker Registry', - 'port': '5000', - 'version': 'latest', - 'restart': 'no', - 'search_backend': 'sqlalchemy', - 'runoptions': [] - }, -}, merge=salt['pillar.get']('registry:lookup')) %} - -{% set amazon = salt['grains.filter_by']({ - 'default': { - 'settings_flavor': 's3', - 'storage_path': '/registry' - }, -}, merge=salt['pillar.get']('registry:lookup:amazon')) %} - -{#- Get the `tplroot` from `tpldir` #} +# -*- coding: utf-8 -*- +# vim: ft=jinja + {%- set tplroot = tpldir.split('/')[0] %} +{%- import_yaml tplroot ~ "/defaults.yaml" as default_settings %} +{%- import_yaml tplroot ~ "/osfamilymap.yaml" as osfamilymap %} +{%- import_yaml tplroot ~ "/osfingermap.yaml" as osfingermap %} +{%- import_yaml tplroot ~ "/osmap.yaml" as osmap %} +{%- import_yaml tplroot ~ "/codenamemap.yaml" as codenamemap %} +{%- import_yaml tplroot ~ "/osarchmap.yaml" as osarchmap %} +{%- import_yaml tplroot ~ "/cpuarchmap.yaml" as cpuarchmap %} + +{%- set _config = salt['config.get'](tplroot, default={}) %} +{%- set defaults = salt['grains.filter_by']( + default_settings, + default=tplroot, + merge=salt['grains.filter_by']( osfamilymap, grain='os_family', + merge=salt['grains.filter_by']( osmap, grain='os', + merge=salt['grains.filter_by']( osfingermap, grain='osfinger', + merge=salt['grains.filter_by']( codenamemap, grain='oscodename', + merge=salt['grains.filter_by']( osarchmap, grain='osarch', + merge=salt['grains.filter_by']( cpuarchmap, grain='cpuarch', + merge=salt['grains.filter_by']( _config, default='lookup' + ) + ) + ) + ) + ) + ) + ) + ) + %} +{%- set d = salt['grains.filter_by']( {'defaults': defaults}, default='defaults', merge=_config) %} + +{%- if 'wanted' in d and d.wanted and 'supported' in d and d.supported %} + {%- for c in d.wanted %} + + {%- if c in d.supported %} + {%- set path = d.dir.base %} + {%- set url = False %} -{# Begin migration to new style map.jinja using tplroot for portability #} -{% import_yaml tplroot ~ "/defaults.yaml" or {} as defaults %} -{% import_yaml tplroot ~ "/osfamilymap.yaml" or {} as osfamilymap %} -{% import_yaml tplroot ~ "/codenamemap.yaml" or {} as codemap %} -{% import_yaml tplroot ~ "/osmap.yaml" or {} as osmap %} + {%- if c in ('docker', 'compose') and c in d.pkg and d.pkg[c] %} + {%- set p = d.pkg[c] %} + {%- if grains.os == 'Windows' %} + {%- do p.update({'path': '%s%sbin%s'|format(d.dir.base, d.div, d.div)}) %} + {%- else %} + {%- do p.update({ 'path': '%s/%s%s-%s/bin/'|format(d.dir.base, '' if c == 'docker' else 'docker-', c, p.version) }) %} + {%- endif %} -{% set pkg = salt['pillar.get']('docker-pkg:lookup', default={}, merge=True) %} -{% do defaults.docker.pkg.update(pkg) %} + {%- if p.use_upstream == 'archive' %} + {%- if c == 'docker' %} + {%- set url = '%s/%s/%s-%s.%s'|format(p.uri_a, d.arch, c, p.version, p.suffix) %} + {%- do p.archive.update({ 'source': url }) %} + {%- endif %} + {%- if 'source_hash' in p.archive and p.archive.source_hash %} + {%- do p.archive.update({'name': p.path, 'source_hash': p.archive.source_hash}) %} + {%- else %} + {%- do p.archive.update({'name': p.path, 'source_hash': url ~ '.sha256'}) %} + {%- endif %} -{% set osfamily = salt['grains.filter_by'](osfamilymap, grain='os_family') or {} %} -{% do defaults.docker.update(osfamily) %} + {%- elif p.use_upstream == 'binary' %} + {%- if 'source_hash' in p.binary and p.binary.source_hash %} + {%- do p.binary.update({'name': p.path, 'source_hash': p.binary.source_hash}) %} + {%- else %} + {%- do p.binary.update({'name': p.path, 'source_hash': url ~ '.sha256'}) %} + {%- endif %} -{% set os = salt['grains.filter_by'](osmap, grain='os') or {} %} -{% do defaults.docker.update(os) %} + {%- elif p.use_upstream == 'desktop' %} + {%- if c == 'docker' %} + {%- set url = '%s%s'|format(p.uri_d, p.suffix) %} + {%- do p.desktop.update({ 'source': url }) %} + {%- endif %} + {%- if 'source_hash' in p.desktop and p.desktop.source_hash %} + {%- do p.desktop.update({'name': p.path, 'source_hash': p.desktop.source_hash}) %} + {%- else %} + {%- do p.desktop.update({'name': p.path, 'source_hash': url ~ '.sha256'}) %} + {%- endif %} -{% set oscode = salt['grains.filter_by'](codemap, grain='oscodename') or {} %} -{% do defaults.docker.update(oscode) %} + {%- endif %} + ## Persistance + {%- do d.pkg.update({ c: p }) %} -{% set docker = salt['pillar.get']('docker', default=defaults['docker'], merge=True) %} + {%- endif %} + {%- endif %} + {%- endfor %} +{%- endif %} -{% set compose = salt['pillar.get']('docker:compose', default={}, merge=True) %} +{%- if 'formula' not in d %} + {%- do d.update({'formula': 'docker'}) %} +{%- endif %} +{%- set data = d %} diff --git a/docker/osarchmap.yaml b/docker/osarchmap.yaml new file mode 100644 index 00000000..56a9a9f9 --- /dev/null +++ b/docker/osarchmap.yaml @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- +# vim: ft=yaml +# +# Setup variables using grains['osarch'] based logic. +# You just need to add the key:values for an `osarch` that differ +# from `defaults.yaml` + `os_family.yaml`. +# Only add an `osarch` which is/will be supported by the formula +# +# If you do not need to provide defaults via the `osarch` grain, +# you will need to provide at least an empty dict in this file, e.g. +# osarch: {} +--- +aarch64: + arch: aarch64 + pkg: + docker: + use_upstream: archive + archive: + source_hash: '5d6ede3368eac8e74ead70489aa7e4e663fe1ccfbb9763a6ac55991d55b70354' + suffix: tgz + +armel: + arch: armel + pkg: + docker: + use_upstream: archive + archive: + source_hash: '16e633ee6615432e5f5942f3a8cf588db1a6958521e12c3eca585ad3113d3de9' + suffix: tgz + +armhf: + arch: armhf + pkg: + docker: + use_upstream: archive + archive: + source_hash: '5e757cf65d99b0326f49cabbfc3b9a65151cb569f04fcb64a7a0c7424772c7cf' + suffix: tgz + +ppc64le: + arch: ppc64le + pkg: + docker: + version: '18.06.3-ce' + use_upstream: archive + archive: + source_hash: '8fee410bc25628fa5310b33af1b362edcfe39533294a8325f3ed2cefac97c005' + suffix: tgz + +s390x: + arch: s390x + pkg: + docker: + use_upstream: archive + archive: + source_hash: '9b37def0df53ebbeb78cc85c0aaeed89fc61261cf90380d374af6c8865775c84' + suffix: tgz + +amd64: + arch: x86_64 # for archive + +x86_64: + arch: x86_64 # amd64 + +386: + arch: '386' + +armv6l: + arch: armv6l + +armv7l: + arch: armv7l diff --git a/docker/osfamilymap.yaml b/docker/osfamilymap.yaml index 18c8550a..73c41b7a 100644 --- a/docker/osfamilymap.yaml +++ b/docker/osfamilymap.yaml @@ -11,66 +11,107 @@ # osfamilymap: {} --- {%- if grains.os == 'MacOS' %} - {% set macos_user = salt['cmd.run']("stat -f '%Su' /dev/console") %} + {%- set rootuser = salt['cmd.run']("stat -f '%Su' /dev/console") %} + {%- set rootgroup = salt['cmd.run']("stat -f '%Sg' /dev/console") %} +{%- elif grains.os == 'Windows' %} + {%- set rootuser = salt['cmd.run']("id -un") %} {%- endif %} Arch: - python_package: ~ - pkgs: - - python-docker - - python-pip - - python2-pip # see https://github.com/saltstack/salt/issues/48632 pkg: - name: docker - # workaround https://github.com/saltstack-formulas/docker-formula/issues/219 - allow_updates: false - hold: false - use_upstream_app: false - pip: - install_pypi_pip: false - upgrade: false + docker: + name: docker + deps: + - python-docker + - python-pip + # python2-pip # see https://github.com/saltstack/salt/issues/48632 Debian: - pkgs: - - apt-transport-https - - python3-apt - - python3-pip - - python3-docker - repo: - url_base: https://download.docker.com/linux/{{ grains['os'] |lower }} - key_url: https://download.docker.com/linux/{{ grains['os'] |lower }}/gpg - version: {{ grains['oscodename']|lower if 'oscodename' in grains else '' }} - file: /etc/apt/sources.list.d/docker.list + pkg: + deps: + - python3-apt + - python3-pip + - python3-docker + - apt-transport-https + - ca-certificates + - curl + - gnupg-agent + - software-properties-common + - iptables + - git + - procps + docker: + repo: + {%- if 'oscodename' in grains %} + name: deb [arch=amd64] https://download.docker.com/linux/{{ grains.os|lower }} {{ grains.oscodename }} stable + {%- endif %} + file: /etc/apt/sources.list.d/docker.list + key_url: "https://download.docker.com/linux/{{ grains.os|lower }}/gpg" RedHat: - pkgs: - - python3-pip - - python3-docker - repo: - # yamllint disable-line rule:line-length - url_base: https://download.docker.com/linux/{{ grains['os'] |lower }}/{{ '' if not 'osmajorrelease' in grains else grains['osmajorrelease'] }}/$basearch/stable/ - key_url: https://download.docker.com/linux/{{ grains['os'] |lower }}/gpg - version: {{ grains['oscodename']|lower if 'oscodename' in grains else '' }} - file: /etc/yum.repos.d/docker-ce.repo + pkg: + deps: + - python3-pip + - iptables + - git + - tar + docker: + repo: + baseurl: 'https://download.docker.com/linux/{{ grains.os|lower }}/$releasever/$basearch/stable' + file: '/etc/yum.repos.d/docker-ce.repo' + gpgkey: 'https://download.docker.com/linux/{{ grains.os|lower }}/gpg' Suse: pkg: - name: docker - pkgs: - - python3-pip - - python3-docker + deps: + - python3-pip + - tar + - gzip + docker: + name: docker MacOS: - rootuser: {{ macos_user | d('') }} - pkgs: - - python3-docker + identity: + rootuser: {{ rootuser | d('') }} + pkg: + deps: + - python3-docker # homebrew + - docker-machine # homebrew + docker: + name: Docker # Docker Desktop (docker=homebrew) + use_upstream: desktop # package or desktop (archive=docker client) + uri_a: 'https://download.docker.com/mac/static/stable/' + archive: + source_hash: '487bb7179873e4b5f06b70f521a806d84edf7dddbeb4153dfc38b508faef5ab2' + uri_d: 'https://desktop.docker.com/mac/stable/Docker' + desktop: + source_hash: 'db78429815fd571bbed319ece03fbe227a3d497b7d1d37c87b0e5a3600b9a23b' + suffix: '.dmg' + compose: + name: docker-compose # homebrew + use_upstream: package # Docker Desktop + archive: + source: 'https://dl.bintray.com/docker-compose/master/docker-compose-Darwin-x86_64' + source_hash: 'c5e326611efa45cbaf5b338bf352cbf27e9eb7dff0619f77639cae1158f6571f' + +Windows: + div: '\' + dir: + base: C:\\docker + source: C:\\docker\src\libs + operators: C:\\docker\src + tmp: C:\\temp\docker + identity: + rootuser: {{ rootuser | d('') }} pkg: - name: docker #homebrew - # workaround https://github.com/saltstack-formulas/docker-formula/issues/219 - allow_updates: false - hold: false - use_upstream_app: true #docker desktop for mac - app: - name: Docker - source: https://download.docker.com/mac/stable/Docker.dmg - source_hash: f69bd8f9d0863497819b998d27da4825b65884519f3f6a0e2ce1d4c5cdd26f5e + deps: + - docker-cli + docker: + name: Docker-Desktop # choco=docker-machine + use_upstream: desktop # choco or desktop + uri_d: 'https://desktop.docker.com/win/stable/Docker%20Desktop%20Installer' + desktop: + source_hash: 'b81b399ec34505981f9f2b0b68d6eec81bfd706b9376350f4ee93c24fa4e2729' + suffix: '.exe' + compose: + use_upstream: null # included in docker-desktop diff --git a/docker/osfingermap.yaml b/docker/osfingermap.yaml new file mode 100644 index 00000000..77d24aca --- /dev/null +++ b/docker/osfingermap.yaml @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +# vim: ft=yaml +# +# Setup variables using grains['osfinger'] based logic. +# You just need to add the key:values for an `osfinger` that differ +# from `defaults.yaml` + `osarch.yaml` + `os_family.yaml` + `osmap.yaml`. +# Only add an `osfinger` which is/will be supported by the formula. +# +# If you do not need to provide defaults via the `os_finger` grain, +# you will need to provide at least an empty dict in this file, e.g. +# osfingermap: {} +--- +Amazon Linux-2: + pkg: + docker: + use_upstream: 'archive' + +CentOS Linux-8: + pkg: + deps: + # selinux-policy + - selinux-policy-minimum + - python3-dnf-plugin-versionlock + +CentOS Linux-7: + pkg: + deps: + - selinux-policy-minimum + - yum-plugin-versionlock + +CentOS-6: + pkg: + deps: + - selinux-policy-minimum + - yum-plugin-versionlock diff --git a/docker/osmap.yaml b/docker/osmap.yaml index b522db41..a57dda52 100644 --- a/docker/osmap.yaml +++ b/docker/osmap.yaml @@ -1,10 +1,26 @@ # -*- coding: utf-8 -*- # vim: ft=yaml --- -CentOS: - pkgs: - - python2-pip - FreeBSD: - pkgs: - - devel/py-pip + # https://reviews.freebsd.org/D21570 + pkg: + deps: + - devel/py-pip + +Centos: + pkg: + deps: + - procps + - yum-utils + +Amazon: + pkg: + docker: + name: docker + repo: null + +Fedora: + pkg: + deps: + - selinux-policy-minimum + - python3-dnf-plugin-versionlock diff --git a/docker/registry.sls b/docker/registry.sls deleted file mode 100644 index f670c4c1..00000000 --- a/docker/registry.sls +++ /dev/null @@ -1,26 +0,0 @@ -{#- Get the `tplroot` from `tpldir` #} -{%- set tplroot = tpldir.split('/')[0] %} -{%- from tplroot ~ "/map.jinja" import docker with context %} - -file-registry-upstart-conf: - file.managed: - - name: /etc/init/registry.conf - - source: salt://docker/files/upstart.conf.deprecated.registry - - mode: 700 - - user: root - - template: jinja - - require: - - cmd: cmd-registry-image-pull - -cmd-registry-image-pull: - cmd.run: - - name: docker pull registry:{{ registry.version }} - - require: - - service: docker-service - -service-registry: - service.running: - - name: registry - - enable: True - - watch: - - file: file-registry-upstart-conf diff --git a/docker/remove.sls b/docker/remove.sls deleted file mode 100644 index f326ff4f..00000000 --- a/docker/remove.sls +++ /dev/null @@ -1,8 +0,0 @@ -# -*- coding: utf-8 -*- -# vim: ft=sls -{#- Get the `tplroot` from `tpldir` #} -{%- set tplroot = tpldir.split('/')[0] %} -{%- from tplroot ~ "/map.jinja" import docker with context %} - -include: - - .clean diff --git a/docker/repo.sls b/docker/repo.sls deleted file mode 100644 index 5ed8bda7..00000000 --- a/docker/repo.sls +++ /dev/null @@ -1,59 +0,0 @@ - -{#- Get the `tplroot` from `tpldir` #} -{%- set tplroot = tpldir.split('/')[0] %} -{%- from tplroot ~ "/map.jinja" import docker with context %} - -{% set repo_state = 'absent' %} -{% if docker.use_upstream_repo or docker.use_old_repo %} - {% set repo_state = 'managed' %} -{% endif %} - -{% set humanname_old = 'Old ' if docker.use_old_repo else '' %} - -{%- if grains['os_family']|lower in ('debian',) %} -{% set url = 'https://apt.dockerproject.org/repo ' ~ grains["os"]|lower ~ '-' ~ grains["oscodename"] ~ ' main' if docker.use_old_repo else docker.repo.url_base ~ ' ' ~ docker.repo.version ~ ' stable' %} - -docker-package-repository: - pkgrepo.{{ repo_state }}: - - humanname: {{ grains["os"] }} {{ grains["oscodename"]|capitalize }} {{ humanname_old }}Docker Package Repository - - name: deb [arch={{ grains["osarch"] }}] {{ url }} - - file: {{ docker.repo.file }} - {% if docker.use_old_repo %} - - keyserver: keyserver.ubuntu.com - - keyid: 58118E89F3A912897C070ADBF76221572C52609D - {% else %} - - key_url: {{ docker.repo.key_url }} - {% endif %} - {%- if grains['saltversioninfo'] >= [2018, 3, 0] %} - - refresh: True - {%- else %} - - refresh_db: True - {%- endif %} - - require_in: - - pkg: docker-package - - require: - - pkg: docker-package-dependencies - -{%- elif grains['os_family']|lower in ('redhat',) %} -{% set url = 'https://yum.dockerproject.org/repo/main/centos/$releasever/' if docker.use_old_repo else docker.repo.url_base %} - -docker-package-repository: - pkgrepo.{{ repo_state }}: - - name: docker-ce-stable - - humanname: {{ grains['os'] }} {{ grains["oscodename"]|capitalize }} {{ humanname_old }}Docker Package Repository - - baseurl: {{ url }} - - enabled: 1 - - gpgcheck: 1 - {% if docker.use_old_repo %} - - gpgkey: https://yum.dockerproject.org/gpg - {% else %} - - gpgkey: {{ docker.repo.key_url }} - {% endif %} - - require_in: - - pkg: docker-package - - require: - - pkg: docker-package-dependencies - -{%- else %} -docker-package-repository: {} -{%- endif %} diff --git a/docker/software/alternatives/clean.sls b/docker/software/alternatives/clean.sls new file mode 100644 index 00000000..97de42d5 --- /dev/null +++ b/docker/software/alternatives/clean.sls @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if grains.kernel == 'Linux' and d.linux.altpriority|int > 0 and grains.os_family not in ('Arch',) %} + {%- for cmd in d.pkg.docker.commands|unique %} + +{{ formula }}-docker-alternatives-clean-{{ cmd }}: + alternatives.remove: + - name: link-k8s-docker-{{ cmd }} + - path: {{ d.pkg.docker.path }}/bin/{{ cmd }} + - onlyif: update-alternatives --list |grep ^link-k8s-docker-{{ cmd }} + + {%- endfor %} + {%- endif %} diff --git a/docker/software/alternatives/init.sls b/docker/software/alternatives/init.sls new file mode 100644 index 00000000..d3e55181 --- /dev/null +++ b/docker/software/alternatives/init.sls @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +include: + - .install diff --git a/docker/software/alternatives/install.sls b/docker/software/alternatives/install.sls new file mode 100644 index 00000000..7f9e6ec6 --- /dev/null +++ b/docker/software/alternatives/install.sls @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if grains.kernel == 'Linux' and d.linux.altpriority|int > 0 and grains.os_family not in ('Arch',) %} + {%- set sls_archive_install = tplroot ~ '.docker.archive.install' %} + +include: + - {{ sls_archive_install }} + + {%- for cmd in d.pkg.docker.commands|unique %} +{{ formula }}-docker-alternatives-install-bin-{{ cmd }}: + {%- if grains.os_family not in ('Suse', 'Arch') %} + alternatives.install: + - name: link-docker-docker-{{ cmd }} + - link: /usr/local/bin/{{ cmd }} + - order: 10 + - path: {{ d.pkg.docker['path'] }}/{{ cmd }} + - priority: {{ d.linux.altpriority }} + {%- else %} + cmd.run: + - name: update-alternatives --install /usr/local/bin/{{ cmd }} link-docker-docker-{{ cmd }} {{ d.pkg.docker['path'] }}/{{ cmd }} {{ d.linux.altpriority }} # noqa 204 + {%- endif %} + + - onlyif: + - test -f {{ d.pkg.docker['path'] }}/{{ cmd }} + - unless: update-alternatives --list |grep ^link-docker-docker-{{ cmd }} || false + - require: + - sls: {{ sls_archive_install }} + - require_in: + - alternatives: {{ formula }}-docker-alternatives-set-bin-{{ cmd }} + +{{ formula }}-docker-alternatives-set-bin-{{ cmd }}: + alternatives.set: + - unless: {{ grains.os_family in ('Suse', 'Arch') }} || false + - name: link-docker-docker-{{ cmd }} + - path: {{ d.pkg.docker.path }}/{{ cmd }} + - onlyif: test -f {{ d.pkg.docker['path'] }}/{{ cmd }} + + {%- endfor %} + {%- endif %} diff --git a/docker/software/archive/clean.sls b/docker/software/archive/clean.sls new file mode 100644 index 00000000..4a017297 --- /dev/null +++ b/docker/software/archive/clean.sls @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if grains.kernel|lower in ('linux',) %} + {%- set sls_alternatives_clean = tplroot ~ '.software.alternatives.clean' %} + +include: + - {{ sls_alternatives_clean }} + +{{ formula }}-docker-archive-absent: + file.absent: + - names: + - {{ d.dir.tmp }}/docker + - {{ d.pkg.docker.path }} + {%- if d.linux.altpriority|int == 0 or grains.os_family in ('Arch', 'MacOS') %} + {%- for cmd in d.pkg.docker.commands|unique %} + - /usr/local/bin/{{ cmd }} + {%- endfor %} + + {%- endif %} + {%- endif %} diff --git a/docker/software/archive/init.sls b/docker/software/archive/init.sls new file mode 100644 index 00000000..051d698c --- /dev/null +++ b/docker/software/archive/init.sls @@ -0,0 +1,5 @@ +#.-*- coding: utf-8 -*- +# vim: ft=sls + +include: + - .install diff --git a/docker/software/archive/install.sls b/docker/software/archive/install.sls new file mode 100644 index 00000000..5bd6891f --- /dev/null +++ b/docker/software/archive/install.sls @@ -0,0 +1,105 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if grains.kernel|lower == 'linux' and d.pkg.docker.use_upstream == 'archive' and 'archive' in d.pkg.docker %} + {%- from tplroot ~ "/files/macros.jinja" import format_kwargs with context %} + {%- from tplroot ~ "/libtofs.jinja" import files_switch with context %} + +{{ formula }}-software-docker-archive-install: + {%- if 'deps' in d.pkg and d.pkg.deps %} + pkg.installed: + - names: {{ d.pkg.deps|json }} + - reload_modules: {{ d.misc.reload or true }} + - require_in: + - file: {{ formula }}-software-docker-archive-install + {%- endif %} + file.directory: + - name: {{ d.pkg.docker.path }} + - makedirs: True + - clean: {{ d.misc.clean }} + - require_in: + - archive: {{ formula }}-software-docker-archive-install + - mode: 755 + - user: {{ d.identity.rootuser }} + - group: {{ d.identity.rootgroup }} + - recurse: + - user + - group + - mode + archive.extracted: + - unless: test -x {{ d.pkg.docker.path }}{{ d.div }}docker + {{- format_kwargs(d.pkg.docker['archive']) }} + - retry: {{ d.retry_option|json }} + - enforce_toplevel: false + - trim_output: true + - user: {{ d.identity.rootuser }} + - group: {{ d.identity.rootgroup }} + - recurse: + - user + - group + - require: + - file: {{ formula }}-software-docker-archive-install + + {%- if d.linux.altpriority|int == 0 or grains.os_family in ('Arch', 'MacOS') %} + {%- for cmd in d.pkg.docker.commands|unique %} + +{{ formula }}-software-docker-archive-install-symlink-{{ cmd }}: + file.symlink: + - name: /usr/local/bin/{{ cmd }} + - target: {{ d.pkg.docker.path }}/{{ cmd }} + - force: True + - onchanges: + - archive: {{ formula }}-software-docker-archive-install + - require: + - archive: {{ formula }}-software-docker-archive-install + + {%- endfor %} + {%- endif %} + {%- if 'service' in d.pkg.docker and d.pkg.docker.service is mapping %} + +{{ formula }}-software-docker-archive-install-file-directory: + file.directory: + - name: {{ d.dir.lib }} + - makedirs: True + - user: {{ d.identity.rootuser }} + - group: {{ d.identity.rootgroup }} + - mode: '0755' + +{{ formula }}-software-docker-archive-install-managed-service: + file.managed: + - name: {{ d.dir.service }}/{{ d.pkg.docker.service.name }}.service + - source: {{ files_switch(['systemd.ini.jinja'], + lookup=formula ~ '-software-docker-archive-install-managed-service' + ) + }} + - mode: '0644' + - user: {{ d.identity.rootuser }} + - group: {{ d.identity.rootgroup }} + - makedirs: True + - template: jinja + - context: + desc: {{ d.pkg.docker.service.name }} service + name: {{ d.pkg.docker.service.name }} + user: {{ d.identity.rootuser }} + group: {{ d.identity.rootgroup }} + workdir: {{ d.dir.lib }} + stop: '' + start: {{ d.pkg.docker.path }}/{{ d.pkg.docker.service.name }} + cmd.run: + - name: systemctl daemon-reload + - require: + - archive: {{ formula }}-software-docker-archive-install + + {%- endif %} + {%- else %} + +{{ formula }}-software-docker-archive-install-other: + test.show_notification: + - text: | + The docker archive is unavailable/unselected for {{ salt['grains.get']('finger', grains.os_family) }} + + {%- endif %} diff --git a/docker/software/clean.sls b/docker/software/clean.sls new file mode 100644 index 00000000..3c740ab8 --- /dev/null +++ b/docker/software/clean.sls @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +include: + - .service.clean + - .config.clean + - .alternatives.clean + - .package.clean + - .archive.clean + - .desktop.clean diff --git a/docker/software/config/clean.sls b/docker/software/config/clean.sls new file mode 100644 index 00000000..6d1d0a46 --- /dev/null +++ b/docker/software/config/clean.sls @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + +{%- set sls_archive_clean = tplroot ~ '.software.archive.clean' %} +{%- set sls_package_clean = tplroot ~ '.software.package.clean' %} + +include: + - {{ sls_archive_clean if d.pkg.docker.use_upstream == 'archive' else sls_package_clean }} + +{{ formula }}-software-config-clean: + file.absent: + - name: {{ d.pkg.docker.config_file }} + - require: + - sls: {{ sls_archive_clean if d.pkg.docker.use_upstream == 'archive' else sls_package_clean }} diff --git a/docker/software/config/file.sls b/docker/software/config/file.sls new file mode 100644 index 00000000..d1b29433 --- /dev/null +++ b/docker/software/config/file.sls @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'config' in d.pkg.docker and d.pkg.docker.config %} + {%- from tplroot ~ "/libtofs.jinja" import files_switch with context %} + {%- set sls_archive = tplroot ~ '.software.archive.install' %} + {%- set sls_desktop = tplroot ~ '.software.desktop.install' %} + {%- set sls_package = tplroot ~ '.software.package.install' %} + +include: + - {{ sls_archive if d.pkg.docker.use_upstream == 'archive' else sls_desktop if d.pkg.docker.use_upstream == 'desktop' else sls_package }} + +{{ formula }}-software-config-file-managed-config_file: + file.managed: + - name: {{ d.pkg.docker.config_file }} + - source: {{ files_switch(['config.sh.jinja'], + lookup='k8s-software-config-file-managed-config_file' + ) + }} + - makedirs: True + {%- if grains.os != 'Windows' %} + - mode: '0640' + - user: {{ d.identity.rootuser }} + - group: {{ d.identity.rootgroup }} + {%- endif %} + - template: jinja + - context: + config: {{ d.pkg.docker.config|json }} + - require: + - sls: {{ sls_archive if d.pkg.docker.use_upstream == 'archive' else sls_desktop if d.pkg.docker.use_upstream == 'desktop' else sls_package }} + + {%- endif %} diff --git a/docker/software/config/init.sls b/docker/software/config/init.sls new file mode 100644 index 00000000..465ddfea --- /dev/null +++ b/docker/software/config/init.sls @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +include: + - .file diff --git a/docker/software/desktop/clean.sls b/docker/software/desktop/clean.sls new file mode 100644 index 00000000..df251040 --- /dev/null +++ b/docker/software/desktop/clean.sls @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + +{{ formula }}-docker-desktop-absent: + file.absent: + - names: + - {{ d.pkg.docker.path }} + - {{ d.dir.tmp }}{{ d.div }}Docker-Desktop{{ d.pkg.docker.suffix }} + - {{ d.div }}Applications{{ d.div }}Docker.app diff --git a/docker/software/desktop/init.sls b/docker/software/desktop/init.sls new file mode 100644 index 00000000..051d698c --- /dev/null +++ b/docker/software/desktop/init.sls @@ -0,0 +1,5 @@ +#.-*- coding: utf-8 -*- +# vim: ft=sls + +include: + - .install diff --git a/docker/software/desktop/install.sls b/docker/software/desktop/install.sls new file mode 100644 index 00000000..cc9e7488 --- /dev/null +++ b/docker/software/desktop/install.sls @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if grains.os|lower in ('darwin', 'windows') %} + {%- from tplroot ~ "/files/macros.jinja" import format_kwargs with context %} + {%- if d.pkg.docker.use_upstream == 'desktop' and 'desktop' in d.pkg.docker %} + + {%- if grains.os == 'MacOS' %} +{{ formula }}-software-desktop-download-tmpdir: + file.directory: + - name: {{ d.dir.tmp }} + - makedirs: true + - require_in: + - pkg: {{ formula }}-macos-app-install-cmd-run + {%- endif %} + +{{ formula }}-software-desktop-download: + file.managed: + - name: {{ d.dir.tmp }}{{ d.div }}Docker-Desktop{{ d.pkg.docker.suffix }} + - source: {{ d.pkg.docker.desktop.source }} + - source_hash: {{ d.pkg.docker.desktop.source_hash }} + - unless: test -f {{ d.dir.tmp }}{{ d.div }}Docker-Desktop{{ d.pkg.docker.suffix }} + - makedirs: True + - retry: {{ d.retry_option|json }} + +{{ formula }}-software-desktop-install: + + {%- if grains.os|lower == 'windows' %} + cmd.run: + - name: {{ d.dir.tmp }}{{ d.div }}Docker-Desktop{{ d.pkg.docker.suffix }} || true + - require: + - file: {{ formula }}-software-desktop-download + + {%- elif grains.os|lower == 'macos' %} + macpackage.installed: + - name: {{ d.dir.tmp }}/Docker-Desktop{{ d.pkg.docker.suffix }} + - store: True + - dmg: True + - app: True + - force: True + - allow_untrusted: True + - onchanges: + - file: {{ formula }}-software-desktop-download + file.append: + - name: /Users/{{ d.identity.rootuser }}/.bash_profile + - text: 'export PATH=$PATH:/Applications/Docker.app/Contents/Versions/latest/bin' + - require: + - macpackage: {{ formula }}-software-desktop-install + + {%- endif %} + {%- endif %} + {%- else %} + +{{ formula }}-software-desktop-install-other: + test.show_notification: + - text: | + The docker desktop is unavailable/unselected for {{ salt['grains.get']('finger', grains.os_family) }} + + {%- endif %} diff --git a/docker/software/init.sls b/docker/software/init.sls new file mode 100644 index 00000000..d4f964c8 --- /dev/null +++ b/docker/software/init.sls @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +include: + - .package + - .archive + - .desktop + - .config + - .alternatives + - .service diff --git a/docker/software/package/clean.sls b/docker/software/package/clean.sls new file mode 100644 index 00000000..ee277c9c --- /dev/null +++ b/docker/software/package/clean.sls @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if d.pkg.docker.use_upstream in ('package', 'repo') %} + {%- if grains.kernel|lower in ('linux',) %} + {%- if d.pkg.docker.use_upstream == 'repo' %} +include: + - .package.repo.clean + {%- endif %} + +{{ formula }}-software-package-clean-pkg: + pkg.removed: + - name: kubectl + - reload_modules: true + {%- if d.pkg.docker.use_upstream == 'repo' %} + - require: + - pkgrepo: {{ formula }}-package-repo-absent + {%- endif %} + + {%- elif grains.os_family == 'MacOS' %} + +{{ formula }}-software-package-clean-brew: + cmd.run: + - name: /usr/local/bin/brew uninstall docker-machine docker-cli + - runas: {{ d.identity.rootuser }} + - onlyif: + - brew list | grep ^docker-machine$ + + {%- elif grains.os_family == 'Windows' %} + +{{ formula }}-software-package-clean-choco: + chocolatey.uninstalled: + - name: {{ d.pkg.docker.name }} + + {%- endif %} + {%- else %} + +{{ formula }}-software-package-clean-other: + test.show_notification: + - text: | + The docker package is unavailable/unselected for {{ salt['grains.get']('finger', grains.os_family) }} + + {%- endif %} diff --git a/docker/software/package/init.sls b/docker/software/package/init.sls new file mode 100644 index 00000000..d3e55181 --- /dev/null +++ b/docker/software/package/init.sls @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +include: + - .install diff --git a/docker/software/package/install.sls b/docker/software/package/install.sls new file mode 100644 index 00000000..142e5600 --- /dev/null +++ b/docker/software/package/install.sls @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if d.pkg.docker.use_upstream in ('package', 'repo') %} + {%- set docker_pkg_version = d.version | default(d.pkg.version, true) %} + {%- if grains.os_family in ('RedHat', 'Debian') %} + {%- set sls_repo_install = tplroot ~ '.software.package.repo.install' %} + +include: + - {{ sls_repo_install }} + {%- endif %} + {%- if grains.kernel|lower in ('linux', 'darwin') %} + {%- if 'deps' in d.pkg and d.pkg.deps %} + +{{ formula }}-software-package-install-deps: + pkg.installed: + - names: {{ d.pkg.deps|json }} + - require_in: + - pkg: {{ formula }}-software-package-install-pkg + + {%- endif %} + +{{ formula }}-software-package-install-pkg: + pkg.installed: + - name: {{ d.pkg.docker.name }} + - version: {{ docker_pkg_version or d.pkg.version or 'latest' }} + - runas: {{ d.identity.rootuser }} + - reload_modules: {{ d.misc.reload|default(true, true) }} + - refresh: {{ d.misc.refresh|default(true, true) }} + {%- if grains.os|lower not in ('suse',) %} + - hold: {{ d.misc.hold|default(false, true) }} + {%- endif %} + {%- if grains.os_family in ('RedHat', 'Debian') %} + - require: + - pkgrepo: {{ formula }}-software-package-repo-managed + {%- endif %} + + {%- elif grains.kernel|lower in ('windows',) %} + +{{ formula }}-software-package-install-deps: + chocolatey.installed: + - name: docker-cli + - force: True + +{{ formula }}-software-package-install-choco: + chocolatey.installed: + - name: docker-machine + - force: True + + {%- endif %} + {%- else %} + +{{ formula }}-software-package-install-other: + test.show_notification: + - text: | + The docker package is unavailable/unselected for {{ salt['grains.get']('finger', grains.os_family) }} + + {%- endif %} diff --git a/docker/software/package/repo/clean.sls b/docker/software/package/repo/clean.sls new file mode 100644 index 00000000..253d8293 --- /dev/null +++ b/docker/software/package/repo/clean.sls @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + +{{ formula }}-software-package-repo-absent: + pkgrepo.absent: + - name: {{ d.pkg.docker.repo.name }} + - onlyif: + - {{ d.pkg.docker.repo }} diff --git a/docker/software/package/repo/init.sls b/docker/software/package/repo/init.sls new file mode 100644 index 00000000..d3e55181 --- /dev/null +++ b/docker/software/package/repo/init.sls @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +include: + - .install diff --git a/docker/software/package/repo/install.sls b/docker/software/package/repo/install.sls new file mode 100644 index 00000000..e50fd932 --- /dev/null +++ b/docker/software/package/repo/install.sls @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'repo' in d.pkg.docker and d.pkg.docker.repo %} + {%- from tplroot ~ "/files/macros.jinja" import format_kwargs with context %} + +{{ formula }}-software-package-repo-managed: + pkgrepo.managed: + {{- format_kwargs(d.pkg.docker.repo) }} + - humanname: {{ grains["os"] }} {{ grains["oscodename"]|capitalize }} Docker Package Repository + - refesh: {{ d.misc.refresh }} + - onlyif: + - {{ d.pkg.docker.repo }} + + {%- endif %} diff --git a/docker/software/service/clean.sls b/docker/software/service/clean.sls new file mode 100644 index 00000000..4395bb0d --- /dev/null +++ b/docker/software/service/clean.sls @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'service' in d.pkg.docker and d.pkg.docker.service and grains.os != 'Windows' %} + +{{ formula }}-software-service-clean-docker: + service.dead: + - name: {{ d.pkg.docker.service.name }} + - enable: False + {%- if grains.kernel|lower == 'linux' %} + - onlyif: systemctl list-units | grep {{ d.pkg.docker.service.name }} >/dev/null 2>&1 + file.absent: + - name: {{ d.dir.service }}{{ d.div }}docker.service + - require: + - service: {{ formula }}-software-service-clean-docker + cmd.run: + - name: systemctl daemon-reload + - require: + - file: {{ formula }}-software-service-clean-docker + {%- endif %} + + {%- endif %} diff --git a/docker/software/service/init.sls b/docker/software/service/init.sls new file mode 100644 index 00000000..6fe4d1a3 --- /dev/null +++ b/docker/software/service/init.sls @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +include: + - .running diff --git a/docker/software/service/running.sls b/docker/software/service/running.sls new file mode 100644 index 00000000..fcc7e445 --- /dev/null +++ b/docker/software/service/running.sls @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'service' in d.pkg.docker and d.pkg.docker.service and grains.os != 'Windows' %} + {%- set sls_config_file = tplroot ~ '.software.config.file' %} + {%- set sls_archive = tplroot ~ '.software.archive.install' %} + {%- set sls_desktop = tplroot ~ '.software.desktop.install' %} + {%- set sls_package = tplroot ~ '.software.package.install' %} + +include: + - {{ sls_archive if d.pkg.docker.use_upstream == 'archive' else sls_desktop if d.pkg.docker.use_upstream == 'desktop' else sls_package }} + - {{ sls_config_file }} + + {%- if grains.kernel|lower == 'linux' %} + +{{ formula }}-software-service-running-unmasked: + service.unmasked: + - name: {{ d.pkg.docker.service.name }} + - onlyif: systemctl list-unit-files | grep {{ d.pkg.docker.service.name }} >/dev/null 2>&1 + - require_in: + - service: {{ formula }}-software-service-running-docker + {%- if 'config' in d.pkg.docker and d.pkg.docker.config %} + - require: + - sls: {{ sls_config_file }} + {%- endif %} + {%- if d.misc.firewall %} + pkg.installed: + - name: firewalld + - reload_modules: true + {%- endif %} + + {%- endif %} + +{{ formula }}-software-service-running-docker: + service.running: + - name: {{ d.pkg.docker.service.name }} + {%- if 'config' in d.pkg.docker and d.pkg.docker.config %} + - require: + - sls: {{ sls_config_file }} + {%- endif %} + - enable: True + {%- if grains.kernel|lower == 'linux' %} + - onlyif: systemctl list-unit-files | grep {{ d.pkg.docker.service.name }} >/dev/null 2>&1 + +{{ formula }}-software-service-running-docker-fail-notify: + test.show_notification: + - text: | + * Rebooting your host is recommended! + In certain circumstances the docker service will not start. + Your kernel is missing some modules, or not in ideal state. + See https://github.com/moby/moby/blob/master/contrib/check-config.sh + * Rebooting your host is recommended! + - onfail: + - service: {{ formula }}-software-service-running-docker + service.enabled: + - onlyif: {{ grains.kernel|lower == 'linux' }} + - name: {{ d.pkg.docker.service.name }} + - onfail: + - service: {{ formula }}-software-service-running-docker + + {%- if d.misc.firewall and d.pkg.docker.firewall.ports %} + +{{ formula }}-software-service-running-docker: + service.running: + - name: firewalld + firewalld.present: + - name: public + - ports: {{ d.pkg.docker.firewall.ports|json }} + - require: + - service: {{ formula }}-software-service-running-docker + + {%- endif %} + {%- endif %} + {%- endif %} diff --git a/docker/swarm/clean.sls b/docker/swarm/clean.sls new file mode 100644 index 00000000..d43af428 --- /dev/null +++ b/docker/swarm/clean.sls @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +include: + - .leaveswarm diff --git a/docker/swarm/create_service.sls b/docker/swarm/create_service.sls new file mode 100644 index 00000000..e8f30dd5 --- /dev/null +++ b/docker/swarm/create_service.sls @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'service_create' in d.swarm and d.swarm.service_create is mapping %} + {%- from tplroot ~ "/files/macros.jinja" import format_kwargs with context %} + +{{ formula }}-swarm-service_create: + module.run: + - name: swarm.service_create + {{- format_kwargs(d.swarm.service_create) }} + + {%- endif %} diff --git a/docker/swarm/init.sls b/docker/swarm/init.sls new file mode 100644 index 00000000..9d915f3d --- /dev/null +++ b/docker/swarm/init.sls @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +include: + - .swarm_init diff --git a/docker/swarm/joinswarm.sls b/docker/swarm/joinswarm.sls new file mode 100644 index 00000000..78416321 --- /dev/null +++ b/docker/swarm/joinswarm.sls @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'joinswarm' in d.swarm and d.swarm.joinswarm is mapping %} + {%- from tplroot ~ "/files/macros.jinja" import format_kwargs with context %} + +{{ formula }}-swarm-joinswarm: + module.run: + - name: swarm.joinswarm + {{- format_kwargs(d.swarm.joinswarm) }} + + {%- endif %} diff --git a/docker/swarm/leaveswarm.sls b/docker/swarm/leaveswarm.sls new file mode 100644 index 00000000..f4db42e6 --- /dev/null +++ b/docker/swarm/leaveswarm.sls @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'leave_swarm' in d.swarm and d.swarm.leave_swarm %} + +{{ formula }}-swarm-leave_swarm: + module.run: + - name: swarm.leave_swarm + - force: true + + {%- endif %} diff --git a/docker/swarm/node_ls.sls b/docker/swarm/node_ls.sls new file mode 100644 index 00000000..49c898e8 --- /dev/null +++ b/docker/swarm/node_ls.sls @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'node_ls' in d.swarm and d.swarm.node_ls is mapping %} + {%- from tplroot ~ "/files/macros.jinja" import format_kwargs with context %} + +{{ formula }}-swarm-node_ls: + module.run: + - name: swarm.node_ls + {{- format_kwargs(d.swarm.node_ls) }} + + {%- endif %} diff --git a/docker/swarm/remove_node.sls b/docker/swarm/remove_node.sls new file mode 100644 index 00000000..995d5041 --- /dev/null +++ b/docker/swarm/remove_node.sls @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'remove_node' in d.swarm and d.swarm.remove_node is mapping %} + {%- from tplroot ~ "/files/macros.jinja" import format_kwargs with context %} + +{{ formula }}-swarm-remove_node: + module.run: + - name: swarm.remove_node + {{- format_kwargs(d.swarm.remove_node) }} + + {%- endif %} diff --git a/docker/swarm/remove_service.sls b/docker/swarm/remove_service.sls new file mode 100644 index 00000000..18902738 --- /dev/null +++ b/docker/swarm/remove_service.sls @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'remove_service' in d.swarm and d.swarm.remove_service is mapping %} + {%- from tplroot ~ "/files/macros.jinja" import format_kwargs with context %} + +{{ formula }}-swarm-remove_service: + module.run: + - name: swarm.remove_service + {{- format_kwargs(d.swarm.remove_service) }} + + {%- endif %} diff --git a/docker/swarm/swarm_init.sls b/docker/swarm/swarm_init.sls new file mode 100644 index 00000000..4b7f3a1d --- /dev/null +++ b/docker/swarm/swarm_init.sls @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'swarm_init' in d.swarm and d.swarm.swarm_init is mapping %} + {%- from tplroot ~ "/files/macros.jinja" import format_kwargs with context %} + +{{ formula }}-swarm-swarm_init: + module.run: + - name: swarm.swarm_init + {{- format_kwargs(d.swarm.swarm_init) }} + + {%- endif %} diff --git a/docker/swarm/swarm_service_info.sls b/docker/swarm/swarm_service_info.sls new file mode 100644 index 00000000..fe114f72 --- /dev/null +++ b/docker/swarm/swarm_service_info.sls @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'swarm_service_info' in d.swarm and d.swarm.swarm_service_info is mapping %} + {%- from tplroot ~ "/files/macros.jinja" import format_kwargs with context %} + +{{ formula }}-swarm-swarm_service_info: + module.run: + - name: swarm.swarm_service_info + {{- format_kwargs(d.swarm.swarm_service_info) }} + + {%- endif %} diff --git a/docker/swarm/swarm_tokens.sls b/docker/swarm/swarm_tokens.sls new file mode 100644 index 00000000..5cc22f31 --- /dev/null +++ b/docker/swarm/swarm_tokens.sls @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'swarm_tokens' in d.swarm and d.swarm.swarm_tokens %} + +{{ formula }}-swarm-swarm_tokens: + module.run: + - name: swarm.swarm_tokens + + {%- endif %} diff --git a/docker/swarm/update_node.sls b/docker/swarm/update_node.sls new file mode 100644 index 00000000..8df7d3be --- /dev/null +++ b/docker/swarm/update_node.sls @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import data as d with context %} +{%- set formula = d.formula %} + + {%- if 'update_node' in d.swarm and d.swarm.update_node is mapping %} + {%- from tplroot ~ "/files/macros.jinja" import format_kwargs with context %} + +{{ formula }}-swarm-update_node: + module.run: + - name: swarm.update_node + {{- format_kwargs(d.swarm.update_node) }} + + {%- endif %} diff --git a/docs/CONTRIBUTING.rst b/docs/CONTRIBUTING.rst new file mode 100644 index 00000000..1179c5a0 --- /dev/null +++ b/docs/CONTRIBUTING.rst @@ -0,0 +1,186 @@ +.. _contributing: + +How to contribute +================= + +This document will eventually outline all aspects of guidance to make your contributing experience a fruitful and enjoyable one. +What it already contains is information about *commit message formatting* and how that directly affects the numerous automated processes that are used for this repo. +It also covers how to contribute to this *formula's documentation*. + +.. contents:: **Table of Contents** + +Overview +-------- + +Submitting a pull request is more than just code! +To achieve a quality product, the *tests* and *documentation* need to be updated as well. +An excellent pull request will include these in the changes, wherever relevant. + +Commit message formatting +------------------------- + +Since every type of change requires making Git commits, +we will start by covering the importance of ensuring that all of your commit +messages are in the correct format. + +Automation of multiple processes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This formula uses `semantic-release `_ for automating numerous processes such as bumping the version number appropriately, creating new tags/releases and updating the changelog. +The entire process relies on the structure of commit messages to determine the version bump, which is then used for the rest of the automation. + +Full details are available in the upstream docs regarding the `Angular Commit Message Conventions `_. +The key factor is that the first line of the commit message must follow this format: + +.. code-block:: + + type(scope): subject + + +* E.g. ``docs(contributing): add commit message formatting instructions``. + +Besides the version bump, the changelog and release notes are formatted accordingly. +So based on the example above: + +.. + + .. raw:: html + +

Documentation

+ + * **contributing:** add commit message formatting instructions + + +* The ``type`` translates into a ``Documentation`` sub-heading. +* The ``(scope):`` will be shown in bold text without the brackets. +* The ``subject`` follows the ``scope`` as standard text. + +Linting commit messages in Travis CI +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This formula uses `commitlint `_ for checking commit messages during CI testing. +This ensures that they are in accordance with the ``semantic-release`` settings. + +For more details about the default settings, refer back to the ``commitlint`` `reference rules `_. + +Relationship between commit type and version bump +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This formula applies some customisations to the defaults, as outlined in the table below, +based upon the `type `_ of the commit: + +.. list-table:: + :name: commit-type-vs-version-bump + :header-rows: 1 + :stub-columns: 0 + :widths: 1,2,3,1,1 + + * - Type + - Heading + - Description + - Bump (default) + - Bump (custom) + * - ``build`` + - Build System + - Changes related to the build system + - – + - + * - ``chore`` + - – + - Changes to the build process or auxiliary tools and libraries such as + documentation generation + - – + - + * - ``ci`` + - Continuous Integration + - Changes to the continuous integration configuration + - – + - + * - ``docs`` + - Documentation + - Documentation only changes + - – + - 0.0.1 + * - ``feat`` + - Features + - A new feature + - 0.1.0 + - + * - ``fix`` + - Bug Fixes + - A bug fix + - 0.0.1 + - + * - ``perf`` + - Performance Improvements + - A code change that improves performance + - 0.0.1 + - + * - ``refactor`` + - Code Refactoring + - A code change that neither fixes a bug nor adds a feature + - – + - 0.0.1 + * - ``revert`` + - Reverts + - A commit used to revert a previous commit + - – + - 0.0.1 + * - ``style`` + - Styles + - Changes that do not affect the meaning of the code (white-space, + formatting, missing semi-colons, etc.) + - – + - 0.0.1 + * - ``test`` + - Tests + - Adding missing or correcting existing tests + - – + - 0.0.1 + +Use ``BREAKING CHANGE`` to trigger a ``major`` version change +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Adding ``BREAKING CHANGE`` to the footer of the extended description of the commit message will **always** trigger a ``major`` version change, no matter which type has been used. +This will be appended to the changelog and release notes as well. +To preserve good formatting of these notes, the following format is prescribed: + +* ``BREAKING CHANGE: .`` + +An example of that: + +.. code-block:: git + + ... + + BREAKING CHANGE: With the removal of all of the `.sls` files under + `template package`, this formula no longer supports the installation of + packages. + + +Semantic release formulas +------------------------- + +These formulas are already compatible with semantic-release: + +* `bind-formula `_ +* `cert-formula `_ +* `chrony-formula `_ +* `collectd-formula `_ +* `fail2ban-formula `_ +* `keepalived-formula `_ +* `nginx-formula `_ +* `postgres-formula `_ +* `prometheus-formula `_ +* `rkhunter-formula `_ +* `salt-formula `_ +* `syslog-ng-formula `_ +* `systemd-formula `_ +* `ufw-formula `_ +* `vault-formula `_ + + +Documentation +------------- + +`Documentation contributing guidelines `_ diff --git a/docs/CONTRIBUTING_DOCS.rst b/docs/CONTRIBUTING_DOCS.rst new file mode 100644 index 00000000..5b59b298 --- /dev/null +++ b/docs/CONTRIBUTING_DOCS.rst @@ -0,0 +1,96 @@ +.. _contributing_docs: + +Contributing documentation +========================== + +|docs| + +.. |docs| image:: https://readthedocs.org/projects/docs/badge/?version=latest + :alt: Documentation Status + :scale: 100% + :target: https://template-formula.readthedocs.io/en/latest/?badge=latest + +Toolchain +^^^^^^^^^ + +The documentation for this formula is written in +`reStructuredText `_ +(also known as RST, ReST, or reST). +It is built by +`Sphinx `_ +and hosted on +`Read the Docs `_. + +Adding a new page +^^^^^^^^^^^^^^^^^ + +Adding a new page involves two steps: + +#. Use the + :ref:`provided page template ` + to create a new page. +#. Add the page name under the ``toctree`` list in ``index.rst``. + + a. Do not just append it to the list. + #. Select the best place where it fits within the overall documentation. + +SaltStack-Formulas' RST page template +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. _saltstack_formulas_rst_page_template + +Use the following template when creating a new page. +This ensures consistency across the documentation for this formula. +The heading symbols have been selected in accordance to the output rendered by the +`Markdown to reStructuredText converter `_ +we are using for some of the pages of this documentation. + +.. code-block:: rst + + .. _template: + + [Page title] + ============ + + [Introductory paragraph] + + .. contents:: **Table of Contents** + + [Heading 2] + ----------- + + [Heading 3] + ^^^^^^^^^^^ + + [Heading 4] + ~~~~~~~~~~~ + + [Heading 5] + """"""""""" + + [Heading 6] + ########### + +#. The first line is an anchor that can be used to link back to (the top of) + this file. + + a. Change this to be the lowercase version of the file name. + #. Do not include the ``.rst`` file extension. + #. Use hyphens (``-``) instead of spaces or non-letter characters. + +#. Change the ``[Page title]`` accordingly, matching the same number of equals + signs (``=``) underneath. +#. Change the ``[Introductory paragraph]`` to be a short summary of the page + content. + Use no more than three paragraphs for this. +#. Leave the ``..contents:: **Table of Contents**`` line as it is. +#. Use the remaining headings as required to break up the page content. + + a. You will rarely need to use beyond ``[Heading 4]``. + #. Again, no single heading should have more than about three paragraphs of + content before the next heading or sub-heading is used. + +Obviously, it is not necessary to follow the steps in the order above. +For example, it is usually easier to write the ``[Introductory paragraph]`` +at the end. + diff --git a/docs/README.rst b/docs/README.rst index 610761a5..dc9fd946 100644 --- a/docs/README.rst +++ b/docs/README.rst @@ -1,7 +1,23 @@ .. _readme: -Docker -====== +docker-formula +============== + +Extensible formula to manage Docker on MacOS, Windows, and GNU/Linux. Currently supports: + +* `software` Docker (https://docs.docker.com/engine/install) [all OS] +* `containers` Manage Containers. [all OS] +* `compose` Compose Containers. [all OS] +* `swarm` Docker Swarm. [Linux] + +The default `docker.software` and `docker.compose.software` states support: + +* `archive` Docker-Engine (https://docs.docker.com/engine/install) [Linux] +* `desktop` Docker-Desktop (https://docs.docker.com/desktop) [Windows, MacOS] +* Docker-Compose (https://docs.docker.com/compose/install/) [Linux] + +The other states support container managmement. + |img_travis| |img_sr| @@ -14,120 +30,119 @@ Docker :scale: 100% :target: https://github.com/semantic-release/semantic-release -Formulas for working with Docker +A SaltStack formula for Docker on MacOS, GNU/Linux and Windows. .. contents:: **Table of Contents** + :depth: 1 General notes ------------- See the full `SaltStack Formulas installation and usage instructions -`_. - -If you are interested in writing or contributing to formulas, please pay attention to the `Writing Formula Section -`_. - -If you want to use this formula, please pay attention to the ``FORMULA`` file and/or ``git tag``, -which contains the currently released version. This formula is versioned according to `Semantic Versioning `_. - -See `Formula Versioning Section `_ for more details. +`_. If you are interested in writing or contributing to formulas, please pay attention to the `Writing Formula Section +`_. If you want to use this formula, please pay attention to the ``FORMULA`` file and/or ``git tag``, which contains the currently released version. This formula is versioned according to `Semantic Versioning `_. See `Formula Versioning Section `_ for more details. Contributing to this repo ------------------------- **Commit message formatting is significant!!** -Please see `How to contribute `_ for more details. +Please see :ref:`How to contribute ` for more details. -Available states ----------------- +Available Meta states +---------------------- .. contents:: - :local: + :local: ``docker`` ^^^^^^^^^^ -Install and run Docker daemon +*Meta-state (This is a state that includes other states)*. -.. note:: +This state installs the Docker solution (see https://docs.docker.io) - On Ubuntu 12.04 state will also update kernel if needed - (as mentioned in `docker installation docs `_). - You should manually reboot minions for kernel update to take affect. - - You can override the default docker daemon options by setting each line in the *"docker-pkg:lookup:config"* pillar. This effectively writes the config in */etc/default/docker*. See *pillar.example* +``docker.clean`` +^^^^^^^^^^^^^^^^ +*Meta-state (This is a state that includes other states)*. -``docker.containers`` -^^^^^^^^^^^^^^^^^^^^^ +Stop Docker daemon and remove docker packages ('docker', 'docker-engine', 'docker-ce', etc) on Linux. To protect OS integrity, this state won't remove packages listed as dependencies (i.e. python is kept). -Pulls and runs a number of docker containers with arbitrary *run* options all configurable via pillars. -Salt includes *dockerio* and *dockerng* states, but both depend on *docker-py* library, which not always implements the latest *docker run* options. This gives the user more control over the docker run options, but it doesn't try to implement all the other docker commands, such as build, ps, inspect, etc. It just pulls an image and runs it. - -To use it, just include *docker.containers* in your *top.sls*, and configure it using pillars: - -:: - - docker-containers: - lookup: - mycontainer: - image: "my_image" - cmd: - runoptions: - - "-e MY_ENV=warn" - - "--log-driver=syslog" - - "-p 2345:2345" - - "--rm" - myapp: - image: "myregistry.com:5000/training/app:3.0" - args: - - "https://someargument_as_an_url" - - "--port 5500" - cmd: python app.py - runoptions: - - "--log-driver=syslog" - - "-v /mnt/myapp:/myapp" - - "-p 80:80" - - "--rm" - stopoptions: - - -t 60 - - -In the example pillar above: - -- *mycontainer* and *myapp* are the container names (ie *--name* option). -- Upstart files are created for each container, so ``service stop|start|status`` should just work -- ``service stop`` will wipeout the container completely (ie ``docker stop + docker rm ``) -``docker.clean`` -^^^^^^^^^^^^^^^^ +``docker.software.package.repo`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Stop Docker daemon and remove docker packages ('docker', 'docker-engine', 'docker-ce', etc) on Linux. To protect OS integrity, this state won't remove packages listed as dependencies (i.e. python is kept). +Configures the upstream Docker's repo on RedHat/Debian OS. -``docker.repo`` -^^^^^^^^^^^^^^^ +``docker.software.package.repo.clean`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Configures the upstream docker's repo (true, by default). +This state removes upstream Docker package repository only, on RedHat/Debian OS. -``docker.macosapp`` +``docker.software`` ^^^^^^^^^^^^^^^^^^^ -Installs Docker Desktop for Mac. +This state installs Docker (see https://docs.docker.com/engine/install and https://docs.docker.com/desktop/) + +``docker.software.service`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This state installs Dockerd daemon on Linux (systemd support). + +``docker.software.service`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This state stops Dockerd daemon on Linux (systemd support). + +``docker.software.config`` +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This state overrides default Docker options (i.e. /etc/default/docker):: -``docker.macosapp.clean`` + docker: + pkg: + docker: + config: + - DOCKER_OPTS="-s btrfs --dns 8.8.8.8" + - export http_proxy="http://172.17.42.1:3128" + + +``docker.software.config.clean`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This state uninstalls Docker overrides (i.e. /etc/default/docker). + +``docker.software.clean`` ^^^^^^^^^^^^^^^^^^^^^^^^^ -Removes Docker Desktop from Mac. +This state uninstalls Docker software. + +``docker.containers`` +^^^^^^^^^^^^^^^^^^^^^ + +Pulls and runs a number of docker containers. See docker container API for docker.containers options:: + + docker: + containers: + running: + - prometheus_simple + - prometheus_detail + + prometheus_simple: + image: "prom/prometheus:v1.7.1" + + prometheus_detail: + image: "prom/prometheus:v1.7.1" + # see https://docker-py.readthedocs.io/en/stable/containers.html + ``docker.compose`` ^^^^^^^^^^^^^^^^^^ -Installs `Docker Compose `_ -(previously ``fig``) to define groups of containers and their relationships -with one another. Use `docker.compose-ng` to run `docker-compose`. +Saltstack `dockercompose module` state support (See https://docs.saltstack.com/en/2018.3/ref/modules/all/salt.modules.dockercompose.html). -``docker.compose-ng`` +``docker.compose.ng`` ^^^^^^^^^^^^^^^^^^^^^ The intent is to provide an interface similar to the `specification `_ @@ -143,48 +158,61 @@ whenever it is reasonable for the sake of simplicity. It is worth noting that we have added one attribute which is decidedly absent from the docker-compose specification. That attribute is ``dvc``. This is a boolean attribute which allows us to define data only volume containers -which can not be represented with the ``docker.running`` state interface +which can not be represented with the ``docker.software.service.running`` state since they are not intended to include a long living service inside the container. See the included ``pillar.example`` for a representative pillar data block. - To use this formula, you might target a host with the following pillar: .. code:: yaml docker: compose: - registry-data: - dvc: True - image: ®istry_image 'library/registry:0.9.1' - container_name: &dvc 'registry-999-99-data' - command: echo *dvc data volume container - volumes: - - &datapath '/registry' - registry-service: - image: *registry_image - container_name: 'registry-999-99-service' - restart: 'always' - volumes_from: - - *dvc - environment: - SETTINGS_FLAVOR: 'local' - STORAGE_PATH: *datapath - SEARCH_BACKEND: 'sqlalchemy' - nginx: - image: 'library/nginx:1.9.0' - container_name: 'nginx-999-99' - restart: 'always' - links: - - 'registry-999-99-service:registry' - working_dir: '/var/www/html' - volume_driver: 'foobar' - userns_mode: 'host' - user: 'nginx' - ports: - - '80:80' - - '443:443' + ng: + registry-datastore: + dvc: true + # image: ®istry_image 'docker.io/registry:latest' ## Fedora + image: ®istry_image 'registry:latest' + container_name: &dvc 'registry-datastore' + command: echo *dvc data volume container + volumes: + - &datapath '/registry' + registry-service: + image: *registry_image + container_name: 'registry-service' + volumes_from: + - *dvc + environment: + SETTINGS_FLAVOR: 'local' + STORAGE_PATH: *datapath + SEARCH_BACKEND: 'sqlalchemy' + REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: '/registry' + ports: + - 127.0.0.1:5000:5000 + # restart: 'always' # compose v1.9 + deploy: # compose v3 + restart_policy: + condition: on-failure + delay: 5s + max_attempts: 3 + window: 120s + nginx-latest: + # image: 'docker.io/nginx:latest' ##Fedora + image: 'nginx:latest' + container_name: 'nginx-latest' + links: + - 'registry-service:registry' + ports: + - '80:80' + - '443:443' + volumes: + - /srv/docker-registry/nginx/:/etc/nginx/conf.d + - /srv/docker-registry/auth/:/etc/nginx/conf.d/auth + - /srv/docker-registry/certs/:/etc/nginx/conf.d/certs + working_dir: '/var/www/html' + volume_driver: 'foobar' + userns_mode: 'host' Then you would target a host with the following states: @@ -192,57 +220,23 @@ Then you would target a host with the following states: include: - base: docker - - base: docker.compose-ng - - -``docker.registry (DEPRECATED)`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -NEW: - -Since the more generic *docker-container* above has been implemented, the *docker-registry* state can now be deprecated. The registry is just another docker image, we can use *docker-container* with a pillar similar to this: - -:: - - docker-containers: - lookup: - registry: - image: "registry:2" - cmd: - runoptions: - - "-e REGISTRY_STORAGE=s3" - - "-e REGISTRY_STORAGE_S3_REGION=us-west-1" - - "-e REGISTRY_STORAGE_S3_BUCKET=my-bucket" - - "-e REGISTRY_STORAGE_S3_ROOTDIRECTORY=my_registry/folder" - - "--log-driver=syslog" - - "-p 5000:5000" - - "--rm" - ------ - -OLD: + - base: docker.compose.ng -IMPORTANT: docker.registry will eventually be removed. - -Run a Docker container to start the registry service. - -If *"registry:lookup:version"* pillar is either the string "latest" or not specified at all, it defaults to the "latest" image tag, which at the time of this writing is still pointing to 0.9.1, even though 2.x is out for a while. It still uses the old registry pillar configuration for backwards compatibility. See the commented out block in *pillar.example* - -If *"registry:lookup:version"* is set to any other version, e.g. *2*, an image with that tag will be downloaded and the new pillar configuation should be used. See *pillar.example*. +``docker.swarm`` +^^^^^^^^^^^^^^^^ -In this case, extra *docker run* options can be provided in your *"registry:lookup:runoptions"* pillar to provide environment variables, volumes, or log configuration to the container. +Saltstack `swarm module` state support (See https://docs.saltstack.com/en/latest/ref/modules/all/salt.modules.swarm.html). -By default, the storage backend used by the registry is "filesystem". Use environment variables to override that, for example to use S3 as backend storage. +``docker.swarm.clean`` +^^^^^^^^^^^^^^^^^^^^^^ -``docker.remove`` -^^^^^^^^^^^^^^^^^ +Opposite of `docker.swarm` state (See https://docs.saltstack.com/en/latest/ref/modules/all/salt.modules.swarm.html). -Stop Docker daemon. Remove older docker packages (usually called 'docker' and 'docker-engine'). -Development ------------ +Sub-states +---------- -Note that some of the internal states such as `docker.running` are references to the internal `dockerio states `_ +Sub-states are available inside sub-directories. Testing @@ -266,26 +260,27 @@ Where ``[platform]`` is the platform name defined in ``kitchen.yml``, e.g. ``debian-9-2019-2-py3``. ``bin/kitchen converge`` -^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^ -Creates the docker instance and runs the ``template`` main state, ready for testing. +Creates the Docker instance and runs the ``docker`` main state, ready for testing. ``bin/kitchen verify`` -^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^ Runs the ``inspec`` tests on the actual instance. ``bin/kitchen destroy`` -^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^ -Removes the docker instance. +Removes the Docker instance. ``bin/kitchen test`` -^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^ Runs all of the stages above in one go: i.e. ``destroy`` + ``converge`` + ``verify`` + ``destroy``. ``bin/kitchen login`` -^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^ Gives you SSH access to the instance for manual testing. + diff --git a/docs/TOFS_pattern.rst b/docs/TOFS_pattern.rst new file mode 100644 index 00000000..4fea5dda --- /dev/null +++ b/docs/TOFS_pattern.rst @@ -0,0 +1,518 @@ +.. _tofs_pattern: + +TOFS: A pattern for using SaltStack +=================================== + +.. list-table:: + :name: tofs-authors + :header-rows: 1 + :stub-columns: 1 + :widths: 2,2,3,2 + + * - + - Person + - Contact + - Date + * - Authored by + - Roberto Moreda + - moreda@allenta.com + - 29/12/2014 + * - Modified by + - Daniel Dehennin + - daniel.dehennin@baby-gnu.org + - 07/02/2019 + * - Modified by + - Imran Iqbal + - https://github.com/myii + - 23/02/2019 + +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. + +.. contents:: **Table of Contents** + +Usage of values in pillar vs templates in ``file_roots`` +-------------------------------------------------------- + +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. + +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). + +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. + +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. + +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. + +On the reusability of SaltStack state files +------------------------------------------- + +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 `_. + +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. + +In the next section, I am going to describe my proposal to extend further the reusability of formulas, suggesting some patterns of usage. + +The Template Override and Files Switch (TOFS) pattern +----------------------------------------------------- + +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. + +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. + +Example: NTP before applying TOFS +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Let's work with the NTP example. A basic formula that follows the `design guidelines `_ has the following files and directories tree: + +.. code-block:: + + /srv/saltstack/salt-formulas/ntp-saltstack-formula/ + ntp/ + map.jinja + init.sls + conf.sls + files/ + default/ + etc/ + ntp.conf.jinja + +In order to use it, let's assume a `masterless configuration `_ and this relevant section of ``/etc/salt/minion``: + +.. code-block:: yaml + + pillar_roots: + base: + - /srv/saltstack/pillar + file_client: local + file_roots: + base: + - /srv/saltstack/salt + - /srv/saltstack/salt-formulas/ntp-saltstack-formula + +.. code-block:: jinja + + {#- /srv/saltstack/salt-formulas/ntp-saltstack-formula/ntp/map.jinja #} + {%- set ntp = salt['grains.filter_by']({ + 'default': { + 'pkg': 'ntp', + 'service': 'ntp', + 'config': '/etc/ntp.conf', + }, + }, merge=salt['pillar.get']('ntp:lookup')) %} + +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. + +.. code-block:: sls + + ## /srv/saltstack/salt-formulas/ntp-saltstack-formula/ntp/init.sls + {%- from 'ntp/map.jinja' import ntp with context %} + + Install NTP: + pkg.installed: + - name: {{ ntp.pkg }} + + Enable and start NTP: + service.running: + - name: {{ ntp.service }} + - enabled: True + - require: + - pkg: Install NTP package + +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. + +.. code-block:: sls + + ## /srv/saltstack/salt-formulas/ntp-saltstack-formula/ntp/conf.sls + include: + - ntp + + {%- from 'ntp/map.jinja' import ntp with context %} + + Configure NTP: + file.managed: + - name: {{ ntp.config }} + - template: jinja + - source: salt://ntp/files/default/etc/ntp.conf.jinja + - watch_in: + - service: Enable and start NTP service + - require: + - pkg: Install NTP package + +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. + +.. code-block:: jinja + + {#- /srv/saltstack/salt-formulas/ntp-saltstack-formula/ntp/files/default/etc/ntp.conf.jinja #} + {#- Managed by saltstack #} + {#- Edit pillars or override this template in saltstack if you need customization #} + {%- set settings = salt['pillar.get']('ntp', {}) %} + {%- set default_servers = ['0.ubuntu.pool.ntp.org', + '1.ubuntu.pool.ntp.org', + '2.ubuntu.pool.ntp.org', + '3.ubuntu.pool.ntp.org'] %} + + driftfile /var/lib/ntp/ntp.drift + statistics loopstats peerstats clockstats + filegen loopstats file loopstats type day enable + filegen peerstats file peerstats type day enable + filegen clockstats file clockstats type day enable + + {%- for server in settings.get('servers', default_servers) %} + server {{ server }} + {%- endfor %} + + restrict -4 default kod notrap nomodify nopeer noquery + restrict -6 default kod notrap nomodify nopeer noquery + + restrict 127.0.0.1 + restrict ::1 + +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. + +Alternatively, you can define a highstate in ``/srv/saltstack/salt/top.sls`` and run ``salt-call state.highstate``. + +.. code-block:: sls + + ## /srv/saltstack/salt/top.sls + base: + '*': + - ntp.conf + +**Customizing the formula just with pillar data**, we have the option to define the NTP servers. + +.. code-block:: sls + + ## /srv/saltstack/pillar/top.sls + base: + '*': + - ntp + +.. code-block:: sls + + ## /srv/saltstack/pillar/ntp.sls + ntp: + servers: + - 0.ch.pool.ntp.org + - 1.ch.pool.ntp.org + - 2.ch.pool.ntp.org + - 3.ch.pool.ntp.org + +Template Override +^^^^^^^^^^^^^^^^^ + +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`` + +.. code-block:: jinja + + {#- /srv/saltstack/salt/ntp/files/default/etc/ntp.conf.jinja #} + {#- Managed by saltstack #} + {#- Edit pillars or override this template in saltstack if you need customization #} + + {#- Some bizarre configurations here #} + {#- ... #} + + {%- for server in settings.get('servers', default_servers) %} + server {{ server }} + {%- endfor %} + +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. + +Files Switch +^^^^^^^^^^^^ + +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``. + +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/``. + +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. + +.. code-block:: + + /srv/saltstack/salt-formulas/ntp-saltstack-formula/ntp/files/ + default/ + etc/ + ntp.conf.jinja + RedHat/ + etc/ + ntp.conf.jinja + Debian/ + etc/ + ntp.conf.jinja + +To make this work we need a ``conf.sls`` state file that takes a list of possible files as the configuration template. + +.. code-block:: sls + + ## /srv/saltstack/salt-formulas/ntp-saltstack-formula/ntp/conf.sls + include: + - ntp + + {%- from 'ntp/map.jinja' import ntp with context %} + + Configure NTP: + file.managed: + - name: {{ ntp.config }} + - template: jinja + - source: + - salt://ntp/files/{{ grains.get('os_family', 'default') }}/etc/ntp.conf.jinja + - salt://ntp/files/default/etc/ntp.conf.jinja + - watch_in: + - service: Enable and start NTP service + - require: + - pkg: Install NTP package + +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``. + +.. code-block:: jinja + + {#- /srv/saltstack/salt/ntp/files/node01/etc/ntp.conf.jinja #} + {#- Managed by saltstack #} + {#- Edit pillars or override this template in saltstack if you need customization #} + + {#- Some crazy configurations here for node01 #} + {#- ... #} + +To make this work we could write a specially crafted ``conf.sls``. + +.. code-block:: sls + + ## /srv/saltstack/salt-formulas/ntp-saltstack-formula/ntp/conf.sls + include: + - ntp + + {%- from 'ntp/map.jinja' import ntp with context %} + + Configure NTP: + file.managed: + - name: {{ ntp.config }} + - template: jinja + - source: + - salt://ntp/files/{{ grains.get('id') }}/etc/ntp.conf.jinja + - salt://ntp/files/{{ grains.get('os_family') }}/etc/ntp.conf.jinja + - salt://ntp/files/default/etc/ntp.conf.jinja + - watch_in: + - service: Enable and start NTP service + - require: + - pkg: Install NTP package + +Using the ``files_switch`` macro +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +We can simplify the ``conf.sls`` with the new ``files_switch`` macro to use in the ``source`` parameter for the ``file.managed`` state. + +.. code-block:: sls + + ## /srv/saltstack/salt-formulas/ntp-saltstack-formula/ntp/conf.sls + include: + - ntp + + {%- set tplroot = tpldir.split('/')[0] %} + {%- from 'ntp/map.jinja' import ntp with context %} + {%- from 'ntp/libtofs.jinja' import files_switch %} + + Configure NTP: + file.managed: + - name: {{ ntp.config }} + - template: jinja + - source: {{ files_switch(['/etc/ntp.conf.jinja'], + lookup='Configure NTP' + ) + }} + - watch_in: + - service: Enable and start NTP service + - require: + - pkg: Install NTP package + + +* This uses ``config.get``, searching for ``ntp:tofs:source_files:Configure NTP`` to determine the list of template files to use. +* If this returns a result, the default of ``['/etc/ntp.conf.jinja']`` will be appended to it. +* If this does not yield any results, the default of ``['/etc/ntp.conf.jinja']`` will be used. + +In ``libtofs.jinja``, we define this new macro ``files_switch``. + +.. literalinclude:: ../template/libtofs.jinja + :caption: /srv/saltstack/salt-formulas/ntp-saltstack-formula/ntp/libtofs.jinja + :language: jinja + +How to customise the ``source`` further +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The examples below are based on an ``Ubuntu`` minion called ``theminion`` being configured via. pillar. + +Using the default settings of the ``files_switch`` macro above, +the ``source`` will be: + +.. code-block:: sls + + - source: + - salt://ntp/files/theminion/etc/ntp.conf.jinja + - salt://ntp/files/Debian/etc/ntp.conf.jinja + - salt://ntp/files/default/etc/ntp.conf.jinja + +Customise ``files`` +~~~~~~~~~~~~~~~~~~~ + +The ``files`` portion can be customised: + +.. code-block:: sls + + ntp: + tofs: + dirs: + files: files_alt + +Resulting in: + +.. code-block:: sls + + - source: + - salt://ntp/files_alt/theminion/etc/ntp.conf.jinja + - salt://ntp/files_alt/Debian/etc/ntp.conf.jinja + - salt://ntp/files_alt/default/etc/ntp.conf.jinja + +Customise the use of grains +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Grains can be customised and even arbitrary paths can be supplied: + +.. code-block:: sls + + ntp: + tofs: + files_switch: + - any/path/can/be/used/here + - id + - os + - os_family + +Resulting in: + +.. code-block:: sls + + - source: + - salt://ntp/files/any/path/can/be/used/here/etc/ntp.conf.jinja + - salt://ntp/files/theminion/etc/ntp.conf.jinja + - salt://ntp/files/Ubuntu/etc/ntp.conf.jinja + - salt://ntp/files/Debian/etc/ntp.conf.jinja + - salt://ntp/files/default/etc/ntp.conf.jinja + +Customise the ``default`` path +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``default`` portion of the path can be customised: + +.. code-block:: sls + + ntp: + tofs: + dirs: + default: default_alt + +Resulting in: + +.. code-block:: sls + + - source: + ... + - salt://ntp/files/default_alt/etc/ntp.conf.jinja + +Customise the list of ``source_files`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The list of ``source_files`` can be given: + +.. code-block:: sls + + ntp: + tofs: + source_files: + Configure NTP: + - '/etc/ntp.conf_alt.jinja' + +Resulting in: + +.. code-block:: sls + + - source: + - salt://ntp/files/theminion/etc/ntp.conf_alt.jinja + - salt://ntp/files/theminion/etc/ntp.conf.jinja + - salt://ntp/files/Debian/etc/ntp.conf_alt.jinja + - salt://ntp/files/Debian/etc/ntp.conf.jinja + - salt://ntp/files/default/etc/ntp.conf_alt.jinja + - salt://ntp/files/default/etc/ntp.conf.jinja + +Note: This does *not* override the default value. +Rather, the value from the pillar/config is prepended to the default. + +Using sub-directories for ``components`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If your formula is composed of several components, you may prefer to provides files under sub-directories, like in the `systemd-formula `_. + +.. code-block:: + + /srv/saltstack/systemd-formula/ + systemd/ + init.sls + libtofs.jinja + map.jinja + networkd/ + init.sls + files/ + default/ + network/ + 99-default.link + resolved/ + init.sls + files/ + default/ + resolved.conf + timesyncd/ + init.sls + files/ + Arch/ + resolved.conf + Debian/ + resolved.conf + default/ + resolved.conf + Ubuntu/ + resolved.conf + +For example, the following ``formula.component.config`` SLS: + +.. code-block:: sls + + {%- from "formula/libtofs.jinja" import files_switch with context %} + + formula configuration file: + file.managed: + - name: /etc/formula.conf + - user: root + - group: root + - mode: 644 + - template: jinja + - source: {{ files_switch(['formula.conf'], + lookup='formula', + use_subpath=True + ) + }} + +will be rendered on a ``Debian`` minion named ``salt-formula.ci.local`` as: + +.. code-block:: sls + + formula configuration file: + file.managed: + - name: /etc/formula.conf + - user: root + - group: root + - mode: 644 + - template: jinja + - source: + - salt://formula/component/files/salt-formula.ci.local/formula.conf + - salt://formula/component/files/Debian/formula.conf + - salt://formula/component/files/default/formula.conf + - salt://formula/files/salt-formula.ci.local/formula.conf + - salt://formula/files/Debian/formula.conf + - salt://formula/files/default/formula.conf diff --git a/docs/_static/css/custom.css b/docs/_static/css/custom.css new file mode 100644 index 00000000..4617efcd --- /dev/null +++ b/docs/_static/css/custom.css @@ -0,0 +1,21 @@ +/* + Override styles for in-use Sphinx theme +*/ + +/* The next two `.wy`-based rules are specifically needed for the dealing with */ +/* the `sphinx_rtd_theme` bug where long lines do not wrap in tables */ + +/* override table width restrictions */ +.wy-table-responsive table th +, .wy-table-responsive table td +{ + /* !important prevents the common CSS stylesheets from + overriding this as on RTD they are loaded after this stylesheet */ + white-space: normal !important; +} + +.wy-table-responsive +{ + overflow: visible !important; +} + diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 00000000..afc8bd3d --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,173 @@ +# -*- coding: utf-8 -*- +"""Configuration file for the Sphinx documentation builder. + +This file does only contain a selection of the most common options. For a +full list see the documentation: + +* http://www.sphinx-doc.org/en/stable/config + +""" + +from __future__ import division, print_function, unicode_literals + +# from datetime import datetime + +from recommonmark.parser import CommonMarkParser + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +__author__ = 'Imran Iqbal' # noqa: E221 +__copyright__ = 'Copyright (C) 2019, MYII' # noqa: E221 +__license__ = 'Apache-2.0' # noqa: E221 +__version__ = 'latest' # noqa: E221 +__maintainer__ = 'Imran Iqbal' # noqa: E221 + + +# -- Project information ----------------------------------------------------- + +project = 'template-formula' +copyright = __copyright__.replace('Copyright (C) ', '') # noqa: A001 +author = __author__ +version = __version__ +release = __version__ + + +# -- General configuration --------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['templates', '_templates', '.templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +source_suffix = ['.rst', '.md'] + +# The master toctree document. +master_doc = 'index' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path . +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + + +# -- Options for the reStructuredText parser --------------------------------- + +file_insertion_enabled = False + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'sphinx_rtd_theme' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# +# html_sidebars = {} + + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = 'template-formula' + + +# -- Options for Markdown output --------------------------------------------- + +source_parsers = { + '.md': CommonMarkParser, +} + + +# -- Options for LaTeX output ------------------------------------------------ + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ( + 'index', + 'template-formula.tex', + u'template-formula Documentation', + u'', + 'manual', + ), +] + + +# -- Functions: `setup`, docstring preprocessing, etc. ----------------------- + +def setup(app): + """Prepare the Sphinx application object. + + Used for providing a custom CSS file for override styles. + + Parameters + ---------- + app : object + The Sphinx application object. + + Returns + ------- + app : object + The Sphinx application object. + + """ + app.add_stylesheet('css/custom.css') + return app diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 00000000..a49c0c3f --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,20 @@ +.. _index: + +.. ``template-formula`` documentation master file. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to template-formula's documentation! +============================================ + +.. toctree:: + :maxdepth: 2 + :caption: Contents + :numbered: + :glob: + + README + CONTRIBUTING + TOFS_pattern + AUTHORS + CHANGELOG diff --git a/kitchen.yml b/kitchen.yml index 11d0c2fa..eb08b516 100644 --- a/kitchen.yml +++ b/kitchen.yml @@ -14,80 +14,204 @@ platforms: ## SALT `master` - name: debian-10-master-py3 driver: - image: saltimages/salt-master-py3:debian-10 + image: netmanagers/salt-master-py3:debian-10 + provision_command: + - apt-get -qq -y install conntrack - name: ubuntu-1804-master-py3 driver: - image: saltimages/salt-master-py3:ubuntu-18.04 + image: netmanagers/salt-master-py3:ubuntu-18.04 + provision_command: + - apt-get -qq -y install conntrack - name: centos-8-master-py3 driver: - image: saltimages/salt-master-py3:centos-8 + image: netmanagers/salt-master-py3:centos-8 + provision_command: + - yum install conntrack-tools -y - name: fedora-31-master-py3 driver: - image: saltimages/salt-master-py3:fedora-31 + image: netmanagers/salt-master-py3:fedora-31 + provision_command: + - dnf install conntrack-tools -y - name: opensuse-leap-151-master-py3 driver: image: netmanagers/salt-master-py3:opensuse-leap-15.1 run_command: /usr/lib/systemd/systemd + provision_command: + - zypper --non-interactive install conntrack-tools # Workaround to avoid intermittent failures on `opensuse-leap-15.1`: # => SCP did not finish successfully (255): (Net::SCP::Error) transport: max_ssh_sessions: 1 - name: amazonlinux-2-master-py3 driver: - image: saltimages/salt-master-py3:amazonlinux-2 + image: netmanagers/salt-master-py3:amazonlinux-2 + provision_command: + - yum install conntrack-tools -y + - name: arch-base-latest-master-py2 + driver: + image: netmanagers/salt-master-py2:arch-base-latest + run_command: /usr/lib/systemd/systemd + provision_command: + - (test -x /usr/bin/pacman-mirrors && /usr/bin/pacman-mirrors -g) || true + - pacman -S --noconfirm conntrack-tools + + ## SALT `3000.1` + - name: debian-10-3000-1-py3 + driver: + image: netmanagers/salt-3000.1-py3:debian-10 + provision_command: + - apt-get -qq -y install conntrack + - name: ubuntu-1804-3000-1-py3 + driver: + image: netmanagers/salt-3000.1-py3:ubuntu-18.04 + provision_command: + - apt-get -qq -y install conntrack + - name: centos-8-3000-1-py3 + driver: + image: netmanagers/salt-3000.1-py3:centos-8 + provision_command: + - yum install conntrack-tools -y + - name: fedora-31-3000-1-py3 + driver: + image: netmanagers/salt-3000.1-py3:fedora-31 + provision_command: + - dnf install conntrack-tools -y + - name: opensuse-leap-151-3000-1-py3 + driver: + image: netmanagers/salt-3000.1-py3:opensuse-leap-15.1 + run_command: /usr/lib/systemd/systemd + provision_command: + - zypper --non-interactive install conntrack-tools + # Workaround to avoid intermittent failures on `opensuse-leap-15.1`: + # => SCP did not finish successfully (255): (Net::SCP::Error) + transport: + max_ssh_sessions: 1 + - name: amazonlinux-2-3000-1-py3 + driver: + image: netmanagers/salt-3000.1-py3:amazonlinux-2 + provision_command: + - yum install conntrack-tools -y + - name: arch-base-latest-3000-1-py2 + driver: + image: netmanagers/salt-3000.1-py2:arch-base-latest + run_command: /usr/lib/systemd/systemd + provision_command: + - (test -x /usr/bin/pacman-mirrors && /usr/bin/pacman-mirrors -g) || true + - pacman -S --noconfirm conntrack-tools ## SALT `2019.2` - name: debian-10-2019-2-py3 driver: - image: saltimages/salt-2019.2-py3:debian-10 + image: netmanagers/salt-2019.2-py3:debian-10 + provision_command: + - apt-get -qq -y install conntrack - name: debian-9-2019-2-py3 driver: - image: saltimages/salt-2019.2-py3:debian-9 + image: netmanagers/salt-2019.2-py3:debian-9 + provision_command: + - apt-get -qq -y install conntrack - name: ubuntu-1804-2019-2-py3 driver: - image: saltimages/salt-2019.2-py3:ubuntu-18.04 + image: netmanagers/salt-2019.2-py3:ubuntu-18.04 + provision_command: + - apt-get -qq -y install conntrack + - name: ubuntu-1604-2019-2-py3 + driver: + image: netmanagers/salt-2019.2-py3:ubuntu-16.04 + provision_command: + - apt-get -qq -y install conntrack - name: centos-8-2019-2-py3 driver: - image: saltimages/salt-2019.2-py3:centos-8 + image: netmanagers/salt-2019.2-py3:centos-8 + provision_command: + - yum install conntrack-tools -y + - name: centos-7-2019-2-py3 + driver: + image: netmanagers/salt-2019.2-py3:centos-7 + provision_command: + - yum install conntrack-tools -y - name: fedora-31-2019-2-py3 driver: - image: saltimages/salt-2019.2-py3:fedora-31 + image: netmanagers/salt-2019.2-py3:fedora-31 + provision_command: + - yum install conntrack-tools -y - name: opensuse-leap-151-2019-2-py3 driver: image: netmanagers/salt-2019.2-py3:opensuse-leap-15.1 run_command: /usr/lib/systemd/systemd + provision_command: + - zypper --non-interactive install conntrack-tools # Workaround to avoid intermittent failures on `opensuse-leap-15.1`: # => SCP did not finish successfully (255): (Net::SCP::Error) transport: max_ssh_sessions: 1 - - name: centos-7-2019-2-py2 - driver: - image: netmanagers/salt-2019.2-py2:centos-7 - name: amazonlinux-2-2019-2-py3 driver: - image: saltimages/salt-2019.2-py3:amazonlinux-2 + image: netmanagers/salt-2019.2-py3:amazonlinux-2 + provision_command: + - yum install conntrack-tools -y + - name: ubuntu-1804-2019-2-py2 + driver: + image: netmanagers/salt-2019.2-py2:ubuntu-18.04 + provision_command: + - apt-get -qq -y install conntrack + - name: amazonlinux-1-2019-2-py2 + driver: + image: netmanagers/salt-2019.2-py2:amazonlinux-1 + run_command: /sbin/init + provision_command: + - yum install conntrack-tools -y - name: arch-base-latest-2019-2-py2 driver: - image: saltimages/salt-2019.2-py2:arch-base-latest + image: netmanagers/salt-2019.2-py2:arch-base-latest run_command: /usr/lib/systemd/systemd + provision_command: + - (test -x /usr/bin/pacman-mirrors && /usr/bin/pacman-mirrors -g) || true + - pacman -S --noconfirm conntrack-tools ## SALT `2018.3` + - name: centos-7-2018-3-py3 + driver: + image: netmanagers/salt-2018.3-py3:centos-7 + provision_command: + - yum install conntrack-tools -y - name: fedora-30-2018-3-py3 driver: image: netmanagers/salt-2018.3-py3:fedora-30 + provision_command: + - yum install conntrack-tools -y - name: debian-9-2018-3-py2 driver: image: netmanagers/salt-2018.3-py2:debian-9 + provision_command: + - apt-get -qq -y install conntrack + - name: debian-8-2018-3-py2 + driver: + image: netmanagers/salt-2018.3-py2:debian-8 + provision_command: + - apt-get -qq -y install conntrack + - name: ubuntu-1804-2018-3-py2 + driver: + image: netmanagers/salt-2018.3-py2:ubuntu-18.04 + provision_command: + - apt-get -qq -y install conntrack - name: ubuntu-1604-2018-3-py2 driver: image: netmanagers/salt-2018.3-py2:ubuntu-16.04 - - name: centos-7-2018-3-py2 + provision_command: + - apt-get -qq -y install conntrack + - name: centos-6-2018-3-py2 driver: - image: netmanagers/salt-2018.3-py2:centos-7 + image: netmanagers/salt-2018.3-py2:centos-6 + run_command: /sbin/init + provision_command: + - yum install conntrack-tools -y - name: opensuse-leap-151-2018-3-py2 driver: image: netmanagers/salt-2018.3-py2:opensuse-leap-15.1 run_command: /usr/lib/systemd/systemd + provision_command: + - zypper --non-interactive install conntrack-tools # Workaround to avoid intermittent failures on `opensuse-leap-15.1`: # => SCP did not finish successfully (255): (Net::SCP::Error) transport: @@ -96,41 +220,15 @@ platforms: driver: image: netmanagers/salt-2018.3-py2:amazonlinux-1 run_command: /sbin/init + provision_command: + - yum install conntrack-tools -y - name: arch-base-latest-2018-3-py2 driver: image: netmanagers/salt-2018.3-py2:arch-base-latest run_command: /usr/lib/systemd/systemd - - ## SALT `2017.7` - - name: debian-8-2017-7-py2 - driver: - image: netmanagers/salt-2017.7-py2:debian-8 - - name: ubuntu-1604-2017-7-py2 - driver: - image: netmanagers/salt-2017.7-py2:ubuntu-16.04 - - name: centos-6-2017-7-py2 - driver: - image: netmanagers/salt-2017.7-py2:centos-6 - run_command: /sbin/init - - name: fedora-30-2017-7-py2 - driver: - image: netmanagers/salt-2017.7-py2:fedora-30 - - name: opensuse-leap-151-2017-7-py2 - driver: - image: netmanagers/salt-2017.7-py2:opensuse-leap-15.1 - run_command: /usr/lib/systemd/systemd - # Workaround to avoid intermittent failures on `opensuse-leap-15.1`: - # => SCP did not finish successfully (255): (Net::SCP::Error) - transport: - max_ssh_sessions: 1 - - name: amazonlinux-1-2017-7-py2 - driver: - image: netmanagers/salt-2017.7-py2:amazonlinux-1 - run_command: /sbin/init - - name: arch-base-latest-2017-7-py2 - driver: - image: netmanagers/salt-2017.7-py2:arch-base-latest - run_command: /usr/lib/systemd/systemd + provision_command: + - (test -x /usr/bin/pacman-mirrors && /usr/bin/pacman-mirrors -g) || true + - pacman -S --noconfirm conntrack-tools provisioner: name: salt_solo @@ -151,20 +249,53 @@ verifier: - cli suites: - - name: default + - name: archive provisioner: state_top: base: '*': + # docker.clean - docker - - docker.containers pillars: top.sls: base: '*': - docker pillars_from_files: - docker.sls: pillar.example + docker.sls: test/salt/pillar/archive.sls + verifier: + inspec_tests: + - path: test/integration/archive + - name: package + provisioner: + state_top: + base: + '*': + # docker.clean + - docker + pillars: + top.sls: + base: + '*': + - docker + pillars_from_files: + docker.sls: test/salt/pillar/package.sls + verifier: + inspec_tests: + - path: test/integration/package + - name: clean + provisioner: + state_top: + base: + '*': + - docker.clean + pillars: + top.sls: + base: + '*': + - docker + pillars_from_files: + docker.sls: test/salt/pillar/archive.sls verifier: inspec_tests: - - path: test/integration/default + - path: test/integration/clean diff --git a/pillar.example b/pillar.example index 9e88b3fd..cebf53cf 100644 --- a/pillar.example +++ b/pillar.example @@ -3,151 +3,166 @@ --- # example docker registry container # if you want to your own docker registry, use this -docker-containers: - lookup: +docker: + wanted: + - docker + - compose + + pkg: + docker: + config: + - DOCKER_OPTS="-s btrfs --dns 8.8.8.8" + - export http_proxy="http://172.17.42.1:3128" + + networks: + - nginxnet + + containers: + running: + - nginx + - prometheus + + nginx: + image: "nginx:latest" + + prometheus: + image: "prom/prometheus:v1.7.1" + env: + - a=b + - ping=pong + - ding=dong + command: + - ls + - ls -l + auto_remove: true + blkio_weight: 1000 + cap_add: ["SYS_ADMIN", "MKNOD"] + dns: + - 8.8.8.8 + - 8.8.4.4 + dns_search: + - EXAMPLE.COM + domainname: + - EXAMPLE.COM + entrypoint: + - ls + - ls -l + - ls -last + - sleep 100 + init: false + labels: + - label1 + - label2 + - label3 + mem_limit: 1g + mem_swappiness: 50 + name: prometheus + network_disabled: false + network_mode: host # bridge or none or container:netcontainer or host + oom_kill_disable: true + oom_score_adj: 100 + pid_mode: host + pids_limit: -1 + privileged: false + publish_all_ports: true + read_only: false + stdin_open: false + tty: true + volume_driver: local - # example docker registry container (if you want your own docker registry, use this) registry: - # image: 'docker.io/registry:latest' ##Fedora image: "registry:latest" - cmd: ~ - # Pull image on service restart - # (useful if you override the same tag. example: latest) - pull_before_start: true - # Remove container on service start - remove_before_start: false - # Do not force container removal on stop (unless true) - remove_on_stop: false - runoptions: - - "-e REGISTRY_LOG_LEVEL=warn" - - "-e REGISTRY_STORAGE=s3" - - "-e REGISTRY_STORAGE_S3_REGION=us-west-1" - - "-e REGISTRY_STORAGE_S3_BUCKET=my-bucket" - - "-e REGISTRY_STORAGE_S3_ROOTDIRECTORY=/registry" + env: + - REGISTRY_LOG_LEVEL=warn + - REGISTRY_STORAGE=s3 + - REGISTRY_STORAGE_S3_REGION=us-west-1 + - REGISTRY_STORAGE_S3_BUCKET=my-bucket + - REGISTRY_STORAGE_S3_ROOTDIRECTORY=/registry + networks: + - nginxnet + command: - "--log-driver=syslog" - "-p 5000:5000" - "--rm" - stopoptions: - - '-t 10' - - prometheus-server: - # example Prometheus container using command arguments - image: "prom/prometheus:v1.7.1" - cmd: ~ - args: - - '-config.file=/prom-data/prometheus.yml' - - '-storage.local.path=/prom-data/data/' - # Pull image on service restart - # (useful if you override the same tag. example: latest) - pull_before_start: true - # Remove container on service start - remove_before_start: false - # Do not force container removal on stop (unless true) - remove_on_stop: false - runoptions: - - '--net="host"' - - '-v /mnt/prom-data:/prom-data' - stopoptions: - - '-t 10' -# Docker service -docker-pkg: - lookup: - process_signature: /usr/bin/docker - -# Docker compose supported attributes -docker: - # install_pypi_pip: true - # install_docker_py: true - # version of docker-compose to install (defaults to latest) - # compose_version: 1.9.0 - # configfile: /etc/default/docker - install_pypi_pip: true - - # yamllint disable-line rule:line-length - ### https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-configuration-file - # daemon_config: - # metrics-addr: '0.0.0.0:9323' - # experimental: true - # registry-mirrors: - # - 'https://proxy-docker.local:5000' - # live-restore: true - # insecure-registries: - # - harbor.local - - pkg: - # Package handling - # version: 1.13.1 - # allow_updates: true - use_upstream_app: false # docker desktop for mac - app: - source: https://download.docker.com/mac/stable/Docker.dmg - source_hash: f69bd8f9d0863497819b998d27da4825b65884519f3f6a0e2ce1d4c5cdd26f5e + compose: + ## salt dockercompose module ## + applications: + - composetest + composetest: + path: /srv/salt/docker/files/composetest/docker-compose.yml - # config for sysvinit/upstart (for systemd, use drop-ins in your own states) - config: - - DOCKER_OPTS="-s btrfs --dns 8.8.8.8" - - export http_proxy="http://172.17.42.1:3128" + ## formerly compose-ng state ## + ng: + registry-datastore: + dvc: true + # image: ®istry_image 'docker.io/registry:latest' ## Fedora + image: ®istry_image 'registry:latest' + container_name: &dvc 'registry-datastore' + command: echo *dvc data volume container + volumes: + - &datapath '/registry' + registry-service: + image: *registry_image + container_name: 'registry-service' + volumes_from: + - *dvc + environment: + SETTINGS_FLAVOR: 'local' + STORAGE_PATH: *datapath + SEARCH_BACKEND: 'sqlalchemy' + REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: '/registry' + ports: + - 127.0.0.1:5000:5000 + # restart: 'always' # compose v1.9 + deploy: # compose v3 + restart_policy: + condition: on-failure + delay: 5s + max_attempts: 3 + window: 120s + nginx-latest: + # image: 'docker.io/nginx:latest' ##Fedora + image: 'nginx:latest' + container_name: 'nginx-latest' + networks: + - nginxnet + ports: + - '80:80' + - '443:443' + volumes: + - /srv/docker-registry/nginx/:/etc/nginx/conf.d + - /srv/docker-registry/auth/:/etc/nginx/conf.d/auth + - /srv/docker-registry/certs/:/etc/nginx/conf.d/certs + working_dir: '/var/www/html' + volume_driver: 'foobar' + userns_mode: 'host' + user: 'nginx' + # restart: 'always' # compose v1.9 + deploy: # compose v3 + restart_policy: + condition: on-failure + delay: 5s + max_attempts: 3 + window: 120s - # PIP proxy configuration (defaults to false) - # proxy: proxy.com:3128 + swarm: + # Per https://docs.saltstack.com/en/latest/ref/modules/all/salt.modules.swarm.html + joinswarm: {} + leave_swarm: false + node_ls: {} + remove_node: {} + remove_service: {} + service_create: {} + swarm_init: + advertise_addr: 127.0.0.1 + listen_addr: 0.0.0.0 + force_new_cluster: true + service_info: {} + swarm_tokens: true + update_node: {} - # Global functions for docker_container states - containers: + misc: skip_translate: ports force_present: false force_running: true - - compose: - registry-datastore: - dvc: true - # image: ®istry_image 'docker.io/registry:latest' ## Fedora - image: ®istry_image 'registry:latest' - container_name: &dvc 'registry-datastore' - command: echo *dvc data volume container - volumes: - - &datapath '/registry' - registry-service: - image: *registry_image - container_name: 'registry-service' - volumes_from: - - *dvc - environment: - SETTINGS_FLAVOR: 'local' - STORAGE_PATH: *datapath - SEARCH_BACKEND: 'sqlalchemy' - REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: '/registry' - ports: - - 127.0.0.1:5000:5000 - # restart: 'always' # compose v1.9 - deploy: # compose v3 - restart_policy: - condition: on-failure - delay: 5s - max_attempts: 3 - window: 120s - - nginx-latest: - # image: 'docker.io/nginx:latest' ##Fedora - image: 'nginx:latest' - container_name: 'nginx-latest' - links: - - 'registry-service:registry' - ports: - - '80:80' - - '443:443' - volumes: - - /srv/docker-registry/nginx/:/etc/nginx/conf.d - - /srv/docker-registry/auth/:/etc/nginx/conf.d/auth - - /srv/docker-registry/certs/:/etc/nginx/conf.d/certs - working_dir: '/var/www/html' - volume_driver: 'foobar' - userns_mode: 'host' - user: 'nginx' - # restart: 'always' # compose v1.9 - deploy: # compose v3 - restart_policy: - condition: on-failure - delay: 5s - max_attempts: 3 - window: 120s diff --git a/test/integration/default/README.md b/test/integration/archive/README.md similarity index 81% rename from test/integration/default/README.md rename to test/integration/archive/README.md index 37cf963c..ea26edea 100644 --- a/test/integration/default/README.md +++ b/test/integration/archive/README.md @@ -1,16 +1,16 @@ -# InSpec Profile: `default` +# InSpec Profile: `archive` -This shows the implementation of the `default` InSpec [profile](https://github.com/inspec/inspec/blob/master/docs/profiles.md). +This shows the implementation of the `archive` InSpec [profile](https://github.com/inspec/inspec/blob/master/docs/profiles.md). ## Verify a profile InSpec ships with built-in features to verify a profile structure. ```bash -$ inspec check default +$ inspec check archive Summary ------- -Location: default +Location: archive Profile: profile Controls: 4 Timestamp: 2019-06-24T23:09:01+00:00 @@ -28,7 +28,7 @@ Warnings To run all **supported** controls on a local machine use `inspec exec /path/to/profile`. ```bash -$ inspec exec default +$ inspec exec archive .. Finished in 0.0025 seconds (files took 0.12449 seconds to load) @@ -40,7 +40,7 @@ Finished in 0.0025 seconds (files took 0.12449 seconds to load) To run one control from the profile use `inspec exec /path/to/profile --controls name`. ```bash -$ inspec exec default --controls package +$ inspec exec archive --controls package . Finished in 0.0025 seconds (files took 0.12449 seconds to load) diff --git a/test/integration/archive/controls/archive_spec.rb b/test/integration/archive/controls/archive_spec.rb new file mode 100644 index 00000000..e457de92 --- /dev/null +++ b/test/integration/archive/controls/archive_spec.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +title 'docker archives profile' + +control 'docker archive' do + impact 1.0 + title 'should be installed' + + describe file('/usr/local/docker-19.03.9/bin') do + it { should exist } + it { should be_directory } + its('type') { should eq :directory } + end + describe file('/usr/local/docker-19.03.9/bin/docker') do + it { should exist } + its('mode') { should cmp '0755' } + end + describe file('/usr/local/docker-19.03.9/bin/runc') do + it { should exist } + its('mode') { should cmp '0755' } + end + describe file('/usr/local/docker-19.03.9/bin/docker-proxy') do + it { should exist } + its('mode') { should cmp '0755' } + end + describe file('/usr/local/docker-19.03.9/bin/containerd') do + it { should exist } + its('mode') { should cmp '0755' } + end + describe file('/usr/local/docker-19.03.9/bin/ctr') do + it { should exist } + its('mode') { should cmp '0755' } + end + describe file('/usr/local/docker-19.03.9/bin/dockerd') do + it { should exist } + its('mode') { should cmp '0755' } + end + describe file('/usr/local/docker-19.03.9/bin/containerd-shim') do + it { should exist } + its('mode') { should cmp '0755' } + end + describe file('/usr/local/bin/docker') do + it { should be_symlink } + it { should be_file } + it { should_not be_directory } + end + describe file('/usr/local/bin/runc') do + it { should be_symlink } + it { should be_file } + it { should_not be_directory } + end + describe file('/usr/local/bin/docker-proxy') do + it { should be_symlink } + it { should be_file } + it { should_not be_directory } + end + describe file('/usr/local/bin/containerd') do + it { should be_symlink } + it { should be_file } + it { should_not be_directory } + end + describe file('/usr/local/bin/ctr') do + it { should be_symlink } + it { should be_file } + it { should_not be_directory } + end + describe file('/usr/local/bin/dockerd') do + it { should be_symlink } + it { should be_file } + it { should_not be_directory } + end + describe file('/usr/local/bin/containerd-shim') do + it { should be_symlink } + it { should be_file } + it { should_not be_directory } + end + describe file('/usr/local/docker-compose-latest/bin') do + it { should exist } + it { should be_directory } + its('type') { should eq :directory } + end + describe file('/usr/local/docker-compose-latest/bin/docker-compose') do + it { should exist } + it { should be_file } + it { should_not be_directory } + its('mode') { should cmp '0755' } + its('type') { should eq :file } + end + describe file('/usr/local/bin/docker-compose') do + it { should be_symlink } + it { should be_file } + it { should_not be_directory } + end +end diff --git a/test/integration/default/controls/config.rb b/test/integration/archive/controls/config.rb similarity index 91% rename from test/integration/default/controls/config.rb rename to test/integration/archive/controls/config.rb index dfd4d22d..32b1aaba 100644 --- a/test/integration/default/controls/config.rb +++ b/test/integration/archive/controls/config.rb @@ -7,7 +7,7 @@ it { should be_file } its('owner') { should eq 'root' } its('group') { should eq 'root' } - its('mode') { should cmp '0644' } + its('mode') { should cmp '0640' } its('content') { should include 'DOCKER_OPTS="-s btrfs --dns 8.8.8.8"' } its('content') { should include 'export http_proxy="http://172.17.42.1:3128"' } end diff --git a/test/integration/archive/controls/package.rb b/test/integration/archive/controls/package.rb new file mode 100644 index 00000000..73a30205 --- /dev/null +++ b/test/integration/archive/controls/package.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +control 'Docker packages' do + title 'should be installed' +end diff --git a/test/integration/default/controls/service.rb b/test/integration/archive/controls/service.rb similarity index 72% rename from test/integration/default/controls/service.rb rename to test/integration/archive/controls/service.rb index d5a83784..09a740d5 100644 --- a/test/integration/default/controls/service.rb +++ b/test/integration/archive/controls/service.rb @@ -3,9 +3,9 @@ control 'Docker service' do title 'should be running and enabled' - describe service('docker') do + describe service('dockerd') do it { should be_installed } it { should be_enabled } - it { should be_running } + # it { should be_running } end end diff --git a/test/integration/default/inspec.yml b/test/integration/archive/inspec.yml similarity index 96% rename from test/integration/default/inspec.yml rename to test/integration/archive/inspec.yml index 477b1fcd..5fc4decd 100644 --- a/test/integration/default/inspec.yml +++ b/test/integration/archive/inspec.yml @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # vim: ft=yaml --- -name: default +name: archive title: docker formula maintainer: SaltStack Formulas license: Apache-2.0 diff --git a/test/integration/clean/README.md b/test/integration/clean/README.md new file mode 100644 index 00000000..ea26edea --- /dev/null +++ b/test/integration/clean/README.md @@ -0,0 +1,50 @@ +# InSpec Profile: `archive` + +This shows the implementation of the `archive` InSpec [profile](https://github.com/inspec/inspec/blob/master/docs/profiles.md). + +## Verify a profile + +InSpec ships with built-in features to verify a profile structure. + +```bash +$ inspec check archive +Summary +------- +Location: archive +Profile: profile +Controls: 4 +Timestamp: 2019-06-24T23:09:01+00:00 +Valid: true + +Errors +------ + +Warnings +-------- +``` + +## Execute a profile + +To run all **supported** controls on a local machine use `inspec exec /path/to/profile`. + +```bash +$ inspec exec archive +.. + +Finished in 0.0025 seconds (files took 0.12449 seconds to load) +8 examples, 0 failures +``` + +## Execute a specific control from a profile + +To run one control from the profile use `inspec exec /path/to/profile --controls name`. + +```bash +$ inspec exec archive --controls package +. + +Finished in 0.0025 seconds (files took 0.12449 seconds to load) +1 examples, 0 failures +``` + +See an [example control here](https://github.com/inspec/inspec/blob/master/examples/profile/controls/example.rb). diff --git a/test/integration/clean/controls/archive_spec.rb b/test/integration/clean/controls/archive_spec.rb new file mode 100644 index 00000000..af35139f --- /dev/null +++ b/test/integration/clean/controls/archive_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +title 'docker-compose archives profile' + +control 'docker-compose archive' do + impact 1.0 + title 'should_not be installed' + + describe file('/usr/local/docker-compose-latest/bin') do + it { should_not exist } + end + describe file('/usr/local/bin/docker-compose') do + it { should_not exist } + end +end diff --git a/test/integration/clean/controls/config.rb b/test/integration/clean/controls/config.rb new file mode 100644 index 00000000..f5559d65 --- /dev/null +++ b/test/integration/clean/controls/config.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +control 'Docker configuration' do + title 'should_not match desired lines' + + describe file('/etc/default/docker') do + it { should_not exist } + end +end diff --git a/test/integration/clean/controls/package.rb b/test/integration/clean/controls/package.rb new file mode 100644 index 00000000..e4ad1c53 --- /dev/null +++ b/test/integration/clean/controls/package.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +PLATFORMS = { + 'suse' => %w[docker], + 'redhat' => %w[docker-ce], + 'debian' => %w[python3-docker docker-ce], + 'arch' => %w[python-docker docker] +}.freeze + +control 'Docker packages' do + title 'should_not be installed' + + packages = PLATFORMS[platform[:family]] + if packages.is_a? Enumerable + packages.each do |p| + describe package(p) do + it { should_not be_installed } + end + end + end +end diff --git a/test/integration/clean/controls/service.rb b/test/integration/clean/controls/service.rb new file mode 100644 index 00000000..e2307639 --- /dev/null +++ b/test/integration/clean/controls/service.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +control 'Docker service' do + title 'should_not be running and enabled' + + describe service('dockerd') do + it { should_not be_enabled } + it { should_not be_running } + end + describe service('docker') do + it { should_not be_enabled } + it { should_not be_running } + end +end diff --git a/test/integration/clean/inspec.yml b/test/integration/clean/inspec.yml new file mode 100644 index 00000000..5fc4decd --- /dev/null +++ b/test/integration/clean/inspec.yml @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# vim: ft=yaml +--- +name: archive +title: docker formula +maintainer: SaltStack Formulas +license: Apache-2.0 +summary: Verify that the docker formula is setup and configured correctly +supports: + - platform-name: debian + - platform-name: ubuntu + - platform-name: centos + - platform-name: fedora + - platform-name: opensuse + - platform-name: suse + - platform-name: freebsd + - platform-name: amazon + - platform-name: arch diff --git a/test/integration/default/controls/package.rb b/test/integration/default/controls/package.rb deleted file mode 100644 index 974981e4..00000000 --- a/test/integration/default/controls/package.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -control 'Docker package' do - title 'should be installed' - - package_name = - case platform[:family] - when 'debian' - 'docker-ce' - # Catch remaining `linux` platforms to identify by `name` at the end - when 'linux' - case platform[:name] - when 'arch' - 'docker' - end - end - - describe package(package_name) do - it { should be_installed } - end -end diff --git a/test/integration/package/README.md b/test/integration/package/README.md new file mode 100644 index 00000000..ea26edea --- /dev/null +++ b/test/integration/package/README.md @@ -0,0 +1,50 @@ +# InSpec Profile: `archive` + +This shows the implementation of the `archive` InSpec [profile](https://github.com/inspec/inspec/blob/master/docs/profiles.md). + +## Verify a profile + +InSpec ships with built-in features to verify a profile structure. + +```bash +$ inspec check archive +Summary +------- +Location: archive +Profile: profile +Controls: 4 +Timestamp: 2019-06-24T23:09:01+00:00 +Valid: true + +Errors +------ + +Warnings +-------- +``` + +## Execute a profile + +To run all **supported** controls on a local machine use `inspec exec /path/to/profile`. + +```bash +$ inspec exec archive +.. + +Finished in 0.0025 seconds (files took 0.12449 seconds to load) +8 examples, 0 failures +``` + +## Execute a specific control from a profile + +To run one control from the profile use `inspec exec /path/to/profile --controls name`. + +```bash +$ inspec exec archive --controls package +. + +Finished in 0.0025 seconds (files took 0.12449 seconds to load) +1 examples, 0 failures +``` + +See an [example control here](https://github.com/inspec/inspec/blob/master/examples/profile/controls/example.rb). diff --git a/test/integration/package/controls/archive_spec.rb b/test/integration/package/controls/archive_spec.rb new file mode 100644 index 00000000..82fbc07c --- /dev/null +++ b/test/integration/package/controls/archive_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +title 'docker-compose archives profile' + +control 'docker-compose archive' do + impact 1.0 + title 'should be installed' + + describe file('/usr/local/docker-compose-latest/bin') do + it { should exist } + it { should be_directory } + its('type') { should eq :directory } + end + describe file('/usr/local/docker-compose-latest/bin/docker-compose') do + it { should exist } + it { should be_file } + it { should_not be_directory } + its('mode') { should cmp '0755' } + its('type') { should eq :file } + end + describe file('/usr/local/bin/docker-compose') do + it { should be_symlink } + it { should be_file } + it { should_not be_directory } + end +end diff --git a/test/integration/package/controls/config.rb b/test/integration/package/controls/config.rb new file mode 100644 index 00000000..32b1aaba --- /dev/null +++ b/test/integration/package/controls/config.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +control 'Docker configuration' do + title 'should match desired lines' + + describe file('/etc/default/docker') do + it { should be_file } + its('owner') { should eq 'root' } + its('group') { should eq 'root' } + its('mode') { should cmp '0640' } + its('content') { should include 'DOCKER_OPTS="-s btrfs --dns 8.8.8.8"' } + its('content') { should include 'export http_proxy="http://172.17.42.1:3128"' } + end +end diff --git a/test/integration/package/controls/package.rb b/test/integration/package/controls/package.rb new file mode 100644 index 00000000..8659feae --- /dev/null +++ b/test/integration/package/controls/package.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +PLATFORMS = { + 'suse' => %w[python3-pip tar gzip docker], + 'redhat' => %w[selinux-policy docker-ce], + 'debian' => %w[python3-docker gnupg-agent software-properties-common docker-ce], + 'arch' => %w[python-docker python-pip docker] +}.freeze + +control 'Docker packages' do + title 'should be installed' + + packages = PLATFORMS[platform[:family]] + if packages.is_a? Enumerable + packages.each do |p| + describe package(p) do + it { should be_installed } + end + end + end +end diff --git a/test/integration/package/controls/service.rb b/test/integration/package/controls/service.rb new file mode 100644 index 00000000..b34b5c0b --- /dev/null +++ b/test/integration/package/controls/service.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +control 'Docker service' do + title 'should be running and enabled' + + # describe service(name) do + # it { should be_enabled } + # it { should be_running } + # end +end diff --git a/test/integration/package/inspec.yml b/test/integration/package/inspec.yml new file mode 100644 index 00000000..5fc4decd --- /dev/null +++ b/test/integration/package/inspec.yml @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# vim: ft=yaml +--- +name: archive +title: docker formula +maintainer: SaltStack Formulas +license: Apache-2.0 +summary: Verify that the docker formula is setup and configured correctly +supports: + - platform-name: debian + - platform-name: ubuntu + - platform-name: centos + - platform-name: fedora + - platform-name: opensuse + - platform-name: suse + - platform-name: freebsd + - platform-name: amazon + - platform-name: arch diff --git a/test/salt/pillar/archive.sls b/test/salt/pillar/archive.sls new file mode 120000 index 00000000..86f893ee --- /dev/null +++ b/test/salt/pillar/archive.sls @@ -0,0 +1 @@ +../../../pillar.example \ No newline at end of file diff --git a/test/salt/pillar/package.sls b/test/salt/pillar/package.sls new file mode 100644 index 00000000..34c68a9f --- /dev/null +++ b/test/salt/pillar/package.sls @@ -0,0 +1,161 @@ +# -*- coding: utf-8 -*- +# vim: ft=yaml +--- +# example docker registry container +# if you want to your own docker registry, use this +docker: + wanted: + - docker + - compose + + pkg: + docker: + use_upstream: package + config: + - DOCKER_OPTS="-s btrfs --dns 8.8.8.8" + - export http_proxy="http://172.17.42.1:3128" + + containers: + running: + - nginx + - prometheus + + nginx: + image: "nginx:latest" + + prometheus: + image: "prom/prometheus:v1.7.1" + env: + - a=b + - ping=pong + - ding=dong + command: + - ls + - ls -l + auto_remove: true + blkio_weight: 1000 + cap_add: ["SYS_ADMIN", "MKNOD"] + dns: + - 8.8.8.8 + - 8.8.4.4 + dns_search: + - EXAMPLE.COM + domainname: + - EXAMPLE.COM + entrypoint: + - ls + - ls -l + - ls -last + - sleep 100 + init: false + labels: + - label1 + - label2 + - label3 + mem_limit: 1g + mem_swappiness: 50 + name: prometheus + network_disabled: false + network_mode: host # bridge or none or container:netcontainer or host + oom_kill_disable: true + oom_score_adj: 100 + pid_mode: host + pids_limit: -1 + privileged: false + publish_all_ports: true + read_only: false + stdin_open: false + tty: true + volume_driver: local + + registry: + image: "registry:latest" + env: + - REGISTRY_LOG_LEVEL=warn + - REGISTRY_STORAGE=s3 + - REGISTRY_STORAGE_S3_REGION=us-west-1 + - REGISTRY_STORAGE_S3_BUCKET=my-bucket + - REGISTRY_STORAGE_S3_ROOTDIRECTORY=/registry + command: + - "--log-driver=syslog" + - "-p 5000:5000" + - "--rm" + + compose: + ## salt dockercompose module ## + applications: + - composetest + composetest: + path: /srv/salt/docker/files/composetest/docker-compose.yml + + ## formerly compose-ng state ## + ng: + registry-datastore: + dvc: true + # image: ®istry_image 'docker.io/registry:latest' ## Fedora + image: ®istry_image 'registry:latest' + container_name: &dvc 'registry-datastore' + command: echo *dvc data volume container + volumes: + - &datapath '/registry' + registry-service: + image: *registry_image + container_name: 'registry-service' + volumes_from: + - *dvc + environment: + SETTINGS_FLAVOR: 'local' + STORAGE_PATH: *datapath + SEARCH_BACKEND: 'sqlalchemy' + REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: '/registry' + ports: + - 127.0.0.1:5000:5000 + # restart: 'always' # compose v1.9 + deploy: # compose v3 + restart_policy: + condition: on-failure + delay: 5s + max_attempts: 3 + window: 120s + nginx-latest: + # image: 'docker.io/nginx:latest' ##Fedora + image: 'nginx:latest' + container_name: 'nginx-latest' + links: + - 'registry-service:registry' + ports: + - '80:80' + - '443:443' + volumes: + - /srv/docker-registry/nginx/:/etc/nginx/conf.d + - /srv/docker-registry/auth/:/etc/nginx/conf.d/auth + - /srv/docker-registry/certs/:/etc/nginx/conf.d/certs + working_dir: '/var/www/html' + volume_driver: 'foobar' + userns_mode: 'host' + user: 'nginx' + # restart: 'always' # compose v1.9 + deploy: # compose v3 + restart_policy: + condition: on-failure + delay: 5s + max_attempts: 3 + window: 120s + + swarm: + # Per https://docs.saltstack.com/en/latest/ref/modules/all/salt.modules.swarm.html + joinswarm: {} + leave_swarm: false + node_ls: {} + remove_node: {} + remove_service: {} + service_create: {} + swarm_init: {} + service_info: {} + swarm_tokens: true + update_node: {} + + misc: + skip_translate: ports + force_present: false + force_running: true