Initial commit.

This commit is contained in:
yohan 2024-03-22 21:46:39 +01:00
commit c9a33ad40c
62 changed files with 2367 additions and 0 deletions

10
README.md Normal file
View 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
View 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
View File

@ -0,0 +1,3 @@
[defaults]
inventory = inventory.yml
host_key_checking = accept-new

View 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
View 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
View 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
View File

@ -0,0 +1,4 @@
target:
vars:
ansible_user: rocky

352
library/ovh_dns.py Normal file
View 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
View 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
View File

@ -0,0 +1,3 @@
---
- name : role_setup_volume
src : git@git.scimetis.net:2222/yohan/role_setup_volume.git

View 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).

View File

@ -0,0 +1,2 @@
---
# defaults file for role_configure_ovh_instance

View File

@ -0,0 +1,6 @@
[DEFAULT]
# Ban hosts for one hour:
bantime = 3600
[sshd]
enabled = true

View File

@ -0,0 +1,2 @@
---
# handlers file for role_configure_ovh_instance

View 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.

View 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 }}"

View File

@ -0,0 +1,2 @@
localhost

View File

@ -0,0 +1,5 @@
---
- hosts: localhost
remote_user: root
roles:
- role_configure_ovh_instance

View File

@ -0,0 +1,2 @@
---
# vars file for role_configure_ovh_instance

View 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).

View File

@ -0,0 +1,2 @@
---
# defaults file for role_delete_openstack_instance

View File

@ -0,0 +1,2 @@
---
# handlers file for role_delete_openstack_instance

View 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.

View 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 }}"

View File

@ -0,0 +1,2 @@
localhost

View File

@ -0,0 +1,5 @@
---
- hosts: localhost
remote_user: root
roles:
- role_delete_openstack_instance

View File

@ -0,0 +1,2 @@
---
# vars file for role_delete_openstack_instance

View 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).

View File

@ -0,0 +1,2 @@
---
# defaults file for role_deploy_nextcloud

View File

@ -0,0 +1,2 @@
---
# handlers file for role_deploy_nextcloud

View 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.

View 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

View File

@ -0,0 +1,2 @@
localhost

View File

@ -0,0 +1,5 @@
---
- hosts: localhost
remote_user: root
roles:
- role_deploy_nextcloud

View File

@ -0,0 +1,2 @@
---
# vars file for role_deploy_nextcloud

View 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).

View File

@ -0,0 +1,2 @@
---
# defaults file for role_deploy_openstack_instance

View File

@ -0,0 +1,2 @@
---
# handlers file for role_deploy_openstack_instance

View 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.

View 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

View File

@ -0,0 +1,2 @@
localhost

View File

@ -0,0 +1,5 @@
---
- hosts: localhost
remote_user: root
roles:
- role_deploy_openstack_instance

View File

@ -0,0 +1,2 @@
---
# vars file for role_deploy_openstack_instance

View 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).

View File

@ -0,0 +1,2 @@
---
# defaults file for role_get_ovh_consumer_key

View File

@ -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))

View File

@ -0,0 +1,2 @@
---
# handlers file for role_get_ovh_consumer_key

View 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.

View 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

View File

@ -0,0 +1,2 @@
localhost

View File

@ -0,0 +1,5 @@
---
- hosts: localhost
remote_user: root
roles:
- role_get_ovh_consumer_key

View File

@ -0,0 +1,2 @@
---
# vars file for role_get_ovh_consumer_key

66
tasks/deploy_gogs.yml Normal file
View 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

View 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

View 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

View 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

View 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

View 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

View 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
View 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
View 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
View 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