initial commit, so far untested
This commit is contained in:
commit
7859fe4fbc
17 changed files with 1282 additions and 0 deletions
3
README.md
Normal file
3
README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# Ansible Collection - s3lph.nextcloud
|
||||||
|
|
||||||
|
Documentation for the collection.
|
69
galaxy.yml
Normal file
69
galaxy.yml
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
### 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: s3lph
|
||||||
|
|
||||||
|
# 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: 0.0.1
|
||||||
|
|
||||||
|
# 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:
|
||||||
|
- s3lph <s3lph@kabelsalat.ch>
|
||||||
|
|
||||||
|
|
||||||
|
### OPTIONAL but strongly recommended
|
||||||
|
# A short summary description of the collection
|
||||||
|
description: Install and configure Nextcloud and PHP-FPM
|
||||||
|
|
||||||
|
# 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:
|
||||||
|
- nextcloud
|
||||||
|
- php
|
||||||
|
|
||||||
|
# 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:
|
||||||
|
community.mysql: '1.2.0'
|
||||||
|
s3lph.webserver: '>=0.0.1'
|
||||||
|
|
||||||
|
# The URL of the originating SCM repository
|
||||||
|
repository: https://git.kabelsalat.ch/s3lph/ansible-collection-nextcloud
|
||||||
|
|
||||||
|
# The URL to any online docs
|
||||||
|
documentation: https://git.kabelsalat.ch/s3lph/ansible-collection-nextcloud
|
||||||
|
|
||||||
|
# The URL to the homepage of the collection/project
|
||||||
|
homepage: https://git.kabelsalat.ch/s3lph/ansible-collection-nextcloud
|
||||||
|
|
||||||
|
# The URL to the collection issue tracker
|
||||||
|
issues: https://git.kabelsalat.ch/s3lph/ansible-collection-nextcloud/issues
|
||||||
|
|
||||||
|
# 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.9.10'
|
||||||
|
|
||||||
|
# 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
|
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.14/plugins/plugins.html).
|
209
plugins/modules/app.py
Normal file
209
plugins/modules/app.py
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = r'''
|
||||||
|
---
|
||||||
|
module: config
|
||||||
|
|
||||||
|
short_description: Set Nextcloud configuration options.
|
||||||
|
|
||||||
|
# If this is part of a collection, you need to use semantic versioning,
|
||||||
|
# i.e. the version is of the form "2.5.0" and not "2.4".
|
||||||
|
version_added: "0.0.1"
|
||||||
|
|
||||||
|
description: Set Nextcloud configuration options via occ config.
|
||||||
|
|
||||||
|
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
|
||||||
|
webroot:
|
||||||
|
description: Path to the Nextcloud webroot.
|
||||||
|
required: false
|
||||||
|
default: /var/www/html
|
||||||
|
type: str
|
||||||
|
php:
|
||||||
|
description: Path to the php-cli binary.
|
||||||
|
required: false
|
||||||
|
default: /usr/bin/php
|
||||||
|
type: str
|
||||||
|
|
||||||
|
# Specify this value according to your collection
|
||||||
|
# in format of namespace.collection.doc_fragment_name
|
||||||
|
#extends_documentation_fragment:
|
||||||
|
# - s3lph.nextcloud.app
|
||||||
|
|
||||||
|
author:
|
||||||
|
- s3lph
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
EXAMPLES = r'''
|
||||||
|
- name: Install and enable photos app
|
||||||
|
s3lph.nextcloud.app:
|
||||||
|
name: photos
|
||||||
|
|
||||||
|
- name: Install and enable PIM apps
|
||||||
|
s3lph.nextcloud.app:
|
||||||
|
name:
|
||||||
|
- contacts
|
||||||
|
- calendar
|
||||||
|
- mail
|
||||||
|
|
||||||
|
- name: Disable resource hungry dashboard
|
||||||
|
s3lph.nextcloud.app:
|
||||||
|
name: dashboard
|
||||||
|
state: disabled
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
RETURN = r'''
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
|
def run_module():
|
||||||
|
# define available arguments/parameters a user can pass to the module
|
||||||
|
module_args = dict(
|
||||||
|
webroot=dict(required=False, default='/var/www/html', type='str'),
|
||||||
|
php=dict(required=False, default='/usr/bin/php', type='str'),
|
||||||
|
name=dict(required=True, type='list'),
|
||||||
|
state=dict(required=False, default='enabled', type='str'),
|
||||||
|
force=dict(required=False, default=False, type='bool'),
|
||||||
|
)
|
||||||
|
|
||||||
|
# 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 = dict(
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
|
||||||
|
state = module.params['state']
|
||||||
|
if state not in ['enabled', 'disabled', 'absent']:
|
||||||
|
module.fail_json(msg='state must be one of enabled, disabled or absent', **result)
|
||||||
|
|
||||||
|
apps = module.params['name']
|
||||||
|
if isinstance(apps, str):
|
||||||
|
apps = [apps]
|
||||||
|
|
||||||
|
# Gather Nextcloud installation status
|
||||||
|
sc = subprocess.run([module.params['php'], 'occ', 'status', '--output=json'],
|
||||||
|
cwd=module.params['webroot'],
|
||||||
|
capture_output=True, encoding='utf-8')
|
||||||
|
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)
|
||||||
|
|
||||||
|
# Gather Nextcloud app list
|
||||||
|
ac = subprocess.run([module.params['php'], 'occ', 'app:list', '--output=json'],
|
||||||
|
cwd=module.params['webroot'],
|
||||||
|
capture_output=True, encoding='utf-8')
|
||||||
|
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)
|
||||||
|
|
||||||
|
app_status = json.loads(ac.stdout)
|
||||||
|
|
||||||
|
# Apply app configuration changes
|
||||||
|
for app in apps:
|
||||||
|
if state == 'absent' and (app in app_status['enabled'] or app in app_status['disabled']):
|
||||||
|
result['changed'] = True
|
||||||
|
if not module.check_mode:
|
||||||
|
c = subprocess.run([module.params['php'], 'occ', 'app:remove', '--keep-data', app],
|
||||||
|
cwd=module.params['webroot'],
|
||||||
|
capture_output=True, encoding='utf-8')
|
||||||
|
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)
|
||||||
|
elif state in ['enabled', 'disabled'] and app not in app_status['enabled'] and app not in app_status['disabled']:
|
||||||
|
result['changed'] = True
|
||||||
|
if not module.check_mode:
|
||||||
|
cmdline = [module.params['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,
|
||||||
|
cwd=module.params['webroot'],
|
||||||
|
capture_output=True, encoding='utf-8')
|
||||||
|
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)
|
||||||
|
elif state == 'enabled' and app in app_status['disabled']:
|
||||||
|
result['changed'] = True
|
||||||
|
if not module.check_mode:
|
||||||
|
cmdline = [module.params['php'], 'occ', 'app:enable']
|
||||||
|
if module.params['force']:
|
||||||
|
cmdline.append('--force')
|
||||||
|
cmdline.append(app)
|
||||||
|
c = subprocess.run(cmdline,
|
||||||
|
cwd=module.params['webroot'],
|
||||||
|
capture_output=True, encoding='utf-8')
|
||||||
|
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)
|
||||||
|
elif state == 'disabled' and app in app_status['enabled']:
|
||||||
|
result['changed'] = True
|
||||||
|
if not module.check_mode:
|
||||||
|
c = subprocess.run([module.params['php'], 'occ', 'app:disable', app],
|
||||||
|
cwd=module.params['webroot'],
|
||||||
|
capture_output=True, encoding='utf-8')
|
||||||
|
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)
|
||||||
|
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
run_module()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
255
plugins/modules/config.py
Normal file
255
plugins/modules/config.py
Normal file
|
@ -0,0 +1,255 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = r'''
|
||||||
|
---
|
||||||
|
module: config
|
||||||
|
|
||||||
|
short_description: Set Nextcloud configuration options.
|
||||||
|
|
||||||
|
# If this is part of a collection, you need to use semantic versioning,
|
||||||
|
# i.e. the version is of the form "2.5.0" and not "2.4".
|
||||||
|
version_added: "0.0.1"
|
||||||
|
|
||||||
|
description: Set Nextcloud configuration options via occ config.
|
||||||
|
|
||||||
|
options:
|
||||||
|
system:
|
||||||
|
description: System configuration options to set.
|
||||||
|
required: false
|
||||||
|
default: {}
|
||||||
|
type: dict
|
||||||
|
apps:
|
||||||
|
description: App configuration options to set.
|
||||||
|
required: false
|
||||||
|
default: {}
|
||||||
|
type: dict
|
||||||
|
force:
|
||||||
|
description: >-
|
||||||
|
Override change protection of options that should never be changed.
|
||||||
|
Use with EXTREME CARE, as IRRECOVERABLE DATA LOSS may be the result of changing these options.
|
||||||
|
Currently the following options are covered by this protection: instanceid, secret, passwordsalt.
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
type: bool
|
||||||
|
webroot:
|
||||||
|
description: Path to the Nextcloud webroot.
|
||||||
|
required: false
|
||||||
|
default: /var/www/html
|
||||||
|
type: str
|
||||||
|
php:
|
||||||
|
description: Path to the php-cli binary.
|
||||||
|
required: false
|
||||||
|
default: /usr/bin/php
|
||||||
|
type: str
|
||||||
|
|
||||||
|
# Specify this value according to your collection
|
||||||
|
# in format of namespace.collection.doc_fragment_name
|
||||||
|
#extends_documentation_fragment:
|
||||||
|
# - s3lph.nextcloud.status
|
||||||
|
|
||||||
|
author:
|
||||||
|
- s3lph
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
EXAMPLES = r'''
|
||||||
|
- name: Set up Redis cache config all redis configuration all at once
|
||||||
|
s3lph.nextcloud.config:
|
||||||
|
system:
|
||||||
|
redis:
|
||||||
|
host: localhost
|
||||||
|
port: 6379
|
||||||
|
dbindex: 0
|
||||||
|
memcache.local: "\OC\Memcache\Redis"
|
||||||
|
memcache.remote: "\OC\Memcache\Redis"
|
||||||
|
memcache.locking: "\OC\Memcache\Redis"
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
RETURN = r'''
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
|
||||||
|
import json
|
||||||
|
import math
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
|
# Changing these keys may lead to irrecoverable data loss
|
||||||
|
REQUIRE_FORCE = ['instanceid', 'secret', 'passwordsalt']
|
||||||
|
|
||||||
|
|
||||||
|
def iter_system(module, tree=None, value=None):
|
||||||
|
if tree is None:
|
||||||
|
tree = []
|
||||||
|
if value is None:
|
||||||
|
value = module.params['system']
|
||||||
|
changed = False
|
||||||
|
# Recursively iterate the options tree
|
||||||
|
for k, v in value.items():
|
||||||
|
sublist = tree + [k]
|
||||||
|
if isinstance(v, dict):
|
||||||
|
changed = changed or iter_system(module, subtree, v)
|
||||||
|
continue
|
||||||
|
if isinstance(v, list):
|
||||||
|
v = {str(i): v for i, v in enumerate(v)}
|
||||||
|
changed = changed or iter_system(module, subtree, v)
|
||||||
|
continue
|
||||||
|
elif isinstance(v, int):
|
||||||
|
typ = 'integer'
|
||||||
|
elif isinstance(v, float):
|
||||||
|
typ = 'double'
|
||||||
|
elif isinstance(v, bool):
|
||||||
|
typ = 'boolean'
|
||||||
|
else:
|
||||||
|
typ = 'string'
|
||||||
|
# Get current value of the system option
|
||||||
|
rc = subprocess.run([module.params['php'], 'occ', 'config:system:get', '--output=json'] + subtree,
|
||||||
|
cwd=module.params['webroot'],
|
||||||
|
capture_output=True, encoding='utf-8')
|
||||||
|
if rc.returncode not in [0, 1]:
|
||||||
|
result['stdout'] = rc.stdout
|
||||||
|
result['stderr'] = rc.stderr
|
||||||
|
module.fail_json(msg='occ config:system:get returned non-zero exit code. Run with -vvv to view the output', **result)
|
||||||
|
if rc.returncode == 1:
|
||||||
|
old_value = None
|
||||||
|
else:
|
||||||
|
old_value = json.loads(rc.stdout)
|
||||||
|
|
||||||
|
if isinstance(v, float) and isinstance(old_value, float) and math.isclose(v, old_value):
|
||||||
|
continue
|
||||||
|
elif v == old_value:
|
||||||
|
continue
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
if not module.check_mode:
|
||||||
|
# Remove key if the new value is none
|
||||||
|
if v is None:
|
||||||
|
wc = subprocess.run([module.params['php'], 'occ', 'config:system:delete'] + subtree,
|
||||||
|
cwd=module.params['webroot'],
|
||||||
|
capture_output=True, encoding='utf-8')
|
||||||
|
if wc.returncode != 0:
|
||||||
|
result['stdout'] = wc.stdout
|
||||||
|
result['stderr'] = wc.stderr
|
||||||
|
msg = 'occ config:system:delete returned non-zero exit code. Run with -vvv to view the output'
|
||||||
|
module.fail_json(msg=msg, **result)
|
||||||
|
|
||||||
|
# Set option to new value
|
||||||
|
else:
|
||||||
|
cmdline = [module.params['php'], 'occ', 'config:system:set', '--type', typ, '--value', str(v)] + subtree
|
||||||
|
wc = subprocess.run(cmdline,
|
||||||
|
cwd=module.params['webroot'],
|
||||||
|
capture_output=True, encoding='utf-8')
|
||||||
|
if wc.returncode != 0:
|
||||||
|
result['stdout'] = wc.stdout
|
||||||
|
result['stderr'] = wc.stderr
|
||||||
|
msg = 'occ config:system:set returned non-zero exit code. Run with -vvv to view the output'
|
||||||
|
module.fail_json(msg=msg, **result)
|
||||||
|
|
||||||
|
return changed
|
||||||
|
|
||||||
|
|
||||||
|
def run_module():
|
||||||
|
# define available arguments/parameters a user can pass to the module
|
||||||
|
module_args = dict(
|
||||||
|
webroot=dict(required=False, default='/var/www/html', type='str'),
|
||||||
|
php=dict(required=False, default='/usr/bin/php', type='str'),
|
||||||
|
name=dict(required=True, type='list'),
|
||||||
|
state=dict(required=False, default='enabled', type='str'),
|
||||||
|
force=dict(required=False, default=False, type='bool'),
|
||||||
|
)
|
||||||
|
|
||||||
|
# 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 = dict(
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Gather Nextcloud installation status
|
||||||
|
sc = subprocess.run([module.params['php'], 'occ', 'status', '--output=json'],
|
||||||
|
cwd=module.params['webroot'],
|
||||||
|
capture_output=True, encoding='utf-8')
|
||||||
|
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 config is not available.', **result)
|
||||||
|
|
||||||
|
# Check for protected options
|
||||||
|
for k in REQUIRE_FORCE:
|
||||||
|
if k in module.params['system'] and not module.params['force']:
|
||||||
|
msg = 'Refusing to change option "' + k + '" as IRRECOVERABLE DATA LOSS may be the result of such a change.'
|
||||||
|
module.fail_json(msg=msg, **result)
|
||||||
|
|
||||||
|
# Apply Nextcloud system configuration recursively
|
||||||
|
result['changed'] = iter_system(module)
|
||||||
|
|
||||||
|
# Apply Nextcloud app configuration
|
||||||
|
for app, ac in module.params['apps'].items():
|
||||||
|
for k, v in ac.items():
|
||||||
|
# Get current value of the app option
|
||||||
|
rc = subprocess.run([module.params['php'], 'occ', 'config:app:get', app, k],
|
||||||
|
cwd=module.params['webroot'],
|
||||||
|
capture_output=True, encoding='utf-8')
|
||||||
|
if rc.returncode not in [0, 1]:
|
||||||
|
result['stdout'] = rc.stdout
|
||||||
|
result['stderr'] = rc.stderr
|
||||||
|
module.fail_json(msg='occ config:app:get returned non-zero exit code. Run with -vvv to view the output', **result)
|
||||||
|
if rc.returncode == 1:
|
||||||
|
old_value = None
|
||||||
|
else:
|
||||||
|
old_value = rc.stdout
|
||||||
|
if old_value == v:
|
||||||
|
continue
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
if not module.check_mode:
|
||||||
|
# Delete key if value is None
|
||||||
|
if v is None:
|
||||||
|
rc = subprocess.run([module.params['php'], 'occ', 'config:app:delete', app, k],
|
||||||
|
cwd=module.params['webroot'],
|
||||||
|
capture_output=True, encoding='utf-8')
|
||||||
|
if rc.returncode != 0:
|
||||||
|
result['stdout'] = rc.stdout
|
||||||
|
result['stderr'] = rc.stderr
|
||||||
|
msg = 'occ config:app:delete returned non-zero exit code. Run with -vvv to view the output'
|
||||||
|
module.fail_json(msg=msg, **result)
|
||||||
|
else:
|
||||||
|
rc = subprocess.run([module.params['php'], 'occ', 'config:app:set', '--value', v, app, k],
|
||||||
|
cwd=module.params['webroot'],
|
||||||
|
capture_output=True, encoding='utf-8')
|
||||||
|
if rc.returncode != 0:
|
||||||
|
result['stdout'] = rc.stdout
|
||||||
|
result['stderr'] = rc.stderr
|
||||||
|
msg = 'occ config:app:set returned non-zero exit code. Run with -vvv to view the output'
|
||||||
|
module.fail_json(msg=msg, **result)
|
||||||
|
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
run_module()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
223
plugins/modules/install.py
Normal file
223
plugins/modules/install.py
Normal file
|
@ -0,0 +1,223 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = r'''
|
||||||
|
---
|
||||||
|
module: install
|
||||||
|
|
||||||
|
short_description: Run occ maintenance:install
|
||||||
|
|
||||||
|
# If this is part of a collection, you need to use semantic versioning,
|
||||||
|
# i.e. the version is of the form "2.5.0" and not "2.4".
|
||||||
|
version_added: "0.0.1"
|
||||||
|
|
||||||
|
description: Bootstrap Nextcloud with an invocation of occ maintenance:install.
|
||||||
|
|
||||||
|
options:
|
||||||
|
database:
|
||||||
|
description: Supported database type.
|
||||||
|
required: false
|
||||||
|
default: sqlite
|
||||||
|
type: str
|
||||||
|
database_name:
|
||||||
|
description: Name of the database.
|
||||||
|
required: false
|
||||||
|
type: str
|
||||||
|
database_host:
|
||||||
|
description: Hostname of the database.
|
||||||
|
required: false
|
||||||
|
default: localhost
|
||||||
|
type: str
|
||||||
|
database_port:
|
||||||
|
description: Port the database is listening on.
|
||||||
|
required: false
|
||||||
|
type: int
|
||||||
|
database_user:
|
||||||
|
description: User name to connect to the database.
|
||||||
|
required: false
|
||||||
|
type: str
|
||||||
|
database_pass:
|
||||||
|
description: Password of the database user.
|
||||||
|
required: false
|
||||||
|
type: str
|
||||||
|
database_table_space:
|
||||||
|
description: Table space of the database (oci only).
|
||||||
|
required: false
|
||||||
|
type: str
|
||||||
|
admin_user:
|
||||||
|
description: User name of the admin account.
|
||||||
|
required: false
|
||||||
|
default: admin
|
||||||
|
type: str
|
||||||
|
admin_pass:
|
||||||
|
description: Password of the admin account.
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
admin_email:
|
||||||
|
description: E-Mail of the admin account.
|
||||||
|
required: false
|
||||||
|
type: str
|
||||||
|
data_dir:
|
||||||
|
description: Path to data directory.
|
||||||
|
required: false
|
||||||
|
default: <webroot>/data
|
||||||
|
type: str
|
||||||
|
webroot:
|
||||||
|
description: Path to the Nextcloud webroot.
|
||||||
|
required: false
|
||||||
|
default: /var/www/html
|
||||||
|
type: str
|
||||||
|
php:
|
||||||
|
description: Path to the php-cli binary.
|
||||||
|
required: false
|
||||||
|
default: /usr/bin/php
|
||||||
|
type: str
|
||||||
|
|
||||||
|
# Specify this value according to your collection
|
||||||
|
# in format of namespace.collection.doc_fragment_name
|
||||||
|
#extends_documentation_fragment:
|
||||||
|
# - s3lph.nextcloud.install
|
||||||
|
|
||||||
|
author:
|
||||||
|
- s3lph
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
EXAMPLES = r'''
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
RETURN = r'''
|
||||||
|
status:
|
||||||
|
type: dict
|
||||||
|
description: Parsed output from occ status.
|
||||||
|
returned: success
|
||||||
|
sample:
|
||||||
|
installed: true
|
||||||
|
version: "25.0.3.2"
|
||||||
|
versionstring: "25.0.3
|
||||||
|
edition: ""
|
||||||
|
maintenance: false
|
||||||
|
needsDbUpgrade: false
|
||||||
|
productname: Nextcloud
|
||||||
|
extendedSupport: false
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
|
def run_module():
|
||||||
|
# define available arguments/parameters a user can pass to the module
|
||||||
|
module_args = dict(
|
||||||
|
database=dict(required=False, default='sqlite', type='str'),
|
||||||
|
database_name=dict(required=False, type='str'),
|
||||||
|
database_host=dict(required=False default='localhost', type='str'),
|
||||||
|
database_port=dict(required=False, type='int'),
|
||||||
|
database_user=dict(required=False, type='str'),
|
||||||
|
database_pass=dict(required=False, type='str'),
|
||||||
|
database_table_space=dict(required=False, type='str'),
|
||||||
|
admin_user=dict(required=False, default='admin', type='str'),
|
||||||
|
admin_pass=dict(required=True, type='str'),
|
||||||
|
admin_email=dict(required=False, type='str'),
|
||||||
|
data_dir=dict(required=False, default='./data', type='str'),
|
||||||
|
webroot=dict(required=False, default='/var/www/html', type='str'),
|
||||||
|
php=dict(required=False, default='/usr/bin/php', 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 = dict(
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
|
||||||
|
sc = subprocess.run([module.params['php'], 'occ', 'status', '--output=json'],
|
||||||
|
cwd=module.params['webroot'],
|
||||||
|
capture_output=True, encoding='utf-8')
|
||||||
|
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)
|
||||||
|
result['status'] = status
|
||||||
|
if status['installed']:
|
||||||
|
# Nextcloud installation has already been completed
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
# Build installation cmdline
|
||||||
|
cmdline = [module.params['php'], 'occ', 'maintenance:install', '--no-interaction', '--no-ansi']
|
||||||
|
|
||||||
|
datadir = os.path.normpath(os.path.join(module.params['webroot'], module.params['data_dir']))
|
||||||
|
cmdline.append('--data-dir=' + datadir)
|
||||||
|
|
||||||
|
cmdline.append('--database=' + module.params['database'])
|
||||||
|
if module.params['database_name'] is not None:
|
||||||
|
cmdline.append('--database-name=' + module.params['database_name'])
|
||||||
|
if module.params['database_host'] is not None:
|
||||||
|
cmdline.append('--database-host=' + module.params['database_host'])
|
||||||
|
if module.params['database_port'] is not None:
|
||||||
|
cmdline.append('--database-port=' + module.params['database_port'])
|
||||||
|
if module.params['database_user'] is not None:
|
||||||
|
cmdline.append('--database-user=' + module.params['database_user'])
|
||||||
|
if module.params['database_pass'] is not None:
|
||||||
|
cmdline.append('--database-pass=' + module.params['database_pass'])
|
||||||
|
if module.params['database_table_space'] is not None:
|
||||||
|
cmdline.append('--database-table-space=' + module.params['database_table_space'])
|
||||||
|
|
||||||
|
cmdline.append('--admin-user=' + module.params['admin_user'])
|
||||||
|
cmdline.append('--admin-pass=' + module.params['admin_pass'])
|
||||||
|
if module.params['admin_email'] is not None:
|
||||||
|
cmdline.append('--admin-email=' + module.params['admin_email'])
|
||||||
|
|
||||||
|
if not module.check_mode:
|
||||||
|
# Perform Nextcloud installation
|
||||||
|
ic = subprocess.run(cmdline,
|
||||||
|
cwd=module.params['webroot'],
|
||||||
|
capture_output=True, encoding='utf-8')
|
||||||
|
result['stdout'] = ic.stdout
|
||||||
|
result['stderr'] = ic.stderr
|
||||||
|
if ic.returncode != 0:
|
||||||
|
module.fail_json(msg='occ maintenance:install returned non-zero exit code. Run with -vvv to view the output', **result)
|
||||||
|
|
||||||
|
result['changed'] = True
|
||||||
|
|
||||||
|
# Get occ status once more
|
||||||
|
sc = subprocess.run([module.params['php'], 'occ', 'status', '--output=json'],
|
||||||
|
cwd=module.params['webroot'],
|
||||||
|
capture_output=True, encoding='utf-8')
|
||||||
|
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)
|
||||||
|
result['status'] = status
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
run_module()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
142
plugins/modules/nextcloud_facts.py
Normal file
142
plugins/modules/nextcloud_facts.py
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = r'''
|
||||||
|
---
|
||||||
|
module: nextcloud_facts
|
||||||
|
|
||||||
|
short_description: Gather ansible_facts from Nextcloud.
|
||||||
|
|
||||||
|
# If this is part of a collection, you need to use semantic versioning,
|
||||||
|
# i.e. the version is of the form "2.5.0" and not "2.4".
|
||||||
|
version_added: "0.0.1"
|
||||||
|
|
||||||
|
description: Gather ansible_facts from Nextcloud via occ status and occ config:list.
|
||||||
|
|
||||||
|
options:
|
||||||
|
webroot:
|
||||||
|
description: Path to the Nextcloud webroot.
|
||||||
|
required: false
|
||||||
|
default: /var/www/html
|
||||||
|
type: str
|
||||||
|
php:
|
||||||
|
description: Path to the php-cli binary.
|
||||||
|
required: false
|
||||||
|
default: /usr/bin/php
|
||||||
|
type: str
|
||||||
|
|
||||||
|
# Specify this value according to your collection
|
||||||
|
# in format of namespace.collection.doc_fragment_name
|
||||||
|
#extends_documentation_fragment:
|
||||||
|
# - s3lph.nextcloud.nextcloud_facts
|
||||||
|
|
||||||
|
author:
|
||||||
|
- s3lph
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
EXAMPLES = r'''
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
RETURN = r'''
|
||||||
|
ansible_facts.nextcloud_status:
|
||||||
|
type: dict
|
||||||
|
description: Parsed output from occ status.
|
||||||
|
returned: success
|
||||||
|
sample:
|
||||||
|
installed: true
|
||||||
|
version: "25.0.3.2"
|
||||||
|
versionstring: "25.0.3
|
||||||
|
edition: ""
|
||||||
|
maintenance: false
|
||||||
|
needsDbUpgrade: false
|
||||||
|
productname: Nextcloud
|
||||||
|
extendedSupport: false
|
||||||
|
ansible_facts.nextcloud_config:
|
||||||
|
type: dict
|
||||||
|
description: Parsed output from occ status:list. Only present if installation was completed.
|
||||||
|
returned: success
|
||||||
|
sample:
|
||||||
|
system:
|
||||||
|
dbtype: sqlite3
|
||||||
|
version: "25.0.3.2"
|
||||||
|
|
||||||
|
apps:
|
||||||
|
activity:
|
||||||
|
installed_version: "2.17.0"
|
||||||
|
types: "filesystem"
|
||||||
|
enabled: "yes"
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
|
def run_module():
|
||||||
|
# define available arguments/parameters a user can pass to the module
|
||||||
|
module_args = dict(
|
||||||
|
webroot=dict(required=False, default='/var/www/html', type='str'),
|
||||||
|
php=dict(required=False, default='/usr/bin/php', 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 = dict(
|
||||||
|
changed=False,
|
||||||
|
ansible_facts={}
|
||||||
|
)
|
||||||
|
|
||||||
|
# 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,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Gather Nextcloud installation status
|
||||||
|
sc = subprocess.run([module.params['php'], 'occ', 'status', '--output=json'],
|
||||||
|
cwd=module.params['webroot'],
|
||||||
|
capture_output=True, encoding='utf-8')
|
||||||
|
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)
|
||||||
|
result['ansible_facts']['nextcloud_status'] = status
|
||||||
|
|
||||||
|
if not status['installed']:
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
# Gather Nextcloud configuration
|
||||||
|
cc = subprocess.run([module.params['php'], 'occ', 'config:list', '--output=json', '--private'],
|
||||||
|
cwd=module.params['webroot'],
|
||||||
|
capture_output=True, encoding='utf-8')
|
||||||
|
if cc.returncode != 0:
|
||||||
|
result['stdout'] = cc.stdout
|
||||||
|
result['stderr'] = cc.stderr
|
||||||
|
module.fail_json(msg='occ config:list returned non-zero exit code. Run with -vvv to view the output', **result)
|
||||||
|
|
||||||
|
config = json.loads(cc.stdout)
|
||||||
|
result['ansible_facts']['nextcloud_config'] = config
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
run_module()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
29
roles/nextcloud/defaults/main.yml
Normal file
29
roles/nextcloud/defaults/main.yml
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
nextcloud_major_version: "25"
|
||||||
|
|
||||||
|
nextcloud_trusted_domains:
|
||||||
|
- "cloud.example.org"
|
||||||
|
nextcloud_cli_baseurl: "https://{{ nextcloud_trusted_domains[0] }}"
|
||||||
|
|
||||||
|
nextcloud_redis_host: localhost
|
||||||
|
nextcloud_redis_port: 6379
|
||||||
|
nextcloud_redis_dbindex: 0
|
||||||
|
|
||||||
|
nextcloud_db_engine: mysql
|
||||||
|
nextcloud_db_host: localhost
|
||||||
|
nextcloud_db_port: 3306
|
||||||
|
nextcloud_db_user: nextcloud
|
||||||
|
nextcloud_db_name: nextcloud
|
||||||
|
|
||||||
|
nextcloud_enabled_apps: []
|
||||||
|
nextcloud_disabled_apps: []
|
||||||
|
nextcloud_app_packages: >-
|
||||||
|
{%- set _apps = [] -%}
|
||||||
|
{%- for app in nextcloud_enabled_apps -%}
|
||||||
|
{%- set _ = _apps.apend('nextcloud-' + nextcloud_major_version + '-app-' + app.replace('_', '-')) -%}
|
||||||
|
{%- endfor -%}
|
||||||
|
{{- _apps -}}
|
||||||
|
|
||||||
|
nextcloud_system_configuration: {}
|
||||||
|
nextcloud_apps_configuration: {}
|
24
roles/nextcloud/tasks/config.yml
Normal file
24
roles/nextcloud/tasks/config.yml
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
- name: Disable Nextcloud apps
|
||||||
|
become: true
|
||||||
|
become_user: www-data
|
||||||
|
s3lph.nextcloud.app:
|
||||||
|
webroot: /var/lib/nextcloud/webroot
|
||||||
|
name: "{{ nextcloud_disabled_apps }}"
|
||||||
|
state: disabled
|
||||||
|
|
||||||
|
- name: Enable Nextcloud apps
|
||||||
|
become: true
|
||||||
|
become_user: www-data
|
||||||
|
s3lph.nextcloud.app:
|
||||||
|
webroot: /var/lib/nextcloud/webroot
|
||||||
|
name: "{{ nextcloud_enabled_apps }}"
|
||||||
|
|
||||||
|
- name: Apply Nextcloud configuration
|
||||||
|
become: true
|
||||||
|
become_user: www-data
|
||||||
|
s3lph.nextcloud.config:
|
||||||
|
webroot: /var/lib/nextcloud/webroot
|
||||||
|
system: "{{ nextcloud_system_configuration }}"
|
||||||
|
apps: "{{ nextcloud_apps_configuration }}"
|
112
roles/nextcloud/tasks/install.yml
Normal file
112
roles/nextcloud/tasks/install.yml
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
- name: Add repo.s3lph.me key
|
||||||
|
ansible.builtin.apt_key:
|
||||||
|
url: https://repo.s3lph.me/debian/repo.gpg
|
||||||
|
keyring: /etc/apt/trusted.gpg.d/repo.s3lph.me.gpg
|
||||||
|
|
||||||
|
- name: Add repo.s3lph.me
|
||||||
|
ansible.builtin.apt_repository:
|
||||||
|
filename: repo.s3lph.me.list
|
||||||
|
repo: deb https://repo.s3lph.me/debian stable main
|
||||||
|
|
||||||
|
- name: Install apache2
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: apache2
|
||||||
|
|
||||||
|
- name: Install redis-server if using localhost
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: redis-server
|
||||||
|
when: "nextcloud_redis_host == 'localhost'"
|
||||||
|
|
||||||
|
- name: Install Nextcloud package
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: "nextcloud-{{ nextcloud_major_version }}"
|
||||||
|
|
||||||
|
- name: Remove die line from config.php
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /var/lib/nextcloud/webroot/config/config.php
|
||||||
|
regexp: "^die\s+'[^']*';"
|
||||||
|
state: absent
|
||||||
|
owner: www-data
|
||||||
|
group: www-data
|
||||||
|
mode: 0644
|
||||||
|
|
||||||
|
- name: Gather Nextcloud facts
|
||||||
|
become: true
|
||||||
|
become_user: www-data
|
||||||
|
s3lph.nextcloud.nextcloud_facts:
|
||||||
|
webroot: /var/lib/nextcloud/webroot
|
||||||
|
|
||||||
|
- name: Initialize MariaDB database if Nextcloud is not installed yet
|
||||||
|
when:
|
||||||
|
- not ansible_facts.nextcloud_status.installed
|
||||||
|
- nextcloud_db_engine == 'mysql'
|
||||||
|
- nextcloud_db_host == 'localhost'
|
||||||
|
block:
|
||||||
|
|
||||||
|
- name: Install MariaDB server
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: mariadb-server
|
||||||
|
|
||||||
|
- name: Create MariaDB Database
|
||||||
|
community.mysql.mysql_db:
|
||||||
|
name: '{{ nextcloud_db_name }}'
|
||||||
|
login_unix_socket: /run/mysqld/mysqld.sock
|
||||||
|
check_implicit_admin: yes
|
||||||
|
|
||||||
|
- name: Create nextcloud database user
|
||||||
|
community.mysql.mysql_user:
|
||||||
|
name: "{{ nextcloud_db_user }}"
|
||||||
|
host: "localhost"
|
||||||
|
password: "{{ nextcloud_db_pass }}"
|
||||||
|
priv: "{{ nextcloud_db_name }}.*:ALL" # grant all privileges (no grant)
|
||||||
|
login_unix_socket: /run/mysqld/mysqld.sock
|
||||||
|
check_implicit_admin: yes
|
||||||
|
|
||||||
|
- name: Perform Nextcloud first-time setup
|
||||||
|
become: true
|
||||||
|
become_user: www-data
|
||||||
|
s3lph.nextcloud.install:
|
||||||
|
webroot: /var/lib/nextcloud/webroot
|
||||||
|
data_dir: /var/lib/nextcloud/data
|
||||||
|
database: "{{ nextcloud_db_engine }}"
|
||||||
|
database_host: "{{ nextcloud_db_host | default(omit) }}"
|
||||||
|
database_port: "{{ nextcloud_db_port | default(omit) }}"
|
||||||
|
database_user: "{{ nextcloud_db_user | default(omit) }}"
|
||||||
|
database_pass: "{{ nextcloud_db_pass | default(omit) }}"
|
||||||
|
database_name: "{{ nextcloud_db_name | default(omit) }}"
|
||||||
|
database_table_space: "{{ nextcloud_db_table_space | default(omit) }}"
|
||||||
|
admin_user: "{{ nextcloud_admin_user | default(omit) }}"
|
||||||
|
admin_pass: "{{ nextcloud_admin_pass }}"
|
||||||
|
admin_email: "{{ nextcloud_admin_email | default(omit) }}"
|
||||||
|
register: nextcloud_register_installation
|
||||||
|
|
||||||
|
- name: Gather Nextcloud facts after completing the installation
|
||||||
|
become: true
|
||||||
|
become_user: www-data
|
||||||
|
s3lph.nextcloud.nextcloud_facts:
|
||||||
|
webroot: /var/lib/nextcloud/webroot
|
||||||
|
when: nextcloud_register_installation.changed
|
||||||
|
|
||||||
|
- name: Set common Nextcloud options
|
||||||
|
become: true
|
||||||
|
become_user: www-data
|
||||||
|
s3lph.nextcloud.config:
|
||||||
|
webroot: /var/lib/nextcloud/webroot
|
||||||
|
system:
|
||||||
|
trusted_domains: "{{ nextcloud_trusted_domains }}"
|
||||||
|
cli_baseurl: "{{ nextcloud_cli_baseurl }}"
|
||||||
|
redis:
|
||||||
|
host: "{{ nextcloud_redis_host }}"
|
||||||
|
port: "{{ nextcloud_redis_port }}"
|
||||||
|
dbindex: "{{ nextcloud_redis_dbindex }}"
|
||||||
|
memcache.local: '\OC\Memcache\Redis'
|
||||||
|
memcache.distributed: '\OC\Memcache\Redis'
|
||||||
|
memcache.locking: '\OC\Memcache\Redis'
|
||||||
|
|
||||||
|
- name: Install Nextcloud app packages
|
||||||
|
become: true
|
||||||
|
become_user: www-data
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: "{{ nextcloud_app_packages }}"
|
11
roles/nextcloud/tasks/main.yml
Normal file
11
roles/nextcloud/tasks/main.yml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
- ansible.builtin.import_tasks: install.yml
|
||||||
|
tags:
|
||||||
|
- "role::nextcloud"
|
||||||
|
- "role::nextcloud:install"
|
||||||
|
|
||||||
|
- ansible.builtin.import_tasks: config.yml
|
||||||
|
tags:
|
||||||
|
- "role::nextcloud"
|
||||||
|
- "role::nextcloud:config"
|
15
roles/php/defaults/main.yml
Normal file
15
roles/php/defaults/main.yml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
php_version: "8.1"
|
||||||
|
|
||||||
|
php_ini:
|
||||||
|
PHP:
|
||||||
|
memory_limit: "512M"
|
||||||
|
upload_max_filesize: "1G"
|
||||||
|
opcache:
|
||||||
|
opcache.enable: "1"
|
||||||
|
opcache.memory_consumption: "256"
|
||||||
|
opcache.interned_strings_buffer: "32"
|
||||||
|
opcache.max_accelerated_files: "10000"
|
||||||
|
opcache.revalidate_freq: "60"
|
||||||
|
opcache.save_comments: "1"
|
55
roles/php/tasks/config.yml
Normal file
55
roles/php/tasks/config.yml
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
- name: Configure php-fpm
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: "etc/php/conf.d/99-nextcloud.ini.j2"
|
||||||
|
dest: "/etc/php/{{ php_version }}/{{ item }}/conf.d/99-nextcloud.ini"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: 0644
|
||||||
|
loop:
|
||||||
|
- fpm
|
||||||
|
- cli
|
||||||
|
notify:
|
||||||
|
- restart php-fpm
|
||||||
|
|
||||||
|
- name: Find enabled php-fpm apache2 config
|
||||||
|
ansible.builtin.find:
|
||||||
|
paths: ["/etc/apache2/conf-enabled/"]
|
||||||
|
patterns: ["php*-fpm.conf"]
|
||||||
|
file_type: file
|
||||||
|
register: php_register_conf_enabled
|
||||||
|
|
||||||
|
- name: Enable wanted and disable unwanted php-fpm apache2 config
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item.path }}"
|
||||||
|
state: >-
|
||||||
|
{%- if item.path.endswith(wanted) -%}
|
||||||
|
link
|
||||||
|
{%- else -%}
|
||||||
|
absent
|
||||||
|
{%- endif -%}
|
||||||
|
src: "/etc/apache2/conf-available{{ wanted }}"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: 0644
|
||||||
|
vars:
|
||||||
|
wanted: "/php{{ php_version }}-fpm.conf"
|
||||||
|
loop: "{{ php_register_conf_enabled.files }}"
|
||||||
|
notify:
|
||||||
|
- restart apache2
|
||||||
|
|
||||||
|
- name: Enable apache2 modules
|
||||||
|
community.general.apache2_module:
|
||||||
|
name: "{{ item }}"
|
||||||
|
loop:
|
||||||
|
- proxy_fcgi
|
||||||
|
- setenvif
|
||||||
|
notify:
|
||||||
|
- restart apache2
|
||||||
|
|
||||||
|
- name: Start and enable php-fpm
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: "php{{ php_version }}-fpm.service"
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
32
roles/php/tasks/install.yml
Normal file
32
roles/php/tasks/install.yml
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
- name: Add packages.sury.org key
|
||||||
|
ansible.builtin.apt_key:
|
||||||
|
url: https://packages.sury.org/php/apt.gpg
|
||||||
|
keyring: /etc/apt/trusted.gpg.d/packages.sury.org-php.gpg
|
||||||
|
|
||||||
|
- name: Add packages.sury.org
|
||||||
|
ansible.builtin.apt_repository:
|
||||||
|
filename: packages.sury.org-php.list
|
||||||
|
repo: "deb https://packages.sury.org/php/ {{ ansible_facts.distribution_release }} main"
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name:
|
||||||
|
- "{{ php }}"
|
||||||
|
- "{{ php }}-fpm"
|
||||||
|
- "{{ php }}-cli"
|
||||||
|
- "{{ php }}-bcmath"
|
||||||
|
- "{{ php }}-bz2"
|
||||||
|
- "{{ php }}-curl"
|
||||||
|
- "{{ php }}-gd"
|
||||||
|
- "{{ php }}-gmp"
|
||||||
|
- "{{ php }}-imagick"
|
||||||
|
- "{{ php }}-intl"
|
||||||
|
- "{{ php }}-mbstring"
|
||||||
|
- "{{ php }}-mysql"
|
||||||
|
- "{{ php }}-redis"
|
||||||
|
- "{{ php }}-xml"
|
||||||
|
- "{{ php }}-zip"
|
||||||
|
vars:
|
||||||
|
php: "php{{ php_version }}"
|
11
roles/php/tasks/main.yml
Normal file
11
roles/php/tasks/main.yml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
- ansible.builtin.import_tasks: install.yml
|
||||||
|
tags:
|
||||||
|
- "role::php"
|
||||||
|
- "role::php:install"
|
||||||
|
|
||||||
|
- ansible.builtin.import_tasks: config.yml
|
||||||
|
tags:
|
||||||
|
- "role::php"
|
||||||
|
- "role::php:config"
|
9
roles/php/templates/etc/php/conf.d/99-nextcloud.ini.j2
Normal file
9
roles/php/templates/etc/php/conf.d/99-nextcloud.ini.j2
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{{ ansible_managed | comment(decoration=';;') }}
|
||||||
|
|
||||||
|
{% for name, section in php_ini.items() %}
|
||||||
|
[name]
|
||||||
|
{% endfor %}{% for key, value in section.items() %}
|
||||||
|
{{ key }}={{ value }}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% endfor %}
|
Loading…
Reference in a new issue