Обо мне

Инженер-программист: г. Иркутск. Я специалист в области информационных технологий. У меня более 5 лет опыта в администрировании серверов различных ОС и в разработки скриптов, ПО и БД. Для саморазвития я в свободное время читаю и перевожу техническую документацию на английском языке, администрирую свой веб-сервер и дорабатываю свои проекты https://github.com/it38dato. Мне интересно работать в команде, активно развиваться в программировании и изучать новые технологии.
Навыки: Html, Css, Windows, Виртуализация, Linux, Sql, Bash, Clouds, Python, English, Etl-процессы, Dwh, AntiFraud, Спутниковые радионавигационные системы, С++.
Обратная связь: it38dato@yandex.ru, telegram - @it38dato.
Услуги:
# Верстка Веб-страниц по макетам.
# Администрирование локальных, виртуальных и облачных серверов.
# Администрирование Веб-сервера Lamp.
# Администрирование Веб-сервера Django.
# Администрирование Веб-сервера React.js.
# Администрирование базы данных.
# Разработка Веб-сайта Django.
# Разработка Веб-сайта React.js.
# Разработка Телеграм бота Переводчик.
# Разработка базы данных.
# Разработка Хранилище данных.
# Написание Sql запросов.
# Обработка и сортировка данных на Python, C++ и Sql-запросах.
# Анализ сетевых технологий.

2011-09-01 - 2018-05-30: Иркутский государственный университет, Иркутск. Должность: Информационные технологии и телекоммуникационные системы - Бакалавр / Электроника и наноэлектроника - Магистр / Информационная безопасность - Дополнительное образование. Дополнительная информация: Навыки - Html, Css, Windows, Виртуализация, Linux, Sql, Bash, Clouds, Python, Спутниковые радионавигационные системы, С++. Достижения: Для защиты выпускной экзаменационной работы по теме "Утилита для сканирования безопасности сети Nmap" подготовил несколько тестовых виртуальных машин ОС, настроил Vsftpd-сервер, Nginx-сервер, Proxy-сервер, просканировал виртуальные машины и настроил Iptables.

Show

# Подготовка ОС.
# Настройка Iptables.
# Настройка Vsftpd-сервера.
# Настройка Nginx-сервера.
# Настройка Proxy-сервера.
# Сканирование сети Nmap.
# Перехват трафиков в Tcpdump.
# Блокировка подозрительных IP-адресов.
# Безопасность сервера.
Task:
Подготовка ОС. Подключение внешнего диска к WSl
Decision:
> wmic diskdrive list brief
Caption       DeviceID   Model         Partitions Size  
ST1000LM 035-1RK172 SCSI Disk Device \\.\PHYSICALDRIVE2 ST1000LM 035-1RK172 SCSI Disk Device 1   1000202273280
...
> wsl --mount \\.\PHYSICALDRIVE2 --partition 1
Диск успешно подключен как "/mnt/wsl/PHYSICALDRIVE2p1".
...
> wsl
# ls /mnt/wsl/PHYSICALDRIVE2p1/
Centos_9.img Ubuntu_2204.qcow2 Windows12.qcow2 ubuntu-22.04.3-desktop-amd64.iso
Kali.qcow2 Windows.qcow2 lost+found
# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
...
sdc 8:32 0 931.5G 0 disk
└─sdc1 8:33 0 931.5G 0 part /mnt/wsl/PHYSICALDRIVE2p1
...
# mount /dev/sdc1 /var/lib/libvirt/images/
# ls /var/lib/libvirt/images/
Centos_9.img Ubuntu_2204.qcow2 Windows12.qcow2 ubuntu-22.04.3-desktop-amd64.iso
Kali.qcow2 Windows.qcow2 lost+found
> wsl.exe --unmount \\.\PHYSICALDRIVE2
Source:
# https://habr.com/ru/news/518806/ - Microsoft добавила в подсистему Windows для Linux 2 (WSL2) возможность монтирования дисков
# https://qna.habr.com/q/861519 - Где находится домашняя директория WSL? 
Task:
Настройка iptables. Выводим список текущих правил iptables и проанализируем какие порты открыты в сервере Centos. 
Decision:
[tuser@kvmcentos ~]$ sudo yum install iptables-services
[tuser@kvmcentos ~]$ sudo iptables --version
[tuser@kvmcentos ~]$ sudo iptables -L -v
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination 
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination 
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination 
[tuser@kvmcentos ~]$ sudo systemctl start iptables
[tuser@kvmcentos ~]$ sudo systemctl enable iptables
[tuser@kvmcentos ~]$ sudo service iptables status
┌──(tuser㉿KvmKali)-[~]
└─$ sudo nmap tipcentos
Starting Nmap 7.80 ( https://nmap.org ) at 2023-10-17 08:33 CDT
Nmap scan report for centos (tipcentos)
Host is up (0.00089s latency).
Not shown: 999 filtered ports
PORT STATE SERVICE
22/tcp open ssh
MAC Address: 52:54:00:7e:05:15 (QEMU virtual NIC)
Nmap done: 1 IP address (1 host up) scanned in 5.30 seconds
Task:
Настройка iptables. В сервере Centos Напишем набор правил iptables, в котором мы разрешаем все исходящие соединения и строго ограничиваем входящие. 
Доступ будет возможен по портам TCP: 21, 22, 25, 53, 80, 143, 443, по портам UDP: 20, 21, 53, также мы пропускаем пакеты для уже установленных соединений.
С удаленной машины просканируем порты на нашем сервере.
Decision:
[tuser@kvmcentos ~]$ sudo vim firewall.sh
[tuser@kvmcentos ~]$ sudo cat firewall.sh
#!/bin/bash
IPT="/sbin/iptables"
# Очищаем правила и удаляем цепочки.
$IPT -F
$IPT -X
# По умолчанию доступ запрещен.
$IPT -P INPUT DROP
$IPT -P FORWARD DROP
$IPT -P OUTPUT DROP
# Список разрешенных TCP и UDP портов.
TCP_PORTS="21,22,25,53,80,143,443"
UDP_PORTS="53,21,20"
# Разрешаем пакеты для интерфейса обратной петли.
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A OUTPUT -o lo -j ACCEPT
# Разрешаем пакеты для установленных соединений.
$IPT -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Разрешаем исходящие соединения.
$IPT -A OUTPUT -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
# Разрешаем доступ к портам, описанным в переменных TCP_PORTS и UDP_PORTS.
$IPT -A INPUT -p tcp -m multiport --dport $TCP_PORTS -j ACCEPT
$IPT -A INPUT -p udp -m multiport --dport $UDP_PORTS -j ACCEPT
# Разрешаем исходящий ping.
$IPT -A INPUT -p icmp -m icmp --icmp-type echo-reply -j ACCEPT
[tuser@kvmcentos ~]$ sudo chmod +x firewall.sh
[tuser@kvmcentos ~]$ sudo ./firewall.sh
[tuser@kvmcentos ~]$ sudo iptables -L -v
Chain INPUT (policy DROP 1986 packets, 87384 bytes)
pkts bytes target prot opt in out source destination 
0 0 ACCEPT all -- lo any anywhere anywhere 
79 5604 ACCEPT all -- any any anywhere anywhere state RELATED,ESTABLISHED
9 396 ACCEPT tcp -- any any anywhere anywhere multiport dports ftp,ssh,smtp,domain,http,imap,https
0 0 ACCEPT udp -- any any anywhere anywhere multiport dports domain,ftp,ftp-data
0 0 ACCEPT icmp -- any any anywhere anywhere icmp echo-reply
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination 
Chain OUTPUT (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination 
0 0 ACCEPT all -- any lo anywhere anywhere 
60 7920 ACCEPT all -- any any anywhere anywhere state NEW,RELATED,ESTABLISHED
[tuser@kvmcentos ~]$ sudo service iptables save
┌──(tuser㉿KvmKali)-[~]
└─$ sudo nmap tipcentos
...
PORT STATE SERVICE
21/tcp closed ftp
22/tcp open ssh
25/tcp closed smtp
53/tcp closed domain
80/tcp closed http
143/tcp closed imap
443/tcp closed https
...
Source:
# https://blog.sedicomm.com/2016/12/16/iptables-ustanovka-i-nastrojka/?ysclid=ln3wplng53988958006#1
Task:
Настройка Vsftpd-сервера. Install and configure an FTP server. Securing the connection to the FTP server.
Decision:
[tuser@kvmcentos ~]$ sudo dnf update -y
[tuser@kvmcentos ~]$ sudo dnf install vsftpd -y
[tuser@kvmcentos ~]$ sudo systemctl enable vsftpd --now
[tuser@kvmcentos ~]$ sudo systemctl status vsftpd
┌──(tuser㉿KvmKali)-[~]
└─$ sudo nmap tipcentos
...
PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
25/tcp closed smtp
53/tcp closed domain
80/tcp closed http
143/tcp closed imap
443/tcp closed https
...
[tuser@kvmcentos ~]$ sudo useradd -m -d "/home/tuser2" tuser2
[tuser@kvmcentos ~]$ sudo passwd tuser2
[tuser@kvmcentos ~]$ sudo mkdir -p /home/tuser2/shared
[tuser@kvmcentos ~]$ sudo chmod -R 750 /home/tuser2/shared
[tuser@kvmcentos ~]$ sudo chown tuser2: /home/tuser2/shared
[tuser@kvmcentos ~]$ sudo vim /etc/vsftpd/user_list
[tuser@kvmcentos ~]$ sudo cat /etc/vsftpd/user_list | grep ftp
tuser2
[tuser@kvmcentos ~]$ sudo vim /etc/vsftpd/vsftpd.conf
[tuser@kvmcentos ~]$ sudo cat /etc/vsftpd/vsftpd.conf
...
anonymous_enable=NO
...
local_enable=YES
...
write_enable=YES
...
chroot_local_user=YES
...
allow_writeable_chroot=YES
pasv_min_port=31500
pasv_max_port=32500
userlist_file=/etc/vsftpd/user_list
userlist_deny=NO
[tuser@kvmcentos ~]$ sudo systemctl restart vsftpd
[tuser@kvmcentos ~]$ sudo openssl req -x509 -nodes -days 3650 \
-newkey rsa:2048 -keyout /etc/vsftpd.pem \
-out /etc/vsftpd/vsftpd.pem
[tuser@kvmcentos ~]$ sudo vim /etc/vsftpd/vsftpd.conf
[tuser@kvmcentos ~]$ sudo cat /etc/vsftpd/vsftpd.conf
...
#rsa_cert_file=/etc/vsftpd/vsftpd.pem
#rsa_private_key_file=/etc/vsftpd.pem
#ssl_enable=YES
[tuser@kvmcentos ~]$ sudo systemctl restart vsftpd
[tuser@kvmcentos ~]$ sudo cat /etc/sysconfig/iptables
# Generated by iptables-save v1.8.8 (nf_tables) on Sun Oct 22 12:10:33 2023
*mangle
:PREROUTING ACCEPT [45:3316]
:INPUT ACCEPT [45:3316]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [34:5048]
:POSTROUTING ACCEPT [34:5048]
COMMIT
# Completed on Sun Oct 22 12:10:33 2023
# Generated by iptables-save v1.8.8 (nf_tables) on Sun Oct 22 12:10:33 2023
*raw
:PREROUTING ACCEPT [45:3316]
:OUTPUT ACCEPT [34:5048]
COMMIT
# Completed on Sun Oct 22 12:10:33 2023
# Generated by iptables-save v1.8.8 (nf_tables) on Sun Oct 22 12:10:33 2023
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m multiport --dports 21,22,25,53,80,143,443 -j ACCEPT
-A INPUT -p udp -m multiport --dports 53,21,20 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 0 -j ACCEPT
-A OUTPUT -o lo -j ACCEPT
-A OUTPUT -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
COMMIT
# Completed on Sun Oct 22 12:10:33 2023
# Generated by iptables-save v1.8.8 (nf_tables) on Sun Oct 22 12:10:33 2023
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT
# Completed on Sun Oct 22 12:10:33 2023
[tuser@kvmcentos ~]$ sudo iptables -t filter -A INPUT -p tcp --dport 20:21 -j ACCEPT
[tuser@kvmcentos ~]$ sudo iptables -t filter -A INPUT -p tcp --dport 31500:32500 -j ACCEPT
[tuser@kvmcentos ~]$ sudo service iptables save
[tuser@kvmcentos ~]$ sudo systemctl restart iptables
┌──(tuser㉿KvmKali)-[~]
└─$ telnet tipcentos 21
Trying tipcentos...
Connected to tipcentos.
Escape character is '^]'.
220 (vsFTPd 3.0.5)
USER tuser2
331 Please specify the password.
PASS tpassword
230 Login successful.
PWD
257 "/" is the current directory
PASV
227 Entering Passive Mode (I,P,126,61).
┌──(tuser㉿KvmKali)-[~]
└─$ 126*256+61
32317
┌──(tuser㉿KvmKali)-[~]
└─$ telnet tipcentos 32317
Trying tipcentos...
Connected to tipcentos.
Escape character is '^]'.
LIST
150 Here comes the directory listing.
226 Directory send OK.
drwxr-x--- 2 1001 1001 6 Oct 21 03:06 shared
QUIT
221 Goodbye.
Task:
Настройка Vsftpd-сервера. Запрещаем доступ к фтп всем пользователям, кроме пользователя с MAC-адресом 52:54:00:19:98:c5.
Decision:
tuser@kvmubuntu:~$ ifconfig | grep 52:54:00:19:98:c5
ether 52:54:00:19:98:c5 txqueuelen 1000 (Ethernet)
[tuser@kvmcentos ~]$ sudo iptables -I INPUT -p tcp --dport 21 -m mac ! --mac-source 52:54:00:19:98:c5 -j REJECT
[tuser@kvmcentos ~]$ sudo service iptables save
[tuser@kvmcentos ~]$ sudo systemctl restart iptables
tuser@kvmubuntu:~$ ftp tipcentos
Connected to tipcentos.
220 (vsFTPd 3.0.5)
Name (tipcentos:user): tuser2
331 Please specify the password.
Password: 
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
229 Entering Extended Passive Mode (|||31695|)
150 Here comes the directory listing.
drwxr-x--- 2 1001 1001 6 Oct 21 03:06 shared
226 Directory send OK.
ftp> exit
221 Goodbye.
┌──(tuser㉿KvmKali)-[~]
└─$ ftp tipcentos
ftp: Can't connect to `tipcentos:21': Connection refused
ftp: Can't connect to `tipcentos:ftp'
ftp> exit
┌──(tuser㉿KvmKali)-[~]
└─$ telnet tipcentos 21 
Trying tipcentos...
telnet: Unable to connect to remote host: Connection refused
Source:
# https://unixcop.com/how-to-install-and-configure-an-ftp-server-on-centos-9-stream/
# https://losst.pro/kak-otkryt-port-iptables?ysclid=lnvrpgxwj8175390861
# https://techviewleo.com/configure-vsftpd-ftp-server-on-ubuntu-linux/
# https://stackoverflow.com/questions/38523250/vsftpd-login-is-not-successful
Task:
Настройка Nginx-сервера. Install Nginx.
Decision:
[tuser@kvmcentos ~]$ sudo dnf update -y
[tuser@kvmcentos ~]$ sudo dnf install nginx
[tuser@kvmcentos ~]$ sudo systemctl start nginx
[tuser@kvmcentos ~]$ sudo systemctl enable nginx
[tuser@kvmcentos ~]$ nginx -v
[tuser@kvmcentos ~]$ firefox http://tipcentos:80/
Source:
# https://devcoops.com/install-nginx-on-centos-9-stream/
Task:
Настройка Proxy-сервера. Configure Squid Proxy Kali.
Decision:
┌──(tuser㉿KvmKali)-[~]
└─$ sudo apt update
┌──(tuser㉿KvmKali)-[~]
└─$ sudo apt install squid
┌──(tuser㉿KvmKali)-[~]
└─$ sudo systemctl start squid
┌──(tuser㉿KvmKali)-[~]
└─$ sudo systemctl enable squid
┌──(tuser㉿KvmKali)-[~]
└─$ grep -Eiv '(^#|^$)' /etc/squid/squid.conf
acl localnet src 0.0.0.1-0.255.255.255 # RFC 1122 "this" network (LAN)
acl localnet src 10.0.0.0/8 # RFC 1918 local private network (LAN)
acl localnet src 100.64.0.0/10 # RFC 6598 shared address space (CGN)
acl localnet src 169.254.0.0/16 # RFC 3927 link-local (directly plugged) machines
acl localnet src 172.16.0.0/12 # RFC 1918 local private network (LAN)
acl localnet src 192.168.0.0/16 # RFC 1918 local private network (LAN)
acl localnet src fc00::/7 # RFC 4193 local private network range
acl localnet src fe80::/10 # RFC 4291 link-local (directly plugged) machines
acl SSL_ports port 443
acl Safe_ports port 80 # http
acl Safe_ports port 21 # ftp
acl Safe_ports port 443 # https
acl Safe_ports port 70 # gopher
acl Safe_ports port 210 # wais
acl Safe_ports port 1025-65535 # unregistered ports
acl Safe_ports port 280 # http-mgmt
acl Safe_ports port 488 # gss-http
acl Safe_ports port 591 # filemaker
acl Safe_ports port 777 # multiling http
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
http_access allow localhost manager
http_access deny manager
http_access allow localhost
http_access deny to_localhost
http_access deny to_linklocal
include /etc/squid/conf.d/*.conf
http_access deny all
http_port 3128
coredump_dir /var/spool/squid
refresh_pattern ^ftp: 1440 20% 10080
refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
refresh_pattern . 0 20% 4320
┌──(tuser㉿KvmKali)-[~]
└─$ sudo mv /etc/squid/squid.conf /etc/squid/squid.conf.bac
┌──(tuser㉿KvmKali)-[~]
└─$ sudo vim /etc/squid/squid.conf
┌──(tuser㉿KvmKali)-[~]
└─$ sudo cat /etc/squid/squid.conf 
acl localnet src tipkali
http_access allow localnet
http_port 3128
┌──(tuser㉿KvmKali)-[~]
└─$ sudo systemctl restart squid 
┌──(tuser㉿KvmKali)-[~]
└─$ cat /var/log/squid/access.log
1698153952.395 1 tipkali NONE_NONE/400 3816 - / - HIER_NONE/- text/html
1698153953.958 7 tipkali TCP_DENIED/403 4185 GET http://kali:3128/squid-internal-static/icons/SN.png - HIER_NONE/- text/html
...
1698154905.087 2 tipkali TCP_MISS/400 3889 GET http://tipkali:3128/ - HIER_DIRECT/tipkali text/html
1698154906.698 149 tipkali TCP_TUNNEL/200 39 CONNECT static.vk.com:443 - HIER_DIRECT/87.240.137.164 -
1698154906.796 0 tipkali NONE_NONE/400 3838 - /favicon.ico - HIER_NONE/- text/html
1698154906.797 2 tipkali TCP_MISS/400 3911 GET http://tipkali:3128/favicon.ico - HIER_DIRECT/tipkali text/html
┌──(tuser㉿KvmKali)-[~]
└─$ sudo apt install apache2-utils 
┌──(tuser㉿KvmKali)-[~]
└─$ sudo htpasswd -c /etc/squid/passwd user
┌──(tuser㉿KvmKali)-[~]
└─$ sudo vim /etc/squid/squid.conf 
┌──(tuser㉿KvmKali)-[~]
└─$ cat /etc/squid/squid.conf
#acl localnet src tipkali
#http_access allow localnet
http_port 3128
via off
auth_param basic program /usr/lib/squid/basic_ncsa_auth /etc/squid/passwd
auth_param basic children 5
auth_param basic credentialsttl 2 hours
auth_param basic casesensitive on
auth_param basic realm Squid proxy for kali
acl auth_users proxy_auth REQUIRED
http_access allow auth_users
┌──(tuser㉿KvmKali)-[~]
└─$ sudo systemctl restart squid
Task:
Настройка Proxy-сервера. Configure Squid Proxy Centos.
Decision:
[tuser@kvmcentos ~]$ sudo dnf install squid
[tuser@kvmcentos ~]$ sudo systemctl enable --now squid
[tuser@kvmcentos ~]$ grep -Eiv '(^#|^$)' /etc/squid/squid.conf
acl localnet src 0.0.0.1-0.255.255.255 # RFC 1122 "this" network (LAN)
acl localnet src 10.0.0.0/8 # RFC 1918 local private network (LAN)
acl localnet src 100.64.0.0/10 # RFC 6598 shared address space (CGN)
acl localnet src 169.254.0.0/16 # RFC 3927 link-local (directly plugged) machines
acl localnet src 172.16.0.0/12 # RFC 1918 local private network (LAN)
acl localnet src 192.168.0.0/16 # RFC 1918 local private network (LAN)
acl localnet src fc00::/7 # RFC 4193 local private network range
acl localnet src fe80::/10 # RFC 4291 link-local (directly plugged) machines
acl SSL_ports port 443
acl Safe_ports port 80 # http
acl Safe_ports port 21 # ftp
acl Safe_ports port 443 # https
acl Safe_ports port 70 # gopher
acl Safe_ports port 210 # wais
acl Safe_ports port 1025-65535 # unregistered ports
acl Safe_ports port 280 # http-mgmt
acl Safe_ports port 488 # gss-http
acl Safe_ports port 591 # filemaker
acl Safe_ports port 777 # multiling http
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
http_access allow localhost manager
http_access deny manager
http_access allow localnet
http_access allow localhost
http_access deny all
http_port 3128
coredump_dir /var/spool/squid
refresh_pattern ^ftp: 1440 20% 10080
refresh_pattern ^gopher: 1440 0% 1440
refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
refresh_pattern . 0 20% 4320
[tuser@kvmcentos ~]$ sudo mv /etc/squid/squid.conf /etc/squid/squid.conf.bac
[tuser@kvmcentos ~]$ sudo vim /etc/squid/squid.conf
[tuser@kvmcentos ~]$ cat /etc/squid/squid.conf
acl localnet src tipcentos
acl localnet src tip.0/32
acl Safe_ports port 80
acl Safe_ports port 443
cache_dir ufs /var/spool/squid 1000 16 256
http_access allow localnet
http_port 3128 
[tuser@kvmcentos ~]$ sudo systemctl restart squid
[tuser@kvmcentos ~]$ sudo iptables -t filter -A INPUT -p tcp --dport 3128 -j ACCEPT
[tuser@kvmcentos ~]$ sudo service iptables save
[tuser@kvmcentos ~]$ sudo systemctl restart iptables.service
[tuser@kvmcentos ~]$ sudo curl -O -L "https://www.redhat.com/index.html" -x "tipcentos:3128"
% Total % Received % Xferd Average Speed Time Time Time Current
     Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
100 156k 0 156k 0 0 147k 0 --:--:-- 0:00:01 --:--:-- 795k
┌──(tuser㉿KvmKali)-[~]
└─$ sudo nmap tipcentos
...
PORT STATE SERVICE
20/tcp closed ftp-data
21/tcp open ftp
22/tcp open ssh
25/tcp closed smtp
53/tcp closed domain
80/tcp open http
143/tcp closed imap
443/tcp closed https
3128/tcp open squid-http
...
[tuser@kvmcentos ~]$ sudo dnf install httpd-tools
[tuser@kvmcentos ~]$ sudo touch /etc/squid/passwd
[tuser@kvmcentos ~]$ sudo chown squid /etc/squid/passwd
[tuser@kvmcentos ~]$ sudo htpasswd /etc/squid/passwd proxyuser
[tuser@kvmcentos ~]$ sudo vim /etc/squid/squid.conf
[tuser@kvmcentos ~]$ cat /etc/squid/squid.conf
#acl localnet src tipcentos
#acl localnet src tip.0/32
#acl Safe_ports port 80
#acl Safe_ports port 443
#cache_dir ufs /var/spool/squid 1000 16 256
#http_access allow localnet
http_port 3128 
auth_param basic program /usr/lib64/squid/basic_ncsa_auth /etc/squid/passwd
auth_param basic children 5
auth_param basic realm Squid Basic Authentication
auth_param basic credentialsttl 2 hours
acl auth_users proxy_auth REQUIRED
http_access allow auth_users
[tuser@kvmcentos ~]$ sudo systemctl restart squid
[tuser@kvmcentos ~]$ sudo curl -O -L "https://www.redhat.com/index.html" -x "proxyuser:tpassword@tipcentos:3128"
% Total % Received % Xferd Average Speed Time Time Time Current
     Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
100 156k 0 156k 0 0 124k 0 --:--:-- 0:00:01 --:--:-- 562k
Source:
# https://support.mozilla.org/ru/kb/parametry-soedineniya-v-firefox
# https://techviewleo.com/configure-squid-proxy-on-centos-almalinux-rhel/
Task:
Настройка Proxy-сервера. Перенаправление пакетов, идущих на 80-й порт, на стандартный порт прокси-сервера.
Decision:
[tuser@kvmcentos ~]$ sudo iptables -t nat -A PREROUTING -s tip.0 -p tcp --dport 80 -j REDIRECT --to-port 3128
[tuser@kvmcentos ~]$ sudo service iptables save
[tuser@kvmcentos ~]$ sudo systemctl restart iptables.service
Task:
Настройка Proxy-сервера. Предоставляем доступ из Интернет к веб-серверу, который расположен в локальной сети (проброс порта). Вместо tipubuntu укажите IP-адрес вашего веб-сервера.
Decision:
[tuser@kvmcentos ~]$ sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination tipubuntu:80
[tuser@kvmcentos ~]$ sudo service iptables save
[tuser@kvmcentos ~]$ sudo systemctl restart iptables.service
Task:
Настройка Proxy-сервера. Включаем маскарадинг для доступа в Интернет пользователей локальной сети.
Decision:
[tuser@kvmcentos ~]$ sudo iptables -t nat -A POSTROUTING -o enp1s0 -s tip.0/32 -j MASQUERADE
[tuser@kvmcentos ~]$ sudo service iptables save
[tuser@kvmcentos ~]$ sudo systemctl restart iptables.service
Task:
Сканирование сети Nmap. Обнаружим активные устройства в сети.
Decision:
┌──(tuser㉿KvmKali)-[~]
└─$ sudo apt install nmap
┌──(tuser㉿KvmKali)-[~]
└─$ sudo nmap -sL tipcentos/24
...
Nmap scan report for KvmKali (tipkali)
...
Nmap scan report for kvmcentos (tipcentos)
...
Nmap scan report for kvmubuntu (tipubuntu)
...
Task:
Сканирование сети Nmap. Просканируем хост и проанализируем порт ftp. В некоторых случаях можно вытащить логин и пароль. Такое происходит, когда используются параметры входа по умолчанию.
Decision:
[tuser@kvmcentos ~]$ sudo nmap -sV tipcentos
...
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.5
22/tcp open ssh OpenSSH 8.7 (protocol 2.0)
80/tcp open http nginx 1.22.1
3128/tcp open http-proxy Squid http proxy 5.5
...
[tuser@kvmcentos ~]$ sudo nmap -sC tipcentos -p 21
...
PORT STATE SERVICE
21/tcp open ftp
...
$ find /usr/share/nmap/scripts/ -name '*.nse' | grep ftp
...
/usr/share/nmap/scripts/ftp-brute.nse
...
$ sudo nmap --script-help ftp-brute.nse
...
Performs brute force password auditing against FTP servers.
...
[tuser@kvmcentos ~]$ sudo nmap --script ftp-brute.nse tipcentos -p 21
...
PORT STATE SERVICE
21/tcp open ftp
| ftp-brute: 
| Accounts: No valid accounts found
| Statistics: Performed 324 guesses in 642 seconds, average tps: 7.5
|_ ERROR: The service seems to have failed or is heavily firewalled...
...
Task:
Сканируем диапазон портов
Decision:
┌──(tuser㉿KvmKali)-[~]
└─$ sudo nmap -sT -p 21-80 tipcentos
...
PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
25/tcp closed smtp
53/tcp closed domain
...
Task:
Сканирование сети Nmap. Просканируем удаленный хост (агрессивный режим).
Decision:
┌──(tuser㉿KvmKali)-[~]
└─$ sudo nmap -A -T4 tipcentos
...
PORT STATE SERVICE VERSION
20/tcp closed ftp-data
21/tcp open ftp vsftpd 3.0.5
22/tcp open ssh OpenSSH 8.7 (protocol 2.0)
25/tcp closed smtp
53/tcp closed domain
143/tcp closed imap
443/tcp closed https
3128/tcp open http-proxy Squid http proxy 5.5
|_http-server-header: squid/5.5
|_http-title: ERROR: The requested URL could not be retrieved
MAC Address: 52:54:00:7e:05:15 (QEMU virtual NIC)
Aggressive OS guesses: Linux 2.6.32 - 3.13 (94%), Linux 2.6.22 - 2.6.36 (92%), Linux 3.10 (92%), Linux 3.10 - 4.11 (92%), Linux 2.6.39 (92%), Linux 2.6.32 (91%), Linux 3.2 - 4.9 (91%), Linux 2.6.32 - 3.10 (91%), Linux 2.6.18 (90%), Linux 3.16 - 4.6 (90%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 1 hop
Service Info: OS: Unix
TRACEROUTE
HOP RTT ADDRESS
1 0.83 ms tipcentos
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 24.18 seconds
Source:
# https://losst.ru/kak-polzovatsya-nmap-dlya-skanirovaniya-seti
Task:
Перехват трафиков в Tcpdump. Перехватываем DNS-трафик между сервером и каким-нибудь узлом в сети.
Decision:
┌──(tuser㉿KvmKali)-[~]
└─$ sudo nmap tipwindows12
...
PORT STATE SERVICE
53/tcp open domain
80/tcp open http
443/tcp open https
...
[tuser@kvmcentos ~]$ sudo tcpdump -i enp1s0 -n -nn -ttt 'host tipwindows12 and port 53'
Task:
Перехват трафиков в Tcpdump. Перехватываем весь трафик для MAC-адреса 52:54:00:7e:05:15 на сетевом интерфейсе enp1s0.
Decision:
[tuser@kvmcentos ~]$ ifconfig
enp1s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
...
ether 52:54:00:7e:05:15 txqueuelen 1000 (Ethernet)
...
[tuser@kvmcentos ~]$ sudo tcpdump -n -i enp1s0 "ether host 52:54:00:7e:05:15"
...
┌──(tuser㉿KvmKali)-[~]
└─$ ssh tuser@tipcentos
[tuser@kvmcentos ~]$ sudo tcpdump -n -i enp1s0 "ether host 52:54:00:7e:05:15"
...
00:11:12.536934 IP tipcentos.58598 > tipubuntu.22: Flags [.], ack 3730, win 501, options [nop,nop,TS val 3107339434 ecr 2462889902], length 0
00:11:12.586762 IP tipubuntu.22 > tipcentos.58598: Flags [P.], seq 3730:3782, ack 2242, win 501, options [nop,nop,TS val 2462889993 ecr 3107339434], length 52
00:11:12.586838 IP tipubuntu.22 > tipcentos.58598: Flags [P.], seq 3782:3898, ack 2242, win 501, options [nop,nop,TS val 2462889993 ecr 3107339434], length 116
00:11:12.588205 IP tipcentos.58598 > tipubuntu.22: Flags [.], ack 3782, win 501, options [nop,nop,TS val 3107339485 ecr 2462889993], length 0
00:11:12.588207 IP tipcentos.58598 > tipubuntu.22: Flags [.], ack 3898, win 501, options [nop,nop,TS val 3107339486 ecr 2462889993], length 0
Task:
Перехват трафиков в Tcpdump. Перехватываем только ICMP-пакеты
Decision:
[tuser@kvmcentos ~]$ sudo tcpdump -i enp1s0 -n -nn -ttt 'ip proto \icmp'
...
┌──(tuser㉿KvmKali)-[~]
└─$ ping tipcentos
...
64 bytes from tipcentos: icmp_seq=1 ttl=64 time=0.692 ms
64 bytes from tipcentos: icmp_seq=2 ttl=64 time=0.764 ms
64 bytes from tipcentos: icmp_seq=3 ttl=64 time=0.868 ms
64 bytes from tipcentos: icmp_seq=4 ttl=64 time=1.01 ms
64 bytes from tipcentos: icmp_seq=5 ttl=64 time=1.13 ms
^C
...
[tuser@kvmcentos ~]$ sudo tcpdump -i enp1s0 -n -nn -ttt 'ip proto \icmp'
...
00:00:00.000000 IP tipcentos > tipubuntu: ICMP echo request, id 4, seq 1, length 64
00:00:00.000171 IP tipubuntu > tipcentos: ICMP echo reply, id 4, seq 1, length 64
00:00:01.001145 IP tipcentos > tipubuntu: ICMP echo request, id 4, seq 2, length 64
00:00:00.000077 IP tipubuntu > tipcentos: ICMP echo reply, id 4, seq 2, length 64
00:00:01.001365 IP tipcentos > tipubuntu: ICMP echo request, id 4, seq 3, length 64
00:00:00.000077 IP tipubuntu > tipcentos: ICMP echo reply, id 4, seq 3, length 64
00:00:01.001375 IP tipcentos > tipubuntu: ICMP echo request, id 4, seq 4, length 64
00:00:00.000077 IP tipubuntu > tipcentos: ICMP echo reply, id 4, seq 4, length 64
00:00:01.001573 IP tipcentos > tipubuntu: ICMP echo request, id 4, seq 5, length 64
00:00:00.000125 IP tipubuntu > tipcentos: ICMP echo reply, id 4, seq 5, length 64
Task:
Перехват трафиков в Tcpdump. Перехватываем входящий трафик на порт 80. сохраняем статистику в файл my.log для первых 500 пакетов. Будет создан бинарный файл my.log, который можно отпарсить с помощью команды
Decision:
[tuser@kvmcentos ~]$ sudo tcpdump -v -i enp1s0 dst port 80
...
┌──(tuser㉿KvmKali)-[~]
└─$ firefox tipcentos:80
[tuser@kvmcentos ~]$ sudo tcpdump -v -i enp1s0 dst port 80
...
14:07:24.835633 IP (tos 0x0, ttl 64, id 15549, offset 0, flags [DF], proto TCP (6), length 60)
kvmcentos.45022 > kvmubuntu.http: Flags [S], cksum 0x76d1 (incorrect -> 0x9a90), seq 1076682845, win 64240, options [mss 1460,sackOK,TS val 3110711737 ecr 0,nop,wscale 7], length 0
14:07:24.836511 IP (tos 0x0, ttl 64, id 15550, offset 0, flags [DF], proto TCP (6), length 52)
kvmcentos.45022 > kvmubuntu.http: Flags [.], cksum 0x76c9 (incorrect -> 0x51b3), ack 2952605173, win 502, options [nop,nop,TS val 3110711738 ecr 3247231251], length 0
14:07:24.836838 IP (tos 0x0, ttl 64, id 15551, offset 0, flags [DF], proto TCP (6), length 412)
kvmcentos.45022 > kvmubuntu.http: Flags [P.], cksum 0x7831 (incorrect -> 0xb0a2), seq 0:360, ack 1, win 502, options [nop,nop,TS val 3110711739 ecr 3247231251], length 360: HTTP, length: 360
GET / HTTP/1.1
Host: tipubuntu
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
14:07:24.844920 IP (tos 0x0, ttl 64, id 15552, offset 0, flags [DF], proto TCP (6), length 52)
kvmcentos.45022 > kvmubuntu.http: Flags [.], cksum 0x76c9 (incorrect -> 0x4285), ack 3522, win 489, options [nop,nop,TS val 3110711747 ecr 3247231260], length 0
14:07:29.846014 IP (tos 0x0, ttl 64, id 15553, offset 0, flags [DF], proto TCP (6), length 52)
kvmcentos.45022 > kvmubuntu.http: Flags [F.], cksum 0x76c9 (incorrect -> 0x2eef), seq 360, ack 3522, win 501, options [nop,nop,TS val 3110716748 ecr 3247231260], length 0
14:07:29.846795 IP (tos 0x0, ttl 64, id 15554, offset 0, flags [DF], proto TCP (6), length 52)
kvmcentos.45022 > kvmubuntu.http: Flags [.], cksum 0x76c9 (incorrect -> 0x1b63), ack 3523, win 501, options [nop,nop,TS val 3110716749 ecr 3247236262], length 0
[tuser@kvmcentos ~]$ sudo tcpdump -v -n -w my.log dst port 80 -c 500
...
[tuser@kvmcentos ~]$ ls my.log
my.log
[tuser@kvmcentos ~]$ sudo tcpdump -nr my.log | awk '{print $3}' | grep -oE '[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}' | sort | uniq -c | sort -rn
reading from file my.log, link-type EN10MB (Ethernet), snapshot length 262144
dropped privs to tcpdump
6 tipkali
Task:
Блокировка подозрительных IP-адресов. IP-адреса, которые вызывают подозрение, можно заблокировать в iptables с помощью команды, указанной ниже.
Decision:
[tuser@kvmcentos ~]$ sudo iptables -A INPUT -s tipkali -j DROP
[tuser@kvmcentos ~]$ sudo service iptables save
[tuser@kvmcentos ~]$ sudo systemctl restart iptables.service
Task:
Безопасность сервера. Установка и настройка tripwire.
Decision:
[tuser@kvmcentos ~]$ sudo dnf -y install epel-releasey
[tuser@kvmcentos ~]$ sudo dnf -y install tripwire
[tuser@kvmcentos ~]$ sudo tripwire-setup-keyfiles
[tuser@kvmcentos ~]$ sudo tripwire --init
...
### Warning: File system error.
### Filename: /proc/pci
### Нет такого файла или каталога
### Continuing...
...
[tuser@kvmcentos ~]$ sudo cat /etc/tripwire/twpol.txt
...
/proc/pci   -> $(Device) ;
...
[tuser@kvmcentos ~]$ sudo vim /etc/tripwire/twpol.txt
[tuser@kvmcentos ~]$ sudo cat /etc/tripwire/twpol.txt
...
#/proc/pci   -> $(Device) ;
...
[tuser@kvmcentos ~]$ sudo tripwire --update-policy --secure-mode low /etc/tripwire/twpol.txt
[tuser@kvmcentos ~]$ sudo tripwire --check —interactive
Task:
Безопасность сервера. Создаем конфигурацию, Создаем базу данных.
Decision:
[tuser@kvmcentos ~]$ ls /etc/tripwire/
centos-local.key site.key tw.cfg twcfg.txt tw.pol tw.pol.bak twpol.txt
[tuser@kvmcentos ~]$ sudo twadmin -m F -c /etc/tripwire/tw.cfg -S /etc/tripwire/site.key /etc/tripwire/twcfg.txt
[tuser@kvmcentos ~]$ sudo vim /etc/tripwire/twpolmake.pl
[tuser@kvmcentos ~]$ cat /etc/tripwire/twpolmake.pl
#!/usr/bin/perl
# Tripwire Policy File customize tool
# ----------------------------------------------------------------
# Copyright (C) 2003 Hiroaki Izumi
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# ----------------------------------------------------------------
# Usage:
# perl twpolmake.pl {Pol file}
# ----------------------------------------------------------------
#
$POLFILE=$ARGV[0];
open(POL,"$POLFILE") or die "open error: $POLFILE" ;
my($myhost,$thost) ;
my($sharp,$tpath,$cond) ;
my($INRULE) = 0 ;
while (<POL>) {
chomp;
if (($thost) = /^HOSTNAME\s*=\s*(.*)\s*;/) {
$myhost = `hostname` ; chomp($myhost) ;
if ($thost ne $myhost) {
$_="HOSTNAME=\"$myhost\";" ;
}
}
elsif ( /^{/ ) {
$INRULE=1 ;
}
elsif ( /^}/ ) {
$INRULE=0 ;
}
elsif ($INRULE == 1 and ($sharp,$tpath,$cond) = /^(\s*\#?\s*)(\/\S+)\b(\s+->\s+.+)$/) {
$ret = ($sharp =~ s/\#//g) ;
if ($tpath eq '/sbin/e2fsadm' ) {
$cond =~ s/;\s+(tune2fs.*)$/; \#$1/ ;
}
if (! -s $tpath) {
$_ = "$sharp#$tpath$cond" if ($ret == 0) ;
}
else {
$_ = "$sharp$tpath$cond" ;
}
}
print "$_\n" ;
}
close(POL) ;
[tuser@kvmcentos ~]$ sudo perl /etc/tripwire/twpolmake.pl /etc/tripwire/twpol.txt > /etc/tripwire/twpol.txt.new 
[tuser@kvmcentos ~]$ sudo twadmin -m P -c /etc/tripwire/tw.cfg -p /etc/tripwire/tw.pol -S /etc/tripwire/site.key /etc/tripwire/twpol.txt.new
[tuser@kvmcentos ~]$ sudo tripwire -m i -s -c /etc/tripwire/tw.cfg
[tuser@kvmcentos ~]$ sudo tripwire -m c -s -c /etc/tripwire/tw.cfg
Open Source Tripwire(R) 2.4.3.7 Integrity Check Report
Report generated by: root
Report created on: Вс 29 окт 2023 14:26:04
Database last updated on: Never
...
===============================================================================
Object Summary: 
===============================================================================
-------------------------------------------------------------------------------
# Section: Unix File System
-------------------------------------------------------------------------------
No violations.
===============================================================================
Error Report: 
===============================================================================
...
[tuser@kvmcentos ~]$ sudo ls /var/lib/tripwire/report
итого 28
-rw-r--r--. 1 root root 350 окт 29 13:55 centos-20231029-135511.twr
-rw-r--r--. 1 root root 350 окт 29 13:57 centos-20231029-135712.twr
-rw-r--r--. 1 root root 350 окт 29 14:00 centos-20231029-140029.twr
-rw-r--r--. 1 root root 350 окт 29 14:08 centos-20231029-140853.twr
-rw-r--r--. 1 root root 350 окт 29 14:09 centos-20231029-140919.twr
-rw-r--r--. 1 root root 6446 окт 29 14:27 centos-20231029-142604.twr
Task:
Безопасность сервера. Проверим на работоспособность утилиты Tripwire. Создав файл в системе, утилита должна показать, что добавлен был файл.
Decision:
[tuser@kvmcentos ~]$ sudo touch /var/lib/tripwire/tfile3.txt
[tuser@kvmcentos ~]$ sudo tripwire -m c -s -c /etc/tripwire/tw.cfg
Open Source Tripwire(R) 2.4.3.7 Integrity Check Report
...
-------------------------------------------------------------------------------
Rule Name: Tripwire Data Files (/var/lib/tripwire)
Severity Level: 100
-------------------------------------------------------------------------------
Added:
"/var/lib/tripwire/tfile3.txt"
===============================================================================
Error Report: 
===============================================================================
...
Decision:
Защитил диплом выпускной экзаменационной работы:
 


Source:
# https://linux-notes.org/ustanovka-i-nastrojka-tripwire-v-centos-redhat-fedora/?ysclid=loazeq8vjc96566460 
# https://www.server-world.info/en/note?os=CentOS_7&p=tripwire
# https://www.lisenet.com/2017/configure-tripwire-on-centos-7/

2018-03-01 - 2022-11-01: Всероссийский государственный университет юстиции, Иркутск. Должность: Технический специалист. Дополнительная информация: Обязанности - работа с сайтами, поддержка функционирования серверов и сервисов СУБД, техническая поддержка пользователей / Навыки - Python, Виртуализация, Linux, Windows. Достижения: Разработал программу Обработка и сортировка Html-кода с целью упрощения корректировки тегов на сайте организации по запросам от руководства.

Show

# Обработка и сортирока Html-кода.
# Парсинг сайта.

Task:
Обработка и сортирока Html-кода. В файле text.txt следующая информация: 
$ cat settings.py
...
DATABASES = {
   'default': {
      #'ENGINE': 'django.db.backends.sqlite3',
      #'NAME': BASE_DIR / 'db.sqlite3',
      'ENGINE': 'django.db.backends.postgresql_psycopg2',
      'PORT': '5432',
   }
}
...
Надо текст преобразовать в html формат и записать результат в output.txt: 
 

$ cat settings.py
...
DATABASES = {
    'default': {
        #'ENGINE': 'django.db.backends.sqlite3',
        #'NAME': BASE_DIR / 'db.sqlite3',
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'PORT': '5432',
    }
}
...
Source:
# https://pythonworld.ru/tipy-dannyx-v-python/fajly-rabota-s-fajlami.html - Чтение из файла.
# https://docs-python.ru/tutorial/chtenie-zapis-fajl/odnovremennoe-chtenie-zapis-raznye-fajly/ - Работа с несколькими файлами в Python.
# https://sky.pro/media/chtenie-fajla-postrochno-v-spisok-na-python/ - Использование встроенной функции open().
# https://sky.pro/media/chtenie-fajla-postrochno-v-spisok-na-python/?ysclid=lv9i6ky8w2363195830 - Использование генераторов.
# https://translated.turbopages.org/proxy_u/en-ru.ru.8446d21d-66250fbc-1552d51e-74722d776562/https/stackoverflow.com/questions/54785152/replace-tab-with-space-in-entire-text-file-python?__ya_mt_enable_static_translations=1 - Заменить табуляцию пробелом во всем текстовом файле python.
# https://pythonturbo.ru/kak-v-python-dobavit-tekst-v-fajl/ - Добавление текста в файл с помощью оператора with
Task:
Парсинг сайта. Проверить все страницы сайта на отсутствие pdf файлов больше 15 Мб.
Decision:
$ wget https://tsite.ru/sveden/document
--2018-11-01 20:12:20-- https://tsite.ru/sveden/document
Распознаётся tsite.ru (tsite.ru)… IpAddr
Подключение к tsite.ru (tsite.ru)|IpAddr|:443... соединение установлено.
ОШИБКА: Нет доверия сертификату для «tsite.ru».
ОШИБКА: Неизвестный издатель сертификата «tsite.ru».
$ wget --no-check-certificate -r -l 1 -A pdf https://tsite.ru/sveden/document
$ vim FileWeight.sh
$ chmod +x FileWeight.sh
$ cat FileWeight.sh
#!/bin/bash
echo -n "Enter a link to the site: "
read linksite
user=$(whoami)
echo -n "Come up with a name for the directory where the files will be written: "
read linkfiles
if [ -d /home/$user/$linkfiles ]; then
rm -rf /home/$user/$linkfiles
echo "/home/$user/$filename delete"
else
mkdir /home/$user/$linkfiles
cd /home/$user/$linkfiles
echo "/home/$user/$linkfiles create"
fi
wget --no-check-certificate -r -l 1 -A pdf $linksite
find /home/$user/$linkfiles -size +15M > output
$ ./FileWeight.sh
Enter a link to the site: https://tsite.ru/sveden/document
Come up with a name for the directory where the files will be written: tdir
/home/tUser/tdir create
...
$ cat /home/tUser/tdir/output
/home/tUser/tdir/tsite.ru/Media/irk/Документы института/2018/tDoc1.pdf
$ ls -l /home/tUser/tdir/tsite.ru/Media/irk/Документы\ института/2018/tDoc1.pdf 
-rw-r--r--. 1 tUser tUser 20055320 июн 30 2018 '/home/tUser/tdir/tsite.ru/Media/irk/Документы института/2018/tDoc1.pdf'
Task:
Отсортировать html-код страницы по атрибутам <tr><td>
Decision:
Task:
Поменять/добавить тег на странице с таблицей,в некоторых строках тег отсутствует
Decision:
Source:
# https://stackoverflow.com/questions/4846007/check-if-directory-exists-and-delete-in-one-command-unix

2018-03-01 - 2022-11-01: Всероссийский государственный университет юстиции, Иркутск. Должность: Технический специалист. Дополнительная информация: Обязанности - работа с сайтами, поддержка функционирования серверов и сервисов СУБД, техническая поддержка пользователей. / Навыки - Python, Виртуализация, Linux, Windows. Достижения: В рамках "Импортозамещения с Windows на Linux" настроил виртуальный сервер с Linux системой и развернул в нем раздачу по сети установщика образа на компьютеры, на что сэкономило время на установку Linux в компьютерных классах.

Show

# Администрирование локальных, виртуальных и облачных серверов.
# Администрирование базы данных.
# Разработка базы данных.
# Написание Sql запросов.
Task:
Администрирование локальных, виртуальных и облачных серверов. Установить Hyper-V в Windows Server 2012 c помощью Shell
Decision:
PS C:\Windows\system32> Get-Module -ListAvailable
Каталог: C:\Windows\system32\WindowsPowerShell\v1.0\Modules
ModuleType Version    Name                                ExportedCo
---------- -------    ----                                ----------
...
Binary     1.1        Hyper-V                             {Add-VMDvd
...
PS C:\Windows\system32> Import-Module -Name Hyper-V
Task:
Администрирование локальных, виртуальных и облачных серверов. Развернуть виртуальную тестовую машину Redos в Hyber-v с помощью Powershell
Decision:
PS C:\Windows\system32> Get-VM
Name State CPUUsage(%) MemoryAssigned(M) Uptime   Status
---- ----- ----------- ----------------- ------   ------
Alt  Off   0           0                 00:00:00 Работает нормально
PS C:\Windows\system32> $ram=1*1024*1024*1024
PS C:\Windows\system32> $ram
1073741824
PS C:\Windows\system32> $hdd=10*1024*1024*1024
PS C:\Windows\system32> $hdd
10737418240
PS C:\Windows\system32> NEW-VM -Name Redos -MemoryStartupBytes $ram -NewVHDPath 'C:\Data\VM\Redos\Redos.vhdx'-NewVHD
SizeBytes $hdd -Path 'C:\Data\VM\Redos'
Name State CPUUsage(%) MemoryAssigned(M) Uptime   Status
---- ----- ----------- ----------------- ------   ------
Redos Off   0           0                 00:00:00 Работает нормально
PS C:\Windows\system32> Get-VM
Name State CPUUsage(%) MemoryAssigned(M) Uptime   Status
---- ----- ----------- ----------------- ------   ------
Alt  Off   0           0                 00:00:00 Работает нормально
Redos Off   0           0                 00:00:00 Работает нормально
PS C:\Windows\system32> Start-VM -name Redos
PS C:\Windows\system32> Get-VM
Name State   CPUUsage(%) MemoryAssigned(M) Uptime   Status
---- -----   ----------- ----------------- ------   ------
Alt  Off     0           0                 00:00:00 Работает нормально
Redos Running 0           1024              00:00:16 Работает нормально
PS C:\Windows\system32> Stop-VM Redos
Подтверждение
Hyper-V не удается завершить работу виртуальной машины Redos, так как служба интеграции по завершению работы недоступна.
 Во избежание потенциальной потери данных вы можете приостановить виртуальную машину или сохранить ее состояние. Другим
 вариантом является отключение виртуальной машины, но при этом возможна потеря данных.
[Y] Да - Y  [N] Нет - N  [S] Приостановить - S  [?] Справка (значением по умолчанию является "Y"): y
PS C:\Windows\system32> Get-VM
Name State CPUUsage(%) MemoryAssigned(M) Uptime   Status
---- ----- ----------- ----------------- ------   ------
Alt  Off   0           0                 00:00:00 Работает нормально
Redos Off   0           0                 00:00:00 Работает нормально
Task:
Администрирование локальных, виртуальных и облачных серверов. Установить и настроить дистрибутив Redos в виртуальной машине
Decision:
выбираем Install - выбрать размер разделов - поменяем систему разметки LVM на Standart Portition - нажимаем на click here to create them autmaticaly - установщик автоматически разделит диск - уменьшить размер корневого раздела / и раздел /home - Меняю у них размеры - Done - интернет настроить в Network & Host Name - Ethernet переключаем тумблер - Done - software Slection - minmal install- Done - запуск
Task:  
Администрирование локальных, виртуальных и облачных серверов. Ввод компьютера в домен Windows и изменение имени хоста
Decision:
# yum install join-to-domain
# join-to-domain.sh
# reboot
# hostname
    thost1.tdomain.ru
# hostname thost2.tdomain.ru
# hostname
    thost2.tdomain.ru
# vim /etc/hostname
# cat /etc/hostname
    thost2.tdomain.ru
# vim /etc/hosts
# cat /etc/hosts
    127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
    127.0.0.1 thost2.tdomain.ru thost2
Task:
Администрирование локальных, виртуальных и облачных серверов. Установка Консультант Плюс и подключение сетевых директорий с использованием automount и механизма Kerberos
Decision:
$ yum install wine winetricks
# winetricks riched30 winhttp
Wine -> Wine Configuration -> Графика -> уберите галочку в пункте "Разрешить менеджеру окон декорировать окна". -> Для запуска «Консультант Плюс» на рабочей станции подключите сетевой диск с «Консультантом» -> Сделать это можно с помощью подключения сетевых директорий с использованием automount и механизма Kerberos
$ smbclient -L thost -k
Sharename Type Comment
--------- ---- -------
Consultant Disk
ConsultantR Disk
...
S Disk
Reconnecting with SMB1 for workgroup listing.
Server Comment
-------- -------
Wg M
--------- -------
# yum install cifs-utils autofs
$ klist
Ticket cache: FILE:/tmp/krb5cc_1
Default principal: tuser@tdomain.RU
Valid starting Expires service principal
31.08.2020 09:51:47 31.08.2020 19:51:47 krbtgt/tdomain.RU@tdomain.RU
renew until 31.08.2020 19:51:47
# vim /etc/auto.master
# cat /etc/auto.master
...
/mnt/.thost    /etc/auto.samba    --ghost
# vim /etc/auto.samba
# cat /etc/auto.samba
Consultant    -fstype=cifs,multiuser,cruid=tuser,sec=krb5,domain=tdomain.RU,vers=2.1     ://thost/Consultant
Students      -fstype=cifs,multiuser,cruid=tuser,sec=krb5,domain=tdomain.RU,vers=2.1       ://thost/Students
Для подключения скрытых сетевых каталогов необходимо экранировать символ $
Consultant    -fstype=cifs,multiuser,cruid=tuser,sec=krb5,domain=tdomain.RU,vers=2.1     ://thost/Consultant\$
В файле /etc/krb5.conf нужно закомментировать строку (если она ещё не закомментирована)
#cat /etc/krb5.conf
...
default_ccache_name = KEYRING:persistent:%{uid}
...
#vim/etc/krb5.conf
#cat /etc/krb5.conf
...
default_ccache_name = FILE:/tmp/krb5cc_%{uid}
...
# systemctl start autofs.service
# systemctl enable autofs --now
Created symlink from /etc/systemd/system/multi-user.target.wants/autofs.service to /usr/lib/systemd/system/autofs.service.
# ls /mnt/.thost/Consultant/
... cons.exe ...
$ winecfg
# wine /mnt/.thost/Сonsultant/cons.exe /linux /yes
Task:
Администрирование локальных, виртуальных и облачных серверов. Создать ярлык Консультант +
Decision:
# vim /home/tuser@thost.ru/Рабочий\ стол/Consultant.desktop
# cat /home/tuser@thost.ru/Рабочий\ стол/Consultant.desktop
[Desktop Entry]
Name=ConsultantPlus
Exec=wine /mnt/.thost/Сonsultant/cons.exe
Type=Application
StartupNotify=true
Comment=ConsultantPlus
icon=43D4_Cons.0
StartupWMClass=c.exe
Task:
Администрирование локальных, виртуальных и облачных серверов. В случае замедленной работы можно добавить ключ /sprocess=0 При нормальной работе, не добавляйте этот ключ. Ключ /yes необходим для подавления сообщения об ошибке [WNetGetUniversalName ...] : NO_NETWORK
Decision:
# ln -s /mnt/.thost/S /home/tuser@thost.ru/Рабочий\ стол/S
Task:
Администрирование локальных, виртуальных и облачных серверов. Создание ярлыка для сетевой директории
Decision:
# ln -s /mnt/.thost/S /home/tuser@thost.ru/Рабочий\ стол/S
Task:
Администрирование локальных, виртуальных и облачных серверов.  После добавления сетевых папок через Kerberos на следующий месяц, все етевые папки на ПК перестали работать. Для решения проблемы нужно обновлять билеты через kdestroy и kinit:
Decision:
$ smbclient -L thost -k
gse_get_client_auth_token: gss_init_sec_context failed with [ Miscellaneous failure (see text): encryption type 0 not supported](2529639062)
gensec_spnego_client_negTokenInit_step: gse_krb5: creating NEG_TOKEN_INIT for cifs/tusertsrvdoc failed (next[(null)]): NT_STATUS_LOGON_FAILURE
session setup failed: NT_STATUS_LOGON_FAILURE
$ klist
Ticket cache: FILE:/tmp/krb5cc_17
Default principal: tuser@tdomain.RU
Valid starting Expires Service principal
01.01.1970 08:00:00 01.01.1970 08:00:00 krbtgt/tdomain.RU@tdomain.RU
$ date
Вт окт 6 14:46:12 +08 2020
$ kdestroy
$ kinit
$ klist
Ticket cache: FILE:/tmp/krb5cc_17
Default principal: tuser@tdomain.RU
Valid starting Expires Service principal
06.10.2020 14:46:51 07.10.2020 00:46:51 krbtgt/tdomain.RU@tdomain.RU
renew until 13.10.2020 14:46:29
Decision:
Проблема решена, но билет кеширования, нужно было обновлять постоянно. Поэтому, на мой взгляд, проще подключать сетевые папки через automount без Kerberos.
Task:
Администрирование локальных, виртуальных и облачных серверов.  Oграничение доступа к USB накопителям
Decision:
# vim /etc/udev/rules.d/99-usb.rules
# cat /etc/udev/rules.d/99-usb.rules
ENV{ID_USB_DRIVER}=="usb-storage",ENV{UDISKS_IGNORE}="1"
# udevadm control --reload-rules
Task:
Администрирование локальных, виртуальных и облачных серверов.  Запрет создания ярлыков и файлов на рабочем столе
Decision:
Проверить, поддерживает ли ваша файловая система ACL можно командой (вместо /dev/sda1 указать нужное имя дискового раздела):
# tune2fs -l /dev/sda1 | grep "Default mount options:"
Default mount options: user_xattr acl
# vim /home/tuser@thost.ru/.config/user-dirs.dirs
# cat /home/tuser@thost.ru/.config/user-dirs.dirs
# This file is written by xdg-user-dirs-update
# If you want to change or add directories, just edit the line you're
# interested in. All local changes will be retained on the next run
# Format is XDG_xxx_DIR="$HOME/yyy", where yyy is a shell-escaped
# homedir-relative path, or XDG_xxx_DIR="/yyy", where /yyy is an
# absolute path. No other format is supported.
#
XDG_DESKTOP_DIR="$HOME/Рабочий стол"
XDG_DOWNLOAD_DIR="$HOME/Загрузки"
XDG_TEMPLATES_DIR="$HOME/Шаблоны"
XDG_PUBLICSHARE_DIR="$HOME/Общедоступные"
XDG_DOCUMENTS_DIR="$HOME/Документы"
XDG_MUSIC_DIR="$HOME/Музыка"
XDG_PICTURES_DIR="$HOME/Изображения"
XDG_VIDEOS_DIR="$HOME/Видео"
# ls -la /home/tuser@thost.ru/.config
...
-rw-------. 1 tuser ïîëüçîâàòåëè äîìåíà 714 àâã 31 09:52 user-dirs.dirs
-rw-r--r--. 1 tuser ïîëüçîâàòåëè äîìåíà 5 àâã 31 09:52 user-dirs.locale
# chown root:root /home/tuser@thost.ru/.config/user-dirs.dirs
# ls -la /home/tuser@thost.ru/.config
...
-rw-------. 1 root root 714 àâã 31 09:52 user-dirs.dirs
-rw-r--r--. 1 tuser ïîëüçîâàòåëè äîìåíà 5 àâã 31 09:52 user-dirs.locale
# ls -la
...
drwxr-xr-x. 2 tuser ïîëüçîâàòåëè äîìåíà 4096 àâã 31 09:52 'Рабочий стол'
...
# chown -R root:root /home/tuser@thost.ru/Рабочий\ стол/
# ls -la
...
drwxr-xr-x. 2 root root 4096 àâã 31 09:52 'Рабочий стол'
drwxr-xr-x. 2 tuser ïîëüçîâàòåëè äîìåíà 4096 àâã 31 09:52 Øàáëîíû
Task:
Администрирование локальных, виртуальных и облачных серверов. Как скрыть пользователей от экрана входа
Decision:
# cat /var/lib/AccountsService/users/user
[User]
Language=
XSession=
SystemAccount=false
# vim /var/lib/AccountsService/users/user
# cat /var/lib/AccountsService/users/user
[User]
Language=
XSession=gnome
SystemAccount=true
Task:
Администрирование локальных, виртуальных и облачных серверов.  Добавление пользователя из доменной сети.
Decision:
[root@thost user]# vim /var/lib/AccountsService/users/tuser
[root@thost user]# cat /var/lib/AccountsService/users/tuser
[User]
Language=
XSession=
Icon=/home/tuser@thost.ru/.face
SystemAccount=false
Task:
Администрирование локальных, виртуальных и облачных серверов.  отключить сетевые принтеры.
Decision:
# vim /etc/avahi/avahi-daemon.conf
cat /etc/avahi/avahi-daemon.conf
# This file is part of avahi.
...
enable-dbus=no
...
# reboot
Task:
Установка Gimp
Decision:
yum provides gimp
Загружены модули: fastestmirror, langpacks
Loading mirror speeds from cached hostfile
2:gimp-2.8.22-2.el7.thost86 : GNU Image Manipulation Program
Источник: base
2:gimp-2.8.22-2.el7.x86_64 : GNU Image Manipulation Program
Источник: base
# yum list | grep gimp
gimp.thost86 2:2.8.22-2.el7 base
# yum -y install gimp
Task:
Администрирование локальных, виртуальных и облачных серверов. Запись дисков Linux в терминале
Decision:
# ls
13 'MyTestX Tests'
# pwd
/home/is@tdomain.RU/Documents
# mkisofs -o first.iso /home/is@tdomain.RU/Documents/13
# ls
13 first.iso 'MyTestX Tests'
# mkisofs -l -o first.iso /home/is@tdomain.RU/Documents/13
# ls
13 first.iso 'MyTestX Tests'
# mkisofs -D -l -o first.iso /home/is@tdomain.RU/Documents/13
# mkisofs -J -l -o first.iso /home/is@tdomain.RU/Documents/13
Warning: creating filesystem with Joliet extensions but without Rock Ridge
extensions. It is highly recommended to add Rock Ridge.
...
Joliet tree sort failed. The -joliet-long switch may help you.
# -joliet-long
# mkisofs -J -joliet-long -l -o first.iso /home/is@tdomain.RU/Documents/13
Warning: creating filesystem with Joliet extensions but without Rock Ridge
extensions. It is highly recommended to add Rock Ridge.
...
99.90% done, estimate finish Fri Jan 15 11:29:00 2021
Total translation table size: 0
Total rockridge attributes bytes: 0
Total directory bytes: 0
Path table size(bytes): 10
Max brk space used 0
545548 extents written (1065 MB# lsblk -d -o +MODEL
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT MODEL
sda 8:0 0 111,8G 0 disk KINGSTON SA400S3
sr0 11:0 1 2K 0 rom CDDVDW SN-208BB
Если вы собираетесь записать образ на диск ubuntu DVD-RW/CD-RW необходимо сначала его очистить:
cdrecord -dev=/dev/sr0 -v blank=fast
# cd Documents/
# ls
13 first.iso 'MyTestX Tests'
Здесь и ниже /dev/sr0 - адрес файла вашего привода:
# cdrecord -dev=/dev/sr0 -speed=16 -eject -v first.iso
first.iso - это файл образа, 16 - скорость записи, а опция -eject - заставляет извлечь диск из привода после записи. Можно указывать скорость 4, 8 и 16. Желательно выбирать минимальную скорость, так диск запишется более качественно.
Task:
Администрирование локальных, виртуальных и облачных серверов. Установка клиента 1С
Decision:
# yum -y install webkitgtk3
# ls
1C_Enterprise83-client-8.3.14-17.x86_64.rpm
1C_Enterprise83-common-8.3.14-17.x86_64.rpm
1C_Enterprise83-server-8.3.14-17.x86_64.rpm
# yum -y install 1C_Enterprise83-*
Task:
Администрирование локальных, виртуальных и облачных серверов.  Установка аналога paint
Decision:
# yum list | grep paint
kolourpaint.thost86 17.12.1-2.el7 base
kolourpaint.x86_64 17.12.1-2.el7 base
kolourpaint-libs.thost86 17.12.1-2.el7 base
kolourpaint-libs.x86_64 17.12.1-2.el7 base
# yum -y install kolourpaint
Task:
Администрирование локальных, виртуальных и облачных серверов. Настройка оповещения и автоматического обновления пакетов в РЕД ОС с помощью yum-cron
Decision:
# yum -y install yum-cron
# vim /etc/yum/yum-cron.conf
# cat /etc/yum/yum-cron.conf
[commands]
# What kind of update to use:
# default = yum upgrade
# security = yum --security upgrade
# security-severity:Critical = yum --sec-severity=Critical upgrade
# minimal = yum --bugfix update-minimal
# minimal-security = yum --security update-minimal
# minimal-security-severity:Critical = --sec-severity=Critical update-minimal
update_cmd = default
# Whether a message should be emitted when updates are available,
# were downloaded, or applied.
update_messages = yes
# Whether updates should be downloaded when they are available.
download_updates = yes
# Whether updates should be applied when they are available. Note
# that download_updates must also be yes for the update to be applied.
apply_updates = no
# Maximum amout of time to randomly sleep, in minutes. The program
# will sleep for a random amount of time between 0 and random_sleep
# minutes before running. This is useful for e.g. staggering the
# times that multiple systems will access update servers. If
# random_sleep is 0 or negative, the program will run immediately.
# 6*60 = 360
random_sleep = 360
...
# vim /etc/yum/yum-cron.conf
# cat /etc/yum/yum-cron.conf
[commands]
# What kind of update to use:
# default = yum upgrade
# security = yum --security upgrade
# security-severity:Critical = yum --sec-severity=Critical upgrade
# minimal = yum --bugfix update-minimal
# minimal-security = yum --security update-minimal
# minimal-security-severity:Critical = --sec-severity=Critical update-minimal
update_cmd = default
# Whether a message should be emitted when updates are available,
# were downloaded, or applied.
update_messages = yes
# Whether updates should be downloaded when they are available.
download_updates = yes
# Whether updates should be applied when they are available. Note
# that download_updates must also be yes for the update to be applied.
apply_updates = yes
# Maximum amout of time to randomly sleep, in minutes. The program
# will sleep for a random amount of time between 0 and random_sleep
# minutes before running. This is useful for e.g. staggering the
# times that multiple systems will access update servers. If
# random_sleep is 0 or negative, the program will run immediately.
# 6*60 = 360
random_sleep = 360
...
# systemctl enable yum-cron --now
Task:  
Администрирование локальных, виртуальных и облачных серверов.  Если не требуется обновлять определенные пакеты (как вручную, так и автоматически), то добавляем их в исключение. Например, kernel и php.
Decision:
#nano /etc/yum.conf
exclude=kernel, php
Task:  
Администрирование локальных, виртуальных и облачных серверов.  Если не требуется обновлять пакеты ТОЛЬКО в автоматическом режиме, тогда в /etc/yum/yum-cron.conf , в раздел [base], добавляем следующую строку:
Decision
# nano /etc/yum/yum-cron.conf
exclude=kernel* php*
Task:
Администрирование локальных, виртуальных и облачных серверов.  Установка Anydesk
Decision:
# tee /etc/yum.repos.d/AnyDesk-RHEL.repo <<EOF
> [anydesk]
> name=AnyDesk RHEL - stable
> baseurl=http://rpm.anydesk.com/rhel/\$basearch/
> gpgcheck=1
> repo_gpgcheck=1
> gpgkey=https://keys.anydesk.com/repos/RPM-GPG-KEY
> EOF
# dnf makecache
# dnf install -y redhat-lsb-core
# dnf install anydesk
# rpm -qi anydesk
# systemctl status anydesk.service
# exit
$ anydesk
Task:
Администрирование локальных, виртуальных и облачных серверов. Создание загрузочных носителей
Decision:
# fdisk -l
...
Диск /dev/sdb: 3,61 GiB, 3880452096 байт, 7579008 секторов
Disk model: Silicon-Power4G
Единицы: секторов по 1 * 512 = 512 байт
Размер сектора (логический/физический): 512 байт / 512 байт
Размер I/O (минимальный/оптимальный): 512 байт / 512 байт
Тип метки диска: gpt
Идентификатор диска: 2BAC44AA-F36D-461C-B12A-D251E7E9373F
Устр-во    начало   Конец Секторы Размер Тип
/dev/sdb1    2048 7578974 7576927   3,6G Microsoft basic data
# ls
Zorin-OS-16.1-Core-64-bit.iso
# dd if=Zorin-OS-16.1-Core-64-bit.iso of=/dev/sdb1 bs=8MB status=progress oflag=direct
3058237440 байт (3,1 GB, 2,8 GiB) скопирован, 659 s, 4,6 MB/s
382+1 записей получено
382+1 записей отправлено
3058237440 байт (3,1 GB, 2,8 GiB) скопирован, 659,39 s, 4,6 MB/s
Task:
Администрирование локальных, виртуальных и облачных серверов. Развернуть Pxe сервер для развертывания Redos с загрузкой в Uefi по сети
Decision:
# ifconfig
enp2s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
    inet IpAddr1  netmask Mask1  broadcast IpAddr.255
    ...
# dnf install dhcp tftp-server syslinux httpd dnf-plugins-core -y
# mkdir /var/lib/tftpboot/pxelinux.cfg
# mkdir /var/lib/tftpboot/uefi
# mkdir -p /var/lib/tftpboot/images/REDOS
# cp /usr/share/syslinux/{chain.c32,mboot.c32,memdisk,menu.c32,pxelinux.0,ldlinux.c32,libutil.c32} /var/lib/tftpboot/
# chmod 777 /var/lib/tftpboot/pxelinux.0
# dnf download shim-x64 grub2-efi-x64 --downloaddir=/root/
# cd /root/
# rpm2cpio shim-x64-*.rpm | cpio -dimv
# rpm2cpio grub2-efi-x64-*.rpm | cpio -dimv
# cp ./boot/efi/EFI/BOOT/BOOTX64.EFI /var/lib/tftpboot/uefi
# cp ./boot/efi/EFI/redos/grubx64.efi /var/lib/tftpboot/uefi
# chmod 777 /var/lib/tftpboot/uefi/*.*
# mount -t iso9660 -o loop redos-MUROM-7.3.2-20211027.0-Everything-x86_64-DVD1.iso /mnt/
# cp -vR /mnt/* /var/lib/tftpboot/images/REDOS/
# umount /mnt/
# vim /etc/dhcp/dhcpd.conf
# cat /etc/dhcp/dhcpd.conf
non-authoritative;
allow bootp;
option space pxelinux;
option pxelinux.magic code 208 = string;
option pxelinux.configfile code 209 = text;
option pxelinux.pathprefix code 210 = text;
option pxelinux.reboottime code 211 = unsigned integer 32;
option architecture-type code 93 = unsigned integer 16;
subnet IpAddr.0 netmask Mask1 {
option routers IpAddr1;
range IpAddr.70 IpAddr.80;
class "pxeclients" {
match if substring (option vendor-class-identifier, 0, 9) = "PXEClient";
next-server IpAddr1;
if option architecture-type = 00:07 {
filename "uefi/grubx64.efi";

else {
filename "pxelinux.0";
}
}

# systemctl enable dhcpd --now
# vim /var/lib/tftpboot/pxelinux.cfg/default
# cat /var/lib/tftpboot/pxelinux.cfg/default
default menu.c32
PROMPT 0
TIMEOUT 150
MENU TITLE PXE Menu
LABEL REDOS 7.3
MENU LABEL REDOS 7.3
KERNEL images/REDOS/images/pxeboot/vmlinuz
APPEND initrd=images/REDOS/images/pxeboot/initrd.img ramdisk_size=128000 ip=dhcp inst.repo=http://IpAddr1/images/REDOS/ 
# vim /var/lib/tftpboot/uefi/grub.cfg 
# cat /var/lib/tftpboot/uefi/grub.cfg 
function load_video { 
insmod efi_gop  
insmod efi_uga 
insmod video_bochs 
insmod video_cirrus 
insmod all_video 

load_video 
set gfxpayload=keep 
insmod gzio 
menuentry 'REDOS 7.3' { 
linux images/REDOS/images/pxeboot/vmlinuz ip=dhcp inst.repo=http://IpAddr1/images/REDOS/ 
initrd images/REDOS/images/pxeboot/initrd.img 

Task:
Администрирование локальных, виртуальных и облачных серверов. Используем web-сервер для публикации файлов дистрибутива РЕД ОС в локальной сети.
Decision:
# vim /etc/httpd/conf.d/pxeboot.conf 
# cat /etc/httpd/conf.d/pxeboot.conf 
Alias /images /var/lib/tftpboot/images 
<Directory /var/lib/tftpboot/images> 
Options Indexes FollowSymLinks 
Require ip 127.0.0.1 IpAddr.0/24 
</Directory>
# systemctl enable httpd --now
Task:
Администрирование локальных, виртуальных и облачных серверов.  Настройка и запуск службы tftp.
Decision:
# vim /usr/lib/systemd/system/tftp.service
# cat /usr/lib/systemd/system/tftp.service
...
[Install]:
WantedBy=multi-user.target 
Also=tftp.socket
...
# vim /usr/lib/systemd/system/tftp.socket
# cat /usr/lib/systemd/system/tftp.socket
...
[Unit] 
Description=Tftp Server Activation Socket 
[Socket] 
ListenDatagram=0.0.0.0:69 
[Install] 
WantedBy=sockets.target 
...
# systemctl daemon-reload
# systemctl enable tftp --now
# ausearch -c 'httpd' --raw | audit2allow -M my-httpd
# semodule -i my-httpd.pp
Task:
Администрирование локальных, виртуальных и облачных серверов.  Автоматизация развертывания (kickstart)
Создать файл кикстарта, Записать файл на локальный или удаленный носитель, Создать загрузочный диск, с которого будет запускаться установка, Предоставить доступ к установочной структуре, Начать процесс установки.
Decision:
# dnf install pykickstart -y
# cp /root/anaconda-ks.cfg /var/lib/tftpboot
# mv /var/lib/tftpboot/anaconda-ks.cfg /var/lib/tftpboot/ks.cfg
# vim /var/lib/tftpboot/pxelinux.cfg/default
# cat /var/lib/tftpboot/pxelinux.cfg/default
...
APPEND initrd=images/REDOS/images/pxeboot/initrd.img ramdisk_size=128000 ip=dhcp method=http://IpAddr1/images/REDOS/ devfs=nomount inst.ks=http://IpAddr1/ks.cfg 
# vim /var/lib/tftpboot/uefi/grub.cfg
# cat /var/lib/tftpboot/uefi/grub.cfg
... { 
linux images/REDOS/images/pxeboot/vmlinuz ip=dhcp kernel vmlinuz inst.repo=http://IpAddr1/images/REDOS/ inst.ks=http://IpAddr1/ks.cfg 
initrd images/REDOS/images/pxeboot/initrd.img

# vim /var/lib/tftpboot/ks.cfg
# cat /var/lib/tftpboot/ks.cfg
# Здесь указываем раскладку клавиатуры
keyboard --vckeymap=us --xlayouts='us','ru' --switch='grp:alt_shift_toggle'
# Системная локаль
lang ru_RU.UTF-8
# Информация о сетевом интерфейсе и имя машины
network  --bootproto=dhcp --device=enp2s0 --noipv6 --activate
network  --hostname=hostname1337
# Пароль Root представлен в виде хэш-суммы
rootpw --iscrypted $6$DUu0yyOYMRbGS8gL$9zHYPsxROGEZdDKG0wnf7h8SGnKOp3V272De6oGTVUsz2uBLmEeiR6T6cInRN5dyWcxNXh5fVluEUTQ/3rmzB0
# Настройка сервисов (в данном случае сервис по обновлению меток времени и дат)
services --enabled="chronyd"
# Настройка временной зоны
timezone Europe/Moscow --isUtc
#Настройка локального пользователя
user --groups=wheel --name=mekka --password=$6$83fyYZ7KMS7G9t6A$E5/99/ffOwjUOo8THr1ngqGDdKMimpTZf3IT9S/SI98BTV7dta7GksLYnQEZjtqqyZQrwibSRlvYccRqHB7m8/ --iscrypted --gecos="Mekka"
# Настройка xorg при загрузке
xconfig  --startxonboot
# Указание загрузочного сектора и тип структуры
bootloader --location=mbr --boot-drive=sda
# Удаление всей информации с партиций для последующей установки
clearpart --none --initlabel
# Здесь указана вся разметка диска
part /boot --fstype="xfs" --onpart=sda2
part biosboot --fstype="biosboot" --noformat --onpart=sda4
part pv.31 --fstype="lvmpv" --noformat --onpart=sda3
part /boot/efi --fstype="efi" --onpart=sda1 --fsoptions="umask=0077,shortname=winnt"
volgroup ro --noformat --useexisting
logvol swap  --fstype="swap" --useexisting --name=swap --vgname=ro
logvol /home  --fstype="xfs" --noformat --useexisting --name=home --vgname=ro
logvol /  --fstype="ext4" --useexisting --name=root --vgname=ro
#дополнительные пакеты для установки
%packages
@^mate-desktop-environment
@backup-client
@base
@branding
@core
@desktop-debugging
@dial-up
@directory-client
@fonts
@guest-agents
@guest-desktop-agents
@input-methods
@internet-applications
@internet-browser
@java-platform
@mate-desktop
@multimedia
@network-file-system-client
@print-client
@x11
chrony
%end
#настройка аварийных дампов памяти в случае сбоев (оставить как есть)
%addon com_redhat_kdump --enable --reserve-mb='auto'
%end
#настройка анаконды (оставить как есть)
%anaconda
pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty
pwpolicy user --minlen=6 --minquality=1 --notstrict --nochanges --emptyok
pwpolicy luks --minlen=6 --minquality=1 --notstrict --nochanges --notempty
%end
Task:
Администрирование локальных, виртуальных и облачных серверов.  Настройка установки РЕД ОС по PXE через VNC вместо Kickstart
Decision:
# vim /var/lib/tftpboot/pxelinux.cfg/default
# cat /var/lib/tftpboot/pxelinux.cfg/default
...
APPEND initrd=images/REDOS/images/pxeboot/initrd.img ramdisk_size=128000 ip=dhcp method=http://IpAddr1/images/REDOS/ devfs=nomount inst.vnc inst.vncpassword=tpassword
# vim /var/lib/tftpboot/uefi/grub.cfg
# cat /var/lib/tftpboot/uefi/grub.cfg
... { 
linux images/REDOS/images/pxeboot/vmlinuz ip=dhcp kernel vmlinuz inst.repo=http://IpAddr1/images/REDOS/ inst.vnc inst.vncpassword=tpassword
initrd images/REDOS/images/pxeboot/initrd.img
}
Source:
# https://redos.red-soft.ru/base/other-soft/other-other/consultant/?sphrase_id=53349
# https://wtuseri.astralinuthost.ru/pages/viewpage.action?pageId=61574227
# https://askubuntu.ru/questions/21203/kak-skry-t-pol-zovatelej-ot-e-krana-vxoda-v-gdm
# https://computingforgeeks.com/how-to-install-gimp-on-centos-rhel-8-desktop/
# https://ru.wtuserihow.com/%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D1%82%D1%8C-ISO-%D1%84%D0%B0%D0%B9%D0%BB-%D0%B2-Linux
# https://losst.ru/zapis-diskov-v-ubuntu
# https://losst.ru/luchshie-analogi-paint-dlya-linux 
# https://computingforgeeks.com/how-to-install-anydesk-on-centos-rhel-8/

Task:
Администрирование локальных, виртуальных и облачных серверов.  В компьютерном классе по 20 компьютеров и в каждом надо было установить Microsoft Office. Для этого я написал скрипты инсталлятор и конфигуратор, которые позволяют мне выбрать дистрибутив, в котором я установливаю, саму программу для установки и настройки (не только офис)
Decision:
$ vim Linux-Installer.sh
$ cat Linux-Installer.sh
#!/bin/bash
checkcmd(){
if [ $? -eq 0 ]; then
    echo ! The command was executed successfully
else
    echo ! The command was executed with an error
fi

#echo YOUR-PASSWORD | sudo -S sudo dnf update
#checkcmd
# https://stackoverflow.com/questions/226703/how-do-i-prompt-for-yes-no-cancel-input-in-a-linux-shell-script
while true; do
    read -p "Do you want to install the program? (y/n) " yn
    case $yn in
        [Yy]* ) 
            echo -n "Select the distribution where you want to install the program (Centos 9 - 1 / Ubuntu 22.04 - 2 / Redos 7.3 - 3): "
            read choicedistr
            case "$choicedistr" in
                1|Centos) 
                    echo YOUR-PASSWORD | sudo -S sudo dnf -y update
                    checkcmd
                    echo -n "Select a program (Test - 0 / Sublime Text - 1 / Postgresql - 2 / PgAdmin - 3 / Git - 4 / Kvm - 5 / nfts-3g - 6 / libreoffice - 7): "
                    read choiceprogr
                    case "$choiceprogr" in
                        0)
                            echo YOUR-PASSWORD | sudo -S sudo dnf -y update
                            checkcmd
                            ;;
                        1)
                            # https://www.sublimetext.com/docs/linux_repositories.html#dnf
                            echo YOUR-PASSWORD | sudo -S sudo rpm -v --import https://download.sublimetext.com/sublimehq-rpm-pub.gpg
                            checkcmd
                            echo YOUR-PASSWORD | sudo -S sudo dnf config-manager --add-repo https://download.sublimetext.com/rpm/stable/x86_64/sublime-text.repo
                            checkcmd
                            echo YOUR-PASSWORD | sudo -S sudo dnf -y install sublime-text
                            checkcmd
                            ;;
                        2)
                            # https://www.postgresql.org/download/linux/redhat/
                            echo YOUR-PASSWORD | sudo -S sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm
                            checkcmd
                            echo YOUR-PASSWORD | sudo -S sudo dnf -qy module disable postgresql
                            checkcmd
                            echo YOUR-PASSWORD | sudo -S sudo dnf install -y postgresql15-server
                            checkcmd
                            echo YOUR-PASSWORD | sudo -S sudo /usr/pgsql-15/bin/postgresql-15-setup initdb
                            checkcmd
                            echo YOUR-PASSWORD | sudo -S sudo systemctl enable postgresql-15
                            echo YOUR-PASSWORD | sudo -S sudo systemctl start postgresql-15
                            checkcmd
                            ;;
                        3)
                            # https://www.pgadmin.org/download/pgadmin-4-rpm/
                            echo YOUR-PASSWORD | sudo -S sudo rpm -i https://ftp.postgresql.org/pub/pgadmin/pgadmin4/yum/pgadmin4-redhat-repo-2-1.noarch.rpm
                            checkcmd
                            echo YOUR-PASSWORD | sudo -S sudo yum install -y pgadmin4
                            checkcmd
                            echo YOUR-PASSWORD | sudo -S sudo yum install -y pgadmin4-desktop
                            checkcmd
                            echo YOUR-PASSWORD | sudo -S sudo yum install -y pgadmin4-web
                            checkcmd
                            sudo /usr/pgadmin4/bin/setup-web.sh
                            checkcmd
                            echo YOUR-PASSWORD | sudo -S sudo yum upgrade -y pgadmin4
                            checkcmd
                            ;;
                        4)
                            # https://unixcop.com/how-to-install-git-on-centos-9-stream-fedora/
                            echo YOUR-PASSWORD | sudo -S sudo dnf -y install git
                            checkcmd
                            git --version
                            ;;
                        5)
                            # https://technixleo.com/install-kvm-on-centos-alma-rhel-9/
                            egrep -c '(vmx|svm)' /proc/cpuinfo
                            echo YOUR-PASSWORD | sudo -S sudo dnf install -y qemu-kvm qemu-img libvirt virt-install libvirt-client virt-manager
                            checkcmd
                            lsmod | grep kvm
                            echo YOUR-PASSWORD | sudo -S sudo systemctl enable --now libvirtd
                            checkcmd
                            sudo virt-host-validate                            
                            ;;
                        6)
                            # https://itisgood.ru/2019/03/26/kak-smontirovat-disk-ntfs-na-centos-rhel-scientific-linux/
                            echo YOUR-PASSWORD | sudo -S sudo yum -y install epel-release
                            checkcmd
                            echo YOUR-PASSWORD | sudo -S sudo yum -y install ntfs-3g
                            checkcmd            
                            ;;
                        7)
                            echo YOUR-PASSWORD | sudo -S sudo dnf -y install libreoffice
                            checkcmd            
                            ;;
                    esac
                    ;;
                2|u|U|Ubuntu) 
                    echo YOUR-PASSWORD | sudo -S sudo apt -y update
                    echo YOUR-PASSWORD | sudo -S sudo apt -y upgrade
                    checkcmd
                    echo -n "Select a program (Test - 0 / Net-Tools - 1 / Ssh - 2): "
                    read choiceprogr
                    case "$choiceprogr" in
                        0)
                            echo YOUR-PASSWORD | sudo -S sudo apt-get -y update
                            checkcmd
                            ;;
                        1)
                            echo YOUR-PASSWORD | sudo -S sudo apt-get install net-tools
                            checkcmd
                            ;;
                        2)#https://help.reg.ru/support/servery-vps/oblachnyye-servery/rabota-s-serverom/kak-ustanovit-i-nastroit-ssh
                            echo YOUR-PASSWORD | sudo -S sudo apt-get install ssh
                            checkcmd
                            echo YOUR-PASSWORD | sudo -S sudo apt-get install openssh-server
                            checkcmd
                            systemctl status ssh
                            ;;
                    esac
                    exit 0
                    ;;
                3|r|R|Redos)
                    echo YOUR-PASSWORD | sudo -S sudo yum -y update
                    checkcmd
                    echo -n "Select a program (Test - 0 / Office - 1 / Playonlinux - 2): "
                    read choiceprogr
                    case "$choiceprogr" in
                        0)
                            echo YOUR-PASSWORD | sudo -S sudo yum -y update
                            checkcmd
                            ;;                        
                        1)
                            echo YOUR-PASSWORD | sudo -S sudo yum -y update
                            checkcmd
                            wine /LINKS/MS\ Office\ 2007-10-13/Office_Professional_Plus_2007_W32_Russia/SETUP.EXE
                            checkcmd    
                            ;;
                        2)
                            echo YOUR-PASSWORD | sudo -S sudo yum -y update
                            checkcmd
                            echo YOUR-PASSWORD | sudo -S sudo touch /etc/yum.repos.d/playonlinux.repo
                            echo YOUR-PASSWORD | sudo -S sudo echo '[playonlinux]
                            name=PlayOnLinux Official repository
                            baseurl=http://rpm.playonlinux.com/fedora/yum/base
                            enable=1
                            gpgcheck=0
                            gpgkey=http://rpm.playonlinux.com/public.gpg' > /etc/yum.repos.d/playonlinux.repo
                            cat /etc/yum.repos.d/playonlinux.repo
                            checkcmd
                            echo YOUR-PASSWORD | sudo -S sudo yum -y install playonlinux nc jq
                            checkcmd
                            echo YOUR-PASSWORD | sudo -S sudo reboot                            
                            ;;
                    esac
                    ;;
                *) 
                    echo "Nothing was entered."
                    ;;
            esac            
            ;;
        [Nn]* ) 
            exit
            ;;
        * ) 
            echo "Please answer yes or no."
            ;;
    esac
done
exit 0
$ ./Linux-Installer.sh
Do you want to install the program? (y/n) y
Select the distribution where you want to install the program (Centos 9 - 1 / Ubuntu 22.04 - 2 / Redos 7.3 - 3): 1
Select a program (Test - 0 / Sublime Text - 1 / Postgresql - 2 / PgAdmin - 3 / Git - 4 / Kvm - 5 / nfts-3g - 6 / libreoffice - 7): 0
Do you want to install the program? (y/n) y
Select the distribution where you want to install the program (Centos 9 - 1 / Ubuntu 22.04 - 2 / Redos 7.3 - 3): 2
Select a program (Test - 0 / Net-Tools - 1 / Ssh - 2): 0
$ vim Linux-Config.sh
$ cat Linux-Config.sh
#!/bin/bash 
checkcmd(){
if [ $? -eq 0 ]; then
    echo ! The command was executed successfully
else
    echo ! The command was executed with an error
fi
}
# https://stackoverflow.com/questions/226703/how-do-i-prompt-for-yes-no-cancel-input-in-a-linux-shell-script
while true; do
    read -p "Do you want to configure the program? (y/n) " yn
    case $yn in
        [Yy]* ) 
            echo -n "Select the distribution where you want to configure the program (Redhat - 1 / Debian - 2): "
            read choicedistr
            case "$choicedistr" in
                1|r|R|Redhat) 
                    echo YOUR-PASSWORD | sudo -S sudo dnf -y update
                    checkcmd
                    echo -n "Select a program (Test - 0 / Disabling Lamp - 1 / Starting Lamp - 2 / Add users in postgressql - 3 / Moving linux folders to another disk - 4): "
                    read choiceprogr
                    case "$choiceprogr" in
                        0)
                            echo YOUR-PASSWORD | sudo -S sudo dnf -y update
                            checkcmd
                            ;;
                        1)
                            echo YOUR-PASSWORD | sudo -S sudo service apache2 stop
                            checkcmd
                            echo YOUR-PASSWORD | sudo -S sudo service mysql stop
                            checkcmd
                            ;;
                        2)
                            echo YOUR-PASSWORD | sudo -S sudo service apache2 start
                            checkcmd
                            echo YOUR-PASSWORD | sudo -S sudo service mysql start
                            checkcmd
                            ;;
                        3) #https://www.dmosk.ru/miniinstruktions.php?mini=postgresql-users&ysclid=lig0a2xuou515754413#create
                            echo -n "Please come up with a new user: "
                            read userdb
                            echo -n "Please come up with a new password: "
                            read passwdb
                            #echo YOUR-PASSWORD | sudo -S 
                            cd /tmp
                            sudo -u postgres -H -- psql -d template1 -c "CREATE USER $userdb WITH PASSWORD '$passwdb';"
                            #psql -U postgres -d template1 -c "CREATE USER tuser0 WITH PASSWORD 'Tpsswd';"
                            checkcmd
                            echo -n "Please come up with a new base: "
                            read namedb
                            sudo -u postgres -H -- psql -d template1 -c "CREATE database $namedb;"
                            checkcmd
                            sudo -u postgres -H -- psql -d template1 -c "GRANT ALL PRIVILEGES ON DATABASE "$namedb" to $userdb;"
                            checkcmd
                            sudo -u postgres -H -- psql -d template1 -c "\c $namedb;"
                            checkcmd
                            sudo -u postgres -H -- psql -d template1 -c "GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "$userdb";"
                            checkcmd
                            ;;
                        4) #http://sysengineering.ru/notes/peremeschenie-papok-linux-na-drugoy-disk?ysclid=lisfix46x1712981898
                            lsblk
                            echo -n "USB device for moving the base (hint above): "
                            read mntusb
                            echo YOUR-PASSWORD | sudo -S sudo fdisk $mntusb
                            lsblk
                            echo -n "USB device for moving the base (hint above): "
                            read mntusb1
                            echo -n "Enter the file system type: "
                            read mntfs
                            echo YOUR-PASSWORD | sudo -S sudo mkfs -t $mntfs $mntusb1
                            checkcmd
                            echo YOUR-PASSWORD | sudo -S sudo mount $mntusb1 /mnt
                            checkcmd
                            shopt -s dotglob
                            echo -n "Which directory do you need to move: "
                            read movedir
                            echo YOUR-PASSWORD | sudo -S sudo rsync -aulvXpogtr $movedir/* /mnt
                            checkcmd
                            ls -Zd $movedir
                            ls -Zd /mnt
                            echo -n "Change the security settings of a new folder (hint above): "
                            read mntset
                            echo YOUR-PASSWORD | sudo -S sudo chcon -t $mntset /mnt
                            checkcmd
                            ls -Zd /mnt
                            echo YOUR-PASSWORD | sudo -S sudo umount /mnt
                            checkcmd
                            echo YOUR-PASSWORD | sudo -S sudo blkid
                            echo -n "Enter the UUID of the disk (hint above): "
                            read mntuid
                            echo YOUR-PASSWORD | sudo -S sudo sh -c "echo 'UUID=$mntuid   $movedir  $mntfs  defaults,noatime,nofail 0 2' >> /etc/fstab"
                            checkcmd
                            echo YOUR-PASSWORD | sudo -S sudo cat /etc/fstab | grep $mntfs
                            echo YOUR-PASSWORD | sudo -S sudo mv $movedir $movedir.back
                            echo YOUR-PASSWORD | sudo -S sudo mkdir $movedir
                            echo YOUR-PASSWORD | sudo -S sudo mount -av
                            checkcmd
                            ls $movedir
                            lsblk                        
                            ;;
                    esac
                    ;;
                2|d|D|Debian) 
                    echo "deb"
                    exit 0
                    ;;
                *) 
                    echo "Nothing was entered."
                    ;;
            esac            
            ;;
        [Nn]* ) 
            exit
            ;;
        * ) 
            echo "Please answer yes or no."
            ;;
    esac
done
exit 0
$ ./Linux-Config.sh
Do you want to configure the program? (y/n) y
Select the distribution where you want to configure the program (Redhat - 1 / Debian - 2): 1
Select a program (Test - 0 / Disabling Lamp - 1 / Starting Lamp - 2 / Add users in postgressql - 3 / Moving linux folders to another disk - 4): 0
Do you want to configure the program? (y/n) n
Task:
Администрирование локальных, виртуальных и облачных серверов. Столкнулся с такой проблемой, что маленький неттоп флешки не читает, он не был добавлен в домен и антивирус на нем не стоял. Убедимся на другой машине, в моем случае ноутбуке, что флешка спокойно видит на нем файлы.    То есть это чистая флешка, не зараженная, и попробуем ее вставить в тот проблемный неттоп. Тут мы увидим, что во флешке другая информация будет. Как будто в самой флешке отображается сама флешка, и если ее открыть (что делать не стоит) тот там и будут наши файлы. на самом деле они будут зашифрованны и флешка заражена. Надо это исправлять. В тот момент у нас не было в неттопе никакого антивируса, поэтому я установил бесплатный антивирус Касперский FREE с официального сайта. И вот, он выдал в момент запуска после установки рекомендации по устранении проблм в компьютере. - Жмем устранить и перезагрузимся - В следующем запуске антивирус покажет информацию об устранении проблем, и можем сразу вставить флешку в неттопе. Тут мы увидим, что антвирус удалил какой-то файл (это и есть вирус) Открываем саму флешку после удаления вируса, а там пустой файл, хотя система показывает, что флешка заполнена. Он содержит зашифрованные файлы. Давайте попробуем их восстановить. Есть скрипт, который возвращает данные. Вставьте этот файл на флешку - запустите его - увидите файл и папку с файлами, которые ему удалось восстановить - Все готово, и неттоп мы подлечили, и данные со флешки восстановили, и антивирус бесплатный установили, и главное что этот бюджетный вариант с восстановлением вполне корректно работает.
Decision:
$ vim Windows-FlashDriveRecovery.bat
$ cat Windows-FlashDriveRecovery.bat
dir /AS /B > list.txt 
FOR /F "eol=# tokens=1* delims=:" %%i in (list.txt) do ( 
attrib -s -h -r "%%i" 

pause
Task:
Администрирование локальных, виртуальных и облачных серверов. Установить виртуальный сервер AltLinux в Hyper-V
Decision:
PS C:\Windows\system32> $ram=1*1024*1024*1024
PS C:\Windows\system32> $ram
1073741824
PS C:\Windows\system32> $hdd=10*1024*1024*1024
PS C:\Windows\system32> $hdd
10737418240
PS C:\Windows\system32> NEW-VM -Name Alt -MemoryStartupBytes $ram -NewVHDPath 'C:\Data\VM\Alt\Alt.vhdx'-NewVHD
SizeBytes $hdd -Path 'C:\Data\VM\Alt'
PS C:\Windows\system32> Start-VM -name Alt
PS C:\Windows\system32> Get-VM
Name State   CPUUsage(%) MemoryAssigned(M) Uptime   Status
---- -----   ----------- ----------------- ------   ------
Alt  Off     0           0                 00:00:00 Работает нормально
Task:
Администрирование локальных, виртуальных и облачных серверов. Set up an ActiveDirectory/Login
Decision:
$ ssh -X tuser@thost1
$ su -
# apt-get install task-auth-ad-sssd
# net time set -S thost.ru
# system-auth write ad thost.ru thost1 thost 'tuser' 'tpassword'
Using short domain name -- thost
Joined 'thost1' to dns domain 'thost.ru'
Successfully registered hostname with DNS
failed to call wbcGetDisplayName: WBC_ERR_WINBIND_NOT_AVAILABLE
Could not lookup sid S-1-5-21-965402400-3010625364-1855727791-513
failed to call wbcGetDisplayName: WBC_ERR_WINBIND_NOT_AVAILABLE
Could not lookup sid S-1-5-21-965402400-3010625364-1855727791-512
# wbinfo -t
checking the trust secret for domain thost via RPC calls succeeded
# acc
2 keyboards found
qt.qpa.xcb: could not connect to display
qt.qpa.plugin: Could not load the Qt platfothost plugin "xcb" in "" even though it was found.
This applthostation failed to start because no Qt platfothost plugin could be initialized. Reinstalling the applthostation may fix this problem.
Available platfothost plugins are: eglfs, linuxfb, minimal, minimalegl, offscreen, vnc, xcb.
# exit
$ exit
$ ssh -X tuser@thost1
$ su -
# acc
2 keyboards found
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/.private/root/runtime-root'
libpng warning: thostCP: known incorrect sRGB profile
libpng warning: thostCP: known incorrect sRGB profile
libpng warning: thostCP: known incorrect sRGB profile
libpng warning: thostCP: known incorrect sRGB profile
libpng warning: thostCP: known incorrect sRGB profile
WARNING: (alterator lookout evaluation): imported module (alterator presentation events) overrides core binding `when'
libpng warning: thostCP: known incorrect sRGB profile
libpng warning: thostCP: known incorrect sRGB profile
libpng warning: thostCP: known incorrect sRGB profile
libpng warning: thostCP: known incorrect sRGB profile
# vim /etc/net/ifaces/eth0/resolv.conf
# cat /etc/net/ifaces/eth0/resolv.conf
nameserver IpAddr1
# hostnamectl set-hostname thost1.thost.ru
# cat /etc/resolv.conf
# Generated by resolvconf
# Do not edit manually, use
# /etc/net/ifaces/<interface>/resolv.conf instead.
search thost.ru
nameserver 127.0.0.1
# vim /etc/resolv.conf
# cat /etc/resolvconf.conf
# Configuration for resolvconf(8)
# See resolvconf.conf(5) for details
resolv_conf_head='# Do not edit manually, use\n# /etc/net/ifaces/<interface>/resolv.conf instead.'
resolv_conf=/etc/resolv.conf
# These interfaces will always be processed first.
interface_order='lo lo[0-9]* lo.*'
# These interfaces will be processed next, unless they have a metrthost.
dynamthost_order='tap[0-9]* tun[0-9]* vpn vpn[0-9]* wg[0-9]* ppp[0-9]* ippp[0-9]*'
#Configuration files for named subscriber.
named_zones=/var/lib/bind/etc/resolvconf-zones.conf
named_options=/var/lib/bind/etc/resolvconf-options.conf
#Configuration files for dnsmasq subscriber.
dnsmasq_conf=/etc/dnsmasq.conf.d/60-resolvconf
dnsmasq_resolv=/etc/resolv.conf.dnsmasq
name_servers=127.0.0.1
# vim /etc/resolvconf.conf
# cat /etc/resolvconf.conf
# Configuration for resolvconf(8)
# See resolvconf.conf(5) for details
resolv_conf_head='# Do not edit manually, use\n# /etc/net/ifaces/<interface>/resolv.conf instead.'
resolv_conf=/etc/resolv.conf
# These interfaces will always be processed first.
#interface_order='lo lo[0-9]* lo.*'
interface_order='lo lo[0-9]* lo.* eth0'
search_domains=thost.ru
# These interfaces will be processed next, unless they have a metrthost.
dynamthost_order='tap[0-9]* tun[0-9]* vpn vpn[0-9]* wg[0-9]* ppp[0-9]* ippp[0-9]*'
#Configuration files for named subscriber.
named_zones=/var/lib/bind/etc/resolvconf-zones.conf
named_options=/var/lib/bind/etc/resolvconf-options.conf
#Configuration files for dnsmasq subscriber.
dnsmasq_conf=/etc/dnsmasq.conf.d/60-resolvconf
dnsmasq_resolv=/etc/resolv.conf.dnsmasq
#name_servers=127.0.0.1
# resolvconf -u
# cat /etc/resolv.conf
# Generated by resolvconf
# Do not edit manually, use
# /etc/net/ifaces/<interface>/resolv.conf instead.
search thost.ru
nameserver IpAddr1
...
nameserver 8.8.8.8
# hostname
thost1.thost.ru
# dig _kerberos._udp.thost.ru SRV | grep ^_kerberos
_kerberos._udp.thost.ru. 600 IN SRV 0 100 88 M-1.thost.ru.
...
_kerberos._udp.thost.ru. 600 IN SRV 0 100 88 T-1.thost.ru.
# dig _kerberos._tcp.thost.ru SRV | grep ^_kerberos
_kerberos._tcp.thost.ru. 600 IN SRV 0 100 88 M-c.thost.ru.
...
_kerberos._tcp.thost.ru. 600 IN SRV 0 100 88 T-1.thost.ru.
# cat /etc/krb5.conf | grep default_realm
default_realm = thost.ru
# default_realm = EXAMPLE.COM
# cat /etc/krb5.conf | grep dns_lookup_realm
dns_lookup_realm = false
# cat /etc/krb5.conf | grep dns_lookup_kdc
dns_lookup_kdc = true
# exit
$ ssh -X tuser@thost1
# kinit tuser
# klist
Tthostket cache: KEYRING:persistent:0:krb_ccache_CCjHpN1
Default principal: a-r@thost.ru
Valid starting       Expires              Servthoste principal
10.08.2022 12:30:34  10.08.2022 22:30:34  krbtgt/thost.ru@thost.ru
    renew until 17.08.2022 12:30:32
# apt-get install samba-client
# cat /etc/samba/smb.conf | grep realm
    realm = thost.ru
# cat /etc/samba/smb.conf | grep workgroup
    workgroup = thost
# cat /etc/samba/smb.conf | grep netbios
    netbios name = thost1
# cat /etc/samba/smb.conf | grep security
    security = ads
# cat /etc/samba/smb.conf | grep method
    kerberos method = system keytab
# cat /etc/samba/smb.conf | grep idmap
        idmap config * : range = 200000-2000200000
        idmap config * : backend = sss
# vim /etc/samba/smb.conf
# cat /etc/samba/smb.conf | grep idmap
        idmap config * : range = 200000-2000200000
;        idmap config * : backend = sss
    idmap config * : backend = tdb
# testpathost
Load smb config files from /etc/samba/smb.conf
Loaded servthostes file OK.
Weak crypto is allowed
Server role: ROLE_DOMAIN_MEMBER
Press enter to see a dump of your servthoste definitions
# Global parameters
[global]
    kerberos method = system keytab
    machine password timeout = 0
    realm = thost.ru
    security = ADS
    template homedir = /home/thost.ru/%U
    template shell = /bin/bash
    winbind use default domain = Yes
    workgroup = thost
    idmap config * : range = 200000-2000200000
    idmap config * : backend = tdb
[share]
    comment = Commonplace
    path = /srv/share
    read only = No
[homes]
    browseable = No
    comment = Home Directory for '%u'
    read only = No
# net ads join -U tuser
Enter tuser's password:
Using short domain name -- thost
Joined 'thost1' to dns domain 'thost.ru'
No DNS domain configured for thost1. Unable to perfothost DNS Update.
DNS update failed: NT_STATUS_INVALID_PARAMETER
# cat /etc/hosts
127.0.0.1   localhost.localdomain localhost
# vim /etc/hosts
# cat /etc/hosts
127.0.0.1   localhost.localdomain localhost
127.0.0.1   thost1.thost.ru thost1
# net ads join -U tuser
Enter tuser's password:
Using short domain name -- thost
Joined 'thost1' to dns domain 'thost.ru'
kerberos_kinit_password thost1$@thost.ru failed: Preauthentthostation failed
DNS update failed: kinit failed: Preauthentthostation failed
# vim /etc/hosts
# cat /etc/hosts
127.0.0.1   thost1.thost.ru thost1
# net ads join -U tuser
Enter tuser's password:
Using short domain name -- thost
Joined 'thost1' to dns domain 'thost.ru'
# klist -k -e
Keytab name: FILE:/etc/krb5.keytab
KVNO Principal
---- --------------------------------------------------------------------------
9 host/thost1.thost.ru@thost.ru (aes256-cts-hmac-sha1-96)
9 host/thost1@thost.ru (aes256-cts-hmac-sha1-96)
9 host/thost1.thost.ru@thost.ru (aes128-cts-hmac-sha1-96)
9 host/thost1@thost.ru (aes128-cts-hmac-sha1-96)
9 host/thost1.thost.ru@thost.ru (DEPRECATED:arcfour-hmac)
9 host/thost1@thost.ru (DEPRECATED:arcfour-hmac)
9 thost1$@thost.ru (aes256-cts-hmac-sha1-96)
9 thost1$@thost.ru (aes128-cts-hmac-sha1-96)
9 thost1$@thost.ru (DEPRECATED:arcfour-hmac)
8 host/thost1.thost.ru@thost.ru (aes256-cts-hmac-sha1-96)
8 host/thost1@thost.ru (aes256-cts-hmac-sha1-96)
8 host/thost1.thost.ru@thost.ru (aes128-cts-hmac-sha1-96)
8 host/thost1@thost.ru (aes128-cts-hmac-sha1-96)
8 host/thost1.thost.ru@thost.ru (DEPRECATED:arcfour-hmac)
8 host/thost1@thost.ru (DEPRECATED:arcfour-hmac)
8 thost1$@thost.ru (aes256-cts-hmac-sha1-96)
8 thost1$@thost.ru (aes128-cts-hmac-sha1-96)
8 thost1$@thost.ru (DEPRECATED:arcfour-hmac)
# apt-get install sssd-ad
# cat /etc/sssd/sssd.conf
[sssd]
config_file_version = 2
servthostes = nss, pam
# Managed by system facility command:
## control sssd-drop-privileges unprivileged|privileged|default
user = _sssd
# SSSD will not start if you do not configure any domains.
domains = thost.ru
[nss]
[pam]
[domain/thost.ru]
id_provider = ad
auth_provider = ad
chpass_provider = ad
access_provider = ad
default_shell = /bin/bash
fallback_homedir = /home/%d/%u
debug_level = 0
; cache_credentials = false
ad_gpo_ignore_unreadable = true
ad_gpo_access_control = pethostissive
ad_update_samba_machine_account_password = true
# vim /etc/sssd/sssd.conf
# cat /etc/sssd/sssd.conf
[sssd]
config_file_version = 2
servthostes = nss, pam
# Managed by system facility command:
## control sssd-drop-privileges unprivileged|privileged|default
#user = _sssd
user=root
# SSSD will not start if you do not configure any domains.
domains = thost.ru
[nss]
[pam]
[domain/thost.ru]
id_provider = ad
auth_provider = ad
chpass_provider = ad
access_provider = ad
;ldap_id_mapping = False
default_shell = /bin/bash
fallback_homedir = /home/%d/%u
debug_level = 0
;use_fully_qualified_names = True
; cache_credentials = True
ad_gpo_ignore_unreadable = true
ad_gpo_access_control = pethostissive
ad_update_samba_machine_account_password = true
# grep sss /etc/nsswitch.conf
passwd: files sss
shadow: tcb files sss
group: files [SUCCESS=merge] sss role
# control system-auth sss
# servthoste sssd status
active
# servthoste sssd start
# getent passwd tuser
tuser:*:1-9:1-3:в-н:/home/thost.ru/tuser:/bin/bash
# id tuser
uid=1-9(tuser) gid=1-3(пользователи домена) группы=1-3(пользователи домена),1-8(администраторы dhcp),1-0(I-s),11-0(пользователи филиалы),1-1(tusert_users),1-9(i-n)
# net ads info
LDAP server: IpAddr2
LDAP server name: MOW-1.thost.ru
Realm: thost.ru
Bind Path: dc=thost,dc=RU
LDAP port: 389
Server time: Ср, 10 авг 2022 13:08:06 +08
KDC server: IpAddr2
Server time offset: 0
Last machine account password change: Ср, 10 авг 2022 12:50:51 +08
# net ads testjoin
Join is OK
# cat /etc/lightdm/lightdm.conf | grep greeter-hide-
# greeter-hide-users = True to hide the user list
#greeter-hide-users=false
greeter-hide-users = true
# cat /etc/lightdm/lightdm-gtk-greeter.conf | grep show-language
show-language-selector = false
# cat /etc/lightdm/lightdm-gtk-greeter.conf | grep show-indthostators
# vim /etc/lightdm/lightdm-gtk-greeter.conf
# cat /etc/lightdm/lightdm-gtk-greeter.conf | grep show-indthostators
show-indthostators=~a11y;~power;~session;~language
# vim /etc/lightdm/lightdm-gtk-greeter.conf
# cat /etc/lightdm/lightdm-gtk-greeter.conf | grep enter-
enter-username = true
# reboot
$ ssh -X tuser@thost1
Decision:
$ su -
# apt-get install libnss-role
# groupadd -r localadmins
groupadd: группа «localadmins» уже существует
# groupadd -r remote
groupadd: группа «remote» уже существует
# control sshd-allow-groups enabled
# sed -i 's/AllowGroups.*/AllowGroups = remote/' /etc/openssh/sshd_config
# roleadd users cdwriter cdrom audio proc radio camera floppy xgrp scanner uucp fuse
# roleadd localadmins wheel remote vboxusers
# roleadd 'Domain Users' users
Error 156: No such group
# roleadd 'Пользователи домена' users
# roleadd 'Администраторы домена' localadmins
# rolelst
users:cdwriter,cdrom,audio,proc,radio,camera,floppy,xgrp,scanner,uucp,fuse,video,vboxusers,vboxadd
localadmins:wheel,remote,vboxusers,vboxadd
пользователи домена:users
администраторы домена:localadmins
powerusers:remote,vboxadd,vboxusers
vboxadd:vboxsf
# id tuser
uid=1-9(tuser) gid=1-3(пользователи домена) группы=1-3(пользователи домена),11-0(пользователи филиалы),1-9(i-n),1-0(I-s),1-1(tusert_users),1-8(администраторы dhcp),100(users),80(cdwriter),22(cdrom),81(audio),19(proc),83(radio),440(camera),71(floppy),466(xgrp),467(scanner),14(uucp),483(fuse),488(video),481(vboxusers),455(vboxadd),454(vboxsf)
# roleadd 'I-s' localadmins
# roleadd 'I-s' wheel
# rolelst
users:cdwriter,cdrom,audio,proc,radio,camera,floppy,xgrp,scanner,uucp,fuse,video,vboxusers,vboxadd
localadmins:wheel,remote,vboxusers,vboxadd
пользователи домена:users
администраторы домена:localadmins
I-s:localadmins
powerusers:remote,vboxadd,vboxusers
vboxadd:vboxsf
# exit
$ exit
$ ssh -X tuser@thost1
$ su -
# id tuser
uid=1-9(tuser) gid=1-3(пользователи домена) группы=1-3(пользователи домена),11-0(пользователи филиалы),1-9(i-n),1-0(I-s),1-1(tusert_users),1-8(администраторы dhcp),100(users),80(cdwriter),22(cdrom),81(audio),19(proc),83(radio),440(camera),71(floppy),466(xgrp),467(scanner),14(uucp),483(fuse),488(video),481(vboxusers),455(vboxadd),454(vboxsf),101(localadmins),10(wheel),110(remote)
Task:
Администрирование локальных, виртуальных и облачных серверов. Добавить сетевые папки
Decision:
# apt-get install autofs
# vim /etc/auto.master
# cat /etc/auto.master
# Fothostat of this file:
# mountpoint map options
# For details of the fothostat look at autofs(8).
/mnt/auto   /etc/auto.tab   -t 5
/mnt/net    /etc/auto.avahi -t 120
/mnt/.tdirectory  /etc/auto.samba --ghost
# vim /etc/auto.samba
# cat /etc/auto.samba
s    -fstype=cifs,multiuser,cruid=$USER,sec=krb5,domain=thost.ru,vers=1.0 ://thost/tdirectory1
o    -fstype=cifs,multiuser,cruid=$USER,sec=krb5,domain=thost.ru,vers=1.0 ://thost/tdirectory2
# systemctl enable autofs
# systemctl start autofs
# ls -la /mnt/.tdirectory/
drwxr-xr-x 4 root root    0 авг 11 14:09 .
drwxr-xr-x 5 root root 4096 авг 11 14:09 ..
d????????? ? ?    ?       ?            ? o
d????????? ? ?    ?       ?            ? s
Task:
Администрирование локальных, виртуальных и облачных серверов. Creating a Network Bridge interface
Decision:
# mkdir /etc/net/ifaces/tethernet1
# cp /etc/net/ifaces/tethernet/* /etc/net/ifaces/tethernet1
# rm -f /etc/net/ifaces/tethernet/{i,r}*
# ls /etc/net/ifaces/tethernet1/
ipv4address  options  resolv.conf
# cat /etc/net/ifaces/tethernet1/options
BOOTPROTO=dhcp
TYPE=eth
NM_CONTROLLED=yes
DISABLED=yes
CONFIG_WIRELESS=no
SYSTEMD_BOOTPROTO=dhcp4
CONFIG_IPV4=yes
SYSTEMD_CONTROLLED=no
# vim /etc/net/ifaces/tethernet1/options
# ls /etc/net/ifaces/
default  tethernet  lo  unknown  tethernet1
# vim /etc/net/ifaces/tethernet1/options
# vim /etc/net/ifaces/tethernet1/options
# cat /etc/net/ifaces/tethernet1/options
BOOTPROTO=static
CONFIG_WIRELESS=no
CONFIG_IPV4=yes
HOST='tethernet'
ONBOOT=yes
TYPE=bri
# ls /etc/net/ifaces/tethernet/
ipv4address  options  resolv.conf
# service network restart
Task:
Администрирование базы данных. Настройка сервера Postgresql+Pgadmin
Decision:
# apt-get update
# apt-get install postgresql12-server
# /etc/init.d/postgresql initdb
# systemctl start postgresql
# systemctl enable postgresql
# pg_isready
Decision:
# psql -U postgres
postgres=# CREATE USER tbuser WITH PASSWORD 'tbpassword';
postgres=# CREATE DATABASE tbbase;
postgres=# GRANT ALL PRIVILEGES ON DATABASE tbbase to tbuser;
postgres=# psql -U postgres -c "\l+"
                                                                         Список баз данных
     Имя     | Владелец | Кодировка | LC_COLLATE  |  LC_CTYPE   |     Права доступа     | Размер  | Табл. пространство |                  Опис
ание                  
-------------+----------+-----------+-------------+-------------+-----------------------+---------+--------------------+----------------------
----------------------
 tbbase | postgres | UTF8      | ru_RU.UTF-8 | ru_RU.UTF-8 | =Tc/postgres         +| 8041 kB | pg_default         |
             |          |           |             |             | postgres=CTc/postgres+|         |                    |
             |          |           |             |             | tbuser=CTc/postgres    |         |                    |
 postgres    | postgres | UTF8      | ru_RU.UTF-8 | ru_RU.UTF-8 |                       | 8185 kB | pg_default         | default administrativ
e connection database
...
postgres=# \c tbbase
tbbase=# GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "tbuser";
tbbase=# ALTER DATABASE tbbase OWNER TO tbuser;
tbbase=# \q
Task:
Администрирование базы данных. Сделаем так, чтобы с клиентской машины Redos мы могли подключаться к серверу AltLinux удаленно
Decision:
# su - postgres -c "psql -c 'SHOW config_file;'"
             config_file             
-------------------------------------
 /var/lib/pgsql/data/postgresql.conf
(1 строка)
# echo "listen_addresses = 'IpAddr3, IpAddr2, thost1'" >> /var/lib/pgsql/data/postgresql.conf
# cat /var/lib/pgsql/data/pg_hba.conf
...
# "local" is for Unix domain socket connections only
local   all             all                                     trust
# IPv4 local connections:
host    all             all             127.0.0.1/32            trust
...
# vim /var/lib/pgsql/data/pg_hba.conf
# cat /var/lib/pgsql/data/pg_hba.conf | grep '10.38.'
# "local" is for Unix domain socket connections only
local   all             all                                     trust
# IPv4 local connections:
host    tbbase            tbuser             IpAddr2/21                  md5
host    all             all             127.0.0.1/32            trust
# systemctl restart postgresql
# systemctl status postgresql
$ psql -d tbbase -U tbuser -h thost1
Task:
Администрирование базы данных. Для работы с базой в графическом интерфейсе установим Pgadmin
Decision:
# apt-get install pgadmin3
# pgadmin3 &
    add server - name - tbuser - host - thost1- password - tbpassword - ok
# dnf install postgresql-server
# postgresql-setup initdb
# systemctl enable postgresql
# systemctl start postgresql
# pg_isready
$ psql -d tbbase -U tbuser -h thost1
tbbase=> \du
                                          Список ролей
 Имя роли |                                Атрибуты                                 | Член ролей
----------+-------------------------------------------------------------------------+------------
 tbuser   |                                                                         | {}
 postgres | Суперпользователь, Создаёт роли, Создаёт БД, Репликация, Пропускать RLS | {}
Decision:
$ sudo dnf install pgadmin4 pgadmin4-qt
$ pgadmin4-qt &
    root's password - add server - name - tbuser - host - thost1- password - tbpassword - ok
Task:
Разработка базы данных. Разработать схему базы данных Инвентаризация
Decision:

 

 

Task:
Разработка базы данных. Создать таблицы. В первой таблице отметим в каких зданиях находятся кабинеты.
Decision:
CREATE TABLE offices (
  id SERIAL PRIMARY KEY,
  office VARCHAR,
  building VARCHAR
);
INSERT INTO offices (office, building)
VALUES ('1', 'Улица1'),
('2', 'Улица1'),
('3', 'Улица1'),
('4', 'Улица2'),
('5', 'Улица2'),
('6', 'Улица2'),
('7', 'Улица2'),
('8', 'Улица2'),
('9', 'Улица2');
SELECT * FROM offices;
+====+========+===============+
| id | office | building      |
+====+========+===============+
| 1  | 1     | Улица1        |
+----+--------+---------------+
| 2  | 2     | Улица1        |
+----+--------+---------------+
| 3  | 3     | Улица1        |
+----+--------+---------------+
| 4  | 4    | Улица2        |
+----+--------+---------------+
| 5  | 5    | Улица2        |
+----+--------+---------------+
| 6  | 6    | Улица2        |
+----+--------+---------------+
| 7  | 7    | Улица2        |
+----+--------+---------------+
| 8  | 8    | Улица2        |
+----+--------+---------------+
| 9  | 9    | Улица2        |
+----+--------+---------------+
Task:
Разработка базы данных. Вторая таблица отвечает за названия оборудований
Decision:
CREATE TABLE devices (
  id SERIAL PRIMARY KEY,
  device VARCHAR,
  title VARCHAR
);
INSERT INTO devices (device, title)
VALUES ('Atc', 'Panasonic kx-tda100ru'),
('Bидеокамера белая', NULL),
('Интерактиная доска с короткофокусным проектором', 'Promethean activeboard i78 mount dlp'),
('Колонки', 'Sven sps-605'),
('Компьютер', 'Nuc'),
('Программно-аапаратный комплекс', 'Vipnet coordinator hw 1000'),
('Сетевой фильтр', 'Sven platinum'),
('Маршрутизатор', 'Mtuserrottuser'),
('Сетевой фильтр', 'Makel с заземлением mpg 137'),
('Роутер', 'Mtuserrottuser browder rb9516'),
('Dvd-плеер', 'Pioner dv-310-k'),
('Акустическая система', 'Electrovoice'),
('Коммутатор', 'Kramer'),
('Масштабатор видео и графики', 'Kramer'),
('Микрофон делегата настольный', NULL),
('Микрофонная стойка', 'Qutuser lok a300'),
('Мультимедийный проектор', 'Epson eb-965h'),
('Пульт микшерский', 'Soundcraft epm8'),
('Система вентилляции и кондиционирования', NULL),
('Эран моторизированный', 'Projecta compact electrol'),
('Ноутбук', 'Acer aspire as5560g-4333g32mn'),
('Bидеокамера серая', NULL),
('Микрофон', 'Shure sh58'),
('Акустическая система', 'Mackie sr1530z'),
('Сетевой фильтр', 'Sven optima'),
('Сетевой фильтр', 'Surge protector'),
('Мультимедийный проектор', 'Optima ex612'),
('Экран настенный', 'Screenmedia economy-p'),
('Колонки', 'Logitech s120'),
('Компьютер', 'Nuc mini pc kit'),
('Сетевой фильтр', 'Pc pet'),
('Интерактиная доска', '80'),
('Короткофокусный проектор', 'Benq'),
('Колонки', 'Microlab solo 1'),
('Акустическая система', 'Eurosound eg-26w 2*6'),
('Микшерный пульт', 'Eurosound compact-802'),
('Планшет графический', 'Wacom pl-1600'),
('Телевизор плазменный', 'Lg 50pa6500'),
('Усилитель мощности', 'Eurosound xz-400'),
('8 port video splitter', NULL);
SELECT * FROM devices;
+====+=================================================+======================================+
| id | device                                          | title                                |
+====+=================================================+======================================+
| 1  | Atc                                             | Panasonic kx-tda100ru                |
+----+-------------------------------------------------+--------------------------------------+
| 2  | Bидеокамера белая                               | (null)                               |
+----+-------------------------------------------------+--------------------------------------+
| 3  | Интерактиная доска с короткофокусным проектором | Promethean activeboard i78 mount dlp |
+----+-------------------------------------------------+--------------------------------------+
| 4  | Колонки                                         | Sven sps-605                         |
+----+-------------------------------------------------+--------------------------------------+
| 5  | Компьютер                                       | Nuc                                  |
+----+-------------------------------------------------+--------------------------------------+
| 6  | Программно-аапаратный комплекс                  | Vipnet coordinator hw 1000           |
+----+-------------------------------------------------+--------------------------------------+
| 7  | Сетевой фильтр                                  | Sven platinum                        |
+----+-------------------------------------------------+--------------------------------------+
| 8  | Маршрутизатор                                   | Mtuserrottuser                       |
+----+-------------------------------------------------+--------------------------------------+
| 9  | Сетевой фильтр                                  | Makel с заземлением mpg 137          |
+----+-------------------------------------------------+--------------------------------------+
| 10 | Роутер                                          | Mtuserrottuser browder rb9516        |
+----+-------------------------------------------------+--------------------------------------+
| 11 | Dvd-плеер                                       | Pioner dv-310-k                      |
+----+-------------------------------------------------+--------------------------------------+
| 12 | Акустическая система                            | Electrovoice                         |
+----+-------------------------------------------------+--------------------------------------+
| 13 | Коммутатор                                      | Kramer                               |
+----+-------------------------------------------------+--------------------------------------+
| 14 | Масштабатор видео и графики                     | Kramer                               |
+----+-------------------------------------------------+--------------------------------------+
| 15 | Микрофон делегата настольный                    | (null)                               |
+----+-------------------------------------------------+--------------------------------------+
| 16 | Микрофонная стойка                              | Qutuser lok a300                     |
+----+-------------------------------------------------+--------------------------------------+
| 17 | Мультимедийный проектор                         | Epson eb-965h                        |
+----+-------------------------------------------------+--------------------------------------+
| 18 | Пульт микшерский                                | Soundcraft epm8                      |
+----+-------------------------------------------------+--------------------------------------+
| 19 | Система вентилляции и кондиционирования         | (null)                               |
+----+-------------------------------------------------+--------------------------------------+
| 20 | Эран моторизированный                           | Projecta compact electrol            |
+----+-------------------------------------------------+--------------------------------------+
| 21 | Ноутбук                                         | Acer aspire as5560g-4333g32mn        |
+----+-------------------------------------------------+--------------------------------------+
| 22 | Bидеокамера серая                               | (null)                               |
+----+-------------------------------------------------+--------------------------------------+
| 23 | Микрофон                                        | Shure sh58                           |
+----+-------------------------------------------------+--------------------------------------+
| 24 | Акустическая система                            | Mackie sr1530z                       |
+----+-------------------------------------------------+--------------------------------------+
| 25 | Сетевой фильтр                                  | Sven optima                          |
+----+-------------------------------------------------+--------------------------------------+
| 26 | Сетевой фильтр                                  | Surge protector                      |
+----+-------------------------------------------------+--------------------------------------+
| 27 | Мультимедийный проектор                         | Optima ex612                         |
+----+-------------------------------------------------+--------------------------------------+
| 28 | Экран настенный                                 | Screenmedia economy-p                |
+----+-------------------------------------------------+--------------------------------------+
| 29 | Колонки                                         | Logitech s120                        |
+----+-------------------------------------------------+--------------------------------------+
| 30 | Компьютер                                       | Nuc mini pc kit                      |
+----+-------------------------------------------------+--------------------------------------+
| 31 | Сетевой фильтр                                  | Pc pet                               |
+----+-------------------------------------------------+--------------------------------------+
| 32 | Интерактиная доска                              | 80                                   |
+----+-------------------------------------------------+--------------------------------------+
| 33 | Короткофокусный проектор                        | Benq                                 |
+----+-------------------------------------------------+--------------------------------------+
| 34 | Колонки                                         | Microlab solo 1                      |
+----+-------------------------------------------------+--------------------------------------+
| 35 | Акустическая система                            | Eurosound eg-26w 2*6                 |
+----+-------------------------------------------------+--------------------------------------+
| 36 | Микшерный пульт                                 | Eurosound compact-802                |
+----+-------------------------------------------------+--------------------------------------+
| 37 | Планшет графический                             | Wacom pl-1600                        |
+----+-------------------------------------------------+--------------------------------------+
| 38 | Телевизор плазменный                            | Lg 50pa6500                          |
+----+-------------------------------------------------+--------------------------------------+
| 39 | Усилитель мощности                              | Eurosound xz-400                     |
+----+-------------------------------------------------+--------------------------------------+
| 40 | 8 port video splitter                           | (null)                               |
+----+-------------------------------------------------+--------------------------------------+
Task:
Разработка базы данных. Третья таблица отвечает за инвентарные номера оборудований, кабинетов и даты изменения
Decision:
CREATE TABLE inventories (
  id SERIAL PRIMARY KEY,
  inventory VARCHAR,
  device_id INT REFERENCES devices(id),
  office_id INT REFERENCES offices(id),                                               
  quantity INT,                                                   
  date TIMESTAMP
);
INSERT INTO inventories (inventory, device_id, office_id, quantity, date)
VALUES ('457', '1', '1', '1', '2017-12-12 12:12:12'),
(NULL, '2', '1', '1', '2017-12-12 12:12:12'),
...
('750', '30', '6', '1', '2021-09-12 12:12:12'),
('707', '17', '6', '1', '2020-05-12 12:12:12'),
('008', '4', '6', '1', '2020-09-12 12:12:12'),
('010', '34', '9', '1', '2017-12-12 12:12:12'),
('650', '5', '9', '1', '2017-12-12 12:12:12'),
('556', '33', '9', '1', '2017-12-12 12:12:12'),
('426', '32', '9', '1', '2017-12-12 12:12:12');
SELECT * FROM inventories;
+====+=============+===========+===========+==========+=====================+
| id | inventory   | device_id | office_id | quantity | date                |
+====+=============+===========+===========+==========+=====================+
| 1  | 457         | 1         | 1         | 1        | 2017-12-12 12:12:12 |
+----+-------------+-----------+-----------+----------+---------------------+
| 2  | (null)      | 2         | 1         | 1        | 2017-12-12 12:12:12 |
+----+-------------+-----------+-----------+----------+---------------------+
...
+----+-------------+-----------+-----------+----------+---------------------+
| 62 | 750         | 30        | 6         | 1        | 2021-09-12 12:12:12 |
+----+-------------+-----------+-----------+----------+---------------------+
| 63 | 707         | 17        | 6         | 1        | 2020-05-12 12:12:12 |
+----+-------------+-----------+-----------+----------+---------------------+
| 64 | 008         | 4         | 6         | 1        | 2020-09-12 12:12:12 |
+----+-------------+-----------+-----------+----------+---------------------+
| 65 | 010         | 34        | 9         | 1        | 2017-12-12 12:12:12 |
+----+-------------+-----------+-----------+----------+---------------------+
| 66 | 650         | 5         | 9         | 1        | 2017-12-12 12:12:12 |
+----+-------------+-----------+-----------+----------+---------------------+
| 67 | 556         | 33        | 9         | 1        | 2017-12-12 12:12:12 |
+----+-------------+-----------+-----------+----------+---------------------+
| 68 | 426         | 32        | 9         | 1        | 2017-12-12 12:12:12 |
+----+-------------+-----------+-----------+----------+---------------------+
Task:
Написание Sql запросов. Мне нужно вывести информацию, где в первом столбце будет инвентарные номера, во втором столбце, устройство и его название, а в третьем столбце вывести кабинеты, где находятся те самые оборудования
Decision:
SELECT inventory, device, title, office
FROM inventories
INNER JOIN devices
ON inventories.device_id = devices.id
INNER JOIN offices
ON inventories.office_id = offices.id
WHERE office_id='6';
+=============+=========================+=================+========+
| inventory   | device                  | title           | office |
+=============+=========================+=================+========+
| 008         | Колонки                 | Sven sps-605    | 6      |
+-------------+-------------------------+-----------------+--------+
| 707         | Мультимедийный проектор | Epson eb-965h   | 6      |
+-------------+-------------------------+-----------------+--------+
| 750         | Компьютер               | Nuc mini pc kit | 6      |
+-------------+-------------------------+-----------------+--------+
Task:
Написание Sql запросов. Заметил ошибку в таблице, есть лишнее оборудование в кабинете. его на самом деле нету в кабинете и значит не должно быть в таблице.
Decision:
DELETE FROM inventories
WHERE id='64';
SELECT inventory, device, title, office
FROM inventories
INNER JOIN devices
ON inventories.device_id = devices.id
INNER JOIN offices
ON inventories.office_id = offices.id
WHERE office_id='6';
+===========+=========================+=================+========+
| inventory | device                  | title           | office |
+===========+=========================+=================+========+
| 707       | Мультимедийный проектор | Epson eb-965h   | 6      |
+-----------+-------------------------+-----------------+--------+
| 750       | Компьютер               | Nuc mini pc kit | 6      |
+-----------+-------------------------+-----------------+--------+
SELECT * FROM inventories;
+====+=============+===========+===========+==========+=====================+
| id | inventory   | device_id | office_id | quantity | date                |
+====+=============+===========+===========+==========+=====================+
| 1  | 457         | 1         | 1         | 1        | 2017-12-12 12:12:12 |
+----+-------------+-----------+-----------+----------+---------------------+
| 2  | (null)      | 2         | 1         | 1        | 2017-12-12 12:12:12 |
+----+-------------+-----------+-----------+----------+---------------------+
...
+----+-------------+-----------+-----------+----------+---------------------+
| 62 | 750         | 30        | 6         | 1        | 2021-09-12 12:12:12 |
+----+-------------+-----------+-----------+----------+---------------------+
| 63 | 707         | 17        | 6         | 1        | 2020-05-12 12:12:12 |
+----+-------------+-----------+-----------+----------+---------------------+
| 65 | 010         | 34        | 9         | 1        | 2017-12-12 12:12:12 |
+----+-------------+-----------+-----------+----------+---------------------+
| 66 | 650         | 5         | 9         | 1        | 2017-12-12 12:12:12 |
+----+-------------+-----------+-----------+----------+---------------------+
| 67 | 556         | 33        | 9         | 1        | 2017-12-12 12:12:12 |
+----+-------------+-----------+-----------+----------+---------------------+
| 68 | 426         | 32        | 9         | 1        | 2017-12-12 12:12:12 |
+----+-------------+-----------+-----------+----------+---------------------+
Task:
Написание Sql запросов. Появилось новое обрудование, и нужно его внести в таблицу.
Decision:
INSERT INTO inventories (inventory, device_id, office_id, quantity, date)
VALUES ('testinv1', '39', '1', '1', '2017-12-12 12:12:12');
SELECT * FROM inventories;
+====+=============+===========+===========+==========+=====================+
| id | inventory   | device_id | office_id | quantity | date                |
+====+=============+===========+===========+==========+=====================+
| 1  | 457         | 1         | 1         | 1        | 2017-12-12 12:12:12 |
+----+-------------+-----------+-----------+----------+---------------------+
| 2  | (null)      | 2         | 1         | 1        | 2017-12-12 12:12:12 |
+----+-------------+-----------+-----------+----------+---------------------+
...
+----+-------------+-----------+-----------+----------+---------------------+
| 68 | 426         | 32        | 9         | 1        | 2017-12-12 12:12:12 |
+----+-------------+-----------+-----------+----------+---------------------+
| 69 | testinv1    | 39        | 1         | 1        | 2017-12-12 12:12:12 |
+----+-------------+-----------+-----------+----------+---------------------+
Task:
Написание Sql запросов. в предыдущей задаче не верные данные внес в таблицу, нужно подкорректировать.
Decision:
UPDATE inventories
SET inventory='testinv2', office_id='9'
WHERE id='69';
SELECT * FROM inventories;
+====+=============+===========+===========+==========+=====================+
| id | inventory   | device_id | office_id | quantity | date                |
+====+=============+===========+===========+==========+=====================+
| 1  | 457         | 1         | 1         | 1        | 2017-12-12 12:12:12 |
+----+-------------+-----------+-----------+----------+---------------------+
| 2  | (null)      | 2         | 1         | 1        | 2017-12-12 12:12:12 |
+----+-------------+-----------+-----------+----------+---------------------+
...
+----+-------------+-----------+-----------+----------+---------------------+
| 68 | 426         | 32        | 9         | 1        | 2017-12-12 12:12:12 |
+----+-------------+-----------+-----------+----------+---------------------+
| 69 | testinv2    | 39        | 9         | 1        | 2017-12-12 12:12:12 |
+----+-------------+-----------+-----------+----------+---------------------+
SELECT inventory, device, title, office
FROM inventories
INNER JOIN devices
ON inventories.device_id = devices.id
INNER JOIN offices
ON inventories.office_id = offices.id
WHERE office_id='9';
+=============+==========================+==================+========+
| inventory   | device                   | title            | office |
+=============+==========================+==================+========+
| 650         | Компьютер                | Nuc              | 9      |
+-------------+--------------------------+------------------+--------+
| 426         | Интерактиная доска       | 80               | 9      |
+-------------+--------------------------+------------------+--------+
| 556         | Короткофокусный проектор | Benq             | 9      |
+-------------+--------------------------+------------------+--------+
| 010         | Колонки                  | Microlab solo 1  | 9      |
+-------------+--------------------------+------------------+--------+
| testinv2    | Усилитель мощности       | Eurosound xz-400 | 9      |
+-------------+--------------------------+------------------+--------+
Source: 
# https://www.altlinux.org/ActiveDirectory/Login#%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BF%D0%B0%D0%BA%D0%B5%D1%82%D0%BE%D0%B2 # https://www.altlinux.org/SSSD/AD 
# https://www.altlinux.org/%D0%A1%D0%B5%D1%82%D0%B5%D0%B2%D0%BE%D0%B9_%D0%BC%D0%BE%D1%81%D1%82 
# https://www.altlinux.org/PostgreSQL#%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B8_%D0%BD%D0%B0%D1%87%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B7%D0%B0%D0%BF%D1%83%D1%81%D0%BA 
# https://www.tecmint.com/install-postgresql-and-pgadmin-in-ubuntu/ 
# https://o7planning.org/11353/install-pgadmin-on-ubuntu 
# https://redos.red-soft.ru/base/server-configuring/dbms/install-postgresql/?sphrase_id=53348 
# https://redos.red-soft.ru/base/server-configuring/dbms/pgadmin4/

 

2011-09-01 - 2018-05-30: Иркутский государственный университет, Иркутск. Должность: Информационные технологии и телекоммуникационные системы - Бакалавр / Электроника и наноэлектроника - Магистр / Информационная безопасность - Дополнительное образование. Дополнительная информация: Навыки - Html, Css, Windows, Виртуализация, Linux, Sql, Bash, Clouds, Python, Спутниковые радионавигационные системы, С++. Достижения: Для защиты магистерской диссертации по теме "Использование данных одночастотных приемников Спутниковых Радионавигационных Систем для коррекции модели ионосферы" разработал программу "Обработка и сортировка данных в файлах Rinex формата"

Show

Цель:
# Рассмотреть возможность использования одночастотных приёмников спутниковых радионавигационных систем (СРНС) для получения информации с целью оперативной коррекции её модели.
# Установить и настроить программные обеспечения для обработки и сортировки данных.
# Получить данные с одночастотного приемника СРНС.
# Описать формат файлов RINEX.
# Разработать программу, которая считывает файлы в формате Rinex и сортирует псевдодальности (ПД) от времени (эпохи) по каждому навигационному спутнику.
# Получить результаты.
Skills:
# Спутниковые радионаввигационные системы.
# Администрирование локальных, виртуальных и облачных серверов.
# Виртуализация.
# Разработка программы Обработка и сортировка данных в файлах Rinex формата.
Task:
Методика коррекции ионосферы по данному приёмнику СРНС.
# Спутниковые радионаввигационные системы.
Decision:
Рассмотрим возможность оценки вклада ионосферы в измерения псевдодальности (ПД) с помощью одночастотного приёмника ГЛОНАСС/GPS. Для этого будем считать, что координаты приемника x, y, z неизменны и известны с высокой точностью. ПД от i-го навигационного спутника (НС) с координатами xi, yi, zi определим как измеренную в свободном пространстве дальность D'i=сτ'i, отличающуюся от геометрической дальности (ГД) Di на неизвестную величину ρ: 

D'i=сτ'i определяется по разности моментов приема и передачи навигационного сигнала между временными шкалами НС и приемника. Если точность шкалы НС с учетом её коррекции достаточна для определения момента излучения, то из-за нестабильности шкалы приемника необходимо учитывать её мгновенный сдвиг относительно шкалы НС на неизвестную величину t' и ρ=ct'. В многоканальных одночастотных приемниках t' не зависит от i и значение ρ одинаково для всех НС в данный момент времени [6].
В реальных условиях результаты измерения ПД D''i отличаются от значения D'i из формулы (4.1) из-за влияния различных факторов на распространение навигационных сигналов. Основные ошибки, возникающие при этом, вызваны запаздыванием сигнала в ионосфере и тропосфере , а также погрешностями определения эфемерид . Другие ошибки хорошо компенсируются алгоритмами обработки сигналов. Например, влияние многолучевости значительно уменьшается усреднением данных на интервале 30 с и более, а релятивистские эффекты устраняются коррекцией навигационного сигнала [6].
Таким образом, ошибка измерения ПД в основном определяется следующими составляющими:

Отсюда можно найти вклад ионосферы в ошибку измерения ПД для i-го НС: 

Величина ρ в формуле (4.3) зависит от расхождения шкал времени НС и приемника и меняется в очень широких пределах. 
При решении навигационной задачи относительно времени, шкала приемника может быть привязана к шкале НС, но найденная при этом величина ρ' будет характеризовать эффективное значение с учетом других ошибок определения ПД, и в этом случае будет иметь смысл отклонения от некоторого среднего значения для всех НС, участвующих в навигационном решении [6].
Для устранения влияния нестабильности временнόй шкалы приемника построим разность ошибок ионосферы для i-го и j-го НС в один момент времени: 

Как видно, точность определения зависит от погрешностей определения эфемерид выбранных НС и разностей тропосферных задержек сигналов от них. обычно составляет единицы метров. Если из созвездия выбирать НС со «свежими» эфемеридами, то эта погрешность уменьшится до ~1 м. Применение постобработки и использование уточнённых эфемерид дает погрешность значительно меньше 1 м. Если предположить, что ошибки для двух НС независимы, а их величины примерно одинаковы, то общая ошибка из-за погрешностей задания эфемерид [6]:

Задержка в тропосфере приводит к ошибке в измерении ПД, которая хорошо компенсируется простыми моделями тропосферы. В нормальных условиях в тропосфере для углов места β > 5º и достижения погрешности после коррекции < 0.5 м можно воспользоваться формулой:

Здесь - задержка сигнала в тропосфере для зенитных НС, равная ~7 нс, что соответствует пути 2.1 м. Для увеличения точности коррекции можно применить модель Саастамойнена.
Таким образом, общая величина ошибки определения в благоприятных условиях составляет ~1÷2 м и вариации ионосферной задержки величиной ~10 и более метров могут быть определены одночастотным приемником ГНСС.
Task:
Adding the Ubuntu using wsl.
# Администрирование локальных, виртуальных и облачных серверов.
Decision:
PS S:\Github> Start-Process powershell -Verb runAs
PS C:\Windows\system32> wsl --list --online
PS C:\Windows\system32> wsl --install -d Ubuntu-22.04
PS C:\Windows\system32> Restart-Computer 
Task:
Установка виртуальной машины.
# Виртуализация. 
Decision:
root@kvmubuntu:/mnt/c/Windows/system32# dnf config-manager --add-repo=https://download.virtualbox.org/virtualbox/rpm/el/virtualbox.repo
root@kvmubuntu:/mnt/c/Windows/system32# rpm --import https://www.virtualbox.org/download/oracle_vbox.asc
root@kvmubuntu:/mnt/c/Windows/system32# dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
root@kvmubuntu:/mnt/c/Windows/system32# dnf install binutils kernel-devel kernel-headers libgomp make patch gcc glibc-headers glibc-devel dkm
root@kvmubuntu:/mnt/c/Windows/system32# dnf search virtualbox
root@kvmubuntu:/mnt/c/Windows/system32# dnf install VirtualBox-7.0
root@kvmubuntu:/mnt/c/Windows/system32# usermod -aG vboxusers $USER
root@kvmubuntu:/mnt/c/Windows/system32# newgrp vboxusers
root@kvmubuntu:/mnt/c/Windows/system32# wget https://download.virtualbox.org/virtualbox/7.0.10/Oracle_VM_VirtualBox_Extension_Pack-7.0.10-158379.vbox-extpack
root@kvmubuntu:/mnt/c/Windows/system32# VBoxManage extpack install Oracle_VM_VirtualBox_Extension_Pack-7.0.10-158379.vbox-extpack
Task:
Установка виртуальной машины Windows в Virtualbox.
# Виртуализация. 
Decision:
root@kvmubuntu:/mnt/c/Windows/system32# VBoxManage list ostypes
...
ID:     Windows2010_64
Description: Windows 2010 (64-bit)
Family ID: Windows
Family Desc: Microsoft Windows
64 bit:   true
...
root@kvmubuntu:/mnt/c/Windows/system32# VBoxManage createvm --name "Windows10" --ostype "Windows2010_64" --register --basefolder /vboximages/
root@kvmubuntu:/mnt/c/Windows/system32# vboxmanage modifyvm Windows10 --memory 4096 --vram 128
root@kvmubuntu:/mnt/c/Windows/system32# vboxmanage modifyvm Windows10 --nic1 bridged
root@kvmubuntu:/mnt/c/Windows/system32# vboxmanage createhd --filename /vboximages/Windows10/Windows10.vdi --size 75000 --format VDI 
root@kvmubuntu:/mnt/c/Windows/system32# vboxmanage storagectl Windows10 --name "SATA Controller" --add sata --controller IntelAhci
root@kvmubuntu:/mnt/c/Windows/system32# vboxmanage storageattach Windows10 --storagectl "SATA Controller" --port 0 --device 0 --type hdd --medium /vboximages/Windows10/Windows10.vdi
root@kvmubuntu:/mnt/c/Windows/system32# vboxmanage storagectl Windows10 --name "IDE Controller" --add ide --controller PIIX4
root@kvmubuntu:/mnt/c/Windows/system32# vboxmanage storageattach Windows10 --storagectl "IDE Controller" --port 1 --device 0 --type dvddrive --medium /iso/Windows10.iso
root@kvmubuntu:/mnt/c/Windows/system32# vboxmanage modifyvm Windows10 --boot1 dvd --boot2 disk --boot3 none --boot4 none
root@kvmubuntu:/mnt/c/Windows/system32# vboxmanage modifyvm Windows10 --vrde on
root@kvmubuntu:/mnt/c/Windows/system32# vboxmanage modifyvm Windows10 --vrdemulticon on --vrdeport 10001
root@kvmubuntu:/mnt/c/Windows/system32# vboxmanage modifyvm Windows10 --graphicscontroller vboxsvga
root@kvmubuntu:/mnt/c/Windows/system32# vboxmanage sharedfolder add Windows10 --name "Загрузки" --hostpath /Загрузки/ --automount
root@kvmubuntu:/mnt/c/Windows/system32# vboxmanage startvm --type gui Windows10 & 
Task:
Установка виртуальной машины Windows в Qemu-Kvm.
# Виртуализация. 
Decision:
root@kvmubuntu:/mnt/c/Windows/system32# virt-install \
--name Windows10 \
--ram 1024 \
--disk path=/var/lib/libvirt/images/Windows10.img,size=75 \
--vcpus 4 \
--os-variant Windows10 \
--network bridge=br0 \
--graphics none \
--console pty,target_type=serial \
--location /var/lib/libvirt/iso/Windows10.iso \
--extra-args 'console=ttyS0,115200n8' 
Task:
Завершение процесса работы в виртуальной машине.
# Виртуализация. 
Decision:
root@kvmubuntu:/mnt/c/Windows/system32# umount /dev/sdc1
root@kvmubuntu:/mnt/c/Windows/system32# exit
PS C:\Windows\system32> wsl --unmount \\.\PHYSICALDRIVE2 
Task:
Установка Sftp сервера.
# Администрирование локальных, виртуальных и облачных серверов. 
Decision:
root@kvmubuntu:/mnt/c/Windows/system32# virsh start Windows10
- Панель управления - Система - Настройка удаленного доступа - +разрешить подключения удаленного помощника к этому компьютеру - +разрешить удаленные подключения к этому компьютеру - -Разрешить подключение только с компьютеров ...
PS C:\Windows\system32> Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
PS C:\Windows\system32> Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
PS C:\Windows\system32> Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'
Name : OpenSSH.Client~~~~0.0.1.0
State : Installed
Name : OpenSSH.Server~~~~0.0.1.0
State : Installed
C:\Users\tuser> ipconfig
...
tipubuntu
PS C:\Windows\system32> Start-Service sshd
PS C:\Windows\system32> Set-Service -Name sshd -StartupType 'Automatic'
PS C:\Windows\System32\OpenSSH> notepad.exe C:\ProgramData\ssh\sshd_config
PS C:\Windows\System32\OpenSSH> type C:\ProgramData\ssh\sshd_config
...
PasswordAuthentication yes
...
# override default of no subsystems
Subsystem sftp sftp-server.exe
...
Match User tuser
ChrootDirectory C:\Users\tuser\Documents
# ForceCommand internal-sftp
X11Forwarding yes
...
PS C:\Windows\System32\OpenSSH> Restart-Service sshd
root@kvmubuntu:/mnt/c/Windows/system32# ssh tuser@tipubuntu
tuser@KVM-TWINDOWS C:\Users\tuser> exit
root@kvmubuntu:/mnt/c/Windows/system32# ls
DataProcessingInCpp Drivers ReceivingDataFromSatellite
root@kvmubuntu:/mnt/c/Windows/system32# sftp tuser@tipubuntu
sftp> put -r ReceivingDataFromSatellite
sftp> put -r DataProcessingInCpp
sftp> ls
DataProcessingInCpp               
ReceivingDataFromSatellite 
sftp> exit
Task:
Установка Borland C++ Builder под Windows.
# Администрирование локальных, виртуальных и облачных серверов.
Decision:
PS C:\users\tuser\documents> Mount-DiskImage -ImagePath "C:\users\tuser\documents\DataProcessingInCpp\Borland C++ Builder 6.0 Enterprise [cd1].iso"
PS C:\users\tuser\documents> Get-PSDrive -PSProvider FileSystem
Name   Used (GB) Free (GB) Provider Root                       CurrentLocation 
----   --------- --------- -------- ----                       --------------- 
C     25,27   49,16 FileSystem C:\                       users\tuser\documents 
D     4,32   0,00 FileSystem D:\
E         FileSystem E:\
F     0,61   0,00 FileSystem F:\
PS C:\users\tuser\documents> ls F:\
Каталог: F:\
Mode     LastWriteTime   Length Name
----     -------------   ------ ----
d-----  01.02.2002 17:00    Install
--r---  01.02.2002 17:00   29550 license.txt
--r---  01.02.2002 17:00   54878 readme.rtf
--r---  01.02.2002 17:00   33959 readme.txt
--r---  01.02.2002 17:00   29550 license.txt
--r---  01.02.2002 17:00   54878 readme.rtf
--r---  01.02.2002 17:00   33959 readme.txt
--r---  01.02.2002 17:00   5337 remote.rtf
--r---  01.02.2002 17:00   1750 remote.txt
--r---  01.02.2002 17:00   1750 install.exe
- Запустим от администратора install.exe - выбираем С++ Builder 6 - нужно ввести сгенерированный ключ программы, зайдя в папку Borland - запустить генератор ключей Borland KeyGen - копируем - вставляем серийный номер - ключ программы в установщик
PS C:\users\tuser\documents> Dismount-DiskImage -ImagePath "C:\users\tuser\documents\DataProcessingInCpp\Borland C++ Builder 6.0 Enterprise [cd1].iso" 
PS C:\users\tuser\documents> Mount-DiskImage -ImagePath "C:\users\tuser\documents\DataProcessingInCpp\Borland C++ Builder 6.0 Enterprise [cd2].iso"
- Ок - finish - NO (Ни в коем случае не перезагружаться)
PS C:\users\tuser\documents> Dismount-DiskImage -ImagePath "C:\users\tuser\documents\DataProcessingInCpp\Borland C++ Builder 6.0 Enterprise [cd2].iso" 
- C:\Programms file (x86)\Bornald\Builder\Bin\ - свойства совместимости bcb.exe - +всегда выполнять от администратора это программу - Запускаем bcb.exe - +регистрируем ее с помощью генератора ключей Borland KeyGe - копировать - вставить - перезагрузиться
Task:
Получение данных с одночастотного приемника СРНС.
# Спутниковые радионаввигационные системы.
Decision:
Для проверки способа определения вариации ионосферной задержки 19 мая 2015 года провел обработку данных измерения навигационных сигналов от нескольких НС. Для измерений использовался 20 канальный одночастотный приемник BU-353 фирмы GlobalSat. Этот приемник предназначен для ГНСС GPS, работает на частоте L1 по C/A коду и имеет высокую чувствительность 159 дБм. Данные о псевдодальностях доступны только при использовании бинарного протокола, поэтому при наблюдениях применялась программа SirfTech версии 2.20 и данные записывались в RINEX файл. Описание программы SirfTech можно увидеть прил. 5. 
Task:
Алгоритм обработки данных.
# Спутниковые радионаввигационные системы.
Decision:
Большая часть программного обеспечения обработки данных GPS использует определенный набор наблюдений:
- фазовые измерения на одной или двух несущих частотах;
- измерения псевдодальности (кода), которые соответствуют разности между временем получения и временем передачи отдельных сигналов спутника;
- время наблюдения считывается с часов приемника в момент измерения фазы несущей и/или кода.
При обработке необходимыми являются: фаза, код и время, определение которых дано выше, и некоторая информация относительно станции, такая как название станции, высота антенны и другие [5].
Task:
Описание формата RINEX.
# Спутниковые радионаввигационные системы.
Decision:
Для решении навигационной задачи исходными данными являются файлы в формате RINEX - независимый от приемника формат для обмена данными СРНС. RINEX - формат состоит из трех типов ASCII файлов - файлы метеорологических параметров (meteorological data file), файлы результатов измерений (observation data file), файлы с оперативной эфемеридной информацией, полученные в составе навигационного сообщения (navigation message file) [5].
Файлы имеют различную длину, максимальное значение равно 80 символам в строке (табл. 2). Каждый файл содержит секцию заголовков и секцию данных. Файл навигационного сообщения располагается независимо, в то время как файлы измерений и метеорологических данных должны быть созданы для каждого используемого при наблюдениях пункта [5]. 
Таблица 2. Общая структура формата RINEX: 

Результаты измерений располагаются по эпохам. Каждой эпохе наблюдения соответствует структура, представленная на табл. 3 (количество и порядок расположения результатов различных типов измерений указывается в заголовке файла в строке "# / TYPES OF OBSERV", например, «7 LI L2C1 PI P2»), где у у mm dd hh mm sec момент приема сигнала по часам потребителя (tp); № - номера спутников, результаты наблюдений которых в соответствующем порядке записываются для каждой эпохи (при совместной обработке наблюдений ИСЗ обеих систем либо резервируются номера с 1 по 32 для спутников GPS и с 33 по 64 для спутников ГЛОНАСС, либо вводятся дополнительные признаки G и R); ИСЗ фаза L1 - псевдодальность, измеренная по фазе несущей на частоте L1; ИСЗ фаза L2 - псевдодальность, измеренная по фазе несущей на частоте L2; ИСЗ код С1 - псевдодальность, измеренная по С/А-коду на частоте L1; ИСЗ код Р1 - псевдодальность, измеренная по Р-коду на частоте L1; ИСЗ код Р2 - псевдодальность, измеренная по Р-коду на частоте L2 [2].
Таблица 3. Результаты СРНС-измерений на одну эпоху 

Оперативная эфемеридная информация, полученная в составе навигационного сообщения, сгруппирована по номерам ИСЗ. Фрагменты файла измерений в формате RINEX представлены в прил. 2 [5].
GPS наблюдения включают в себя три основных понятия, которым необходимо дать определение: время, фаза и псевдодальность. Время измерений - это время приемника в момент приема сигналов. Оно одинаково для измерений фазы и псевдодальности и одинаково для всех наблюдаемых спутников в данную эпоху. Время выражается в единицах GPS-времени (не в мировом времени, UTC).
Псевдодальность (ПД) - это расстояние от приемной антенны до антенны спутника, включая сдвиги шкалы времени приемника и спутниковых часов (и другие сдвиги, такие как атмосферные задержки). Псевдодальность отражает реальное поведение часов приемника и передатчика. Псевдодальность указывается в единицах длины - метрах.
Фаза - это фаза несущей, измеренная в целых циклах. Измеряемое количество полуциклов квадратурными приемниками должно быть конвертировано в целые циклы и соответственно изменено значение длины волны в заголовке файла (только для GPS) [5].
Изменения фазы положительно коррелированны с изменениями дальности (негативный эффект Доплера). Фазовые наблюдения между эпохами должны быть скорректированы включением целого числа циклов. Фазовые наблюдения не будут содержать никаких систематических сдвигов от намеренных сдвигов опорных генераторов.
Данные всех измерений не скорректированы на внешние эффекты, такие как атмосферная рефракция, сдвиг часов спутникового передатчика и другие. Если приемник или программа конвертера производят измерения сдвига часов приемника в реальном времени dT(изм), то соответственно три параметра (фаза, псевдодальность, эпоха) должны быть исправлены. Знак доплеровского сдвига частоты определяется как обычно - положительный знак при приближении спутника [5].
Task:
Для дальнейшей обработки и сортировки данных мною была написана программа на языке С++, которая считывает файлы в RINEX формате и сортирует псевдодальности по каждому НС, что упрощает дальнейшую обработку. Для основной обработки данных по формуле 4.4 выполнялись вычисления с помощью редактора EXCEL.
Мы хотим чтобы наша программа с графическим интерфейсом сначала с нами поздоровалась в Bornald Builder.
# Разработка программы Обработка и сортировка данных в файлах Rinex формата.
Decision:
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
  : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  ShowMessage("Hello world!");
}
//---------------------------------------------------------------------------
Task:
Алгоритм.
# Разработка программы Обработка и сортировка данных в файлах Rinex формата.
Decision:
Из текстового файла вывести всю информацию до END OF HEADER в out.txt.
Вывести следующую строку после END OF HEADER - время и название спутников.
Вывести количество спутников и названия спутников в строке.
Вывести название спутников по буквам, то есть создаем динамический массив с указателем.
Вывести вторую строку название спутников.
Вывести буквы спутников в столбец.
Вывести по буквам и по цифрам. если увидим пробел, тогда операция не должна выполняться.
Вывести все спутники в столбец.
Вывести псевдодальности для одной/первой эпохи (время - 0:0).
Вывести названия спутников для первой эпохи.
Вывести псевдодальности для каждого спутника.
Вывести название спутника и расстояние (дальность) спутника. первая строка - для первой эпохи, вторая строка - для второй эпохи
Вывести для всех эпох данные спутников.
Вывести на экран данные для двух спутников.
Вывести данные именно для одного спутника, например первого.
Task:
Вывести названия спутников из файла для первой минуты.
# Разработка программы Обработка и сортировка данных в файлах Rinex формата.
Decision:
root@kvmubuntu:/mnt/c/Windows/system32# cat IRKL1119.txt
2.11 OBSERVATION DATA M (MIXED) RINEX VERSION / TYPE
...
       END OF HEADER
11 11 19 0 0 0.0000000 0 18G 1G28R22G1R12G 7G 3G 6R 6R24R 5G26-0.000381360
    G11G16R13R14G 8R23
23815384.399 23815383.399 125150709.498 3 3673.062 23.000
...
root@kvmubuntu:/mnt/c/Windows/system32# cat Unit1.cpp
//---------------------------------------------------------------------------
#include <iostream>
#include <vector>
#include <fstream>
#include <string.h>
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
ifstream in ("IRKL1119.txt");
ofstream out ("output.txt");
string a;
//���������� �� �� END OF HEADER
while(true) {
getline (in,a);
if(a == "       END OF HEADER") {
break;
}
}
string name;
// ������� ������� � ���������
int temp;
double temp2;
in >> temp;
in >> temp;
in >> temp;
in >> temp;
in >> temp;
in >> temp2;
in >> temp;
int countSputnik;
in >> countSputnik;
cout<< countSputnik<<endl ;
getline(in,name);
// cout<< name <<endl;
vector <string> allSputnik;// ������ ������ � ������� ����������
int index=-1; //��������� ��������
string tempName = ""; //
for(int i=0; i< name.size(); i++)
{
  if(name[i] == '-')
  break;
  if(name[i] >= 'A' && name[i] <= 'Z') {
   index++;
   if(tempName != "") {
    allSputnik.push_back(tempName);
    tempName="";
   }
  }
  if (name[i] != ' '){
   tempName = tempName + name[i];
  }
}
if(index != countSputnik -1) { //��������� ��������� �� ����� ���� ��������
//2 stroka
  getline(in,name);
  for(int i=0; i<name.size(); i++){
   if(name[i] >= 'A' && name[i] <= 'Z') {
    index++;
    if(tempName != "") {
     allSputnik.push_back(tempName);
     tempName="";
    }
   }
   if (name[i] != ' '){
   tempName = tempName + name[i];
  }
}
}
for(int i=0; i<countSputnik; i++){
out << allSputnik[i] << endl;
}
/*
delete [] Sputnik;
// ���������� ��������������� ��� ����� �����
double *information = new double [countSputnik];
for(int i=0; i<countSputnik; i++){
in >> information[i];
getline (in,name);
getline (in,name);
}
for(int i=0; i<countSputnik; i++){
out << information[i] << endl;
}
*/
/*
double *information = new double [countSputnik];
double information1;
for(int i=0; i<countSputnik; i++){
in >> information1;
in >> information[i];
getline (in,name);
getline (in,name);
}
for(int i=0; i<countSputnik; i++){
cout << information[i] << endl;
}
*/
}
//---------------------------------------------------------------------------
root@kvmubuntu:/mnt/c/Windows/system32# cat output.txt
G1
G28
R22
G1
R12
G7
G3
G6
R6
R24
R5
G26
G11
G16
R13
R14
G8
Task:
Читаем Каждую Букву И Цифру После строки названия спутников для первой минуты.
# Разработка программы Обработка и сортировка данных в файлах Rinex формата.
Decision:
root@kvmubuntu:/mnt/c/Windows/system32# cat igs19236-1.txt
#cP2016 11 19 0 0 0.00000000 96 ORBIT IGb08 HLM IGS
...
* 2016 11 19 0 0 0.00000000
PG01 -20514.995126 -11031.142105 12884.404415 40.929190 7 8 4 99 
PG02 12690.844622 22403.534044 7723.409365 523.430781 9 7 9 125 
...
root@kvmubuntu:/mnt/c/Windows/system32# cat Unit1.cpp
//---------------------------------------------------------------------------
#include <iostream>
#include <fstream>
#include <string.h>
#include <vector>
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
ifstream in ("igs19236-1.txt");
ofstream out ("out.txt"); 
// ���������� �� ORB:CMB CLK:CMB
string stroka;
for (int i=0; i<22; i++)
{
  getline (in,stroka);
}
// ��������� �����
string epoha;
getline(in,epoha);
//out << epoha << endl;
/*char zvezda;
int data;
int vremia;
double sostoianie;
in >> zvezda;
in >> data;
in >> data;
in >> data;
in >> vremia;
in >> vremia;
in >> sostoianie;
//out << sostoianie;*/
// ��������� ������� ���� ��������� � �� ����������
/*
string position; // ��� ���� ������
getline (in,position);
out << position << endl;
*/
/*//������ ������� +
string sputnik; //������� ��������
string e; // EOF � * 2016 11 19
string x;
string y;
string z;
string signali; //������ �������
for (int j=0; j<96; j++){ //��� ���� ��������� � ��� ���� ����
  for (int i=0; i<32; i++){ //��� ���� ��������� � ��� ����� �����
   in >> sputnik >> x >> y >> z;
   getline (in, signali);
   out << sputnik << " " << x << " " << y << " " << z << " " << endl;
  }
  getline (in, e); // ��������� EOF � * 2016 11 19
}*/
/* //������ ������� -
int b;
//getline (in,position);
//out << position << endl;

string *info = new string [b];
for (int i=0; i<b; i++)
{
  info[i]="";
}
int index=-1;
for(int i=0; i< position.size(); i++) {
  if(position[i] >= 'A' && position[i] <= 'Z') {
   index++;
  }
  if (position[i] !=' '){
   info[index] = info[index] + position[i];
  }
}
for(int i=0; i<b; i++)
{
  out << " " << info[i] << " " << endl;
}
delete [] info;
*/
/*
double *information = new double [b];

for(int i=0; i<b; i++)
{
  in >> information[i];
  //getline (in,position);
  //getline (in,position);
}
for(int i=0; i<b; i++){
  out << information[i] << endl;
}
*/
string position; // ��� ���� ������
getline (in,position); // ����������� ��� ������ �������
//out << position << endl;
// ������� ������ ������� ���� ������
vector <string> infa; // ������� ������ ������ � ����� ������� �����
int index=-1; // ��������� ��������
string infaPosition = ""; // ������ ������� ��� ������ ��������
for(int i=0; i< position.size(); i++) { // ��� ������ ���� ������� ����� �������
  if(position[i] >= 'A' && position[i] <= 'Z') { // 1 ���� ��������� �����
   index++; // �������� ���������
   /*if(infaPosition != "") { // ����
    infa.push_back(infaPosition);
    infaPosition="";
   } */
  }
  /*if (position[i] != ' '){
   infaPosition = infaPosition + position[i];
  }*/
  out << position[i] << endl; // ������� � ������ ������ �������
}
/* string a;
getline (in,a);
out << a << endl; 
*/
}
//---------------------------------------------------------------------------
root@kvmubuntu:/mnt/c/Windows/system32# cat out.txt
P
G
0
1
-
2
0
5
1
4
.
9
9
5
1
2
6
-
1
1
0
3
1
.
1
4
2
1
0
5
1
2
8
8
4
.
4
0
4
4
1
5
4
0
.
9
2
9
1
9
0
7
8
4
9
9
Task:
Мы Выводим Данные Спутников G16 В Текстовый Файл для каждой эпохи.
# Разработка программы Обработка и сортировка данных в файлах Rinex формата.
Decision:
root@kvmubuntu:/mnt/c/Windows/system32# cat IRKL1119.txt
...
    G11G16R13R14G 8R23
23815384.399 23815383.399 125150709.498 3 3673.062 23.000
23815389.819 97520038.895 3 2862.131 23.000
23418101.271 23418101.711 123062972.555 4 2734.873 26.000
23418102.171 95893253.756 4 2131.058 26.000
...
root@kvmubuntu:/mnt/c/Windows/system32# cat Unit1.cpp
//---------------------------------------------------------------------------
#include <iostream>
#include <vector>
#include <fstream>
#include <string.h>
#include <iomanip.h>
#include <cmath>
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
ifstream in ("IRKL1119.txt");
ofstream out ("output.txt");
string a;
//���������� �� �� END OF HEADER
while(true) {
getline (in,a);
if(a == "       END OF HEADER") {
break;
}
}
string name;
// ������� ������� � ���������
int temp;
double temp2;
int countSputnik;
vector <vector <double> > info;
vector <double> tempVector;
tempVector.resize(53);
vector <string> Sputnik;
vector <string> allSputnik;// ������ ������ � ������� ����������
int index=-1; //��������� ��������
string tempName = "";
for(int i=0; i<2880; i++) {
in >> temp;
in >> temp;
in >> temp;
in >> temp;
in >> temp;
in >> temp2;
in >> temp;
in >> countSputnik;
/*out << countSputnik << endl; */
getline(in,name);
allSputnik.resize(0);
index=-1; //��������� ��������
tempName = ""; //
for(int i=0; i< name.size(); i++) {
if(name[i] == '-')
break;
if(name[i] >= 'A' && name[i] <= 'Z') {
index++;
if(tempName != "") {
allSputnik.push_back(tempName);
tempName="";
}
}
if (name[i] != ' '){
tempName = tempName + name[i];
}
}
if(tempName != "") {
allSputnik.push_back(tempName);
tempName="";
}
tempName="";
if(index <= countSputnik-1) { //��������� ��������� �� ����� ���� ��������
//2 stroka
getline(in,name);
for(int i=0; i<name.size(); i++){
if(name[i] >= 'A' && name[i] <= 'Z') {
  index++;
  if(tempName != "") {
   allSputnik.push_back(tempName);
   tempName="";
  }
}
if (name[i] != ' '){
  tempName = tempName + name[i];
}
}
}
if(tempName != "") {
allSputnik.push_back(tempName);
tempName="";
}
/*
for(int i=0; i<allSputnik.size(); i++){
out << allSputnik[i] << endl;
}
*/
info.push_back(tempVector);
for(int i = 0; i<allSputnik.size(); i++) {
double dalnost=0;
/*
in >> dalnost;
in >> dalnost;
*/
string b = "";
getline (in, b);
a ="";
if(b.size()>=30){
a=b.substr(17,13);
}
int tochka=-1;
int chislo=0;
for (int i=0; i<a.size(); i++){
  if (a[i]>='0' && a[i]<='9'){
   dalnost = dalnost *10 + (a[i]-'0');
  }
  else {
   if(a[i]== '.') {
    tochka=i;
   }
  }
}
if(tochka != -1){
  chislo = a.size()-1 - tochka;
  chislo = (int) pow(10, (double)chislo);
  dalnost=dalnost/chislo;
}
getline (in,name);
index=-1;
for(int j=0; j<Sputnik.size(); j++) {
  if(allSputnik[i] == Sputnik[j]) {
   index = j;
   break;
  }
}
if(index == -1) {
  Sputnik.push_back(allSputnik[i]);
  info[info.size()-1][Sputnik.size()-1] = dalnost;
}
else {
  info[info.size()-1][index] = dalnost;
}
}
}
// out << endl;
for(int j=0; j<Sputnik.size(); j++) {
out << setw(13) << Sputnik[j] << " ";
}
out << endl;
for(int i=0; i<info.size(); i++) {
for(int j=0; j<info[i].size(); j++) {
  out << setw(13) << setprecision(13) << info[i][j] << " ";
}
out << endl;
}
out << endl;
for(int i=0; i<info.size(); i++){
out << setw(13) << setprecision(13) << info[i][0] << setw(14) << info[i][1] << endl;
}
}
//---------------------------------------------------------------------------
root@kvmubuntu:/mnt/c/Windows/system32# cat output.txt
...
23418101.711
23402498.509
23386912.128
23371345.657
23355798.957
...
Task:
Выводим список спутников и их псевдоальность для первой эпохи.
# Разработка программы Обработка и сортировка данных в файлах Rinex формата.
Decision:
root@kvmubuntu:/mnt/c/Windows/system32# cat Unit1.cpp
//---------------------------------------------------------------------------
#include <iostream>
#include <vector>
#include <fstream>
#include <string.h>
#include <iomanip.h>
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
ifstream in ("IRKL1119.txt");
ofstream out ("output.txt");
string a;
//���������� �� �� END OF HEADER
while(true) {
getline (in,a);
if(a == "       END OF HEADER") {
break;
}
}
string name;
// ������� ������� � ���������
int temp;
double temp2;
in >> temp;
in >> temp;
in >> temp;
in >> temp;
in >> temp;
in >> temp2;
in >> temp;
int countSputnik;
in >> countSputnik;
//out<< countSputnik<<endl ;
vector <vector <double> > info;
vector <double> tempVector;
tempVector.resize(100);
getline(in,name);
vector <string> Sputnik;
vector <string> allSputnik;// ������ ������ � ������� ���������
int index=-1; //��������� ��������
string tempName = ""; //
for(int i=0; i< name.size(); i++) {
if(name[i] == '-')
break;
if(name[i] >= 'A' && name[i] <= 'Z') {
index++;
if(tempName != "") {
allSputnik.push_back(tempName);
tempName="";
}
}
if (name[i] != ' '){
tempName = tempName + name[i];
}
}
if(tempName != "") {
allSputnik.push_back(tempName);
tempName="";
}
tempName="";
if(index <= countSputnik-1) { //��������� ��������� �� ����� ���� ��������
//2 stroka
getline(in,name);
for(int i=0; i<name.size(); i++){
if(name[i] >= 'A' && name[i] <= 'Z') {
  index++;
  if(tempName != "") {
   allSputnik.push_back(tempName);
   tempName="";
  }
}
if (name[i] != ' '){
  tempName = tempName + name[i];
}
}
}
if(tempName != "") {
allSputnik.push_back(tempName);
tempName="";
}
for(int i=0; i<allSputnik.size(); i++){
//out << allSputnik[i] << endl;
}
info.push_back(tempVector);
for(int i = 0; i<allSputnik.size(); i++) {
double dalnost;
in >> dalnost;
in >> dalnost;
getline (in,name);
getline (in,name);
index=-1;
for(int j=0; j<Sputnik.size(); j++) {
  if(allSputnik[i] == Sputnik[j]) {
   index = j;
   break;
  }
}
if(index == -1) {
  Sputnik.push_back(allSputnik[i]);
  info[info.size()-1][Sputnik.size()-1] = dalnost;
}
else {
  info[info.size()-1][index] = dalnost;
}
}
out << endl;
for(int j=0; j<Sputnik.size(); j++) {
out << Sputnik[j] << " ";
}
out << endl;
for(int i=0; i<info.size(); i++) {
for(int j=0; j<info[i].size(); j++) {
  out << setprecision(12) << info[i][j] << " ";
}
out << endl;
}
}
//---------------------------------------------------------------------------
root@kvmubuntu:/mnt/c/Windows/system32# cat output.txt
G1 G28 R22 G19 R12 G7 G3 G6 R6 R24 R5 G26 G11 G16 R13 R14 G9 R23 
23815383.399 23418101.711 20126478.966 20576502.049 20850572.801 20361179.631 22177242.661 23871188.467 23896969.354 22949017.462 23330231.749 23194678.499 21898256.651 24811902.872 19151353.321 21666798.485 20650945.821 19472152.449 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
Task:
Выводим количество спутников, название спутников и пссевдодальность для каждого спутника за первые 15 минут.
# Разработка программы Обработка и сортировка данных в файлах Rinex формата.
Decision:
root@kvmubuntu:/mnt/c/Windows/system32# cat Unit1.cpp
//---------------------------------------------------------------------------
#include <iostream>
#include <vector>
#include <fstream>
#include <string.h>
#include <iomanip.h>
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
ifstream in ("IRKL1119.txt");
ofstream out ("output.txt");
string a;
//���������� �� �� END OF HEADER
while(true) {
getline (in,a);
if(a == "       END OF HEADER") {
break;
}
}
string name;
// ������� ������� � ���������
int temp;
double temp2;
in >> temp;
in >> temp;
in >> temp;
in >> temp;
in >> temp;
in >> temp2;
in >> temp;
int countSputnik;
in >> countSputnik;
cout<< countSputnik<<endl ;
vector <vector <double> > info;
vector <double> tempVector;
tempVector.resize(100);
getline(in,name);
vector <string> Sputnik;
vector <string> allSputnik;// ������ ������ � ������� ����������
int index=-1; //��������� ��������
string tempName = ""; //
for(int i=0; i< name.size(); i++) {
if(name[i] == '-')
break;
if(name[i] >= 'A' && name[i] <= 'Z') {
index++;
if(tempName != "") {
allSputnik.push_back(tempName);
tempName="";
}
}
if (name[i] != ' '){
tempName = tempName + name[i];
}
}
if(tempName != "") {
allSputnik.push_back(tempName);
tempName="";
}
tempName="";
if(index <= countSputnik-1) { //��������� ��������� �� ����� ���� ��������
//2 stroka
getline(in,name);
for(int i=0; i<name.size(); i++){
if(name[i] >= 'A' && name[i] <= 'Z') {
  index++;
  if(tempName != "") {
   allSputnik.push_back(tempName);
   tempName="";
  }
}
if (name[i] != ' '){
  tempName = tempName + name[i];
}
}
}
if(tempName != "") {
allSputnik.push_back(tempName);
tempName="";
}
for(int i=0; i<allSputnik.size(); i++){
out << allSputnik[i] << endl;
}
info.push_back(tempVector);
for(int i = 0; i<allSputnik.size(); i++) {
double dalnost;
in >> dalnost;
in >> dalnost;
getline (in,name);
getline (in,name);
index=-1;
for(int j=0; j<Sputnik.size(); j++) {
  if(allSputnik[i] == Sputnik[j]) {
   index = j;
   break;
  }
}
if(index == -1) {
  Sputnik.push_back(allSputnik[i]);
  info[info.size()-1][Sputnik.size()-1] = dalnost;
}
else {
  info[info.size()-1][index] = dalnost;
}
}
/*
out << endl;
for(int j=0; j<Sputnik.size(); j++) {
out << Sputnik[j] << " ";
}
out << endl;
for(int i=0; i<info.size(); i++) {
for(int j=0; j<info[i].size(); j++) {
  out << setprecision(12) << info[i][j] << " ";
}
out << endl;
}
*/
////////////////////////////////////////////////////////////////////
//getline(in, name);
//out << endl << name << endl;
in >> temp;
in >> temp;
in >> temp;
in >> temp;
in >> temp;
in >> temp2;
in >> temp;
in >> countSputnik;
out << countSputnik << endl;
getline(in,name);
allSputnik.resize(0);
index=-1; //��������� ��������
tempName = ""; //
for(int i=0; i< name.size(); i++) {
if(name[i] == '-')
break;
if(name[i] >= 'A' && name[i] <= 'Z') {
index++;
if(tempName != "") {
allSputnik.push_back(tempName);
tempName="";
}
}
if (name[i] != ' '){
tempName = tempName + name[i];
}
}
if(tempName != "") {
allSputnik.push_back(tempName);
tempName="";
}
tempName="";
if(index <= countSputnik-1) { //��������� ��������� �� ����� ���� ��������
//2 stroka
getline(in,name);
for(int i=0; i<name.size(); i++){
if(name[i] >= 'A' && name[i] <= 'Z') {
  index++;
  if(tempName != "") {
   allSputnik.push_back(tempName);
   tempName="";
  }
}
if (name[i] != ' '){
  tempName = tempName + name[i];
}
}
}
if(tempName != "") {
allSputnik.push_back(tempName);
tempName="";
}
for(int i=0; i<allSputnik.size(); i++){
out << allSputnik[i] << endl;
}
info.push_back(tempVector);
for(int i = 0; i<allSputnik.size(); i++) {
double dalnost;
in >> dalnost;
in >> dalnost;
getline (in,name);
getline (in,name);
index=-1;
for(int j=0; j<Sputnik.size(); j++) {
  if(allSputnik[i] == Sputnik[j]) {
   index = j;
   break;
  }
}
if(index == -1) {
  Sputnik.push_back(allSputnik[i]);
  info[info.size()-1][Sputnik.size()-1] = dalnost;
}
else {
  info[info.size()-1][index] = dalnost;
}
}
out << endl;
for(int j=0; j<Sputnik.size(); j++) {
out << setw(13) << Sputnik[j] << " ";
}
out << endl;
for(int i=0; i<info.size(); i++) {
for(int j=0; j<info[i].size(); j++) {
  out << setw(13) << setprecision(13) << info[i][j] << " ";
}
out << endl;
}
}
//---------------------------------------------------------------------------
root@kvmubuntu:/mnt/c/Windows/system32# cat output.txt
G1
G28
R22
G19
R12
G7
G3
G6
R6
R24
R5
G26
G11
G16
R13
R14
G9
R23
19472155.069 81015603.872 8 1314.191 51.000
18
G1
G28
R22
G19
R12
G7
G3
G6
R6
R24
R5
G26
G11
G16
R13
R14
G8
R23
G1 G28 R22 G19 R12 G7 G3 G6 R6 R24 R5 G26 G11 G16 R13 R14 G9 R23 G8 
23815383.399 23418101.711 20126478.966 20576502.049 20850572.801 20361179.631 22177242.661 23871188.467 23896969.354 22949017.462 23330231.749 23194678.499 21898256.651 24811902.872 19151353.321 21666798.485 20650945.821 19472152.449 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
23794425.041 23402498.509 20141642.176 20584598.589 20869652.326 20367330.686 22196301.185 23890335.007 23883323.395 22925234.933 23334086.485 23188096.286 21881612.664 24830710.969 19148858.027 21645612.101 0 19462739.332 20642124.208 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
root@kvmubuntu:/mnt/c/Windows/system32# cat Unit1.cpp
//---------------------------------------------------------------------------
#include <iostream>
#include <vector>
#include <fstream>
#include <string.h>
#include <iomanip.h>
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
ifstream in ("IRKL1119.txt");
ofstream out ("output.txt");
string a;
//���������� �� �� END OF HEADER
while(true) {
getline (in,a);
if(a == "       END OF HEADER") {
break;
}
}
string name;
// ������� ������� � ���������
int temp;
double temp2;
int countSputnik;
vector <vector <double> > info;
vector <double> tempVector;
tempVector.resize(100);
vector <string> Sputnik;
vector <string> allSputnik;// ������ ������ � ������� ����������
int index=-1; //��������� ��������
string tempName = "";
/*
in >> temp;
in >> temp;
in >> temp;
in >> temp;
in >> temp;
in >> temp2;
in >> temp;
in >> countSputnik;
cout<< countSputnik<<endl ;
getline(in,name);
allSputnik.resize(0);// ������ ������ � ������� ����������
*/
/*
int index=-1; //��������� ��������
string tempName = ""; //
for(int i=0; i< name.size(); i++) {
if(name[i] == '-')
break;
if(name[i] >= 'A' && name[i] <= 'Z') {
index++;
if(tempName != "") {
allSputnik.push_back(tempName);
tempName="";
}
}
if (name[i] != ' '){
tempName = tempName + name[i];
}
}
if(tempName != "") {
allSputnik.push_back(tempName);
tempName="";
}
tempName="";
if(index <= countSputnik-1) { //��������� ��������� �� ����� ���� ��������
//2 stroka
getline(in,name);
for(int i=0; i<name.size(); i++){
if(name[i] >= 'A' && name[i] <= 'Z') {
  index++;
  if(tempName != "") {
   allSputnik.push_back(tempName);
   tempName="";
  }
}
if (name[i] != ' '){
  tempName = tempName + name[i];
}
}
}
if(tempName != "") {
allSputnik.push_back(tempName);
tempName="";
}
for(int i=0; i<allSputnik.size(); i++){
out << allSputnik[i] << endl;
}
info.push_back(tempVector);
for(int i = 0; i<allSputnik.size(); i++) {
double dalnost;
in >> dalnost;
in >> dalnost;
getline (in,name);
getline (in,name);
index=-1;
for(int j=0; j<Sputnik.size(); j++) {
  if(allSputnik[i] == Sputnik[j]) {
   index = j;
   break;
  }
}
if(index == -1) {
  Sputnik.push_back(allSputnik[i]);
  info[info.size()-1][Sputnik.size()-1] = dalnost;
}
else {
  info[info.size()-1][index] = dalnost;
}
}
*/
/*
out << endl;
for(int j=0; j<Sputnik.size(); j++) {
out << Sputnik[j] << " ";
}
out << endl;

for(int i=0; i<info.size(); i++) {
for(int j=0; j<info[i].size(); j++) {
  out << setprecision(12) << info[i][j] << " ";
}
out << endl;
}
*/
////////////////////////////////////////////////////////////////////
//getline(in, name);
//out << endl << name << endl;
for(int i=0; i<4; i++) {
in >> temp;
in >> temp;
in >> temp;
in >> temp;
in >> temp;
in >> temp2;
in >> temp;
in >> countSputnik;
out << countSputnik << endl;
getline(in,name);
allSputnik.resize(0);
index=-1; //��������� ��������
tempName = ""; //
for(int i=0; i< name.size(); i++) {
if(name[i] == '-')
break;
if(name[i] >= 'A' && name[i] <= 'Z') {
index++;
if(tempName != "") {
allSputnik.push_back(tempName);
tempName="";
}
}
if (name[i] != ' '){
tempName = tempName + name[i];
}
}
if(tempName != "") {
allSputnik.push_back(tempName);
tempName="";
}
tempName="";
if(index <= countSputnik-1) { //��������� ��������� �� ����� ���� ��������
//2 stroka
getline(in,name);

for(int i=0; i<name.size(); i++){
if(name[i] >= 'A' && name[i] <= 'Z') {
  index++;
  if(tempName != "") {
   allSputnik.push_back(tempName);
   tempName="";
  }
}
if (name[i] != ' '){
  tempName = tempName + name[i];
}
}
}
if(tempName != "") {
allSputnik.push_back(tempName);
tempName="";
}
for(int i=0; i<allSputnik.size(); i++){
out << allSputnik[i] << endl;
}
info.push_back(tempVector);
for(int i = 0; i<allSputnik.size(); i++) {
double dalnost;
in >> dalnost;
in >> dalnost;

getline (in,name);
getline (in,name);

index=-1;
for(int j=0; j<Sputnik.size(); j++) {
  if(allSputnik[i] == Sputnik[j]) {
   index = j;
   break;
  }
}
if(index == -1) {
  Sputnik.push_back(allSputnik[i]);
  info[info.size()-1][Sputnik.size()-1] = dalnost;
}
else {
  info[info.size()-1][index] = dalnost;
}
}
}
out << endl;
for(int j=0; j<Sputnik.size(); j++) {
out << setw(13) << Sputnik[j] << " ";
}
out << endl;
for(int i=0; i<info.size(); i++) {
for(int j=0; j<info[i].size(); j++) {
  out << setw(13) << setprecision(13) << info[i][j] << " ";
}
out << endl;
}

}
//---------------------------------------------------------------------------
root@kvmubuntu:/mnt/c/Windows/system32# cat output.txt
18
G1
G28
R22
G19
R12
G7
G3
G6
R6
R24
R5
G26
G11
G16
R13
R14
G9
R23
18
G1
G28
R22
G19
R12
G7
G3
G6
R6
R24
R5
G26
G11
G16
R13
R14
G8
R23
18
G1
G28
R22
G19
R12
G7
G3
G6
R6
R24
R5
G26
G11
G16
R13
R14
G8
R23
1243988
19453454.30480937797.92821279.27712.000
19453454.30480937797.92821279.27712.000
G1 G28 R22 G19 R12 G7 G3 G6 R6 R24 R5 G26 G11 G16 R13 R14 G9 R23 G8 19453454.30480937797.92821279.27712.000 
23815383.399 23418101.711 20126478.966 20576502.049 20850572.801 20361179.631 22177242.661 23871188.467 23896969.354 22949017.462 23330231.749 23194678.499 21898256.651 24811902.872 19151353.321 21666798.485 20650945.821 19472152.449 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
23794425.041 23402498.509 20141642.176 20584598.589 20869652.326 20367330.686 22196301.185 23890335.007 23883323.395 22925234.933 23334086.485 23188096.286 21881612.664 24830710.969 19148858.027 21645612.101 0 19462739.332 20642124.208 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
23773491.181 23386912.128 -2723.261 20592788.59 20888815.333 20373592.145 22215405.514 23909502.132 23869784.311 22901490.193 23338082.579 23181639.852 21865044.244 24849525.498 19146493.433 21624473.283 0 19453451.974 20633403.301 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19453451.974 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
Task:
Выведем данные Псевдодальности для каждого спутника.
# Разработка программы Обработка и сортировка данных в файлах Rinex формата.
Decision:
root@kvmubuntu:/mnt/c/Windows/system32# cat IRKL1119.txt
2.11 OBSERVATION DATA M (MIXED) RINEX VERSION / TYPE
...
       END OF HEADER
11 11 19 0 0 0.0000000 0 18G 1G28R22G19R12G 7G 3G 6R 6R24R 5G26-0.000381360
    G11G16R13R14G 8R23
23815384.399 23815383.399 125150709.498 3 3673.062 23.000
23815389.819 97520038.895 3 2862.131 23.000
...
root@kvmubuntu:/mnt/c/Windows/system32# cat Unit1.cpp
//---------------------------------------------------------------------------
#include <iostream>
#include <vector>
#include <fstream>
#include <string.h>
#include <iomanip.h>
#include <cmath>
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
ifstream in ("IRKL1119.txt");
ofstream out ("output.txt");
string a;
//���������� �� �� END OF HEADER
while(true) {
getline (in,a);
if(a == "       END OF HEADER") {
break;
}
}
string name;
// ������� ������� � ���������
int temp;
double temp2;
int countSputnik;
vector <vector <double> > info;
vector <double> tempVector;
tempVector.resize(100);
vector <string> Sputnik;
vector <string> allSputnik;// ������ ������ � ������� ����������
int index=-1; //��������� ��������
string tempName = "";
for(int i=0; i<2880; i++) {
in >> temp;
in >> temp;
in >> temp;
in >> temp;
in >> temp;
in >> temp2;
in >> temp;
in >> countSputnik;
/*out << countSputnik << endl; */
getline(in,name);
allSputnik.resize(0);
index=-1; //��������� ��������
tempName = ""; //
for(int i=0; i< name.size(); i++) {
if(name[i] == '-')
break;
if(name[i] >= 'A' && name[i] <= 'Z') {
index++;
if(tempName != "") {
allSputnik.push_back(tempName);
tempName="";
}
}
if (name[i] != ' '){
tempName = tempName + name[i];
}
}
if(tempName != "") {
allSputnik.push_back(tempName);
tempName="";
}
tempName="";
if(index <= countSputnik-1) { //��������� ��������� �� ����� ���� ��������
//2 stroka
getline(in,name);
for(int i=0; i<name.size(); i++){
if(name[i] >= 'A' && name[i] <= 'Z') {
  index++;
  if(tempName != "") {
   allSputnik.push_back(tempName);
   tempName="";
  }
}
if (name[i] != ' '){
  tempName = tempName + name[i];
}
}
}
if(tempName != "") {
allSputnik.push_back(tempName);
tempName="";
}
/*
for(int i=0; i<allSputnik.size(); i++){
out << allSputnik[i] << endl;
}
*/
info.push_back(tempVector);
for(int i = 0; i<allSputnik.size(); i++) {
double dalnost=0;
/*
in >> dalnost;
in >> dalnost;
*/
string b = "";
getline (in, b);
a ="";
if(b.size()>=30){
a=b.substr(17,13);
}
int tochka=-1;
int chislo=0;
for (int i=0; i<a.size(); i++){
  if (a[i]>='0' && a[i]<='9'){
   dalnost = dalnost *10 + (a[i]-'0');
  }
  else {
   if(a[i]== '.') {
    tochka=i;
   }
  }
}
if(tochka != -1){
  chislo = a.size()-1 - tochka;
  chislo = (int) pow(10, (double)chislo);
  dalnost=dalnost/chislo;
}
getline (in,name);
index=-1;
for(int j=0; j<Sputnik.size(); j++) {
  if(allSputnik[i] == Sputnik[j]) {
   index = j;
   break;
  }
}
if(index == -1) {
  Sputnik.push_back(allSputnik[i]);
  info[info.size()-1][Sputnik.size()-1] = dalnost;
}
else {
  info[info.size()-1][index] = dalnost;
}
}
}
out << endl;
for(int j=0; j<Sputnik.size(); j++) {
out << setw(13) << Sputnik[j] << " ";
}
out << endl;
for(int i=0; i<info.size(); i++) {
for(int j=0; j<info[i].size(); j++) {
  out << setw(13) << setprecision(13) << info[i][j] << " ";
}
out << endl;
}
}
//---------------------------------------------------------------------------
root@kvmubuntu:/mnt/c/Windows/system32# cat output.txt
G1 G28 R22 G19 R12 G7 G3 G6 R6 R24 R5 G26 G11 G16 R13 R14 G8 R23 G15 G22 G17 R7 R15 R17 R8 G32 G20 G9 R1 R16 G4 R18 R2 G12 G2 R9 G10 G23 G25 R19 R10 G13 G5 R4 G31 R11 G29 R20 G30 G21 R21 G18 G14 
23815383.399 23418101.711 20126478.966 20576502.049 20850572.801 20361179.631 22177242.661 23871188.467 23896969.354 22949017.462 23330231.749 23194678.499 21898256.651 24811902.872 19151353.321 21666798.485 20650945.821 19472152.449 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
23794425.041 23402498.509 20141642.176 20584598.589 20869652.326 20367330.686 22196301.185 23890335.007 23883323.395 22925234.933 23334086.485 23188096.286 21881612.664 24830710.969 19148858.027 21645612.101 20642124.208 19462739.332 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
...
Task:
Выведем данные из файла Sirftin.
# Разработка программы Обработка и сортировка данных в файлах Rinex формата.
Decision:
root@kvmubuntu:/mnt/c/Windows/system32# cat sirfrin1.txt
2.10 OBSERVATION DATA G (GPS) RINEX VERSION / TYPE
...
       END OF HEADER
15 5 18 0 41 23.0000613 0 11G 1G12G32G24G22G14G11G 4G18G31G17
23527987.056 8
21972648.359 8
22403365.951 6
23784621.452 7
21148286.543 6
20408196.378 4
24488332.428 4
23108442.059 5
23196661.017 4
22514486.129 5
25648439.341 3
15 5 18 0 41 24.0000613 0 11G 1G12G32G24G22G14G11G 4G18G31G17
23527900.192 8
21972620.569 8
22402887.237 5
23785272.449 7
21148685.515 6
20408150.444 4
24488620.925 4
23108699.683 5
23197296.183 4
22513871.405 5
25648503.069 3
...
root@kvmubuntu:/mnt/c/Windows/system32# cat Unit1.cpp
//---------------------------------------------------------------------------
#include <iostream>
#include <vector>
#include <fstream>
#include <string.h>
#include <iomanip.h>
#include <cmath>
#include <vcl.h>>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
ifstream in ("sirfrin1.txt");
ofstream out ("output.txt");
//////// ������� END OF HEADER
string a;
while(true) {
  getline (in,a);
  if(a == "       END OF HEADER") {
    break;
  }
}
//////// ����
string name; // ������� ������
int temp; // �����
double temp2; // ����� � ������
int countSputnik; // ���������� ���������
vector <vector <double> > info; // ������� ������
vector <double> tempVector;
tempVector.resize(15); // ������ �������
vector <string> Sputnik; // ������� ������� �� ���������
vector <string> allSputnik; // ������� ������� �� ����� ����������
int index=-1; // ��������� ��������
string tempName = ""; // ������ �������� ���������
//////// ������� ������� � ���������
for(int i=0; i<4797; i++) { // ������� ����� ����
  in >> temp;
  in >> temp;
  in >> temp;
  in >> temp;
  in >> temp;
  in >> temp2;
  in >> temp;
  in >> countSputnik;
  // out << countSputnik << endl; // ���������� ���������
//////////////// ��������� �� �����
  getline(in,name);
  // out << name; // �������� ���������
//////////////// ��������� �������� ���������
  allSputnik.resize(0);
  index=-1;
  tempName = "";
  for(int i=0; i< name.size(); i++) {
   if(name[i] == '-') // ���� ��������� -
   break; // �� ���������
   if(name[i] >= 'A' && name[i] <= 'Z') { // ���� ��������� �����
    index++; // �� ��������� ������
    if(tempName != "") {
     allSputnik.push_back(tempName);
     tempName="";
    }
   }
   if (name[i] != ' '){
    tempName = tempName + name[i];
   }
  }
  if(tempName != "") {
   allSputnik.push_back(tempName);
   tempName="";
  }
  //tempName="";
//////////////// ������� ��� ��������� ��������� ������ ������
  /* for(int i=0; i<allSputnik.size(); i++){
   out << allSputnik[i] << endl;
  } */
//////////////// 2�� ������ �������� ���������
  /*if(index <= countSputnik-1) { //��������� ��������� �� ����� ���� ��������
   //getline(in,name); // ��������� ������ �� �����
   for(int i=0; i<name.size(); i++){
    if(name[i] >= 'A' && name[i] <= 'Z') {
     index++;
     if(tempName != "") {
      allSputnik.push_back(tempName);
      tempName="";
     }
    }
    if (name[i] != ' '){
     tempName = tempName + name[i];
    }
   }
  }
  if(tempName != "") {
   allSputnik.push_back(tempName);
   tempName="";
  }
  /* for(int i=0; i<allSputnik.size(); i++){
   out << allSputnik[i] << endl; // ������� ��� ��������� ��������� � ������ � ������ ������
  } */
/////////////// ��������� ���������� ���������
  info.push_back(tempVector);
  for(int i = 0; i<allSputnik.size(); i++) {
   double dalnost=0;
   string b = "";
   getline (in, b);
   a ="";
   if(b.size()>=14){
    a=b.substr(2,12); // �������� ������ ��� ����������
   }
   // out << a << endl; // ������� ���������� ���������
/////////////////////// ����������� ������ ������� � ������� ��� ���� ����� ���������� ������ ������
   int tochka=-1;
   int chislo=0;
   for (int i=0; i<a.size(); i++){
    if (a[i]>='0' && a[i]<='9'){
     dalnost = dalnost *10 + (a[i]-'0');
    }
    else {
     if(a[i]== '.') {
      tochka=i;
     }
    }
   }
   if(tochka != -1){
    chislo = a.size()-1 - tochka;
    chislo = (int) pow(10, (double)chislo);
    dalnost=dalnost/chislo;
   }
/////////////////////// ��������� �������� � ��������� � ������������
   // getline (in,name); //��������� �� ����� ����� ������
   index=-1;
   for(int j=0; j<Sputnik.size(); j++) {
    if(allSputnik[i] == Sputnik[j]) {
     index = j;
     break;
    }
   }
   if(index == -1) {
    Sputnik.push_back(allSputnik[i]);
    info[info.size()-1][Sputnik.size()-1] = dalnost;
   }
   else {
    info[info.size()-1][index] = dalnost;
   }

  }
}
//////// ������� ���������� �� �������
// out << endl;
for(int j=0; j<Sputnik.size(); j++) {
  out << setw(13) << Sputnik[j] << " ";
}
out << endl;
/////// ������� ���������� �� �������
for(int i=0; i<info.size(); i++) {
  for(int j=0; j<info[i].size(); j++) {
   out << setw(13) << setprecision(13) << info[i][j] << " ";
  }
  out << endl;
}
}
//---------------------------------------------------------------------------
root@kvmubuntu:/mnt/c/Windows/system32# cat output.txt
G1 G12 G32 G24 G22 G14 G11 G4 G18 G31 G17 G3 G25 G26 G29 
23527987.056 21972648.359 22403365.951 23784621.452 21148286.543 20408196.378 24488332.428 23108442.059 23196661.017 22514486.129 25648439.341 0 0 0 0 
23527900.192 21972620.569 22402887.237 23785272.449 21148685.515 20408150.444 24488620.925 23108699.683 23197296.183 22513871.405 25648503.069 0 0 0 0 
23527815.469 21972594.92 22402410.598 23785925.499 21149086.34 20408107.268 24488915.359 23108959.419 23197938.791 22513258.71 25648554.131 0 0 0 0 
23527729.677 21972568.22 22401932.854 23786577.382 21149485.828 20408062.76 24489187.365 23109217.855 23198578.688 22512592.942 25648601.174 0 0 0 0 
...
Task:
Нарисуйте График с файла Sirfrin1.
# Разработка программы Обработка и сортировка данных в файлах Rinex формата.
Decision:
root@kvmubuntu:/mnt/c/Windows/system32# cat Unit1.cpp
//---------------------------------------------------------------------------
#include <iostream>
#include <vector>
#include <fstream>
#include <string.h>
#include <iomanip.h>
#include <cmath>
#include <vcl.h>>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
ifstream in ("sirfrin1.txt");
ofstream out ("output.txt");
//////// ������� END OF HEADER
string a;
while(true) {
  getline (in,a);
  if(a == "       END OF HEADER") {
    break;
  }
}
//////// ����
string name; // ������� ������
int temp; // �����
double temp2; // ����� � ������
int countSputnik; // ���������� ���������
vector <vector <double> > info; // ������� ������
vector <double> tempVector;
tempVector.resize(15); // ������ �������
vector <string> Sputnik; // ������� ������� �� ���������
vector <string> allSputnik; // ������� ������� �� ����� ����������
int index=-1; // ��������� ��������
string tempName = ""; // ������ �������� ���������
//////// ������� ������� � ���������
for(int i=0; i<4797; i++) { // ������� ����� ����
  in >> temp;
  in >> temp;
  in >> temp;
  in >> temp;
  in >> temp;
  in >> temp2;
  in >> temp;
  in >> countSputnik;
  // out << countSputnik << endl; // ���������� ���������
//////////////// ��������� �� �����
  getline(in,name);
  // out << name; // �������� ���������
//////////////// ��������� �������� ���������
  allSputnik.resize(0);
  index=-1;
  tempName = "";
  for(int i=0; i< name.size(); i++) {
   if(name[i] == '-') // ���� ��������� -
   break; // �� ���������
   if(name[i] >= 'A' && name[i] <= 'Z') { // ���� ��������� �����
    index++; // �� ��������� ������
    if(tempName != "") {
     allSputnik.push_back(tempName);
     tempName="";
    }
   }
   if (name[i] != ' '){
    tempName = tempName + name[i];
   }
  }
  if(tempName != "") {
   allSputnik.push_back(tempName);
   tempName="";
  }
  //tempName="";
//////////////// ������� ��� ��������� ��������� ������ ������
  /* for(int i=0; i<allSputnik.size(); i++){
   out << allSputnik[i] << endl;
  } */
//////////////// 2�� ������ �������� ���������
  /*if(index <= countSputnik-1) { //��������� ��������� �� ����� ���� ��������
   //getline(in,name); // ��������� ������ �� �����
   for(int i=0; i<name.size(); i++){
    if(name[i] >= 'A' && name[i] <= 'Z') {
     index++;
     if(tempName != "") {
      allSputnik.push_back(tempName);
      tempName="";
     }
    }
    if (name[i] != ' '){
     tempName = tempName + name[i];
    }
   }
  }
  if(tempName != "") {
   allSputnik.push_back(tempName);
   tempName="";
  }
  /* for(int i=0; i<allSputnik.size(); i++){
   out << allSputnik[i] << endl; // ������� ��� ��������� ��������� � ������ � ������ ������
  } */
/////////////// ��������� ���������� ���������
  info.push_back(tempVector);
  for(int i = 0; i<allSputnik.size(); i++) {
   double dalnost=0;
   string b = "";
   getline (in, b);
   a ="";
   if(b.size()>=14){
    a=b.substr(2,12); // �������� ������ ��� ����������
   }
   // out << a << endl; // ������� ���������� ���������
/////////////////////// ����������� ������ ������� � ������� ��� ���� ����� ���������� ������ ������
   int tochka=-1;
   int chislo=0;
   for (int i=0; i<a.size(); i++){
    if (a[i]>='0' && a[i]<='9'){
     dalnost = dalnost *10 + (a[i]-'0');
    }
    else {
     if(a[i]== '.') {
      tochka=i;
     }
    }
   }
   if(tochka != -1){
    chislo = a.size()-1 - tochka;
    chislo = (int) pow(10, (double)chislo);
    dalnost=dalnost/chislo;
   }
/////////////////////// ��������� �������� � ��������� � ������������
   // getline (in,name); //��������� �� ����� ����� ������
   index=-1;
   for(int j=0; j<Sputnik.size(); j++) {
    if(allSputnik[i] == Sputnik[j]) {
     index = j;
     break;
    }
   }
   if(index == -1) {
    Sputnik.push_back(allSputnik[i]);
    info[info.size()-1][Sputnik.size()-1] = dalnost;
   }
   else {
    info[info.size()-1][index] = dalnost;
   }

  }
}
//////// ������� ���������� �� �������
// out << endl;
for(int j=0; j<Sputnik.size(); j++) {
  out << setw(13) << Sputnik[j] << " ";
}
out << endl;
/////// ������� ���������� �� �������
for(int i=0; i<info.size(); i++) {
  for(int j=0; j<info[i].size(); j++) {
   out << setw(13) << setprecision(13) << info[i][j] << " ";
  }
  out << endl;
}
out << endl;
for(int i=0; i<info.size(); i++){
  out << setw(13) << setprecision(13) << info[i][0] << setw(14) << info[i][1] << endl;
Form1->Memo1->Lines->Add(info[i][0]);
Form1->Memo2->Lines->Add(info[i][1]);
Form1->Memo3->Lines->Add(info[i][0]-info[i][1]);
//Series1->Add(info[i][0],clBlue);
//Series2->Add(info[i][1],clBlue);
Series2->Add(info[i][0]-info[i][1],clBlue);
}
}
//---------------------------------------------------------------------------
Task:
Нарисуйте График И Вычислите Разницу.
# Разработка программы Обработка и сортировка данных в файлах Rinex формата.
Decision:
root@kvmubuntu:/mnt/c/Windows/system32# cat Unit1.cpp
//---------------------------------------------------------------------------
#include <iostream>
#include <vector>
#include <fstream>
#include <string.h>
#include <iomanip.h>
#include <cmath>
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
ifstream in ("IRKL1119.txt");
ofstream out ("output.txt");
string a;
//���������� �� �� END OF HEADER
while(true) {
getline (in,a);
if(a == "       END OF HEADER") {
break;
}
}
string name;
// ������� ������� � ���������
int temp;
double temp2;
int countSputnik;
vector <vector <double> > info;
vector <double> tempVector;
tempVector.resize(53);
vector <string> Sputnik;
vector <string> allSputnik;// ������ ������ � ������� ����������
int index=-1; //��������� ��������
string tempName = "";
for(int i=0; i<2880; i++) {
in >> temp;
in >> temp;
in >> temp;
in >> temp;
in >> temp;
in >> temp2;
in >> temp;
in >> countSputnik;
/*out << countSputnik << endl; */
getline(in,name);
allSputnik.resize(0);
index=-1; //��������� ��������
tempName = ""; //
for(int i=0; i< name.size(); i++) {
if(name[i] == '-')
break;
if(name[i] >= 'A' && name[i] <= 'Z') {
index++;
if(tempName != "") {
allSputnik.push_back(tempName);
tempName="";
}
}
if (name[i] != ' '){
tempName = tempName + name[i];
}
}
if(tempName != "") {
allSputnik.push_back(tempName);
tempName="";
}
tempName="";
if(index <= countSputnik-1) { //��������� ��������� �� ����� ���� ��������
//2 stroka
getline(in,name);
for(int i=0; i<name.size(); i++){
if(name[i] >= 'A' && name[i] <= 'Z') {
  index++;
  if(tempName != "") {
   allSputnik.push_back(tempName);
   tempName="";
  }
}
if (name[i] != ' '){
  tempName = tempName + name[i];
}
}
}
if(tempName != "") {
allSputnik.push_back(tempName);
tempName="";
}
/*
for(int i=0; i<allSputnik.size(); i++){
out << allSputnik[i] << endl;
}
*/
info.push_back(tempVector);
for(int i = 0; i<allSputnik.size(); i++) {
double dalnost=0;
/*
in >> dalnost;
in >> dalnost;
*/
string b = "";
getline (in, b);
a ="";
if(b.size()>=14){
a=b.substr(1,13);
}
int tochka=-1;
int chislo=0;
for (int i=0; i<a.size(); i++){
  if (a[i]>='0' && a[i]<='9'){
   dalnost = dalnost *10 + (a[i]-'0');
  }
  else {
   if(a[i]== '.') {
    tochka=i;
   }
  }
}
if(tochka != -1){
  chislo = a.size()-1 - tochka;
  chislo = (int) pow(10, (double)chislo);
  dalnost=dalnost/chislo;
}
getline (in,name);
index=-1;
for(int j=0; j<Sputnik.size(); j++) {
  if(allSputnik[i] == Sputnik[j]) {
   index = j;
   break;
  }
}
if(index == -1) {
  Sputnik.push_back(allSputnik[i]);
  info[info.size()-1][Sputnik.size()-1] = dalnost;
}
else {
  info[info.size()-1][index] = dalnost;
}
}
}
// out << endl;
for(int j=0; j<Sputnik.size(); j++) {
out << setw(13) << Sputnik[j] << " ";
}
out << endl;
for(int i=0; i<info.size(); i++) {
for(int j=0; j<info[i].size(); j++) {
  out << setw(13) << setprecision(13) << info[i][j] << " ";
}
out << endl;
}
out << endl;
for(int i=0; i<info.size(); i++){
Form1->Memo1->Lines->Add(info[i][0]);
Form1->Memo2->Lines->Add(info[i][1]);
//Form1->Memo3->Lines->Add(info[i][0]-info[i][1]);
Series1->Add(info[i][0],clBlue);
Series2->Add(info[i][1],clBlue);
//out << setw(13) << setprecision(13) << info[i][0] << setw(14) << info[i][1] << endl;
}
}
//---------------------------------------------------------------------------
Task:
Попробуем просто сделать это все на графическом интерфейсе, вывести данные двух спутников, плюс еще нарисовать графики этих данных для двух спутников.
Теперь нужно обработать и сортировать данные с геометрической дальностью для спутников. Файл называется igr18451.txt. Вот как выглядят данные, которые нужно отсортировать. Тут уже одна эпоха равняется 15 минутам.
То что я выделил, это координаты спутника X,Y,Z. Именно их и нужно отсортировать. PG01 - название первого спутника. Попробуем вывести данные именно для него.
# Разработка программы Обработка и сортировка данных в файлах Rinex формата.
Decision:
PG04 16571.755106 7091.147720 19268.134634
PG04 17081.817393 9222.831883 17918.904800
PG04 17633.922784 11162.951350 16256.328779
PG04 18194.986791 12883.319207 14310.615388
PG04 18728.745598 14363.489413 12116.696076
PG04 19197.262350 15591.290270 9713.525830
PG04 19562.489921 16563.032391 7143.333216
PG04 19787.827341 17283.391677 4450.837454
PG04 19839.609715 17764.980464 1682.449322
PG04 19688.476298 18027.631365 -1114.528992
PG04 19310.568086 18097.427949 -3892.691773
PG04 18688.514262 18005.524210 -6605.294077
PG04 17812.175758 17786.800613 -9206.983073
PG04 16679.123638 17478.408399 -11654.488894
PG04 15294.839581 17118.255856 -13907.269035
PG04 13672.635233 16743.490595 -15928.101701
PG04 11833.296299 16389.030589 -17683.624513
PG04 9804.465824 16086.194088 -19144.815686
PG04 7619.789018 15861.474593 -20287.415200
...
Task:
Это мы вывели координаты X,Y,Z и название спутника. Но мне теперь нужно вывести данные только Х для первого спутника.
# Разработка программы Обработка и сортировка данных в файлах Rinex формата.
Decision:
14736.411108
15414.203154
16201.304785
17074.555745
18004.439905
18956.228081
19891.328698
20768.792721
21546.914135
...
Task:
Аналогично выводятся только для Y и Z выводим данные. Просто нужно поменять в коде x на y или z.
# Разработка программы Обработка и сортировка данных в файлах Rinex формата.
Task:
Аналогично нужно вывести данные псевдодальности полученные с моего приемника. файл - sirfrin1.txt.
Тут мы увидим только две данные для спутников. Первые, это дальность, которую как раз и нужно отсортировать по каждом НС, а вторые - сигналы спутника, которые нас не особо не интересуют. А также эпоха здесь начинается не с нуля, как мы видим, а с 41 минуты 23 секунды. Это тоже нужно учитывать, когда нужно будет сравнивать эти данные с ГД.
# Разработка программы Обработка и сортировка данных в файлах Rinex формата.
Decision:
Мы задачу выполнили (отсортировать данные ГД и ПД по каждом навигационному спутнику), остается только обработать эти данные по формулам и посторить по ним графики через Эксель.
Task:
Экспериментальные результаты.
# Спутниковые радионаввигационные системы.
Decision:
Для наглядности на рис. 14 показан пример измерения навигационных сигналов, принимаемых с НС GPS1 и GPS20, взятый из статьи [6]. По горизонтали отложены номера 30-ти секундных интервалов (эпох) от 0 часов всемирного времени. В верхней части рисунка даны результаты вычислений углов места НС GPS1 (пунктир) и GPS20 (точки). В нижней части рисунка тонкой линией в соответствии с формулой (3.4) показана разность измеренных псевдодальностей за вычетом разности ГД от этих НС с коррекцией запаздывания лучей в тропосфере по формуле (4.5). Для расчета ГД использовались уточненные эфемериды SP3 [6]. 
Рис. 14. Пример измерений вариаций ионосферы:

Здесь же для сравнения жирной линией приведена разность ионосферных ошибок для этих же НС по данным двухчастотного приемника JPS EGGDT станции Иркутск (IRKL). 
На рис. 15 показана средняя часть рис. 14 для детального сравнения данных о вариациях ионосферной ошибки, определяемой вариациями ПЭС между двумя НС [6].
Рис.15. Сравнение данных одночастотного и двухчастотного приемников: 

Видно, что для высоких углов места в среднем наблюдается хорошее совпадение результатов, полученных разными методами. Следует отметить, что случайные отклонения у одночастотного приемника примерно в два раза больше. При приближении НС к горизонту данные одночастотного приемника начинают сильно отличаться от двухчастотного, и при углах места около 5° различие доходит до 15-20 м (~ 60 нс). Вероятно, это связано с влиянием тропосферы и неучтенной при коррекции «влажной» составляющей тропосферной погрешности [6].
Приведенные данные свидетельствуют о близости результатов определения разности ионосферных ошибок двухчастотным и одночастотным приемниками. Как видно из сравнения описанных результатов, в диапазоне углов места больше 15° две кривые хорошо совпадают, различие между ними в 90% случаев не превышает 2 м (7 нс), при регулярном ходе около 20 м (70 нс) [6].
Для сравнения, я пытался построить свои примеры измерения навигационных сигналов. В прил. 3 показан код программы на языке С++, которая обрабатывает и сортирует данные ПД по каждому НС. На табл. 4 показан пример вычислений и интерпретаций данных с помощью EXCEL:
Таблица 4. Вычисления данных с помощью Excel: 

где x, y, z – координаты приёмника, а Xi, Yi, Zi – координаты спутника, ГД- вычисленная по формуле (4.1) геометрическая дальность, ПД – пседодальность и последний столбец является разностью ошибок ионосферы для двух спутников G1и G28 вычисленная по формуле (4.4).
На рис. 16-19 построены разности ошибок ионосферы для двух НС в один момент времени. Первая часть данных взяты из собственных измерений, а вторая часть данных для сравнения давались мне руководителем. По горизонтали отложены номера 15-ти минутных интервалов. 
Рис. 16. Пример измерений, принимаемых с GPS 1 и GPS 28, Рис. 17. Пример измерений, принимаемых с GPS 20 и GPS 32, Рис. 18. Пример измерений, принимаемых с GPS 2 и GPS 5, Рис. 19. Пример измерений, принимаемых с GPS 1 и GPS 4: 

Разность псевдодальности и геометрической дальности на рис. 16-17 является разностью ионосферной задержки и может быть использована для коррекции ионосферы. На рис. 18-19 получились большие разности, и такие данные использовать для уточнения состояния ионосферы при её оперативной коррекции нельзя.
Decision:
Для защиты диссертации по теме "Использование данных с одночастотных приемников спутниковых радионавигационных систем для коррекции модели ионосферы" освоил технологию приёма получения данных с одночастотных приемников спутниковых радионавигационных систем, получил данные, разработал программу на C++, которая обрабатывает и сортирует данные двух координат из файла по столбцам, рисует график, чтобы увидеть желаемый результат в точности определения координат спутников, рассмотрел способы уменьшения ошибок измерения псевдодальности и показал, что из-за нестабильности аппаратуры потребителя информация о состоянии ионосферы может быть получена в каждый момент времени по разностям ПД двух навигационных спутников 
Decision:
Защитил диплом выпускной квалификационной работы бакалавра и магистерскую диссертацию.
Source:
# https://forum.calculate-linux.org/t/windows-qemu-kvm-libvirt/9357
# https://blog.sedicomm.com/2019/07/21/rdesktop-klient-rdp-dlya-podklyucheniya-rabochego-stola-windows-iz-linux/
# https://learn.microsoft.com/ru-ru/windows-server/administration/openssh/openssh_install_firstuse
# https://learn.microsoft.com/ru-ru/powershell/scripting/learn/remoting/ssh-remoting-in-powershell-core?view=powershell-7.3
# https://learn.microsoft.com/en-us/powershell/module/storage/dismount-diskimage?view=windowsserver2022-ps
# https://superuser.com/questions/499264/how-can-i-mount-an-iso-via-powershell-programmatically
# https://winitpro.ru/index.php/2016/03/31/sftp-ssh-ftp-na-windows-server-2012-r2/
# https://mhelp.pro/ru/kak-zapustit-powershell-ot-imeni-administratora/?ysclid=lmzwqntxfi559273426
# https://remontka.pro/text-files-cmd-powershell/?ysclid=lmzy2p5172409325479
# https://www.digitalocean.com/community/tutorials/sftp-ru
# http://ftp.glonass-iac.ru/guide/navfaq.php
# https://ru.wtuseripedia.org/wtuseri/%D0%A1%D0%BF%D1%83%D1%82%D0%BD%D0%B8%D0%BA%D0%BE%D0%B2%D0%B0%D1%8F_%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0_%D0%BD%D0%B0%D0%B2%D0%B8%D0%B3%D0%B0%D1%86%D0%B8%D0%B8
# Харисов В.Н. Глобальная спутниковая радионавигационная система ГЛОНАСС
# Грудинская Г.П. Распространение радиоволн
# http://begin.clan.su/news/speciftusera_provedenija_psevdodalnomernykh_i_fazov/2013-09-18-135
# http://rrv.iszf.irk.ru/sites/default/files/conf2014/articles/tom2/17-20.pdf
# http://www.u-blox.com
# Дэвис К. Радиоволны в ионосфере
# https://www.youtube.com/watch?v=bDvVosvyVp0&list=LL&index=315

2022-11-01 - 2023-05-30: Сбер Университет, Иркутск. Должность: Инженер с большими данными - Дополнительное образование. Дополнительная информация: Навыки: Виртуализация, Linux, Sql, Python, English, Clouds, Bash, Etl-процессы, DWH, AntiFraud. Достижения: При работе с транзакционными банковскими данными с помощью Python и SQL разработал хранилище данных - DWH, процесс сбора, очистки, трансформации и хранения данных, систему автоматического поиска мошеннических операций (AntiFraud-система).

Show

# Администрирование локальных, виртуальных и облачных серверов.
# Разработка Хранилище данных.
Task:
Администрирование локальных, виртуальных и облачных серверов. Docker установка
Decision:
$ sudo apt update
$ sudo apt install apt-transport-https ca-certificates curl software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
$ echo"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
$ sudo apt update
$ apt-cache policy docker-ce
$ sudo apt install docker-ce
$ systemctl status docker
$ sudo docker run hello-world
$ sudo usermod -aG docker tuser
$ docker run hello-world
$ curl -SL https://github.com/docker/compose/releases/download/v2.6.0/docker-compose-linux-x86_64 -o ~/.docker/cli-plugins/docker-compose
$ chmod +x ~/.docker/cli-plugins/docker-compose
$ docker compose version
Task:
Администрирование локальных, виртуальных и облачных серверов. Create Postgres Docker Image
Decision:
$ mkdir docks
$ mkdir docks/postgres
$ touch docks/postgres/Dockerfile
$ vim docks/postgres/Dockerfile
$ cat docks/postgres/Dockerfile
FROM postgres:latest
ENV POSTGRES_USER YOUR-USERNAME
ENV POSTGRES_PASSWORD YOUR-PASSWORD
ENV POSTGRES_DB YOUR-DB
EXPOSE 5432 
$ cd docks/postgres/
$ docker build -t YOUR-DB/postgres .
$ docker run -d --name postg -p 5432:5432 YOUR-DB/postgres
FULLYOUR-ID1
$ sudo netstat -tulpn | grep 5432
$ docker logs -f postg
$ docker ps
$ docker ps -a
CONTAINER ID   IMAGE                          COMMAND                  CREATED        STATUS                       PORTS                                       NAMES
YOUR-ID1   YOUR-DB/postgres                 "docker-entrypoint.s…"   10 hours ago   Exited (255) 5 minutes ago   0.0.0.0:5432->5432/tcp, :::5432->5432/tcp   postg
$ docker start postg
Task:
Администрирование локальных, виртуальных и облачных серверов. Pgadmin Postgres Docker container
Decision:
$ google-chrome https://www.pgadmin.org/download/ &
$ curl -fsS https://www.pgadmin.org/static/packages_pgadmin_org.pub | sudo gpg --dearmor -o /usr/share/keyrings/packages-pgadmin-org.gpg
$ sudo sh -c 'echo "deb [signed-by=/usr/share/keyrings/packages-pgadmin-org.gpg] https://ftp.postgresql.org/pub/pgadmin/pgadmin4/apt/$(lsb_release -cs) pgadmin4 main" > /etc/apt/sources.list.d/pgadmin4.list && apt update'
$ sudo apt install pgadmin4
$ sudo /usr/pgadmin4/bin/setup-web.sh
$ docker ps -a
CONTAINER ID   IMAGE                          COMMAND                  CREATED        STATUS                        PORTS                                       NAMES
YOUR-ID   YOUR-DB/postgres                 "docker-entrypoint.s…"   45 hours ago   Exited (255) 37 seconds ago   0.0.0.0:5432->5432/tcp, :::5432->5432/tcp   postg
$ docker start postg
$ google-chrome http://YOUR-IP/pgadmin4 &
Task:
Администрирование локальных, виртуальных и облачных серверов. Stop, remove postgres container
Decision:
$ docker stop postg
$ docker rm postg
$ docker push YOUR-DB/postgres
Task:
Разработка Хранилище данных. Разработать ETL процесс, получающий ежедневную выгрузку данных (предоставляется за 3 дня), загружающий ее в хранилище данных и ежедневно строящий отчет.
Ежедневно некие информационные системы выгружают три следующих файла:
1. Список транзакций за текущий день. Формат – CSV.
2. Список терминалов полным срезом. Формат – XLSX.
3. Список паспортов, включенных в «черный список» - с накоплением с начала месяца. Формат – XLSX.
Сведения о картах, счетах и клиентах хранятся в СУБД PostgreSQL. Во вложении реквизиты для подключения. 
Вам предоставляется выгрузка за последние три дня, ее надо обработать. В качестве хранилища выступает ваша учебная база (edu). Данные должны быть загружены в хранилище со следующей структурой (имена сущностей указаны по существу, без особенностей правил нейминга, указанных далее).
Типы данных в полях можно изменять на однородные если для этого есть необходимость. Имена полей менять нельзя. Ко всем таблицам SCD1 должны
быть добавлены технические поля create_dt, update_dt; ко всем таблицам SCD2 должны быть добавлены технические поля effective_from, effective_to, deleted_flg.
По результатам загрузки ежедневно необходимо строить витрину отчетности по мошенническим операциям. Витрина строится накоплением, каждый новый отчет укладывается в эту же таблицу с новым report_dt.
В витрине должны содержаться следующие поля:
1. event_dt - Время наступления события. Если событие наступило по результату нескольких действий – указывается время действия, по которому установлен факт мошенничества.
2. passport - Номер паспорта клиента, совершившего мошенническую операцию.
3. fio - ФИО клиента, совершившего мошенническую операцию.
4. phone - Номер телефона клиента, совершившего мошенническую операцию.
5. event_type - Описание типа мошенничества.
6. report_dt - Время построения отчета.
Признаки мошеннических операций:
1. Совершение операции при просроченном или заблокированном паспорте.
2. Совершение операции при недействующем договоре.
3. Совершение операций в разных городах в течение одного часа.
4. Попытка подбора суммы. В течение 20 минут проходит более 3х операций соследующим шаблоном – каждая последующая меньше предыдущей, при этом отклонены все кроме последней. Последняя операция (успешная) в такой цепочке считается мошеннической.
При именовании таблиц необходимо придерживаться следующих правил (для автоматизации проверки):
1. YOUR-USERNAME.<CODE>_STG_<TABLE_NAME> - Таблицы для размещения стейджинговых таблиц (первоначальная загрузка), промежуточное выделение инкремента, если требуется. Временные таблицы, если такие потребуются в расчете, можно также складывать с таким именованием. Имя таблиц можете выбирать произвольное, но смысловое.
2. YOUR-USERNAME.<CODE>_DWH_FACT_<TABLE_NAME> - Таблицы фактов, загруженных в хранилище. В качестве фактов выступают сами транзакции и «черный список» паспортов. Имя таблиц – как в ER диаграмме.
3. YOUR-USERNAME.<CODE>_DWH_DIM_<TABLE_NAME> - Таблицы измерений, хранящиеся в формате SCD1. Имя таблиц – как в ER диаграмме.
4. YOUR-USERNAME.<CODE>_DWH_DIM_<TABLE_NAME>_HIST - Таблицы измерений, хранящиеся в SCD2 формате (только для тех, кто выполняет усложненное задание). Имя таблиц – как в ER диаграмме.
5. YOUR-USERNAME.<CODE>_REP_FRAUD - Таблица с отчетом.
6. YOUR-USERNAME.<CODE>_META_<TABLE_NAME> - Таблицы для хранения метаданных. Имя таблиц можете выбирать произвольное, но
смысловое.
7. <CODE> - 4 буквы вашего персонального кода.
Выгружаемые файлы именуются согласно следующему шаблону:
1. transactions_DDMMYYYY.txt
2. passport_blacklist_DDMMYYYY.xlsx
3. terminals_DDMMYYYY.xlsx
Предполагается что в один день приходит по одному такому файлу. После загрузки соответствующего файла он должен быть переименован в файл с расширением .backup чтобы при следующем запуске файл не искался и перемещен в каталог archive:
1. transactions_DDMMYYYY.txt.backup
2. passport_blacklist_DDMMYYYY.xlsx.back
3. upterminals_DDMMYYYY.xlsx.backup
Желающие могут придумать, обосновать и реализовать более технологичные и учитывающие сбои способы обработки (за это будет повышен балл).
В classroom выкладывается zip-архив, содержащий следующие файлы и каталоги:
1. main.py - Файл, обязательный. Основной процесс обработки.
2. файлы с данными - Файл, обязательный. Те файлы, которые вы получили в качестве задания. Просто скопируйте все 9 файлов.
3. main.ddl - Файл, обязательный. Файл с SQL кодом для создания всех необходимых объектов в базе edu.
4. main.cron - Файл, обязательный. Файл для постановки вашего процесса на расписание, в формате crontab
5. archive - Каталог, обязательный. Пустой, сюда должны перемещаться отработанные файлы
6. sql_scripts - Каталог, необязательный. Если вы включаете в main.py какие-то SQL скрипты, вынесенные в отдельные файлы – помещайте их сюда.
7. py_scripts - Каталог, необязательный. Если вы включаете в main.py какие-то python скрипты, вынесенные в отдельные файлы – помещайте их сюда.
Decision:
$ mkdir archive
$ touch main.py
$ chmod +x main.py
$ touch main.ddl
$ touch main.cron
$ cat snippet_pg.py
import psycopg2
import pandas as pd
# Создание подключения к PostgreSQL
conn = psycopg2.connect (
        database = "YOUR-DB",
        host =     "YOUR-IP",
        user =     "YOUR-USERNAME",
        password = "YOUR-PASSWORD",
        port =     "5432"
    )
# Отключение автокоммита
conn.autocommit = False
# Создание курсора
cursor = conn.cursor()
####################################################
# Выполнение SQL кода в базе данных без возврата результата
cursor.execute( "INSERT INTO YOUR-USERNAME.testtable( id, val ) VALUES ( 1, 'ABC' )" )
conn.commit()
# Выполнение SQL кода в базе данных с возвратом результата
cursor.execute( "SELECT * FROM YOUR-USERNAME.testtable" )
records = cursor.fetchall()
for row in records:
    print( row )
####################################################
# Формирование DataFrame
names = [ x[0] for x in cursor.description ]
df = pd.DataFrame( records, columns = names )
# Запись в файл
df.to_excel( 'pandas_out.xlsx', sheet_name='sheet1', header=True, index=False )
####################################################
# Чтение из файла
df = pd.read_excel( 'pandas.xlsx', sheet_name='sheet1', header=0, index_col=None )
# Запись DataFrame в таблицу базы данных
cursor.executemany( "INSERT INTO YOUR-USERNAME.testtable( id, val ) VALUES( %s, %s )", df.values.tolist() )
# Закрываем соединение
cursor.close()
conn.close()
$ /SCD1_incremental_full_script.sql 
----------------------------------------------------------------------------
-- Подготока данных

create table YOUR-USERNAME.XXXX_source( 
        id integer,
        val varchar(50),
        update_dt timestamp(0)
);
insert into YOUR-USERNAME.XXXX_source ( id, val, update_dt ) values ( 1, 'A', now() );
insert into YOUR-USERNAME.XXXX_source ( id, val, update_dt ) values ( 2, 'B', now() );
insert into YOUR-USERNAME.XXXX_source ( id, val, update_dt ) values ( 3, 'C', now() );
update YOUR-USERNAME.XXXX_source set val = 'X', update_dt = now() where id = 3;
delete from YOUR-USERNAME.XXXX_source where id = 3;
create table YOUR-USERNAME.XXXX_stg( 
        id integer,
        val varchar(50),
        update_dt timestamp(0)
);
create table YOUR-USERNAME.XXXX_target (
        id integer,
        val varchar(50),
        create_dt timestamp(0),
        update_dt timestamp(0)
);
create table YOUR-USERNAME.XXXX_meta(
    schema_name varchar(30),
    table_name varchar(30),
    max_update_dt timestamp(0)
);
insert into YOUR-USERNAME.XXXX_meta( schema_name, table_name, max_update_dt )
values( 'YOUR-USERNAME','XXXX_SOURCE', to_timestamp('1900-01-01','YYYY-MM-DD') );
create table YOUR-USERNAME.XXXX_stg_del( 
        id integer
);
----------------------------------------------------------------------------
-- Инкрементальная загрузка
-- 1. Очистка стейджинговых таблиц
delete from YOUR-USERNAME.XXXX_stg;
delete from YOUR-USERNAME.XXXX_stg_del;
-- 2. Захват данных из источника (измененных с момента последней загрузки) в стейджинг
insert into YOUR-USERNAME.XXXX_stg( id, val, update_dt )
select id, val, update_dt from YOUR-USERNAME.XXXX_source
where update_dt > ( select max_update_dt from YOUR-USERNAME.XXXX_meta where schema_name='YOUR-USERNAME' and table_name='XXXX_SOURCE' );
-- 3. Захват в стейджинг ключей из источника полным срезом для вычисления удалений.
insert into YOUR-USERNAME.XXXX_stg_del( id )
select id from YOUR-USERNAME.XXXX_source;
-- 4. Загрузка в приемник "вставок" на источнике (формат SCD1).
insert into YOUR-USERNAME.XXXX_target( id, val, create_dt, update_dt )
select 
        stg.id, 
        stg.val, 
        stg.update_dt, 
        null 
from YOUR-USERNAME.XXXX_stg stg
left join YOUR-USERNAME.XXXX_target trg
on stg.id = trg.id
where trg.id is null;
-- 5. Обновление в приемнике "обновлений" на источнике (формат SCD1).
update YOUR-USERNAME.XXXX_target
set 
        val = tmp.val,
        update_dt = tmp.update_dt
from (
        select 
                stg.id, 
                stg.val, 
                stg.update_dt, 
                null 
        from YOUR-USERNAME.XXXX_stg stg
                inner join YOUR-USERNAME.XXXX_target trg on stg.id = trg.id
        where stg.val <> trg.val 
                or ( stg.val is null and trg.val is not null ) or ( stg.val is not null and trg.val is null )
) tmp
where XXXX_target.id = tmp.id; 
-- 6. Удаление в приемнике удаленных в источнике записей (формат SCD1).
delete from YOUR-USERNAME.XXXX_target
where id in (
        select trg.id
        from YOUR-USERNAME.XXXX_target trg
        left join YOUR-USERNAME.XXXX_stg_del stg
        on stg.id = trg.id
        where stg.id is null
);
-- 7. Обновление метаданных.
update YOUR-USERNAME.XXXX_meta
set max_update_dt = coalesce( (select max( update_dt ) from YOUR-USERNAME.XXXX_stg ), ( select max_update_dt from YOUR-USERNAME.XXXX_meta where schema_name='YOUR-USERNAME' and table_name='XXXX_SOURCE' ) )
where schema_name='YOUR-USERNAME' and table_name = 'XXXX_SOURCE';
-- 8. Фиксация транзакции.
commit;
SCD1_incremental_full_script.sql
SCD1_incremental_full_script.sql. На экране
$ wget https://drive.google.com/file/d/13WSK0C1Z36hhsopebgEv2bGLAoxEsLUp/view?usp=drive_web&authuser=0
$ unzip data.zip
Task:
Разработка Хранилище данных. Создадите таблицы в базе
Decision:
$ vim main.ddl
$ cat main.ddl
#!/usr/bin/python3
----------------------------------
create table YOUR-USERNAME.XXXX_stg_transactions(
    trans_id varchar(15),
    trans_date timestamp(0),
    --amt decimal(10,2),
    amt numeric(10,2),    
    card_num varchar(20),
    oper_type varchar(10),
    oper_result varchar(10),
    terminal varchar(10),
    create_dt timestamp(0), 
    update_dt timestamp(0));
create table YOUR-USERNAME.XXXX_dwh_fact_transactions(
    trans_id varchar(15),
    trans_date timestamp(0),
    --amt numeric(10,2),
    amt decimal(10,2),
    card_num varchar(20),
    oper_type varchar(10),
    oper_result varchar(10),
    terminal varchar(10),
    create_dt timestamp(0), 
    update_dt timestamp(0));
----------------------------------
create table YOUR-USERNAME.XXXX_stg_terminals(
    terminal_id varchar(10),
    terminal_type varchar(10),
    terminal_city varchar(30),
    terminal_address varchar(70),
    create_dt timestamp(0), 
    update_dt timestamp(0));
create table YOUR-USERNAME.XXXX_dwh_dim_terminals(
    terminal_id varchar(10),
    terminal_type varchar(10),
    terminal_city varchar(30),
    terminal_address varchar(70),
    create_dt timestamp(0),
    update_dt timestamp(0),
    effective_from timestamp(0),
    effective_to timestamp(0),
    deleted_flg char(1));
create table YOUR-USERNAME.XXXX_stg_del_terminals(
    terminal_id varchar(10));
----------------------------------
create table YOUR-USERNAME.XXXX_stg_blacklist(
    passport_num varchar(15),
    --entry_dt date
    entry_dt timestamp(0),
    create_dt timestamp(0), 
    update_dt timestamp(0));
create table YOUR-USERNAME.XXXX_dwh_fact_passport_blacklist(
    passport_num varchar(30),
    --entry_dt date
    --date timestamp(0)
    entry_dt timestamp(0),
    create_dt timestamp(0), 
    update_dt timestamp(0));
----------------------------------
create table YOUR-USERNAME.XXXX_stg_cards(
    card_num varchar(20),
    account_num varchar(20),
    create_dt timestamp(0),
    update_dt timestamp(0));
create table YOUR-USERNAME.XXXX_dwh_dim_cards(
    card_num varchar(20),
    account_num varchar(20),
    --create_dt date,
    --update_dt date
    create_dt timestamp(0), 
    update_dt timestamp(0),
    effective_from timestamp(0),
    effective_to timestamp(0),
    deleted_flg char(1));
create table YOUR-USERNAME.XXXX_stg_del_cards(
    card_num varchar(20));
----------------------------------
create table YOUR-USERNAME.XXXX_stg_accounts(
    account_num varchar(20),
    --valid_to date,
    valid_to timestamp(0), 
    client varchar(10),
    create_dt timestamp(0),
    update_dt timestamp(0));
create table YOUR-USERNAME.XXXX_dwh_dim_accounts(
    account_num varchar(20),
    --valid_to date,
    valid_to timestamp(0), 
    client varchar(10),
    --create_dt date,
    --update_dt date
    create_dt timestamp(0), 
    update_dt timestamp(0),
    effective_from timestamp(0),
    effective_to timestamp(0),
    deleted_flg char(1)); 
create table YOUR-USERNAME.XXXX_stg_del_accounts(
    account_num varchar(20));
----------------------------------
create table YOUR-USERNAME.XXXX_stg_clients(
    client_id varchar(10),
    last_name varchar(20),
    first_name varchar(20),
    patronymic varchar(20),
    --date_of_birth date,
    date_of_birth timestamp(0), 
    passport_num varchar(15),
    --passport_valid_to date,
    passport_valid_to timestamp(0),
    phone varchar(16),
    create_dt timestamp(0),
    update_dt timestamp(0));
create table YOUR-USERNAME.XXXX_dwh_dim_clients(
    client_id varchar(10),
    last_name varchar(20),
    first_name varchar(20),
    patronymic varchar(20),
    --date_of_birth date,
    date_of_birth timestamp(0),
    passport_num varchar(15),
    --passport_valid_to date,
    passport_valid_to timestamp(0),
    phone varchar(16),
    --create_dt date,
    --update_dt date
    create_dt timestamp(0), 
    update_dt timestamp(0),
    effective_from timestamp(0),
    effective_to timestamp(0),
    deleted_flg char(1));
create table YOUR-USERNAME.XXXX_stg_del_clients(
    client_id varchar(10));
----------------------------------
create table YOUR-USERNAME.XXXX_rep_fraud(
    event_dt timestamp(0), 
    passport varchar(20), 
    fio varchar(50),
    phone varchar(16), 
    event_type varchar(120), 
    --report_dt date
    report_dt timestamp(0));
----------------------------------
create table YOUR-USERNAME.XXXX_meta(
    schema_name varchar(30),
    table_name varchar(30),
    max_update_dt timestamp(0));
----------------------------------
Task:
Разработка Хранилище данных. Алгоритм для файла main.py: Подключитесь к двум базам, Очистите весь стейджинг. Загрузите файлы transactions_01032021.txt, terminals_01032021.xlsx, passport_blacklist_01032021.xlsx в стейджинг. Загрузите таблицы clients, accounts, cards в стейджинг. Используйте следующий подход: Выполните запрос к базе 1, Сохраните полученный результат в DataFrame, Загрузите DataFrame в базу 2. Загрузите данные из стейджинга в целевую таблицу xxxx_dwh_dim_terminals, xxxx_dwh_dim_cards, xxxx_dwh_dim_accounts, xxxx_dwh_dim_clients. Загрузите данные из стейджинга в целевую таблицу xxxx_dwh_fact_passport_blacklist, xxxx_dwh_fact_transactions.. Фактовые таблицы данные перекладываются «простым инсертом», то есть необходимо выполнить один INSERT INTO ... SELECT .... Напишите скрипт, соединяющий нужные таблицы для поиска операций, совершенных при недействующем договоре. Отладьте ваш скрипт для одной даты PgAdmin, он должен выдавать результат. Результат выполнения скрипта загружайте в таблицу xxxx_rep_fraud. Незабывайте сформировать поле report_dt. Зафиксируйте изменения. Отключитесь от баз. Переименуйте обработанные файлы и перенесите их в другой каталог. отладить его работоспособность навсех трех днях загрузки.
Decision:
$ vim main.py
$ cat main.py
#!/usr/bin/python3
import pandas as pd
import psycopg2
import os
###################Подключение к базам
#conn_YOUR-DB1 = psycopg2.connect(database = "YOUR-DB",host = "YOUR-IP",user = "YOUR-USERNAME",password = "YOUR-PASSWORD",port = "5432")
conn_YOUR-DB1 = psycopg2.connect(database = "YOUR-DB1",host = "YOUR-HOST",user = "YOUR-USERNAME1",password = "YOUR-PASSWORD1",port = "5432")
conn_YOUR-DB2 = psycopg2.connect(database = "bank",host = "YOUR-HOST",user = "YOUR-USERNAME2",password = "YOUR-PASSWORD2",port = "5432")
conn_YOUR-DB1.autocommit = False
conn_YOUR-DB2.autocommit = False
cursor_YOUR-DB1 = conn_YOUR-DB1.cursor()
cursor_YOUR-DB2 = conn_YOUR-DB2.cursor()
######################################
###################Очистка стейджинговых таблиц
cursor_YOUR-DB1.execute("""DELETE FROM YOUR-USERNAME1.XXXX_stg_transactions;""")
###################Загрузка данных в стейджинг
#df = pd.read_csv(f'/home/YOUR-USERNAME1/XXXX/project/data/transactions_01032021.txt', sep=';', decimal=',', header=0, index_col=None)
dirpath = "/home/YOUR-USERNAME1/XXXX/project"
project_files = os.listdir(dirpath)
for transactions in project_files:
        if transactions.endswith('.txt'):
                df = pd.read_csv(transactions, sep=";")
                datenow_w_txt = transactions.rsplit('_')[1]
                datenow_str = datenow_w_txt.split('.')[0]
df['amount'] = df['amount'].map(lambda z: z.strip().replace(',', '.')).astype('float')
df['create_dt'] = datenow_str
df['update_dt'] = datenow_str
###################
cursor_YOUR-DB1.executemany("""
                INSERT INTO YOUR-USERNAME1.XXXX_stg_transactions(trans_id, trans_date, amt, card_num, oper_type, oper_result, terminal , create_dt, update_dt) 
                VALUES(%s, %s , %s , %s , %s , %s , %s, to_timestamp(%s,'DDMMYYYY'), to_timestamp(%s,'DDMMYYYY'))
        """, df.values.tolist())
###################Загрузка данных в целевые таблицы фактов
cursor_YOUR-DB1.execute("""
                INSERT INTO YOUR-USERNAME1.XXXX_dwh_fact_transactions (trans_id,trans_date,card_num,oper_type,amt,oper_result,terminal,create_dt,update_dt)
                SELECT stg.trans_id,stg.trans_date,stg.card_num,stg.oper_type,stg.amt,stg.oper_result,stg.terminal,stg.create_dt,stg.update_dt 
                FROM YOUR-USERNAME1.XXXX_stg_transactions as stg;
        """)
###################
######################################
###################Очистка стейджинговых таблиц
cursor_YOUR-DB1.execute("""DELETE FROM YOUR-USERNAME1.XXXX_stg_terminals;""")
###################Загрузка данных в стейджинг
#df = pd.read_excel(f'/home/YOUR-USERNAME1/XXXX/project/data/terminals_01032021.xlsx', sheet_name='terminals', header=0, index_col=None)
for terminals in project_files:
        if terminals.startswith('terminals'):
                df = pd.read_excel(terminals, sheet_name='terminals', header=0, index_col=None )
                datenow_w_txt = terminals.rsplit('_')[1]
                datenow_str = datenow_w_txt.split('.')[0]
df['create_dt'] = datenow_str
df['update_dt'] = datenow_str
#df.insert(4, 'update_dt','2021-03-01')
###################
cursor_YOUR-DB1.executemany("""
                INSERT INTO YOUR-USERNAME1.XXXX_stg_terminals(terminal_id,terminal_type,terminal_city,terminal_address,create_dt,update_dt)
                VALUES(%s,%s,%s,%s,to_timestamp(%s,'DDMMYYYY'),to_timestamp(%s,'DDMMYYYY'));
        """, df.values.tolist())
###################Загрузка данных в целевые таблицы измерений
cursor_YOUR-DB1.execute("""
                INSERT INTO YOUR-USERNAME1.XXXX_dwh_dim_terminals (terminal_id,terminal_type,terminal_city,terminal_address,create_dt,update_dt)
                SELECT stg.terminal_id, stg.terminal_type, stg.terminal_city, stg.terminal_address, stg.update_dt,to_timestamp('9999-12-31', 'YYYY-MM-DD') 
                from YOUR-USERNAME1.XXXX_stg_terminals as stg  
                left join YOUR-USERNAME1.XXXX_dwh_dim_terminals as trg
                on stg.terminal_id = trg.terminal_id 
                where trg.terminal_id is null;
        """)
###################
######################################
###################Очистка стейджинговых таблиц
cursor_YOUR-DB1.execute("""DELETE FROM YOUR-USERNAME1.XXXX_stg_blacklist;""")
###################Загрузка данных в стейджинг
#df = pd.read_excel(f'/home/YOUR-USERNAME1/XXXX/project/data/passport_blacklist_01032021.xlsx', sheet_name='blacklist', header=0, index_col=None)
for blacklist in project_files:
        if blacklist.startswith('passport_blacklist'):
                df = pd.read_excel(blacklist, sheet_name='blacklist', header=0, index_col=None )
                datenow_w_ext = blacklist.rsplit('blacklist_')[1]
                datenow_str = datenow_w_ext.split('.')[0]
df['create_dt'] = datenow_str
df['update_dt'] = datenow_str
###################
cursor_YOUR-DB1.executemany("""
                INSERT INTO YOUR-USERNAME1.XXXX_stg_blacklist(entry_dt,passport_num,create_dt,update_dt)
                VALUES(%s, %s,to_timestamp(%s,'DDMMYYYY'),to_timestamp(%s,'DDMMYYYY'));
        """, df.values.tolist())
###################Загрузка данных в целевые таблицы фактов
cursor_YOUR-DB1.execute("""
                INSERT INTO YOUR-USERNAME1.XXXX_dwh_fact_passport_blacklist 
                SELECT stg.passport_num,stg.entry_dt,stg.create_dt,stg.update_dt
                from YOUR-USERNAME1.XXXX_stg_blacklist as stg 
                left join YOUR-USERNAME1.XXXX_dwh_fact_passport_blacklist as trg 
                on stg.passport_num = trg.passport_num 
                where trg.passport_num is null;
        """)
######################################
###################Очистка стейджинговых таблиц
cursor_YOUR-DB1.execute("""DELETE FROM YOUR-USERNAME1.XXXX_stg_cards;""")
###################Загрузка данных в стейджинг
cursor_YOUR-DB2.execute("""
                --SELECT regexp_replace(card_num, '\s+$', '') as card_num,account,create_dt,update_dt 
                SELECT card_num,account,create_dt,update_dt 
                FROM info.cards
        """)
records = cursor_YOUR-DB2.fetchall()
#for row in records:
#    print(row)
names = [ x[0] for x in cursor_YOUR-DB2.description ]
df = pd.DataFrame( records, columns = names )
cursor_YOUR-DB1.executemany("""
                INSERT INTO YOUR-USERNAME1.XXXX_stg_cards(card_num,account_num,create_dt,update_dt) 
                VALUES(%s,%s,%s,%s)
        """, df.values.tolist())
###################Загрузка данных в целевые таблицы измерений
cursor_YOUR-DB1.execute("""
                INSERT INTO YOUR-USERNAME1.XXXX_dwh_dim_cards (card_num,account_num,create_dt,update_dt)
                SELECT stg.card_num, stg.account_num, stg.create_dt, to_timestamp('9999-12-31', 'YYYY-MM-DD')
                from YOUR-USERNAME1.XXXX_stg_cards as stg 
                left join YOUR-USERNAME1.XXXX_dwh_dim_cards as trg 
                on stg.card_num = trg.card_num 
                where trg.card_num is null;
        """)
###################
######################################
###################Очистка стейджинговых таблиц
cursor_YOUR-DB1.execute("""DELETE FROM YOUR-USERNAME1.XXXX_stg_accounts;""")
###################Загрузка данных в стейджинг
cursor_YOUR-DB2.execute("""
                SELECT account,valid_to,client,create_dt,update_dt 
                FROM info.accounts
        """)
records = cursor_YOUR-DB2.fetchall()
#for row in records:
#        print(row)
names = [ x[0] for x in cursor_YOUR-DB2.description ]
df = pd.DataFrame( records, columns = names )
cursor_YOUR-DB1.executemany("""
                INSERT INTO YOUR-USERNAME1.XXXX_stg_accounts(account_num,valid_to,client,create_dt,update_dt)
                VALUES( %s, %s, %s, %s, %s)
        """, df.values.tolist())
###################Загрузка данных в целевые таблицы измерений
cursor_YOUR-DB1.execute("""
                INSERT INTO YOUR-USERNAME1.XXXX_dwh_dim_accounts(account_num,valid_to,client,create_dt,update_dt) 
                SELECT stg.account_num,stg.valid_to,stg.client,stg.create_dt,to_timestamp('9999-12-31', 'YYYY-MM-DD')
                        from YOUR-USERNAME1.XXXX_stg_accounts as stg 
                left join YOUR-USERNAME1.XXXX_dwh_dim_accounts as trg
                on stg.account_num = trg.account_num 
                where trg.account_num is null;
        """)
###################
######################################
###################Очистка стейджинговых таблиц
cursor_YOUR-DB1.execute("""DELETE FROM YOUR-USERNAME1.XXXX_stg_clients;""")
###################Загрузка данных в стейджинг
cursor_YOUR-DB2.execute("""
                SELECT client_id,last_name,first_name,patronymic,date_of_birth,passport_num,passport_valid_to,phone,create_dt,update_dt
                FROM info.clients; 
        """)
records = cursor_YOUR-DB2.fetchall()
#for row in records:
#        print(row)
names = [ x[0] for x in cursor_YOUR-DB2.description ]
df = pd.DataFrame(records, columns = names) 
cursor_YOUR-DB1.executemany(""" 
                INSERT INTO YOUR-USERNAME1.XXXX_stg_clients(client_id,last_name,first_name,patronymic,date_of_birth,passport_num,passport_valid_to,phone,create_dt,update_dt)
                VALUES(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s);
        """, df.values.tolist()) 
###################Загрузка данных в целевые таблицы измерений
cursor_YOUR-DB1.execute("""
                INSERT INTO YOUR-USERNAME1.XXXX_dwh_dim_clients(client_id,last_name,first_name,patronymic,date_of_birth,passport_num,passport_valid_to,phone,create_dt,update_dt)
                SELECT stg.client_id,stg.last_name,stg.first_name,stg.patronymic,stg.date_of_birth,stg.passport_num,stg.passport_valid_to,stg.phone,stg.create_dt,now()
                from YOUR-USERNAME1.XXXX_stg_clients as stg
                left join YOUR-USERNAME1.XXXX_dwh_dim_clients as trg
                on stg.client_id = trg.client_id 
                where trg.client_id is null;
        """)
###################
######################################
###################Выявление мошеннических операций и построение отчёта
cursor_YOUR-DB1.execute("""
                INSERT INTO YOUR-USERNAME1.XXXX_rep_fraud 
                select 
                        min(t2.trans_date) as trans_date, 
                        tgddcl.passport_num as passport_num, 
                        (tgddcl.last_name || ' ' || tgddcl.first_name || ' ' || tgddcl.patronymic ) as fio, 
                        tgddcl.phone as phone, 
                        '1' as event_type,
                        now() as report_dt
                from (
                        select *
                        from (
                                with current_dt as ( 
                                        select trans_date 
                                        from YOUR-USERNAME1.XXXX_stg_transactions) 
                                select  tgdft.*, tgddca.account_num 
                                from YOUR-USERNAME1.XXXX_dwh_fact_transactions as tgdft 
                                left join YOUR-USERNAME1.XXXX_dwh_dim_cards as tgddca
                                on trim(tgdft.card_num) = trim(tgddca.card_num ) 
                                where tgdft.oper_result = 'SUCCESS' 
                                        and tgdft.trans_date in (
                                                select trans_date 
                                                from current_dt)) as t 
                        left join YOUR-USERNAME1.XXXX_dwh_dim_accounts as gdda 
                        on t.account_num = gdda.account_num ) as t2 
                left join YOUR-USERNAME1.XXXX_dwh_dim_clients as tgddcl 
                on t2.client = tgddcl.client_id 
                where (tgddcl.passport_valid_to < t2.trans_date 
                        or tgddcl.passport_num in (
                                select passport_num
                                from YOUR-USERNAME1.XXXX_dwh_fact_passport_blacklist))  
                group by tgddcl.passport_num, (tgddcl.last_name || ' ' || tgddcl.first_name || ' ' || tgddcl.patronymic ), tgddcl.phone;
        """)
###################Совершение операции при недействующем договоре.
cursor_YOUR-DB1.execute("""
                INSERT INTO YOUR-USERNAME1.XXXX_rep_fraud
                select 
                        t2.trans_date as trans_date, 
                        gddcl.passport_num as passport_num, 
                        (gddcl.last_name || ' ' || gddcl.first_name || ' ' || gddcl.patronymic ) as fio, 
                        gddcl.phone as phone, 
                        '2' as event_type,
                        now() as report_dt
                from (
                        select min(t.trans_date) trans_date, t.account_num, gdda.client
                        from (
                                with current_dt as ( 
                                        select trans_date 
                                        from YOUR-USERNAME1.XXXX_stg_transactions) 
                                select gdft.trans_date, gdft.card_num, gddca.account_num
                                from YOUR-USERNAME1.XXXX_dwh_fact_transactions as gdft 
                                left join YOUR-USERNAME1.XXXX_dwh_dim_cards as gddca
                                on trim(gdft.card_num) = trim(gddca.card_num ) 
                                where gdft.oper_result = 'SUCCESS'
                                        and gdft.trans_date in (
                                                select trans_date 
                                                from current_dt)) as t 
                        left join YOUR-USERNAME1.XXXX_dwh_dim_accounts as gdda 
                        on t.account_num = gdda.account_num 
                        where t.trans_date > gdda.valid_to
                        group by t.account_num, gdda.client ) as t2 
                left join YOUR-USERNAME1.XXXX_dwh_dim_clients as gddcl 
                on t2.client = gddcl.client_id;
        """)
###################Совершение операций в разных городах в течение одного часа
cursor_YOUR-DB1.execute("""
                INSERT INTO YOUR-USERNAME1.XXXX_rep_fraud
                select
                        t3.trans_date,
                        t3.passport_num,
                        (t3.last_name || ' ' || t3.first_name || ' ' || t3.patronymic ) as fio,
                        t3.phone ,
                        '3' as event_type,
                        now() as report_dt
                from (
                        select trans_date, trg2.*
                        from (
                                select * from (
                                        select * from (
                                                with lds as  (
                                                        select
                                                                trans_date,
                                                                terminal_city,
                                                                card_num,
                                                                lag(terminal_city) over (
                                                                        partition by gdftr.card_num
                                                                        order by gdftr.trans_date) as lag_c,
                                                                lag(trans_date) over (
                                                                        partition by card_num
                                                                        order by gdftr.trans_date) as lag_t,
                                                                lead(terminal_city) over (
                                                                        partition by gdftr.card_num
                                                                        order by gdftr.trans_date) as lead_c ,
                                                                lead(trans_date) over (
                                                                        partition by card_num
                                                                        order by gdftr.trans_date) as lead_t
                                                        from YOUR-USERNAME1.XXXX_dwh_fact_transactions as gdftr
                                                        left join YOUR-USERNAME1.XXXX_dwh_dim_terminals as gddt
                                                        on gdftr.terminal = gddt.terminal_id
                                                        where gdftr.oper_result = 'SUCCESS'),
                                                current_dt as (
                                                        select trans_date
                                                        from YOUR-USERNAME1.XXXX_stg_transactions )
                                                select
                                                        min(trans_date) as trans_date,
                                                        card_num
                                                from lds
                                                where lag_c <> terminal_city
                                                        and (trans_date-lag_t) < '01:00:00'
                                                        and trans_date  in (
                                                                select trans_date
                                                                from current_dt)
                                                group by card_num) as trg
                                        left join YOUR-USERNAME1.XXXX_dwh_dim_cards as trg3
                                        on trim(trg.card_num) = trim(trg3.card_num )) as t
                                left join YOUR-USERNAME1.XXXX_dwh_dim_accounts as trg4
                                on t.account_num = trg4.account_num ) as t2
                        left join YOUR-USERNAME1.XXXX_dwh_dim_clients as trg2
                        on t2.client = trg2.client_id ) as t3;
        """)
###################Попытка подбора суммы
cursor_YOUR-DB1.execute("""
                INSERT INTO YOUR-USERNAME1.XXXX_rep_fraud 
                select 
                        t3.trans_date, 
                        t3.passport_num , 
                        (t3.last_name || ' ' || t3.first_name || ' ' || t3.patronymic ) as fio, 
                        t3.phone , 
                        '4' as event_type,
                        now() as report_dt
                from (
                        select 
                                trans_date, 
                                gddcl.*
                        from  (
                                select * from (
                                        select * from(
                                                with rj as (
                                                        select 
                                                                *,
                                                                lag(amt) over (
                                                                        partition by gdft.card_num 
                                                                        order by gdft.trans_date) as lag_a,
                                                                lag(amt,2) over (
                                                                        partition by gdft.card_num 
                                                                        order by gdft.trans_date) as lag_a2,
                                                                lag(amt,3) over (
                                                                        partition by gdft.card_num 
                                                                        order by gdft.trans_date) as lag_a3,
                                                                lag(oper_result) over (
                                                                        partition by gdft.card_num 
                                                                        order by gdft.trans_date) as lag_r,
                                                                lag(oper_result,2) over (
                                                                        partition by gdft.card_num 
                                                                        order by gdft.trans_date) as lag_r2,
                                                                lag(oper_result,3) over (
                                                                        partition by gdft.card_num 
                                                                        order by gdft.trans_date) as lag_r3,
                                                                lag(trans_date,3) over (
                                                                        partition by gdft.card_num 
                                                                        order by gdft.trans_date) as min_t
                                                        from YOUR-USERNAME1.XXXX_dwh_fact_transactions gdft),
                                                current_dt as ( 
                                                        select trans_date 
                                                        from YOUR-USERNAME1.XXXX_stg_transactions )
                                                select * 
                                                from rj
                                                where oper_result = 'SUCCESS' 
                                                        and lag_r = 'REJECT' 
                                                        and lag_a > amt 
                                                        and lag_r2 = 'REJECT' 
                                                        and lag_a2 > lag_a
                                                        and lag_r3 = 'REJECT' 
                                                        and lag_a3 > lag_a2
                                                        and (trans_date - min_t) <= '00:20:00'
                                                        and trans_date  in (
                                                                select trans_date 
                                                                from current_dt)) as trg
                                        left join YOUR-USERNAME1.XXXX_dwh_dim_cards as gddca
                                        on trim(trg.card_num) = trim(gddca.card_num )) as t 
                                left join YOUR-USERNAME1.XXXX_dwh_dim_accounts as gdda 
                                on t.account_num = gdda.account_num ) as t2 
                        left join YOUR-USERNAME1.XXXX_dwh_dim_clients as gddcl 
                        on t2.client = gddcl.client_id ) as t3;
        """)
######################################
conn_YOUR-DB2.commit()
conn_YOUR-DB1.commit()
######################################Запись файлов в архив
os.rename('/home/YOUR-USERNAME1/XXXX/project/terminals_01032021.xlsx', '/home/YOUR-USERNAME1/XXXX/project/archive/terminals_01032021.xlsx.backup')
os.rename('/home/YOUR-USERNAME1/XXXX/project/transactions_01032021.txt', '/home/YOUR-USERNAME1/XXXX/project/archive/transactions_01032021.txt.backup')
os.rename('/home/YOUR-USERNAME1/XXXX/project/passport_blacklist_01032021.xlsx', '/home/YOUR-USERNAME1/XXXX/project/archive/passport_blacklist_01032021.xlsx.backup')
os.rename('/home/YOUR-USERNAME1/XXXX/project/terminals_02032021.xlsx', '/home/YOUR-USERNAME1/XXXX/project/archive/terminals_02032021.xlsx.backup')
os.rename('/home/YOUR-USERNAME1/XXXX/project/transactions_02032021.txt', '/home/YOUR-USERNAME1/XXXX/project/archive/transactions_02032021.txt.backup')
os.rename('/home/YOUR-USERNAME1/XXXX/project/passport_blacklist_02032021.xlsx', '/home/YOUR-USERNAME1/XXXX/project/archive/passport_blacklist_02032021.xlsx.backup')
os.rename('/home/YOUR-USERNAME1/XXXX/project/terminals_03032021.xlsx', '/home/YOUR-USERNAME1/XXXX/project/archive/terminals_03032021.xlsx.backup')
os.rename('/home/YOUR-USERNAME1/XXXX/project/transactions_03032021.txt', '/home/YOUR-USERNAME1/XXXX/project/archive/transactions_03032021.txt.backup')
os.rename('/home/YOUR-USERNAME1/XXXX/project/passport_blacklist_03032021.xlsx', '/home/YOUR-USERNAME1/XXXX/project/archive/passport_blacklist_03032021.xlsx.backup')
######################################
cursor_YOUR-DB2.close();
cursor_YOUR-DB1.close();
$ sudo apt install python3.10-venv
$ python3.10 -m venv venv
$ source venv/bin/activate
$ pip install pandas
$ python3 main.py
$ ls archive/
passport_blacklist_01032021.xlsx.backup  terminals_01032021.xlsx.backup  transactions_01032021.txt.backup
$ sudo psql -U YOUR-USERNAME
YOUR-USERNAME=# select * from YOUR-USERNAME.XXXX_rep_fraud;
Task:
Администрирование локальных, виртуальных и облачных серверов. Заполните файл main.cron расписанием и командой исполнения вашего скрипта. Расписание установите так, как считаете нужным чтобы ваши данные заполнились корректно.
Decision:
$ vim main.cron 
$ cat main.cron 
0 0 * * * /home/david/project/main.py
Decision:
По следующим признакам получилось выявить мошеннические транзакции: выполнение операции с просроченным или заблокированным паспортом, выполнение операции с недействительным контрактом, выполнение операций в разных городах в течение одного часа
Decision:
Защитил диплом о профессиональной переподготовке:

 


Source:
# https://dzen.ru/a/Ypr65Wh4jmLimA3o
# https://www.youtube.com/watch?v=Je3Y8up0Qbs&list=LL&index=5&t=98s
# https://losst.pro/kak-posmotret-otkrytye-porty-v-linux?ysclid=lpe5qjsv9o445640330
# https://www.pgadmin.org/download/pgadmin-4-apt/
# https://losst.pro/spisok-kontejnerov-docker

2019-11-01 - 2021-05-30: Easy School, Иркутск. Должность: English Level Elementary A - Дополнительное образование. Дополнительная информация: Навыки - English, Python, Clouds. Достижения: Разработал программу телеграмм бот Переводчик.

Show

# Разработка функции меню.
# Применение библиотеки Translator.
# Применение библиотеки Aiogram.
# Администрирование баз данный.
# Разработка базы данных.
# Написание Sql запросов.
# Применение библиотеки psycopg2.
# Применение библиотеки Telebot.
# Настройка службы бота.
Task:
Разработка функции меню.
Decision:
tuser@kvmubuntu:~/TelegramBotTranslator$ vim pyMenu.py
tuser@kvmubuntu:~/TelegramBotTranslator$ cat pyMenu.py
def fun(t1, b, t2, l, t3):
while True: 
  cmd1 = input("Привет!\nЯ тестовый бот.\nВыбери программу, которую ты хочешь выполнить\n(0, translator, dictionary): ")
  if cmd1 == "0":
   break
  elif cmd1 == t1:
   while True:
    cmd2 = input("Что именно нужно сделать\n(translate, back): ")
    if cmd2 == b:
     print('Вы вернулись в главное меню')
     break
    elif cmd2 == t2:
     print("Здесь программа переведет вам текст")
    else:
     print("Я такую команду не знаю")
  elif cmd1 == "dictionary":
   while True:
    cmd2 = input("Что именно нужно сделать\n(list,term,back): ")
    if cmd2 == b:
     print('Вы вернулись в главное меню')
     break
    elif cmd2 == l:
     print("Вывести список слов")
    elif cmd2 == t3:
     print("Выбрать слово их списка")
    else:
     print("Я такую команду не знаю")
  else:
   print("Я такую команду не знаю")
return t1
print(fun("translator","back","translate","list","term"))
tuser@kvmubuntu:~/TelegramBotTranslator$ python3 pyMenu.py
Привет!
Я тестовый бот.
Выбери программу, которую ты хочешь выполнить
(0, translator, dictionary): translator
Что именно нужно сделать
(translate, back): translate 
Здесь программа переведет вам текст
Что именно нужно сделать
(translate, back): back
Вы вернулись в главное меню
Привет!
Я тестовый бот.
Выбери программу, которую ты хочешь выполнить
(0, translator, dictionary): dictionary
Что именно нужно сделать
(list,term,back): list
Вывести список слов
Что именно нужно сделать
(list,term,back): term
Выбрать слово их списка
Что именно нужно сделать
(list,term,back): back
Вы вернулись в главное меню
Привет!
Я тестовый бот.
Выбери программу, которую ты хочешь выполнить
(0, translator, dictionary): 0
translator
Task:
Подготовка библиотек.
Decision:
tuser@kvmubuntu:~/TelegramBotTranslator$ python3 -m venv tenv
tuser@kvmubuntu:~/TelegramBotTranslator$ source tenv/bin/activate
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ vim requirements.txt
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ cat requirements.txt
translate==3.6.1
pyTelegramBotAPI==4.21.0
googletrans==3.1.0a0
langdetect==1.0.9
aiogram==2.23.1
psycopg2-binary==2.9.9
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ pip install -r requirements.txt
Task:
Раработка программы переводчик.
Decision:
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ vim pyTranslator.py
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ cat pyTranslator.py
from translate import Translator
translator=Translator(from_lang="russian", to_lang="english")
translation=translator.translate("Вчера я забронировал у вас номер в отеле.")
print(translation)
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ python3 translator.py
Hi, how are you?
Decision:
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ vim pyTranslator1.py
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ cat pyTranslator1.py
from translate import Translator
ru_letters = "абвгдеёжзийклмнопрстуфхцчшщъыьэюя"
en_letters = "abcdefghijklmnopqrstuvwxyz"
cmd3 = input("Введите текст, который вы хотите перевести: ")
if cmd3[0].lower() in ru_letters:
  translator = Translator(from_lang="russian", to_lang="english")
elif cmd3[0].lower() in en_letters:
  translator = Translator(from_lang="english", to_lang="russian")
else:
  print('Я тебя не понимаю')
translation = translator.translate(cmd3)
print(translation)
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ python3 pyTranslator1.py
Введите текст, который вы хотите перевести: Вчера я забронировал у вас номер в отеле.
Tom booked a room at the hotel
Decision:
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ vim pyTranslator2.py
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ cat pyTranslator2.py
from googletrans import Translator
from langdetect import detect
translator = Translator()
cmd3 = input("Введите текст, который вы хотите перевести: ")
translation = translator.translate(cmd3, src=detect(cmd3), dest='en').text
print(translation.encode('utf-8', 'replace').decode())
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ python3 pyTranslator2.py
Введите текст, который вы хотите перевести: Вчера я забронировал у вас номер в отеле.
Yesterday I booked a hotel room with you.
Decision:
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ vim pyTranslator3.py
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ cat pyTranslator3.py
from googletrans import Translator
from langdetect import detect
translator = Translator()
cmd3 = input("Введите текст, который вы хотите перевести: ")
ru_letters = "абвгдеёжзийклмнопрстуфхцчшщъыьэюя"
en_letters = "abcdefghijklmnopqrstuvwxyz"
if cmd3[0].lower() in ru_letters:
  translation = translator.translate(cmd3, src=detect(cmd3), dest='en').text
  print(translation.encode('utf-8', 'replace').decode())
elif cmd3[0].lower() in en_letters:
  translation = translator.translate(cmd3, src=detect(cmd3), dest='ru').text
  print(translation.encode('utf-8', 'replace').decode())
else:
  print('Я тебя не понимаю')
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ python3 pyTranslator3.py
Введите текст, который вы хотите перевести: Для тестирования работоспособности телеграм бота переводчик, написанном на Python мы использовали готовый преднастроенный телеграм бот сервер.
To test the functionality of the telegram bot translator, written in Python, we used a ready-made pre-configured telegram bot server.
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ python3 pyTranslator3.py
Введите текст, который вы хотите перевести: To test the functionality of the telegram bot translator, written in Python, we used a ready-made pre-configured telegram bot server.
Для проверки работоспособности переводчика телеграмм-бота, написанного на Python, мы использовали готовый, предварительно настроенный сервер телеграм-бота.
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ python3 pyTranslator3.py
Введите текст, который вы хотите перевести: ;
Я тебя не понимаю
Task:
Применение библиотеки Translator и готовой функции меню. 
Decision:
(tenv) root@kvmubuntu:~# vim pyMenuTranslator.py
(tenv) root@kvmubuntu:~# cat pyMenuTranslator.py
from translate import Translator
def fun(t1, b, t2, l, t3):
while True: 
  cmd1 = input("Привет!\nЯ тестовый бот.\nВыбери программу, которую ты хочешь выполнить\n(0, translator, dictionary): ")
  if cmd1 == "0":
   break
  elif cmd1 == t1:
   while True:
    cmd2 = input("Что именно нужно сделать\n(translate, back): ")
    if cmd2 == b:
     print('Вы вернулись в главное меню')
     break
    elif cmd2 == t2:
     cmd3 = input("Введите текст, который вы хотите перевести: ")
     t4=Translator(from_lang="russian", to_lang="english")
     translation=t4.translate(cmd3)
     print(translation)
    else:
     print("Я такую команду не знаю")
  elif cmd1 == "dictionary":
   while True:
    cmd2 = input("Что именно нужно сделать\n(list,term,back): ")
    if cmd2 == b:
     print('Вы вернулись в главное меню')
     break
    elif cmd2 == l:
     print("Вывести список слов")
    elif cmd2 == t3:
     print("Выбрать слово их списка")
    else:
     print("Я такую команду не знаю")
  else:
   print("Я такую команду не знаю")
return t1
print(fun("translator","back","translate","list","term"))
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ python3 pyMenuTranslator.py
Привет!
Я тестовый бот.
Выбери программу, которую ты хочешь выполнить
(0, translator, dictionary): translator
Что именно нужно сделать
(translate, back): translate 
Введите текст, который вы хотите перевести: Привет. Как дела?
Hi, how are you?
Что именно нужно сделать
(translate, back): back 
Вы вернулись в главное меню
Привет!
Я тестовый бот.
Выбери программу, которую ты хочешь выполнить
(0, translator, dictionary): 0
translator
Task:
Администрирование базы данных. Установка и настройка базы данных в PostgreSQL.
Decision:
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ createdb tbase2
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ psql -U tuser -d tbase -h tipubuntu
tbase=# GRANT ALL PRIVILEGES ON DATABASE tbase2 to tuser;
tbase=# ALTER DATABASE tbase2 OWNER TO tuser;
tbase=# \l+
tbase   | tuser  | UTF8   | en_US.UTF-8 | en_US.UTF-8 | =Tc/tuser      +| 9801 kB | pg_default |
     |     |     |       |       | tuser=CTc/tuser   |     |      |
tbase2  | tuser  | UTF8   | en_US.UTF-8 | en_US.UTF-8 | =Tc/tuser      +| 8577 kB | pg_default |
     |     |     |       |       | tuser=CTc/tuser   |     |      |
root@kvmubuntu:~# vim /etc/postgresql/14/main/pg_hba.conf
root@kvmubuntu:~# cat /etc/postgresql/14/main/pg_hba.conf
...
host  tbase2   tuser      tipubuntu1/24   md5
root@kvmubuntu:~# systemctl restart postgresql
Source:
# https://postgrespro.ru/docs/postgresql/9.5/manage-ag-createdb - Создание базы данных.
Task:
Разработка базы данных. Разработать схему БД Словарь
Decision:

Task:
Разработка базы данных.
Словарь
id | words | translate 
1 | Текст1 | Text1 
2 | Текст2 | Text2 
3 | Текст3 | Text3 
Термины
id | words_id | description | translate
1 | 1 | Текст4 | Text4 
2 | 3 | Текст5 | Text5 
Decision:
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ psql -U tuser -d tbase2 -h tipubuntu
tbase2=# CREATE TABLE tbase2 (
id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
words VARCHAR(1000),
translate VARCHAR(1000)
);
tbase2=# CREATE TABLE Terms (
id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
words_id INT,
description VARCHAR(1000),
translate VARCHAR(1000),
CONSTRAINT fk_tbase2
FOREIGN KEY(words_id)
REFERENCES tbase2(id)
);
tbase2=# INSERT INTO tbase2 (words, translate)
VALUES ('Текст1', 'Text1'), ('Текст2', 'Text2'), ('Текст3', 'Text3');
tbase2=# INSERT INTO Terms (words_id, description, translate)
VALUES (1, 'Текст4', 'Text4'), (3, 'Текст5','Text5');
Task:
Написание Sql запросов.
words | translate | description | translate
Текст1 | Text1 | Текст4 | Text4
Текст3 | Text3 | Текст5 | Text5
Decision:
tbase2=# select words, dictionary.translate, description, Terms.translate 
from dictionary
inner join Terms 
on dictionary.id = Terms.words_id;
words | translate | description | translate 
--------+-----------+-------------+-----------
Текст1 | Text1 | Текст4 | Text4
Текст3 | Text3 | Текст5 | Text5
(2 rows)
Source:
# https://proglib.io/p/rukovodstvo-po-sql-dlya-nachinayushchih-chast-1-sozdanie-bazy-dannyh-tablic-i-ustanovka-svyazey-mezhdu-tablicami-2022-02-07 - Руководство по SQL для начинающих. Часть 1: создание базы данных, таблиц и установка связей между таблицами.
# https://sql-academy.org/ru/guide/inner-join - Внутреннее соединение INNER JOIN.
Task:
Администрирование базы данных. Миграция базы с одного сервера на другой.
Decision:
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ pg_dump -Fc -v --username=tuser --dbname=tbase2 -f datapsql2.dump
root@aw:/# scp datapsql2.dump tuser@tipubuntu:/home/tuser/
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ pg_restore -v --no-owner --port=5432 --username=tuser --dbname=tbase2 datapsql2.dump
Task:
Применение библиотеки Aiogram.
Decision:
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ vim pyTranslatorAiogram.py
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ cat pyTranslatorAiogram.py
import logging
from translate import Translator
from aiogram import Bot, Dispatcher, executor, types
API_TOKEN = 'ttoken'
# Configure logging
logging.basicConfig(level=logging.INFO)
# Initialize bot and dispatcher
bot = Bot(token=API_TOKEN)
dp = Dispatcher(bot)
ru_letters = "абвгдеёжзийклмнопрстуфхцчшщъыьэюя"
en_letters = "abcdefghijklmnopqrstuvwxyz"
@dp.message_handler(commands=['start', 'help'])
async def send_welcome(message: types.Message):
await message.reply("Hi!\nI'm EchoBot!\nPowered by aiogram.")
@dp.message_handler()
async def echo(message: types.Message):
text = message.text
if text[0].lower() in ru_letters:
translator = Translator(from_lang="russian", to_lang="english")
elif text[0].lower() in en_letters:
translator = Translator(from_lang="english", to_lang="russian")
else:
await message.answer('Я тебя не понимаю')
return
translation = translator.translate(text)
await message.answer(translation)
if __name__ == '__main__':
executor.start_polling(dp, skip_updates=True)
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ python3 pyTranslatorAiogram.py
Source:
# https://www.youtube.com/@shcoder001 - Переводчик бот в telegram на python за 5 минут aiogram.
Task:
Применение библиотеки psycopg2.
Decision:
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ vim pyPsql.py
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ cat pyPsql.py
import psycopg2
try:
# пытаемся подключиться к базе данных
conn = psycopg2.connect(dbname='tbase2', user='tuser', password='tpassword', host='tipubuntu')
except:
# в случае сбоя подключения будет выведено сообщение в STDOUT
print('Can`t establish connection to database')
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ python3 pyPsql.py
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ vim pyPsql.py
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ cat pyPsql.py
import psycopg2
try:
# пытаемся подключиться к базе данных
conn = psycopg2.connect(dbname='tbase2', user='tuser', password='tpassword', host='tipubuntu')
cursor = conn.cursor()
cursor.execute('select words, dictionary.translate, description, Terms.translate from dictionary inner join Terms on dictionary.id = Terms.words_id')
#records = cursor.fetchall()
#print(records)
for row in cursor:
print(row)
cursor.close()
conn.close()
except:
# в случае сбоя подключения будет выведено сообщение в STDOUT
print('Can`t establish connection to database')
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ python3 pyPsql.py
('Внутреннее соединение', 'Inner join', 'Возвращаются только те строки, где ключевые значения совпадают в обеих таблицах', 'Only those rows are returned where the key values match in both tables')
('Полное соединение', 'Cross Join', 'Позволяет получить декартово произведение нескольких таблиц. особенно полезен, когда между таблицами нет определенной связи, и вам нужно создать полную комбинацию записей из каждой таблицы', '-')
('Декартово произведение', 'Cartesian product', 'Результат соединения строки из первой таблицы с каждой строкой из второй таблицы', '-')
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ vim pyPsql.py
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ cat pyPsql.py
import psycopg2
from contextlib import closing
with closing(psycopg2.connect(dbname='dictionary', user='tuser', password='tpassword', host='tipubuntu')) as conn:
with conn.cursor() as cursor:
cursor.execute('select words, dictionary.translate, description, Terms.translate from dictionary inner join Terms on dictionary.id = Terms.words_id')
for row in cursor:
print(row)
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ python3 pyPsql.py
('Внутреннее соединение', 'Inner join', 'Возвращаются только те строки, где ключевые значения совпадают в обеих таблицах', 'Only those rows are returned where the key values match in both tables')
('Полное соединение', 'Cross Join', 'Позволяет получить декартово произведение нескольких таблиц. особенно полезен, когда между таблицами нет определенной связи, и вам нужно создать полную комбинацию записей из каждой таблицы', '-')
('Декартово произведение', 'Cartesian product', 'Результат соединения строки из первой таблицы с каждой строкой из второй таблицы', '-')
Source:
# https://ru.hexlet.io/blog/posts/python-postgresql - Использование Psycopg2.
# https://khashtamov.com/ru/postgresql-python-psycopg2/ - Начало работы.
Task:
Применение библиотеки Telebot.
Decision:
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ vim pyTranslatorMenuTelebot.py
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ cat pyTranslatorMenuTelebot.py
import telebot
from telebot import types
from googletrans import Translator
from langdetect import detect
TOKEN='tkey'
bot = telebot.TeleBot(TOKEN)
translator = Translator()
ru_letters = "абвгдеёжзийклмнопрстуфхцчшщъыьэюя"
en_letters = "abcdefghijklmnopqrstuvwxyz"
@bot.message_handler(commands=["start"])
def start(message):
  message_user = f"Привет, <b>{message.from_user.first_name.title()}</b>! Я тестовый бот.\n" \
         f"<b>Выбери программу, которую ты хочешь выполнить:</b>\n" \
         f"1. Чем полезен данный бот\n" \
         f"2. Функции бота (что может данный бот)\n" \
         f"3. Для тех кто хочет поддержать нас и наш проект"
  markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
  item1 = types.KeyboardButton(text="Чем полезен бот ?")
  item2 = types.KeyboardButton(text="Функции бота")
  item3 = types.KeyboardButton(text="Поддержать проект")
  markup.add(item1, item2, item3)
  bot.send_message(message.from_user.id, message_user, reply_markup=markup, parse_mode='html')
  bot.register_next_step_handler(message, impact_KEYBORD_bot)
  bot.register_next_step_handler(message, fuctional_KEYBORD_bot)
  bot.register_next_step_handler(message, donat_user_bot)
def impact_KEYBORD_bot(message):
  if message.text == "Чем полезен бот ?":
    message_user = "Этот бот много чем будет полезен для вас. Ознакомьтесь с функционалом бота чтобы понять это." \
           " В этого бота со временем мы будем внедрять новые фичи и полезные функции. Чтобы узнавать о новых фишках бота, слидите за нашим Telegramm каналом"
    key = types.InlineKeyboardMarkup()
    button = types.InlineKeyboardButton(text='Мое портфолио', url="http://dato138it.ru")
    key.add(button)
    bot.send_message(message.from_user.id, message_user, reply_markup=key, parse_mode='html')
    bot.register_next_step_handler(message, fuctional_KEYBORD_bot)
    bot.register_next_step_handler(message, donat_user_bot)
def fuctional_KEYBORD_bot(message):
  if message.text == 'Функции бота':
    message_user = "<b>Добро пожаловать главное меню бота</b>\n\n" \
           "В скором будущем мы будем добавлять сюда новые функции!"
    key = types.ReplyKeyboardMarkup(resize_keyboard=True)
    button0 = types.KeyboardButton("Переводчик")
    button1 = types.KeyboardButton("Словарь")
    key.add(button0, button1)
    bot.send_message(message.from_user.id, message_user, reply_markup=key, parse_mode='html')
    bot.register_next_step_handler(message, impact_KEYBORD_bot)
    bot.register_next_step_handler(message, donat_user_bot)
    bot.register_next_step_handler(message, translate_message)
    bot.register_next_step_handler(message, dictionary_message)
def donat_user_bot(message):
  if message.text == "Поддержать проект":
    message_users = f"<b>Приветствую уважаемый {message.from_user.first_name.title()}</b>, вы перешли в отдел поддержки нашего проекта \n\n" \
            f"Мы будем благодарны любой поддержки от вас. И также благодарим, что вы пользуетесь нашим ботом - это главная ваша поддержка для нас!\n\n" \
            f"Мы принимаем материальную поддержку на:\n" \
            f"<b>1. Donationalerts</b>\n" \
            f"<b>2. PAYEER</b>\nномер счёта для пополнения: P1091200672\n" \
            f"<b>3. QIWI</b>\n" \
            f"<b>4. Тинькофф банк</b>"
    key = types.InlineKeyboardMarkup()
    button0 = types.InlineKeyboardButton(text="Donationalerts", url="https://www.donationalerts.com/r/tgbot_v")
    button1 = types.InlineKeyboardButton(text="PAYEER", url="https://payeer.com/ru/account/send/")
    button2 = types.InlineKeyboardButton(text="QIWI", url="https://my.qiwi.com/VLADYSLAV-DTJ4Y_MwOA")
    button3 = types.InlineKeyboardButton(text="Тинькофф банк", url="https://www.tinkoff.ru/cf/35TWsWpG8Fe")
    key.add(button0, button1, button2, button3)
    bot.send_message(message.from_user.id, message_users, reply_markup=key, parse_mode='html')
    bot.register_next_step_handler(message, impact_KEYBORD_bot)
    bot.register_next_step_handler(message, fuctional_KEYBORD_bot)
@bot.message_handler(content_types=['text'])
def translate_message(message):
  if message.text == 'Переводчик':
    bot.send_message(message.chat.id, 'Напишите сообщения а я переведу его')
    bot.register_next_step_handler(message, translate_message_step_2)
def translate_message_step_2(message):
  cmd3 = message.text
  if cmd3[0].lower() in ru_letters:
    translation = translator.translate(cmd3, src=detect(cmd3), dest='en').text
    bot.send_message(message.chat.id, translation.encode('utf-8', 'replace').decode())
  elif cmd3[0].lower() in en_letters:
    translation = translator.translate(cmd3, src=detect(cmd3), dest='ru').text
    bot.send_message(message.chat.id, translation.encode('utf-8', 'replace').decode())
  else:
    bot.send_message(message.chat.id, 'Я тебя не понимаю')
def dictionary_message(message):
  if message.text == 'Словарь':
    bot.send_message(message.chat.id, 'list | term')
    #text = message.text
    #bot.send_message("TEST")
if __name__ == '__main__':
  bot.polling(none_stop=True, interval=0)
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ python3 pyTranslatorMenuTelebot.py
- /Start
- Привет, David! Я тестовый бот.
Выбери программу, которую ты хочешь выполнить:
1. Чем полезен данный бот
2. Функции бота (что может данный бот)
3. Для тех кто хочет поддержать нас и наш проект
- Функции бота
- Добро пожаловать главное меню бота
В скором будущем мы будем добавлять сюда новые функции!
1. Переводчик
2. Словарь
- Переводчик
- Напишите сообщения, а я переведу его
- Привет, Катя!
- Hello, Katya!
- Переводчик
- Напишите сообщения, а я переведу его
- Dear Kate!
- Дорогая Кейт!
Source:
# https://www.w3schools.com/python/ref_func_input.asp - Python input() Function.
# https://proglib.io/p/samouchitel-po-python-dlya-nachinayushchih-chast-10-uslovnyy-cikl-while-2022-12-22 - Управление бесконечным циклом while в Питоне.
# https://letpy.com/python-guide/functions/ - Функции в Python для начинающих.
# https://ru.stackoverflow.com/questions/1211592/%D0%9A%D0%B0%D0%BA-%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D1%82%D1%8C-%D0%BC%D0%B5%D0%BD%D1%8E-%D1%81-%D0%B2%D1%8B%D0%B1%D0%BE%D1%80%D0%BE%D0%BC-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B9-%D0%BD%D0%B0-python - Как создать меню с выбором функций на Python?
# https://ru.stackoverflow.com/questions/1341916/%D0%9A%D0%B0%D0%BA-%D0%B7%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%82%D1%8C-%D0%BC%D0%B5%D0%BD%D1%8E-%D0%B8%D0%BC%D0%B5%D1%8E%D1%89%D0%B5%D0%B5-%D0%BF%D0%BE%D0%B4%D0%BC%D0%B5%D0%BD%D1%8E-%D0%B2-python - Как зациклить меню, имеющее подменю в python?
# https://docs.python.org/3/tutorial/venv.html - Creating Virtual Environments.
# https://www.youtube.com/watch?v=A1p7bEtTlxc&t=4s - Как сделать меню для Телеграм Бота на Python.
Task:
Добавить информацию в базу данных в телеграм бот.
Decision:
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ vim pyPsqlTelebot.py
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ cat pyPsqlTelebot.py
import psycopg2
import telebot
from telebot import types
from telebot.types import Message
TOKEN='tkey'
bot = telebot.TeleBot(TOKEN)
DATABASE_URL = "postgres://tuser:tpassword@tipubuntu:5432/tbase2"
def connect_to_db():
  conn = psycopg2.connect(DATABASE_URL, sslmode='require')
  return conn
def insert_data(words, translate):
  conn = connect_to_db()
  cursor = conn.cursor()
  query = "INSERT INTO Dictionary (words, translate) VALUES (%s, %s)"
  cursor.execute(query, (words, translate))
  conn.commit()
  cursor.close()
  conn.close()
@bot.message_handler(commands=['start'])
def handle_start(message: Message):
  words = "Текст4"
  translate = "Text4"
  insert_data(words, translate)
  bot.reply_to(message, "Add Info in Doctionary.")
if __name__ == '__main__':
  bot.polling(none_stop=True, interval=0)
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ python3 pyPsqlTelebot.py
- /Start
- Add Info in Doctionary.
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ psql -U tuser -d tbase2 -h tipubuntu
tbase2=# select * from Dictionary;
id |     words     |   translate
----+------------------------+-------------------
1 | Внутреннее соединение | Inner join
2 | Доступ         | Available
3 | Полное соединение   | Cross Join
4 | Декартово произведение | Cartesian product
5 | Текст4         | Text4
(5 rows)
Decision:
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ vim .env
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ cat .env
TOKEN='tkey'
DB_URL='postgres://tuser:tpassword@tipubuntu:5432/tbase2'
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ vim requirements.txt
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ cat requirements.txt
translate==3.6.1
pyTelegramBotAPI==4.21.0
googletrans==3.1.0a0
langdetect==1.0.9
psycopg2-binary==2.9.9
python-dotenv==1.0.1
python-decouple==3.8
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ vim .env
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ cat .env
TOKEN='tkey'
DB_URL='postgres://tuser:tpassword@tipubuntu:5432/tbase2'
Decision:
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ vim pyTranslatorMenuTelebotPsql.py
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ cat pyTranslatorMenuTelebotPsql.py
import psycopg2
import telebot
from telebot import types
from telebot.types import Message
from googletrans import Translator
from langdetect import detect
from decouple import config
from contextlib import closing
bot = telebot.TeleBot(config('TOKEN'))
translator = Translator()
ru_letters = "абвгдеёжзийклмнопрстуфхцчшщъыьэюя"
en_letters = "abcdefghijklmnopqrstuvwxyz"
DATABASE_URL = config('DB_URL')
def connect_to_db():
  conn = psycopg2.connect(DATABASE_URL, sslmode='require')
  return conn
def insert_dictionary(words, translate):
  conn = connect_to_db()
  cursor = conn.cursor()
  query = "INSERT INTO Dictionary (words, translate) VALUES (%s, %s)"
  cursor.execute(query, (words, translate))
  conn.commit()
  cursor.close()
  conn.close()
def insert_terms(words_id, description, translate):
  conn = connect_to_db()
  cursor = conn.cursor()
  query = "INSERT INTO Terms (words_id, description, translate) VALUES (%s, %s, %s)"
  cursor.execute(query, (words_id, description, translate))
  conn.commit()
  cursor.close()
  conn.close()
@bot.message_handler(commands=['start'])
def start(message):
  message_user = f"Привет, <b>{message.from_user.first_name.title()}</b>! Я тестовый бот.\n" \
         f"1. Чем полезен бот\n" \
         f"2. Для тех кто хочет поддержать проект"
  markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
  but1 = types.KeyboardButton(text="Чем полезен бот ?")
  but2 = types.KeyboardButton(text="Поддержать проект")
  markup.add(but1, but2)
  bot.send_message(message.from_user.id, message_user, reply_markup=markup, parse_mode='html')
  bot.register_next_step_handler(message, funcs_bot)
  bot.register_next_step_handler(message, donat_bot)
def funcs_bot(message):
  if message.text == "Чем полезен бот ?":
    message_user = "Функции бота:\n" \
            "1. Переводчик\n" \
            "2. Дополнить словарь\n" \
            "3. Словарь\n" \
            "4. Термины\n" \
            "5. Дополнить описание"
    key = types.ReplyKeyboardMarkup(resize_keyboard=True)
    #button = types.InlineKeyboardButton(text='Мое портфолио', url="http://dato138it.ru")
    but1 = types.KeyboardButton("Переводчик")
    but2 = types.KeyboardButton("Дополнить словарь")
    but3 = types.KeyboardButton("Словарь")
    but4 = types.KeyboardButton("Термины")
    but5 = types.KeyboardButton("Дополнить описание")
    key.add(but1, but2, but3, but4, but5)
    bot.send_message(message.from_user.id, message_user, reply_markup=key, parse_mode='html')
    #bot.register_next_step_handler(message, funcs_mess)
def donat_bot(message):
  if message.text == "Поддержать проект":
    message_users = f"<b>Приветствую, уважаемый {message.from_user.first_name.title()}</b>, вы перешли в отдел поддержки нашего проекта\n" \
            f"Мы будем благодарны материальной поддержки от вас на:\n" \
            f"<b>1. ЮMoney</b>\n" \
            f"<b>2. Альфа банк</b>"
    key = types.InlineKeyboardMarkup()
    but1 = types.InlineKeyboardButton(text="ЮMoney", url="http://dato138it.ru")
    but2 = types.InlineKeyboardButton(text="Альфа банк", url="http://dato138it.ru")
    key.add(but1, but2)
    bot.send_message(message.from_user.id, message_users, reply_markup=key, parse_mode='html')
    bot.register_next_step_handler(message, funcs_bot)
@bot.message_handler(content_types=['text'])
def funcs_mess(message):
  if message.text == 'Переводчик':
    bot.send_message(message.chat.id, 'Напишите сообщение, которое нужно перевести:')
    bot.register_next_step_handler(message, translator_mess)
  elif message.text == 'Дополнить словарь':
    if message.from_user.id == int(config('ADMIN_ID')):
      bot.send_message(message.chat.id, 'Напишите 2 сообщения (предложение и его перевод), которые нужно добавить в словарь:')
      bot.register_next_step_handler(message, AddDictionary_mess1)
    else:
      bot.send_message(message.chat.id, 'У вас нет прав на добавление и удаление предложений из базы')
  elif message.text == 'Дополнить описание':
    if message.from_user.id == int(config('ADMIN_ID')):
      bot.send_message(message.chat.id, 'Напишите 3 сообщения (id - в словаре можно увидеть id, описание и его перевод), которые нужно добавить в словарь:')
      bot.register_next_step_handler(message, AddTerms_mess1)
    else:
      bot.send_message(message.chat.id, 'У вас нет прав на добавление и удаление предложений из базы')
  elif message.text == 'Словарь':
    bot.send_message(message.chat.id, 'Вывожу список слов:')
    #bot.register_next_step_handler(message, dictionary_mess)
    with closing(connect_to_db()) as conn:
      with conn.cursor() as cursor:
        cursor.execute('select * from Dictionary;')
        for row in cursor:
          bot.send_message(message.chat.id, "| "+str(row[0])+" | "+row[1]+" | "+row[2]+" |")
    bot.reply_to(message, "Selected to the dictionary.")
  elif message.text == 'Термины':
    bot.send_message(message.chat.id, 'Вывожу список терминов:')
    with closing(connect_to_db()) as conn:
      with conn.cursor() as cursor:
        cursor.execute('select words, Dictionary.translate, description, Terms.translate from Dictionary inner join Terms on Dictionary.id = Terms.words_id;')
        for row in cursor:
          bot.send_message(message.chat.id, " | "+str(row[0])+" | "+row[1]+" | "+row[2]+" | "+row[3]+" | ")
    bot.reply_to(message, "Selected to the terms.")
  else:
    bot.send_message(message.chat.id, 'Я тебя не понимаю')
def translator_mess(message):
  cmd1 = message.text
  if cmd1[0].lower() in ru_letters:
    translation = translator.translate(cmd1, src=detect(cmd1), dest='en').text
    bot.send_message(message.chat.id, translation.encode('utf-8', 'replace').decode())
  elif cmd1[0].lower() in en_letters:
    translation = translator.translate(cmd1, src=detect(cmd1), dest='ru').text
    bot.send_message(message.chat.id, translation.encode('utf-8', 'replace').decode())
  else:
    bot.send_message(message.chat.id, 'Я тебя не понимаю')
def AddDictionary_mess1(message):
  global cmd2
  cmd2 = message.text
  bot.register_next_step_handler(message, AddDictionary_mess2)
def AddDictionary_mess2(message):
  global cmd3
  cmd3 = message.text
  insert_dictionary(cmd2, cmd3)
  bot.reply_to(message, "Info added to the dictionary.")
def AddTerms_mess1(message):
  global cmd4
  cmd4 = message.text
  bot.register_next_step_handler(message, AddTerms_mess2)
def AddTerms_mess2(message):
  global cmd5
  cmd5 = message.text
  bot.register_next_step_handler(message, AddTerms_mess3)
def AddTerms_mess3(message):
  global cmd6
  cmd6 = message.text
  insert_terms(cmd4, cmd5, cmd6)
  bot.reply_to(message, "Info added to the terms.")
if __name__ == '__main__':
  bot.polling(none_stop=True, interval=0)
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ python3 py.py
- Чем полезен бот ?
- Функции бота:
1. Переводчик
2. Дополнить словарь
- Дополнить словарь
- Напишите 2 сообщения (предложение и его перевод), которые нужно добавить в словарь:
- new
новый
- Info added to the dictionary.
- Словарь
- Вывожу словарь:
| Inner join | Возвращаются только те строки, где ключевые значения совпадают в обеих таблицах | Only those rows are returned where the key values match in both tables |
| Cross Join | Позволяет получить декартово произведение нескольких таблиц. особенно полезен, когда между таблицами нет определенной связи, и вам нужно создать полную комбинацию записей из каждой таблицы | - |
| Cartesian product | Результат соединения строки из первой таблицы с каждой строкой из второй таблицы | - |
Selected to the dictionary.
(tenv) tuser@kvmubuntu:~/TelegramBotTranslator$ psql -U tuser -d tbase2 -h tipubuntu
tbase2=# select * from Dictionary;
...
49 | new | новый
tbase2=# TRUNCATE Terms, Dictionary CASCADE;
Source:
# https://stackoverflow.com/questions/75900203/how-do-i-connect-my-telegram-bot-telebot-to-postgresql-url - How do I connect my telegram bot (telebot) to PostgreSQL url.
# https://pythonru.com/osnovy/globalnye-peremennye-python - Правила использования global.
# https://ru.stackoverflow.com/questions/1103332/Авторизация-в-телеграмм-боте-на-python - Авторизация в телеграмм боте на Python.
# https://otvet.mail.ru/question/219454196 - Python. Telegram bot api Как из Username получить user_id.
# https://stackoverflow.com/questions/13223820/postgresql-delete-all-content - PostgreSQL удаляет все содержимое.
Task:
Настройка службы бота.
Decision:
root@kvmubuntu:~# vim /etc/systemd/system/dato38itbot.service
root@kvmubuntu:~# cat /etc/systemd/system/dato38itbot.service
[Unit]
Description=Telegram dato38it-bot
After=network.target
[Service]
User=tuser
Group=tuser
WorkingDirectory=/home/tuser/dato38itbot/
VIRTUAL_ENV=/home/tuser/dato38itbot/telegaenv
Environment=PATH=$VIRTUAL_ENV/bin:$PATH
ExecStart=/home/tuser/dato38itbot/telegaenv/bin/python /home/tuser/dato38itbot/main.py
Restart=on-failure
[Install]
WantedBy=multi-user.target
root@kvmubuntu:~# systemctl daemon-reload
root@kvmubuntu:~# systemctl enable dato38itbot.service
root@kvmubuntu:~# systemctl start dato38itbot.service
root@kvmubuntu:~# systemctl status dato38itbot.service
Source:
# https://thecode.media/systemctl/ - Готовим файл для работы службы.
# https://synay.net/vps/preconfigured/own-telegram-bot-server-debian-12 - Создадим файл службы, чтобы запускать бот автоматически.
# https://gist.github.com/ricferr/90583f608f0b0ae9c3cf6833be04ab85 - How to create a systemd service for python script with virtualenv.
Decision:
Защитил сертификат:

2023-11-01 - 2024-05-30: Информационно-аналитический центр поддержки ГАС правосудие, Иркутск. Должность: Инженер 2 категории / Системный администратор. Дополнительная информация: Обязанности - Установка, обновление и контроль состояния программного обеспечения на объектах автоматизации, Введение эксплуатационной документации, Поддержка функционирования серверов и сервисов СУБД, Техническая поддержка пользователей. Навыки - Виртуализация, Windows, Sql. Достижения: Разработал скрипты, которые автоматизируют процессы резервного копирования базы данных перед обновлением программы ГАС правосудие.

Show

# Администрирование локальных, виртуальных и облачных серверов.
# Администрирование базы данных.
Task:
Администрирование локальных, виртуальных и облачных серверов. Ошибка после ввода пароля в программе у всех пользователей - "Не отвечает программа"
ВНЕШНЯЯБАЗА2.exe не работает
На одном из объектов автоматизации второй раз за месяц происходит процесс переполнения внешней базы документооборота C:\ПУТЬКБАЗЕ\ВНЕШНЯЯБАЗА1.GDB. База данных увеличивается в размерах с 1.8 Гб до 115Гб за три дня. После проведения инженером филиала процедуры Бэкап/Рестор внешняя база возвращается к прежнему размеру. Данная проблема наблюдается второй раз за месяц с периодичностью в две недели.
Decision:
Отключить службы Firebird, Сделать backup/restore базы ВНЕШНЯЯБАЗА1.GDB, запустив скрипты 
1. backup.bat
2. restore.bat
после чего сохранится файл ВНЕШНЯЯБАЗА1.GDB в КУДАСОХРАНЯТЬИЗМЕНЕНИЯ. Файл заменить на файл в сервере, который занимал 120 гб. Посмотреть лог файлы:
1. retranslator.log
2. retranslator_2022-01-11_15-23-40-694.log
3. retranslator_2022-01-24_16-36-09-627.log
4. retranslator_2022-01-24_16-36-16-806.log
Decision:
$ cat backup.bat
@ echo on
SET ISC_USER=ИМЯПОЛЬЗОВАТЕЛЯБАЗЫ
SET ISC_PASSWORD=ПАРОЛЬКБАЗЕ
SET dbpath=localhost:C:\ПУТЬКБАЗЕ\ВНЕШНЯЯБАЗА1.GDB
SET fbpath=C:\ПУТЬFIREBIRD\Firebird_1_5\bin\
SET bbpath=C:\КУДАСОХРАНЯТЬИЗМЕНЕНИЯ\
"%fbpath%gfix" -shut -force 5 "%dbpath%"
"%fbpath%gbak" -b -v -g -y "%bbpath%%date%.log" "%dbpath%" "%bbpath%ВНЕШНЯЯБАЗА1_%date%.gbk"
@ pause
$ cat restore.bat
@ echo on
SET ISC_USER=ИМЯПОЛЬЗОВАТЕЛЯБАЗЫ
SET ISC_PASSWORD=ПАРОЛЬКБАЗЕ
SET fbpath=C:\ПУТЬFIREBIRD\Firebird_1_5\bin\
SET bbpath=localhost:C:\КУДАСОХРАНЯТЬИЗМЕНЕНИЯ\
"%fbpath%gbak.exe" -c -v -r -y "c:\КУДАСОХРАНЯТЬИЗМЕНЕНИЯ\%date%_fix.log" "c:\КУДАСОХРАНЯТЬИЗМЕНЕНИЯ\ВНЕШНЯЯБАЗА1_backup.gbk" "%bbpath%ВНЕШНЯЯБАЗА1_fix.GDB" 
@ pause
$ cat retranslator.log
...
INF|09.12.2022 16:27:36 Сообщения в очереди "viv.client.КОДОА.1" отсутствуют
INF|09.12.2022 16:32:39 Отправка запроса id="ИДЕНТИФИКАТОРПРОЦЕССА1", type_id=ИДЕНТИФИКАТОРТИП ...
ERR|09.12.2022 16:33:37 Out of memory.
    E.ClassName=EOutOfMemory
    Sender.ClassName=TWorkThread
...
INF|11.12.2022 22:28:27 Отправка запроса id="ИДЕНТИФИКАТОРПРОЦЕССА2", type_id=ИДЕНТИФИКАТОРТИП ...
ERR|11.12.2022 22:28:53 При отправке запроса id="ИДЕНТИФИКАТОРПРОЦЕССА2" произошла неустранимая ошибка чтения из БД, запрос отклонён. Текст ошибки:
    Unsuccessful execution caused by a system error that precludes
    successful execution of subsequent statements.
    I/O error for file "C:\ПУТЬКБАЗЕ\ВНЕШНЯЯБАЗА1.GDB".
    Error while trying to write to file.
    Недостаточно места на диске.
...
Decision:
при обработке одного запроса id="ИДЕНТИФИКАТОРПРОЦЕССА1", type_id=ИДЕНТИФИКАТОРТИП происходит нехватка памяти, что далее приводит к сбою функционирования. Вероятно в запросе большое вложение. Для дальнейшего анализа смотрим БД ВНЕШНЯЯБАЗА2.gdb, в которой покажет технические ошибки состояния базы ВНЕШНЯЯБАЗА2.gdb.
Для их устранения также сделать бэкап/ресторе БД ВНЕШНЯЯБАЗА2.gdb. Далее понаблюдать за ситуацией с размером БД ВНЕШНЯЯБАЗА2.GDB, чтобы он весил не больше 19 Гб.
Task:
Администрирование базы данных. После отключения света в здании служба OracleServiceНАЗВАНИЕСИСТЕМЫ не запускается. При подключении к БСР клиента на сервере выходит следующая ошибка:
ОШИБКА ORA-01033. ORACLE INITIALIZATION OR SHUTDOWN IN PROGRESS
Не помогает перезапуск службы ORACLE и перезагрузка сервера.
Также пробовали подключиться и настроить базу в командной строке через sql plus. После ввода команды выдает ошибку:
C:\>sqlplus
Enter user-name: СОКРАЩЕННОЕОЕИМЯПОЛЬЗОВАТЕЛЯ as ПОЛНОЕИМЯПОЛЬЗОВАТЕЛЯ
SQL> alter pluggable database all open;
alter pluggable database all open
*
ERROR at line 1:
ORA-00940: invalid ALTER command
Нужно сделать рестарт базы
Decision:
C:\>sqlplus /nolog
SQL> connect СОКРАЩЕННОЕОЕИМЯПОЛЬЗОВАТЕЛЯ/pass@НАЗВАНИЕСИСТЕМЫ as ПОЛНОЕИМЯПОЛЬЗОВАТЕЛЯ
ERROR:
ORA-01017: invalid username/password; logon denied
SQL> conn СОКРАЩЕННОЕОЕИМЯПОЛЬЗОВАТЕЛЯ/oracle@НАЗВАНИЕСИСТЕМЫ as ПОЛНОЕИМЯПОЛЬЗОВАТЕЛЯ
SQL> startup mount
ORA-01081: cannot start already-running ORACLE - shut it down first
SQL> shutdown immediate
ORA-01109: database not open
Database dismounted.
ORACLE instance shut down.
SQL> startup mount
SQL> col file format a5;
SQL> col name format a20;
SQL> col status format a10;
SQL> select file#,name,status from v$datafile;
FILE# NAME         STATUS
---------- -------------------- ----------
1 C:\ORACLE\ORADATA\GA SYSTEM
S\SYSTEM01.DBF
2 C:\ORACLE\ORADATA\GA ONLINE
S\UNDOTBS01.DBF
3 C:\ORACLE\ORADATA\GA ONLINE
S\CWMLITE01.DBF
4 C:\ORACLE\ORADATA\GA ONLINE
S\DRSYS01.DBF
FILE# NAME         STATUS
---------- -------------------- ----------
5 C:\ORACLE\ORADATA\GA ONLINE
S\EXAMPLE01.DBF
6 C:\ORACLE\ORADATA\GA ONLINE
S\INDX01.DBF
7 C:\ORACLE\ORADATA\GA ONLINE
S\ODM01.DBF
8 C:\ORACLE\ORADATA\GA ONLINE
FILE# NAME         STATUS
---------- -------------------- ----------
S\TOOLS01.DBF
9 C:\ORACLE\ORADATA\GA ONLINE
S\USERS01.DBF
10 C:\ORACLE\ORADATA\GA ONLINE
S\XDB01.DBF
11 C:\ORACLE\ORADATA\GA ONLINE
S\TBLS_BSR.ORA
FILE# NAME         STATUS
---------- -------------------- ----------
12 C:\ORACLE\ORADATA\GA ONLINE
S\DELO_D.DAT
13 C:\ORACLE\ORADATA\GA ONLINE
S\DELO_I.DAT
14 C:\ORACLE\ORADATA\GA ONLINE
S\DELO_O.DAT
15 C:\ORACLE\ORADATA\GA ONLINE
S\KADR_D.DAT
FILE# NAME         STATUS
---------- -------------------- ----------
16 C:\ORACLE\ORADATA\GA ONLINE
S\KADR_I.DAT
17 C:\ORACLE\ORADATA\GA ONLINE
S\KADR_O.DAT
18 C:\ORACLE\ORADATA\GA ONLINE
S\ARCH_D.DAT
19 C:\ORACLE\ORADATA\GA ONLINE
FILE# NAME         STATUS
---------- -------------------- ----------
S\ARCH_I.DAT
20 C:\ORACLE\ORADATA\GA ONLINE
S\EDS_D.DAT
21 C:\ORACLE\ORADATA\GA ONLINE
S\EDS_I.DAT
22 C:\ORACLE\ORADATA\GA ONLINE
S\EDS_O.DAT
FILE# NAME         STATUS
---------- -------------------- ----------
23 C:\ORACLE\ORADATA\GA ONLINE
S\.ORA
24 C:\ORACLE\ORADATA\GA SYSTEM
S\SYSTEM02.ORA
25 C:\ORACLE\ORADATA\GA SYSTEM
S\SYSTEM03.ORA
25 rows selected.
SQL> recover datafile 1;
SQL> select file#,name,status from v$datafile;
FILE# NAME         STATUS
---------- -------------------- ----------
1 C:\ORACLE\ORADATA\GA SYSTEM
S\SYSTEM01.DBF
2 C:\ORACLE\ORADATA\GA ONLINE
S\UNDOTBS01.DBF
3 C:\ORACLE\ORADATA\GA ONLINE
S\CWMLITE01.DBF
4 C:\ORACLE\ORADATA\GA ONLINE
S\DRSYS01.DBF
FILE# NAME         STATUS
---------- -------------------- ----------
5 C:\ORACLE\ORADATA\GA ONLINE
S\EXAMPLE01.DBF
6 C:\ORACLE\ORADATA\GA ONLINE
S\INDX01.DBF
7 C:\ORACLE\ORADATA\GA ONLINE
S\ODM01.DBF
8 C:\ORACLE\ORADATA\GA ONLINE
FILE# NAME         STATUS
---------- -------------------- ----------
S\TOOLS01.DBF
9 C:\ORACLE\ORADATA\GA ONLINE
S\USERS01.DBF
10 C:\ORACLE\ORADATA\GA ONLINE
S\XDB01.DBF
11 C:\ORACLE\ORADATA\GA ONLINE
S\TBLS_BSR.ORA
FILE# NAME         STATUS
---------- -------------------- ----------
12 C:\ORACLE\ORADATA\GA ONLINE
S\DELO_D.DAT
13 C:\ORACLE\ORADATA\GA ONLINE
S\DELO_I.DAT
14 C:\ORACLE\ORADATA\GA ONLINE
S\DELO_O.DAT
15 C:\ORACLE\ORADATA\GA ONLINE
S\KADR_D.DAT
FILE# NAME         STATUS
---------- -------------------- ----------
16 C:\ORACLE\ORADATA\GA ONLINE
S\KADR_I.DAT
17 C:\ORACLE\ORADATA\GA ONLINE
S\KADR_O.DAT
18 C:\ORACLE\ORADATA\GA ONLINE
S\ARCH_D.DAT
19 C:\ORACLE\ORADATA\GA ONLINE
FILE# NAME         STATUS
---------- -------------------- ----------
S\ARCH_I.DAT
20 C:\ORACLE\ORADATA\GA ONLINE
S\EDS_D.DAT
21 C:\ORACLE\ORADATA\GA ONLINE
S\EDS_I.DAT
22 C:\ORACLE\ORADATA\GA ONLINE
S\EDS_O.DAT
FILE# NAME         STATUS
---------- -------------------- ----------
23 C:\ORACLE\ORADATA\GA ONLINE
S\.ORA
24 C:\ORACLE\ORADATA\GA SYSTEM
S\SYSTEM02.ORA
25 C:\ORACLE\ORADATA\GA SYSTEM
S\SYSTEM03.ORA
25 rows selected.
SQL> alter database open;
Task:
Администрирование базы данных. В ПОДСИСТЕМА не грузятся на сайт 200 дел. Смотрим лог файл:
$ cat importer.log.xml
...
<Error ReadableDateTime="23.01.2023 12:51:31" FileTimeUtc="133189230912753002">
<Message>Îøèáêà ïðè âûïîëíåíèè çàïðîñà:
BEGIN BSR.PK_BSR.CTX_Sinxronize; END;
Òåêñò îøèáêè:
ORA-20000: Oracle Text error:
DRG-50857: oracle error in dreii0fsh
ORA-01653: unable to extend table BSR.DR$CTX_SRH$I by 8192 in tablespace SYSTEM
ORA-06512: at "CTXSYS.DRUE", line 157
ORA-06512: at "CTXSYS.CTX_DDL", line 1328
ORA-06512: at "BSR.PK_BSR", line 313
ORA-06512: at line 1
</Message>
<Details>System.Exception: Îøèáêà ïðè âûïîëíåíèè çàïðîñà:
BEGIN BSR.PK_BSR.CTX_Sinxronize; END;
Òåêñò îøèáêè:
ORA-20000: Oracle Text error:
DRG-50857: oracle error in dreii0fsh
ORA-01653: unable to extend table BSR.DR$CTX_SRH$I by 8192 in tablespace SYSTEM
ORA-06512: at "CTXSYS.DRUE", line 157
ORA-06512: at "CTXSYS.CTX_DDL", line 1328
ORA-06512: at "BSR.PK_BSR", line 313
ORA-06512: at line 1

â ImpFunktions.Database.DbaseIns(String cmdString) 
â ImpFunktions.Importer.synchronize()</Details>
</Error>
пуск - все программы - oracle orahome92 - enterprize manager console - ок - databases - gas - system - oracle - storage - tablespaces
Проблема из за того, что у Вас закончилось свободное оракловое ТП SYSTEM и Tbls_bsr, которые надо увеличить вручную путем добавления DATA файла. "Флаг" в чек боксе Авторасширение не поможет.
Decision:
Обязательно делайте бэкап перед любыми действиями с базой. Дважды щелкните ЛКМ табличное пространство SYSTEM и добавьте в него второй файл. Oracle автоматически подставит расширение ORA. Исправьте его на DBF перед сохранением. 
system - add datafile - name - SYSTEM04.ORA - file size - 4096MB - storage - automatically extend datafile when full - increment - 10240KB - value - 32767MB - ok - перезапустить службу BSRImport - В админке обновлять авоматический импорт из СДП
Task:
Администрирование базы данных. Можно сделать это в командной строке, добавив дополнительный файл данных к табличному пространству и изменив размер текущего файла данных, Некоторые версии Oracle не позволяют такого!
Decision:
ALTER TABLESPACE USERS ADD DATAFILE '/u01/oradata/orcl/users02.dbf' size 25m;
ALTER DATABASE DATAFILE '/u01/oradata/orcl/users01.dbf' resize 50M;
Необходимо добавить новый датафайл к табличному пространству SYSTEM.

2022-06-01 - 2022-11-01: Yandex Практикум, Иркутск. Должность: Инженер облачных сервисов - Дополнительное образование. Дополнительная информация: Навыки - Html, Виртуализация, Linux, Sql, Bash, Clouds, Docker, Python. Достижения: В рамках программы "Инженер облачных сервисов Yandex" защитил практические работы по темам "Хранение и анализ данных", "Devops и автоматизация", "Serverless" и "Безопасность".

Show

# развернул пять кластеров баз данных MySQL, PostgreSQL, MongoDB, ClickHouse и Ydb
# добавил данные из файлов в БД ClickHouse для анализа прогноза за всю историю наблюдений за последние несколько лет с помощью SQL-запросов
# добавил данные из тестового приложения для подключения к БД YDB и запуска тестового приложения, чтобы создать в ней несколько таблиц с данными о популярных сериалах
# реализовал систему хранения рентгеновских снимков для клиники
# развернул кластер Hadoop с помощью сервиса Yandex Data Proc
# поднял кластер Kubernetes в Yandex Cloud
# развернул приложение веб-сервер NGINX c Балансировкой нагрузки и Автомасштабированием в Yandex Managed Kubernetes
# проверил на отказоустойчивость по основным сценариям сбоев
# разработал навык Алисы, которая повторяет всё, что вы ему напишете с сохранением фраз в новом файле в бакете
# разработал функцию для проверки доступности сайта ya.ru, которая будет измерять время ответа, передавать в БД PostgreSQL результаты работы функции, запускать триггер-таймер для регулярного опроса сайта ya.ru
# с помощью REST API получил до 50 результатов проверки из БД,
# реализовал проекты, которые позволят пользователям конвертировать видеофайлы в GIF и конвертировать длинные ссылки в короткие
# реализовал права на управление сервисным аккаунтом
# организовал защищённый канал настроив IPSec VPN-туннель между двумя VPN-шлюзами в ВМ с помощью демона strongSwan
# реализовал для домена втоматический выпуск сертификата с помощью Certificate Manager
Task:
Хранение и анализ данных в Yandex Cloud
Task:
Создание бакетов и загрузка объектов
Потренируемся работать с объектным хранилищем на практике. Представьте, что вы создаёте облачную систему хранения рентгеновских снимков для крупной клиники.
Рентгеновские снимки — это неструктурированные данные, которые нельзя изменять, нужно надежно хранить и легко находить.
Загруженные файлы будут скачивать нечасто. Также важно предоставлять доступ к файлам другим клиникам (это пригодится, если пациента переводят или врачу надо посоветоваться с коллегами). Объектное хранилище — подходящее решение задачи.
Decision:
Выберите на стартовой странице консоли управления сервис Object Storage.
Давайте создадим бакет для рентгеновских снимков.
Нажмите кнопку Создать бакет. Откроется окно с основными параметрами:
Имя. Придумайте его с учетом правил. Обратите внимание, что дать бакету имя hospital не получится. Имена бакетов во всем Yandex Object Storage уникальны — назвать два бакета одинаково нельзя даже в разных облаках. Помните об этом, если будете создавать бакеты автоматически.
Макс. размер. У вас есть два варианта: Выбрать опцию Без ограничения. Размер бакета будет увеличиваться, сколько бы объектов в него ни помещали. Указать максимальный размер. Это убережёт вас от финансовых потерь, если что-то пойдёт не так и в бакет загрузится слишком много объектов.
Другие опции. Далее для всех типов операций оставьте ограниченный доступ (публичный позволяет выполнять операции всем пользователям интернета), выберите стандартный класс хранилища и нажмите кнопку Создать бакет.
На странице объектного хранилища появился пустой бакет. Мы приготовили два рентгеновских снимка: image01.dat и image02.dat. Файлы можно загрузить в бакет с помощью: консоли управления; приложений; S3-совместимого HTTP API; HTML-форм на сайте.
Разберём два способа: ручную загрузку через консоль управления и автоматическую с помощью утилиты S3cmd.
Для загрузки файла через консоль управления выберите созданный бакет и в открывшемся окне нажмите кнопку Загрузить объекты.
Выберем файл image01.dat. В появившейся форме нажмите кнопку Загрузить — и вы увидите, что файл оказался в хранилище.
Загрузите второй файл с помощью утилиты S3cmd — консольного клиента для Linux и MacOS, предназначенного для работы с S3-совместимым HTTP API. Для работы в Windows используйте один из вариантов: установите другой консольный клиент для объектных хранилищ, например AWS CLI; установите подсистему Linux на Windows с помощью утилиты WSL (Windows Subsystem for Linux) и работайте с S3cmd в ней; создайте в облаке виртуальную машину с Ubuntu и работайте с S3cmd в ней. Для загрузки файла-примера в виртуальную машину воспользуйтесь командой:
$ wget "https://disk.yandex.ru/i/2UlugGkurhcxWw" -O image02.dat
Установите S3cmd (в Ubuntu, например, это делается с помощью команды sudo apt-get install s3cmd). Теперь настройте S3cmd для работы с Yandex Object Storage:
$ s3cmd --configure
Инструкции о настройке клиента вы найдете в документации.
После ввода параметров утилита попытается установить соединение с объектным хранилищем и в случае успеха покажет такое сообщение: Success. Your access key and secret key worked fine :-)
Загрузим в бакет второй файл (image02.dat) и затем получим список хранящихся в бакете объектов:
s3cmd put <путь к второму файлу>/image02.dat s3://<имя бакета>
s3cmd ls s3://<имя бакета>
Вернемся в консоль управления.
Мы видим, что класс хранилища у обоих объектов — стандартное. Напомним: стандартное хранилище подходит для данных, к которым обращаются часто, а тариф за размещение данных в нем примерно в два раза выше, чем в холодном хранилище.
Спустя несколько недель после того, как рентгеновский снимок сделан, к нему будут редко обращаться (если вообще будут), потому что пациент, скорее всего, выздоровеет.
Чтобы оптимизировать затраты на хранение данных, настроим жизненный цикл объектов в бакете. Создадим правило, согласно которому через 30 дней после загрузки объектов в бакет класс их хранилища будет автоматически меняться со стандартного на холодное.
Перейдите на вкладку Жизненный цикл и нажмите кнопку Настроить. Задайте произвольное описание. В поле Префикс укажите Все объекты. Выберите тип операции Transition. В качестве Условия срабатывания правила задайте Точную дату или Количество дней. В первом случае правило сработает в 00:00 установленной даты. Во втором — через указанное количество дней после загрузки объекта в бакет.
Если понадобится настроить автоматическое удаление объектов, выберите тип операции Expiration. Нажмите кнопку Сохранить.
Представим теперь, что объекты в хранилище — это оцифрованные рентгеновские снимки пациента Петрова. Первый из них (image01.dat) сделали несколько месяцев назад в ходе профосмотра, а второй (image02.dat) — вчера, после того как Петров обратился к врачу с жалобой на недомогание. В обоих случаях на снимках не увидели патологий.
Опишите с помощью пользовательских метаданных эти снимки, и позже вы быстро найдете их среди множества объектов в бакете.
С помощью утилиты S3cmd задайте для загруженных объектов метаданные с фамилией пациента (x-amz-meta-patient:petrov) и с результатами обследования (x-amz-meta-status:ok):
s3cmd modify --add-header=x-amz-meta-patient:petrov --add-header=x-amz-meta-status:ok s3://hospital/image01.dat s3://hospital/image02.dat
Выведите на экран информацию об этих объектах, чтобы проверить, что получилось:
s3cmd info s3://hospital/image01.dat s3://hospital/image02.dat
В результате вы должны увидеть информацию об объектах в бакете.
s3://hospital/image01.dat (object):
File size: 33
Last mod: Thu, 04 Mar 2021 22:05:31 GMT
MIME type: application/x-www-form-urlencoded
Storage: STANDARD
MD5 sum: 6f6d5a1cb79839e523582ed8810a42fd
SSE: none
Policy: none
CORS: none
x-amz-meta-patient: petrov
x-amz-meta-status: ok
s3://hospital/image02.dat (object):
File size: 16
Last mod: Thu, 04 Mar 2021 23:11:27 GMT
MIME type: text/plain
Storage: STANDARD
MD5 sum: 0366a1d19e584ce79d5c05ddedc69310
SSE: none
Policy: none
CORS: none
x-amz-meta-patient: petrov
x-amz-meta-status: ok
Предположим, Петров чувствует себя хуже. Судя по анализам, он действительно болен. Лечащий врач решает проконсультироваться с более опытной коллегой Ивановой из профильной клиники. Объекты в бакете недоступны для внешних пользователей, поскольку при его создании мы ограничили доступ. Чтобы Иванова увидела рентгеновский снимок Петрова, отправим ей временную ссылку на объект image02.dat.
Для этого в консоли управления кликните на объект и в открывшемся окне информации об объекте нажмите кнопку Получить ссылку. Укажите время жизни ссылки в часах или днях.
Можно поделиться ссылкой или использовать ее в любом сервисе для доступа к файлу.
После консультации Иванова поставила Петрову правильный диагноз: вирусная пневмония (код J12 по Международной классификации болезней). Вам осталось исправить метаданные объекта image02.dat. Замените значение метаданных с результатами обследования с ok на J12 самостоятельно.
Decision:
$ wget "https://disk.yandex.ru/i/2UlugGkurhcxWw" -O image02.dat
$ wget "https://disk.yandex.ru/i/qpl0T4u-nWPgiw" -O image01.dat
$ ls *.dat
image01.dat image02.dat
$ sudo apt-get install s3cmd
$ s3cmd --configure
$ s3cmd ls
2023-12-06 02:37 s3://klinika138
$ s3cmd put /YOUR-DIR/image02.dat s3://klinika138
$ s3cmd modify \
--add-header=x-amz-meta-patient:petrov \
--add-header=x-amz-meta-status:ok \
s3://klinika138/image01.dat \
s3://klinika138/image02.dat
$ s3cmd info \
s3://klinika138/image01.dat \
s3://klinika138/image02.dat
Task:
Хранение статических веб-сайтов в Object Storage
Представьте, что вам нужно выбрать оптимальный хостинг для сайта клиники. Главные критерии: отказоустойчивый, недорогой и простой в обслуживании.
Один из вариантов решения такой задачи — использовать объектное хранилище. Вы можете, не настраивая никаких серверов, просто загрузить HTML-файлы, скрипты, стили и другие файлы в хранилище. Пользователи будут открывать в браузере ваш сайт, а по сути — скачивать файлы прямо из бакета.
Важно понимать, что этот вариант подойдет только для полностью статических сайтов. Иными словами, сайт должен быть сделан с помощью клиентских технологий (HTML, CSS и JavaScript) и не требовать запуска чего-либо на стороне веб-сервера.
Предположим, что сайт нашей клиники как раз такой — полностью статический. Опубликуйте его с помощью объектного хранилища. Прежде всего для него нужно создать бакет:
Decision
Обратите внимание на несколько особенностей: Если вы планируете использовать собственный домен (например www.example.com), то присвойте бакету точно такое же имя. Откройте публичный доступ на чтение объектов. Это позволит пользователям интернета скачивать объекты из бакета и просматривать сайт в браузере.
Задайте необходимые настройки и нажмите кнопку Создать бакет.
Теперь загрузите в бакет файлы сайта (например, этот и этот) любым удобным способом.
Чтобы настроить хостинг, перейдите на страницу бакета в консоли управления. Выберите вкладку Веб-сайт на левой панели и включите опцию Хостинг.
Укажите файл с главной страницей сайта (как правило, это index.html), а поле со страницей ошибки можно не заполнять.
Сохраните настройки, и сайт станет доступен по адресам:
http(s)://<имя_бакета>.website.yandexcloud.net
http(s)://website.yandexcloud.net/<имя_бакета>
По умолчанию сайт будет доступен только по протоколу HTTP. Для поддержки HTTPS нужно загрузить в объектное хранилище TLS-сертификат. Вам предстоит это сделать в одной из практических работ курса «Безопасность».
Если у вас есть собственный домен и вы хотите опубликовать сайт на нём, то настройте CNAME-запись у DNS-провайдера или на своем DNS-сервере. Например, для домена www.example.com CNAME-запись выглядела бы так: www.example.com CNAME www.example.com.website.yandexcloud.net
В этом случае можно использовать домены не ниже третьего уровня (то есть использовать домен example.com не получится, только www.example.com). Это связано с особенностями обработки CNAME-записей на DNS-хостингах.
Decision:
$ wget "https://disk.yandex.ru/d/KcpMuYBwKjIa6Q" -O index.html
$ wget "https://disk.yandex.ru/i/uTai62_esPSaEw" -O doctor.png
$ s3cmd put /YOUR-DIR/doctor.png s3://www.aibloit.healthcare138
$ s3cmd put /YOUR-DIR/index.html s3://www.aibloit.healthcare138
Task:
Создание кластера базы данных MySQL. Object Storage — удобный и полезный инструмент для хранения данных в облаке. Но для решения практических задач важно не просто хранить данные, но и иметь возможность их изменять и выполнять с ними различные операции (сортировать, группировать, делать выборки и так далее). Для этого используются базы данных. В этой и следующих темах вы научитесь работать с несколькими управляемыми БД. И начнем мы с одной из самых популярных — MySQL.
На этом уроке вы создадите и настроите кластер управляемой БД MySQL, подключитесь к нему, перенесёте данные в облако, познакомитесь с возможностями резервного копирования и мониторинга. Эти навыки пригодятся вам и в других сервисах управляемых БД, поскольку принципы работы в них очень похожи.
Предположим, вы решили добавить в разрабатываемый вами мессенджер новую функциональность. Вы написали микросервис, который позволяет оценивать сообщения в групповых чатах и хранит оценки в БД MySQL. Давайте поместим эту БД в Yandex Cloud.
Decision:
Прежде всего понадобится создать кластер: набор виртуальных машин (ВМ, или хостов), на которых будет развёрнута БД. Это обязательный первый шаг при использовании любого сервиса управляемых БД.
Войдите в консоль управления Yandex Cloud и выберите каталог для кластера. Вверху справа нажмите кнопку Создать ресурс и выберите из выпадающего списка Кластер MySQL.
Откроется страница с основными настройками кластера. Рассмотрим их подробнее.
Базовые параметры. Имя кластера может включать только цифры, прописные и строчные латинские буквы, дефисы.
Поле Описание заполнять необязательно. Оно полезно, если вам нужно создать несколько кластеров для разных целей, чтобы в них было проще ориентироваться.
О том, какое бывает Окружение кластера и чем различаются PRESTABLE и PRODUCTION, мы говорили на одном из предыдущих уроков. Поскольку микросервис только разрабатывается, выберите окружение PRESTABLE.
Версия. В качестве сервера MySQL в Yandex Cloud используется Percona Server версии 5.7 или 8.0. У этих реализаций сервера улучшенная производительность на многоядерных машинах. Если для вас критична стабильность работы микросервиса, выбирайте проверенную временем 5.7. Для нашей задачи подойдёт 8.0: в ней много новых функций, но она ещё не полностью обкатана.
Класс хостов. Следующий шаг — выбор класса хостов, или шаблона ВМ. Хосты кластера будут развёрнуты на базе ВМ Compute Cloud с использованием этого шаблона.
Платформа определяет тип физического процессора (Intel Broadwell или Intel Cascade Lake), а также конфигурации числа ядер виртуального процессора (vCPU) и размера оперативной памяти.
Если тип процессора для вас неважен, выбирайте более современную платформу Intel Cascade Lake. Она предоставляет широкий выбор конфигураций вычислительных ресурсов.
Также на конфигурации влияет тип ВМ, на которой будет развёрнута БД.
Standard — это обычные ВМ с 4 ГБ RAM на ядро vCPU. Это оптимальный баланс между количеством запущенных процессов, быстродействием и потребляемой оперативной памятью.
Memory-optimized — машины с вдвое увеличенным объёмом RAM на каждое ядро. Выбирайте их для высоконагруженных сервисов с повышенными требованиями к кешу.
Burstable — машины, для которых гарантируется использование лишь доли ядра vCPU (5, 20 или 50%) с вероятностью временного повышения вплоть до 100%. Они стоят дешевле и подходят для задач, где не нужен постоянный уровень производительности, т. е. для тестирования или разработки.
Выберем для микросервиса следующий класс хоста: платформа — Intel Cascade Lake; тип — standard; конфигурация вычислительных ресурсов — s2.micro (два ядра vCPU, 8 ГБ RAM).
Хранилище данных. Хранилище БД может быть сетевым или локальным. В первом случае данные находятся на виртуальных дисках в инфраструктуре Yandex Cloud. Локальное хранилище — это диски, которые физически размещаются в серверах хостов БД.
При создании кластера можно выбирать между следующими типами хранилища:
- Стандартное сетевое (network-hdd) — это наиболее экономичный вариант. Выбирайте его, если к скорости записи и чтения нет особых требований.
- Быстрое сетевое (network-ssd) стоит примерно в четыре раза дороже, но при размере хранилища от 100 ГБ работает быстрее стандартного в десять и более раз (чем больше размер, тем заметнее разница в скорости).
- Сетевое на нереплицируемых SSD-дисках (network-ssd-nonreplicated) — использует сетевые SSD-диски с повышенной производительностью, реализованной за счет устранения избыточности. Объём такого хранилища можно увеличивать только с шагом 93 ГБ.
- Быстрое локальное (local-ssd) — самое быстрое и дорогое. Если локальный диск откажет, все сохранённые на нём данные будут потеряны. Чтобы этого избежать, при выборе локального хранилища сервис автоматически создаст отказоустойчивый кластер минимум из трёх хостов.
При создании кластера внимательно выбирайте тип хранилища. Размер хранилища можно будет позже изменить, а тип — нет.
Выберите для кластера стандартное сетевое хранилище network-hdd размером 50 ГБ.
База данных. В этом разделе настроек задаются атрибуты базы: Имя БД, уникальное в рамках кластера, Имя пользователя (владельца БД) и Пароль пользователя.
Сеть. Здесь можно выбрать облачную сеть для кластера и группы безопасности для его сетевого трафика.
Оставьте сеть по умолчанию (default) или выберите сеть, которую создали на предыдущем курсе. Кластер будет доступен для всех ВМ, которые подключены к вашей облачной сети.
Параметры хостов. В этом блоке можно добавить количество хостов, которые будут созданы вместе с кластером, и изменить их параметры. Дополнительные хосты могут понадобиться, например, для репликации БД или снижения нагрузки на хост-мастер.
Для наших целей достаточно кластера из одного хоста. Нажмите значок редактирования параметров хоста и в открывшемся окне выберите опцию Публичный доступ. Это означает, что к хосту можно будет подключиться из интернета, а не только из облачной сети. Остальные параметры оставьте без изменений.
Дополнительные настройки.Здесь можно: указать время Начала резервного копирования и Окна обслуживания. Это пригодится, если вы хотите, чтобы резервное копирование и техобслуживание хостов кластера не совпадали с периодами пиковых нагрузок на БД; разрешить Доступ из DataLens, если вы планируете анализировать в DataLens данные из базы. Подробнее о DataLens вы узнаете на одном из следующих занятий; разрешить Доступ из консоли управления, чтобы выполнять SQL-запросы к БД из консоли управления Yandex Cloud. Отметьте этот пункт: доступ из консоли понадобится нам на следующих практических работах; разрешить Доступ из Data Transfer, чтобы разрешить доступ к кластеру из сервиса Yandex Data Transfer в Serverless-режиме; разрешить Сбор статистики, чтобы воспользоваться инструментом Диагностика производительности в кластере; установить Защиту от удаления, чтобы защитить кластер от непреднамеренного удаления пользователем.
В этом блоке также можно задать настройки БД (например используемую сервером MySQL кодировку при работе с данными и обмене информацией с клиентами). По умолчанию при создании кластера сервис выбирает оптимальные настройки. Изменяйте их, если уверены, что это необходимо.
Настройка завершена. Осталось только нажать кнопку Создать кластер.
Создание кластера займёт несколько минут. Когда он будет готов к работе, его статус на панели Managed Service for MySQL сменится с Creating на Running, а состояние — на Alive.
Статус показывает, что происходит с кластером: Creating — создаётся; Running — работает; Error — не отвечает, возникла проблема; Updating — обновляется; Stopped — остановлен; Unknown — статус неизвестен (так может быть, например, когда кластер не виден из интернета).
Состояние — это показатель доступности кластера: Alive — все хосты кластера работают; Degraded — часть хостов (один или больше) не работает; Dead — все хосты не работают.
Task:
Подключение к БД и добавление данных
Доступ из консоли управления. В кластере, который вы создали, уже есть БД. Она пока пустая. Поскольку при создании кластера вы выбрали в настройках пункт Доступ из консоли управления, в консоли управления Yandex Cloud появилась вкладка с интерфейсом для выполнения SQL-запросов к БД.
Давайте зайдём туда и создадим в БД таблицу для нашего микросервиса.
Decision:
На странице Managed Service for MySQL выберите строку с созданным вами кластером. В панели консоли управления перейдите на вкладку SQL. Вам будет предложено выбрать БД для SQL-запросов и имя пользователя, а также ввести пароль. Все эти атрибуты вы задавали при создании кластера.
Нажмите кнопку Подключиться. Откроется структура БД (сейчас там написано, что данных нет) и окно ввода для SQL-запросов.
Теперь создадим таблицу. Введите в окне ввода следующий запрос и нажмите кнопку Выполнить.
CREATE TABLE IF NOT EXISTS ratings (
rating_id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
message_id INT NOT NULL,
rating INT NOT NULL
) ENGINE=INNODB;
Обратите внимание, что в качестве движка в сервисе управляемых БД MySQL используется только InnoDB.
В таблицу можно добавить данные с помощью команды INSERT.
INSERT INTO ratings (user_id,message_id,rating) VALUES (44,368,4);
Чтобы отобразить обновлённую структуру БД, нажмите на имя БД и выберите таблицу ratings.
Наведите указатель на заголовок столбца, чтобы увидеть тип данных в нём.
SQL-запросы через консоль управления Yandex Cloud — нетипичный способ работы с БД. Используйте его для небольших, разовых задач, когда быстрее и проще открыть подключение в браузере. Этот способ не очень удобен: текст запроса и результат его выполнения доступны, только пока вы не закрыли или не перезагрузили страницу в браузере. Конечно, если запрос успешно запущен, то сервис обработает его независимо от состояния консоли управления.
В консоли выводятся только первые 1000 строк результата запроса, даже если данных больше. Чтобы увидеть строку, введите её номер в поле Номер первой строки.
Подключение к кластеру
В основном вы будете работать с БД из приложений или из командной строки. Однако для этого нужно подключиться к хосту, на котором развёрнута БД.
Есть два варианта подключения. Если публичный доступ к хосту открыт, подключитесь к нему через интернет с помощью защищённого SSL-соединения. Если публичного доступа нет, подключитесь к хосту с виртуальной машины, созданной в той же виртуальной сети. SSL-соединение можно не использовать, но тогда трафик между виртуальной машиной и БД шифроваться не будет.
Давайте подключимся к БД через интернет и создадим в ней ещё одну таблицу. Для выполнения этого задания вы можете использовать виртуальную машину с Ubuntu.
Для создания таблицы сделаем в текстовом редакторе файл createTables.sql с командами. Например, такой:
CREATE TABLE IF NOT EXISTS users (
user_id INT AUTO_INCREMENT,
nickname VARCHAR(128) NOT NULL,
avatar VARCHAR(255),
mail VARCHAR(255),
  PRIMARY KEY (user_id)
) ENGINE=INNODB;
Чтобы выполнить этот запрос в БД, подключимся к хосту. Для этого понадобится SSL-сертификат. Команды для его получения в Ubuntu:
mkdir ~/.mysql
wget "https://storage.yandexcloud.net/cloud-certs/CA.pem" -O ~/.mysql/root.crt
chmod 0600 ~/.mysql/root.crt
Чтобы получить команды для подключения к БД, в консоли управления перейдите на страницу кластера, на вкладке Обзор нажмите кнопку Подключиться. В результате их выполнения в директории /home/<домашняя_директория>/.mysql/ сохранится SSL-сертификат root.crt.
Установите утилиту mysql-client, если на вашем компьютере или виртуальной машине её нет.
sudo apt update
sudo apt install -y mysql-client
Чтобы подключиться к БД, введите команду mysql. Для запуска нашего скрипта она выглядит следующим образом:
mysql --host=<адрес хоста> \
  --port=3306 \
  --ssl-ca=~/.mysql/root.crt \
  --ssl-mode=VERIFY_IDENTITY \
  --user=<имя пользователя> \
  --password \
<имя_базы_данных> < createTables.sql
Сервис помогает заполнить параметры в команде. Чтобы посмотреть пример команды с адресом хоста, именами пользователя и БД, в консоли управления перейдите на страницу кластера, на вкладке Обзор нажмите кнопку Подключиться.
После запуска команды введите пароль к БД, после чего в ней будет создана таблица users.
Если при создании кластера вы не включили публичный доступ, то к БД можно подключиться с виртуальной машины из той же облачной сети без использования шифрования. \\Следовательно, в этом случае в команде для подключения опускается параметр --ssl-ca, а --ssl-mode передаётся со значением DISABLED:
mysql --host=адрес_хоста \
--port=3306 \
--ssl-mode=DISABLED \
--user=<имя пользователя> \
--password \
<имя_базы_данных> < createTables.sql
Естественно, подключаться к БД можно не только из командной оболочки, но и из приложений. Нажмите уже знакомую вам кнопку Подключиться и посмотрите примеры кода для Python, PHP, Java, Node.js, Go, Ruby или настроек для драйвера ODBC.
Если вы хотите перенести БД в облако, то понадобится создать дамп и восстановить его в нужном кластере. Дамп — это копия БД или её части, представляющая собой текстовый файл с командами SQL (например, CREATE TABLE или INSERT). Его создают с помощью утилиты mysqldump.
Давайте попробуем перенести данные в кластер с помощью дампа. Для этого воспользуемся тестовой БД с данными о сотрудниках компании (имя, дата рождения, дата найма, место работы, зарплата и т. д.). Размер БД — около 167 Мб.
Скачайте из репозитория и сохраните на компьютере файлы с расширениями .sql и .dump. В файле employees.sql содержатся SQL команды, необходимые для создания таблиц и добавления в них данных из dump-файлов. Для переноса тестовой БД в облако понадобится запустить этот файл. Но, прежде чем приступить к переносу БД, откройте этот файл и удалите или закомментируйте (допишите в начало строки --) в нём строку 110. В этой строке расположена команда FLUSH LOGS, которая закрывает и снова открывает файлы журналов, а они в этой тестовой БД отсутствуют.
Создайте базу данных employees через консоль управления. Для этого на странице кластера перейдите на вкладку Базы данных и нажмите кнопку Добавить.
Добавьте пользователю, например user1, разрешение на доступ к БД employees. Для этого на странице кластера перейдите на вкладку Пользователи, напротив пользователя user1 нажмите кнопку ··· и выберите Настроить. Во всплывающем окне нажмите Добавить базу данных, выберите employees, добавьте роль ALL_PRIVILEGES и нажмите Сохранить.
Затем в командной строке перейдите в папку сохраненными файлами .sql и .dump и восстановите данные из дампа с помощью команды:
mysql --host=<адрес хоста> \
  --port=3306 \
  --ssl-ca=~/.mysql/root.crt \
  --ssl-mode=VERIFY_IDENTITY \
  --user=<имя_пользователя> \
  --password \
employees < ~/employees.sql
После того как данные скопируются, ваш кластер и БД будут готовы к работе. Подключитесь к БД в консоли управления и убедитесь, что данные перенесены.
Decision:
$ mkdir ~/.mysql
$ wget "https://storage.yandexcloud.net/cloud-certs/CA.pem" -O ~/.mysql/root.crt
$ chmod 0600 ~/.mysql/root.crt
$ sudo apt update
$ sudo apt install mysql-client
$ vim createTables.sql
$ cat createTables.sql
CREATE TABLE IF NOT EXISTS users (
user_id INT AUTO_INCREMENT,
nickname VARCHAR(128) NOT NULL,
avatar VARCHAR(255),
mail VARCHAR(255),
PRIMARY KEY (user_id)
) ENGINE=INNODB;
$ mysql --host=rc1a-642tdtv6ope6gk7u.mdb.yandexcloud.net \
--port=3306 \
--ssl-ca=~/.mysql/root.crt \
--ssl-mode=VERIFY_IDENTITY \
--user=tuser \
--password \
tdb < createTables.sql
$ wget https://github.com/datacharmer/test_db/archive/refs/heads/master.zip
$ unzip master.zip
$ ls test_db-master/
Changelog     employees.sql   load_dept_emp.dump load_salaries1.dump load_titles.dump sakila   test_employees_md5.sql
employees_partitioned_5.1.sql images     load_dept_manager.dump load_salaries2.dump objects.sql show_elapsed.sql test_employees_sha.sql
employees_partitioned.sql load_departments.dump load_employees.dump load_salaries3.dump README.md   sql_test.sh test_versions.sh
$ cat test_db-master/employees.sql | grep flush
flush /*!50503 binary */ logs;
$ vim test_db-master/employees.sql
$ cat test_db-master/employees.sql | grep flush
$ cd test_db-master/
$ mysql --host=rc1a-642tdtv6ope6gk7u.mdb.yandexcloud.net \
--port=3306 \
--ssl-ca=~/.mysql/root.crt \
--ssl-mode=VERIFY_IDENTITY \
--user=tuser1 \
--password \
employees < employees.sql
$ mysql --host=rc1a-642tdtv6ope6gk7u.mdb.yandexcloud.net \
--port=3306 \
--ssl-ca=~/.mysql/root.crt \
--ssl-mode=VERIFY_IDENTITY \
--user=tuser1 \
--password \
employees
mysql> show tables;
Task:
Создание кластера базы данных PostgreSQL.
В этой практической работе вы создадите кластер еще одной управляемой БД, на этот раз PostgreSQL, подключитесь к ней и загрузите в нее данные.
Decision:
Создание кластера управляемой базы данных PostgreSQL аналогично созданию кластера базы данных MySQL.
Перейдите в сервис управляемых баз данных PostgreSQL и нажмите кнопку Создать кластер.
В появившемся окне настроек задайте необходимые параметры.
- Имя кластера и его описание. Выберите уникальное в облаке имя кластера. Описание опционально, поэтому можно оставить это поле пустым.
- В поле Окружение выберите PRODUCTION.
- Выберите версию PostgreSQL и класс хоста.
- Выберите размер и тип сетевого хранилища.
- Задайте атрибуты базы данных.
- Выберите из списка сеть, в которой будут находиться хосты кластера (для подключения потребуются публичные хосты).
- В блоке Хосты добавьте ещё два хоста в других зонах доступности для обеспечения отказоустойчивости кластера. База автоматически реплицируется.
- В блоке Дополнительные настройки задайте время начала резервного копирования и включите доступ из консоли управления.
- Нажмите кнопку Создать кластер.
Как и в случае с MySQL, к хостам кластера Managed Service for PostgreSQL можно подключиться двумя способами.
Через интернет. Если вы настроили публичный доступ для нужного хоста, то подключиться к нему можно с помощью SSL-соединения.
С виртуальных машин Yandex Cloud. Они должны быть расположены в той же облачной сети. Если к хосту нет публичного доступа, для подключения с таких виртуальных машин SSL-соединение использовать необязательно. Обратите внимание, что если публичный доступ в вашем кластере настроен только для некоторых хостов, автоматическая смена мастера может привести к тому, что вы не сможете подключиться к мастеру из интернета.
Установите клиент для подключения к БД PostgreSQL. Команда установки в Ubuntu: sudo apt update && sudo apt install -y postgresql-client
Скачайте сертификат для подключения к БД PostgreSQL:
mkdir -p ~/.postgresql
wget "https://storage.yandexcloud.net/cloud-certs/CA.pem" -O ~/.postgresql/root.crt
chmod 0600 ~/.postgresql/root.crt
Пример команды для подключения можно посмотреть в консоли управления, нажав на кнопку Подключиться на странице кластера. Подключение с SSL происходит при помощи следующей команды:
psql "host=<FQDN_хоста> \
port=6432 \
sslmode=verify-full \
dbname=<имя базы данных> \
user=<имя пользователя базы данных> \
target_session_attrs=read-write"
Загрузка данных в базу данных из CSV. Одним из способов добавления данных в базу является их загрузка из csv-файла.
Предположим, вы используете БД для организации работы транспортной службы интернет-магазина. Вам нужно добавить в базу таблицу, содержащую данные о расстояниях между складом и пунктами самовывоза, а также о стандартном времени доставки товаров со склада в эти пункты. Создадим csv-файл, например DTM.csv, который содержит такие данные (100 - код склада, 101-109 - коды пунктов, Time - стандартное время доставки в минутах, Distance - расстояние в километрах):
"depot","store","time","distance"
"100","101",31,12
"100","102",38,17
"100","103",56,33
"100","104",70,60
"100","105",41,25
"100","106",21,8
"100","107",33,14
"100","108",62,42
"100","109",45,29
Важные моменты при миграции из CSV:
- Названия колонок в файле и в таблице необязательно совпадают.
- Файл содержит заголовок, который не нужно импортировать.
- Первые 2 колонки конвертируем из строк (string) в целые числа (int).
PostgreSQL позволяет импортировать данные из файла несколькими способами:
- Командой copy.
- Через функции pl/pgsql.
- Средствами другого языка, например Python.
Воспользуемся первым способом. Сначала нам понадобится создать таблицу, в которую будет осуществлена миграция данных. Подключитесь к БД согласно инструкциям выше. Выполните следующую команду:
CREATE TABLE dtm (
id serial PRIMARY KEY,
depot int NOT NULL,
store int NOT NULL,
time int NOT NULL,
distance int NOT NULL
);
Загрузите данные: \copy dtm(depot,store,time,distance) from '/<путь к файлу>/DTM.csv' DELIMITERS ',' CSV HEADER;
В этой команде мы учли те моменты, о которых говорили вначале:
- dtm (depot, store, time, distance) маппинг колонок связывает колонки в файле с колонками в таблице, их имена могут не совпадать
- CSV HEADER показывает, что заголовок импортировать не нужно
- Колонки в таблице уже имеют правильные типы данных, конвертация будет выполнена автоматически.
В консоли управления на странице кластера перейдите на вкладку SQL. Введите пароль пользователя БД и нажмите кнопку Подключиться. Выберите таблицу dtm, чтобы убедиться, что добавление данных выполнено правильно.
Decision:
$ sudo apt update && sudo apt install postgresql-client
$ mkdir -p ~/.postgresql
$ wget "https://storage.yandexcloud.net/cloud-certs/CA.pem" -O ~/.postgresql/root.crt
$ chmod 0600 ~/.postgresql/root.crt
$ vim DTM.csv
$ cat DTM.csv
"deport","store","time","distance"
"100","101",31,12
"100","102",38,17
"100","103",56,33
"100","104",70,60
"100","105",41,25
"100","106",21,8
"100","107",33,14
"100","108",62,42
"100","109",45,29
$ psql "host=rc1a-w3usdays081v0itf.mdb.yandexcloud.net,rc1c-qga7rd1sqe5jm8io.mdb.yandexcloud.net,rc1d-l1vzj1210qj68s8n.mdb.yandexcloud.net \
port=6432 \
sslmode=verify-full \
dbname=YOUR-DB \
user=YOUR-USERNAME \
target_session_attrs=read-write"
YOUR-DB=> CREATE TABLE dtm (
YOUR-DB(> id serial PRIMARY KEY,
YOUR-DB(> depot int NOT NULL,
YOUR-DB(> store int NOT NULL,
YOUR-DB(> time int NOT NULL,
YOUR-DB(> distance int NOT NULL
YOUR-DB(> );
YOUR-DB=> \copy dtm(depot,store,time,distance) from '/home/test/DTM.csv' DELIMITERS ',' CSV HEADER;
YOUR-DB=> exit
Task:
Создание кластера MongoDB.
На этом уроке вы создадите кластер MongoDB, подключитесь к нему и загрузите в него данные.
Раньше вы работали только с реляционными БД, но использование кластера MongoDB принципиально не отличается от работы с кластером MySQL или PostgreSQL, так что многое будет вам знакомо.
Decision:
Выберите в консоли управления Yandex Cloud каталог для кластера БД. На дашборде каталога откройте раздел Managed Service for MongoDB. В открывшемся окне нажмите кнопку Создать кластер.
Установите основные настройки кластера. Для этого урока создайте кластер с минимальной конфигурацией: тип хоста burstable, класс b2.nano, стандартное сетевое хранилище размером 10 ГБ. Откройте публичный доступ к хосту и задайте пароль пользователя БД. Остальные значения оставьте по умолчанию.
В сервисе управляемых БД MongoDB к хостам можно подключаться через интернет или с виртуальных машин в той же сети. Порт для подключения — 27018.
Для подключения через интернет хосты кластера должны находиться в публичном доступе. Подключаться можно только через зашифрованное соединение.
Обратите внимание: если публичный доступ настроен только для некоторых хостов в кластере, то при автоматической смене основной реплики она может оказаться недоступной из интернета.
Если к хосту нет публичного доступа и вы подключаетесь к нему с виртуальных машин Yandex Cloud, то зашифрованное соединение необязательно.
Подключитесь к созданной БД из интернета. Используйте SSL-сертификат, который вы подготовили на одной из предыдущих практических работ, или команду (для Ubuntu):
sudo mkdir -p /usr/local/share/ca-certificates/Yandex && \
sudo wget "https://storage.yandexcloud.net/cloud-certs/CA.pem" -O /usr/local/share/ca-certificates/Yandex/YandexInternalRootCA.crt
Если всё пройдет успешно — вы получите сообщение операционной системы о том, что сертификат сохранён.
Установите утилиту Mongo Shell:
sudo apt install mongodb-clients
Подключитесь к БД с помощью команды mongo. Чтобы получить строку подключения, на основной странице сервиса в консоли управления выберите кластер, на вкладке Обзор нажмите кнопку Подключиться.
Сервис сформирует пример строки подключения для кластера. Там же вы можете посмотреть примеры кода на Python, PHP, Java, Node.js, Go для подключения из приложений.
Подключитесь к кластеру из командной строки.
mongo --norc \
  --ssl \
  --sslCAFile /usr/local/share/ca-certificates/Yandex/YandexInternalRootCA.crt \
  --host '<FQDN хоста MongoDB>:27018' \
  -u <имя пользователя БД> \
  -p <пароль пользователя БД> \
  <имя БД>
Создадим в БД коллекцию users. Предположим, в ней содержится информация о пользователях вашего приложения.
db.createCollection("users")
Загрузим в коллекцию тестовые данные с помощью методов добавления одного документа db.insertOne(...) и сразу нескольких db.insertMany(...).
Сначала добавим один документ (данные одного пользователя).
db.users.insertOne({firstName: "Adam", lastName: "Smith", age: 37, email: "adam.smith@test.com"});
Дополним коллекцию данными еще двух пользователей.
db.users.insertMany( [
{firstName: "Viktoria", lastName: "Holmes", age: 73, email: "viktoria.holmes@test.com", phone: "737772727"},
{firstName: "Tina", lastName: "Anders", age: 29, email: "tina.anders@test.com", children: [{firstName: "Sam", lastName: "Anders"},{firstName: "Anna", lastName: "Anders"}]}
] );
Обратите внимание, что документы в коллекции users содержат разный набор данных. С помощью MongoDB мы можем работать с данными, структура которых частично не совпадает.
Теперь посмотрим на содержимое коллекции с помощью команды db.users.find(). Результат показывает, что все данные успешно добавлены:
Проверим, есть ли среди пользователей те, кому больше 37 лет. Сделаем запрос к БД с помощью метода find.
db.users.find({age: {$gt: 37}});
Decision:
$ sudo mkdir -p /usr/local/share/ca-certificates/Yandex && \
sudo wget "https://storage.yandexcloud.net/cloud-certs/CA.pem" -O /usr/local/share/ca-certificates/Yandex/YandexInternalRootCA.crt
$ wget https://downloads.mongodb.com/linux/mongodb-linux-x86_64-enterprise-ubuntu2004-6.0.2.tgz
$ tar -zxvf mongodb-linux-x86_64-enterprise-ubuntu2004-6.0.2.tgz
$ sudo ln -s /path/to/the/mongodb-directory/bin/* /usr/local/bin/
$ sudo apt install mongodb-clients
$ mongo --norc \
  --ssl \
  --sslCAFile /usr/local/share/ca-certificates/Yandex/YandexInternalRootCA.crt \
  --host 'rs01/rc1b-b7xwau9lvu3hdt0w.mdb.yandexcloud.net:27018' \
  -u YOUR-USERNAME \
  -p YOUR-PASSWORD \
  YOUR-DB
rs01:PRIMARY> db.createCollection("users")
rs01:PRIMARY> db.users.insertOne({firstName: "Adam", lastName: "Smith", age: 37, email: "adam.smith@test.com"});
rs01:PRIMARY> db.users.insertMany( [
{firstName: "Viktoria", lastName: "Holmes", age: 73, email: "viktoria.holmes@test.com", phone: "737772727"},
{firstName: "Tina", lastName: "Anders", age: 29, email: "tina.anders@test.com", children: [{firstName: "Sam", lastName: "Anders"},{firstName: "Anna", lastName: "Anders"}]}
] );
rs01:PRIMARY> db.users.find({age: {$gt: 37}});
Task:
Создание кластера ClickHouse и подключение к нему.
В этой практической работе вы создадите кластер ClickHouse. Вы уже знаете, как создавать кластеры и выставлять их основные настройки в сервисах платформы данных. Но у БД ClickHouse есть свои особенности.
Когда вы создадите кластер из двух или более хостов, сервис дополнительно создаст ещё один кластер из трёх хостов, где развернёт Apache ZooKeeper. Это служба для распределенных систем, которая управляет конфигурацией, репликацией и распределением запросов по хостам БД. Без неё кластер ClickHouse работать не будет. К ZooKeeper у пользователей доступа нет, однако его хосты учитываются при расчёте квоты ресурсов облака и стоимости сервиса.
ZooKeeper синхронизирует шарды (т. е. хосты) ClickHouse. В отличие от классических реляционных БД, у ClickHouse нет главного узла (мастера), через который добавляются данные. В ClickHouse данные можно и записывать, и читать с любого узла.
Decision:
Перейдите в каталог, где нужно создать кластер БД, выберите Managed Service for ClickHouse и нажмите кнопку Создать кластер.
Для практической работы нам понадобится кластер с минимальной конфигурацией: тип хоста burstable, класс b2.nano и стандартное сетевое хранилище размером 10 ГБ.
Задайте настройки: введите имена для кластера и БД, а также имя и пароль пользователя. Откройте публичный доступ к хосту.
Обратите внимание: в отличие от сервисов, которые мы уже рассматривали, здесь в разделе База данных можно включить опции управления пользователями и БД с помощью SQL-запросов.
Кроме того, в дополнительных настройках можно включить доступ к БД из консоли управления, сервисов DataLens, Яндекс Метрики и AppMetrica, а также возможность использовать бессерверные вычисления (подробно о них мы расскажем на курсе «Serverless»). С помощью DataLens, например, вы визуализируете результаты поисковых запросов в виде графиков, диаграмм и дашбордов, а подключение AppMetrica позволит импортировать данные из этого сервиса в кластер.
Отметьте пункт Доступ из DataLens: он понадобится вам на одном из следующих уроков. Нажмите кнопку Создать кластер.
К хостам кластера ClickHouse можно подключаться через интернет или с виртуальных машин в той же виртуальной сети. Если к хостам БД открыт публичный доступ, то для подключения к ним используется шифрованное соединение.
Подключайтесь к кластеру с помощью HTTP-протокола или более низкоуровневого Native TCP-протокола. В большинстве случаев рекомендуется взаимодействовать с ClickHouse не напрямую, а с помощью инструмента или библиотеки. Официально поддерживаются консольный клиент, драйверы JDBC и ODBC, клиентская библиотека для C++. Также можно использовать библиотеки сторонних разработчиков для Python, PHP, Go, Ruby и т. д.
Примеры строк подключения приводятся в документации и консоли управления на вкладке Обзор страницы кластера.
С БД удобно работать в приложении с графическим интерфейсом. Один из вариантов — универсальный клиент DBeaver. Другие варианты вы найдёте в полном списке клиентов.
Подробная информация о настройке подключения приведена в документации. Чтобы создать подключение к ClickHouse в DBeaver, помимо обычных параметров (адреса хоста, порта, имени БД, логина и пароля) задайте на вкладке Свойства драйвера настройки свойств драйвера JDBC. Укажите следующие параметры: ssl = true; sslmode = strict; sslrootcert = <путь к SSL-сертификату>. Как получить SSL-сертификат, вы уже узнали на предыдущих уроках.
При подключении DBeaver покажет номер версии ClickHouse и пинг до хоста.
В двух следующих практических работах мы используем кластер для аналитической работы с датасетами и для создания БД ClickHouse.
Decision:
$ wget https://dbeaver.io/files/dbeaver-ce_latest_amd64.deb
$ sudo dpkg -i dbeaver-ce_latest_amd64.deb
$ dbeaver-ce &
$ mkdir -p ~/.clickhouse-client
$ sudo wget "https://storage.yandexcloud.net/mdb/clickhouse-client.conf.example" -O ~/.clickhouse-client/config.xml
$ sudo apt-get install -y apt-transport-https ca-certificates dirmngr
$ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 8919F6BD2B48D754
$ echo "deb https://packages.clickhouse.com/deb stable main" | sudo tee \
/etc/apt/sources.list.d/clickhouse.list
$ sudo apt-get update
$ sudo apt-get install -y clickhouse-server clickhouse-client
$ clickhouse-client --host rc1a-mg8yquor7pspcwkc.mdb.yandexcloud.net \
     --secure \
     --user YOUR-USERNAME \
     --database YOUR-DB \
     --port 9440 \
     --ask-password
Task:
Работа с данными из объектного хранилища.
В интернете выложено множество датасетов — структурированных наборов данных, связанных общей темой. Например в репозитории проекта Our World in Data находится около тысячи разнообразных датасетов: от численности населения государств до сведений об употреблении алкоголя в США с 1850 года.
Датасеты часто выкладывают в виде CSV- или TSV-файлов. В них значения разделены запятой (comma separated values, CSV) или табуляцией (tab separated values, TSV).
Сохраняйте датасеты в объектное хранилище и анализируйте данные с помощью ClickHouse. При этом не требуется создавать БД и копировать в неё данные из датасета. Отправляйте запросы к ClickHouse — а ClickHouse сходит за данными напрямую в объектное хранилище.
Decision:
В качестве примера возьмем датасет с историей метеонаблюдений за 10 лет и попробуем развеять мифы о разнице погоды в Москве и Санкт-Петербурге. Датасет содержит примерно 50 тысяч записей, он выложен в объектном хранилище Yandex Cloud и доступен всем.
Воспользуемся кластером БД, который мы создали на предыдущем уроке. Откройте его в консоли управления. Запросы к датасету будем делать через SQL-консоль. На панели слева выберите вкладку SQL и введите пароль пользователя. В правом поле открывшейся консоли мы и станем вводить SQL-запросы.
Как вы думаете, где зарегистрирована самая низкая температура? Наверняка в Санкт-Петербурге! Давайте проверим.
Выполните запрос:
SELECT
City,
LocalDate,
TempC
FROM s3(
  'https://storage.yandexcloud.net/arhipov/weather_data.tsv',
  'TSV',
  'LocalDateTime DateTime, LocalDate Date, Month Int8, Day Int8, TempC Float32,Pressure Float32, RelHumidity Int32, WindSpeed10MinAvg Int32, VisibilityKm Float32, City String')
ORDER BY TempC ASC
LIMIT 1
Всё-таки наши интуитивные представления не всегда верны и могут опровергаться данными.
А что насчет самой высокой температуры, скорости ветра и влажности? Проверьте сами, изменив поля в запросе (средняя скорость ветра за 10 минут — WindSpeed10MinAvg, относительная влажность — RelHumidity; сортировка по возрастанию — ASC, по убыванию — DESC). Увеличив количество выводимых данных, вы получите более точное представление (измените параметр LIMIT c 1 до 10).
Но это были крайние значения. Давайте проверим, насколько в этих городах отличается климат в целом. Узнаем, например, разницу среднегодовых температур.
SELECT
Year,
msk.t - spb.t
FROM
(
SELECT
  toYear(LocalDate) AS Year,
  avg(TempC) AS t
FROM s3(
  'https://storage.yandexcloud.net/arhipov/weather_data.tsv',
  'TSV',
  'LocalDateTime DateTime, LocalDate Date, Month Int8, Day Int8, TempC Float32,Pressure Float32, RelHumidity Int32, WindSpeed10MinAvg Int32, VisibilityKm Float32, City String')
WHERE City = 'Moscow'
GROUP BY Year
ORDER BY Year ASC
) AS msk
INNER JOIN
(
SELECT
  toYear(LocalDate) AS Year,
  avg(TempC) AS t
FROM s3(
  'https://storage.yandexcloud.net/arhipov/weather_data.tsv',
  'TSV',
  'LocalDateTime DateTime, LocalDate Date, Month Int8, Day Int8, TempC Float32,Pressure Float32, RelHumidity Int32, WindSpeed10MinAvg Int32, VisibilityKm Float32, City String')
WHERE City = 'Saint-Petersburg'
GROUP BY Year
ORDER BY Year ASC
) AS spb ON msk.Year = spb.Year
Измените поля в запросе, чтобы проверить разницу относительной влажности.
Давайте теперь рассчитаем, где раньше начинается лето. Будем считать началом лета день, начиная с которого температура поднималась выше +15 °С хотя бы пять раз в течение 10-дневного периода (864 тысячи секунд).
SELECT
City,
toYear(LocalDate) AS year,
MIN(LocalDate)
FROM
(
SELECT
  City,
  LocalDate,
  windowFunnel(864000)(LocalDateTime, TempC >= 15, TempC >= 15, TempC >= 15, TempC >= 15, TempC >= 15) AS warmdays
FROM s3(
  'https://storage.yandexcloud.net/arhipov/weather_data.tsv',
  'TSV',
  'LocalDateTime DateTime, LocalDate Date, Month Int8, Day Int8, TempC Float32,Pressure Float32, RelHumidity Int32, WindSpeed10MinAvg Int32, VisibilityKm Float32, City String')
GROUP BY
  City,
  LocalDate
)
WHERE warmdays = 5
GROUP BY
year,
City
ORDER BY
year ASC,
City ASC
Task:
Добавление данных.
Предположим, вы работаете в метеорологической службе и постоянно изучаете датасеты с погодными данными.
Сбор данных о погоде автоматизирован: на территории области расположены несколько десятков пунктов наблюдения с датчиками.
Информация о температуре, давлении, влажности и скорости ветра раз в полчаса передаётся с датчиков на центральный сервер.
Приложение на сервере обрабатывает данные, переводит их в нужный формат и записывает в файл. Каждый файл содержит данные за три часа наблюдений.
Для прогноза нужно учитывать всю историю наблюдений за последние несколько лет, то есть все файлы потребуется собрать в одну БД.
Давайте потренируемся добавлять данные из файлов в БД ClickHouse.
На предыдущих уроках мы создали кластер, на котором развёрнута БД, и научились подключаться к нему.
Продолжим работать с этой БД, а в качестве добавляемого файла возьмем уже известный вам датасет с данными о погоде в Москве и Санкт-Петербурге.
Decision:
Сохраните файл на компьютере.
Прежде чем добавлять файл в БД, создадим в ней таблицу, куда будут вставляться данные. Перейдите в SQL-консоль кластера и выполните команду:
CREATE TABLE <имя вашей БД>.Weather
( LocalDateTime DateTime,
LocalDate Date,
Month Int8,
Day Int8,
TempC Float32,
Pressure Float32,
RelHumidity Int32,
WindSpeed10MinAvg Int32,
VisibilityKm Float32,
City String
) ENGINE=MergeTree
ORDER BY LocalDateTime;
В результате будет создана пустая таблица с полями и типами данных, соответствующими полям и типам данных в нашем файле (датасете).
Вставим данные в таблицу с помощью клиента командной строки clickhouse-client. Команды для его установки (для Ubuntu):
sudo apt update && sudo apt install --yes apt-transport-https ca-certificates dirmngr && \
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv E0C56BD4 && \
echo "deb https://repo.clickhouse.com/deb/stable/ main/" | sudo tee \
/etc/apt/sources.list.d/clickhouse.list
sudo apt update && sudo apt install --yes clickhouse-client
mkdir --parents ~/.clickhouse-client && \
wget "https://storage.yandexcloud.net/mdb/clickhouse-client.conf.example" \
--output-document ~/.clickhouse-client/config.xml
Подробности о том, как установить клиент и работать с ним, вы найдёте в документации ClickHouse.
Подключитесь к кластеру. Пример строки подключения посмотрите в консоли управления.
Добавим файл с данными в БД с помощью команды:
cat weather_data.tsv | clickhouse-client \
--host <адрес вашей БД> \
--secure \
--user user1 \
--database db1 \
--port 9440 \
-q "INSERT INTO db1.Weather FORMAT TabSeparated" \
--ask-password
Переключившись в SQL-консоль, вы увидите, что данные появились в таблице.
Данные в БД можно загружать и другими способами: из приложений или клиентов с графическим интерфейсом (например DBeaver). В этом случае подключение к БД и передача данных будут идти по HTTP-протоколу через порт 8443.
Теперь вы можете анализировать 10-летний срез данных о погоде в Москве и Санкт-Петербурге непосредственно в ClickHouse, без обращений к внешним источникам. Попробуйте, например, выяснить, какой день был самым ветреным в этих городах.
После практической работы остановите кластер, но не удаляйте его. Кластер ещё понадобится, когда мы будем рассматривать сервис визуализации и анализа данных Yandex DataLens.
Decision:
$ wget https://storage.yandexcloud.net/arhipov/weather_data.tsv
$ cat weather_data.tsv | clickhouse-client \
--host YOUR-IP \
--secure \
--user YOUR-USERNAME \
--database YOUR-DB \
--port 9440 \
-q "INSERT INTO YOUR-DB.Weather FORMAT TabSeparated" \
--ask-password
Task:
Создание базы данных.
В этой практической работе вы создадите БД YDB в dedicated режиме, научитесь подключаться к ней и добавлять данные из тестового приложения.
Также вы подключитесь к БД и запустите тестовое приложение, чтобы создать в ней несколько таблиц с данными о популярных сериалах.
Decision:
На стартовой странице консоли управления перейдите в каталог, в котором будете создавать БД, выберите в списке сервисов База данных YDB и нажмите кнопку Создать ресурс.
В открывшемся окне выберите тип БД dedicated. Появившийся интерфейс создания новой БД практически идентичен уже знакомым вам интерфейсам создания кластеров управляемых БД.
Выберите для вашей БД имя, назначьте необходимые вычислительные ресурсы (для этой и следующих практических работ достаточно одного хоста конфигурации medium), тип и количество групп хранения (достаточно одной группы).
Группа хранения – это массив независимых дисковых накопителей, объединённых по сети в единый логический элемент. В YDB такой массив состоит из 9 дисков, расположенных по три в каждой из трёх зон доступности. Такая конфигурация обеспечивает устойчивость при одновременном отказе одной из зон и отказе диска в другой зоне. Стандартный размер группы хранения — 100 ГБ.
Выберите облачную сеть и подсети для работы с БД. Вы можете оставить сеть по умолчанию или выбрать ту, которую создали на предыдущем курсе. БД будет доступна для всех виртуальных машин, которые подключены к той же облачной сети.
Также выберите опцию присвоения публичного IP-адреса, чтобы иметь возможность подключаться к БД из интернета.Нажмите кнопку Создать базу данных. Создание БД занимает несколько минут. Когда статус БД изменится с Provisioning на Running, она готова к работе. Кликнув на созданную БД в консоли управления, вы перейдёте на вкладку Обзор.
В разделе Соединение на этой странице приведена информация, которая вам понадобится для подключения к БД:
- Эндпоинт — точка подключения с указанием протокола, представляющая собой в данном случае адрес, на который посылаются сообщения;
- Размещение базы данных — полный путь к БД.
- Примеры подключений из командной строки и приложений вы можете посмотреть, нажав на кнопку Подключиться.
Подключение к базе данных и запуск тестового приложения.
Для того, чтобы выполнить эту задачу, вам понадобится сервисный аккаунт с ролями viewer и editor. Перейдите в дашборд каталога и выберите вкладку Сервисные аккаунты. Создайте сервисный аккаунт, назначив для него указанные роли. Сохраните идентификатор этого аккаунта.
Вы можете запускать тестовое приложение со своего компьютера или с виртуальной машины в Yandex Cloud. В данном примере используется OC Ubuntu и приложение на Python.
Если при создании БД вы не присвоили ей публичный IP-адрес, то подключиться к ней вы сможете только с виртуальной машины, расположенной в той же облачной сети.
Для запуска приложения нужно склонировать на свою машину репозиторий YDB Python SDK, из которого оно будет вызываться, а также установить библиотеки ydb, iso8601 и yandexcloud. Воспользуйтесь для этого следующими командами:
git clone https://github.com/yandex-cloud/ydb-python-sdk.git
sudo pip3 install iso8601 ydb yandexcloud
Создайте авторизованный ключ для вашего сервисного аккаунта и сохраните его в файл с помощью интерфейса командной строки Yandex Cloud.
mkdir ~/.ydb
yc iam key create \
--folder-id <идентификатор каталога> \
--service-account-name <имя сервисного аккаунта> \
--output ~/.ydb/sa_name.json
Получите SSL-сертификат:
wget "https://storage.yandexcloud.net/cloud-certs/CA.pem" \
-O ~/.ydb/CA.pem
Установите переменную окружения YDB_SERVICE_ACCOUNT_KEY_FILE_CREDENTIALS и переменную окружения с SSL-сертификатом.
export YDB_SERVICE_ACCOUNT_KEY_FILE_CREDENTIALS=~/.ydb/sa_name.json
export YDB_SSL_ROOT_CERTIFICATES_FILE=~/.ydb/CA.pem
Запустите тестовое приложение basic_example_v1 из репозитория ydb-python-sdk, указав в качестве параметров подключения значения протокола, эндпоинта и полного пути к БД.
cd ./ydb-python-sdk/examples/basic_example_v1
python3 __main__.py \
-e <Эндпоинт> \
-d <Размещение базы данных>
Результат выполнения приложения должен выглядеть так:
> describe table: series
column, name: series_id , Uint64
column, name: title , Utf8
column, name: series_info , Utf8
column, name: release_date , Uint64
> select_simple_transaction:
series, id: 1 , title: IT Crowd , release date: b'2006-02-03'
> bulk upsert: episodes
> select_prepared_transaction:
episode title: To Build a Better Beta , air date: b'2016-06-05'
> select_prepared_transaction:
episode title: Bachman's Earnings Over-Ride , air date: b'2016-06-12'
> explicit TCL call
> select_prepared_transaction:
episode title: TBD , air date: b'2022-08-24'
Вернитесь в консоль управления Yandex Cloud, чтобы посмотреть на результаты работы приложения. Переключитесь на вкладку Навигация.
В вашей БД созданы три таблицы: episodes, seasons и series с информацией о двух популярных сериалах IT Crowd и Silicon Valley. Кликнув по названию таблицы, вы увидите содержащиеся в ней данные. А если подвести к названию таблицы курсор и кликнуть на значок «информация» справа, то внизу появится дополнительное окно с вкладками Обзор, Схема и Партиции.
Кнопка Создать на панели Навигация служит для создания директорий и таблиц. С её помощью можно создать новую таблицу, не прибегая к командам YQL.
Decision:
$ git clone https://github.com/yandex-cloud/ydb-python-sdk.git
$ mkdir ~/.ydb
$ yc iam key create \
--service-account-name sa-ydb \
--output ~/.ydb/authorized_key.json
$ export YDB_SERVICE_ACCOUNT_KEY_FILE_CREDENTIALS=~/.ydb/authorized_key.json
$ cd ydb-python-sdk/examples/basic_example_v1
$ python3 __main__.py \
-e <Эндпоинт> \
-d <Размещение базы данных>
Task:
YQL и работа с данными
В этом уроке вы освоите базовый набор операций для работы с данными с использованием YQL и консоли управления Yandex.Cloud.
Decision:
Чтобы начать, войдите в раздел Навигация консоли управления и откройте редактор SQL, нажав на кнопку SQL-запрос.
На прошлом уроке мы уже создали в нашей БД три таблицы, содержащие информацию о сериалах IT Crowd и Silicon Valley.
Добавим в БД еще одну таблицу с рейтингами эпизодов сериала IT Crowd на IMDb.com.
YQL является диалектом SQL, поэтому многие инструкции в этих языках идентичны.
Для создания таблицы вам понадобится сделать запрос к БД, содержащий инструкцию CREATE TABLE. Например, если бы мы хотели создать таблицу seasons (она уже есть в вашей БД), то SQL запрос выглядел бы следующим образом:
CREATE TABLE seasons
(
series_id Uint64,
season_id Uint64,
first_aired Date,
last_aired Date,
title Utf8,
  PRIMARY KEY (series_id, season_id)
);
Обратите внимание, что в пределах директории YDB имена таблиц должны быть уникальны. Первичный ключ (PRIMARY KEY) — это столбец или комбинация столбцов, однозначно идентифицирующих каждую строку в таблице. Он может содержать только неповторяющиеся значения. Для таблицы YDB указание первичного ключа обязательно, при этом он может быть только один.
Первичный ключ по сути является первичным индексом, который помогает СУБД быстрее обнаруживать отдельные записи в таблице и сокращает время выполнения запросов. Также в таблицу можно добавить один или несколько вторичных индексов. Они служат той же цели, но в отличие от первичного индекса могут содержать повторяющиеся значения. Добавить вторичные индексы можно в любой момент, когда возникнет необходимость, и это не вызовет деградацию производительности БД. Чтобы при создании таблицы добавить в нее вторичный индекс, используется такая конструкция:
INDEX <имя индекса> GLOBAL ON (<имя столбца1>, <имя столбца2>, ...)
Вторичный индекс можно добавить и в уже существующую таблицу. Работа БД при этом не прерывается. В отличие от предыдущего случая в существующую таблицу можно добавлять только один вторичный индекс за раз. Делается это с помощью следующей команды:
ALTER TABLE <имя таблицы> ADD INDEX <имя индекса> GLOBAL ON (<имя столбца>);
Task:
создайте таблицу ratings, в которой будут содержаться рейтинги всех эпизодов сериала IT Crowd, со столбцами season_id (Uint64), episodes_id (Uint64), title (Utf8), air_date (Date) и imdb_rating (Uint64) и вторичным индексом rating_index по полю imdb_rating.
Decision:
CREATE TABLE ratings (
season_id Uint64,
episodes_id Uint64,
title Utf8,
air_date Date,
imdb_rating Uint64,
  PRIMARY KEY (season_id, episodes_id),
  INDEX rating_index GLOBAL ON (imdb_rating)
);
Decision:
Добавим в эту таблицу данные. Для вставки данных в YDB помимо обычной SQL инструкции INSERT также используются инструкции REPLACE и UPSERT.
При выполнении INSERT перед операцией записи выполняется операция чтения данных. Это позволяет убедиться, что уникальность первичного ключа будет соблюдена. При выполнении инструкций REPLACE и UPSERT осуществляется слепая запись.
Инструкции REPLACE и UPSERT используются для добавления новой или изменения существующей строки по заданному значению первичного ключа. При операциях записи и изменения данных использование этих инструкций эффективнее.
Если при выполнении этих инструкций строка с указанным значением первичного ключа не существует, то она будет создана. Если же такая строка существует, то значения ее столбцов будут заменены на новые. Отличие между REPLACE и UPSERT заключается в том, что первая из этих инструкций устанавливает значения столбцов, не участвующих в операции, в значения по умолчанию, а вторая такие значения не меняет.
Одним запросом REPLACE, UPSERT или INSERT можно вставить в таблицу несколько строк.
Например, если бы мы хотели добавить в таблицу series те данные, которые в ней сейчас содержатся, то SQL запрос выглядел бы так:
REPLACE INTO series (series_id, title, release_date, series_info)
VALUES
(
  1,
  "IT Crowd",
  Date("2006-02-03"),
  "The IT Crowd is a British sitcom produced by Channel 4, written by Graham Linehan, produced by Ash Atalla and starring Chris O'Dowd, Richard Ayoade, Katherine Parkinson, and Matt Berry."),
(
  2,
  "Silicon Valley",
  Date("2014-04-06"),
  "Silicon Valley is an American comedy television series created by Mike Judge, John Altschuler and Dave Krinsky. The series focuses on five young men who founded a startup company in Silicon Valley."
);
Task:
добавьте в таблицу ratings данные из этого файла.
Decision:
REPLACE INTO ratings (season_id, episodes_id, title, air_date, imdb_rating) VALUES
(1, 1, "Yesterday's Jam", Date("2006-02-03"), 76),
(1, 2, "Calamity Jen", Date("2006-02-03"), 82),
(1, 3, "Fifty-Fifty", Date("2006-02-10"), 79),
(1, 4, "The Red Door", Date("2006-02-17"), 80),
(1, 5, "The Haunting of Bill Crouse", Date("2006-02-24"), 85),
(1, 6, "Aunt Irma Visits", Date("2006-03-03"), 81),
(2, 1, "The Work Outing", Date("2006-08-24"), 95),
(2, 2, "Return of the Golden Child", Date("2007-08-31"), 82),
(2, 3, "Moss and the German", Date("2007-09-07"), 82),
(2, 4, "The Dinner Party", Date("2007-09-14"), 87),
(2, 5, "Smoke and Mirrors", Date("2007-09-21"), 78),
(2, 6, "Men Without Women", Date("2007-09-28"), 76),
(3, 1, "From Hell", Date("2008-11-21"), 78),
(3, 2, "Are We Not Men?", Date("2008-11-28"), 85),
(3, 3, "Tramps Like Us", Date("2008-12-05"), 82),
(3, 4, "The Speech", Date("2008-12-12"), 90),
(3, 5, "Friendface", Date("2008-12-19"), 85),
(3, 6, "Calendar Geeks", Date("2008-12-26"), 78),
(4, 1, "Jen The Fredo", Date("2010-06-25"), 80),
(4, 2, "The Final Countdown", Date("2010-07-02"), 84),
(4, 3, "Something Happened", Date("2010-07-09"), 75),
(4, 4, "Italian For Beginners", Date("2010-07-16"), 82),
(4, 5, "Bad Boys", Date("2010-07-23"), 84),
(4, 6, "Reynholm vs Reynholm", Date("2010-07-30"), 76);
Decision:
C помощью SQL запросов можно добавлять и удалять не только строки таблицы, но и столбцы. Для этого используется команда ALTER TABLE и фразы ADD COLUMN и DROP COLUMN.
Например, если вы хотите добавить в таблицу ratings столбец viewed с данными о том, какие эпизоды сериала вы уже посмотрели, то это можно сделать с помощью следующей команды.
ALTER TABLE ratings ADD COLUMN viewed Bool;
Task:
Вы решили, что столбец с датой выхода эпизодов в таблице ratings не нужен, поскольку эта информация уже содержится в другой таблице. Удалите столбец air_date из таблицы ratings.
Decision:
ALTER TABLE ratings DROP COLUMN air_date;
Decision:
Теперь потренируемся извлекать данные из БД. Для этого используется команда SELECT. В простейшем случае ее синтаксис выглядит так:
SELECT <имя столбца1>, <имя столбца2>, ...
FROM <имя таблицы>;
Например, чтобы выбрать всю информацию из таблицы seasons, нужно сделать следующий запрос к БД.
SELECT * FROM seasons;
Если нужно выбрать из таблицы только те строки, которые удовлетворяют определенному условию, в запросе используют секцию WHERE. В этой секции должно находиться выражение, возвращающее логический результат. Обычно оно состоит из логических операций and, or, not и операций сравнения.
Например, выбрать из таблицы episodes только первые эпизоды всех сезонов можно так:
SELECT * FROM episodes
WHERE episode_id = 1;
Запрос SELECT извлекает строки без определенного порядка. Чтобы отсортировать полученные данные нужным образом, в этот запрос включают секцию ORDER BY. В ней указывается список столбцов, которые будут определять порядок сортировки результатов запроса.
Task:
получите список самых популярных (с рейтингом не менее 85) эпизодов сериала IT Crowd. При поиске используйте созданный ранее вторичный индекс rating_index. Чтобы упорядочить результаты по убыванию рейтинга используйте конструкцию ORDER BY … DESC.
Decision:
SELECT
season_id,
episodes_id,
title,
imdb_rating
FROM ratings VIEW rating_index
WHERE
imdb_rating >= 85
ORDER BY
imdb_rating DESC;
Decision:
Для получения обобщённых сведений о содержащихся в таблице данных — например, о числе строк в таблице или среднем значении какого-либо выражения — в запрос SELECT включают агрегатные функции и секцию GROUP BY. Эта секция используется для агрегации внутри каждого ключа. Ключом является значение одной или более колонок, указанных в GROUP BY.
Примеры агрегатных функций:
COUNT(*) — вычисляет число строк в таблице.
MAX(expr) — находит максимум выражения expr по всем строкам.
SUM(expr) — суммирует выражение expr по всем строкам. Тип выражения должен быть числовым.
AVG(expr) — находит среднее значение выражения expr по всем строкам. Тип выражения должен быть числовым или интервалом.
SOME(expr) — возвращает одно произвольное значение выражения по всем строкам.
Результаты выполнения агрегатной функции выводятся в отдельном столбце. Чтобы задать этому столбцу имя, используют оператор AS. Конструкция может выглядеть, например, так:
SELECT
<имя столбца1>,
MAX(<имя столбца2>) AS max_value
...;
Task:
Напишите SQL запрос к таблице episodes, который выводит данные о числе эпизодов каждого сериала.
Вам понадобится вычислить число строк для каждого значения столбца series_id и сгруппировать результаты по series_id.
Decision:
SELECT
series_id,
COUNT(*) AS total_episodes
FROM episodes
GROUP BY
series_id
ORDER BY
series_id;
Task:
Напишите SQL запрос, с помощью которого можно сравнить популярность сезонов сериала IT Crowd.
Вам понадобится вычислить средний рейтинг эпизодов для каждого сезона и сгруппировать результаты по столбцу season_id.
Decision:
SELECT
season_id,
AVG (imdb_rating) AS avg_rating
FROM ratings
GROUP BY season_id
ORDER BY avg_rating DESC;
Decision:
В реляционной БД таблицы логически связаны друг с другом. С помощью объединений (JOIN) можно получить данные из нескольких связанных друг с другом таблиц и представить их в виде одной результирующей таблицы.
Столбцы, по которым выполняется объединение, можно указать одним из двух способов.
- После ключевого слова USING, например table1 AS a JOIN table2 AS b USING (foo). Это более короткий способ записи, удобный для простых случаев. Имена столбцов, по которым происходит объединение таблиц, должны быть одинаковы.
- После ключевого слова ON (например, a JOIN b ON a.foo = b.bar). Этот способ позволяет использовать разные имена столбцов и указывать дополнительные условия по аналогии с WHERE.
Поскольку такие запросы затрагивают столбцы разных таблиц, имена столбцов должны содержать и имя таблицы (то есть, например, не просто series_id, а seasons.series_id).
В YDB доступны следующие логические типы объединений:
INNER (используется по умолчанию) — строки попадают в результат, только если значение ключевых колонок присутствует в обеих таблицах;
FULL, LEFT и RIGHT — при отсутствии значения в обеих или в одной из таблиц включает строку в результат, но оставляет пустыми (NULL) колонки, соответствующие противоположной таблице.
LEFT/RIGHT SEMI — одна сторона выступает как белый список (whitelist) ключей, её значения недоступны. В результат включаются столбцы только из одной таблицы, декартового произведения не возникает;
LEFT/RIGHT ONLY — вычитание множеств по ключам (blacklist). Практически эквивалентно добавлению условия IS NULL на ключ противоположной стороны в обычном LEFT/RIGHT, но, как и в SEMI, нет доступа к значениям;
CROSS — декартово произведение двух таблиц целиком без указания ключевых колонок, секция с ON/USING явно не пишется;
EXCLUSION — обе стороны минус пересечение.
Простой пример запроса с объединением таблиц приведен ниже.
SELECT
sa.title AS season_title,
sr.title AS series_title,
sr.series_id, sa.season_id
FROM seasons AS sa
INNER JOIN series AS sr ON sa.series_id = sr.series_id
WHERE sa.season_id = 1
ORDER BY sr.series_id;
Этот запрос извлекает из таблиц series и seasons сведения о первых сезонах всех сериалов и выводит объединённые данные в результирующей таблице.
Task:
напишите запрос, который выводит таблицу, содержащую название сериала IT Crowd и названия всех его эпизодов (то есть, каждая строка итоговой таблице должна содержать название сериала и название отдельного эпизода).
Decision:
SELECT
sr.title AS series_title,
ep.title AS episode_title,
ep.season_id, 
ep.episode_id
FROM
series AS sr
INNER JOIN
episodes AS ep
ON sr.series_id = ep.series_id
WHERE sr.series_id = 1
ORDER BY
ep.season_id, 
ep.episode_id;
Task:
Создание кластера Hadoop.
На этом уроке вы создадите и настроите кластер Hadoop с помощью сервиса Yandex Data Proc.
Hadoop предназначается для работы с большими данными, поэтому создание кластера потребует от вас больше усилий, чем на предыдущих практических работах (но гораздо меньше, чем если бы вы делали это самостоятельно).
Decision:
Для хранения зависимостей заданий нашего кластера и результатов их выполнения нужно предварительно создать бакет в объектном хранилище. О том, как это сделать, мы рассказывали на одном из предыдущих занятий.
Также создайте сервисный аккаунт для доступа к кластеру. Обратите внимание: можно использовать только аккаунт с ролью mdb.dataproc.agent. Для автоматического масштабирования кластера сервисному аккаунту также понадобятся роли editor и dataproc.agent.
Откройте каталог, где будете создавать кластер, и выберите сервис Data Proc.
В открывшемся окне нажмите кнопку Создать кластер.
Задайте для кластера имя и выберите версию образа — 1.4. В образ включена одна из версий Hadoop и дополнительные компоненты. Некоторые вы можете устанавливать по выбору. Кроме того, в каждую версию образа входит Conda (менеджер окружений для Python) и набор инструментов машинного обучения (scikit-learn, TensorFlow, CatBoost, LightGBM и XGBoost).
Обратите внимание на то, что некоторые из сервисов обязательны, чтобы использовать другие. На следующем уроке нам понадобится сервис HIVE. Выберите его, и рядом с MAPREDUCE и YARN вы увидите напоминания о том, что они нужны для HIVE.
Вставьте в поле публичный ключ публичную часть SSH-ключа. Как сгенерировать и использовать SSH-ключи, мы рассказывали в одной из практических работ о виртуальных машинах.
Выберите созданный сервисный аккаунт для доступа к кластеру.
Выберите зону доступности для кластера. Все подкластеры будут находиться в этой
Если нужно, задайте свойства Hadoop и его компонентов. Доступные свойства перечислены в документации.
Выберите бакет в объектном хранилище, где будут храниться зависимости заданий и результаты их выполнения.
Выберите или создайте сеть для кластера. Включите опцию NAT в интернет для подсетей, в которых размещается кластер.
Если нужно, создайте группу безопасности. Правила для неё вы добавите позже в сервисе Virtual Private Cloud.
Включите опцию UI Proxy, чтобы получить доступ к веб-интерфейсам компонентов Data Proc. У некоторых компонентов (например Hadoop, Spark, YARN и Zeppelin) есть пользовательские веб-интерфейсы, доступные на мастер-узле кластера. С помощью этих интерфейсов вы можете:
- отслеживать ресурсы кластера и управлять ими (YARN Resource Manager, HDFS NameNode);
- просматривать статус и отлаживать задания (Spark History, JobHistory);
- проводить эксперименты, совместно работать или выполнять отдельные операции (Zeppelin).
Настройка подкластеров. В состав кластера входит один главный подкластер (Мастер) с управляющим хостом, а также подкластеры для хранения данных (Data) или вычислений (Compute).
В подкластерах Data можно разворачивать компоненты для хранения данных, а в подкластерах Compute — для обработки данных. Хранилище в подкластере Compute предназначено только для временного хранения обрабатываемых файлов.
Для каждого подкластера можно задать число и класс хостов, размер и тип хранилища, а также подсеть той сети, в которой расположен кластер. Кроме того, для подкластеров Compute можно настроить автоматическое масштабирование. Это позволит выполнять задания на обработку данных быстрее без дополнительных усилий с вашей стороны.
Создадим подкластер Compute с одним хостом.
В блоке Добавить подкластер нажмите кнопку Добавить.
В поле Роли выберите COMPUTENODE. В блоке Масштабирование включите опцию Автоматическое масштабирование.
Все открывшиеся настройки знакомы вам из практических работ по созданию виртуальных машин.
Автоматическое масштабирование подкластеров обработки данных поддерживается в кластерах Yandex Data Proc версии 1.2 и выше. Чтобы оно работало, в кластере с установленным Spark или Hive должен быть также установлен сервис YARN.
Yandex Data Proc автоматически масштабирует кластер, используя для этого системные метрики нагрузки на кластер. Когда их значение выходит из установленного диапазона, запускается масштабирование. Если значение метрики превысит порог, в подкластер добавятся хосты. Если опустится ниже порога, начнётся декомиссия (высвобождение ненужных ресурсов), а избыточные хосты удалятся.
По умолчанию для масштабирования используется внутренняя метрика YARN (yarn.cluster.containersPending). Она показывает, сколько единиц ресурсов нужно заданиям в очереди. Выбирайте эту опцию Масштабирование по умолчанию, если в кластере выполняется много относительно небольших заданий.
Другой вариант — масштабирование на основе метрики загрузки процессора (vCPU). Чтобы использовать его, отключите опцию Масштабирование по умолчанию и укажите целевой уровень загрузки vCPU.
Настроив подкластеры, нажмите кнопку Создать кластер.
Сервис запустит создание кластера. После того как статус кластера изменится на Running, вы сможете подключиться к любому активному подкластеру с помощью указанного в настройках SSH-ключа.
Task:
Подключение к кластеру и работа с Hive.
На этом уроке вы научитесь подключаться к кластеру Hadoop и работать с ним на примере выполнения запросов с помощью Hive.
Decision:
Подключимся к управляющему хосту главного подкластера. Поскольку хостам кластера Hadoop не назначается публичный IP-адрес, для подключения к ним нужна виртуальная машина, расположенная в той же сети Yandex Cloud.
Выберите машину, которую создавали раньше, или создайте новую. Подключитесь к ней по SSH. Вы уже делали это, когда изучали виртуальные машины.
Подключитесь с этой машины к хосту главного подкластера также с помощью SSH. Для этого на машине должна быть закрытая часть SSH-ключа, открытую часть которого вы указали при создании кластера Data Proc. Вы можете скопировать ключ на виртуальную машину или подключаться к ней с запущенным SSH-агентом.
Скопировать ключ можно с помощью утилиты nano. На виртуальной машине выполните команду:
sudo nano ~/.ssh/<имя ключа>
В открывшийся редактор скопируйте содержимое закрытой части SSH-ключа с вашей локальной машины.
Запустите SSH-агент:
eval `ssh-agent -s`
Добавьте ключ в список доступных агенту:
ssh-add ~/.ssh/<имя ключа>
Узнайте внутренний FQDN хоста главного подкластера. Для этого в консоли управления на странице кластера перейдите на вкладку Хосты и выберите хост с ролью MASTERNODE.
Откройте SSH-соединение с хостом Data Proc для пользователя root, например:
ssh root@<FQDN хоста>
Пошаговые инструкции по различным способам подключения к кластеру Data Proc приведены в документации.
Проверим, что команды Hadoop выполняются, например:
hadoop version
Результат выполнения этой команды выглядит так:
Запуск заданий Apache Hive
Как мы уже говорили ранее, Hive — это платформа для хранения данных и управления ими в экосистеме Hadoop. Она используется для доступа к большим датасетам, сохранённым в распределённом хранилище.
Hive позволяет работать с данными различного формата (csv, tsv, Parquet, ORC, Avro и другими), подключаться к БД и взаимодействовать с ней с помощью SQL-подобного языка запросов. Hive используется преимущественно для работы с данными в HDFS, HBase, S3-совместимых хранилищах и реляционных СУБД.
Запрос на действия с данными в Hive называется заданием. Задания можно запускать на управляющем хосте с помощью командной оболочки CLI Hive, а также с помощью CLI Yandex Cloud.
Для запуска Hive CLI выполните команду hive на управляющем хосте.
Проверьте, всё ли работает: выполните, например, команду select 1; — корректный результат выглядит так:
Теперь создайте внешнюю таблицу (external table) в формате Parquet, содержащую открытые данные о списке перелётов между городами США в 2018 году. Для этого с помощью Hive CLI выполните запрос:
hive> CREATE EXTERNAL TABLE flights (Year bigint, Month bigint, FlightDate string, Flight_Number_Reporting_Airline bigint, OriginAirportID bigint, DestAirportID bigint) STORED AS PARQUET LOCATION 's3a://yc-mdb-examples/dataproc/example01/set01';
Проверим список таблиц, выполнив команду show tables. Результат должен выглядеть так:
Запросим число перелётов с разбивкой по месяцам:
hive> SELECT Month, COUNT(*) FROM flights GROUP BY Month;
Пример результата такого запроса:
Безусловно, на одном примере сложно показать возможности сервиса Data Proc. Если вас интересует работа с большими данными в облаке, посмотрите доклады сотрудников Yandex Cloud об управлении кластерами Hadoop и заданиями в Data Proc на YouTube-канале Yandex Cloud.
Decision:
$ cat YOUR-KEY
$ eval `ssh-agent -s`
$ ssh-add YOUR-KEY
$ ssh root@<FQDN хоста>
$ hadoop version
$ hive
hive> select 1;
hive> CREATE EXTERNAL TABLE flights (Year bigint, Month bigint, FlightDate string, Flight_Number_Reporting_Airline bigint, OriginAirportID bigint, DestAirportID bigint) STORED AS PARQUET LOCATION 's3a://yc-mdb-examples/dataproc/example01/set01';
hive> show tables;
hive> SELECT Month, COUNT(*) FROM flights GROUP BY Month;
Task:
Создание датасетов, чартов и дашбордов.
На этом уроке вы научитесь создавать чарты и дашборды. Мы пройдём по всей цепочке сущностей DataLens начиная с источника данных.
Изучая ClickHouse, мы анализировали данные о погоде с помощью SQL-запросов.
Давайте посмотрим на примере того же самого набора данных, как с помощью DataLens быстро и наглядно показать отличия климата в Москве и Санкт-Петербурге.
Decision:
Источник данных.ClickHouse и DataLens интегрированы друг с другом, поэтому подключение DataLens к ClickHouse можно настроить всего за пару кликов.
В консоли управления запустите кластер ClickHouse, в котором развёрнута БД с таблицей Weather, созданной вами ранее. Перейдите на страницу кластера, на панели слева выберите DataLens.
Подключение. Нажмите кнопку Создать подключение. В открывшемся диалоговом окне вы увидите, что кластер ClickHouse, из которого мы возьмём данные для анализа, имя хоста и имя пользователя БД уже указаны.
Вам осталось только дать имя подключению в пустом поле вверху, ввести пароль к БД, нажать кнопку Проверить подключение и убедиться, что всё в порядке, а потом — кнопку Создать.
Датасет. После того как подключение будет создано, DataLens выведет на панели слева таблицы из БД и предложит создать датасет. Наш датасет будет состоять из одной таблицы: db1.Weather. Перетащите её на центральную панель, и внизу откроется предпросмотр данных.
Нажмите кнопку Сохранить и задайте имя датасета.
Подготовим данные. Это важная часть аналитической работы, и её не стоит пропускать. Прежде всего укажем имена полей на русском языке. Перейдите на вкладку Поля и переименуйте их:
- LocalDateTime - Дата и время
- LocalDate - Дата
- Month - Месяц
- Day - День
- TempC - Температура
- Pressure - Давление
- RelHumidity - Влажность
- Тип WindSpeed10MinAvg - Скорость ветра
- VisibilityKm - Видимость
- City - Город
Поля Дата и время, Дата, Месяц, День, Город будут полями-измерениями, а Температура, Давление, Влажность, Скорость ветра, Видимость — полями-показателями. Зададим для показателей тип агрегации Среднее.
Чарты. Приступим к созданию первого чарта. Нажмите кнопку Создать чарт. Выберите тип чарта Линейная диаграмма и перетащите Дата в раздел X , а Температура — в раздел Y.
На этом примере видно, что средства визуализации иногда помогают быстро проверить качество датасета: есть ли в нём пропущенные или странные, выбивающиеся из общей тенденции данные.
В нашем случае можно сделать вывод о том, что в датасете не хватает данных примерно с середины 2015-го по середину 2016-го.
Разделим показатели температуры для двух городов. Для этого перетащим Город в раздел Цвета. Кроме того, округлим значения поля Дата до месяцев, чтобы лучше увидеть, как различаются данные для Москвы и Санкт-Петербурга. Для этого слева от поля Дата нажмите зелёный значок календаря и в разделе Группировка выберите округление по месяцам.
Из этого графика уже можно делать выводы. В целом температура в Москве выше, чем в Санкт-Петербурге. Летом примерно на 5 градусов, зимой — на 1−2 градуса.
Сохраните чарт, чтобы затем использовать его для дашборда.
Чтобы окончательно разобраться с температурой, построим ещё один чарт — Столбчатую диаграмму — и сравним среднегодовую температуру. Выберите тип диаграммы. Добавьте поле Город в раздел X, чтобы разделить отображение значений температуры. Также для поля Дата выберите группировку по годам.
Кроме того, для чарта понадобится задать фильтр по датам. Поскольку мы сравниваем среднегодовые значения, неполные данные за 2009 и 2019 годы отбросим. В разделе Фильтры нажмите + и выберите поле Дата.
Для этого чарта мы возьмём только данные из диапазона с начала 2010-го по конец 2018-го. Нажмите кнопку Применить фильтр и сохраните чарт.
Сделайте сами два таких же чарта с данными о скорости ветра: линейную диаграмму со среднемесячными значениями скорости ветра в городах и столбчатую диаграмму со среднегодовыми значениями.
Теперь у нас достаточно чартов для информативного дашборда.
Дашборд. На панели слева выберите Дашборды и нажмите кнопку Создать дашборд. Введите название дашборда и нажмите Создать.
Если в каталоге это первый дашборд — он откроется сразу после создания. Если в каталоге есть другие дашборды, вы увидите список. В этом случае выберите из списка только что созданный дашборд.
Теперь добавим созданные нами чарты на дашборд. Нажмите Добавить и в выпадающем списке выберите Чарт. Поочерёдно выбирайте из списка и добавляйте чарты.
В результате на дашборде появятся четыре виджета с чартами. Меняйте размеры и положение виджетов для лучшей визуализации.
Осталось лишь несколько последних штрихов. В том же пункте меню Добавить создадим пару заголовков и селектор по датам. В правом верхнем углу каждого виджета нажмите значок шестерёнки, чтобы изменить названия. Сохраним дашборд.
То, какие чарты сделать и как их разместить на дашборде, бывает понятно не сразу. Рассмотрите несколько вариантов, когда строите дашборд, чтобы разобраться, какая именно визуализация лучше помогает ответить на вопросы.
В маркетплейсе DataLens вы найдёте ещё один дашборд с погодой. Он хорошо демонстрирует возможности визуализации данных этого сервиса.
Чтобы открыть публичный доступ к дашборду, справа от его названия нажмите ··· и выберите Публичный доступ. Скопируйте ссылку. По ней дашборд будет доступен всем, с любых устройств и без аутентификации.
Task:
Права доступа и роли для сервисного аккаунта.
В этом уроке вы научитесь работать с сервисными аккаунтами и назначать для них роли и права доступа к объектам.
В качестве объекта будет выступать созданный в сервисе KMS ключ шифрования.
Предположим, что перед вами стоит задача использовать сервисный аккаунт для ротации ключей.
Чтобы решить эту задачу, понадобится выполнить следующие шаги:
- Создать сервисный аккаунт.
- Получить права на управление этим сервисным аккаунтом.
- Создать статические ключи доступа и привязать их к сервисному аккаунту, чтобы он мог пройти авторизацию в сервисе KMS.
- Создать в сервисе KMS ключ шифрования и назначить сервисному аккаунту роль kms.admin для управления этим ключом.
- И, наконец, ротировать ключ, то есть создать его новую версию с такими же параметрами, из-под сервисного аккаунта.
- Нужно заметить, что через консоль управления сервисному аккаунту можно назначить роль только на каталог, в котором он был создан. Роли на все остальные ресурсы назначаются с помощью CLI или API. Поэтому для выполнения этой практической работы вам понадобится вспомнить, как пользоваться утилитой yc, чему вы уже научились в курсе «DevOps и автоматизация».
Decision:
ШАГ 1
Для начала создадим сервисный аккаунт. В консоли управления войдите в каталог облака, в котором вы будете выполнять эту практическую работу, и перейдите на вкладку Сервисные аккаунты. Нажмите кнопку Создать сервисный аккаунт.
В открывшемся окне задайте для нового сервисного аккаунта имя и, при желании, добавьте описание. Здесь аккаунту также можно добавить роли на каталог, в котором он создаётся.
Оставьте поле с ролями пустым и нажмите Создать.
ШАГ 2
Настройте для вашего аккаунта на Яндексе доступ на авторизацию под созданным сервисным аккаунтом.
Для начала убедитесь, что вы авторизованы в аккаунте с ролью admin. Чтобы это проверить, выполните команду
yc iam role list
Вы увидите список ролей вашего аккаунта. Примерно такой (роль admin должна в нем присутствовать):
Узнайте идентификатор своего аккаунта. Он понадобится, чтобы добавить вашему аккаунту роль editor на созданный сервисный аккаунт (сервисный аккаунт тоже является ресурсом, и для работы с ним нужна соответствующая роль). Воспользуйтесь для этого командой:
yc iam user-account get <имя_вашего_аккаунта>
Кроме того, нужно узнать идентификатор созданного сервисного аккаунта. Это можно сделать в разделе Сервисные аккаунты консоли управления. Выбрав нужный аккаунт в списке, вы перейдёте на страницу с детальной информацией о нем.
Теперь предоставьте вашему пользовательскому аккаунту права на управление созданным сервисным аккаунтом. Для этого нужно выполнить команду
yc iam service-account add-access-binding <ID_сервисного_аккаунта> \
--role editor --subject userAccount:<ID_пользовательского_аккаунта>
ШАГ 3
Настройте аутентификацию под сервисным аккаунтом с вашей машины.
Сначала нужно создать статические ключи доступа и сохранить их в json-файле (например key.json).
Воспользуйтесь для этого командой
yc --folder-name <имя_каталога> iam key create \
--service-account-name <имя_сервисного_аккаунта> --output key.json
После выполнения команды вы получите идентификатор созданной ключевой пары. Используя статические ключи доступа, можно получить IAM-токен для авторизации в сервисах.
Теперь нужно создать профиль, от имени которого будут выполняться операции из-под сервисного аккаунта. Для этого придумайте имя этого профиля (например yc-lab23-profile) и выполните команду:
yc config profile create <имя_профиля>
Привяжите к этому профилю ранее созданный статический ключ доступа с помощью команды:
yc config set service-account-key key.json
Чтобы убедиться, что всё сделано правильно, выведите информацию об авторизации и ключах доступа
yc config list
Вы должны получить примерно такой результат:
ШАГ 4
Теперь нужно создать ключ шифрования, ротацией которого вы будете управлять с помощью сервисного аккаунта. Для этого перейдите в дашборд каталога в консоли управления, нажмите кнопку Создать ресурс и выберите Ключ шифрования.
В открывшемся окне задайте для ключа имя и нажмите кнопку Создать. Новый ключ появится в списке в открывшемся разделе Ключи.
Чтобы назначить сервисному аккаунту роль для какого-либо ресурса, нужно знать идентификатор этого ресурса. Нажмите строку с созданным ключом, чтобы перейти на страницу детальной информации о нём, и скопируйте ID ключа.
Перейдем к назначению сервисному аккаунту роли kms.admin для управления созданным ключом шифрования. Перед этим нужно сначала вернуться в профиль вашего аккаунта.
yc config profile activate <имя_профиля>
Выполните команду:
yc --folder-name <имя_каталога> kms symmetric-key \
add-access-binding <ID_ключа_шифрования> --role kms.admin \
--subject serviceAccount:<ID_сервисного_аккаунта>
Теперь с помощью сервисного аккаунта вы можете управлять этим ключом шифрования.
ШАГ 5
В CLI переключитесь обратно в профиль сервисного аккаунта:
yc config profile activate <имя_профиля_сервисного_аккаунта>
Ротируйте ключ шифрования:
yc kms symmetric-key rotate <ID_ключа>
После выполнения команды перейдите на страницу детальной информации о ключе и откройте вкладку Операции.
Вы увидите, что операция по ротации ключа выполнена под вашим сервисным аккаунтом. Значит, всё получилось и задача решена!
Decision:
$ yc iam service-account create --name <имя_сервисного_аккаунта>
$ yc iam service-account create --name security-labs \
--description "Service account for Security course labs"
$ yc iam role list
$ yc iam user-account get <ваш_логин>
$ yc iam service-account list
$ yc iam service-account get <имя_сервисного_аккаунта>
$ yc iam service-account add-access-binding <id_сервисного_аккаунта> \
--role editor \
--subject userAccount:<id_пользовательского_аккаунта>
$ vim key.json
$ cat key.json
{
"id": "YOUR-ID1",
"service_account_id": "YOUR-ID2",
"created_at": "2023-12-09T01:19:35.625144946Z",
"key_algorithm": "RSA_2048",
"public_key": "-----BEGIN PUBLIC KEY-----\nYOUR-KEY1\n-----END PUBLIC KEY-----\n",
"private_key": "PLEASE DO NOT REMOVE THIS LINE! Yandex.Cloud SA Key ID <YOUR-ID1>\n-----BEGIN PRIVATE KEY-----\nYOUR-KEY2\n-----END PRIVATE KEY-----\n"
}
$ yc iam key create \
--service-account-name <имя_сервисного_аккаунта> \
--output key.json
$ yc config profile create <имя_профиля_сервисного_аккаунта>
$ yc config set service-account-key key.json
$ yc config set folder-id <идентификатор_рабочего_каталога>
$ yc config list
$ yc config profile list
$ yc config profile activate <имя_основного_профиля>
$ yc kms symmetric-key add-access-binding \
--id <id_ключа_шифрования> \
--role kms.admin \
--subject serviceAccount:<id_сервисного_аккаунта>
$ yc config profile activate <имя_профиля_сервисного_аккаунта>
$ yc kms symmetric-key rotate --id <id_ключа_шифрования>
Task:
Организация защищённого канала.
Защита данных, передаваемых между вашей локальной инфраструктурой и облаком, — важный элемент информационной безопасности. А удалённая работа, которая получила распространение в период пандемии коронавируса и сейчас закрепилась в практиках многих компаний, сделала эту задачу ещё более актуальной.
Чтобы защитить передаваемую информацию, используют VPN (Virtual Private Network) — технологию, позволяющую развернуть защищённое сетевое соединение «поверх» незащищённой сети (чаще всего это интернет). VPN-соединение представляет собой канал передачи данных между двумя узлами. Этот канал обычно называют VPN-туннелем. Если за одним из узлов находится целая сеть, то его называют VPN-шлюзом.
Механизм работы VPN:
- Перед созданием туннеля узлы идентифицируют друг друга, чтобы удостовериться, что шифрованные данные будут отправлены на нужный узел.
- На обоих узлах нужно заранее определить, какие протоколы будут использоваться для шифрования и обеспечения целостности данных.
- Узлы сверяют настройки, чтобы договориться об используемых алгоритмах. Если настройки разные, туннель не создаётся.
- Если сверка прошла успешно, то создаётся ключ, который используется для симметричного шифрования.
Этот механизм регламентируют несколько стандартов. Один из самых популярных — IPSec (Internet Protocol Security).
На этом уроке вы научитесь настраивать IPSec VPN-туннель между двумя VPN-шлюзами с помощью демона strongSwan. Один шлюз вы настроите на виртуальной машине в Yandex Cloud, второй — на своей локальной машине или виртуальной машине в другой облачной сети.
Decision:
Шаг 1. Создание ресурсов
Для практической работы вам понадобится сеть и подсеть в Yandex Cloud, а также созданная в этой подсети тестовая ВМ без публичного IP-адреса. Создайте эти ресурсы, если у вас их нет.
Теперь создадим IPSec-инстанс — ВМ, которая будет служить шлюзом для IPSec-туннеля. Чтобы это сделать:
Откройте ваш каталог, нажмите кнопку Создать ресурс и выберите пункт Виртуальная машина.
В поле Имя задайте имя ВМ, например ipsec-instance.
Выберите зону доступности, где находится подсеть, к которой будет подключён IPSec-инстанс, и тестовая ВМ.
В разделе Выбор образа/загрузочного диска перейдите в блок Cloud Marketplace и выберите образ IPSec-инстанс.
В блоке Сетевые настройки выберите нужную сеть, подсеть и назначьте ВМ публичный IP-адрес из списка или автоматически.
Важно использовать только статические публичные IP-адреса из списка или сделать IP-адрес ВМ статическим после её создания. Динамический IP-адрес может измениться после перезагрузки ВМ, и туннель перестанет работать.
В блоке Доступ укажите логин и SSH-ключ для доступа к ВМ.
Нажмите кнопку Создать ВМ.
Виртуальная машина готова.
Шаг 2. Настраиваем IPSec
Теперь настроим шлюз с публичным IP-адресом, который будет устанавливать IPSec-соединение с удалённым шлюзом (вашей локальной машиной или ВМ в другой облачной сети).
Вы можете создать в своём каталоге ещё одну облачную сеть с подсетью, создать в ней IPSec-инстанс из образа и использовать его в качестве удалённого шлюза. Либо можно использовать в качестве шлюза машину в вашей локальной сети. Вам понадобится публичный IP-адрес удалённого шлюза и CIDR подсети.
Допустим, публичный IP-адрес вашего шлюза — 130.193.32.25, а за ним находится подсеть c префиксом подсети CIDR 10.128.0.0/24. Шлюз будет устанавливать IPSec-соединение с удалённым шлюзом с IP-адресом, например, 1.1.1.1, за которым находится подсеть с префиксом подсети CIDR 192.168.0.0/24.
Подключитесь к ВМ IPSec-инстанс по SSH:
ssh <имя пользователя>@130.193.32.25
Откройте конфигурацию IPSec:
sudo nano /etc/ipsec.conf
В разделе config setup файла конфигурации задайте следующие параметры:
config setup
    charondebug="all"
    uniqueids=yes
    strictcrlpolicy=no
Добавьте новый раздел с описанием тестового соединения, например conn cloud-to-hq.
Задайте параметры тестового соединения:
leftid — публичный IP-адрес IPSec-инстанса.
leftsubnet — CIDR подсети, к которой подключён IPSec-инстанс.
right — публичный IP-адрес шлюза на другом конце VPN-туннеля.
rightsubnet — CIDR подсети, к которой подключён VPN-шлюз на другом конце VPN-туннеля.
Параметры ike и esp — это алгоритмы шифрования, которые поддерживаются на удалённом шлюзе. Перечень поддерживаемых алгоритмов можно посмотреть на сайте strongSwan: IKEv1 и IKEv2.
Укажите остальные настройки, консультируясь с документацией strongSwan и учитывая настройки удалённого шлюза.
У вас должна получиться примерно такая конфигурация:
conn cloud-to-hq
    authby=secret
    left=%defaultroute
    leftid=130.193.32.25
    leftsubnet=10.128.0.0/24
    right=1.1.1.1
    rightsubnet=192.168.0.0/24
    ike=aes256-sha2_256-modp1024!
    esp=aes256-sha2_256!
    keyingtries=0
    ikelifetime=1h
    lifetime=8h
    dpddelay=30
    dpdtimeout=120
    dpdaction=restart
    auto=start
Сохраните изменения и закройте файл.
Откройте файл /etc/ipsec.secrets и укажите в нём пароль для установки соединения:
130.193.32.25 1.1.1.1 : PSK "<пароль>"
Перезапустите strongSwan:
sudo systemctl restart strongswan-starter
Шаг 3. Настраиваем статическую маршрутизацию
Теперь нужно настроить маршрутизацию между IPSec-инстансом и тестовой ВМ без публичного IP-адреса. Для этого создадим таблицу маршрутизации и добавим в неё статические маршруты.
Откройте сервис Virtual Private Cloud в каталоге, где требуется создать статический маршрут.
Выберите раздел Таблицы маршрутизации в панели слева и нажмите кнопку Создать таблицу маршрутизации.
Задайте имя таблицы маршрутизации, выберите сеть, в которой требуется её создать, и нажмите кнопку Добавить маршрут.
В открывшемся окне введите префикс подсети назначения на удалённой стороне, в примере это 192.168.0.0/24.
В поле Next hop укажите внутренний IP-адрес IPSec-шлюза и нажмите кнопку Добавить.
Нажмите кнопку Создать таблицу маршрутизации.
Чтобы использовать статические маршруты, нужно привязать таблицу маршрутизации к подсети. Для этого в разделе Подсети, в строке нужной подсети, нажмите кнопку … и в открывшемся меню выберите пункт Привязать таблицу маршрутизации.
В открывшемся окне выберите созданную таблицу и нажмите кнопку Привязать. Созданный маршрут можно применять и к другим подсетям этой сети.
Шаг 4. Настраиваем IPSec на другом шлюзе
Для работы VPN-туннеля нужно настроить второй шлюз.
Настройте strongSwan аналогично первому IPSec-шлюзу, но с зеркальными настройками IP-адресов и подсетей в файле /etc/ipsec.conf. Должна получиться такая конфигурация:
conn hq-to-cloud
    authby=secret
    left=%defaultroute
    leftid=1.1.1.1
    leftsubnet=192.168.0.0/24
    right=130.193.32.25
    rightsubnet=10.128.0.0/24
    ike=aes256-sha2_256-modp1024!
    esp=aes256-sha2_256!
    keyingtries=0
    ikelifetime=1h
    lifetime=8h
    dpddelay=30
    dpdtimeout=120
    dpdaction=restart
    auto=start
Укажите пароль для соединения в файле /etc/ipsec.secrets, указав IP-адреса шлюзов в обратном порядке:
1.1.1.1 130.193.32.25 : PSK "<пароль>"
Перезапустите strongSwan:
sudo systemctl restart strongswan-starter
Шаг 5. Проверяем, что всё работает
Чтобы убедиться, что туннель между шлюзами установлен, выполните на любом из шлюзов команду:
sudo ipsec status
Если всё в порядке, то у вас должно появиться примерно такое сообщение:
Security Associations (1 up, 0 connecting):
hq-to-cloud[3]: ESTABLISHED 29 minutes ago, 10.128.0.26[130.193.33.12]...192.168.0.23[1.1.1.1]
hq-to-cloud{3}: INSTALLED, TUNNEL, reqid 3, ESP in UDP SPIs: c7fa371d_i ce8b91ad_o
hq-to-cloud{3}: 10.128.0.0/24 === 192.168.0.0/24
Статус ESTABLISHED означает, что туннель между шлюзами создан.
Сведения об установке и работе соединения находятся в логах strongSwan. Просмотреть логи можно с помощью команды:
sudo journalctl -u strongswan-starter
Проверить статус демона strongSwan можно командой:
systemctl status strongswan-starter
Осталось проверить связность соединения. Для этого создайте ещё одну тестовую виртуальную машину за вторым шлюзом, а затем пропингуйте одну тестовую машину с другой.
Decision:
$ ssh <имя пользователя>@130.193.32.25
$ sudo vim /etc/ipsec.conf
$ sudo cat /etc/ipsec.conf
...
config setup
    charondebug="all"
    uniqueids=yes
    strictcrlpolicy=no
...
conn cloud-to-hq
    authby=secret
    left=%defaultroute
    leftid=130.193.32.25
    leftsubnet=10.128.0.0/24
    right=1.1.1.1
    rightsubnet=192.168.0.0/24
    ike=aes256-sha2_256-modp1024!
    esp=aes256-sha2_256!
    keyingtries=0
    ikelifetime=1h
    lifetime=8h
    dpddelay=30
    dpdtimeout=120
    dpdaction=restart
    auto=start
$ sudo vim /etc/ipsec.secrets
$ sudo cat /etc/ipsec.secrets
130.193.32.25 1.1.1.1 : PSK "<пароль>"
$ sudo systemctl restart strongswan-starter
$ exit
$ ssh <имя пользователя>@130.193.32.26
$ sudo vim /etc/ipsec.conf
$ sudo cat /etc/ipsec.conf
...
config setup
    charondebug="all"
    uniqueids=yes
    strictcrlpolicy=no
...
conn hq-to-cloud
    authby=secret
    left=%defaultroute
    leftid=1.1.1.1
    leftsubnet=192.168.0.0/24
    right=130.193.32.25
    rightsubnet=10.128.0.0/24
    ike=aes256-sha2_256-modp1024!
    esp=aes256-sha2_256!
    keyingtries=0
    ikelifetime=1h
    lifetime=8h
    dpddelay=30
    dpdtimeout=120
    dpdaction=restart
    auto=start
$ sudo vim /etc/ipsec.secrets
$ sudo cat /etc/ipsec.secrets
1.1.1.1 130.193.32.25 : PSK "<пароль>"
$ sudo systemctl restart strongswan-starter
$ ssh <имя пользователя>@130.193.32.25
$ sudo ipsec status
$ sudo journalctl -u strongswan-starter
$ systemctl status strongswan-starter
Task:
Выпуск сертификата для сайта.
В этой практической работе мы зарегистрируем домен, привяжем его к бакету в объектном хранилище и настроим для этого домена автоматический выпуск сертификата с помощью Certificate Manager.
Decision:
Шаг 1
Если у вас нет своего домена, зарегистрируйте временный домен, например, на сайте freenom.com:
Проверьте на сайте доступность имени, которое вы придумали для своего домена.
Введите имя вместе с доменом верхнего уровня, например testpracticum2022.ml, иначе при попытке зарезервировать домен сервис будет сообщать, что домен занят.
Если это имя доступно, добавьте домен в корзину и укажите свой email для подтверждения.
Проверьте почту и подтвердите регистрацию домена.
Обновите страницу с заказом.
После подтверждения регистрации домена зайдите в объектное хранилище (Object Storage) и создайте новый публичный бакет. Его название должно совпадать с полным названием домена.
Переключите доступ на чтение объектов в Публичный. Загрузите в бакет файлы статического сайта (вы можете воспользоваться файлами из практической работы курса «Хранение и анализ данных».
Выберите на панели управления раздел Веб-сайт, переключите бакет в режим Хостинг и нажмите Сохранить.
Шаг 2
Настроить защищённый доступ к бакету можно двумя способами: загрузить сертификат прямо в бакет или с помощью Certificate Manager. Воспользуемся вторым способом.
В консоли управления перейдите в сервис Certificate Manager. Для выпуска сертификата с помощью этого сервиса подтвердите владение доменом: в разделе Сертификаты нажмите кнопку Добавить сертификат и выберите Сертификат Let’s Encrypt.
В открывшемся окне задайте имя создаваемого сертификата и заполните поле с именем вашего домена. Нажмите кнопку Создать.
Сервис автоматически направит запрос на создание сертификата, а домен перейдёт в статус проверки.
Для выпуска сертификата необходимо подтвердить статус владения доменом. Откройте страницу с деталями запроса на сертификат:
На этой странице для нас важны два поля: имя DNS-записи и её значение. Если вы создавали домен на freenom.com, то перейдите в личный кабинет на этом сайте, выберите раздел Services → My Domains и нажмите кнопку Manage Domains:
Выберите Manage Freenom DNS:
В открывшемся редакторе добавьте TXT-запись для подтверждения владения доменом. В качестве названия записи задайте _acme-challenge без полного названия домена. В качестве значения TXT-записи — значение со страницы проверки прав на домен в консоли управления Yandex Cloud.
Аналогично внесите значение CNAME-записи со страницы проверки прав на домен в консоли управления Yandex Cloud.
Добавьте также запись CNAME для привязки поддомена WWW к вашему бакету:
В поле Target укажите полное имя бакета, включая .website.yandexcloud.net. Сохраните сделанные изменения.
Если вы используете собственный домен, задайте параметры DNS в настройках вашего DNS-сервера. Для применения настроек DNS потребуется некоторое время — обычно до 15 минут.
После окончания проверки домена Certificate Manager автоматически выпустит сертификат.
Шаг 3
Теперь настроим доступ к сайту, то есть к созданному бакету, по протоколу HTTPS с помощью сертификата. Для этого перейдите в раздел HTTPS и нажмите кнопку Настроить.
В поле Источник выберите Certificate Manager, в поле Сертификат — ранее выпущенный сертификат. Нажмите кнопку Сохранить.
Теперь ваш сайт доступен по протоколу HTTPS. Чтобы проверить это, откройте его в браузере. В адресной строке браузера должен отображаться значок защищённого соединения.
Task:
Создание и ротация ключей шифрования
На прошлом уроке вы познакомились с возможностями сервиса управления ключами шифрования KMS. В этой практической работе вы научитесь создавать ключи шифрования и управлять ими, а также использовать эти ключи для шифрования и расшифрования данных.
Decision:
Шаг 1
Перейдите в панель управления Yandex Cloud, нажмите кнопку Создать ресурс и выберите из выпадающего списка пункт Ключ шифрования.
Задайте для создаваемого ключа имя (например yc-lab-key1), заполните поле Описание (это необязательно) и выберите алгоритм шифрования. Предположим, что ключ нужно ротировать каждый день. Для этого в поле Период ротации, дни выберите вариант Своё значение и введите число 1 в поле справа.
Нажмите кнопку Создать. Когда операция создания ключа завершится, новый ключ появится в списке.
Нажав на строку с ключом, вы перейдёте на страницу детальной информации. На ней приведены все параметры ключа, а также список его версий. Обратите внимание, что ID (идентификатор) ключа и ID конкретной версии ключа отличаются. Важно их не путать.
Шаг 2
Давайте используем созданный ключ для шифрования и расшифрования данных. Создайте у себя на диске файл (например, текстовый файл с именем plain.txt). Добавьте в него любой текст и сохраните содержимое. Напомним, что размер файла не должен превышать 32 килобайта.
Запустите утилиту командной строки (bash или cmd) и перейдите в каталог с файлом plain.txt. Зашифруйте этот файл с помощью утилиты yc, а результат операции шифрования выведите в файл encrypted.txt. Для этого выполните команду:
yc kms symmetric-crypto encrypt --id <ID ключа> --plaintext-file plain.txt --ciphertext-file encrypted.txt
После выполнения команды будет создан файл encrypted.txt, который содержит зашифрованный текст. Утилита yc также выведет информацию о том, каким ключом и какой его версией файл был зашифрован.
Шаг 3
Теперь расшифруйте этот файл, а результат операции выведите в файл decrypted.txt. Для этого выполните команду:
yc kms symmetric-crypto decrypt --id <ID ключа> --ciphertext-file encrypted.txt --plaintext-file decrypted.txt
В результате выполнения команды будет создан файл decrypted.txt с идентичным исходному файлу (plain.txt) содержимым.
Если расшифровать файл не удалось, утилита выдаст сообщение об ошибке.
Шаг 4
Создайте новую версию ключа. Для этого перейдите на страницу детальной информации о ключе и нажмите кнопку Ротировать. Новая версия ключа появится в списке версий и станет основной (Primary). Обратите внимание, что идентификаторы версий отличаются друг от друга.
Шаг 5
Запланируйте удаление первой версии ключа. Для этого в списке версий нажмите на значок … в строке с этой версией, а затем выберите пункт Запланировать удаление.
В появившемся окне установите время, по истечении которого ключ будет удалён, и нажмите Запланировать. Версия ключа не может быть удалена моментально, минимальный период времени для её удаления составляет один день.
После этого в списке версий удаляемый ключ будет помечен как запланированный на удаление (Scheduled For Destruction). Теперь этой версией ключа невозможно расшифровать файлы, которые были зашифрованы с её помощью.
Провести ротацию ключа можно и из командной строки. Для этого используется команда:
yc kms symmetric-key rotate <ID ключа>
Шаг 6
Зашифруйте исходный файл plain.txt с помощью новой версии ключа. Результат запишите в файл encrypted_with_new_key.txt.
yc kms symmetric-crypto encrypt --id <ID ключа> --plaintext-file plain.txt --ciphertext-file encrypted_with_new_key.txt
Теперь у вас есть два файла:
- encrypted.txt, зашифрованный версией ключа, которая помечена на удаление;
- encrypted_with_new_version.txt, зашифрованный новой версией ключа.
Попробуйте расшифровать данные из обоих файлов. Вы увидите, что расшифровать первый файл не получилось, а файл, который зашифрован второй версией ключа, расшифрован.
Запланированное удаление первой версии ключа можно отменить. Это позволит расшифровать данные из первого файла.
В строке версии ключа, которая запланирована на удаление, нажмите значок …, а затем кнопку кнопку Отменить удаление. Эта версия снова получит статус активной. Проверьте, что она работает, расшифровав файл encrypted.txt.
Decision:
$ vim plain.txt
$ cat plain.txt
test text
$ yc kms symmetric-crypto encrypt --id <ID ключа> --plaintext-file plain.txt --ciphertext-file encrypted.txt
$ yc kms symmetric-crypto encrypt --id abjkh5a8k2uao3f8qi8k --plaintext-file plain.txt --ciphertext-file encrypted.txt
$ cat encrypted.txt
abj2vjcrv89d83cef26in#���k��|�V�X�
                 ����:�F���*Y��l�(���у��֜�l�S
$ yc kms symmetric-crypto decrypt --id <ID ключа> --ciphertext-file encrypted.txt --plaintext-file decrypted.txt
$ cat decrypted.txt
test text
$ yc kms symmetric-key rotate <ID ключа>
$ yc kms symmetric-crypto encrypt --id <ID ключа> --plaintext-file plain.txt --ciphertext-file encrypted_with_new_key.txt
$ cat encrypted_with_new_key.txt
abjofv85g302tc8mjhqq��n�nߊz6�5�A�
                 �)ڀi�R0���лo��s    �^
�m�C zci�b�'
Decision:
Защитил диплом о дополнительной переподготовке:
 

2011-09-01 - 2018-05-30: Иркутский государственный университет, Иркутск. Должность: Информационные технологии и телекоммуникационные системы - Бакалавр / Электроника и наноэлектроника - Магистр / Информационная безопасность - Дополнительное образование. Дополнительная информация: Навыки - Html, Css, Windows, Виртуализация, Linux, Sql, Bash, Clouds, Python, Спутниковые радионавигационные системы, С++. Достижения: Разработал сайт портфолио, куда публиковал все решенные мной интересные задачи, отчеты лабораторных работ и презентации, сверстал простой сайт.

Show

# Верстка Веб-страниц.
# Администрирование локальных, виртуальных и облачных серверов.
# Администрирование веб-сервера
# Разработка базы данных.
# Написание Sql запросов.
# Администрирование базы данных.
# Администрирование Веб-сервера Django.
# Администрирование Веб-сервера React.js.
# Frontend-разработка Веб-сайта React.js.
# Разработка Веб-сайта Django.
Task:
Верстка Веб-страниц. 
Decision:

Task:
Верстка Веб-страниц. Создание HTML-списков.
Decision:
<ul>
<li>Linux Server Administration</li>
<li>Working with websites</li>
</ul>
Source:
# https://html5book.ru/html-lists/?ysclid=lis7im73ng615064864 - Создание HTML-списков.
Task:
Администрирование локальных, виртуальных и облачных серверов. Настройка SSH сервера.
Decision:
root@aw:/# cat /root/.ssh/known_hosts
root@aw:/# cd keys 
root@aw:/keys# ssh-keygen
root@aw:/keys# ls
wslkvmubuntu wslkvmubuntu.pub
root@aw:/keys# ssh-copy-id -i wslkvmubuntu.pub tuser@tipubuntu
root@aw:/keys# cat /root/.ssh/known_hosts
root@aw:/keys# ssh tuser@tipubuntu
Source:
# https://timeweb.cloud/docs/unix-guides/ssh-key-authentication - Авторизация по SSH-ключу.
Task:
Администрирование локальных, виртуальных и облачных серверов. Создание пользователя.
Decision:
tuser@kvmubuntu:~$ sudo passwd root
tuser@kvmubuntu:~$ su -
root@kvmubuntu:~# useradd -m -d /home/tuser -u 1001 -s /bin/bash tuser
root@kvmubuntu:~# passwd tuser
root@kvmubuntu:~# cat /etc/passwd | grep tuser
tuser:x:1001:1001::/home/tuser:/bin/bash
root@kvmubuntu:~# id tuser
uid=1001(tuser) gid=1001(tuser) groups=1001(tuser)
root@kvmubuntu:~# usermod -aG sudo tuser
Source:
# https://www.inp.nsk.su/~bolkhov/teach/inpunix/setup_users.ru.html - Манипуляции с пользователями.
# https://losst.pro/kak-sozdat-polzovatelya-linux - Команда useradd.
Task:
Администрирование локальных, виртуальных и облачных серверов. Переименовать имя хоста.
Decision:
tuser@kvmubuntu:~$ hostname
UBUNTU.twc1.net
tuser@kvmubuntu:~$ sudo hostname kvmubuntu.twc1.net
tuser@kvmubuntu:~$ cat /etc/hosts
127.0.0.1 UBUNTU.twc1.net
tuser@kvmubuntu:~$ sudo vim /etc/hosts
tuser@kvmubuntu:~$ cat /etc/hosts
127.0.0.1 kvmubuntu.twc1.net
tuser@kvmubuntu:~$ cat /etc/hostname
UBUNTU.twc1.net
tuser@kvmubuntu:~$ sudo vim /etc/hostname
tuser@kvmubuntu:~$ cat /etc/hostname
kvmubuntu.twc1.net
tuser@kvmubuntu:~$ sudo reboot
Task:
Администрирование локальных, виртуальных и облачных серверов. Удаление пользователя из группы Linux.
Decision:
root@kvmubuntu:~# groups tuser
tuser : tuser adm cdrom sudo dip plugdev lpadmin lxd sambashare
root@kvmubuntu:~# deluser tuser adm
Removing user `tuser' from group `adm' ...
Done.
root@kvmubuntu:~# deluser tuser cdrom
Removing user `tuser' from group `cdrom' ...
Done.
root@kvmubuntu:~# deluser tuser dip
Removing user `tuser' from group `dip' ...
Done.
root@kvmubuntu:~# deluser tuser plugdev
Removing user `tuser' from group `plugdev' ...
Done.
root@kvmubuntu:~# deluser tuser lpadmin
Removing user `tuser' from group `lpadmin' ...
Done.
root@kvmubuntu:~# deluser tuser lxd
Removing user `tuser' from group `lxd' ...
Done.
root@kvmubuntu:~# deluser tuser sambashare
Removing user `tuser' from group `sambashare' ...
Done.
root@kvmubuntu:~# deluser tuser sudo
Removing user `tuser' from group `sudo' ...
Done.
root@kvmubuntu:~# groups tuser
tuser : tuser
$ sudo apt update
tuser is not in the sudoers file. This incident will be reported.
Source:
# https://losst.pro/udalit-polzovatelya-iz-gruppy-linux?ysclid=lxbdgff7yz225601747 - Удаление пользователя из группы Linux.
Task:
Администрирование локальных, виртуальных и облачных серверов. Отключение входа для суперпользователя.
Decision:
root@kvmubuntu:~# sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin no/' /etc/ssh/sshd_config
root@kvmubuntu:~# sed -i 's/PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
root@kvmubuntu:~# sed -i 's/UsePAM yes/UsePAM no/' /etc/ssh/sshd_config
root@kvmubuntu:~# vim /etc/ssh/sshd_config
root@kvmubuntu:~# cat /etc/ssh/sshd_config | grep PermitRootLogin
#PermitRootLogin yes
PermitRootLogin no
# the setting of "PermitRootLogin without-password".
root@kvmubuntu:~# cat /etc/ssh/sshd_config | grep PasswordAuthentication
#PasswordAuthentication yes
PasswordAuthentication no
# PasswordAuthentication. Depending on your PAM configuration,
# PAM authentication, then enable this but set PasswordAuthentication
    PasswordAuthentication yes
root@kvmubuntu:~# vim /etc/ssh/sshd_config
root@kvmubuntu:~# cat /etc/ssh/sshd_config | grep UsePAM
#UsePAM yes
UsePAM no
root@kvmubuntu:~# cat /etc/ssh/sshd_config | grep ChallengeResponseAuthentication
ChallengeResponseAuthentication no
root@kvmubuntu:~# systemctl restart ssh
Source:
# https://linuxconfig.org/allow-ssh-root-login-on-ubuntu-22-04-jammy-jellyfish-linux?ysclid=lxbo86izx4139346766 - Allowing SSH root login on Ubuntu 22.04 step by step instructions. 
# https://losst.pro/bezopasnost-servera-linux#toc-13-programmy-s-suid-i-sgid-bitami - Настройка SSH сервера.
Task:
Администрирование локальных, виртуальных и облачных серверов. Регулярная смена пароля
Decision:
root@kvmubuntu:~# chage -M 7 -m 6 -W 5 tuser
Source:
# https://manpages.ubuntu.com/manpages/trusty/ru/man1/chage.1.html - ПАРАМЕТРЫ.
Task:
Администрирование локальных, виртуальных и облачных серверов. Установка браузера chrome для тестирования Веб-приложений.
Decision:
root@kvmubuntu:~# wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
root@kvmubuntu:~# dpkg -i --force-depends google-chrome-stable_current_amd64.deb
tuser@kvmubuntu:~$ google-chrome
Source:
# https://askubuntu.com/questions/510056/how-to-install-google-chrome - How to install Google Chrome.
Task:
Администрирование локальных, виртуальных и облачных серверов. Настройка SELinux.
Decision:
root@kvmubuntu:~# apt install policycoreutils selinux-utils selinux-basics
root@kvmubuntu:~# sestatus
SELinux status: disabled
root@kvmubuntu:~# selinux-activate
root@kvmubuntu:~# cat /etc/selinux/config 
...
SELINUX=permissive
SELINUXTYPE=default
SETLOCALDEFS=0
root@kvmubuntu:~# reboot
root@kvmubuntu:~# sestatus
...
SELinux status: enabled
Current mode: permissive
Mode from config file: permissive
root@kvmubuntu:~# setenforce 1
root@kvmubuntu:~# getenforce
Enforcing
root@kvmubuntu:~# touch /.autolabel
root@kvmubuntu:~# reboot
Source:
# https://ruvds.com/ru/helpcenter/vvedenie-v-selinux-pod-ubuntu-20-04/ - Инсталляция SELinux.
# https://losst.pro/nastrojka-selinux - Настройка SELinux.
# https://www.dmosk.ru/miniinstruktions.php?mini=selinux-setting&ysclid=lvn75pdsk3201545540#settings-policies - Диагностика проблем.
Task:
Администрирование локальных, виртуальных и облачных серверов. Change SSH Port on CentOS or RHEL or Fedora With SELinux.
Decision:
root@kvmubuntu:~# semanage port -l | grep ssh
ssh_port_t tcp 22
root@kvmubuntu:~# vim /etc/ssh/sshd_config
root@kvmubuntu:~# cat /etc/ssh/sshd_config
...
#Port 22
Port 2233
root@kvmubuntu:~# semanage port -a -t ssh_port_t -p tcp 2233
root@kvmubuntu:~# semanage port -l | grep ssh
ssh_port_t tcp 2233, 22
root@kvmubuntu:~# ufw allow 2233
root@kvmubuntu:~# systemctl restart sshd
root@kvmubuntu:~# netstat -tunl | grep 2233
tcp 0 0 0.0.0.0:2233 0.0.0.0:* LISTEN 
tcp6 0 0 :::2233 :::* LISTEN
root@kvmubuntu:~# exit 
root@aw:/# ssh -X tuser@tipubuntu
ssh: connect to host tipubuntu port 22: Connection refused
root@aw:/# ssh -Xp 2233 tuser@tipubuntu
Source:
# https://computingforgeeks.com/change-ssh-port-centos-rhel-fedora-with-selinux/ - Change SSH Port on CentOS or RHEL or Fedora With SELinux.
Task:
Администрирование локальных, виртуальных и облачных серверов. Sftp сервер.
Decision:
root@kvmubuntu:~# groupadd sftpgroup
root@kvmubuntu:~# useradd --no-create-home --gid sftpgroup sftptuser
root@kvmubuntu:~# passwd sftptuser
root@kvmubuntu:~# mkdir /srv/sftp
root@kvmubuntu:~# chown root:root /srv/sftp
root@kvmubuntu:~# chmod 755 /srv/sftp
root@kvmubuntu:~# mkdir /srv/sftp/sftptuser
root@kvmubuntu:~# chown sftptuser:sftpgroup /srv/sftp/sftptuser
root@kvmubuntu:~# vim /etc/ssh/sshd_config
root@kvmubuntu:~# cat /etc/ssh/sshd_config
...
#Subsystem sftp /usr/lib/openssh/sftp-server
# использовать встроенный sftp-сервер
Subsystem sftp internal-sftp
...
# только для пользователей группы sftpgroup
Match Group sftpgroup
  # только работа с файлами, запрет shell
  ForceCommand internal-sftp
  # разрешить аутентификацию по паролю
  PasswordAuthentication yes
  # разрешить доступ только к /srv/sftp
  ChrootDirectory /srv/sftp
  # запретить все, что не нужно для работы
  PermitTunnel no
  AllowAgentForwarding no
  AllowTcpForwarding no
  X11Forwarding no
root@kvmubuntu:~# systemctl restart sshd.service
root@kvmubuntu:~# touch /srv/sftp/sftptuser/test.txt
root@kvmubuntu:~# exit
root@Windows-Asus:/home/dato# sftp -P 2233 sftptuser@tipubuntu
sftp> ls
sftptuser 
sftp> lls mnt/
requirements.txt dato138it
sftp> cd sftptuser/
sftp> get test.txt
sftp> put -r mnt/dato138it
sftp> exit
root@Windows-Asus:/home/dato# ls test.txt
test.txt
sftp> exit
Source:
# https://tokmakov.msk.ru/blog/item/484?ysclid=lvlnz4iz7m313316662 - Настройка SFTP-сервера.
Task:
Администрирование локальных, виртуальных и облачных серверов. Install and Use Rkhunter for Security
Decision:
root@kvmubuntu:~# apt install rkhunter
root@kvmubuntu:~# vim /etc/rkhunter.conf
root@kvmubuntu:~# cat /etc/rkhunter.conf
...
#WEB_CMD="/bin/false"
UPDATE_MIRRORS=1
MIRRORS_MODE=0
root@kvmubuntu:~# rkhunter -C
root@kvmubuntu:~# rkhunter --update
[ Rootkit Hunter version 1.4.6 ]
Checking rkhunter data files...
Checking file mirrors.dat [ No update ]
Checking file programs_bad.dat [ No update ]
Checking file backdoorports.dat [ No update ]
Checking file suspscan.dat [ No update ]
Checking file i18n/cn [ Skipped ]
Checking file i18n/de [ Skipped ]
Checking file i18n/en [ No update ]
Checking file i18n/tr [ Skipped ]
Checking file i18n/tr.utf8 [ Skipped ]
Checking file i18n/zh [ Skipped ]
Checking file i18n/zh.utf8 [ Skipped ]
Checking file i18n/ja [ Skipped ]
root@kvmubuntu:~# rkhunter --propupd
root@kvmubuntu:~# vim /etc/cron.daily/rkhunter.sh
root@kvmubuntu:~# cat /etc/cron.daily/rkhunter.sh
#!/bin/sh
(
/usr/local/bin/rkhunter --versioncheck
/usr/local/bin/rkhunter --update
/usr/local/bin/rkhunter --cronjob --report-warnings-only
) | /bin/mail -s 'rkhunter Daily Run (tipubuntu)' tmail38@mail.ru
root@kvmubuntu:~# chmod 755 /etc/cron.daily/rkhunter.sh
root@kvmubuntu:~# rkhunter --list rootkits
root@kvmubuntu:~# rkhunter --check
root@kvmubuntu:~# cat /var/log/rkhunter.log | grep hidden
root@kvmubuntu:~# cat /var/log/rkhunter.log | grep -A5 "\[ Warning \]"
Source:
# https://losst.pro/proverka-linux-na-virusy?ysclid=lv2diq667c645946178#poisk-virusov-s-pomoshchyu-rkhunter - Поиск вирусов с помощью RkHunter
# https://vegastack.com/tutorials/how-to-install-and-use-rkhunter-for-security-on-ubuntu-22-04/ - Install and Use Rkhunter for Security
# https://linux-notes.org/poisk-rutkitov-v-debian-ubuntu-linux-mint-i-red-hat-centos-fedora/?ysclid=lob3rn9gk6547904603
# https://winitpro.ru/index.php/2020/04/21/planirovshhik-zadach-cron-v-linux/
Task:
Администрирование локальных, виртуальных и облачных серверов. Установка IDS.
Decision:
root@kvmubuntu:~# apt install tripwire
root@kvmubuntu:~# tripwire --init
...
### Warning: File system error.
### Filename: /proc/pci
### Нет такого файла или каталога
### Continuing...
...
root@kvmubuntu:~# vim /etc/tripwire/twpol.txt
root@kvmubuntu:~# cat /etc/tripwire/twpol.txt
...
{
    #/var/lock       -> $(SEC_CONFIG) ;
    #/var/run       -> $(SEC_CONFIG) ; # daemon PIDs
    /var/log        -> $(SEC_CONFIG) ;
}
...
{
    /root             -> $(SEC_CRIT) ; # Catch all additions to /root
    #/root/mail           -> $(SEC_CONFIG) ;
    #/root/Mail           -> $(SEC_CONFIG) ;
    #/root/.xsession-errors     -> $(SEC_CONFIG) ;
    #/root/.xauth         -> $(SEC_CONFIG) ;
    #/root/.tcshrc         -> $(SEC_CONFIG) ;
    #/root/.sawfish         -> $(SEC_CONFIG) ;
    #/root/.pinerc         -> $(SEC_CONFIG) ;
    #/root/.mc           -> $(SEC_CONFIG) ;
    #/root/.gnome_private     -> $(SEC_CONFIG) ;
    #/root/.gnome-desktop     -> $(SEC_CONFIG) ;
    #/root/.gnome         -> $(SEC_CONFIG) ;
    #/root/.esd_auth            -> $(SEC_CONFIG) ;
    #/root/.elm           -> $(SEC_CONFIG) ;
    #/root/.cshrc         -> $(SEC_CONFIG) ;
    /root/.bashrc         -> $(SEC_CONFIG) ;
    #/root/.bash_profile      -> $(SEC_CONFIG) ;
    #/root/.bash_logout       -> $(SEC_CONFIG) ;
    /root/.bash_history       -> $(SEC_CONFIG) ;
    #/root/.amandahosts       -> $(SEC_CONFIG) ;
    #/root/.addressbook.lu     -> $(SEC_CONFIG) ;
    #/root/.addressbook       -> $(SEC_CONFIG) ;
    #/root/.Xresources       -> $(SEC_CONFIG) ;
    #/root/.Xauthority       -> $(SEC_CONFIG) -i ; # Changes Inode number on login
    #/root/.ICEauthority        -> $(SEC_CONFIG) ;
}
...
{
    /dev      -> $(Device) ;
    /dev/pts    -> $(Device) ;
    #/proc     -> $(Device) ;
    /proc/devices -> $(Device) ;
    /proc/net   -> $(Device) ;
    /proc/tty   -> $(Device) ;
    /proc/sys   -> $(Device) ;
    /proc/cpuinfo -> $(Device) ;
    /proc/modules -> $(Device) ;
    /proc/mounts  -> $(Device) ;
    /proc/dma   -> $(Device) ;
    /proc/filesystems   -> $(Device) ;
    /proc/interrupts    -> $(Device) ;
    /proc/ioports -> $(Device) ;
    /proc/scsi   -> $(Device) ;
    /proc/kcore   -> $(Device) ;
    /proc/self   -> $(Device) ;
    /proc/kmsg   -> $(Device) ;
    /proc/stat   -> $(Device) ;
    /proc/loadavg -> $(Device) ;
    /proc/uptime  -> $(Device) ;
    /proc/locks   -> $(Device) ;
    /proc/meminfo -> $(Device) ;
    /proc/misc   -> $(Device) ;
}
...
root@kvmubuntu:~# twadmin -m P /etc/tripwire/twpol.txt
root@kvmubuntu:~# tripwire --init
root@kvmubuntu:~# tripwire --check
...
Wrote report file: /var/lib/tripwire/report/kvmubuntu-20240817-222433.twr
...
Report generated by:     root
Report created on:      Sat 17 Aug 2024 10:24:33 PM EDT
Database last updated on:   Never
===============================================================================
Report Summary:
===============================================================================
Host name:          kvmubuntu
Host IP address:       127.0.1.1
Host ID:           None
Policy file used:       /etc/tripwire/tw.pol
Configuration file used:   /etc/tripwire/tw.cfg
Database file used:     /var/lib/tripwire/kvmubuntu.twd
Command line used:      tripwire --check
===============================================================================
Rule Summary:
===============================================================================
...
Rule Name           Severity Level  Added  Removed Modified
---------           --------------  -----  ------- --------
Other binaries         66        0    0    0
Tripwire Binaries       100       0    0    0
Other libraries         66        0    0    0
Root file-system executables  100       0    0    0
Tripwire Data Files       100       0    0    0
System boot changes       100       0    0    0
(/var/log)
Root file-system libraries   100       0    0    0
(/lib)
Critical system boot files   100       0    0    0
Other configuration files   66        0    0    0
(/etc)
Boot Scripts          100       0    0    0
Security Control        66        0    0    0
Root config files       100       0    0    0
Devices & Kernel information  100       0    0    0
Invariant Directories     66        0    0    0
...
===============================================================================
Object Summary:
===============================================================================
...
No violations.
===============================================================================
Error Report:
===============================================================================
No Errors
...
root@kvmubuntu:~# apt install mailutils
root@kvmubuntu:~# dpkg-reconfigure postfix
...
1. No configuration 2. Internet Site 3. Internet with smarthost 4. Satellite system 5. Local only
General mail configuration type: 2
...
System mail name: tmail38@mail.ru
...
Recipient for root and postmaster mail: tuser
...
Other destinations to accept mail for (blank for none): mail.ru
...
Force synchronous updates on mail queue? [yes/no] yes
...
Local networks: tipubuntu
...
Mailbox size limit (bytes): 
...
Local address extension character: 
all : use both IPv4 and IPv6 addresses;
ipv6: listen only on IPv6 addresses;
ipv4: listen only on IPv4 addresses.
1. all 2. ipv6 3. ipv4
...
Internet protocols to use: 1
root@kvmubuntu:~# systemctl reload postfix
root@kvmubuntu:~# tripwire --check | mail -s "Tripwire report for `uname -n`" tmail38@mail.ru
Source:
# https://stackoverflow.com/questions/12867573/searching-from-end-of-file-using-vim - Базовый поиск.
# https://www.8host.com/blog/ispolzovanie-tripwire-dlya-obnaruzheniya-vtorzhenij-na-server-ubuntu/ - ИСПОЛЬЗОВАНИЕ TRIPWIRE ДЛЯ ОБНАРУЖЕНИЯ ВТОРЖЕНИЙ НА СЕРВЕР UBUNTU.
# https://computingforgeeks.com/install-and-configure-tripwire-on-ubuntu/ - Install and Configure Tripwire on Ubuntu 22.04|20.04|18.04.
Task:
Администрирование локальных, виртуальных и облачных серверов. Использование fail2ban.
Decision:
root@kvmubuntu:~# apt install fail2ban
root@kvmubuntu:~# systemctl enable fail2ban --now
root@kvmubuntu:~# faillog -a | grep tuser
tuser     0    0 12/31/69 19:00:00 -0500
sftptuser   0    0 12/31/69 19:00:00 -0500
Task:
Администрирование локальных, виртуальных и облачных серверов. Настройка ядра.
Decision:
root@kvmubuntu:~# vim /etc/sysctl.conf
root@kvmubuntu:~# cat /etc/sysctl.conf
...
net.ipv4.conf.all.rp_filter=1
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.log_martians = 1
kernel.randomize_va_space=1
net.ipv4.icmp_echo_ignore_broadcasts=1
net.ipv4.conf.all.log_martians = 1
root@kvmubuntu:~# sysctl -p /etc/sysctl.conf
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.log_martians = 1
kernel.randomize_va_space = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.conf.all.log_martians = 1
Task: 
Администрирование локальных, виртуальных и облачных серверов. Программы с SUID и SGID битами.
Decision:
root@kvmubuntu:~# find / \( -perm -4000 -o -perm -2000 \) -print
Source:
# https://unix.stackexchange.com/questions/180867/how-to-search-for-all-suid-sgid-files - How to search for all SUID/SGID files?
Task:
Администрирование локальных, виртуальных и облачных серверов. Общедоступные файлы.
Decision:
root@kvmubuntu:~# find / -xdev -type d \( -perm -0002 -a ! -perm -1000 \) -print
root@kvmubuntu:~# find / -xdev \( -nouser -o -nogroup \) -print
Task:
Администрирование локальных, виртуальных и облачных серверов. Логирование и аудит.
Decision:
root@kvmubuntu:~# apt install logwatch
General mail configuration type: 1
root@kvmubuntu:~# cp /usr/share/logwatch/default.conf/logwatch.conf /etc/logwatch/conf/
root@kvmubuntu:~# vim /etc/logwatch/conf/logwatch.conf
root@kvmubuntu:~# cat /etc/logwatch/conf/logwatch.conf | grep Output
...
#Output = stdout
Output = mail
root@kvmubuntu:~# cat /etc/logwatch/conf/logwatch.conf | grep MailTo
#MailTo = root
MailTo = tmail38@mail.ru
root@kvmubuntu:~# cat /etc/logwatch/conf/logwatch.conf | grep LogDir
LogDir = /var/log
root@kvmubuntu:~# apt install postfix
root@kvmubuntu:~# logwatch --detail Low --range today
root@kvmubuntu:~# vim /etc/cron.daily/00logwatch
root@kvmubuntu:~# cat /etc/cron.daily/00logwatch | grep /usr/sbin/logwatch
#/usr/sbin/logwatch --output mail
/usr/sbin/logwatch --output mail --mailto tmail38@mail.ru --detail high
Source:
# https://ubuntu.com/server/docs/how-to-install-and-configure-logwatch - Настроить logwatch.
# https://habr.com/ru/companies/rootwelt/articles/303462/ - Logwatch.
Decision:
root@kvmubuntu:~# apt install logcheck
root@kvmubuntu:~# vim /etc/aliases
root@kvmubuntu:~# cat /etc/aliases
postmaster: tmail38@mail.ru
logcheck: tuser
root@kvmubuntu:~# vim /etc/logcheck/logcheck.conf
root@kvmubuntu:~# cat /etc/logcheck/logcheck.conf
...
INTRO=1
REPORTLEVEL="kvmubuntu"
SENDMAILTO="tmail38@mail.ru"
ADDTAG="yes"
root@kvmubuntu:~# ls /etc/logcheck/
cracking.d ignore.d.paranoid logcheck.conf violations.d
cracking.ignore.d ignore.d.server logcheck.logfiles violations.ignore.d
header.txt ignore.d.workstation logcheck.logfiles.d
root@kvmubuntu:~# vim /etc/logcheck/ignore.d.server/local-rules
root@kvmubuntu:~# cat /etc/logcheck/ignore.d.server/local-rules
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: Disconnected from (user [^[:space:]]+ )?[[:xdigit:]:.]+ port [[:digit:]]+?( \[preauth\])?$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: user cronuser login class \[preauth\]$
root@kvmubuntu:~# egrep -f /etc/logcheck/ignore.d.server/local-rules /var/log/syslog
root@kvmubuntu:~# su -s /bin/bash -c "/usr/sbin/logcheck" logcheck
Source:
# http://snakeproject.ru/rubric/article.php?art=logcheck_15.04.2019 - Настроить logcheck.
Task:
Администрирование локальных, виртуальных и облачных серверов. Сравнить образ раздела или файла перед взломом с образом из взломанной системы.
Decision:
root@kvmubuntu:~# dd if=/bin/ls of=ls.dd | md5sum ls.dd > sum.txt
274+1 записей получено
274+1 записей отправлено
140760 байт (141 kB, 137 KiB) скопирован, 0,00362538 s, 38,8 MB/s
root@kvmubuntu:~# cat sum.txt
0ad8006df0caff12335f45fdf6c7c0f7 ls.dd
root@kvmubuntu:~# file /bin/ls
/bin/ls: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=bdfe7bf382f12e8361d590aa148cb3e591f83d30, for GNU/Linux 3.2.0, stripped
root@kvmubuntu:~# stat /bin/ls
Файл: /bin/ls
Размер: 140760 Блоков: 280 Блок В/В: 4096 обычный файл
Устройство: fd00h/64768d Инода: 33894006 Ссылки: 1
Доступ: (0755/-rwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root)
Контекст: system_u:object_r:bin_t:s0
Доступ: 2023-10-29 10:10:37.199000000 +0800
Модифицирован: 2023-01-06 19:42:38.000000000 +0800
Изменён: 2023-09-28 12:38:12.337575533 +0800
Создан: 2023-09-28 12:38:12.333575533 +0800
Task:
Администрирование локальных, виртуальных и облачных серверов. Cоздать список контрольных сумм для популярных файлов, которые обычно могут изменяться при взломе системы
Decision:
root@kvmubuntu:~# md5sum /bin/ls >> sums.txt
root@kvmubuntu:~# cat sums.txt
07c62424e4c26afc0d7e393bab60546c /bin/ls
Source:
# https://www.youtube.com/playlist?list=PLtSGboPf3g50Aejrp6KjQsqqjxvAO4aKw
# https://tokmakov.msk.ru/blog/item/477
# https://linux-notes.org/fil-tratsiya-mac-ispol-zuya-iptables-v-linux/?ysclid=lo0z3u2sro842609893
# https://ru.linux-console.net/?p=1297&ysclid=lo0tx5owhk496498608
# https://itsecforu.ru/2022/01/14/%F0%9F%90%89-%D0%BD%D0%B0%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA%D0%B0-http-%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80%D0%B0-kali-linux/?ysclid=lo4exvw84m943299837
# https://hackware.ru/?p=15739
# https://uzverss.livejournal.com/109496.html?ysclid=lo9hqkxw2s612202120
# https://habr.com/ru/companies/alexhost/articles/531170/
# https://drive.google.com/drive/folders/1SUpqELdGy0O2zEDbmfnx35zViexy5xZL 
# https://habr.com/sandbox/29825/
# https://kamaok.org.ua/?p=813
# https://habr.com/company/first/blog/243487/
# https://habr.com/sandbox/29825/
Task:
Администрирование локальных, виртуальных и облачных серверов. Настройка брандмауэра.
Decision:
root@kvmubuntu:~# vim /etc/ufw/sysctl.conf
root@kvmubuntu:~# cat /etc/ufw/sysctl.conf | grep ip_forward=1
...
#net/ipv4/ip_forward=1
net/ipv4/ip_forward=1
root@kvmubuntu:~# vim /etc/ufw/before.rules
root@kvmubuntu:~# cat /etc/ufw/before.rules
...
*nat
:PREROUTING ACCEPT [0:0]
-A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8033
COMMIT
root@kvmubuntu:~# ufw enable
root@kvmubuntu:~# ufw allow 8033/tcp
Rule added
Rule added (v6)
root@kvmubuntu:~# systemctl restart ufw
root@kvmubuntu:~# ufw status numbered
...
[ 1] 8033 ALLOW IN Anywhere
[ 2] 2233/tcp ALLOW IN tipubuntu.1
[ 3] 2233/tcp ALLOW IN tipubuntu
[ 4] 2233 ALLOW IN Anywhere
[ 5] 2233 (v6) ALLOW IN Anywhere (v6)
root@kvmubuntu:~# ufw delete 3
root@kvmubuntu:~# ufw delete 2
root@kvmubuntu:~# systemctl restart ufw
root@kvmubuntu:~# vim firewall.sh
root@kvmubuntu:~# cat firewall.sh
#!/bin/bash
IPT="/sbin/iptables"
# Очищаем правила и удаляем цепочки.
$IPT -F
$IPT -X
# По умолчанию доступ запрещен.
$IPT -P INPUT DROP
$IPT -P FORWARD DROP
$IPT -P OUTPUT DROP
# Список разрешенных TCP и UDP портов.
TCP_PORTS="2233,8033"
# Разрешаем пакеты для интерфейса обратной петли.
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A OUTPUT -o lo -j ACCEPT
# Разрешаем пакеты для установленных соединений.
$IPT -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Разрешаем исходящие соединения.
$IPT -A OUTPUT -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
# Разрешаем доступ к портам, описанным в переменных TCP_PORTS.
$IPT -A INPUT -p tcp -m multiport --dport $TCP_PORTS -j ACCEPT
# Разрешаем исходящий ping.
$IPT -A INPUT -p icmp -m icmp --icmp-type echo-reply -j ACCEPT
root@kvmubuntu:~# ./firewall.sh
root@kvmubuntu:~# iptables -L
Chain INPUT (policy DROP)
target prot opt source destination
ACCEPT all -- anywhere anywhere
ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED
ACCEPT tcp -- anywhere anywhere multiport dports 2233,8033
ACCEPT icmp -- anywhere anywhere icmp echo-reply
Chain FORWARD (policy DROP)
target prot opt source destination
Chain OUTPUT (policy DROP)
target prot opt source destination
ACCEPT all -- anywhere anywhere
ACCEPT all -- anywhere anywhere state NEW,RELATED,ESTABLISHED
root@kvmubuntu:~# /sbin/iptables -A INPUT -p tcp --dport 5432 -j ACCEPT
root@kvmubuntu:~# iptables -t nat -A PREROUTING -i enp1s0 -p tcp --dport 80 -m conntrack --ctstate NEW -j DNAT --to tipubuntu:8033
root@kvmubuntu:~# iptables -t nat -A PREROUTING -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
root@kvmubuntu:~# iptables -A POSTROUTING -t nat -j MASQUERADE -o enp1s0
root@kvmubuntu:~# iptables-save > /etc/iptables.rules
root@kvmubuntu:~# /sbin/iptables-save
root@kvmubuntu:~# reboot
root@kvmubuntu:~# iptables-restore < /etc/iptables.rules
root@kvmubuntu:~# apt install iptables-persistent
root@kvmubuntu:~# netfilter-persistent save
Source:
# https://serverspace.ru/support/help/osnovnye-komandy-ufw/?utm_source=yandex.ru&utm_medium=organic&utm_campaign=yandex.ru&utm_referrer=yandex.ru - Удалить правило брандмауэра.
# https://serverfault.com/questions/411538/configure-ufw-to-redirect-http-traffic-to-another-ip - Configure ufw to redirect http traffic to another IP.
# https://habr.com/ru/articles/747186/ - Вывод хоста в интернет.
# https://www.dmosk.ru/instruktions.php?object=iptables-settings - Сохранение правил (permanent).
Task:
Администрирование веб-сервера Lamp. Установка Apache2.
Decision:
root@kvmubuntu:~# apt install apache2
root@kvmubuntu:~# ufw app list
Available applications:
Apache
Apache Full
Apache Secure
OpenSSH
root@kvmubuntu:~# ufw allow 80
root@kvmubuntu:~# ufw status
Status: active
To       Action From
...
80       ALLOW Anywhere
80 (v6)     ALLOW Anywhere (v6)
tuser@kvmubuntu:~$ google-chrome http://tipubuntu:80
Task:
Администрирование баз данных. Установка и настройка Mysql.
Decision:
root@kvmubuntu:~# apt install mysql-server
root@kvmubuntu:~# mysql
mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'tpassword';
mysql> exit
root@kvmubuntu:~# mysql_secure_installation
...
Press y|Y for Yes, any other key for No: y
Please enter 0 = LOW, 1 = MEDIUM and 2 = STRONG: 1
Change the password for root ? ((Press y|Y for Yes, any other key for No) : n
Remove anonymous users? (Press y|Y for Yes, any other key for No) : y
Disallow root login remotely? (Press y|Y for Yes, any other key for No) : n
Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y
Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y
root@kvmubuntu:~# mysql -u root -p
mysql> SELECT user,authentication_string,plugin,host FROM mysql.user;
mysql> rename user 'root'@'localhost' to 'tuser'@'localhost';
mysql> create database tbase;
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| tbase |
...
+--------------------+
mysql> exit
Task:
Администрирование веб-сервера Lamp. Настройка Lamp.
Decision:
root@kvmubuntu:~# apt install php libapache2-mod-php php-mysql
root@kvmubuntu:~# php -v
PHP 8.1.2-1ubuntu2.18 (cli) (built: Jun 14 2024 15:52:55) (NTS)
...
root@kvmubuntu:~# vim /etc/php/8.1/apache2/php.ini
root@kvmubuntu:~# cat /etc/php/8.1/apache2/php.ini | grep upload_max_filesize
...
upload_max_filesize = 32M
post_max_size = 48M
memory_limit = 256M
max_execution_time = 600
max_input_vars = 3000
max_input_time = 1000
root@kvmubuntu:~# service apache2 restart
root@kvmubuntu:~# mkdir /var/www/dato138it
root@kvmubuntu:~# chown -R $USER:$USER /var/www/dato138it
root@kvmubuntu:~# vim /etc/apache2/sites-available/dato138it.conf
root@kvmubuntu:~# cat /etc/apache2/sites-available/dato138it.conf
<VirtualHost *:80>
ServerName dato138it
ServerAlias www.dato138it
ServerAdmin tmail138@mail.ru
DocumentRoot /var/www/dato138it
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
root@kvmubuntu:~# a2ensite dato138it
root@kvmubuntu:~# a2dissite 000-default
root@kvmubuntu:~# apache2ctl configtest
root@kvmubuntu:~# systemctl reload apache2
root@kvmubuntu:~# vim /var/www/dato138it/index.html
root@kvmubuntu:~# cat /var/www/dato138it/index.html
<html>
<head>
<title>dato138it website</title>
</head>
<body>
<h1>Hello World!</h1>
<p>This is the landing page of <strong>dato138it</strong>.</p>
</body>
</html>
root@kvmubuntu:~# google-chrome http://tipubuntu:80
root@kvmubuntu:~# cat /etc/apache2/mods-enabled/dir.conf
<IfModule mod_dir.c>
DirectoryIndex index.html index.cgi index.pl index.php index.xhtml index.htm
</IfModule>
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
root@kvmubuntu:~# systemctl reload apache2
root@kvmubuntu:~# vim /var/www/dato138it/info.php
root@kvmubuntu:~# cat /var/www/dato138it/info.php
<?php
phpinfo();
root@kvmubuntu:~# google-chrome http://tipubuntu:80/info.php
Task:
Разработка базы данных. Разработать схему БД.
Decision:

Task:
Разработка базы данных. Создание таблиц.
Decision:
mysql> create table tbase.ttable1
(ttable1_id INT PRIMARY KEY AUTO_INCREMENT,
content VARCHAR(255));
CREATE TABLE tbase.ttable1
(ttable1_id INT PRIMARY KEY AUTO_INCREMENT,
column1 VARCHAR(255),
column2 VARCHAR(255),
column3 VARCHAR(255),
column4 VARCHAR(255),
column5 Date,
column6 Date);
mysql> INSERT INTO tbase.ttable1
(column1, column2)
VALUES
("text1","text2"),
("text3","text4"),
("text5","text6"),
("text7","text8");
mysql> select * from tbase.ttable1;
+------------+---------+---------+---------+---------+---------+---------+
| ttable1_id | column1 | column2 | column3 | column4 | column5 | column6 |
+------------+---------+---------+---------+---------+---------+---------+
| 1 | text1 | text2 | NULL | NULL | NULL | NULL |
| 2 | text3 | text4 | NULL | NULL | NULL | NULL |
| 3 | text5 | text6 | NULL | NULL | NULL | NULL |
| 4 | text7 | text8 | NULL | NULL | NULL | NULL |
+------------+---------+---------+---------+---------+---------+---------+
4 rows in set (0.00 sec)
mysql> CREATE TABLE tbase.ttable2
(ttable2_id INT PRIMARY KEY AUTO_INCREMENT,
columnId INT,
column1 VARCHAR(500),
FOREIGN KEY (columnId) REFERENCES tbase.ttable1 (ttable1_id));
mysql> INSERT INTO tbase.ttable2
(columnId, column1)
VALUES
(1, "text9"),
(1, "text10"),
(2, "text11"),
(3, "text12"),
(4, "text13");
mysql> select * from tbase.ttable2;
+------------+----------+---------+
| ttable2_id | columnId | column1 |
+------------+----------+---------+
| 1 | 1 | text9 |
| 2 | 1 | text10 |
| 3 | 2 | text11 |
| 4 | 3 | text12 |
| 5 | 4 | text13 |
+------------+----------+---------+
5 rows in set (0.00 sec)
Task:
Написание Sql запросов. Выборка данных из двух таблиц.
Decision:
mysql> select * from tbase.ttable2
inner join tbase.ttable1
on ttable1.ttable1_id = ttable2.columnId;
+------------+----------+---------+------------+---------+---------+---------+---------+---------+---------+
| ttable2_id | columnId | column1 | ttable1_id | column1 | column2 | column3 | column4 | column5 | column6 |
+------------+----------+---------+------------+---------+---------+---------+---------+---------+---------+
| 1 | 1 | text9 | 1 | text1 | text2 | NULL | NULL | NULL | NULL |
| 2 | 1 | text10 | 1 | text1 | text2 | NULL | NULL | NULL | NULL |
| 3 | 2 | text11 | 2 | text3 | text4 | NULL | NULL | NULL | NULL |
| 4 | 3 | text12 | 3 | text5 | text6 | NULL | NULL | NULL | NULL |
| 5 | 4 | text13 | 4 | text7 | text8 | NULL | NULL | NULL | NULL |
+------------+----------+---------+------------+---------+---------+---------+---------+---------+---------+
5 rows in set (0.00 sec)
mysql> exit
Source:
# https://metanit.com/sql/mysql/2.5.php
# https://metanit.com/sql/mysql/5.2.php
Task:
Администрирование базы данных. Добавление учетной записи к базе данных.
Decision:
mysql> CREATE USER 'tuser'@'%' IDENTIFIED BY 'tpassword';
mysql> GRANT ALL ON tbase.* TO 'tuser'@'%';
mysql> exit
tuser@kvmubuntu:~$ mysql -u tuser -p
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| performance_schema |
| tbase |
+--------------------+
3 rows in set (0.07 sec)
Task:
Администрирование базы данных. Бэкап базы.
Decision:
tuser@kvmubuntu:~$ mysql -V
mysql Ver 8.0.39-0ubuntu0.22.04.1 for Linux on x86_64 ((Ubuntu))
tuser@kvmubuntu:~$ mysql -u tuser -p
mysql> SELECT User, Host FROM mysql.user;
+------------------+-----------+
| User | Host |
+------------------+-----------+
| root | localhost |
| tuser | localhost |
+------------------+-----------+
6 rows in set (0.43 sec)
mysql> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| tbase |
+--------------------+
6 rows in set (0.80 sec)
mysql> exit
root@kvmubuntu:~# mysqldump -u tuser -p --opt tbase > datamysql.sql
root@kvmubuntu:~# ls datamysql.sql
datamysql.sql
Task:
Администрирование базы данных. Перенос базы.
Decision:
root@Windows-Asus:/home/dato# scp -r datamysql.sql tuser@tipubuntu:/var/www/dato138it/
Task:
Администрирование базы данных. Восстановление базы.
Decision:
tuser@kvmubuntu:~$ mysql -V
mysql Ver 8.0.34-0ubuntu0.22.04.1 for Linux on x86_64 ((Ubuntu))
tuser@kvmubuntu:~$ mysql -u tuser -p
tuser@kvmubuntu:~$ mysql -u tuser -p tbase < datamysql.sql
tuser@kvmubuntu:~$ mysql -u tuser -p
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| tbase |
| information_schema |
| performance_schema |
+--------------------+
mysql> USE tbase;
Source:
# https://www.digitalocean.com/community/tutorials/how-to-install-linux-apache-mysql-php-lamp-stack-on-ubuntu-22-04
# https://losst.pro/ustanovka-chrome-v-ubuntu-18-04?ysclid=lmdflkvc3v463974954
# https://qna.habr.com/q/439469?ysclid=lmdgkb49q827401606
# https://steptuser.org/course/63054/syllabus
# https://www.digitalocean.com/community/tutorials/how-to-install-and-secure-phpmyadmin-on-ubuntu-20-04
# https://www.tutsmake.com/how-to-install-lamp-apache-mysql-php-in-ubuntu-22-04/
# https://www.php.net/manual/ru/faq.html.php
# https://www.8host.com/blog/kak-rabotayut-stroki-v-php/
# https://www.youtube.com/watch?v=FxwPQkP3OGY&t=611s
# https://timeweb.com/ru/community/articles/kak-ustanovit-stek-lamp-na-ubuntu-20-04
# https://wiki.merionet.ru/articles/perenos-bazy-dannyx-mysql-so-starogo-na-novyj-server
Task:
Администрирование веб-сервера Lamp. Настройка Php.
Decision:
root@kvmubuntu:~# vim /var/www/dato138it/index.php
root@kvmubuntu:~# cat /var/www/dato138it/index.php
<?php
$user = "tuser";
$password = "tpassword";
$database = "tbase";
$table1 = "ttable1";
$table2 = "ttable2";
try {
$db = new PDO("mysql:host=localhost;dbname=$database", $user, $password);
$query = $db->query("
select * from $database.$table2
inner join $database.$table1
on $table1.experience_id=$table2.experienceId;
");
foreach($query as $row) {
echo '
<li><strong>
' . $row['column1'] . '
-
' . $row['column2'] . '
:</strong>
' . $row['column3'] . '
;
' . $row['column4'] . '
;
' . $row['column5'] . '
;
' . $row['column6'] . '
</li>
';
}
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
root@kvmubuntu:~# google-chrome http://tipubuntu/index.php
Task:
Администрирование веб-сервера Lamp. Настройка Phpmyadmin.
Decision:
root@kvmubuntu:~# apt install phpmyadmin php-mbstring php-zip php-gd php-json php-curl
...
Configure database for phpmyadmin with dbconfig-common? [yes/no] y
granting access to database phpmyadmin for phpmyadmin@localhost: failed.
error encountered creating user:
mysql said: ERROR 1819 (HY000) at line 1: Your password does not satisfy the current policy requirements
An error occurred while installing the database:
mysql said: ERROR 1819 (HY000) at line 1: Your password does not satisfy the current policy requirements . Your options are:
* abort - Causes the operation to fail; you will need to downgrade,
reinstall, reconfigure this package, or otherwise manually intervene
to continue using it. This will usually also impact your ability to
install other packages until the installation failure is resolved.
* retry - Prompts once more with all the configuration questions
...
1. abort 2. retry 3. retry (skip questions) 4. ignore
Next step for database installation: 1
...
Errors were encountered while processing:
phpmyadmin
needrestart is being skipped since dpkg has failed
E: Sub-process /usr/bin/dpkg returned an error code (1)
root@kvmubuntu:~# mysql -u tuser -p
mysql> UNINSTALL COMPONENT "file://component_validate_password";
mysql> exit
root@kvmubuntu:~# apt install phpmyadmin
root@kvmubuntu:~# apt install php8.1-fpm php8.1 libapache2-mod-php8.1 php8.1-common php8.1-mysql php8.1-xml php8.1-xmlrpc php8.1-imagick php8.1-cli php8.1-imap php8.1-opcache php8.1-soap php8.1-intl php8.1-bcmath unzip
root@kvmubuntu:~# mysql -u tuser -p
mysql> INSTALL COMPONENT "file://component_validate_password";
mysql> exit
root@kvmubuntu:~# phpenmod mbstring
root@kvmubuntu:~# systemctl restart apache2
root@kvmubuntu:~# cp /etc/phpmyadmin/apache.conf /etc/apache2/conf-available/phpmyadmin.conf
root@kvmubuntu:~# a2enconf phpmyadmin.conf
root@kvmubuntu:~# systemctl reload apache2
root@kvmubuntu:~# google-chrome http://tipubuntu/phpmyadmin
Source:
# https://bozza.ru/art-260.html
# https://www.digitalocean.com/community/tutorials/how-to-install-linux-apache-mysql-php-lamp-stack-on-ubuntu-22-04
# https://losst.pro/ustanovka-chrome-v-ubuntu-18-04?ysclid=lmdflkvc3v463974954
# https://qna.habr.com/q/439469?ysclid=lmdgkb49q827401606
# https://steptuser.org/course/63054/syllabus
# https://metanit.com/sql/mysql/2.5.php
# https://metanit.com/sql/mysql/5.2.php
# https://www.digitalocean.com/community/tutorials/how-to-install-and-secure-phpmyadmin-on-ubuntu-20-04
# https://serverspace.ru/support/help/osnovnye-komandy-ufw/
# https://www.tutsmake.com/how-to-install-lamp-apache-mysql-php-in-ubuntu-22-04/
# https://www.php.net/manual/ru/faq.html.php
# https://www.8host.com/blog/kak-rabotayut-stroki-v-php/
# https://www.youtube.com/watch?v=FxwPQkP3OGY&t=611s
# https://timeweb.com/ru/community/articles/kak-ustanovit-stek-lamp-na-ubuntu-20-04
# https://wiki.merionet.ru/articles/perenos-bazy-dannyx-mysql-so-starogo-na-novyj-server
Task:
Администрирование Веб-сервера Lamp. Изменить порт Apache.
Decision:
root@kvmubuntu:~# semanage port -l | grep -w http_port_t
http_port_t tcp 80, 443, 488, 8008, 8009, 8443, 8448
root@kvmubuntu:~# vim /etc/apache2/sites-enabled/dato138it.conf
root@kvmubuntu:~# cat /etc/apache2/sites-enabled/dato138it.conf
<VirtualHost *:8033>
...
root@kvmubuntu:~# vim /etc/apache2/ports.conf 
root@kvmubuntu:~# cat /etc/apache2/ports.conf 
...
Listen 8033
root@kvmubuntu:~# systemctl restart apache2
root@kvmubuntu:~# netstat -tlpn | grep apache
tcp6 0 0 :::8033 :::* LISTEN 2452/apache2 
root@kvmubuntu:~# semanage port -a -t http_port_t -p tcp 8033
root@kvmubuntu:~# semanage port -l | grep -w http_port_t
http_port_t tcp 8033, 80, 443, 488, 8008, 8009, 8443, 8448
root@kvmubuntu:~# ufw allow 8033
root@kvmubuntu:~# systemctl restart apache2
root@kvmubuntu:~# google-chrome http://tipubuntu:8033/
root@kvmubuntu:~# a2enconf phpmyadmin.conf
root@kvmubuntu:~# systemctl reload apache2
root@kvmubuntu:~# apt-get install php8.1-mbstring
root@kvmubuntu:~# cat /etc/php/8.1/apache2/php.ini | grep extension=
...
;extension=curl
;extension=ffi
...
root@kvmubuntu:~# vim /etc/php/8.1/apache2/php.ini
...
;extension=curl
extension=ctype
;extension=ffi
...
root@kvmubuntu:~# cat /etc/php/8.1/apache2/php.ini | grep extension=
root@kvmubuntu:~# service apache2 restart
root@kvmubuntu:~# google-chrome http://tipubuntu:8033/phpmyadmin/
Source:
# https://losst.pro/kak-izmenit-port-apache?ysclid=lwgcvc9brc641723993 - Как изменить порт Apache.
# https://linux-notes.org/nastrojka-selinux-dlya-apache-nginx-v-unix-linux/?ysclid=lwgc6svixb429450995 - Настройка SELinux для Apache/Nginx в Unix/Linux.
Task:
Администрирование Веб-сервера Lamp. How to Install SELinux to Harden Apache Webserver.
Decision:
root@kvmubuntu:~# mkdir /var/www/dato138it/cache
root@kvmubuntu:~# mkdir /var/www/dato138it/logs
root@kvmubuntu:~# tree /var/www/dato138it/
/var/www/dato138it/
├── cache
├── css
│ └── style.css
├── index.php
├── js
│ ├── jquery.js
│ └── main.js
└── logs
root@kvmubuntu:~# cd /var/www/
root@kvmubuntu:~# setenforce 0
root@kvmubuntu:~# semanage fcontext -a -t httpd_sys_content_t "/var/www/dato138it(/.*)?"
root@kvmubuntu:~# semanage fcontext -a -t httpd_log_t "/var/www/dato138it/logs(/.*)?"
root@kvmubuntu:~# semanage fcontext -a -t httpd_cache_t "/var/www/dato138it/cache(/.*)?"
root@kvmubuntu:~# semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/dato138it/index.php"
root@kvmubuntu:~# restorecon -Rv /var/www/dato138it
Relabeled /var/www/dato138it/index.php from system_u:object_r:httpd_sys_content_t:s0 to system_u:object_r:httpd_sys_rw_content_t:s0
Relabeled /var/www/dato138it/cache from unconfined_u:object_r:httpd_sys_content_t:s0 to unconfined_u:object_r:httpd_cache_t:s0
Relabeled /var/www/dato138it/logs from unconfined_u:object_r:httpd_sys_content_t:s0 to unconfined_u:object_r:httpd_log_t:s0
root@kvmubuntu:~# ls -lZ /var/www/dato138it
total 24
drwxr-xr-x. 2 root root unconfined_u:object_r:httpd_cache_t:s0 4096 may 21 07:33 cache
drwxrwxr-x. 2 tuser tuser system_u:object_r:httpd_sys_content_t:s0 4096 mar 9 07:10 css
-rw-rw-r--. 1 tuser tuser system_u:object_r:httpd_sys_rw_content_t:s0 4180 abr 9 14:44 index.php
drwxrwxr-x. 2 tuser tuser system_u:object_r:httpd_sys_content_t:s0 4096 mar 9 07:10 js
drwxr-xr-x. 2 root root unconfined_u:object_r:httpd_log_t:s0 4096 may 21 07:33 logs
root@kvmubuntu:~# semanage fcontext -l | grep '/var/www/dato138it'
/var/www/dato138it(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 
/var/www/dato138it/cache(/.*)? all files system_u:object_r:httpd_cache_t:s0 
/var/www/dato138it/index.php all files system_u:object_r:httpd_sys_rw_content_t:s0 
/var/www/dato138it/logs(/.*)? all files system_u:object_r:httpd_log_t:s0
Source:
# https://www.ubuntumint.com/selinux-harden-apache-webserver/ - How to Install SELinux to Harden Apache Webserver.
Task:
Администрирование Веб-сервера Django. Настройка приложения Django.
Decision:
root@kvmubuntu:~# apt install python3.10-venv
tuser@kvmubuntu:~$ python3 -m venv djangoenv
tuser@kvmubuntu:~$ vim requirements.txt
tuser@kvmubuntu:~$ cat requirements.txt
Django==5.0.2
djangorestframework==3.14.0
django-ckeditor-5==0.2.12
psycopg2-binary==2.9.9
django-ckeditor==6.7.1
python-decouple==3.8
tuser@kvmubuntu:~$ source djangoenv/bin/activate
tuser@kvmubuntu:~$ pip install -r requirements.txt
tuser@kvmubuntu:~$ pip list
Package   Version
------------------- -------
asgiref   3.8.1
Django   5.0.2
django-ckeditor 6.7.1
django-ckeditor-5 0.2.12
django-js-asset 2.2.0
djangorestframework 3.14.0
pillow   10.4.0
pip     22.0.2
psycopg2-binary 2.9.9
pytz    2024.1
setuptools   59.6.0
sqlparse   0.5.1
typing_extensions 4.12.2
Task:
Администрирование базы данных. Запустить Sqlite3.
Decision:
root@kvmubuntu:~# apt install sqlite3
tuser@kvmubuntu:~$ sqlite3 db.sqlite3
sqlite> .tables
auth_group django_content_type 
auth_group_permissions django_migrations 
auth_permission django_session 
auth_user portfolio_category 
auth_user_groups portfolio_place 
auth_user_user_permissions portfolio_portfolio 
django_admin_log 
sqlite> select * from portfolio_place;
...
sqlite> .q
Source:
# https://www.guru99.com/ru/sqlite-database.html - SQLite СОЗДАТЬ базу данных.
Task:
Администрирование локальных, виртуальных и облачных серверов. Переименовать пользователя для корректного подключения с базой.
Decision:
root@kvmubuntu:~# usermod -l Tuser tuser
root@kvmubuntu:~# groupmod -n Tuser tuser
Source:
# https://itsecforu.ru/2020/04/29/%F0%9F%90%A7-%D0%BA%D0%B0%D0%BA-%D0%BF%D0%B5%D1%80%D0%B5%D0%B8%D0%BC%D0%B5%D0%BD%D0%BE%D0%B2%D0%B0%D1%82%D1%8C-%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8F-%D0%B2-linux/ - Изменить имя пользователя на Linux
Task:
Администрирование базы данных. Установка и настройка базы данных в PostgreSQL.
Decision:
root@kvmubuntu:~# apt install postgresql postgresql-contrib
root@kvmubuntu:~# usermod -aG postgres tuser
root@kvmubuntu:~# sudo -i -u postgres
postgres@kvmubuntu:~$ psql
postgres=# \q
postgres@kvmubuntu:~$ createuser --interactive
Enter name of role to add: tuser
Shall the new role be a superuser? (y/n) y
postgres@kvmubuntu:~$ createdb tbase
postgres@kvmubuntu:~$ exit
tuser@kvmubuntu:~$ psql -U tuser -d tbase
tbase=# \password
tbase=# GRANT ALL PRIVILEGES ON DATABASE tbase to tuser;
tbase=# GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "tuser";
tbase=# ALTER DATABASE tbase OWNER TO tuser;
tbase=# GRANT pg_read_all_settings TO tuser;
tbase=# \conninfo
You are connected to database "tbase" as user "tuser" via socket in "/var/run/postgresql" at port "5432".
tbase=# \l+
                 List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges | Size | Tablespace |    Description
-----------+----------+----------+-------------+-------------+-----------------------+---------+------------+--------------------------------------------
tbase | tuser | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =Tc/tuser   +| 8561 kB | pg_default |
   |   |   |   |   | tuser=CTc/tuser   |   |   |
...
tbase=# SHOW config_file;
...
/etc/postgresql/14/main/postgresql.conf
tbase=# \q
root@kvmubuntu:~# vim /etc/postgresql/14/main/postgresql.conf
root@kvmubuntu:~# cat /etc/postgresql/14/main/postgresql.conf | grep listen_addresses
listen_addresses = 'tipubuntu'   # what IP address(es) to listen on;
root@kvmubuntu:~# vim /etc/postgresql/14/main/pg_hba.conf
root@kvmubuntu:~# cat /etc/postgresql/14/main/pg_hba.conf
...
# "local" is for Unix domain socket connections only
host tbase tuser   tipubuntu/32 md5
local all   all         peer
root@kvmubuntu:~# systemctl restart postgresql
tuser@kvmubuntu:~$ psql -U tuser -d tbase -h tipubuntu
tbase=# \d
Did not find any relations.
tbase=# \q
Source:
# https://www.digitalocean.com/community/tutorials/how-to-install-postgresql-on-ubuntu-22-04-quickstart - How To Install PostgreSQL on Ubuntu 22.04 [Quickstart].
# https://uchet-jkh.ru/i/kak-izmenit-parol-k-baze-dannyx-postgresql/ - Измените пароль для выбранного пользователя.
# https://asvignesh.in/how-to-get-the-postgresql-conf-file-location/ - Grant Role to the non-default user.
Task:
Администрирование базы данных. Миграция БД с Sqlite3 на PostgreSQL.
Decision:
root@kvmubuntu:~# pip install --upgrade pip
root@kvmubuntu:~# pip install --upgrade setuptools wheel
root@kvmubuntu:~# apt-get install libpq-dev python3-dev
root@kvmubuntu:~# pip install psycopg2-binary==2.9.9
tuser@kvmubuntu:~$ python dato138it/manage.py dumpdata > datadump.json
tuser@kvmubuntu:~$ vim dato138it/settings.py
tuser@kvmubuntu:~$ cat dato138it/settings.py
...
DATABASES = {
'default': {
  #'ENGINE': 'django.db.backends.sqlite3',
  #'NAME': BASE_DIR / 'db.sqlite3',
  'ENGINE': 'django.db.backends.postgresql_psycopg2',
  'NAME': 'tbase',
  'USER': 'tuser',
  'PASSWORD': 'tpassword',
  'HOST': 'tipubuntu',
  'PORT': '5432',
}
}
...
tuser@kvmubuntu:~$ python dato138it/manage.py migrate --run-syncdb
...
django.core.exceptions.ImproperlyConfigured: 'django.db.backends.potgresql_psycopg2' isn't an available database backend or couldn't be imported. Check the above exception. To use one of the built-in backends, use 'django.db.backends.XXX', where XXX is one of:
'mysql', 'oracle', 'postgresql', 'sqlite3'
tuser@kvmubuntu:~$ vim dato138it/settings.py
tuser@kvmubuntu:~$ cat dato138it/settings.py
...
DATABASES = {
'default': {
...
'ENGINE': 'django.db.backends.postgresql',
...
}
}
...
tuser@kvmubuntu:~$ python dato138it/manage.py migrate --run-syncdb
tuser@kvmubuntu:~$ python dato138it/manage.py shell
>>> from django.contrib.contenttypes.models import ContentType
>>> ContentType.objects.all().delete()
>>> quit()
tuser@kvmubuntu:~$ python dato138it/manage.py loaddata datadump.json
tuser@kvmubuntu:~$ python dato138it/manage.py runserver
Source:
# https://www.youtube.com/watch?v=pQzKHNozHts - Миграция с Sqlite3 на PostgreSQL.
Task:
Администрирование базы данных. Миграция БД PostgreSQL с помощью дампа.
Decision:
tuser@kvmubuntu:~$ pg_dump -Fc -v --username=tuser --dbname=tbase -f datapsql.dump
root@aw:/# scp datapsql.dump tuser@tipubuntu:/home/tuser/
tuser@kvmubuntu:~$ pg_restore -v --no-owner --port=5432 --username=tuser --dbname=tbase datapsql.dump
tuser@kvmubuntu:~$ psql -U tuser -d tbase -h tipubuntu
tbase=# \d
Source:
# https://procloud.ru/blog/cases/perenos-bazy-dannykh-postgresql-s-pomoshchyu-dampa-i-ee-vosstanovlenie/ - Перенос базы данных PostgreSQL с помощью дампа и ее восстановление.
# https://losst.pro/kopirovanie-fajlov-scp - Копирование файлов scp.
Task:
Администрирование Веб-сервера Django. Применить изменения в проекте Django с момента бэкапа. Запуск проекта.
Decision:
tuser@kvmubuntu:~$ python dato138it/manage.py makemigrations
tuser@kvmubuntu:~$ python dato138it/manage.py migrate
tuser@kvmubuntu:~$ python dato138it/manage.py runserver tipubuntu:8000 &
tuser@kvmubuntu:~$ google-chrome http://tipubuntu:8000
Source:
# https://pocoz.gitbooks.io/django-v-primerah/content/sozdanie-i-primenenie-migracij.html - Создание и применение миграций.
Task:
Администрирование Веб-сервера React.js. Установить и настроить node.js сервер.
Decision:
root@kvmubuntu:~# apt install npm
root@kvmubuntu:~# npm cache clean -f 
root@kvmubuntu:~# npm install -g n
root@kvmubuntu:~# n latest
root@kvmubuntu:~# reboot
Task:
Администрирование Веб-сервера React.js. Добавить проект в node.js.
Decision:
tuser@kvmubuntu:~$ npx create-react-app frontend
tuser@kvmubuntu:~$ cd frontend
tuser@kvmubuntu:~$ npm install -D tailwindcss postcss autoprefixer
tuser@kvmubuntu:~$ npx tailwindcss init -p
Task:
Администрирование Веб-сервера React.js. Запуск Веб-сайта.
Decision:
tuser@kvmubuntu:~$ cd frontend
tuser@kvmubuntu:~$ python frontend/manage.py runserver tipubuntu:8000 &
tuser@kvmubuntu:~$ google-chrome http://tipubuntu:8000/ &
tuser@kvmubuntu:~$ cd frontend
tuser@kvmubuntu:~$ npm run start &
Source:
# https://www.youtube.com/playlist?list=PLPSM8rIid1a06M7kDOE6WMTXc9CpBskBg - DRF & React Portfolio Website.
Task:
Frontend-разработка Веб-сайта React.js. После редактирования блока в посте, блок стал смещаться за границы следующего блока.
Decision:
tuser@kvmubuntu:~$ cat frontend/App.js
...
<div className='md:h-screen pt-10' ref={homeRef}>
...
</div>
<div className='md:h-screen pt-16' ref={placeRef}>
...
</div>
...
tuser@kvmubuntu:~$ vim frontend/App.js
tuser@kvmubuntu:~$ cat frontend/App.js
...
<div className='md:h-full pt-10' ref={homeRef}>
...
</div>
<div className='md:h-full pt-16' ref={placeRef}>
...
</div>
...
Source:
# https://tailwindcss.com/docs/height - Height.
Task:
Разработка Веб-сайта Django. B проекте нужно сделать так, чтобы необязательно заполнялось определенное поле. В нашем случае это поле doc.
Decision:
tuser@kvmubuntu:~$ cat portfolio/models.py
...
doc=models.FileField(upload_to="uploads/%Y/%m/%d/", verbose_name="Файлы")
tuser@kvmubuntu:~$ vim portfolio/models.py
tuser@kvmubuntu:~$ cat portfolio/models.py
...
doc=models.FileField(upload_to="uploads/%Y/%m/%d/", verbose_name="Файлы", blank=True, null=True)
tuser@kvmubuntu:~$ python3 manage.py makemigrations
tuser@kvmubuntu:~$ python3 manage.py migrate
tuser@kvmubuntu:~$ python3 manage.py runserver
Source:
# https://ru.stackoverflow.com/questions/1059864/%D0%A1%D0%B4%D0%B5%D0%BB%D0%B0%D1%82%D1%8C-%D0%BD%D0%B5%D0%BE%D0%B1%D1%8F%D0%B7%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%BC-%D0%BF%D0%BE%D0%BB%D0%B5-arrayfield-%D0%B2-django-%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D0%B8 - Сделать необязательным поле ArrayField в Django модели.
# https://ru.stackoverflow.com/questions/758588/%D0%9A%D0%B0%D0%BA-%D0%B4%D0%BE%D0%B1%D0%B0%D0%B2%D0%B8%D1%82%D1%8C-%D0%BD%D0%BE%D0%B2%D0%BE%D0%B5-%D0%BF%D0%BE%D0%BB%D0%B5-%D0%B2-%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C-django - Как добавить новое поле в модель django.
Task:
Разработка Веб-сайта Django. Integrating CKEditor in Django Admin and Rendering HTML in a template.
Decision:
tuser@kvmubuntu:~$ pip install django-ckeditor==6.7.1
django-ckeditor-5==0.2.12
tuser@kvmubuntu:~$ vim dato138it/settings.py
tuser@kvmubuntu:~$ cat dato138it/settings.py
...
INSTALLED_APPS = [
...,
'ckeditor', 
'ckeditor_uploader',
]
...
MEDIA_URL = "/media/"
MEDIA_ROOT = BASE_DIR / "media/"
#ckeditor upload path
CKEDITOR_UPLOAD_PATH="uploads/"
CKEDITOR_CONFIGS = {
'default': {
# 'skin': 'moono',
# # 'skin': 'office2013',
# 'toolbar_Basic': [
# ['Source', '-', 'Bold', 'Italic']
# ],
'toolbar_Custom': [
{'name': 'document', 'items': ['Source', '-', 'Save', 'NewPage', 'Preview', 'Print', '-', 'Templates']},
{'name': 'clipboard', 'items': ['Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'Undo', 'Redo']},
{'name': 'editing', 'items': ['Find', 'Replace', '-', 'SelectAll']},
{'name': 'forms',
'items': ['Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton',
'HiddenField']},
'/',
{'name': 'basicstyles',
'items': ['Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat']},
{'name': 'paragraph',
'items': ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote', 'CreateDiv', '-',
'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-', 'BidiLtr', 'BidiRtl',
'Language']},
{'name': 'links', 'items': ['Link', 'Unlink', 'Anchor']},
{'name': 'insert',
'items': ['Image', 'Youtube','Flash', 'Table', 'HorizontalRule', 'Smiley', 'SpecialChar', 'PageBreak', 'Iframe']},
'/',
{'name': 'styles', 'items': ['Styles', 'Format', 'Font', 'FontSize']},
{'name': 'colors', 'items': ['TextColor', 'BGColor']},
{'name': 'tools', 'items': ['Maximize', 'ShowBlocks']},
{'name': 'about', 'items': ['CodeSnippet']},
{'name': 'about', 'items': ['About']},
'/', # put this to force next toolbar on new line
{'name': 'yourcustomtools', 'items': [
# put the name of your editor.ui.addButton here
'Preview',
'Maximize',
]},
],
'toolbar': 'Custom', # put selected toolbar config here
'toolbarGroups': [{ 'name': 'document', 'groups': [ 'mode', 'document', 'doctools' ] }],
'height': 400,
# 'width': '100%',
'filebrowserWindowHeight': 725,
'filebrowserWindowWidth': 940,
'toolbarCanCollapse': True,
'mathJaxLib': '//cdn.mathjax.org/mathjax/2.2-latest/MathJax.js?config=TeX-AMS_HTML',
'tabSpaces': 4,
'extraPlugins': ','.join([
'uploadimage', # the upload image feature
# your extra plugins here
'div',
'autolink',
'autoembed',
'embedsemantic',
'autogrow',
'devtools',
'widget',
'lineutils',
'clipboard',
'dialog',
'dialogui',
'elementspath',
'codesnippet',
]),
}
}
tuser@kvmubuntu:~$ vim dato138it/urls.py
tuser@kvmubuntu:~$ cat dato138it/urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
...
path('ckeditor/',include('ckeditor_uploader.urls')),
]+static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
$ vim portfolio/models.py
$ cat portfolio/models.py
from ckeditor_uploader.fields import RichTextUploadingField
...
class Portfolio(models.Model):
title = models.TextField(verbose_name="Достижение")
description = RichTextUploadingField(verbose_name="Статья")
image = models.ImageField(upload_to='uploads/%Y/%m/%d/', blank=True, null=True)
url = models.URLField(blank=True, null=True)
ordinal = models.IntegerField()
...
tuser@kvmubuntu:~$ python manage.py makemigrations
tuser@kvmubuntu:~$ python manage.py migrate
tuser@kvmubuntu:~$ python manage.py runserver
Source:
# https://www.codesnail.com/integrating-ckeditor-in-django-admin-and-rendering-html-in-a-template-django-blog-4/ - Integrating CKEditor in Django Admin and Rendering HTML in a template.
Task:
Разработка Веб-сайта Django. Как добавить страницу в Django.
Decision:
tuser@kvmubuntu:~$ vim dato138it/urls.py
tuser@kvmubuntu:~$ cat dato138it/urls.py
...
#from django.http import HttpResponse
#def show_contents(request):
# print('Кто-то зашёл на главную!')
# return HttpResponse('Привет!')
from portfolio import views
urlpatterns = [
...
path('contents/', views.show_contents),
]+static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
tuser@kvmubuntu:~$ vim portfolio/views.py
tuser@kvmubuntu:~$ cat portfolio/views.py
...
from django.http import HttpResponse
...
def show_contents(request):
print('Кто-то зашёл на главную!')
return HttpResponse('Привет!')
tuser@kvmubuntu:~$ python manage.py runserver tipubuntu:8000
tuser@kvmubuntu:~$ google-chrome http://tipubuntu:8000/contents/
tuser@kvmubuntu:~$ cp -r /var/www/tdb ../backend
tuser@kvmubuntu:~$ ls tdb/
css index.html js
tuser@kvmubuntu:~$ vim dato138it/settings.py
tuser@kvmubuntu:~$ cat dato138it/settings.py
...
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'tdb')],
...
},
]
...
tuser@kvmubuntu:~$ vim portfolio/views.py
tuser@kvmubuntu:~$ cat portfolio/views.py
...
from django.http import HttpResponse
from django.template import loader
...
def show_contents(request):
#print('Кто-то зашёл на главную!')
template = loader.get_template('index.html')
context = {}
rendered_page = template.render(context, request)
return HttpResponse(rendered_page)
Source:
# https://dvmn.org/encyclopedia/django/how-to-add-page/?ysclid=lul44qesp8431289715 - Как добавить страницу в Django.
# https://codeease.net/programming/python/NameError-name-os-is-not-defined-django#:~:text=NameError%3A%20name%20'os'%20is%20not,directory%20operations%2C%20and%20environment%20variables - NameError name os is not defined django.
Task:
Разработка Веб-сайта Django. Настройка и подключение статических файлов в Django.
Decision:
tuser@kvmubuntu:~$ mkdir static
tuser@kvmubuntu:~$ vim dato138it/settings.py
tuser@kvmubuntu:~$ cat dato138it/settings.py
...
import os
...
INSTALLED_APPS = [
...
'django.contrib.staticfiles',
...
]
TEMPLATES = [
{
...
'DIRS': [os.path.join(BASE_DIR, 'tdb')],
'APP_DIRS': True,
...
...
# https://docs.djangoproject.com/en/5.0/howto/static-files/
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),
]
...
tuser@kvmubuntu:~$ mv tdb/css static/
tuser@kvmubuntu:~$ mv tdb/js static/
tuser@kvmubuntu:~$ ls static/
css js
tuser@kvmubuntu:~$ vim tdb/index.html
tuser@kvmubuntu:~$ cat tdb/index.html
{% load static %}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0">
<link rel="stylesheet" href="{% static 'css/style.css' %}">
</head>
<body>
<!--SECTIONS CARDS-->
<section>
<div class="container">
{% if content.count > 0 %}
<div class="cards">
{% for portfolio in content %}
<div class="card__content" id="" style="text-align: left;"> 
<p class="card_hidden" onclick="card__hidden(this)">{{portfolio.progress}}</p>
<p>{{portfolio.description}}</p>
</div>
{% endfor %}
</div> 
{% endif %}
</div>
</section> 
<script src="{% static 'js/jquery.js' %}"></script>
<script src="{% static 'js/main.js' %}"></script>
</body>
</html>
tuser@kvmubuntu:~$ python manage.py runserver tipubuntu:8000
Source:
# https://pythonru.com/uroki/django-static?ysclid=lul6hmdpge797629443 - Настройка и подключение статических файлов в Django.
Task:
Разработка Веб-сайта Django. Настройка блоков с разделами.
Decision:
tuser@kvmubuntu:~$ vim portfolio/models.py 
tuser@kvmubuntu:~$ cat portfolio/models.py 
from django.db import models
...
class Place(models.Model):
...
class Portfolio(models.Model):
progress = models.TextField(verbose_name="Достижение")
description = RichTextUploadingField(verbose_name="Описание")
image = models.ImageField(upload_to='uploads/%Y/%m/%d/', blank=True, null=True)
url = models.URLField(blank=True, null=True)
class Category(models.Model):
...
tuser@kvmubuntu:~$ python manage.py makemigrations
...
Was portfolio.title renamed to portfolio.progress (a TextField)? [y/N] y
...
tuser@kvmubuntu:~$ python manage.py migrate
tuser@kvmubuntu:~$ vim portfolio/views.py
tuser@kvmubuntu:~$ cat portfolio/views.py
...
from .models import Place, Portfolio, Category
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseNotFound
from django.shortcuts import render
class UserViewSet(viewsets.ModelViewSet):
...
class PlaceViewSet(viewsets.ModelViewSet):
...
class PortfolioViewSet(viewsets.ModelViewSet):
...
class CategoryViewSet(viewsets.ModelViewSet):
...
def show_contents(request):
...
# получение данных из бд
def index(request):
content = Portfolio.objects.all()
return render(request, "index.html", {"content": content})
tuser@kvmubuntu:~$ vim tdb/index.html
tuser@kvmubuntu:~$ cat tdb/index.html
{% load static %}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0">
<link rel="stylesheet" href="{% static 'css/style.css' %}">
<title>dato138it</title>
</head>
<body>
<!--SECTIONS CARDS-->
<section>
<div class="container">
{% if content.count > 0 %}
<div class="cards">
{% for portfolio in content %}
<div class="card__content" id="" style="text-align: left;"> 
{{portfolio.progress|safe}}
<p class="card_hidden" onclick="card__hidden(this)">Show</p>
<div style="display:none;" style=&{head};>{{portfolio.description|safe}}</div>
</div>
{% endfor %}
</div> 
{% endif %}
</div>
</section> 
<!-- JS -->
<script src="{% static 'js/jquery.js' %}"></script>
<script src="{% static 'js/main.js' %}"></script>
</body>
</html>
tuser@kvmubuntu:~$ vim dato138it/urls.py
tuser@kvmubuntu:~$ cat dato138it/urls.py
...
from django.urls import path, include
from portfolio import views
urlpatterns = [
...
path("index/", views.index),
]+static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Source:
# https://metanit.com/python/django/5.4.php - CRUD.
# https://stackoverflow.com/questions/17880663/ckeditor-shows-me-html-code - CKEditor shows me html code.
Task:
Разработка Веб-сайта Django. Сделать страницу контентов основной страницей сайта.
Decision:
tuser@kvmubuntu:~$ vim /var/www/dato138it/dato138it/urls.py
tuser@kvmubuntu:~$ cat /var/www/dato138it/dato138it/urls.py
....
path('admin/', admin.site.urls),
path('api-auth/', include('rest_framework.urls')),
#path('', include('portfolio.urls')),
path("ckeditor5/", include('django_ckeditor_5.urls'), name="ck_editor_5_upload_file"),
#path('contents/', views.contents),
path('urls-rest/', include('portfolio.urls')),
path('', views.contents),
...
Task:
Разработка Веб-сайта Django. Как скрыть токены и пароли в python?
Decision:
tuser@kvmubuntu:~$ source /var/www/dato138it/djangoenv/bin/activate
tuser@kvmubuntu:~$ vim requirements.txt
tuser@kvmubuntu:~$ cat requirements.txt
...
python-decouple==3.8
python-dotenv==1.0.1
tuser@kvmubuntu:~$ pip install -r requirements.txt
tuser@kvmubuntu:~$ vim /var/www/dato138it/.env
tuser@kvmubuntu:~$ cat /var/www/dato138it/.env
DB_NAME = 'tbase'
DB_USER = 'tuser'
DB_PASSWD = 'tpassword'
SERVER_IP = 'tipubuntu'
DB_PORT = '5432'
DJANGO_KEY = 'tkey'
tuser@kvmubuntu:~$ vim /var/www/dato138it/dato138it/settings.py
tuser@kvmubuntu:~$ cat /var/www/dato138it/dato138it/settings.py
from pathlib import Path
import os
#from dotenv import load_dotenv
from decouple import config
...
SECRET_KEY = config('DJANGO_KEY')
...
ALLOWED_HOSTS = [config('SERVER_IP'), 'dato138it.ru']
...
DATABASES = {
'default': {
  'ENGINE': 'django.db.backends.postgresql',
  'NAME': config('DB_NAME'),
  'USER': config('DB_USER'),
  'PASSWORD': config('DB_PASSWD'),
  'HOST': config('SERVER_IP'),
  'PORT': config('DB_PORT'),
}
}
...
root@kvmubuntu:~# ls -la /var/www/dato138it/.env
-rw-r--r--. 1 tuser tuser 191 Aug 1 16:06 /var/www/dato138it/.env
root@kvmubuntu:~# chown root:root /var/www/dato138it/.env
root@kvmubuntu:~# chmod 604 /var/www/dato138it/.env
root@kvmubuntu:~# ls -la /var/www/dato138it/.env
-rw----r--. 1 root root 191 Aug 1 16:06 /var/www/dato138it/.env
Source:
# https://www.youtube.com/watch?v=OQ6cEG0ykVs&list=PLV0FNhq3XMOJ31X9eBWLIZJ4OVjBwb-KM&index=10 - PostgreSQL + Скрытие Токена в .env - Aiogram 3.
# https://dev.to/earthcomfy/django-how-to-keep-secrets-safe-with-python-dotenv-5811 - Django - How to keep secrets safe with python-dotenv.
# https://dontrepeatyourself.org/post/how-to-use-python-decouple-with-django/ - How to Use Python Decouple with Django.
# https://redos.red-soft.ru/base/arm/share/network-directories-connection-with-automount/ - Автоматическое монтирование ресурсов CIFS.
Task:
Администрирование Веб-сервера Django. Selinux + django.
Decision:
root@kvmubuntu:~# setenforce 0
root@kvmubuntu:~# semanage fcontext -a -t httpd_sys_script_exec_t /var/www/dato138it/djangoenv/lib/python3.10/site-packages/psycopg2/_psycopg.cpython-310-x86_64-linux-gnu.so
root@kvmubuntu:~# restorecon -vv /var/www/dato138it/djangoenv/lib/python3.10/site-packages/psycopg2/_psycopg.cpython-310-x86_64-linux-gnu.so
root@kvmubuntu:~# setsebool -P httpd_can_network_connect_db on
root@kvmubuntu:~# semanage fcontext -a -t httpd_sys_content_t /var/www/dato138it
root@kvmubuntu:~# restorecon -v -R /var/www/dato138it
root@kvmubuntu:~# ls -lZ /var/www/dato138it
total 108
drwxr-xr-x. 7 tuser tuser system_u:object_r:httpd_sys_content_t:s0 4096 abr 7 06:11 backend
-rw-rw-r--. 1 tuser tuser system_u:object_r:user_home_t:s0 46322 mar 9 07:27 datadump.json
-rw-rw-r--. 1 tuser tuser system_u:object_r:user_home_t:s0 45572 mar 10 04:15 datapsql.dump
drwxrwxr-x. 6 tuser tuser system_u:object_r:user_home_t:s0 4096 abr 2 13:42 frontend
-rw-rw-r--. 1 tuser tuser system_u:object_r:user_home_t:s0 129 abr 7 08:08 requirements.txt
root@kvmubuntu:~# semanage fcontext -l | grep '/var/www/dato138it'
/var/www/dato138it         all files   system_u:object_r:httpd_sys_content_t:s0
/var/www/dato138it/djangoenv/lib/python3.10/site-packages/psycopg2/_psycopg.cpython-310-x86_64-linux-gnu.so all files   system_u:object_r:httpd_sys_script_exec_t:s0
Source:
# https://czep.net/16/django-stuff.html - Deploying Django projects.
Task:
Администрирование Веб-сервера Django. как привязать домен timeweb к начальной странице проекта веб-сервера django если уже установлен Apache?
Decision:
root@kvmubuntu:~# apt install libapache2-mod-wsgi-py3
root@kvmubuntu:~# systemctl restart apache2
root@kvmubuntu:~# systemctl status apache2
root@kvmubuntu:~# cp -r /home/tuser/dato138it/* /var/www/dato138it/
root@kvmubuntu:~# cat /var/www/dato138it/dato138it/settings.py
...
from pathlib import Path
import os
...
ALLOWED_HOSTS = ['tipubuntu', 'dato138it.ru']
...
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.0/howto/static-files/
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),
]
STATIC_ROOT=os.path.join(BASE_DIR, 'static/') 
...
MEDIA_URL = "/media/"
MEDIA_ROOT = BASE_DIR / "media/"
#MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
...
root@kvmubuntu:~# cat /etc/apache2/sites-available/dato138it.conf
<VirtualHost *:80>
ServerName dato138it
ServerAlias www.dato138it
ServerAdmin webmaster@localhost
DocumentRoot /var/www/dato138it
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
root@kvmubuntu:~# vim /etc/apache2/sites-available/dato138it.conf
root@kvmubuntu:~# cat /etc/apache2/sites-available/dato138it.conf
<VirtualHost *:8033>
ServerAdmin tmail@mail.ru
ServerName dato138it.ru
ServerAlias www.dato138it.ru
DocumentRoot /var/www/dato138it
ErrorLog ${APACHE_LOG_DIR}/dato138it.ru_error.log
CustomLog ${APACHE_LOG_DIR}/dato138it.ru_access.log combined
Alias /static /var/www/dato138it/static
<Directory /var/www/dato138it/static>
  Require all granted
</Directory>
Alias /media /var/www/dato138it/media
<Directory /var/www/dato138it/media>
  Require all granted
</Directory>
<Directory /var/www/dato138it/dato138it>
  <Files wsgi.py>
  Require all granted
  </Files>
</Directory>
WSGIDaemonProcess dato138it python-path=/var/www/dato138it python-home=/var/www/dato138it/djangoenv
WSGIProcessGroup dato138it
WSGIScriptAlias / /var/www/dato138it/dato138it/wsgi.py
</VirtualHost>
root@kvmubuntu:~# cat /etc/apache2/sites-available/dato138it.conf | grep djangoenv
WSGIDaemonProcess dato138it python-path=/var/www/dato138it python-home=/var/www/dato138it/djangoenv
root@kvmubuntu:~# a2ensite dato138it.conf
root@kvmubuntu:~# apache2ctl configtest
root@kvmubuntu:~# systemctl restart apache2
root@kvmubuntu:~# systemctl reload apache2
tuser@kvmubuntu:~$ google-chrome http://tipubuntu:80
tuser@kvmubuntu:~$ vim /var/www/dato138it/dato138it/settings.py
tuser@kvmubuntu:~$ cat /var/www/dato138it/dato138it/settings.py
...
STATIC_URL = '/static/'
#STATICFILES_DIRS = [
# os.path.join(BASE_DIR, "static"),
#]
STATIC_ROOT=os.path.join(BASE_DIR, 'static/')
...
tuser@kvmubuntu:~$ python /var/www/dato138it/manage.py collectstatic
tuser@kvmubuntu:~$ google-chrome http://tipubuntu:80
Source:
# https://www.linuxtuto.com/how-to-install-django-with-apache-on-ubuntu-22-04/ - How to Install Django with Apache on Ubuntu 22.04.

2024-06-02 - None: Tele2, Иркутск. Должность: Инженер эксплуатации подсистемы базовых станций. Дополнительная информация: Обязанности - Обеспечивать эксплуатацию оборудования контроллеров и базовых станций стандартов 2G/3G/4G, Обеспечивать локальную поддержку работ по аварийному восстановлению работоспособности оборудования контроллеров, Поддерживать ввод в работу новых узлов контроллеров базовых станций, Предоставлять техническую поддержку региональным инженерам по эксплуатации базовых станций и транспортной сети, инженерам по эксплуатации коммутаторов по вопросам работы подсистемы базовых станций. Достижения: Разработал скрипт , который делает бэкап файлов конфигураций базовых станций.

Show

# Написание скриптов для бэкап файлов.
# Администрирование локальных, виртуальных и облачных серверов.
Task:
Написание скриптов для бэкап файлов. Написать скрипт, который копирует файлы с ftp://tipftp/Backups/tdir/MRBTS* в сетевую папку \\tdomain.ru\tdir каждую неделю ночью.
Decision:
PS C:\Users\tuser\Documents\scripts> vim mrbtsbackup.bat
PS C:\Users\tuser\Documents\scripts> cat mrbtsbackup.bat
rem xcopy C:\Users\tuser\Documents\scripts\new1\*.txt C:\Users\tuser\Documents\scripts\new2 /e
xcopy C:\Users\tuser\Documents\scripts\new1\test2.txt C:\Users\tuser\Documents\scripts\new2 /s
PS C:\Users\tuser\Documents\scripts> ls .\new1\
  Каталог: C:\Users\tuser\Documents\scripts\new1
Mode         LastWriteTime     Length Name
----         -------------     ------ ----
d-----    05.09.2024   14:21        test
d-----    05.09.2024   14:18        test2
PS C:\Users\tuser\Documents\scripts> ls .\new1\test\
  Каталог: C:\Users\tuser\Documents\scripts\new1\test
Mode         LastWriteTime     Length Name
----         -------------     ------ ----
d-----    05.09.2024   14:17        Новая папка
d-----    05.09.2024   14:18        Новая папка (2)
-a----    05.09.2024   14:00       3 test.txt
-a----    05.09.2024   14:00       3 test2.txt
Task:
Администрирование локальных, виртуальных и облачных серверов. Подключиться к ftp и скопировать файлы в сетевую папку.
Decision:
PS C:\Users\tuser\Documents\scripts> ftp
ftp> open tipftp
ftp> tuser
ftp> ls Backups/tdir
ftp> get /Backups/tdir/MRBTS2279.xml \\tdomain.ru\tdir\Test.txt
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for /Backups/tdir/MRBTS2279.xml (126410 bytes).
226 Transfer complete.
ftp: 126410 байт получено за 0.24 (сек) со скоростью 533.38 (КБ/сек).
Task:
Написание скриптов для бэкап файлов. Реализовать подключение и копирование файлов скриптом
Decision:
PS C:\Users\tuser\Documents\scripts> vim mrbtsbackup.bat
PS C:\Users\tuser\Documents\scripts> cat mrbtsbackup.bat
@Echo Off
:: ~Параметры соединения
Set $Host=tipftp
Set $User=tuser
Set $Pass=tpassword
:: ~Что и куда копируем
SET $SRC=/Backups/tdir/MRBTS2279.xml
SET $DST=\\tdomain.ru\tdir\Test2.txt
:: ~Временные файлы
Set $FFtp=%~dpn0.cfg
:: Готовим CFG-файл
Echo.%$User%>"%$FFtp%"
Echo.%$Pass%>>"%$FFtp%"
Echo get "%$SRC%" "%$DST%">>"%$FFtp%"
Echo bye>>"%$FFtp%"
:: Выполняем команду
FTP -s:"%$FFtp%" %$Host%
rem exit
pause
Task:
Написание скриптов для бэкап файлов. Написать команды, которые заархивируют скопированные файлы и удалят файлы. Добавить в скрипт команды
Decision:
C:\WINDOWS\system32> "C:\Program Files\7-Zip\7z.exe" a -tzip \\tdomain.ru\tdir\Test.zip \\tdomain.ru\tdir\*.txt
C:\WINDOWS\system32> del \\tdomain.ru\tdir\*.txt
PS C:\Users\tuser\Documents\scripts> vim mrbtsbackup.bat
PS C:\Users\tuser\Documents\scripts> cat mrbtsbackup.bat
@Echo Off
:: ~Параметры соединения
Set $Host=tipftp
Set $User=tuser
Set $Pass=tpassword
:: ~Что и куда копируем
SET $SRC=/Backups/tdir/MRBTS2279.xml
SET $DST=\\tdomain.ru\tdir\Test2.txt
:: Формат текущей даты
SET dd=%date:~0,2%
SET mm=%date:~3,2%
SET yyyy=%date:~6,4%
SET curdate=%dd%_%mm%_%yyyy%
:: ~Временные файлы
Set $FFtp=%~dpn0.cfg
:: Готовим CFG-файл
Echo.%$User%>"%$FFtp%"
Echo.%$Pass%>>"%$FFtp%"
Echo get "%$SRC%" "%$DST%">>"%$FFtp%"
Echo bye>>"%$FFtp%"
:: Выполняем команду
FTP -s:"%$FFtp%" %$Host%
:: Добавим в архив скопированные файлы
"C:\Program Files\7-Zip\7z.exe" a -tzip \\tdomain.ru\tdir\Test_%curdate%.zip \\tdomain.ru\tdir\*.txt
:: Удалим лишние файлы
del \\tdomain.ru\tdir\*.txt
rem exit
pause
Task:
Написание скриптов для бэкап файлов. Обработать все файлы с расширением .xml.
Decision:
PS C:\Users\tuser\Documents\scripts> vim mrbtsbackup.bat
PS C:\Users\tuser\Documents\scripts> cat mrbtsbackup.bat
@Echo Off
:: ~Параметры соединения
Set server=tipftp
Set user=tuser
Set pass=tpassword
:: ~Что и куда копируем
:: SET $SRC=/Backups/tdir/*.xml
SET src=/Backups/tdir
SET dst=\\tdomain.ru\tdir\
:: Формат текущей даты
SET dd=%date:~0,2%
SET mm=%date:~3,2%
SET yyyy=%date:~6,4%
SET curdate=%dd%_%mm%_%yyyy%
:: ~Временные файлы
::Set $FFtp=%~dpn0.cfg
:: Готовим CFG-файл
Echo open %server%>tempfile.txt
Echo %user%>>tempfile.txt
Echo %pass%>>tempfile.txt
Echo lcd %dst%>>tempfile.txt
Echo cd %src%>>tempfile.txt
:: Echo mget *.* | Y>>tempfile.txt
Echo bye>>tempfile.txt
:: Выполняем команду
FTP -s:tempfile.txt
:: Добавим в архив скопированные файлы
"C:\Program Files\7-Zip\7z.exe" a -tzip \\tdomain.ru\tdir\Test_%curdate%.zip \\tdomain.ru\tdir\*.xml
:: Удалим лишние файлы
del \\tdomain.ru\tdir\*.txt
rem exit
pause
Task:
Написание скриптов для бэкап файлов. Реализация бэкап файлов на языке PowerShell.
Decision:
PS C:\Users\tuser\Documents\scripts> Get-Date -Format "_MM_dd_yyyy_HH_mm"
_09_09_2024_09_23
PS C:\Users\tuser\Documents\scripts> vim mrbtsbackup.ps1
PS C:\Users\tuser\Documents\scripts> cat mrbtsbackup.ps1
# Переменные
$ftpServer = "ftp://tipftp/Backups/tdir/"
$ftpUser = "tuser"
$ftpPassword = "tpassword"
$localFolder = "\\tdomain.ru\tdir\"
$curdate = Get-Date -Format "_MM_dd_yyyy_HH_mm"
#Write-Output $curdate
# Создание объекта для загрузки
$webclient = New-Object System.Net.WebClient
$webclient.Credentials = New-Object System.Net.NetworkCredential($ftpUser, $ftpPassword)
# Получение списка файлов на FTP-сервере
$ftpRequest = [System.Net.FtpWebRequest]::Create($ftpServer)
$ftpRequest.Method = [System.Net.WebRequestMethods+Ftp]::ListDirectory
$ftpRequest.Credentials = $webclient.Credentials
$response = $ftpRequest.GetResponse()
$streamReader = New-Object System.IO.StreamReader($response.GetResponseStream())
# Чтение имен файлов
$files = @()
while($file = $streamReader.ReadLine()) {
  $files += $file
}
$streamReader.Close()
$response.Close()
#Write-Output $files
# Скачивание файлов
foreach ($file in $files) {
  $remoteFile = "$ftpServer/$file"
  $localFile = Join-Path $localFolder $file
  $webclient.DownloadFile($remoteFile, $localFile)
}
# Завершение работы
$webclient.Dispose()
$compress = @{
  Path = "\\tdomain.ru\tdir\*.xml"
  CompressionLevel = "Fastest"
  DestinationPath = "\\tdomain.ru\tdir\IRK$curdate.zip"
}
Compress-Archive @compress
Remove-Item \\tdomain.ru\tdir\*.xml
PS C:\Users\tuser\Documents\scripts\backups> powershell -file mrbtsbackup.ps1
PS C:\Users\tuser\Documents\scripts\backups> ls \\tdomain.ru\tdir\
Task:
Администрирование локальных, виртуальных и облачных серверов. Добавить раписание.
Decision:
- Планировщик задач - Создать задачу - Имя - Backup MTBTS - +Выполнить для всех пользователей - Триггеры - +Еженедельно - Начать - суббота - 23:00 - ок - действия - запуск программы - Программа или сценарий - powershell.exe - добавить аргументы
-file "C:\Users\tuser\Documents\scripts\backups\mrbtsbackup.ps1"
- ок
Source:
# https://comp-security.net/%D0%BA%D0%B0%D0%BA-%D1%81%D0%BA%D0%BE%D0%BF%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D1%82%D1%8C-%D1%84%D0%B0%D0%B9%D0%BB-%D0%BF%D0%B0%D0%BF%D0%BA%D1%83-%D0%B2-cmd/ - Как скопировать файл (папку) в командной строке Windows.
# https://pc.ru/articles/kak-dobavit-kommentarii-v-bat-fajl - Как добавить комментарии в bat-файл.
# https://learn.microsoft.com/ru-ru/powershell/module/microsoft.powershell.utility/get-date?view=powershell-7.4 - Get-Date.
# https://learn.microsoft.com/ru-ru/powershell/module/microsoft.powershell.management/remove-item?view=powershell-7.4 - Remove-Item.
# https://learn.microsoft.com/ru-ru/powershell/module/microsoft.powershell.utility/write-output?view=powershell-7.4 - Write-Output.
# https://docs.oracle.com/cd/E19120-01/open.solaris/819-1634/remotehowtoaccess-87541/index.html - How to Copy Files From a Remote System (ftp).
# http://forum.oszone.net/post-2962057.html - Powershell. Копировать файлы в новую dir, созданную с именем текущей даты.
# https://windowsnotes.ru/powershell-2/zapusk-powershell-skripta-po-raspisaniyu/ - Способ 1.
# https://stackoverflow.com/questions/18180060/how-to-zip-a-file-using-cmd-line - How to zip a file using cmd line?
# https://learn.microsoft.com/ru-ru/windows-server/administration/windows-commands/del - del.
# https://www.dmosk.ru/miniinstruktions.php?mini=7zip-cmd - Резервное копирование с помощью 7-Zip.
Task:
Написание скриптов для бэкап файлов. Знакомство с Python.
Decision:
[tuser@kvmredhat(enm11) scripts]$ hostnamectl
Static hostname: kvmredhat
     Icon name: computer-vm
     Chassis: vm
    Machine ID: tid1
     Boot ID: tid2
  Virtualization: kvm
Operating System: Red Hat Enterprise Linux Server 7.6 (Maipo)
   CPE OS Name: cpe:/o:redhat:enterprise_linux:7.6:GA:server
      Kernel: Linux 3.10.0-957.66.1.el7.x86_64
   Architecture: x86-64
[tuser@kvmredhat(enm11) scripts]$ python3 -V
-bash: python3: command not found
[tuser@kvmredhat(enm11) scripts]$ python -V
Python 2.7.5
PS P:\> cd c:\Users\tuser\Documents\py\
PS C:\Users\tuser\Documents\py> python -m venv tenv
PS C:\Users\tuser\Documents\py> ls
Mode         LastWriteTime     Length Name
----         -------------     ------ ----
d-----    09.09.2024   16:20        tenv
-a----    09.09.2024   15:59      264 tpy.py
PS C:\Users\tuser\Documents\py> .\tenv\Scripts\activate
pip install
(tenv) PS C:\Users\tuser\Documents\py> pip list
Package      Version
------------------ ---------
certifi      2024.8.30
charset-normalizer 3.3.2
idna       3.8
pip        21.2.3
requests     2.32.3
setuptools     57.4.0
urllib3      2.2.3
WARNING: You are using pip version 21.2.3; however, version 24.2 is available.
You should consider upgrading via the 'C:\Users\tuser\Documents\py\tenv\Scripts\python.exe -m pip install --upgrade pip' command.
(tenv) PS C:\Users\tuser\Documents\py> C:\Users\tuser\Documents\py\tenv\Scripts\python.exe -m pip install --upgrade pip --proxy http://t2rs-fgproxy.tdomain.ru:8080
(tenv) PS C:\Users\tuser\Documents\py> pip install requests --proxy http://t2rs-fgproxy.tdomain.ru:8080
Source:
# https://docs.python.org/3/library/venv.html - Creating virtual environments.
# https://realpython.com/python-coding-setup-windows/#installing-python-with-pyenv-for-windows - Installing Python With pyenv for Windows.
# https://wiki.merionet.ru/articles/kak-opredelit-versiyu-linux#:~:text=%D0%A1%D0%B0%D0%BC%D1%8B%D0%B9%20%D0%BF%D1%80%D0%BE%D1%81%D1%82%D0%BE%D0%B9%20%D1%81%D0%BF%D0%BE%D1%81%D0%BE%D0%B1%20%D0%BF%D1%80%D0%BE%D0%B2%D0%B5%D1%80%D0%B8%D1%82%D1%8C%20%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D1%8E,%D0%B2%D0%BC%D0%B5%D1%81%D1%82%D0%B5%20%D1%81%20%D0%BA%D0%BE%D0%BD%D0%BA%D1%80%D0%B5%D1%82%D0%BD%D0%BE%D0%B9%20%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B5%D0%B9%20%D1%8F%D0%B4%D1%80%D0%B0. - Как определить версию Linux?
Task:
Написание скриптов для бэкап файлов. Реализация бэкап файлов на языке Python.
Decision:
PS C:\Users\tuser\Documents\py> vim .\tpy.py
PS C:\Users\tuser\Documents\py> cat .\tpy.py
from ftplib import FTP
ftp = FTP("tipftp")
ftp.login(user="tuser", passwd="tpassword")
local_file = '/Users/tuser/Documents/py/test/testfile.txt'
#files = ftp.nlst('/Backups/tdir/*.xml')
files = ftp.nlst('/Backups/tdir/MRBTS881364.xml')
#print(files)
for file in files:
  print(file)
  file_list=[]
  file_list.append(file)
  file_list1=str(file_list)
  print(file_list1)
  with open(local_file, 'wb') as tempfile:
    #print("Работа с файлом testfile")
    #ftp.retrbinary('RETR' + file_list1, tempfile.write)
    ftp.retrbinary('retr ' + file, tempfile.write)
ftp.quit()

Source:
# https://sky.pro/media/rabota-s-fajlami-v-python-kak-poluchit-spisok-vseh-fajlov-v-direktorii/
# https://docs.python.org/3/library/ftplib.html
# https://sky.pro/media/kak-ispolzovat-python-dlya-raboty-s-ftp/
# https://pythonworld.ru/tipy-dannyx-v-python/spiski-list-funkcii-i-metody-spiskov.html
# https://dvmn.org/encyclopedia/python_intermediate/python_lists/
# https://metanit.com/python/tutorial/4.1.php
# https://lavrynenko.com/python-ftplib-skachat-fajl/