Initial commit.
This commit is contained in:
commit
c9a33ad40c
10
README.md
Normal file
10
README.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# deploy then delete:
|
||||||
|
$ SECRETS_ARCHIVE_PASSPHRASE=XXXXXX ansible-playbook -e target_name=host.domain -e SECRET_HOST=host2.domain2 deploy_ovh_instance.yml
|
||||||
|
|
||||||
|
# only delete:
|
||||||
|
$ SECRETS_ARCHIVE_PASSPHRASE=XXXXXX ansible-playbook -e target_name=host.domain -e SECRET_HOST=host2.domain2 -t delete deploy_ovh_instance.yml
|
||||||
|
|
||||||
|
# deploy and do not delete:
|
||||||
|
$ SECRETS_ARCHIVE_PASSPHRASE=XXXXXX ansible-playbook -e target_name=host.domain -e SECRET_HOST=host2.domain2 -e delete=False deploy_ovh_instance.yml
|
||||||
|
|
||||||
|
library directory contains Ansible modules from https://github.com/gheesh/ansible-ovh-dns
|
34
TODO
Normal file
34
TODO
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
pousser sur Gogs
|
||||||
|
|
||||||
|
créer un autre repo Git avec un script de déploiement qui télécharge le code, lance ansible-galaxy et lance le playbook
|
||||||
|
|
||||||
|
create Nextcloud deployment
|
||||||
|
==>
|
||||||
|
- turn setup_volume.yml into a role then migrate everything to it
|
||||||
|
- We need to build the image
|
||||||
|
- we need to retrieve configuration files from secrets and put them in the mount directory
|
||||||
|
|
||||||
|
make sure containers start on reboot
|
||||||
|
add DNS record in serveur-appart DNS configuration
|
||||||
|
add name in local /etc/hosts of ansible controller too
|
||||||
|
|
||||||
|
|
||||||
|
fix Gogs mysql connection:
|
||||||
|
2024/03/21 02:33:21 [FATAL] [...o/gogs/internal/route/install.go:76 GlobalInit()] Failed to initialize ORM engine: open database: failed to connect to `host=mysql-server user=gogs database=gogs`: failed to receive message (CopyDone body must have length of 0, but it is 6)
|
||||||
|
==> solution here:
|
||||||
|
https://github.com/gogs/gogs/issues/7474
|
||||||
|
==> use same image version as OVH1 for now
|
||||||
|
|
||||||
|
supprimer le fichier des secrets de Nextcloud (on récupère toujours depuis serveur-appart ou le dernier mail de backup ou l'object storage)
|
||||||
|
mettre toute ma doc dans un repo Git sur Gogs au lieu de Nextcloud (facile de faire un grep et versioning de qualité, on peut coder en markdown avec un rendu temps réel avec un bon éditeur)
|
||||||
|
|
||||||
|
enlever le code de github et supprimer mon compte
|
||||||
|
sauvegarder les projets Git indispensables pour réinstaller Gogs, comme archives dans le bootstrap à la place
|
||||||
|
|
||||||
|
"duplicity restore" will not overwrite existing files, so either clean tmp workdir first or check whether the file is up to date with "duplicity verify"
|
||||||
|
|
||||||
|
Dans un rôle dédié :
|
||||||
|
conf postfix
|
||||||
|
conf FTP
|
||||||
|
volume restore should be a role
|
||||||
|
reading from secrets should be a role ==> put secrets in secrets.yml in secrets archive
|
3
ansible.cfg
Normal file
3
ansible.cfg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[defaults]
|
||||||
|
inventory = inventory.yml
|
||||||
|
host_key_checking = accept-new
|
7
collections/requirements.yml
Normal file
7
collections/requirements.yml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
collections:
|
||||||
|
- name: openstack.cloud
|
||||||
|
version: 1.2.1
|
||||||
|
source: https://galaxy.ansible.com
|
||||||
|
- name: containers.podman
|
||||||
|
version: 1.11.0
|
||||||
|
source: https://galaxy.ansible.com
|
94
deploy_ovh_instance.yml
Normal file
94
deploy_ovh_instance.yml
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
- name: deploy OVH instance
|
||||||
|
hosts: localhost
|
||||||
|
tags: create
|
||||||
|
vars_files:
|
||||||
|
- vars/main.yml
|
||||||
|
tasks:
|
||||||
|
- name: Retrieve secrets
|
||||||
|
ansible.builtin.include_tasks: "tasks/retrieve_secret_vars.yml"
|
||||||
|
|
||||||
|
- name: Include OVH application credentials
|
||||||
|
ansible.builtin.include_vars: "{{ remote_workdir }}/OVH_APPLICATION.yml"
|
||||||
|
|
||||||
|
- name: include role_deploy_openstack_instance
|
||||||
|
ansible.builtin.include_role:
|
||||||
|
name: role_deploy_openstack_instance
|
||||||
|
|
||||||
|
- name: add new instance to host group at runtime
|
||||||
|
ansible.builtin.add_host:
|
||||||
|
name: "{{ target_name }}"
|
||||||
|
ansible_host: "{{ openstack_output.openstack.accessIPv4 }}"
|
||||||
|
groups: target
|
||||||
|
|
||||||
|
- name: Remove old SSH host key
|
||||||
|
command: ssh-keygen -f "/home/{{ LINUX_USERNAME }}/.ssh/known_hosts" -R "{{ target_name }}"
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: configure OVH instance
|
||||||
|
hosts: target
|
||||||
|
vars_files:
|
||||||
|
- vars/main.yml
|
||||||
|
gather_facts: false
|
||||||
|
tasks:
|
||||||
|
- name: Wait for system to become reachable
|
||||||
|
ansible.builtin.wait_for_connection:
|
||||||
|
timeout: 30
|
||||||
|
tags: configure
|
||||||
|
|
||||||
|
- name: Gather facts
|
||||||
|
ansible.builtin.setup:
|
||||||
|
tags: common
|
||||||
|
|
||||||
|
- name: Include retrieve_secret_vars tasks
|
||||||
|
ansible.builtin.include_tasks: "tasks/retrieve_secret_vars.yml"
|
||||||
|
tags: common
|
||||||
|
|
||||||
|
- name: Include secrets from yml db
|
||||||
|
ansible.builtin.include_vars: "{{ local_workdir }}/secrets.yml"
|
||||||
|
|
||||||
|
- name: Register variable DUPLICITY_PASSPHRASE
|
||||||
|
command: "cat {{ remote_workdir }}/duplicity_passphrase"
|
||||||
|
register: cat_duplicity_passphrase
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Set variable DUPLICITY_PASSPHRASE
|
||||||
|
set_fact:
|
||||||
|
"DUPLICITY_PASSPHRASE": "{{ cat_duplicity_passphrase.stdout }}"
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Include role_configure_ovh_instance
|
||||||
|
ansible.builtin.include_role:
|
||||||
|
name: role_configure_ovh_instance
|
||||||
|
tags: configure
|
||||||
|
|
||||||
|
- name: Include deploy_reverse-proxy tasks
|
||||||
|
ansible.builtin.include_tasks: "tasks/deploy_reverse-proxy.yml"
|
||||||
|
tags: deploy_reverse-proxy
|
||||||
|
|
||||||
|
- name: Include deploy_mysql-server tasks
|
||||||
|
ansible.builtin.include_tasks: "tasks/deploy_mysql-server.yml"
|
||||||
|
tags: deploy_mysql-server
|
||||||
|
|
||||||
|
- name: Include deploy_gogs tasks
|
||||||
|
ansible.builtin.include_tasks: "tasks/deploy_gogs.yml"
|
||||||
|
tags: deploy_gogs
|
||||||
|
|
||||||
|
- name: delete OVH instance
|
||||||
|
hosts: localhost
|
||||||
|
connection: local
|
||||||
|
tags: delete
|
||||||
|
vars_files:
|
||||||
|
- vars/main.yml
|
||||||
|
tasks:
|
||||||
|
- name: Retrieve secrets
|
||||||
|
ansible.builtin.include_tasks: "tasks/retrieve_secret_vars.yml"
|
||||||
|
when: delete | default(True) | bool
|
||||||
|
|
||||||
|
- name: Include OVH application credentials
|
||||||
|
ansible.builtin.include_vars: "{{ remote_workdir }}/OVH_APPLICATION.yml"
|
||||||
|
when: delete | default(True) | bool
|
||||||
|
|
||||||
|
- name: include role_delete_openstack_instance
|
||||||
|
ansible.builtin.include_role:
|
||||||
|
name: role_delete_openstack_instance
|
||||||
|
when: delete | default(True) | bool
|
8
install_requirements.sh
Executable file
8
install_requirements.sh
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#Absolute path to this script
|
||||||
|
SCRIPT=$(readlink -f $0)
|
||||||
|
#Absolute path this script is in
|
||||||
|
SCRIPTPATH=$(dirname $SCRIPT)
|
||||||
|
|
||||||
|
cd $SCRIPTPATH
|
||||||
|
ansible-galaxy collection install --force -r collections/requirements.yml
|
4
inventory.yml
Normal file
4
inventory.yml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
target:
|
||||||
|
vars:
|
||||||
|
ansible_user: rocky
|
||||||
|
|
352
library/ovh_dns.py
Normal file
352
library/ovh_dns.py
Normal file
@ -0,0 +1,352 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# ovh_dns, an Ansible module for managing OVH DNS records
|
||||||
|
# Copyright (C) 2014, Carlos Izquierdo <gheesh@gheesh.org>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovh_dns
|
||||||
|
author: Carlos Izquierdo
|
||||||
|
short_description: Manage OVH DNS records
|
||||||
|
description:
|
||||||
|
- Manage OVH (French European hosting provider) DNS records
|
||||||
|
requirements: [ "ovh" ]
|
||||||
|
options:
|
||||||
|
create:
|
||||||
|
required: false
|
||||||
|
description:
|
||||||
|
- If 'state' == 'present' and 'replace' is not empty then create the record
|
||||||
|
domain:
|
||||||
|
required: true
|
||||||
|
description:
|
||||||
|
- Name of the domain zone
|
||||||
|
name:
|
||||||
|
required: true
|
||||||
|
description:
|
||||||
|
- Name of the DNS record
|
||||||
|
value:
|
||||||
|
required: true if present/append
|
||||||
|
description:
|
||||||
|
- Value of the DNS record (i.e. what it points to)
|
||||||
|
- If None with 'present' then deletes ALL records at 'name'
|
||||||
|
removes:
|
||||||
|
required: false
|
||||||
|
description:
|
||||||
|
- specifies a regex pattern to match for bulk deletion
|
||||||
|
replace:
|
||||||
|
required: true if present and multi records found
|
||||||
|
- Old value of the DNS record (i.e. what it points to now)
|
||||||
|
- Accept regex
|
||||||
|
ttl:
|
||||||
|
required: false
|
||||||
|
description:
|
||||||
|
- value of record TTL value in seconds (defaults to 3600)
|
||||||
|
type:
|
||||||
|
required: true if present/append
|
||||||
|
choices: ['A', 'AAAA', 'CAA', 'CNAME', 'DKIM', 'LOC', 'MX', 'NAPTR', 'NS', 'PTR', 'SPF', 'SRV', 'SSHFP', 'TLSA', 'TXT']
|
||||||
|
description:
|
||||||
|
- Type of DNS record (A, AAAA, PTR, CNAME, etc.)
|
||||||
|
state:
|
||||||
|
required: false
|
||||||
|
default: present
|
||||||
|
choices: ['present', 'absent', 'append']
|
||||||
|
description:
|
||||||
|
- Determines wether the record is to be created/modified or deleted
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Create a typical A record
|
||||||
|
- ovh_dns: state=present domain=mydomain.com name=db1 value=10.10.10.10
|
||||||
|
|
||||||
|
# Create a CNAME record
|
||||||
|
- ovh_dns: state=present domain=mydomain.com name=dbprod type=cname value=db1
|
||||||
|
|
||||||
|
# Delete an existing record, must specify all parameters
|
||||||
|
- ovh_dns: state=absent domain=mydomain.com name=dbprod type=cname value=db1
|
||||||
|
|
||||||
|
# Delete all TXT records matching '^_acme-challenge.*$' regex
|
||||||
|
- ovh_dns: state=absent domain=mydomain.com name='' type=TXT removes='^_acme-challenge.*'
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
try:
|
||||||
|
import ovh
|
||||||
|
except ImportError:
|
||||||
|
print("failed=True msg='ovh required for this module'")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: Try to automate this in case the supplied credentials are not valid
|
||||||
|
def get_credentials():
|
||||||
|
"""This function is used to obtain an authentication token.
|
||||||
|
It should only be called once."""
|
||||||
|
client = ovh.Client()
|
||||||
|
access_rules = [
|
||||||
|
{'method': 'GET', 'path': '/domain/*'},
|
||||||
|
{'method': 'PUT', 'path': '/domain/*'},
|
||||||
|
{'method': 'POST', 'path': '/domain/*'},
|
||||||
|
{'method': 'DELETE', 'path': '/domain/*'},
|
||||||
|
]
|
||||||
|
validation = client.request_consumerkey(access_rules)
|
||||||
|
# print("Your consumer key is {}".format(validation['consumerKey']))
|
||||||
|
# print("Please visit {} to validate".format(validation['validationUrl']))
|
||||||
|
return validation['consumerKey']
|
||||||
|
|
||||||
|
|
||||||
|
def get_domain_records(client, domain, fieldtype=None, subDomain=None):
|
||||||
|
"""Obtain all records for a specific domain"""
|
||||||
|
records = {}
|
||||||
|
|
||||||
|
params = {}
|
||||||
|
|
||||||
|
# List all ids and then get info for each one
|
||||||
|
if subDomain is not None:
|
||||||
|
params['subDomain'] = subDomain
|
||||||
|
if fieldtype is not None:
|
||||||
|
params['fieldType'] = fieldtype
|
||||||
|
|
||||||
|
record_ids = client.get('/domain/zone/{}/record'.format(domain),
|
||||||
|
**params)
|
||||||
|
for record_id in record_ids:
|
||||||
|
info = client.get('/domain/zone/{}/record/{}'.format(domain, record_id))
|
||||||
|
records[record_id] = info
|
||||||
|
|
||||||
|
return records
|
||||||
|
|
||||||
|
|
||||||
|
def count_type(records, fieldtype=['A', 'AAAA']):
|
||||||
|
i = 0
|
||||||
|
for id in records:
|
||||||
|
if records[id]['fieldType'] in fieldtype:
|
||||||
|
i+=1
|
||||||
|
return i
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=dict(
|
||||||
|
domain=dict(required=True),
|
||||||
|
name=dict(required=True),
|
||||||
|
state=dict(default='present', choices=['present', 'absent', 'append']),
|
||||||
|
type=dict(default=None, choices=['A', 'AAAA', 'CNAME', 'CAA', 'DKIM', 'LOC', 'MX', 'NAPTR', 'NS', 'PTR', 'SPF', 'SRV', 'SSHFP', 'TXT', 'TLSA']),
|
||||||
|
removes=dict(default=None),
|
||||||
|
replace=dict(default=None),
|
||||||
|
value=dict(default=None),
|
||||||
|
create=dict(default=False, type='bool'),
|
||||||
|
ttl=dict(default=3600, type='int'),
|
||||||
|
),
|
||||||
|
supports_check_mode=True
|
||||||
|
)
|
||||||
|
results = dict(
|
||||||
|
changed=False,
|
||||||
|
msg='',
|
||||||
|
records='',
|
||||||
|
response='',
|
||||||
|
original_message=module.params['name'],
|
||||||
|
diff={}
|
||||||
|
)
|
||||||
|
response = []
|
||||||
|
|
||||||
|
# Get parameters
|
||||||
|
domain = module.params.get('domain')
|
||||||
|
name = module.params.get('name')
|
||||||
|
state = module.params.get('state')
|
||||||
|
fieldtype = module.params.get('type')
|
||||||
|
targetval = module.params.get('value')
|
||||||
|
removes = module.params.get('removes')
|
||||||
|
ttlval = module.params.get('ttl')
|
||||||
|
oldtargetval = module.params.get('replace')
|
||||||
|
create = module.params.get('create')
|
||||||
|
|
||||||
|
# Connect to OVH API
|
||||||
|
client = ovh.Client()
|
||||||
|
|
||||||
|
# Check that the domain exists
|
||||||
|
domains = client.get('/domain/zone')
|
||||||
|
if domain not in domains:
|
||||||
|
module.fail_json(msg='Domain {} does not exist'.format(domain))
|
||||||
|
|
||||||
|
# Obtain all domain records to check status against what is demanded
|
||||||
|
records = get_domain_records(client, domain, fieldtype, name)
|
||||||
|
|
||||||
|
# Remove a record(s)
|
||||||
|
if state == 'absent':
|
||||||
|
|
||||||
|
if len(name) == 0 and not removes:
|
||||||
|
module.fail_json(msg='wildcard delete not allowed')
|
||||||
|
|
||||||
|
if not records:
|
||||||
|
module.exit_json(changed=False)
|
||||||
|
|
||||||
|
# Delete same target
|
||||||
|
rn = None
|
||||||
|
rv = None
|
||||||
|
if removes:
|
||||||
|
rn = re.compile(removes, re.IGNORECASE)
|
||||||
|
else:
|
||||||
|
rn = re.compile("^{}$".format(name), re.IGNORECASE)
|
||||||
|
if targetval:
|
||||||
|
rv = re.compile(targetval, re.IGNORECASE)
|
||||||
|
else:
|
||||||
|
rv = re.compile(r'.*')
|
||||||
|
|
||||||
|
tmprecords = records.copy()
|
||||||
|
for id in records:
|
||||||
|
if not rn.match(records[id]['subDomain']) or not rv.match(records[id]['target']):
|
||||||
|
tmprecords.pop(id)
|
||||||
|
records = tmprecords
|
||||||
|
|
||||||
|
results['delete'] = records
|
||||||
|
if records:
|
||||||
|
before_records=[]
|
||||||
|
# Remove the ALL record
|
||||||
|
for id in records:
|
||||||
|
before_records.append(dict(
|
||||||
|
domain=domain,
|
||||||
|
fieldType=records[id]['fieldType'],
|
||||||
|
subDomain=records[id]['subDomain'],
|
||||||
|
target=records[id]['target'],
|
||||||
|
ttl=records[id]['ttl'],
|
||||||
|
))
|
||||||
|
if not module.check_mode:
|
||||||
|
client.delete('/domain/zone/{}/record/{}'.format(domain, id))
|
||||||
|
if not module.check_mode:
|
||||||
|
client.post('/domain/zone/{}/refresh'.format(domain))
|
||||||
|
results['changed'] = True
|
||||||
|
results['diff']['before'] = yaml.dump(before_records)
|
||||||
|
results['diff']['after'] = ''
|
||||||
|
module.exit_json(**results)
|
||||||
|
|
||||||
|
# Add / modify a record
|
||||||
|
elif state in ['present', 'append']:
|
||||||
|
|
||||||
|
# Since we are inserting a record, we need a target
|
||||||
|
if targetval is None:
|
||||||
|
module.fail_json(msg='Did not specify a value')
|
||||||
|
if fieldtype is None:
|
||||||
|
module.fail_json(msg='Did not specify a type')
|
||||||
|
|
||||||
|
# Does the record exist already? Yes
|
||||||
|
if records:
|
||||||
|
for id in records:
|
||||||
|
if records[id]['target'].lower() == targetval.lower() and records[id]['ttl'] == ttlval:
|
||||||
|
# The record is already as requested, no need to change anything
|
||||||
|
module.exit_json(changed=False)
|
||||||
|
|
||||||
|
# list records modify in end
|
||||||
|
oldrecords = {}
|
||||||
|
if state == 'present':
|
||||||
|
if oldtargetval:
|
||||||
|
r = re.compile(oldtargetval, re.IGNORECASE)
|
||||||
|
for id in records:
|
||||||
|
# update target
|
||||||
|
if oldtargetval:
|
||||||
|
if re.match(r, records[id]['target']):
|
||||||
|
oldrecords.update({id: records[id]})
|
||||||
|
# uniq update
|
||||||
|
else:
|
||||||
|
oldrecords.update({id: records[id]})
|
||||||
|
if oldtargetval and not oldrecords and not create:
|
||||||
|
module.fail_json(msg='Old record not match, use append ?')
|
||||||
|
|
||||||
|
if oldrecords:
|
||||||
|
before_records = []
|
||||||
|
# FIXME: check if all records as same fieldType not A/AAAA and CNAME
|
||||||
|
# if fieldtype in ['A', 'AAAA', 'CNAME']:
|
||||||
|
# oldA = count_type(records)
|
||||||
|
# oldC = count_type(records, 'CNAME')
|
||||||
|
# newA = count_type(oldrecords)
|
||||||
|
# newC = count_type(oldrecords, 'CNAME')
|
||||||
|
# check = True
|
||||||
|
# if oldA > 0 and newC > 0 and oldA != newC:
|
||||||
|
# check = False
|
||||||
|
# if oldC > 0 and newA > 0 and oldC != newA:
|
||||||
|
# check = False
|
||||||
|
# if not check:
|
||||||
|
# module.fail_json(msg='The subdomain already uses a DNS record. You can not register a {} field because of an incompatibility.'.format(fieldType))
|
||||||
|
|
||||||
|
# Delete all records and re-create the record
|
||||||
|
newrecord = dict(
|
||||||
|
fieldType=fieldtype,
|
||||||
|
subDomain=name,
|
||||||
|
target=targetval,
|
||||||
|
ttl=ttlval
|
||||||
|
)
|
||||||
|
for id in oldrecords:
|
||||||
|
before_records.append(dict(
|
||||||
|
domain=domain,
|
||||||
|
fieldType=oldrecords[id]['fieldType'],
|
||||||
|
subDomain=oldrecords[id]['subDomain'],
|
||||||
|
target=oldrecords[id]['target'],
|
||||||
|
ttl=oldrecords[id]['ttl'],
|
||||||
|
))
|
||||||
|
if not module.check_mode:
|
||||||
|
client.delete('/domain/zone/{}/record/{}'.format(domain, id))
|
||||||
|
if not module.check_mode:
|
||||||
|
response.append({'delete': oldrecords})
|
||||||
|
|
||||||
|
res = client.post('/domain/zone/{}/record'.format(domain), **newrecord)
|
||||||
|
response.append(res)
|
||||||
|
# Refresh the zone and exit
|
||||||
|
client.post('/domain/zone/{}/refresh'.format(domain))
|
||||||
|
results['response'] = response
|
||||||
|
results['diff']['before'] = yaml.dump(before_records)
|
||||||
|
after = [newrecord]
|
||||||
|
after[0]['domain'] = domain
|
||||||
|
results['diff']['after'] = yaml.dump(after)
|
||||||
|
results['changed'] = True
|
||||||
|
module.exit_json(**results)
|
||||||
|
# end records exist
|
||||||
|
|
||||||
|
# Add record
|
||||||
|
if state == 'append' or not records:
|
||||||
|
newrecord = dict(
|
||||||
|
fieldType=fieldtype,
|
||||||
|
subDomain=name,
|
||||||
|
target=targetval,
|
||||||
|
ttl=ttlval
|
||||||
|
)
|
||||||
|
if not module.check_mode:
|
||||||
|
# Add the record
|
||||||
|
res = client.post('/domain/zone/{}/record'.format(domain), **newrecord)
|
||||||
|
response.append(res)
|
||||||
|
client.post('/domain/zone/{}/refresh'.format(domain))
|
||||||
|
results['diff']['before'] = ''
|
||||||
|
after = dict(newrecord)
|
||||||
|
after['domain'] = domain
|
||||||
|
results['diff']['after'] = yaml.dump(after)
|
||||||
|
results['changed'] = True
|
||||||
|
|
||||||
|
results['response'] = response
|
||||||
|
module.exit_json(**results)
|
||||||
|
# end state == 'present'
|
||||||
|
|
||||||
|
# We should never reach here
|
||||||
|
results['msg'] = 'Internal ovh_dns module error'
|
||||||
|
module.fail_json(**results)
|
||||||
|
|
||||||
|
|
||||||
|
# import module snippets
|
||||||
|
from ansible.module_utils.basic import *
|
||||||
|
|
||||||
|
main()
|
214
library/ovh_reverse.py
Normal file
214
library/ovh_reverse.py
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# ovh_reverse, an Ansible module for managing OVH DNS reverse
|
||||||
|
# Copyright (C) 2014, Carlos Izquierdo <gheesh@gheesh.org>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovh_reverse
|
||||||
|
author: Laurent Almeras
|
||||||
|
short_description: Manage OVH DNS reverse
|
||||||
|
description:
|
||||||
|
- Manage OVH (French European hosting provider) DNS reverse
|
||||||
|
requirements: [ "ovh" ]
|
||||||
|
options:
|
||||||
|
ip:
|
||||||
|
required: true
|
||||||
|
description:
|
||||||
|
- IP we want to manage
|
||||||
|
reverse:
|
||||||
|
required: false
|
||||||
|
description:
|
||||||
|
- reverse name to associate the IP with; not used if state: absent.
|
||||||
|
For state: present and reverse is empty, only checks if a reverse
|
||||||
|
exists else triggers a failure
|
||||||
|
state:
|
||||||
|
required: false
|
||||||
|
default: present
|
||||||
|
choices: ['present', 'absent']
|
||||||
|
description:
|
||||||
|
- present or absent: present checks current reverse and update it as
|
||||||
|
needed, absent delete reverse record if present.
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Create a reverse
|
||||||
|
- ovh_reverse: ip=10.10.10.10 state=present reverse=myhost.mydomain.tld.
|
||||||
|
|
||||||
|
# Check a reverse exists, else triggers a failure
|
||||||
|
- ovh_reverse: ip=10.10.10.10 state=present
|
||||||
|
|
||||||
|
# Delete a reverse
|
||||||
|
- ovh_reverse: ip=10.10.10.10 state=absent
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
try:
|
||||||
|
import ovh
|
||||||
|
except ImportError:
|
||||||
|
print("failed=True msg='ovh required for this module'")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: Try to automate this in case the supplied credentials are not valid
|
||||||
|
def get_credentials():
|
||||||
|
"""This function is used to obtain an authentication token.
|
||||||
|
It should only be called once."""
|
||||||
|
client = ovh.Client()
|
||||||
|
access_rules = [
|
||||||
|
{'method': 'GET', 'path': '/domain/*'},
|
||||||
|
{'method': 'PUT', 'path': '/domain/*'},
|
||||||
|
{'method': 'POST', 'path': '/domain/*'},
|
||||||
|
{'method': 'DELETE', 'path': '/domain/*'},
|
||||||
|
]
|
||||||
|
validation = client.request_consumerkey(access_rules)
|
||||||
|
# print("Your consumer key is {}".format(validation['consumerKey']))
|
||||||
|
# print("Please visit {} to validate".format(validation['validationUrl']))
|
||||||
|
return validation['consumerKey']
|
||||||
|
|
||||||
|
|
||||||
|
def get_reverse(client, ip):
|
||||||
|
"""Obtain a reverse"""
|
||||||
|
# this url works both with /32 blocks or ip as first parameter
|
||||||
|
# may throw an APIError
|
||||||
|
|
||||||
|
# first check ip management is accessible, throw an ApiError if not
|
||||||
|
ip_reverses = client.get('/ip/{}%2F32/reverse'.format(ip))
|
||||||
|
if not ip_reverses:
|
||||||
|
# if list if empty, ip is manageable but there is no reverse
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
# if ip is manageable, get reverse information
|
||||||
|
# result is a list; only one reverse is expected
|
||||||
|
return client.get('/ip/{}%2F32/reverse/{}'.format(ip, ip_reverses[0]))
|
||||||
|
|
||||||
|
def exc_str(ovh_exception):
|
||||||
|
"""__str__ is overloaded in ovh APIError and does not provide any insight.
|
||||||
|
Alternative implementation to retrieve first exception parameter.
|
||||||
|
"""
|
||||||
|
args = getattr(ovh_exception, 'args', None)
|
||||||
|
if args:
|
||||||
|
return args[0]
|
||||||
|
else:
|
||||||
|
return str(ovh_exception)
|
||||||
|
|
||||||
|
|
||||||
|
def update_reverse(check_mode, client, ip, original_reverse, reverse, results):
|
||||||
|
"""Update a reverse"""
|
||||||
|
if original_reverse is None or original_reverse['reverse'] != reverse:
|
||||||
|
if original_reverse:
|
||||||
|
results['diff']['before'] = original_reverse['reverse'] + "\n"
|
||||||
|
updated_reverse = None
|
||||||
|
results['diff']['before'] = original_reverse['reverse'] + "\n" if original_reverse else "\n"
|
||||||
|
if not check_mode:
|
||||||
|
client.post('/ip/{}%2F32/reverse'.format(ip), ipReverse=ip, reverse=reverse)
|
||||||
|
updated_reverse = get_reverse(client, ip)
|
||||||
|
results['reverse'] = updated_reverse
|
||||||
|
results['msg'] = 'IP reverse for {} updated from {} to {}'.format(ip, original_reverse['reverse'] if original_reverse else '<none>', updated_reverse['reverse'])
|
||||||
|
results['diff']['after'] = updated_reverse['reverse'] + "\n"
|
||||||
|
else:
|
||||||
|
results['reverse'] = None
|
||||||
|
results['msg'] = 'IP reverse for {} needs to be updated from {} to {}'.format(ip, original_reverse['reverse'] if original_reverse else '<none>', reverse)
|
||||||
|
results['diff']['after'] = reverse + "\n"
|
||||||
|
results['changed'] = True
|
||||||
|
else:
|
||||||
|
results['msg'] = 'IP reverse for {} already set to {}'.format(ip, reverse)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=dict(
|
||||||
|
ip=dict(required=True),
|
||||||
|
reverse=dict(required=False),
|
||||||
|
state=dict(default='present', choices=['present', 'absent'])
|
||||||
|
),
|
||||||
|
supports_check_mode=True
|
||||||
|
)
|
||||||
|
results = dict(
|
||||||
|
changed=False,
|
||||||
|
msg='',
|
||||||
|
original_reverse=None,
|
||||||
|
reverse=None,
|
||||||
|
diff={},
|
||||||
|
failed=False
|
||||||
|
)
|
||||||
|
response = []
|
||||||
|
|
||||||
|
# Get parameters
|
||||||
|
ip = module.params.get('ip')
|
||||||
|
reverse = module.params.get('reverse')
|
||||||
|
state = module.params.get('state')
|
||||||
|
|
||||||
|
# Connect to OVH API
|
||||||
|
client = ovh.Client()
|
||||||
|
|
||||||
|
# Check that the domain exists
|
||||||
|
original_reverse = None
|
||||||
|
try:
|
||||||
|
original_reverse = get_reverse(client, ip)
|
||||||
|
results['original_reverse'] = original_reverse
|
||||||
|
results['reverse'] = original_reverse
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg='IP reverse for {} does not seem to be manageable: {}.'.format(ip, exc_str(e)))
|
||||||
|
|
||||||
|
try:
|
||||||
|
if state == 'present':
|
||||||
|
if reverse:
|
||||||
|
# we have a value to check and set
|
||||||
|
update_reverse(module.check_mode, client, ip, original_reverse, reverse, results)
|
||||||
|
else:
|
||||||
|
# we only check if reverse is set (whatever value it is)
|
||||||
|
if original_reverse is None:
|
||||||
|
# no reverse to set and no reverse, failure
|
||||||
|
results['msg'] = 'No IP reverse for {} and not reverse provided. Failure.'.format(ip)
|
||||||
|
results['failed'] = True
|
||||||
|
else:
|
||||||
|
results['msg'] = 'IP reverse record for {} is set to {}.'.format(ip, original_reverse['reverse'])
|
||||||
|
elif state == 'absent' and original_reverse is None:
|
||||||
|
results['msg'] = 'IP reverse record for {} is absent.'.format(ip)
|
||||||
|
elif state == 'absent' and not original_reverse is None:
|
||||||
|
if not module.check_mode:
|
||||||
|
client.delete('/ip/{}%2F32/reverse/{}'.format(ip, original_reverse['ipReverse']))
|
||||||
|
results['msg'] = 'IP reverse record for {} deleted.'.format(ip)
|
||||||
|
else:
|
||||||
|
results['msg'] = 'IP reverse record for {} needs to be deleted.'.format(ip)
|
||||||
|
results['diff']['before'] = original_reverse['reverse'] + "\n"
|
||||||
|
results['diff']['after'] = "\n"
|
||||||
|
results['changed'] = True
|
||||||
|
results['reverse'] = None
|
||||||
|
|
||||||
|
failed = results['failed']
|
||||||
|
results.pop('failed')
|
||||||
|
if failed:
|
||||||
|
module.fail_json(**results)
|
||||||
|
else:
|
||||||
|
module.exit_json(**results)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg='IP reverse for {} fails during update: {}.'.format(ip, exc_str(e)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# import module snippets
|
||||||
|
from ansible.module_utils.basic import *
|
||||||
|
|
||||||
|
main()
|
3
roles/requirements.yml
Normal file
3
roles/requirements.yml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
- name : role_setup_volume
|
||||||
|
src : git@git.scimetis.net:2222/yohan/role_setup_volume.git
|
38
roles/role_configure_ovh_instance/README.md
Normal file
38
roles/role_configure_ovh_instance/README.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
Role Name
|
||||||
|
=========
|
||||||
|
|
||||||
|
A brief description of the role goes here.
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
|
||||||
|
Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
|
||||||
|
|
||||||
|
Role Variables
|
||||||
|
--------------
|
||||||
|
|
||||||
|
A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
|
||||||
|
|
||||||
|
Dependencies
|
||||||
|
------------
|
||||||
|
|
||||||
|
A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
|
||||||
|
|
||||||
|
Example Playbook
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
|
||||||
|
|
||||||
|
- hosts: servers
|
||||||
|
roles:
|
||||||
|
- { role: username.rolename, x: 42 }
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
|
||||||
|
BSD
|
||||||
|
|
||||||
|
Author Information
|
||||||
|
------------------
|
||||||
|
|
||||||
|
An optional section for the role authors to include contact information, or a website (HTML is not allowed).
|
2
roles/role_configure_ovh_instance/defaults/main.yml
Normal file
2
roles/role_configure_ovh_instance/defaults/main.yml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
# defaults file for role_configure_ovh_instance
|
6
roles/role_configure_ovh_instance/files/jail.local
Normal file
6
roles/role_configure_ovh_instance/files/jail.local
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[DEFAULT]
|
||||||
|
# Ban hosts for one hour:
|
||||||
|
bantime = 3600
|
||||||
|
|
||||||
|
[sshd]
|
||||||
|
enabled = true
|
2
roles/role_configure_ovh_instance/handlers/main.yml
Normal file
2
roles/role_configure_ovh_instance/handlers/main.yml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
# handlers file for role_configure_ovh_instance
|
52
roles/role_configure_ovh_instance/meta/main.yml
Normal file
52
roles/role_configure_ovh_instance/meta/main.yml
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
galaxy_info:
|
||||||
|
author: your name
|
||||||
|
description: your role description
|
||||||
|
company: your company (optional)
|
||||||
|
|
||||||
|
# If the issue tracker for your role is not on github, uncomment the
|
||||||
|
# next line and provide a value
|
||||||
|
# issue_tracker_url: http://example.com/issue/tracker
|
||||||
|
|
||||||
|
# Choose a valid license ID from https://spdx.org - some suggested licenses:
|
||||||
|
# - BSD-3-Clause (default)
|
||||||
|
# - MIT
|
||||||
|
# - GPL-2.0-or-later
|
||||||
|
# - GPL-3.0-only
|
||||||
|
# - Apache-2.0
|
||||||
|
# - CC-BY-4.0
|
||||||
|
license: license (GPL-2.0-or-later, MIT, etc)
|
||||||
|
|
||||||
|
min_ansible_version: 2.1
|
||||||
|
|
||||||
|
# If this a Container Enabled role, provide the minimum Ansible Container version.
|
||||||
|
# min_ansible_container_version:
|
||||||
|
|
||||||
|
#
|
||||||
|
# Provide a list of supported platforms, and for each platform a list of versions.
|
||||||
|
# If you don't wish to enumerate all versions for a particular platform, use 'all'.
|
||||||
|
# To view available platforms and versions (or releases), visit:
|
||||||
|
# https://galaxy.ansible.com/api/v1/platforms/
|
||||||
|
#
|
||||||
|
# platforms:
|
||||||
|
# - name: Fedora
|
||||||
|
# versions:
|
||||||
|
# - all
|
||||||
|
# - 25
|
||||||
|
# - name: SomePlatform
|
||||||
|
# versions:
|
||||||
|
# - all
|
||||||
|
# - 1.0
|
||||||
|
# - 7
|
||||||
|
# - 99.99
|
||||||
|
|
||||||
|
galaxy_tags: []
|
||||||
|
# List tags for your role here, one per line. A tag is a keyword that describes
|
||||||
|
# and categorizes the role. Users find roles by searching for tags. Be sure to
|
||||||
|
# remove the '[]' above, if you add tags to this list.
|
||||||
|
#
|
||||||
|
# NOTE: A tag is limited to a single word comprised of alphanumeric characters.
|
||||||
|
# Maximum 20 tags per role.
|
||||||
|
|
||||||
|
dependencies: []
|
||||||
|
# List your role dependencies here, one per line. Be sure to remove the '[]' above,
|
||||||
|
# if you add dependencies to this list.
|
257
roles/role_configure_ovh_instance/tasks/main.yml
Normal file
257
roles/role_configure_ovh_instance/tasks/main.yml
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
---
|
||||||
|
# tasks file for role_configure_ovh_instance
|
||||||
|
|
||||||
|
- name: Enable DNF fastestmirror
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/dnf/dnf.conf
|
||||||
|
line: fastestmirror=1
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Configure DNF fastestmirror
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/dnf/plugins/fastestmirror.conf
|
||||||
|
line: include_only=.ovh.net
|
||||||
|
create: True
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Upgrade all packages
|
||||||
|
ansible.builtin.dnf:
|
||||||
|
name: '*'
|
||||||
|
state: latest
|
||||||
|
register: upgrade_register
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: reboot
|
||||||
|
ansible.builtin.reboot:
|
||||||
|
when: upgrade_register is changed
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: enable EPEL
|
||||||
|
ansible.builtin.package:
|
||||||
|
name:
|
||||||
|
- epel-release.noarch
|
||||||
|
state: latest
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: install useful packages
|
||||||
|
ansible.builtin.package:
|
||||||
|
name:
|
||||||
|
- vim
|
||||||
|
- ioping
|
||||||
|
- fio
|
||||||
|
- sysstat
|
||||||
|
- git
|
||||||
|
- strace
|
||||||
|
- perf
|
||||||
|
- sysbench
|
||||||
|
- screen
|
||||||
|
- telnet
|
||||||
|
- nmap
|
||||||
|
- atop
|
||||||
|
- bzip2
|
||||||
|
- bind-utils
|
||||||
|
- lsof
|
||||||
|
- tcpdump
|
||||||
|
- net-tools
|
||||||
|
- bash-completion
|
||||||
|
state: latest
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: enable atop
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: atop
|
||||||
|
state: started
|
||||||
|
enabled: True
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: install fail2ban
|
||||||
|
ansible.builtin.package:
|
||||||
|
name:
|
||||||
|
- fail2ban
|
||||||
|
state: latest
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: enable firewalld
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: firewalld
|
||||||
|
state: started
|
||||||
|
enabled: True
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: disable useless firewall allowed services
|
||||||
|
ansible.posix.firewalld:
|
||||||
|
zone: public
|
||||||
|
service: "{{ item }}"
|
||||||
|
permanent: true
|
||||||
|
immediate: true
|
||||||
|
state: disabled
|
||||||
|
become: true
|
||||||
|
with_items:
|
||||||
|
- dhcpv6-client
|
||||||
|
- cockpit
|
||||||
|
|
||||||
|
- name: enable fail2ban
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: fail2ban
|
||||||
|
state: started
|
||||||
|
enabled: True
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: deploy jail.local
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: jail.local
|
||||||
|
dest: /etc/fail2ban/jail.local
|
||||||
|
register: jail_conf_register
|
||||||
|
become: true
|
||||||
|
|
||||||
|
# We need to change the rules to also block brute force attempt on gogs sshd:
|
||||||
|
# TODO
|
||||||
|
|
||||||
|
- name: restart fail2ban
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: fail2ban
|
||||||
|
state: restarted
|
||||||
|
become: true
|
||||||
|
when: jail_conf_register is changed
|
||||||
|
|
||||||
|
- name: disable useless rpcbind.socket
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: rpcbind.socket
|
||||||
|
state: stopped
|
||||||
|
enabled: False
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Configure logrotate
|
||||||
|
ansible.builtin.blockinfile:
|
||||||
|
path: /etc/logrotate.d/rsyslog
|
||||||
|
insertafter: "sharedscripts"
|
||||||
|
block: |2
|
||||||
|
daily
|
||||||
|
rotate 15
|
||||||
|
compress
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: install podman
|
||||||
|
ansible.builtin.package:
|
||||||
|
name:
|
||||||
|
- podman
|
||||||
|
- podman-compose
|
||||||
|
- podman-docker
|
||||||
|
state: latest
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: install mosh
|
||||||
|
ansible.builtin.package:
|
||||||
|
name:
|
||||||
|
- mosh
|
||||||
|
state: latest
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Allow mosh ports
|
||||||
|
ansible.posix.firewalld:
|
||||||
|
zone: public
|
||||||
|
port: 60000-61000/udp
|
||||||
|
permanent: true
|
||||||
|
immediate: true
|
||||||
|
state: enabled
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: install duplicity
|
||||||
|
ansible.builtin.package:
|
||||||
|
name:
|
||||||
|
- duplicity
|
||||||
|
- python3-pip.noarch
|
||||||
|
state: latest
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Add user
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: "{{ LINUX_USERNAME }}"
|
||||||
|
shell: /bin/bash
|
||||||
|
groups: wheel
|
||||||
|
append: yes
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Set authorized key
|
||||||
|
ansible.posix.authorized_key:
|
||||||
|
user: "{{ LINUX_USERNAME }}"
|
||||||
|
state: present
|
||||||
|
key: "{{ lookup('file', PUBLIC_KEY_FILE) }}"
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Comment out PASSWD wheel sudo rule
|
||||||
|
replace:
|
||||||
|
dest: /etc/sudoers
|
||||||
|
regexp: '^%wheel\s+ALL=\(ALL\)\s+ALL'
|
||||||
|
replace: '#%wheel ALL=(ALL) ALL'
|
||||||
|
become: true
|
||||||
|
tags: sudo
|
||||||
|
|
||||||
|
- name: Allow sudo NOPASSWD for the wheel group
|
||||||
|
replace:
|
||||||
|
dest: /etc/sudoers
|
||||||
|
regexp: '^#\s%wheel\s+ALL=\(ALL\)\s+NOPASSWD: ALL'
|
||||||
|
replace: '%wheel ALL=(ALL) NOPASSWD: ALL'
|
||||||
|
become: true
|
||||||
|
tags: sudo
|
||||||
|
|
||||||
|
- name: switch to new user
|
||||||
|
set_fact:
|
||||||
|
ansible_user: "{{ LINUX_USERNAME }}"
|
||||||
|
|
||||||
|
- name: Configure VIM
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/vimrc
|
||||||
|
line: set bg=dark
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: install openstack python modules
|
||||||
|
ansible.builtin.pip:
|
||||||
|
name:
|
||||||
|
- python-swiftclient
|
||||||
|
- python-keystoneclient
|
||||||
|
- python-novaclient
|
||||||
|
- python-cinderclient
|
||||||
|
- python-openstackclient
|
||||||
|
|
||||||
|
# Selinux prevents auto load of kernel module from container
|
||||||
|
# but we need to be able to mark packets with iptables in proxy-squid container.
|
||||||
|
- name: Enable Selinux boolean domain_kernel_load_modules
|
||||||
|
ansible.posix.seboolean:
|
||||||
|
name: domain_kernel_load_modules
|
||||||
|
state: true
|
||||||
|
persistent: true
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: install postfix
|
||||||
|
ansible.builtin.package:
|
||||||
|
name:
|
||||||
|
- postfix
|
||||||
|
- cyrus-sasl-lib
|
||||||
|
- cyrus-sasl-plain
|
||||||
|
- sendemail
|
||||||
|
state: latest
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: enable postfix
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: postfix
|
||||||
|
state: started
|
||||||
|
enabled: True
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: send test email
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "sendEmail -o tls=no -f {{ target_name.split('.')[0] }}@{{ DOMAIN }} -t {{ recipient_email }} -u 'Test subject' -m 'This is a test message.'"
|
||||||
|
|
||||||
|
- name: Add a setting to ~/.gitconfig
|
||||||
|
community.general.git_config:
|
||||||
|
name: "{{ item.name }}"
|
||||||
|
scope: global
|
||||||
|
value: "{{ item.value }}"
|
||||||
|
with_items:
|
||||||
|
- name: user.name
|
||||||
|
value: "{{ LINUX_USERNAME }}"
|
||||||
|
- name: user.email
|
||||||
|
value: "{{ git_email }}"
|
||||||
|
|
2
roles/role_configure_ovh_instance/tests/inventory
Normal file
2
roles/role_configure_ovh_instance/tests/inventory
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
localhost
|
||||||
|
|
5
roles/role_configure_ovh_instance/tests/test.yml
Normal file
5
roles/role_configure_ovh_instance/tests/test.yml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
- hosts: localhost
|
||||||
|
remote_user: root
|
||||||
|
roles:
|
||||||
|
- role_configure_ovh_instance
|
2
roles/role_configure_ovh_instance/vars/main.yml
Normal file
2
roles/role_configure_ovh_instance/vars/main.yml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
# vars file for role_configure_ovh_instance
|
38
roles/role_delete_openstack_instance/README.md
Normal file
38
roles/role_delete_openstack_instance/README.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
Role Name
|
||||||
|
=========
|
||||||
|
|
||||||
|
A brief description of the role goes here.
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
|
||||||
|
Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
|
||||||
|
|
||||||
|
Role Variables
|
||||||
|
--------------
|
||||||
|
|
||||||
|
A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
|
||||||
|
|
||||||
|
Dependencies
|
||||||
|
------------
|
||||||
|
|
||||||
|
A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
|
||||||
|
|
||||||
|
Example Playbook
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
|
||||||
|
|
||||||
|
- hosts: servers
|
||||||
|
roles:
|
||||||
|
- { role: username.rolename, x: 42 }
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
|
||||||
|
BSD
|
||||||
|
|
||||||
|
Author Information
|
||||||
|
------------------
|
||||||
|
|
||||||
|
An optional section for the role authors to include contact information, or a website (HTML is not allowed).
|
2
roles/role_delete_openstack_instance/defaults/main.yml
Normal file
2
roles/role_delete_openstack_instance/defaults/main.yml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
# defaults file for role_delete_openstack_instance
|
2
roles/role_delete_openstack_instance/handlers/main.yml
Normal file
2
roles/role_delete_openstack_instance/handlers/main.yml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
# handlers file for role_delete_openstack_instance
|
52
roles/role_delete_openstack_instance/meta/main.yml
Normal file
52
roles/role_delete_openstack_instance/meta/main.yml
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
galaxy_info:
|
||||||
|
author: your name
|
||||||
|
description: your role description
|
||||||
|
company: your company (optional)
|
||||||
|
|
||||||
|
# If the issue tracker for your role is not on github, uncomment the
|
||||||
|
# next line and provide a value
|
||||||
|
# issue_tracker_url: http://example.com/issue/tracker
|
||||||
|
|
||||||
|
# Choose a valid license ID from https://spdx.org - some suggested licenses:
|
||||||
|
# - BSD-3-Clause (default)
|
||||||
|
# - MIT
|
||||||
|
# - GPL-2.0-or-later
|
||||||
|
# - GPL-3.0-only
|
||||||
|
# - Apache-2.0
|
||||||
|
# - CC-BY-4.0
|
||||||
|
license: license (GPL-2.0-or-later, MIT, etc)
|
||||||
|
|
||||||
|
min_ansible_version: 2.1
|
||||||
|
|
||||||
|
# If this a Container Enabled role, provide the minimum Ansible Container version.
|
||||||
|
# min_ansible_container_version:
|
||||||
|
|
||||||
|
#
|
||||||
|
# Provide a list of supported platforms, and for each platform a list of versions.
|
||||||
|
# If you don't wish to enumerate all versions for a particular platform, use 'all'.
|
||||||
|
# To view available platforms and versions (or releases), visit:
|
||||||
|
# https://galaxy.ansible.com/api/v1/platforms/
|
||||||
|
#
|
||||||
|
# platforms:
|
||||||
|
# - name: Fedora
|
||||||
|
# versions:
|
||||||
|
# - all
|
||||||
|
# - 25
|
||||||
|
# - name: SomePlatform
|
||||||
|
# versions:
|
||||||
|
# - all
|
||||||
|
# - 1.0
|
||||||
|
# - 7
|
||||||
|
# - 99.99
|
||||||
|
|
||||||
|
galaxy_tags: []
|
||||||
|
# List tags for your role here, one per line. A tag is a keyword that describes
|
||||||
|
# and categorizes the role. Users find roles by searching for tags. Be sure to
|
||||||
|
# remove the '[]' above, if you add tags to this list.
|
||||||
|
#
|
||||||
|
# NOTE: A tag is limited to a single word comprised of alphanumeric characters.
|
||||||
|
# Maximum 20 tags per role.
|
||||||
|
|
||||||
|
dependencies: []
|
||||||
|
# List your role dependencies here, one per line. Be sure to remove the '[]' above,
|
||||||
|
# if you add dependencies to this list.
|
61
roles/role_delete_openstack_instance/tasks/main.yml
Normal file
61
roles/role_delete_openstack_instance/tasks/main.yml
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
---
|
||||||
|
# tasks file for role_delete_openstack_instance
|
||||||
|
- name: install openstack
|
||||||
|
ansible.builtin.package:
|
||||||
|
name:
|
||||||
|
- python3-openstacksdk
|
||||||
|
state: latest
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: delete instance
|
||||||
|
openstack.cloud.server:
|
||||||
|
name: "{{ target_name }}"
|
||||||
|
state: absent
|
||||||
|
region_name: "{{ OS_REGION_NAME }}"
|
||||||
|
environment:
|
||||||
|
OS_AUTH_URL: "{{ OS_AUTH_URL }}"
|
||||||
|
OS_USERNAME: "{{ OS_USERNAME }}"
|
||||||
|
OS_PASSWORD: "{{ OS_PASSWORD }}"
|
||||||
|
OS_USER_DOMAIN_NAME: "{{ OS_USER_DOMAIN_NAME }}"
|
||||||
|
register: openstack_output
|
||||||
|
|
||||||
|
- name: Find {{ target_name }} volumes
|
||||||
|
openstack.cloud.volume_info:
|
||||||
|
register: volumes_info
|
||||||
|
environment:
|
||||||
|
OS_AUTH_URL: "{{ OS_AUTH_URL }}"
|
||||||
|
OS_USERNAME: "{{ OS_USERNAME }}"
|
||||||
|
OS_PASSWORD: "{{ OS_PASSWORD }}"
|
||||||
|
OS_USER_DOMAIN_NAME: "{{ OS_USER_DOMAIN_NAME }}"
|
||||||
|
OS_REGION_NAME: "{{ OS_REGION_NAME }}"
|
||||||
|
|
||||||
|
- name: remove {{ target_name }} volumes
|
||||||
|
openstack.cloud.volume:
|
||||||
|
state: absent
|
||||||
|
name: "{{ item }}"
|
||||||
|
with_items: "{{ volumes_info.volumes|json_query('[].[name]') }}"
|
||||||
|
when: item is search('^' ~ target_name.split('.')[0] ~ '-')
|
||||||
|
environment:
|
||||||
|
OS_AUTH_URL: "{{ OS_AUTH_URL }}"
|
||||||
|
OS_USERNAME: "{{ OS_USERNAME }}"
|
||||||
|
OS_PASSWORD: "{{ OS_PASSWORD }}"
|
||||||
|
OS_USER_DOMAIN_NAME: "{{ OS_USER_DOMAIN_NAME }}"
|
||||||
|
OS_REGION_NAME: "{{ OS_REGION_NAME }}"
|
||||||
|
|
||||||
|
- name: install ovh python module
|
||||||
|
ansible.builtin.pip:
|
||||||
|
name:
|
||||||
|
- ovh
|
||||||
|
|
||||||
|
- name: Remove A server record
|
||||||
|
ovh_dns:
|
||||||
|
state: absent
|
||||||
|
domain: "{{ DOMAIN }}"
|
||||||
|
name: "{{ target_name.split('.')[0] }}"
|
||||||
|
type: A
|
||||||
|
environment:
|
||||||
|
OVH_ENDPOINT: ovh-eu
|
||||||
|
OVH_APPLICATION_KEY: "{{ OVH_APPLICATION_KEY }}"
|
||||||
|
OVH_APPLICATION_SECRET: "{{ OVH_APPLICATION_SECRET }}"
|
||||||
|
OVH_CONSUMER_KEY: "{{ OVH_DNS_CONSUMER_KEY }}"
|
||||||
|
|
2
roles/role_delete_openstack_instance/tests/inventory
Normal file
2
roles/role_delete_openstack_instance/tests/inventory
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
localhost
|
||||||
|
|
5
roles/role_delete_openstack_instance/tests/test.yml
Normal file
5
roles/role_delete_openstack_instance/tests/test.yml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
- hosts: localhost
|
||||||
|
remote_user: root
|
||||||
|
roles:
|
||||||
|
- role_delete_openstack_instance
|
2
roles/role_delete_openstack_instance/vars/main.yml
Normal file
2
roles/role_delete_openstack_instance/vars/main.yml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
# vars file for role_delete_openstack_instance
|
38
roles/role_deploy_nextcloud/README.md
Normal file
38
roles/role_deploy_nextcloud/README.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
Role Name
|
||||||
|
=========
|
||||||
|
|
||||||
|
A brief description of the role goes here.
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
|
||||||
|
Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
|
||||||
|
|
||||||
|
Role Variables
|
||||||
|
--------------
|
||||||
|
|
||||||
|
A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
|
||||||
|
|
||||||
|
Dependencies
|
||||||
|
------------
|
||||||
|
|
||||||
|
A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
|
||||||
|
|
||||||
|
Example Playbook
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
|
||||||
|
|
||||||
|
- hosts: servers
|
||||||
|
roles:
|
||||||
|
- { role: username.rolename, x: 42 }
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
|
||||||
|
BSD
|
||||||
|
|
||||||
|
Author Information
|
||||||
|
------------------
|
||||||
|
|
||||||
|
An optional section for the role authors to include contact information, or a website (HTML is not allowed).
|
2
roles/role_deploy_nextcloud/defaults/main.yml
Normal file
2
roles/role_deploy_nextcloud/defaults/main.yml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
# defaults file for role_deploy_nextcloud
|
2
roles/role_deploy_nextcloud/handlers/main.yml
Normal file
2
roles/role_deploy_nextcloud/handlers/main.yml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
# handlers file for role_deploy_nextcloud
|
52
roles/role_deploy_nextcloud/meta/main.yml
Normal file
52
roles/role_deploy_nextcloud/meta/main.yml
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
galaxy_info:
|
||||||
|
author: your name
|
||||||
|
description: your role description
|
||||||
|
company: your company (optional)
|
||||||
|
|
||||||
|
# If the issue tracker for your role is not on github, uncomment the
|
||||||
|
# next line and provide a value
|
||||||
|
# issue_tracker_url: http://example.com/issue/tracker
|
||||||
|
|
||||||
|
# Choose a valid license ID from https://spdx.org - some suggested licenses:
|
||||||
|
# - BSD-3-Clause (default)
|
||||||
|
# - MIT
|
||||||
|
# - GPL-2.0-or-later
|
||||||
|
# - GPL-3.0-only
|
||||||
|
# - Apache-2.0
|
||||||
|
# - CC-BY-4.0
|
||||||
|
license: license (GPL-2.0-or-later, MIT, etc)
|
||||||
|
|
||||||
|
min_ansible_version: 2.1
|
||||||
|
|
||||||
|
# If this a Container Enabled role, provide the minimum Ansible Container version.
|
||||||
|
# min_ansible_container_version:
|
||||||
|
|
||||||
|
#
|
||||||
|
# Provide a list of supported platforms, and for each platform a list of versions.
|
||||||
|
# If you don't wish to enumerate all versions for a particular platform, use 'all'.
|
||||||
|
# To view available platforms and versions (or releases), visit:
|
||||||
|
# https://galaxy.ansible.com/api/v1/platforms/
|
||||||
|
#
|
||||||
|
# platforms:
|
||||||
|
# - name: Fedora
|
||||||
|
# versions:
|
||||||
|
# - all
|
||||||
|
# - 25
|
||||||
|
# - name: SomePlatform
|
||||||
|
# versions:
|
||||||
|
# - all
|
||||||
|
# - 1.0
|
||||||
|
# - 7
|
||||||
|
# - 99.99
|
||||||
|
|
||||||
|
galaxy_tags: []
|
||||||
|
# List tags for your role here, one per line. A tag is a keyword that describes
|
||||||
|
# and categorizes the role. Users find roles by searching for tags. Be sure to
|
||||||
|
# remove the '[]' above, if you add tags to this list.
|
||||||
|
#
|
||||||
|
# NOTE: A tag is limited to a single word comprised of alphanumeric characters.
|
||||||
|
# Maximum 20 tags per role.
|
||||||
|
|
||||||
|
dependencies: []
|
||||||
|
# List your role dependencies here, one per line. Be sure to remove the '[]' above,
|
||||||
|
# if you add dependencies to this list.
|
64
roles/role_deploy_nextcloud/tasks/main.yml
Normal file
64
roles/role_deploy_nextcloud/tasks/main.yml
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
---
|
||||||
|
- name: Setup volume
|
||||||
|
ansible.builtin.include_tasks: "tasks/setup_volume.yml"
|
||||||
|
with_items:
|
||||||
|
- name: nextcloud
|
||||||
|
size: 10
|
||||||
|
vol_type: high-speed
|
||||||
|
|
||||||
|
- name: change ownership of duplicity working directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
owner: "{{ LINUX_USERNAME }}"
|
||||||
|
group: "{{ LINUX_USERNAME }}"
|
||||||
|
become: true
|
||||||
|
with_items:
|
||||||
|
- "{{ DUPLICITY_WORKDIR }}"
|
||||||
|
- "{{ DUPLICITY_ARCHIVE_DIR }}"
|
||||||
|
|
||||||
|
- name: restore volume backup
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "duplicity restore --file-to-restore {{ item }}.tar.gz --do-not-restore-ownership --archive-dir {{ DUPLICITY_ARCHIVE_DIR }} swift://backup_ovh1 {{ DUPLICITY_WORKDIR }}/{{ item }}.tar.gz"
|
||||||
|
environment:
|
||||||
|
SWIFT_USERNAME: "{{ OS_USERNAME }}"
|
||||||
|
SWIFT_PASSWORD: "{{ OS_PASSWORD }}"
|
||||||
|
SWIFT_AUTHURL: "{{ OS_AUTH_URL }}"
|
||||||
|
SWIFT_REGIONNAME: "{{ SWIFT_REGIONNAME }}"
|
||||||
|
SWIFT_TENANTNAME: "{{ OS_TENANT_NAME }}"
|
||||||
|
SWIFT_AUTHVERSION: "{{ OS_IDENTITY_API_VERSION }}"
|
||||||
|
PASSPHRASE: "{{ DUPLICITY_PASSPHRASE}}"
|
||||||
|
# /usr/bin/duplicity uses "-s" python argument to prevent loading modules from user's python directory,
|
||||||
|
# this variable will override that.
|
||||||
|
PYTHONPATH: ".local/lib/python3.9/site-packages"
|
||||||
|
register: duplicity_result
|
||||||
|
with_items:
|
||||||
|
- nextcloud
|
||||||
|
failed_when: duplicity_result is failed and (duplicity_result.rc is not defined or duplicity_result.rc != 11)
|
||||||
|
changed_when: duplicity_result.rc is defined and duplicity_result.rc == 0
|
||||||
|
|
||||||
|
- name: Unarchive volume backup
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "tar -xzvf {{ DUPLICITY_WORKDIR }}/{{ item }}.tar.gz -C /mnt/volumes/{{ item }}/data --strip 2"
|
||||||
|
become: true
|
||||||
|
with_items:
|
||||||
|
- nextcloud
|
||||||
|
|
||||||
|
- name: Create nextcloud container
|
||||||
|
containers.podman.podman_container:
|
||||||
|
name: nextcloud-full
|
||||||
|
image: docker.io/nextcloud:18.0.3
|
||||||
|
network:
|
||||||
|
- reverse-proxy
|
||||||
|
- mysqlnet
|
||||||
|
- mailnet
|
||||||
|
volume:
|
||||||
|
- /mnt/volumes/nextcloud/data:/var/www/html:Z
|
||||||
|
- ./supervisord.conf:/supervisord.conf
|
||||||
|
- ./run_elasticsearch.sh:/run_elasticsearch.sh
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Add cloud.{{ DOMAIN }} to /etc/hosts
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: "/etc/hosts"
|
||||||
|
line: "{{ ansible_host }} cloud.{{ DOMAIN }} cloud"
|
||||||
|
become: true
|
2
roles/role_deploy_nextcloud/tests/inventory
Normal file
2
roles/role_deploy_nextcloud/tests/inventory
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
localhost
|
||||||
|
|
5
roles/role_deploy_nextcloud/tests/test.yml
Normal file
5
roles/role_deploy_nextcloud/tests/test.yml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
- hosts: localhost
|
||||||
|
remote_user: root
|
||||||
|
roles:
|
||||||
|
- role_deploy_nextcloud
|
2
roles/role_deploy_nextcloud/vars/main.yml
Normal file
2
roles/role_deploy_nextcloud/vars/main.yml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
# vars file for role_deploy_nextcloud
|
38
roles/role_deploy_openstack_instance/README.md
Normal file
38
roles/role_deploy_openstack_instance/README.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
Role Name
|
||||||
|
=========
|
||||||
|
|
||||||
|
A brief description of the role goes here.
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
|
||||||
|
Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
|
||||||
|
|
||||||
|
Role Variables
|
||||||
|
--------------
|
||||||
|
|
||||||
|
A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
|
||||||
|
|
||||||
|
Dependencies
|
||||||
|
------------
|
||||||
|
|
||||||
|
A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
|
||||||
|
|
||||||
|
Example Playbook
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
|
||||||
|
|
||||||
|
- hosts: servers
|
||||||
|
roles:
|
||||||
|
- { role: username.rolename, x: 42 }
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
|
||||||
|
BSD
|
||||||
|
|
||||||
|
Author Information
|
||||||
|
------------------
|
||||||
|
|
||||||
|
An optional section for the role authors to include contact information, or a website (HTML is not allowed).
|
2
roles/role_deploy_openstack_instance/defaults/main.yml
Normal file
2
roles/role_deploy_openstack_instance/defaults/main.yml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
# defaults file for role_deploy_openstack_instance
|
2
roles/role_deploy_openstack_instance/handlers/main.yml
Normal file
2
roles/role_deploy_openstack_instance/handlers/main.yml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
# handlers file for role_deploy_openstack_instance
|
52
roles/role_deploy_openstack_instance/meta/main.yml
Normal file
52
roles/role_deploy_openstack_instance/meta/main.yml
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
galaxy_info:
|
||||||
|
author: your name
|
||||||
|
description: your role description
|
||||||
|
company: your company (optional)
|
||||||
|
|
||||||
|
# If the issue tracker for your role is not on github, uncomment the
|
||||||
|
# next line and provide a value
|
||||||
|
# issue_tracker_url: http://example.com/issue/tracker
|
||||||
|
|
||||||
|
# Choose a valid license ID from https://spdx.org - some suggested licenses:
|
||||||
|
# - BSD-3-Clause (default)
|
||||||
|
# - MIT
|
||||||
|
# - GPL-2.0-or-later
|
||||||
|
# - GPL-3.0-only
|
||||||
|
# - Apache-2.0
|
||||||
|
# - CC-BY-4.0
|
||||||
|
license: license (GPL-2.0-or-later, MIT, etc)
|
||||||
|
|
||||||
|
min_ansible_version: 2.1
|
||||||
|
|
||||||
|
# If this a Container Enabled role, provide the minimum Ansible Container version.
|
||||||
|
# min_ansible_container_version:
|
||||||
|
|
||||||
|
#
|
||||||
|
# Provide a list of supported platforms, and for each platform a list of versions.
|
||||||
|
# If you don't wish to enumerate all versions for a particular platform, use 'all'.
|
||||||
|
# To view available platforms and versions (or releases), visit:
|
||||||
|
# https://galaxy.ansible.com/api/v1/platforms/
|
||||||
|
#
|
||||||
|
# platforms:
|
||||||
|
# - name: Fedora
|
||||||
|
# versions:
|
||||||
|
# - all
|
||||||
|
# - 25
|
||||||
|
# - name: SomePlatform
|
||||||
|
# versions:
|
||||||
|
# - all
|
||||||
|
# - 1.0
|
||||||
|
# - 7
|
||||||
|
# - 99.99
|
||||||
|
|
||||||
|
galaxy_tags: []
|
||||||
|
# List tags for your role here, one per line. A tag is a keyword that describes
|
||||||
|
# and categorizes the role. Users find roles by searching for tags. Be sure to
|
||||||
|
# remove the '[]' above, if you add tags to this list.
|
||||||
|
#
|
||||||
|
# NOTE: A tag is limited to a single word comprised of alphanumeric characters.
|
||||||
|
# Maximum 20 tags per role.
|
||||||
|
|
||||||
|
dependencies: []
|
||||||
|
# List your role dependencies here, one per line. Be sure to remove the '[]' above,
|
||||||
|
# if you add dependencies to this list.
|
70
roles/role_deploy_openstack_instance/tasks/main.yml
Normal file
70
roles/role_deploy_openstack_instance/tasks/main.yml
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
---
|
||||||
|
# tasks file for role_deploy_openstack_instance
|
||||||
|
- name: install openstack
|
||||||
|
ansible.builtin.package:
|
||||||
|
name:
|
||||||
|
- python3-openstacksdk
|
||||||
|
state: latest
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: create SSH keypair
|
||||||
|
openstack.cloud.keypair:
|
||||||
|
name: "{{ OS_KEY_NAME }}"
|
||||||
|
public_key_file: "{{ PUBLIC_KEY_FILE }}"
|
||||||
|
state: present
|
||||||
|
environment:
|
||||||
|
OS_AUTH_URL: "{{ OS_AUTH_URL }}"
|
||||||
|
OS_USERNAME: "{{ OS_USERNAME }}"
|
||||||
|
OS_PASSWORD: "{{ OS_PASSWORD }}"
|
||||||
|
OS_USER_DOMAIN_NAME: "{{ OS_USER_DOMAIN_NAME }}"
|
||||||
|
|
||||||
|
- name: create instance
|
||||||
|
openstack.cloud.server:
|
||||||
|
name: "{{ target_name }}"
|
||||||
|
state: present
|
||||||
|
region_name: "{{ OS_REGION_NAME }}"
|
||||||
|
image: "{{ OS_IMAGE }}"
|
||||||
|
flavor: "{{ OS_FLAVOR }}"
|
||||||
|
key_name: "{{ OS_KEY_NAME }}"
|
||||||
|
timeout: 300
|
||||||
|
environment:
|
||||||
|
OS_AUTH_URL: "{{ OS_AUTH_URL }}"
|
||||||
|
OS_USERNAME: "{{ OS_USERNAME }}"
|
||||||
|
OS_PASSWORD: "{{ OS_PASSWORD }}"
|
||||||
|
OS_USER_DOMAIN_NAME: "{{ OS_USER_DOMAIN_NAME }}"
|
||||||
|
register: openstack_output
|
||||||
|
|
||||||
|
- debug: var=openstack_output.openstack.accessIPv4
|
||||||
|
|
||||||
|
- name: install ovh python module
|
||||||
|
ansible.builtin.pip:
|
||||||
|
name:
|
||||||
|
- ovh
|
||||||
|
|
||||||
|
- name: Create A server record
|
||||||
|
ovh_dns:
|
||||||
|
state: present
|
||||||
|
domain: "{{ DOMAIN }}"
|
||||||
|
name: "{{ target_name.split('.')[0] }}"
|
||||||
|
type: A
|
||||||
|
value: "{{ openstack_output.openstack.accessIPv4 }}"
|
||||||
|
environment:
|
||||||
|
OVH_ENDPOINT: ovh-eu
|
||||||
|
OVH_APPLICATION_KEY: "{{ OVH_APPLICATION_KEY }}"
|
||||||
|
OVH_APPLICATION_SECRET: "{{ OVH_APPLICATION_SECRET }}"
|
||||||
|
OVH_CONSUMER_KEY: "{{ OVH_DNS_CONSUMER_KEY }}"
|
||||||
|
|
||||||
|
- name: Create PTR server record
|
||||||
|
ovh_reverse:
|
||||||
|
state: present
|
||||||
|
reverse: "{{ target_name }}."
|
||||||
|
ip: "{{ openstack_output.openstack.accessIPv4 }}"
|
||||||
|
environment:
|
||||||
|
OVH_ENDPOINT: ovh-eu
|
||||||
|
OVH_APPLICATION_KEY: "{{ OVH_APPLICATION_KEY }}"
|
||||||
|
OVH_APPLICATION_SECRET: "{{ OVH_APPLICATION_SECRET }}"
|
||||||
|
OVH_CONSUMER_KEY: "{{ OVH_DNS_CONSUMER_KEY }}"
|
||||||
|
register: ovh_reverse_output
|
||||||
|
until: "ovh_reverse_output is not failed"
|
||||||
|
retries: 10
|
||||||
|
delay: 10
|
2
roles/role_deploy_openstack_instance/tests/inventory
Normal file
2
roles/role_deploy_openstack_instance/tests/inventory
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
localhost
|
||||||
|
|
5
roles/role_deploy_openstack_instance/tests/test.yml
Normal file
5
roles/role_deploy_openstack_instance/tests/test.yml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
- hosts: localhost
|
||||||
|
remote_user: root
|
||||||
|
roles:
|
||||||
|
- role_deploy_openstack_instance
|
2
roles/role_deploy_openstack_instance/vars/main.yml
Normal file
2
roles/role_deploy_openstack_instance/vars/main.yml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
# vars file for role_deploy_openstack_instance
|
38
roles/role_get_ovh_consumer_key/README.md
Normal file
38
roles/role_get_ovh_consumer_key/README.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
Role Name
|
||||||
|
=========
|
||||||
|
|
||||||
|
A brief description of the role goes here.
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
|
||||||
|
Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
|
||||||
|
|
||||||
|
Role Variables
|
||||||
|
--------------
|
||||||
|
|
||||||
|
A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
|
||||||
|
|
||||||
|
Dependencies
|
||||||
|
------------
|
||||||
|
|
||||||
|
A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
|
||||||
|
|
||||||
|
Example Playbook
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
|
||||||
|
|
||||||
|
- hosts: servers
|
||||||
|
roles:
|
||||||
|
- { role: username.rolename, x: 42 }
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
|
||||||
|
BSD
|
||||||
|
|
||||||
|
Author Information
|
||||||
|
------------------
|
||||||
|
|
||||||
|
An optional section for the role authors to include contact information, or a website (HTML is not allowed).
|
2
roles/role_get_ovh_consumer_key/defaults/main.yml
Normal file
2
roles/role_get_ovh_consumer_key/defaults/main.yml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
# defaults file for role_get_ovh_consumer_key
|
@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import ovh
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if "OVH_APPLICATION_KEY" not in os.environ:
|
||||||
|
print("ERROR: missing environment variable OVH_APPLICATION_KEY.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if "OVH_APPLICATION_SECRET" not in os.environ:
|
||||||
|
print("ERROR: missing environment variable OVH_APPLICATION_SECRET.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
client = ovh.Client('ovh-eu', os.environ["OVH_APPLICATION_KEY"], os.environ["OVH_APPLICATION_SECRET"])
|
||||||
|
access_rules = [
|
||||||
|
{'method': 'GET', 'path': '/domain/*'},
|
||||||
|
{'method': 'POST', 'path': '/domain/*'},
|
||||||
|
{'method': 'PUT', 'path': '/domain/*'},
|
||||||
|
{'method': 'DELETE', 'path': '/domain/*'},
|
||||||
|
{'method': 'GET', 'path': '/ip/*'},
|
||||||
|
{'method': 'POST', 'path': '/ip/*'},
|
||||||
|
{'method': 'DELETE', 'path': '/ip/*'}
|
||||||
|
]
|
||||||
|
print(client.request_consumerkey(access_rules))
|
2
roles/role_get_ovh_consumer_key/handlers/main.yml
Normal file
2
roles/role_get_ovh_consumer_key/handlers/main.yml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
# handlers file for role_get_ovh_consumer_key
|
52
roles/role_get_ovh_consumer_key/meta/main.yml
Normal file
52
roles/role_get_ovh_consumer_key/meta/main.yml
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
galaxy_info:
|
||||||
|
author: your name
|
||||||
|
description: your role description
|
||||||
|
company: your company (optional)
|
||||||
|
|
||||||
|
# If the issue tracker for your role is not on github, uncomment the
|
||||||
|
# next line and provide a value
|
||||||
|
# issue_tracker_url: http://example.com/issue/tracker
|
||||||
|
|
||||||
|
# Choose a valid license ID from https://spdx.org - some suggested licenses:
|
||||||
|
# - BSD-3-Clause (default)
|
||||||
|
# - MIT
|
||||||
|
# - GPL-2.0-or-later
|
||||||
|
# - GPL-3.0-only
|
||||||
|
# - Apache-2.0
|
||||||
|
# - CC-BY-4.0
|
||||||
|
license: license (GPL-2.0-or-later, MIT, etc)
|
||||||
|
|
||||||
|
min_ansible_version: 2.1
|
||||||
|
|
||||||
|
# If this a Container Enabled role, provide the minimum Ansible Container version.
|
||||||
|
# min_ansible_container_version:
|
||||||
|
|
||||||
|
#
|
||||||
|
# Provide a list of supported platforms, and for each platform a list of versions.
|
||||||
|
# If you don't wish to enumerate all versions for a particular platform, use 'all'.
|
||||||
|
# To view available platforms and versions (or releases), visit:
|
||||||
|
# https://galaxy.ansible.com/api/v1/platforms/
|
||||||
|
#
|
||||||
|
# platforms:
|
||||||
|
# - name: Fedora
|
||||||
|
# versions:
|
||||||
|
# - all
|
||||||
|
# - 25
|
||||||
|
# - name: SomePlatform
|
||||||
|
# versions:
|
||||||
|
# - all
|
||||||
|
# - 1.0
|
||||||
|
# - 7
|
||||||
|
# - 99.99
|
||||||
|
|
||||||
|
galaxy_tags: []
|
||||||
|
# List tags for your role here, one per line. A tag is a keyword that describes
|
||||||
|
# and categorizes the role. Users find roles by searching for tags. Be sure to
|
||||||
|
# remove the '[]' above, if you add tags to this list.
|
||||||
|
#
|
||||||
|
# NOTE: A tag is limited to a single word comprised of alphanumeric characters.
|
||||||
|
# Maximum 20 tags per role.
|
||||||
|
|
||||||
|
dependencies: []
|
||||||
|
# List your role dependencies here, one per line. Be sure to remove the '[]' above,
|
||||||
|
# if you add dependencies to this list.
|
16
roles/role_get_ovh_consumer_key/tasks/main.yml
Normal file
16
roles/role_get_ovh_consumer_key/tasks/main.yml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
# tasks file for role_get_ovh_consumer_key
|
||||||
|
- name: install ovh python module
|
||||||
|
ansible.builtin.pip:
|
||||||
|
name:
|
||||||
|
- ovh
|
||||||
|
|
||||||
|
- name: Get OVH consumer key and manual validation URL
|
||||||
|
ansible.builtin.script: get_OVH_consumer_key.py
|
||||||
|
register: get_OVH_consumer_key
|
||||||
|
environment:
|
||||||
|
OVH_APPLICATION_KEY: "{{ OVH_APPLICATION_KEY }}"
|
||||||
|
OVH_APPLICATION_SECRET: "{{ OVH_APPLICATION_SECRET }}"
|
||||||
|
|
||||||
|
- debug: var=get_OVH_consumer_key
|
||||||
|
|
2
roles/role_get_ovh_consumer_key/tests/inventory
Normal file
2
roles/role_get_ovh_consumer_key/tests/inventory
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
localhost
|
||||||
|
|
5
roles/role_get_ovh_consumer_key/tests/test.yml
Normal file
5
roles/role_get_ovh_consumer_key/tests/test.yml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
- hosts: localhost
|
||||||
|
remote_user: root
|
||||||
|
roles:
|
||||||
|
- role_get_ovh_consumer_key
|
2
roles/role_get_ovh_consumer_key/vars/main.yml
Normal file
2
roles/role_get_ovh_consumer_key/vars/main.yml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
# vars file for role_get_ovh_consumer_key
|
66
tasks/deploy_gogs.yml
Normal file
66
tasks/deploy_gogs.yml
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
---
|
||||||
|
- name: Setup volume
|
||||||
|
ansible.builtin.include_role:
|
||||||
|
name: role_setup_volume
|
||||||
|
vars:
|
||||||
|
volume: "{{ item }}"
|
||||||
|
with_items:
|
||||||
|
- name: gogs_data
|
||||||
|
size: 1
|
||||||
|
vol_type: classic
|
||||||
|
|
||||||
|
- name: change ownership of duplicity working directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
owner: "{{ LINUX_USERNAME }}"
|
||||||
|
group: "{{ LINUX_USERNAME }}"
|
||||||
|
become: true
|
||||||
|
with_items:
|
||||||
|
- "{{ DUPLICITY_WORKDIR }}"
|
||||||
|
- "{{ DUPLICITY_ARCHIVE_DIR }}"
|
||||||
|
|
||||||
|
- name: restore volume backup
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "duplicity restore --file-to-restore {{ item }}.tar.gz --do-not-restore-ownership --archive-dir {{ DUPLICITY_ARCHIVE_DIR }} swift://backup_ovh1 {{ DUPLICITY_WORKDIR }}/{{ item }}.tar.gz"
|
||||||
|
environment:
|
||||||
|
SWIFT_USERNAME: "{{ OS_USERNAME }}"
|
||||||
|
SWIFT_PASSWORD: "{{ OS_PASSWORD }}"
|
||||||
|
SWIFT_AUTHURL: "{{ OS_AUTH_URL }}"
|
||||||
|
SWIFT_REGIONNAME: "{{ SWIFT_REGIONNAME }}"
|
||||||
|
SWIFT_TENANTNAME: "{{ OS_TENANT_NAME }}"
|
||||||
|
SWIFT_AUTHVERSION: "{{ OS_IDENTITY_API_VERSION }}"
|
||||||
|
PASSPHRASE: "{{ DUPLICITY_PASSPHRASE}}"
|
||||||
|
# /usr/bin/duplicity uses "-s" python argument to prevent loading modules from user's python directory,
|
||||||
|
# this variable will override that.
|
||||||
|
PYTHONPATH: ".local/lib/python3.9/site-packages"
|
||||||
|
register: duplicity_result
|
||||||
|
with_items:
|
||||||
|
- gogs_data
|
||||||
|
failed_when: duplicity_result is failed and (duplicity_result.rc is not defined or duplicity_result.rc != 11)
|
||||||
|
changed_when: duplicity_result.rc is defined and duplicity_result.rc == 0
|
||||||
|
|
||||||
|
- name: Unarchive volume backup
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "tar -xzvf {{ DUPLICITY_WORKDIR }}/{{ item }}.tar.gz -C /mnt/volumes/{{ item }}/data --strip 2"
|
||||||
|
become: true
|
||||||
|
with_items:
|
||||||
|
- gogs_data
|
||||||
|
|
||||||
|
- name: Create gogs container
|
||||||
|
containers.podman.podman_container:
|
||||||
|
name: gogs
|
||||||
|
image: docker.io/gogs/gogs:0.12.3
|
||||||
|
network:
|
||||||
|
- reverse-proxy
|
||||||
|
- mysqlnet
|
||||||
|
ports:
|
||||||
|
- 2222:22/tcp
|
||||||
|
volume:
|
||||||
|
- /mnt/volumes/gogs_data/data:/data:Z
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Add git.{{ DOMAIN }} to /etc/hosts
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: "/etc/hosts"
|
||||||
|
line: "{{ ansible_host }} git.{{ DOMAIN }} git"
|
||||||
|
become: true
|
55
tasks/deploy_mysql-server.yml
Normal file
55
tasks/deploy_mysql-server.yml
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
---
|
||||||
|
- name: Check if install from backup is already done
|
||||||
|
stat:
|
||||||
|
path: /mnt/volumes/install_states/mysql_installed
|
||||||
|
register: mysql_installed_flag
|
||||||
|
|
||||||
|
- name: Include tasks/mysql-server_install_from_backup_stage_1.yml
|
||||||
|
ansible.builtin.include_tasks: "tasks/mysql-server_install_from_backup_stage_1.yml"
|
||||||
|
when: not mysql_installed_flag.stat.exists
|
||||||
|
|
||||||
|
- name: Get docker-mysql repo's last commit
|
||||||
|
ansible.builtin.git:
|
||||||
|
repo: https://github.com/yohan-b/docker-mysql.git
|
||||||
|
clone: no
|
||||||
|
update: no
|
||||||
|
version: master
|
||||||
|
register: git
|
||||||
|
|
||||||
|
- name: Set fact commit
|
||||||
|
set_fact:
|
||||||
|
commit: "{{ git.after[0:10] }}"
|
||||||
|
|
||||||
|
- name: Build mysql-server image
|
||||||
|
containers.podman.podman_image:
|
||||||
|
name: mysql-server
|
||||||
|
path: https://github.com/yohan-b/docker-mysql.git
|
||||||
|
force: true
|
||||||
|
build:
|
||||||
|
force_rm: true
|
||||||
|
annotation:
|
||||||
|
git_commit: "{{ commit }}"
|
||||||
|
become: true
|
||||||
|
register: image
|
||||||
|
|
||||||
|
- name: Include tasks/mysql-server_install_from_backup_stage_2.yml
|
||||||
|
ansible.builtin.include_tasks: "tasks/mysql-server_install_from_backup_stage_2.yml"
|
||||||
|
when: not mysql_installed_flag.stat.exists
|
||||||
|
|
||||||
|
- name: Create mysql-server container
|
||||||
|
containers.podman.podman_container:
|
||||||
|
name: mysql-server
|
||||||
|
image: mysql-server
|
||||||
|
recreate: "{{ image is changed }}"
|
||||||
|
network:
|
||||||
|
- mysqlnet
|
||||||
|
volume:
|
||||||
|
- /mnt/volumes/mysql-server_data/data:/var/lib/mysql:z
|
||||||
|
- /mnt/volumes/mysql-server_dumps/data:/mnt/dumps:z
|
||||||
|
- /mnt/volumes/mysql-server_scripts:/mnt/mysql-server_scripts:z
|
||||||
|
- /usr/local/docker-mounted-files/docker-mysql-server-stack/debian.cnf:/etc/mysql/debian.cnf:z
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Include tasks/mysql-server_install_from_backup_stage_3.yml
|
||||||
|
ansible.builtin.include_tasks: "tasks/mysql-server_install_from_backup_stage_3.yml"
|
||||||
|
when: not mysql_installed_flag.stat.exists
|
106
tasks/deploy_reverse-proxy.yml
Normal file
106
tasks/deploy_reverse-proxy.yml
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
---
|
||||||
|
# tasks file for role_deploy_reverse-proxy
|
||||||
|
- name: Create reverse-proxy network
|
||||||
|
containers.podman.podman_network:
|
||||||
|
name: reverse-proxy
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Setup volume
|
||||||
|
ansible.builtin.include_tasks: "tasks/setup_volume.yml"
|
||||||
|
with_items:
|
||||||
|
- name: reverse-proxy_conf
|
||||||
|
size: 1
|
||||||
|
vol_type: classic
|
||||||
|
- name: reverse-proxy_conf_enabled
|
||||||
|
size: 1
|
||||||
|
vol_type: classic
|
||||||
|
- name: reverse-proxy_letsencrypt
|
||||||
|
size: 1
|
||||||
|
vol_type: classic
|
||||||
|
- name: tmp_duplicity_workdir
|
||||||
|
size: 20
|
||||||
|
vol_type: high-speed
|
||||||
|
- name: duplicity_cache
|
||||||
|
size: 5
|
||||||
|
vol_type: high-speed
|
||||||
|
|
||||||
|
- name: change ownership of duplicity working directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
owner: "{{ LINUX_USERNAME }}"
|
||||||
|
group: "{{ LINUX_USERNAME }}"
|
||||||
|
become: true
|
||||||
|
with_items:
|
||||||
|
- "{{ DUPLICITY_WORKDIR }}"
|
||||||
|
- "{{ DUPLICITY_ARCHIVE_DIR }}"
|
||||||
|
|
||||||
|
- name: restore volume backup
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "duplicity restore --file-to-restore {{ item }}.tar.gz --do-not-restore-ownership --archive-dir {{ DUPLICITY_ARCHIVE_DIR }} swift://backup_ovh1 {{ DUPLICITY_WORKDIR }}/{{ item }}.tar.gz"
|
||||||
|
environment:
|
||||||
|
SWIFT_USERNAME: "{{ OS_USERNAME }}"
|
||||||
|
SWIFT_PASSWORD: "{{ OS_PASSWORD }}"
|
||||||
|
SWIFT_AUTHURL: "{{ OS_AUTH_URL }}"
|
||||||
|
SWIFT_REGIONNAME: "{{ SWIFT_REGIONNAME }}"
|
||||||
|
SWIFT_TENANTNAME: "{{ OS_TENANT_NAME }}"
|
||||||
|
SWIFT_AUTHVERSION: "{{ OS_IDENTITY_API_VERSION }}"
|
||||||
|
PASSPHRASE: "{{ DUPLICITY_PASSPHRASE}}"
|
||||||
|
# /usr/bin/duplicity uses "-s" python argument to prevent loading modules from user's python directory,
|
||||||
|
# this variable will override that.
|
||||||
|
PYTHONPATH: ".local/lib/python3.9/site-packages"
|
||||||
|
register: duplicity_result
|
||||||
|
with_items:
|
||||||
|
- reverse-proxy_conf
|
||||||
|
- reverse-proxy_conf_enabled
|
||||||
|
- reverse-proxy_letsencrypt
|
||||||
|
failed_when: duplicity_result is failed and (duplicity_result.rc is not defined or duplicity_result.rc != 11)
|
||||||
|
changed_when: duplicity_result.rc is defined and duplicity_result.rc == 0
|
||||||
|
|
||||||
|
- name: Unarchive volume backup
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "tar -xzvf {{ DUPLICITY_WORKDIR }}/{{ item }}.tar.gz -C /mnt/volumes/{{ item }}/data --strip 2"
|
||||||
|
become: true
|
||||||
|
with_items:
|
||||||
|
- reverse-proxy_conf
|
||||||
|
- reverse-proxy_conf_enabled
|
||||||
|
- reverse-proxy_letsencrypt
|
||||||
|
|
||||||
|
- name: Get docker-reverse-proxy repo's last commit
|
||||||
|
ansible.builtin.git:
|
||||||
|
repo: https://github.com/yohan-b/docker-reverse-proxy.git
|
||||||
|
clone: no
|
||||||
|
update: no
|
||||||
|
version: master
|
||||||
|
register: git
|
||||||
|
|
||||||
|
- name: Set fact commit
|
||||||
|
set_fact:
|
||||||
|
commit: "{{ git.after[0:10] }}"
|
||||||
|
|
||||||
|
- name: Build reverse-proxy image
|
||||||
|
containers.podman.podman_image:
|
||||||
|
name: reverse-proxy
|
||||||
|
path: https://github.com/yohan-b/docker-reverse-proxy.git
|
||||||
|
force: true
|
||||||
|
build:
|
||||||
|
force_rm: true
|
||||||
|
annotation:
|
||||||
|
git_commit: "{{ commit }}"
|
||||||
|
become: true
|
||||||
|
register: image
|
||||||
|
|
||||||
|
- name: Create reverse-proxy container
|
||||||
|
containers.podman.podman_container:
|
||||||
|
name: reverse-proxy
|
||||||
|
image: reverse-proxy
|
||||||
|
recreate: "{{ image is changed }}"
|
||||||
|
network:
|
||||||
|
- reverse-proxy
|
||||||
|
ports:
|
||||||
|
- 80:80/tcp
|
||||||
|
- 443:443/tcp
|
||||||
|
volume:
|
||||||
|
- /mnt/volumes/reverse-proxy_conf/data:/etc/apache2/sites-available:Z
|
||||||
|
- /mnt/volumes/reverse-proxy_conf_enabled/data:/etc/apache2/sites-enabled:Z
|
||||||
|
- /mnt/volumes/reverse-proxy_letsencrypt/data:/etc/letsencrypt:Z
|
||||||
|
become: true
|
86
tasks/mysql-server_install_from_backup_stage_1.yml
Normal file
86
tasks/mysql-server_install_from_backup_stage_1.yml
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
---
|
||||||
|
- name: Create mysqlnet network
|
||||||
|
containers.podman.podman_network:
|
||||||
|
name: mysqlnet
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Create /usr/local/docker-mounted-files/docker-mysql-server-stack directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "/usr/local/docker-mounted-files/docker-mysql-server-stack"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: set remote workdir path
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
remote_workdir: /home/{{ ansible_user_id }}/.tmp_deploy_ovh
|
||||||
|
|
||||||
|
- name: Extract from secrets.tar.gz.enc
|
||||||
|
shell: "openssl enc -aes-256-cbc -md md5 -pass env:SECRETS_ARCHIVE_PASSPHRASE -d -in {{ remote_workdir }}/secrets.tar.gz.enc | tar -zxv -C {{ item.dir }} --strip 2 {{ item.name }}"
|
||||||
|
with_items:
|
||||||
|
- name: secrets/docker-mysql-stack/debian.cnf
|
||||||
|
dir: "/usr/local/docker-mounted-files/docker-mysql-server-stack"
|
||||||
|
environment:
|
||||||
|
SECRETS_ARCHIVE_PASSPHRASE: "{{ lookup('env', 'SECRETS_ARCHIVE_PASSPHRASE') }}"
|
||||||
|
become: true
|
||||||
|
|
||||||
|
# A local volume is needed where other stacks will be able to copy scripts like Nextcloud's nettoyer_quotas.sh
|
||||||
|
- name: Create /mnt/volumes/mysql-server_scripts directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "/mnt/volumes/mysql-server_scripts"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Setup volume
|
||||||
|
ansible.builtin.include_tasks: "tasks/setup_volume.yml"
|
||||||
|
with_items:
|
||||||
|
- name: mysql-server_data
|
||||||
|
size: 2
|
||||||
|
vol_type: classic
|
||||||
|
- name: mysql-server_dumps
|
||||||
|
size: 10
|
||||||
|
vol_type: classic
|
||||||
|
- name: tmp_duplicity_workdir
|
||||||
|
size: 20
|
||||||
|
vol_type: high-speed
|
||||||
|
- name: duplicity_cache
|
||||||
|
size: 5
|
||||||
|
vol_type: high-speed
|
||||||
|
|
||||||
|
- name: change ownership of duplicity working directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
owner: "{{ LINUX_USERNAME }}"
|
||||||
|
group: "{{ LINUX_USERNAME }}"
|
||||||
|
become: true
|
||||||
|
with_items:
|
||||||
|
- "{{ DUPLICITY_WORKDIR }}"
|
||||||
|
- "{{ DUPLICITY_ARCHIVE_DIR }}"
|
||||||
|
|
||||||
|
- name: restore volume backup
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "duplicity restore --file-to-restore {{ item }}.tar.gz --do-not-restore-ownership --archive-dir {{ DUPLICITY_ARCHIVE_DIR }} swift://backup_ovh1 {{ DUPLICITY_WORKDIR }}/{{ item }}.tar.gz"
|
||||||
|
environment:
|
||||||
|
SWIFT_USERNAME: "{{ OS_USERNAME }}"
|
||||||
|
SWIFT_PASSWORD: "{{ OS_PASSWORD }}"
|
||||||
|
SWIFT_AUTHURL: "{{ OS_AUTH_URL }}"
|
||||||
|
SWIFT_REGIONNAME: "{{ SWIFT_REGIONNAME }}"
|
||||||
|
SWIFT_TENANTNAME: "{{ OS_TENANT_NAME }}"
|
||||||
|
SWIFT_AUTHVERSION: "{{ OS_IDENTITY_API_VERSION }}"
|
||||||
|
PASSPHRASE: "{{ DUPLICITY_PASSPHRASE}}"
|
||||||
|
# /usr/bin/duplicity uses "-s" python argument to prevent loading modules from user's python directory,
|
||||||
|
# this variable will override that.
|
||||||
|
PYTHONPATH: ".local/lib/python3.9/site-packages"
|
||||||
|
register: duplicity_result
|
||||||
|
with_items:
|
||||||
|
- mysql-server_dumps
|
||||||
|
failed_when: duplicity_result is failed and (duplicity_result.rc is not defined or duplicity_result.rc != 11)
|
||||||
|
changed_when: duplicity_result.rc is defined and duplicity_result.rc == 0
|
||||||
|
|
||||||
|
- name: Unarchive volume backup
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "tar -xzvf {{ DUPLICITY_WORKDIR }}/{{ item }}.tar.gz -C /mnt/volumes/{{ item }}/data --strip 2"
|
||||||
|
become: true
|
||||||
|
with_items:
|
||||||
|
- mysql-server_dumps
|
24
tasks/mysql-server_install_from_backup_stage_2.yml
Normal file
24
tasks/mysql-server_install_from_backup_stage_2.yml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
- name: Check if mysql-server container exists
|
||||||
|
containers.podman.podman_container_info:
|
||||||
|
name: mysql-server
|
||||||
|
register: mysql_server_podman_info
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Assert that no mysql-server container already exists
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- mysql_server_podman_info.containers | length == 0
|
||||||
|
|
||||||
|
- name: Populate mysql-server_data volume
|
||||||
|
containers.podman.podman_container:
|
||||||
|
name: mysql-server-populate
|
||||||
|
image: mysql-server
|
||||||
|
recreate: "{{ image is changed }}"
|
||||||
|
auto_remove: true
|
||||||
|
volume:
|
||||||
|
- /mnt/volumes/mysql-server_data/data:/mnt/mysql:z
|
||||||
|
- /usr/local/docker-mounted-files/docker-mysql-server-stack/debian.cnf:/etc/mysql/debian.cnf:z
|
||||||
|
entrypoint: '["/bin/rsync", "-itrlpgovDH", "--delete-before", "/var/lib/mysql/", "/mnt/mysql/"]'
|
||||||
|
become: true
|
||||||
|
|
63
tasks/mysql-server_install_from_backup_stage_3.yml
Normal file
63
tasks/mysql-server_install_from_backup_stage_3.yml
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
---
|
||||||
|
- name: Find lastest MySQL DB dump
|
||||||
|
ansible.builtin.shell: "ls -tr /mnt/volumes/mysql-server_dumps/data/mysql_dump-mysql_* | xargs basename"
|
||||||
|
register: MySQL_dump
|
||||||
|
|
||||||
|
- name: Find lastest applications DB dump
|
||||||
|
ansible.builtin.shell: "ls -tr /mnt/volumes/mysql-server_dumps/data/mysql_dump_* | xargs basename"
|
||||||
|
register: DBs_dump
|
||||||
|
|
||||||
|
# https://dba.stackexchange.com/questions/266480/mariadb-mysql-all-db-import-table-user-already-exists
|
||||||
|
- name: Fix MySQL dump file
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: "/mnt/volumes/mysql-server_dumps/data/{{ MySQL_dump.stdout_lines | last }}"
|
||||||
|
line: "{{ item }}"
|
||||||
|
insertafter: '^USE `mysql`;'
|
||||||
|
firstmatch: true
|
||||||
|
become: true
|
||||||
|
with_items:
|
||||||
|
- "DROP TABLE IF EXISTS `mysql`.`global_priv`;"
|
||||||
|
- "DROP VIEW IF EXISTS `mysql`.`user`;"
|
||||||
|
|
||||||
|
- name: Restore database
|
||||||
|
containers.podman.podman_container_exec:
|
||||||
|
name: mysql-server
|
||||||
|
command: "bash -c 'mysql -u root -p{{ mysql_root_ovh1.password }} < /mnt/dumps/{{ item }}'"
|
||||||
|
become: true
|
||||||
|
with_items:
|
||||||
|
- "{{ MySQL_dump.stdout_lines | last }}"
|
||||||
|
- "{{ DBs_dump.stdout_lines | last }}"
|
||||||
|
|
||||||
|
- name: Restore database
|
||||||
|
containers.podman.podman_container_exec:
|
||||||
|
name: mysql-server
|
||||||
|
command: 'bash -c ''echo "FLUSH PRIVILEGES;" | mysql -u root -p{{ mysql_root_ovh1.password }}'''
|
||||||
|
become: true
|
||||||
|
|
||||||
|
#- name: Restore database
|
||||||
|
# community.mysql.mysql_db:
|
||||||
|
# name: all
|
||||||
|
# state: import
|
||||||
|
# target: "/mnt/volumes/mysql-server_dumps/data/{{ item }}"
|
||||||
|
# login_user: "root"
|
||||||
|
# login_password: "{{ mysql_root_ovh1.password }}"
|
||||||
|
# become: true
|
||||||
|
# with_items:
|
||||||
|
# - "{{ MySQL_dump.stdout_lines | last }}"
|
||||||
|
# - "{{ DBs_dump.stdout_lines | last }}"
|
||||||
|
|
||||||
|
# A local volume is needed to store install states
|
||||||
|
- name: Create /mnt/volumes/install_states directory if it does not exist
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "/mnt/volumes/install_states"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Create mysql_installed state file
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "/mnt/volumes/install_states/mysql_installed"
|
||||||
|
state: touch
|
||||||
|
mode: '0755'
|
||||||
|
become: true
|
||||||
|
|
135
tasks/retrieve_secret_vars.yml
Normal file
135
tasks/retrieve_secret_vars.yml
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
---
|
||||||
|
- name: get local machine-id
|
||||||
|
command: cat /etc/machine-id
|
||||||
|
register: get_local_machine_id_output
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: set local machine-id
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
local_system_uuid: "{{ get_local_machine_id_output.stdout }}"
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: get remote machine-id
|
||||||
|
command: cat /etc/machine-id
|
||||||
|
register: get_remote_machine_id_output
|
||||||
|
|
||||||
|
- name: set remote machine-id
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
remote_system_uuid: "{{ get_remote_machine_id_output.stdout }}"
|
||||||
|
|
||||||
|
- name: set remote workdir path
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
remote_workdir: /home/{{ ansible_user_id }}/.tmp_deploy_ovh
|
||||||
|
|
||||||
|
- name: set local workdir path
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
local_workdir: /home/{{ lookup('env', 'USER') }}/.tmp_deploy_ovh
|
||||||
|
|
||||||
|
- name: create remote workdir
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ remote_workdir }}"
|
||||||
|
state: directory
|
||||||
|
|
||||||
|
- name: create local workdir
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ local_workdir }}"
|
||||||
|
state: directory
|
||||||
|
delegate_to: localhost
|
||||||
|
when: local_system_uuid != remote_system_uuid
|
||||||
|
|
||||||
|
- name: Find secret files
|
||||||
|
ansible.builtin.find:
|
||||||
|
paths: "/mnt/archives_critiques/secrets"
|
||||||
|
patterns: 'secrets.tar.gz.enc-*'
|
||||||
|
register: find_secret_files_output
|
||||||
|
remote_user: "{{ LINUX_USERNAME }}"
|
||||||
|
vars:
|
||||||
|
ansible_ssh_port: "{{ SECRET_SSH_PORT }}"
|
||||||
|
delegate_to: "{{ SECRET_HOST }}"
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Fetch secrets
|
||||||
|
ansible.builtin.fetch:
|
||||||
|
src: "{{ (find_secret_files_output.files | sort(attribute='mtime') | last).path }}"
|
||||||
|
dest: "{{ local_workdir }}/secrets.tar.gz.enc"
|
||||||
|
flat: yes
|
||||||
|
remote_user: "{{ LINUX_USERNAME }}"
|
||||||
|
vars:
|
||||||
|
ansible_ssh_port: "{{ SECRET_SSH_PORT }}"
|
||||||
|
delegate_to: "{{ SECRET_HOST }}"
|
||||||
|
when: find_secret_files_output.files | length > 0
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Check local secrets.tar.gz.enc status
|
||||||
|
stat:
|
||||||
|
path: "{{ local_workdir }}/secrets.tar.gz.enc"
|
||||||
|
register: local_stat_result
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: Assert that local secrets.tar.gz.enc exists
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- local_stat_result.stat.exists
|
||||||
|
fail_msg: "ERROR: Could not auto-retrieve secrets.tar.gz.enc. Please copy it in {{ local_workdir }} on Ansible controller and restart the playbook."
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: Copy secrets to remote server
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "{{ local_workdir }}/secrets.tar.gz.enc"
|
||||||
|
dest: "{{ remote_workdir }}/secrets.tar.gz.enc"
|
||||||
|
when: local_system_uuid != remote_system_uuid
|
||||||
|
|
||||||
|
- name: Extract from secrets.tar.gz.enc
|
||||||
|
shell: "openssl enc -aes-256-cbc -md md5 -pass env:SECRETS_ARCHIVE_PASSPHRASE -d -in {{ remote_workdir }}/secrets.tar.gz.enc | tar -zxv -C {{ item.dir }} --strip 2 {{ item.name }}"
|
||||||
|
with_items:
|
||||||
|
- name: secrets/bootstrap/id_rsa
|
||||||
|
dir: "{{ remote_workdir }}"
|
||||||
|
- name: secrets/bootstrap/openrc.sh
|
||||||
|
dir: "{{ remote_workdir }}"
|
||||||
|
- name: secrets/bootstrap/OVH_APPLICATION.yml
|
||||||
|
dir: "{{ remote_workdir }}"
|
||||||
|
- name: secrets/bootstrap/duplicity_passphrase
|
||||||
|
dir: "{{ remote_workdir }}"
|
||||||
|
environment:
|
||||||
|
SECRETS_ARCHIVE_PASSPHRASE: "{{ lookup('env', 'SECRETS_ARCHIVE_PASSPHRASE') }}"
|
||||||
|
|
||||||
|
- name: Extract secrets.yml from secrets.tar.gz.enc
|
||||||
|
shell: "openssl enc -aes-256-cbc -md md5 -pass env:SECRETS_ARCHIVE_PASSPHRASE -d -in {{ remote_workdir }}/secrets.tar.gz.enc | tar -zxv -C {{ item.dir }} --strip 1 {{ item.name }}"
|
||||||
|
with_items:
|
||||||
|
- name: secrets/secrets.yml
|
||||||
|
dir: "{{ remote_workdir }}"
|
||||||
|
environment:
|
||||||
|
SECRETS_ARCHIVE_PASSPHRASE: "{{ lookup('env', 'SECRETS_ARCHIVE_PASSPHRASE') }}"
|
||||||
|
|
||||||
|
- name: Set OpenStack credentials
|
||||||
|
ansible.builtin.include_tasks: "tasks/source_vars.yml"
|
||||||
|
with_items:
|
||||||
|
- OS_AUTH_URL
|
||||||
|
- OS_IDENTITY_API_VERSION
|
||||||
|
- OS_USER_DOMAIN_NAME
|
||||||
|
- OS_PROJECT_DOMAIN_NAME
|
||||||
|
- OS_TENANT_ID
|
||||||
|
- OS_TENANT_NAME
|
||||||
|
- OS_USERNAME
|
||||||
|
- OS_PASSWORD
|
||||||
|
- OS_REGION_NAME
|
||||||
|
vars:
|
||||||
|
shell_script: "{{ remote_workdir }}/openrc.sh"
|
||||||
|
#
|
||||||
|
#- name: download bootstrap
|
||||||
|
# ansible.builtin.command:
|
||||||
|
# cmd: duplicity restore swift://bootstrap {{ workdir }}
|
||||||
|
# environment:
|
||||||
|
# SWIFT_USERNAME: "{{ OS_USERNAME }}"
|
||||||
|
# SWIFT_PASSWORD: "{{ OS_PASSWORD }}"
|
||||||
|
# SWIFT_AUTHURL: "{{ OS_AUTH_URL }}"
|
||||||
|
# SWIFT_REGIONNAME: "{{ SWIFT_REGIONNAME }}"
|
||||||
|
# SWIFT_TENANTNAME: "{{ OS_TENANT_NAME }}"
|
||||||
|
# SWIFT_AUTHVERSION: "{{ OS_IDENTITY_API_VERSION }}"
|
||||||
|
# PASSPHRASE: "{{ DUPLICITY_PASSPHRASE}}"
|
||||||
|
# # /usr/bin/duplicity uses "-s" python argument to prevent loading modules from user's python directory,
|
||||||
|
# # this variable will override that.
|
||||||
|
# PYTHONPATH: ".local/lib/python3.9/site-packages"
|
||||||
|
#
|
||||||
|
|
||||||
|
|
63
tasks/setup_volume.yml
Normal file
63
tasks/setup_volume.yml
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
---
|
||||||
|
- name: Create /mnt/volumes/{{ item.name }} directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "/mnt/volumes/{{ item.name }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Create {{ item.name }} volume
|
||||||
|
openstack.cloud.volume:
|
||||||
|
state: present
|
||||||
|
size: "{{ item.size }}"
|
||||||
|
volume_type: "{{ item.vol_type }}"
|
||||||
|
name: "{{ target_name.split('.')[0] }}-{{ item.name }}"
|
||||||
|
environment:
|
||||||
|
OS_AUTH_URL: "{{ OS_AUTH_URL }}"
|
||||||
|
OS_IDENTITY_API_VERSION: "{{ OS_IDENTITY_API_VERSION }}"
|
||||||
|
OS_USER_DOMAIN_NAME: "{{ OS_USER_DOMAIN_NAME }}"
|
||||||
|
OS_PROJECT_DOMAIN_NAME: "{{ OS_PROJECT_DOMAIN_NAME }}"
|
||||||
|
OS_TENANT_ID: "{{ OS_TENANT_ID }}"
|
||||||
|
OS_TENANT_NAME: "{{ OS_TENANT_NAME }}"
|
||||||
|
OS_USERNAME: "{{ OS_USERNAME }}"
|
||||||
|
OS_PASSWORD: "{{ OS_PASSWORD }}"
|
||||||
|
OS_REGION_NAME: "{{ OS_REGION_NAME }}"
|
||||||
|
|
||||||
|
- name: Attach {{ item.name }} volume to instance
|
||||||
|
openstack.cloud.server_volume:
|
||||||
|
state: present
|
||||||
|
server: "{{ target_name }}"
|
||||||
|
volume: "{{ target_name.split('.')[0] }}-{{ item.name }}"
|
||||||
|
environment:
|
||||||
|
OS_AUTH_URL: "{{ OS_AUTH_URL }}"
|
||||||
|
OS_IDENTITY_API_VERSION: "{{ OS_IDENTITY_API_VERSION }}"
|
||||||
|
OS_USER_DOMAIN_NAME: "{{ OS_USER_DOMAIN_NAME }}"
|
||||||
|
OS_PROJECT_DOMAIN_NAME: "{{ OS_PROJECT_DOMAIN_NAME }}"
|
||||||
|
OS_TENANT_ID: "{{ OS_TENANT_ID }}"
|
||||||
|
OS_TENANT_NAME: "{{ OS_TENANT_NAME }}"
|
||||||
|
OS_USERNAME: "{{ OS_USERNAME }}"
|
||||||
|
OS_PASSWORD: "{{ OS_PASSWORD }}"
|
||||||
|
OS_REGION_NAME: "{{ OS_REGION_NAME }}"
|
||||||
|
register: volume_output
|
||||||
|
|
||||||
|
- name: Create a ext4 filesystem on {{ item.name }} volume
|
||||||
|
community.general.filesystem:
|
||||||
|
fstype: ext4
|
||||||
|
dev: "{{ volume_output.attachments[0].device }}"
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: mount /mnt/volumes/{{ item.name }}
|
||||||
|
ansible.posix.mount:
|
||||||
|
path: "/mnt/volumes/{{ item.name }}"
|
||||||
|
src: "{{ volume_output.attachments[0].device }}"
|
||||||
|
fstype: ext4
|
||||||
|
state: mounted
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Create /mnt/volumes/{{ item.name }}/data directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "/mnt/volumes/{{ item.name }}/data"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
become: true
|
||||||
|
|
10
tasks/source_vars.yml
Normal file
10
tasks/source_vars.yml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
- name: Register variable {{ item }}
|
||||||
|
shell: . {{ shell_script }} && echo ${{ item }}
|
||||||
|
register: output_var
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Set variable {{ item }}
|
||||||
|
set_fact:
|
||||||
|
"{{ item }}": "{{ output_var.stdout }}"
|
||||||
|
changed_when: false
|
17
vars/main.yml
Normal file
17
vars/main.yml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
DOMAIN: "{{ target_name[target_name.index('.') + 1:] }}"
|
||||||
|
|
||||||
|
OS_IMAGE: Rocky Linux 9
|
||||||
|
OS_FLAVOR: b2-7
|
||||||
|
OS_KEY_NAME: "{{ DOMAIN.split('.')[0] }}"
|
||||||
|
|
||||||
|
SWIFT_REGIONNAME: "GRA"
|
||||||
|
|
||||||
|
LINUX_USERNAME: "yohan"
|
||||||
|
|
||||||
|
PUBLIC_KEY_FILE: "/home/{{ LINUX_USERNAME }}/.ssh/id_rsa.pub"
|
||||||
|
|
||||||
|
DUPLICITY_WORKDIR: /mnt/volumes/tmp_duplicity_workdir/data
|
||||||
|
DUPLICITY_ARCHIVE_DIR: /mnt/volumes/duplicity_cache/data
|
||||||
|
|
||||||
|
SECRET_SSH_PORT: 2224
|
Loading…
Reference in New Issue
Block a user