From 431b4f5cfde95a18302e13c7f9395d24160719ed Mon Sep 17 00:00:00 2001 From: Pavel Guzaev Date: Sat, 9 Mar 2024 17:36:50 +0500 Subject: [PATCH] all demo --- README.md | 2 + ansible/playbook/hetzner_app.yml | 35 ++ ansible/playbook/pg_dump/README.md | 39 ++ ansible/playbook/pg_dump/pg_dump.yml | 28 ++ ansible/playbook/roles/gate/README.md | 6 + ansible/playbook/roles/gate/gate.yml | 5 + .../roles/gate/roles/gate/defaults/main.yml | 15 + .../roles/gate/roles/gate/handlers/main.yml | 6 + .../roles/gate/roles/gate/tasks/main.yml | 62 +++ .../roles/gate/templates/rules.iptables.j2 | 192 +++++++++ .../roles/hetzner_app/defaults/main.yml | 7 + .../playbook/roles/hetzner_app/tasks/main.yml | 160 +++++++ .../roles/hetzner_server/defaults/main.yml | 6 + .../roles/hetzner_server/handlers/main.yml | 6 + .../roles/hetzner_server/tasks/main.yml | 65 +++ .../templates/01-network-manager.yaml.js2 | 23 + .../roles/ldap-auth/defaults/main.yml | 16 + .../playbook/roles/ldap-auth/files/key.pub | 0 .../ldap-auth/files/nsswitch.conf.Debian | 14 + .../ldap-auth/files/nsswitch.conf.RedHat | 23 + .../playbook/roles/ldap-auth/files/sudoers | 7 + .../roles/ldap-auth/handlers/main.yml | 19 + .../playbook/roles/ldap-auth/tasks/main.yml | 356 +++++++++++++++ .../roles/ldap-auth/tasks/sec_ssh.yml | 108 +++++ .../roles/ldap-auth/tasks/sec_test.yml | 29 ++ .../templates/get_ldap_ssh_key.sh.j2 | 16 + .../roles/ldap-auth/templates/ldap.conf.j2 | 7 + compose/ncc-compose/README.md | 47 ++ compose/ncc-compose/createdb/create.sh | 5 + compose/ncc-compose/docker-compose.yaml | 217 ++++++++++ compose/themes_generator/Dockerfile | 18 + compose/themes_generator/requirements.txt | 51 +++ jenkins/1cdb.groovy | 235 ++++++++++ jenkins/1cdb_session.ps1 | 10 + jenkins/1csrv.groovy | 218 ++++++++++ jenkins/1csrv_session.ps1 | 20 + jenkins/astarot.groovy | 204 +++++++++ jenkins/branch_ncc.groovy | 405 ++++++++++++++++++ jenkins/getmailbox.groovy | 237 ++++++++++ jenkins/getmailbox.ps1 | 8 + jenkins/newmailbox.ps1 | 29 ++ jenkins/removemailbox.ps1 | 19 + jenkins/site.groovy | 256 +++++++++++ jenkins/site_session.ps1 | 8 + 44 files changed, 3239 insertions(+) create mode 100644 README.md create mode 100644 ansible/playbook/hetzner_app.yml create mode 100644 ansible/playbook/pg_dump/README.md create mode 100644 ansible/playbook/pg_dump/pg_dump.yml create mode 100644 ansible/playbook/roles/gate/README.md create mode 100644 ansible/playbook/roles/gate/gate.yml create mode 100644 ansible/playbook/roles/gate/roles/gate/defaults/main.yml create mode 100644 ansible/playbook/roles/gate/roles/gate/handlers/main.yml create mode 100644 ansible/playbook/roles/gate/roles/gate/tasks/main.yml create mode 100644 ansible/playbook/roles/gate/roles/gate/templates/rules.iptables.j2 create mode 100644 ansible/playbook/roles/hetzner_app/defaults/main.yml create mode 100644 ansible/playbook/roles/hetzner_app/tasks/main.yml create mode 100644 ansible/playbook/roles/hetzner_server/defaults/main.yml create mode 100644 ansible/playbook/roles/hetzner_server/handlers/main.yml create mode 100644 ansible/playbook/roles/hetzner_server/tasks/main.yml create mode 100644 ansible/playbook/roles/hetzner_server/templates/01-network-manager.yaml.js2 create mode 100644 ansible/playbook/roles/ldap-auth/defaults/main.yml create mode 100644 ansible/playbook/roles/ldap-auth/files/key.pub create mode 100644 ansible/playbook/roles/ldap-auth/files/nsswitch.conf.Debian create mode 100644 ansible/playbook/roles/ldap-auth/files/nsswitch.conf.RedHat create mode 100644 ansible/playbook/roles/ldap-auth/files/sudoers create mode 100644 ansible/playbook/roles/ldap-auth/handlers/main.yml create mode 100644 ansible/playbook/roles/ldap-auth/tasks/main.yml create mode 100644 ansible/playbook/roles/ldap-auth/tasks/sec_ssh.yml create mode 100644 ansible/playbook/roles/ldap-auth/tasks/sec_test.yml create mode 100644 ansible/playbook/roles/ldap-auth/templates/get_ldap_ssh_key.sh.j2 create mode 100644 ansible/playbook/roles/ldap-auth/templates/ldap.conf.j2 create mode 100644 compose/ncc-compose/README.md create mode 100755 compose/ncc-compose/createdb/create.sh create mode 100644 compose/ncc-compose/docker-compose.yaml create mode 100644 compose/themes_generator/Dockerfile create mode 100644 compose/themes_generator/requirements.txt create mode 100644 jenkins/1cdb.groovy create mode 100644 jenkins/1cdb_session.ps1 create mode 100644 jenkins/1csrv.groovy create mode 100644 jenkins/1csrv_session.ps1 create mode 100644 jenkins/astarot.groovy create mode 100644 jenkins/branch_ncc.groovy create mode 100644 jenkins/getmailbox.groovy create mode 100644 jenkins/getmailbox.ps1 create mode 100644 jenkins/newmailbox.ps1 create mode 100644 jenkins/removemailbox.ps1 create mode 100644 jenkins/site.groovy create mode 100644 jenkins/site_session.ps1 diff --git a/README.md b/README.md new file mode 100644 index 0000000..cbeb2fa --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# DEMO + diff --git a/ansible/playbook/hetzner_app.yml b/ansible/playbook/hetzner_app.yml new file mode 100644 index 0000000..1c80c5e --- /dev/null +++ b/ansible/playbook/hetzner_app.yml @@ -0,0 +1,35 @@ +# Основной playbook-файл для настройки сервера приложений для presale стендов в Hetzner +# Автор: Гузаев Павел +# Дата создания: 01.02.2022 + +- hosts: sd-gate-presale + remote_user: root + gather_facts: yes + + roles: + - hetzner_server + + post_tasks: + - name: Add host to group 'sd-presale' + add_host: + name: "{{ ip_addr }}" + groups: + - sd-presale + +- hosts: sd-presale + remote_user: root + gather_facts: yes + + roles: + - hetzner_app + - role: consul + vars: + pool: hetzner + service: sd-apps,apps,presale + machine_type: virtual + - role: system_exporter + vars: + pool: hetzner + service: sd-apps,apps,presale + machine_type: virtual + - ldap-auth diff --git a/ansible/playbook/pg_dump/README.md b/ansible/playbook/pg_dump/README.md new file mode 100644 index 0000000..438dab2 --- /dev/null +++ b/ansible/playbook/pg_dump/README.md @@ -0,0 +1,39 @@ +# Ansible Database Backup + +[![Use community.postgresql.postgresql_db](https://docs.ansible.com/ansible/latest/collections/community/postgresql/postgresql_db_module.html#ansible-collections-community-postgresql-postgresql-db-module)](https://docs.ansible.com/ansible/latest/collections/community/postgresql/postgresql_db_module.html#ansible-collections-community-postgresql-postgresql-db-module) + +Backup database from remote postgresql for {{store}} days. + +## Install + +``` +ansible-galaxy collection install community.postgresql +``` +## How to dump +``` +ansible-playbook sd_pro_dump.yml -l sd-pgsql9 --extra-vars "dbname=sd4_itsmcorp_devel store=7 arg=--format=custom" +``` +``` +Avalable env: +store: default('1') - how long do you need to store current backup +target: default('/opt/back/internal/postgres/') - where place put the archive +arg: default('--exclude-table=tbl_event --format=custom') - pg_dump argument +``` + +#### PostgreSQL + +[Official documentaiton.](https://www.postgresql.org/docs/current/static/app-pgdump.html) + +Example: + +``` +pg_dump --format "custom" --file "/opt/back/internal/postgres/{{ dbname }}.bak" {{ dbname }} +``` + +## Supported Databases + +For now supports: +* PostgreSQL + +## Supported OS +Linux \ No newline at end of file diff --git a/ansible/playbook/pg_dump/pg_dump.yml b/ansible/playbook/pg_dump/pg_dump.yml new file mode 100644 index 0000000..08e2bb9 --- /dev/null +++ b/ansible/playbook/pg_dump/pg_dump.yml @@ -0,0 +1,28 @@ +- hosts: all + remote_user: ansible + vars: + store_env: "{{ store|default('1') }}" + target_env: "{{ target|default('/opt/back/internal/postgres/') }}" + extra_args: "{{ arg|default('--exclude-table=tbl_event --format=custom') }}" + + tasks: + - debug: + var: store_env + - debug: + var: target_env + + - name: Add num_of_days days to start_date + command: date +'%Y-%m-%d' -d "+{{store_env}} days" + register: end_date + - debug: + var: end_date.stdout + + - name: Dump the "{{ dbname }}" database to a file + become: yes + become_method: sudo + become_user: postgres + community.postgresql.postgresql_db: + name: "{{ dbname }}" + state: dump + target: "{{ target_env }}{{ dbname }}_{{ ansible_date_time.date }}_{{ end_date.stdout }}.bak" + dump_extra_args: "{{ extra_args }}" diff --git a/ansible/playbook/roles/gate/README.md b/ansible/playbook/roles/gate/README.md new file mode 100644 index 0000000..321df27 --- /dev/null +++ b/ansible/playbook/roles/gate/README.md @@ -0,0 +1,6 @@ +Получаем данные напрямую из naupp + + url: "https://{{ gate_naupp_fqdn }}/sd/services/rest/exec?accessKey={{ accesskey }}&func=modules.externalAccess.getExternalAccesses¶ms=user" + +На текущий момент роль ставит все необходимые для работы пакеты, настраивает их автозапуск и разрешает проброс пакетов, после чего настраивает файлы для iptables-save и перезапускает службу при необходимости. +Для отключения проброса пакетов, например, в случае подозрения на несанкционированный доступ, поменять переменную iptables_ip_forward \ No newline at end of file diff --git a/ansible/playbook/roles/gate/gate.yml b/ansible/playbook/roles/gate/gate.yml new file mode 100644 index 0000000..7c2be40 --- /dev/null +++ b/ansible/playbook/roles/gate/gate.yml @@ -0,0 +1,5 @@ +- hosts: sd-gw + become: yes + remote_user: root + roles: + - gate diff --git a/ansible/playbook/roles/gate/roles/gate/defaults/main.yml b/ansible/playbook/roles/gate/roles/gate/defaults/main.yml new file mode 100644 index 0000000..0c39585 --- /dev/null +++ b/ansible/playbook/roles/gate/roles/gate/defaults/main.yml @@ -0,0 +1,15 @@ +--- +# Fast disable forward if we have a problem now +gate_iptables_ip_forward: 1 + +# Name of the service to reload +gate_iptables_rules_file: /etc/iptables/rules + +# gate host ext and int ip. +gate_local_net: 192.168.0.0/16,10.0.0.0/8 +gate_int_if: ens18 +gate_ext_if: ens19 + +# naupp site and access_key +gate_naupp_fqdn: naupp.nau.com +gate_access_key: akfjj666-f897-9978-b5006c-0508938848 diff --git a/ansible/playbook/roles/gate/roles/gate/handlers/main.yml b/ansible/playbook/roles/gate/roles/gate/handlers/main.yml new file mode 100644 index 0000000..b6cba6b --- /dev/null +++ b/ansible/playbook/roles/gate/roles/gate/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: restart netfilter-persistent + service: + name: netfilter-persistent + state: restarted + sleep: 10 diff --git a/ansible/playbook/roles/gate/roles/gate/tasks/main.yml b/ansible/playbook/roles/gate/roles/gate/tasks/main.yml new file mode 100644 index 0000000..4f23cc4 --- /dev/null +++ b/ansible/playbook/roles/gate/roles/gate/tasks/main.yml @@ -0,0 +1,62 @@ +--- +- name: install iptables + apt: + name: iptables + state: present + tags: packages + +- name: install iptables-persistent for Debian + apt: + pkg: iptables-persistent + state: present + tags: packages + +- name: GET RESULT + uri: + url: "https://{{ gate_naupp_fqdn }}/sd/services/rest/exec?accessKey={{ gate_access_key }}&func=modules.externalAccess.getExternalAccesses¶ms=user" + method: GET + return_content: yes + delegate_to: 127.0.0.1 + register: _result + until: _result.status != -1 + retries: 15 + delay: 15 + +- set_fact: + endpoint_naupp: "{{ _result['content'] }}" + +- debug: + msg: "{{ endpoint_naupp }}" + +- name: setup IP forwarding for IPv4 + sysctl: + name: net.ipv4.ip_forward + value: "{{ gate_iptables_ip_forward }}" + tags: configuration + +- name: start iptables and add to boot runlevel + service: + name: netfilter-persistent + enabled: true + state: started + +- name: configure rules + template: + src: rules.iptables.j2 + dest: "{{ gate_iptables_rules_file }}" + notify: restart netfilter-persistent + tags: configuration + +- name: symlink IPv4 rules + file: + src: "{{ gate_iptables_rules_file }}" + dest: /etc/iptables/rules.v4 + state: link + tags: configuration + +- name: disable IPv6 on all interfaces + sysctl: + name: net.ipv6.conf.all.disable_ipv6 + value: 1 + tags: configuration + diff --git a/ansible/playbook/roles/gate/roles/gate/templates/rules.iptables.j2 b/ansible/playbook/roles/gate/roles/gate/templates/rules.iptables.j2 new file mode 100644 index 0000000..a2b871b --- /dev/null +++ b/ansible/playbook/roles/gate/roles/gate/templates/rules.iptables.j2 @@ -0,0 +1,192 @@ +############################################################################### +# The MIT License +# +# Copyright 2012-2014 Jakub Jirutka . +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +############################################################################### +# +# Basic iptables/IPv4 template for an ordinary servers +# +# This file is in iptables-restore format. See the man pages for +# iptables-restore(8) and iptables-save(8). +# +# The following is a set of firewall rules that should be applicable to Linux +# servers running within departments. It is intended to provide a useful +# starting point from which to devise a comprehensive firewall policy for +# a host. +# +# Parts 1 and 3 of these rules are the same for each host, whilst part 2 can be +# populated with rules specific to particular hosts. The optional part 4 is +# prepared for a NAT rules, e.g. for port forwarding, redirect, masquerade... +# +# This template is based on http://jdem.cz/v64a3 from University of Leicester. +# +# For the newest version go to https://gist.github.com/jirutka/3742890. +# +# @author Jakub Jirutka +# @version 1.3.1 +# @date 2014-01-28 +# + +############################################################################### +# 1. COMMON HEADER # +# # +# This section is a generic header that should be suitable for most hosts. # +############################################################################### + +*filter + +# Base policy +:INPUT DROP [0:0] +:FORWARD DROP [0:0] +:OUTPUT ACCEPT [0:0] + +# Don't attempt to firewall internal traffic on the loopback device. +-A INPUT -i lo -j ACCEPT + +# Continue connections that are already established or related to an established +# connection. +-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT + +# Drop non-conforming packets, such as malformed headers, etc. +-A INPUT -m conntrack --ctstate INVALID -j DROP + +# Block remote packets claiming to be from a loopback address. +-A INPUT -s 127.0.0.0/8 ! -i lo -j DROP + +# Drop all packets that are going to broadcast, multicast or anycast address. +-A INPUT -m addrtype --dst-type BROADCAST -j DROP +-A INPUT -m addrtype --dst-type MULTICAST -j DROP +-A INPUT -m addrtype --dst-type ANYCAST -j DROP +-A INPUT -d 224.0.0.0/4 -j DROP + +# Chain for preventing SSH brute-force attacks. +# Permits 10 new connections within 5 minutes from a single host then drops +# incomming connections from that host. Beyond a burst of 100 connections we +# log at up 1 attempt per second to prevent filling of logs. +-N SSHBRUTE +-A SSHBRUTE -m recent --name SSH --set +-A SSHBRUTE -m recent --name SSH --update --seconds 300 --hitcount 10 -m limit --limit 1/second --limit-burst 100 -j LOG --log-prefix "iptables[SSH-brute]: " +-A SSHBRUTE -m recent --name SSH --update --seconds 300 --hitcount 10 -j DROP +-A SSHBRUTE -j ACCEPT + +# Chain for preventing ping flooding - up to 6 pings per second from a single +# source, again with log limiting. Also prevents us from ICMP REPLY flooding +# some victim when replying to ICMP ECHO from a spoofed source. +-N ICMPFLOOD +-A ICMPFLOOD -m recent --set --name ICMP --rsource +-A ICMPFLOOD -m recent --update --seconds 1 --hitcount 6 --name ICMP --rsource --rttl -m limit --limit 1/sec --limit-burst 1 -j LOG --log-prefix "iptables[ICMP-flood]: " +-A ICMPFLOOD -m recent --update --seconds 1 --hitcount 6 --name ICMP --rsource --rttl -j DROP +-A ICMPFLOOD -j ACCEPT + + +############################################################################### +# 2. HOST SPECIFIC RULES # +# # +# This section is a good place to enable your host-specific services. # +# ! DO NOT FORGOT TO COPY THESE RULES TO firewall.ip6tables TO ALLOW IPV6 ! # +############################################################################### + +# Accept HTTP and HTTPS +#-A INPUT -p tcp -m multiport --dports 80,443 --syn -m conntrack --ctstate NEW -j ACCEPT + + +# ACCEPT RULES FROM naupp + +{% for params in endpoint_naupp %} +-A INPUT -p tcp -m tcp -s {{ params.source_ip|join(',') }} --dport {{ params.external_port }} -j ACCEPT +-A FORWARD -p tcp -m tcp -s {{ params.source_ip|join(',') }} --dport {{ params.target_port }} -j ACCEPT +{% endfor %} + +############################################################################### +# 3. GENERAL RULES # +# # +# This section contains general rules that should be suitable for most hosts. # +############################################################################### + +# Accept worldwide access to SSH and use SSHBRUTE chain for preventing +# brute-force attacks. +-A INPUT -s {{ gate_local_net }} -i {{ gate_int_if }} -j ACCEPT +-A FORWARD -s {{ gate_local_net }} -i {{ gate_int_if }} -j ACCEPT + +-A INPUT -p tcp --dport 22 --syn -m conntrack --ctstate NEW -j SSHBRUTE + +# Permit useful IMCP packet types. +# Note: RFC 792 states that all hosts MUST respond to ICMP ECHO requests. +# Blocking these can make diagnosing of even simple faults much more tricky. +# Real security lies in locking down and hardening all services, not by hiding. +-A INPUT -p icmp --icmp-type 0 -m conntrack --ctstate NEW -j ACCEPT +-A INPUT -p icmp --icmp-type 3 -m conntrack --ctstate NEW -j ACCEPT +-A INPUT -p icmp --icmp-type 8 -m conntrack --ctstate NEW -j ICMPFLOOD +-A INPUT -p icmp --icmp-type 11 -m conntrack --ctstate NEW -j ACCEPT + +# Do not log packets that are going to ports used by SMB +# (Samba / Windows Sharing). +-A INPUT -p udp -m multiport --dports 135,445 -j DROP +-A INPUT -p udp --dport 137:139 -j DROP +-A INPUT -p udp --sport 137 --dport 1024:65535 -j DROP +-A INPUT -p tcp -m multiport --dports 135,139,445 -j DROP + +# Do not log packets that are going to port used by UPnP protocol. +-A INPUT -p udp --dport 1900 -j DROP + +# Do not log late replies from nameservers. +-A INPUT -p udp --sport 53 -j DROP + +# Good practise is to explicately reject AUTH traffic so that it fails fast. +-A INPUT -p tcp --dport 113 --syn -m conntrack --ctstate NEW -j REJECT --reject-with tcp-reset + +# Prevent DOS by filling log files. +-A INPUT -m limit --limit 1/second --limit-burst 100 -j LOG --log-prefix "iptables[DOS]: " + +COMMIT + + +############################################################################### +# 4. HOST SPECIFIC NAT RULES # +# # +# Uncomment this section if you want to use NAT table, e.g. for port # +# forwarding, redirect, masquerade... # +############################################################################### + +*nat + +# Base policy +:PREROUTING ACCEPT [0:0] +:POSTROUTING ACCEPT [0:0] +:OUTPUT ACCEPT [0:0] + +# Redirect port 21 to local port 2121 +#-A PREROUTING -i eth0 -p tcp --dport 21 -j REDIRECT --to-port 2121 +# Forward port 8080 to port 80 on host 192.168.1.10 +#-A PREROUTING -i eth0 -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.10:80 + +# NAT rules from naupp +{% for params in endpoint_naupp %} +-A PREROUTING -i {{ gate_ext_if }} -p tcp --dport {{ params.external_port }} -j DNAT --to-destination {{ params.target_ip }}:{{ params.target_port }} +{% endfor %} + +# mask because not default route +-A POSTROUTING -o {{ gate_ext_if }} -j MASQUERADE +-A POSTROUTING -o {{ gate_int_if }} -j MASQUERADE + +COMMIT diff --git a/ansible/playbook/roles/hetzner_app/defaults/main.yml b/ansible/playbook/roles/hetzner_app/defaults/main.yml new file mode 100644 index 0000000..6f2abb8 --- /dev/null +++ b/ansible/playbook/roles/hetzner_app/defaults/main.yml @@ -0,0 +1,7 @@ +hetzner_app_java_11: jdk-11.0.12+7 +hetzner_app_java_11_file: OpenJDK11U-jdk_x64_linux_hotspot_11.0.12_7.tar.gz +hetzner_app_java_8: jdk8u312-b07 +hetzner_app_java_8_file: OpenJDK8U-jdk_x64_linux_hotspot_8u312b07.tar.gz +hetzner_app_swap_file_path: /swapfile +hetzner_app_swap_file_size_gb: 8 +hetzner_app_stands_user: nausd4 diff --git a/ansible/playbook/roles/hetzner_app/tasks/main.yml b/ansible/playbook/roles/hetzner_app/tasks/main.yml new file mode 100644 index 0000000..503ce37 --- /dev/null +++ b/ansible/playbook/roles/hetzner_app/tasks/main.yml @@ -0,0 +1,160 @@ +--- +- name: Allow all access from RFC1918 networks to this host + community.general.ufw: + rule: allow + src: '{{ item }}' + loop: + - 10.0.0.0/8 + - 172.16.0.0/12 + - 192.168.0.0/16 + - 195.151.207.0/24 + - 37.29.46.132/32 + - 109.235.215.238/32 + - 84.47.191.162/32 + - 77.232.53.10/32 + - 188.187.118.117/32 + - 91.234.153.110/32 + - 195.151.8.25/32 + - 78.30.223.233/32 + - 109.237.104.138/32 + - 84.47.168.163/32 + - 94.28.29.140/32 + +- name: Enable UFW + community.general.ufw: + state: enabled + +- name: set timezone to Asia/Yekaterinburg + community.general.timezone: + hwclock: local + name: Asia/Yekaterinburg + +- name: Install java_11 + ansible.builtin.unarchive: + src: "https://github.com/adoptium/temurin11-binaries/releases/download/{{ hetzner_app_java_11 }}/{{ hetzner_app_java_11_file }}" + dest: /opt + remote_src: yes + +- name: symlink java_11 + file: + src: "/opt/{{ hetzner_app_java_11 }}/" + dest: /opt/openjdk_11 + state: link + +- name: Install java_8 + ansible.builtin.unarchive: + src: "https://github.com/adoptium/temurin8-binaries/releases/download/{{ hetzner_app_java_8 }}/{{ hetzner_app_java_8_file }}" + dest: /opt + remote_src: yes + +- name: symlink java_8 + file: + src: "/opt/{{ hetzner_app_java_8 }}/" + dest: /opt/openjdk_8 + state: link + +- name: Run the equivalent of "apt-get update" as a separate step + apt: + update_cache: yes + +- name: Install a list of packages + apt: + pkg: + - libmime-tools-perl + - atop + - iotop + - less + - nano + - vim + - telnet + - dnsutils + - curl + - wget + - zip + - unzip + - tar + - rsync + - screen + - openssl + - ldap-utils + - fontconfig + - htop + - mc + - ttf-mscorefonts-installer + - python-simplejson + - software-properties-common + - traceroute + - file + - chrony + +- name: Create swap file + command: fallocate -l {{ hetzner_app_swap_file_size_gb }}G {{ hetzner_app_swap_file_path }} + creates="{{ hetzner_app_swap_file_path }}" + tags: + - swap.file.create + +- name: Change swap file permissions + file: path="{{ hetzner_app_swap_file_path }}" + owner=root + group=root + mode=0600 + tags: + - swap.file.permissions + +- name: "Check swap file type" + command: file {{ hetzner_app_swap_file_path }} + register: swapfile + tags: + - swap.file.mkswap + +- name: Make swap file + command: "sudo mkswap {{ hetzner_app_swap_file_path }}" + when: swapfile.stdout.find('swap file') == -1 + tags: + - swap.file.mkswap + +- name: Write swap entry in fstab + mount: name=none + src={{ hetzner_app_swap_file_path }} + fstype=swap + opts=sw + passno=0 + dump=0 + state=present + tags: + - swap.fstab + +- name: Mount swap + command: "swapon {{ hetzner_app_swap_file_path }}" + when: ansible_swaptotal_mb < 1 + tags: + - swap.file.swapon + +- name: "Add the user {{ hetzner_app_stands_user }} with a bash shell" + ansible.builtin.user: + name: "{{ hetzner_app_stands_user }}" + shell: /bin/bash + home: "/home/{{ hetzner_app_stands_user }}" + create_home: yes + generate_ssh_key: yes + +- name: Ansible copy authorized_keys + copy: + src: /root/.ssh/authorized_keys + dest: "/home/{{ hetzner_app_stands_user }}/.ssh/authorized_keys" + remote_src: yes + +- name: Change file permissions + file: path="/home/{{ hetzner_app_stands_user }}/.ssh/authorized_keys" + owner="{{ hetzner_app_stands_user }}" + group="{{ hetzner_app_stands_user }}" + mode=0600 + +- name: Create stands directory + file: + path: /opt/stands + state: directory + owner: "{{ hetzner_app_stands_user }}" + group: "{{ hetzner_app_stands_user }}" + mode: 0775 + diff --git a/ansible/playbook/roles/hetzner_server/defaults/main.yml b/ansible/playbook/roles/hetzner_server/defaults/main.yml new file mode 100644 index 0000000..bc27379 --- /dev/null +++ b/ansible/playbook/roles/hetzner_server/defaults/main.yml @@ -0,0 +1,6 @@ +# NetPlan file for internal network +hetzner_server_netplan_int_net: /etc/netplan/01-network-manager.yaml +hetzner_server_server_location: hel1-dc2 +# hetzner_server_server_location: fsn1-dc14 +# default gateway +hetzner_server_gw_ip: 10.106.100.1 \ No newline at end of file diff --git a/ansible/playbook/roles/hetzner_server/handlers/main.yml b/ansible/playbook/roles/hetzner_server/handlers/main.yml new file mode 100644 index 0000000..1b30b93 --- /dev/null +++ b/ansible/playbook/roles/hetzner_server/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: netplan apply + tags: netplan + command: ssh {{ ip_addr }} -oStrictHostKeyChecking=no "netplan apply" + async: 1 + poll: 0 diff --git a/ansible/playbook/roles/hetzner_server/tasks/main.yml b/ansible/playbook/roles/hetzner_server/tasks/main.yml new file mode 100644 index 0000000..fe611ab --- /dev/null +++ b/ansible/playbook/roles/hetzner_server/tasks/main.yml @@ -0,0 +1,65 @@ +--- +- name: GET APPS NUMBER + shell: hcloud server list -o columns=name | grep sd-apps[[:digit:]] | sed s/[^0-9]//g + register: _nodes + +- set_fact: + nodes: "{{ _nodes.stdout_lines }}" + +- name: GET NEXT NODE NUMBER + set_fact: max_node_id="{{ nodes | sort | last }}" + +- debug: + msg: "Next Node id is {{ max_node_id | int + 1 }}" + +- name: "Create new sd-apps server with next number {{ max_node_id | int + 1 }}" + shell: hcloud server create --datacenter "{{ hetzner_server_server_location }}" --image ubuntu-20.04 --ssh-key ansible,manager,pguzaev@naumen.ru --network 1127862 --start-after-create --type cpx51 --name "sd-apps{{ max_node_id | int + 1 }}-presale" + register: _status + +- debug: + msg: "Status is {{ _status.stdout_lines }}" + +- set_fact: + ext_ip_addr: "{{ _status.stdout_lines[3] }}" + +- debug: + msg: "External ip address is {{ ext_ip_addr.split()[1] }}" + +- name: Wait ssh avalaible + wait_for: + host: "{{ ext_ip_addr.split()[1] }}" + port: "22" + state: started # Port should be open + delay: 10 # No wait before first check (sec) + timeout: 240 # Stop checking after timeout (sec) + ignore_errors: no + +- name: GET APPS + shell: hcloud server describe -o json "sd-apps{{ max_node_id | int + 1 }}-presale" + register: _result + +- set_fact: + private_net: "{{ (_result.stdout | from_json).private_net }}" + +- set_fact: + ip_addr: "{{ private_net[0]['ip'] }}" + +- name: GET APPS + shell: hcloud server ssh sd-apps{{ max_node_id | int + 1 }}-presale -oStrictHostKeyChecking=no ifconfig | awk '/{{ ip_addr }}/ {print $1}' RS="\n\n" + register: _if_int + +- set_fact: + if_int: "{{ _if_int.stdout }}" + +- debug: + msg: "internal iface is {{ if_int }} and has ip adress is {{ ip_addr }}" + +- name: Netplan configure rules + template: + src: 01-network-manager.yaml.js2 + dest: "/tmp/sd-apps{{ max_node_id | int + 1 }}-presale.yaml" + +- name: Set Netplan + shell: scp -oStrictHostKeyChecking=no "/tmp/sd-apps{{ max_node_id | int + 1 }}-presale.yaml" "{{ ip_addr }}:{{ hetzner_server_netplan_int_net }}" + notify: + - netplan apply diff --git a/ansible/playbook/roles/hetzner_server/templates/01-network-manager.yaml.js2 b/ansible/playbook/roles/hetzner_server/templates/01-network-manager.yaml.js2 new file mode 100644 index 0000000..12f5f2b --- /dev/null +++ b/ansible/playbook/roles/hetzner_server/templates/01-network-manager.yaml.js2 @@ -0,0 +1,23 @@ +# This file is generated from ansible autogeneration scripts +# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following: +# network: {config: disabled} +network: + version: 2 + ethernets: + {{ if_int }} + dhcp4: true + nameservers: + addresses: + - 192.168.224.7 + - 192.168.240.7 + - 91.232.196.12 + search: + - office0.naumen.ru + routes: + - to: 192.168.0.0/16 + via: 10.106.100.1 + - to: 172.16.0.0/16 + via: 10.106.100.1 + - to: 10.0.0.0/8 + via: {{ hetzner_server_gw_ip }} + diff --git a/ansible/playbook/roles/ldap-auth/defaults/main.yml b/ansible/playbook/roles/ldap-auth/defaults/main.yml new file mode 100644 index 0000000..6283d9b --- /dev/null +++ b/ansible/playbook/roles/ldap-auth/defaults/main.yml @@ -0,0 +1,16 @@ +--- +# ldap +ldap_server: "ldap://" +ldap_port: "389" +ldap_base: dc=naumen,dc=ru +base_group: ou=groups,dc=naumen,dc=ru +base_passwd: ou=users,dc=naumen,dc=ru +filter_group: (|(objectClass=posixGroup)(objectClass=groupOfNames)) +filter_passwd: (&(objectClass=posixAccount)(shadowInactive=0)(memberOf=cn=users,ou=groups,dc=naumen,dc=ru)) +nss_nested_groups: on +reconnect_invalidate: passwd,group,nfsidmap +uid: nslcd +gid: nslcd +ssl_type: start_tls +ssl: "no" +tls_reqcert: "allow" diff --git a/ansible/playbook/roles/ldap-auth/files/key.pub b/ansible/playbook/roles/ldap-auth/files/key.pub new file mode 100644 index 0000000..e69de29 diff --git a/ansible/playbook/roles/ldap-auth/files/nsswitch.conf.Debian b/ansible/playbook/roles/ldap-auth/files/nsswitch.conf.Debian new file mode 100644 index 0000000..1f6420c --- /dev/null +++ b/ansible/playbook/roles/ldap-auth/files/nsswitch.conf.Debian @@ -0,0 +1,14 @@ +passwd: compat ldap +group: compat ldap +shadow: compat ldap +gshadow: files + +hosts: files dns +networks: files + +protocols: db files +services: db files +ethers: db files +rpc: db files + +netgroup: nis ldap diff --git a/ansible/playbook/roles/ldap-auth/files/nsswitch.conf.RedHat b/ansible/playbook/roles/ldap-auth/files/nsswitch.conf.RedHat new file mode 100644 index 0000000..7d85ca8 --- /dev/null +++ b/ansible/playbook/roles/ldap-auth/files/nsswitch.conf.RedHat @@ -0,0 +1,23 @@ +passwd: files sss ldap +shadow: files sss ldap +group: files sss ldap +#initgroups: files + +#hosts: db files nisplus nis dns +hosts: files dns + +bootparams: nisplus [NOTFOUND=return] files + +ethers: files +netmasks: files +networks: files +protocols: files +rpc: files +services: files sss + +netgroup: files sss + +publickey: nisplus + +automount: files +aliases: files nisplus diff --git a/ansible/playbook/roles/ldap-auth/files/sudoers b/ansible/playbook/roles/ldap-auth/files/sudoers new file mode 100644 index 0000000..5d2f4ac --- /dev/null +++ b/ansible/playbook/roles/ldap-auth/files/sudoers @@ -0,0 +1,7 @@ +Defaults env_reset +Defaults mail_badpass +Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin" +root ALL=(ALL:ALL) ALL +%sudo ALL=(ALL:ALL) NOPASSWD: ALL +% ALL=(ALL) NOPASSWD: ALL +administrator ALL=(root) NOPASSWD: /bin/systemctl * dev_branch*_hornetq* \ No newline at end of file diff --git a/ansible/playbook/roles/ldap-auth/handlers/main.yml b/ansible/playbook/roles/ldap-auth/handlers/main.yml new file mode 100644 index 0000000..b6166a1 --- /dev/null +++ b/ansible/playbook/roles/ldap-auth/handlers/main.yml @@ -0,0 +1,19 @@ +--- + +- name: restart nscd + service: + name: nscd + enabled: true + state: restarted + +- name: restart nslcd + service: + name: nslcd + enabled: true + state: restarted + +- name: restart sshd + service: + name: sshd + enabled: true + state: restarted \ No newline at end of file diff --git a/ansible/playbook/roles/ldap-auth/tasks/main.yml b/ansible/playbook/roles/ldap-auth/tasks/main.yml new file mode 100644 index 0000000..6fbcd3b --- /dev/null +++ b/ansible/playbook/roles/ldap-auth/tasks/main.yml @@ -0,0 +1,356 @@ +--- +- name: Install ldap package (Debian-like) + apt: + pkg: + - libpam-ldapd + - libnss-ldapd + - ldap-utils + - nscd + state: present + update_cache: true + cache_valid_time: 36000 + when: ansible_os_family == "Debian" + +- name: Install ldap package (RedHat-like) + yum: + name: + - pam_ldap + - nss-pam-ldapd + - openldap-clients + - nscd + state: present + when: ansible_os_family == "RedHat" + +- name: Disable SELinux on (RedHat-like) + selinux: + state: disabled + when: ansible_os_family == "RedHat" + +- name: Remove dist configs (RedHat-like) + file: + path: /etc/nslcd.conf + state: absent + when: ansible_os_family == "RedHat" + +- name: Backup dist configs (Debian-like) + command: mv /etc/nslcd.conf /etc/nslcd_dist.conf + when: ansible_os_family == "Debian" + +- name: Create config files (RedHat-like) + file: + src: /etc/openldap/ldap.conf + dest: /etc/nslcd.conf + state: link + when: ansible_os_family == "RedHat" + +- name: Create config files (Debian-like) + file: + src: /etc/ldap/ldap.conf + dest: /etc/nslcd.conf + state: link + when: ansible_os_family == "Debian" + +- name: Create ldap.conf file (RedHat-like) + template: + src: ldap.conf.j2 + dest: "/etc/openldap/ldap.conf" + mode: 0440 + owner: root + group: root + when: ansible_os_family == "RedHat" + +- name: Create ldap.conf file (Debian-like) + template: + src: ldap.conf.j2 + dest: "/etc/ldap/ldap.conf" + mode: 0440 + owner: root + group: root + when: ansible_os_family == "Debian" + +- name: Edit nsswitch.conf (RedHat-like) + copy: + src: "{{ role_path }}/files/nsswitch.conf.RedHat" + dest: /etc/nsswitch.conf + backup: true + when: ansible_os_family == "RedHat" + + +- name: Edit nsswitch.conf (Debian-like) + copy: + src: "{{ role_path }}/files/nsswitch.conf.Debian" + dest: /etc/nsswitch.conf + backup: true + when: ansible_os_family == "Debian" + notify: + - restart nslcd + +- name: Create get_ldap_ssh_key.sh bash script + template: + src: get_ldap_ssh_key.sh.j2 + dest: "/usr/bin/get_ldap_ssh_key.sh" + mode: 0755 + owner: root + group: root + +- name: Update pam.d (Debian-like) + pamd: + name: common-account + type: account + control: "required" + module_path: pam_permit.so + new_type: account + new_control: "[success=ok new_authtok_reqd=done ignore=ignore user_unknown=ignore authinfo_unavail=ignore default=bad]" + new_module_path: pam_ldap.so + module_arguments: 'minimum_uid=500' + state: after + when: ansible_os_family == "Debian" + +- name: Update pam.d (Debian-like) + pamd: + name: common-auth + type: auth + control: "[success=2 default=ignore]" + module_path: pam_unix.so + new_type: auth + new_control: "[success=1 default=ignore]" + new_module_path: pam_ldap.so + module_arguments: 'minimum_uid=500 use_first_pass' + state: after + when: ansible_os_family == "Debian" + +- name: Update pam.d (Debian-like) + pamd: + name: common-password + type: password + control: "[success=2 default=ignore]" + module_path: pam_unix.so + new_type: password + new_control: "[success=1 default=ignore]" + new_module_path: pam_ldap.so + module_arguments: 'minimum_uid=500 use_first_pass' + state: after + when: ansible_os_family == "Debian" + +- name: Update pam.d (Debian-like) + pamd: + name: common-session + type: session + control: "required" + module_path: pam_unix.so + new_type: session + new_control: "[success=ok default=ignore]" + new_module_path: pam_ldap.so + module_arguments: 'minimum_uid=500' + state: after + when: ansible_os_family == "Debian" + +- name: Update pam.d (Debian-like) + pamd: + name: common-session + type: session + control: "required" + module_path: pam_permit.so + new_type: session + new_control: optional + new_module_path: pam_mkhomedir.so + module_arguments: 'skel=/etc/skel/' + state: after + when: ansible_os_family == "Debian" + +- name: Update pam.d (RedHat-like) + pamd: + name: system-auth-ac + type: session + control: "required" + module_path: pam_unix.so + new_type: session + new_control: "[success=ok default=ignore]" + new_module_path: pam_ldap.so + module_arguments: 'minimum_uid=500' + state: after + when: ansible_os_family == "RedHat" + +- name: Update pam.d (RedHat-like) + pamd: + name: system-auth-ac + type: session + control: "[success=ok default=ignore]" + module_path: pam_ldap.so + new_type: session + new_control: "optional" + new_module_path: pam_ldap.so + state: after + when: ansible_os_family == "RedHat" + +- name: Update pam.d (RedHat-like) + pamd: + name: password-auth-ac + type: session + control: "required" + module_path: pam_unix.so + new_type: session + new_control: "[success=ok default=ignore]" + new_module_path: pam_ldap.so + module_arguments: 'minimum_uid=500' + state: after + when: ansible_os_family == "RedHat" + +- name: Update pam.d (RedHat-like) + pamd: + name: password-auth-ac + type: session + control: "[success=ok default=ignore]" + module_path: pam_ldap.so + new_type: session + new_control: "optional" + new_module_path: pam_ldap.so + state: after + when: ansible_os_family == "RedHat" + +- name: Update pam.d (RedHat-like) + pamd: + name: postlogin-ac + type: session + control: "optional" + module_path: pam_lastlog.so + new_type: session + new_control: optional + new_module_path: pam_mkhomedir.so + module_arguments: 'skel=/etc/skel/' + state: after + when: ansible_os_family == "RedHat" + +- name: Update nscd.conf + lineinfile: + path: /etc/nscd.conf + regexp: "^reload-count" + line: 'reload-count unlimited' + +- name: Update nscd.conf + lineinfile: + path: /etc/nscd.conf + regexp: '^positive-time-to-live passwd' + line: 'positive-time-to-live passwd 2592000' + +- name: Update nscd.conf + lineinfile: + path: /etc/nscd.conf + regexp: '^positive-time-to-live group' + line: "positive-time-to-live passwd 2592000" + + +- name: Update sudoes users for sd-tpivi group + lineinfile: + path: /etc/sudoers + line: "%sd-tpivi ALL=(ALL) NOPASSWD: ALL" + state: present + +- name: Update sudoes users for sd-devel-321 group + lineinfile: + path: /etc/sudoers + line: "%sd-devel-321 ALL=(administrator,postgres,mssql,oinstall,nausd4) NOPASSWD: ALL" + state: present + +- name: Update sudoes users for sd-devel-322 group + lineinfile: + path: /etc/sudoers + line: "%sd-devel-322 ALL=(administrator,postgres,mssql,oinstall,nausd4) NOPASSWD: ALL" + state: present + +- name: Update sudoes users for sd-devel-323 group + lineinfile: + path: /etc/sudoers + line: "%sd-devel-323 ALL=(administrator,postgres,mssql,oinstall,nausd4) NOPASSWD: ALL" + state: present + +- name: Update sudoes users for sd-devel-324 group + lineinfile: + path: /etc/sudoers + line: "%sd-devel-324 ALL=(administrator,postgres,mssql,oinstall,nausd4) NOPASSWD: ALL" + state: present + +- name: Update sudoes users for sd-devel-325 group + lineinfile: + path: /etc/sudoers + line: "%sd-devel-325 ALL=(administrator,postgres,mssql,oinstall,nausd4) NOPASSWD: ALL" + state: present + +- name: Update sudoes users for sd-devel-326 group + lineinfile: + path: /etc/sudoers + line: "%sd-devel-326 ALL=(administrator,postgres,mssql,oinstall,nausd4) NOPASSWD: ALL" + state: present + +- name: Update sudoes users for sd-devel-327 group + lineinfile: + path: /etc/sudoers + line: "%sd-devel-327 ALL=(administrator,postgres,mssql,oinstall,nausd4) NOPASSWD: ALL" + state: present + +- name: Update sudoes users for sd-devel-328 group + lineinfile: + path: /etc/sudoers + line: "%sd-devel-328 ALL=(administrator,postgres,mssql,oinstall,nausd4) NOPASSWD: ALL" + state: present + +- name: Update sudoes users for sd-devel-329 group + lineinfile: + path: /etc/sudoers + line: "%sd-devel-329 ALL=(administrator,postgres,mssql,oinstall,nausd4) NOPASSWD: ALL" + state: present + +- name: Update sudoes users for sd-devel-329 group + lineinfile: + path: /etc/sudoers + line: "%sd-devel-353 ALL=(administrator,postgres,mssql,oinstall,nausd4) NOPASSWD: ALL" + state: present + +- name: Update sshd_config for AuthorizedKeysCommand + lineinfile: + path: /etc/ssh/sshd_config + line: "AuthorizedKeysCommand /usr/bin/get_ldap_ssh_key.sh" + state: present + +- name: Update sshd_config for AuthorizedKeysCommandUser + lineinfile: + path: /etc/ssh/sshd_config + line: "AuthorizedKeysCommandUser nobody" + state: present + +- name: Update sshd_config for AuthorizedKeysCommandUser + lineinfile: + path: /etc/ssh/sshd_config + line: "AllowGroups sd-all root administrator postgres mssql oinstall ansible nausd4" + state: present + +- name: Update sshd.conf PermitRootLogin + lineinfile: + path: /etc/ssh/sshd_config + regexp: "^PermitRootLogin" + line: 'PermitRootLogin No' + +- name: Update sshd.conf Match All + lineinfile: + path: /etc/ssh/sshd_config + regexp: '^#Match User' + insertbefore: '^AuthorizedKeysCommand /usr/bin/get_ldap_ssh_key.sh' + line: 'Match All' + +- name: Update sshd.conf PasswordAuthentication no + lineinfile: + path: /etc/ssh/sshd_config + regexp: '^#Match User' + insertbefore: '^Match All' + line: ' PasswordAuthentication no' + +- name: Update sshd.conf Match User administrator,oracle,postgres,mssql,nausd4,ansible + lineinfile: + path: /etc/ssh/sshd_config + regexp: '^#Match User' + insertbefore: '^ PasswordAuthentication no' + line: 'Match User administrator,oracle,postgres,mssql,nausd4,ansible' + notify: + - restart sshd + - restart nscd + - restart nslcd \ No newline at end of file diff --git a/ansible/playbook/roles/ldap-auth/tasks/sec_ssh.yml b/ansible/playbook/roles/ldap-auth/tasks/sec_ssh.yml new file mode 100644 index 0000000..737a956 --- /dev/null +++ b/ansible/playbook/roles/ldap-auth/tasks/sec_ssh.yml @@ -0,0 +1,108 @@ +--- +- name: sec_ssh start! + hosts: ldap-auth + become: yes + tasks: + + - name: Update sshd.conf PermitRootLogin + lineinfile: + path: /etc/ssh/sshd_config + regexp: "^PermitRootLogin" + line: 'PermitRootLogin No' + tags: + - sec_ssh + + - name: Update sshd.conf Match All + lineinfile: + path: /etc/ssh/sshd_config + regexp: '^#Match User' + insertbefore: '^AuthorizedKeysCommand /usr/bin/get_ldap_ssh_key.sh' + line: 'Match All' + tags: + - sec_ssh + + - name: Update sshd.conf PasswordAuthentication no + lineinfile: + path: /etc/ssh/sshd_config + regexp: '^#Match User' + insertbefore: '^Match All' + line: ' PasswordAuthentication no' + tags: + - sec_ssh + + - name: Update sshd.conf Match User administrator,oracle,postgres,mssql,nausd4,ansible + lineinfile: + path: /etc/ssh/sshd_config + regexp: '^#Match User' + insertbefore: '^ PasswordAuthentication no' + line: 'Match User administrator,oracle,postgres,mssql,nausd4,ansible' + tags: + - sec_ssh + + - name: Update sshd.conf AllowGroups + lineinfile: + path: /etc/ssh/sshd_config + regexp: "^AllowGroups" + line: 'AllowGroups sd-all root administrator postgres mssql oinstall ansible nausd4' + tags: + - sec_ssh + + - name: Update sudoes users for sd-devel-321 group + lineinfile: + path: /etc/sudoers + line: "%sd-devel-321 ALL=(administrator,postgres,mssql,oinstall,nausd4) NOPASSWD: ALL" + state: present + + - name: Update sudoes users for sd-devel-322 group + lineinfile: + path: /etc/sudoers + line: "%sd-devel-322 ALL=(administrator,postgres,mssql,oinstall,nausd4) NOPASSWD: ALL" + state: present + + - name: Update sudoes users for sd-devel-323 group + lineinfile: + path: /etc/sudoers + line: "%sd-devel-323 ALL=(administrator,postgres,mssql,oinstall,nausd4) NOPASSWD: ALL" + state: present + + - name: Update sudoes users for sd-devel-324 group + lineinfile: + path: /etc/sudoers + line: "%sd-devel-324 ALL=(administrator,postgres,mssql,oinstall,nausd4) NOPASSWD: ALL" + state: present + + - name: Update sudoes users for sd-devel-325 group + lineinfile: + path: /etc/sudoers + line: "%sd-devel-325 ALL=(administrator,postgres,mssql,oinstall,nausd4) NOPASSWD: ALL" + state: present + + - name: Update sudoes users for sd-devel-326 group + lineinfile: + path: /etc/sudoers + line: "%sd-devel-326 ALL=(administrator,postgres,mssql,oinstall,nausd4) NOPASSWD: ALL" + state: present + + - name: Update sudoes users for sd-devel-327 group + lineinfile: + path: /etc/sudoers + line: "%sd-devel-327 ALL=(administrator,postgres,mssql,oinstall,nausd4) NOPASSWD: ALL" + state: present + + - name: Update sudoes users for sd-devel-328 group + lineinfile: + path: /etc/sudoers + line: "%sd-devel-328 ALL=(administrator,postgres,mssql,oinstall,nausd4) NOPASSWD: ALL" + state: present + + - name: Update sudoes users for sd-devel-329 group + lineinfile: + path: /etc/sudoers + line: "%sd-devel-329 ALL=(administrator,postgres,mssql,oinstall,nausd4) NOPASSWD: ALL" + state: present + + - name: restart sshd + service: + name: sshd + enabled: true + state: restarted diff --git a/ansible/playbook/roles/ldap-auth/tasks/sec_test.yml b/ansible/playbook/roles/ldap-auth/tasks/sec_test.yml new file mode 100644 index 0000000..51aff4f --- /dev/null +++ b/ansible/playbook/roles/ldap-auth/tasks/sec_test.yml @@ -0,0 +1,29 @@ +--- +- hosts: sec + become: yes + gather_facts: yes + vars: + user_to_check: administrator + tasks: + - name: Check if administrator has sudo right + shell: sudo -n -l -U administrator 2>&1 | egrep -c -i "not allowed to run sudo|unknown user|неизвестный пользователь|не разрешается" + args: + executable: /bin/bash + ignore_errors: yes + register: right + + - name: show administrator sudo right + debug: var=right.stdout + + - name: Create temporary backup of /etc/sudoers + copy: + src: "/etc/sudoers" + remote_src: yes + dest: "/etc/sudoers_{{ now().strftime('%Y-%m-%d_%H_%M_%S') }}.bak" +# register: "sudoers_backup" + when: right.stdout == "0" +# changed_when: false + + - name: Send sudoers to remote Server + copy: src="../files/sudoers" dest=/etc/sudoers + when: right.stdout == "0" \ No newline at end of file diff --git a/ansible/playbook/roles/ldap-auth/templates/get_ldap_ssh_key.sh.j2 b/ansible/playbook/roles/ldap-auth/templates/get_ldap_ssh_key.sh.j2 new file mode 100644 index 0000000..c64861f --- /dev/null +++ b/ansible/playbook/roles/ldap-auth/templates/get_ldap_ssh_key.sh.j2 @@ -0,0 +1,16 @@ +#!/bin/bash +SSH_USER=$1 +LDAP_URI={{ ldap_server }}:{{ ldap_port }} +GROUP_DN={{ base_group }} +BASE_DN={{ base_passwd }} + + +ldapFilter="(&(shadowInactive=0)(uid=${SSH_USER})(memberOf=cn=users,ou=groups,dc=dc1,dc=com)(sshPublicKey=*))" + +# Get "sshPublicKey": +KEY=$(ldapsearch -x -LLL -o ldif-wrap=no -H "${LDAP_URI}" -b "${BASE_DN}" "${ldapFilter}" sshPublicKey | \ + grep sshPublicKey | \ + perl -MMIME::Base64 -wpe 's/^sshPublicKey(:{1,2}) (.+)$/$1 eq "::" ? decode_base64($2) : $2/e') +echo "${KEY}" + +exit 0 \ No newline at end of file diff --git a/ansible/playbook/roles/ldap-auth/templates/ldap.conf.j2 b/ansible/playbook/roles/ldap-auth/templates/ldap.conf.j2 new file mode 100644 index 0000000..7cd9e28 --- /dev/null +++ b/ansible/playbook/roles/ldap-auth/templates/ldap.conf.j2 @@ -0,0 +1,7 @@ +uri {{ ldap_server }}:{{ ldap_port }}/ +base {{ ldap_base }} +base group {{ base_group }} +base passwd {{ base_passwd }} +filter group {{ filter_group }} +filter passwd {{ filter_passwd }} +tls_reqcert {{ tls_reqcert }} diff --git a/compose/ncc-compose/README.md b/compose/ncc-compose/README.md new file mode 100644 index 0000000..a3b7fe5 --- /dev/null +++ b/compose/ncc-compose/README.md @@ -0,0 +1,47 @@ +## Требования +- Установленый docker + [Инструкция по установке](https://docs.docker.com/install/linux/docker-ce/ubuntu/#install-docker-ce) +- Установленый docker-compose => 1.19.0 + [Инструкция по установке](https://docs.docker.com/compose/install/#install-compose) +- Авторизация в реестре sd-docker-registry2.naumen.ru +- Авторизация в реестре ncc-75.nau.team + +```bash +docker login -u user -p superpaassword sd-docker-registry2.naumen.ru +docker login -u user -p superpaassword ncc-75.nau.team +``` + +### В папке createdb script для создания пустых БД необходимых для работы: + + [Инструкция по установке и базовой настройке пакета](https://start.nau.im/pages/viewpage.action?pageId=50773357) + +### Развертывание и запуск приложения осуществляется docker-compose up -d +Перед запуском: +1. +!!! НЕОБХОДИМО проверить что порты на рабочем копьютере свободны, например так: +netstat -nat | grep 8081 (для HOST_PORT) + +Прокинутые порты сейчас: +- Консул + - "8301:8301" + - "8400:8400" + - "8500:8500" + - "8600:8600/udp" +- naucore + - "3242:3242" + +- chat + - "8081:8081" + - "8444:8444" + - "9000:9000" + +Если порт занят, его необходимо поменять на любой свободный, в противном случае, приложение не запустится. + +2. +Убедиться в наличии доступа до сети naumen (ВПН поднят, ресурсы доступны) - все данные для работы будут выкачиваться оттуда. + +### Запускаем приложение + docker-compose up -d + +После сборки и запуска ( если не меняли порты) веб чата доступен по ссылке: +http://localhost:8081/workplace.html#/login diff --git a/compose/ncc-compose/createdb/create.sh b/compose/ncc-compose/createdb/create.sh new file mode 100755 index 0000000..583272f --- /dev/null +++ b/compose/ncc-compose/createdb/create.sh @@ -0,0 +1,5 @@ +#!/bin/bash + psql -c "create user ncc_system encrypted password 'ncc_system';" + psql -c "create database ncc_system owner ncc_system encoding 'utf-8';" + psql -c "create database chat owner ncc_system encoding 'utf-8';" + psql -c "create database ncc_report owner ncc_system encoding 'utf-8';" diff --git a/compose/ncc-compose/docker-compose.yaml b/compose/ncc-compose/docker-compose.yaml new file mode 100644 index 0000000..508442b --- /dev/null +++ b/compose/ncc-compose/docker-compose.yaml @@ -0,0 +1,217 @@ +version: '2.3' +services: + + redis-naumb: + image: ncc-75.nau.team/redis:5.0.6 + restart: always + + postgres: + image: sd-docker-registry2.naumen.ru/library/postgres:12RU + environment: + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=postgres + - POSTGRES_MULTIPLE_DATABASES=ncc_system,chat,ncc_report + volumes: + - ./dbdata:/var/lib/postgresql/data/ + - ./createdb:/docker-entrypoint-initdb.d + healthcheck: + test: "pg_isready -q -U ncc_system -d ncc_system && ! pidof pg_restore" + interval: 30s + start_period: 5m + stop_grace_period: 15s + + consul-server: + image: "ncc-75.nau.team/consul:1.6" + environment: + CONSUL_LOCAL_CONFIG: "{\"disable_update_check\": true}" + CONSUL_BIND_INTERFACE: "eth0" + hostname: "consul-server" + ports: + - "${CONSUL_PORT:-8500}:8500" + volumes: + - "./consul-data:/consul/data" + command: agent -server -data-dir="/consul/data" -bootstrap -domain="example.com" -client="0.0.0.0" -advertise="127.0.0.1" -ui + + naucore: + image: ncc-75.nau.team/naucore:7.5 + ports: + - "${NCC_PORT:-3242}:3242" + environment: + HOSTNAME: "naucore" + domain_id: "ncc.net" + node_id: "naucore" + CONSUL_SERVER: "consul-server:8500" + restart: always + depends_on: + postgres: + condition: service_healthy + links: + - consul-server + + nauauth: + image: ncc-75.nau.team/nauauth:7.5 + tty: yes + environment: + bus.ip: "naucore" + restart: always + depends_on: + postgres: + condition: service_healthy + links: + - consul-server + - naucore + + naubuddy: + image: ncc-75.nau.team/naubuddy:7.5 + environment: + bus.ip: "naucore" + systemdb.engine: "postgresql" + systemdb.host: "postgres" + systemdb.port: '5432' + systemdb.database: "ncc_system" + systemdb.user: "ncc_system" + systemdb.password: "ncc_system" + reportdb.engine: "postgresql" + reportdb.host: "postgres" + reportdb.port: '5432' + reportdb.database: "ncc_report" + reportdb.user: "ncc_system" + reportdb.password: "ncc_system" + links: + - naucore + - postgres + restart: always + tty: yes + volumes: + - "./spool/naubuddy:/opt/naumen/nauphone/spool/naubuddy" + depends_on: + postgres: + condition: service_healthy + + nauconfig: + image: ncc-75.nau.team/nauconfig:7.5 + environment: + bus.ip: "naucore" + systemdb.engine: "postgresql" + systemdb.host: "postgres" + systemdb.port: '5432' + systemdb.database: "ncc_system" + systemdb.user: "ncc_system" + systemdb.password: "ncc_system" + reportdb.engine: "postgresql" + reportdb.host: "postgres" + reportdb.port: '5432' + reportdb.database: "ncc_report" + reportdb.user: "ncc_system" + reportdb.password: "ncc_system" + useBuddyListProxy: "true" + links: + - naucore + - postgres + restart: always + tty: yes + depends_on: + postgres: + condition: service_healthy + + naufileservice: + image: ncc-75.nau.team/naufileservice:7.5 + ports: + - "${NCCF_PORT:-8088}:8088" + environment: + CONSUL_SERVER: "consul-server:8500" + bus.ip: "naucore" + ncc_ip: "naucore" + log_level: "4" + tty: yes + volumes: + - "./spool/recconv:/opt/naumen/nauphone/spool/naurecconv" + - "./spool/naubuddy:/opt/naumen/nauphone/spool/naubuddy" + - "./spool/naumb:/opt/naumen/nauphone/spool/naumb" + - "./spool/nauqpm:/opt/naumen/nauphone/spool/nauqpm" + links: + - naucore + - postgres + depends_on: + postgres: + condition: service_healthy + + naumb: + image: ncc-75.nau.team/naumb:7.5 + environment: + bus.ip: "naucore" + redis.host: "redis-naumb" + systemdb.engine: "postgresql" + systemdb.host: "postgres" + systemdb.port: '5432' + systemdb.database: "ncc_system" + systemdb.user: "ncc_system" + systemdb.password: "ncc_system" + reportdb.engine: "postgresql" + reportdb.host: "postgres" + reportdb.port: '5432' + reportdb.database: "ncc_report" + reportdb.user: "ncc_system" + reportdb.password: "ncc_system" + gateways.service: "nausd" + NCC_LOG_TYPE: "raw" + volumes: + - "./spool/naubuddy:/opt/naumen/nauphone/spool/naubuddy" + - "./spool/naumb:/opt/naumen/nauphone/spool/naumb" + links: + - naucore + - postgres + - redis-naumb + restart: always + depends_on: + postgres: + condition: service_healthy + + naumbstat: + image: ncc-75.nau.team/naumbstat:7.5 + tty: yes + environment: + bus.ip: "naucore" + redis.host: "redis-naumb" + links: + - naucore + - postgres + - redis-naumb + depends_on: + postgres: + condition: service_healthy + + nauqpm: + image: ncc-75.nau.team/nauqpm:7.5 + volumes: + - "./spool/nauqpm:/opt/naumen/nauphone/spool/nauqpm" + environment: + bus.ip: "naucore" + links: + - naucore + - postgres + depends_on: + postgres: + condition: service_healthy + + chat: + image: ncc-75.nau.team/chat:7.5 + ports: + - "${CHAT_PORT:-8081}:8081" + - "${WS_PORT:-9000}:9000" + environment: + bus.ip: "naucore" + chatdb.engine: postgresql + chatdb.host: postgres + chatdb.port: '5432' + chatdb.database: chat + chatdb.user: "ncc_system" + chatdb.password: "ncc_system" + links: + - naucore + - postgres + restart: always + depends_on: + postgres: + condition: service_healthy + diff --git a/compose/themes_generator/Dockerfile b/compose/themes_generator/Dockerfile new file mode 100644 index 0000000..8551743 --- /dev/null +++ b/compose/themes_generator/Dockerfile @@ -0,0 +1,18 @@ +FROM openjdk:11 +COPY --from=python:3.7 / / + +WORKDIR /app/ +ADD ./app /app/ + +RUN set -ex \ + && pip3 install --no-cache-dir -r /app/requirements.txt \ + && chmod +x /app/mallet/bin/* \ + && apt-get update \ + && apt install ant -y \ + && rm -rf /var/lib/apt/lists/* /var/cache/apt/* \ + && cd /app/mallet/ \ + && ant + +ENTRYPOINT ["python3", "clustering_server.py"] + +EXPOSE 5000 diff --git a/compose/themes_generator/requirements.txt b/compose/themes_generator/requirements.txt new file mode 100644 index 0000000..32c1615 --- /dev/null +++ b/compose/themes_generator/requirements.txt @@ -0,0 +1,51 @@ +beautifulsoup4==4.8.2 +boto3==1.12.32 +botocore==1.15.32 +bottle==0.12.18 +cachetools==4.0.0 +certifi==2019.11.28 +chardet==3.0.4 +cheroot==8.3.0 +CherryPy==8.9.1 +docutils==0.15.2 +gensim==3.8.1 +google-api-core==1.16.0 +google-auth==1.12.0 +google-cloud-core==1.3.0 +google-cloud-storage==1.26.0 +google-resumable-media==0.5.0 +googleapis-common-protos==1.51.0 +idna==2.9 +importlib-metadata==1.6.0 +importlib-resources==1.4.0 +jaraco.classes==3.1.0 +jaraco.collections==3.0.0 +jaraco.functools==3.0.0 +jaraco.text==3.2.0 +jmespath==0.9.5 +lxml==4.5.0 +more-itertools==8.2.0 +nltk==3.4.5 +numexpr==2.7.1 +numpy==1.18.2 +pandas==1.0.3 +portend==2.6 +protobuf==3.11.3 +psycopg2-binary==2.8.4 +pyasn1==0.4.8 +pyasn1-modules==0.2.8 +pymystem3==0.2.0 +python-dateutil==2.8.1 +pytz==2019.3 +requests==2.23.0 +rsa==4.0 +s3transfer==0.3.3 +scipy==1.4.1 +six==1.14.0 +smart-open==1.10.0 +soupsieve==2.0 +tables==3.6.1 +tempora==3.0.0 +urllib3==1.25.8 +zc.lockfile==2.0 +zipp==3.1.0 \ No newline at end of file diff --git a/jenkins/1cdb.groovy b/jenkins/1cdb.groovy new file mode 100644 index 0000000..720941a --- /dev/null +++ b/jenkins/1cdb.groovy @@ -0,0 +1,235 @@ +import java.text.SimpleDateFormat +import groovy.transform.Field +@Field List props = [] + +pipeline { + agent none + + parameters { + choice( + name: 'ACTION', + choices: ['DAY','WEEK'], + description: 'Выбор бэкапа' + ) + } + + options { + disableConcurrentBuilds() + timestamps() + buildDiscarder(logRotator(numToKeepStr: '10')) + skipDefaultCheckout() + timeout(time: 360, unit: 'MINUTES') + } + environment { + BUILD_USER = getBuildUser() + CURRENT_DATE = new Date().format( 'dd.MM.yy_HH:mm' ) + } + + + triggers{ + parameterizedCron(''' + 30 19 * * 1,2,3,4 %ACTION=DAY + 30 19 * * 5 %ACTION=WEEK + ''') + } + + + stages { + + stage('Prepare_MASTER') { + agent {label "master"} + steps { + deleteDir() + gitClone("master") + } + } + + stage('Prepare_SITE') { + agent {label "net"} + steps { + deleteDir() + gitClone("master") + } + } + + +///// + stage('1CDB') { + agent {label "master"} + when { beforeAgent true + anyOf {environment name: 'ACTION', value: 'DAY'; environment name: 'ACTION', value: 'WEEK'} + } + + steps { + pwsh script: "./site/1cdb_session.ps1 1CDB" + updateDesc("${env.STAGE_NAME}") + sendME("${env.STAGE_NAME}","Backup success!!!") + telegramSend(message: '1C backup success!!!', chatId: 648920818) + } + } +//// + + stage('Move_day') { + agent {label "master"} + when { beforeAgent true + anyOf {environment name: 'ACTION', value: 'MOVE'; environment name: 'ACTION', value: 'DAY'} + } + steps { + sh ''' + mv /srv/SITE/1CDB*.7z /srv/SITE/1CDB/ + find /srv/SITE/1CDB/ -name "*.7z" -mtime +10 -exec rm -f {} \\; + ''' + telegramSend(message: 'Day 1CDB MOVE success!!!', chatId: 648920818) + } + } + +//// + +//// + + stage('Move_week') { + agent {label "master"} + when { beforeAgent true + anyOf {environment name: 'ACTION', value: 'MOVE'; environment name: 'ACTION', value: 'WEEK'} + } + steps { + sh ''' + mv /srv/SITE/1CDB*.7z /srv/1CSRV/1CDB/ + find /srv/1CSRV/1CDB/ -name "*.7z" -mtime +60 -exec rm -f {} \\; + ''' + telegramSend(message: 'WEEK 1CDB MOVE success!!!', chatId: 648920818) + } + } + +//// + + + + } + + post { + success { + node ("master") { + jabberNotify notificationStrategy: 'success', notifyCulprits: true, notifyFixers: true, notifySuspects: true, notifyUpstreamCommitters: true, extraMessage: 'Бэкап 1С завершен успешно', targets: 'user@domen' + } + } + + aborted { + node ("master") { + jabberNotify notificationStrategy: 'aborted', notifyCulprits: true, notifyFixers: true, notifySuspects: true, notifyUpstreamCommitters: true, extraMessage: 'Бэкап 1С пришлось остановить', targets: 'user@domen' + } + } + failure { + node ("master") { + jabberNotify notificationStrategy: 'failure', notifyCulprits: true, notifyFixers: true, notifySuspects: true, notifyUpstreamCommitters: true, extraMessage: 'Бэкап 1С завершился с ошибкой', targets: 'user@domen' + } + } + } + +} + +def getBuildUser() { + return currentBuild.rawBuild.getCause(Cause.UserIdCause)?.getUserId() +} + +def updateDesc(ACTION) +{ + def d = [ACTION: '', BACKUP_DATE: '', END_TIME: ''] + END_TIME = new Date().format( 'dd.MM.yy_HH:mm' ) + d.ACTION = "${ACTION}" + d.BACKUP_DATE = "${CURRENT_DATE}" + d.END_TIME = "${END_TIME}" + d1 = d.clone() + props << d1 + println d1 + d.clear() + println props + println d + println "${END_TIME}" + def item = Jenkins.instance.getItemByFullName("${JOB_NAME}") + item.setDescription("${getDescTemplate(props)}") + + +} + +def sendME(ACTION,STATUS) +{ +emailext body: "${STATUS}", + subject: "${ACTION}", + to: 'therion@nasda.ru' +} + + +def gitClone(String stand) { + checkout poll: false, scm: [ + $class: 'GitSCM', + branches: [[name: '*/master']], + doGenerateSubmoduleConfigurations: false, + userRemoteConfigs: [[url: 'git@gitlab.domen:user/sys.git']] + ] +} + +def scriptDir = getClass().protectionDomain.codeSource.location.path +println "${scriptDir}" + +String currentDir = new File(".").getAbsolutePath() + + +def getDescTemplate(List props) { + return """ + + +Задача бэкапирует сетевые диски +
+ Если сборка не прошла, звонить :) +
+ + + + + + + + + + + ${props.collect { prop -> + def idx = props.findIndexOf { it.equals(prop) } + return """ + + + + """ + }.join('')} + + +
Задания бэкапа:
БэкапированиеДата выполненияВремя завершения
${prop.ACTION}${prop.BACKUP_DATE}${prop.END_TIME}
+
+
+
При запуске необходимо указать параметры: +
+
    +
  • + ACTION - выполняемое действие (DAY, WEEK) +
      +
    • + DAY - Ежедневный бэкап 1С, автоматически делается в 19:30 с понедельника по четверг, архивы в C:\\Backup\\1CDB на сервере SITE +
    • +
    • + WEEK - Еженедельный бэкап 1С, автоматически делается в 19:30 в пятницу, архивы в C:\\Backup\\1CDB на сервере 1CSRV +
    • +
    +
  • +
+ + +""" +} + diff --git a/jenkins/1cdb_session.ps1 b/jenkins/1cdb_session.ps1 new file mode 100644 index 0000000..80a6dab --- /dev/null +++ b/jenkins/1cdb_session.ps1 @@ -0,0 +1,10 @@ +$Action=$args[0] +Write-Host $Action + +$Cred = New-Object System.Management.Automation.PSCredential ('user', (ConvertTo-SecureString 'passwd' -AsPlainText -Force)) + +Invoke-Command -ComputerName 192.16.0.1 -Credential $Cred -Verbose -Authentication Negotiate -ScriptBlock {Remove-Item "D:\SRV\1CDB\*.bak"} +Invoke-Command -ComputerName 192.16.0.1 -Credential $Cred -Verbose -Authentication Negotiate -ScriptBlock {Backup-SqlDatabase -ServerInstance "." -Database "KD" -BackupFile "D:\SRV\1CDB\KD.bak"} +Invoke-Command -ComputerName 192.16.0.1 -Credential $Cred -Verbose -Authentication Negotiate -ScriptBlock {Backup-SqlDatabase -ServerInstance "." -Database "IP" -BackupFile "D:\SRV\1CDB\IP.bak"} + +Invoke-Command -ComputerName 192.16.0.1 -Credential $Cred -Authentication Negotiate -ScriptBlock {..\.jenkins\workspace\1cdb_backup\site\site_backup.ps1 $Using:Action} diff --git a/jenkins/1csrv.groovy b/jenkins/1csrv.groovy new file mode 100644 index 0000000..3d44fa2 --- /dev/null +++ b/jenkins/1csrv.groovy @@ -0,0 +1,218 @@ +import java.text.SimpleDateFormat +import groovy.transform.Field +@Field List props = [] + +pipeline { + agent none + + parameters { + choice( + name: 'ACTION', + choices: ['ALL','1CDB','KD'], + description: 'Выбор бэкапа' + ) + } + + options { + disableConcurrentBuilds() + timestamps() + buildDiscarder(logRotator(numToKeepStr: '10')) + skipDefaultCheckout() + timeout(time: 2400, unit: 'MINUTES') + } + environment { + BUILD_USER = getBuildUser() + CURRENT_DATE = new Date().format( 'dd.MM.yy_HH:mm' ) + } + + + triggers{ + parameterizedCron(''' + 00 23 * * 5 %ACTION=KD + ''') + } + + stages { + + stage('Prepare_MASTER') { + agent {label "master"} + steps { + deleteDir() + gitClone("master") + } + } + + stage('Prepare_1CSRV') { + agent {label "mssql"} + steps { + deleteDir() + gitClone("master") + } + } + + +///// + stage('Backup_KD') { + agent {label "master"} + when { beforeAgent true + anyOf {environment name: 'ACTION', value: 'KD'; environment name: 'ACTION', value: 'ALL'} + } + + steps { + pwsh script: "./1csrv/1csrv_session.ps1 KD $env.JOB_NAME" + updateDesc("${env.STAGE_NAME}") + sendME("${env.STAGE_NAME}","Backup success!!!") + telegramSend(message: 'KD backup success!!!', chatId: 648920818) + } + } +///// + + stage('Backup_1C_MSSQL') { + agent {label "master"} + when { beforeAgent true + anyOf {environment name: 'ACTION', value: '1CDB'; environment name: 'ACTION', value: 'ALL'} + } + + steps { + pwsh script: "./1csrv/1csrv_session.ps1 1CDB $env.JOB_NAME" + updateDesc("${env.STAGE_NAME}") + sendME("${env.STAGE_NAME}","Backup success!!!") + telegramSend(message: '1C backup success!!!', chatId: 648920818) + } + } + + } + + + post { + success { + node ("master") { + jabberNotify notificationStrategy: 'success', extraMessage: 'MSSQL и Сетевые диски успешно сбэкапированы, можно забирать', targets: 'user@domen' + } + } + + aborted { + node ("master") { + jabberNotify notificationStrategy: 'aborted', notifyCulprits: true, notifyFixers: true, notifySuspects: true, notifyUpstreamCommitters: true, extraMessage: 'Пришлось остановить', targets: 'user@domen' + } + } + failure { + node ("master") { + jabberNotify notificationStrategy: 'failure', notifyCulprits: true, notifyFixers: true, notifySuspects: true, notifyUpstreamCommitters: true, extraMessage: 'Бэкап сетевых дисков завершился с ошибкой', targets: 'user@domen' + } + } + } + +} + +def getBuildUser() { + return currentBuild.rawBuild.getCause(Cause.UserIdCause)?.getUserId() +} + +def updateDesc(ACTION) +{ + def d = [ACTION: '', BACKUP_DATE: '', END_TIME: ''] + END_TIME = new Date().format( 'dd.MM.yy_HH:mm' ) + d.ACTION = "${ACTION}" + d.BACKUP_DATE = "${CURRENT_DATE}" + d.END_TIME = "${END_TIME}" + d1 = d.clone() + props << d1 + println d1 + d.clear() + println props + println d + println "${END_TIME}" + def item = Jenkins.instance.getItemByFullName("${JOB_NAME}") + item.setDescription("${getDescTemplate(props)}") + + +} + +def sendME(ACTION,STATUS) +{ +emailext body: "${STATUS}", + subject: "${ACTION}", + to: 'therion@nasda.ru' +} + + +def gitClone(String stand) { + checkout poll: false, scm: [ + $class: 'GitSCM', + branches: [[name: '*/master']], + doGenerateSubmoduleConfigurations: false, + userRemoteConfigs: [[url: 'git@gitlab.domen:user/sys.git']] + ] +} + +def scriptDir = getClass().protectionDomain.codeSource.location.path +println "${scriptDir}" + +String currentDir = new File(".").getAbsolutePath() + + +def getDescTemplate(List props) { + return """ + + +Задача бэкапирует базы данных 1С +
+ Если сборка не прошла, звонить :) +
+ + + + + + + + + + + ${props.collect { prop -> + def idx = props.findIndexOf { it.equals(prop) } + return """ + + + + """ + }.join('')} + + +
Задания бэкапа:
БэкапированиеДата выполненияВремя завершения
${prop.ACTION}${prop.BACKUP_DATE}${prop.END_TIME}
+
+
+
При запуске необходимо указать параметры: +
+
    +
  • + ACTION - выполняемое действие (ALL, 1CDB, WORK) +
      +
    • + ALL - Выполнение всех задач, планировщик делает по умолчанию в выходной +
    • +
    • + 1CDB - Бэкап Баз Данных 1С, после выполнения, архив доступен для скачки по ссылке +
    • +
    • + KD - Бэкап Конструкторской документации +
    • +
    +
  • +
  • + Бэкапы тут - \\\\1CSRV.domen\\Backup +
  • +
