feat(role: common): add common roles
This commit is contained in:
parent
95fea75d4c
commit
69cac4d4be
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
|
||||
root_password_hashed: "{{ vault_root_password_hashed }}"
|
||||
user_password_hashed: "{{ vault_root_user_hashed }}"
|
||||
user_ssh_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDl05rLhOKK4M2pqp7xRbKzIYlnkLRvp61NLrP2E0fiU l01@L01"
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
$ANSIBLE_VAULT;1.1;AES256
|
||||
36346637303464633032623363643762663630363863323565623263343931393834306138666463
|
||||
3934336362316235323039616435653764323936613338340a616434656434303138646637663962
|
||||
34363762333634393863653634316638303865373632396231623734303239356365626661363832
|
||||
3039613031346637630a626464396530326237326338376166393663356538313731653639373661
|
||||
38373061313337323938656165343965633732626335653739656464343431343364326362333038
|
||||
39323834633434343062303962366531643734363235326564303538613161373161383364343539
|
||||
64646336316538613535613464623631653730316365323539396533343731356263323632383233
|
||||
62393262653637616239643834316166316432383230373232386131313866326237663265383130
|
||||
61623736393261656437346236666664393365666637366531636563303933663832396163326366
|
||||
39656164396462666634303732396439636462626366313663663766303632353266633139343939
|
||||
61336236366334336536626161353330646533663265353161643538336434623834663064323565
|
||||
33376534323330616238376562623763346565303237366639663133656562623762303961333062
|
||||
30626630383232656636363131343135626432613638623664336232376266623936633436613735
|
||||
31373033616163313239656465356632343536356637623336393965376565356338323365323862
|
||||
35653362376537396636303337306663306235653661353831616337346562643963643935653735
|
||||
63663263326466626365393634373133313239303337633766386238613634633337666536663332
|
||||
38326438363361323830356632363863636332333039353865363032613133613062323763303565
|
||||
3630663937633964666135323666326530633266353232346337
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
#### YAML inventory file
|
||||
|
||||
# the two first lines above are needed for the script
|
||||
# to identify the file as an inventory file
|
||||
|
||||
## Structure
|
||||
# hosts:
|
||||
# - host: <HOSTNAME>
|
||||
# # if needed
|
||||
# hostvars:
|
||||
# key: value
|
||||
# # if needed
|
||||
# groups:
|
||||
# - group1
|
||||
# - group2
|
||||
|
||||
hosts:
|
||||
- host: 192.168.3.2
|
||||
groups:
|
||||
- nginx
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
|
||||
- name: Gather facts
|
||||
hosts: all
|
||||
gather_facts: true
|
||||
tags:
|
||||
- always
|
||||
|
||||
- name: Common
|
||||
hosts: all
|
||||
roles:
|
||||
- common
|
||||
tags:
|
||||
- common
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
|
||||
- name: Base
|
||||
import_playbooks: base.yml
|
||||
|
||||
#- name: Nginx
|
||||
# import_playbooks: nginx.yml
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
|
||||
collections:
|
||||
- name: ansible.utils
|
||||
version: 2.9.0
|
||||
- name: community.crypto
|
||||
version: 2.10.0
|
||||
- name: community.general
|
||||
version: 3.4.0
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
|
||||
- name: Packages
|
||||
ansible.builtin.import_tasks: packages.yml
|
||||
|
||||
- name: Service account
|
||||
ansible.builtin.import_tasks: user.yml
|
||||
|
||||
- name: Root password
|
||||
ansible.builtin.import_tasks: password.yml
|
||||
|
||||
- name: Timezone
|
||||
ansible.builtin.import_tasks: timezone.yml
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
|
||||
- name: Install aptitude
|
||||
ansible.builtin.apt:
|
||||
name: aptitude
|
||||
update_cache: true
|
||||
force_apt_get: true
|
||||
|
||||
- name: Install common packages
|
||||
ansible.builtin.apt:
|
||||
install_recommends: false
|
||||
update_cache: true
|
||||
state: present
|
||||
name:
|
||||
- bash
|
||||
- curl
|
||||
- file
|
||||
- git
|
||||
- htop
|
||||
- iftop
|
||||
- iotop
|
||||
- ldnsutils
|
||||
- lsof
|
||||
- man
|
||||
- molly-guard
|
||||
- rsync
|
||||
- sudo
|
||||
- tcpdump
|
||||
- tmux
|
||||
- traceroute
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
|
||||
- name: Set root password
|
||||
ansible.builtin.user:
|
||||
name: root
|
||||
password: "{{ root_password_hashed }}"
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
|
||||
- name: Set timezone to Europe/Paris
|
||||
community.general.timezone:
|
||||
name: Europe/Paris
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
|
||||
- name: Add service account ansible
|
||||
ansible.builtin.user:
|
||||
name: ansible
|
||||
state: present
|
||||
shell: /bin/bash
|
||||
groups: sudo
|
||||
append: yes
|
||||
password: "{{ user_password_hashed }}"
|
||||
|
||||
- name: Add ssh key to the user ansible
|
||||
authorized_key:
|
||||
user: ansible
|
||||
state: present
|
||||
key: "{{ ssh_key }}"
|
||||
|
|
@ -0,0 +1,327 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import logging
|
||||
import os
|
||||
import argparse
|
||||
import yaml
|
||||
import json
|
||||
import re
|
||||
import copy
|
||||
import textwrap
|
||||
|
||||
"""
|
||||
Project repo
|
||||
https://github.com/leboncoin/simple-ansible-inventory
|
||||
|
||||
For further details about Ansible best practices including directory layout, see
|
||||
https://docs.ansible.com/ansible/2.5/user_guide/playbooks_best_practices.html
|
||||
|
||||
For further details about developing Ansible inventory, see
|
||||
http://docs.ansible.com/ansible/latest/dev_guide/developing_inventory.html
|
||||
"""
|
||||
|
||||
INVENTORY_SCRIPT_NAME = "SimpleAnsibleInventory"
|
||||
INVENTORY_SCRIPT_VERSION = 1.0
|
||||
LOGGER = None
|
||||
INVENTORY_FILE_REGEX_PATTERN = ".*\.y[a]?ml"
|
||||
INVENTORY_FILE_HEADER_SIZE = 28
|
||||
INVENTORY_FILE_HEADER = "---\n#### YAML inventory file"
|
||||
INVENTORY_FILE_ENV_VAR = "ANSIBLE_YAML_INVENTORY"
|
||||
ACCEPTED_REGEX = r"\[(?:(?:[\d]+-[\d]+|[\d]+)+,?)+\]"
|
||||
|
||||
|
||||
def build_meta_header(host, meta_header):
|
||||
"""
|
||||
Progressively build the meta header host by host
|
||||
|
||||
:param host: current host to add to meta header
|
||||
:type host: dict
|
||||
:param meta_header: meta header to build
|
||||
:type meta_header: dict
|
||||
:return:
|
||||
"""
|
||||
# If found host doesn't exists in dict, we create it
|
||||
if host['host'] not in meta_header['hostvars']:
|
||||
meta_header['hostvars'][host['host']] = dict()
|
||||
# Browsing and adding all vars found for host
|
||||
if 'hostvars' in host:
|
||||
for hostvar in host['hostvars']:
|
||||
meta_header['hostvars'][host['host']][hostvar] = \
|
||||
host['hostvars'][hostvar]
|
||||
# Return new meta_header version containing new host
|
||||
return meta_header
|
||||
|
||||
|
||||
def build_groups(host, partial_inventory):
|
||||
"""
|
||||
Progressively build groups conf host by host
|
||||
|
||||
:param host: current host to add to meta header
|
||||
:type host: dict
|
||||
:param partial_inventory: Only contains _meta header
|
||||
:type partial_inventory: dict
|
||||
:return: filled inventory
|
||||
"""
|
||||
# check if 'all' group exists, if no, create it
|
||||
if 'all' not in partial_inventory:
|
||||
partial_inventory['all'] = dict()
|
||||
partial_inventory['all']['hosts'] = list()
|
||||
partial_inventory['all']['vars'] = dict()
|
||||
partial_inventory['all']['children'] = list()
|
||||
# If groups section doesn't exists return inventory without modification
|
||||
if 'groups' not in host:
|
||||
return partial_inventory
|
||||
# For each group of the host
|
||||
for group in host['groups']:
|
||||
# If groups doesn't already exists, creating it
|
||||
if group not in partial_inventory:
|
||||
partial_inventory[group] = dict()
|
||||
partial_inventory[group]['hosts'] = list()
|
||||
partial_inventory[group]['vars'] = dict()
|
||||
partial_inventory[group]['children'] = list()
|
||||
# add group to 'all' group if not already in
|
||||
if group not in partial_inventory['all']['children']:
|
||||
partial_inventory['all']['children'].append(group)
|
||||
partial_inventory[group]['hosts'].append(host['host'])
|
||||
return partial_inventory
|
||||
|
||||
|
||||
def get_int_interval(from_int, to_int):
|
||||
"""
|
||||
Return a list of all integers between two integers
|
||||
|
||||
:param from_int: start from
|
||||
:type from_int: int
|
||||
:param to_int: end at
|
||||
:type to_int: int
|
||||
:return: list(int)
|
||||
"""
|
||||
LOGGER.debug("Calculating int interval between " + str(from_int) +
|
||||
" and " + str(to_int))
|
||||
return [str(value) for value in range(from_int, to_int + 1)]
|
||||
|
||||
|
||||
def all_string_from_pattern(input_string, matching_part):
|
||||
"""
|
||||
Return a list of all string matching the input string containing a pattern
|
||||
|
||||
:param input_string: input string containing pattern
|
||||
:type input_string: str
|
||||
:param matching_part: pattern extracted from hostname
|
||||
:type matching_part: str
|
||||
:return: str
|
||||
"""
|
||||
# Transform matched pattern to a list of ranges
|
||||
regex_found = matching_part.group(0).replace("[", "").replace("]", "").split(',')
|
||||
possibilities = list()
|
||||
# let's fill all ranges
|
||||
for pattern in regex_found:
|
||||
split_range = pattern.split('-')
|
||||
int_1 = int(split_range[0])
|
||||
int_possibilities = [int_1]
|
||||
if len(split_range) == 2:
|
||||
int_1 = min(int_1, int(split_range[1]))
|
||||
int_2 = max(int(split_range[0]), int(split_range[1]))
|
||||
int_possibilities = get_int_interval(int_1, int_2)
|
||||
LOGGER.debug("Possibilities: " + str(int_possibilities))
|
||||
for possibility in int_possibilities:
|
||||
possibilities.append(
|
||||
input_string[:matching_part.start(0)] +
|
||||
str(possibility) +
|
||||
input_string[matching_part.end(0):]
|
||||
)
|
||||
return possibilities
|
||||
|
||||
|
||||
def patterning_hosts(regex_found, host, filled_pattern_host_list):
|
||||
"""
|
||||
Function used recursively to fill all patterns in hostname
|
||||
|
||||
:param regex_found: re.match object
|
||||
:type regex_found: re.match()
|
||||
:param host: host read in conf
|
||||
:type host: dict
|
||||
:param filled_pattern_host_list: list containing all hosts
|
||||
with all patterns filled
|
||||
:type filled_pattern_host_list: list
|
||||
:return:
|
||||
"""
|
||||
LOGGER.debug("Processing regex " + str(regex_found.group(0)) +
|
||||
" found in host name: " + host['host'])
|
||||
# For each hostname possibility with first pattern
|
||||
for patterned_host in all_string_from_pattern(host['host'], regex_found):
|
||||
# Checking if there is still another pattern left in hostname
|
||||
regex_found = re.search(ACCEPTED_REGEX, patterned_host)
|
||||
# build a new host with the hostname
|
||||
new_host = dict(host)
|
||||
new_host['host'] = patterned_host
|
||||
# If hostname still containing pattern, call itself
|
||||
if regex_found:
|
||||
patterning_hosts(regex_found, new_host, filled_pattern_host_list)
|
||||
# If no pattern left, append host to list
|
||||
else:
|
||||
filled_pattern_host_list.append(new_host)
|
||||
|
||||
|
||||
def get_inventory_recursively(raw_conf):
|
||||
"""
|
||||
Build and return the inventory
|
||||
|
||||
:param raw_conf: Raw configuration loaded from yml configuration file
|
||||
:type raw_conf: dict
|
||||
:return: dict
|
||||
"""
|
||||
LOGGER.debug("Building full inventory from loaded YAML(s)")
|
||||
inventory = dict()
|
||||
meta_header = dict()
|
||||
meta_header['hostvars'] = dict()
|
||||
# Browsing all hosts
|
||||
for host in raw_conf['hosts']:
|
||||
LOGGER.debug("Processing host entry " + str(host))
|
||||
filled_pattern_host_list = list()
|
||||
regex_found = re.search(ACCEPTED_REGEX, host['host'])
|
||||
# If no regex pattern, directly add the host
|
||||
if not regex_found:
|
||||
filled_pattern_host_list.append(host)
|
||||
# Else fill all patterns
|
||||
else:
|
||||
patterning_hosts(regex_found, host, filled_pattern_host_list)
|
||||
LOGGER.debug("Host(s) generated from this host entry: " +
|
||||
str([hn['host'] for hn in filled_pattern_host_list]))
|
||||
for filled_pattern_host in filled_pattern_host_list:
|
||||
# Complete meta header for each host
|
||||
meta_header = build_meta_header(filled_pattern_host, meta_header)
|
||||
inventory = build_groups(filled_pattern_host, inventory)
|
||||
inventory['_meta'] = meta_header
|
||||
return inventory
|
||||
|
||||
|
||||
def find_inventory_files():
|
||||
"""
|
||||
find the inventory file in sub folders
|
||||
|
||||
:return: string
|
||||
"""
|
||||
if INVENTORY_FILE_ENV_VAR in os.environ:
|
||||
LOGGER.debug("env VAR " + INVENTORY_FILE_ENV_VAR + " found")
|
||||
return [os.environ[INVENTORY_FILE_ENV_VAR]]
|
||||
inventory_files = list()
|
||||
LOGGER.debug("Looking for inventory files")
|
||||
# script py path
|
||||
script_path = os.path.realpath(__file__)
|
||||
inventories_path = os.path.dirname(script_path)
|
||||
# walking through script folder looking for yaml files
|
||||
for root, dirnames, filenames in os.walk(inventories_path):
|
||||
LOGGER.debug("All files found: " + str(filenames))
|
||||
for file in [f for f in filenames if re.search(INVENTORY_FILE_REGEX_PATTERN, f)]:
|
||||
# if file beginning match header
|
||||
with open(os.path.join(root, file), 'r') as fd:
|
||||
if fd.read(INVENTORY_FILE_HEADER_SIZE) == INVENTORY_FILE_HEADER:
|
||||
inventory_files.append(os.path.join(root, file))
|
||||
return inventory_files
|
||||
|
||||
|
||||
def list_all_hosts():
|
||||
"""
|
||||
Build the dictionary containing all hosts
|
||||
|
||||
:return: dict
|
||||
"""
|
||||
LOGGER.debug("listing all hosts")
|
||||
raw_confs_list = list()
|
||||
# Load all configuration files
|
||||
inventory_files = find_inventory_files()
|
||||
LOGGER.debug("Inventory files found: " + str(inventory_files))
|
||||
# If no inventory files found, return empty inventory
|
||||
if not len(inventory_files):
|
||||
return {"_meta": {"hostvars": {}}, "all": {"children": ["ungrouped"]}}
|
||||
for inventory_file in inventory_files:
|
||||
with open(inventory_file, 'r') as fd:
|
||||
LOGGER.debug("Loading file: " + inventory_file)
|
||||
raw_confs_list.append(yaml.safe_load(fd))
|
||||
# Copy first conf loaded to another object
|
||||
raw_conf = copy.deepcopy(raw_confs_list[0])
|
||||
# Delete first conf loaded
|
||||
raw_confs_list.pop(0)
|
||||
# Append all others conf to the first one by merging dictionaries
|
||||
LOGGER.debug("Merging files if needed")
|
||||
for conf in raw_confs_list:
|
||||
for key, value in conf.items():
|
||||
raw_conf.setdefault(key, []).extend(value)
|
||||
inventory = get_inventory_recursively(raw_conf)
|
||||
LOGGER.debug("Inventory found: " + str(inventory))
|
||||
return inventory
|
||||
|
||||
|
||||
def create_logger():
|
||||
"""
|
||||
Create a logger instance
|
||||
|
||||
:return: logger instance
|
||||
"""
|
||||
logger = logging.getLogger()
|
||||
handler = logging.StreamHandler()
|
||||
formatter = logging.Formatter('%(asctime)s - %(message)s')
|
||||
handler.setFormatter(formatter)
|
||||
logger.addHandler(handler)
|
||||
logger.setLevel(logging.INFO)
|
||||
return logger
|
||||
|
||||
|
||||
def parse_arguments():
|
||||
"""
|
||||
Initialize the parser, flags list is mandatory
|
||||
|
||||
:return: parsed arguments
|
||||
"""
|
||||
epilog = '''
|
||||
By default the script will walk in script folder and in all its subfolders
|
||||
looking for inventory files.
|
||||
If a filename match the regex
|
||||
%s
|
||||
and if the first %d
|
||||
%s
|
||||
the file will be considered as an inventory file
|
||||
|
||||
If the environment variable INVENTORY_FILE_ENV_VAR is found, the only
|
||||
inventory file read will be the file specified in the environment
|
||||
variable.
|
||||
''' % (str(INVENTORY_FILE_REGEX_PATTERN),
|
||||
INVENTORY_FILE_HEADER_SIZE,
|
||||
INVENTORY_FILE_HEADER.replace('\n', '\n\t'))
|
||||
parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description="YAML Ansible inventory script loader",
|
||||
epilog=textwrap.dedent(epilog)
|
||||
)
|
||||
parser.add_argument('--list',
|
||||
action='store_true',
|
||||
help="display all loaded inventory")
|
||||
parser.add_argument('--host',
|
||||
nargs=1,
|
||||
help="display vars for specified host")
|
||||
parser.add_argument('-v', '--verbose',
|
||||
action='store_true',
|
||||
help="enable verbose mode")
|
||||
parser.add_argument('-V', '--version',
|
||||
action='store_true',
|
||||
help="display inventory script version and exit")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
LOGGER = create_logger()
|
||||
parsed_arguments = parse_arguments()
|
||||
if parsed_arguments.verbose:
|
||||
LOGGER.setLevel(logging.DEBUG)
|
||||
for hdlr in LOGGER.handlers:
|
||||
hdlr.setLevel(logging.DEBUG)
|
||||
if parsed_arguments.version:
|
||||
LOGGER.debug("version flag found")
|
||||
print(INVENTORY_SCRIPT_NAME + " v" + str(INVENTORY_SCRIPT_VERSION))
|
||||
elif parsed_arguments.list:
|
||||
LOGGER.debug("list flag found")
|
||||
print(json.dumps(list_all_hosts()))
|
||||
elif parsed_arguments.host:
|
||||
LOGGER.debug("host flag found")
|
||||
print(json.dumps(dict()))
|
||||
Loading…
Reference in New Issue