Initial version of nextcloud collection
Signed-off-by: Nis Wechselberg <enbewe@enbewe.de>
This commit is contained in:
parent
e559257349
commit
4ee5aacf61
17 changed files with 914 additions and 0 deletions
5
CHANGELOG.md
Normal file
5
CHANGELOG.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# Changelog
|
||||||
|
|
||||||
|
## 1.0.0
|
||||||
|
|
||||||
|
* Initial Release
|
19
README.md
Normal file
19
README.md
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# Ansible Collection - enbewe.nextcloud
|
||||||
|
Collecion to deploy Nextcloud for file storage as well as CalDav/CardDav Server.
|
||||||
|
|
||||||
|
## Playbooks
|
||||||
|
### enbewe.nextcloud.deployment
|
||||||
|
Deploys the role `enbewe.nextcloud.nextcloud` to all hosts in the group `nextcloud`.
|
||||||
|
|
||||||
|
## Roles
|
||||||
|
### enbewe.nextcloud.nextcloud
|
||||||
|
Deploys [Nextcloud](https://nextcloud.com/) through a podman container.
|
||||||
|
The deployment consists of a separate postgres database container, a redis container,
|
||||||
|
an application container as well as a container for the cron service.
|
||||||
|
|
||||||
|
The configuration of the instance is automatically adjusted to work with
|
||||||
|
a OpenID provider.
|
||||||
|
|
||||||
|
## Modules
|
||||||
|
### enbewe.nextcloud.nextcloud_app
|
||||||
|
Manages the apps installed in the instance.
|
67
galaxy.yml
Normal file
67
galaxy.yml
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
---
|
||||||
|
### REQUIRED
|
||||||
|
# The namespace of the collection. This can be a company/brand/organization or product namespace under which all
|
||||||
|
# content lives. May only contain alphanumeric lowercase characters and underscores. Namespaces cannot start with
|
||||||
|
# underscores or numbers and cannot contain consecutive underscores
|
||||||
|
namespace: 'enbewe'
|
||||||
|
|
||||||
|
# The name of the collection. Has the same character restrictions as 'namespace'
|
||||||
|
name: 'nextcloud'
|
||||||
|
|
||||||
|
# The version of the collection. Must be compatible with semantic versioning
|
||||||
|
version: '1.0.0'
|
||||||
|
|
||||||
|
# The path to the Markdown (.md) readme file. This path is relative to the root of the collection
|
||||||
|
readme: 'README.md'
|
||||||
|
|
||||||
|
# A list of the collection's content authors. Can be just the name or in the format 'Full Name <email> (url)
|
||||||
|
# @nicks:irc/im.site#channel'
|
||||||
|
authors:
|
||||||
|
- 'Nis Wechselberg <enbewe+ansible@enbewe.de>'
|
||||||
|
|
||||||
|
|
||||||
|
### OPTIONAL but strongly recommended
|
||||||
|
# A short summary description of the collection
|
||||||
|
description: 'Deployment tools for nextcloud'
|
||||||
|
|
||||||
|
# Either a single license or a list of licenses for content inside of a collection. Ansible Galaxy currently only
|
||||||
|
# accepts L(SPDX,https://spdx.org/licenses/) licenses. This key is mutually exclusive with 'license_file'
|
||||||
|
license:
|
||||||
|
- 'MIT'
|
||||||
|
|
||||||
|
# A list of tags you want to associate with the collection for indexing/searching. A tag name has the same character
|
||||||
|
# requirements as 'namespace' and 'name'
|
||||||
|
tags:
|
||||||
|
- 'linux'
|
||||||
|
|
||||||
|
# Collections that this collection requires to be installed for it to be usable. The key of the dict is the
|
||||||
|
# collection label 'namespace.name'. The value is a version range
|
||||||
|
# L(specifiers,https://python-semanticversion.readthedocs.io/en/latest/#requirement-specification). Multiple version
|
||||||
|
# range specifiers can be set and are separated by ','
|
||||||
|
dependencies:
|
||||||
|
containers.podman: '1.13.0'
|
||||||
|
|
||||||
|
# The URL of the originating SCM repository
|
||||||
|
repository: 'https://git.enbewe.de/Coding/ansible-collection-nextcloud'
|
||||||
|
|
||||||
|
# The URL to any online docs
|
||||||
|
# documentation: http://docs.example.com
|
||||||
|
|
||||||
|
# The URL to the homepage of the collection/project
|
||||||
|
# homepage: http://example.com
|
||||||
|
|
||||||
|
# The URL to the collection issue tracker
|
||||||
|
# issues: http://example.com/issue/tracker
|
||||||
|
|
||||||
|
# A list of file glob-like patterns used to filter any files or directories that should not be included in the build
|
||||||
|
# artifact. A pattern is matched from the relative path of the file or directory of the collection directory. This
|
||||||
|
# uses 'fnmatch' to match the files or directories. Some directories and files like 'galaxy.yml', '*.pyc', '*.retry',
|
||||||
|
# and '.git' are always filtered. Mutually exclusive with 'manifest'
|
||||||
|
# build_ignore: []
|
||||||
|
|
||||||
|
# A dict controlling use of manifest directives used in building the collection artifact. The key 'directives' is a
|
||||||
|
# list of MANIFEST.in style
|
||||||
|
# L(directives,https://packaging.python.org/en/latest/guides/using-manifest-in/#manifest-in-commands). The key
|
||||||
|
# 'omit_default_directives' is a boolean that controls whether the default directives are used. Mutually exclusive
|
||||||
|
# with 'build_ignore'
|
||||||
|
# manifest: null
|
52
meta/runtime.yml
Normal file
52
meta/runtime.yml
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
---
|
||||||
|
# Collections must specify a minimum required ansible version to upload
|
||||||
|
# to galaxy
|
||||||
|
requires_ansible: '>=2.17.0'
|
||||||
|
|
||||||
|
# Content that Ansible needs to load from another location or that has
|
||||||
|
# been deprecated/removed
|
||||||
|
# plugin_routing:
|
||||||
|
# action:
|
||||||
|
# redirected_plugin_name:
|
||||||
|
# redirect: ns.col.new_location
|
||||||
|
# deprecated_plugin_name:
|
||||||
|
# deprecation:
|
||||||
|
# removal_version: "4.0.0"
|
||||||
|
# warning_text: |
|
||||||
|
# See the porting guide on how to update your playbook to
|
||||||
|
# use ns.col.another_plugin instead.
|
||||||
|
# removed_plugin_name:
|
||||||
|
# tombstone:
|
||||||
|
# removal_version: "2.0.0"
|
||||||
|
# warning_text: |
|
||||||
|
# See the porting guide on how to update your playbook to
|
||||||
|
# use ns.col.another_plugin instead.
|
||||||
|
# become:
|
||||||
|
# cache:
|
||||||
|
# callback:
|
||||||
|
# cliconf:
|
||||||
|
# connection:
|
||||||
|
# doc_fragments:
|
||||||
|
# filter:
|
||||||
|
# httpapi:
|
||||||
|
# inventory:
|
||||||
|
# lookup:
|
||||||
|
# module_utils:
|
||||||
|
# modules:
|
||||||
|
# netconf:
|
||||||
|
# shell:
|
||||||
|
# strategy:
|
||||||
|
# terminal:
|
||||||
|
# test:
|
||||||
|
# vars:
|
||||||
|
|
||||||
|
# Python import statements that Ansible needs to load from another location
|
||||||
|
# import_redirection:
|
||||||
|
# ansible_collections.ns.col.plugins.module_utils.old_location:
|
||||||
|
# redirect: ansible_collections.ns.col.plugins.module_utils.new_location
|
||||||
|
|
||||||
|
# Groups of actions/modules that take a common set of options
|
||||||
|
# action_groups:
|
||||||
|
# group_name:
|
||||||
|
# - module1
|
||||||
|
# - module2
|
5
playbooks/deployment.yml
Normal file
5
playbooks/deployment.yml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
- name: 'Deploy collection roles to matching host groups'
|
||||||
|
hosts: 'nextcloud'
|
||||||
|
roles:
|
||||||
|
- 'enbewe.nextcloud.nextcloud'
|
31
plugins/README.md
Normal file
31
plugins/README.md
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
# Collections Plugins Directory
|
||||||
|
|
||||||
|
This directory can be used to ship various plugins inside an Ansible collection. Each plugin is placed in a folder that
|
||||||
|
is named after the type of plugin it is in. It can also include the `module_utils` and `modules` directory that
|
||||||
|
would contain module utils and modules respectively.
|
||||||
|
|
||||||
|
Here is an example directory of the majority of plugins currently supported by Ansible:
|
||||||
|
|
||||||
|
```
|
||||||
|
└── plugins
|
||||||
|
├── action
|
||||||
|
├── become
|
||||||
|
├── cache
|
||||||
|
├── callback
|
||||||
|
├── cliconf
|
||||||
|
├── connection
|
||||||
|
├── filter
|
||||||
|
├── httpapi
|
||||||
|
├── inventory
|
||||||
|
├── lookup
|
||||||
|
├── module_utils
|
||||||
|
├── modules
|
||||||
|
├── netconf
|
||||||
|
├── shell
|
||||||
|
├── strategy
|
||||||
|
├── terminal
|
||||||
|
├── test
|
||||||
|
└── vars
|
||||||
|
```
|
||||||
|
|
||||||
|
A full list of plugin types can be found at [Working With Plugins](https://docs.ansible.com/ansible-core/2.17/plugins/plugins.html).
|
279
plugins/modules/nextcloud_app.py
Normal file
279
plugins/modules/nextcloud_app.py
Normal file
|
@ -0,0 +1,279 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright: Nis Wechselberg <enbewe@enbewe.de>
|
||||||
|
# MIT License (see https://spdx.org/licenses/MIT.html)
|
||||||
|
# Based upon code by s3lph <s3lph@kabelsalat.ch>
|
||||||
|
# MIT License (see https://spdx.org/licenses/MIT.html)
|
||||||
|
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
|
||||||
|
DOCUMENTATION = r'''
|
||||||
|
---
|
||||||
|
module: nextcloud_app
|
||||||
|
|
||||||
|
short_description: Enable or disable Nextcloud apps.
|
||||||
|
|
||||||
|
version_added: "1.0.0"
|
||||||
|
|
||||||
|
description: Enable or disable Nextcloud apps via C(occ app:) in the running container.
|
||||||
|
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description: Name of the app or apps to install/remove/enable/disable.
|
||||||
|
required: true
|
||||||
|
type: list
|
||||||
|
elements: str
|
||||||
|
state:
|
||||||
|
description: State the app or apps should be in.
|
||||||
|
required: false
|
||||||
|
default: enabled
|
||||||
|
type: str
|
||||||
|
choices:
|
||||||
|
- enabled
|
||||||
|
- disabled
|
||||||
|
- absent
|
||||||
|
force:
|
||||||
|
description: Install and enable apps that are not compatible with the current Nextcloud version.
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
type: bool
|
||||||
|
engine:
|
||||||
|
description: Engine to use for the OCI runtime.
|
||||||
|
required: false
|
||||||
|
default: podman
|
||||||
|
type: str
|
||||||
|
container_user:
|
||||||
|
description: The user to run the occ command as while in the container.
|
||||||
|
required: false
|
||||||
|
default: www-data
|
||||||
|
type: str
|
||||||
|
container_name:
|
||||||
|
description: The name of the container to run the command in.
|
||||||
|
required: false
|
||||||
|
default: nextcloud-app
|
||||||
|
type: str
|
||||||
|
|
||||||
|
author:
|
||||||
|
- Nis Wechselberg
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = r'''
|
||||||
|
- name: Install and enable photos app
|
||||||
|
enbewe.nextcloud.nextcloud_app:
|
||||||
|
name: photos
|
||||||
|
|
||||||
|
- name: Install and enable PIM apps
|
||||||
|
enbewe.nextcloud.nextcloud_app:
|
||||||
|
name:
|
||||||
|
- contacts
|
||||||
|
- calendar
|
||||||
|
- mail
|
||||||
|
|
||||||
|
- name: Disable resource hungry dashboard
|
||||||
|
enbewe.nextcloud.nextcloud_app:
|
||||||
|
name: dashboard
|
||||||
|
state: disabled
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = r'''
|
||||||
|
'''
|
||||||
|
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
|
||||||
|
def check_nextcloud_status(module, result):
|
||||||
|
'''
|
||||||
|
Gather nextcloud status through calling `occ status`.
|
||||||
|
'''
|
||||||
|
sc = subprocess.run([module.params['engine'], 'exec',
|
||||||
|
'--user', module.params['container_user'],
|
||||||
|
module.params['container_name'],
|
||||||
|
'php', 'occ', 'status', '--output=json'],
|
||||||
|
capture_output=True, encoding='utf-8', check=False)
|
||||||
|
if sc.returncode != 0:
|
||||||
|
result['stdout'] = sc.stdout
|
||||||
|
result['stderr'] = sc.stderr
|
||||||
|
module.fail_json(
|
||||||
|
msg='occ status returned non-zero exit code. Run with -vvv to view the output',
|
||||||
|
**result)
|
||||||
|
|
||||||
|
status = json.loads(sc.stdout)
|
||||||
|
if not status['installed']:
|
||||||
|
module.fail_json(
|
||||||
|
msg='Nextcloud installation has not been completed, so occ app is not available.',
|
||||||
|
**result)
|
||||||
|
|
||||||
|
def get_app_status(module, result):
|
||||||
|
'''
|
||||||
|
Gather state of installed apps in nextcloud.
|
||||||
|
'''
|
||||||
|
# Gather Nextcloud app list
|
||||||
|
ac = subprocess.run([module.params['engine'], 'exec',
|
||||||
|
'--user', module.params['container_user'],
|
||||||
|
module.params['container_name'],
|
||||||
|
'php', 'occ', 'app:list', '--output=json'],
|
||||||
|
capture_output=True, encoding='utf-8', check=False)
|
||||||
|
if ac.returncode != 0:
|
||||||
|
result['stdout'] = ac.stdout
|
||||||
|
result['stderr'] = ac.stderr
|
||||||
|
module.fail_json(
|
||||||
|
msg='occ app:list returned non-zero exit code. Run with -vvv to view the output',
|
||||||
|
**result)
|
||||||
|
|
||||||
|
return json.loads(ac.stdout)
|
||||||
|
|
||||||
|
def remove_app(module, result, app):
|
||||||
|
'''
|
||||||
|
Remove the given app from the installation.
|
||||||
|
'''
|
||||||
|
result['changed'] = True
|
||||||
|
if not module.check_mode:
|
||||||
|
c = subprocess.run([module.params['engine'], 'exec',
|
||||||
|
'--user', module.params['container_user'],
|
||||||
|
module.params['container_name'],
|
||||||
|
'php', 'occ', 'app:remove', '--keep-data', app],
|
||||||
|
capture_output=True, encoding='utf-8', check=False)
|
||||||
|
if c.returncode != 0:
|
||||||
|
result['stdout'] = c.stdout
|
||||||
|
result['stderr'] = c.stderr
|
||||||
|
module.fail_json(
|
||||||
|
msg='occ app:remove returned non-zero exit code. Run with -vvv to view the output',
|
||||||
|
**result)
|
||||||
|
|
||||||
|
def install_app(module, result, app):
|
||||||
|
'''
|
||||||
|
Install the given app to the installation.
|
||||||
|
'''
|
||||||
|
state = module.params['state']
|
||||||
|
result['changed'] = True
|
||||||
|
if not module.check_mode:
|
||||||
|
cmdline = [module.params['engine'], 'exec',
|
||||||
|
'--user', module.params['container_user'],
|
||||||
|
module.params['container_name'],
|
||||||
|
'php', 'occ', 'app:install']
|
||||||
|
if state == 'disabled':
|
||||||
|
cmdline.append('--keep-disabled')
|
||||||
|
if module.params['force']:
|
||||||
|
cmdline.append('--force')
|
||||||
|
cmdline.append(app)
|
||||||
|
c = subprocess.run(cmdline,
|
||||||
|
capture_output=True, encoding='utf-8', check=False)
|
||||||
|
if c.returncode != 0:
|
||||||
|
result['stdout'] = c.stdout
|
||||||
|
result['stderr'] = c.stderr
|
||||||
|
module.fail_json(
|
||||||
|
msg='occ app:install returned non-zero exit code. Run with -vvv to view the output',
|
||||||
|
**result)
|
||||||
|
|
||||||
|
def enable_app(module, result, app):
|
||||||
|
'''
|
||||||
|
Enable the (already installed) app.
|
||||||
|
'''
|
||||||
|
result['changed'] = True
|
||||||
|
if not module.check_mode:
|
||||||
|
cmdline = [module.params['engine'], 'exec',
|
||||||
|
'--user', module.params['container_user'],
|
||||||
|
module.params['container_name'],
|
||||||
|
'php', 'occ', 'app:enable']
|
||||||
|
if module.params['force']:
|
||||||
|
cmdline.append('--force')
|
||||||
|
cmdline.append(app)
|
||||||
|
c = subprocess.run(cmdline,
|
||||||
|
capture_output=True, encoding='utf-8', check=False)
|
||||||
|
if c.returncode != 0:
|
||||||
|
result['stdout'] = c.stdout
|
||||||
|
result['stderr'] = c.stderr
|
||||||
|
module.fail_json(
|
||||||
|
msg='occ app:enable returned non-zero exit code. Run with -vvv to view the output',
|
||||||
|
**result)
|
||||||
|
|
||||||
|
def disable_app(module, result, app):
|
||||||
|
'''
|
||||||
|
Disable the given app without removing it.
|
||||||
|
'''
|
||||||
|
result['changed'] = True
|
||||||
|
if not module.check_mode:
|
||||||
|
c = subprocess.run([module.params['engine'], 'exec',
|
||||||
|
'--user', module.params['container_user'],
|
||||||
|
module.params['container_name'],
|
||||||
|
'php', 'occ', 'app:disable', app],
|
||||||
|
capture_output=True, encoding='utf-8', check=False)
|
||||||
|
if c.returncode != 0:
|
||||||
|
result['stdout'] = c.stdout
|
||||||
|
result['stderr'] = c.stderr
|
||||||
|
module.fail_json(
|
||||||
|
msg='occ app:disable returned non-zero exit code. Run with -vvv to view the output',
|
||||||
|
**result)
|
||||||
|
|
||||||
|
def apply_app_status(module, result, app_status):
|
||||||
|
'''
|
||||||
|
Apply the status from the configuration to the applications in nextcloud.
|
||||||
|
'''
|
||||||
|
state = module.params['state']
|
||||||
|
apps = module.params['name']
|
||||||
|
if isinstance(apps, str):
|
||||||
|
apps = [apps]
|
||||||
|
|
||||||
|
# Apply app configuration changes
|
||||||
|
for app in apps:
|
||||||
|
if state == 'absent' and (app in app_status['enabled'] or app in app_status['disabled']):
|
||||||
|
remove_app(module, result, app)
|
||||||
|
elif (state in ['enabled', 'disabled']
|
||||||
|
and app not in app_status['enabled']
|
||||||
|
and app not in app_status['disabled']):
|
||||||
|
install_app(module, result, app)
|
||||||
|
elif state == 'enabled' and app in app_status['disabled']:
|
||||||
|
enable_app(module, result, app)
|
||||||
|
elif state == 'disabled' and app in app_status['enabled']:
|
||||||
|
disable_app(module, result, app)
|
||||||
|
|
||||||
|
def run_module():
|
||||||
|
'''
|
||||||
|
Run the ansible module code.
|
||||||
|
'''
|
||||||
|
# define available arguments/parameters a user can pass to the module
|
||||||
|
module_args = {
|
||||||
|
'name': { 'required': True, 'type': 'list' },
|
||||||
|
'state': { 'required': False, 'default': 'enabled', 'type': 'str' },
|
||||||
|
'force': { 'required': False, 'default': False, 'type': 'bool' },
|
||||||
|
'engine': { 'required': False, 'default': 'podman', 'type': 'str' },
|
||||||
|
'container_user': { 'required': False, 'default': 'www-data', 'type': 'str' },
|
||||||
|
'container_name': { 'required': False, 'default': 'nextcloud-app', 'type': 'str' },
|
||||||
|
}
|
||||||
|
|
||||||
|
# seed the result dict in the object
|
||||||
|
# we primarily care about changed and state
|
||||||
|
# changed is if this module effectively modified the target
|
||||||
|
# state will include any data that you want your module to pass back
|
||||||
|
# for consumption, for example, in a subsequent task
|
||||||
|
result = { 'changed': False }
|
||||||
|
|
||||||
|
# the AnsibleModule object will be our abstraction working with Ansible
|
||||||
|
# this includes instantiation, a couple of common attr would be the
|
||||||
|
# args/params passed to the execution, as well as if the module
|
||||||
|
# supports check mode
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=module_args,
|
||||||
|
supports_check_mode=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
if module.params['state'] not in ['enabled', 'disabled', 'absent']:
|
||||||
|
module.fail_json(msg='state must be one of enabled, disabled or absent', **result)
|
||||||
|
|
||||||
|
check_nextcloud_status(module, result)
|
||||||
|
app_status = get_app_status(module, result)
|
||||||
|
apply_app_status(module, result, app_status)
|
||||||
|
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
'''
|
||||||
|
The main method called for the module.
|
||||||
|
'''
|
||||||
|
run_module()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
20
roles/nextcloud/defaults/main.yml
Normal file
20
roles/nextcloud/defaults/main.yml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
nextcloud_podman_network: 'nextcloud'
|
||||||
|
|
||||||
|
nextcloud_db_container_name: nextcloud-db
|
||||||
|
nextcloud_db_image_name: 'docker.io/library/postgres'
|
||||||
|
nextcloud_db_image_tag: '16'
|
||||||
|
nextcloud_db_volume: 'nextcloud-db'
|
||||||
|
|
||||||
|
nextcloud_redis_container_name: nextcloud-redis
|
||||||
|
nextcloud_redis_image_name: 'docker.io/library/redis'
|
||||||
|
nextcloud_redis_image_tag: 'alpine'
|
||||||
|
|
||||||
|
nextcloud_cron_container_name: 'nextcloud-cron'
|
||||||
|
|
||||||
|
nextcloud_app_listen_port: '127.0.0.1:8085'
|
||||||
|
nextcloud_app_container_name: 'nextcloud-app'
|
||||||
|
nextcloud_app_image_name: 'docker.io/library/nextcloud'
|
||||||
|
nextcloud_app_image_tag: '29-apache'
|
||||||
|
nextcloud_app_volume: 'nextcloud-app'
|
||||||
|
nextcloud_app_environments: []
|
34
roles/nextcloud/handlers/main.yml
Normal file
34
roles/nextcloud/handlers/main.yml
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
---
|
||||||
|
- name: 'Restart nextcloud-db container'
|
||||||
|
become: true
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: 'container-nextcloud-db'
|
||||||
|
state: 'restarted'
|
||||||
|
daemon_reload: true
|
||||||
|
notify:
|
||||||
|
- 'Restart nextcloud-app container'
|
||||||
|
- 'Restart nextcloud-cron container'
|
||||||
|
|
||||||
|
- name: 'Restart nextcloud-redis container'
|
||||||
|
become: true
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: 'container-nextcloud-redis'
|
||||||
|
state: 'restarted'
|
||||||
|
daemon_reload: true
|
||||||
|
notify:
|
||||||
|
- 'Restart nextcloud-app container'
|
||||||
|
- 'Restart nextcloud-cron container'
|
||||||
|
|
||||||
|
- name: 'Restart nextcloud-app container'
|
||||||
|
become: true
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: 'container-nextcloud-app'
|
||||||
|
state: 'restarted'
|
||||||
|
daemon_reload: true
|
||||||
|
|
||||||
|
- name: 'Restart nextcloud-cron container'
|
||||||
|
become: true
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: 'container-nextcloud-cron'
|
||||||
|
state: 'restarted'
|
||||||
|
daemon_reload: true
|
93
roles/nextcloud/tasks/main.yml
Normal file
93
roles/nextcloud/tasks/main.yml
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
---
|
||||||
|
- name: 'Ensure needed software is installed'
|
||||||
|
become: true
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: 'podman'
|
||||||
|
state: 'present'
|
||||||
|
update_cache: true
|
||||||
|
cache_valid_time: 3600
|
||||||
|
|
||||||
|
- name: 'Prepare network'
|
||||||
|
become: true
|
||||||
|
containers.podman.podman_network:
|
||||||
|
name: '{{ nextcloud_podman_network }}'
|
||||||
|
state: 'present'
|
||||||
|
|
||||||
|
- name: 'Prepare nextcloud config files location'
|
||||||
|
become: true
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: '/etc/nextcloud'
|
||||||
|
state: 'directory'
|
||||||
|
owner: 'root'
|
||||||
|
group: 'root'
|
||||||
|
mode: 'u=rwx,g=rx,o=rx'
|
||||||
|
|
||||||
|
- name: 'Create config files for nextcloud'
|
||||||
|
become: true
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: '{{ item.src }}'
|
||||||
|
dest: '{{ item.dest }}'
|
||||||
|
owner: 33
|
||||||
|
group: 33
|
||||||
|
mode: '{{ item.mode }}'
|
||||||
|
notify: 'Restart nextcloud-app container'
|
||||||
|
loop:
|
||||||
|
- src: 'nextcloud/oidc.config.php.j2'
|
||||||
|
dest: '/etc/nextcloud/oidc.config.php'
|
||||||
|
mode: 'u=rw,g=r,o=r'
|
||||||
|
- src: 'nextcloud/ansible.config.php.j2'
|
||||||
|
dest: '/etc/nextcloud/ansible.config.php'
|
||||||
|
mode: 'u=rw,g=r,o=r'
|
||||||
|
- src: 'nextcloud/copy_config.sh.j2'
|
||||||
|
dest: '/etc/nextcloud/copy_config.sh'
|
||||||
|
mode: 'u=rwx,g=rx,o=rx'
|
||||||
|
|
||||||
|
- name: 'Create service files'
|
||||||
|
become: true
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: '{{ item.src }}'
|
||||||
|
dest: '{{ item.dest }}'
|
||||||
|
owner: 'root'
|
||||||
|
group: 'root'
|
||||||
|
mode: 'u=rw,g=r,o=r'
|
||||||
|
notify: '{{ item.notify }}'
|
||||||
|
loop:
|
||||||
|
- src: 'systemd/container-nextcloud-db.service.j2'
|
||||||
|
dest: '/etc/systemd/system/container-nextcloud-db.service'
|
||||||
|
notify: 'Restart nextcloud-db container'
|
||||||
|
- src: 'systemd/container-nextcloud-redis.service.j2'
|
||||||
|
dest: '/etc/systemd/system/container-nextcloud-redis.service'
|
||||||
|
notify: 'Restart nextcloud-redis container'
|
||||||
|
- src: 'systemd/container-nextcloud-cron.service.j2'
|
||||||
|
dest: '/etc/systemd/system/container-nextcloud-cron.service'
|
||||||
|
notify: 'Restart nextcloud-cron container'
|
||||||
|
- src: 'systemd/container-nextcloud-app.service.j2'
|
||||||
|
dest: '/etc/systemd/system/container-nextcloud-app.service'
|
||||||
|
notify: 'Restart nextcloud-app container'
|
||||||
|
|
||||||
|
- name: 'Start and enable services'
|
||||||
|
become: true
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: '{{ item }}'
|
||||||
|
state: 'started'
|
||||||
|
daemon_reload: true
|
||||||
|
enabled: true
|
||||||
|
loop:
|
||||||
|
- 'container-nextcloud-db.service'
|
||||||
|
- 'container-nextcloud-redis.service'
|
||||||
|
- 'container-nextcloud-cron.service'
|
||||||
|
- 'container-nextcloud-app.service'
|
||||||
|
|
||||||
|
- name: 'Configure apps'
|
||||||
|
become: true
|
||||||
|
enbewe.nextcloud.nextcloud_app:
|
||||||
|
state: '{{ item.key }}'
|
||||||
|
name: '{{ item.value }}'
|
||||||
|
force: true
|
||||||
|
container_name: '{{ nextcloud_app_container_name }}'
|
||||||
|
retries: 30
|
||||||
|
delay: 10
|
||||||
|
notify:
|
||||||
|
- 'Restart nextcloud-cron container'
|
||||||
|
- 'Restart nextcloud-app container'
|
||||||
|
loop: '{{ nextcloud_apps | dict2items }}'
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
$CONFIG = array (
|
||||||
|
'allow_user_to_change_display_name' => {{ nextcloud_oidc_allow_user_change_display_name | default('false') }},
|
||||||
|
'skeletondirectory' => '',
|
||||||
|
'templatedirectory' => '',
|
||||||
|
'hide_login_form' => {{ nextcloud_oidc_hide_password_form | default('false') }},
|
||||||
|
'maintenance_window_start' => {{ nextcloud_maintenance_window_start | default(2) }},
|
||||||
|
);
|
3
roles/nextcloud/templates/nextcloud/copy_config.sh.j2
Normal file
3
roles/nextcloud/templates/nextcloud/copy_config.sh.j2
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
cp /docker-entrypoint-hooks.d/before-starting/*.config.php /var/www/html/config/
|
123
roles/nextcloud/templates/nextcloud/oidc.config.php.j2
Normal file
123
roles/nextcloud/templates/nextcloud/oidc.config.php.j2
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
<?php
|
||||||
|
$CONFIG = array (
|
||||||
|
// Some Nextcloud options that might make sense here
|
||||||
|
'allow_user_to_change_display_name' => {{ nextcloud_oidc_allow_user_change_display_name | default('false') }},
|
||||||
|
'lost_password_link' => '{{ nextcloud_oidc_lost_password_link | default('disabled') }}',
|
||||||
|
|
||||||
|
// URL of provider. All other URLs are auto-discovered from .well-known
|
||||||
|
'oidc_login_provider_url' => '{{ nextcloud_oidc_provider_url }}',
|
||||||
|
|
||||||
|
// Client ID and secret registered with the provider
|
||||||
|
'oidc_login_client_id' => '{{ nextcloud_oidc_client_id }}',
|
||||||
|
'oidc_login_client_secret' => '{{ nextcloud_oidc_client_secret }}',
|
||||||
|
|
||||||
|
// Automatically redirect the login page to the provider
|
||||||
|
'oidc_login_auto_redirect' => {{ nextcloud_oidc_auto_redirect | default('false') }},
|
||||||
|
|
||||||
|
// Redirect to this page after logging out the user
|
||||||
|
'oidc_login_logout_url' => '{{ nextcloud_oidc_logout_url | default('') }}',
|
||||||
|
|
||||||
|
// If set to true the user will be redirected to the logout endpoint of the OIDC provider after logout
|
||||||
|
// in Nextcloud. After successfull logout the OIDC provider will redirect back to 'oidc_login_logout_url' (MUST be set).
|
||||||
|
'oidc_login_end_session_redirect' => {{ nextcloud_oidc_end_session_redirect | default('false') }},
|
||||||
|
|
||||||
|
// Login button text
|
||||||
|
'oidc_login_button_text' => '{{ nextcloud_oidc_button_text | default('Log in with Open ID') }}',
|
||||||
|
|
||||||
|
// Hide the NextCloud password change form.
|
||||||
|
'oidc_login_hide_password_form' => {{ nextcloud_oidc_hide_password_form | default('false') }},
|
||||||
|
|
||||||
|
// Use ID Token instead of UserInfo
|
||||||
|
'oidc_login_use_id_token' => {{ nextcloud_oidc_use_id_token | default('false') }},
|
||||||
|
|
||||||
|
// Attribute map for OIDC response. Available keys are:
|
||||||
|
// * id: Unique identifier for username
|
||||||
|
// * name: Full name
|
||||||
|
// If set to null, existing display name won't be overwritten
|
||||||
|
// * mail: Email address
|
||||||
|
// If set to null, existing email address won't be overwritten
|
||||||
|
// * quota: Nextcloud storage quota
|
||||||
|
// * home: Home directory location. A symlink or external storage to this location is used
|
||||||
|
// * ldap_uid: LDAP uid to search for when running in proxy mode
|
||||||
|
// * groups: Array or space separated string of Nextcloud groups for the user.
|
||||||
|
// Note that the name here corresponds to the GID of the group and not the display name
|
||||||
|
// In the admin panel, the GID may be obtained from the URL when editing a group
|
||||||
|
// * login_filter: Array or space separated string. If 'oidc_login_filter_allowed_values' is
|
||||||
|
// set, it is checked against these values.
|
||||||
|
// * photoURL: The URL of the user avatar. The nextcloud server will download the picture
|
||||||
|
// at user login. This may lead to security issues. Use with care.
|
||||||
|
// This will only be effective if oidc_login_update_avatar is enabled.
|
||||||
|
// * is_admin: If this value is truthy, the user is added to the admin group (optional)
|
||||||
|
'oidc_login_attributes' => array (
|
||||||
|
'id' => 'sub',
|
||||||
|
'name' => 'name',
|
||||||
|
'mail' => 'email',
|
||||||
|
'groups' => 'groups',
|
||||||
|
'is_admin' => 'groups_cloud_admin',
|
||||||
|
),
|
||||||
|
|
||||||
|
// Allow only users in configured value(s) to access Nextcloud. In case the user
|
||||||
|
// is not assigned to this value (read from oidc_login_attributes) the login
|
||||||
|
// will not be allowed for this user.
|
||||||
|
//
|
||||||
|
// Must be specified as an array of values (e.g. roles) that are allowed to
|
||||||
|
// access Nextcloud. e.g. 'oidc_login_filter_allowed_values' => array('role1', 'role2')
|
||||||
|
'oidc_login_filter_allowed_values' => null,
|
||||||
|
|
||||||
|
// Set OpenID Connect scope
|
||||||
|
'oidc_login_scope' => '{{ nextcloud_oidc_scope | default('openid profile') }}',
|
||||||
|
|
||||||
|
// Disable creation of users new to Nextcloud from OIDC login.
|
||||||
|
// A user may be known to the IdP but not (yet) known to Nextcloud.
|
||||||
|
// This setting controls what to do in this case.
|
||||||
|
// - 'true' (default): if the user authenticates to the IdP but is not known to Nextcloud,
|
||||||
|
// then they will be returned to the login screen and not allowed entry;
|
||||||
|
// - 'false': if the user authenticates but is not yet known to Nextcloud,
|
||||||
|
// then the user will be automatically created; note that with this setting,
|
||||||
|
// you will be allowing (or relying on) a third-party (the IdP) to create new users
|
||||||
|
'oidc_login_disable_registration' => {{ nextcloud_oidc_disable_registration | default('true') }},
|
||||||
|
|
||||||
|
// For development, you may disable TLS verification. Default value is `true`
|
||||||
|
// which should be kept in production
|
||||||
|
'oidc_login_tls_verify' => {{ nextcloud_oidc_tls_verify | default('true') }},
|
||||||
|
|
||||||
|
// If you get your groups from the oidc_login_attributes, you might want
|
||||||
|
// to create them if they are not already existing, Default is `false`.
|
||||||
|
'oidc_create_groups' => {{ nextcloud_oidc_create_groups | default('false') }},
|
||||||
|
|
||||||
|
// Enable use of WebDAV via OIDC bearer token.
|
||||||
|
'oidc_login_webdav_enabled' => false,
|
||||||
|
|
||||||
|
// Enable authentication with user/password for DAV clients that do not
|
||||||
|
// support token authentication (e.g. DAVx⁵)
|
||||||
|
'oidc_login_password_authentication' => false,
|
||||||
|
|
||||||
|
// The time in seconds used to cache public keys from provider.
|
||||||
|
// The default value is 1 day.
|
||||||
|
'oidc_login_public_key_caching_time' => 86400,
|
||||||
|
|
||||||
|
// The minimum time in seconds to wait between requests to the jwks_uri endpoint.
|
||||||
|
// Avoids that the provider will be DoSed when someone requests with unknown kids.
|
||||||
|
// The default is 10 seconds.
|
||||||
|
'oidc_login_min_time_between_jwks_requests' => 10,
|
||||||
|
|
||||||
|
// The time in seconds used to cache the OIDC well-known configuration from the provider.
|
||||||
|
// The default value is 1 day.
|
||||||
|
'oidc_login_well_known_caching_time' => 86400,
|
||||||
|
|
||||||
|
// If true, nextcloud will download user avatars on login.
|
||||||
|
// This may lead to security issues as the server does not control
|
||||||
|
// which URLs will be requested. Use with care.
|
||||||
|
'oidc_login_update_avatar' => false,
|
||||||
|
|
||||||
|
// If true, the default Nextcloud proxy won't be used to make internals OIDC call.
|
||||||
|
// The default is false.
|
||||||
|
'oidc_login_skip_proxy' => false,
|
||||||
|
|
||||||
|
// Code challenge method for PKCE flow.
|
||||||
|
// Possible values are:
|
||||||
|
// - 'S256'
|
||||||
|
// - 'plain'
|
||||||
|
// The default value is empty, which won't apply the PKCE flow.
|
||||||
|
'oidc_login_code_challenge_method' => '',
|
||||||
|
);
|
|
@ -0,0 +1,49 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Podman container-nextcloud-app.service
|
||||||
|
Documentation=man:podman-generate-systemd(1)
|
||||||
|
Wants=network-online.target
|
||||||
|
After=network-online.target
|
||||||
|
After=container-nextcloud-db.service
|
||||||
|
After=container-nextcloud-redis.service
|
||||||
|
RequiresMountsFor=%t/containers
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Environment=PODMAN_SYSTEMD_UNIT=%n
|
||||||
|
Restart=on-failure
|
||||||
|
TimeoutStopSec=70
|
||||||
|
Type=notify
|
||||||
|
NotifyAccess=all
|
||||||
|
|
||||||
|
ExecStartPre=/bin/rm -f %t/%n.ctr-id
|
||||||
|
|
||||||
|
ExecStart=/usr/bin/podman run \
|
||||||
|
--cidfile=%t/%n.ctr-id \
|
||||||
|
--cgroups=no-conmon \
|
||||||
|
--rm \
|
||||||
|
--sdnotify=conmon \
|
||||||
|
--replace \
|
||||||
|
--network={{ nextcloud_podman_network }} \
|
||||||
|
--detach \
|
||||||
|
--tty \
|
||||||
|
--publish {{ nextcloud_app_listen_port }}:80 \
|
||||||
|
--volume {{ nextcloud_app_volume }}:/var/www/html:Z \
|
||||||
|
--volume /etc/nextcloud/oidc.config.php:/docker-entrypoint-hooks.d/before-starting/oidc.config.php:Z \
|
||||||
|
--volume /etc/nextcloud/ansible.config.php:/docker-entrypoint-hooks.d/before-starting/ansible.config.php:Z \
|
||||||
|
--volume /etc/nextcloud/copy_config.sh:/docker-entrypoint-hooks.d/before-starting/copy_config.sh:Z \
|
||||||
|
{% for environment in nextcloud_app_environments %}
|
||||||
|
--env {{ environment.key }}={{ environment.value }} \
|
||||||
|
{% endfor %}
|
||||||
|
--name={{ nextcloud_app_container_name }} \
|
||||||
|
{{ nextcloud_app_image_name }}:{{ nextcloud_app_image_tag }}
|
||||||
|
|
||||||
|
ExecStop=/usr/bin/podman stop \
|
||||||
|
--ignore \
|
||||||
|
--cidfile=%t/%n.ctr-id
|
||||||
|
|
||||||
|
ExecStopPost=/usr/bin/podman rm \
|
||||||
|
--force \
|
||||||
|
--ignore \
|
||||||
|
--cidfile=%t/%n.ctr-id
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
|
@ -0,0 +1,45 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Podman container-nextcloud-cron.service
|
||||||
|
Documentation=man:podman-generate-systemd(1)
|
||||||
|
Wants=network-online.target
|
||||||
|
After=network-online.target
|
||||||
|
After=container-nextcloud-db.service
|
||||||
|
After=container-nextcloud-redis.service
|
||||||
|
RequiresMountsFor=%t/containers
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Environment=PODMAN_SYSTEMD_UNIT=%n
|
||||||
|
Restart=on-failure
|
||||||
|
TimeoutStopSec=70
|
||||||
|
Type=notify
|
||||||
|
NotifyAccess=all
|
||||||
|
|
||||||
|
ExecStartPre=/bin/rm -f %t/%n.ctr-id
|
||||||
|
|
||||||
|
ExecStart=/usr/bin/podman run \
|
||||||
|
--cidfile=%t/%n.ctr-id \
|
||||||
|
--cgroups=no-conmon \
|
||||||
|
--rm \
|
||||||
|
--sdnotify=conmon \
|
||||||
|
--replace \
|
||||||
|
--network={{ nextcloud_podman_network }} \
|
||||||
|
--detach \
|
||||||
|
--tty \
|
||||||
|
--volume {{ nextcloud_app_volume }}:/var/www/html:Z \
|
||||||
|
--volume /etc/nextcloud/oidc.config.php:/docker-entrypoint-hooks.d/before-starting/oidc.config.php:Z \
|
||||||
|
--volume /etc/nextcloud/copy_oidc_config.sh:/docker-entrypoint-hooks.d/before-starting/copy_oidc_config.sh:Z \
|
||||||
|
--name={{ nextcloud_cron_container_name }} \
|
||||||
|
--entrypoint=/cron.sh \
|
||||||
|
{{ nextcloud_app_image_name }}:{{ nextcloud_app_image_tag }}
|
||||||
|
|
||||||
|
ExecStop=/usr/bin/podman stop \
|
||||||
|
--ignore \
|
||||||
|
--cidfile=%t/%n.ctr-id
|
||||||
|
|
||||||
|
ExecStopPost=/usr/bin/podman rm \
|
||||||
|
--force \
|
||||||
|
--ignore \
|
||||||
|
--cidfile=%t/%n.ctr-id
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
|
@ -0,0 +1,42 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Podman container-nextcloud-db.service
|
||||||
|
Documentation=man:podman-generate-systemd(1)
|
||||||
|
Wants=network-online.target
|
||||||
|
After=network-online.target
|
||||||
|
RequiresMountsFor=%t/containers
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Environment=PODMAN_SYSTEMD_UNIT=%n
|
||||||
|
Restart=on-failure
|
||||||
|
TimeoutStopSec=70
|
||||||
|
Type=notify
|
||||||
|
NotifyAccess=all
|
||||||
|
|
||||||
|
ExecStartPre=/bin/rm -f %t/%n.ctr-id
|
||||||
|
|
||||||
|
ExecStart=/usr/bin/podman run \
|
||||||
|
--cidfile=%t/%n.ctr-id \
|
||||||
|
--cgroups=no-conmon \
|
||||||
|
--rm \
|
||||||
|
--sdnotify=conmon \
|
||||||
|
--replace \
|
||||||
|
--detach \
|
||||||
|
--tty \
|
||||||
|
--network={{ nextcloud_podman_network }} \
|
||||||
|
--volume {{ nextcloud_db_volume }}:/var/lib/postgresql/data/:Z \
|
||||||
|
--env POSTGRES_USER={{ nextcloud_db_user }} \
|
||||||
|
--env POSTGRES_PASSWORD={{ nextcloud_db_password }} \
|
||||||
|
--env POSTGRES_DB={{ nextcloud_db_database }} \
|
||||||
|
--name={{ nextcloud_db_container_name }} \
|
||||||
|
{{ nextcloud_db_image_name }}:{{ nextcloud_db_image_tag }}
|
||||||
|
|
||||||
|
ExecStop=/usr/bin/podman stop \
|
||||||
|
--ignore \
|
||||||
|
--cidfile=%t/%n.ctr-id
|
||||||
|
|
||||||
|
ExecStopPost=/usr/bin/podman rm \
|
||||||
|
--force --ignore \
|
||||||
|
--cidfile=%t/%n.ctr-id
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
|
@ -0,0 +1,39 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Podman container-nextcloud-redis.service
|
||||||
|
Documentation=man:podman-generate-systemd(1)
|
||||||
|
Wants=network-online.target
|
||||||
|
After=network-online.target
|
||||||
|
RequiresMountsFor=%t/containers
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Environment=PODMAN_SYSTEMD_UNIT=%n
|
||||||
|
Restart=on-failure
|
||||||
|
TimeoutStopSec=70
|
||||||
|
Type=notify
|
||||||
|
NotifyAccess=all
|
||||||
|
|
||||||
|
ExecStartPre=/bin/rm -f %t/%n.ctr-id
|
||||||
|
|
||||||
|
ExecStart=/usr/bin/podman run \
|
||||||
|
--cidfile=%t/%n.ctr-id \
|
||||||
|
--cgroups=no-conmon \
|
||||||
|
--rm \
|
||||||
|
--sdnotify=conmon \
|
||||||
|
--replace \
|
||||||
|
--detach \
|
||||||
|
--tty \
|
||||||
|
--network={{ nextcloud_podman_network }} \
|
||||||
|
--name={{ nextcloud_redis_container_name }} \
|
||||||
|
--volume nextcloud-redis:/data:Z \
|
||||||
|
{{ nextcloud_redis_image_name }}:{{ nextcloud_redis_image_tag }}
|
||||||
|
|
||||||
|
ExecStop=/usr/bin/podman stop \
|
||||||
|
--ignore \
|
||||||
|
--cidfile=%t/%n.ctr-id
|
||||||
|
|
||||||
|
ExecStopPost=/usr/bin/podman rm \
|
||||||
|
--force --ignore \
|
||||||
|
--cidfile=%t/%n.ctr-id
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
Loading…
Reference in a new issue