diff --git a/README.md b/README.md index 10745eb..8b9c3c0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,27 @@ # Ansible Collection - bodsch.docker -Documentation for the collection. +A collection of Ansible roles for docker Stuff. + + + +## supported operating systems + +* Arch Linux +* Debian based + - Debian 10 / 11 + - Ubuntu 20.10 + +## Contribution + +Please read [Contribution](CONTRIBUTING.md) + +## Development, Branches (Git Tags) + +The `master` Branch is my *Working Horse* includes the "latest, hot shit" and can be complete broken! + +If you want to use something stable, please use a [Tagged Version](https://github.com/bodsch/ansible-collection-prometheus/tags)! + +--- ## Roles diff --git a/galaxy.yml b/galaxy.yml index 319ebf9..48428c2 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -3,7 +3,7 @@ namespace: bodsch name: docker -version: 1.0.3 +version: 1.1.0 readme: README.md diff --git a/roles/container/README.md b/roles/container/README.md index 00baf63..0e1f5fe 100644 --- a/roles/container/README.md +++ b/roles/container/README.md @@ -1,19 +1,9 @@ -# Ansible Role: `container` +# Ansible Role: `bodsch.docker.container` ansible role for docker deployment of generic container applications -[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/bodsch/ansible-container/main.yml?branch=main)][ci] -[![GitHub issues](https://img.shields.io/github/issues/bodsch/ansible-container)][issues] -[![GitHub release (latest by date)](https://img.shields.io/github/v/release/bodsch/ansible-container)][releases] -[![Ansible Quality Score](https://img.shields.io/ansible/quality/50067?label=role%20quality)][quality] - -[ci]: https://github.com/bodsch/ansible-container/actions -[issues]: https://github.com/bodsch/ansible-container/issues?q=is%3Aopen+is%3Aissue -[releases]: https://github.com/bodsch/ansible-container/releases -[quality]: https://galaxy.ansible.com/bodsch/container - ## Requirements & Dependencies @@ -31,16 +21,6 @@ or ansible-galaxy collection install --requirements-file collections.yml ``` - -### Operating systems - -Tested on - -* Arch Linux -* Debian based - - Debian 10 / 11 - - Ubuntu 20.10 - ## usage ```yaml @@ -412,43 +392,3 @@ The specification of `owner` and `group` enables the setting of access rights. ``` -## tests - -Local tests are executed in a docker container. -Note that this container must provide its own docker daemon (*docker-in-docker*). - -```bash -make -make verify -make destroy -``` - -You can call these tests with different Ansible versions: - -```bash -make -e TOX_ANSIBLE=ansible_6.4 -make destroy -e TOX_ANSIBLE=ansible_6.4 -``` - -The currently testable Ansible versions are defined in [`tox.ini`](./tox.ini). - - -Below `molecule`, various tests are provided. If none is explicitly specified, `default` is used. -To call a special test, you can define it via `-e TOX_SCENARIO=$TEST`. - -```bash -make -e TOX_SCENARIO=multiple-container -make destroy -e TOX_SCENARIO=multiple-container -``` - ---- - -## Author and License - -- Bodo Schulz - -## License - -[Apache](LICENSE) - -**FREE SOFTWARE, HELL YEAH!** diff --git a/roles/docker/README.md b/roles/docker/README.md index 2d8ecc5..a89f1a7 100644 --- a/roles/docker/README.md +++ b/roles/docker/README.md @@ -1,5 +1,5 @@ -# Ansible Role: `docker` +# Ansible Role: `bodsch.docker.docker` This role will fully configure and install [dockerd](https://www.docker.com/). @@ -384,16 +384,3 @@ Advanced playbook with various variables applied ``` --- -## Author and License - -- original `docker` role written by: - - George Bolo | [linuxctl.com](https://linuxctl.com) - -- modified: - - Bodo Schulz - -## License - -MIT - -**FREE SOFTWARE, HELL YEAH!** diff --git a/roles/registry/README.md b/roles/registry/README.md index b41b1b9..227ad7c 100644 --- a/roles/registry/README.md +++ b/roles/registry/README.md @@ -1,18 +1,8 @@ -# Ansible Role: `registry` +# Ansible Role: `bodsch.docker.registry` Ansible role to install and configure docker [registry](https://github.com/distribution/distribution). -[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/bodsch/ansible-registry/main.yml?branch=main)][ci] -[![GitHub issues](https://img.shields.io/github/issues/bodsch/ansible-registry)][issues] -[![GitHub release (latest by date)](https://img.shields.io/github/v/release/bodsch/ansible-registry)][releases] -[![Ansible Quality Score](https://img.shields.io/ansible/quality/50067?label=role%20quality)][quality] - -[ci]: https://github.com/bodsch/ansible-registry/actions -[issues]: https://github.com/bodsch/ansible-registry/issues?q=is%3Aopen+is%3Aissue -[releases]: https://github.com/bodsch/ansible-registry/releases -[quality]: https://galaxy.ansible.com/bodsch/registry - If `latest` is set for `registry_version`, the role tries to install the latest release version. **Please use this with caution, as incompatibilities between releases may occur!** @@ -25,42 +15,6 @@ By default it is `${HOME}/.cache/ansible/registry`. If this type of installation is not desired, the download can take place directly on the target system. However, this must be explicitly activated by setting `registry_direct_download` to `true`. -## Requirements & Dependencies - -Ansible Collections - -- [bodsch.core](https://github.com/bodsch/ansible-collection-core) -- [bodsch.scm](https://github.com/bodsch/ansible-collection-scm) - -```bash -ansible-galaxy collection install bodsch.core -ansible-galaxy collection install bodsch.scm -``` -or -```bash -ansible-galaxy collection install --requirements-file collections.yml -``` - -## Operating systems - -Tested on - -* Arch Linux -* Debian based - - Debian 10 / 11 - - Ubuntu 20.10 - - -## Contribution - -Please read [Contribution](CONTRIBUTING.md) - -## Development, Branches (Git Tags) - -The `master` Branch is my *Working Horse* includes the "latest, hot shit" and can be complete broken! - -If you want to use something stable, please use a [Tagged Version](https://github.com/bodsch/ansible-registry/tags)! - ## Configuration ```yaml @@ -200,12 +154,3 @@ registry_validation: {} --- -## Author and License - -- Bodo Schulz - -## License - -[Apache](LICENSE) - -**FREE SOFTWARE, HELL YEAH!** diff --git a/roles/registry_ui/README.md b/roles/registry_ui/README.md index 8fbb94c..62e8f7f 100644 --- a/roles/registry_ui/README.md +++ b/roles/registry_ui/README.md @@ -1,20 +1,10 @@ -# Ansible Role: `registry-ui` +# Ansible Role: `bodsch.docker.registry_ui` Ansible role for installing and configuring Docker [registry-ui](https://github.com/Quiq/docker-registry-ui) without dependencies on a container. Natively supports systemd and openrc as init system. -[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/bodsch/ansible-registry-ui/main.yml?branch=main)][ci] -[![GitHub issues](https://img.shields.io/github/issues/bodsch/ansible-registry-ui)][issues] -[![GitHub release (latest by date)](https://img.shields.io/github/v/release/bodsch/ansible-registry-ui)][releases] -[![Ansible Quality Score](https://img.shields.io/ansible/quality/50067?label=role%20quality)][quality] - -[ci]: https://github.com/bodsch/ansible-registry-ui/actions -[issues]: https://github.com/bodsch/ansible-registry-ui/issues?q=is%3Aopen+is%3Aissue -[releases]: https://github.com/bodsch/ansible-registry-ui/releases -[quality]: https://galaxy.ansible.com/bodsch/registry_ui - If `latest` is set for `registry_ui_version`, the role tries to install the latest release version. **Please use this with caution, as incompatibilities between releases may occur!** @@ -27,50 +17,143 @@ By default it is `${HOME}/.cache/ansible/registry-ui`. If this type of installation is not desired, the download can take place directly on the target system. However, this must be explicitly activated by setting `registry_ui_direct_download` to `true`. -## Requirements & Dependencies -Ansible Collections +## Configuration + +> **Please note:** The release of the registry-ui binary is done from a fork and not from the [original](https://github.com/Quiq/docker-registry-ui), because the original repository does not provide a go-binary yet! + +**ATTENTION!** + +Breaking changes: Since version 0.10, the syntax of the configuration file has changed and is no longer compatible! + +Here you can find the current version of the configuration: [https://github.com/bodsch/docker-registry-ui/blob/master/config.yml](config.yml) + +```yaml +registry_ui_version: 0.10.3 + +registry_ui_release: + download_url: https://github.com/bodsch/docker-registry-ui/releases + +registry_ui_system_user: registry-ui +registry_ui_system_group: registry-ui +registry_ui_config_dir: /etc/registry-ui +registry_ui_data_dir: /var/lib/registry-ui + +registry_ui_direct_download: false + +registry_ui_service: + log_level: info + +registry_ui_listen: + address: 127.0.0.1 + port: 8000 + +registry_ui_base_path: / + +registry_ui_performance: {} + +registry_ui_registry: + hostname: "127.0.0.1:5000" + insecure: true + username: admin + password: admin + +registry_ui_access_control: {} -- [bodsch.core](https://github.com/bodsch/ansible-collection-core) -- [bodsch.scm](https://github.com/bodsch/ansible-collection-scm) +registry_ui_event_listener: {} -```bash -ansible-galaxy collection install bodsch.core -ansible-galaxy collection install bodsch.scm +registry_ui_purge_tags: {} + +registry_ui_debug: {} +``` + +### `registry_ui_listen` + +Listen interface and Port + +```yaml +registry_ui_listen: + address: 127.0.0.1 + port: 8000 ``` -or -```bash -ansible-galaxy collection install --requirements-file collections.yml + +### `registry_ui_performance` + +```yaml +registry_ui_performance: + catalog_page_size: 100 + catalog_refresh_interval: 10 + tags_count_refresh_interval: 60 ``` -## Operating systems +### `registry_ui_registry` + +Registry URL without schema and port. + +Verify TLS certificate when using https. -Tested on +Docker registry credentials. +They need to have a full access to the registry. +If token authentication service is enabled, it will be auto-discovered and those credentials +will be used to obtain access tokens. +When the `password_file` entry is used, the password can be passed as a docker secret +and read from file. This overides the `password` entry. -* Arch Linux -* Debian based - - Debian 10 / 11 - - Ubuntu 20.10 +```yaml +registry_ui_registry: + hostname: docker-registry.local + insecure: false + username: "" + password: "" + password_file: "" + auth_with_keychain: "" +``` -## Requirements -Running Docker Registry. +### `registry_ui_access_control` +```yaml +registry_ui_access_control: + anyone_can_view_events: true + anyone_can_delete_tags: false + admins: [] +``` -## Contribution +### `registry_ui_event_listener` -Please read [Contribution](CONTRIBUTING.md) +```yaml +registry_ui_event_listener: + bearer_token: "" + retention_days: 7 + database: + driver: sqlite3 # sqlite3 or mysql + location: "" + username: "" + password: "" + hostname: 127.0.0.1:3306 + schemaname: docker_events + deletion_enabled: true +``` -## Development, Branches (Git Tags) +### `registry_ui_purge_tags` -The `master` Branch is my *Working Horse* includes the "latest, hot shit" and can be complete broken! +```yaml +registry_ui_purge_tags: + keep_days: 90 + keep_count: 10 + keep_regexp: '' + keep_from_file: '' +``` -If you want to use something stable, please use a [Tagged Version](https://github.com/bodsch/ansible-registry-ui/tags)! +### `registry_ui_debug` -## Configuration +```yaml +registry_ui_debug: + templates: false +``` -> **Please note:** The release of the registry-ui binary is done from a fork and not from the [original](https://github.com/Quiq/docker-registry-ui), because the original repository does not provide a go-binary yet! +### OBSOLETE VERSION 0.9.x ```yaml registry_ui_version: 0.9.5 @@ -195,12 +278,3 @@ registry_ui_purge: --- -## Author and License - -- Bodo Schulz - -## License - -[Apache](LICENSE) - -**FREE SOFTWARE, HELL YEAH!** diff --git a/roles/registry_ui/defaults/main.yml b/roles/registry_ui/defaults/main.yml index 266ad8f..889bfbc 100644 --- a/roles/registry_ui/defaults/main.yml +++ b/roles/registry_ui/defaults/main.yml @@ -1,8 +1,9 @@ --- -registry_ui_version: 0.9.5 +registry_ui_version: 0.10.3 -registry_ui_release_download_url: https://github.com/bodsch/docker-registry-ui/releases +registry_ui_release: + download_url: https://github.com/bodsch/docker-registry-ui/releases registry_ui_system_user: registry-ui registry_ui_system_group: registry-ui @@ -20,16 +21,26 @@ registry_ui_listen: registry_ui_base_path: / -registry_ui_debug: false +registry_ui_performance: {} -registry_ui_registry: {} +registry_ui_registry: + hostname: "127.0.0.1:5000" + insecure: true + username: admin + password: admin -registry_ui_event: {} +registry_ui_access_control: {} -registry_ui_cache: {} +registry_ui_event_listener: {} -registry_ui_admins: [] +registry_ui_purge_tags: {} + +registry_ui_debug: {} +# obsole since version 0.10.x +registry_ui_event: {} +registry_ui_cache: {} +registry_ui_admins: [] registry_ui_purge: {} ... diff --git a/roles/registry_ui/molecule/configured-0.9/converge.yml b/roles/registry_ui/molecule/configured-0.9/converge.yml new file mode 100644 index 0000000..5190178 --- /dev/null +++ b/roles/registry_ui/molecule/configured-0.9/converge.yml @@ -0,0 +1,11 @@ +--- + +- name: converge + hosts: instance + any_errors_fatal: false + become: false + + roles: + - role: bodsch.docker.registry_ui + +... diff --git a/roles/registry_ui/molecule/configured-0.9/group_vars/all/htpasswd.yml b/roles/registry_ui/molecule/configured-0.9/group_vars/all/htpasswd.yml new file mode 100644 index 0000000..6a852ef --- /dev/null +++ b/roles/registry_ui/molecule/configured-0.9/group_vars/all/htpasswd.yml @@ -0,0 +1,21 @@ +--- + +htpasswd_credentials_path: /etc/nginx/htpasswd.d + +htpasswd_credentials: + + - path: "{{ htpasswd_credentials_path }}/.admin-passwdfile" + users: + - username: admin + password: ZRhgqhaAjdbuFXj2PLJTzYy5PrRsStNaeYWd9c3Ze3 + - username: registry + password: registry + + - path: /etc/docker/registry/.registry-passwdfile + mode: "u=rw,g=r,o-r" + group: registry + users: + - username: registry + password: registry + crypt_scheme: md5_crypt +... diff --git a/roles/registry_ui/molecule/configured-0.9/group_vars/all/nginx.yml b/roles/registry_ui/molecule/configured-0.9/group_vars/all/nginx.yml new file mode 100644 index 0000000..4a22398 --- /dev/null +++ b/roles/registry_ui/molecule/configured-0.9/group_vars/all/nginx.yml @@ -0,0 +1,113 @@ +--- + +nginx_events: + multi_accept: true + +nginx_gzip: + enabled: false + +# The client_max_body_size parameter is now set to 16384m, making the maximum upload size equal to 16GB. +nginx_http: + client: # + max_body_size: "1G" + maps: + - name: upstream_http_docker_distribution_api_version + description: | + ## Set a variable to help us decide if we need to add the + ## 'Docker-Distribution-Api-Version' header. + ## The registry always sets this header. + ## In the case of nginx performing auth, the header is unset + ## since nginx is auth-ing before proxying. + variable: docker_distribution_api_version + mapping: + - source: "" + result: "registry/2.0" + + includes: + - includes.d/useragent.rules + - includes.d/proxy_cache.rules + - sites-enabled/*.conf + +nginx_custom_includes: + registry.conf: | + # https://nginx.org/en/docs/http/ngx_http_core_module.html#satisfy + satisfy any; + # Die IP des HAProxy + # damit ist es möglich das Jobs, die über den Jenkins aufgerufen werden und gegen + # die admin URLs (https://admin.*.DOMAIN.TLD/admin/*) gehen + # ohne Username/Passwort zu nutzen + # Alle anderen Requests benötigen weiterhin die Authentifizierung via BA + allow 192.168.0.0/24; + deny all; + + auth_basic "Administrator’s Area"; + auth_basic_user_file "{{ htpasswd_credentials_path }}/.admin-passwdfile"; + +nginx_vhosts: + - name: registry + filename: 00-registry.conf + state: present # default: present + enabled: true # default: true + + domains: + - registry.molecule.lan + - molecule.molecule.lan + + listen: + - "80" + + upstreams: + - name: registry + servers: + - 127.0.0.1:5000 + - name: registry_ui_metrics + servers: + - 127.0.0.1:5001 + - name: registry_ui_ui + servers: + - 127.0.0.1:8000 + + logfiles: + access: + file: /var/log/nginx/registry.molecule.lan/access.log + # loglevel: json_combined + error: + file: /var/log/nginx/registry.molecule.lan/error.log + loglevel: notice + + locations: + "/metrics": + options: | + add_header X-Backend "registry-metrics"; + + proxy_pass http://registry_ui_metrics; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + "/": + options: | + add_header X-Backend "registry-ui"; + + proxy_pass http://registry_ui_ui; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + "/v2/": + options: | + if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*$" ) { + return 404; + } + + add_header X-Backend "registry"; + add_header 'Docker-Distribution-Api-Version' $docker_distribution_api_version always; + + proxy_pass http://registry; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 900; diff --git a/roles/registry_ui/molecule/configured-0.9/group_vars/all/redis.yml b/roles/registry_ui/molecule/configured-0.9/group_vars/all/redis.yml new file mode 100644 index 0000000..e0f81b3 --- /dev/null +++ b/roles/registry_ui/molecule/configured-0.9/group_vars/all/redis.yml @@ -0,0 +1,5 @@ +--- + +redis_network_port: 6379 + +... diff --git a/roles/registry_ui/molecule/configured-0.9/group_vars/all/registry.yml b/roles/registry_ui/molecule/configured-0.9/group_vars/all/registry.yml new file mode 100644 index 0000000..8c5c46f --- /dev/null +++ b/roles/registry_ui/molecule/configured-0.9/group_vars/all/registry.yml @@ -0,0 +1,72 @@ +--- + +registry_log: + level: info + formatter: json + +registry_storage: + filesystem: + # rootdirectory: /opt/registry + maxthreads: 100 + delete: + enabled: true +# redirect: +# disable: false + cache: + blobdescriptor: redis + blobdescriptorsize: 10000 + maintenance: + uploadpurging: + enabled: true + age: 168h + interval: 10m + dryrun: false + +registry_http: + addr: localhost:5000 + relativeurls: true + secret: ZRhgqhaAjdbuFXj2PLJTzYy5PrRsStNaeYWd9c3Ze3 + debug: + addr: localhost:5001 + prometheus: + enabled: true + path: /metrics + +registry_redis: + addr: localhost:6379 + db: 0 + dialtimeout: 10ms + readtimeout: 10ms + writetimeout: 10ms + pool: + maxidle: 16 + maxactive: 64 + idletimeout: 300s + tls: + enabled: false + +registry_notifications: + events: + includereferences: true + endpoints: + - name: registry_ui + disabled: false + url: http://127.0.0.1:8000/api/events + # headers: + headers: + Content-Type: + - application/json + Authorization: + - "Bearer 74RwH03rOPh8kTnIgcCqAWhgV3cGMAuz" + timeout: 1s + threshold: 10 + backoff: 10s + ignoredmediatypes: + - application/octet-stream + ignore: + mediatypes: + - application/octet-stream + actions: + - pull + +... diff --git a/roles/registry_ui/molecule/configured-0.9/group_vars/all/snakeoil.yml b/roles/registry_ui/molecule/configured-0.9/group_vars/all/snakeoil.yml new file mode 100644 index 0000000..81457ec --- /dev/null +++ b/roles/registry_ui/molecule/configured-0.9/group_vars/all/snakeoil.yml @@ -0,0 +1,16 @@ +--- + +snakeoil_extract_to: /etc/snakeoil + +# snakeoil_force: true + +snakeoil_domain: matrix.lan + +snakeoil_life_time: 30 + +snakeoil_alt_names: + - dns: + - registry.matrix.lan + - molecule.matrix.lan + +... diff --git a/roles/registry_ui/molecule/configured-0.9/group_vars/all/vars.yml b/roles/registry_ui/molecule/configured-0.9/group_vars/all/vars.yml new file mode 100644 index 0000000..a44a502 --- /dev/null +++ b/roles/registry_ui/molecule/configured-0.9/group_vars/all/vars.yml @@ -0,0 +1,29 @@ +--- + +registry_ui_version: 0.9.5 + +registry_ui_service: + log_level: debug + +registry_ui_base_path: / + +registry_ui_listen: + address: 127.0.0.1 + port: 8000 + +registry_ui_registry: + url: http://127.0.0.1:5000 + verify_tls: false + +registry_ui_delete: + anyone_can_delete: true + +registry_ui_event: + deletion_enabled: true + anyone_can_view: true + token: 74RwH03rOPh8kTnIgcCqAWhgV3cGMAuz + +registry_ui_cache: + refresh_interval: 10 + +... diff --git a/roles/registry_ui/molecule/configured-0.9/molecule.yml b/roles/registry_ui/molecule/configured-0.9/molecule.yml new file mode 100644 index 0000000..5beec74 --- /dev/null +++ b/roles/registry_ui/molecule/configured-0.9/molecule.yml @@ -0,0 +1,61 @@ +--- + +role_name_check: 1 + +dependency: + name: galaxy + +driver: + name: docker + +platforms: + - name: instance + image: "bodsch/ansible-${DISTRIBUTION:-debian:12}" + command: ${MOLECULE_DOCKER_COMMAND:-""} + docker_host: "${DOCKER_HOST:-unix://run/docker.sock}" + privileged: true + pre_build_image: true + cgroupns_mode: host + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:rw + - /var/lib/containerd + capabilities: + - SYS_ADMIN + tmpfs: + - /run + - /tmp + published_ports: + - 80:80 + - 443:443 + - 5000:5000 + - 5001:5001 + - 8080:8080 + +provisioner: + name: ansible + ansible_args: + - --diff + - -v + config_options: + defaults: + deprecation_warnings: true + stdout_callback: yaml + callbacks_enabled: profile_tasks + gathering: smart + fact_caching: jsonfile + fact_caching_timeout: 8640 + fact_caching_connection: ansible_facts + +scenario: + test_sequence: + - destroy + - dependency + - syntax + - create + - prepare + - converge + - verify + - destroy + +verifier: + name: testinfra diff --git a/roles/registry_ui/molecule/configured-0.9/prepare.yml b/roles/registry_ui/molecule/configured-0.9/prepare.yml new file mode 100644 index 0000000..b5fbfee --- /dev/null +++ b/roles/registry_ui/molecule/configured-0.9/prepare.yml @@ -0,0 +1,62 @@ +--- + +- name: information + hosts: all + gather_facts: true + + pre_tasks: + - name: arch- / artixlinux + when: + - ansible_distribution | lower == 'archlinux' or + ansible_os_family | lower == 'artix linux' + block: + - name: update pacman system + ansible.builtin.command: | + pacman --refresh --sync --sysupgrade --noconfirm + register: pacman + changed_when: pacman.rc != 0 + failed_when: pacman.rc != 0 + + - name: create depends service + ansible.builtin.copy: + mode: 0755 + dest: /etc/init.d/net + content: | + #!/usr/bin/openrc-run + true + when: + - ansible_os_family | lower == 'artix linux' + + - name: make sure python3-apt is installed (only debian based) + ansible.builtin.package: + name: + - python3-apt + state: present + when: + - ansible_os_family | lower == 'debian' + + - name: update package cache + become: true + ansible.builtin.package: + update_cache: true + + - name: environment + ansible.builtin.debug: + msg: + - "os family : {{ ansible_distribution }} ({{ ansible_os_family }})" + - "distribution version : {{ ansible_distribution_major_version }}" + - "ansible version : {{ ansible_version.full }}" + - "python version : {{ ansible_python.version.major }}.{{ ansible_python.version.minor }}" + +- name: prepare container + hosts: all + gather_facts: true + + roles: + - role: bodsch.core.syslog_ng + - role: bodsch.core.snakeoil + - role: redis + - role: nginx + - role: bodsch.docker.registry + +... diff --git a/roles/registry_ui/molecule/configured-0.9/requirements.yml b/roles/registry_ui/molecule/configured-0.9/requirements.yml new file mode 100644 index 0000000..83daf37 --- /dev/null +++ b/roles/registry_ui/molecule/configured-0.9/requirements.yml @@ -0,0 +1,10 @@ +--- + +- name: nginx + src: bodsch.nginx + version: 0.27.2 + +- name: redis + src: bodsch.redis + +... diff --git a/roles/registry_ui/molecule/configured-0.9/tests/test_default.py b/roles/registry_ui/molecule/configured-0.9/tests/test_default.py new file mode 100644 index 0000000..054cc7d --- /dev/null +++ b/roles/registry_ui/molecule/configured-0.9/tests/test_default.py @@ -0,0 +1,188 @@ +# coding: utf-8 +from __future__ import unicode_literals + +from ansible.parsing.dataloader import DataLoader +from ansible.template import Templar + +import json +import pytest +import os + +import testinfra.utils.ansible_runner + +HOST = 'instance' + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts(HOST) + + +def pp_json(json_thing, sort=True, indents=2): + if type(json_thing) is str: + print(json.dumps(json.loads(json_thing), sort_keys=sort, indent=indents)) + else: + print(json.dumps(json_thing, sort_keys=sort, indent=indents)) + return None + + +def base_directory(): + """ + """ + cwd = os.getcwd() + + if 'group_vars' in os.listdir(cwd): + directory = "../.." + molecule_directory = "." + else: + directory = "." + molecule_directory = f"molecule/{os.environ.get('MOLECULE_SCENARIO_NAME')}" + + return directory, molecule_directory + + +def read_ansible_yaml(file_name, role_name): + """ + """ + read_file = None + + for e in ["yml", "yaml"]: + test_file = "{}.{}".format(file_name, e) + if os.path.isfile(test_file): + read_file = test_file + break + + return f"file={read_file} name={role_name}" + + +@pytest.fixture() +def get_vars(host): + """ + parse ansible variables + - defaults/main.yml + - vars/main.yml + - vars/${DISTRIBUTION}.yaml + - molecule/${MOLECULE_SCENARIO_NAME}/group_vars/all/vars.yml + """ + base_dir, molecule_dir = base_directory() + distribution = host.system_info.distribution + operation_system = None + + if distribution in ['debian', 'ubuntu']: + operation_system = "debian" + elif distribution in ['redhat', 'ol', 'centos', 'rocky', 'almalinux']: + operation_system = "redhat" + elif distribution in ['arch', 'artix']: + operation_system = f"{distribution}linux" + + # print(" -> {} / {}".format(distribution, os)) + # print(" -> {}".format(base_dir)) + + file_defaults = read_ansible_yaml(f"{base_dir}/defaults/main", "role_defaults") + file_vars = read_ansible_yaml(f"{base_dir}/vars/main", "role_vars") + file_distibution = read_ansible_yaml(f"{base_dir}/vars/{operation_system}", "role_distibution") + file_molecule = read_ansible_yaml(f"{molecule_dir}/group_vars/all/vars", "test_vars") + # file_host_molecule = read_ansible_yaml("{}/host_vars/{}/vars".format(base_dir, HOST), "host_vars") + + defaults_vars = host.ansible("include_vars", file_defaults).get("ansible_facts").get("role_defaults") + vars_vars = host.ansible("include_vars", file_vars).get("ansible_facts").get("role_vars") + distibution_vars = host.ansible("include_vars", file_distibution).get("ansible_facts").get("role_distibution") + molecule_vars = host.ansible("include_vars", file_molecule).get("ansible_facts").get("test_vars") + # host_vars = host.ansible("include_vars", file_host_molecule).get("ansible_facts").get("host_vars") + + ansible_vars = defaults_vars + ansible_vars.update(vars_vars) + ansible_vars.update(distibution_vars) + ansible_vars.update(molecule_vars) + # ansible_vars.update(host_vars) + + templar = Templar(loader=DataLoader(), variables=ansible_vars) + result = templar.template(ansible_vars, fail_on_undefined=False) + + return result + + +def local_facts(host): + """ + return local facts + """ + return host.ansible("setup").get("ansible_facts").get("ansible_local").get("registry_ui") + + +def test_directories(host, get_vars): + """ + """ + directories = [] + directories.append("/etc/registry-ui") + directories.append("/var/lib/registry-ui") + + for dirs in directories: + d = host.file(dirs) + assert d.is_directory + + +def test_files(host, get_vars): + """ + """ + distribution = host.system_info.distribution + release = host.system_info.release + + print(f"distribution: {distribution}") + print(f"release : {release}") + + version = local_facts(host).get("version") + + install_dir = get_vars.get("registry_ui_install_path") + defaults_dir = get_vars.get("registry_ui_defaults_directory") + config_dir = get_vars.get("registry_ui_config_dir") + + if 'latest' in install_dir: + install_dir = install_dir.replace('latest', version) + + files = [] + files.append("/usr/bin/registry-ui") + + if install_dir: + files.append(f"{install_dir}/registry-ui") + if defaults_dir and not distribution == "artix": + files.append(f"{defaults_dir}/registry-ui") + if config_dir: + files.append(f"{config_dir}/config.yml") + + print(files) + + for _file in files: + f = host.file(_file) + assert f.exists + assert f.is_file + + +def test_user(host, get_vars): + """ + """ + user = get_vars.get("registry_ui_system_user", "registry") + group = get_vars.get("registry_ui_system_group", "registry") + + assert host.group(group).exists + assert host.user(user).exists + assert group in host.user(user).groups + assert host.user(user).home == "/var/lib/registry-ui" + + +def test_service(host, get_vars): + """ + """ + service = host.service("registry-ui") + assert service.is_enabled + assert service.is_running + + +def test_open_port(host, get_vars): + """ + """ + listen = get_vars.get("registry_ui_listen", None) + + if listen: + address = listen.get("address", "127.0.0.1") + port = listen.get("port", "8080") + + service = host.socket(f"tcp://{address}:{port}") + assert service.is_listening diff --git a/roles/registry_ui/molecule/configured/group_vars/all/vars.yml b/roles/registry_ui/molecule/configured/group_vars/all/vars.yml index d175623..1d96697 100644 --- a/roles/registry_ui/molecule/configured/group_vars/all/vars.yml +++ b/roles/registry_ui/molecule/configured/group_vars/all/vars.yml @@ -3,8 +3,6 @@ registry_ui_service: log_level: debug -registry_ui_debug: true - registry_ui_base_path: / registry_ui_listen: @@ -12,18 +10,18 @@ registry_ui_listen: port: 8000 registry_ui_registry: - url: http://127.0.0.1:5000 - verify_tls: false - -registry_ui_delete: - anyone_can_delete: true + hostname: 127.0.0.1:5000 + insecure: false -registry_ui_event: +registry_ui_event_listener: deletion_enabled: true - anyone_can_view: true - token: 74RwH03rOPh8kTnIgcCqAWhgV3cGMAuz + bearer_token: 74RwH03rOPh8kTnIgcCqAWhgV3cGMAuz + +registry_ui_access_control: + anyone_can_view_events: true + anyone_can_delete_tags: true -registry_ui_cache: - refresh_interval: 10 +registry_ui_performance: + catalog_refresh_interval: 10 ... diff --git a/roles/registry_ui/molecule/default/group_vars/all/vars.yml b/roles/registry_ui/molecule/default/group_vars/all/vars.yml index e3e210e..321c958 100644 --- a/roles/registry_ui/molecule/default/group_vars/all/vars.yml +++ b/roles/registry_ui/molecule/default/group_vars/all/vars.yml @@ -1,14 +1,7 @@ --- -registry_ui_service: - log_level: info - registry_ui_listen: address: 0.0.0.0 port: 8080 -registry_ui_registry: - url: http://127.0.0.1:5000 - verify_tls: false - ... diff --git a/roles/registry_ui/molecule/latest/group_vars/all/vars.yml b/roles/registry_ui/molecule/latest/group_vars/all/vars.yml index 58323f8..90f59a3 100644 --- a/roles/registry_ui/molecule/latest/group_vars/all/vars.yml +++ b/roles/registry_ui/molecule/latest/group_vars/all/vars.yml @@ -3,14 +3,19 @@ registry_ui_version: latest registry_ui_service: - log_level: info + log_level: debug registry_ui_listen: address: 0.0.0.0 port: 8080 registry_ui_registry: - url: http://127.0.0.1:5000 - verify_tls: false + hostname: "127.0.0.1:5000" + insecure: true + username: admin + password: admin + +registry_ui_event: + listener_token: "" ... diff --git a/roles/registry_ui/tasks/configure.yml b/roles/registry_ui/tasks/configure.yml index 9685326..7af8d86 100644 --- a/roles/registry_ui/tasks/configure.yml +++ b/roles/registry_ui/tasks/configure.yml @@ -1,5 +1,21 @@ --- +- name: merge registry configuration between defaults and custom + ansible.builtin.set_fact: + registry_ui_service: "{{ registry_ui_defaults_service | combine(registry_ui_service, recursive=True) }}" + registry_ui_listen: "{{ registry_ui_defaults_listen | combine(registry_ui_listen, recursive=True) }}" + registry_ui_performance: "{{ registry_ui_defaults_performance | combine(registry_ui_performance, recursive=True) }}" + registry_ui_registry: "{{ registry_ui_defaults_registry | combine(registry_ui_registry, recursive=True) }}" + registry_ui_access_control: "{{ registry_ui_defaults_access_control | combine(registry_ui_access_control, recursive=True) }}" + registry_ui_event_listener: "{{ registry_ui_defaults_event_listener | combine(registry_ui_event_listener, recursive=True) }}" + registry_ui_purge_tags: "{{ registry_ui_defaults_purge_tags | combine(registry_ui_purge_tags, recursive=True) }}" + registry_ui_debug: "{{ registry_ui_defaults_debug | combine(registry_ui_debug, recursive=True) }}" + # obsolete + registry_ui_event: "{{ registry_ui_defaults_event | combine(registry_ui_event, recursive=True) }}" + registry_ui_cache: "{{ registry_ui_defaults_cache | combine(registry_ui_cache, recursive=True) }}" + registry_ui_admins: "{{ registry_ui_defaults_admins | combine(registry_ui_admins, recursive=True) }}" + registry_ui_purge: "{{ registry_ui_defaults_purge | combine(registry_ui_purge, recursive=True) }}" + - name: create registry-ui configuration directory ansible.builtin.file: path: "{{ registry_ui_config_dir }}" @@ -18,7 +34,7 @@ mode: 0664 notify: - validate config - - reload registry-ui + - restart registry-ui - name: restart registry if needed ansible.builtin.meta: flush_handlers diff --git a/roles/registry_ui/tasks/download.yml b/roles/registry_ui/tasks/download.yml index 250e315..3a6faf4 100644 --- a/roles/registry_ui/tasks/download.yml +++ b/roles/registry_ui/tasks/download.yml @@ -1,53 +1,133 @@ --- -- name: checksum - become: false +- name: get latest release delegate_to: localhost + become: false run_once: true + when: + - registry_ui_version == "latest" block: - - name: get checksum list - bodsch.scm.github_checksum: + - name: get latest release + delegate_to: localhost + become: false + run_once: true + bodsch.scm.github_latest: project: bodsch repository: docker-registry-ui - checksum_file: "{{ registry_ui_archive }}.sha256" user: "{{ lookup('env', 'GH_USER') | default(omit) }}" password: "{{ lookup('env', 'GH_TOKEN') | default(omit) }}" - architecture: "{{ ansible_architecture }}" - system: "{{ ansible_facts.system }}" - version: "{{ registry_ui_version }}" - register: _latest_checksum + register: _latest_release - - name: define checksum for {{ go_arch }} architecture + - name: re-define registry_ui_version ansible.builtin.set_fact: - __registry_ui_checksum: "{{ _latest_checksum.checksum }}" - when: - - _latest_checksum.rc == 0 - - _latest_checksum.checksum is defined - - _latest_checksum.checksum | string | length > 0 + registry_ui_version: "{{ _latest_release.latest_release }}" + +- name: define download information + ansible.builtin.set_fact: + registry_ui_release: "{{ registry_ui_defaults_release | combine(registry_ui_release, recursive=True) }}" + +- name: define delegate instance for download handling + ansible.builtin.set_fact: + registry_ui_delegate_to: "{{ ansible_host }}" + registry_ui_local_tmp_directory: "{{ + lookup('env', 'CUSTOM_LOCAL_TMP_DIRECTORY') | + default('/var/cache/ansible/registry-ui', true) }}/{{ registry_ui_version }}" + when: + - registry_ui_direct_download + +- name: create download directory + become: false + delegate_to: "{{ registry_ui_delegate_to }}" + run_once: "{{ 'false' if registry_ui_direct_download else 'true' }}" + ansible.builtin.file: + path: "{{ registry_ui_local_tmp_directory }}" + state: directory + mode: 0750 -- name: download registry-ui binary archive +- name: detect the downloaded registry_ui archive become: false delegate_to: "{{ registry_ui_delegate_to }}" run_once: "{{ 'false' if registry_ui_direct_download else 'true' }}" - ansible.builtin.get_url: - url: "{{ registry_ui_release_download_url }}/download/{{ registry_ui_version }}/registry-ui-{{ registry_ui_version }}-{{ ansible_facts.system }}-{{ system_architecture }}.tar.gz" - dest: "{{ registry_ui_local_tmp_directory }}/registry-ui-{{ system_architecture }}.tar.gz" - checksum: "sha256:{{ __registry_ui_checksum }}" - mode: 0660 - register: _download_archive - until: _download_archive is succeeded - retries: 5 - delay: 2 - check_mode: false - -- name: extract registry-ui archive + ansible.builtin.stat: + path: "{{ registry_ui_local_tmp_directory }}/{{ registry_ui_release.file }}" + register: stat_registry_ui_archive + +- name: download + when: + - stat_registry_ui_archive.stat is defined + - not stat_registry_ui_archive.stat.exists | default('false') + block: + - name: checksum + become: false + delegate_to: localhost + run_once: true + block: + - name: get checksum list + bodsch.scm.github_checksum: + project: bodsch + repository: docker-registry-ui + checksum_file: "{{ registry_ui_release.file }}.sha256" + user: "{{ lookup('env', 'GH_USER') | default(omit) }}" + password: "{{ lookup('env', 'GH_TOKEN') | default(omit) }}" + architecture: "{{ ansible_architecture }}" + system: "{{ ansible_facts.system | lower }}" + version: "{{ registry_ui_version }}" + register: _latest_checksum + + - name: define checksum for {{ system_architecture }} architecture + ansible.builtin.set_fact: + __registry_ui_checksum: "sha256:{{ _latest_checksum.checksum }}" + when: + - _latest_checksum.rc == 0 + - _latest_checksum.checksum is defined + - _latest_checksum.checksum | string | length > 0 + + - name: download registry_ui binary archive + become: false + delegate_to: "{{ registry_ui_delegate_to }}" + run_once: "{{ 'false' if registry_ui_direct_download else 'true' }}" + ansible.builtin.get_url: + url: "{{ registry_ui_release.download_url }}/download/{{ registry_ui_version }}/{{ registry_ui_release.file }}" + dest: "{{ registry_ui_local_tmp_directory }}/" + checksum: "{{ __registry_ui_checksum | default(omit) }}" + mode: 0640 + register: _download_archive + until: _download_archive is succeeded + retries: 5 + delay: 2 + check_mode: false + + rescue: + - name: delete download directory + become: false + delegate_to: "{{ registry_ui_delegate_to }}" + run_once: "{{ 'false' if registry_ui_direct_download else 'true' }}" + ansible.builtin.file: + path: "{{ registry_ui_local_tmp_directory }}" + state: absent + + - name: exit with fail + ansible.builtin.fail: + msg: A serious error occurred when downloading the archive. + +- name: detect extracted binary + become: false + delegate_to: "{{ registry_ui_delegate_to }}" + run_once: "{{ 'false' if registry_ui_direct_download else 'true' }}" + ansible.builtin.stat: + path: "{{ registry_ui_local_tmp_directory }}/{{ registry_ui_release.binary }}" + register: stat_registry_ui_binary + +- name: extract registry_ui archive become: false delegate_to: "{{ registry_ui_delegate_to }}" run_once: "{{ 'false' if registry_ui_direct_download else 'true' }}" ansible.builtin.unarchive: - src: "{{ registry_ui_local_tmp_directory }}/registry-ui-{{ system_architecture }}.tar.gz" - dest: "{{ registry_ui_local_tmp_directory }}" + src: "{{ registry_ui_local_tmp_directory }}/{{ registry_ui_release.file }}" + dest: "{{ registry_ui_local_tmp_directory }}/" copy: false - register: _extract_archive + when: + - stat_registry_ui_binary.stat is defined + - not stat_registry_ui_binary.stat.exists | default('false') ... diff --git a/roles/registry_ui/tasks/install.yml b/roles/registry_ui/tasks/install.yml index f747c61..391efdb 100644 --- a/roles/registry_ui/tasks/install.yml +++ b/roles/registry_ui/tasks/install.yml @@ -1,5 +1,37 @@ --- +- name: user and group handling + when: + - registry_ui_system_user != "root" or registry_ui_system_group != "root" + block: + - name: create registry group + ansible.builtin.group: + name: "{{ registry_ui_system_group }}" + state: present + system: true + when: + - registry_ui_system_group != "root" + + - name: create registry user + ansible.builtin.user: + name: "{{ registry_ui_system_user }}" + groups: "{{ registry_ui_system_group }}" + append: true + shell: /usr/sbin/nologin + system: true + createhome: false + home: "{{ registry_ui_data_dir }}" + when: + - registry_ui_system_user != "root" + +- name: create install directory + ansible.builtin.file: + path: "{{ registry_ui_install_path }}" + state: directory + owner: "{{ registry_ui_system_user }}" + group: "{{ registry_ui_system_group }}" + mode: 0755 + - name: detect extracted binary file for registry on {{ registry_ui_delegate_to }} become: false delegate_to: "{{ registry_ui_delegate_to }}" @@ -8,72 +40,77 @@ path: "{{ registry_ui_local_tmp_directory }}/registry-ui" register: stat_file_binary -- name: copy files +- name: fail when extracted binary are missing + ansible.builtin.fail: + msg: "missing extracted binary on ansible controller" + when: + - not stat_file_binary.stat.exists + +- name: detect installed registry_ui binary + ansible.builtin.stat: + path: "{{ registry_ui_install_path }}/{{ registry_ui_release.binary }}" + register: stat_registry_ui_binary + +- name: detect activated registry_ui binary + ansible.builtin.stat: + path: /usr/bin/{{ registry_ui_release.binary }} + register: stat_registry_ui_activated + +- name: install and activate registry_ui when: - - stat_file_binary.stat.exists + - (stat_registry_ui_binary.stat is defined and not stat_registry_ui_binary.stat.exists | default('false')) or + not stat_registry_ui_activated.stat | bodsch.prometheus.linked_version(registry_ui_install_path, registry_ui_version) block: - - name: propagate registry binaries - ansible.builtin.copy: - src: "{{ registry_ui_local_tmp_directory }}/registry-ui" - dest: "{{ registry_ui_install_path }}/registry-ui" - mode: 0755 - owner: "{{ registry_ui_system_user }}" - group: "{{ registry_ui_system_group }}" - remote_src: "{{ 'true' if registry_ui_direct_download else 'false' }}" + - name: propagate files + block: + - name: propagate registry binaries + ansible.builtin.copy: + src: "{{ registry_ui_local_tmp_directory }}/registry-ui" + dest: "{{ registry_ui_install_path }}/registry-ui" + mode: 0755 + owner: "{{ registry_ui_system_user }}" + group: "{{ registry_ui_system_group }}" + remote_src: "{{ 'true' if registry_ui_direct_download else 'false' }}" - - name: propagate static files - ansible.builtin.copy: - src: "{{ registry_ui_local_tmp_directory }}/{{ item }}/" - dest: "{{ registry_ui_data_dir }}/{{ item }}/" - mode: 0644 - owner: "{{ registry_ui_system_user }}" - group: "{{ registry_ui_system_group }}" - remote_src: "{{ 'true' if registry_ui_direct_download else 'false' }}" - loop: - - static - - templates - notify: - - reload registry-ui + - name: propagate static files + ansible.builtin.copy: + src: "{{ registry_ui_local_tmp_directory }}/{{ item }}/" + dest: "{{ registry_ui_data_dir }}/{{ item }}/" + mode: 0644 + owner: "{{ registry_ui_system_user }}" + group: "{{ registry_ui_system_group }}" + remote_src: "{{ 'true' if registry_ui_direct_download else 'false' }}" + loop: + - static + - templates + notify: + - reload registry-ui -- name: make files executable - ansible.builtin.file: - path: "{{ registry_ui_install_path }}/registry-ui" - mode: 0755 - owner: "{{ registry_ui_system_user }}" - group: "{{ registry_ui_system_group }}" + - name: create link to binary + ansible.builtin.file: + src: "{{ registry_ui_install_path }}/{{ registry_ui_release.binary }}" + dest: "/usr/bin/{{ registry_ui_release.binary }}" + state: link + force: true + follow: false + notify: + - restart registry-ui -- name: create custom fact file - bodsch.core.facts: - name: registry_ui - facts: - version: "{{ registry_ui_version }}" + rescue: + - name: delete install directory + ansible.builtin.file: + path: "{{ registry_ui_install_path }}" + state: absent -- name: create link to binary - ansible.builtin.file: - src: "{{ registry_ui_install_path }}/registry-ui" - dest: "/usr/bin/registry-ui" - state: link - force: true - follow: false - notify: - - restart registry-ui + - name: exit with fail + ansible.builtin.fail: + msg: A serious error occurred during the installation of the binary. - name: systemd when: - ansible_service_mgr | lower == "systemd" block: - - name: create systemd service unit - ansible.builtin.template: - src: "init/systemd/registry-ui.service.j2" - dest: "{{ systemd_lib_directory }}/registry-ui.service" - owner: root - group: root - mode: 0644 - notify: - - daemon-reload - - restart registry-ui - - - name: create systemd service configuration + - name: create systemd run configuration ansible.builtin.template: src: "registry-ui.j2" dest: "{{ registry_ui_defaults_directory }}/registry-ui" @@ -82,9 +119,18 @@ group: "{{ registry_ui_system_group }}" mode: 0640 notify: - - validate config - reload registry-ui + - name: create systemd service unit + ansible.builtin.template: + src: "init/systemd/registry-ui.service.j2" + dest: "{{ systemd_lib_directory }}/registry-ui.service" + owner: root + group: root + mode: 0644 + notify: + - daemon-reload + - name: openrc when: - ansible_service_mgr | lower == "openrc" @@ -105,4 +151,10 @@ group: root mode: 0750 +- name: create custom fact file + bodsch.core.facts: + name: registry_ui + facts: + version: "{{ registry_ui_version }}" + ... diff --git a/roles/registry_ui/tasks/main.yml b/roles/registry_ui/tasks/main.yml index 7d99bb3..21f6c55 100644 --- a/roles/registry_ui/tasks/main.yml +++ b/roles/registry_ui/tasks/main.yml @@ -5,8 +5,6 @@ - name: download ansible.builtin.include_tasks: download.yml - when: - - not stat_registry_ui_binary.stat.exists - name: install ansible.builtin.include_tasks: install.yml diff --git a/roles/registry_ui/tasks/prepare.yml b/roles/registry_ui/tasks/prepare.yml index e5774d4..7c16e63 100644 --- a/roles/registry_ui/tasks/prepare.yml +++ b/roles/registry_ui/tasks/prepare.yml @@ -36,81 +36,4 @@ when: - registry_ui_requirements | default([]) | count > 0 -- name: get latest release - delegate_to: localhost - become: false - run_once: true - when: - - registry_ui_version == "latest" - block: - - name: get latest release - delegate_to: localhost - become: false - run_once: true - bodsch.scm.github_latest: - project: bodsch - repository: docker-registry-ui - user: "{{ lookup('env', 'GH_USER') | default(omit) }}" - password: "{{ lookup('env', 'GH_TOKEN') | default(omit) }}" - register: _latest_release - - - name: re-define registry_ui_version - ansible.builtin.set_fact: - registry_ui_version: "{{ _latest_release.latest_release }}" - -- name: detect installed registry-ui binary - ansible.builtin.stat: - path: "{{ registry_ui_install_path }}/registry-ui" - register: stat_registry_ui_binary - -- name: create download directory - become: false - delegate_to: "{{ registry_ui_delegate_to }}" - ansible.builtin.file: - path: "{{ registry_ui_local_tmp_directory }}" - state: directory - mode: 0750 - -- name: user and group handling - when: - - registry_ui_system_user != "root" or registry_ui_system_group != "root" - block: - - name: create registry group - ansible.builtin.group: - name: "{{ registry_ui_system_group }}" - state: present - system: true - when: - - registry_ui_system_group != "root" - - - name: create registry user - ansible.builtin.user: - name: "{{ registry_ui_system_user }}" - groups: "{{ registry_ui_system_group }}" - append: true - shell: /usr/sbin/nologin - system: true - createhome: false - home: "{{ registry_ui_data_dir }}" - when: - - registry_ui_system_user != "root" - -- name: create install directory - ansible.builtin.file: - path: "{{ registry_ui_install_path }}" - state: directory - owner: "{{ registry_ui_system_user }}" - group: "{{ registry_ui_system_group }}" - mode: 0755 - -- name: merge registry configuration between defaults and custom - ansible.builtin.set_fact: - registry_ui_service: "{{ registry_ui_defaults_service | combine(registry_ui_service, recursive=True) }}" - registry_ui_listen: "{{ registry_ui_defaults_listen | combine(registry_ui_listen, recursive=True) }}" - registry_ui_registry: "{{ registry_ui_defaults_registry | combine(registry_ui_registry, recursive=True) }}" - registry_ui_event: "{{ registry_ui_defaults_event | combine(registry_ui_event, recursive=True) }}" - registry_ui_cache: "{{ registry_ui_defaults_cache | combine(registry_ui_cache, recursive=True) }}" - registry_ui_admins: "{{ registry_ui_defaults_admins | combine(registry_ui_admins, recursive=True) }}" - registry_ui_purge: "{{ registry_ui_defaults_purge | combine(registry_ui_purge, recursive=True) }}" - ... diff --git a/roles/registry_ui/tasks/service.yml b/roles/registry_ui/tasks/service.yml index 7b375f8..9f4062b 100644 --- a/roles/registry_ui/tasks/service.yml +++ b/roles/registry_ui/tasks/service.yml @@ -1,5 +1,8 @@ --- +- name: flush handlers + ansible.builtin.meta: flush_handlers + - name: ensure registry-ui is enabled on boot become: true ansible.builtin.service: diff --git a/roles/registry_ui/templates/registry-ui.j2 b/roles/registry_ui/templates/registry-ui.j2 index 5230be9..bb3de63 100644 --- a/roles/registry_ui/templates/registry-ui.j2 +++ b/roles/registry_ui/templates/registry-ui.j2 @@ -21,7 +21,10 @@ Usage of registry-ui: dry-run for purging task, does not delete anything -log-level string logging level (default "info") + -purge-exclude-repos string + comma-separated list of repos to skip from purging tags, otherwise none + -purge-include-repos string + comma-separated list of repos to purge tags from, otherwise all -purge-tags purge old tags instead of running a web server - #} diff --git a/roles/registry_ui/templates/registry-ui/config.yml.j2 b/roles/registry_ui/templates/registry-ui/config.yml.j2 index 15ea4b2..5d66592 100644 --- a/roles/registry_ui/templates/registry-ui/config.yml.j2 +++ b/roles/registry_ui/templates/registry-ui/config.yml.j2 @@ -1,5 +1,8 @@ #jinja2: trim_blocks: True, lstrip_blocks: True +--- # {{ ansible_managed }} +# registry-ui version: {{ registry_ui_version }} +{# https://github.com/bodsch/docker-registry-ui/blob/master/config.yml #} {% if registry_ui_listen is defined and registry_ui_listen | count > 0 %} @@ -7,6 +10,193 @@ listen_addr: {{ registry_ui_listen.address | default('127.0.0.1') }}:{{ registry_ui_listen.port | default('8000') }} {% endif %} +{% if registry_ui_version is version("0.10", ">=") %} +uri_base_path: {{ registry_ui_base_path }} +{% if registry_ui_performance is defined and + registry_ui_performance | count > 0 %} + +# Background tasks. +performance: + {% if registry_ui_performance.catalog_page_size is defined and + registry_ui_performance.catalog_page_size | string | length > 0 %} + # Catalog list page size. It depends from the underlying storage performance. + catalog_page_size: {{ registry_ui_performance.catalog_page_size }} + {% endif %} + {% if registry_ui_performance.catalog_refresh_interval is defined and + registry_ui_performance.catalog_refresh_interval | string | length > 0 %} + # Catalog (repo list) refresh interval in minutes. + # If set to 0 it will never refresh but will run once. + catalog_refresh_interval: {{ registry_ui_performance.catalog_refresh_interval }} + {% endif %} + {% if registry_ui_performance.tags_count_refresh_interval is defined and + registry_ui_performance.tags_count_refresh_interval | string | length > 0 %} + # Tags counting refresh interval in minutes. + # If set to 0 it will never run. This is fast operation. + tags_count_refresh_interval: {{ registry_ui_performance.tags_count_refresh_interval }} + {% endif %} +{% endif %} +{% if registry_ui_registry is defined and + registry_ui_registry | count > 0 %} + +registry: + {% if registry_ui_registry.hostname is defined and + registry_ui_registry.hostname | string | length > 0 %} + # Registry hostname (without protocol but may include port). + hostname: {{ registry_ui_registry.hostname }} + {% endif %} + {% if registry_ui_registry.insecure is defined and + registry_ui_registry.insecure %} + # Allow to access non-https enabled registry. + insecure: {{ registry_ui_registry.insecure | bool | bodsch.core.config_bool(true_as='true', false_as='false') }} + {% endif %} + # Registry credentials. + # They need to have a full access to the registry. + # If token authentication service is enabled, it will be auto-discovered and those credentials + # will be used to obtain access tokens. + {% if registry_ui_registry.username is defined and + registry_ui_registry.username | string | length > 0 %} + username: {{ registry_ui_registry.username }} + {% endif %} + {% if registry_ui_registry.password is defined and + registry_ui_registry.password | string | length > 0 %} + password: {{ registry_ui_registry.password }} + {% endif %} + {% if registry_ui_registry.password_file is defined and + registry_ui_registry.password_file | string | length > 0 %} + # Set password to '' in order to read it from the file below. Otherwise, it is ignored. + password_file: {{ registry_ui_registry.password_file }} + {% else %} + password_file: '' + {% endif %} + {% if registry_ui_registry.auth_with_keychain is defined and + registry_ui_registry.auth_with_keychain %} + # Alternatively, you can do auth with Keychain, useful for local development. + # When enabled the above credentials will not be used. + auth_with_keychain: {{ registry_ui_registry.auth_with_keychain | bool | bodsch.core.config_bool(true_as='true', false_as='false') }} + {% endif %} +{% endif %} +{% if registry_ui_access_control is defined and + registry_ui_access_control | count > 0 %} + +# UI access management. +access_control: + {% if registry_ui_access_control.anyone_can_view_events is defined and + registry_ui_access_control.anyone_can_view_events | string | length > 0 %} + # Whether users can the event log. Otherwise, only admins listed below. + anyone_can_view_events: {{ registry_ui_access_control.anyone_can_view_events | bool | bodsch.core.config_bool(true_as='true', false_as='false') }} + {% endif %} + {% if registry_ui_access_control.anyone_can_delete_tags is defined and + registry_ui_access_control.anyone_can_delete_tags | string | length > 0 %} + # Whether users can delete tags. Otherwise, only admins listed below. + anyone_can_delete_tags: {{ registry_ui_access_control.anyone_can_delete_tags | bool | bodsch.core.config_bool(true_as='true', false_as='false') }} + {% endif %} + {% if registry_ui_access_control.admins is defined and + registry_ui_access_control.admins | count > 0 %} + # The list of users to do everything. + # User identifier should be set via X-WEBAUTH-USER header from your proxy + # because registry UI itself does not employ any auth. + admins: [] + {% endif %} +{% endif %} +{% if registry_ui_event_listener is defined and + registry_ui_event_listener | count > 0 %} + +# Event listener configuration. +event_listener: + {% if registry_ui_event_listener.bearer_token is defined and + registry_ui_event_listener.bearer_token | string | length > 0 %} + # The same token should be configured on Docker registry as Authorization Bearer token. + bearer_token: xxx + {% endif %} + {% if registry_ui_event_listener.retention_days is defined and + registry_ui_event_listener.retention_days | string | length > 0 %} + # Retention of records to keep. + retention_days: {{ registry_ui_event_listener.retention_days }} + {% endif %} + {% if registry_ui_event_listener.database is defined and + registry_ui_event_listener.database | count > 0 and + registry_ui_event_listener.database.driver is defined and + registry_ui_event_listener.database.driver | string | length > 0 %} + # Event listener storage. + # database_driver: sqlite3 + # database_location: data/registry_events.db + # database_driver: mysql + # database_location: user:password@tcp(localhost:3306)/docker_events + {% if registry_ui_event_listener.database.driver in ["sqlite3", "mysql"] %} + {% if registry_ui_event_listener.database.driver == "sqlite3" %} + # Event listener storage. + database_driver: sqlite3 + {% set _database_location = registry_ui_data_dir ~ "/registry_events.db" %} + {% if registry_ui_event_listener.database.location is defined and + registry_ui_event_listener.database.location | string | length > 0 %} + {% set _database_location = registry_ui_event_listener.database.location %} + {% endif %} + database_location: {{ _database_location }} + {% endif %} + {% if registry_ui_event_listener.database.driver == "mysql" %} + database_driver: mysql + {% if registry_ui_event_listener.database.username is defined and + registry_ui_event_listener.database.username | string | length > 0 and + registry_ui_event_listener.database.password is defined and + registry_ui_event_listener.database.password | string | length > 0 %} + # user:password@tcp(localhost:3306)/docker_events + database_location: {{ registry_ui_event_listener.database.username }}:{{ registry_ui_event_listener.database.password }}@tcp({{ registry_ui_event_listener.database.hostname | default('127.0.0.1:3306') }})/{{ registry_ui_event_listener.database.schemaname }} + {% endif %} + {% endif%} + {% endif %} + {% endif %} + {% if registry_ui_event_listener.deletion_enabled is defined and + registry_ui_event_listener.deletion_enabled | string | length > 0 %} + # You can disable event deletion on some hosts when you are running registry UI on MySQL master-master or + # cluster setup to avoid deadlocks or replication breaks. + deletion_enabled: {{ registry_ui_event_listener.deletion_enabled | bool | bodsch.core.config_bool(true_as='true', false_as='false') }} + {% endif %} +{% endif %} +{% if registry_ui_purge_tags is defined and + registry_ui_purge_tags | count > 0 %} + +# Options for tag purging. +purge_tags: + {% if registry_ui_purge_tags.keep_days is defined and + registry_ui_purge_tags.keep_days | string | length > 0 %} + # How many days to keep tags but also keep the minimal count provided no matter how old. + keep_days: {{ registry_ui_purge_tags.keep_days }} + {% endif %} + {% if registry_ui_purge_tags.keep_count is defined and + registry_ui_purge_tags.keep_count | string | length > 0 %} + keep_count: 10 + {% endif %} + {% if registry_ui_purge_tags.keep_regexp is defined and + registry_ui_purge_tags.keep_regexp | string | length > 0 %} + # Keep tags matching regexp no matter how old, e.g. '^latest$' + # Empty string disables this feature. + keep_regexp: '{{ registry_ui_purge_tags.keep_regexp }}' + {% else %} + keep_regexp: '' + {% endif %} + {% if registry_ui_purge_tags.keep_from_file is defined and + registry_ui_purge_tags.keep_from_file | string | length > 0 %} + # Keep tags listed in the file no matter how old. + # File format is JSON: {"repo1": ["tag1", "tag2"], "repoX": ["tagX"]} + # Empty string disables this feature. + keep_from_file: '' + {% else %} + keep_from_file: '' + {% endif %} +{% endif %} +{% if registry_ui_debug is defined and + registry_ui_debug | count > 0 %} + +# Debug mode. +debug: + {% if registry_ui_debug.templates is defined and + registry_ui_debug.templates | string | length > 0 %} + # Affects only templates. + templates: {{ registry_ui_debug.templates | bool | bodsch.core.config_bool(true_as='true', false_as='false') }} + {% endif %} +{% endif %} + +{% else %} {% if registry_ui_base_path is defined and registry_ui_base_path | string | length > 0 %} # Base path of Docker Registry UI. @@ -157,3 +347,5 @@ purge_tags_keep_from_file: {{ registry_ui_purge.tags_keep_from_file }} purge_tags_schedule: "{{ registry_ui_purge.tags_schedule }}" {% endif %} {% endif %} + +{% endif %} diff --git a/roles/registry_ui/vars/main.yml b/roles/registry_ui/vars/main.yml index 2c488d5..61baa6b 100644 --- a/roles/registry_ui/vars/main.yml +++ b/roles/registry_ui/vars/main.yml @@ -25,12 +25,63 @@ registry_ui_defaults_listen: registry_ui_defaults_base_path: /ui +registry_ui_defaults_performance: + catalog_page_size: 100 + catalog_refresh_interval: 10 + tags_count_refresh_interval: 60 + registry_ui_defaults_registry: - url: https://docker-registry.local:5000 - verify_tls: true - username: "" # user - password: "" # pass - password_file: "" # /run/secrets/registry_password_file + hostname: docker-registry.local + insecure: false + username: "" + password: "" + password_file: "" + auth_with_keychain: "" # false + +registry_ui_defaults_access_control: + # Whether users can the event log. Otherwise, only admins listed below. + anyone_can_view_events: true + # Whether users can delete tags. Otherwise, only admins listed below. + anyone_can_delete_tags: false + # The list of users to do everything. + # User identifier should be set via X-WEBAUTH-USER header from your proxy + # because registry UI itself does not employ any auth. + admins: [] + +registry_ui_defaults_event_listener: + bearer_token: "" + retention_days: 7 + database: + driver: sqlite3 # sqlite3 or mysql + location: "" + username: "" + password: "" + hostname: 127.0.0.1:3306 + schemaname: docker_events + deletion_enabled: true + +registry_ui_defaults_purge_tags: + # How many days to keep tags but also keep the minimal count provided no matter how old. + keep_days: 90 + keep_count: 10 + # Keep tags matching regexp no matter how old, e.g. '^latest$' + # Empty string disables this feature. + keep_regexp: '' + # Keep tags listed in the file no matter how old. + # File format is JSON: {"repo1": ["tag1", "tag2"], "repoX": ["tagX"]} + # Empty string disables this feature. + keep_from_file: '' + +registry_ui_defaults_debug: + # Affects only templates. + templates: false + +# registry_ui_defaults_registry: +# url: https://docker-registry.local:5000 +# verify_tls: true +# username: "" # user +# password: "" # pass +# password_file: "" # /run/secrets/registry_password_file registry_ui_defaults_event: listener_token: "" # token @@ -63,8 +114,15 @@ registry_ui_defaults_purge: # ---------------------------------------------------------------------------------------- -registry_ui_archive: "registry-ui-{{ registry_ui_version }}-{{ ansible_facts.system }}-{{ system_architecture }}.tar.gz" -registry_ui_checksum_url: "{{ registry_ui_release_download_url }}/download/{{ registry_ui_version }}/{{ registry_ui_archive }}.sha256" +registry_ui_defaults_release: + # https://github.com/oliver006/redis_exporter/releases/download/v1.56.0/redis_exporter-v1.56.0.linux-amd64.tar.gz + download_url: https://github.com/bodsch/docker-registry-ui/releases + file: registry-ui-{{ registry_ui_version }}-{{ ansible_facts.system | lower }}-{{ system_architecture }}.tar.gz + # checksum_file: "{{ registry_ui_release_download_url }}/download/{{ registry_ui_version }}/{{ registry_ui_archive }}.sha256" + binary: registry-ui + +# registry_ui_archive: "registry-ui-{{ registry_ui_version }}-{{ ansible_facts.system }}-{{ system_architecture }}.tar.gz" +# : "{{ registry_ui_release_download_url }}/download/{{ registry_ui_version }}/{{ registry_ui_archive }}.sha256" registry_ui_defaults_directory: /etc/default