+ + +""" +} + diff --git a/jenkins/1csrv_session.ps1 b/jenkins/1csrv_session.ps1 new file mode 100644 index 0000000..45c5a25 --- /dev/null +++ b/jenkins/1csrv_session.ps1 @@ -0,0 +1,20 @@ +$Action=$args[0] +$Job=$args[1] +Write-Host $Action +Write-Host $Job + +$Cred = New-Object System.Management.Automation.PSCredential ('user', (ConvertTo-SecureString 'password' -AsPlainText -Force)) + +if ( $Action -match '1CDB') +{ +Invoke-Command -ComputerName 192.16.0.6 -Credential $Cred -Verbose -Authentication Negotiate -ScriptBlock {Remove-Item "D:\1CDB\*.bak"} +Invoke-Command -ComputerName 192.16.0.6 -Credential $Cred -Verbose -Authentication Negotiate -ScriptBlock {Backup-SqlDatabase -ServerInstance "." -Database "KD" -BackupFile "D:\1CDB\KD.bak"} +Invoke-Command -ComputerName 192.16.0.6 -Credential $Cred -Verbose -Authentication Negotiate -ScriptBlock {Backup-SqlDatabase -ServerInstance "." -Database "IP" -BackupFile "D:\1CDB\IP.bak"} +Invoke-Command -ComputerName 192.16.0.6 -Credential $Cred -Authentication Negotiate -ScriptBlock {..\.jenkins\workspace\1csrv_backup\1csrv\1csrv_backup.ps1 $Using:Action} +} + +if ( $Action -match 'KD') +{ +Invoke-Command -ComputerName 172.16.0.6 -Credential $Cred -Authentication Negotiate -ScriptBlock {..\.jenkins\workspace\1csrv_backup\1csrv\1csrv_backup.ps1 $Using:Action} +} + diff --git a/jenkins/astarot.groovy b/jenkins/astarot.groovy new file mode 100644 index 0000000..f189e95 --- /dev/null +++ b/jenkins/astarot.groovy @@ -0,0 +1,204 @@ +import java.text.SimpleDateFormat +import groovy.transform.Field +@Field List props = [] + +pipeline { + agent none + + parameters { + choice( + name: 'ACTION', + choices: ['ALL','WEB','LINUX'], + description: 'Выбор бэкапа' + ) + } + + options { + disableConcurrentBuilds() + timestamps() + buildDiscarder(logRotator(numToKeepStr: '10')) + skipDefaultCheckout() + timeout(time: 2400, unit: 'MINUTES') + } + environment { + BUILD_USER = getBuildUser() + CURRENT_DATE = new Date().format( 'dd.MM.yy_HH:mm' ) + } + + + triggers{ + parameterizedCron(''' + 00 21 * * 5 %ACTION=WEB + ''') + } + + + stages { + + stage('Prepare_ASTAROT') { + agent {label "site"} + steps { + deleteDir() + gitClone("master") + } + } + + + stage('WEB_BACKUP') { + agent {label "site"} + when { beforeAgent true + anyOf {environment name: 'ACTION', value: 'WEB'; environment name: 'ACTION', value: 'ALL'} + } + steps { + sh ''' + rsync -avHAXxz --progress --delete --numeric-ids --exclude devpribor.ru/core/cache/* -e ssh intertest@188.120.241.91://var/www/intpribor/www /srv/archive/site/dev/ + rsync -avHAXxz --progress --delete --numeric-ids --exclude interpribor.ru/core/cache/* -e ssh intertest@188.120.241.91://var/www/devtest/www /srv/archive/site/test/ + rsync -avHAXxz --progress --delete --numeric-ids --exclude interpribor.ru/core/cache/* -e ssh interbase@82.146.55.174://var/www/intpribor/www /srv/archive/site/prod/ + ssh interbase@82.146.55.174 "mysqldump --host 127.0.0.1 --port 3307 --column-statistics=0 --no-tablespaces -ucarpribor -p1L5n0E7Ah8A9 carpribor | gzip -9" > /srv/archive/site/prod/carpribor_$(date +%d%m%Y).sql.gz + tar -zcvf /mnt/backup/site/site_prod_$(date +%d%m%Y).tar.gz /srv/archive/site/prod/ + tar -zcvf /mnt/backup/site/site_dev_$(date +%d%m%Y).tar.gz /srv/archive/site/dev/www/devpribor.ru/ + find /mnt/backup/site/ -name "*.gz" -mtime +27 -exec rm -f {} \\; + ''' + updateDesc("${env.STAGE_NAME}") + sendME("${env.STAGE_NAME}","WEB Backup success!!!") + telegramSend(message: 'WEB BACKUP success!!!', chatId: 648920818) + } + } + +//// + + + } + + post { + success { + node ("site") { + jabberNotify notificationStrategy: 'success', notifyCulprits: true, notifyFixers: true, notifySuspects: true, notifyUpstreamCommitters: true, extraMessage: 'WEB BACKUP SUCCESS!!!', targets: 'user@domen' + } + } + + aborted { + node ("site") { + jabberNotify notificationStrategy: 'aborted', notifyCulprits: true, notifyFixers: true, notifySuspects: true, notifyUpstreamCommitters: true, extraMessage: 'WEB BACKUP ABORT!!!', targets: 'user@domen' + } + } + failure { + node ("site") { + jabberNotify notificationStrategy: 'failure', notifyCulprits: true, notifyFixers: true, notifySuspects: true, notifyUpstreamCommitters: true, extraMessage: 'WEB BACKUP ERROR!!!', targets: 'user@domen' + } + } + } + +} + +def getBuildUser() { + return currentBuild.rawBuild.getCause(Cause.UserIdCause)?.getUserId() +} + +def updateDesc(ACTION) +{ + def d = [ACTION: '', BACKUP_DATE: '', END_TIME: ''] + END_TIME = new Date().format( 'dd.MM.yy_HH:mm' ) + d.ACTION = "${ACTION}" + d.BACKUP_DATE = "${CURRENT_DATE}" + d.END_TIME = "${END_TIME}" + d1 = d.clone() + props << d1 + println d1 + d.clear() + println props + println d + println "${END_TIME}" + def item = Jenkins.instance.getItemByFullName("${JOB_NAME}") + item.setDescription("${getDescTemplate(props)}") + + +} + +def sendME(ACTION,STATUS) +{ +emailext body: "${STATUS}", + subject: "${ACTION}", + to: 'therion@nasda.ru' +} + + +def gitClone(String stand) { + checkout poll: false, scm: [ + $class: 'GitSCM', + branches: [[name: '*/master']], + doGenerateSubmoduleConfigurations: false, + userRemoteConfigs: [[url: 'git@gitlab.domen:user/sys.git']] + ] +} + +def scriptDir = getClass().protectionDomain.codeSource.location.path +println "${scriptDir}" + +String currentDir = new File(".").getAbsolutePath() + + +def getDescTemplate(List props) { + return """ + + +Задача бэкапирует сетевые диски +
+ Если сборка не прошла, звонить :) +
+ + + + + + + + + + + ${props.collect { prop -> + def idx = props.findIndexOf { it.equals(prop) } + return """ + + + + """ + }.join('')} + + +
Задания бэкапа:
БэкапированиеДата выполненияВремя завершения
${prop.ACTION}${prop.BACKUP_DATE}${prop.END_TIME}
+
+
+
При запуске необходимо указать параметры: +
+
    +
  • + ACTION - выполняемое действие (ALL, 1CDB, WORK) +
      +
    • + ALL - Выполнение всех задач, планировщик делает по умолчанию в выходной +
    • +
    • + WEB - Бэкап Продуктивного и тестового сайтов +
    • +
    • + LINUX - Бэкап Linux server with rsync +
    • +
    +
  • +
  • + Бэкапы тут - \\\\ASTAROT.domen\\Backup +
  • +
