forked from evolix/ansible-roles
Squash: conventions, evolinux, etc-git…
This commit is contained in:
parent
a3a56cdc3e
commit
c0ab8f99ce
158
CONVENTIONS.md
Normal file
158
CONVENTIONS.md
Normal file
|
@ -0,0 +1,158 @@
|
|||
# Conventions
|
||||
|
||||
## Roles
|
||||
|
||||
We can use the `ansible-galaxy init` command to bootstrap a new role :
|
||||
|
||||
$ ansible-galaxy init foo
|
||||
- foo was created successfully
|
||||
$ tree foo
|
||||
foo
|
||||
├── defaults
|
||||
│ └── main.yml
|
||||
├── files
|
||||
├── handlers
|
||||
│ └── main.yml
|
||||
├── meta
|
||||
│ └── main.yml
|
||||
├── README.md
|
||||
├── tasks
|
||||
│ └── main.yml
|
||||
├── templates
|
||||
├── tests
|
||||
│ ├── inventory
|
||||
│ └── test.yml
|
||||
└── vars
|
||||
└── main.yml
|
||||
|
||||
All `main.yml` file will be picked up by Ansible automatically, with respect to their own responsibility.
|
||||
|
||||
The main directory is `tasks`. It will contains tasks, either all in the `main.yml` file, or grouped in files that can be included in the main file.
|
||||
|
||||
`defaults/main.yml` is the place to put the list of all variables for the role with a default value.
|
||||
|
||||
`vars` will hold files with variables definitions. Those differ from the defaults because of a much higher precedence (see below).
|
||||
|
||||
`files` is the directory where we'll put files to copy on hosts. They will be copied "as-is". When a role has multiple logical groups of tasks, it's best to create a sub-directroy for each group that needs files. The name of files in these directories doesn't have to be the same as the destination name. Example :
|
||||
|
||||
copy:
|
||||
src: apt/jessie_backports_preferences
|
||||
dest: /etc/apt/apt.conf.d/backports
|
||||
|
||||
`templates` is the twin brother of `files`, but differs in that it contains files that can be pre-processed by the Jinja2 templating language. It can contain variables that will be extrapolated before copying the file to its destination.
|
||||
|
||||
`handlers` is the place to put special tasks that can be triggered by the `notify` argument of modules. For example an `nginx -s reload` command.
|
||||
|
||||
`meta/main.yml` contains … well … "meta" information. There we can define role dependencies, but also some "galaxy" information like the desired Ansible version, supported OS and distributions, a destription, author/ownership, license…
|
||||
|
||||
`tests` and `.travis.yml` are here to help testing with a test matrix, a test inventory and a test playbook.
|
||||
|
||||
We can delete parts we don't need.
|
||||
|
||||
### How much goes into a role
|
||||
|
||||
We create roles (instead of a plain tasks files) when it makes sense as a whole, and it is more that a series of tasks. It often has variables, files/templates, handlers…
|
||||
|
||||
## Syntax
|
||||
|
||||
### Pure YAML
|
||||
|
||||
It's possible to use a compact (Ansible specific) syntax,
|
||||
|
||||
- name: Add evomaintenance trap for '{{ user.name }}'
|
||||
lineinfile: state=present dest='/home/{{ user.name }}/.profile' insertafter=EOF line='trap "sudo /usr/share/scripts/evomaintenance.sh" 0'
|
||||
when: evomaintenance_script.stat.exists
|
||||
|
||||
but we prefer the pure-YAML syntax
|
||||
|
||||
- name: Add evomaintenance trap for '{{ user.name }}'
|
||||
lineinfile:
|
||||
state: present
|
||||
dest: '/home/{{ user.name }}/.profile'
|
||||
insertafter: EOF
|
||||
line: 'trap "sudo /usr/share/scripts/evomaintenance.sh" 0'
|
||||
when: evomaintenance_script.stat.exists
|
||||
|
||||
Here are some reasons :
|
||||
|
||||
* when lines get long, it's easier to read ;
|
||||
* it's a pure YAML syntax, so there is no Ansible-specific preprocessing
|
||||
* … with means that IDE can show the proper syntax highligthing ;
|
||||
* each argument stands on its own.
|
||||
|
||||
## Variables
|
||||
|
||||
### defaults
|
||||
|
||||
When a role is using variables, they must be defined (for example in the `defaults/main.yml`) with a default value (possibly Ǹull). That way, there will never be an "foo is undefined" situation.
|
||||
|
||||
### progressive specificity
|
||||
|
||||
In many roles, we use a *progressive specificity* pattern for some variables.
|
||||
The most common is for "alert_email" ; we want to have a default email address where all alerts or message will be sent, but it can be customized globally, and also customized per task/role.
|
||||
|
||||
For the *evolinux-base* role we have those defaults :
|
||||
|
||||
general_alert_email: "root@localhost"
|
||||
reboot_alert_email: Null
|
||||
log2mail_alert_email: Null
|
||||
raid_alert_email: Null
|
||||
|
||||
In the *log2mail* template, we set the email address like this :
|
||||
|
||||
mailto = {{ log2mail_alert_email or general_alert_email | mandatory }}
|
||||
|
||||
if nothing is customize, the mail will be sent to root@localhost, if geeral_alert_email is changed, it will be use, but if log2mail_alert_email is set to a non-null value, it will have precedence.
|
||||
|
||||
## precedence
|
||||
|
||||
There are multiple places where we can define variables ans there is a specific precedence order for the resolution. Here is [the (ascending) order](http://docs.ansible.com/ansible/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable) :
|
||||
|
||||
* role defaults
|
||||
* inventory vars
|
||||
* inventory group_vars
|
||||
* inventory host_vars
|
||||
* playbook group_vars
|
||||
* playbook host_vars
|
||||
* host facts
|
||||
* play vars
|
||||
* play vars_prompt
|
||||
* play vars_files
|
||||
* registered vars
|
||||
* set_facts
|
||||
* role and include vars
|
||||
* block vars (only for tasks in block)
|
||||
* task vars (only for the task)
|
||||
* extra vars (always win precedence)
|
||||
|
||||
## Configuration patterns
|
||||
|
||||
### lineinfile vs. blockinfile vs. copy/template
|
||||
|
||||
When possible, we prefer using the [lineinfile](http://docs.ansible.com/ansible/lineinfile_module.html) module to make very specific changes.
|
||||
If a `regexp` argument is specified, every line that matches the pattern will be updated. It's a good way to comment/uncomment variable, of add a piece inside a line.
|
||||
|
||||
When it's not possible (multi-line changes, for example), we can use the [blockinfile](http://docs.ansible.com/ansible/blockinfile_module.html) module. It managed blocs of text with begin/end markers. The marker can be customized, mostly to use the proper comment syntax, but also to prevent collisions within a file.
|
||||
|
||||
If none of the previous ca be used, we can use [copy](http://docs.ansible.com/ansible/copy_module.html) or [template](http://docs.ansible.com/ansible/template_module.html) modules to copy an entire file.
|
||||
|
||||
### defaults and custom files
|
||||
|
||||
We try not to alter configuration files managed by packages. It makes upgrading easier, so when a piece of software has a "foo.d" configuration directory, we add custom files there.
|
||||
|
||||
We usually put a `z-evolinux-defaults` with our core configuration. This file can be changed later via Ansible and must not be edited by hand. Example :
|
||||
|
||||
copy:
|
||||
src: evolinux-defaults.cnf
|
||||
dest: /etc/mysql/conf.d/z-evolinux-defaults.cnf
|
||||
force: yes
|
||||
|
||||
|
||||
We also create a blank `zzz-evolinux-custom` file, with commented examples, to allow custom configuration that will never be reverted by Ansible. Example :
|
||||
|
||||
copy:
|
||||
src: evolinux-custom.cnf
|
||||
dest: /etc/mysql/conf.d/zzz-evolinux-custom.cnf
|
||||
force: no
|
||||
|
||||
The source file or template shouldn't to be prefixed for ordering (eg. `z-` or `zzz-`). It's the task's responsibility to choose how destination files must be ordered.
|
2
Vagrantfile
vendored
2
Vagrantfile
vendored
|
@ -9,7 +9,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
|||
config.vm.synced_folder "./vagrant_share/", "/vagrant", disabled: true
|
||||
|
||||
config.vm.provider :virtualbox do |v|
|
||||
v.memory = 1024
|
||||
v.memory = 2048
|
||||
v.cpus = 2
|
||||
v.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
|
||||
v.customize ["modifyvm", :id, "--ioapic", "on"]
|
||||
|
|
|
@ -6,6 +6,13 @@ Install Apache
|
|||
|
||||
Everything is in the `tasks/main.yml` file for now.
|
||||
|
||||
## Variables
|
||||
## Available variables
|
||||
|
||||
To add IP to apache whitelist, define apache_ipaddr_whitelist variable as list.
|
||||
Main variables are :
|
||||
|
||||
* `apache_private_ipaddr_whitelist_present` : list of IP addresses to have in the private whitelist ;
|
||||
* `apache_private_ipaddr_whitelist_absent` : list of IP addresses **not** to have in the whitelist;
|
||||
* `apache_private_htpasswd_present` : list of users to have in the private htpasswd ;
|
||||
* `apache_private_htpasswd_absent` : list of users to **not** have in the private htpasswd.
|
||||
|
||||
The full list of variables (with default values) can be found in `defaults/main.yml`.
|
||||
|
|
|
@ -1 +1,6 @@
|
|||
apache_ipaddr_whitelist: []
|
||||
---
|
||||
apache_private_ipaddr_whitelist_present: []
|
||||
apache_private_ipaddr_whitelist_absent: []
|
||||
|
||||
apache_private_htpasswd_present: []
|
||||
apache_private_htpasswd_absent: []
|
||||
|
|
1
apache/files/private_htpasswd
Normal file
1
apache/files/private_htpasswd
Normal file
|
@ -0,0 +1 @@
|
|||
# user:password for HTTP Basic authentication
|
|
@ -1,4 +1,4 @@
|
|||
- name: Ensure packages are installed
|
||||
- name: packages are installed
|
||||
apt:
|
||||
name: '{{ item }}'
|
||||
state: present
|
||||
|
@ -7,8 +7,10 @@
|
|||
- apachetop
|
||||
- libapache2-mod-evasive
|
||||
- libwww-perl
|
||||
tags:
|
||||
- apache
|
||||
|
||||
- name: Ensure basic modules are enabled
|
||||
- name: basic modules are enabled
|
||||
apache2_module:
|
||||
name: '{{ item }}'
|
||||
state: present
|
||||
|
@ -18,48 +20,120 @@
|
|||
- headers
|
||||
- rewrite
|
||||
- cgi
|
||||
tags:
|
||||
- apache
|
||||
|
||||
- name: Copy Apache config files
|
||||
- name: Copy Apache defaults config file
|
||||
copy:
|
||||
src: "{{ item.file }}"
|
||||
dest: "/etc/apache2/conf-available/{{ item.file }}"
|
||||
src: evolinux-defaults.conf
|
||||
dest: "/etc/apache2/conf-available/z-evolinux-defaults.conf
|
||||
owner: root
|
||||
group: root
|
||||
mode: "{{ item.mode }}"
|
||||
with_items:
|
||||
- { file: z_evolinux.conf, mode: 0644 }
|
||||
- { file: zzz_evolinux.conf, mode: 0640 }
|
||||
mode: 0644
|
||||
force: yes
|
||||
tags:
|
||||
- apache
|
||||
|
||||
- name: Ensure Apache default config is enabled
|
||||
command: a2enconf z_evolinux.conf zzz_evolinux.conf
|
||||
- name: Copy Apache custom config file
|
||||
template:
|
||||
src: evolinux-custom.conf.j2
|
||||
dest: "/etc/apache2/conf-available/zzz-evolinux-custom.conf
|
||||
owner: root
|
||||
group: root
|
||||
mode: 0644
|
||||
force: no
|
||||
tags:
|
||||
- apache
|
||||
|
||||
- name: Ensure Apache config files are enabled
|
||||
command: "a2enconf {{ item }}"
|
||||
register: command_result
|
||||
changed_when: "'Enabling' in command_result.stderr"
|
||||
with_items:
|
||||
- z-evolinux-defaults.conf
|
||||
- zzz-evolinux-custom.conf
|
||||
tags:
|
||||
- apache
|
||||
|
||||
- name: Init ipaddr_whitelist.conf file
|
||||
- name: Init private_ipaddr_whitelist.conf file
|
||||
copy:
|
||||
src: ipaddr_whitelist.conf
|
||||
dest: /etc/apache2/ipaddr_whitelist.conf
|
||||
src: private_ipaddr_whitelist.conf
|
||||
dest: /etc/apache2/private_ipaddr_whitelist.conf
|
||||
owner: root
|
||||
group: root
|
||||
mode: 0640
|
||||
force: no
|
||||
tags:
|
||||
- apache
|
||||
|
||||
- name: Add IP addresses to private IP whitelist if defined
|
||||
- name: add IP addresses to private IP whitelist
|
||||
lineinfile:
|
||||
dest: /etc/apache2/ipaddr_whitelist.conf
|
||||
dest: /etc/apache2/private_ipaddr_whitelist.conf
|
||||
line: "Allow from {{ item }}"
|
||||
state: present
|
||||
with_items: "{{ apache_ipaddr_whitelist }}"
|
||||
with_items: "{{ apache_private_ipaddr_whitelist_present }}"
|
||||
notify: reload apache
|
||||
tags:
|
||||
- apache
|
||||
|
||||
- name: remove IP addresses from private IP whitelist
|
||||
lineinfile:
|
||||
dest: /etc/apache2/private_ipaddr_whitelist.conf
|
||||
line: "Allow from {{ item }}"
|
||||
state: absent
|
||||
with_items: "{{ apache_private_ipaddr_whitelist_absent }}"
|
||||
notify: reload apache
|
||||
tags:
|
||||
- apache
|
||||
|
||||
- name: Copy private_htpasswd
|
||||
copy:
|
||||
src: private_htpasswd
|
||||
dest: /etc/apache2/private_htpasswd
|
||||
owner: root
|
||||
group: root
|
||||
mode: 0640
|
||||
force: no
|
||||
notify: reload apache
|
||||
tags:
|
||||
- apache
|
||||
|
||||
- name: add user:pwd to private htpasswd
|
||||
lineinfile:
|
||||
dest: /etc/apache2/private_htpasswd
|
||||
line: "{{ item }}"
|
||||
state: present
|
||||
with_items: "{{ apache_private_htpasswd_present }}"
|
||||
notify: reload apache
|
||||
tags:
|
||||
- apache
|
||||
|
||||
- name: remove user:pwd from private htpasswd
|
||||
lineinfile:
|
||||
dest: /etc/apache2/private_htpasswd
|
||||
line: "{{ item }}"
|
||||
state: absent
|
||||
with_items: "{{ apache_private_htpasswd_absent }}"
|
||||
notify: reload apache
|
||||
tags:
|
||||
- apache
|
||||
|
||||
- name: is umask already present?
|
||||
command: "grep -E '^umask ' /etc/apache2/envvars"
|
||||
failed_when: False
|
||||
changed_when: False
|
||||
register: envvar_grep_umask
|
||||
tags:
|
||||
- apache
|
||||
|
||||
- name: Add a mark in envvars for umask
|
||||
blockinfile:
|
||||
dest: /etc/apache2/envvars
|
||||
marker: "## {mark} ANSIBLE MANAGED BLOCK"
|
||||
block: |
|
||||
## Set umask for writing by Apache user.
|
||||
## Set rights on files and directories written by Apache
|
||||
|
||||
- name : Ensure umask is set in envvars (default is umask 007)
|
||||
lineinfile:
|
||||
dest: /etc/apache2/envvars
|
||||
regexp: "^umask"
|
||||
line: "umask 007"
|
||||
umask 007
|
||||
when: envvar_grep_umask.rc != 0
|
||||
tags:
|
||||
- apache
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
---
|
||||
- name: Jessie-backports list is available
|
||||
apt_repository:
|
||||
repo: "deb http://mirror.evolix.org/debian jessie-backports main contrib non-free"
|
||||
update_cache: yes
|
||||
state: present
|
||||
tags:
|
||||
- system
|
||||
- packages
|
||||
|
||||
- name: Backports have a low priority
|
||||
blockinfile:
|
||||
dest: /etc/apt/preferences.d/backports
|
||||
marker: "// {mark} ANSIBLE MANAGED BLOCK"
|
||||
insertafter: EOF
|
||||
create: yes
|
||||
block: |
|
||||
Package: *
|
||||
Pin: release a=jessie-backports
|
||||
Pin-Priority: 50
|
||||
tags:
|
||||
- system
|
||||
- packages
|
1
apt-repositories/defaults/main.yml
Normal file
1
apt-repositories/defaults/main.yml
Normal file
|
@ -0,0 +1 @@
|
|||
apt_repositories_components: "main"
|
3
apt-repositories/files/jessie_backports_preferences
Normal file
3
apt-repositories/files/jessie_backports_preferences
Normal file
|
@ -0,0 +1,3 @@
|
|||
Package: *
|
||||
Pin: release a=jessie-backports
|
||||
Pin-Priority: 50
|
17
apt-repositories/tasks/main.yml
Normal file
17
apt-repositories/tasks/main.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
|
||||
- name: Backports sources list is installed
|
||||
template:
|
||||
src: backports.list.j2
|
||||
dest: /etc/apt/sources.list.d/backports.list
|
||||
force: yes
|
||||
backup: yes
|
||||
mode: 0640
|
||||
|
||||
- name: Backports configuration
|
||||
copy:
|
||||
src: jessie_backports_preferences
|
||||
dest: /etc/apt/preferences.d/backports
|
||||
force: yes
|
||||
backup: yes
|
||||
mode: 0640
|
1
apt-repositories/templates/backports.list.j2
Normal file
1
apt-repositories/templates/backports.list.j2
Normal file
|
@ -0,0 +1 @@
|
|||
deb http://mirror.evolix.org/debian jessie-backports {{ apt_repositories_components | mandatory }}
|
|
@ -1,13 +0,0 @@
|
|||
# apt-upgrade
|
||||
|
||||
Upgrades Debian packages
|
||||
|
||||
## Tasks
|
||||
|
||||
Everything is in the `tasks/main.yml` file.
|
||||
|
||||
## Available variables
|
||||
|
||||
* `apt_upgrade_mode` : kind of upgrade to do (cf. http://docs.ansible.com/ansible/apt_module.html#options)
|
||||
|
||||
Choice of upgrade mode can be set in a variables file (ex. `vars/main.yml`) or when invoking the role (`- { role: apt-upgrade, apt_upgrade_mode: safe }`).
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
- name: Ensure Debian is up-to-date
|
||||
apt:
|
||||
update_cache: yes
|
||||
upgrade: "{{ apt_upgrade_mode | default('safe') }}"
|
||||
tags:
|
||||
- system
|
||||
- packages
|
|
@ -1,3 +1,4 @@
|
|||
---
|
||||
elasticsearch_plugin_head_home: /home/elasticsearch-head
|
||||
elasticsearch_plugin_head_clone_dir: "{{ elasticsearch_plugin_head_home }}/www"
|
||||
elasticsearch_plugin_head_owner: "elasticsearch-head"
|
||||
|
|
3
elasticsearch-plugin-head/meta/main.yml
Normal file
3
elasticsearch-plugin-head/meta/main.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
dependencies:
|
||||
- nodejs
|
|
@ -1,41 +1,5 @@
|
|||
---
|
||||
|
||||
|
||||
- name: APT https transport is enabled
|
||||
apt:
|
||||
name: apt-transport-https
|
||||
state: installed
|
||||
tags:
|
||||
- system
|
||||
- packages
|
||||
|
||||
- name: Node GPG key is installed
|
||||
apt_key:
|
||||
url: https://deb.nodesource.com/gpgkey/nodesource.gpg.key
|
||||
state: present
|
||||
tags:
|
||||
- system
|
||||
- packages
|
||||
- npm
|
||||
|
||||
- name: Node sources list is available
|
||||
apt_repository:
|
||||
repo: "deb https://deb.nodesource.com/node_6.x jessie main"
|
||||
state: present
|
||||
tags:
|
||||
- system
|
||||
- packages
|
||||
- npm
|
||||
|
||||
- name: Node is installed
|
||||
apt:
|
||||
name: nodejs
|
||||
update_cache: yes
|
||||
state: installed
|
||||
tags:
|
||||
- packages
|
||||
- npm
|
||||
|
||||
- name: "User {{ elasticsearch_plugin_head_owner }} is present"
|
||||
user:
|
||||
name: "{{ elasticsearch_plugin_head_owner }}"
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
---
|
||||
elasticsearch_cluster_name: Null
|
||||
elasticsearch_node_name: "${HOSTNAME}"
|
||||
elasticsearch_network_host: "[_site_, _local_]"
|
||||
|
|
7
etc-git/README.md
Normal file
7
etc-git/README.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
# etc-git
|
||||
|
||||
Put /etc under Git version control.
|
||||
|
||||
## Tasks
|
||||
|
||||
Everything is in the `tasks/main.yml` file.
|
1
etc-git/files/gitignore
Normal file
1
etc-git/files/gitignore
Normal file
|
@ -0,0 +1 @@
|
|||
aliases.db
|
36
etc-git/tasks/main.yml
Normal file
36
etc-git/tasks/main.yml
Normal file
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
|
||||
- name: Git is installed
|
||||
apt:
|
||||
name: git
|
||||
state: present
|
||||
|
||||
- name: /etc is versioned with git
|
||||
command: "git init ."
|
||||
args:
|
||||
chdir: /etc
|
||||
creates: /etc/.git/
|
||||
register: git_init
|
||||
|
||||
- name: /etc/.gitignore is present
|
||||
copy:
|
||||
src: gitignore
|
||||
dest: /etc/.gitignore
|
||||
owner: root
|
||||
group: root
|
||||
mode: 0600
|
||||
|
||||
- name: does /etc/ have any commit?
|
||||
command: "git log"
|
||||
args:
|
||||
chdir: /etc
|
||||
changed_when: False
|
||||
failed_when: False
|
||||
register: git_log
|
||||
|
||||
- name: initial commit is present?
|
||||
shell: "git add -A . && git commit -m \"Initial commit via Ansible\""
|
||||
args:
|
||||
chdir: /etc
|
||||
register: git_commit
|
||||
when: git_init.changed or git_log.rc != 0
|
7
evocheck/README.md
Normal file
7
evocheck/README.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
# evocheck
|
||||
|
||||
Install a script to verify compliance of a Debian/OpenBSD server
|
||||
|
||||
## Tasks
|
||||
|
||||
Everything is in the `tasks/main.yml` file.
|
3
evocheck/meta/main.yml
Normal file
3
evocheck/meta/main.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
dependencies:
|
||||
- { role: evolinux-sources-list }
|
8
evocheck/tasks/main.yml
Normal file
8
evocheck/tasks/main.yml
Normal file
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
|
||||
- name: evocheck is installed
|
||||
command: "apt-get install -yq --allow-unauthenticated evomaintenance"
|
||||
register: installed_evomaintenance
|
||||
changed_when: not (installed_evomaintenance.stdout | search("0 upgraded") and installed_evomaintenance.stdout | search("0 newly installed"))
|
||||
|
||||
# TODO make sure that the package is in the right version
|
29
evolinux-admin-users/README.md
Normal file
29
evolinux-admin-users/README.md
Normal file
|
@ -0,0 +1,29 @@
|
|||
# evolinux-admin-users
|
||||
|
||||
Creates admin users accounts, based on a configuration data structure.
|
||||
|
||||
## Tasks
|
||||
|
||||
Everything is in the `tasks/main.yml` file.
|
||||
|
||||
## Available variables
|
||||
|
||||
The variable `evolinux_admin_users` must be a "hash" of one or more users :
|
||||
|
||||
```
|
||||
evolinux_admin_users:
|
||||
- name: foo
|
||||
uid: 1001
|
||||
fullname: 'Mr Foo'
|
||||
password_hash: 'sdfgsdfgsdfgsdfg'
|
||||
ssh_key: 'ssh-rsa AZERTYXYZ'
|
||||
- name: bar
|
||||
uid: 1002
|
||||
fullname: 'Mr Bar'
|
||||
password_hash: 'gsdfgsdfgsdfgsdf'
|
||||
ssh_key: 'ssh-rsa QWERTYUIOP'
|
||||
```
|
||||
|
||||
* `general_scripts_dir`: general directory for scripts installation (default: `/usr/local/bin`).
|
||||
* `listupgrade_scripts_dir`: script directory for listupgrade (default: `general_scripts_dir`).
|
||||
* `evomaintenance_scripts_dir`: script directory for evomaintenance (default: `general_scripts_dir`).
|
6
evolinux-admin-users/defaults/main.yml
Normal file
6
evolinux-admin-users/defaults/main.yml
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
evolinux_admin_users: []
|
||||
|
||||
general_scripts_dir: "/usr/local/bin"
|
||||
evomaintenance_scripts_dir: Null
|
||||
listupgrade_scripts_dir: Null
|
95
evolinux-admin-users/tasks/adduser_debian.yml
Normal file
95
evolinux-admin-users/tasks/adduser_debian.yml
Normal file
|
@ -0,0 +1,95 @@
|
|||
---
|
||||
|
||||
- name: Test if uid exists for '{{ user.name }}'
|
||||
command: 'getent passwd {{ user.uid }}'
|
||||
register: uidisbusy
|
||||
failed_when: False
|
||||
changed_when: False
|
||||
|
||||
- name: Add Unix account with classical uid for '{{ user.name }}'
|
||||
user:
|
||||
state: present
|
||||
uid: '{{ user.uid }}'
|
||||
name: '{{ user.name }}'
|
||||
comment: '{{ user.fullname }}'
|
||||
shell: /bin/bash
|
||||
password: '{{ user.password_hash }}'
|
||||
update_password: on_create
|
||||
when: uidisbusy|failed
|
||||
|
||||
- name: Add Unix account with random uid for '{{ user.name }}'
|
||||
user:
|
||||
state: present
|
||||
name: '{{ user.name }}'
|
||||
comment: '{{ user.fullname }}'
|
||||
shell: /bin/bash
|
||||
password: '{{ user.password_hash }}'
|
||||
update_password: on_create
|
||||
when: uidisbusy|success
|
||||
|
||||
- name: Fix perms on homedirectory for '{{ user.name }}'
|
||||
file:
|
||||
name: '/home/{{ user.name }}'
|
||||
mode: 0700
|
||||
state: directory
|
||||
|
||||
- name: is evomaintenance installed?
|
||||
stat:
|
||||
path: "{{ evomaintenance_scripts_dir or general_scripts_dir | mandatory }}/evomaintenance.sh"
|
||||
register: evomaintenance_script
|
||||
|
||||
- name: Add evomaintenance trap for '{{ user.name }}'
|
||||
lineinfile:
|
||||
state: present
|
||||
dest: '/home/{{ user.name }}/.profile'
|
||||
insertafter: EOF
|
||||
line: 'trap "sudo {{ evomaintenance_scripts_dir or general_scripts_dir | mandatory }}/evomaintenance.sh" 0'
|
||||
when: evomaintenance_script.stat.exists
|
||||
|
||||
- name: Create .ssh directory for '{{ user.name }}'
|
||||
file:
|
||||
dest: '/home/{{ user.name }}/.ssh/'
|
||||
state: directory
|
||||
mode: 0700
|
||||
owner: '{{ user.name }}'
|
||||
group: '{{ user.name }}'
|
||||
|
||||
- name: Add user's SSH public key for '{{ user.name }}'
|
||||
lineinfile:
|
||||
dest: '/home/{{ user.name }}/.ssh/authorized_keys'
|
||||
create: yes
|
||||
line: '{{ user.ssh_key }}'
|
||||
owner: '{{ user.name }}'
|
||||
group: '{{ user.name }}'
|
||||
|
||||
- name: Modify AllowUsers' sshd directive for '{{ user.name }}'
|
||||
replace:
|
||||
dest: /etc/ssh/sshd_config
|
||||
regexp: '^(AllowUsers ((?!{{ user.name }}).)*)$'
|
||||
replace: '\1 {{ user.name }}'
|
||||
notify:
|
||||
- reload sshd
|
||||
|
||||
- name: Modify Match User's sshd directive for '{{ user.name }}'
|
||||
replace:
|
||||
dest: /etc/ssh/sshd_config
|
||||
regexp: '^(Match User ((?!{{ user.name }}).)*)$'
|
||||
replace: '\1,{{ user.name }}'
|
||||
notify:
|
||||
- reload sshd
|
||||
|
||||
- name: Evolinux sudoers file is present
|
||||
template:
|
||||
src: sudoers_debian.j2
|
||||
dest: /etc/sudoers.d/evolinux
|
||||
force: false
|
||||
validate: '/usr/sbin/visudo -cf %s'
|
||||
register: copy_sudoers_evolinux
|
||||
|
||||
- name: Add user in sudoers file for '{{ user.name }}'
|
||||
replace:
|
||||
dest: /etc/sudoers.d/evolinux
|
||||
regexp: '^(User_Alias\s+ADMINS\s+=((?!{{ user.name }}).)*)$'
|
||||
replace: '\1,{{ user.name }}'
|
||||
validate: '/usr/sbin/visudo -cf %s'
|
||||
when: not copy_sudoers_evolinux.changed
|
8
evolinux-admin-users/tasks/main.yml
Normal file
8
evolinux-admin-users/tasks/main.yml
Normal file
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
|
||||
- include: adduser_debian.yml user={{ item }}
|
||||
with_items: "{{ evolinux_admin_users }}"
|
||||
when: ansible_distribution == "Debian"
|
||||
|
||||
# - include: openbsd.yml
|
||||
# when: ansible_distribution == "OpenBSD"
|
10
evolinux-admin-users/templates/sudoers_debian.j2
Normal file
10
evolinux-admin-users/templates/sudoers_debian.j2
Normal file
|
@ -0,0 +1,10 @@
|
|||
Defaults umask=0077
|
||||
|
||||
Cmnd_Alias MAINT = {{ evomaintenance_scripts_dir or general_scripts_dir | mandatory }}/evomaintenance.sh, {{ listupgrade_scripts_dir or general_scripts_dir | mandatory }}/listupgrade.sh, /usr/bin/apt, /bin/mount
|
||||
User_Alias ADMINS = {{ user.name }}
|
||||
|
||||
nagios ALL = NOPASSWD: /usr/lib/nagios/plugins/check_procs
|
||||
nagios ALL = (clamav) NOPASSWD: /usr/bin/clamscan /tmp/safe.txt
|
||||
|
||||
ADMINS ALL = (ALL:ALL) ALL
|
||||
ADMINS ALL = NOPASSWD: MAINT
|
24
evolinux-base/README.md
Normal file
24
evolinux-base/README.md
Normal file
|
@ -0,0 +1,24 @@
|
|||
# evolinux-base
|
||||
|
||||
Various tasks for Evolinux setup.
|
||||
|
||||
## Tasks
|
||||
|
||||
* `system.yml` :
|
||||
* `apt.yml` :
|
||||
* `install_tools.yml` :
|
||||
* `root.yml` :
|
||||
* `logs.yml` :
|
||||
|
||||
## Available variables
|
||||
|
||||
Main variables are :
|
||||
|
||||
* `evolinux_delete_nfs`: delete NFS tools (default: `True`)
|
||||
* `evolinux_ntp_server`: custom NTP server host or IP (default: `Null`)
|
||||
* `evolinux_additional_packages`: optional additional packages to install (default: `[]`)
|
||||
* `general_alert_email`: email address to send various alert messages (default: `root@localhost`).
|
||||
* `apt_alert_email`: email address to send APT messages to (default: `general_alert_email`).
|
||||
* `log2mail_alert_email`: email address to send Log2mail messages to (default: `general_alert_email`).
|
||||
|
||||
The full list of variables (with default values) can be found in `defaults/main.yml`.
|
41
evolinux-base/defaults/main.yml
Normal file
41
evolinux-base/defaults/main.yml
Normal file
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
general_alert_email: "root@localhost"
|
||||
reboot_alert_email: Null
|
||||
apt_alert_email: Null
|
||||
log2mail_alert_email: Null
|
||||
raid_alert_email: Null
|
||||
|
||||
# hostname
|
||||
|
||||
evolinux_hostname: "{{ ansible_hostname }}"
|
||||
evolinux_domain: "{{ ansible_domain }}"
|
||||
evolinux_fqdn: "{{ ansible_fqdn }}"
|
||||
evolinux_internal_hostname: "{{ evolinux_hostname }}"
|
||||
|
||||
# apt
|
||||
|
||||
evolinux_apt_repositories_components: "main"
|
||||
evolinux_apt_hooks: False
|
||||
# kernel
|
||||
|
||||
evolinux_kernel_reboot_after_panic: True
|
||||
evolinux_kernel_disable_tcp_timestamps: True
|
||||
evolinux_kernel_reduce_swapiness: True
|
||||
evolinux_kernel_cve20165696: True
|
||||
|
||||
# providers
|
||||
|
||||
evolinux_provider_online: False
|
||||
evolinux_provider_orange_fce: False
|
||||
|
||||
# default www
|
||||
|
||||
evolinux_default_www_redirect_url: "http://evolix.fr"
|
||||
evolinux_default_www_ssl_subject: "/CN={{ ansible_fqdn }}"
|
||||
evolinux_default_www_nginx_enabled: False
|
||||
evolinux_default_www_apache_enabled: False
|
||||
|
||||
# misc.
|
||||
|
||||
evolinux_ntp_server: Null
|
||||
evolinux_delete_nfs: True
|
BIN
evolinux-base/files/default_www/img/background-top.png
Normal file
BIN
evolinux-base/files/default_www/img/background-top.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
BIN
evolinux-base/files/default_www/img/favicon.ico
Normal file
BIN
evolinux-base/files/default_www/img/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
9
evolinux-base/files/logs/logrotate.d/apache2-php
Normal file
9
evolinux-base/files/logs/logrotate.d/apache2-php
Normal file
|
@ -0,0 +1,9 @@
|
|||
/var/log/php.log {
|
||||
weekly
|
||||
missingok
|
||||
rotate 52
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
create 640 www-data adm
|
||||
}
|
16
evolinux-base/files/logs/logrotate.d/apt
Normal file
16
evolinux-base/files/logs/logrotate.d/apt
Normal file
|
@ -0,0 +1,16 @@
|
|||
/var/log/apt/term.log {
|
||||
rotate 120
|
||||
monthly
|
||||
compress
|
||||
missingok
|
||||
notifempty
|
||||
}
|
||||
|
||||
/var/log/apt/history.log {
|
||||
rotate 120
|
||||
monthly
|
||||
compress
|
||||
missingok
|
||||
notifempty
|
||||
}
|
||||
|
14
evolinux-base/files/logs/logrotate.d/bind.disabled
Normal file
14
evolinux-base/files/logs/logrotate.d/bind.disabled
Normal file
|
@ -0,0 +1,14 @@
|
|||
/var/chroot-bind/var/log/bind.log {
|
||||
weekly
|
||||
missingok
|
||||
notifempty
|
||||
rotate 4
|
||||
create 640 bind bind
|
||||
compress
|
||||
delaycompress
|
||||
sharedscripts
|
||||
postrotate
|
||||
rndc reload > /dev/null
|
||||
endscript
|
||||
}
|
||||
|
9
evolinux-base/files/logs/logrotate.d/dhcp
Normal file
9
evolinux-base/files/logs/logrotate.d/dhcp
Normal file
|
@ -0,0 +1,9 @@
|
|||
/var/log/dhcp.log {
|
||||
weekly
|
||||
missingok
|
||||
rotate 52
|
||||
compress
|
||||
delaycompress
|
||||
create 640 root adm
|
||||
notifempty
|
||||
}
|
19
evolinux-base/files/logs/logrotate.d/dpkg
Normal file
19
evolinux-base/files/logs/logrotate.d/dpkg
Normal file
|
@ -0,0 +1,19 @@
|
|||
/var/log/dpkg.log {
|
||||
monthly
|
||||
rotate 120
|
||||
compress
|
||||
delaycompress
|
||||
missingok
|
||||
notifempty
|
||||
create 644 root root
|
||||
}
|
||||
/var/log/alternatives.log {
|
||||
monthly
|
||||
rotate 120
|
||||
compress
|
||||
delaycompress
|
||||
missingok
|
||||
notifempty
|
||||
create 644 root root
|
||||
}
|
||||
|
8
evolinux-base/files/logs/logrotate.d/freeradius
Normal file
8
evolinux-base/files/logs/logrotate.d/freeradius
Normal file
|
@ -0,0 +1,8 @@
|
|||
/var/log/freeradius/*.log {
|
||||
weekly
|
||||
missingok
|
||||
rotate 52
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
}
|
31
evolinux-base/files/logs/logrotate.d/ftp.disabled
Normal file
31
evolinux-base/files/logs/logrotate.d/ftp.disabled
Normal file
|
@ -0,0 +1,31 @@
|
|||
/var/log/proftpd.log {
|
||||
weekly
|
||||
missingok
|
||||
rotate 13
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
create 640 root adm
|
||||
sharedscripts
|
||||
postrotate
|
||||
/etc/init.d/proftpd restart > /dev/null
|
||||
endscript
|
||||
}
|
||||
|
||||
|
||||
/var/log/xferlog.log {
|
||||
weekly
|
||||
rotate 1
|
||||
missingok
|
||||
create 640 root adm
|
||||
sharedscripts
|
||||
postrotate
|
||||
DATE=$(date +"%d-%m-%Y")
|
||||
cd /var/log
|
||||
ftpstats -a -r -l 2 -d i-f xferlog.log.1 2>/dev/null >xferreport.$DATE
|
||||
mv xferlog.log.1 xferlog.log.$DATE
|
||||
gzip xferlog.log.$DATE
|
||||
gzip xferreport.$DATE
|
||||
endscript
|
||||
}
|
||||
|
9
evolinux-base/files/logs/logrotate.d/ldap
Normal file
9
evolinux-base/files/logs/logrotate.d/ldap
Normal file
|
@ -0,0 +1,9 @@
|
|||
/var/log/openldap.log {
|
||||
weekly
|
||||
missingok
|
||||
rotate 3
|
||||
compress
|
||||
notifempty
|
||||
create 640 root adm
|
||||
}
|
||||
|
19
evolinux-base/files/logs/logrotate.d/lighttpd.disabled
Normal file
19
evolinux-base/files/logs/logrotate.d/lighttpd.disabled
Normal file
|
@ -0,0 +1,19 @@
|
|||
/var/log/lighttpd/*.log {
|
||||
weekly
|
||||
missingok
|
||||
copytruncate
|
||||
rotate 52
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
sharedscripts
|
||||
postrotate
|
||||
if [ -f /var/run/lighttpd.pid ]; then \
|
||||
if [ -x /usr/sbin/invoke-rc.d ]; then \
|
||||
invoke-rc.d lighttpd force-reload > /dev/null; \
|
||||
else \
|
||||
/etc/init.d/lighttpd force-reload > /dev/null; \
|
||||
fi; \
|
||||
fi;
|
||||
endscript
|
||||
}
|
6
evolinux-base/files/logs/logrotate.d/lvm-common.disabled
Normal file
6
evolinux-base/files/logs/logrotate.d/lvm-common.disabled
Normal file
|
@ -0,0 +1,6 @@
|
|||
/var/log/lvm {
|
||||
daily
|
||||
rotate 3
|
||||
missingok
|
||||
create 0640 root adm
|
||||
}
|
8
evolinux-base/files/logs/logrotate.d/news.disabled
Normal file
8
evolinux-base/files/logs/logrotate.d/news.disabled
Normal file
|
@ -0,0 +1,8 @@
|
|||
/var/log/news.log {
|
||||
monthly
|
||||
missingok
|
||||
notifempty
|
||||
rotate 1
|
||||
create 640 root adm
|
||||
}
|
||||
|
18
evolinux-base/files/logs/logrotate.d/nginx
Normal file
18
evolinux-base/files/logs/logrotate.d/nginx
Normal file
|
@ -0,0 +1,18 @@
|
|||
/var/log/nginx/*.log {
|
||||
weekly
|
||||
missingok
|
||||
rotate 52
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
create 640 root adm
|
||||
sharedscripts
|
||||
prerotate
|
||||
if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
|
||||
run-parts /etc/logrotate.d/httpd-prerotate; \
|
||||
fi; \
|
||||
endscript
|
||||
postrotate
|
||||
[ ! -f /var/run/nginx.pid ] || kill -USR1 `cat /var/run/nginx.pid`
|
||||
endscript
|
||||
}
|
14
evolinux-base/files/logs/logrotate.d/ntp.disabled
Normal file
14
evolinux-base/files/logs/logrotate.d/ntp.disabled
Normal file
|
@ -0,0 +1,14 @@
|
|||
/var/log/ntp.log {
|
||||
weekly
|
||||
rotate 1
|
||||
missingok
|
||||
create 640 root adm
|
||||
sharedscripts
|
||||
postrotate
|
||||
DATE=$(date +"%d-%m-%Y")
|
||||
cd /var/log
|
||||
mv ntp.log.1 ntp.log.$DATE
|
||||
gzip ntp.log.$DATE
|
||||
endscript
|
||||
}
|
||||
|
7
evolinux-base/files/logs/logrotate.d/postgresql
Normal file
7
evolinux-base/files/logs/logrotate.d/postgresql
Normal file
|
@ -0,0 +1,7 @@
|
|||
/var/log/postgresql.log {
|
||||
weekly
|
||||
missingok
|
||||
rotate 8
|
||||
create 640 root adm
|
||||
}
|
||||
|
11
evolinux-base/files/logs/logrotate.d/procmail
Normal file
11
evolinux-base/files/logs/logrotate.d/procmail
Normal file
|
@ -0,0 +1,11 @@
|
|||
/var/log/procmail.log {
|
||||
daily
|
||||
rotate 365
|
||||
dateext
|
||||
dateyesterday
|
||||
dateformat .%Y%m%d
|
||||
missingok
|
||||
rotate 365
|
||||
create 640 root adm
|
||||
}
|
||||
|
14
evolinux-base/files/logs/logrotate.d/samba
Normal file
14
evolinux-base/files/logs/logrotate.d/samba
Normal file
|
@ -0,0 +1,14 @@
|
|||
# Attention, bien mettre "log file = /var/log/samba/%m.log" dans la conf Samba
|
||||
/var/log/samba/*.log {
|
||||
weekly
|
||||
missingok
|
||||
rotate 52
|
||||
postrotate
|
||||
invoke-rc.d --quiet samba reload > /dev/null
|
||||
[ ! -f /var/run/samba/nmbd.pid ] || kill -HUP `cat /var/run/samba/nmbd.pid`
|
||||
[ -f /var/run/samba/winbindd.pid ] && kill -HUP `cat /var/run/samba/winbindd.pid` || true
|
||||
endscript
|
||||
compress
|
||||
notifempty
|
||||
}
|
||||
|
11
evolinux-base/files/logs/logrotate.d/squid3.disabled
Normal file
11
evolinux-base/files/logs/logrotate.d/squid3.disabled
Normal file
|
@ -0,0 +1,11 @@
|
|||
/var/log/squid3/*.log {
|
||||
monthly
|
||||
compress
|
||||
rotate 12
|
||||
missingok
|
||||
create 640 proxy adm
|
||||
sharedscripts
|
||||
postrotate
|
||||
test ! -e /var/run/squid3.pid || /usr/sbin/squid3 -k rotate
|
||||
endscript
|
||||
}
|
35
evolinux-base/files/logs/logrotate.d/zsyslog
Normal file
35
evolinux-base/files/logs/logrotate.d/zsyslog
Normal file
|
@ -0,0 +1,35 @@
|
|||
# Custom EvoLinux
|
||||
create 640 root adm
|
||||
dateext
|
||||
dateyesterday
|
||||
dateformat .%Y%m%d
|
||||
missingok
|
||||
notifempty
|
||||
delaycompress
|
||||
compress
|
||||
postrotate
|
||||
invoke-rc.d rsyslog rotate > /dev/null
|
||||
endscript
|
||||
|
||||
/var/log/daemon.log
|
||||
/var/log/kern.log
|
||||
/var/log/lpr.log
|
||||
{
|
||||
weekly
|
||||
rotate 5
|
||||
}
|
||||
|
||||
/var/log/auth.log
|
||||
/var/log/user.log
|
||||
/var/log/cron.log
|
||||
/var/log/debug
|
||||
/var/log/messages
|
||||
/var/log/syslog
|
||||
/var/log/mail.info
|
||||
/var/log/mail.warn
|
||||
/var/log/mail.err
|
||||
/var/log/mail.log
|
||||
{
|
||||
daily
|
||||
rotate 365
|
||||
}
|
122
evolinux-base/files/logs/rsyslog.conf
Normal file
122
evolinux-base/files/logs/rsyslog.conf
Normal file
|
@ -0,0 +1,122 @@
|
|||
# Syslog for Pack Evolix serveur - Debian Squeeze
|
||||
|
||||
|
||||
#################
|
||||
#### MODULES ####
|
||||
#################
|
||||
|
||||
$ModLoad imuxsock # provides support for local system logging
|
||||
$ModLoad imklog # provides kernel logging support (previously done by rklogd)
|
||||
#$ModLoad immark # provides --MARK-- message capability
|
||||
|
||||
# provides UDP syslog reception
|
||||
#$ModLoad imudp
|
||||
#$UDPServerRun 514
|
||||
|
||||
# provides TCP syslog reception
|
||||
#$ModLoad imtcp
|
||||
#$InputTCPServerRun 514
|
||||
|
||||
|
||||
###########################
|
||||
#### GLOBAL DIRECTIVES ####
|
||||
###########################
|
||||
|
||||
#
|
||||
# Use traditional timestamp format.
|
||||
# To enable high precision timestamps, comment out the following line.
|
||||
#
|
||||
$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat
|
||||
|
||||
#
|
||||
# Set the default permissions for all log files.
|
||||
#
|
||||
$FileOwner root
|
||||
$FileGroup adm
|
||||
$FileCreateMode 0640
|
||||
$DirCreateMode 0755
|
||||
$Umask 0022
|
||||
|
||||
#
|
||||
# Include all config files in /etc/rsyslog.d/
|
||||
#
|
||||
$IncludeConfig /etc/rsyslog.d/*.conf
|
||||
|
||||
|
||||
###############
|
||||
#### RULES ####
|
||||
###############
|
||||
|
||||
#
|
||||
# First some standard log files. Log by facility.
|
||||
#
|
||||
auth,authpriv.* /var/log/auth.log
|
||||
*.*;auth,authpriv.none;cron,mail,local4,local5.none -/var/log/syslog
|
||||
cron.* /var/log/cron.log
|
||||
daemon.* -/var/log/daemon.log
|
||||
kern.* -/var/log/kern.log
|
||||
lpr.* -/var/log/lpr.log
|
||||
mail.* -/var/log/mail.log
|
||||
user.* -/var/log/user.log
|
||||
uucp.* /var/log/uucp.log
|
||||
news.* /var/log/news.log
|
||||
|
||||
local4.* -/var/log/openldap.log
|
||||
local1.* /var/log/sympa.log
|
||||
local0.* /var/log/postgresql.log
|
||||
local7.* -/var/log/dhcp.log
|
||||
local5.* -/var/log/haproxy.log
|
||||
|
||||
|
||||
#
|
||||
# Logging for the mail system. Split it up so that
|
||||
# it is easy to write scripts to parse these files.
|
||||
#
|
||||
#mail.info -/var/log/mail.info
|
||||
#mail.warn -/var/log/mail.warn
|
||||
#mail.err /var/log/mail.err
|
||||
|
||||
#
|
||||
# Logging for INN news system.
|
||||
#
|
||||
#news.crit /var/log/news/news.crit
|
||||
#news.err /var/log/news/news.err
|
||||
#news.notice -/var/log/news/news.notice
|
||||
|
||||
#
|
||||
# Some "catch-all" log files.
|
||||
#
|
||||
#*.=debug;\
|
||||
# auth,authpriv.none;\
|
||||
# news.none;mail.none -/var/log/debug
|
||||
#*.=info;*.=notice;*.=warn;\
|
||||
# auth,authpriv.none;\
|
||||
# cron,daemon.none;\
|
||||
# mail,news.none -/var/log/messages
|
||||
|
||||
#
|
||||
# Emergencies are sent to everybody logged in.
|
||||
#
|
||||
*.emerg *
|
||||
|
||||
#
|
||||
# I like to have messages displayed on the console, but only on a virtual
|
||||
# console I usually leave idle.
|
||||
#
|
||||
#daemon,mail.*;\
|
||||
# news.=crit;news.=err;news.=notice;\
|
||||
# *.=debug;*.=info;\
|
||||
# *.=notice;*.=warn /dev/tty8
|
||||
|
||||
# The named pipe /dev/xconsole is for the `xconsole' utility. To use it,
|
||||
# you must invoke `xconsole' with the `-file' option:
|
||||
#
|
||||
# $ xconsole -file /dev/xconsole [...]
|
||||
#
|
||||
# NOTE: adjust the list below, or you'll go crazy if you have a reasonably
|
||||
# busy site..
|
||||
#
|
||||
#daemon.*;mail.*;\
|
||||
# news.err;\
|
||||
# *.=debug;*.=info;\
|
||||
# *.=notice;*.=warn |/dev/xconsole
|
22
evolinux-base/files/root/gitconfig
Normal file
22
evolinux-base/files/root/gitconfig
Normal file
|
@ -0,0 +1,22 @@
|
|||
[core]
|
||||
filemode = true
|
||||
bare = false
|
||||
[color]
|
||||
branch = auto
|
||||
status = auto
|
||||
diff = auto
|
||||
interactive = auto
|
||||
decorate = auto
|
||||
grep = auto
|
||||
ui = true
|
||||
[apply]
|
||||
whitespace = nowarn
|
||||
[alias]
|
||||
a = add
|
||||
aa = add -A .
|
||||
c = commit -v
|
||||
ca = commit -v -a
|
||||
d = diff --ignore-space-change --patience --no-prefix
|
||||
dw = diff --word-diff
|
||||
lg = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative
|
||||
s = status -s -b
|
49
evolinux-base/handlers/main.yml
Normal file
49
evolinux-base/handlers/main.yml
Normal file
|
@ -0,0 +1,49 @@
|
|||
---
|
||||
- name: dpkg-reconfigure-debconf
|
||||
command: dpkg-reconfigure --frontend noninteractive debconf
|
||||
|
||||
- name: dpkg-reconfigure-locales
|
||||
command: dpkg-reconfigure --frontend noninteractive locales
|
||||
|
||||
- name: dpkg-reconfigure-apt
|
||||
command: dpkg-reconfigure --frontend noninteractive apt-listchanges
|
||||
|
||||
# - name: debconf-set-selections
|
||||
# command: debconf-set-selections /root/debconf-preseed
|
||||
|
||||
- name: apt update
|
||||
apt:
|
||||
update_cache: yes
|
||||
|
||||
- name: restart rsyslog
|
||||
service:
|
||||
name: rsyslog
|
||||
state: restarted
|
||||
|
||||
|
||||
- name: remount /home
|
||||
command: mount -o remount /home
|
||||
|
||||
- name: remount /var
|
||||
command: mount -o remount /var
|
||||
|
||||
|
||||
- name: restart nginx
|
||||
service:
|
||||
name: nginx
|
||||
state: restarted
|
||||
|
||||
- name: reload nginx
|
||||
service:
|
||||
name: nginx
|
||||
state: reloaded
|
||||
|
||||
- name: restart apache
|
||||
service:
|
||||
name: apache2
|
||||
state: restarted
|
||||
|
||||
- name: reload apache
|
||||
service:
|
||||
name: apache2
|
||||
state: reloaded
|
55
evolinux-base/tasks/apt.yml
Normal file
55
evolinux-base/tasks/apt.yml
Normal file
|
@ -0,0 +1,55 @@
|
|||
---
|
||||
|
||||
- name: Setting apt config
|
||||
lineinfile:
|
||||
dest: /etc/apt/apt.conf.d/z-evolinux.conf
|
||||
line: "{{ item }}"
|
||||
create: yes
|
||||
state: present
|
||||
mode: 0640
|
||||
with_items:
|
||||
- "APT::Install-Recommends \"0\";"
|
||||
- "APT::Install-Suggests \"0\";"
|
||||
|
||||
- name: DPKg invoke hooks
|
||||
lineinfile:
|
||||
dest: /etc/apt/apt.conf.d/z-evolinux.conf
|
||||
line: "{{ item }}"
|
||||
create: yes
|
||||
state: present
|
||||
mode: 0640
|
||||
with_items:
|
||||
- "DPkg::Pre-Invoke { \"mount -oremount,exec /tmp && mount -oremount,rw /usr || true\"; };"
|
||||
- "DPkg::Post-Invoke { \"mount -oremount /tmp && mount -oremount /usr || exit 0\"; };"
|
||||
when: evolinux_apt_hooks
|
||||
|
||||
- name: Original repositories are disabled
|
||||
replace:
|
||||
dest: /etc/apt/sources.list
|
||||
regexp: '^(deb(-src)? {{ item }}.+)'
|
||||
replace: '# \1'
|
||||
with_items:
|
||||
# - '.+\.debian\.org'
|
||||
- 'cdrom:'
|
||||
|
||||
- name: Basic sources list is installed
|
||||
lineinfile:
|
||||
dest: /etc/apt/sources.list
|
||||
line: "{{ item }}"
|
||||
with_items:
|
||||
- "deb http://security.debian.org/ jessie/updates {{ evolinux_apt_components | mandatory }}"
|
||||
- "deb http://mirror.evolix.org/debian/ jessie {{ evolinux_apt_components | mandatory }}"
|
||||
- "deb http://mirror.evolix.org/debian/ jessie-updates {{ evolinux_apt_components | mandatory }}"
|
||||
|
||||
- name: Evolix public list is installed
|
||||
template:
|
||||
src: apt/evolix_public.list.j2
|
||||
dest: /etc/apt/sources.list.d/evolix_public.list
|
||||
force: yes
|
||||
backup: yes
|
||||
mode: 0640
|
||||
|
||||
- name: Upgrading system
|
||||
apt:
|
||||
upgrade: dist
|
||||
update_cache: yes
|
14
evolinux-base/tasks/default_packages.yml
Normal file
14
evolinux-base/tasks/default_packages.yml
Normal file
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
- name: Install/Update default packages (might take some time)
|
||||
command: "apt-get install -yq --allow-unauthenticated {{ evolinux_default_packages | join(' ') }}"
|
||||
register: install_default_packages
|
||||
changed_when: not (install_default_packages.stdout | search("0 upgraded") and install_default_packages.stdout | search("0 newly installed"))
|
||||
|
||||
- name: Deleting rpcbin and nfs-common
|
||||
apt:
|
||||
name: "{{ item }}"
|
||||
state: absent
|
||||
with_items:
|
||||
- rpcbind
|
||||
- nfs-common
|
||||
when: evolinux_delete_nfs
|
108
evolinux-base/tasks/default_www.yml
Normal file
108
evolinux-base/tasks/default_www.yml
Normal file
|
@ -0,0 +1,108 @@
|
|||
---
|
||||
- name: /var/www is present
|
||||
file:
|
||||
path: /var/www
|
||||
state: directory
|
||||
mode: 0755
|
||||
|
||||
- name: images are copied
|
||||
copy:
|
||||
src: default_www/img
|
||||
dest: /var/www/
|
||||
mode: 0755
|
||||
directory_mode: 0755
|
||||
follow: yes
|
||||
|
||||
- name: index is copied
|
||||
template:
|
||||
src: default_www/index.html.j2
|
||||
dest: /var/www/index.html
|
||||
mode: 0755
|
||||
|
||||
# SSL cert
|
||||
|
||||
- name: ssl-cert package is installed
|
||||
apt:
|
||||
name: ssl-cert
|
||||
state: installed
|
||||
|
||||
- name: Create private key and csr for default site ({{ ansible_fqdn }})
|
||||
shell: openssl req -newkey rsa:2048 -sha256 -nodes -keyout /etc/ssl/private/{{ ansible_fqdn }}.key -out /etc/ssl/{{ ansible_fqdn }}.csr -batch -subj "{{ evolinux_default_www_ssl_subject }}"
|
||||
args:
|
||||
creates: "/etc/ssl/private/{{ ansible_fqdn }}.key"
|
||||
|
||||
- name: Adjust rights on private key
|
||||
file:
|
||||
path: /etc/ssl/private/{{ ansible_fqdn }}.key
|
||||
owner: root
|
||||
group: ssl-cert
|
||||
mode: 0640
|
||||
|
||||
- name: Create certificate for default site
|
||||
shell: openssl x509 -req -days 3650 -sha256 -in /etc/ssl/{{ ansible_fqdn }}.csr -signkey /etc/ssl/private/{{ ansible_fqdn }}.key -out /etc/ssl/certs/{{ ansible_fqdn }}.crt
|
||||
args:
|
||||
creates: "/etc/ssl/certs/{{ ansible_fqdn }}.crt"
|
||||
|
||||
|
||||
# Nginx vhost
|
||||
|
||||
- name: is Nginx installed?
|
||||
stat:
|
||||
path: /etc/nginx/sites-available
|
||||
register: nginx_sites_available
|
||||
|
||||
- block:
|
||||
- name: nginx vhost is installed
|
||||
template:
|
||||
src: default_www/nginx_default_site.j2
|
||||
dest: /etc/nginx/sites-available/000-default
|
||||
mode: 0640
|
||||
# force: yes
|
||||
notify: reload nginx
|
||||
tags:
|
||||
- nginx
|
||||
|
||||
|
||||
- name: nginx vhost is enabled
|
||||
file:
|
||||
src: /etc/nginx/sites-available/000-default
|
||||
dest: /etc/nginx/sites-enabled/000-default
|
||||
state: link
|
||||
notify: reload nginx
|
||||
when: evolinux_default_www_nginx_enabled
|
||||
tags:
|
||||
- nginx
|
||||
|
||||
when: nginx_sites_available.stat.exists
|
||||
|
||||
|
||||
# Apache vhost
|
||||
|
||||
- name: is Apache installed?
|
||||
stat:
|
||||
path: /etc/apache2/sites-available
|
||||
register: apache_sites_available
|
||||
|
||||
- block:
|
||||
- name: Apache vhost is installed
|
||||
template:
|
||||
src: default_www/apache_default_site.j2
|
||||
dest: /etc/apache2/sites-available/000-default
|
||||
mode: 0640
|
||||
# force: yes
|
||||
notify: reload apache
|
||||
tags:
|
||||
- apache
|
||||
|
||||
|
||||
- name: Apache vhost is enabled
|
||||
file:
|
||||
src: /etc/apache2/sites-available/000-default
|
||||
dest: /etc/apache2/sites-enabled/000-default
|
||||
state: link
|
||||
notify: reload apache
|
||||
when: evolinux_default_www_apache_enabled
|
||||
tags:
|
||||
- apache
|
||||
|
||||
when: apache_sites_available.stat.exists
|
53
evolinux-base/tasks/fstab.yml
Normal file
53
evolinux-base/tasks/fstab.yml
Normal file
|
@ -0,0 +1,53 @@
|
|||
---
|
||||
# TODO: trouver comment faire une copie initiale de /etc/fstab
|
||||
# TODO: try to use the custom mount_uuid module for a different approach
|
||||
|
||||
- name: Fetch fstab content
|
||||
shell: "grep -v '^#' /etc/fstab"
|
||||
register: fstab_content
|
||||
failed_when: False
|
||||
changed_when: False
|
||||
|
||||
- name: /home partition is customized (noexec,nosuid,nodev)
|
||||
replace:
|
||||
dest: /etc/fstab
|
||||
regexp: '(\s+/home\s+\w+\s+defaults)(\s+)'
|
||||
replace: '\1,noexec,nosuid,nodev\2'
|
||||
backup: yes
|
||||
notify: remount /home
|
||||
when: "' /home ' in fstab_content.stdout"
|
||||
|
||||
- name: /tmp partition is customized (noexec,nosuid,nodev)
|
||||
replace:
|
||||
dest: /etc/fstab
|
||||
regexp: '(\s+/tmp\s+\w+\s+defaults)(\s+)'
|
||||
replace: '\1,noexec,nosuid,nodev\2'
|
||||
backup: yes
|
||||
when: "' /tmp ' in fstab_content.stdout"
|
||||
|
||||
- name: /usr partition is customized (ro)
|
||||
replace:
|
||||
dest: /etc/fstab
|
||||
regexp: '(\s+/usr\s+\w+\s+defaults)(\s+)'
|
||||
replace: '\1,ro\2'
|
||||
backup: yes
|
||||
when: "' /usr ' in fstab_content.stdout"
|
||||
|
||||
- name: /var partition is customized (nosuid)
|
||||
replace:
|
||||
dest: /etc/fstab
|
||||
regexp: '(\s+/var\s+\w+\s+defaults)(\s+)'
|
||||
replace: '\1,nosuid\2'
|
||||
backup: yes
|
||||
notify: remount /var
|
||||
when: "' /var ' in fstab_content.stdout"
|
||||
|
||||
- name: /var/tmp is created
|
||||
mount:
|
||||
src: tmpfs
|
||||
name: /var/tmpfs
|
||||
fstype: tmpfs
|
||||
opts: defaults,noexec,nosuid,nodev,size=1024m
|
||||
state: mounted
|
||||
|
||||
- meta: flush_handlers
|
71
evolinux-base/tasks/hardware.yml
Normal file
71
evolinux-base/tasks/hardware.yml
Normal file
|
@ -0,0 +1,71 @@
|
|||
---
|
||||
- name: Install pciutils
|
||||
apt:
|
||||
name: pciutils
|
||||
state: present
|
||||
|
||||
## Broadcom NetXtreme II
|
||||
|
||||
- name: Check if Broadcom NetXtreme II device is present
|
||||
shell: "lspci | grep -q 'NetXtreme II'"
|
||||
register: broadcom
|
||||
failed_when: False
|
||||
changed_when: False
|
||||
|
||||
# TODO: add the "non-free" part to the existing sources
|
||||
# instead of adding a new source
|
||||
|
||||
- name: Add non-free repo for Broadcom NetXtreme II
|
||||
apt_repository:
|
||||
repo: 'deb http://mirror.evolix.org/debian/ jessie non-free'
|
||||
state: present
|
||||
when: broadcom|success
|
||||
|
||||
## RAID
|
||||
|
||||
- name: Detect if RAID is installed
|
||||
shell: lspci | grep "RAID bus controller" | grep -v Intel
|
||||
register: raidmodel
|
||||
changed_when: "'FAILED' in raidmodel.stdout"
|
||||
failed_when: "'FAILED' in raidmodel.stdout"
|
||||
|
||||
- block:
|
||||
- name: Install packages for HP hardware
|
||||
apt:
|
||||
name: cciss-vol-status
|
||||
state: present
|
||||
|
||||
- name: Configure packages for HP hardware
|
||||
template:
|
||||
src: hardware/cciss-vol-statusd.j2
|
||||
dest: /etc/init.d/cciss-vol-statusd
|
||||
mode: 0755
|
||||
|
||||
- name: Enable HP hardware in sysctl
|
||||
service:
|
||||
name: cciss-vol-statusd
|
||||
enabled: true
|
||||
state: started
|
||||
when: "'Hewlett-Packard Company Smart Array' in raidmodel.stdout"
|
||||
|
||||
- block:
|
||||
- name: Install packages for DELL/LSI hardware
|
||||
apt:
|
||||
name: "{{ item }}"
|
||||
state: present
|
||||
with_items:
|
||||
- megacli
|
||||
- megaclisas-statusd
|
||||
|
||||
- name: Configure packages for DELL/LSI hardware
|
||||
template:
|
||||
src: hardware/megaclisas-statusd.j2
|
||||
dest: /etc/default/megaclisas-statusd
|
||||
mode: 0755
|
||||
|
||||
- name: Enable DELL/LSI hardware in sysctl
|
||||
service:
|
||||
name: megaclisas-statusd
|
||||
enabled: true
|
||||
state: started
|
||||
when: "'MegaRAID SAS' in raidmodel.stdout"
|
37
evolinux-base/tasks/hostname.yml
Normal file
37
evolinux-base/tasks/hostname.yml
Normal file
|
@ -0,0 +1,37 @@
|
|||
---
|
||||
- name: Set hostname "{{ evolinux_hostname }}"
|
||||
hostname:
|
||||
name: "{{ evolinux_hostname }}"
|
||||
|
||||
- name: Set right localhost line in /etc/hosts
|
||||
replace:
|
||||
dest: /etc/hosts
|
||||
regexp: '^127.0.0.1(\s+)localhost.*$'
|
||||
replace: '127.0.0.1\1localhost.localdomain localhost'
|
||||
|
||||
- name: Set ip+fqdn+hostname in /etc/hosts
|
||||
lineinfile:
|
||||
dest: /etc/hosts
|
||||
line: "{{ ansible_default_ipv4.address }} {{ evolinux_fqdn }} {{ evolinux_hostname }}"
|
||||
insertafter: '127.0.0.1\s+localhost.localdomain'
|
||||
|
||||
- name: 127.0.1.1 is removed
|
||||
lineinfile:
|
||||
dest: /etc/hosts
|
||||
regexp: '^127.0.1.1\s+{{ evolinux_fqdn }}'
|
||||
state: absent
|
||||
|
||||
- name: override ansible_hostname fact
|
||||
set_fact:
|
||||
ansible_hostname: "{{ evolinux_hostname }}"
|
||||
when: ansible_hostname != evolinux_hostname
|
||||
|
||||
- name: override ansible_domain fact
|
||||
set_fact:
|
||||
ansible_domain: "{{ evolinux_domain }}"
|
||||
when: ansible_domain != evolinux_domain
|
||||
|
||||
- name: override ansible_fqdn fact
|
||||
set_fact:
|
||||
ansible_fqdn: "{{ evolinux_fqdn }}"
|
||||
when: ansible_fqdn != evolinux_fqdn
|
39
evolinux-base/tasks/kernel.yml
Normal file
39
evolinux-base/tasks/kernel.yml
Normal file
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
- name: Enable reboot after panic
|
||||
sysctl:
|
||||
name: "{{ item.name }}"
|
||||
value: "{{ item.value }}"
|
||||
sysctl_file: /etc/sysctl.d/evolinux.conf
|
||||
state: present
|
||||
reload: yes
|
||||
with_items:
|
||||
- { name: kernel.panic_on_oops, value: 1 }
|
||||
- { name: kernel.panic, value: 60 }
|
||||
when: evolinux_kernel_reboot_after_panic
|
||||
|
||||
- name: Disable net.ipv4.tcp_timestamps
|
||||
sysctl:
|
||||
name: net.ipv4.tcp_timestamps
|
||||
value: 0
|
||||
sysctl_file: /etc/sysctl.d/evolinux.conf
|
||||
state: present
|
||||
reload: yes
|
||||
when: evolinux_kernel_disable_tcp_timestamps
|
||||
|
||||
- name: Reduce the swapiness
|
||||
sysctl:
|
||||
name: vm.swappiness
|
||||
value: 20
|
||||
sysctl_file: /etc/sysctl.d/evolinux.conf
|
||||
state: present
|
||||
reload: yes
|
||||
when: evolinux_kernel_reduce_swapiness
|
||||
|
||||
- name: Patch for TCP stack vulnerability CVE-2016-5696
|
||||
sysctl:
|
||||
name: net.ipv4.tcp_challenge_ack_limit
|
||||
value: 1073741823
|
||||
sysctl_file: /etc/sysctl.d/evolinux.conf
|
||||
state: present
|
||||
reload: yes
|
||||
when: evolinux_kernel_cve20165696
|
28
evolinux-base/tasks/logs.yml
Normal file
28
evolinux-base/tasks/logs.yml
Normal file
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
|
||||
# TODO: voir comment faire des backups initiaux des fichiers
|
||||
|
||||
- name: Copy rsyslog.conf
|
||||
copy:
|
||||
src: logs/rsyslog.conf
|
||||
dest: /etc/rsyslog.conf
|
||||
mode: 0644
|
||||
notify: restart rsyslog
|
||||
|
||||
- name: Disable logrotate default conf
|
||||
command: mv /etc/logrotate.d/rsyslog /etc/logrotate.d/rsyslog.disabled
|
||||
args:
|
||||
removes: /etc/logrotate.d/rsyslog
|
||||
creates: /etc/logrotate.d/rsyslog.disabled
|
||||
notify: restart rsyslog
|
||||
|
||||
- name: Configure logrotate
|
||||
copy:
|
||||
src: logs/logrotate.d
|
||||
dest: /etc/logrotate.d
|
||||
|
||||
- name: Configure logrotate.conf
|
||||
replace:
|
||||
dest: /etc/logrotate.conf
|
||||
regexp: "rotate [0-9]*"
|
||||
replace: "rotate 12"
|
39
evolinux-base/tasks/main.yml
Normal file
39
evolinux-base/tasks/main.yml
Normal file
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
- name: Hostname
|
||||
include: hostname.yml
|
||||
|
||||
- name: Kernel tuning
|
||||
include: kernel.yml
|
||||
|
||||
- name: Apt configuration and packages install
|
||||
include: apt.yml
|
||||
|
||||
- name: Fstab configuration
|
||||
include: fstab.yml
|
||||
|
||||
- name: Default packages
|
||||
include: default_packages.yml
|
||||
|
||||
- name: System settings
|
||||
include: system.yml
|
||||
|
||||
- name: Root user configuration
|
||||
include: root.yml
|
||||
|
||||
- name: Logs management
|
||||
include: logs.yml
|
||||
|
||||
|
||||
- name: Default index page
|
||||
include: default_www.yml
|
||||
|
||||
- name: Hardware drivers and tools
|
||||
include: hardware.yml
|
||||
|
||||
- name: Customize for Online.net
|
||||
include: provider_online.yml
|
||||
when: evolinux_provider_online
|
||||
|
||||
- name: Customize for Orange FCE
|
||||
include: provider_orange_fce.yml
|
||||
when: evolinux_provider_orange_fce
|
2
evolinux-base/tasks/provider_online.yml
Normal file
2
evolinux-base/tasks/provider_online.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
- debug:
|
||||
msg: "Online DNS servers fails sometimes! Please change them in /etc/resolv.conf."
|
14
evolinux-base/tasks/provider_orange_fce.yml
Normal file
14
evolinux-base/tasks/provider_orange_fce.yml
Normal file
|
@ -0,0 +1,14 @@
|
|||
- name: Customize kernel for Orange FCE
|
||||
sysctl:
|
||||
name: "{{ item.name }}"
|
||||
value: "{{ item.value }}"
|
||||
sysctl_file: /etc/sysctl.d/evolinux_fce.conf
|
||||
state: present
|
||||
reload: yes
|
||||
with_items:
|
||||
- { name: net.ipv4.tcp_keepalive_time, value: 250 }
|
||||
- { name: net.ipv4.tcp_keepalive_intvl, value: 60 }
|
||||
- { name: net.ipv6.conf.all.disable_ipv6, value: 1 }
|
||||
|
||||
- debug:
|
||||
msg: "Orange DNS servers suck! Please change them in /etc/resolv.conf."
|
78
evolinux-base/tasks/root.yml
Normal file
78
evolinux-base/tasks/root.yml
Normal file
|
@ -0,0 +1,78 @@
|
|||
---
|
||||
|
||||
- name: chmod 700 /root
|
||||
file:
|
||||
path: /root
|
||||
state: directory
|
||||
mode: 0700
|
||||
tags:
|
||||
- root
|
||||
|
||||
- name: "Customize root's bashrc..."
|
||||
lineinfile:
|
||||
dest: /root/.bashrc
|
||||
line: "{{ item }}"
|
||||
create: yes
|
||||
state: present
|
||||
with_items:
|
||||
- "export HISTCONTROL=$HISTCONTROL${HISTCONTROL+,}ignoreboth"
|
||||
- "export HISTSIZE=65535"
|
||||
- "export HISTTIMEFORMAT=\"%c : \""
|
||||
tags:
|
||||
- root
|
||||
|
||||
## .bash_history should be append-only
|
||||
|
||||
- name: Create .bash_history if missing
|
||||
copy:
|
||||
content: ""
|
||||
dest: "/root/.bash_history"
|
||||
force: no
|
||||
tags:
|
||||
- root
|
||||
|
||||
- name: Set umask in /root/.profile
|
||||
lineinfile:
|
||||
dest: "/root/.profile"
|
||||
line: "umask 0077"
|
||||
regexp: "umask [0-9]+"
|
||||
tags:
|
||||
- root
|
||||
|
||||
- name: Custom git config for root
|
||||
copy:
|
||||
src: root/gitconfig
|
||||
dest: "/root/.gitconfig"
|
||||
force: no
|
||||
tags:
|
||||
- root
|
||||
|
||||
- name: Is .bash_history append-only
|
||||
shell: lsattr /root/.bash_history | grep -E "^.*a.* "
|
||||
register: bash_history_append_only
|
||||
failed_when: False
|
||||
changed_when: False
|
||||
tags:
|
||||
- root
|
||||
|
||||
- name: Set .bash_history append-only
|
||||
command: chattr +a /root/.bash_history
|
||||
when: bash_history_append_only.rc != 0
|
||||
tags:
|
||||
- root
|
||||
|
||||
- name: Setting vim root configuration
|
||||
lineinfile:
|
||||
dest: /root/.vimrc
|
||||
line: "{{ item }}"
|
||||
create: yes
|
||||
state: present
|
||||
with_items:
|
||||
- "syntax on"
|
||||
- "set hlsearch"
|
||||
- "set background=dark"
|
||||
- "set expandtab"
|
||||
- "set tabstop=4"
|
||||
- "set softtabstop=0"
|
||||
- "set shiftwidth=4"
|
||||
- "set smarttab"
|
104
evolinux-base/tasks/system.yml
Normal file
104
evolinux-base/tasks/system.yml
Normal file
|
@ -0,0 +1,104 @@
|
|||
---
|
||||
- name: /tmp must be world-writable
|
||||
file:
|
||||
path: /tmp
|
||||
state: directory
|
||||
mode: 1777
|
||||
|
||||
- name: Setting default locales
|
||||
lineinfile:
|
||||
dest: /etc/locale.gen
|
||||
line: "{{ item }}"
|
||||
state: present
|
||||
with_items:
|
||||
- "en_US.UTF-8 UTF-8"
|
||||
- "fr_FR ISO-8859-1"
|
||||
- "fr_FR.UTF-8 UTF-8"
|
||||
notify: dpkg-reconfigure-locales
|
||||
# when: not docker
|
||||
|
||||
- name: Setting vim as default editor
|
||||
alternatives:
|
||||
name: editor
|
||||
path: /usr/bin/vim.basic
|
||||
|
||||
- name: Add "umask 027" to /etc/profile.d/evolinux.sh
|
||||
lineinfile:
|
||||
dest: /etc/profile.d/evolinux.sh
|
||||
line: "umask 027"
|
||||
create: yes
|
||||
state: present
|
||||
|
||||
- name: Set /etc/adduser.conf DIR_MODE to 0700
|
||||
replace:
|
||||
dest: /etc/adduser.conf
|
||||
regexp: "^DIR_MODE=.*$"
|
||||
replace: "DIR_MODE=0700"
|
||||
|
||||
# TODO: trouver comment ne pas faire ça sur Xen Dom-U
|
||||
|
||||
- name: Deactivating login on all tty except tty2
|
||||
lineinfile:
|
||||
dest: /etc/securetty
|
||||
line: "tty2"
|
||||
create: yes
|
||||
state: present
|
||||
|
||||
- name: Setting TMOUT to deconnect inactive users
|
||||
lineinfile:
|
||||
dest: /etc/profile
|
||||
line: "export TMOUT=36000"
|
||||
state: present
|
||||
|
||||
#- name: Customizing /etc/fstab
|
||||
|
||||
- name: Modify default umask for cron deamon
|
||||
lineinfile:
|
||||
dest: /etc/default/cron
|
||||
line: "umask 022"
|
||||
create: yes
|
||||
state: present
|
||||
|
||||
- name: Randomize periodic crontabs
|
||||
replace:
|
||||
dest: /etc/crontab
|
||||
regexp: "{{ item.regexp }}"
|
||||
replace: "{{ item.replace }}"
|
||||
backup: "{{ item.backup }}"
|
||||
with_items:
|
||||
- {regexp: '^17((\s*\*){4})', replace: '{{ 59|random(start=1) }}\1', backup: "yes"}
|
||||
- {regexp: '^25\s*6((\s*\*){3})', replace: '{{ 59|random(start=1) }} {{ [0,1,3,4,5,6,7]|random }}\1', backup: "no"}
|
||||
- {regexp: '^47\s*6((\s*\*){2}\s*7)', replace: '{{ 59|random(start=1) }} {{ [0,1,3,4,5,6,7]|random }}\1', backup: "no"}
|
||||
- {regexp: '^52\s*6(\s*1(\s*\*){2})', replace: '{{ 59|random(start=1) }} {{ [0,1,3,4,5,6,7]|random }}\1', backup: "no"}
|
||||
|
||||
# NTP server address
|
||||
|
||||
- name: Configure NTP
|
||||
replace:
|
||||
dest: /etc/ntp.conf
|
||||
regexp: "^server .*$"
|
||||
replace: "server {{ evolinux_ntp_server }}"
|
||||
backup: yes
|
||||
when: evolinux_ntp_server | default(False)
|
||||
|
||||
## alert5
|
||||
|
||||
- name: "Install alert5 init script"
|
||||
template:
|
||||
src: system/init_alert5.j2
|
||||
dest: /etc/init.d/alert5
|
||||
mode: 0755
|
||||
|
||||
- name: Enable alert5 init script
|
||||
service:
|
||||
name: alert5
|
||||
enabled: yes
|
||||
|
||||
## network interfaces
|
||||
|
||||
- name: "Network interfaces must be \"auto\" and not \"allow-hotplug\""
|
||||
replace:
|
||||
dest: /etc/network/interfaces
|
||||
regexp: "allow-hotplug"
|
||||
replace: "auto"
|
||||
backup: yes
|
2
evolinux-base/templates/apt/evolix_public.list.j2
Normal file
2
evolinux-base/templates/apt/evolix_public.list.j2
Normal file
|
@ -0,0 +1,2 @@
|
|||
deb http://pub.evolix.net/ kernel/
|
||||
deb http://pub.evolix.net/ jessie/
|
55
evolinux-base/templates/default_www/apache_default_site.j2
Normal file
55
evolinux-base/templates/default_www/apache_default_site.j2
Normal file
|
@ -0,0 +1,55 @@
|
|||
<VirtualHost *:80 *:443>
|
||||
ServerName {{ ansible_fqdn }}
|
||||
ServerAdmin webmaster@localhost
|
||||
DocumentRoot /var/www/
|
||||
|
||||
SSLEngine on
|
||||
SSLCertificateFile /etc/ssl/certs/{{ ansible_fqdn }}.crt
|
||||
SSLCertificateKeyFile /etc/ssl/private/{{ ansible_fqdn }}.key
|
||||
SSLProtocol all -SSLv2 -SSLv3
|
||||
|
||||
# Redirect to HTTPS, execpt for server-status, because Munin plugin
|
||||
# can't handle HTTPS! :(
|
||||
RewriteEngine on
|
||||
RewriteCond %{REQUEST_URI} !^/server-status.*$ [NC]
|
||||
RewriteCond %{REQUEST_URI} !^/munin_opcache.php$ [NC]
|
||||
RewriteRule ^/(.*) https://{{ ansible_fqdn }}/$1 [L,R=permanent]
|
||||
|
||||
<Directory />
|
||||
Options FollowSymLinks
|
||||
AllowOverride None
|
||||
Deny from all
|
||||
Include /etc/apache2/private_ipaddr_whitelist.conf
|
||||
</Directory>
|
||||
|
||||
<Directory /var/www/>
|
||||
Options Indexes FollowSymLinks MultiViews
|
||||
AllowOverride None
|
||||
</Directory>
|
||||
|
||||
<Location /munin_opcache.php>
|
||||
Deny from all
|
||||
Allow from 127.0.0.1
|
||||
Include /etc/apache2/private_ipaddr_whitelist.conf
|
||||
</Location>
|
||||
|
||||
ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
|
||||
<Directory "/usr/lib/cgi-bin">
|
||||
AllowOverride None
|
||||
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
|
||||
</Directory>
|
||||
|
||||
ErrorDocument 403 {{ evolinux_default_www_redirect_url }}
|
||||
CustomLog /var/log/apache2/access.log vhost_combined
|
||||
ErrorLog /var/log/apache2/error.log
|
||||
LogLevel warn
|
||||
|
||||
Alias /munin /var/cache/munin/www
|
||||
Alias /phpmyadmin-SED_RANDOM /usr/share/phpmyadmin/
|
||||
IncludeOptional /etc/apache2/conf-available/phpmyadmin*
|
||||
|
||||
<Files ~ "\.(inc|bak)$">
|
||||
deny from all
|
||||
</Files>
|
||||
|
||||
</VirtualHost>
|
78
evolinux-base/templates/default_www/index.html.j2
Normal file
78
evolinux-base/templates/default_www/index.html.j2
Normal file
|
@ -0,0 +1,78 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" >
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta name="robots" content="noindex, nofollow"/>
|
||||
<link rel="icon" type="image/ico" href="img/favicon.ico" />
|
||||
<title>{{ ansible_hostname }}</title>
|
||||
<style type="text/css">
|
||||
body, html {
|
||||
margin: auto;
|
||||
font-family: "Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;
|
||||
font-size: 14px;
|
||||
border-top: #86CBE7 solid 1px;
|
||||
}
|
||||
#container {
|
||||
padding-top: 20px;
|
||||
width: 500px;
|
||||
margin: auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
h1.hostname {
|
||||
padding-top: 50px;
|
||||
color: #373637;
|
||||
border-bottom: 1px solid #a9a9a9;
|
||||
background-image: url(./img/background-top.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 245px 5px;
|
||||
}
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
li:before
|
||||
{
|
||||
content: "• ";
|
||||
color: #373637;
|
||||
}
|
||||
a {
|
||||
color: #86CBE7;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
color: #373637;
|
||||
text-decoration: none;
|
||||
}
|
||||
p.footer {
|
||||
border-top: 1px solid #a9a9a9;
|
||||
padding-top: 5px;
|
||||
font-size: 12px;
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="container">
|
||||
<h1 class="hostname">{{ ansible_hostname }}</h1>
|
||||
|
||||
<ul>
|
||||
<li><a href="/munin/{{ ansible_domain }}/{{ ansible_fqdn }}/">Stats système</a></li>
|
||||
<!--
|
||||
<li><a href="/phpmyadmin-PHPMASECRET/">Accès PhpMyAdmin</a></li>
|
||||
<li><a href="/mysqlreport.html">Dernier rapport MySQL Tuner</a></li>
|
||||
<li><a href="/cgi-bin/awstats.pl">Stats web</a></li>
|
||||
<li><a href="/info.php">Infos PHP</a></li>
|
||||
<li><a href="/opcache.php">Infos OpCache PHP</a></li>
|
||||
<li><a href="/server-status-RANDOM_SERVERSTATUS/">Server Status</a></li>
|
||||
-->
|
||||
</ul>
|
||||
|
||||
<p class="footer">
|
||||
Powered by <a href="http://www.evolix.fr/">Evolix</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -18,7 +18,7 @@ server {
|
|||
|
||||
access_log /var/log/nginx/access.log;
|
||||
error_log /var/log/nginx/error.log;
|
||||
error_page 403 {{ nginx_default_redirect_url }};
|
||||
error_page 403 {{ evolinux_default_www_redirect_url }};
|
||||
|
||||
root /var/www;
|
||||
|
191
evolinux-base/templates/hardware/cciss-vol-statusd.j2
Normal file
191
evolinux-base/templates/hardware/cciss-vol-statusd.j2
Normal file
|
@ -0,0 +1,191 @@
|
|||
#! /bin/sh
|
||||
|
||||
# Author: Petter Reinholdtsen <pere@hungry.com>
|
||||
# Author: Adam Cécile (Le_Vert) <gandalf@le-vert.net>
|
||||
# License: GNU General Public License v2 or later
|
||||
#
|
||||
### BEGIN INIT INFO
|
||||
# Provides: cciss-vol-statusd
|
||||
# Required-Start: $remote_fs $syslog
|
||||
# Required-Stop: $remote_fs $syslog
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Check cciss_vol_status values in the background.
|
||||
### END INIT INFO
|
||||
|
||||
PATH=/sbin:/bin:/usr/sbin:/usr/bin
|
||||
DESC="cciss-vol-status monitor"
|
||||
NAME="cciss-vol-statusd"
|
||||
PIDFILE=/var/run/$NAME.pid
|
||||
STATUSFILE=/var/run/$NAME.status
|
||||
SCRIPTNAME=/etc/init.d/$NAME
|
||||
|
||||
MAILTO="{{ raid_alert_email or general_alert_email | mandatory }}" # Where to report problems
|
||||
PERIOD=600 # Seconds between each check (default 10 minutes)
|
||||
REMIND=86400 # Seconds between each reminder (default 2 hours)
|
||||
RUN_DAEMON=yes
|
||||
ID=/dev/cciss/sda
|
||||
|
||||
[ -e /etc/default/cciss-vol-statusd ] && . /etc/default/cciss-vol-statusd
|
||||
|
||||
# Gracefully exit if the package has been removed.
|
||||
test -x /usr/sbin/cciss_vol_status || exit 0
|
||||
|
||||
. /lib/lsb/init-functions
|
||||
[ -e /etc/default/rcS ] && . /etc/default/rcS
|
||||
|
||||
if [ $RUN_DAEMON = "no" ] ; then
|
||||
log_begin_msg "cciss-vol-statusd is disabled in /etc/default/cciss-vol-statusd, not starting."
|
||||
log_end_msg 0
|
||||
exit 0
|
||||
fi
|
||||
|
||||
check_cciss() {
|
||||
echo $$ > $PIDFILE.new && mv $PIDFILE.new $PIDFILE
|
||||
while true ; do
|
||||
# Check ever $PERIOD seconds, send email on every status
|
||||
# change and repeat ever $REMIND seconds if the raid is still
|
||||
# bad.
|
||||
if (cciss_vol_status $ID); then
|
||||
BADRAID=false
|
||||
else
|
||||
BADRAID=true
|
||||
logger -t cciss-vol-statusd "detected non-optimal RAID status"
|
||||
fi
|
||||
STATUSCHANGE=false
|
||||
if [ true = "$BADRAID" ] ; then
|
||||
# RAID not OK
|
||||
(cciss_vol_status $ID) > $STATUSFILE.new
|
||||
if [ ! -f $STATUSFILE ] ; then # RAID just became broken
|
||||
STATUSCHANGE=true
|
||||
mv $STATUSFILE.new $STATUSFILE
|
||||
elif cmp -s $STATUSFILE $STATUSFILE.new ; then
|
||||
# No change. Should we send reminder?
|
||||
LASTTIME="`stat -c '%Z' $STATUSFILE`"
|
||||
NOW="`date +%s`"
|
||||
SINCELAST="`expr $NOW - $LASTTIME`"
|
||||
if [ $REMIND -le "$SINCELAST" ]; then
|
||||
# Time to send reminder
|
||||
STATUSCHANGE=true
|
||||
mv $STATUSFILE.new $STATUSFILE
|
||||
else
|
||||
rm $STATUSFILE.new
|
||||
fi
|
||||
else
|
||||
STATUSCHANGE=true
|
||||
mv $STATUSFILE.new $STATUSFILE
|
||||
fi
|
||||
else
|
||||
# RAID OK
|
||||
if [ -f $STATUSFILE ] ; then
|
||||
rm $STATUSFILE
|
||||
STATUSCHANGE=true
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ true = "$STATUSCHANGE" ]; then
|
||||
hostname="`uname -n`"
|
||||
(
|
||||
cat <<EOF
|
||||
This is a RAID status update from cciss-vol-statusd. The cciss_vol_status
|
||||
program reports that one of the RAIDs changed state:
|
||||
|
||||
EOF
|
||||
if [ -f $STATUSFILE ] ; then
|
||||
cat $STATUSFILE
|
||||
else
|
||||
(cciss_vol_status $ID)
|
||||
fi
|
||||
echo
|
||||
echo "Report from $0 on $hostname"
|
||||
) | mail -s "info: CCISS raid status change on $hostname" $MAILTO
|
||||
fi
|
||||
sleep $PERIOD
|
||||
done
|
||||
}
|
||||
|
||||
check_daemon() {
|
||||
# Let's check if there is a daemon which is really running and not timing out
|
||||
DAEMON_RUN=`ps aux | grep "/etc/init.d/cciss-vol-statusd check_cciss" | grep -v grep | grep -v daemon`
|
||||
if [ -n "$DAEMON_RUN" ] ; then
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
# Function that starts the daemon/service.
|
||||
#
|
||||
d_start() {
|
||||
[ -f $PIDFILE ] && PID="`cat $PIDFILE`"
|
||||
if [ "$PID" ] ; then
|
||||
log_progress_msg "Daemon already running. Refusing to start another"
|
||||
return 0
|
||||
elif check_daemon ; then
|
||||
# Use the daemon package to turn this script into a daemon
|
||||
start-stop-daemon --start --quiet --pidfile $PIDFILE \
|
||||
--oknodo --exec /usr/bin/daemon /usr/bin/daemon $SCRIPTNAME check_cciss
|
||||
return 0
|
||||
else
|
||||
log_progress_msg "Daemon is already running. Refusing to start another"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
# Function that stops the daemon/service.
|
||||
#
|
||||
d_stop() {
|
||||
if [ -f $PIDFILE ] ; then
|
||||
start-stop-daemon --stop --oknodo --quiet --pidfile $PIDFILE > /dev/null 2>&1
|
||||
rm -f $PIDFILE
|
||||
else
|
||||
log_progress_msg "Daemon is already stopped."
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# This is a workaround function which does not directly exit and
|
||||
# therefore can be used by a restart
|
||||
d_stop_by_restart() {
|
||||
if [ -f $PIDFILE ] ; then
|
||||
start-stop-daemon --oknodo --stop --quiet --pidfile $PIDFILE
|
||||
rm -f $PIDFILE
|
||||
log_end_msg 0
|
||||
else
|
||||
log_progress_msg "Daemon is already stopped."
|
||||
log_end_msg 0
|
||||
fi
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo -n ""
|
||||
log_begin_msg "Starting $DESC: $NAME"
|
||||
d_start ; CODE=$?
|
||||
log_end_msg $CODE
|
||||
;;
|
||||
stop)
|
||||
log_begin_msg "Stopping $DESC: $NAME"
|
||||
d_stop ; CODE=$?
|
||||
log_end_msg $CODE
|
||||
;;
|
||||
check_cciss)
|
||||
check_cciss
|
||||
;;
|
||||
restart|force-reload)
|
||||
log_begin_msg "Restarting $DESC: $NAME"
|
||||
d_stop_by_restart
|
||||
sleep 1
|
||||
d_start || CODE=$?
|
||||
log_end_msg $CODE
|
||||
;;
|
||||
*)
|
||||
# echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
|
||||
echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
4
evolinux-base/templates/hardware/megaclisas-statusd.j2
Normal file
4
evolinux-base/templates/hardware/megaclisas-statusd.j2
Normal file
|
@ -0,0 +1,4 @@
|
|||
MAILTO={{ raid_alert_email or general_alert_email | mandatory }} # Where to report problems
|
||||
PERIOD=600 # Seconds between each check (default 10 minutes)
|
||||
REMIND=86400 # Seconds between each reminder (default 2 hours)
|
||||
RUN_DAEMON=yes
|
16
evolinux-base/templates/system/init_alert5.j2
Normal file
16
evolinux-base/templates/system/init_alert5.j2
Normal file
|
@ -0,0 +1,16 @@
|
|||
#!/bin/sh
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: alert5
|
||||
# Required-Start: $local_fs
|
||||
# Required-Stop: $local_fs
|
||||
# Should-Start: $all
|
||||
# Should-Stop: $all
|
||||
# Default-Start: 2
|
||||
# Default-Stop:
|
||||
# Short-Description: Send boot/reboot mail on start
|
||||
# Description: Send boot/reboot mail on start
|
||||
### END INIT INFO
|
||||
|
||||
date | mail -s'boot/reboot' {{ reboot_alert_email or general_alert_email | mandatory }}
|
||||
#/etc/init.d/minifirewall start
|
31
evolinux-base/vars/main.yml
Normal file
31
evolinux-base/vars/main.yml
Normal file
|
@ -0,0 +1,31 @@
|
|||
evolinux_default_packages:
|
||||
- serveur-base
|
||||
- strace
|
||||
- htop
|
||||
- iftop
|
||||
- iptraf
|
||||
- ncdu
|
||||
- vim
|
||||
- iotop
|
||||
- rsync
|
||||
- mtr-tiny
|
||||
- sudo
|
||||
- git
|
||||
- subversion
|
||||
- ntp
|
||||
- screen
|
||||
- pv
|
||||
- apg
|
||||
- tcpdump
|
||||
- ntpdate
|
||||
- lsb-release
|
||||
- mutt
|
||||
- pinentry-curses
|
||||
- bc
|
||||
- dnsutils
|
||||
- lm-sensors
|
||||
- conntrack
|
||||
- hdparm
|
||||
- lsb-invalid-mta
|
||||
- smartmontools
|
||||
- tree
|
23
evomaintenance/defaults/main.yml
Normal file
23
evomaintenance/defaults/main.yml
Normal file
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
general_alert_email: "root@localhost"
|
||||
evomaintenance_alert_email: Null
|
||||
|
||||
general_scripts_dir: "/usr/local/bin"
|
||||
evomaintenance_scripts_dir: Null
|
||||
|
||||
evomaintenance_hostname: "{{ ansible_fqdn }}"
|
||||
|
||||
evomaintenance_pg_host: Null
|
||||
evomaintenance_pg_passwd: Null
|
||||
evomaintenance_pg_db: Null
|
||||
evomaintenance_pg_table: Null
|
||||
|
||||
evomaintenance_from: "evomaintenance@{{ ansible_fqdn }}"
|
||||
evomaintenance_full_from: "Evomaintenance <{{ evomaintenance_from }}>"
|
||||
|
||||
evomaintenance_urgency_from: mama.doe@example.com
|
||||
evomaintenance_urgency_tel: "06.00.00.00.00"
|
||||
|
||||
evomaintenance_realm: "{{ ansible_domain }}"
|
||||
|
||||
evomaintenance_hosts: []
|
3
evomaintenance/meta/main.yml
Normal file
3
evomaintenance/meta/main.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
dependencies:
|
||||
- { role: evolinux-sources-list }
|
32
evomaintenance/tasks/main.yml
Normal file
32
evomaintenance/tasks/main.yml
Normal file
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
|
||||
- name: evomaintenance is installed
|
||||
command: "apt-get install -yq --allow-unauthenticated evomaintenance"
|
||||
register: installed_evomaintenance
|
||||
changed_when: not (installed_evomaintenance.stdout | search("0 upgraded") and installed_evomaintenance.stdout | search("0 newly installed"))
|
||||
|
||||
- name: configuration is applied
|
||||
template:
|
||||
src: evomaintenance.j2
|
||||
dest: /etc/evomaintenance.cf
|
||||
|
||||
- name: list users with a shell
|
||||
shell: "cat /etc/passwd | grep -vE \"^root:\" | grep -E \":/[^:]+sh$\" | cut -d: -f6"
|
||||
changed_when: False
|
||||
register: home_of_shell_users
|
||||
|
||||
- include: trap.yml home={{ item }}
|
||||
with_items: "{{ home_of_shell_users.stdout_lines }}"
|
||||
|
||||
- name: minifirewall section for evomaintenance
|
||||
lineinfile:
|
||||
dest: /etc/default/minifirewall
|
||||
line: "/sbin/iptables -A INPUT -p tcp --sport 5432 --dport 1024:65535 -s {{ item }} -m state --state ESTABLISHED,RELATED -j ACCEPT"
|
||||
insertafter: "^# EvoMaintenance"
|
||||
with_items: "{{ evomaintenance_hosts }}"
|
||||
|
||||
- name: remove minifirewall example rule for the proxy
|
||||
lineinfile:
|
||||
dest: /etc/default/minifirewall
|
||||
regexp: '^#.*(--sport 5432).*(-s X\.X\.X\.X)'
|
||||
state: absent
|
26
evomaintenance/tasks/trap.yml
Normal file
26
evomaintenance/tasks/trap.yml
Normal file
|
@ -0,0 +1,26 @@
|
|||
- name: is {{ home }}/.bash_profile present?
|
||||
stat:
|
||||
path: "{{ home }}/.bash_profile"
|
||||
register: bash_profile
|
||||
|
||||
- name: install shell trap in {{ home }}/.bash_profile
|
||||
lineinfile:
|
||||
dest: "{{ home }}/.bash_profile"
|
||||
line: "trap \"sudo {{ evomaintenance_scripts_dir or general_scripts_dir | mandatory }}/evomaintenance.sh\" 0"
|
||||
insertafter: EOF
|
||||
create: no
|
||||
when: bash_profile.stat.exists
|
||||
|
||||
- name: is {{ home }}/.profile present?
|
||||
stat:
|
||||
path: "{{ home }}/.profile"
|
||||
register: profile
|
||||
when: not bash_profile.stat.exists
|
||||
|
||||
- name: install shell trap in {{ home }}/.profile
|
||||
lineinfile:
|
||||
dest: "{{ home }}/.profile"
|
||||
line: "trap \"sudo {{ evomaintenance_scripts_dir or general_scripts_dir | mandatory }}/evomaintenance.sh\" 0"
|
||||
insertafter: EOF
|
||||
create: yes
|
||||
when: not bash_profile.stat.exists
|
13
evomaintenance/templates/evomaintenance.j2
Normal file
13
evomaintenance/templates/evomaintenance.j2
Normal file
|
@ -0,0 +1,13 @@
|
|||
HOSTNAME={{ evomaintenance_hostname }}
|
||||
EVOMAINTMAIL={{ evomaintenance_alert_email or general_alert_email | mandatory }}
|
||||
|
||||
export PGPASSWORD={{ evomaintenance_pg_passwd }}
|
||||
|
||||
PGDB={{ evomaintenance_pg_db }}
|
||||
PGTABLE={{ evomaintenance_pg_table }}
|
||||
PGHOST={{ evomaintenance_pg_host }}
|
||||
FROM={{ evomaintenance_from }}
|
||||
FULLFROM="{{ evomaintenance_full_from }}"
|
||||
URGENCYFROM={{ evomaintenance_urgency_from }}
|
||||
URGENCYTEL="{{ evomaintenance_urgency_tel }}"
|
||||
REALM={{ evomaintenance_realm }}
|
16
fail2ban/README.md
Normal file
16
fail2ban/README.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
# fail2ban
|
||||
|
||||
Install Fail2ban.
|
||||
|
||||
## Tasks
|
||||
|
||||
Everything is in the `tasks/main.yml` file.
|
||||
|
||||
## Available variables
|
||||
|
||||
Main variables are :
|
||||
|
||||
* `general_alert_email`: email address to send various alert messages (default: `root@localhost`).
|
||||
* `fail2ban_alert_email`: email address for messages sent to root (default: `general_alert_email`).
|
||||
|
||||
The full list of variables (with default values) can be found in `defaults/main.yml`.
|
3
fail2ban/defaults/main.yml
Normal file
3
fail2ban/defaults/main.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
general_alert_email: "root@localhost"
|
||||
fail2ban_alert_email: Null
|
3
fail2ban/files/dovecot-evolix.conf
Normal file
3
fail2ban/files/dovecot-evolix.conf
Normal file
|
@ -0,0 +1,3 @@
|
|||
[Definition]
|
||||
failregex = (?: pop3-login|imap-login): .*(?:Authentication failure|Aborted login \(auth failed|Aborted login \(tried to use disabled|Disconnected \(auth failed|Aborted login \(\d+ authentication attempts).*rip=(?P<host>\S*),.*
|
||||
ignoreregex =
|
3
fail2ban/files/sasl-evolix.conf
Normal file
3
fail2ban/files/sasl-evolix.conf
Normal file
|
@ -0,0 +1,3 @@
|
|||
[Definition]
|
||||
failregex = (?i): warning: [-._\w]+\[<HOST>\]: SASL (?:LOGIN|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failed:
|
||||
ignoreregex =
|
5
fail2ban/handlers/main.yml
Normal file
5
fail2ban/handlers/main.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
- name: restart fail2ban
|
||||
service:
|
||||
name: fail2ban
|
||||
state: restarted
|
24
fail2ban/tasks/main.yml
Normal file
24
fail2ban/tasks/main.yml
Normal file
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
- name: package is installed
|
||||
apt:
|
||||
name: fail2ban
|
||||
state: installed
|
||||
tags:
|
||||
- packages
|
||||
|
||||
- name: custom filters are installed
|
||||
copy:
|
||||
src: "{{ item }}"
|
||||
dest: /etc/fail2ban/filter.d/
|
||||
mode: 0644
|
||||
with_items:
|
||||
- dovecot-evolix.conf
|
||||
- sasl-evolix.conf
|
||||
notify: restart fail2ban
|
||||
|
||||
- name: local jail is installed
|
||||
template:
|
||||
src: jail.local.j2
|
||||
dest: /etc/fail2ban/jail.local
|
||||
mode: 0644
|
||||
notify: restart fail2ban
|
27
fail2ban/templates/jail.local.j2
Normal file
27
fail2ban/templates/jail.local.j2
Normal file
|
@ -0,0 +1,27 @@
|
|||
# EvoLinux Fail2Ban config.
|
||||
|
||||
[DEFAULT]
|
||||
|
||||
# "ignoreip" can be an IP address, a CIDR mask or a DNS host
|
||||
ignoreip = 127.0.0.1/8
|
||||
bantime = 600
|
||||
maxretry = 3
|
||||
|
||||
# "backend" specifies the backend used to get files modification. Available
|
||||
# options are "gamin", "polling" and "auto".
|
||||
# yoh: For some reason Debian shipped python-gamin didn't work as expected
|
||||
# This issue left ToDo, so polling is default backend for now
|
||||
backend = auto
|
||||
|
||||
destemail = {{ fail2ban_alert_email or general_alert_email | mandatory }}
|
||||
|
||||
# ACTIONS
|
||||
|
||||
banaction = iptables-multiport
|
||||
mta = sendmail
|
||||
protocol = tcp
|
||||
chain = INPUT
|
||||
action_mwl = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
%(mta)s-whois-lines[name=%(__name__)s, dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"]
|
||||
|
||||
action = %(action_mwl)s
|
|
@ -1,2 +1,3 @@
|
|||
---
|
||||
filebeat_kibana_dashboards: False
|
||||
filebeat_logstash_plugin: False
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
---
|
||||
java8_default_alternative: True
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
---
|
||||
kibana_proxy_domain: "kibana.{{ ansible_fqdn }}"
|
||||
kibana_proxy_ssl_cert: "/etc/ssl/certs/{{ ansible_fqdn }}.crt"
|
||||
kibana_proxy_ssl_key: "/etc/ssl/private/{{ ansible_fqdn }}.key"
|
||||
|
|
6
listupgrade/defaults/main.yml
Normal file
6
listupgrade/defaults/main.yml
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
general_alert_email: "root@localhost"
|
||||
listupgrade_alert_email: Null
|
||||
|
||||
general_scripts_dir: "/usr/local/bin"
|
||||
listupgrade_scripts_dir: Null
|
39
listupgrade/tasks/main.yml
Normal file
39
listupgrade/tasks/main.yml
Normal file
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
- name: Scripts dir is present
|
||||
file:
|
||||
path: "{{ evomaintenance_scripts_dir or general_scripts_dir | mandatory }}"
|
||||
state: directory
|
||||
mode: 0700
|
||||
|
||||
- name: Copy listupgrade script
|
||||
template:
|
||||
src: listupgrade.sh.j2
|
||||
dest: "{{ evomaintenance_scripts_dir or general_scripts_dir | mandatory }}/listupgrade.sh"
|
||||
mode: 0700
|
||||
owner: root
|
||||
group: root
|
||||
force: yes
|
||||
backup: yes
|
||||
|
||||
- name: Create /etc/evolinux
|
||||
file:
|
||||
path: /etc/evolinux
|
||||
state: directory
|
||||
mode: 0600
|
||||
|
||||
- name: Copy listupgrade config
|
||||
template:
|
||||
src: listupgrade.cnf.j2
|
||||
dest: /etc/evolinux/listupgrade.cnf
|
||||
mode: 0600
|
||||
owner: root
|
||||
group: root
|
||||
force: no
|
||||
|
||||
- name: Enable listupgrade cron
|
||||
template:
|
||||
src: listupgrade_cron.j2
|
||||
dest: /etc/cron.d/listupgrade
|
||||
mode: 0600
|
||||
owner: root
|
||||
group: root
|
4
listupgrade/templates/listupgrade.cnf.j2
Normal file
4
listupgrade/templates/listupgrade.cnf.j2
Normal file
|
@ -0,0 +1,4 @@
|
|||
#date="Ce jeudi entre 18h00 et 23h00."
|
||||
#clientmail="client@evolix.net"
|
||||
#mailto="{{ listupgrade_alert_email or general_alert_email | mandatory }}"
|
||||
#hostname=""
|
217
listupgrade/templates/listupgrade.sh.j2
Normal file
217
listupgrade/templates/listupgrade.sh.j2
Normal file
|
@ -0,0 +1,217 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Exit codes :
|
||||
# - 30 : $skip_releases or $skip_packages is set to "all"
|
||||
# - 40 : current release is in $skip_releases list
|
||||
# - 50 : all upgradable packages are in the $skip_packages list
|
||||
# - 60 : current release is not in the $r_releases list
|
||||
# - 70 : at least an upgradable package is not in the $r_packages list
|
||||
|
||||
set -e
|
||||
|
||||
configFile="/etc/evolinux/listupgrade.cnf"
|
||||
|
||||
packages=$(mktemp --tmpdir=/tmp evoupdate.XXX)
|
||||
packagesHold=$(mktemp --tmpdir=/tmp evoupdate.XXX)
|
||||
servicesToRestart=$(mktemp --tmpdir=/tmp evoupdate.XXX)
|
||||
template=$(mktemp --tmpdir=/tmp evoupdate.XXX)
|
||||
clientmail=$(grep EVOMAINTMAIL /etc/evomaintenance.cf | cut -d'=' -f2)
|
||||
mailto=$clientmail
|
||||
date="Ce jeudi entre 18h00 et 23h00."
|
||||
hostname=$(grep HOSTNAME /etc/evomaintenance.cf | cut -d'=' -f2)
|
||||
hostname=${hostname%%.evolix.net}
|
||||
# If hostname is composed with -, remove the first part.
|
||||
if [[ $hostname =~ "-" ]]; then
|
||||
hostname=$(echo $hostname | cut -d'-' -f2-)
|
||||
fi
|
||||
# Edit $configFile to override some variables.
|
||||
[ -r $configFile ] && . $configFile
|
||||
|
||||
# Remove temporary files on exit.
|
||||
trap "rm $packages $packagesHold $servicesToRestart $template" EXIT
|
||||
|
||||
# Parse line in retrieved upgrade file and ensure there is no malicious values.
|
||||
get_value() {
|
||||
file="$1"
|
||||
variable="$2"
|
||||
value="$(grep "^$2:" $1 |head -n 1 |cut -d ':' -f 2 |sed 's/^ //')"
|
||||
if echo "$value" |grep -q -E '^[-.: [:alnum:]]*$'; then
|
||||
echo $value
|
||||
else
|
||||
printf >&2 "Error parsing value \"$value\" for variable $variables.\n"
|
||||
fi
|
||||
}
|
||||
|
||||
# Fetch which packages/releases will be upgraded.
|
||||
fetch_upgrade_info() {
|
||||
upgradeInfo=$(mktemp --tmpdir=/tmp evoupdate.XXX)
|
||||
wget -q -O $upgradeInfo https://upgrades.evolix.org/upgrade
|
||||
r_releases="$(get_value $upgradeInfo "releases")"
|
||||
r_skip_releases="$(get_value $upgradeInfo "skip_releases")"
|
||||
r_packages="$(get_value $upgradeInfo "packages")"
|
||||
r_skip_packages="$(get_value $upgradeInfo "skip_packages")"
|
||||
rm $upgradeInfo
|
||||
}
|
||||
|
||||
# Check if element $element is in (space separated) list $list.
|
||||
is_in() {
|
||||
list="$1"
|
||||
element="$2"
|
||||
|
||||
for i in $list; do
|
||||
if [ "$element" = "$i" ]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
if [[ "$1" != "--cron" ]]; then
|
||||
echo "À quel date/heure allez vous planifier l'envoi ?"
|
||||
echo "Exemple : le jeudi 6 mars entre 18h00 et 23h00"
|
||||
echo -n ">"
|
||||
read date
|
||||
echo "À qui envoyer le mail ?"
|
||||
echo -n ">"
|
||||
read mailto
|
||||
fi
|
||||
|
||||
# Update APT cache and get packages to upgrade and packages on hold.
|
||||
apt -q2 update 2>&1 | (egrep -ve '^(Listing|WARNING|$)' -e upgraded -e 'up to date' || true )
|
||||
apt-mark showhold > $packagesHold
|
||||
apt list --upgradable 2>&1 | grep -v -f $packagesHold | egrep -v '^(Listing|WARNING|$)' > $packages
|
||||
packagesParsable=$(cut -f 1 -d / <$packages |tr '\n' ' ')
|
||||
|
||||
# No updates? Exit!
|
||||
test ! -s $packages && exit 0
|
||||
test ! -s $packagesHold && echo 'Aucun' > $packagesHold
|
||||
|
||||
fetch_upgrade_info
|
||||
local_release=$(cut -f 1 -d . </etc/debian_version)
|
||||
|
||||
# Exit if skip_releases or skip_packages in upgrade info file are set to all.
|
||||
([ "$r_skip_releases" = "all" ] || [ "$r_skip_packages" = "all" ]) && exit 30
|
||||
|
||||
# Exit if the server's release is in skip_releases.
|
||||
[ -n "$r_skip_releases" ] && is_in "$r_skip_releases" "$local_release" && exit 40
|
||||
|
||||
# Exit if all packages to upgrade are listed in skip_packages:
|
||||
# we remove each package to skip from the $packageToUpgrade list. At the end,
|
||||
# if there is no additional packages to upgrade, we can exit.
|
||||
if [ -n "$r_skip_packages" ]; then
|
||||
packageToUpgrade="$packagesParsable"
|
||||
for pkg in $r_skip_packages; do
|
||||
packageToUpgrade="${packageToUpgrade/$pkg}"
|
||||
done
|
||||
packageToUpgrade=$(echo $packageToUpgrade |sed 's/ \+//g')
|
||||
if [ -z "$packageToUpgrade" ]; then
|
||||
exit 50
|
||||
fi
|
||||
fi
|
||||
|
||||
# Exit if the server's release is not in releases.
|
||||
if [ -n "$r_releases" ] && [ "$r_releases" != "all" ]; then
|
||||
is_in "$r_releases" "$local_release" || exit 60
|
||||
fi
|
||||
|
||||
# Exit if there is packages to upgrades that are not in packages list:
|
||||
# we exit at the first package encountered that is not in packages list.
|
||||
if [ -n "$r_packages" ] && [ "$r_packages" != "all" ]; then
|
||||
for pkg in $packagesParsable; do
|
||||
is_in "$r_packages" "$pkg" || exit 70
|
||||
done
|
||||
fi
|
||||
|
||||
# Guess which services will be restarted.
|
||||
for pkg in $packagesParsable; do
|
||||
if echo "$pkg" |grep -qE "^(lib)?apache2"; then
|
||||
echo "Apache2" >>$servicesToRestart
|
||||
elif echo "$pkg" |grep -q "^nginx"; then
|
||||
echo "Nginx" >>$servicesToRestart
|
||||
elif echo "$pkg" |grep -q "^php5-fpm"; then
|
||||
echo "PHP FPM" >>$servicesToRestart
|
||||
elif echo "$pkg" |grep -q "^mysql-server"; then
|
||||
echo "MySQL" >>$servicesToRestart
|
||||
elif echo "$pkg" |grep -q "^mariadb-server"; then
|
||||
echo "MariaDB" >>$servicesToRestart
|
||||
elif echo "$pkg" |grep -qE "^postgresql-[[:digit:]]+\.[[:digit:]]+$"; then
|
||||
echo "PostgreSQL" >>$servicesToRestart
|
||||
elif echo "$pkg" |grep -qE "^tomcat[[:digit:]]+$"; then
|
||||
echo "Tomcat" >>$servicesToRestart
|
||||
elif [ "$pkg" = "redis-server" ]; then
|
||||
echo "redis-server" >>$servicesToRestart
|
||||
elif [ "$pkg" = "mongodb-server" ]; then
|
||||
echo "redis-server" >>$servicesToRestart
|
||||
elif echo "$pkg" |grep -qE "^courier-(pop|imap)"; then
|
||||
echo "Courier POP/IMAP" >>$servicesToRestart
|
||||
elif echo "$pkg" |grep -qE "^dovecot-(pop|imap)d"; then
|
||||
echo "Dovecot POP/IMAP" >>$servicesToRestart
|
||||
elif [ "$pkg" = "samba" ]; then
|
||||
echo "Samba" >>$servicesToRestart
|
||||
elif [ "$pkg" = "slapd" ]; then
|
||||
echo "OpenLDAP" >>$servicesToRestart
|
||||
elif [ "$pkg" = "bind9" ]; then
|
||||
echo "Bind9" >>$servicesToRestart
|
||||
elif [ "$pkg" = "postfix" ]; then
|
||||
echo "Postfix" >>$servicesToRestart
|
||||
elif [ "$pkg" = "haproxy" ]; then
|
||||
echo "HAProxy" >>$servicesToRestart
|
||||
elif [ "$pkg" = "varnish" ]; then
|
||||
echo "Varnish" >>$servicesToRestart
|
||||
|
||||
elif [ "$pkg" = "libc6" ]; then
|
||||
echo "Tous les services (mise à jour de libc6)." >$servicesToRestart
|
||||
break
|
||||
elif echo "$pkg" |grep -q "^libssl"; then
|
||||
echo "Tous les services (mise à jour de libssl)." >$servicesToRestart
|
||||
break
|
||||
fi
|
||||
done
|
||||
test ! -s $servicesToRestart && echo "Aucun" >$servicesToRestart
|
||||
|
||||
cat << EOT > $template
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
Reply-To: equipe@evolix.fr
|
||||
From: equipe@evolix.net
|
||||
To: ${clientmail}
|
||||
Subject: Prochain creneau pour mise a jour de votre serveur $hostname
|
||||
X-Debian-Release: $local_release
|
||||
X-Packages: $packagesParsable
|
||||
X-Date: $date
|
||||
|
||||
Bonjour,
|
||||
|
||||
Des mises-à-jour de sécurité ou mineures sont à réaliser sur votre serveur
|
||||
${hostname}.
|
||||
Sauf indication contraire de votre part, le prochain créneau prévu pour
|
||||
intervenir manuellement pour réaliser ces mises-à-jour est :
|
||||
${date}
|
||||
|
||||
Si nous intervenons, un redémarrage des éventuels services concernés sera
|
||||
réalisé, entraînant a priori quelques secondes de coupure. Si nous ne sommes
|
||||
pas intervenus sur ce créneau, vous recevrez une nouvelle notification la
|
||||
semaine prochaine.
|
||||
|
||||
Voici la listes de packages qui seront mis à jour :
|
||||
|
||||
$(cat $packages)
|
||||
|
||||
Liste des packages dont la mise-à-jour a été manuellement suspendue :
|
||||
|
||||
$(cat $packagesHold)
|
||||
|
||||
Liste des services qui seront redémarrés :
|
||||
|
||||
$(cat $servicesToRestart)
|
||||
|
||||
N'hésitez pas à nous faire toute remarque sur ce créneau d'intervention le plus
|
||||
tôt possible.
|
||||
|
||||
Cordialement,
|
||||
--
|
||||
Équipe Evolix <equipe@evolix.fr>
|
||||
Evolix - Hébergement et Infogérance Open Source http://www.evolix.fr/
|
||||
EOT
|
||||
|
||||
<$template /usr/sbin/sendmail $mailto
|
1
listupgrade/templates/listupgrade_cron.j2
Normal file
1
listupgrade/templates/listupgrade_cron.j2
Normal file
|
@ -0,0 +1 @@
|
|||
42 9 * * 2 root {{ listupgrade_scripts_dir or general_scripts_dir | mandatory }}/listupgrade.sh --cron
|
|
@ -1,2 +1,3 @@
|
|||
---
|
||||
logstash_jvm_xms: 256m
|
||||
logstash_jvm_xmx: 1g
|
||||
|
|
19
minifirewall/README.md
Normal file
19
minifirewall/README.md
Normal file
|
@ -0,0 +1,19 @@
|
|||
# minifirewall
|
||||
|
||||
Install minifirewall a simple and versatile local firewall.
|
||||
|
||||
The firewall is not started by default, but an init script is installed.
|
||||
|
||||
## Tasks
|
||||
|
||||
Everything is in the `tasks/main.yml` file.
|
||||
|
||||
## Available variables
|
||||
|
||||
* `minifirewall_int`: which network interface to protect (default: detected default ipv4 interface)
|
||||
* `minifirewall_ipv6_enabled`: (default: `on`)
|
||||
* `minifirewall_int_lan`: (default: IP/32)
|
||||
* `minifirewall_trusted_ips`: with IP/hosts should be trusted for full access (default: none)
|
||||
* `minifirewall_privilegied_ips`: with IP/hosts should be trusted for restricted access (default: none)
|
||||
|
||||
Some IP/hosts must be configured or the server will be inaccessible via network.
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue