From 6034d87f9713d243242fc2a7b76f6da877ebcfec Mon Sep 17 00:00:00 2001 From: "Heise, Peter" Date: Mon, 9 Aug 2021 16:54:00 +0000 Subject: [PATCH] feature/postgresql-cluster --- README.md | 36 +- create-database-cluster.yml | 104 ++++ ...abase.yml => create-database-container.yml | 3 +- group_vars/all/plain.yml | 2 + group_vars/all/vault.yml | 144 +++--- group_vars/postgres/plain.yml | 7 +- group_vars/stage_dev/plain.yml | 15 + info.yml | 25 + poetry.lock | 447 ++++++++++++++++++ pyproject.toml | 18 + .../templates/firewall-monitoring.json.j2 | 13 + roles/postgres/defaults/main.yml | 11 + roles/postgres/tasks/base-requirements.yml | 91 ++++ roles/postgres/tasks/main.yml | 48 ++ roles/postgres/tasks/master-requirements.yml | 159 +++++++ roles/postgres/tasks/postgres-acls.yml | 79 ++++ roles/postgres/tasks/slave-requirements.yml | 85 ++++ smardigo.yml | 10 +- 18 files changed, 1212 insertions(+), 85 deletions(-) create mode 100644 create-database-cluster.yml rename create-database.yml => create-database-container.yml (98%) create mode 100644 info.yml create mode 100644 poetry.lock create mode 100644 pyproject.toml create mode 100644 roles/postgres/defaults/main.yml create mode 100644 roles/postgres/tasks/base-requirements.yml create mode 100644 roles/postgres/tasks/main.yml create mode 100644 roles/postgres/tasks/master-requirements.yml create mode 100644 roles/postgres/tasks/postgres-acls.yml create mode 100644 roles/postgres/tasks/slave-requirements.yml diff --git a/README.md b/README.md index e24d800..ec41b18 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,34 @@ # Prepare ansible Installation -Install ansible with Python. - pip3 install ansible +## Option 1 +- Install ansible with Python. +- Install library jmespath (https://jmespath.org/). Will be used to parse JSON data. +- Install hcloud (python library for hetzner) -Install library jmespath (https://jmespath.org/). Will be used to parse JSON data. + pip3 install ansible jmespath hcloud netaddr - pip3 install jmespath +## Option 2 +- Install python dependencies with poetry -Install ansible role for managing hetzner cloud servers. + poetry install + + +# Install needed ansible collections / roles + +## Without poetry - pip3 install hcloud ansible-galaxy collection install hetzner.hcloud ansible-galaxy collection install community.general ansible-galaxy install geerlingguy.kubernetes ansible-galaxy collection install community.kubernetes +## With poetry + + poetry run ansible-galaxy collection install hetzner.hcloud + poetry run ansible-galaxy collection install community.general + poetry run ansible-galaxy install geerlingguy.kubernetes + poetry run ansible-galaxy collection install community.kubernetes + # Setup Create/Start servers for stage-dev @@ -22,17 +36,23 @@ Create/Start servers for stage-dev ansible-playbook -i stage-dev start.yml --vault-password-file ~/vault-pass ansible-playbook -i stage-dev stop.yml --vault-password-file ~/vault-pass +> with Poetry prefix with `poetry run` + # Provisioning ansible-playbook -i stage-dev setup.yml --vault-password-file ~/vault-pass -u root ansible-playbook dynamic-provisioning.yml --vault-password-file ~/vault-pass -e "stage=dev name=test node=01 service=connect" +> with Poetry prefix with `poetry run` + # Setup Smardigo Service Setup/Configure a Server, Database, Realm (keycloak) and Smardigo ansible-playbook create-server.yml -e "stage='dev' tenant_id='sken' cluster_name='test01' cluster_size='1' cluster_service='connect' stage='dev'" ansible-playbook create-database.yml -e "stage='dev' tenant_id='sken' cluster_name='test01' cluster_size='1' cluster_service='connect' stage='dev'" ansible-playbook create-realm.yml -e "stage='dev' tenant_id='sken' cluster_name='test01' cluster_size='1' cluster_service='connect' stage='dev' current_realm_name='sken' current_realm_display_name='S-K-E-N'" - ansible-playbook create-service.yml -e "stage='dev' tenant_id='sken' cluster_name='test01' cluster_size='1' cluster_service='connect' stage='dev' current_realm_name='sken' current_realm_display_name='S-K-E-N'" + ansible-playbook create-service.yml -e "stage='dev' tenant_id='sken' cluster_name='test01' cluster_size='1' cluster_service='connect' stage='dev' current_realm_name='sken' current_realm_display_name='S-K-E-N'" + +> with Poetry prefix with `poetry run` # TODO @@ -49,4 +69,4 @@ AWX wget https://github.com/derailed/k9s/releases/download/v0.24.14/k9s_Linux_x86_64.tar.gz tar -xzf k9s_*.tar.gz -C . ln -s /etc/kubernetes/k9s/k9s /usr/bin/k9s - kubectl taint nodes --all node-role.kubernetes.io/master- \ No newline at end of file + kubectl taint nodes --all node-role.kubernetes.io/master- diff --git a/create-database-cluster.yml b/create-database-cluster.yml new file mode 100644 index 0000000..9952af0 --- /dev/null +++ b/create-database-cluster.yml @@ -0,0 +1,104 @@ +--- + +# Parameters: +# playbook inventory +# stage := the type of the stage (e.g. dev, int, qa, prod) +# tenant_id := (unique key for the tenant, e.g. customer) +# cluster_name := (business name for the cluster, e.g. product, department ) +# cluster_size := (WIP node count for the cluster) (Currently max is 2 master/slave) +# cluster_service := (service to setup, e.g. connect) +# smardigo message callback +# scope_id := (scope id of the management process) +# process_instance_id := (process instance id of the management process) +# smardigo_management_action := (smardigo management action anme of the management process) + +############################################################# +# Creating inventory dynamically for given parameters +############################################################# + +- hosts: localhost + connection: local + gather_facts: false + + pre_tasks: + - name: "Check if ansible version is at least 2.10.x" + assert: + that: + - ansible_version.major >= 2 + - ansible_version.minor >= 10 + msg: "The ansible version has to be at least ({{ ansible_version.full }})" + + tasks: + - name: Add hosts + add_host: + name: "{{ stage }}-{{ tenant_id }}-{{ cluster_name }}-{{ '%02d' | format(item|int) }}" + groups: + - "stage_{{ stage }}" + - "{{ cluster_service }}" + with_sequence: start=1 end={{ cluster_size | default(1) }} + +############################################################# +# Setup databases for created inventory +############################################################# + +- hosts: "stage_{{ stage }}" + serial: "{{ serial_number | default(1) }}" + remote_user: root + + pre_tasks: + - name: "Gathering current server infos from hetzner" + hcloud_server_info: + api_token: "{{ hetzner_authentication_token }}" + register: hetzner_server_infos + delegate_to: 127.0.0.1 + become: false + + - name: "Setting current server infos as fact: hetzner_server_infos_json" + set_fact: + hetzner_server_infos_json: "{{ hetzner_server_infos.hcloud_server_info }}" + delegate_to: 127.0.0.1 + become: false + + - name: "Reading ip address for {{ inventory_hostname }}" + set_fact: + stage_server_ip: "{{ hetzner_server_infos_json | json_query(querystr) | first }}" + vars: + querystr: "[?name=='{{ inventory_hostname }}'].ipv4_address" + delegate_to: 127.0.0.1 + become: false + + - name: "Printing ip address for {{ inventory_hostname }}" + debug: + msg: "{{ stage_server_ip }}" + delegate_to: 127.0.0.1 + become: false + when: + - debug + + roles: + - role: postgres + when: "'postgres' in group_names" + +############################################################# +# Sending smardigo management message to process +############################################################# + +- hosts: "stage_{{ stage }}" + serial: "{{ serial_number | default(5) }}" + connection: local + gather_facts: false + + post_tasks: + - name: "Sending smardigo management message <{{ smardigo_management_action }}> to <{{ scope_id }}/{{ process_instance_id }}>" + uri: + url: "{{ smardigo_management_url }}" + method: POST + body_format: json + body: "{{ lookup('template','smardigo-management-message.json.j2') }}" + headers: + accept: "*/*" + Content-Type: "application/json" + Smardigo-User-Token: "{{ smardigo_management_token }}" + status_code: [200] + retries: 5 + delay: 5 diff --git a/create-database.yml b/create-database-container.yml similarity index 98% rename from create-database.yml rename to create-database-container.yml index dfc5c1e..fb1fc6f 100644 --- a/create-database.yml +++ b/create-database-container.yml @@ -54,7 +54,7 @@ become: false - name: "Setting current server infos as fact: hetzner_server_infos_json" - set_fact: + set_fact: hetzner_server_infos_json: "{{ hetzner_server_infos.hcloud_server_info }}" delegate_to: 127.0.0.1 become: false @@ -77,6 +77,7 @@ roles: - role: postgres-container + when: "'postgres' in group_names" ############################################################# # Sending smardigo management message to process diff --git a/group_vars/all/plain.yml b/group_vars/all/plain.yml index 92f71ae..bc03e26 100644 --- a/group_vars/all/plain.yml +++ b/group_vars/all/plain.yml @@ -132,3 +132,5 @@ hetzner_ssh_keys: #harbor_admin_password: "< see vault >" #harbor_postgresql_password: "< see vault >" + +#vault_replicator_user_password: "< see vault >" diff --git a/group_vars/all/vault.yml b/group_vars/all/vault.yml index ab16530..edc8ad3 100644 --- a/group_vars/all/vault.yml +++ b/group_vars/all/vault.yml @@ -1,72 +1,74 @@ $ANSIBLE_VAULT;1.1;AES256 -64373530623332356231386331653266373239306139363330316238366361343734313334343966 -3230363930626130633962626236383532373862393965330a633732633365383739643333396233 -62663165353231383062623063313032643036323837303464656632396137323233346333333735 -6665343037336438660a313133643264376465396166333961393264363934306263343562373032 -33393333653963366630326635323736653564653164303131623132306633623530623735343436 -61346265383133663839343664343239386134656433663634396665303338633266313430633261 -34393964323636323963646335316432383264663830643136623963303534616430373863393730 -37656235643763383062643162346137386361366566306236393033323037343935636632313030 -32303438333232663030346234313737373236353336373238336631323166363462313837326263 -38313738623461653338626536353330323565376164303233383265306636386234653438616565 -30646265663733373465616532613331633561343132396538393961663761643535626231323733 -32613566396236653839353832623038383232363235656233633366363330656630633236646638 -35303532613762343236626132366338363865643738356139626633653937656331383661626536 -38363762623764663935306462383531353034383232633464323462393432633233373839343436 -38313064656132343236383433396638643864633466303730663936306531363731313537343733 -35343439393733656163663038613366376639343831396363396234623761653564643632356466 -37343837373530376138333939666635643333633739366361316435316130616334396230386237 -37663232626165383062373761323933646236396437336661626663373364653262616539346433 -34653365643964326231616438353432643636366438313438383665363638343833616335376364 -39616636343430363638313466396536643363663264396431313661646438356262323633643663 -62613266383365623330393435643139666136643461323132333363633536323535393261633831 -37366632663935373333643630336139336465383932643935363530313434386235303166323165 -33623565613833386233613235643137646464333831623362336134323362346235646565663232 -63393234333735353938643232393066643632613231633762633266333237386232336330393435 -36323632636439326666313730613536353761373465373961303831653266333231316434313235 -36386464376633396164373834626464613331653337373134383165323137656332663862303637 -62646533653434623036646362623965333039633565663062333538386639336435393635663539 -39363938353662623437376666626363613039643864333165613663316662386535636533613461 -38313533623338653863336338396136646238313766303837663932333839363032303539303931 -66393065623165383361343935633562383461636364643135616331613034363864616236383935 -65376139316562346466656538386166653162613539616135616664376164316463313433633933 -31313938373135613133643031396333333564306531306661643830653966353565643733633736 -39353563303961386164623535666235386561333664343839643136663232333766623630613766 -64316161366266633264626135656633333239366639353838336664353237313839633065323866 -65356461353364313835343563386462616233326266663534303134326666383334383935343733 -37616535336336313631633737386162663035336136663765623732333432623761636263376331 -33353165336634653930656435623765323737666361363039346466353864353833373339616664 -38613931656565373535323838383766316438306430386165383461623666613536373031623762 -32313230663934356631656638656161646661303133333930333737323031663662393037396564 -37323664353164643137316235366137306365663535616330663930616135306131643566666365 -35643934326264636561366265643038626361336366313834616535633930303433323065646563 -61356462373265616663383333343938336435663264373331323437373761646165346634663464 -62383335643134376331636230616531616661393236386532646135633663313766346239323562 -63356139663838353235393566353830666134313934353539613737386332623938383736616337 -65343065303832353934663937666331316331613436363237636534393161326562663834653765 -35646136313532616539373863303633393634626133363538353832306262306335623932613236 -33313131366164666465376438653132663438333131663131343937646238633636353662643438 -31396330313166363461306139306264643137383533643039613035393434383161363532613064 -65646234633662343361353462376239393666333630663433366530636434333637333635393662 -30376337616562346232306636333037643339613961343936373363336564613132333539373834 -38333132326130653862656266313664633831616431656331303565663931666432653964313639 -63313166386266363462636366313261633363613761303263643362376463373737636639626134 -66616134353963656531646538653739306266376638336163643736333832653439653362343936 -66333132396465643464316463336161666366636364353466616164643465646633633365636633 -31623639336666613437613838633537623065313564333338656632326335316265316632633130 -64646331326465656339626461373366393165336134336135616264303830346435306633643562 -30363761396135343635633761613238323162393139383162653131393530353462666630313531 -63663037306231656539363938383430636666636265303034363531383730366462333230353836 -63373639326566646534336436343832353437333136373432366336646631313962343431303538 -37663566383863383062366531386266303962383734633964633236646339623132313739353533 -33353930306238366231313333653732353766343036323934356633623937646366333339326262 -66396264343062636230366664613934303964633432633239363166303961613233613762393235 -61383132643037616134636531643138373964313763643235613733633230393861386238366163 -33326664303639323564363137393165363439306139663738636364333533333938343962363162 -36393239363939313264393237616134383638363063646261613361336130326264336566613663 -66636432353731393832356364316164626536663230333030326362613437393234636335303636 -34373237376135643234646361363934643466313138643638373061383134396431353134383166 -36396237633165616637643832366439316430643234343136303861336138333761356636613834 -34343533366630653735316531333230663562336530663332616565643732303063623731393435 -30373361326630336530633036393930393862646638363165396238333437623563373062623837 -386531326435383563616639633339383734 +64363634663737386334633461386262333537616332666562633062666163633664306663343432 +3864363865353062393836646165643138393533396333320a383161323865353734653033656563 +37633463373163336365666639356362306236646236643433613335623734313462303335333635 +3133616330373534350a666334303966383264663833366538376436396535666633616338336163 +30343266323031633139663338306466313230646233623863383334666332353061333235636236 +37333165336461643261356532306262623231343362613037363933356366643363333663613866 +36373963616238666161653432393565636532666665356665633339316363613336386133633766 +38363430303464386165396536633766383263646631653664376262393832323465333837363566 +65646262323430396237396235303962346264363431313235396264363834366230373036396432 +63623063393336326139623334656434303039393966663030653436373834636539646636386331 +35323839663863313733393261363361666261643463363736653663313364363565643564636536 +61396466613237313938623731623735626264373564633263303336383766306163643561376661 +32396139666433393432646463353730383461323139346461346662326535613532623034646162 +35626666653536666630386135613162343165323637646235383363663232343036383035363063 +37653966663836396531303738333564613933366531373738626132333634623261623533373966 +65663063323831393962373439326334363632326339643863613161316532313534613536363537 +35633666643265303461633564336530353136393063333935383163313766643334333234623430 +34656531643637306365353231303532323732353566316433336138656233336365616638303437 +37633366626139366666333466393436313265643935383631393362323666623131383331383464 +37303838386566396239656330636162386566366131616630316566633333333262333534336463 +64353838306238396637623763633464333966653432653732303063326235383830363237313565 +63366563323537616334396330303131363732626136313437363537656665353564373439313831 +34663834623136333961653737363163376636336264643064343635376532326132363035383637 +37336465653933663931376633346538663866363135626465653138353339646161383636663238 +33313831646163353131303234333637306337613561393361616337373537306161616562343331 +33646362366134373339376366616364633263633562613463663936663966613566346638396434 +36313638313663626538373539353437316363646166393866643062353333386533333632333164 +35643463353731306537316465373730666334626235663039316632626430313337303632616237 +37386633373634333238623464353139316236613039313961653535613835636562393335646637 +33326666653532636230343766323937313331666334333830383264653135663962356138313737 +63316431393565323166343164663530356130316335323662323530373233356435323965303866 +35376462306136333565386533366637333265393264303136663161626661666635323136316430 +66623962616365363962393838333133313133323431636530306539303837333731326566396335 +38636464353936363030303764623861373362656237303032653661613262626431353238336536 +30343865633165613433613635376337643632613562656133633435333063313262366561343535 +36363562313766666263653934376161656332626333323062346131346132323331316332646266 +35373562633639386266646439623866336434373536633236316361383233663363643936656339 +35333736663966326166613261626531616530353165326162653564363832386232313764663737 +30336666356463356161613566373661633566303061353439373162306330396437356461663139 +31646465623234343130623736653031326230323432656462366435653564623433393539626537 +36646536313033663937363535366361386535613436313735383931666533646662633831303538 +64306437306631303162336561323431373464623031333932356433363536346533366430366238 +32306166376262616165353635386164633933663732373933376430396362663465343331616636 +66306431626233343564663235376465623665373536653136633932353265666366633235363461 +62623063613730666530333030613463636363383431653130643137373737393134643064333332 +64393134323137303164623238636235623266323466373430393265323637366131333166643666 +32303338656536373539303433383964373862333032363333373333313839353763643061313930 +35333833353465643938633365366261633438316264356234363766383438366161333862383338 +32633433346462353733323761613633343734393439386333346534393564633166646166306236 +62336266373766363332303866393733353263323164646535323066306134623538663532363665 +39366539386362363538653363336639323634366631393732616563393561363333383435363730 +34626166393239656636366562333261346431366330393339356537383034663961306636356633 +31623262323434656465333536376565373736383537613361373062636631353631636433343161 +62356534326239376264303439373033626336303031313661303333636663366366343534636237 +37356438316539643663363237363131666537333562656439323739656635393665366538323462 +30346539393764316435353962363266653439376232656263326262653833313564633636303639 +61373064373164316462346234313536643537373630323339353866646436663538653234643932 +32353238613166336330633434323363363439373339383139393137376337303531346430396637 +61363638353665373364383365613538373962613830666535636339636336646436326433663065 +64643330313666373035653031326535633739616437386261386333356234343334316432313363 +34626637633362343464646565343330383239303431316333323337626531623966316438623839 +37623461303138653030356632623064656333373866633165353062613831313364653135613738 +37666331663532366437393663636237636333636564656131303331643961363737626437353934 +34633463353561313035613261323137386461313362626462626335306433383530313534626539 +30656638396232303031363937643164653230356462663435636436306166383436383231383935 +61653937353163666234333465363237386465656637313235386338626561306531363633626563 +34343431663238663633643165326664346237356337646231653639313234633332623330623734 +66656166303666656565626461626332383261353862366562626231646461323231393162323738 +33303236326362383932643533383165613766376666333338666636316636353062346136623335 +32643966353734616333336665653032363162623035346662386237623663356666303038346137 +61383334643762663865393264343533386666343435313661613133613535336466373638363165 +64623062623932323137633162623832356566393464333061646537613431616339393131333137 +36643639383639326537316434643761653762356130633165373637303938343930 diff --git a/group_vars/postgres/plain.yml b/group_vars/postgres/plain.yml index eb102d7..d9bc925 100644 --- a/group_vars/postgres/plain.yml +++ b/group_vars/postgres/plain.yml @@ -1,5 +1,10 @@ --- hetzner_server_labels: "stage={{ stage }} service=postgres" - hetzner_server_type: cpx11 + +postgres_acls: + - name: smardigo + user: smardigo + password: smardigo + trusted_cidr_entry: 10.0.0.0/16 diff --git a/group_vars/stage_dev/plain.yml b/group_vars/stage_dev/plain.yml index 9fd57fe..045e7b3 100644 --- a/group_vars/stage_dev/plain.yml +++ b/group_vars/stage_dev/plain.yml @@ -4,6 +4,8 @@ stage: "dev" alertmanager_channel_smardigo: "#monitoring-qa" +shared_service_netword: "10.0.0.0/16" + # TODO read configuration with hetzner rest api shared_service_elastic_01: "10.0.0.2" shared_service_elastic_02: "10.0.0.3" @@ -13,12 +15,17 @@ shared_service_docker_ip: "10.0.0.7" shared_service_iam_ip: "10.0.0.13" shared_service_keycloak_ip: "10.0.0.6" shared_service_mail_ip: "10.0.0.8" +shared_service_pg_master_ip: "10.0.0.17" +shared_service_pg_slave_ip: "10.0.0.18" shared_service_awx_hostname: dev-awx-01.smardigo.digital shared_service_docker_registry_hostname: dev-docker-registry-01.smardigo.digital shared_service_iam_hostname: "dev-iam-01.smardigo.digital" shared_service_keycloak_hostname: "dev-keycloak-01.smardigo.digital" shared_service_mail_hostname: "dev-mail-01.smardigo.digital" +shared_service_pg_master_hostname: "dev-postgres-01.smardigo.digital" +shared_service_pg_slave_hostname: "dev-postgres-02.smardigo.digital" + shared_service_hosts: [ { @@ -44,6 +51,14 @@ shared_service_hosts: [ { ip: "{{ shared_service_mail_ip }}", name: "{{ shared_service_mail_hostname }}" + }, + { + ip: "{{ shared_service_pg_master_ip }}", + name: "{{ shared_service_pg_master_hostname }}" + }, + { + ip: "{{ shared_service_pg_slave_ip }}", + name: "{{ shared_service_pg_slave_hostname }}" } ] diff --git a/info.yml b/info.yml new file mode 100644 index 0000000..cf7b4d8 --- /dev/null +++ b/info.yml @@ -0,0 +1,25 @@ +--- +- name: 'apply setup to {{ host | default("all") }}' + hosts: '{{ host | default("all") }}' + serial: "{{ serial_number|default(5) }}" + become: yes + + pre_tasks: + - name: "Check if ansible version is at least 2.10.x" + assert: + that: + - ansible_version.major >= 2 + - ansible_version.minor >= 10 + msg: "The ansible version has to be at least ({{ ansible_version.full }})" + + - name: "Variable " + debug: + msg: "{{ ansible_distribution }}" + - name: "Variable " + debug: + msg: "{{ group_names }}" + - name: "Variable " + debug: + msg: "{{ sudo_group }}" + + roles: diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..90a47ff --- /dev/null +++ b/poetry.lock @@ -0,0 +1,447 @@ +[[package]] +name = "ansible" +version = "4.3.0" +description = "Radically simple IT automation" +category = "main" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" + +[package.dependencies] +ansible-core = ">=2.11.3,<2.12" + +[[package]] +name = "ansible-core" +version = "2.11.3" +description = "Radically simple IT automation" +category = "main" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" + +[package.dependencies] +cryptography = "*" +jinja2 = "*" +packaging = "*" +PyYAML = "*" +resolvelib = ">=0.5.3,<0.6.0" + +[[package]] +name = "certifi" +version = "2021.5.30" +description = "Python package for providing Mozilla's CA Bundle." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "cffi" +version = "1.14.6" +description = "Foreign Function Interface for Python calling C code." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "charset-normalizer" +version = "2.0.4" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "main" +optional = false +python-versions = ">=3.5.0" + +[package.extras] +unicode_backport = ["unicodedata2"] + +[[package]] +name = "cryptography" +version = "3.4.7" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +cffi = ">=1.12" + +[package.extras] +docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"] +docstest = ["doc8", "pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"] +pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"] +sdist = ["setuptools-rust (>=0.11.4)"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["pytest (>=6.0)", "pytest-cov", "pytest-subtests", "pytest-xdist", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"] + +[[package]] +name = "future" +version = "0.18.2" +description = "Clean single-source support for Python 3 and 2" +category = "main" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "hcloud" +version = "1.13.0" +description = "Official Hetzner Cloud python library" +category = "main" +optional = false +python-versions = "!=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <3.11" + +[package.dependencies] +future = ">=0.17.1,<1" +python-dateutil = ">=2.7.5,<3" +requests = ">=2.20,<3" + +[package.extras] +docs = ["Sphinx (==1.8.1)", "sphinx-rtd-theme (==0.4.2)"] + +[[package]] +name = "idna" +version = "3.2" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "jinja2" +version = "3.0.1" +description = "A very fast and expressive template engine." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "jmespath" +version = "0.10.0" +description = "JSON Matching Expressions" +category = "main" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "markupsafe" +version = "2.0.1" +description = "Safely add untrusted strings to HTML/XML markup." +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "netaddr" +version = "0.8.0" +description = "A network address manipulation library for Python" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "packaging" +version = "21.0" +description = "Core utilities for Python packages" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +pyparsing = ">=2.0.2" + +[[package]] +name = "pycparser" +version = "2.20" +description = "C parser in Python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "pyparsing" +version = "2.4.7" +description = "Python parsing module" +category = "main" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pyyaml" +version = "5.4.1" +description = "YAML parser and emitter for Python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[[package]] +name = "requests" +version = "2.26.0" +description = "Python HTTP for Humans." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} +idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} +urllib3 = ">=1.21.1,<1.27" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] + +[[package]] +name = "resolvelib" +version = "0.5.5" +description = "Resolve abstract dependencies into concrete ones" +category = "main" +optional = false +python-versions = "*" + +[package.extras] +examples = ["html5lib", "packaging", "pygraphviz", "requests"] +lint = ["black", "flake8"] +release = ["setl", "towncrier"] +test = ["commentjson", "packaging", "pytest"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "urllib3" +version = "1.26.6" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" + +[package.extras] +brotli = ["brotlipy (>=0.6.0)"] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[metadata] +lock-version = "1.1" +python-versions = ">=3.9,<3.11" +content-hash = "9bb67107f8f659a87e02e90f5bbe3d8c210b00a0aa9b012c0af6123dfb474bda" + +[metadata.files] +ansible = [ + {file = "ansible-4.3.0.tar.gz", hash = "sha256:aeb0007a18e8914dd3ffe0acb2c4377f2d1f25e01c39e845c6cb8b16bdc1018b"}, +] +ansible-core = [ + {file = "ansible-core-2.11.3.tar.gz", hash = "sha256:0ced1b4f67197edb27b50934c95d4cb644c6d635d72c7f826c4425dfe4537674"}, +] +certifi = [ + {file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"}, + {file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"}, +] +cffi = [ + {file = "cffi-1.14.6-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:22b9c3c320171c108e903d61a3723b51e37aaa8c81255b5e7ce102775bd01e2c"}, + {file = "cffi-1.14.6-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:f0c5d1acbfca6ebdd6b1e3eded8d261affb6ddcf2186205518f1428b8569bb99"}, + {file = "cffi-1.14.6-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:99f27fefe34c37ba9875f224a8f36e31d744d8083e00f520f133cab79ad5e819"}, + {file = "cffi-1.14.6-cp27-cp27m-win32.whl", hash = "sha256:55af55e32ae468e9946f741a5d51f9896da6b9bf0bbdd326843fec05c730eb20"}, + {file = "cffi-1.14.6-cp27-cp27m-win_amd64.whl", hash = "sha256:7bcac9a2b4fdbed2c16fa5681356d7121ecabf041f18d97ed5b8e0dd38a80224"}, + {file = "cffi-1.14.6-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ed38b924ce794e505647f7c331b22a693bee1538fdf46b0222c4717b42f744e7"}, + {file = "cffi-1.14.6-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e22dcb48709fc51a7b58a927391b23ab37eb3737a98ac4338e2448bef8559b33"}, + {file = "cffi-1.14.6-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:aedb15f0a5a5949ecb129a82b72b19df97bbbca024081ed2ef88bd5c0a610534"}, + {file = "cffi-1.14.6-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:48916e459c54c4a70e52745639f1db524542140433599e13911b2f329834276a"}, + {file = "cffi-1.14.6-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f627688813d0a4140153ff532537fbe4afea5a3dffce1f9deb7f91f848a832b5"}, + {file = "cffi-1.14.6-cp35-cp35m-win32.whl", hash = "sha256:f0010c6f9d1a4011e429109fda55a225921e3206e7f62a0c22a35344bfd13cca"}, + {file = "cffi-1.14.6-cp35-cp35m-win_amd64.whl", hash = "sha256:57e555a9feb4a8460415f1aac331a2dc833b1115284f7ded7278b54afc5bd218"}, + {file = "cffi-1.14.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e8c6a99be100371dbb046880e7a282152aa5d6127ae01783e37662ef73850d8f"}, + {file = "cffi-1.14.6-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:19ca0dbdeda3b2615421d54bef8985f72af6e0c47082a8d26122adac81a95872"}, + {file = "cffi-1.14.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d950695ae4381ecd856bcaf2b1e866720e4ab9a1498cba61c602e56630ca7195"}, + {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9dc245e3ac69c92ee4c167fbdd7428ec1956d4e754223124991ef29eb57a09d"}, + {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8661b2ce9694ca01c529bfa204dbb144b275a31685a075ce123f12331be790b"}, + {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b315d709717a99f4b27b59b021e6207c64620790ca3e0bde636a6c7f14618abb"}, + {file = "cffi-1.14.6-cp36-cp36m-win32.whl", hash = "sha256:80b06212075346b5546b0417b9f2bf467fea3bfe7352f781ffc05a8ab24ba14a"}, + {file = "cffi-1.14.6-cp36-cp36m-win_amd64.whl", hash = "sha256:a9da7010cec5a12193d1af9872a00888f396aba3dc79186604a09ea3ee7c029e"}, + {file = "cffi-1.14.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4373612d59c404baeb7cbd788a18b2b2a8331abcc84c3ba40051fcd18b17a4d5"}, + {file = "cffi-1.14.6-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f10afb1004f102c7868ebfe91c28f4a712227fe4cb24974350ace1f90e1febbf"}, + {file = "cffi-1.14.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fd4305f86f53dfd8cd3522269ed7fc34856a8ee3709a5e28b2836b2db9d4cd69"}, + {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d6169cb3c6c2ad50db5b868db6491a790300ade1ed5d1da29289d73bbe40b56"}, + {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d4b68e216fc65e9fe4f524c177b54964af043dde734807586cf5435af84045c"}, + {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33791e8a2dc2953f28b8d8d300dde42dd929ac28f974c4b4c6272cb2955cb762"}, + {file = "cffi-1.14.6-cp37-cp37m-win32.whl", hash = "sha256:0c0591bee64e438883b0c92a7bed78f6290d40bf02e54c5bf0978eaf36061771"}, + {file = "cffi-1.14.6-cp37-cp37m-win_amd64.whl", hash = "sha256:8eb687582ed7cd8c4bdbff3df6c0da443eb89c3c72e6e5dcdd9c81729712791a"}, + {file = "cffi-1.14.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ba6f2b3f452e150945d58f4badd92310449876c4c954836cfb1803bdd7b422f0"}, + {file = "cffi-1.14.6-cp38-cp38-manylinux1_i686.whl", hash = "sha256:64fda793737bc4037521d4899be780534b9aea552eb673b9833b01f945904c2e"}, + {file = "cffi-1.14.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:9f3e33c28cd39d1b655ed1ba7247133b6f7fc16fa16887b120c0c670e35ce346"}, + {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26bb2549b72708c833f5abe62b756176022a7b9a7f689b571e74c8478ead51dc"}, + {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb687a11f0a7a1839719edd80f41e459cc5366857ecbed383ff376c4e3cc6afd"}, + {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2ad4d668a5c0645d281dcd17aff2be3212bc109b33814bbb15c4939f44181cc"}, + {file = "cffi-1.14.6-cp38-cp38-win32.whl", hash = "sha256:487d63e1454627c8e47dd230025780e91869cfba4c753a74fda196a1f6ad6548"}, + {file = "cffi-1.14.6-cp38-cp38-win_amd64.whl", hash = "sha256:c33d18eb6e6bc36f09d793c0dc58b0211fccc6ae5149b808da4a62660678b156"}, + {file = "cffi-1.14.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:06c54a68935738d206570b20da5ef2b6b6d92b38ef3ec45c5422c0ebaf338d4d"}, + {file = "cffi-1.14.6-cp39-cp39-manylinux1_i686.whl", hash = "sha256:f174135f5609428cc6e1b9090f9268f5c8935fddb1b25ccb8255a2d50de6789e"}, + {file = "cffi-1.14.6-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f3ebe6e73c319340830a9b2825d32eb6d8475c1dac020b4f0aa774ee3b898d1c"}, + {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c8d896becff2fa653dc4438b54a5a25a971d1f4110b32bd3068db3722c80202"}, + {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4922cd707b25e623b902c86188aca466d3620892db76c0bdd7b99a3d5e61d35f"}, + {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c9e005e9bd57bc987764c32a1bee4364c44fdc11a3cc20a40b93b444984f2b87"}, + {file = "cffi-1.14.6-cp39-cp39-win32.whl", hash = "sha256:eb9e2a346c5238a30a746893f23a9535e700f8192a68c07c0258e7ece6ff3728"}, + {file = "cffi-1.14.6-cp39-cp39-win_amd64.whl", hash = "sha256:818014c754cd3dba7229c0f5884396264d51ffb87ec86e927ef0be140bfdb0d2"}, + {file = "cffi-1.14.6.tar.gz", hash = "sha256:c9a875ce9d7fe32887784274dd533c57909b7b1dcadcc128a2ac21331a9765dd"}, +] +charset-normalizer = [ + {file = "charset-normalizer-2.0.4.tar.gz", hash = "sha256:f23667ebe1084be45f6ae0538e4a5a865206544097e4e8bbcacf42cd02a348f3"}, + {file = "charset_normalizer-2.0.4-py3-none-any.whl", hash = "sha256:0c8911edd15d19223366a194a513099a302055a962bca2cec0f54b8b63175d8b"}, +] +cryptography = [ + {file = "cryptography-3.4.7-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:3d8427734c781ea5f1b41d6589c293089704d4759e34597dce91014ac125aad1"}, + {file = "cryptography-3.4.7-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:8e56e16617872b0957d1c9742a3f94b43533447fd78321514abbe7db216aa250"}, + {file = "cryptography-3.4.7-cp36-abi3-manylinux2010_x86_64.whl", hash = "sha256:37340614f8a5d2fb9aeea67fd159bfe4f5f4ed535b1090ce8ec428b2f15a11f2"}, + {file = "cryptography-3.4.7-cp36-abi3-manylinux2014_aarch64.whl", hash = "sha256:240f5c21aef0b73f40bb9f78d2caff73186700bf1bc6b94285699aff98cc16c6"}, + {file = "cryptography-3.4.7-cp36-abi3-manylinux2014_x86_64.whl", hash = "sha256:1e056c28420c072c5e3cb36e2b23ee55e260cb04eee08f702e0edfec3fb51959"}, + {file = "cryptography-3.4.7-cp36-abi3-win32.whl", hash = "sha256:0f1212a66329c80d68aeeb39b8a16d54ef57071bf22ff4e521657b27372e327d"}, + {file = "cryptography-3.4.7-cp36-abi3-win_amd64.whl", hash = "sha256:de4e5f7f68220d92b7637fc99847475b59154b7a1b3868fb7385337af54ac9ca"}, + {file = "cryptography-3.4.7-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:26965837447f9c82f1855e0bc8bc4fb910240b6e0d16a664bb722df3b5b06873"}, + {file = "cryptography-3.4.7-pp36-pypy36_pp73-manylinux2014_x86_64.whl", hash = "sha256:eb8cc2afe8b05acbd84a43905832ec78e7b3873fb124ca190f574dca7389a87d"}, + {file = "cryptography-3.4.7-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:7ec5d3b029f5fa2b179325908b9cd93db28ab7b85bb6c1db56b10e0b54235177"}, + {file = "cryptography-3.4.7-pp37-pypy37_pp73-manylinux2014_x86_64.whl", hash = "sha256:ee77aa129f481be46f8d92a1a7db57269a2f23052d5f2433b4621bb457081cc9"}, + {file = "cryptography-3.4.7.tar.gz", hash = "sha256:3d10de8116d25649631977cb37da6cbdd2d6fa0e0281d014a5b7d337255ca713"}, +] +future = [ + {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"}, +] +hcloud = [ + {file = "hcloud-1.13.0-py2.py3-none-any.whl", hash = "sha256:4846b195282f99940709b8f2bc633a2eb1243ff8ab997dfb59a3dc13836a4f83"}, + {file = "hcloud-1.13.0.tar.gz", hash = "sha256:f62e1f1aebb6cc8bfb48de677becf02ee14747ddb072ae2dddf1b73632b70439"}, +] +idna = [ + {file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a"}, + {file = "idna-3.2.tar.gz", hash = "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"}, +] +jinja2 = [ + {file = "Jinja2-3.0.1-py3-none-any.whl", hash = "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4"}, + {file = "Jinja2-3.0.1.tar.gz", hash = "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4"}, +] +jmespath = [ + {file = "jmespath-0.10.0-py2.py3-none-any.whl", hash = "sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"}, + {file = "jmespath-0.10.0.tar.gz", hash = "sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9"}, +] +markupsafe = [ + {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, + {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, +] +netaddr = [ + {file = "netaddr-0.8.0-py2.py3-none-any.whl", hash = "sha256:9666d0232c32d2656e5e5f8d735f58fd6c7457ce52fc21c98d45f2af78f990ac"}, + {file = "netaddr-0.8.0.tar.gz", hash = "sha256:d6cc57c7a07b1d9d2e917aa8b36ae8ce61c35ba3fcd1b83ca31c5a0ee2b5a243"}, +] +packaging = [ + {file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"}, + {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"}, +] +pycparser = [ + {file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"}, + {file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"}, +] +pyparsing = [ + {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, + {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, +] +python-dateutil = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] +pyyaml = [ + {file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"}, + {file = "PyYAML-5.4.1-cp27-cp27m-win32.whl", hash = "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393"}, + {file = "PyYAML-5.4.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8"}, + {file = "PyYAML-5.4.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185"}, + {file = "PyYAML-5.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541"}, + {file = "PyYAML-5.4.1-cp36-cp36m-win32.whl", hash = "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5"}, + {file = "PyYAML-5.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df"}, + {file = "PyYAML-5.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"}, + {file = "PyYAML-5.4.1-cp37-cp37m-win32.whl", hash = "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b"}, + {file = "PyYAML-5.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf"}, + {file = "PyYAML-5.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc"}, + {file = "PyYAML-5.4.1-cp38-cp38-win32.whl", hash = "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc"}, + {file = "PyYAML-5.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696"}, + {file = "PyYAML-5.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6"}, + {file = "PyYAML-5.4.1-cp39-cp39-win32.whl", hash = "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10"}, + {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"}, + {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, +] +requests = [ + {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"}, + {file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"}, +] +resolvelib = [ + {file = "resolvelib-0.5.5-py2.py3-none-any.whl", hash = "sha256:b0143b9d074550a6c5163a0f587e49c49017434e3cdfe853941725f5455dd29c"}, + {file = "resolvelib-0.5.5.tar.gz", hash = "sha256:123de56548c90df85137425a3f51eb93df89e2ba719aeb6a8023c032758be950"}, +] +six = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] +urllib3 = [ + {file = "urllib3-1.26.6-py2.py3-none-any.whl", hash = "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4"}, + {file = "urllib3-1.26.6.tar.gz", hash = "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f"}, +] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..e6e6d7c --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,18 @@ +[tool.poetry] +name = "hetzner-ansible" +version = "0.1.0" +description = "" +authors = ["Peter Heise "] + +[tool.poetry.dependencies] +python = ">=3.9,<3.11" +ansible = "^4.3.0" +hcloud = "^1.13.0" +jmespath = "^0.10.0" +netaddr = "^0.8.0" + +[tool.poetry.dev-dependencies] + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/roles/hcloud/templates/firewall-monitoring.json.j2 b/roles/hcloud/templates/firewall-monitoring.json.j2 index 12b3684..c24a2b0 100644 --- a/roles/hcloud/templates/firewall-monitoring.json.j2 +++ b/roles/hcloud/templates/firewall-monitoring.json.j2 @@ -15,6 +15,19 @@ ], "destination_ips": [ ] + }, + { + "direction": "in", + "protocol": "tcp", + "port": "9187", + "source_ips": [ + "149.233.6.129/32", + "212.121.131.106/32", + "79.215.1.110/32", + "94.130.97.253/32" + ], + "destination_ips": [ + ] } ] } diff --git a/roles/postgres/defaults/main.yml b/roles/postgres/defaults/main.yml new file mode 100644 index 0000000..4625689 --- /dev/null +++ b/roles/postgres/defaults/main.yml @@ -0,0 +1,11 @@ +--- +default_postgres_version: 13 +default_postgres_target_distribution: focal-pgdg # (bionic-pgdg, bullseye-pgdg, buster-pgdg, + # focal-pgdg, groovy-pgdg, hirsute-pgdg, + # sid-pgdg, stretch-pgdg, xenial-pgdg) +default_max_connections: 1000 +default_shared_buffers: 256MB + +default_master_ip: "{{ shared_service_pg_master_ip }}" +default_slave_ip: "{{ shared_service_pg_slave_ip }}" +default_private_network: "{{ shared_service_netword }}" diff --git a/roles/postgres/tasks/base-requirements.yml b/roles/postgres/tasks/base-requirements.yml new file mode 100644 index 0000000..731c62f --- /dev/null +++ b/roles/postgres/tasks/base-requirements.yml @@ -0,0 +1,91 @@ +- name: Add Postgresql-Group + group: + name: postgres + gid: 2001 + +- name: Add Postgresql-User + user: + name: postgres + uid: 2000 + group: postgres + home: /var/lib/postgresql + system: true + shell: /bin/bash + +- name: Ensure Repository Meta is installed + apt: + name: ["debian-keyring", "debian-archive-keyring", "apt-transport-https"] + update_cache: yes + cache_valid_time: 900 + state: present + +- name: Add an Apt signing key, uses whichever key is at the URL + ansible.builtin.apt_key: + url: https://www.postgresql.org/media/keys/ACCC4CF8.asc + state: present + validate_certs: false + +- name: Add Postgresql repository into sources list + ansible.builtin.apt_repository: + repo: deb http://apt.postgresql.org/pub/repos/apt {{ default_postgres_target_distribution }} main + state: present + +- name: Ensure postgres is installed + apt: + name: "postgresql-{{ default_postgres_version }}" + update_cache: yes + cache_valid_time: 900 + state: present + +- name: Setup listen interfaces for postgresql instance + lineinfile: + state: present + regex: "^listen_addresses" + line: "listen_addresses = 'localhost,{{ ansible_all_ipv4_addresses | ansible.netcommon.ipaddr(default_private_network) | first }}'" + path: /etc/postgresql/{{ default_postgres_version }}/main/postgresql.conf + register: listen_addresses + +- name: Set 'max_connections = {{ default_max_connections }}' + lineinfile: + state: present + regex: "^max_connections" + line: "max_connections = {{ default_max_connections }}" + path: /etc/postgresql/{{ default_postgres_version }}/main/postgresql.conf + register: max_connections + +- name: "Set 'shared_buffers = {{ default_shared_buffers }}'" + lineinfile: + state: present + regex: "^shared_buffers" + line: "shared_buffers = {{ default_shared_buffers }}" + path: /etc/postgresql/{{ default_postgres_version }}/main/postgresql.conf + register: shared_buffers + +- name: Create archive directory if necessary + file: + state: directory + path: /postgresql/replication + owner: postgres + group: postgres + mode: "g+s" + +- name: Create backups directory if necessary + file: + state: directory + path: /backups + owner: postgres + group: postgres + mode: "g+s" + +- name: "Install prometheus postgres exporter .." + apt: + name: "prometheus-postgres-exporter" + update_cache: yes + cache_valid_time: 900 + state: present + +- name: Restart postgres if necessary + service: + name: postgresql + state: restarted + when: listen_addresses.changed or max_connections.changed or shared_buffers.changed diff --git a/roles/postgres/tasks/main.yml b/roles/postgres/tasks/main.yml new file mode 100644 index 0000000..1626791 --- /dev/null +++ b/roles/postgres/tasks/main.yml @@ -0,0 +1,48 @@ +--- + +### tags: +### postgres_acls + +- name: "Setup master/slave fact for {{ inventory_hostname }}" + set_fact: + server_type: "{% set hostname_splitted = inventory_hostname.split('-') %}{% if hostname_splitted[-1]|int == 1 %}master{% else %}slave{% endif %}" + tags: + - postgres_acls + +- debug: + msg: "Server-Type: {{ server_type }}, Internal-IP {{ default_master_ip }}" + when: + - debug | bool + - server_type == "master" + + tags: + - postgres_acls + +- debug: + msg: "Server-Type: {{ server_type }}, Internal-IP {{ default_slave_ip }}" + when: + - debug | bool + - server_type == "slave" + tags: + - postgres_acls + +# Minimal requirements for postgres +- name: Include Base Requirements + include_tasks: base-requirements.yml + +# Master requirements for postgres +- name: Include Master Requirements + include_tasks: master-requirements.yml + when: server_type == "master" + +# Slave requirements for postgres +- name: Include Slave Requirements + include_tasks: slave-requirements.yml + when: server_type == "slave" + +# Apply Postgres ACLs +- name: Include Postgresl ACL Requirements + include_tasks: postgres-acls.yml + when: server_type == "master" + tags: + - postgres_acls diff --git a/roles/postgres/tasks/master-requirements.yml b/roles/postgres/tasks/master-requirements.yml new file mode 100644 index 0000000..2013e4d --- /dev/null +++ b/roles/postgres/tasks/master-requirements.yml @@ -0,0 +1,159 @@ +--- + +- name: Check role exists + become: yes + become_user: postgres + shell: "/usr/bin/psql -Atc \"SELECT count(rolname) FROM pg_roles where rolname='replicator'\"" + register: role_check + ignore_errors: yes + +- name: Create role if necessary + become: yes + become_user: postgres + shell: "/usr/bin/psql -c 'CREATE ROLE replicator WITH REPLICATION LOGIN;'" + when: role_check.stdout == "0" + ignore_errors: yes + +- name: Change password with scram-sha-256! for replicator and set password + become: yes + become_user: postgres + shell: "/usr/bin/psql -c \"set password_encryption = 'scram-sha-256';ALTER ROLE replicator WITH PASSWORD '{{ vault_replicator_user_password }}';\"" + ignore_errors: yes + +- name: Setup pg_hba.conf for replicator user + lineinfile: + state: present + regex: "^host[ ]+replication[ ]+replicator" + line: "host replication replicator {{ default_slave_ip }}/32 trust" + path: /etc/postgresql/{{ default_postgres_version }}/main/pg_hba.conf + register: pg_hba_conf_replicator + +- name: Set 'wal_level = replica' for master postgresql instance + lineinfile: + state: present + regex: "^wal_level" + line: "wal_level = replica" + path: /etc/postgresql/{{ default_postgres_version }}/main/postgresql.conf + register: wal_level + +- name: Set 'max_wal_senders = 10' for master postgresql instance + lineinfile: + state: present + regex: "^max_wal_senders" + line: "max_wal_senders = 10" + path: /etc/postgresql/{{ default_postgres_version }}/main/postgresql.conf + register: max_wal_senders + +- name: Set 'archive_mode = on' for master postgresql instance + lineinfile: + state: present + regex: "^archive_mode" + line: "archive_mode = on" + path: /etc/postgresql/{{ default_postgres_version }}/main/postgresql.conf + register: archive_mode + +- name: Set 'archive_command = cp -f %p /postgresql/replication/%f' for master postgresql instance + lineinfile: + state: present + regex: "^archive_command" + line: "archive_command = 'cp -f %p /postgresql/replication/%f'" + path: /etc/postgresql/{{ default_postgres_version }}/main/postgresql.conf + register: archive_command + +- name: Set 'wal_keep_size = 16' for master postgresql instance + lineinfile: + state: present + regex: "^wal_keep_size" + line: "wal_keep_size = 16" + path: /etc/postgresql/{{ default_postgres_version }}/main/postgresql.conf + register: wal_keep_size + +- name: Install nfs-server + apt: name=nfs-kernel-server state=present update_cache=yes cache_valid_time=900 + +- name: Install nfs-common + apt: name=nfs-common state=present update_cache=yes cache_valid_time=900 + +- name: Create nfs share for archive + lineinfile: + path: /etc/exports + regex: "^/postgresql/replication" + line: "/postgresql/replication/ {{ default_slave_ip }}/32(rw,crossmnt,root_squash,no_subtree_check,sync)" + state: present + register: nfsshare_archive_check + +- name: Restart nfs-server if necessary + service: + name: nfs-kernel-server + state: restarted + when: nfsshare_archive_check.changed + +- name: Restart postgres if necessary + service: + name: postgresql + state: restarted + when: + pg_hba_conf_replicator.changed or + wal_level.changed or + archive_mode.changed or + archive_command.changed or + max_wal_senders.changed or + wal_keep_size.changed + +- name: Create extension pgcrypto for template1 + become: yes + become_user: postgres + shell: "/usr/bin/psql template1 -c \"create extension if not exists pgcrypto;\"" + ignore_errors: yes + +- name: Check database replication_cron exists + become: yes + become_user: postgres + shell: "/usr/bin/psql -Atc \"SELECT count(*) FROM pg_database WHERE datname = 'replication_cron'\"" + register: database_replication_check + ignore_errors: yes + +- name: Create replication_cron update database + become: yes + become_user: postgres + shell: "/usr/bin/psql -c \"CREATE DATABASE replication_cron;\"" + when: database_replication_check.stdout == "0" + ignore_errors: yes + +- name: Create replication update schema + become: yes + become_user: postgres + shell: "/usr/bin/psql replication_cron -c \"CREATE SCHEMA IF NOT EXISTS replication_cron;\"" + ignore_errors: yes + +- name: Create replication update table + become: yes + become_user: postgres + shell: "/usr/bin/psql replication_cron -c \"CREATE TABLE IF NOT EXISTS replication_cron.replication_cron (dt timestamp);\"" + ignore_errors: yes + +- name: Create dummy update data + become: yes + become_user: postgres + shell: "/usr/bin/psql replication_cron -c \"INSERT INTO replication_cron.replication_cron SELECT now() WHERE NOT EXISTS (SELECT 1 from replication_cron.replication_cron);\"" + ignore_errors: yes + +- name: Ensure a cron runs every 5 minutes and update replication check table" + ansible.builtin.cron: + name: "update replication table" + minute: "*/5" + job: su - postgres -c "/usr/bin/psql replication_cron -c \"UPDATE replication_cron.replication_cron SET dt=now();\"" + +- name: Check replication slot exists + become: yes + become_user: postgres + shell: "/usr/bin/psql -Atc \"select count(*) from pg_replication_slots where slot_name='pgstandby1'\"" + register: replication_slot_check + ignore_errors: yes + +- name: Create replication-slot + become: yes + become_user: postgres + shell: "/usr/bin/psql -Atc \"SELECT pg_create_physical_replication_slot('pgstandby1');\"" + ignore_errors: yes + when: replication_slot_check.stdout == "0" diff --git a/roles/postgres/tasks/postgres-acls.yml b/roles/postgres/tasks/postgres-acls.yml new file mode 100644 index 0000000..3fcc393 --- /dev/null +++ b/roles/postgres/tasks/postgres-acls.yml @@ -0,0 +1,79 @@ +--- + +### properties: +### postgres_acls: +### - name +### - user +### - password +### - trusted_cidr_entry [default_private_network] + +- debug: + msg: "{{ postgres_acls }}" + tags: + - postgres_acls +:1 +- name: "Add pg_hba entries for users/nodes/schemas .." + lineinfile: + state: present + regex: '^host[ ]+{{ item.name }}[ ]+{{ item.user }}' + line: 'host {{ item.name }} {{ item.user }} {{ item.trusted_cidr_entry | default(default_private_network) }} md5' + path: /etc/postgresql/{{ default_postgres_version }}/main/pg_hba.conf + with_items: "{{ postgres_acls }}" + tags: + - postgres_acls + +- name: Check role exists + become: yes + become_user: postgres + shell: "/usr/bin/psql -Atc \"SELECT count(rolname) FROM pg_roles where rolname='{{ item.user }}'\"" + with_items: "{{ postgres_acls }}" + register: role_check + changed_when: "role_check.stdout == '0'" + tags: + - postgres_acls + +- name: Create role if necessary + become: yes + become_user: postgres + shell: "/usr/bin/psql -c 'CREATE ROLE {{ item.item.name }} LOGIN;'" + when: item.stdout == '0' + with_items: "{{ role_check.results }}" + tags: + - postgres_acls + +- name: "check databases exists" + become: yes + become_user: postgres + shell: "/usr/bin/psql -Atc \"SELECT count(*) FROM pg_database WHERE datname = '{{ item.name }}'\"" + with_items: "{{ postgres_acls }}" + register: database_check + changed_when: "database_check.stdout == '0'" + tags: + - postgres_acls + +- name: "Create Databases if necessary" + become: yes + become_user: postgres + shell: "/usr/bin/psql -c \"CREATE DATABASE {{ item.item.name }};\"" + when: item.stdout == '0' + with_items: "{{ database_check.results }}" + tags: + - postgres_acls + +- name: Change password with scram-sha-256! for users and set password + become: yes + become_user: postgres + shell: "/usr/bin/psql -c \"set password_encryption = 'scram-sha-256';ALTER ROLE {{ item.user }} WITH PASSWORD '{{ item.password }}';\"" + with_items: "{{ postgres_acls }}" + register: role_check + tags: + - postgres_acls + +- name: "Change owners for databases" + become: yes + become_user: postgres + shell: "/usr/bin/psql -c \"ALTER DATABASE {{ item.name }} OWNER TO {{ item.user }};\"" + with_items: "{{ postgres_acls }}" + register: role_check + tags: + - postgres_acls diff --git a/roles/postgres/tasks/slave-requirements.yml b/roles/postgres/tasks/slave-requirements.yml new file mode 100644 index 0000000..6ecf760 --- /dev/null +++ b/roles/postgres/tasks/slave-requirements.yml @@ -0,0 +1,85 @@ +--- + +- name: Install nfs-common + apt: name=nfs-common state=present update_cache=yes cache_valid_time=900 + +- name: Set 'hot_standby = on' for slave postgresql instance + lineinfile: + state: present + regex: "^hot_standby " + line: "hot_standby = on" + path: /etc/postgresql/{{ default_postgres_version }}/main/postgresql.conf + +- name: Set 'hot_standby_feedback = on' for slave postgresql instance + lineinfile: + state: present + regex: "^hot_standby_feedback" + line: "hot_standby_feedback = on" + path: /etc/postgresql/{{ default_postgres_version }}/main/postgresql.conf + +- name: Create hosts entry for master (db-master) + lineinfile: + path: /etc/hosts + line: "{{ default_master_ip }} db-master" + state: present + +- name: Create hosts entry for backups (db-backups) + lineinfile: + path: /etc/hosts + line: "{{ default_master_ip }} db-backups" + state: present + +- name: Mount replication NFS volume + ansible.posix.mount: + src: db-master:/postgresql/replication + path: /postgresql/replication + opts: "rw,bg,hard,nfsvers=4.2,x-systemd.automount,x-systemd.requires=network-online.target,x-systemd.device-timeout=60 0 0" + state: mounted + fstype: nfs + +# - name: Mount backup NFS volume +# ansible.posix.mount: +# src: db-backups:/backups +# path: /backups +# opts: "rw,bg,hard,nfsvers=4.2,x-systemd.automount,x-systemd.requires=network-online.target,x-systemd.device-timeout=60 0 0" +# state: mounted +# fstype: nfs + +- name: Stop postgres on slave + service: + name: postgresql + state: stopped + +- name: Remove db data from db-slave + file: + state: absent + path: /var/lib/postgresql/{{ default_postgres_version }}/main/ + +- name: Sync data from db-master + become: yes + become_user: postgres + shell: "pg_basebackup -h {{ default_master_ip }} -D /var/lib/postgresql/{{ default_postgres_version }}/main -U replicator -P -v -R -X stream -S pgstandby1" + register: pg_basebackup + +- name: Change restore_command in postgresql.conf + lineinfile: + path: /etc/postgresql/{{ default_postgres_version }}/main/postgresql.conf + regex: "^restore_command" + line: "restore_command = 'cp -f /postgresql/replication/%f %p'" + +- name: Change archive_cleanup_command in postgresql.conf + lineinfile: + path: /etc/postgresql/{{ default_postgres_version }}/main/postgresql.conf + regex: "^archive_cleanup_command" + line: "archive_cleanup_command = 'pg_archivecleanup -d /postgresql/replication %r 2>>cleanup.log'" + +- name: Change recovery_target_timeline in postgresql.conf + lineinfile: + path: /etc/postgresql/{{ default_postgres_version }}/main/postgresql.conf + regex: "^recovery_target_timeline" + line: "recovery_target_timeline = 'latest'" + +- name: Start postgres + service: + name: postgresql + state: started diff --git a/smardigo.yml b/smardigo.yml index 9a166cc..6225ab6 100644 --- a/smardigo.yml +++ b/smardigo.yml @@ -56,20 +56,22 @@ roles: - role: postfix when: "'postfix' in group_names" + - role: keycloak when: "'keycloak' in group_names" - - role: harbor when: "'harbor' in group_names" - role: elastic when: "'elastic' in group_names" + - role: postgres + when: "'postgres' in group_names" - role: prometheus when: "'prometheus' in group_names" + - role: awx + when: "'awx' in group_names" + - role: iam when: "'iam' in group_names" - role: connect when: "'connect' in group_names" - - - role: awx - when: "'awx' in group_names"