+ + +""" +} + diff --git a/jenkins/branch_ncc.groovy b/jenkins/branch_ncc.groovy new file mode 100644 index 0000000..2d79864 --- /dev/null +++ b/jenkins/branch_ncc.groovy @@ -0,0 +1,405 @@ +import java.text.SimpleDateFormat +import groovy.transform.Field +// import java.time.* +// import hudson.model.Computer.ListPossibleNames + + +@Field int NUMBER_OF_STANDS = 4 +@Field String STAND_NAME_TEMPLATE = "nccbranch" + +pipeline { + agent { + node { + label 'ncc-apps' + customWorkspace '/opt/ncc/' + } + } + parameters { + choice( + name: 'ACTION', + choices: ['Deploy', 'Prolong', 'Stop'], + description: 'Выбор действия' + ) + choice( + name: 'STAND', + choices: "${getStandsNames()}", + description: 'Выбор стенда' + ) + string( + name: 'VERSION', + defaultValue: '7.5', + description: 'Номер версии NCC' + ) + string( + name: 'NOT_OFF', + defaultValue: getParamNotOff(), + description: 'Не выключать до указанного времени, например, "31/01 20-00"' + ) + booleanParam( + name: 'clearDB', + defaultValue: false, + description: "Очистить базу данных" + ) + } + options { + timestamps() + buildDiscarder(logRotator(numToKeepStr: '10')) + skipDefaultCheckout() + timeout(time: 40, unit: 'MINUTES') + } + environment { + BUILD_USER = getBuildUser() + CHAT_PORT = getPort("${STAND}") + DIR_STAND = "/opt/ncc/${STAND}" + CURRENT_DATE = new Date().format( 'dd.MM.yy_HHmm' ) + COMPOSE_INTERACTIVE_NO_CLI = 1 + COMPOSE_HTTP_TIMEOUT = 180 + } + triggers{ + parameterizedCron(''' + 02 3 * * * %STAND=nccbranch4;ACTION=Deploy;BUILD_USER=Jenkins + ''') + } + + stages { + + stage('Stop') { + when { + beforeAgent true + environment name: 'ACTION', value: 'Stop' + } + steps { + dir("${DIR_STAND}/ncc-compose/") { + sh ''' + docker version + docker-compose --ansi never version + docker-compose --ansi never ps && docker-compose --ansi never down --remove-orphans --volumes || exit 0 + ''' + } + } + } + + stage('PrepareDB') { + when { + beforeAgent true + environment name: 'clearDB', value: 'false' + not { environment name: 'VERSION', value: '' } + environment name: 'ACTION', value: 'Deploy' + } + steps { + dir("${DIR_STAND}/ncc-compose/") { + sh ''' + docker version + docker-compose --ansi never version + docker login -u user -p 123 sd-docker-registry2.naumen.ru + docker login -u pavykeka -p pesogane33145713 ncc-75.nau.team + rm -rf ./createdb/*.bak || true + ''' + + } + dir("${DIR_STAND}") { + sh ''' + echo "BUILD_ID=${BUILD_ID}" > build.properties + echo "BUILD_USER=${BUILD_USER}" >> build.properties + echo "VERSION=${VERSION}" >> build.properties + echo "NOT_OFF=${NOT_OFF}" >> build.properties + ''' + } + updateDesc() + } + } + + + stage('Prepare') { + when { + beforeAgent true + environment name: 'clearDB', value: 'true' + not { environment name: 'VERSION', value: '' } + environment name: 'ACTION', value: 'Deploy' + } + steps { + dir("${DIR_STAND}/ncc-compose/") { + sh ''' + docker version + docker-compose --ansi never version + docker-compose --ansi never ps && docker-compose --ansi never down --remove-orphans --volumes || exit 0 + docker login -u user -p 123 sd-docker-registry2.naumen.ru + docker login -u pavykeka -p pesogane33145713 ncc-75.nau.team + sudo chown -R administrator. ./ + ''' + } + dir("${DIR_STAND}") { + deleteDir() + gitClone("master") + sh ''' + echo "BUILD_ID=${BUILD_ID}" > build.properties + echo "BUILD_USER=${BUILD_USER}" >> build.properties + echo "VERSION=${VERSION}" >> build.properties + echo "NOT_OFF=${NOT_OFF}" >> build.properties + mkdir ./ncc-compose/dbdata + sudo chown -R 100 ./ncc-compose/consul-data + sudo chown -R 777 ./ncc-compose/dbdata + sudo chown -R 777 ./ncc-compose/spool + sudo chown -R 777 ./ncc-compose/createdb + ''' + } + updateDesc() + } + } + + stage('Deploy') { + when { + beforeAgent true + not { environment name: 'VERSION', value: '' } + environment name: 'ACTION', value: 'Deploy' + } + steps { + script { + currentBuild.description = "${STAND} <- $VERSION
Не выключать до $NOT_OFF" + } + dir("${DIR_STAND}/ncc-compose/") { + writeFile file:".env_tmp", text:getEnvFile() + sh ''' + cat .env_tmp > .env + docker-compose --ansi never config + docker-compose --ansi never up --build -d + sudo chown -R 777 spool + ''' + } + dir("${DIR_STAND}/ncc-compose/") { + sh 'docker-compose --ansi never ps || exit 0' + } + } + } + + stage('Prolong') { + when { + beforeAgent true + environment name: 'ACTION', value: 'Prolong' + } + steps { + script { + currentBuild.description = "${STAND} <- Prolong
Не выключать до $NOT_OFF" + } + dir("${DIR_STAND}") { + sh 'sed -i -r "s|(NOT_OFF=).*|\\1${NOT_OFF}|" build.properties' + } + } + } + } + post { + always { + updateDesc() + emailext ( + subject: "${currentBuild.currentResult}: Pipeline ${currentBuild.fullDisplayName}", + body: "${currentBuild.currentResult} Pipeline: ${currentBuild.fullDisplayName}:\n${currentBuild.absoluteUrl}", + recipientProviders: [[$class: 'RequesterRecipientProvider']] + ) + } + } +} + +// def node = jenkins.model.Jenkins.instance.getNode( "ncc-ci" ) +// def node_ip = node.computer.getChannel().call(new ListPossibleNames()) +// println "${node_ip}" + +def getParamNotOff() { + return new Date().plus(1).format( 'dd/MM ' ) + "20-00" +// LocalDateTime t = LocalDateTime.now(); +// return t as String +} + +def getBuildUser() { + return currentBuild.rawBuild.getCause(Cause.UserIdCause)?.getUserId() +} + +def getProjectDirectory() { + return fileExists("${DIR_STAND}") ? "${DIR_STAND}" : "${DIR_STAND}" +} + +def getPort(String stand) throws NumberFormatException { + int initialPort = 10000 + return initialPort + (stand - STAND_NAME_TEMPLATE).toInteger() +} + +def getEnvFile() { + String stand = "${STAND}" + int initialDbPort = 54320 + int initalNCCPort = 10100 + int initalNCCFPort = 10110 + int initialCONSULPort = 8000 + int initialWSPort = 10800 + int NCCPort = initalNCCPort + (stand - STAND_NAME_TEMPLATE).toInteger() + int CONSULPort = initialCONSULPort + (stand - STAND_NAME_TEMPLATE).toInteger() + int NCCFPort = initalNCCFPort + (stand - STAND_NAME_TEMPLATE).toInteger() + int WSPort = initialWSPort + (stand - STAND_NAME_TEMPLATE).toInteger() + int dbPort = initialDbPort + (stand - STAND_NAME_TEMPLATE).toInteger() + return """ +COMPOSE_PROJECT_NAME=${stand} +COMPOSE_FILE=docker-compose.yaml +chatOnSite=https://${stand}.nsd.naumen.ru/chatOnSite/ +URL=https://${stand}.nsd.naumen.ru/workplace.html#/login +CHAT_PORT=${CHAT_PORT} +NCC_PORT=${NCCPort} +NCCF_PORT=${NCCFPort} +DB_PORT=${dbPort} +CONSUL_PORT=${CONSULPort} +WS_PORT=${WSPort} + +""" +} + +def gitClone(String stand) { + checkout poll: false, scm: [ + $class: 'GitSCM', + branches: [[name: '*/master']], + doGenerateSubmoduleConfigurations: false, + userRemoteConfigs: [[url: 'git@gitsd.naumen.ru:ops/compose.git']] + ] +} + +def updateDesc() { + def d = [BUILD_ID: '', BUILD_USER: '', VERSION: '', NOT_OFF: ''] + def props = [] + for (int i = 1; i <= NUMBER_OF_STANDS; i++) { + prop = readProperties defaults: d, file: "/opt/ncc/nccbranch${i}/build.properties" + props << prop + } +println props + def item = Jenkins.instance.getItemByFullName("${JOB_NAME}") + item.setDescription("${getDescTemplate(props)}") +} + +def nowTime() { + return new Date().format( 'yyyy-MM-dd HH:mm' ) +} + +def getStandStatus(String notOff) { + if (!(notOff =~ /^[0-9][0-9]?\/[0-9][0-9] [0-9][0-9]?[-:][0-9][0-9]/)) { + standStatus = '' + } else { + yy = new Date().format( 'yyyy' ) + fullDate = yy + ' ' + notOff + till = new SimpleDateFormat("yyyy dd/MM HH-mm").parse(fullDate).getTime() + now = new Date().getTime() + standStatus = (till > now) ? 'stand_busy' : 'stand_free' + } + return standStatus +} + +def getDescTemplate(List props) { + return """ + + +Задача обновляет один из стендов из ветки +
+ Если сборка не прошла, то обращаться в ТПиВИ +
+ + + + + + + + + + + + + + + + + + ${props.collect { prop -> + def idx = props.findIndexOf { it.equals(prop) } + return """ + + + + + + + + + + + """ + }.join('')} + + + +
Стенды:
СтендАдминистративный интерфейс admin/adminЧат на сайтеНомер сборкиПользовательНодаПорт шиныФайловое ХранилищеПорт консулаНе отключать
${idx+1} + https://nccbranch${idx+1}.nsd.naumen.ru/workplace.html#/login + + https://nccbranch${idx+1}.nsd.naumen.ru/chatOnSite/ + ${prop.BUILD_ID}${prop.BUILD_USER}nccbranch${idx+1}.sd.naumen.ru1010${idx+1} + https://nccbranch${idx+1}.nsd.naumen.ru/fx + 800${idx+1}${prop.NOT_OFF}
Last updated: ${nowTime()}
+
+
+
При запуске необходимо выбрать стенд для обновления и указать параметры: +
+
    +
  • + ACTION - выполняемое действие (Deploy, Prolong, Stop) +
      +
    • + Deploy - развертывание стенда. Используемые параметры: VERSION, NOT_OFF, крыжик clearDB (пересоздаст с настройками по умолчанию) +
    • +
    • + Prolong - продление стенда. Используемые параметры: NOT_OFF +
    • +
    • + Stop - остановить стенд. По просьбе тестирования, для эмуляции сбоя. Последующий запускс стенда через Delpoy +
    • +
    +
  • +
  • + STAND - имя стенда +
  • +
  • + VERSION - версия системы, заложено на будущее, а настоящее время, интеграция тестировалась только на версии 7.5 +
  • +
  • + Не отключать - указать время и дату, до которой нужен стенд (поле информативное, стенд не будет автоматически выключен) +
  • +
  • + Нода - данные указать в поле Адрес сервера при настройке интеграции со стороны NSD +
  • +
  • + Порт шины - данные для поля порт при настройке интеграции со стороны NSD +
  • +
  • + Файловое хранилище - Пишем в поле файлового хранилища при настроке интеграции со стороны NSD +
  • +
  • + Логины к чату на сайте - Логины в системе: portal1...portal8 (под портальные бранчи), test1...test4 (под ncc). Пароли для всех 123. Менять, добавлять, логины к витринам: http://nccbranch1.sd.naumen.ru:8001/. +
  • +
