Добавить readme.md
This commit is contained in:
commit
52e3c9875c
1 file changed
+576
@@ -0,0 +1,576 @@
|
|||||||
|
# Документация проекта: Развертывание резервной конфигурации HAProxy по требованию
|
||||||
|
|
||||||
|
## 1. Архитектурное описание
|
||||||
|
|
||||||
|
Комплекс предназначен для контролируемого применения резервной конфигурации балансировщика **HAProxy** по клику оператора с рабочей станции Windows.
|
||||||
|
|
||||||
|
```
|
||||||
|
[ Рабочая станция Windows ]
|
||||||
|
|
|
||||||
|
(Ярлык на рабочем столе)
|
||||||
|
|
|
||||||
|
deployfile.exe (.NET 4.8)
|
||||||
|
|
|
||||||
|
| (1. SSH connection: ed25519)
|
||||||
|
| (2. Генерация status/change.me + status/sha256.hash)
|
||||||
|
v
|
||||||
|
[ Linux-сервер (HAProxy) ]
|
||||||
|
/var/lib/depfile/ (Домашний каталог depfile)
|
||||||
|
├── .ssh/authorized_keys
|
||||||
|
├── status/
|
||||||
|
│ ├── change.me
|
||||||
|
│ └── sha256.hash
|
||||||
|
└── deployment/
|
||||||
|
└── success.me
|
||||||
|
|
|
||||||
|
(cron: раз в минуту)
|
||||||
|
v
|
||||||
|
deploy_haproxy.sh (Bash)
|
||||||
|
|-- 1. Валидация SHA-256 суммы файла change.me
|
||||||
|
|-- 2. Валидация синтаксиса backup/haproxy.cfg (haproxy -c)
|
||||||
|
|-- 3. Подмена /etc/haproxy/haproxy.cfg
|
||||||
|
|-- 4. Перезапуск службы haproxy (systemctl restart)
|
||||||
|
|-- 5. Удаление каталога status/
|
||||||
|
`-- 6. Запись метки в deployment/success.me
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Принцип работы
|
||||||
|
|
||||||
|
1. **Windows-клиент (`deployfile.exe`):**
|
||||||
|
* Разработан на .NET Framework 4.8 без внешних библиотек.
|
||||||
|
* Вызывает встроенный клиент Windows OpenSSH (`ssh.exe`) с автоопределением путей (включая обход WOW64-редиректа `Sysnative` для 32-битных процессов) и автоматической установкой OpenSSH через PowerShell при его отсутствии.
|
||||||
|
* Генерирует случайный текстовый блок, подключается к серверу по SSH под пользователем `depfile` с использованием ED25519-ключа и записывает данные в `/var/lib/depfile/status/change.me`.
|
||||||
|
* На стороне сервера генерирует файл контрольной суммы `/var/lib/depfile/status/sha256.hash`.
|
||||||
|
|
||||||
|
|
||||||
|
2. **Серверный обработчик (`deploy_haproxy.sh`):**
|
||||||
|
* Выполняется по cron от имени `root`.
|
||||||
|
* Проверяет наличие файла `/var/lib/depfile/status/change.me`. Если файл отсутствует — завершает работу без нагрузки на систему.
|
||||||
|
* Валидирует целостность `change.me` через `sha256sum -c`.
|
||||||
|
* Выполняет проверку синтаксиса резервного файла (`haproxy -c -f /etc/haproxy/backup/haproxy.cfg`). При обнаружении ошибок применение отменяется.
|
||||||
|
* Копирует резервную конфигурацию в боевой файл `/etc/haproxy/haproxy.cfg`.
|
||||||
|
* Перезапускает службу `haproxy`.
|
||||||
|
* Удаляет временную директорию `/var/lib/depfile/status`.
|
||||||
|
* Фиксирует статус и метку времени в файле `/var/lib/depfile/deployment/success.me`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Настройка Linux-сервера
|
||||||
|
|
||||||
|
### 2.1. Создание сервисного пользователя и директорий
|
||||||
|
|
||||||
|
Подключитесь к серверу с правами `root` или через `sudo`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Создаем системного пользователя с домашним каталогом /var/lib/depfile
|
||||||
|
sudo useradd -m -d /var/lib/depfile -s /bin/bash -c "File deploment service" depfile
|
||||||
|
|
||||||
|
# 2. Выставляем права доступа на домашнюю директорию
|
||||||
|
sudo chown -R depfile:depfile /var/lib/depfile
|
||||||
|
sudo chmod 750 /var/lib/depfile
|
||||||
|
|
||||||
|
# 3. Создаем каталог резервных конфигураций HAProxy и копируем текущий рабочий конфиг
|
||||||
|
sudo mkdir -p /etc/haproxy/backup
|
||||||
|
sudo cp /etc/haproxy/haproxy.cfg /etc/haproxy/backup/haproxy.cfg
|
||||||
|
sudo chown -R root:root /etc/haproxy/backup
|
||||||
|
sudo chmod 750 /etc/haproxy/backup
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2. Подготовка каталога SSH-ключей
|
||||||
|
|
||||||
|
Так как домашний каталог пользователя расположен в `/var/lib/depfile`, файл доверенных ключей находится по пути `/var/lib/depfile/.ssh/authorized_keys`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo -u depfile mkdir -p /var/lib/depfile/.ssh
|
||||||
|
sudo -u depfile touch /var/lib/depfile/.ssh/authorized_keys
|
||||||
|
sudo chmod 700 /var/lib/depfile/.ssh
|
||||||
|
sudo chmod 600 /var/lib/depfile/.ssh/authorized_keys
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.3. Создание скрипта развертывания
|
||||||
|
|
||||||
|
Создайте файл `/usr/local/bin/deploy_haproxy.sh`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo nano /usr/local/bin/deploy_haproxy.sh
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Вставьте следующий код:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
# ================= КОНФИГУРАЦИЯ =================
|
||||||
|
BASE_DIR="/var/lib/depfile"
|
||||||
|
STATUS_DIR="${BASE_DIR}/status"
|
||||||
|
CHANGE_FILE="${STATUS_DIR}/change.me"
|
||||||
|
HASH_FILE="${STATUS_DIR}/sha256.hash"
|
||||||
|
|
||||||
|
DEPLOY_DIR="${BASE_DIR}/deployment"
|
||||||
|
SUCCESS_FILE="${DEPLOY_DIR}/success.me"
|
||||||
|
|
||||||
|
BACKUP_CFG="/etc/haproxy/backup/haproxy.cfg"
|
||||||
|
TARGET_CFG="/etc/haproxy/haproxy.cfg"
|
||||||
|
# ===============================================
|
||||||
|
|
||||||
|
log() {
|
||||||
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
|
||||||
|
}
|
||||||
|
|
||||||
|
err() {
|
||||||
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ОШИБКА] $*" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
# 1. Проверяем наличие триггер-файла change.me
|
||||||
|
if [ ! -f "${CHANGE_FILE}" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Обнаружен файл ${CHANGE_FILE}. Запуск процедуры развертывания..."
|
||||||
|
|
||||||
|
# 2. Проверяем наличие файла с хешем
|
||||||
|
if [ ! -f "${HASH_FILE}" ]; then
|
||||||
|
err "Файл хеша ${HASH_FILE} не найден. Отмена операции."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 3. Проверяем целостность файла change.me по sha256.hash
|
||||||
|
log "Проверка контрольной суммы SHA-256..."
|
||||||
|
if ! (cd "${STATUS_DIR}" && sha256sum -c --status "sha256.hash"); then
|
||||||
|
err "Несовпадение контрольной суммы файла ${CHANGE_FILE}!"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
log "Контрольная сумма успешно подтверждена."
|
||||||
|
|
||||||
|
# 4. Проверяем наличие файла резервной копии конфигурации
|
||||||
|
if [ ! -f "${BACKUP_CFG}" ]; then
|
||||||
|
err "Файл резервной копии не найден: ${BACKUP_CFG}"
|
||||||
|
exit 3
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 5. Валидация синтаксиса резервного конфига перед его применением
|
||||||
|
log "Валидация синтаксиса конфигурации из бэкапа..."
|
||||||
|
if ! haproxy -c -f "${BACKUP_CFG}" > /dev/null 2>&1; then
|
||||||
|
err "Резервная конфигурация содержит синтаксические ошибки. Отмена применения."
|
||||||
|
haproxy -c -f "${BACKUP_CFG}" || true
|
||||||
|
exit 4
|
||||||
|
fi
|
||||||
|
log "Синтаксис резервного конфига корректен."
|
||||||
|
|
||||||
|
# 6. Замена рабочей конфигурации
|
||||||
|
log "Копирование конфигурации в ${TARGET_CFG}..."
|
||||||
|
cp -f "${BACKUP_CFG}" "${TARGET_CFG}"
|
||||||
|
|
||||||
|
# Повторный контрольный тест целевого файла
|
||||||
|
if ! haproxy -c -f "${TARGET_CFG}" > /dev/null 2>&1; then
|
||||||
|
err "Критическая ошибка: целевой файл после копирования не прошел валидацию!"
|
||||||
|
exit 5
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 7. Перезапуск службы haproxy
|
||||||
|
log "Перезапуск службы haproxy..."
|
||||||
|
if ! systemctl restart haproxy; then
|
||||||
|
err "Не удалось перезапустить сервис haproxy!"
|
||||||
|
exit 6
|
||||||
|
fi
|
||||||
|
log "Сервис haproxy успешно перезапущен."
|
||||||
|
|
||||||
|
# 8. Очистка каталога status
|
||||||
|
log "Удаление директории ${STATUS_DIR}..."
|
||||||
|
rm -rf "${STATUS_DIR}"
|
||||||
|
|
||||||
|
# 9. Формирование каталога deployment и файла success.me
|
||||||
|
mkdir -p "${DEPLOY_DIR}"
|
||||||
|
chown depfile:depfile "${DEPLOY_DIR}"
|
||||||
|
CURRENT_DATETIME=$(date '+%Y-%m-%d %H:%M:%S')
|
||||||
|
|
||||||
|
# Перезаписываем файл актуальной датой и временем
|
||||||
|
echo "deploment success {${CURRENT_DATETIME}}" > "${SUCCESS_FILE}"
|
||||||
|
chown depfile:depfile "${SUCCESS_FILE}"
|
||||||
|
log "Зафиксирован статус в ${SUCCESS_FILE}."
|
||||||
|
|
||||||
|
log "Процесс успешно завершен."
|
||||||
|
exit 0
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Назначьте права на запуск:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo chmod +x /usr/local/bin/deploy_haproxy.sh
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.4. Настройка периодического запуска в cron
|
||||||
|
|
||||||
|
Откройте планировщик суперпользователя:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo crontab -e
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Добавьте задачу запуска раз в минуту:
|
||||||
|
|
||||||
|
```cron
|
||||||
|
* * * * * /usr/local/bin/deploy_haproxy.sh >> /var/log/deploy_haproxy.log 2>&1
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Настройка рабочей станции Windows
|
||||||
|
|
||||||
|
### 3.1. Генерация SSH-ключа
|
||||||
|
|
||||||
|
В командной строке (`cmd`) или PowerShell выполните:
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
ssh-keygen -t ed25519 -f "D:\sys\C-Sharp\deployfile\key\test_key.key" -N ""
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Создаются:
|
||||||
|
|
||||||
|
* `test_key.key` — закрытый ключ (хранится строго локально).
|
||||||
|
* `test_key.key.pub` — открытый ключ для передачи на сервер.
|
||||||
|
|
||||||
|
### 3.2. Добавление открытого ключа на сервер
|
||||||
|
|
||||||
|
Передайте содержимое открытого ключа в `authorized_keys` пользователя `depfile`:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
type "D:\sys\C-Sharp\deployfile\key\test_key.key.pub" | ssh depfile@10.228.48.110 "cat >> /var/lib/depfile/.ssh/authorized_keys"
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
*(При первом подключении введите пароль пользователя `depfile` на сервере).*
|
||||||
|
|
||||||
|
Проверьте беспарольный вход:
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
ssh -i "D:\sys\C-Sharp\deployfile\key\test_key.key" depfile@10.228.48.110 "whoami && pwd"
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
*Вывод должен вернуть:*
|
||||||
|
|
||||||
|
```text
|
||||||
|
depfile
|
||||||
|
/var/lib/depfile
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Клиентское приложение C# (.NET Framework 4.8)
|
||||||
|
|
||||||
|
### 4.1. Исходный код (`Program.cs`)
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace SshStatusUpdater
|
||||||
|
{
|
||||||
|
internal class Program
|
||||||
|
{
|
||||||
|
// ================= НАСТРОЙКИ ПОДКЛЮЧЕНИЯ =================
|
||||||
|
private const string RemoteUser = "depfile"; // Логин пользователя на сервере
|
||||||
|
private const string RemoteHost = "10.228.48.110"; // IP-адрес или доменное имя сервера
|
||||||
|
private const int RemotePort = 22; // Порт SSH-сервера
|
||||||
|
|
||||||
|
// Путь к приватному ключу по умолчанию (если не задан аргументом)
|
||||||
|
private const string DefaultKeyPath = @"D:\sys\C-Sharp\deployfile\key\test_key.key";
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
|
static int Main(string[] args)
|
||||||
|
{
|
||||||
|
// 1. Определение пути к ключу (аргумент командной строки либо константа по умолчанию)
|
||||||
|
string rawKeyPath = (args.Length > 0 && !string.IsNullOrWhiteSpace(args[0]))
|
||||||
|
? args[0].Trim('"')
|
||||||
|
: DefaultKeyPath;
|
||||||
|
|
||||||
|
string keyPath = Environment.ExpandEnvironmentVariables(rawKeyPath);
|
||||||
|
|
||||||
|
if (!File.Exists(keyPath))
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
|
Console.WriteLine($"Ошибка: Файл ключа не найден по указанному пути: {keyPath}");
|
||||||
|
Console.ResetColor();
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($"Используется ключ: {keyPath}");
|
||||||
|
|
||||||
|
// 2. Проверка доступности OpenSSH клиента (с возможностью автоустановки)
|
||||||
|
string sshExecutable = EnsureOpenSshAvailable();
|
||||||
|
if (string.IsNullOrEmpty(sshExecutable))
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
|
Console.WriteLine("\n[ОШИБКА] Клиент OpenSSH не найден в системе и не удалось выполнить его установку.");
|
||||||
|
Console.WriteLine("Для работы приложения необходимо установить компонент OpenSSH вручную.");
|
||||||
|
Console.WriteLine("Откройте PowerShell от имени Администратора и выполните:");
|
||||||
|
Console.WriteLine(" Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0");
|
||||||
|
Console.ResetColor();
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Формирование случайных данных и удаленной команды
|
||||||
|
string randomContent = GenerateRandomPayload(linesCount: 5, charsPerLine: 32);
|
||||||
|
|
||||||
|
// Так как домашний каталог /var/lib/depfile, команда выполняется относительно него
|
||||||
|
string remoteCommand = "mkdir -p status && cat > status/change.me && (cd status && sha256sum change.me > sha256.hash)";
|
||||||
|
|
||||||
|
string sshArgs = $"-i \"{keyPath}\" -p {RemotePort} -o BatchMode=yes -o StrictHostKeyChecking=accept-new {RemoteUser}@{RemoteHost} \"{remoteCommand}\"";
|
||||||
|
|
||||||
|
ProcessStartInfo psi = new ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = sshExecutable,
|
||||||
|
Arguments = sshArgs,
|
||||||
|
UseShellExecute = false,
|
||||||
|
RedirectStandardInput = true,
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardError = true,
|
||||||
|
CreateNoWindow = true
|
||||||
|
};
|
||||||
|
|
||||||
|
Console.WriteLine($"Подключение к {RemoteUser}@{RemoteHost}:{RemotePort}...");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (Process proc = new Process { StartInfo = psi })
|
||||||
|
{
|
||||||
|
proc.Start();
|
||||||
|
|
||||||
|
// Передаем сгенерированный текст в STDIN удаленного процесса ssh
|
||||||
|
using (StreamWriter sw = new StreamWriter(proc.StandardInput.BaseStream, new UTF8Encoding(false)))
|
||||||
|
{
|
||||||
|
sw.Write(randomContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
string stdOut = proc.StandardOutput.ReadToEnd();
|
||||||
|
string stdErr = proc.StandardError.ReadToEnd();
|
||||||
|
|
||||||
|
proc.WaitForExit();
|
||||||
|
|
||||||
|
if (proc.ExitCode == 0)
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Green;
|
||||||
|
Console.WriteLine("Файл status/change.me и хеш status/sha256.hash успешно созданы на сервере.");
|
||||||
|
Console.ResetColor();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
|
Console.WriteLine($"Ошибка выполнения SSH (Код: {proc.ExitCode}):");
|
||||||
|
if (!string.IsNullOrWhiteSpace(stdErr))
|
||||||
|
Console.WriteLine(stdErr.Trim());
|
||||||
|
if (!string.IsNullOrWhiteSpace(stdOut))
|
||||||
|
Console.WriteLine(stdOut.Trim());
|
||||||
|
Console.ResetColor();
|
||||||
|
return proc.ExitCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
|
Console.WriteLine($"Критическая ошибка выполнения SSH: {ex.Message}");
|
||||||
|
Console.ResetColor();
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string EnsureOpenSshAvailable()
|
||||||
|
{
|
||||||
|
string path = FindSshPath();
|
||||||
|
if (!string.IsNullOrEmpty(path))
|
||||||
|
return path;
|
||||||
|
|
||||||
|
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||||
|
Console.WriteLine("Клиент OpenSSH не обнаружен. Попытка автоматической установки компонента Windows...");
|
||||||
|
Console.ResetColor();
|
||||||
|
|
||||||
|
bool installed = TryInstallOpenSsh();
|
||||||
|
if (installed)
|
||||||
|
{
|
||||||
|
path = FindSshPath();
|
||||||
|
if (!string.IsNullOrEmpty(path))
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Green;
|
||||||
|
Console.WriteLine("Клиент OpenSSH успешно установлен.");
|
||||||
|
Console.ResetColor();
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FindSshPath()
|
||||||
|
{
|
||||||
|
string windir = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
|
||||||
|
|
||||||
|
string[] candidates = new[]
|
||||||
|
{
|
||||||
|
Path.Combine(windir, "Sysnative", "OpenSSH", "ssh.exe"),
|
||||||
|
Path.Combine(windir, "System32", "OpenSSH", "ssh.exe"),
|
||||||
|
@"C:\Windows\System32\OpenSSH\ssh.exe"
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var candidate in candidates)
|
||||||
|
{
|
||||||
|
if (File.Exists(candidate))
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ProcessStartInfo testPsi = new ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = "ssh",
|
||||||
|
Arguments = "-V",
|
||||||
|
UseShellExecute = false,
|
||||||
|
RedirectStandardError = true,
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
CreateNoWindow = true
|
||||||
|
};
|
||||||
|
|
||||||
|
using (var testProc = Process.Start(testPsi))
|
||||||
|
{
|
||||||
|
testProc?.WaitForExit(1000);
|
||||||
|
return "ssh";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string TryInstallOpenSsh()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ProcessStartInfo installPsi = new ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = "powershell.exe",
|
||||||
|
Arguments = "-NoProfile -ExecutionPolicy Bypass -Command \"Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0\"",
|
||||||
|
UseShellExecute = true,
|
||||||
|
Verb = "runas",
|
||||||
|
WindowStyle = ProcessWindowStyle.Normal
|
||||||
|
};
|
||||||
|
|
||||||
|
using (Process installProc = Process.Start(installPsi))
|
||||||
|
{
|
||||||
|
if (installProc == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
installProc.WaitForExit();
|
||||||
|
return installProc.ExitCode == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Win32Exception)
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||||
|
Console.WriteLine("Запрос прав Администратора был отклонён пользователем.");
|
||||||
|
Console.ResetColor();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||||
|
Console.WriteLine($"Не удалось запустить автоматическую установку: {ex.Message}");
|
||||||
|
Console.ResetColor();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GenerateRandomPayload(int linesCount, int charsPerLine)
|
||||||
|
{
|
||||||
|
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
Random rng = new Random();
|
||||||
|
|
||||||
|
for (int i = 0; i < linesCount; i++)
|
||||||
|
{
|
||||||
|
char[] buffer = new char[charsPerLine];
|
||||||
|
for (int j = 0; j < charsPerLine; j++)
|
||||||
|
{
|
||||||
|
buffer[j] = chars[rng.Next(chars.Length)];
|
||||||
|
}
|
||||||
|
sb.AppendLine(new string(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2. Сборка и создание ярлыка на рабочем столе
|
||||||
|
|
||||||
|
1. В Visual Studio в свойствах проекта (**Свойства** -> **Сборка** / **Build**) рекомендуется выставить целевую платформу **x64** (или снять флаг *Prefer 32-bit*).
|
||||||
|
2. Скомпилируйте проект в конфигурации **Release** (результирующий бинарник: `D:\sys\C-Sharp\deployfile\bin\Release\deployfile.exe`).
|
||||||
|
3. Создайте ярлык на рабочем столе:
|
||||||
|
* **Расположение объекта:**
|
||||||
|
```cmd
|
||||||
|
"D:\sys\C-Sharp\deployfile\bin\Release\deployfile.exe"
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
* **Имя ярлыка:** `Откатить конфигурацию HAProxy`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Проверка работы комплекса
|
||||||
|
|
||||||
|
1. **Запуск с клиента:**
|
||||||
|
* Дважды кликните по созданному ярлыку на рабочем столе.
|
||||||
|
* Консоль отобразит процесс подключения и результат:
|
||||||
|
```text
|
||||||
|
Используется ключ: D:\sys\C-Sharp\deployfile\key\test_key.key
|
||||||
|
Подключение к depfile@10.228.48.110:22...
|
||||||
|
Файл status/change.me и хеш status/sha256.hash успешно созданы на сервере.
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
2. **Проверка на сервере (в пределах 1 минуты):**
|
||||||
|
* Каталог `/var/lib/depfile/status` удален.
|
||||||
|
* Файл конфигурации `/etc/haproxy/haproxy.cfg` перезаписан из `/etc/haproxy/backup/haproxy.cfg`.
|
||||||
|
* Статус HAProxy: `systemctl status haproxy` в состоянии `active (running)`.
|
||||||
|
* Проверка фиксации развертывания:
|
||||||
|
```bash
|
||||||
|
cat /var/lib/depfile/deployment/success.me
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
*Вывод:*
|
||||||
|
```text
|
||||||
|
deploment success {2026-10-13 12:45:00}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
* Журнал работы скрипта доступен в `/var/log/deploy_haproxy.log`.
|
||||||
Reference in new issue
Block a user