diff --git a/README.md b/README.md new file mode 100644 index 0000000..0611000 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# Vars + +postgres_host + +# Links +http://www.postgresql.org/message-id/CADKbJJXP-eKGf=ntcHRJgTqiN-XhogmD2RJsRdCt4TcW7Mp8=w@mail.gmail.com +http://docs.pgbarman.org/#getting_started diff --git a/defaults/main.yml b/defaults/main.yml new file mode 100644 index 0000000..71de230 --- /dev/null +++ b/defaults/main.yml @@ -0,0 +1,22 @@ +postgresql_apt_key_id: ACCC4CF8 +postgresql_apt_key_url: "https://www.postgresql.org/media/keys/ACCC4CF8.asc" +postgresql_apt_repository: 'deb http://apt.postgresql.org/pub/repos/apt/ {{ansible_distribution_release}}-pgdg main' + +postgres_host_name: "{{ postgres_host }}" +postgres_host_description: "{{ postgres_host_name }} PostgreSQL Database for {{ postgres_host }}" +postgres_version: "9.3" +postgres_include_dir: conf.d +# postgres_include_dir_regex: '{{ postgres_include_dir | replace(".","\.") }}' +postgres_include_dir_fullpath: "/etc/postgresql/{{ postgres_version }}/main/{{ postgres_include_dir }}" + +barman_ip: "{{ ansible_default_ipv4.address }}" +postgres_barman_pass: "{{ 'barman' | md5 }}" + +# wal_level archive or hot_standby +postgres_wal_level: hot_standby + +postgres_confirm_service_restart: yes + +postgres_restart_params: + archive_mode: "on" + wal_level: "{{ postgres_wal_level }}" diff --git a/examples/Vagrantfile b/examples/Vagrantfile new file mode 100644 index 0000000..8bd21a7 --- /dev/null +++ b/examples/Vagrantfile @@ -0,0 +1,46 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +defaultbox = "ubuntu/trusty64" +box = ENV['BOX'] || defaultbox + +ENV['ANSIBLE_ROLES_PATH'] = "../../" + +Vagrant.configure(2) do |config| + + config.vm.box = box + + config.vm.define "barman" do |barman_cfg| + barman_cfg.vm.hostname = "barman" + barman_cfg.vm.network "private_network", type: "dhcp" + barman_cfg.vm.provider :virtualbox do |v| + v.name = "barman" + # v.gui = true + end + end + + config.vm.define "postgres" do |postgres_cfg| + postgres_cfg.vm.hostname = "postgres" + postgres_cfg.vm.network "private_network", type: "dhcp" + postgres_cfg.vm.provider :virtualbox do |v| + v.memory = 4096 + v.name = "postgres" + # v.gui = true + end + end + + config.vm.provision :ansible do |ansible| + ansible.playbook = "vagrant.yml" + ansible.sudo = true + # ansible.tags = ['debug'] + ansible.groups = { + "vagrant" => ["barman", "postgres"], + } + ansible.extra_vars = { + ansible_ssh_user: 'vagrant', + hbase_standalone: true, + } + + end + +end diff --git a/examples/ansible.cfg b/examples/ansible.cfg new file mode 100644 index 0000000..2bba9fb --- /dev/null +++ b/examples/ansible.cfg @@ -0,0 +1,8 @@ +[defaults] +retry_files_save_path = /tmp/retry/ +ansible_managed = Ansible managed: file modified on %Y-%m-%d %H:%M:%S by {uid} on {host} +hostfile = ./vagrant.py +roles_path = ../../ + +[ssh_connection] +ssh_args = -o StrictHostKeyChecking=no diff --git a/examples/barman.yml b/examples/barman.yml new file mode 100644 index 0000000..cfaddb7 --- /dev/null +++ b/examples/barman.yml @@ -0,0 +1,39 @@ +- hosts: all + +- name: set up postgres + gather_facts: no + hosts: postgres + sudo: yes + tasks: + + - name: install PostgreSQL, postgresql-contrib and postgres ansible management requirements + apt: name={{ item }} cache_valid_time=3600 update_cache=yes + with_items: + - postgresql-9.3 + - postgresql-contrib-9.3 + - libpq-dev + - python-psycopg2 + + - name: set listen address to * + lineinfile: dest="/etc/postgresql/9.3/main/postgresql.conf" + regexp="(^\s*)#*(\s*listen_addresses\s*=\s*')[^']*('.*$)" + backrefs=on + line="\1\2*\3" + backup=yes + + - service: name=postgresql state=started +# - postgresql_db: name=barmantest +# sudo_user: postgres +# - postgresql_user: db=barmantest name=barman password=barman +# sudo_user: postgres +# + +- hosts: barman + sudo: yes + gather_facts: no + vars: + postgres_host: "{{ hostvars.postgres.ansible_eth1.ipv4.address }}" + # postgres_host_name: postgres_vagrant + barman_ip: "{{ hostvars.barman.ansible_eth1.ipv4.address }}" + roles: + - barman diff --git a/examples/vagrant.py b/examples/vagrant.py new file mode 100755 index 0000000..e5c6f82 --- /dev/null +++ b/examples/vagrant.py @@ -0,0 +1,47 @@ +#!/usr/bin/python +import json +import string +import os +import argparse +import glob + +parser = argparse.ArgumentParser(description='Process ansible inventory options') +parser.add_argument("-l", "--list", action='store_true', help="list of groups" ) +parser.add_argument("-H", "--host", help="dictionary of variables for host") + +args = parser.parse_args() + +def prettyprint(string): + print json.dumps(string, indent=4, sort_keys=True) + + +def getClients(): + clientListString = os.popen("grep ssh .vagrant/provisioners/ansible/inventory/vagrant_ansible_inventory|tr '=' ' '").read() + clients = {} + for clientString in clientListString.split('\n'): + clientVars = clientString.split() + if len(clientVars) == 5: + c={} + name, _, c['ansible_ssh_host'], _, c['ansible_ssh_port'] = clientVars + clients[name] = c + return clients + +clients=getClients() + +if args.list: + hostlist = { + "_meta" : { + "hostvars": clients + }, + "vpnclients": clients.keys(), + # "setupme" : setupmeHosts + } + prettyprint(hostlist) + +elif args.host: + try: + prettyprint( clients[args.host] ) + except: + pass +else: + prettyprint(clients) diff --git a/examples/vagrant.yml b/examples/vagrant.yml new file mode 100644 index 0000000..1dc8acd --- /dev/null +++ b/examples/vagrant.yml @@ -0,0 +1,8 @@ +- hosts: vagrant + sudo: yes + roles: + - vagrant-simple + tasks: + + - name: now run 'ansible-playbook barman.yml' + debug: msg="now run 'ansible-playbook barman.yml'" diff --git a/handlers/main.yml b/handlers/main.yml new file mode 100644 index 0000000..73eb9e9 --- /dev/null +++ b/handlers/main.yml @@ -0,0 +1,7 @@ +- name: delegate postgresql reload + service: name=postgresql state=reloaded + delegate_to: "{{ postgres_host }}" + +- name: delegate postgres restart + service: name=postgresql state=restarted + delegate_to: "{{ postgres_host }}" diff --git a/tasks/main.yml b/tasks/main.yml new file mode 100644 index 0000000..54f85da --- /dev/null +++ b/tasks/main.yml @@ -0,0 +1,74 @@ +--- +- name: Barman | Add PostgreSQL repository apt-key + apt_key: + id: "{{ postgresql_apt_key_id }}" + url: "{{ postgresql_apt_key_url }}" + state: present + when: postgresql_apt_key_url and postgresql_apt_key_id and ansible_distribution_version|version_compare(14.04, '<') + +- name: Barman | Add PostgreSQL repository + apt_repository: + repo: "{{ postgresql_apt_repository }}" + state: present + when: postgresql_apt_repository and ansible_distribution_version|version_compare(14.04, '<') + +- name: Barman | Install Barman + apt: + name: "{{ item }}" + state: "present" + with_items: + - barman + # - postgresql-client + +- name: create /etc/barman.d + file: dest=/etc/barman.d state=directory + +- name: deploy global configuration + template: src=barman.conf dest=/etc/barman.conf + +- name: deploy server specific configuration + template: src=barman.d/template.conf dest=/etc/barman.d/{{ postgres_host_name }}.conf + +- name: setup postgres server and access + include: postgres.yml + +- name: check if there's a backup + shell: barman show-backup {{ postgres_host_name }} latest + register: latest_backup + changed_when: latest_backup.rc != 0 + failed_when: false + sudo_user: barman + +- name: initiate backup for server if there're still 0 of them + shell: barman backup {{ postgres_host_name }} | logger -t barman_{{ postgres_host_name }} + sudo_user: barman + when: latest_backup.changed + +- name: check requirements + shell: "barman check {{ postgres_host_name }}" + changed_when: false + sudo_user: barman + +- name: remove default cron to add log support + lineinfile: dest=/etc/cron.d/barman + state=absent + regexp='^\s*\*\s+\*\s+\*\s+\*\s+\*\s+barman\s*\[\s*-x\s*/usr/bin/barman\s*\]\s*&&\s*/usr/bin/barman\s*-q\s*cron\s?$' + tags: cron + +- name: replace default cron to add log support + cron: + name: "barman cron" + cron_file: barman + user: barman + job: "[ -x /usr/bin/barman ] cron 2>&1 | /usr/bin/logger -t barman" + tags: cron + +- name: add daily backups for all servers + cron: + hour: 4 + minute: 4 + name: "barman backup all" + cron_file: barman + user: barman + job: "[ -x /usr/bin/barman ] backup all 2>&1 | /usr/bin/logger -t barman" + tags: cron diff --git a/tasks/postgres.yml b/tasks/postgres.yml new file mode 100644 index 0000000..b846068 --- /dev/null +++ b/tasks/postgres.yml @@ -0,0 +1,83 @@ +- name: install ansible management requirements + apt: name={{ item }} cache_valid_time=3600 update_cache=yes + with_items: + - libpq-dev + - python-psycopg2 + delegate_to: "{{ postgres_host }}" + +- name: read configuration parameters + shell: barman show-server all + changed_when: false + register: config_all_raw + tags: psql + +- name: import configuration to a fact + set_fact: + config_all: "{{ config_all_raw.stdout.replace('\t',' ') | from_yaml }}" + tags: psql + +- name: check incoming_wals_directory + debug: var=config_all['Server main'].incoming_wals_directory + tags: psql + +- name: create {{ postgres_include_dir_fullpath }} + file: dest={{ postgres_include_dir_fullpath }} state=directory + delegate_to: "{{ postgres_host }}" + tags: psql + +- name: enable {{ postgres_include_dir }} configs inclusion + lineinfile: dest="/etc/postgresql/{{ postgres_version }}/main/postgresql.conf" + regexp="(^\s*)#*(\s*include_dir\s*=\s*')[^']*('.*$)" + backrefs=on + line='\1\2{{ postgres_include_dir }}\3' + backup=yes + delegate_to: "{{ postgres_host }}" + tags: psql + +- name: enable Continuous WAL archiving + template: dest={{ postgres_include_dir_fullpath }}/03_barman.conf src=postgres/barman.conf + delegate_to: "{{ postgres_host }}" + register: delegate_postgres_reload1 + tags: psql + +- name: Allow connections + lineinfile: dest=/etc/postgresql/9.3/main/pg_hba.conf + state=present + regexp="\s*host\s+all\s+barman\s+{{ barman_ip }}\/32" + line="host all barman {{ barman_ip }}/32 md5" + register: delegate_postgres_reload2 + delegate_to: "{{ postgres_host }}" + tags: psql + +- name: delegate postgresql reload + service: name=postgresql state=reloaded + delegate_to: "{{ postgres_host }}" + when: delegate_postgres_reload1.changed or delegate_postgres_reload2.changed + tags: psql + +- name: check if restart is required + command: psql -At -c "SELECT current_setting('{{ item.key }}') <> '{{ item.value }}';" + with_dict: postgres_restart_params + register: postgres_restart_required + always_run: yes + ignore_errors: yes + changed_when: postgres_restart_required.stdout == 't' or postgres_restart_required|failed + delegate_to: "{{ postgres_host }}" + sudo_user: postgres + tags: psql + +- name: pause if restart requires confirmation + pause: prompt="Postgres service restart required and it is going to be performed in the next task!" + when: postgres_restart_required.changed and postgres_confirm_service_restart + tags: psql + +- name: delegate postgresql restart + service: name=postgresql state=restarted + delegate_to: "{{ postgres_host }}" + when: postgres_restart_required.changed + tags: psql + +- include: users.yml + tags: users + +# - debug: msg="'{{ postgres_include_dir_regex }}', '{{ postgres_include_dir }}'" diff --git a/tasks/users.yml b/tasks/users.yml new file mode 100644 index 0000000..b253cfa --- /dev/null +++ b/tasks/users.yml @@ -0,0 +1,83 @@ +- name: generate ssh key for user barman + user: name=barman generate_ssh_key=yes + +- name: generate ssh key for user postgres + user: name=postgres generate_ssh_key=yes + delegate_to: "{{ postgres_host }}" + +- name: read public key for user barman + shell: cat ~/.ssh/id_rsa.pub + register: barman_key + sudo_user: barman + changed_when: no + +- name: read public key for user postgres + shell: cat ~/.ssh/id_rsa.pub + sudo_user: postgres + register: postgres_key + delegate_to: "{{ postgres_host }}" + changed_when: no + +- name: put postgres key for user barman + authorized_key: user=barman key="{{ postgres_key.stdout }}" + +- name: put barman key for user postgres + authorized_key: user=postgres key="{{ barman_key.stdout }}" + delegate_to: "{{ postgres_host }}" + +- name: ensure known_hosts file exists on barman + file: dest=~/.ssh/known_hosts state=touch + changed_when: false + sudo_user: barman + +- name: ensure known_hosts file exists on postgres + file: dest=~/.ssh/known_hosts state=touch + changed_when: false + sudo_user: postgres + delegate_to: "{{ postgres_host }}" + +- name: get postgres rsa key + shell: ssh-keyscan -t rsa {{ postgres_host }} + sudo_user: barman + register: postgres_rsa_key + changed_when: no + tags: keys + +- name: get barman rsa key + shell: ssh-keyscan -t rsa {{ barman_ip }} + sudo_user: postgres + register: barman_rsa_key + delegate_to: "{{ postgres_host }}" + changed_when: no + tags: keys + +- name: ensure we have postgres key in known hosts file for barman + lineinfile: dest=~/.ssh/known_hosts regexp="^{{ postgres_host }}\s+ssh-rsa\s+.*" line="{{ postgres_rsa_key.stdout }}" + sudo_user: barman + tags: keys + +- name: ensure we have barman key in known hosts file for postgres + lineinfile: dest=~/.ssh/known_hosts regexp="^{{ barman_ip }}\s+ssh-rsa\s+.*" line="{{ barman_rsa_key.stdout }}" + sudo_user: postgres + delegate_to: "{{ postgres_host }}" + tags: keys + +- name: create barman superuser on postgres + postgresql_user: name=barman password={{ postgres_barman_pass }} role_attr_flags=SUPERUSER + delegate_to: "{{ postgres_host }}" + sudo_user: postgres + +- name: create db for user barman + postgresql_db: name=barman + delegate_to: "{{ postgres_host }}" + sudo_user: postgres + +# hostname:port:database:username:password +- name: setup access for barman user + lineinfile: dest=~/.pgpass + regexp="^{{ postgres_host }}:[^:]*:[^:]:barman:" + line="{{ postgres_host }}:*:*:barman:{{ postgres_barman_pass }}" + state=present + create=yes + mode=600 + sudo_user: barman diff --git a/templates/barman.conf b/templates/barman.conf new file mode 100644 index 0000000..8634642 --- /dev/null +++ b/templates/barman.conf @@ -0,0 +1,68 @@ +; Barman, Backup and Recovery Manager for PostgreSQL +; http://www.pgbarman.org/ - http://www.2ndQuadrant.com/ +; +; Main configuration file + +[barman] +; Main directory +barman_home = /var/lib/barman + +; System user +barman_user = barman + +; Log location +log_file = /var/log/barman/barman.log +; log_level = DEBUG + +; Default compression level: possible values are None (default), bzip2, gzip or custom +;compression = gzip + +; Pre/post backup hook scripts +;pre_backup_script = env | grep ^BARMAN +;post_backup_script = env | grep ^BARMAN + +; Pre/post archive hook scripts +;pre_archive_script = env | grep ^BARMAN +;post_archive_script = env | grep ^BARMAN + +; Directory of configuration files. Place your sections in separate files with .conf extension +; For example place the 'main' server section in /etc/barman.d/main.conf +configuration_files_directory = /etc/barman.d + +; Minimum number of required backups (redundancy) +minimum_redundancy = 1 + +; Global retention policy (REDUNDANCY or RECOVERY WINDOW) - default empty +;retention_policy = + +; Global bandwidth limit in KBPS - default 0 (meaning no limit) +;bandwidth_limit = 4000 + +; Immediate checkpoint for backup command +;immediate_checkpoint = false + +; Enable network compression for data transfers +;network_compression = false + +;; ; 'main' PostgreSQL Server configuration +;; [main] +;; ; Human readable description +;; description = "Main PostgreSQL Database" +;; +;; ; SSH options +;; ssh_command = ssh postgres@pg +;; +;; ; PostgreSQL connection string +;; conninfo = host=pg user=postgres +;; +;; ; Minimum number of required backups (redundancy) +;; ; minimum_redundancy = 1 +;; +;; ; Examples of retention policies +;; +;; ; Retention policy (disabled) +;; ; retention_policy = +;; ; Retention policy (based on redundancy) +;; ; retention_policy = REDUNDANCY 2 +;; ; Retention policy (based on recovery window) +;; ; retention_policy = RECOVERY WINDOW OF 4 WEEKS diff --git a/templates/barman.d/template.conf b/templates/barman.d/template.conf new file mode 100644 index 0000000..211118a --- /dev/null +++ b/templates/barman.d/template.conf @@ -0,0 +1,7 @@ +;{{ ansible_managed }} +[{{ postgres_host_name }}] +description = "{{ postgres_host_description }}" +ssh_command = ssh postgres@{{ postgres_host }} +conninfo = host={{ postgres_host }} user=barman +compression = gzip +retention_policy = REDUNDANCY 4 diff --git a/templates/postgres/barman.conf b/templates/postgres/barman.conf new file mode 100644 index 0000000..f44f7f2 --- /dev/null +++ b/templates/postgres/barman.conf @@ -0,0 +1,4 @@ +# {{ ansible_managed }} +wal_level = '{{ postgres_wal_level }}' +archive_mode = on +archive_command = 'rsync -a %p barman@{{ barman_ip }}:{{ config_all[ 'Server ' + postgres_host_name ].incoming_wals_directory }}/%f'