+ + + +""" +} + +def getStandsNames() { + def standsNames = '' + for (int i = 1; i <= NUMBER_OF_STANDS; i++) { + standsNames += "nccbranch${i}" + standsNames += "${i.equals(NUMBER_OF_STANDS) ? "" : "\n"}" + } + return standsNames +} diff --git a/jenkins/getmailbox.groovy b/jenkins/getmailbox.groovy new file mode 100644 index 0000000..13296e3 --- /dev/null +++ b/jenkins/getmailbox.groovy @@ -0,0 +1,237 @@ +import java.text.SimpleDateFormat +import groovy.transform.Field +// Misc manipulations +import java.nio.charset.StandardCharsets + +pipeline { + agent { + node { + label 'mail_acc' + } + } + parameters { + choice( + name: 'ACTION', + choices: ['New-Mail', 'Delete-Mail', 'Get-Mail'], + description: 'Выбор действия, Get-Mail - только обновит список пользователей' + ) + string( + name: 'email', + defaultValue: '@domain', + description: 'Желаемый email пользователя, если меняем пароль, выбираем из списка, при создании нового, выбрать свободное имя' + ) + string( + name: 'MailPass', + defaultValue: '123qweASD', + description: 'Пароль пользователя, стандартный лучше не использовать, во избежании случайного подключения другого пользователя' + ) + booleanParam( + name: 'NeedSharedMail', + defaultValue: false, + description: 'Нужны права на общий ящик: shared@domain' + ) + + } + + options { + disableConcurrentBuilds() + timestamps() + buildDiscarder(logRotator(numToKeepStr: '10')) + skipDefaultCheckout() + timeout(time: 40, unit: 'MINUTES') + } + environment { + BUILD_USER = getBuildUser() + CURRENT_DATE = new Date().format('dd.MM.yy_HHmm') + DIR_MAIL = "./jenkins/ps1/" + username = "${BUILD_USER}"+"${BUILD_ID}" + } + + stages { + + stage('getmail') { + when { + beforeAgent true + environment name: 'ACTION', value: 'Get-Mail' + } + + steps { + dir("${DIR_MAIL}") { + powershell ''' + ./getmailbox.ps1 + ''' + updateDesc('mailbox.nausd') + } + } + } + + stage('newmail') { + when { + beforeAgent true + environment name: 'ACTION', value: 'New-Mail' + } + + steps { + dir("${DIR_MAIL}") { + println "${username}" + println "${email}" + println "${MailPass}" + powershell script: "./newmailbox.ps1 $username $email $MailPass $NeedSharedMail" + updateDesc('mailbox.nausd') + } + } + } + + stage('removemailbox') { + when { + beforeAgent true + environment name: 'ACTION', value: 'Delete-Mail' + } + + steps { + dir("${DIR_MAIL}") { + println "${username}" + println "${email}" + println "${MailPass}" + powershell script: "./removemailbox.ps1 $email" + updateDesc('mailbox.nausd') + } + } + } + + } +} + + +def updateDesc(String propertyFile) { + def keyMapping = [ + DisplayName: 'UserName', + WindowsEmailAddress: 'EMail', + CustomAttribute1: 'Password', + + ] + + def props = [] + def mailInfo = [:] + readFile("${propertyFile}").split('\n').each { line -> + if (!line.isEmpty()) { + def fields = line.split(':').collect { it.trim() } + mailInfo.put(keyMapping.get(fields.first()), fields.last()) + if (fields.first().equals(keyMapping.keySet().last())) { + props.add(mailInfo.clone()) + mailInfo.clear() + } + } else { + return + } + } + int NUMBER_OF_MAILS = props.size(); + println("NUMBER_OF_MAILS: ${NUMBER_OF_MAILS}") + props.each { + println("Mail Info
: ${it}") + } + + def item = Jenkins.instance.getItemByFullName("${JOB_NAME}") + item.setDescription("${getDescTemplate(props)}") + +} + +def getBuildUser() { + return currentBuild.rawBuild.getCause(Cause.UserIdCause)?.getUserId() +} + +/* +def gitClone(String stand) { + checkout poll: false, scm: [ + $class : 'GitSCM', + branches : [[name: 'master']], + doGenerateSubmoduleConfigurations: false, + userRemoteConfigs : [[url: 'git@gitsd.naumen.ru:repo/scripts_tpivi.git']] + ] +} +*/ + +def scriptDir = getClass().protectionDomain.codeSource.location.path +println "${scriptDir}" + +String currentDir = new File(".").getAbsolutePath() + + +def getDescTemplate(List props) { + return """ + + +Задача управляет тестовым почтовым сервером Exchange +
+ Если сборка не прошла, то обращаться в ТПиВИ +
+ + + + + + + + + + + + + ${props.collect { prop -> + def idx = props.findIndexOf { it.equals(prop) } + return """ + + + + """ + }.join('')} + + +
Почтовые ящики:
Имя пользователяПочтовый ящик пользователяПароль пользователя
${prop.UserName}${prop.EMail}${prop.Password}
+
+
+
При запуске необходимо указать параметры: +
+
    +
  • + ACTION - выполняемое действие (New-Mail, Delete-Mail, Get-Mail) +
      +
    • + New-Mail - Создание нового ящика пользователя или обновление существующего +
    • +
    • + Delete-Mail - Удаление ящика пользователя в котором отпала необходимость ( попутно вычистит ящики к которым не было подключения более года ) +
    • +
    • + Get-Mail - Обновит список почтовых ящиков с сервера +
    • +
    +
  • +
  • + Имя пользователя - Формируется из параметров сборки +
  • +
  • + Почтовый ящик пользователя - Должен быть в формате login@domain. Допускаются только символы латинского алфавита +
  • +
  • + Пароль пользователя - Не менее 8 сиволов разного регистра и цифры. Рекомендуется использовать пароль отличный от стандартного +
  • +
  • + shared@domain - Общий почтовый ящик, подключается галочкой в сборке при создании нового или изменениии параметров текущего почтового ящиков +
  • +
  • + Веб интерфейс для доступа - https://win2016-dc-exch.domain/owa/ +
  • +
+ + +""" +} + diff --git a/jenkins/getmailbox.ps1 b/jenkins/getmailbox.ps1 new file mode 100644 index 0000000..d63120c --- /dev/null +++ b/jenkins/getmailbox.ps1 @@ -0,0 +1,8 @@ +$username='adm_exch@domain' +$pwsd='superpass' +$password = ConvertTo-SecureString $pwsd -AsPlainText -Force +$Cred = New-Object System.Management.Automation.PSCredential ($username, $password) + +$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://win2016-dc-exch.domain/powershell/ -Authentication Basic -AllowRedirection -Credential $Cred +Invoke-Command -Session $Session -ScriptBlock { Get-Mailbox -OrganizationalUnit domain/NSD -ResultSize Unlimited } | Format-List DisplayName, WindowsEmailAddress, CustomAttribute1 | Out-File -Encoding UTF8 mailbox.nausd +Remove-PSSession $Session diff --git a/jenkins/newmailbox.ps1 b/jenkins/newmailbox.ps1 new file mode 100644 index 0000000..15540fa --- /dev/null +++ b/jenkins/newmailbox.ps1 @@ -0,0 +1,29 @@ +$Cred = New-Object System.Management.Automation.PSCredential ('adm_exch@domain', (ConvertTo-SecureString 'superpass' -AsPlainText -Force)) + +$UserName=$args[0] +$Email=$args[1] +$MailPass=$args[2] +$NeedSharedMail=$args[3] + +Write-Host $UserName +Write-Host $Email +Write-Host $MailPass +Write-Host $NeedSharedMail + +$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://win2016-dc-exch.domain/powershell/ -Authentication Basic -AllowRedirection -Credential $Cred +Import-PSSession $Session -DisableNameChecking -AllowClobber + +if(Get-Mailbox $Email) { Write-Host "$Email is ALREADY create" } +else { New-Mailbox -Name "$UserName" -UserPrincipalName "$Email" -Password (ConvertTo-SecureString "$MailPass" -AsPlainText -Force) -DisplayName "$UserName" -OrganizationalUnit NSD } +Set-Mailbox "$Email" -CustomAttribute1 "$MailPass" -Password (ConvertTo-SecureString "$MailPass" -AsPlainText -Force) -Force -Confirm:$false + +if($NeedSharedMail -eq "True") +{ +Add-MailboxPermission -User "$Email" -AccessRights FullAccess -InheritanceType All Shared@domain +Add-ADPermission -Identity "CN=shared,OU=Shared,DC=nausd,DC=local" -User "$Email" -ExtendedRights "Send As" +Set-Mailbox Shared -GrantSendOnBehalfTo "$Email" +} + +Get-Mailbox -OrganizationalUnit NSD -ResultSize Unlimited | Format-List DisplayName, WindowsEmailAddress, CustomAttribute1 | Out-File -Encoding UTF8 mailbox.nausd + +Remove-PSSession $Session \ No newline at end of file diff --git a/jenkins/removemailbox.ps1 b/jenkins/removemailbox.ps1 new file mode 100644 index 0000000..e08be48 --- /dev/null +++ b/jenkins/removemailbox.ps1 @@ -0,0 +1,19 @@ +$Cred = New-Object System.Management.Automation.PSCredential ('adm_exch@domain', (ConvertTo-SecureString 'superpass' -AsPlainText -Force)) + +$Email=$args[0] + +Write-Host $Email + +$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://win2016-dc-exch.domain/powershell/ -Authentication Basic -AllowRedirection -Credential $Cred +Import-PSSession $Session -DisableNameChecking -AllowClobber + +#Invoke-Command -Session $Session -ScriptBlock { Remove-Mailbox -Identity "$Using:Email" -Permanent $true -Force -Confirm:$false } +#Invoke-Command -Session $Session -ScriptBlock { Get-Mailbox -OrganizationalUnit domain/NSD -ResultSize Unlimited } | Format-List DisplayName, WindowsEmailAddress, CustomAttribute1 | Out-File -Encoding UTF8 mailbox.nausd +# Remove email from jenkins +Remove-Mailbox -Identity "$Email" -Permanent $true -Force -Confirm:$false +# Remove Older then 360 days emails +Get-Mailbox -OrganizationalUnit domain/NSD -resultsize unlimited | Get-MailboxStatistics | ?{$_.LastLogonTime -lt (get-date).adddays(-360)} | Remove-Mailbox -Permanent $true -Force -Confirm:$false + +Get-Mailbox -OrganizationalUnit NSD -ResultSize Unlimited | Format-List DisplayName, WindowsEmailAddress, CustomAttribute1 | Out-File -Encoding UTF8 mailbox.nausd + +Remove-PSSession $Session \ No newline at end of file diff --git a/jenkins/site.groovy b/jenkins/site.groovy new file mode 100644 index 0000000..2e24d5f --- /dev/null +++ b/jenkins/site.groovy @@ -0,0 +1,256 @@ +import java.text.SimpleDateFormat +import groovy.transform.Field +@Field List props = [] + +pipeline { + agent none + + parameters { + choice( + name: 'ACTION', + choices: ['ALL','PROG','DOC','WORK','MOVE'], + description: 'Выбор бэкапа' + ) + } + + options { + disableConcurrentBuilds() + timestamps() + buildDiscarder(logRotator(numToKeepStr: '10')) + skipDefaultCheckout() + timeout(time: 2400, unit: 'MINUTES') + } + environment { + BUILD_USER = getBuildUser() + CURRENT_DATE = new Date().format( 'dd.MM.yy_HH:mm' ) + } + + + triggers{ + parameterizedCron(''' + 00 01 * * 6 %ACTION=ALL + ''') + } + + + stages { + + stage('Prepare_MASTER') { + agent {label "master"} + steps { + deleteDir() + gitClone("master") + } + } + + stage('Prepare_SITE') { + agent {label "net"} + steps { + deleteDir() + gitClone("master") + } + } + + +///// + stage('Backup_WORK') { + agent {label "master"} + when { beforeAgent true + anyOf {environment name: 'ACTION', value: 'WORK'; environment name: 'ACTION', value: 'ALL'} + } + + steps { + pwsh script: "./site/site_session.ps1 WORK $env.JOB_NAME" + updateDesc("${env.STAGE_NAME}") + sendME("${env.STAGE_NAME}","Backup success!!!") + telegramSend(message: 'WORK backup success!!!', chatId: 648920818) + } + } +///// +///// + stage('Backup_PROG') { + agent {label "master"} + when { beforeAgent true + anyOf {environment name: 'ACTION', value: 'PROG'; environment name: 'ACTION', value: 'ALL'} + } + + steps { + pwsh script: "./site/site_session.ps1 PROG $env.JOB_NAME" + updateDesc("${env.STAGE_NAME}") + sendME("${env.STAGE_NAME}","Backup success!!!") + telegramSend(message: 'PROG backup success!!!', chatId: 648920818) + } + } +///// + stage('Backup_DOC') { + agent {label "master"} + when { beforeAgent true + anyOf {environment name: 'ACTION', value: 'DOC'; environment name: 'ACTION', value: 'ALL'} + } + + steps { + pwsh script: "./site/site_session.ps1 DOC $env.JOB_NAME" + updateDesc("${env.STAGE_NAME}") + sendME("${env.STAGE_NAME}","Backup success!!!") + telegramSend(message: 'DOC backup success!!!', chatId: 648920818) + } + } +//// + + stage('Move_del') { + agent {label "master"} + when { beforeAgent true + anyOf {environment name: 'ACTION', value: 'MOVE'; environment name: 'ACTION', value: 'ALL'} + } + steps { + sh ''' + mv /srv/SITE/*.7z /srv/1CSRV/ + find /srv/1CSRV/ -name "*.7z" -mtime +6 -exec rm -f {} \\; + ''' + telegramSend(message: 'ALL MOVE success!!!', chatId: 648920818) + } + } + +//// + + + } + + post { + success { + node ("master") { + jabberNotify notificationStrategy: 'success', notifyCulprits: true, notifyFixers: true, notifySuspects: true, notifyUpstreamCommitters: true, extraMessage: 'Сетевые диски успешно сбэкапированы, можно забирать', targets: 'user@domen' + } + } + + aborted { + node ("master") { + jabberNotify notificationStrategy: 'aborted', notifyCulprits: true, notifyFixers: true, notifySuspects: true, notifyUpstreamCommitters: true, extraMessage: 'Пришлось остановить', targets: 'user@domen' + } + } + failure { + node ("master") { + jabberNotify notificationStrategy: 'failure', notifyCulprits: true, notifyFixers: true, notifySuspects: true, notifyUpstreamCommitters: true, extraMessage: 'Бэкап сетевых дисков завершился с ошибкой', targets: 'user@domen' + } + } + } + +} + +def getBuildUser() { + return currentBuild.rawBuild.getCause(Cause.UserIdCause)?.getUserId() +} + +def updateDesc(ACTION) +{ + def d = [ACTION: '', BACKUP_DATE: '', END_TIME: ''] + END_TIME = new Date().format( 'dd.MM.yy_HH:mm' ) + d.ACTION = "${ACTION}" + d.BACKUP_DATE = "${CURRENT_DATE}" + d.END_TIME = "${END_TIME}" + d1 = d.clone() + props << d1 + println d1 + d.clear() + println props + println d + println "${END_TIME}" + def item = Jenkins.instance.getItemByFullName("${JOB_NAME}") + item.setDescription("${getDescTemplate(props)}") + + +} + +def sendME(ACTION,STATUS) +{ +emailext body: "${STATUS}", + subject: "${ACTION}", + to: 'therion@nasda.ru' +} + + +def gitClone(String stand) { + checkout poll: false, scm: [ + $class: 'GitSCM', + branches: [[name: '*/master']], + doGenerateSubmoduleConfigurations: false, + userRemoteConfigs: [[url: 'git@gitlab.domen:user/sys.git']] + ] +} + +def scriptDir = getClass().protectionDomain.codeSource.location.path +println "${scriptDir}" + +String currentDir = new File(".").getAbsolutePath() + + +def getDescTemplate(List props) { + return """ + + +Задача бэкапирует сетевые диски +
+ Если сборка не прошла, звонить :) +
+ + + + + + + + + + + ${props.collect { prop -> + def idx = props.findIndexOf { it.equals(prop) } + return """ + + + + """ + }.join('')} + + +
Задания бэкапа:
БэкапированиеДата выполненияВремя завершения
${prop.ACTION}${prop.BACKUP_DATE}${prop.END_TIME}
+
+
+
При запуске необходимо указать параметры: +
+
    +
  • + ACTION - выполняемое действие (ALL, 1CDB, WORK) +
      +
    • + ALL - Выполнение всех задач, планировщик делает по умолчанию в выходной +
    • +
    • + WORK - Бэкап сетевого диска W (WORK) +
    • +
    • + PROG - Бэкап сетевого диска K (PROG) +
    • +
    • + DOC - Бэкап сетевого диска V (DOC) +
    • +
    • + MOVE - Перенос бэкапов в папку на сервере 1CSRV, удаление старых +
    • +
    +
  • +
  • + Бэкапы тут - \\\\1CSRV.domen\\Backup +
  • +
+ + +""" +} + diff --git a/jenkins/site_session.ps1 b/jenkins/site_session.ps1 new file mode 100644 index 0000000..b1d0543 --- /dev/null +++ b/jenkins/site_session.ps1 @@ -0,0 +1,8 @@ +$Action=$args[0] +$Job=$args[1] +Write-Host $Action +Write-Host $Job + +$Cred = New-Object System.Management.Automation.PSCredential ('user', (ConvertTo-SecureString 'passwd' -AsPlainText -Force)) +Invoke-Command -ComputerName 172.16.0.1 -Credential $Cred -Authentication Negotiate -ScriptBlock {..\.jenkins\workspace\site_backup\site\site_backup.ps1 $Using:Action} +