├── .gitattributes ├── .gitignore ├── README.md ├── debian ├── changelog ├── compat ├── control ├── copyright ├── install ├── postinst ├── postrm ├── rules ├── source │ └── format └── triggers ├── etc └── logrotate.d │ └── omv-compose-command ├── srv └── salt │ └── omv │ └── deploy │ └── compose │ ├── 10compose.sls │ ├── 20dockerfile.sls │ ├── 30docker.sls │ ├── 40job.sls │ ├── default.sls │ ├── files │ ├── backup.j2 │ ├── compose_cnf.j2 │ ├── compose_env_yml.j2 │ ├── compose_yml.j2 │ ├── dockerfile.j2 │ ├── dockerfile_conf.j2 │ ├── dockerfile_script.j2 │ ├── global_env_yml.j2 │ ├── override_yml.j2 │ ├── prune.j2 │ ├── start.j2 │ ├── stop.j2 │ └── update.j2 │ └── init.sls └── usr ├── bin └── autocompose.py ├── sbin ├── omv-compose-backup ├── omv-compose-backup-multi ├── omv-compose-download-icons ├── omv-compose-init-git ├── omv-compose-prune ├── omv-compose-restore ├── omv-compose-restore-multi ├── omv-compose-start ├── omv-compose-start-multi ├── omv-compose-stop ├── omv-compose-stop-multi ├── omv-compose-update └── omv-compose-update-multi └── share └── openmediavault ├── confdb ├── create.d │ └── conf.service.compose.sh └── migrations.d │ ├── conf.service.compose_6.0.4.sh │ ├── conf.service.compose_6.11.sh │ ├── conf.service.compose_6.4.sh │ ├── conf.service.compose_6.7.sh │ ├── conf.service.compose_6.9.1.sh │ ├── conf.service.compose_6.9.2.sh │ ├── conf.service.compose_6.9.6.sh │ ├── conf.service.compose_6.9.sh │ ├── conf.service.compose_7.0.2.sh │ ├── conf.service.compose_7.0.8.sh │ ├── conf.service.compose_7.1.4.sh │ ├── conf.service.compose_7.2.4.sh │ ├── conf.service.compose_7.2.5.sh │ ├── conf.service.compose_7.2.8.sh │ ├── conf.service.compose_7.2.sh │ ├── conf.service.compose_7.3.sh │ ├── conf.service.compose_7.4.3.sh │ ├── conf.service.compose_7.5.0.sh │ ├── conf.service.compose_7.5.3.sh │ ├── conf.service.compose_7.6.0.sh │ ├── conf.service.compose_7.6.2.sh │ └── conf.service.compose_7.6.3.sh ├── datamodels ├── conf.service.compose.config.json ├── conf.service.compose.dockerfile.json ├── conf.service.compose.file.json ├── conf.service.compose.globalenv.json ├── conf.service.compose.job.json ├── conf.service.compose.json └── rpc.compose.json ├── engined ├── inc │ └── 90composebackup.inc ├── module │ ├── compose.inc │ └── composeterm.inc └── rpc │ └── compose.inc ├── locale ├── ach │ └── openmediavault-compose.po ├── ady │ └── openmediavault-compose.po ├── ar_SA │ └── openmediavault-compose.po ├── bg │ └── openmediavault-compose.po ├── ca_ES │ └── openmediavault-compose.po ├── cs_CZ │ └── openmediavault-compose.po ├── da_DA │ └── openmediavault-compose.po ├── de_DE │ └── openmediavault-compose.po ├── en_GB │ └── openmediavault-compose.po ├── es_CO │ └── openmediavault-compose.po ├── es_ES │ └── openmediavault-compose.po ├── eu │ └── openmediavault-compose.po ├── fi │ └── openmediavault-compose.po ├── fr_FR │ └── openmediavault-compose.po ├── gl │ └── openmediavault-compose.po ├── hu │ └── openmediavault-compose.po ├── hu_HU │ └── openmediavault-compose.po ├── it_IT │ └── openmediavault-compose.po ├── ja_JP │ └── openmediavault-compose.po ├── jv │ └── openmediavault-compose.po ├── ko_KR │ └── openmediavault-compose.po ├── nl_BE │ └── openmediavault-compose.po ├── nl_NL │ └── openmediavault-compose.po ├── no_NO │ └── openmediavault-compose.po ├── oc │ └── openmediavault-compose.po ├── openmediavault-compose.pot ├── pl │ └── openmediavault-compose.po ├── pl_PL │ └── openmediavault-compose.po ├── pt │ └── openmediavault-compose.po ├── pt_BR │ └── openmediavault-compose.po ├── ru_RU │ └── openmediavault-compose.po ├── sl_SI │ └── openmediavault-compose.po ├── sv_SV │ └── openmediavault-compose.po ├── tr │ └── openmediavault-compose.po ├── uk_UK │ └── openmediavault-compose.po ├── zh_CN │ └── openmediavault-compose.po └── zh_TW │ └── openmediavault-compose.po └── workbench ├── component.d ├── omv-services-compose-configs-datatable-page.yaml ├── omv-services-compose-configs-form-page.yaml ├── omv-services-compose-containers-datatable-page.yaml ├── omv-services-compose-dockerfiles-datatable-page.yaml ├── omv-services-compose-dockerfiles-form-page.yaml ├── omv-services-compose-files-datatable-page.yaml ├── omv-services-compose-files-example-form-page.yaml ├── omv-services-compose-files-form-page.yaml ├── omv-services-compose-files-global-form-page.yaml ├── omv-services-compose-files-url-form-page.yaml ├── omv-services-compose-images-datatable-page.yaml ├── omv-services-compose-navigation-page.yaml ├── omv-services-compose-networks-datatable-page.yaml ├── omv-services-compose-networks-form-page.yaml ├── omv-services-compose-repos-datatable-page.yaml ├── omv-services-compose-restore-datatable-page.yaml ├── omv-services-compose-schedule-datatable-page.yaml ├── omv-services-compose-schedule-form-page.yaml ├── omv-services-compose-services-datatable-page.yaml ├── omv-services-compose-settings-form-page.yaml ├── omv-services-compose-stats-datatable-page.yaml └── omv-services-compose-volumes-datatable-page.yaml ├── dashboard.d ├── containers.yaml ├── containers_grid.yaml └── containers_term.yaml ├── log.d ├── omv-compose-backup.yaml ├── omv-compose-restore.yaml ├── omv-compose-start.yaml ├── omv-compose-stop.yaml └── omv-compose-update.yaml ├── navigation.d ├── services.compose.configs.yaml ├── services.compose.containers.yaml ├── services.compose.dockerfiles.yaml ├── services.compose.files.yaml ├── services.compose.images.yaml ├── services.compose.networks.yaml ├── services.compose.repos.yaml ├── services.compose.restore.yaml ├── services.compose.schedule.yaml ├── services.compose.services.yaml ├── services.compose.settings.yaml ├── services.compose.stats.yaml ├── services.compose.volumes.yaml └── services.compose.yaml └── route.d ├── services.compose.configs.create.yaml ├── services.compose.configs.edit.yaml ├── services.compose.configs.yaml ├── services.compose.containers.yaml ├── services.compose.dockerfiles.create.yaml ├── services.compose.dockerfiles.edit.yaml ├── services.compose.dockerfiles.yaml ├── services.compose.examples.create.yaml ├── services.compose.files.create.yaml ├── services.compose.files.edit.yaml ├── services.compose.files.global.yaml ├── services.compose.files.yaml ├── services.compose.images.yaml ├── services.compose.networks.create.yaml ├── services.compose.networks.yaml ├── services.compose.repos.yaml ├── services.compose.restore.yaml ├── services.compose.schedule.create.yaml ├── services.compose.schedule.edit.yaml ├── services.compose.schedule.yaml ├── services.compose.services.yaml ├── services.compose.settings.yaml ├── services.compose.stats.yaml ├── services.compose.url.create.yaml ├── services.compose.volumes.yaml └── services.compose.yaml /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | 3 | *.gif binary 4 | *.jpg binary 5 | *.png binary 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # General 2 | *.tmp 3 | *.bak 4 | *.swp 5 | *~ 6 | 7 | # Eclipse 8 | .project 9 | .metadata 10 | .settings/ 11 | *.launch 12 | .buildpath 13 | 14 | # Sublime Text 15 | *.sublime-workspace 16 | *.sublime-project 17 | 18 | # Vim 19 | [._]*.s[a-w][a-z] 20 | [._]s[a-w][a-z] 21 | *.un~ 22 | Session.vim 23 | .netrwhist 24 | 25 | # SVN 26 | .svn/ 27 | 28 | # Mac 29 | .DS_Store 30 | .AppleDouble 31 | .LSOverride 32 | 33 | # Windows 34 | Thumbs.db 35 | ehthumbs.db 36 | Desktop.ini 37 | 38 | # OpenMediaVault / Debian 39 | debian/openmediavault-* 40 | debian/files 41 | debian/*.debhelper.log 42 | debian/*.debhelper 43 | debian/*substvars 44 | debian/debhelper-build-stamp 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | openmediavault-compose 2 | ====================== 3 | 4 | docker-compose plugin for OpenMediaVault 5 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 13 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: openmediavault-compose 2 | Section: net 3 | XB-Plugin-Section: utilities 4 | Priority: optional 5 | Maintainer: OpenMediaVault Plugin Developers 6 | Build-Depends: debhelper (>= 13 ) 7 | Standards-Version: 4.3.0 8 | Homepage: http://omv-extras.org/ 9 | 10 | Package: openmediavault-compose 11 | Architecture: all 12 | Depends: openmediavault (>= 7.7.6), 13 | openmediavault-cterm (>= 7.8), 14 | openmediavault-omvextrasorg (>= 7), 15 | openmediavault-sharerootfs, 16 | python3-docker, 17 | python3-pretty-yaml, 18 | ${misc:Depends} 19 | Recommends: docker-ce (>= 27.2.1), 20 | docker-compose-plugin (>= 2.29.2) 21 | Description: OpenMediaVault compose plugin 22 | This plugin enhances OpenMediaVault by providing a comprehensive solution for managing 23 | Docker containers and their resources. Key features include: 24 | . 25 | * Docker-Compose Management: Maintain and execute Docker Compose files. 26 | * Automated Backups: Schedule regular backups of containers to ensure data integrity. 27 | * Backup Restoration: Restore backups to minimize downtime. 28 | * Cleanup Automation: Automatically purge outdated images, containers, and resources. 29 | * Container Monitoring: Access statistics on running containers. 30 | * Image Status Tracking: Monitor image statuses and relevant metrics. 31 | * Network Management: Create and manage Docker networks. 32 | * Log Viewing: View logs for your containers. 33 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: http://dep.debian.net/deps/dep5 2 | Upstream-Contact: OpenMediaVault Plugin Developers 3 | Copyright: 2022-2025 openmediavault plugin developers 4 | License: GPL-3 5 | -------------------------------------------------------------------------------- /debian/install: -------------------------------------------------------------------------------- 1 | etc/* etc 2 | usr/bin/* usr/bin 3 | usr/sbin/* usr/sbin 4 | usr/share/openmediavault/* usr/share/openmediavault 5 | srv/* srv 6 | -------------------------------------------------------------------------------- /debian/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | . /etc/default/openmediavault 6 | . /usr/share/openmediavault/scripts/helper-functions 7 | 8 | case "$1" in 9 | configure) 10 | # Activate package triggers. 11 | dpkg-trigger update-workbench 12 | 13 | # remove cache files 14 | rm -f /var/cache/openmediavault/compose_cache_* 15 | 16 | # Initialize and migrate configuration database. 17 | echo "Updating configuration database ..." 18 | omv-confdbadm create "conf.service.compose" 19 | if [ -n "$2" ]; then 20 | omv-confdbadm migrate "conf.service.compose" "${2}" 21 | fi 22 | 23 | # clear cache 24 | find /var/cache/openmediavault/ -type f -name "compose_cache_*" 25 | ;; 26 | 27 | abort-upgrade|abort-remove|abort-deconfigure) 28 | ;; 29 | 30 | *) 31 | echo "postinst called with unknown argument '$1'" >&2 32 | exit 1 33 | ;; 34 | esac 35 | 36 | exit 0 37 | -------------------------------------------------------------------------------- /debian/postrm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | . /etc/default/openmediavault 6 | . /usr/share/openmediavault/scripts/helper-functions 7 | 8 | remove_action() { 9 | dpkg-trigger update-workbench 10 | } 11 | 12 | case "$1" in 13 | purge) 14 | remove_action 15 | # Remove the configuration data 16 | omv_config_delete "/config/services/compose" 17 | ;; 18 | 19 | remove) 20 | remove_action 21 | ;; 22 | 23 | upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) 24 | ;; 25 | 26 | *) 27 | echo "postrm called with unknown argument '$1'" >&2 28 | exit 1 29 | ;; 30 | esac 31 | 32 | exit 0 33 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | %: 4 | dh $@ 5 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (native) 2 | -------------------------------------------------------------------------------- /debian/triggers: -------------------------------------------------------------------------------- 1 | activate restart-engined 2 | -------------------------------------------------------------------------------- /etc/logrotate.d/omv-compose-command: -------------------------------------------------------------------------------- 1 | /var/log/omv-compose-backup.log 2 | /var/log/omv-compose-restore.log 3 | /var/log/omv-compose-update.log 4 | /var/log/omv-compose-start.log 5 | /var/log/omv-compose-stop.log 6 | { 7 | monthly 8 | missingok 9 | rotate 12 10 | compress 11 | notifempty 12 | } 13 | -------------------------------------------------------------------------------- /srv/salt/omv/deploy/compose/10compose.sls: -------------------------------------------------------------------------------- 1 | # @license http://www.gnu.org/licenses/gpl.html GPL Version 3 2 | # @author OpenMediaVault Plugin Developers 3 | # @copyright Copyright (c) 2022-2025 openmediavault plugin developers 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | {% set config = salt['omv_conf.get']('conf.service.compose') %} 19 | {% if config.sharedfolderref | length > 0 %} 20 | {% set sfpath = salt['omv_conf.get_sharedfolder_path'](config.sharedfolderref).rstrip('/') %} 21 | {% set datapath = "" %} 22 | {% if config.datasharedfolderref | string | length > 1 %} 23 | {% set datapath = salt['omv_conf.get_sharedfolder_path'](config.datasharedfolderref).rstrip('/') %} 24 | {% if not salt['file.directory_exists'](datapath) %} 25 | {% set datapath = "" %} 26 | {% endif %} 27 | {% endif %} 28 | 29 | {% for file in config.files.file %} 30 | {% set composeDir = sfpath ~ '/' ~ file.name %} 31 | {% set composeFile = composeDir ~ '/' ~ file.name ~ '.yml' %} 32 | {% set overrideFile = composeDir ~ '/compose.override.yml' %} 33 | {% set envFile = composeDir ~ '/' ~ file.name ~ '.env' %} 34 | 35 | configure_compose_file_dir_{{ file.name }}: 36 | file.directory: 37 | - name: "{{ composeDir }}" 38 | - user: "{{ config.composeowner }}" 39 | - group: "{{ config.composegroup }}" 40 | - mode: "{{ config.mode }}" 41 | - makedirs: True 42 | 43 | configure_compose_{{ file.name }}_file: 44 | file.managed: 45 | - name: '{{ composeFile }}' 46 | - source: 47 | - salt://{{ tpldir }}/files/compose_yml.j2 48 | - context: 49 | file: {{ file | json }} 50 | datapath: {{ datapath }} 51 | - template: jinja 52 | - user: "{{ config.composeowner }}" 53 | - group: "{{ config.composegroup }}" 54 | - mode: "{{ config.fileperms }}" 55 | 56 | configure_compose_{{ file.name }}_override: 57 | file.managed: 58 | - name: '{{ overrideFile }}' 59 | - source: 60 | - salt://{{ tpldir }}/files/override_yml.j2 61 | - context: 62 | file: {{ file | json }} 63 | datapath: {{ datapath }} 64 | - template: jinja 65 | - user: "{{ config.composeowner }}" 66 | - group: "{{ config.composegroup }}" 67 | - mode: "{{ config.fileperms }}" 68 | 69 | configure_compose_env_{{ file.name }}_file: 70 | file.managed: 71 | - name: '{{ envFile }}' 72 | - source: 73 | - salt://{{ tpldir }}/files/compose_env_yml.j2 74 | - context: 75 | file: {{ file | json }} 76 | datapath: {{ datapath }} 77 | - template: jinja 78 | - user: "{{ config.composeowner }}" 79 | - group: "{{ config.composegroup }}" 80 | - mode: "{{ config.fileperms }}" 81 | 82 | {%- for cnf in config.configs.config | selectattr("fileref", "equalto", file.uuid) %} 83 | 84 | {% set cnfFile = composeDir ~ '/' ~ cnf.name %} 85 | 86 | configure_compose_{{ file.name }}_config_{{ cnf.uuid }}: 87 | file.managed: 88 | - name: '{{ cnfFile }}' 89 | - source: 90 | - salt://{{ tpldir }}/files/compose_cnf.j2 91 | - context: 92 | file: {{ cnf | json }} 93 | - template: jinja 94 | - user: "{{ config.composeowner }}" 95 | - group: "{{ config.composegroup }}" 96 | - mode: "{{ config.fileperms }}" 97 | 98 | {% endfor %} 99 | {% endfor %} 100 | 101 | {% set globalenv = salt['omv_conf.get']('conf.service.compose.globalenv') %} 102 | {% set globalEnvFile = sfpath ~ '/global.env' %} 103 | 104 | {% if globalenv.enabled | to_bool %} 105 | 106 | configure_compose_global_env_file: 107 | file.managed: 108 | - name: '{{ globalEnvFile }}' 109 | - source: 110 | - salt://{{ tpldir }}/files/global_env_yml.j2 111 | - context: 112 | globalenv: {{ globalenv | json }} 113 | datapath: {{ datapath }} 114 | - template: jinja 115 | - user: "{{ config.composeowner }}" 116 | - group: "{{ config.composegroup }}" 117 | - mode: "{{ config.fileperms }}" 118 | 119 | {% else %} 120 | 121 | {% set datapath = "" %} 122 | remove_compose_global_env_file: 123 | file.absent: 124 | - name: '{{ globalEnvFile }}' 125 | 126 | {% endif %} 127 | {% endif %} 128 | -------------------------------------------------------------------------------- /srv/salt/omv/deploy/compose/20dockerfile.sls: -------------------------------------------------------------------------------- 1 | # @license http://www.gnu.org/licenses/gpl.html GPL Version 3 2 | # @author OpenMediaVault Plugin Developers 3 | # @copyright Copyright (c) 2022-2025 openmediavault plugin developers 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | {% set config = salt['omv_conf.get']('conf.service.compose') %} 19 | {% if config.sharedfolderref | length > 0 %} 20 | {% set sfpath = salt['omv_conf.get_sharedfolder_path'](config.sharedfolderref).rstrip('/') %} 21 | 22 | {% for file in config.dockerfiles.dockerfile %} 23 | {% set dockerfileDir = sfpath ~ '/' ~ file.name %} 24 | {% set dockerFile = dockerfileDir ~ '/Dockerfile' %} 25 | 26 | configure_compose_dockerfile_dir_{{ file.name }}: 27 | file.directory: 28 | - name: "{{ dockerfileDir }}" 29 | - user: "{{ config.composeowner }}" 30 | - group: "{{ config.composegroup }}" 31 | - mode: "{{ config.mode }}" 32 | - makedirs: True 33 | 34 | configure_dockerfile_{{ dockerFile }}: 35 | file.managed: 36 | - name: '{{ dockerFile }}' 37 | - source: 38 | - salt://{{ tpldir }}/files/dockerfile.j2 39 | - context: 40 | file: {{ file | json }} 41 | - template: jinja 42 | - user: "{{ config.composeowner }}" 43 | - group: "{{ config.composegroup }}" 44 | - mode: "{{ config.fileperms }}" 45 | 46 | {% if file.script | length > 0 %} 47 | {% set scriptFile = dockerfileDir ~ '/' ~ file.script %} 48 | 49 | configure_dockerfile_script_{{ scriptFile }}: 50 | file.managed: 51 | - name: '{{ scriptFile }}' 52 | - source: 53 | - salt://{{ tpldir }}/files/dockerfile_script.j2 54 | - context: 55 | file: {{ file | json }} 56 | - template: jinja 57 | - user: "{{ config.composeowner }}" 58 | - group: "{{ config.composegroup }}" 59 | - mode: "{{ config.fileperms }}" 60 | 61 | {% endif %} 62 | 63 | {% if file.conf | length > 0 %} 64 | {% set confFile = dockerfileDir ~ '/' ~ file.conf %} 65 | 66 | configure_dockerfile_conf_{{ confFile }}: 67 | file.managed: 68 | - name: '{{ confFile }}' 69 | - source: 70 | - salt://{{ tpldir }}/files/dockerfile_conf.j2 71 | - context: 72 | file: {{ file | json }} 73 | - template: jinja 74 | - user: "{{ config.composeowner }}" 75 | - group: "{{ config.composegroup }}" 76 | - mode: "{{ config.fileperms }}" 77 | 78 | {% endif %} 79 | 80 | {% endfor %} 81 | {% endif %} 82 | -------------------------------------------------------------------------------- /srv/salt/omv/deploy/compose/30docker.sls: -------------------------------------------------------------------------------- 1 | # @license http://www.gnu.org/licenses/gpl.html GPL Version 3 2 | # @author OpenMediaVault Plugin Developers 3 | # @copyright Copyright (c) 2022-2025 openmediavault plugin developers 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | {% set config = salt['omv_conf.get']('conf.service.compose') %} 19 | 20 | # create daemon.json file if docker storage path is specified 21 | {% if config.dockerStorage | length > 1 %} 22 | 23 | configure_etc_docker_dir: 24 | file.directory: 25 | - name: "/etc/docker" 26 | - user: "root" 27 | - group: "root" 28 | - mode: "0755" 29 | - makedirs: True 30 | 31 | /etc/docker/daemon.json: 32 | file.serialize: 33 | - dataset: 34 | data-root: "{{ config.dockerStorage }}" 35 | - serializer: json 36 | - user: root 37 | - group: root 38 | - mode: "0600" 39 | 40 | {% endif %} 41 | 42 | docker_install_packages: 43 | pkg.installed: 44 | - pkgs: 45 | - docker-ce: '>=27.2.1' 46 | 47 | docker_compose_install_packages: 48 | pkg.installed: 49 | - pkgs: 50 | - docker-compose-plugin: '>=2.29.2' 51 | - containerd.io: '>=1.7.21' 52 | - docker-ce-cli: '>=27.2.1' 53 | - docker-buildx-plugin: '>=0.16.2' 54 | 55 | docker_purged_packages: 56 | pkg.purged: 57 | - pkgs: 58 | - docker-compose 59 | - docker.io 60 | 61 | {% if config.dockerStorage | length > 1 %} 62 | 63 | docker: 64 | service.running: 65 | - enable: True 66 | - watch: 67 | - file: /etc/docker/daemon.json 68 | 69 | {% endif %} 70 | 71 | {% set mounts = salt['cmd.shell']('systemctl list-units --type=mount | awk \'$5 ~ "/srv" { printf "%s ",$1 }\'') %} 72 | {% set waitConf = '/etc/systemd/system/docker.service.d/waitAllMounts.conf' %} 73 | 74 | {{ waitConf }}: 75 | file.managed: 76 | - contents: | 77 | [Unit] 78 | After=local-fs.target {{ mounts }} 79 | - mode: "0644" 80 | - makedirs: True 81 | 82 | systemd_daemon_reload_docker: 83 | cmd.run: 84 | - name: systemctl daemon-reload 85 | - onchanges: 86 | - file: {{ waitConf }} 87 | 88 | create_usr_local_bin_dir: 89 | file.directory: 90 | - name: "/usr/local/bin" 91 | - user: root 92 | - group: root 93 | - mode: "0755" 94 | - makedirs: True 95 | -------------------------------------------------------------------------------- /srv/salt/omv/deploy/compose/40job.sls: -------------------------------------------------------------------------------- 1 | # @license http://www.gnu.org/licenses/gpl.html GPL Version 3 2 | # @author OpenMediaVault Plugin Developers 3 | # @copyright Copyright (c) 2024 OpenMediaVault Plugin Developers 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | {% set config = salt['omv_conf.get']('conf.service.compose.job') %} 19 | 20 | configure_compose_scheduled_backup: 21 | file.managed: 22 | - name: "/etc/cron.d/omv-compose-backup" 23 | - source: 24 | - salt://{{ tpldir }}/files/backup.j2 25 | - template: jinja 26 | - context: 27 | jobs: {{ config | json }} 28 | - user: root 29 | - group: root 30 | - mode: 644 31 | 32 | configure_compose_scheduled_update: 33 | file.managed: 34 | - name: "/etc/cron.d/omv-compose-update" 35 | - source: 36 | - salt://{{ tpldir }}/files/update.j2 37 | - template: jinja 38 | - context: 39 | jobs: {{ config | json }} 40 | - user: root 41 | - group: root 42 | - mode: 644 43 | 44 | configure_compose_scheduled_prune: 45 | file.managed: 46 | - name: "/etc/cron.d/omv-compose-prune" 47 | - source: 48 | - salt://{{ tpldir }}/files/prune.j2 49 | - template: jinja 50 | - context: 51 | jobs: {{ config | json }} 52 | - user: root 53 | - group: root 54 | - mode: 644 55 | 56 | configure_compose_scheduled_start: 57 | file.managed: 58 | - name: "/etc/cron.d/omv-compose-start" 59 | - source: 60 | - salt://{{ tpldir }}/files/start.j2 61 | - template: jinja 62 | - context: 63 | jobs: {{ config | json }} 64 | - user: root 65 | - group: root 66 | - mode: 644 67 | 68 | configure_compose_scheduled_stop: 69 | file.managed: 70 | - name: "/etc/cron.d/omv-compose-stop" 71 | - source: 72 | - salt://{{ tpldir }}/files/stop.j2 73 | - template: jinja 74 | - context: 75 | jobs: {{ config | json }} 76 | - user: root 77 | - group: root 78 | - mode: 644 79 | -------------------------------------------------------------------------------- /srv/salt/omv/deploy/compose/default.sls: -------------------------------------------------------------------------------- 1 | # @license http://www.gnu.org/licenses/gpl.html GPL Version 3 2 | # @author OpenMediaVault Plugin Developers 3 | # @copyright Copyright (c) 2019-2025 openmediavault plugin developers 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | {% set dirpath = '/srv/salt' | path_join(tpldir) %} 19 | 20 | include: 21 | {% for file in salt['file.readdir'](dirpath) | sort %} 22 | {% if file not in ('.', '..', 'init.sls', 'default.sls') %} 23 | {% if file.endswith('.sls') %} 24 | - .{{ file | replace('.sls', '') }} 25 | {% endif %} 26 | {% endif %} 27 | {% endfor %} 28 | -------------------------------------------------------------------------------- /srv/salt/omv/deploy/compose/files/backup.j2: -------------------------------------------------------------------------------- 1 | {%- set separator = ' ' -%} 2 | {{ pillar['headers']['multiline'] -}} 3 | SHELL=/bin/sh 4 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 5 | # m h dom mon dow user command 6 | {%- for job in jobs | selectattr('enable') | selectattr('backup') %} 7 | {% if job.execution == "exactly" -%} 8 | {% if job.everynminute | to_bool %}*/{{ job.minute }}{% else %}{{ job.minute }}{% endif -%} 9 | {{ separator }}{% if job.everynhour | to_bool %}*/{{ job.hour }}{% else %}{{ job.hour }}{% endif -%} 10 | {{ separator }}{% if job.everyndayofmonth | to_bool %}*/{{ job.dayofmonth }}{% else %}{{ job.dayofmonth }}{% endif -%} 11 | {{ separator }}{{ job.month }}{{ separator }}{{ job.dayofweek }} 12 | {%- else -%} 13 | @{{ job.execution }} 14 | {%- endif -%} 15 | {{ separator }}root omv-compose-backup-multi -f '{{ job.filter }}' -u '{{ job.uuid }}' 16 | {%- if not job.sendemail | to_bool -%} 17 | {{ separator }}>/dev/null 2>&1 18 | {%- else -%} 19 | {{ separator }}2>&1 | mail -E -s "Cron{{ ' - ' ~ job.comment | replace('\n', ' ') if job.comment | length > 0 else '' }}" -a "From: Cron Daemon " root >/dev/null 2>&1 20 | {%- endif -%} 21 | {%- endfor -%} 22 | -------------------------------------------------------------------------------- /srv/salt/omv/deploy/compose/files/compose_cnf.j2: -------------------------------------------------------------------------------- 1 | {{ file.body }} 2 | -------------------------------------------------------------------------------- /srv/salt/omv/deploy/compose/files/compose_env_yml.j2: -------------------------------------------------------------------------------- 1 | {{ pillar['headers']['auto_generated'] }} 2 | {{ pillar['headers']['warning'] }} 3 | 4 | # environment file for {{ file.name }} 5 | # {{ file.description }} 6 | 7 | {%- if datapath is not none %} 8 | {{ file.env | replace("CHANGE_TO_COMPOSE_DATA_PATH", datapath) | replace("CHANGE_TO_COMPOSE_NAME", file.name) }} 9 | {%- else %} 10 | {{ file.env | replace("CHANGE_TO_COMPOSE_NAME", file.name) }} 11 | {%- endif %} 12 | -------------------------------------------------------------------------------- /srv/salt/omv/deploy/compose/files/compose_yml.j2: -------------------------------------------------------------------------------- 1 | {{ pillar['headers']['auto_generated'] }} 2 | {{ pillar['headers']['warning'] }} 3 | 4 | # {{ file.name }} 5 | # {{ file.description }} 6 | 7 | {%- if datapath is not none %} 8 | {{ file.body | replace("CHANGE_TO_COMPOSE_DATA_PATH", datapath) | replace("CHANGE_TO_COMPOSE_NAME", file.name) }} 9 | {%- else %} 10 | {{ file.body | replace("CHANGE_TO_COMPOSE_NAME", file.name) }} 11 | {%- endif %} 12 | -------------------------------------------------------------------------------- /srv/salt/omv/deploy/compose/files/dockerfile.j2: -------------------------------------------------------------------------------- 1 | {{ pillar['headers']['auto_generated'] }} 2 | {{ pillar['headers']['warning'] }} 3 | 4 | # {{ file.name }} 5 | # {{ file.description }} 6 | 7 | {{ file.body }} 8 | -------------------------------------------------------------------------------- /srv/salt/omv/deploy/compose/files/dockerfile_conf.j2: -------------------------------------------------------------------------------- 1 | {{ pillar['headers']['auto_generated'] }} 2 | {{ pillar['headers']['warning'] }} 3 | 4 | # config file for {{ file.name }} 5 | # {{ file.description }} 6 | 7 | {{ file.conffile }} 8 | -------------------------------------------------------------------------------- /srv/salt/omv/deploy/compose/files/dockerfile_script.j2: -------------------------------------------------------------------------------- 1 | {{ file.scriptfile }} 2 | -------------------------------------------------------------------------------- /srv/salt/omv/deploy/compose/files/global_env_yml.j2: -------------------------------------------------------------------------------- 1 | {%- if datapath is not none -%} 2 | {{ globalenv.globalenv | replace("CHANGE_TO_COMPOSE_DATA_PATH", datapath) }} 3 | {%- else -%} 4 | {{ globalenv.globalenv }} 5 | {%- endif %} 6 | -------------------------------------------------------------------------------- /srv/salt/omv/deploy/compose/files/override_yml.j2: -------------------------------------------------------------------------------- 1 | {{ pillar['headers']['auto_generated'] }} 2 | {{ pillar['headers']['warning'] }} 3 | 4 | # {{ file.name }} 5 | # {{ file.description }} 6 | 7 | {%- if datapath is not none %} 8 | {{ file.override | replace("CHANGE_TO_COMPOSE_DATA_PATH", datapath) }} 9 | {%- else %} 10 | {{ file.override }} 11 | {%- endif %} 12 | -------------------------------------------------------------------------------- /srv/salt/omv/deploy/compose/files/prune.j2: -------------------------------------------------------------------------------- 1 | {%- set separator = ' ' -%} 2 | {{ pillar['headers']['multiline'] -}} 3 | SHELL=/bin/sh 4 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 5 | # m h dom mon dow user command 6 | {%- for job in jobs | selectattr('enable') | selectattr('prune') %} 7 | {% if job.execution == "exactly" -%} 8 | {% if job.everynminute | to_bool %}*/{{ job.minute }}{% else %}{{ job.minute }}{% endif -%} 9 | {{ separator }}{% if job.everynhour | to_bool %}*/{{ job.hour }}{% else %}{{ job.hour }}{% endif -%} 10 | {{ separator }}{% if job.everyndayofmonth | to_bool %}*/{{ job.dayofmonth }}{% else %}{{ job.dayofmonth }}{% endif -%} 11 | {{ separator }}{{ job.month }}{{ separator }}{{ job.dayofweek }} 12 | {%- else -%} 13 | @{{ job.execution }} 14 | {%- endif -%} 15 | {{ separator }}root omv-compose-prune 16 | {%- if not job.sendemail | to_bool -%} 17 | {{ separator }}>/dev/null 2>&1 18 | {%- else -%} 19 | {{ separator }}2>&1 | mail -E -s "Cron{{ ' - ' ~ job.comment | replace('\n', ' ') if job.comment | length > 0 else '' }}" -a "From: Cron Daemon " root >/dev/null 2>&1 20 | {%- endif -%} 21 | {%- endfor -%} 22 | -------------------------------------------------------------------------------- /srv/salt/omv/deploy/compose/files/start.j2: -------------------------------------------------------------------------------- 1 | {%- set separator = ' ' -%} 2 | {{ pillar['headers']['multiline'] -}} 3 | SHELL=/bin/sh 4 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 5 | # m h dom mon dow user command 6 | {%- for job in jobs | selectattr('enable') | selectattr('filestart') %} 7 | {% if job.execution == "exactly" -%} 8 | {% if job.everynminute | to_bool %}*/{{ job.minute }}{% else %}{{ job.minute }}{% endif -%} 9 | {{ separator }}{% if job.everynhour | to_bool %}*/{{ job.hour }}{% else %}{{ job.hour }}{% endif -%} 10 | {{ separator }}{% if job.everyndayofmonth | to_bool %}*/{{ job.dayofmonth }}{% else %}{{ job.dayofmonth }}{% endif -%} 11 | {{ separator }}{{ job.month }}{{ separator }}{{ job.dayofweek }} 12 | {%- else -%} 13 | @{{ job.execution }} 14 | {%- endif -%} 15 | {{ separator }}root omv-compose-start-multi '{{ job.filter }}' 16 | {%- if not job.sendemail | to_bool -%} 17 | {{ separator }}>/dev/null 2>&1 18 | {%- else -%} 19 | {{ separator }}2>&1 | mail -E -s "Cron{{ ' - ' ~ job.comment | replace('\n', ' ') if job.comment | length > 0 else '' }}" -a "From: Cron Daemon " root >/dev/null 2>&1 20 | {%- endif -%} 21 | {%- endfor -%} 22 | -------------------------------------------------------------------------------- /srv/salt/omv/deploy/compose/files/stop.j2: -------------------------------------------------------------------------------- 1 | {%- set separator = ' ' -%} 2 | {{ pillar['headers']['multiline'] -}} 3 | SHELL=/bin/sh 4 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 5 | # m h dom mon dow user command 6 | {%- for job in jobs | selectattr('enable') | selectattr('filestop') %} 7 | {% if job.execution == "exactly" -%} 8 | {% if job.everynminute | to_bool %}*/{{ job.minute }}{% else %}{{ job.minute }}{% endif -%} 9 | {{ separator }}{% if job.everynhour | to_bool %}*/{{ job.hour }}{% else %}{{ job.hour }}{% endif -%} 10 | {{ separator }}{% if job.everyndayofmonth | to_bool %}*/{{ job.dayofmonth }}{% else %}{{ job.dayofmonth }}{% endif -%} 11 | {{ separator }}{{ job.month }}{{ separator }}{{ job.dayofweek }} 12 | {%- else -%} 13 | @{{ job.execution }} 14 | {%- endif -%} 15 | {{ separator }}root omv-compose-stop-multi '{{ job.filter }}' 16 | {%- if not job.sendemail | to_bool -%} 17 | {{ separator }}>/dev/null 2>&1 18 | {%- else -%} 19 | {{ separator }}2>&1 | mail -E -s "Cron{{ ' - ' ~ job.comment | replace('\n', ' ') if job.comment | length > 0 else '' }}" -a "From: Cron Daemon " root >/dev/null 2>&1 20 | {%- endif -%} 21 | {%- endfor -%} 22 | -------------------------------------------------------------------------------- /srv/salt/omv/deploy/compose/files/update.j2: -------------------------------------------------------------------------------- 1 | {%- set separator = ' ' -%} 2 | {{ pillar['headers']['multiline'] -}} 3 | SHELL=/bin/sh 4 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 5 | # m h dom mon dow user command 6 | {%- for job in jobs | selectattr('enable') | selectattr('update') %} 7 | {% if job.execution == "exactly" -%} 8 | {% if job.everynminute | to_bool %}*/{{ job.minute }}{% else %}{{ job.minute }}{% endif -%} 9 | {{ separator }}{% if job.everynhour | to_bool %}*/{{ job.hour }}{% else %}{{ job.hour }}{% endif -%} 10 | {{ separator }}{% if job.everyndayofmonth | to_bool %}*/{{ job.dayofmonth }}{% else %}{{ job.dayofmonth }}{% endif -%} 11 | {{ separator }}{{ job.month }}{{ separator }}{{ job.dayofweek }} 12 | {%- else -%} 13 | @{{ job.execution }} 14 | {%- endif -%} 15 | {{ separator }}root omv-compose-update-multi '{{ job.filter }}' 16 | {%- if not job.sendemail | to_bool -%} 17 | {{ separator }}>/dev/null 2>&1 18 | {%- else -%} 19 | {{ separator }}2>&1 | mail -E -s "Cron{{ ' - ' ~ job.comment | replace('\n', ' ') if job.comment | length > 0 else '' }}" -a "From: Cron Daemon " root >/dev/null 2>&1 20 | {%- endif -%} 21 | {%- endfor -%} 22 | -------------------------------------------------------------------------------- /srv/salt/omv/deploy/compose/init.sls: -------------------------------------------------------------------------------- 1 | include: 2 | - .{{ salt['pillar.get']('deploy_compose', 'default') }} 3 | -------------------------------------------------------------------------------- /usr/bin/autocompose.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | import argparse 3 | import datetime 4 | import re 5 | import sys 6 | 7 | from collections import OrderedDict 8 | 9 | import docker 10 | import pyaml 11 | 12 | IGNORE_VALUES = [None, "", [], "null", {}, "default", 0, ",", "no"] 13 | 14 | 15 | def list_container_names(): 16 | c = docker.from_env() 17 | return [container.name for container in c.containers.list(all=True)] 18 | 19 | 20 | def list_network_names(): 21 | c = docker.from_env() 22 | return [network.name for network in c.networks.list()] 23 | 24 | 25 | def generate_network_info(): 26 | networks = {} 27 | 28 | for network_name in list_network_names(): 29 | connection = docker.from_env() 30 | network_attributes = connection.networks.get(network_name).attrs 31 | 32 | values = { 33 | "name": network_attributes.get("Name"), 34 | "scope": network_attributes.get("Scope", "local"), 35 | "driver": network_attributes.get("Driver", None), 36 | "enable_ipv6": network_attributes.get("EnableIPv6", False), 37 | "internal": network_attributes.get("Internal", False), 38 | "ipam": { 39 | "driver": network_attributes.get("IPAM", {}).get("Driver", "default"), 40 | "config": [ 41 | {key.lower(): value for key, value in config.items()} 42 | for config in network_attributes.get("IPAM", {}).get("Config", []) 43 | ], 44 | }, 45 | } 46 | 47 | networks[network_name] = {key: value for key, value in values.items()} 48 | 49 | return networks 50 | 51 | 52 | def main(): 53 | parser = argparse.ArgumentParser( 54 | description="Generate docker-compose yaml definition from running container.", 55 | ) 56 | parser.add_argument( 57 | "-a", 58 | "--all", 59 | action="store_true", 60 | help="Include all active containers", 61 | ) 62 | parser.add_argument( 63 | "-v", 64 | "--version", 65 | type=int, 66 | default=3, 67 | help="Compose file version (1 or 3)", 68 | ) 69 | parser.add_argument( 70 | "cnames", 71 | nargs="*", 72 | type=str, 73 | help="The name of the container to process.", 74 | ) 75 | parser.add_argument( 76 | "-c", 77 | "--createvolumes", 78 | action="store_true", 79 | help="Create new volumes instead of reusing existing ones", 80 | ) 81 | parser.add_argument( 82 | "-f", 83 | "--filter", 84 | type=str, 85 | help="Filter containers by regex", 86 | ) 87 | args = parser.parse_args() 88 | 89 | container_names = args.cnames 90 | 91 | if args.all: 92 | container_names.extend(list_container_names()) 93 | 94 | if args.filter: 95 | cfilter = re.compile(args.filter) 96 | container_names = [c for c in container_names if cfilter.search(c)] 97 | 98 | struct = {} 99 | networks = {} 100 | volumes = {} 101 | containers = {} 102 | 103 | for cname in container_names: 104 | cfile, c_networks, c_volumes = generate(cname, createvolumes=args.createvolumes) 105 | 106 | struct.update(cfile) 107 | 108 | if not c_networks == None: 109 | networks.update(c_networks) 110 | if not c_volumes == None: 111 | volumes.update(c_volumes) 112 | 113 | # moving the networks = None statements outside of the for loop. Otherwise any container could reset it. 114 | if len(networks) == 0: 115 | networks = None 116 | if len(volumes) == 0: 117 | volumes = None 118 | 119 | if args.all: 120 | host_networks = generate_network_info() 121 | networks = host_networks 122 | 123 | render(struct, args, networks, volumes) 124 | 125 | 126 | def render(struct, args, networks, volumes): 127 | # Render yaml file 128 | if args.version == 1: 129 | pyaml.p(OrderedDict(struct)) 130 | else: 131 | ans = {"version": '3.6', "services": struct} 132 | 133 | if networks is not None: 134 | ans["networks"] = networks 135 | 136 | if volumes is not None: 137 | ans["volumes"] = volumes 138 | 139 | pyaml.p(OrderedDict(ans), string_val_style='"') 140 | 141 | 142 | def generate(cname, createvolumes=False): 143 | c = docker.from_env() 144 | 145 | try: 146 | cid = [x.short_id for x in c.containers.list(all=True) if cname == x.name or x.short_id in cname][0] 147 | except IndexError: 148 | print("That container is not available.", file=sys.stderr) 149 | sys.exit(1) 150 | 151 | cattrs = c.containers.get(cid).attrs 152 | 153 | # Build yaml dict structure 154 | 155 | cfile = {} 156 | cfile[cattrs.get("Name")[1:]] = {} 157 | ct = cfile[cattrs.get("Name")[1:]] 158 | 159 | default_networks = ["bridge", "host", "none"] 160 | 161 | values = { 162 | "cap_drop": cattrs.get("HostConfig", {}).get("CapDrop", None), 163 | "cgroup_parent": cattrs.get("HostConfig", {}).get("CgroupParent", None), 164 | "container_name": cattrs.get("Name")[1:], 165 | "devices": [], 166 | "dns": cattrs.get("HostConfig", {}).get("Dns", None), 167 | "dns_search": cattrs.get("HostConfig", {}).get("DnsSearch", None), 168 | "environment": cattrs.get("Config", {}).get("Env", None), 169 | "extra_hosts": cattrs.get("HostConfig", {}).get("ExtraHosts", None), 170 | "image": cattrs.get("Config", {}).get("Image", None), 171 | "labels": cattrs.get("Config", {}).get("Labels", {}), 172 | "links": cattrs.get("HostConfig", {}).get("Links"), 173 | #'log_driver': cattrs.get('HostConfig']['LogConfig']['Type'], 174 | #'log_opt': cattrs.get('HostConfig']['LogConfig']['Config'], 175 | "logging": { 176 | "driver": cattrs.get("HostConfig", {}).get("LogConfig", {}).get("Type", None), 177 | "options": cattrs.get("HostConfig", {}).get("LogConfig", {}).get("Config", None), 178 | }, 179 | "networks": { 180 | x for x in cattrs.get("NetworkSettings", {}).get("Networks", {}).keys() if x not in default_networks 181 | }, 182 | "security_opt": cattrs.get("HostConfig", {}).get("SecurityOpt"), 183 | "ulimits": cattrs.get("HostConfig", {}).get("Ulimits"), 184 | # the line below would not handle type bind 185 | # 'volumes': [f'{m["Name"]}:{m["Destination"]}' for m in cattrs.get('Mounts'] if m['Type'] == 'volume'], 186 | "mounts": cattrs.get("Mounts"), # this could be moved outside of the dict. will only use it for generate 187 | "volume_driver": cattrs.get("HostConfig", {}).get("VolumeDriver", None), 188 | "volumes_from": cattrs.get("HostConfig", {}).get("VolumesFrom", None), 189 | "entrypoint": cattrs.get("Config", {}).get("Entrypoint", None), 190 | "user": cattrs.get("Config", {}).get("User", None), 191 | "working_dir": cattrs.get("Config", {}).get("WorkingDir", None), 192 | "domainname": cattrs.get("Config", {}).get("Domainname", None), 193 | "hostname": cattrs.get("Config", {}).get("Hostname", None), 194 | "ipc": cattrs.get("HostConfig", {}).get("IpcMode", None), 195 | "mac_address": cattrs.get("NetworkSettings", {}).get("MacAddress", None), 196 | "privileged": cattrs.get("HostConfig", {}).get("Privileged", None), 197 | "restart": cattrs.get("HostConfig", {}).get("RestartPolicy", {}).get("Name", None), 198 | "read_only": cattrs.get("HostConfig", {}).get("ReadonlyRootfs", None), 199 | "stdin_open": cattrs.get("Config", {}).get("OpenStdin", None), 200 | "tty": cattrs.get("Config", {}).get("Tty", None), 201 | } 202 | 203 | # Populate devices key if device values are present 204 | if cattrs.get("HostConfig", {}).get("Devices"): 205 | values["devices"] = [ 206 | x["PathOnHost"] + ":" + x["PathInContainer"] for x in cattrs.get("HostConfig", {}).get("Devices") 207 | ] 208 | 209 | networks = {} 210 | if values["networks"] == set(): 211 | del values["networks"] 212 | 213 | if len(cattrs.get("NetworkSettings", {}).get("Networks", {}).keys()) > 0: 214 | assumed_default_network = list(cattrs.get("NetworkSettings", {}).get("Networks", {}).keys())[0] 215 | values["network_mode"] = assumed_default_network 216 | networks = None 217 | else: 218 | networklist = c.networks.list() 219 | for network in networklist: 220 | if network.attrs["Name"] in values["networks"]: 221 | networks[network.attrs["Name"]] = { 222 | "external": (not network.attrs["Internal"]), 223 | "name": network.attrs["Name"], 224 | } 225 | # volumes = {} 226 | # if values['volumes'] is not None: 227 | # for volume in values['volumes']: 228 | # volume_name = volume.split(':')[0] 229 | # volumes[volume_name] = {'external': True} 230 | # else: 231 | # volumes = None 232 | 233 | # handles both the returned values['volumes'] (in c_file) and volumes for both, the bind and volume types 234 | # also includes the read only option 235 | volumes = {} 236 | mountpoints = [] 237 | if values["mounts"] is not None: 238 | for mount in values["mounts"]: 239 | destination = mount["Destination"] 240 | if not mount["RW"]: 241 | destination = destination + ":ro" 242 | if mount["Type"] == "volume": 243 | mountpoints.append(mount["Name"] + ":" + destination) 244 | if not createvolumes: 245 | volumes[mount["Name"]] = { 246 | "external": True 247 | } # to reuse an existing volume ... better to make that a choice? (cli argument) 248 | elif mount["Type"] == "bind": 249 | mountpoints.append(mount["Source"] + ":" + destination) 250 | values["volumes"] = mountpoints 251 | if len(volumes) == 0: 252 | volumes = None 253 | values["mounts"] = None # remove this temporary data from the returned data 254 | 255 | # Check for command and add it if present. 256 | if cattrs.get("Config", {}).get("Cmd") is not None: 257 | values["command"] = cattrs.get("Config", {}).get("Cmd") 258 | 259 | # Check for exposed/bound ports and add them if needed. 260 | try: 261 | expose_value = list(cattrs.get("Config", {}).get("ExposedPorts", {}).keys()) 262 | ports_value = [ 263 | cattrs.get("HostConfig", {}).get("PortBindings", {})[key][0]["HostIp"] 264 | + ":" 265 | + cattrs.get("HostConfig", {}).get("PortBindings", {})[key][0]["HostPort"] 266 | + ":" 267 | + key 268 | for key in cattrs.get("HostConfig", {}).get("PortBindings") 269 | ] 270 | 271 | # If bound ports found, don't use the 'expose' value. 272 | if ports_value not in IGNORE_VALUES: 273 | for index, port in enumerate(ports_value): 274 | if port[0] == ":": 275 | ports_value[index] = port[1:] 276 | 277 | values["ports"] = ports_value 278 | else: 279 | values["expose"] = expose_value 280 | 281 | except (KeyError, TypeError): 282 | # No ports exposed/bound. Continue without them. 283 | ports = None 284 | 285 | # Iterate through values to finish building yaml dict. 286 | for key in values: 287 | value = values[key] 288 | if value not in IGNORE_VALUES: 289 | ct[key] = value 290 | 291 | return cfile, networks, volumes 292 | 293 | 294 | if __name__ == "__main__": 295 | main() 296 | -------------------------------------------------------------------------------- /usr/sbin/omv-compose-backup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # shellcheck disable=SC1091,SC2086,SC2181,SC2207 4 | # 5 | # Copyright (c) 2023-2025 openmediavault plugin developers 6 | # 7 | # This file is licensed under the terms of the GNU General Public 8 | # License version 2. This program is licensed "as is" without any 9 | # warranty of any kind, whether express or implied. 10 | # 11 | # version: 1.2.1 12 | 13 | export LC_ALL=C.UTF-8 14 | 15 | . /usr/share/openmediavault/scripts/helper-functions 16 | 17 | declare -i force=0 18 | declare -i verbose=1 19 | declare -i i=0 20 | declare -i j=0 21 | 22 | # logging location 23 | logDir="/var/log/" 24 | logFile="${logDir}/omv-compose-backup.log" 25 | 26 | _log() 27 | { 28 | msg=${1} 29 | echo "[$(date +'%Y-%m-%d %H:%M:%S%z')] [composebackup] ${msg}" | tee -a ${logFile} >&2 30 | } 31 | 32 | extractContPath() { 33 | local val="$1" 34 | # Remove everything before the first colon 35 | val="${val#*:}" 36 | # Remove anything after a '#' (comment) 37 | val="${val%%#*}" 38 | # Remove everything after the next colon 39 | val="${val%%:*}" 40 | # Trim trailing whitespace 41 | val="${val%"${val##*[![:space:]]}"}" 42 | echo "${val}" 43 | } 44 | 45 | compose="${1}" 46 | uuid="${2}" 47 | if [ -z "${compose}" ]; then 48 | _log "No compose name set. Exiting..." 49 | exit 10 50 | fi 51 | _log "compose :: ${compose}" 52 | _log "uuid :: ${uuid}" 53 | 54 | # Get docker storage path 55 | dockerStorage=$(omv_config_get "/config/services/compose/dockerStorage") 56 | _log "Docker storage :: ${dockerStorage}" 57 | 58 | # Get the shared folder reference and path 59 | sfref=$(omv_config_get "/config/services/compose/sharedfolderref") 60 | if ! omv_isuuid "${sfref}"; then 61 | _log "No compose sharedfolder set." 62 | exit 11 63 | fi 64 | sfpath="$(omv_get_sharedfolder_path "${sfref}")" 65 | if [ ! -d "${sfpath}" ]; then 66 | _log "Shared folder directory does not exist. Exiting..." 67 | exit 12 68 | fi 69 | sfpath="${sfpath/%\/}" 70 | sfpath="${sfpath//\/\//\/}" 71 | _log "Compose file path :: ${sfpath}" 72 | 73 | # Get the backup shared folder reference and path 74 | sfref=$(omv_config_get "/config/services/compose/backupsharedfolderref") 75 | if ! omv_isuuid "${sfref}"; then 76 | _log "No backup sharedfolder set." 77 | exit 13 78 | fi 79 | backuppath="$(omv_get_sharedfolder_path "${sfref}")" 80 | if [ ! -d "${backuppath}" ]; then 81 | _log "Backup shared folder directory does not exist. Exiting..." 82 | exit 14 83 | fi 84 | backuppath="${backuppath/%\/}" 85 | backuppath="${backuppath//\/\//\/}" 86 | _log "Backup path :: ${backuppath}" 87 | 88 | # set path for yml and env files 89 | composepath="${sfpath}/${compose}" 90 | env="${composepath}/${compose}.env" 91 | globalenv="${sfpath}/global.env" 92 | yml="${composepath}/${compose}.yml" 93 | ovr="${composepath}/compose.override.yml" 94 | if [ ! -f "${yml}" ]; then 95 | _log "Compose file '${yml}' does not exist. Exiting..." 96 | exit 15 97 | fi 98 | _log "Compose file :: ${yml}" 99 | 100 | yq="/usr/local/bin/yq" 101 | if [ ! -f "${yq}" ]; then 102 | _log "'${yq}' does not exist. Exiting..." 103 | exit 16 104 | fi 105 | 106 | if omv_isuuid "${uuid}"; then 107 | verbose="$(omv_config_get "/config/services/compose/jobs/job[uuid='${uuid}']/verbose")" 108 | fi 109 | _log "Verbose :: ${verbose}" 110 | 111 | # Get the backup max size 112 | backupmaxsize=$(omv_config_get "/config/services/compose/backupmaxsize") 113 | if [ ${backupmaxsize} -lt 1 ]; then 114 | _log "Backup max size is set to unlimited." 115 | backupmaxsize=0 116 | fi 117 | _log "Backup max size :: ${backupmaxsize} GB" 118 | backupmax=$((backupmaxsize * 1024 * 1024 * 1024)) 119 | 120 | OFS=$IFS 121 | IFS=$'\n' 122 | 123 | # build compose arguments 124 | dockerComposeArgs=("--file" "${yml}") 125 | if [ -f "${ovr}" ]; then 126 | dockerComposeArgs+=("--file" "${ovr}") 127 | fi 128 | if [ -f "${globalenv}" ]; then 129 | dockerComposeArgs+=("--env-file" "${globalenv}") 130 | fi 131 | dockerComposeArgs+=("--env-file" "${env}") 132 | 133 | # run docker compose config 134 | confout="$(mktemp)" 135 | docker compose "${dockerComposeArgs[@]}" config --output "${confout}" 136 | if [ $? -gt 0 ] || [ -z "${confout}" ]; then 137 | _log "Failed to run docker compose config. Exiting..." 138 | exit 17 139 | fi 140 | 141 | # get services 142 | services=($(${yq} '.services | keys | .[]' "${yml}")) 143 | 144 | serviceVolsMap=() 145 | 146 | OFS=$IFS 147 | IFS=$'\n' 148 | 149 | # build list of all container host and container paths with comments 150 | for service in "${services[@]}"; do 151 | ymlVolsSvc=($(${yq} ".services.${service}.volumes" "${yml}" 2>/dev/null | sed 's/^- //' | sed 's/"//g')) 152 | confVolsSvc=($(${yq} eval ".services.${service}.volumes[]? | .source + \":\" + .target" "${confout}" 2>/dev/null)) 153 | 154 | for vol in "${ymlVolsSvc[@]}"; do 155 | if [ -n "${vol}" ]; then 156 | vol2="${vol#*:}" 157 | vol2a="$(extractContPath "${vol}")" 158 | for confvol in "${confVolsSvc[@]}"; do 159 | confvol1="${confvol%%:*}" 160 | confvol2="${confvol#*:}" 161 | if [ "${confvol2}" = "${vol2a}" ]; then 162 | serviceVolsMap+=("${confvol1}:${vol2}") 163 | break 164 | fi 165 | done 166 | fi 167 | done 168 | done 169 | 170 | IFS=$OFS 171 | 172 | # create backup subdirectory 173 | backupdir="${backuppath}/${compose}" 174 | mkdir -pv "${backupdir}" 175 | 176 | # update volume list 177 | vollist="${backupdir}/vol.list" 178 | echo "${i},${composepath}" > "${vollist}" 179 | 180 | # save status 181 | status="$(mktemp)" 182 | docker compose ls --all --format json | jq -r ".[] | select(.ConfigFiles | contains(\"${yml}\")) | .Status" > "${status}" 183 | _log "status :: $(cat "${status}")" 184 | 185 | wait_for_compose_to_exit() { 186 | local total_wait_s=10 # Total time to wait in seconds 187 | local sleep_interval_s=0.1 # Sleep interval in seconds 188 | local max_attempts=100 # Manually calculated as total_wait_s/sleep_interval_s 189 | local attempt=0 190 | 191 | _log "Waiting for compose to fully stop (max ${total_wait_s}s with ${sleep_interval_s}s intervals)..." 192 | 193 | while [ $attempt -lt $max_attempts ]; do 194 | current_status=$(docker compose ls --all --format json | jq -r ".[] | select(.ConfigFiles | contains(\"${yml}\")) | .Status") 195 | 196 | if grep -q "exited" <(echo "${current_status}"); then 197 | _log "compose stopped: ${current_status}" 198 | return 0 199 | fi 200 | 201 | _log "compose still stopping (attempt $((attempt+1))/${max_attempts}): ${current_status}" 202 | ((attempt++)) 203 | sleep $sleep_interval_s 204 | done 205 | 206 | _log "WARNING: compose might not be fully stopped after ${total_wait_s} seconds. Proceeding anyway..." 207 | return 1 208 | } 209 | 210 | # stop compose if running 211 | if grep -q "running" "${status}"; then 212 | docker compose "${dockerComposeArgs[@]}" stop 213 | wait_for_compose_to_exit 214 | else 215 | _log "${compose} is not running" 216 | fi 217 | 218 | # copy yml and env files and other files that use a relative path 219 | voldir="${backupdir}/${i}" 220 | mkdir -pv "${voldir}" 221 | cp -v "${yml}" "${ovr}" "${env}" "${voldir}/" 222 | 223 | # loop through volumes 224 | for vol in "${serviceVolsMap[@]}"; do 225 | _log "Volume :: ${vol}" 226 | hostpath="${vol%%:*}" 227 | hostpath="${hostpath//\'/}" 228 | _log "host path :: ${hostpath}" 229 | contpath=$(extractContPath "${vol}") 230 | _log "container path :: ${contpath}" 231 | cmt="" 232 | if [[ "$vol" == *#* ]]; then 233 | cmt="${vol##*#}" 234 | fi 235 | _log "path comment :: ${cmt}" 236 | # check for paths to skip or force 237 | if [[ "${cmt}" == *"SKIP_BACKUP"* ]]; then 238 | _log "Skipping for SKIP_BACKUP comment :: ${vol}" 239 | echo 240 | continue 241 | elif [[ "${hostpath}" == @(/dev|/dev/*|/lib|/lib/*|/sys|/sys/*|./*|../*|/) ]]; then 242 | _log "Skipping :: ${hostpath}" 243 | echo 244 | continue 245 | elif [[ "${vol}" == *":ro"* ]]; then 246 | _log "Read only volume. Skipping :: ${hostpath}" 247 | echo 248 | continue 249 | elif [[ "${hostpath}" != *"/"* ]]; then 250 | _log "Named volume :: ${hostpath}" 251 | fullvolname=$(docker compose "${dockerComposeArgs[@]}" config 2>/dev/null | yq ".volumes.${hostpath}.name") 252 | if [ -z "${fullvolname}" ]; then 253 | _log "Failed to retrieve full volume name. Skipping" 254 | continue 255 | fi 256 | _log "Full volume name :: ${fullvolname}" 257 | hostpath=$(docker volume inspect "${fullvolname}" --format '{{ .Mountpoint }}') 258 | if [ -z "${hostpath}" ]; then 259 | _log "Failed to retrieve named volume path. Skipping" 260 | continue 261 | fi 262 | if [ ! -d "${hostpath}" ]; then 263 | _log "Named volume path does not exist. Skipping" 264 | continue 265 | fi 266 | _log "Named volume path :: ${hostpath}" 267 | elif [[ "${cmt}" == *"BACKUP"* ]]; then 268 | _log "Forcing for BACKUP comment :: ${vol}" 269 | force=1 270 | else 271 | _log "Backup host path :: ${hostpath}" 272 | force=0 273 | fi 274 | if [ ! -f "${hostpath}" ] && [ ! -d "${hostpath}" ]; then 275 | if [ -e "${hostpath}" ]; then 276 | _log "Special file. Skipping..." 277 | echo 278 | else 279 | _log "Path does not exist. Skipping..." 280 | echo 281 | fi 282 | continue 283 | fi 284 | if [ ${backupmaxsize} -gt 0 ]; then 285 | foldersize=$(du --summarize --bytes "${hostpath}" | awk '{ print $1 }') 286 | _log "Folder size :: ${foldersize} bytes" 287 | if [ ${foldersize} -gt ${backupmax} ] && [ ${force} -eq 0 ]; then 288 | _log "Folder size greater than max backup size. Skipping..." 289 | continue; 290 | fi 291 | fi 292 | if cut -d"," -f2 "${vollist}" | sed 's#/$##' | grep -Fqx "${hostpath%/}"; then 293 | _log "Duplicate volume path '${hostpath}' - skipping..." 294 | else 295 | ((i++)) 296 | # rsync to numbered subdirectory 297 | voldir="${backupdir}/${i}" 298 | mkdir -pv "${voldir}" 299 | _log "Backup to :: ${voldir}" 300 | if [ ${verbose} -eq 0 ]; then 301 | args=(-ar) 302 | else 303 | args=(-avr) 304 | fi 305 | args+=(--delete) 306 | if [ -d "${hostpath}" ]; then 307 | hostpath="${hostpath}/" 308 | if [ "${force}" -ne 1 ]; then 309 | args+=(--exclude="*.qcow2") 310 | fi 311 | fi 312 | 313 | # check for exclusions 314 | if omv_isuuid "${uuid}"; then 315 | exclusions="$(omv_config_get "/config/services/compose/jobs/job[uuid='${uuid}']/excludes")" 316 | if [ -n "${exclusions}" ]; then 317 | IFS=',' read -r -a exclude_array <<< "${exclusions}" 318 | for item in "${exclude_array[@]}"; do 319 | _log "exclude: ${item}" 320 | args+=(--exclude="${item}") 321 | done 322 | fi 323 | fi 324 | 325 | # add volume list entry 326 | echo "${i},${hostpath}" >> "${vollist}" 327 | # rsync 328 | rsync "${args[@]}" "${hostpath}" "${voldir}" 329 | fi 330 | echo 331 | done 332 | 333 | # remove extra directories from a previous backup 334 | # if a volume(s) were removed from the compose file. 335 | while [ ${i} -le 100 ] && [ ${j} -le 3 ]; do 336 | ((i++)) 337 | voldir="${backupdir}/${i}" 338 | if [ -d "${voldir}" ]; then 339 | _log "Removing '${voldir}' directory from previous backup that is no longer in compose file." 340 | rm -rf "${voldir}" 341 | else 342 | ((j++)) 343 | fi 344 | done 345 | 346 | # start compose if running before backup 347 | if grep -q "running" "${status}"; then 348 | docker compose "${dockerComposeArgs[@]}" start 349 | fi 350 | 351 | # store size of backup 352 | spaceused="${backupdir}/space.used" 353 | backupsize=$(du --summarize --bytes "${backupdir}" | awk '{ print $1 }') 354 | _log "Backup size :: ${backupsize} bytes" 355 | echo ${backupsize} > "${spaceused}" 356 | 357 | # remove temp files 358 | rm -f "${confout}" "${status}" 359 | 360 | _log "Done." 361 | 362 | exit 0 363 | -------------------------------------------------------------------------------- /usr/sbin/omv-compose-backup-multi: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # shellcheck disable=SC1091,SC2053,SC2086,SC2162 4 | # 5 | # Copyright (c) 2023-2025 openmediavault plugin developers 6 | # 7 | # This file is licensed under the terms of the GNU General Public 8 | # License version 2. This program is licensed "as is" without any 9 | # warranty of any kind, whether express or implied. 10 | # 11 | # version: 0.2.0 12 | 13 | . /usr/share/openmediavault/scripts/helper-functions 14 | 15 | export LC_ALL=C.UTF-8 16 | 17 | declare -i count=0 18 | declare -i index=0 19 | 20 | filter="" 21 | postbackup="" 22 | prebackup="" 23 | uuid="" 24 | 25 | # logging location 26 | logDir="/var/log/" 27 | logFile="${logDir}/omv-compose-backup.log" 28 | 29 | _log() 30 | { 31 | msg=${1} 32 | echo "[$(date +'%Y-%m-%d %H:%M:%S%z')] [composebackup] ${msg}" | tee -a ${logFile} >&2 33 | } 34 | 35 | # loop through options 36 | while [[ $# -gt 0 ]]; do 37 | case "$1" in 38 | -f) 39 | filter="$2" 40 | shift 2 41 | ;; 42 | -u) 43 | uuid="$2" 44 | _log "uuid :: ${uuid}" 45 | shift 2 46 | ;; 47 | -h) 48 | echo "Use the following flags:" 49 | echo " -f 'filter'" 50 | echo " will be used over filter specified without -f flag" 51 | echo " -h" 52 | echo " show this help" 53 | echo " -u uuid of job" 54 | echo "" 55 | echo "Examples:" 56 | echo " omv-compile-backup-multi -u '41f4e112-cda9-11ee-938c-6715fcf387b0'" 57 | echo " omv-compile-backup-multi -f '*' -u '41f4e112-cda9-11ee-938c-6715fcf387b0'" 58 | echo " omv-compile-backup-multi -f 'tst' -u '41f4e112-cda9-11ee-938c-6715fcf387b0'" 59 | echo " omv-compile-backup-multi -f 'tst1,tst2,tst3' -u '41f4e112-cda9-11ee-938c-6715fcf387b0'" 60 | echo " omv-compile-backup-multi tst" 61 | echo "" 62 | exit 100 63 | ;; 64 | -*) 65 | echo "Invalid option: $1" 66 | exit 1 67 | ;; 68 | *) 69 | # if no dash in front, treat as a filter 70 | if [[ -z "${filter}" ]]; then 71 | filter="$1" 72 | fi 73 | shift 74 | ;; 75 | esac 76 | done 77 | 78 | if [[ "${filter}" == "*" ]]; then 79 | filter="" 80 | elif [[ "${filter}" == *","* ]]; then 81 | filter="@(${filter//,/|})" 82 | fi 83 | _log "filter :: ${filter}" 84 | 85 | if omv_isuuid "${uuid}"; then 86 | job="/config/services/compose/jobs/job[uuid='${uuid}']" 87 | prebackup=$(omv_config_get "${job}/prebackup") 88 | postbackup=$(omv_config_get "${job}/postbackup") 89 | fi 90 | 91 | # execute pre-backup 92 | if [ -f "${prebackup}" ] && [ -x "${prebackup}" ]; then 93 | _log "Executing pre-backup script :: ${prebackup}" 94 | ${prebackup} 95 | _log "pre-backup script complete." 96 | else 97 | if [ -n "${prebackup}" ]; then 98 | _log "pre-backup script not found." 99 | fi 100 | fi 101 | 102 | # Get the shared folder reference and path 103 | sfref=$(omv_config_get "/config/services/compose/sharedfolderref") 104 | if ! omv_isuuid "${sfref}"; then 105 | _log "No compose sharedfolder set." 106 | exit 11 107 | fi 108 | sfpath="$(omv_get_sharedfolder_path "${sfref}")" 109 | if [ ! -d "${sfpath}" ]; then 110 | _log "Shared folder directory does not exist. Exiting..." 111 | exit 12 112 | fi 113 | sfpath="${sfpath/%\/}" 114 | sfpath="${sfpath//\/\//\/}" 115 | _log "Compose file path :: ${sfpath}" 116 | 117 | # Get the backup shared folder reference and path 118 | sfref=$(omv_config_get "/config/services/compose/backupsharedfolderref") 119 | if ! omv_isuuid "${sfref}"; then 120 | _log "No backup sharedfolder set." 121 | exit 13 122 | fi 123 | backuppath="$(omv_get_sharedfolder_path "${sfref}")" 124 | if [ ! -d "${backuppath}" ]; then 125 | _log "Backup shared folder directory does not exist. Exiting..." 126 | exit 14 127 | fi 128 | backuppath="${backuppath/%\/}" 129 | backuppath="${backuppath//\/\//\/}" 130 | _log "Backup path :: ${backuppath}" 131 | 132 | # backup global.env 133 | globalenv="${sfpath}/global.env" 134 | if [ -f "${globalenv}" ]; then 135 | _log "Backup global.env..." 136 | cp -pv "${globalenv}" "${backuppath}/" 137 | fi 138 | 139 | xpath="/config/services/compose/files/file" 140 | count=$(omv_config_get_count "${xpath}") 141 | index=1 142 | while [ ${index} -le ${count} ]; do 143 | pos="${xpath}[position()=${index}]" 144 | name=$(omv_config_get "${pos}/name") 145 | if [ -n "${filter}" ] && [[ "${name}" != ${filter} ]]; then 146 | index=$(( index + 1 )) 147 | continue 148 | fi 149 | echo ${name} 150 | omv-compose-backup "${name}" "${uuid:+${uuid}}" 151 | index=$(( index + 1 )) 152 | done; 153 | 154 | # execute post-backup 155 | if [ -f "${postbackup}" ] && [ -x "${postbackup}" ]; then 156 | _log "Executing post-backup script :: ${postbackup}" 157 | ${postbackup} 158 | _log "post-backup script complete." 159 | else 160 | if [ -n "${postbackup}" ]; then 161 | _log "post-backup script not found." 162 | fi 163 | fi 164 | -------------------------------------------------------------------------------- /usr/sbin/omv-compose-download-icons: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | url="https://github.com/OpenMediaVault-Plugin-Developers/packages/raw/master/compose-files/icons.tar.gz" 4 | icon_file="/tmp/icons.tar.gz" 5 | icon_dir="/var/www/openmediavault/assets/composeImages/" 6 | 7 | # download tar ball 8 | wget --quiet ${url} -O ${icon_file} 9 | 10 | # remove existing dir and recreate 11 | rm -rf "${icon_dir}" 12 | mkdir -p "${icon_dir}" 13 | 14 | # extract tar ball 15 | tar -xzf "${icon_file}" --strip-components=2 -C "${icon_dir}" 16 | 17 | # fix permissions on icon files 18 | chown -R openmediavault-webgui:openmediavault-webgui "${icon_dir}" 19 | 20 | # remove temp file 21 | rm -f "${icon_file}" 22 | 23 | exit 0 24 | -------------------------------------------------------------------------------- /usr/sbin/omv-compose-init-git: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . /usr/share/openmediavault/scripts/helper-functions 4 | 5 | sfpath="${1}" 6 | 7 | if [ ! -d "${sfpath}" ]; then 8 | echo "Invalid directory: ${sfpath}" 9 | exit 1 10 | fi 11 | 12 | echo "Removing old .git directory (if found) ..." 13 | rm -rf "${sfpath}/.git" 14 | 15 | echo "Initializing new git repo ..." 16 | GIT_OPTIONAL_LOCKS=0 git init --initial-branch=main "${sfpath}" --quiet 17 | 18 | echo "Configuring ..." 19 | git -C "${sfpath}" config user.name "openmediavault-compose" 20 | git -C "${sfpath}" config user.email "compose@localhost" 21 | 22 | echo "Adding existing files to repo ..." 23 | cd "${sfpath}" || exit 2 24 | 25 | # Add global.env if it exists 26 | [ -f "global.env" ] && git add global.env 27 | 28 | # Add docker-compose relevant files 29 | for dir in */; do 30 | [ -d "${dir}" ] || continue 31 | name="${dir%/}" 32 | [ -f "${dir}${name}.yml" ] && git add "${dir}${name}.yml" 33 | [ -f "${dir}${name}.env" ] && git add "${dir}${name}.env" 34 | [ -f "${dir}compose.override.yml" ] && git add "${dir}compose.override.yml" 35 | done 36 | 37 | # Add configs from OMV database 38 | xpath="/config/services/compose/configs/config" 39 | count=$(omv_config_get_count "${xpath}") 40 | 41 | for (( index=1; index<=count; index++ )); do 42 | pos="${xpath}[position()=${index}]" 43 | if omv_config_exists "${pos}/name"; then 44 | cfgname="$(omv_config_get "${pos}/name")" 45 | cfguuid="$(omv_config_get "${pos}/fileref")" 46 | 47 | if [ -n "${cfgname}" ] && [ -n "${cfguuid}" ]; then 48 | filename="$(omv_config_get "/config/services/compose/files/file[uuid='${cfguuid}']/name")" 49 | if [ -n "${filename}" ]; then 50 | cfgpath="${filename}/${cfgname}" 51 | [ -f "${cfgpath}" ] && git add "${cfgpath}" 52 | fi 53 | fi 54 | fi 55 | done 56 | 57 | # Commit if there are staged changes 58 | if git diff --cached --quiet; then 59 | echo "No files to commit." 60 | else 61 | git commit --quiet --message "initial commit" 62 | echo "Initial commit created." 63 | fi 64 | 65 | echo "Done." 66 | 67 | exit 0 68 | -------------------------------------------------------------------------------- /usr/sbin/omv-compose-prune: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # shellcheck disable= 4 | # 5 | # Copyright (c) 2023-2025 openmediavault plugin developers 6 | # 7 | # This file is licensed under the terms of the GNU General Public 8 | # License version 2. This program is licensed "as is" without any 9 | # warranty of any kind, whether express or implied. 10 | # 11 | # version: 0.0.1 12 | 13 | export LC_ALL=C.UTF-8 14 | 15 | declare -i timeout=180 16 | declare -i i=0 17 | 18 | # logging location 19 | logDir="/var/log/" 20 | logFile="${logDir}/omv-compose-prune.log" 21 | 22 | _log() 23 | { 24 | msg=${1} 25 | echo "[$(date +'%Y-%m-%d %H:%M:%S%z')] [composeupdate] ${msg}" | tee -a ${logFile} >&2 26 | } 27 | 28 | _log "Starting docker image prune ..." 29 | 30 | while pgrep -f omv-compose-update -l > /dev/null; do 31 | _log "Update is running. Waiting ... ${i}" 32 | sleep 10 33 | (( i++ )) 34 | if [ ${i} -gt ${timeout} ]; then 35 | _log "Timed out waiting. Exiting." 36 | exit 10 37 | fi 38 | done 39 | 40 | docker image prune -f | tee -a ${logFile} >&2 41 | 42 | _log "Done." 43 | 44 | exit 0 45 | -------------------------------------------------------------------------------- /usr/sbin/omv-compose-restore: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # shellcheck disable=SC1091,SC2086 4 | # 5 | # Copyright (c) 2023-2025 openmediavault plugin developers 6 | # 7 | # This file is licensed under the terms of the GNU General Public 8 | # License version 2. This program is licensed "as is" without any 9 | # warranty of any kind, whether express or implied. 10 | # 11 | # version: 1.0.2 12 | 13 | . /usr/share/openmediavault/scripts/helper-functions 14 | 15 | declare -i skip=0 16 | 17 | # logging location 18 | logDir="/var/log/" 19 | logFile="${logDir}/omv-compose-restore.log" 20 | 21 | _log() 22 | { 23 | msg=${1} 24 | echo "[$(date +'%Y-%m-%d %H:%M:%S%z')] [composerestore] ${msg}" | tee -a ${logFile} >&2 25 | } 26 | 27 | compose="${1}" 28 | if [ -z "${compose}" ]; then 29 | _log "No compose name set. Exiting..." 30 | exit 10 31 | fi 32 | _log "compose :: ${compose}" 33 | 34 | # Get docker storage path 35 | dockerStorage=$(omv_config_get "/config/services/compose/dockerStorage") 36 | _log "Docker storage :: ${dockerStorage}" 37 | 38 | # Get the shared folder reference and path 39 | sfref=$(omv_config_get "/config/services/compose/sharedfolderref") 40 | if ! omv_isuuid "${sfref}"; then 41 | _log "No compose sharedfolder set." 42 | exit 11 43 | fi 44 | sfpath="$(omv_get_sharedfolder_path "${sfref}")" 45 | if [ ! -d "${sfpath}" ]; then 46 | _log "Shared folder directory does not exist. Exiting..." 47 | exit 12 48 | fi 49 | sfpath="${sfpath/%\/}" 50 | sfpath="${sfpath//\/\//\/}" 51 | _log "Compose file path :: ${sfpath}" 52 | 53 | # Get the backup shared folder reference and path 54 | sfref=$(omv_config_get "/config/services/compose/backupsharedfolderref") 55 | if ! omv_isuuid "${sfref}"; then 56 | _log "No backup sharedfolder set." 57 | exit 13 58 | fi 59 | backuppath="$(omv_get_sharedfolder_path "${sfref}")" 60 | if [ ! -d "${backuppath}" ]; then 61 | _log "Backup shared folder directory does not exist. Exiting..." 62 | exit 14 63 | fi 64 | backuppath="${backuppath/%\/}" 65 | _log "Backup path :: ${backuppath}" 66 | 67 | # set path for yml and env files 68 | composepath="${sfpath}/${compose}" 69 | env="${composepath}/${compose}.env" 70 | globalenv="${sfpath}/global.env" 71 | ovr="${composepath}/compose.override.yml" 72 | yml="${composepath}/${compose}.yml" 73 | if [ ! -f "${yml}" ]; then 74 | _log "Compose file '${yml}' does not exist." 75 | skip=1 76 | fi 77 | _log "Compose file :: ${yml}" 78 | 79 | # build compose arguments 80 | dockerComposeArgs=("--file" "${yml}") 81 | if [ -f "${ovr}" ]; then 82 | dockerComposeArgs+=("--file" "${ovr}") 83 | fi 84 | if [ -f "${globalenv}" ]; then 85 | dockerComposeArgs+=("--env-file" "${globalenv}") 86 | fi 87 | dockerComposeArgs+=("--env-file" "${env}") 88 | 89 | if [ ${skip} -ne 1 ]; then 90 | # save status 91 | status="$(mktemp)" 92 | docker compose ls --all --format json | jq -r ".[] | select(.ConfigFiles | contains(\"${yml}\")) | .Status" | tee "${status}" 93 | _log "status :: $(cat ${status})" 94 | 95 | # stop compose if running 96 | if grep -q "running" "${status}"; then 97 | docker compose "${dockerComposeArgs[@]}" stop 98 | else 99 | _log "${compose} is not running" 100 | fi 101 | fi 102 | 103 | path="${backuppath}/${compose}" 104 | _log "path :: ${path}" 105 | echo 106 | vollist="${path}/vol.list" 107 | if [ -f "${vollist}" ]; then 108 | while read -r line; do 109 | volnum="${line%%,*}" 110 | volpath="${line#*,}" 111 | args=(-avr) 112 | if [[ ! "${volpath}" == */ ]]; then 113 | volpath="$(dirname "${volpath}")" 114 | else 115 | args+=(--delete) 116 | fi 117 | src="${path}/${volnum}/" 118 | if [ ${volnum} -eq 0 ]; then 119 | volpath="${volpath}/${compose}/" 120 | volpath="${volpath//\/\//\/}" 121 | fi 122 | _log "Source :: ${src}" 123 | _log "Dest :: ${volpath}" 124 | if [ ${volnum} -eq 0 ]; then 125 | cp -v "${src}/${compose}.yml" "${src}/compose.override.yml" "${src}/${compose}.env" "${volpath}" 126 | else 127 | rsync "${args[@]}" "${src}" "${volpath}" 128 | fi 129 | done < "${vollist}" 130 | else 131 | _log "No volume list found." 132 | fi 133 | 134 | if [ ${skip} -ne 1 ]; then 135 | # start compose if running before backup 136 | if grep -q "running" "${status}"; then 137 | docker compose "${dockerComposeArgs[@]}" start 138 | fi 139 | 140 | rm -f "${status}" 141 | else 142 | # add compose file to database if it doesn't exist already 143 | xpath="//services/compose/files" 144 | if ! omv_config_exists "${xpath}/file[name='${compose}']"; then 145 | _log "Adding '${compose}' to the database..." 146 | composepath="${path}/0/${compose}" 147 | envfile="${composepath}.env" 148 | ymlfile="${composepath}.yml" 149 | envtxt="" 150 | ymltxt="" 151 | # escape for xml 152 | if [ -f "${envfile}" ]; then 153 | envtxt=$(sed -e 's/&/\&/g' -e 's//\>/g' "${envfile}") 154 | fi 155 | if [ -f "${ymlfile}" ]; then 156 | ymltxt=$(sed -e 's/&/\&/g' -e 's//\>/g' "${ymlfile}") 157 | fi 158 | if [ -n "${ymltxt}" ]; then 159 | # create backup of omv database 160 | date="$(date +'%Y-%m-%d_%H-%M-%S')" 161 | cp -fv "${OMV_CONFIG_FILE}" "/root/config_${date}.xml" 162 | # create database entry 163 | object="$(uuid)" 164 | object="${object}${compose}" 165 | object="${object}" 166 | object="${object}@@YAML_DATA@@" 167 | object="${object}@@ENV_DATA@@" 168 | # add new entry to database 169 | omv_config_add_node_data "${xpath}" "file" "${object}" 170 | # repalce temp variables with compose yaml and environment file 171 | omvdb=$(<"${OMV_CONFIG_FILE}") 172 | omvdbmod=$(awk -v env="${envtxt}" -v yml="${ymltxt}" '{gsub(/@@ENV_DATA@@/, env); gsub(/@@YAML_DATA@@/, yml)} 1' <<< "${omvdb}") 173 | echo "${omvdbmod}" > "${OMV_CONFIG_FILE}" 174 | # mark compose module dirty 175 | omv_module_set_dirty compose 176 | fi 177 | else 178 | _log "File exists in database." 179 | fi 180 | fi 181 | 182 | _log "Done." 183 | 184 | exit 0 185 | -------------------------------------------------------------------------------- /usr/sbin/omv-compose-restore-multi: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # shellcheck disable=SC1091,SC2086,SC2207,SC2162 4 | # 5 | # Copyright (c) 2023-2025 openmediavault plugin developers 6 | # 7 | # This file is licensed under the terms of the GNU General Public 8 | # License version 2. This program is licensed "as is" without any 9 | # warranty of any kind, whether express or implied. 10 | # 11 | # version: 0.9.2 12 | 13 | export LC_ALL=C.UTF-8 14 | 15 | . /usr/share/openmediavault/scripts/helper-functions 16 | 17 | filter=${1} 18 | 19 | if [ -z "${filter}" ]; then 20 | filter="*" 21 | fi 22 | 23 | if [[ "${filter}" == *","* ]]; then 24 | filter="@(${filter//,/|})" 25 | fi 26 | 27 | # Get the backup shared folder reference and path 28 | sfref=$(omv_config_get "/config/services/compose/backupsharedfolderref") 29 | if ! omv_isuuid "${sfref}"; then 30 | echo "No backup sharedfolder set." 31 | exit 13 32 | fi 33 | backuppath="$(omv_get_sharedfolder_path "${sfref}")" 34 | if [ ! -d "${backuppath}" ]; then 35 | echo "Backup shared folder directory does not exist. Exiting..." 36 | exit 14 37 | fi 38 | backuppath="${backuppath/%\/}" 39 | echo "Backup path :: ${backuppath}" 40 | 41 | find "${backuppath}" -mindepth 1 -maxdepth 1 -type d -iname "${filter}" | while read path; do 42 | echo "path :: ${path}" 43 | compose="$(basename "${path}")" 44 | echo "compose :: ${compose}" 45 | omv-compose-restore "${compose}" 46 | done 47 | 48 | exit 0 49 | -------------------------------------------------------------------------------- /usr/sbin/omv-compose-start: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # shellcheck disable=SC1091,SC2086,SC2207 4 | # 5 | # Copyright (c) 2023-2025 openmediavault plugin developers 6 | # 7 | # This file is licensed under the terms of the GNU General Public 8 | # License version 2. This program is licensed "as is" without any 9 | # warranty of any kind, whether express or implied. 10 | # 11 | # version: 0.0.1 12 | 13 | export LC_ALL=C.UTF-8 14 | 15 | declare -i timeout=180 16 | declare -i i=0 17 | 18 | . /usr/share/openmediavault/scripts/helper-functions 19 | 20 | # logging location 21 | logDir="/var/log/" 22 | logFile="${logDir}/omv-compose-start.log" 23 | 24 | _log() 25 | { 26 | msg=${1} 27 | echo "[$(date +'%Y-%m-%d %H:%M:%S%z')] [composestart] ${msg}" | tee -a ${logFile} >&2 28 | } 29 | 30 | compose="${1}" 31 | if [ -z "${compose}" ]; then 32 | _log "No compose name set. Exiting..." 33 | exit 10 34 | fi 35 | _log "compose :: ${compose}" 36 | 37 | # Get docker storage path 38 | dockerStorage=$(omv_config_get "/config/services/compose/dockerStorage") 39 | _log "Docker storage :: ${dockerStorage}" 40 | 41 | # Get the shared folder reference and path 42 | sfref=$(omv_config_get "/config/services/compose/sharedfolderref") 43 | if ! omv_isuuid "${sfref}"; then 44 | _log "No compose sharedfolder set." 45 | exit 11 46 | fi 47 | sfpath="$(omv_get_sharedfolder_path "${sfref}")" 48 | if [ ! -d "${sfpath}" ]; then 49 | _log "Shared folder directory does not exist. Exiting..." 50 | exit 12 51 | fi 52 | sfpath="${sfpath/%\/}" 53 | sfpath="${sfpath//\/\//\/}" 54 | _log "Compose file path :: ${sfpath}" 55 | 56 | # set path for yml and env files 57 | composepath="${sfpath}/${compose}" 58 | env="${composepath}/${compose}.env" 59 | globalenv="${sfpath}/global.env" 60 | ovr="${composepath}/compose.override.yml" 61 | yml="${composepath}/${compose}.yml" 62 | if [ ! -f "${yml}" ]; then 63 | _log "Compose file '${yml}' does not exist. Exiting..." 64 | exit 13 65 | fi 66 | _log "Compose file :: ${yml}" 67 | 68 | while pgrep -f omv-compose-backup -l > /dev/null; do 69 | _log "Backup is running. Waiting ... ${i}" 70 | sleep 10 71 | (( i++ )) 72 | if [ ${i} -gt ${timeout} ]; then 73 | _log "Timed out waiting. Exiting." 74 | exit 15 75 | fi 76 | done 77 | 78 | # build compose arguments 79 | dockerComposeArgs=("--file" "${yml}") 80 | if [ -f "${ovr}" ]; then 81 | dockerComposeArgs+=("--file" "${ovr}") 82 | fi 83 | if [ -f "${globalenv}" ]; then 84 | dockerComposeArgs+=("--env-file" "${globalenv}") 85 | fi 86 | dockerComposeArgs+=("--env-file" "${env}") 87 | 88 | # start container(s) 89 | _log "Starting container(s) ..." 90 | docker compose "${dockerComposeArgs[@]}" start 91 | 92 | _log "Done." 93 | 94 | exit 0 95 | -------------------------------------------------------------------------------- /usr/sbin/omv-compose-start-multi: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # shellcheck disable=SC1091,SC2053,SC2086,SC2162 4 | # 5 | # Copyright (c) 2023-2025 openmediavault plugin developers 6 | # 7 | # This file is licensed under the terms of the GNU General Public 8 | # License version 2. This program is licensed "as is" without any 9 | # warranty of any kind, whether express or implied. 10 | # 11 | # version: 0.0.1 12 | 13 | export LC_ALL=C.UTF-8 14 | 15 | declare -i count=0 16 | declare -i index=0 17 | 18 | . /usr/share/openmediavault/scripts/helper-functions 19 | 20 | filter="${1}" 21 | 22 | if [[ "${filter}" == "*" ]]; then 23 | filter="" 24 | elif [[ "${filter}" == *","* ]]; then 25 | filter="@(${filter//,/|})" 26 | fi 27 | 28 | xpath="/config/services/compose/files/file" 29 | count=$(omv_config_get_count "${xpath}") 30 | index=1 31 | while [ ${index} -le ${count} ]; do 32 | pos="${xpath}[position()=${index}]" 33 | name=$(omv_config_get "${pos}/name") 34 | if [ -n "${filter}" ] && [[ "${name}" != ${filter} ]]; then 35 | index=$(( index + 1 )) 36 | continue 37 | fi 38 | echo ${name} 39 | omv-compose-start "${name}" 40 | index=$(( index + 1 )) 41 | done; 42 | -------------------------------------------------------------------------------- /usr/sbin/omv-compose-stop: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # shellcheck disable=SC1091,SC2086,SC2207 4 | # 5 | # Copyright (c) 2023-2025 openmediavault plugin developers 6 | # 7 | # This file is licensed under the terms of the GNU General Public 8 | # License version 2. This program is licensed "as is" without any 9 | # warranty of any kind, whether express or implied. 10 | # 11 | # version: 0.0.1 12 | 13 | export LC_ALL=C.UTF-8 14 | 15 | declare -i timeout=180 16 | declare -i i=0 17 | 18 | . /usr/share/openmediavault/scripts/helper-functions 19 | 20 | # logging location 21 | logDir="/var/log/" 22 | logFile="${logDir}/omv-compose-stop.log" 23 | 24 | _log() 25 | { 26 | msg=${1} 27 | echo "[$(date +'%Y-%m-%d %H:%M:%S%z')] [composestop] ${msg}" | tee -a ${logFile} >&2 28 | } 29 | 30 | compose="${1}" 31 | if [ -z "${compose}" ]; then 32 | _log "No compose name set. Exiting..." 33 | exit 10 34 | fi 35 | _log "compose :: ${compose}" 36 | 37 | # Get docker storage path 38 | dockerStorage=$(omv_config_get "/config/services/compose/dockerStorage") 39 | _log "Docker storage :: ${dockerStorage}" 40 | 41 | # Get the shared folder reference and path 42 | sfref=$(omv_config_get "/config/services/compose/sharedfolderref") 43 | if ! omv_isuuid "${sfref}"; then 44 | _log "No compose sharedfolder set." 45 | exit 11 46 | fi 47 | sfpath="$(omv_get_sharedfolder_path "${sfref}")" 48 | if [ ! -d "${sfpath}" ]; then 49 | _log "Shared folder directory does not exist. Exiting..." 50 | exit 12 51 | fi 52 | sfpath="${sfpath/%\/}" 53 | sfpath="${sfpath//\/\//\/}" 54 | _log "Compose file path :: ${sfpath}" 55 | 56 | # set path for yml and env files 57 | composepath="${sfpath}/${compose}" 58 | env="${composepath}/${compose}.env" 59 | globalenv="${sfpath}/global.env" 60 | ovr="${composepath}/compose.override.yml" 61 | yml="${composepath}/${compose}.yml" 62 | if [ ! -f "${yml}" ]; then 63 | _log "Compose file '${yml}' does not exist. Exiting..." 64 | exit 13 65 | fi 66 | _log "Compose file :: ${yml}" 67 | 68 | while pgrep -f omv-compose-backup -l > /dev/null; do 69 | _log "Backup is running. Waiting ... ${i}" 70 | sleep 10 71 | (( i++ )) 72 | if [ ${i} -gt ${timeout} ]; then 73 | _log "Timed out waiting. Exiting." 74 | exit 15 75 | fi 76 | done 77 | 78 | # build compose arguments 79 | dockerComposeArgs=("--file" "${yml}") 80 | if [ -f "${ovr}" ]; then 81 | dockerComposeArgs+=("--file" "${ovr}") 82 | fi 83 | if [ -f "${globalenv}" ]; then 84 | dockerComposeArgs+=("--env-file" "${globalenv}") 85 | fi 86 | dockerComposeArgs+=("--env-file" "${env}") 87 | 88 | # stop container(s) 89 | _log "Stopping container(s) ..." 90 | docker compose "${dockerComposeArgs[@]}" stop 91 | 92 | _log "Done." 93 | 94 | exit 0 95 | -------------------------------------------------------------------------------- /usr/sbin/omv-compose-stop-multi: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # shellcheck disable=SC1091,SC2053,SC2086,SC2162 4 | # 5 | # Copyright (c) 2023-2025 openmediavault plugin developers 6 | # 7 | # This file is licensed under the terms of the GNU General Public 8 | # License version 2. This program is licensed "as is" without any 9 | # warranty of any kind, whether express or implied. 10 | # 11 | # version: 0.0.1 12 | 13 | export LC_ALL=C.UTF-8 14 | 15 | declare -i count=0 16 | declare -i index=0 17 | 18 | . /usr/share/openmediavault/scripts/helper-functions 19 | 20 | filter="${1}" 21 | 22 | if [[ "${filter}" == "*" ]]; then 23 | filter="" 24 | elif [[ "${filter}" == *","* ]]; then 25 | filter="@(${filter//,/|})" 26 | fi 27 | 28 | xpath="/config/services/compose/files/file" 29 | count=$(omv_config_get_count "${xpath}") 30 | index=1 31 | while [ ${index} -le ${count} ]; do 32 | pos="${xpath}[position()=${index}]" 33 | name=$(omv_config_get "${pos}/name") 34 | if [ -n "${filter}" ] && [[ "${name}" != ${filter} ]]; then 35 | index=$(( index + 1 )) 36 | continue 37 | fi 38 | echo ${name} 39 | omv-compose-stop "${name}" 40 | index=$(( index + 1 )) 41 | done; 42 | -------------------------------------------------------------------------------- /usr/sbin/omv-compose-update: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # shellcheck disable=SC1091,SC2086,SC2207 4 | # 5 | # Copyright (c) 2023-2025 openmediavault plugin developers 6 | # 7 | # This file is licensed under the terms of the GNU General Public 8 | # License version 2. This program is licensed "as is" without any 9 | # warranty of any kind, whether express or implied. 10 | # 11 | # version: 0.1.2 12 | 13 | export LC_ALL=C.UTF-8 14 | 15 | declare -i timeout=180 16 | declare -i i=0 17 | declare -A before_versions 18 | 19 | . /usr/share/openmediavault/scripts/helper-functions 20 | 21 | # logging location 22 | logDir="/var/log/" 23 | logFile="${logDir}/omv-compose-update.log" 24 | 25 | _log() 26 | { 27 | msg=${1} 28 | echo "[$(date +'%Y-%m-%d %H:%M:%S%z')] [composeupdate] ${msg}" | tee -a ${logFile} >&2 29 | } 30 | 31 | compose="${1}" 32 | if [ -z "${compose}" ]; then 33 | _log "No compose name set. Exiting..." 34 | exit 10 35 | fi 36 | _log "compose :: ${compose}" 37 | 38 | # Get docker storage path 39 | dockerStorage=$(omv_config_get "/config/services/compose/dockerStorage") 40 | _log "Docker storage :: ${dockerStorage}" 41 | 42 | # Get the shared folder reference and path 43 | sfref=$(omv_config_get "/config/services/compose/sharedfolderref") 44 | if ! omv_isuuid "${sfref}"; then 45 | _log "No compose sharedfolder set." 46 | exit 11 47 | fi 48 | sfpath="$(omv_get_sharedfolder_path "${sfref}")" 49 | if [ ! -d "${sfpath}" ]; then 50 | _log "Shared folder directory does not exist. Exiting..." 51 | exit 12 52 | fi 53 | sfpath="${sfpath/%\/}" 54 | sfpath="${sfpath//\/\//\/}" 55 | _log "Compose file path :: ${sfpath}" 56 | 57 | # set path for yml and env files 58 | composepath="${sfpath}/${compose}" 59 | env="${composepath}/${compose}.env" 60 | globalenv="${sfpath}/global.env" 61 | ovr="${composepath}/compose.override.yml" 62 | yml="${composepath}/${compose}.yml" 63 | if [ ! -f "${yml}" ]; then 64 | _log "Compose file '${yml}' does not exist. Exiting..." 65 | exit 13 66 | fi 67 | _log "Compose file :: ${yml}" 68 | 69 | yq="/usr/local/bin/yq" 70 | if [ ! -f "${yq}" ]; then 71 | _log "'${yq}' does not exist. Exiting..." 72 | exit 14 73 | fi 74 | 75 | while pgrep -f omv-compose-backup -l > /dev/null; do 76 | _log "Backup is running. Waiting ... ${i}" 77 | sleep 10 78 | (( i++ )) 79 | if [ ${i} -gt ${timeout} ]; then 80 | _log "Timed out waiting. Exiting." 81 | exit 15 82 | fi 83 | done 84 | 85 | # save status 86 | status="$(mktemp)" 87 | docker compose ls --all --format json | jq -r ".[] | select(.ConfigFiles | contains(\"${yml}\")) | .Status" | tee "${status}" 88 | _log "status :: $(cat ${status})" 89 | 90 | # log current image versions 91 | for image in $(sudo ${yq} .services.[].image "${yml}"); do 92 | version_before=$(docker image ls --format '{{.ID}},{{.Repository}}:{{.Tag}}' "${image}") 93 | _log "version before :: ${version_before}" 94 | before_versions["${image}"]="${version_before}" 95 | done 96 | 97 | # build compose arguments 98 | dockerComposeArgs=("--file" "${yml}") 99 | if [ -f "${ovr}" ]; then 100 | dockerComposeArgs+=("--file" "${ovr}") 101 | fi 102 | if [ -f "${globalenv}" ]; then 103 | dockerComposeArgs+=("--env-file" "${globalenv}") 104 | fi 105 | dockerComposeArgs+=("--env-file" "${env}") 106 | 107 | # pull new images 108 | _log "Pulling new images ..." 109 | docker compose "${dockerComposeArgs[@]}" pull 110 | 111 | # log image versions after update 112 | for image in $(sudo ${yq} .services.[].image "${yml}"); do 113 | version_after=$(docker image ls --format '{{.ID}},{{.Repository}}:{{.Tag}}' "${image}") 114 | if [ "${version_after}" != "${before_versions["${image}"]}" ]; then 115 | _log "version after :: ${version_after}" 116 | fi 117 | done 118 | 119 | # recreate containers with new images if running 120 | if grep -q "running" "${status}"; then 121 | _log "Recreating containers with new images ..." 122 | docker compose "${dockerComposeArgs[@]}" up -d 123 | fi 124 | 125 | rm -f "${status}" 126 | 127 | _log "Done." 128 | 129 | exit 0 130 | -------------------------------------------------------------------------------- /usr/sbin/omv-compose-update-multi: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # shellcheck disable=SC1091,SC2053,SC2086,SC2162 4 | # 5 | # Copyright (c) 2023-2025 openmediavault plugin developers 6 | # 7 | # This file is licensed under the terms of the GNU General Public 8 | # License version 2. This program is licensed "as is" without any 9 | # warranty of any kind, whether express or implied. 10 | # 11 | # version: 0.0.2 12 | 13 | export LC_ALL=C.UTF-8 14 | 15 | declare -i count=0 16 | declare -i index=0 17 | 18 | . /usr/share/openmediavault/scripts/helper-functions 19 | 20 | filter="${1}" 21 | 22 | if [[ "${filter}" == "*" ]]; then 23 | filter="" 24 | elif [[ "${filter}" == *","* ]]; then 25 | filter="@(${filter//,/|})" 26 | fi 27 | 28 | xpath="/config/services/compose/files/file" 29 | count=$(omv_config_get_count "${xpath}") 30 | index=1 31 | while [ ${index} -le ${count} ]; do 32 | pos="${xpath}[position()=${index}]" 33 | name=$(omv_config_get "${pos}/name") 34 | if [ -n "${filter}" ] && [[ "${name}" != ${filter} ]]; then 35 | index=$(( index + 1 )) 36 | continue 37 | fi 38 | echo ${name} 39 | omv-compose-update "${name}" 40 | index=$(( index + 1 )) 41 | done; 42 | -------------------------------------------------------------------------------- /usr/share/openmediavault/confdb/create.d/conf.service.compose.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # @license http://www.gnu.org/licenses/gpl.html GPL Version 3 4 | # @author OpenMediaVault Plugin Developers 5 | # @copyright Copyright (c) 2022-2025 openmediavault plugin developers 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program. If not, see . 19 | 20 | set -e 21 | 22 | . /etc/default/openmediavault 23 | . /usr/share/openmediavault/scripts/helper-functions 24 | 25 | if ! omv_config_exists "/config/services/compose"; then 26 | dockerPath="/var/lib/docker" 27 | if [ -f "/usr/bin/docker" ]; then 28 | dockerRoot="$(docker info | grep "Docker Root Dir:" | awk '{ print $4 }')" 29 | if [ -d "${dockerRoot}" ]; then 30 | dockerPath="${dockerRoot}" 31 | fi 32 | fi 33 | daemonJson="/etc/docker/daemon.json" 34 | if [ -f "${daemonJson}" ]; then 35 | if grep -qi nvidia ${daemonJson}; then 36 | dockerPath="" 37 | fi 38 | fi 39 | omv_config_add_node "/config/services" "compose" 40 | omv_config_add_key "/config/services/compose" "sharedfolderref" "" 41 | omv_config_add_key "/config/services/compose" "composeowner" "root" 42 | omv_config_add_key "/config/services/compose" "composegroup" "root" 43 | omv_config_add_key "/config/services/compose" "mode" "700" 44 | omv_config_add_key "/config/services/compose" "fileperms" "600" 45 | omv_config_add_key "/config/services/compose" "datasharedfolderref" "" 46 | omv_config_add_key "/config/services/compose" "backupsharedfolderref" "" 47 | omv_config_add_key "/config/services/compose" "backupmaxsize" "1" 48 | omv_config_add_key "/config/services/compose" "dockerStorage" "${dockerPath}" 49 | omv_config_add_key "/config/services/compose" "urlHostname" "" 50 | omv_config_add_key "/config/services/compose" "cachetimefiles" "60" 51 | omv_config_add_key "/config/services/compose" "cachetimeservices" "60" 52 | omv_config_add_key "/config/services/compose" "cachetimestats" "60" 53 | omv_config_add_key "/config/services/compose" "cachetimeimages" "60" 54 | omv_config_add_key "/config/services/compose" "cachetimenetworks" "60" 55 | omv_config_add_key "/config/services/compose" "cachetimevolumes" "60" 56 | omv_config_add_key "/config/services/compose" "cachetimecontainers" "60" 57 | omv_config_add_key "/config/services/compose" "showcmd" "0" 58 | omv_config_add_node "/config/services/compose" "files" 59 | omv_config_add_node "/config/services/compose" "configs" 60 | omv_config_add_node "/config/services/compose" "dockerfiles" 61 | omv_config_add_node "/config/services/compose" "jobs" 62 | omv_config_add_node "/config/services/compose" "globalenv" 63 | omv_config_add_key "/config/services/compose/globalenv" "enabled" "1" 64 | omv_config_add_key "/config/services/compose/globalenv" "globalenv" "" 65 | fi 66 | 67 | # download yq 68 | version="v4.45.2" 69 | bindir="/usr/local/bin" 70 | yq="${bindir}/yq" 71 | arch="$(dpkg --print-architecture)" 72 | case "${arch}" in 73 | armhf) arch="arm" ;; 74 | i386) arch="386" ;; 75 | esac 76 | repo_url=${OMV_EXTRAS_YQ_URL:-"https://github.com/mikefarah/yq/releases/download"} 77 | if [ ! -d "${bindir}" ]; then 78 | mkdir -p ${bindir} 79 | fi 80 | if [ ! -f "${yq}" ]; then 81 | echo "Downloading yq ..." 82 | wget -O ${yq} "${repo_url}/${version}/yq_linux_${arch}" 83 | else 84 | echo "Checking yq version ..." 85 | chmod 755 ${yq} 86 | yqvers="$(${yq} -V | awk '{ print $4 }')" 87 | if [ ! "${version}" = "${yqvers}" ]; then 88 | wget -O ${yq} "${repo_url}/${version}/yq_linux_${arch}" 89 | else 90 | echo "Correct version of yq installed - '${version}'" 91 | fi 92 | fi 93 | chmod 755 ${yq} 94 | 95 | # download regctl 96 | arch="$(dpkg --print-architecture)" 97 | if [ "${arch}" = "amd64" ] || [ "${arch}" = "arm64" ]; then 98 | version="v0.8.3" 99 | bindir="/usr/local/bin" 100 | regctl="${bindir}/regctl" 101 | repo_url=${OMV_EXTRAS_REGCTL_URL:-"https://github.com/regclient/regclient/releases/download"} 102 | if [ ! -f "${regctl}" ]; then 103 | echo "Downloading regctl ..." 104 | wget -O ${regctl} "${repo_url}/${version}/regctl-linux-${arch}" 105 | else 106 | echo "Checking regctl version ..." 107 | chmod 755 ${regctl} 108 | regctlvers="$(${regctl} version | awk '$1 == "VCSTag:" { print $2 }')" 109 | if [ ! "${version}" = "${regctlvers}" ]; then 110 | wget -O ${regctl} "${repo_url}/${version}/regctl-linux-${arch}" 111 | else 112 | echo "Correct version of regctl installed - '${version}'" 113 | fi 114 | fi 115 | chmod 755 ${regctl} 116 | fi 117 | 118 | # make sure log files exist to eliminate log viewer error 119 | for log in backup restore update; do 120 | file="/var/log/omv-compose-${log}.log" 121 | if [ ! -f "${file}" ]; then 122 | touch ${file} 123 | fi 124 | done 125 | 126 | # download icons 127 | echo "Downloading example file icons ..." 128 | omv-compose-download-icons 129 | 130 | exit 0 131 | -------------------------------------------------------------------------------- /usr/share/openmediavault/confdb/migrations.d/conf.service.compose_6.0.4.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | . /usr/share/openmediavault/scripts/helper-functions 6 | 7 | status=0 8 | 9 | echo "Updating database ..." 10 | xpath="/config/services/compose/files/file" 11 | count=$(omv_config_get_count "${xpath}"); 12 | index=1; 13 | while [ ${index} -le ${count} ]; do 14 | pos="${xpath}[position()=${index}]" 15 | if ! omv_config_exists "${pos}/env"; then 16 | omv_config_add_key "${pos}" "env" "" 17 | status=1 18 | fi 19 | index=$(( index + 1 )) 20 | done; 21 | 22 | if [ ${status} -eq 1 ]; then 23 | # update compose files and put in sub-directories 24 | echo "Regenerating compose files and moving to sub-directories ..." 25 | omv-salt deploy run compose 26 | 27 | # remove old compose files in root directory 28 | sfref=$(omv_config_get "/config/services/compose/sharedfolderref") 29 | sfpath=$(omv_get_sharedfolder_path "${sfref}") 30 | echo "Removing old compose files from ${sfpath} ..." 31 | if [ -d "${sfpath}" ] && [ ! "${sfpath}" = "/" ]; then 32 | find "${sfpath}" -maxdepth 1 -type f -name "*.yml" -print -delete 33 | fi 34 | fi 35 | 36 | exit 0 37 | 38 | -------------------------------------------------------------------------------- /usr/share/openmediavault/confdb/migrations.d/conf.service.compose_6.11.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | . /usr/share/openmediavault/scripts/helper-functions 6 | 7 | status=0 8 | 9 | echo "Updating database ..." 10 | xpath="/config/services/compose/jobs/job" 11 | count=$(omv_config_get_count "${xpath}"); 12 | index=1; 13 | while [ ${index} -le ${count} ]; do 14 | pos="${xpath}[position()=${index}]" 15 | if ! omv_config_exists "${pos}/backup"; then 16 | omv_config_add_key "${pos}" "backup" "1" 17 | status=1 18 | fi 19 | if ! omv_config_exists "${pos}/update"; then 20 | omv_config_add_key "${pos}" "update" "0" 21 | status=1 22 | fi 23 | index=$(( index + 1 )) 24 | done; 25 | 26 | if [ ${status} -eq 1 ]; then 27 | # update jobs to add backup and update fields 28 | echo "Regenerating jobs to add backup and update fields ..." 29 | omv-salt deploy run compose 30 | fi 31 | 32 | exit 0 33 | 34 | -------------------------------------------------------------------------------- /usr/share/openmediavault/confdb/migrations.d/conf.service.compose_6.4.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | . /usr/share/openmediavault/scripts/helper-functions 6 | 7 | if ! omv_config_exists "/config/services/compose/dockerfiles"; then 8 | omv_config_add_node "/config/services/compose" "dockerfiles" "" 9 | fi 10 | 11 | exit 0 12 | 13 | -------------------------------------------------------------------------------- /usr/share/openmediavault/confdb/migrations.d/conf.service.compose_6.7.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | . /usr/share/openmediavault/scripts/helper-functions 6 | 7 | if ! omv_config_exists "/config/services/compose/dockerStorage"; then 8 | dockerPath="/var/lib/docker" 9 | if [ -f "/usr/bin/docker" ]; then 10 | dockerRoot="$(docker info | grep "Docker Root Dir:" | awk '{ print $4 }')" 11 | if [ -d "${dockerRoot}" ]; then 12 | dockerPath="${dockerRoot}" 13 | fi 14 | fi 15 | omv_config_add_key "/config/services/compose" "dockerStorage" "${dockerPath}" 16 | fi 17 | 18 | exit 0 19 | 20 | -------------------------------------------------------------------------------- /usr/share/openmediavault/confdb/migrations.d/conf.service.compose_6.9.1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | . /usr/share/openmediavault/scripts/helper-functions 6 | 7 | if ! omv_config_exists "/config/services/compose/composeowner"; then 8 | omv_config_add_key "/config/services/compose" "composeowner" "root" 9 | omv_module_set_dirty compose 10 | fi 11 | if ! omv_config_exists "/config/services/compose/composegroup"; then 12 | omv_config_add_key "/config/services/compose" "composegroup" "root" 13 | fi 14 | if ! omv_config_exists "/config/services/compose/mode"; then 15 | omv_config_add_key "/config/services/compose" "mode" "700" 16 | fi 17 | if ! omv_config_exists "/config/services/compose/fileperms"; then 18 | omv_config_add_key "/config/services/compose" "fileperms" "600" 19 | fi 20 | 21 | exit 0 22 | -------------------------------------------------------------------------------- /usr/share/openmediavault/confdb/migrations.d/conf.service.compose_6.9.2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | . /usr/share/openmediavault/scripts/helper-functions 6 | 7 | if ! omv_config_exists "/config/services/compose/datasharedfolderref"; then 8 | omv_config_add_key "/config/services/compose" "datasharedfolderref" "" 9 | fi 10 | 11 | exit 0 12 | 13 | -------------------------------------------------------------------------------- /usr/share/openmediavault/confdb/migrations.d/conf.service.compose_6.9.6.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | . /usr/share/openmediavault/scripts/helper-functions 6 | 7 | if ! omv_config_exists "/config/services/compose/globalenv"; then 8 | omv_config_add_node "/config/services/compose" "globalenv" 9 | omv_config_add_key "/config/services/compose/globalenv" "enabled" "1" 10 | omv_config_add_key "/config/services/compose/globalenv" "globalenv" "" 11 | fi 12 | 13 | exit 0 14 | 15 | -------------------------------------------------------------------------------- /usr/share/openmediavault/confdb/migrations.d/conf.service.compose_6.9.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | . /usr/share/openmediavault/scripts/helper-functions 6 | 7 | if ! omv_config_exists "/config/services/compose/backupsharedfolderref"; then 8 | omv_config_add_key "/config/services/compose" "backupsharedfolderref" "" 9 | fi 10 | if ! omv_config_exists "/config/services/compose/backupmaxsize"; then 11 | omv_config_add_key "/config/services/compose" "backupmaxsize" "1" 12 | fi 13 | if ! omv_config_exists "/config/services/compose/jobs"; then 14 | omv_config_add_node "/config/services/compose" "jobs" 15 | fi 16 | 17 | exit 0 18 | 19 | -------------------------------------------------------------------------------- /usr/share/openmediavault/confdb/migrations.d/conf.service.compose_7.0.2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | . /usr/share/openmediavault/scripts/helper-functions 6 | 7 | status=0 8 | 9 | echo "Updating database ..." 10 | xpath="/config/services/compose/jobs/job" 11 | count=$(omv_config_get_count "${xpath}"); 12 | index=1; 13 | while [ ${index} -le ${count} ]; do 14 | pos="${xpath}[position()=${index}]" 15 | if ! omv_config_exists "${pos}/prune"; then 16 | omv_config_add_key "${pos}" "prune" "0" 17 | status=1 18 | fi 19 | index=$(( index + 1 )) 20 | done; 21 | 22 | if [ ${status} -eq 1 ]; then 23 | omv_module_set_dirty compose 24 | fi 25 | 26 | exit 0 27 | 28 | -------------------------------------------------------------------------------- /usr/share/openmediavault/confdb/migrations.d/conf.service.compose_7.0.8.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | . /usr/share/openmediavault/scripts/helper-functions 6 | 7 | echo "Updating database ..." 8 | xpath="/config/services/compose/jobs/job" 9 | count=$(omv_config_get_count "${xpath}"); 10 | index=1; 11 | while [ ${index} -le ${count} ]; do 12 | pos="${xpath}[position()=${index}]" 13 | if ! omv_config_exists "${pos}/prebackup"; then 14 | omv_config_add_key "${pos}" "prebackup" "" 15 | fi 16 | if ! omv_config_exists "${pos}/postbackup"; then 17 | omv_config_add_key "${pos}" "postbackup" "" 18 | fi 19 | index=$(( index + 1 )) 20 | done; 21 | 22 | omv_module_set_dirty compose 23 | 24 | exit 0 25 | 26 | -------------------------------------------------------------------------------- /usr/share/openmediavault/confdb/migrations.d/conf.service.compose_7.1.4.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | . /usr/share/openmediavault/scripts/helper-functions 6 | 7 | omv_module_set_dirty compose 8 | 9 | exit 0 10 | 11 | -------------------------------------------------------------------------------- /usr/share/openmediavault/confdb/migrations.d/conf.service.compose_7.2.4.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | . /usr/share/openmediavault/scripts/helper-functions 6 | 7 | if ! omv_config_exists "/config/services/compose/urlHostname"; then 8 | omv_config_add_key "/config/services/compose" "urlHostname" "" 9 | fi 10 | 11 | exit 0 12 | 13 | -------------------------------------------------------------------------------- /usr/share/openmediavault/confdb/migrations.d/conf.service.compose_7.2.5.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | . /usr/share/openmediavault/scripts/helper-functions 6 | 7 | status=0 8 | 9 | echo "Updating database ..." 10 | xpath="/config/services/compose/files/file" 11 | count=$(omv_config_get_count "${xpath}"); 12 | index=1; 13 | while [ ${index} -le ${count} ]; do 14 | pos="${xpath}[position()=${index}]" 15 | if ! omv_config_exists "${pos}/override"; then 16 | omv_config_add_key "${pos}" "override" "" 17 | fi 18 | index=$(( index + 1 )) 19 | done; 20 | 21 | omv_module_set_dirty compose 22 | 23 | exit 0 24 | 25 | -------------------------------------------------------------------------------- /usr/share/openmediavault/confdb/migrations.d/conf.service.compose_7.2.8.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | . /usr/share/openmediavault/scripts/helper-functions 6 | 7 | if ! omv_config_exists "/config/services/compose/showcmd"; then 8 | omv_config_add_key "/config/services/compose" "showcmd" "0" 9 | fi 10 | 11 | xpath="/config/services/compose/files/file" 12 | count=$(omv_config_get_count "${xpath}"); 13 | index=1; 14 | while [ ${index} -le ${count} ]; do 15 | pos="${xpath}[position()=${index}]" 16 | if ! omv_config_exists "${pos}/showenv"; then 17 | omv_config_add_key "${pos}" "showenv" "0" 18 | fi 19 | if ! omv_config_exists "${pos}/showoverride"; then 20 | omv_config_add_key "${pos}" "showoverride" "0" 21 | fi 22 | index=$(( index + 1 )) 23 | done; 24 | 25 | exit 0 26 | 27 | -------------------------------------------------------------------------------- /usr/share/openmediavault/confdb/migrations.d/conf.service.compose_7.2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | . /usr/share/openmediavault/scripts/helper-functions 6 | 7 | xpath="/config/services/compose" 8 | keys=("files" "services" "stats" "images" "networks" "volumes" "containers") 9 | 10 | for key in "${keys[@]}"; do 11 | if ! omv_config_exists "${xpath}/cachetime${key}"; then 12 | omv_config_add_key "${xpath}" "cachetime${key}" "60" 13 | fi 14 | done 15 | 16 | exit 0 17 | 18 | -------------------------------------------------------------------------------- /usr/share/openmediavault/confdb/migrations.d/conf.service.compose_7.3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | . /usr/share/openmediavault/scripts/helper-functions 6 | 7 | if ! omv_config_exists "/config/services/compose/configs"; then 8 | omv_config_add_node "/config/services/compose" "configs" 9 | fi 10 | 11 | xpath="/config/services/compose/jobs/job" 12 | count=$(omv_config_get_count "${xpath}"); 13 | index=1; 14 | while [ ${index} -le ${count} ]; do 15 | pos="${xpath}[position()=${index}]" 16 | if ! omv_config_exists "${pos}/excludes"; then 17 | omv_config_add_key "${pos}" "excludes" "" 18 | fi 19 | index=$(( index + 1 )) 20 | done; 21 | 22 | exit 0 23 | 24 | -------------------------------------------------------------------------------- /usr/share/openmediavault/confdb/migrations.d/conf.service.compose_7.4.3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | . /usr/share/openmediavault/scripts/helper-functions 6 | 7 | status=0 8 | 9 | echo "Updating database ..." 10 | xpath="/config/services/compose/jobs/job" 11 | count=$(omv_config_get_count "${xpath}"); 12 | index=1; 13 | while [ ${index} -le ${count} ]; do 14 | pos="${xpath}[position()=${index}]" 15 | if ! omv_config_exists "${pos}/filestart"; then 16 | omv_config_add_key "${pos}" "filestart" "0" 17 | status=1 18 | fi 19 | if ! omv_config_exists "${pos}/filestop"; then 20 | omv_config_add_key "${pos}" "filestop" "0" 21 | status=1 22 | fi 23 | index=$(( index + 1 )) 24 | done; 25 | 26 | if [ ${status} -eq 1 ]; then 27 | omv_module_set_dirty compose 28 | fi 29 | 30 | exit 0 31 | 32 | -------------------------------------------------------------------------------- /usr/share/openmediavault/confdb/migrations.d/conf.service.compose_7.5.0.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | . /usr/share/openmediavault/scripts/helper-functions 6 | 7 | status=0 8 | 9 | echo "Updating database ..." 10 | 11 | if ! omv_config_exists "/config/services/compose/execenable"; then 12 | omv_config_add_key "/config/services/compose" "execenable" 0 13 | status=1 14 | fi 15 | 16 | if ! omv_config_exists "/config/services/compose/host"; then 17 | omv_config_add_key "/config/services/compose" "host" "0.0.0.0" 18 | status=1 19 | fi 20 | 21 | if ! omv_config_exists "/config/services/compose/port"; then 22 | omv_config_add_key "/config/services/compose" "port" "5000" 23 | status=1 24 | fi 25 | 26 | if ! omv_config_exists "/config/services/compose/debug"; then 27 | omv_config_add_key "/config/services/compose" "debug" "0" 28 | status=1 29 | fi 30 | 31 | xpath="/config/services/compose/jobs/job" 32 | count=$(omv_config_get_count "${xpath}"); 33 | index=1; 34 | while [ ${index} -le ${count} ]; do 35 | pos="${xpath}[position()=${index}]" 36 | if ! omv_config_exists "${pos}/verbose"; then 37 | omv_config_add_key "${pos}" "verbose" "1" 38 | status=1 39 | fi 40 | index=$(( index + 1 )) 41 | done; 42 | 43 | if [ ${status} -eq 1 ]; then 44 | omv_module_set_dirty compose 45 | fi 46 | 47 | exit 0 48 | -------------------------------------------------------------------------------- /usr/share/openmediavault/confdb/migrations.d/conf.service.compose_7.5.3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | . /usr/share/openmediavault/scripts/helper-functions 6 | 7 | echo "Updating database ..." 8 | 9 | if ! omv_config_exists "/config/services/compose/hostshell"; then 10 | omv_config_add_key "/config/services/compose" "hostshell" "0" 11 | omv_module_set_dirty compose 12 | fi 13 | 14 | exit 0 15 | -------------------------------------------------------------------------------- /usr/share/openmediavault/confdb/migrations.d/conf.service.compose_7.6.0.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | . /usr/share/openmediavault/scripts/helper-functions 6 | 7 | echo "Updating database ..." 8 | 9 | change=0 10 | 11 | for i in execenable host port debug hostshell; do 12 | if omv_config_exists "/config/services/compose/${i}"; then 13 | omv_config_delete "/config/services/compose/${i}" 14 | change=1 15 | fi 16 | done 17 | 18 | if [ ${change} -eq 1 ]; then 19 | # stop and remove service 20 | term="omv_compose_term.service" 21 | unit="/etc/systemd/system/${term}" 22 | if [ -f "${unit}" ]; then 23 | systemctl stop "${term}" || : 24 | rm -fv "${unit}" 25 | systemctl daemon-reload 26 | fi 27 | rm -rfv /opt/omv_compose_term 28 | rm -fv /etc/omv_compose_term.conf 29 | omv_module_set_dirty compose 30 | fi 31 | 32 | exit 0 33 | -------------------------------------------------------------------------------- /usr/share/openmediavault/confdb/migrations.d/conf.service.compose_7.6.2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | . /usr/share/openmediavault/scripts/helper-functions 6 | 7 | echo "Updating database ..." 8 | 9 | change=0 10 | 11 | for i in execenable host port debug hostshell; do 12 | if omv_config_exists "/config/services/compose/${i}"; then 13 | omv_config_delete "/config/services/compose/${i}" 14 | change=1 15 | fi 16 | done 17 | 18 | exit 0 19 | -------------------------------------------------------------------------------- /usr/share/openmediavault/confdb/migrations.d/conf.service.compose_7.6.3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | grp="dockerterm" 4 | 5 | if getent group "${grp}" > /dev/null; then 6 | groupdel --force "${grp}" 7 | fi 8 | 9 | exit 0 10 | -------------------------------------------------------------------------------- /usr/share/openmediavault/datamodels/conf.service.compose.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "config", 3 | "id": "conf.service.compose.config", 4 | "title": "additional files for compose", 5 | "queryinfo": { 6 | "xpath": "//services/compose/configs/config", 7 | "iterable": true, 8 | "idproperty": "uuid" 9 | }, 10 | "properties": { 11 | "uuid": { 12 | "type": "string", 13 | "format": "uuidv4" 14 | }, 15 | "name": { 16 | "type": "string" 17 | }, 18 | "description": { 19 | "type": "string" 20 | }, 21 | "fileref": { 22 | "type": "string", 23 | "format": "uuidv4" 24 | }, 25 | "body": { 26 | "type": "string" 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /usr/share/openmediavault/datamodels/conf.service.compose.dockerfile.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "config", 3 | "id": "conf.service.compose.dockerfile", 4 | "title": "dockerfile", 5 | "queryinfo": { 6 | "xpath": "//services/compose/dockerfiles/dockerfile", 7 | "iterable": true, 8 | "idproperty": "uuid" 9 | }, 10 | "properties": { 11 | "uuid": { 12 | "type": "string", 13 | "format": "uuidv4" 14 | }, 15 | "name": { 16 | "type": "string" 17 | }, 18 | "description": { 19 | "type": "string" 20 | }, 21 | "body": { 22 | "type": "string" 23 | }, 24 | "script": { 25 | "type": "string" 26 | }, 27 | "scriptfile": { 28 | "type": "string" 29 | }, 30 | "conf": { 31 | "type": "string" 32 | }, 33 | "conffile": { 34 | "type": "string" 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /usr/share/openmediavault/datamodels/conf.service.compose.file.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "config", 3 | "id": "conf.service.compose.file", 4 | "title": "compose file", 5 | "queryinfo": { 6 | "xpath": "//services/compose/files/file", 7 | "iterable": true, 8 | "idproperty": "uuid" 9 | }, 10 | "properties": { 11 | "uuid": { 12 | "type": "string", 13 | "format": "uuidv4" 14 | }, 15 | "name": { 16 | "type": "string" 17 | }, 18 | "description": { 19 | "type": "string" 20 | }, 21 | "body": { 22 | "type": "string" 23 | }, 24 | "showenv": { 25 | "type": "boolean" 26 | }, 27 | "env": { 28 | "type": "string" 29 | }, 30 | "showoverride": { 31 | "type": "boolean" 32 | }, 33 | "override": { 34 | "type": "string" 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /usr/share/openmediavault/datamodels/conf.service.compose.globalenv.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "config", 3 | "id": "conf.service.compose.globalenv", 4 | "title": "global environment file", 5 | "queryinfo": { 6 | "xpath": "//services/compose/globalenv", 7 | "iterable": false 8 | }, 9 | "properties": { 10 | "enabled": { 11 | "type": "boolean" 12 | }, 13 | "globalenv": { 14 | "type": "string" 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /usr/share/openmediavault/datamodels/conf.service.compose.job.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "config", 3 | "id": "conf.service.compose.job", 4 | "title": "compose backup scheduled job", 5 | "queryinfo": { 6 | "xpath": "//services/compose/jobs/job", 7 | "iterable": true, 8 | "idproperty": "uuid" 9 | }, 10 | "properties": { 11 | "uuid": { 12 | "type": "string", 13 | "format": "uuidv4" 14 | }, 15 | "enable": { 16 | "type": "boolean", 17 | "default": false 18 | }, 19 | "filter": { 20 | "type": "string", 21 | "default": "" 22 | }, 23 | "backup": { 24 | "type": "boolean", 25 | "default": true 26 | }, 27 | "prebackup": { 28 | "type": "string", 29 | "default": "" 30 | }, 31 | "postbackup": { 32 | "type": "string", 33 | "default": "" 34 | }, 35 | "update": { 36 | "type": "boolean", 37 | "default": false 38 | }, 39 | "prune": { 40 | "type": "boolean", 41 | "default": false 42 | }, 43 | "filestart": { 44 | "type": "boolean", 45 | "default": false 46 | }, 47 | "filestop": { 48 | "type": "boolean", 49 | "default": false 50 | }, 51 | "sendemail": { 52 | "type": "boolean", 53 | "default": false 54 | }, 55 | "verbose": { 56 | "type": "boolean", 57 | "default": true 58 | }, 59 | "comment": { 60 | "type": "string", 61 | "default": "" 62 | }, 63 | "excludes": { 64 | "type": "string", 65 | "default": "" 66 | }, 67 | "execution": { 68 | "type": "string", 69 | "enum": [ 70 | "exactly", 71 | "hourly", 72 | "daily", 73 | "weekly", 74 | "monthly", 75 | "yearly", 76 | "reboot" 77 | ], 78 | "default": "exactly" 79 | }, 80 | "minute": { 81 | "type": "string", 82 | "pattern": "^[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[*]$", 83 | "default": 0 84 | }, 85 | "everynminute": { 86 | "type": "boolean", 87 | "default": false 88 | }, 89 | "hour": { 90 | "type": "string", 91 | "pattern": "^[0-9]|1[0-9]|2[0-3]|[*]$", 92 | "default": 0 93 | }, 94 | "everynhour": { 95 | "type": "boolean", 96 | "default": false 97 | }, 98 | "month": { 99 | "type": "string", 100 | "pattern": "^[1-9]|1[0-2]|[*]$", 101 | "default": "*" 102 | }, 103 | "dayofmonth": { 104 | "type": "string", 105 | "pattern": "^[1-9]|1[0-9]|2[0-9]|3[0-1]|[*]$", 106 | "default": "*" 107 | }, 108 | "everyndayofmonth": { 109 | "type": "boolean", 110 | "default": false 111 | }, 112 | "dayofweek": { 113 | "type": "string", 114 | "pattern": "^[1-7]|[*]$", 115 | "default": "*" 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /usr/share/openmediavault/datamodels/conf.service.compose.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "config", 3 | "id": "conf.service.compose", 4 | "title": "compose", 5 | "queryinfo": { 6 | "xpath": "//services/compose", 7 | "iterable": false 8 | }, 9 | "properties": { 10 | "sharedfolderref": { 11 | "type": "string", 12 | "oneOf": [ 13 | { 14 | "type": "string", 15 | "format": "uuidv4" 16 | }, 17 | { 18 | "type": "string", 19 | "maxLength": 0 20 | } 21 | ] 22 | }, 23 | "composeowner": { 24 | "type": "string", 25 | "default": "root" 26 | }, 27 | "composegroup": { 28 | "type": "string", 29 | "default": "root" 30 | }, 31 | "mode": { 32 | "type": "string", 33 | "default": "700" 34 | }, 35 | "fileperms": { 36 | "type": "string", 37 | "default": "600" 38 | }, 39 | "datasharedfolderref": { 40 | "type": "string", 41 | "oneOf": [ 42 | { 43 | "type": "string", 44 | "format": "uuidv4" 45 | }, 46 | { 47 | "type": "string", 48 | "maxLength": 0 49 | } 50 | ] 51 | }, 52 | "backupsharedfolderref": { 53 | "type": "string", 54 | "oneOf": [ 55 | { 56 | "type": "string", 57 | "format": "uuidv4" 58 | }, 59 | { 60 | "type": "string", 61 | "maxLength": 0 62 | } 63 | ] 64 | }, 65 | "backupmaxsize": { 66 | "type": "integer", 67 | "minimum": 0, 68 | "maximum": 65535, 69 | "default": 1 70 | }, 71 | "dockerStorage": { 72 | "type": "string", 73 | "default": "/var/lib/docker" 74 | }, 75 | "urlHostname": { 76 | "type": "string", 77 | "default": "" 78 | }, 79 | "cachetimefiles": { 80 | "type": "integer", 81 | "minimum": 0, 82 | "maximum": 65535, 83 | "default": 60 84 | }, 85 | "cachetimeservices": { 86 | "type": "integer", 87 | "minimum": 0, 88 | "maximum": 65535, 89 | "default": 60 90 | }, 91 | "cachetimestats": { 92 | "type": "integer", 93 | "minimum": 0, 94 | "maximum": 65535, 95 | "default": 60 96 | }, 97 | "cachetimeimages": { 98 | "type": "integer", 99 | "minimum": 0, 100 | "maximum": 65535, 101 | "default": 60 102 | }, 103 | "cachetimenetworks": { 104 | "type": "integer", 105 | "minimum": 0, 106 | "maximum": 65535, 107 | "default": 60 108 | }, 109 | "cachetimevolumes": { 110 | "type": "integer", 111 | "minimum": 0, 112 | "maximum": 65535, 113 | "default": 60 114 | }, 115 | "cachetimecontainers": { 116 | "type": "integer", 117 | "minimum": 0, 118 | "maximum": 65535, 119 | "default": 60 120 | }, 121 | "showcmd": { 122 | "type": "boolean" 123 | }, 124 | "files": { 125 | "type": "object", 126 | "properties": { 127 | "file": { 128 | "type": "array", 129 | "items": { 130 | "type": "object", 131 | "properties": { 132 | "uuid": { 133 | "type": "string", 134 | "format": "uuidv4" 135 | }, 136 | "name": { 137 | "type": "string" 138 | }, 139 | "description": { 140 | "type": "string" 141 | }, 142 | "body": { 143 | "type": "string" 144 | }, 145 | "showenv": { 146 | "type": "boolean" 147 | }, 148 | "env": { 149 | "type": "string" 150 | }, 151 | "showoverride": { 152 | "type": "boolean" 153 | }, 154 | "override": { 155 | "type": "string" 156 | } 157 | } 158 | } 159 | } 160 | } 161 | }, 162 | "configs": { 163 | "type": "object", 164 | "properties": { 165 | "config": { 166 | "type": "array", 167 | "items": { 168 | "type": "object", 169 | "properties": { 170 | "uuid": { 171 | "type": "string", 172 | "format": "uuidv4" 173 | }, 174 | "name": { 175 | "type": "string" 176 | }, 177 | "description": { 178 | "type": "string" 179 | }, 180 | "fileref": { 181 | "type": "string", 182 | "format": "uuidv4" 183 | }, 184 | "body": { 185 | "type": "string" 186 | } 187 | } 188 | } 189 | } 190 | } 191 | }, 192 | "dockerfiles": { 193 | "type": "object", 194 | "properties": { 195 | "dockerfile": { 196 | "type": "array", 197 | "items": { 198 | "type": "object", 199 | "properties": { 200 | "uuid": { 201 | "type": "string", 202 | "format": "uuidv4" 203 | }, 204 | "name": { 205 | "type": "string" 206 | }, 207 | "description": { 208 | "type": "string" 209 | }, 210 | "body": { 211 | "type": "string" 212 | }, 213 | "script": { 214 | "type": "string" 215 | }, 216 | "scriptfile": { 217 | "type": "string" 218 | }, 219 | "conf": { 220 | "type": "string" 221 | }, 222 | "conffile": { 223 | "type": "string" 224 | } 225 | } 226 | } 227 | } 228 | } 229 | }, 230 | "jobs": { 231 | "type": "object", 232 | "properties": { 233 | "job": { 234 | "type": "array", 235 | "items": { 236 | "type": "object", 237 | "properties": { 238 | "uuid": { 239 | "type": "string", 240 | "format": "uuidv4" 241 | }, 242 | "enable": { 243 | "type": "boolean" 244 | }, 245 | "filter": { 246 | "type": "string" 247 | }, 248 | "backup": { 249 | "type": "boolean" 250 | }, 251 | "prebackup": { 252 | "type": "string" 253 | }, 254 | "postbackup": { 255 | "type": "string" 256 | }, 257 | "update": { 258 | "type": "boolean" 259 | }, 260 | "prune": { 261 | "type": "boolean" 262 | }, 263 | "filestart": { 264 | "type": "boolean" 265 | }, 266 | "filestop": { 267 | "type": "boolean" 268 | }, 269 | "sendemail": { 270 | "type": "boolean" 271 | }, 272 | "verbose": { 273 | "type": "boolean" 274 | }, 275 | "comment": { 276 | "type": "string" 277 | }, 278 | "excludes": { 279 | "type": "string" 280 | }, 281 | "execution": { 282 | "type": "string", 283 | "enum": [ 284 | "exactly", 285 | "hourly", 286 | "daily", 287 | "weekly", 288 | "monthly", 289 | "yearly", 290 | "reboot" 291 | ], 292 | "default": "exactly" 293 | }, 294 | "minute": { 295 | "type": "string", 296 | "pattern": "^[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[*]$", 297 | "default": 0 298 | }, 299 | "everynminute": { 300 | "type": "boolean", 301 | "default": false 302 | }, 303 | "hour": { 304 | "type": "string", 305 | "pattern": "^[0-9]|1[0-9]|2[0-3]|[*]$", 306 | "default": 0 307 | }, 308 | "everynhour": { 309 | "type": "boolean", 310 | "default": false 311 | }, 312 | "month": { 313 | "type": "string", 314 | "pattern": "^[1-9]|1[0-2]|[*]$", 315 | "default": "*" 316 | }, 317 | "dayofmonth": { 318 | "type": "string", 319 | "pattern": "^[1-9]|1[0-9]|2[0-9]|3[0-1]|[*]$", 320 | "default": "*" 321 | }, 322 | "everyndayofmonth": { 323 | "type": "boolean", 324 | "default": false 325 | }, 326 | "dayofweek": { 327 | "type": "string", 328 | "pattern": "^[1-7]|[*]$", 329 | "default": "*" 330 | } 331 | } 332 | } 333 | } 334 | } 335 | }, 336 | "globalenv": { 337 | "type": "object", 338 | "properties": { 339 | "enabled": { 340 | "type": "boolean" 341 | }, 342 | "globalenv": { 343 | "type": "string" 344 | } 345 | } 346 | } 347 | } 348 | } 349 | -------------------------------------------------------------------------------- /usr/share/openmediavault/engined/inc/90composebackup.inc: -------------------------------------------------------------------------------- 1 | . 18 | */ 19 | require_once("openmediavault/functions.inc"); 20 | 21 | \OMV\System\LogFileSpec::registerSpecification("omv-compose-backup", [ 22 | "filename" => "omv-compose-backup.log", 23 | "filepath" => "/var/log/omv-compose-backup.log", 24 | "regex" => "/^\[((.*?)\s+(.*?))\]\s+\[(.*?)\]\s+(.*?)$/", 25 | "columns" => [ 26 | "date" => 1, 27 | "action" => 4, 28 | "message" => 5 29 | ] 30 | ]); 31 | 32 | \OMV\System\LogFileSpec::registerSpecification("omv-compose-restore", [ 33 | "filename" => "omv-compose-restore.log", 34 | "filepath" => "/var/log/omv-compose-restore.log", 35 | "regex" => "/^\[((.*?)\s+(.*?))\]\s+\[(.*?)\]\s+(.*?)$/", 36 | "columns" => [ 37 | "date" => 1, 38 | "action" => 4, 39 | "message" => 5 40 | ] 41 | ]); 42 | 43 | \OMV\System\LogFileSpec::registerSpecification("omv-compose-update", [ 44 | "filename" => "omv-compose-update.log", 45 | "filepath" => "/var/log/omv-compose-update.log", 46 | "regex" => "/^\[((.*?)\s+(.*?))\]\s+\[(.*?)\]\s+(.*?)$/", 47 | "columns" => [ 48 | "date" => 1, 49 | "action" => 4, 50 | "message" => 5 51 | ] 52 | ]); 53 | 54 | \OMV\System\LogFileSpec::registerSpecification("omv-compose-start", [ 55 | "filename" => "omv-compose-start.log", 56 | "filepath" => "/var/log/omv-compose-start.log", 57 | "regex" => "/^\[((.*?)\s+(.*?))\]\s+\[(.*?)\]\s+(.*?)$/", 58 | "columns" => [ 59 | "date" => 1, 60 | "action" => 4, 61 | "message" => 5 62 | ] 63 | ]); 64 | 65 | \OMV\System\LogFileSpec::registerSpecification("omv-compose-stop", [ 66 | "filename" => "omv-compose-stop.log", 67 | "filepath" => "/var/log/omv-compose-stop.log", 68 | "regex" => "/^\[((.*?)\s+(.*?))\]\s+\[(.*?)\]\s+(.*?)$/", 69 | "columns" => [ 70 | "date" => 1, 71 | "action" => 4, 72 | "message" => 5 73 | ] 74 | ]); 75 | -------------------------------------------------------------------------------- /usr/share/openmediavault/engined/module/compose.inc: -------------------------------------------------------------------------------- 1 | . 18 | */ 19 | 20 | class OMVModuleCompose extends \OMV\Engine\Module\ServiceAbstract 21 | implements \OMV\Engine\Notify\IListener, \OMV\Engine\Module\IServiceStatus 22 | { 23 | public function getName() 24 | { 25 | return "compose"; 26 | } 27 | 28 | public function getStatus() 29 | { 30 | if (file_exists("/lib/systemd/system/docker.service")) { 31 | $systemCtl = new \OMV\System\SystemCtl("docker"); 32 | $enabled = $systemCtl->isEnabled(); 33 | $running = $systemCtl->isActive(); 34 | } else { 35 | $enabled = false; 36 | $running = false; 37 | } 38 | return array( 39 | "name" => "Docker", 40 | "title" => "Docker", 41 | "enabled" => $enabled, 42 | "running" => $running 43 | ); 44 | } 45 | 46 | final public function onSharedFolder($type, $path, $object) 47 | { 48 | $db = \OMV\Config\Database::getInstance(); 49 | if (TRUE === $db->exists("conf.service.compose.file", [ 50 | "operator" => "stringEquals", 51 | "arg0" => "sharedfolderref", 52 | "arg1" => $object['uuid'] 53 | ])) { 54 | $this->setDirty(); 55 | } 56 | } 57 | 58 | public function bindListeners(\OMV\Engine\Notify\Dispatcher $dispatcher) 59 | { 60 | $dispatcher->addListener( 61 | OMV_NOTIFY_MODIFY, 62 | "org.openmediavault.conf.service.compose", 63 | [ $this, "setDirty" ] 64 | ); 65 | $dispatcher->addListener( 66 | OMV_NOTIFY_CREATE | OMV_NOTIFY_DELETE, 67 | "org.openmediavault.conf.service.compose.file", 68 | [ $this, "setDirty" ] 69 | ); 70 | $dispatcher->addListener( 71 | OMV_NOTIFY_MODIFY, 72 | "org.openmediavault.conf.service.compose.globalenv", 73 | [ $this, "setDirty" ] 74 | ); 75 | $dispatcher->addListener( 76 | OMV_NOTIFY_CREATE | OMV_NOTIFY_DELETE, 77 | "org.openmediavault.conf.service.compose.dockerfile", 78 | [ $this, "setDirty" ] 79 | ); 80 | $dispatcher->addListener( 81 | OMV_NOTIFY_CREATE | OMV_NOTIFY_MODIFY | OMV_NOTIFY_DELETE, 82 | "org.openmediavault.conf.service.compose.job", 83 | [ $this, "setDirty" ] 84 | ); 85 | $dispatcher->addListener( 86 | OMV_NOTIFY_MODIFY, 87 | "org.openmediavault.conf.system.sharedfolder", 88 | [ $this, "onSharedFolder" ] 89 | ); 90 | $dispatcher->addListener( 91 | OMV_NOTIFY_MODIFY, 92 | "org.openmediavault.conf.system.sharedfolder.privilege", 93 | [ $this, "onSharedFolder" ] 94 | ); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /usr/share/openmediavault/engined/module/composeterm.inc: -------------------------------------------------------------------------------- 1 | $this->getName(), 16 | "title" => gettext("CTerm"), 17 | "enabled" => $systemCtl->isEnabled(), 18 | "running" => $systemCtl->isActive() 19 | ]; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/component.d/omv-services-compose-configs-datatable-page.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: component 3 | data: 4 | name: omv-services-compose-configs-datatable-page 5 | type: datatablePage 6 | config: 7 | autoReload: false 8 | hasSearchField: true 9 | stateId: 284c8cb0-9b99-11ef-b1fd-f7b945601cd3 10 | sorters: 11 | - dir: asc 12 | prop: name 13 | store: 14 | proxy: 15 | service: Compose 16 | get: 17 | method: getConfigList 18 | columns: 19 | - name: "uuid" 20 | prop: uuid 21 | flexGrow: 1 22 | sortable: true 23 | hidden: true 24 | - name: _("Name") 25 | prop: name 26 | flexGrow: 1 27 | sortable: true 28 | - name: _("Description") 29 | prop: description 30 | flexGrow: 1 31 | sortable: true 32 | - name: _("Compose File") 33 | prop: composefile 34 | flexGrow: 1 35 | sortable: true 36 | - name: _("Path") 37 | prop: fullpath 38 | flexGrow: 2 39 | sortable: true 40 | cellTemplateName: copyToClipboard 41 | actions: 42 | - type: menu 43 | icon: add 44 | tooltip: _("Add") 45 | actions: 46 | - text: _("Add") 47 | icon: add 48 | execute: 49 | type: url 50 | url: "/services/compose/configs/create" 51 | - text: _("Import") 52 | icon: mdi:file-import-outline 53 | execute: 54 | type: formDialog 55 | formDialog: 56 | title: _("Import config files from folders ...") 57 | fields: 58 | - type: hint 59 | hintType: info 60 | text: _("This will import config files in from the selected folder.
It will not import any config files that already exist in the plugin.") 61 | - type: hidden 62 | name: rootfsref 63 | value: "79684322-3eac-11ea-a974-63a080abab18" 64 | submitValue: false 65 | - type: folderBrowser 66 | name: path 67 | label: _("Path") 68 | value: "" 69 | dirType: mntent 70 | dirRefIdField: rootfsref 71 | - type: select 72 | name: fileref 73 | label: _('Compose File') 74 | textField: name 75 | valueField: uuid 76 | store: 77 | proxy: 78 | service: Compose 79 | get: 80 | method: enumerateFiles 81 | hint: _("Compose file to be associate imported files with") 82 | buttons: 83 | submit: 84 | text: _("Import") 85 | execute: 86 | type: request 87 | request: 88 | service: Compose 89 | method: importConfig 90 | - template: edit 91 | execute: 92 | type: url 93 | url: "/services/compose/configs/edit/{{ _selected[0].uuid }}" 94 | - template: delete 95 | execute: 96 | type: request 97 | request: 98 | service: Compose 99 | method: deleteConfig 100 | params: 101 | uuid: "{{ _selected[0].uuid }}" 102 | - type: iconButton 103 | icon: mdi:vector-difference 104 | tooltip: _("Show config changes") 105 | execute: 106 | type: taskDialog 107 | taskDialog: 108 | config: 109 | title: _("Show all file changes ...") 110 | startOnInit: true 111 | autoScroll: false 112 | request: 113 | service: Compose 114 | method: doGit 115 | params: 116 | uuid: "{{ _selected[0].uuid }}" 117 | command: "diffc" 118 | enabledConstraints: 119 | minSelected: 1 120 | maxSelected: 1 121 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/component.d/omv-services-compose-configs-form-page.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: component 3 | data: 4 | name: omv-services-compose-config-form-page 5 | type: formPage 6 | config: 7 | request: 8 | service: Compose 9 | get: 10 | method: getConfig 11 | params: 12 | uuid: "{{ _routeParams.uuid }}" 13 | post: 14 | method: setConfig 15 | fields: 16 | - type: confObjUuid 17 | - type: textInput 18 | name: name 19 | label: _("Filename") 20 | value: "" 21 | disabled: '{{ _routeConfig.data.editing | toboolean }}' 22 | validators: 23 | required: true 24 | hint: _("This is the filename. This should not be a path.") 25 | - type: textInput 26 | name: description 27 | label: _("Description") 28 | value: "" 29 | - type: select 30 | name: fileref 31 | label: _('Compose File') 32 | textField: name 33 | valueField: uuid 34 | store: 35 | proxy: 36 | service: Compose 37 | get: 38 | method: enumerateFiles 39 | hint: _("The config file will be created in this compose file's directory.") 40 | - type: codeEditor 41 | name: body 42 | label: _("Body") 43 | value: "" 44 | language: "none" 45 | buttons: 46 | - template: submit 47 | execute: 48 | type: url 49 | url: "/services/compose/configs" 50 | - template: cancel 51 | execute: 52 | type: url 53 | url: "/services/compose/configs" 54 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/component.d/omv-services-compose-containers-datatable-page.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: component 3 | data: 4 | name: omv-services-compose-containers-datatable-page 5 | type: datatablePage 6 | config: 7 | autoReload: false 8 | hasSearchField: true 9 | remoteSorting: true 10 | stateId: 21c6ac02-0e98-11ee-99b7-d3fb1b8b430a 11 | rowId: name 12 | sorters: 13 | - dir: asc 14 | prop: name 15 | store: 16 | proxy: 17 | service: Compose 18 | get: 19 | method: getContainerListBg 20 | task: true 21 | columns: 22 | - name: _("ID") 23 | prop: id 24 | flexGrow: 1 25 | sortable: true 26 | hidden: true 27 | - name: _("Name") 28 | prop: name 29 | flexGrow: 1 30 | sortable: true 31 | - name: _("Image") 32 | prop: image 33 | flexGrow: 2 34 | sortable: true 35 | - name: _("State") 36 | prop: state 37 | flexGrow: 1 38 | sortable: true 39 | - name: _("Status") 40 | prop: status 41 | flexGrow: 1 42 | sortable: true 43 | - name: _("Created") 44 | prop: created 45 | flexGrow: 1 46 | sortable: true 47 | hidden: true 48 | - name: _("Running For") 49 | prop: running 50 | flexGrow: 1 51 | sortable: true 52 | hidden: true 53 | - name: _("Terminal Link") 54 | prop: execurl 55 | flexGrow: 1 56 | sortable: true 57 | - name: _("Ports") 58 | prop: ports 59 | flexGrow: 1 60 | sortable: true 61 | - name: _("Mounts") 62 | prop: mounts 63 | flexGrow: 2 64 | sortable: true 65 | - name: _("Command") 66 | prop: command 67 | flexGrow: 2 68 | sortable: true 69 | hidden: true 70 | - name: _("Network") 71 | prop: network 72 | flexGrow: 1 73 | sortable: true 74 | hidden: true 75 | actions: 76 | - type: iconButton 77 | icon: mdi:restart 78 | tooltip: _("restart") 79 | enabledConstraints: 80 | minSelected: 1 81 | maxSelected: 1 82 | execute: 83 | type: taskDialog 84 | taskDialog: 85 | config: 86 | title: _("docker restart ...") 87 | startOnInit: true 88 | request: 89 | service: Compose 90 | method: doContainerCommand 91 | params: 92 | command: "restart" 93 | command2: "" 94 | id: "{{ _selected[0].id }}" 95 | - type: iconButton 96 | icon: mdi:note-search-outline 97 | tooltip: _("inspect") 98 | enabledConstraints: 99 | minSelected: 1 100 | maxSelected: 1 101 | execute: 102 | type: taskDialog 103 | taskDialog: 104 | config: 105 | title: _("docker inspect ...") 106 | startOnInit: true 107 | request: 108 | service: Compose 109 | method: doContainerCommand 110 | params: 111 | command: "inspect" 112 | command2: "" 113 | id: "{{ _selected[0].id }}" 114 | - type: iconButton 115 | icon: mdi:file-document-outline 116 | tooltip: _("logs") 117 | enabledConstraints: 118 | minSelected: 1 119 | maxSelected: 1 120 | execute: 121 | type: taskDialog 122 | taskDialog: 123 | config: 124 | title: _("docker logs ...") 125 | startOnInit: true 126 | request: 127 | service: Compose 128 | method: doContainerCommand 129 | params: 130 | command: "logs" 131 | command2: "" 132 | id: "{{ _selected[0].id }}" 133 | - type: iconButton 134 | icon: mdi:file-document-refresh-outline 135 | tooltip: _("follow logs") 136 | enabledConstraints: 137 | minSelected: 1 138 | maxSelected: 1 139 | execute: 140 | type: taskDialog 141 | taskDialog: 142 | config: 143 | title: _("docker logs --follow ...") 144 | startOnInit: true 145 | request: 146 | service: Compose 147 | method: doContainerCommand 148 | params: 149 | command: "logs" 150 | command2: "--follow" 151 | id: "{{ _selected[0].id }}" 152 | - type: iconButton 153 | icon: mdi:download 154 | tooltip: _("Download log") 155 | enabledConstraints: 156 | minSelected: 1 157 | maxSelected: 1 158 | execute: 159 | type: url 160 | url: '/download?service=Compose&method=getContainerLog¶ms={"id":"{{ _selected[0].id }}","name":"{{ _selected[0].name }}"}' 161 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/component.d/omv-services-compose-dockerfiles-datatable-page.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: component 3 | data: 4 | name: omv-services-compose-dockerfiles-datatable-page 5 | type: datatablePage 6 | config: 7 | autoReload: false 8 | hasSearchField: true 9 | rowId: name 10 | stateId: 6ab36dd0-7698-11ed-b240-a73c8036aead 11 | sorters: 12 | - dir: asc 13 | prop: name 14 | store: 15 | proxy: 16 | service: Compose 17 | get: 18 | method: getDockerfileList 19 | columns: 20 | - name: _("Name") 21 | prop: name 22 | flexGrow: 1 23 | sortable: true 24 | - name: _("Description") 25 | prop: description 26 | flexGrow: 1 27 | sortable: true 28 | - name: _("Script") 29 | prop: script 30 | flexGrow: 1 31 | sortable: true 32 | hidden: true 33 | - name: _("Conf") 34 | prop: conf 35 | flexGrow: 1 36 | sortable: true 37 | hidden: true 38 | actions: 39 | - template: create 40 | execute: 41 | type: url 42 | url: "/services/compose/dockerfiles/create" 43 | - template: edit 44 | execute: 45 | type: url 46 | url: "/services/compose/dockerfiles/edit/{{ _selected[0].uuid }}" 47 | - template: delete 48 | execute: 49 | type: request 50 | request: 51 | service: Compose 52 | method: deleteDockerfile 53 | params: 54 | uuid: "{{ _selected[0].uuid }}" 55 | - type: iconButton 56 | icon: mdi:wrench-outline 57 | tooltip: _("Build") 58 | enabledConstraints: 59 | minSelected: 1 60 | maxSelected: 1 61 | execute: 62 | type: taskDialog 63 | taskDialog: 64 | config: 65 | title: _("dockerfile build ...") 66 | startOnInit: true 67 | request: 68 | service: Compose 69 | method: doBuild 70 | params: 71 | name: "{{ _selected[0].name }}" 72 | options: "" 73 | - type: iconButton 74 | icon: mdi:wrench-cog-outline 75 | tooltip: _("Pull and Build") 76 | enabledConstraints: 77 | minSelected: 1 78 | maxSelected: 1 79 | execute: 80 | type: taskDialog 81 | taskDialog: 82 | config: 83 | title: _("dockerfile build ...") 84 | startOnInit: true 85 | request: 86 | service: Compose 87 | method: doBuild 88 | params: 89 | name: "{{ _selected[0].name }}" 90 | options: "pull" 91 | - type: iconButton 92 | icon: mdi:tag-plus-outline 93 | tooltip: _("Tag") 94 | enabledConstraints: 95 | minSelected: 0 96 | maxSelected: 1 97 | execute: 98 | type: formDialog 99 | formDialog: 100 | title: _("Create new image tag ...") 101 | fields: 102 | - type: textInput 103 | name: repo 104 | label: _('Repository') 105 | value: '{{ _selected[0].name }}' 106 | - type: textInput 107 | name: tag 108 | label: _('Tag') 109 | value: '' 110 | - type: hidden 111 | name: srcid 112 | label: _('Image ID') 113 | value: '' 114 | - type: textInput 115 | name: tgtimg 116 | label: _('Target repo') 117 | value: '' 118 | - type: textInput 119 | name: tgttag 120 | label: _('Target tag') 121 | value: '' 122 | buttons: 123 | submit: 124 | text: _("Tag") 125 | execute: 126 | type: request 127 | request: 128 | service: Compose 129 | method: doTag 130 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/component.d/omv-services-compose-dockerfiles-form-page.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: component 3 | data: 4 | name: omv-services-compose-dockerfile-form-page 5 | type: formPage 6 | config: 7 | request: 8 | service: Compose 9 | get: 10 | method: getDockerfile 11 | params: 12 | uuid: "{{ _routeParams.uuid }}" 13 | post: 14 | method: setDockerfile 15 | fields: 16 | - type: confObjUuid 17 | - type: textInput 18 | name: name 19 | label: _("Name") 20 | value: "" 21 | disabled: '{{ _routeConfig.data.editing | toboolean }}' 22 | validators: 23 | required: true 24 | - type: textInput 25 | name: description 26 | label: _("Description") 27 | value: "" 28 | - type: codeEditor 29 | name: body 30 | label: _("Dockerfile") 31 | value: "" 32 | language: "yaml" 33 | - type: textInput 34 | name: script 35 | label: _("Script filename") 36 | value: "" 37 | - type: codeEditor 38 | name: scriptfile 39 | label: _("Script") 40 | value: "" 41 | language: "shell" 42 | - type: textInput 43 | name: conf 44 | label: _("Conf filename") 45 | value: "" 46 | - type: codeEditor 47 | name: conffile 48 | label: _("Conf file") 49 | value: "" 50 | language: "shell" 51 | buttons: 52 | - template: submit 53 | execute: 54 | type: url 55 | url: "/services/compose/dockerfiles" 56 | - template: cancel 57 | execute: 58 | type: url 59 | url: "/services/compose/dockerfiles" 60 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/component.d/omv-services-compose-files-example-form-page.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: component 3 | data: 4 | name: omv-services-compose-file-example-form-page 5 | type: datatablePage 6 | config: 7 | autoReload: false 8 | hasSearchField: true 9 | rowId: name 10 | stateId: ecd28e82-d9eb-11ef-9165-73923693377a 11 | sorters: 12 | - dir: asc 13 | prop: name 14 | store: 15 | proxy: 16 | service: Compose 17 | get: 18 | method: getExampleList 19 | columns: 20 | - name: " " 21 | prop: image 22 | flexGrow: 0.15 23 | cellTemplateName: image 24 | cellTemplateConfig: 25 | class: "mat-icon notranslate mat-icon-no-color" 26 | alt: " " 27 | src: "{{ image }}" 28 | - name: _("Name") 29 | prop: name 30 | flexGrow: 1 31 | sortable: true 32 | - name: _("Description") 33 | prop: description 34 | flexGrow: 3 35 | sortable: true 36 | actions: 37 | - type: iconButton 38 | icon: mdi:plus-box 39 | tooltip: _("Add example compose file") 40 | enabledConstraints: 41 | minSelected: 1 42 | maxSelected: 1 43 | execute: 44 | type: formDialog 45 | formDialog: 46 | title: _("Add...") 47 | fields: 48 | - type: hidden 49 | name: example 50 | value: "{{ _selected[0].name }}" 51 | - type: textInput 52 | name: name 53 | label: _("Name") 54 | value: "{{ _selected[0].name }}" 55 | - type: textInput 56 | name: description 57 | label: _("Description") 58 | value: "" 59 | buttons: 60 | submit: 61 | text: _("Add") 62 | execute: 63 | type: request 64 | request: 65 | service: Compose 66 | method: setExample 67 | progressMessage: _("Adding an example compose file ...") 68 | successNotification: _("Example compose file has been added.") 69 | successUrl: /services/compose/files 70 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/component.d/omv-services-compose-files-form-page.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: component 3 | data: 4 | name: omv-services-compose-file-form-page 5 | type: formPage 6 | config: 7 | request: 8 | service: Compose 9 | get: 10 | method: getFile 11 | params: 12 | uuid: "{{ _routeParams.uuid }}" 13 | post: 14 | method: setFile 15 | fields: 16 | - type: confObjUuid 17 | - type: textInput 18 | name: name 19 | label: _("Name") 20 | value: "" 21 | disabled: '{{ _routeConfig.data.editing | toboolean }}' 22 | validators: 23 | required: true 24 | - type: textInput 25 | name: description 26 | label: _("Description") 27 | value: "" 28 | - type: codeEditor 29 | name: body 30 | label: _("File") 31 | value: "" 32 | language: "yaml" 33 | - type: checkbox 34 | name: showenv 35 | label: _("Show environment file") 36 | value: false 37 | - type: codeEditor 38 | name: env 39 | label: _("Environment") 40 | value: "" 41 | language: "shell" 42 | modifiers: 43 | - type: visible 44 | constraint: 45 | operator: truthy 46 | arg0: 47 | prop: showenv 48 | - type: checkbox 49 | name: showoverride 50 | label: _("Show override") 51 | value: false 52 | - type: codeEditor 53 | name: override 54 | label: _("Override") 55 | value: "" 56 | language: "yaml" 57 | modifiers: 58 | - type: visible 59 | constraint: 60 | operator: truthy 61 | arg0: 62 | prop: showoverride 63 | buttons: 64 | - template: submit 65 | execute: 66 | type: url 67 | url: "/services/compose/files" 68 | - template: cancel 69 | execute: 70 | type: url 71 | url: "/services/compose/files" 72 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/component.d/omv-services-compose-files-global-form-page.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: component 3 | data: 4 | name: omv-services-compose-files-global-form-page 5 | type: formPage 6 | config: 7 | request: 8 | service: Compose 9 | get: 10 | method: getGlobalEnv 11 | post: 12 | method: setGlobalEnv 13 | fields: 14 | - type: checkbox 15 | name: enabled 16 | label: _('Enabled') 17 | value: true 18 | - type: codeEditor 19 | name: globalenv 20 | label: _("Global Environment") 21 | value: "" 22 | language: "shell" 23 | buttons: 24 | - template: submit 25 | execute: 26 | type: url 27 | url: "/services/compose/files" 28 | - template: cancel 29 | execute: 30 | type: url 31 | url: "/services/compose/files" 32 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/component.d/omv-services-compose-files-url-form-page.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: component 3 | data: 4 | name: omv-services-compose-file-url-form-page 5 | type: formPage 6 | config: 7 | request: 8 | service: Compose 9 | post: 10 | method: setUrl 11 | fields: 12 | - type: textInput 13 | name: url 14 | label: _("URL") 15 | value: "" 16 | validators: 17 | required: true 18 | - type: textInput 19 | name: name 20 | label: _("Name") 21 | value: "" 22 | validators: 23 | required: true 24 | - type: textInput 25 | name: description 26 | label: _("Description") 27 | value: "" 28 | buttons: 29 | - template: submit 30 | execute: 31 | type: url 32 | url: "/services/compose/files" 33 | - template: cancel 34 | execute: 35 | type: url 36 | url: "/services/compose/files" 37 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/component.d/omv-services-compose-images-datatable-page.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: component 3 | data: 4 | name: omv-services-compose-images-datatable-page 5 | type: datatablePage 6 | config: 7 | autoReload: false 8 | hasSearchField: true 9 | remoteSorting: true 10 | rowId: id 11 | stateId: c2e1baf6-0a19-11ee-9a0a-1bbcfb3e6ead 12 | sorters: 13 | - dir: asc 14 | prop: repo 15 | store: 16 | proxy: 17 | service: Compose 18 | get: 19 | method: getImagesBg 20 | task: true 21 | columns: 22 | - name: _("ID") 23 | prop: id 24 | flexGrow: 1 25 | sortable: true 26 | hidden: true 27 | - name: _("Repository") 28 | prop: repo 29 | flexGrow: 2 30 | sortable: true 31 | - name: _("Tag") 32 | prop: tag 33 | flexGrow: 1 34 | sortable: true 35 | - name: _("Digest") 36 | prop: digest 37 | flexGrow: 2 38 | sortable: true 39 | hidden: true 40 | - name: _("Created At") 41 | prop: createat 42 | flexGrow: 2 43 | sortable: true 44 | hidden: true 45 | - name: _("Created") 46 | prop: createsince 47 | flexGrow: 1 48 | - name: _("Size") 49 | prop: size 50 | flexGrow: 1 51 | sortable: true 52 | cellTemplateName: template 53 | cellTemplateConfig: '{{ size | tobytes | binaryunit | notavailable("-") }}' 54 | - name: _("Virtual Size") 55 | prop: virtualsize 56 | flexGrow: 1 57 | sortable: true 58 | cellTemplateName: template 59 | cellTemplateConfig: '{{ virtualsize | tobytes | binaryunit | notavailable("-") }}' 60 | hidden: true 61 | - name: _("Status") 62 | prop: status 63 | flexGrow: 1 64 | sortable: true 65 | cellTemplateName: chip 66 | cellTemplateConfig: 67 | map: 68 | AVAILABLE: 69 | value: _("Available") 70 | class: omv-background-color-pair-yellow 71 | CURRENT: 72 | value: _("Current") 73 | class: omv-background-color-pair-green 74 | NA: 75 | value: _("n/a") 76 | class: omv-background-color-pair-blue 77 | NOIMAGE: 78 | value: _("No Image") 79 | class: omv-background-color-pair-blue 80 | FAILED: 81 | value: _("Failed") 82 | class: omv-background-color-pair-red 83 | - name: _("In Use") 84 | prop: inuse 85 | flexGrow: 1 86 | sortable: true 87 | cellTemplateName: checkIcon 88 | actions: 89 | - type: iconButton 90 | icon: mdi:delete 91 | tooltip: _("Delete") 92 | enabledConstraints: 93 | minSelected: 1 94 | maxSelected: 1 95 | execute: 96 | type: taskDialog 97 | taskDialog: 98 | config: 99 | title: _("docker image rm ...") 100 | startOnInit: true 101 | request: 102 | service: Compose 103 | method: doDockerImageCmd 104 | params: 105 | id: "{{ _selected[0].id }}" 106 | command: "rm" 107 | - type: iconButton 108 | icon: mdi:magnify 109 | tooltip: _("Inspect") 110 | enabledConstraints: 111 | minSelected: 1 112 | maxSelected: 1 113 | execute: 114 | type: taskDialog 115 | taskDialog: 116 | config: 117 | title: _("docker image inspect ...") 118 | startOnInit: true 119 | request: 120 | service: Compose 121 | method: doDockerImageCmd 122 | params: 123 | id: "{{ _selected[0].id }}" 124 | command: "inspect" 125 | buttons: 126 | stop: 127 | hidden: true 128 | - type: iconButton 129 | icon: mdi:download-network-outline 130 | tooltip: _("pull image") 131 | enabledConstraints: 132 | minSelected: 1 133 | maxSelected: 1 134 | execute: 135 | type: taskDialog 136 | taskDialog: 137 | config: 138 | title: _("docker image pull ...") 139 | startOnInit: true 140 | request: 141 | service: Compose 142 | method: doDockerImageCmd 143 | params: 144 | id: "{{ _selected[0].repo }}" 145 | command: "pull" 146 | - type: iconButton 147 | icon: mdi:download-network 148 | tooltip: _("pull image+tag") 149 | enabledConstraints: 150 | minSelected: 1 151 | maxSelected: 1 152 | execute: 153 | type: taskDialog 154 | taskDialog: 155 | config: 156 | title: _("docker image pull ...") 157 | startOnInit: true 158 | request: 159 | service: Compose 160 | method: doDockerImageCmd 161 | params: 162 | id: "{{ _selected[0].repo }}:{{ _selected[0].tag }}" 163 | command: "pull" 164 | - type: iconButton 165 | icon: mdi:tag-plus-outline 166 | tooltip: _("Tag") 167 | enabledConstraints: 168 | minSelected: 1 169 | maxSelected: 1 170 | execute: 171 | type: formDialog 172 | formDialog: 173 | title: _("Create new image tag ...") 174 | fields: 175 | - type: textInput 176 | name: repo 177 | label: _('Repository') 178 | value: '{{ _selected[0].repo }}' 179 | readonly: true 180 | submitValue: false 181 | - type: textInput 182 | name: tag 183 | label: _('Tag') 184 | value: '{{ _selected[0].tag }}' 185 | readonly: true 186 | submitValue: false 187 | - type: textInput 188 | name: srcid 189 | label: _('Image ID') 190 | value: '{{ _selected[0].id }}' 191 | readonly: true 192 | - type: textInput 193 | name: tgtimg 194 | label: _('Target repo') 195 | value: '{{ _selected[0].repo }}' 196 | - type: textInput 197 | name: tgttag 198 | label: _('Target tag') 199 | value: '' 200 | buttons: 201 | submit: 202 | text: _("Tag") 203 | execute: 204 | type: request 205 | request: 206 | service: Compose 207 | method: doTag 208 | - type: iconButton 209 | icon: mdi:tag-arrow-up-outline 210 | tooltip: _("Push") 211 | enabledConstraints: 212 | minSelected: 1 213 | maxSelected: 1 214 | execute: 215 | type: taskDialog 216 | taskDialog: 217 | config: 218 | title: _("Push to Docker Hub ...") 219 | startOnInit: true 220 | request: 221 | service: Compose 222 | method: doHubPush 223 | params: 224 | imgname: "{{ _selected[0].repo }}" 225 | imgtag: "{{ _selected[0].tag }}" 226 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/component.d/omv-services-compose-navigation-page.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: component 3 | data: 4 | name: omv-services-compose-navigation-page 5 | type: navigationPage 6 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/component.d/omv-services-compose-networks-datatable-page.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: component 3 | data: 4 | name: omv-services-compose-networks-datatable-page 5 | type: datatablePage 6 | config: 7 | autoReload: false 8 | hasSearchField: true 9 | remoteSorting: true 10 | rowId: name 11 | stateId: d32e223c-0591-11ee-9d61-9bfb68b33e85 12 | sorters: 13 | - dir: asc 14 | prop: name 15 | store: 16 | proxy: 17 | service: Compose 18 | get: 19 | method: getNetworksBg 20 | task: true 21 | columns: 22 | - name: _("Name") 23 | prop: name 24 | flexGrow: 1 25 | sortable: true 26 | - name: _("Driver") 27 | prop: driver 28 | flexGrow: 1 29 | sortable: true 30 | actions: 31 | - template: create 32 | execute: 33 | type: url 34 | url: "/services/compose/networks/create" 35 | - type: iconButton 36 | icon: mdi:delete 37 | tooltip: _("Delete") 38 | enabledConstraints: 39 | minSelected: 1 40 | maxSelected: 1 41 | execute: 42 | type: taskDialog 43 | taskDialog: 44 | config: 45 | title: _("docker network rm ...") 46 | startOnInit: true 47 | request: 48 | service: Compose 49 | method: doDockerNetworkCmd 50 | params: 51 | name: "{{ _selected[0].name }}" 52 | command: "rm" 53 | - type: iconButton 54 | icon: mdi:magnify 55 | tooltip: _("Inspect") 56 | enabledConstraints: 57 | minSelected: 1 58 | maxSelected: 1 59 | execute: 60 | type: taskDialog 61 | taskDialog: 62 | config: 63 | title: _("docker network inspect ...") 64 | startOnInit: true 65 | request: 66 | service: Compose 67 | method: doDockerNetworkCmd 68 | params: 69 | name: "{{ _selected[0].name }}" 70 | command: "inspect" 71 | buttons: 72 | stop: 73 | hidden: true 74 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/component.d/omv-services-compose-networks-form-page.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: component 3 | data: 4 | name: omv-services-compose-network-form-page 5 | type: formPage 6 | config: 7 | request: 8 | service: Compose 9 | post: 10 | method: setNetwork 11 | fields: 12 | - type: confObjUuid 13 | - type: textInput 14 | name: name 15 | label: _("Name") 16 | value: "" 17 | validators: 18 | required: true 19 | - type: select 20 | name: driver 21 | label: _("Driver") 22 | value: "bridge" 23 | store: 24 | data: 25 | - ["bridge", "bridge"] 26 | - ["ipvlan", "ipvlan"] 27 | - ["macvlan", "macvlan"] 28 | - ["overlay", "overlay"] 29 | - type: textInput 30 | name: parentnetwork 31 | label: _("Parent network") 32 | value: '' 33 | suggestions: true 34 | store: 35 | proxy: 36 | service: Compose 37 | get: 38 | method: enumerateNetworkList 39 | modifiers: 40 | - type: visible 41 | constraint: 42 | operator: eq 43 | arg0: 44 | prop: driver 45 | arg1: "macvlan" 46 | - type: container 47 | fields: 48 | - type: textInput 49 | name: subnet 50 | label: _("Subnet") 51 | value: "" 52 | hint: _("e.g. 172.20.0.0/16") 53 | - type: textInput 54 | name: gateway 55 | label: _("Gateway") 56 | value: "" 57 | hint: _("e.g. 172.20.0.1") 58 | validators: 59 | patternType: ipv4 60 | - type: textInput 61 | name: iprange 62 | label: _("IP range") 63 | value: "" 64 | hint: _("e.g. 172.20.10.128/25") 65 | - type: textInput 66 | name: auxaddress 67 | label: _("Aux address") 68 | value: "" 69 | hint: _("Format is name=ip. Comma separate multiple entries.
e.g. my-router=192.168.10.5,my-nas=192.168.20.6") 70 | buttons: 71 | - template: submit 72 | execute: 73 | type: url 74 | url: "/services/compose/networks" 75 | - template: cancel 76 | execute: 77 | type: url 78 | url: "/services/compose/networks" 79 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/component.d/omv-services-compose-repos-datatable-page.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: component 3 | data: 4 | name: omv-services-compose-repos-datatable-page 5 | type: datatablePage 6 | config: 7 | autoReload: false 8 | hasSearchField: true 9 | remoteSorting: true 10 | rowId: repo 11 | stateId: 1abf3ad8-b67a-11ef-904d-5bc7eacaba79 12 | sorters: 13 | - dir: asc 14 | prop: repo 15 | store: 16 | proxy: 17 | service: Compose 18 | get: 19 | method: getRepoList 20 | columns: 21 | - name: _("Repo") 22 | prop: repo 23 | flexGrow: 4 24 | sortable: true 25 | actions: 26 | - type: iconButton 27 | icon: mdi:login 28 | tooltip: _("Login") 29 | execute: 30 | type: formDialog 31 | formDialog: 32 | title: _("Login to docker repo ...") 33 | fields: 34 | - type: textInput 35 | name: url 36 | label: _('URL') 37 | value: '' 38 | - type: textInput 39 | name: username 40 | label: _('Username') 41 | value: '' 42 | - type: passwordInput 43 | name: passwd 44 | label: _('Password') 45 | value: '' 46 | buttons: 47 | submit: 48 | text: _("Login") 49 | execute: 50 | type: request 51 | request: 52 | service: Compose 53 | method: repoLogin 54 | - type: iconButton 55 | icon: mdi:logout 56 | tooltip: _("Logout") 57 | enabledConstraints: 58 | minSelected: 1 59 | maxSelected: 1 60 | confirmationDialogConfig: 61 | template: confirmation-danger 62 | message: _("Are you sure you want to delete?") 63 | execute: 64 | type: request 65 | request: 66 | service: Compose 67 | method: repoLogout 68 | params: 69 | repo: "{{ _selected[0].repo }}" 70 | progressMessage: _("Logging out ...") 71 | successNotification: _("Logged out.") 72 | task: false 73 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/component.d/omv-services-compose-restore-datatable-page.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: component 3 | data: 4 | name: omv-services-compose-restore-datatable-page 5 | type: datatablePage 6 | config: 7 | autoReload: false 8 | hasSearchField: true 9 | rowId: backup 10 | stateId: d4f9aeb6-1b7f-11ee-8b96-b71aa60c188d 11 | store: 12 | proxy: 13 | service: Compose 14 | get: 15 | method: getRestoreList 16 | columns: 17 | - name: _('Backup') 18 | prop: backup 19 | flexGrow: 1 20 | sortable: true 21 | - name: _("Size") 22 | prop: backupsize 23 | flexGrow: 1 24 | sortable: true 25 | cellTemplateName: template 26 | cellTemplateConfig: '{{ backupsize | tobytes | binaryunit | notavailable("-") }}' 27 | - name: _('Backup Time') 28 | prop: time 29 | flexGrow: 1 30 | sortable: true 31 | actions: 32 | - type: iconButton 33 | tooltip: _("Restore") 34 | icon: mdi:restore 35 | enabledConstraints: 36 | minSelected: 1 37 | maxSelected: 1 38 | execute: 39 | type: taskDialog 40 | taskDialog: 41 | config: 42 | title: _("Restore Compose ...") 43 | startOnInit: false 44 | request: 45 | service: Compose 46 | method: doRestore 47 | params: 48 | backup: "{{ _selected[0].backup }}" 49 | - type: iconButton 50 | tooltip: _("Restore global.env") 51 | icon: mdi:file-restore-outline 52 | confirmationDialogConfig: 53 | template: confirmation-danger 54 | message: _("Are you sure you want to restore global.env from backup?") 55 | execute: 56 | type: request 57 | request: 58 | service: Compose 59 | method: restoreGlobalEnv 60 | progressMessage: _("Restoring global.env from backup ...") 61 | successNotification: _("global.env has been restored from backup.") 62 | - type: iconButton 63 | icon: mdi:delete 64 | tooltip: _("Delete") 65 | confirmationDialogConfig: 66 | template: confirmation-danger 67 | message: _("Are you sure you want to delete this backup?") 68 | enabledConstraints: 69 | minSelected: 1 70 | maxSelected: 1 71 | execute: 72 | type: taskDialog 73 | taskDialog: 74 | config: 75 | title: _("Delete backup ...") 76 | startOnInit: true 77 | request: 78 | service: Compose 79 | method: deleteBackup 80 | params: 81 | name: "{{ _selected[0].backup }}" 82 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/component.d/omv-services-compose-schedule-datatable-page.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: component 3 | data: 4 | name: omv-services-compose-schedule-datatable-page 5 | type: datatablePage 6 | config: 7 | autoReload: false 8 | hasSearchField: true 9 | stateId: 721723ee-1843-11ee-8845-f794b6ff9154 10 | store: 11 | proxy: 12 | service: Compose 13 | get: 14 | method: getJobList 15 | columns: 16 | - name: _('Enabled') 17 | prop: enable 18 | flexGrow: 1 19 | sortable: true 20 | cellTemplateName: checkIcon 21 | - name: _("Filter") 22 | prop: filter 23 | flexGrow: 1 24 | sortable: true 25 | - name: _("Excludes") 26 | prop: excludes 27 | flexGrow: 1 28 | hidden: true 29 | - name: _('Backup') 30 | prop: backup 31 | flexGrow: 1 32 | sortable: true 33 | cellTemplateName: checkIcon 34 | - name: _('Update') 35 | prop: update 36 | flexGrow: 1 37 | sortable: true 38 | cellTemplateName: checkIcon 39 | - name: _('Prune') 40 | prop: prune 41 | flexGrow: 1 42 | sortable: true 43 | cellTemplateName: checkIcon 44 | - name: _('Start') 45 | prop: filestart 46 | flexGrow: 1 47 | sortable: true 48 | cellTemplateName: checkIcon 49 | - name: _('Stop') 50 | prop: filestop 51 | flexGrow: 1 52 | sortable: true 53 | cellTemplateName: checkIcon 54 | - name: _('Verbose') 55 | prop: verbose 56 | flexGrow: 1 57 | sortable: true 58 | cellTemplateName: checkIcon 59 | hidden: true 60 | - name: _('Scheduling') 61 | prop: '' 62 | flexGrow: 1 63 | cellTemplateName: template 64 | cellTemplateConfig: | 65 | {% if execution == "exactly" %} 66 | {% set _minute = minute %} 67 | {% set _hour = hour %} 68 | {% set _dayofmonth = dayofmonth %} 69 | {% if everynminute %}{% set _minute %}*/{{ minute }}{% endset %}{% endif %} 70 | {% if everynhour %}{% set _hour %}*/{{ hour }}{% endset %}{% endif %} 71 | {% if everyndayofmonth %}{% set _dayofmonth %}*/{{ dayofmonth }}{% endset %}{% endif %} 72 | {{ [_minute, _hour, _dayofmonth, month, dayofweek] | join(" ") | cron2human }} 73 | {% else %} 74 | {{ execution | capitalize | translate }} 75 | {% endif %} 76 | actions: 77 | - template: create 78 | execute: 79 | type: url 80 | url: "/services/compose/schedule/create" 81 | - template: edit 82 | execute: 83 | type: url 84 | url: "/services/compose/schedule/edit/{{ _selected[0].uuid }}" 85 | - template: delete 86 | execute: 87 | type: request 88 | request: 89 | service: Compose 90 | method: deleteJob 91 | params: 92 | uuid: "{{ _selected[0].uuid }}" 93 | - type: iconButton 94 | tooltip: _("Run") 95 | icon: mdi:play-box-outline 96 | enabledConstraints: 97 | minSelected: 1 98 | maxSelected: 1 99 | execute: 100 | type: taskDialog 101 | taskDialog: 102 | config: 103 | title: _("Execute scheduled job ...") 104 | startOnInit: false 105 | showCompletion: false 106 | request: 107 | service: Compose 108 | method: doJob 109 | params: 110 | uuid: '{{ _selected[0].uuid }}' 111 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/component.d/omv-services-compose-services-datatable-page.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: component 3 | data: 4 | name: omv-services-compose-services-datatable-page 5 | type: datatablePage 6 | config: 7 | autoReload: false 8 | hasSearchField: true 9 | remoteSorting: true 10 | stateId: f350a8e8-9997-11ed-8f7b-83968f3f3a4f 11 | rowId: name 12 | sorters: 13 | - dir: asc 14 | prop: name 15 | store: 16 | proxy: 17 | service: Compose 18 | get: 19 | method: getServicesListBg 20 | task: true 21 | columns: 22 | - name: _("Name") 23 | prop: name 24 | flexGrow: 1 25 | sortable: true 26 | - name: _("Image") 27 | prop: image 28 | flexGrow: 2 29 | sortable: true 30 | - name: _("Project") 31 | prop: project 32 | flexGrow: 1 33 | sortable: true 34 | - name: _("Service") 35 | prop: service 36 | flexGrow: 1 37 | sortable: true 38 | - name: _("State") 39 | prop: state 40 | flexGrow: 1 41 | sortable: true 42 | - name: _("Status") 43 | prop: status 44 | flexGrow: 1 45 | sortable: true 46 | - name: _("Terminal Link") 47 | prop: execurl 48 | flexGrow: 1 49 | sortable: true 50 | - name: _("Ports") 51 | prop: ports 52 | flexGrow: 1 53 | sortable: true 54 | - name: _("Created") 55 | prop: created 56 | flexGrow: 1 57 | sortable: true 58 | hidden: true 59 | - name: _("Path") 60 | prop: filepath 61 | flexGrow: 1 62 | sortable: true 63 | hidden: true 64 | cellTemplateName: copyToClipboard 65 | - name: _("Env Path") 66 | prop: envpath 67 | flexGrow: 1 68 | sortable: true 69 | hidden: true 70 | cellTemplateName: copyToClipboard 71 | - name: _("Override Path") 72 | prop: overridepath 73 | flexGrow: 1 74 | sortable: true 75 | hidden: true 76 | cellTemplateName: copyToClipboard 77 | actions: 78 | - type: iconButton 79 | icon: mdi:download-network-outline 80 | tooltip: _("pull") 81 | enabledConstraints: 82 | minSelected: 1 83 | maxSelected: 1 84 | execute: 85 | type: taskDialog 86 | taskDialog: 87 | config: 88 | title: _("docker compose pull ...") 89 | startOnInit: true 90 | request: 91 | service: Compose 92 | method: doServiceCommand 93 | params: 94 | command: "pull" 95 | command2: "" 96 | service: "{{ _selected[0].service }}" 97 | path: "{{ _selected[0].filepath }}" 98 | envpath: "{{ _selected[0].envpath }}" 99 | overridepath: "{{ _selected[0].overridepath }}" 100 | - type: iconButton 101 | icon: mdi:arrow-up-circle-outline 102 | tooltip: _("up") 103 | enabledConstraints: 104 | minSelected: 1 105 | maxSelected: 1 106 | execute: 107 | type: taskDialog 108 | taskDialog: 109 | config: 110 | title: _("docker compose up -d ...") 111 | startOnInit: true 112 | request: 113 | service: Compose 114 | method: doServiceCommand 115 | params: 116 | command: "up -d" 117 | command2: "" 118 | service: "{{ _selected[0].service }}" 119 | path: "{{ _selected[0].filepath }}" 120 | envpath: "{{ _selected[0].envpath }}" 121 | overridepath: "{{ _selected[0].overridepath }}" 122 | - type: iconButton 123 | icon: mdi:stop 124 | tooltip: _("stop") 125 | enabledConstraints: 126 | minSelected: 1 127 | maxSelected: 1 128 | execute: 129 | type: taskDialog 130 | taskDialog: 131 | config: 132 | title: _("docker compose stop ...") 133 | startOnInit: true 134 | request: 135 | service: Compose 136 | method: doServiceCommand 137 | params: 138 | command: "stop" 139 | command2: "" 140 | service: "{{ _selected[0].service }}" 141 | path: "{{ _selected[0].filepath }}" 142 | envpath: "{{ _selected[0].envpath }}" 143 | overridepath: "{{ _selected[0].overridepath }}" 144 | - type: iconButton 145 | icon: mdi:arrow-down-circle-outline 146 | tooltip: _("down") 147 | enabledConstraints: 148 | minSelected: 1 149 | maxSelected: 1 150 | execute: 151 | type: taskDialog 152 | taskDialog: 153 | config: 154 | title: _("docker compose down ...") 155 | startOnInit: true 156 | request: 157 | service: Compose 158 | method: doServiceCommand 159 | params: 160 | command: "down" 161 | command2: "" 162 | service: "{{ _selected[0].service }}" 163 | path: "{{ _selected[0].filepath }}" 164 | envpath: "{{ _selected[0].envpath }}" 165 | overridepath: "{{ _selected[0].overridepath }}" 166 | - type: iconButton 167 | icon: mdi:restart 168 | tooltip: _("restart") 169 | enabledConstraints: 170 | minSelected: 1 171 | maxSelected: 1 172 | execute: 173 | type: taskDialog 174 | taskDialog: 175 | config: 176 | title: _("docker compose restart ...") 177 | startOnInit: true 178 | request: 179 | service: Compose 180 | method: doServiceCommand 181 | params: 182 | command: "restart" 183 | command2: "" 184 | service: "{{ _selected[0].service }}" 185 | path: "{{ _selected[0].filepath }}" 186 | envpath: "{{ _selected[0].envpath }}" 187 | overridepath: "{{ _selected[0].overridepath }}" 188 | - type: iconButton 189 | icon: mdi:note-search-outline 190 | tooltip: _("inspect") 191 | enabledConstraints: 192 | minSelected: 1 193 | maxSelected: 1 194 | execute: 195 | type: taskDialog 196 | taskDialog: 197 | config: 198 | title: _("docker inspect ...") 199 | startOnInit: true 200 | request: 201 | service: Compose 202 | method: doContainerCommand 203 | params: 204 | command: "inspect" 205 | command2: "" 206 | id: "{{ _selected[0].name }}" 207 | - type: iconButton 208 | icon: mdi:file-document-outline 209 | tooltip: _("logs") 210 | enabledConstraints: 211 | minSelected: 1 212 | maxSelected: 1 213 | execute: 214 | type: taskDialog 215 | taskDialog: 216 | config: 217 | title: _("docker compose logs ...") 218 | startOnInit: true 219 | request: 220 | service: Compose 221 | method: doServiceCommand 222 | params: 223 | command: "logs" 224 | command2: "" 225 | service: "{{ _selected[0].service }}" 226 | path: "{{ _selected[0].filepath }}" 227 | envpath: "{{ _selected[0].envpath }}" 228 | overridepath: "{{ _selected[0].overridepath }}" 229 | - type: iconButton 230 | icon: mdi:file-document-refresh-outline 231 | tooltip: _("follow logs") 232 | enabledConstraints: 233 | minSelected: 1 234 | maxSelected: 1 235 | execute: 236 | type: taskDialog 237 | taskDialog: 238 | config: 239 | title: _("docker compose logs --follow ...") 240 | startOnInit: true 241 | request: 242 | service: Compose 243 | method: doServiceCommand 244 | params: 245 | command: "logs" 246 | command2: "--follow" 247 | service: "{{ _selected[0].service }}" 248 | path: "{{ _selected[0].filepath }}" 249 | envpath: "{{ _selected[0].envpath }}" 250 | overridepath: "{{ _selected[0].overridepath }}" 251 | - type: iconButton 252 | icon: mdi:download 253 | tooltip: _("Download log") 254 | enabledConstraints: 255 | minSelected: 1 256 | maxSelected: 1 257 | execute: 258 | type: url 259 | url: '/download?service=Compose&method=getServiceLog¶ms={"service":"{{ _selected[0].service }}","name":"{{ _selected[0].name }}","path":"{{ _selected[0].filepath }}","envpath":"{{ _selected[0].envpath }}","overridepath":"{{ _selected[0].overridepath }}"}' 260 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/component.d/omv-services-compose-settings-form-page.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: component 3 | data: 4 | name: omv-services-compose-settings-form-page 5 | type: formPage 6 | config: 7 | request: 8 | service: Compose 9 | get: 10 | method: get 11 | post: 12 | method: set 13 | fields: 14 | - type: divider 15 | title: _("Compose Files") 16 | - type: sharedFolderSelect 17 | name: sharedfolderref 18 | label: _("Shared folder") 19 | hasEmptyOption: true 20 | hint: _("Location of compose files") 21 | - type: container 22 | fields: 23 | - type: select 24 | name: composeowner 25 | label: _("Owner of directories and files") 26 | placeholder: _("Select a user ...") 27 | value: "root" 28 | valueField: "name" 29 | textField: "name" 30 | store: 31 | proxy: 32 | service: UserMgmt 33 | get: 34 | method: enumerateAllUsers 35 | sorters: 36 | - dir: asc 37 | prop: name 38 | validators: 39 | required: true 40 | - type: select 41 | name: composegroup 42 | label: _("Group of directories and files") 43 | placeholder: _("Select a group ...") 44 | value: "root" 45 | valueField: "name" 46 | textField: "name" 47 | store: 48 | proxy: 49 | service: UserMgmt 50 | get: 51 | method: enumerateAllGroups 52 | sorters: 53 | - dir: asc 54 | prop: name 55 | validators: 56 | required: true 57 | - type: select 58 | name: mode 59 | label: _("Permissions of directories and files") 60 | value: "700" 61 | store: 62 | data: 63 | - - "700" 64 | - _("Administrator - read/write, Users - no access, Others - no access") 65 | - - "750" 66 | - _("Administrator - read/write, Users - read-only, Others - no access") 67 | - - "770" 68 | - _("Administrator - read/write, Users - read/write, Others - no access") 69 | - - "755" 70 | - _("Administrator - read/write, Users - read-only, Others - read-only") 71 | - - "775" 72 | - _("Administrator - read/write, Users - read/write, Others - read-only") 73 | - - "777" 74 | - _("Everyone - read/write") 75 | - type: divider 76 | title: _("Data") 77 | - type: sharedFolderSelect 78 | name: datasharedfolderref 79 | label: _("Shared folder") 80 | hasEmptyOption: true 81 | hint: _("Optional - Location of persistent container data
Only used to substitute CHANGE_TO_COMPOSE_DATA_PATH in compose and env files with this shared folder path.") 82 | - type: divider 83 | title: _("Backup") 84 | - type: sharedFolderSelect 85 | name: backupsharedfolderref 86 | label: _("Shared folder") 87 | hasEmptyOption: true 88 | hint: _("Location of backups") 89 | - type: numberInput 90 | name: backupmaxsize 91 | label: _("Max Size") 92 | value: 1 93 | validators: 94 | min: 0 95 | max: 65536 96 | patternType: integer 97 | required: true 98 | hint: _("Units in GB. Backup will skip volumes larger than this size.
Set to 0 for unlimited.") 99 | - type: divider 100 | title: _("Docker") 101 | - type: textInput 102 | name: dockerStorage 103 | label: _("Docker storage") 104 | value: "/var/lib/docker" 105 | hint: _("Leave blank to use a custom /etc/docker/daemon.json") 106 | - type: textInput 107 | name: dockerStatus 108 | label: _("Status") 109 | submitValue: false 110 | readonly: true 111 | - type: textInput 112 | name: dockerVersion 113 | label: _("Docker version") 114 | submitValue: false 115 | readonly: true 116 | - type: textInput 117 | name: composeVersion 118 | label: _("Compose version") 119 | submitValue: false 120 | readonly: true 121 | - type: divider 122 | title: _("Overrides") 123 | - type: textInput 124 | name: urlHostname 125 | label: _("URL hostname") 126 | value: "" 127 | hint: _("Override hostname when opening ports in Files, Services, and Containers tabs") 128 | - type: checkbox 129 | name: showcmd 130 | label: _("Show commands") 131 | hint: _("Show docker command for task in task dialog") 132 | - type: divider 133 | title: _("Cache times for tabs") 134 | - type: container 135 | fields: 136 | - type: numberInput 137 | name: cachetimefiles 138 | label: _("Files") 139 | value: 60 140 | hint: _("Units in seconds.
Set to 0 for no caching.") 141 | validators: 142 | min: 0 143 | max: 65536 144 | patternType: integer 145 | required: true 146 | - type: numberInput 147 | name: cachetimeservices 148 | label: _("Services") 149 | value: 60 150 | validators: 151 | min: 0 152 | max: 65536 153 | patternType: integer 154 | required: true 155 | - type: numberInput 156 | name: cachetimestats 157 | label: _("Stats") 158 | value: 60 159 | validators: 160 | min: 0 161 | max: 65536 162 | patternType: integer 163 | required: true 164 | - type: numberInput 165 | name: cachetimeimages 166 | label: _("Images") 167 | value: 60 168 | validators: 169 | min: 0 170 | max: 65536 171 | patternType: integer 172 | required: true 173 | - type: numberInput 174 | name: cachetimenetworks 175 | label: _("Networks") 176 | value: 60 177 | validators: 178 | min: 0 179 | max: 65536 180 | patternType: integer 181 | required: true 182 | - type: numberInput 183 | name: cachetimevolumes 184 | label: _("Volumes") 185 | value: 60 186 | validators: 187 | min: 0 188 | max: 65536 189 | patternType: integer 190 | required: true 191 | - type: numberInput 192 | name: cachetimecontainers 193 | label: _("Containers") 194 | value: 60 195 | validators: 196 | min: 0 197 | max: 65536 198 | patternType: integer 199 | required: true 200 | buttons: 201 | - template: submit 202 | - template: cancel 203 | execute: 204 | type: url 205 | url: "/services/compose" 206 | - text: _("Enable Docker repo") 207 | execute: 208 | type: taskDialog 209 | taskDialog: 210 | config: 211 | title: _("Enable Docker repo ...") 212 | startOnInit: true 213 | request: 214 | service: Compose 215 | method: enableDockerRepo 216 | buttons: 217 | stop: 218 | hidden: true 219 | - text: _("Reinstall Docker") 220 | confirmationDialogConfig: 221 | template: confirmation-danger 222 | message: _("Are you sure you want to reinstall?") 223 | execute: 224 | type: taskDialog 225 | taskDialog: 226 | config: 227 | title: _("Reinstall Docker ...") 228 | startOnInit: true 229 | request: 230 | service: Compose 231 | method: reinstallDocker 232 | buttons: 233 | stop: 234 | hidden: true 235 | - text: _("Restart Docker") 236 | confirmationDialogConfig: 237 | template: confirmation-danger 238 | message: _("Are you sure you want to restart?") 239 | execute: 240 | type: request 241 | request: 242 | service: Compose 243 | method: restartDocker 244 | progressMessage: _("Docker is restarting ...") 245 | successNotification: _("Docker has been restarted.") 246 | - text: _("Clear cache") 247 | execute: 248 | type: request 249 | request: 250 | service: Compose 251 | method: clearCacheFiles 252 | progressMessage: _("Clearing cache ...") 253 | successNotification: _("Cache has been cleared.") 254 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/component.d/omv-services-compose-stats-datatable-page.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: component 3 | data: 4 | name: omv-services-compose-stats-datatable-page 5 | type: datatablePage 6 | config: 7 | autoReload: false 8 | hasSearchField: true 9 | remoteSorting: true 10 | rowId: id 11 | stateId: 8050106c-797c-11ed-bbaf-bb845b3510b9 12 | sorters: 13 | - dir: asc 14 | prop: name 15 | store: 16 | proxy: 17 | service: Compose 18 | get: 19 | method: getStatsBg 20 | task: true 21 | columns: 22 | - name: _("ID") 23 | prop: id 24 | flexGrow: 1 25 | sortable: true 26 | hidden: true 27 | - name: _("Name") 28 | prop: name 29 | flexGrow: 1 30 | sortable: true 31 | - name: _("CPU %") 32 | prop: cpu 33 | flexGrow: 1 34 | sortable: true 35 | cellTemplateName: progressBar 36 | cellTemplateConfig: 37 | text: '{{ cpu | tofixed(2) }}' 38 | - name: _("Mem Usage") 39 | prop: memuse 40 | flexGrow: 1 41 | sortable: true 42 | cellTemplateName: template 43 | cellTemplateConfig: '{{ memuse | tobytes | binaryunit | notavailable("-") }}' 44 | - name: _("Mem Limit") 45 | prop: memlim 46 | flexGrow: 1 47 | sortable: true 48 | cellTemplateName: template 49 | cellTemplateConfig: '{{ memlim | tobytes | binaryunit | notavailable("-") }}' 50 | - name: _("Mem %") 51 | prop: mem 52 | flexGrow: 1 53 | sortable: true 54 | cellTemplateName: template 55 | cellTemplateConfig: '{{ mem | tofixed(2) }}' 56 | - name: _("Net In") 57 | prop: netin 58 | flexGrow: 1 59 | sortable: true 60 | cellTemplateName: template 61 | cellTemplateConfig: '{{ netin | tobytes | binaryunit | notavailable("-") }}' 62 | - name: _("Net Out") 63 | prop: netout 64 | flexGrow: 1 65 | sortable: true 66 | cellTemplateName: template 67 | cellTemplateConfig: '{{ netout | tobytes | binaryunit | notavailable("-") }}' 68 | - name: _("Block In") 69 | prop: blockin 70 | flexGrow: 1 71 | sortable: true 72 | cellTemplateName: template 73 | cellTemplateConfig: '{{ blockin | tobytes | binaryunit | notavailable("-") }}' 74 | - name: _("Block Out") 75 | prop: blockout 76 | flexGrow: 1 77 | sortable: true 78 | cellTemplateName: template 79 | cellTemplateConfig: '{{ blockout | tobytes | binaryunit | notavailable("-") }}' 80 | - name: _("PIDs") 81 | prop: pids 82 | flexGrow: 1 83 | sortable: true 84 | actions: 85 | - type: iconButton 86 | icon: mdi:magnify 87 | tooltip: _("Inspect") 88 | enabledConstraints: 89 | minSelected: 1 90 | maxSelected: 1 91 | execute: 92 | type: taskDialog 93 | taskDialog: 94 | config: 95 | title: _("docker inspect ...") 96 | startOnInit: true 97 | request: 98 | service: Compose 99 | method: doDockerCmd 100 | params: 101 | id: "{{ _selected[0].id }}" 102 | cmd: "inspect" 103 | cmd2: "" 104 | buttons: 105 | stop: 106 | hidden: true 107 | - type: iconButton 108 | icon: mdi:file-document-outline 109 | tooltip: _("logs") 110 | enabledConstraints: 111 | minSelected: 1 112 | maxSelected: 1 113 | execute: 114 | type: taskDialog 115 | taskDialog: 116 | config: 117 | title: _("docker logs ...") 118 | startOnInit: true 119 | request: 120 | service: Compose 121 | method: doDockerCmd 122 | params: 123 | id: "{{ _selected[0].id }}" 124 | cmd: "logs" 125 | cmd2: "" 126 | buttons: 127 | stop: 128 | hidden: true 129 | - type: iconButton 130 | icon: mdi:file-document-refresh-outline 131 | tooltip: _("follow logs") 132 | enabledConstraints: 133 | minSelected: 1 134 | maxSelected: 1 135 | execute: 136 | type: taskDialog 137 | taskDialog: 138 | config: 139 | title: _("docker logs --follow ...") 140 | startOnInit: true 141 | request: 142 | service: Compose 143 | method: doDockerCmd 144 | params: 145 | id: "{{ _selected[0].id }}" 146 | cmd: "logs" 147 | cmd2: "--follow" 148 | - type: iconButton 149 | icon: mdi:restart 150 | tooltip: _("restart") 151 | enabledConstraints: 152 | minSelected: 1 153 | maxSelected: 1 154 | execute: 155 | type: taskDialog 156 | taskDialog: 157 | config: 158 | title: _("docker restart ...") 159 | startOnInit: true 160 | request: 161 | service: Compose 162 | method: doDockerCmd 163 | params: 164 | cmd: "restart" 165 | cmd2: "" 166 | id: "{{ _selected[0].id }}" 167 | - type: iconButton 168 | icon: mdi:download 169 | tooltip: _("Download log") 170 | enabledConstraints: 171 | minSelected: 1 172 | maxSelected: 1 173 | execute: 174 | type: url 175 | url: '/download?service=Compose&method=getContainerLog¶ms={"id":"{{ _selected[0].id }}","name":"{{ _selected[0].name }}"}' 176 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/component.d/omv-services-compose-volumes-datatable-page.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: component 3 | data: 4 | name: omv-services-compose-volumes-datatable-page 5 | type: datatablePage 6 | config: 7 | autoReload: false 8 | hasSearchField: true 9 | remoteSorting: true 10 | rowId: name 11 | stateId: 834f2d10-0591-11ee-bcac-d35108090f95 12 | sorters: 13 | - dir: asc 14 | prop: name 15 | store: 16 | proxy: 17 | service: Compose 18 | get: 19 | method: getVolumesBg 20 | task: true 21 | columns: 22 | - name: _("Name") 23 | prop: name 24 | flexGrow: 2 25 | sortable: true 26 | - name: _("Size") 27 | prop: size 28 | flexGrow: 1 29 | sortable: true 30 | cellTemplateName: template 31 | cellTemplateConfig: '{{ size | tobytes | binaryunit | notavailable("-") }}' 32 | - name: _("Mountpoint") 33 | prop: mountpoint 34 | flexGrow: 4 35 | sortable: true 36 | - name: _("Driver") 37 | prop: driver 38 | flexGrow: 1 39 | sortable: true 40 | actions: 41 | - type: iconButton 42 | icon: mdi:delete 43 | tooltip: _("Delete") 44 | enabledConstraints: 45 | minSelected: 1 46 | maxSelected: 1 47 | execute: 48 | type: taskDialog 49 | taskDialog: 50 | config: 51 | title: _("docker volume rm ...") 52 | startOnInit: true 53 | request: 54 | service: Compose 55 | method: doDockerVolumeCmd 56 | params: 57 | name: "{{ _selected[0].name }}" 58 | command: "rm" 59 | - type: iconButton 60 | icon: mdi:magnify 61 | tooltip: _("Inspect") 62 | enabledConstraints: 63 | minSelected: 1 64 | maxSelected: 1 65 | execute: 66 | type: taskDialog 67 | taskDialog: 68 | config: 69 | title: _("docker volume inspect ...") 70 | startOnInit: true 71 | request: 72 | service: Compose 73 | method: doDockerVolumeCmd 74 | params: 75 | name: "{{ _selected[0].name }}" 76 | command: "inspect" 77 | buttons: 78 | stop: 79 | hidden: true 80 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/dashboard.d/containers.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: dashboard-widget 3 | data: 4 | id: 33ebe908-8878-11ec-991b-f356096873ad 5 | title: _("Containers") 6 | description: _("Displays information about containers in a table.") 7 | type: datatable 8 | permissions: 9 | role: 10 | - admin 11 | - user 12 | datatable: 13 | columns: 14 | - name: _("Name") 15 | prop: name 16 | flexGrow: 1 17 | sortable: true 18 | - name: _("Image") 19 | prop: image 20 | sortable: true 21 | flexGrow: 2 22 | - name: _("Status") 23 | prop: status 24 | flexGrow: 1 25 | sortable: true 26 | store: 27 | proxy: 28 | service: Compose 29 | get: 30 | method: getContainers 31 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/dashboard.d/containers_grid.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: dashboard-widget 3 | data: 4 | id: 76185fc5-024b-4246-93e7-735ef1331b20 5 | title: _("Containers") 6 | description: _("Displays information about containers in a grid.") 7 | type: grid 8 | reloadPeriod: 10000 9 | permissions: 10 | role: 11 | - admin 12 | - user 13 | grid: 14 | item: 15 | content: '{{ name }}' 16 | tooltip: '{% if status|slice(0,3) == "Up " %}{{ "Running" | translate }}{% else %}{{ "Not running" | translate }}{% endif %}' 17 | class: 'omv-text-center omv-text-nowrap {% if status|slice(0,3) == "Up " %}omv-background-color-pair-success{% else %}omv-background-color-pair-error{% endif %}' 18 | contentClass: 'omv-text-truncate' 19 | store: 20 | proxy: 21 | service: Compose 22 | get: 23 | method: getContainers 24 | filters: 25 | - operator: ne 26 | arg0: 27 | prop: name 28 | arg1: 'Docker' 29 | sorters: 30 | - prop: name 31 | dir: asc -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/dashboard.d/containers_term.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: dashboard-widget 3 | data: 4 | id: 10e100ae-41a9-11f0-bfdc-9378defeb859 5 | title: _("Container Terminals") 6 | description: _("Displays containers with a link to cterm exec terminal in a table.") 7 | type: datatable 8 | permissions: 9 | role: 10 | - admin 11 | - user 12 | datatable: 13 | columns: 14 | - name: _("Name") 15 | prop: name 16 | flexGrow: 1 17 | sortable: true 18 | - name: _("Terminal") 19 | prop: term 20 | sortable: true 21 | flexGrow: 1 22 | store: 23 | proxy: 24 | service: Compose 25 | get: 26 | method: getContainersTerm 27 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/log.d/omv-compose-backup.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: log 3 | data: 4 | id: omv-compose-backup 5 | text: _("Compose Backup") 6 | columns: 7 | - name: _("Date & Time") 8 | sortable: true 9 | prop: date 10 | cellTemplateName: localeDateTime 11 | flexGrow: 1 12 | - name: _("Action") 13 | sortable: true 14 | prop: action 15 | flexGrow: 1 16 | - name: _("Message") 17 | sortable: true 18 | prop: message 19 | flexGrow: 4 20 | request: 21 | service: LogFile 22 | method: getList 23 | params: 24 | id: omv-compose-backup 25 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/log.d/omv-compose-restore.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: log 3 | data: 4 | id: omv-compose-restore 5 | text: _("Compose Restore") 6 | columns: 7 | - name: _("Date & Time") 8 | sortable: true 9 | prop: date 10 | cellTemplateName: localeDateTime 11 | flexGrow: 1 12 | - name: _("Action") 13 | sortable: true 14 | prop: action 15 | flexGrow: 1 16 | - name: _("Message") 17 | sortable: true 18 | prop: message 19 | flexGrow: 4 20 | request: 21 | service: LogFile 22 | method: getList 23 | params: 24 | id: omv-compose-restore 25 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/log.d/omv-compose-start.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: log 3 | data: 4 | id: omv-compose-start 5 | text: _("Compose Start") 6 | columns: 7 | - name: _("Date & Time") 8 | sortable: true 9 | prop: date 10 | cellTemplateName: localeDateTime 11 | flexGrow: 1 12 | - name: _("Action") 13 | sortable: true 14 | prop: action 15 | flexGrow: 1 16 | - name: _("Message") 17 | sortable: true 18 | prop: message 19 | flexGrow: 4 20 | request: 21 | service: LogFile 22 | method: getList 23 | params: 24 | id: omv-compose-start 25 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/log.d/omv-compose-stop.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: log 3 | data: 4 | id: omv-compose-stop 5 | text: _("Compose Stop") 6 | columns: 7 | - name: _("Date & Time") 8 | sortable: true 9 | prop: date 10 | cellTemplateName: localeDateTime 11 | flexGrow: 1 12 | - name: _("Action") 13 | sortable: true 14 | prop: action 15 | flexGrow: 1 16 | - name: _("Message") 17 | sortable: true 18 | prop: message 19 | flexGrow: 4 20 | request: 21 | service: LogFile 22 | method: getList 23 | params: 24 | id: omv-compose-stop 25 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/log.d/omv-compose-update.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: log 3 | data: 4 | id: omv-compose-update 5 | text: _("Compose Update") 6 | columns: 7 | - name: _("Date & Time") 8 | sortable: true 9 | prop: date 10 | cellTemplateName: localeDateTime 11 | flexGrow: 1 12 | - name: _("Action") 13 | sortable: true 14 | prop: action 15 | flexGrow: 1 16 | - name: _("Message") 17 | sortable: true 18 | prop: message 19 | flexGrow: 4 20 | request: 21 | service: LogFile 22 | method: getList 23 | params: 24 | id: omv-compose-update 25 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/navigation.d/services.compose.configs.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: navigation-item 3 | data: 4 | path: "services.compose.configs" 5 | text: _("Configs") 6 | position: 22 7 | icon: mdi:text 8 | url: "/services/compose/configs" 9 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/navigation.d/services.compose.containers.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: navigation-item 3 | data: 4 | path: "services.compose.containers" 5 | text: _("Containers") 6 | position: 80 7 | icon: mdi:list-box-outline 8 | url: "/services/compose/containers" 9 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/navigation.d/services.compose.dockerfiles.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: navigation-item 3 | data: 4 | path: "services.compose.dockerfiles" 5 | text: _("Dockerfiles") 6 | position: 90 7 | icon: mdi:docker 8 | url: "/services/compose/dockerfiles" 9 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/navigation.d/services.compose.files.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: navigation-item 3 | data: 4 | path: "services.compose.files" 5 | text: _("Files") 6 | position: 20 7 | icon: mdi:file-document-outline 8 | url: "/services/compose/files" 9 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/navigation.d/services.compose.images.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: navigation-item 3 | data: 4 | path: "services.compose.images" 5 | text: _("Images") 6 | position: 50 7 | icon: mdi:image-multiple-outline 8 | url: "/services/compose/images" 9 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/navigation.d/services.compose.networks.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: navigation-item 3 | data: 4 | path: "services.compose.networks" 5 | text: _("Networks") 6 | position: 60 7 | icon: mdi:lan 8 | url: "/services/compose/networks" 9 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/navigation.d/services.compose.repos.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: navigation-item 3 | data: 4 | path: "services.compose.repos" 5 | text: _("Repos") 6 | position: 120 7 | icon: mdi:file-key-outline 8 | url: "/services/compose/repos" 9 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/navigation.d/services.compose.restore.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: navigation-item 3 | data: 4 | path: "services.compose.restore" 5 | text: _("Restore") 6 | position: 110 7 | icon: mdi:restore 8 | url: "/services/compose/restore" 9 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/navigation.d/services.compose.schedule.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: navigation-item 3 | data: 4 | path: "services.compose.schedule" 5 | text: _("Schedule") 6 | position: 100 7 | icon: mdi:calendar-clock-outline 8 | url: "/services/compose/schedule" 9 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/navigation.d/services.compose.services.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: navigation-item 3 | data: 4 | path: "services.compose.services" 5 | text: _("Services") 6 | position: 30 7 | icon: mdi:format-list-group 8 | url: "/services/compose/services" 9 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/navigation.d/services.compose.settings.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: navigation-item 3 | data: 4 | path: "services.compose.settings" 5 | text: _("Settings") 6 | position: 10 7 | icon: "tune" 8 | url: "/services/compose/settings" 9 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/navigation.d/services.compose.stats.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: navigation-item 3 | data: 4 | path: "services.compose.stats" 5 | text: _("Stats") 6 | position: 40 7 | icon: mdi:poll 8 | url: "/services/compose/stats" 9 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/navigation.d/services.compose.volumes.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: navigation-item 3 | data: 4 | path: "services.compose.volumes" 5 | text: _("Volumes") 6 | position: 70 7 | icon: mdi:database 8 | url: "/services/compose/volumes" 9 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/navigation.d/services.compose.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: navigation-item 3 | data: 4 | path: "services.compose" 5 | text: _("Compose") 6 | icon: "mdi:playlist-music-outline" 7 | url: "/services/compose" 8 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.configs.create.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose/configs/create" 5 | title: _("Create") 6 | notificationTitle: _("Created config.") 7 | component: omv-services-compose-config-form-page 8 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.configs.edit.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose/configs/edit/:uuid" 5 | title: _("Edit") 6 | editing: true 7 | notificationTitle: _("Edit config.") 8 | component: omv-services-compose-config-form-page 9 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.configs.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose/configs" 5 | title: _("Configs") 6 | component: omv-services-compose-configs-datatable-page 7 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.containers.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose/containers" 5 | title: _("Containers") 6 | component: omv-services-compose-containers-datatable-page 7 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.dockerfiles.create.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose/dockerfiles/create" 5 | title: _("Create") 6 | notificationTitle: _("Created dockerfile.") 7 | component: omv-services-compose-dockerfile-form-page 8 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.dockerfiles.edit.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose/dockerfiles/edit/:uuid" 5 | title: _("Edit") 6 | editing: true 7 | notificationTitle: _("Edit dockerfile.") 8 | component: omv-services-compose-dockerfile-form-page 9 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.dockerfiles.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose/dockerfiles" 5 | title: _("Dockerfiles") 6 | component: omv-services-compose-dockerfiles-datatable-page 7 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.examples.create.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose/files/example" 5 | title: _("Create from example") 6 | notificationTitle: _("Created file.") 7 | component: omv-services-compose-file-example-form-page 8 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.files.create.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose/files/create" 5 | title: _("Create") 6 | notificationTitle: _("Created file.") 7 | component: omv-services-compose-file-form-page 8 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.files.edit.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose/files/edit/:uuid" 5 | title: _("Edit") 6 | editing: true 7 | notificationTitle: _("Edit file.") 8 | component: omv-services-compose-file-form-page 9 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.files.global.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose/files/global" 5 | title: _("Global environment variables") 6 | editing: true 7 | notificationTitle: _("Edit global environment variable file.") 8 | component: omv-services-compose-files-global-form-page 9 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.files.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose/files" 5 | title: _("Files") 6 | component: omv-services-compose-files-datatable-page 7 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.images.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose/images" 5 | title: _("Images") 6 | component: omv-services-compose-images-datatable-page 7 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.networks.create.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose/networks/create" 5 | title: _("Create") 6 | notificationTitle: _("Created network.") 7 | component: omv-services-compose-network-form-page 8 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.networks.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose/networks" 5 | title: _("Networks") 6 | component: omv-services-compose-networks-datatable-page 7 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.repos.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose/repos" 5 | title: _("Repos") 6 | component: omv-services-compose-repos-datatable-page 7 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.restore.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose/restore" 5 | title: _("Restore") 6 | component: omv-services-compose-restore-datatable-page 7 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.schedule.create.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose/schedule/create" 5 | title: _("Create") 6 | notificationTitle: _("Created scheduled job.") 7 | component: omv-services-compose-schedule-form-page 8 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.schedule.edit.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose/schedule/edit/:uuid" 5 | title: _("Edit") 6 | editing: true 7 | notificationTitle: _("Edit scheduled job.") 8 | component: omv-services-compose-schedule-form-page 9 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.schedule.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose/schedule" 5 | title: _("Schedule") 6 | component: omv-services-compose-schedule-datatable-page 7 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.services.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose/services" 5 | title: _("Services") 6 | component: omv-services-compose-services-datatable-page 7 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.settings.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose/settings" 5 | title: _("Settings") 6 | editing: true 7 | component: omv-services-compose-settings-form-page 8 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.stats.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose/stats" 5 | title: _("Stats") 6 | component: omv-services-compose-stats-datatable-page 7 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.url.create.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose/files/url" 5 | title: _("Create from URL") 6 | notificationTitle: _("Created file from url.") 7 | component: omv-services-compose-file-url-form-page 8 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.volumes.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose/volumes" 5 | title: _("Volumes") 6 | component: omv-services-compose-volumes-datatable-page 7 | -------------------------------------------------------------------------------- /usr/share/openmediavault/workbench/route.d/services.compose.yaml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | type: route 3 | data: 4 | url: "/services/compose" 5 | title: _("Compose") 6 | component: omv-services-compose-navigation-page 7 | --------------------------------------------------------------------------------