Настройка RDP2 версии 1.25.9.x
Введение
Начиная с версии 1.25.9.x службы WebApi и RDP2 могут взаимодействовать одим из двух способов:
- REST-запросами по протоколу HTTP(S), способ по умолчанию;
- Сообщениями через шину по протоколу MQTT-over-WebSockets на базе RabbitMQ.
Взаимодействие служб WebApi и RDP2 с помощью REST-запросов
При старте служба RDP2 отправляет уведомление об используемом AddressFilter с помощью запроса PUT /api/RdpSessions/UpdateAddressFilter.
На регулярной основе служба RDP2 запрашивает все “причитающиеся” ей сессии RDP и, после обработки, отправляет состояние этих сессий обратно в WebApi. Для запроса сессий используется GET /api/RdpSessions?addressFilter={filterString}. Для отправки состояний - запрос PUT api/RdpSessions/UpdateConnectionStatuses. В этом же цикле обработки служба RDP2 уведомляет WebApi о необходимости проверить периоды простоя для машин роботов с помощью запроса GET api/RdpSessions/CheckNoRdpPeriods?addressFilter={filterString}.
При необходимости завершить сессию RDP, служба RDP2 отправляет запрос PUT api/RdpSessions/{id}/SetNeedForLogOffRDPSessionUser.
Взаимодействие служб WebApi и RDP2 по протоколу MQTT-over-WebSockets
При старте или останове служба RDP2 отправляет в шину уведомление об этом в сообщении RdpServiceNoticeMessage с RdpServiceNotice внутри:
/// <summary>
/// Данные, отправляемые службой RDP2 для WebApi при старте или останове службы RDP2
/// </summary>
public class RdpServiceNotice
{
/// <summary>
/// Перечень адресов обслуживаемых службой RDP2, все доступные адреса, если значение пустое.
/// </summary>
public string AddressFilter { get; set; }
/// <summary>
/// IP-адрес машины со службой RDP2.
/// </summary>
public string Host { get; set; }
/// <summary>
/// Флаг запуска/останова службы RDP2.
/// </summary>
public bool IsStarted { get; set; }
}Служба WebApi, получив это сообщение, сохраняет информацию в таблице Rdp2AddressFilters и отправляет в шину полный список “причитающихся” этой службе RDP2 сессий RDP в сообщении RdpSessionDataMessage, где каждая сессия представлена классом RdpSessionData:
public class RdpSessionData
{
public int Id { get; set; }
/// <summary>
/// Имя RDP-пользователя
/// </summary>
public string AdminName { get; set; }
// TODO: зачем 2?
/// <summary>
/// Имя RDP-пользователя
/// </summary>
public string UserName { get; set; }
/// <summary>
/// Пароль пользователя.
/// </summary>
public string Password { get; set; }
/// <summary>
/// Ip-адрес удаленного компьютера.
/// </summary>
public string Address { get; set; }
/// <summary>
/// Флаг поднимается автоматически, если установлен NeedNoRdpPause и на сервере нет активных сессий роботов (оркестраторных)
/// Флаг сбрасывается автоматически по истечении паузы (длительность задается в NoRdpPauseDurationInSeconds).
/// </summary>
public bool IsNoRdpPause { get; set; }
/// <summary>
/// Флаг поднимается, если нужно устроить "паузу" на машине без сессий роботов (оркестраторных).
/// Флаг сбрасывается автоматически после начала паузы.
/// </summary>
public bool NeedNoRdpPause { get; set; }
/// <summary>
/// Длительность паузы без сессий роботов (оркестраторных).
/// </summary>
public int NoRdpPauseDurationInSeconds { get; set; } = 60;
/// <summary>
/// Продолжать поддерживать RDP-сессию (тогда больше никто не сможет подключиться по RDP)
/// Если надо подключиться по RDP отдельно, должен быть сброшен
/// </summary>
public bool KeepRdpSession { get; set; }
public bool UserProfileLoaded { get; set; }
public int AuthenticationLevel { get; set; }
public bool NegotiateSecurityLayer { get; set; }
public bool EnableCredSspSupport { get; set; }
public int DesktopWidth { get; set; }
public int DesktopHeight { get; set; }
public int ColorDepth { get; set; }
public bool Connected { get; set; }
/// <summary>
/// Последняя дата переключения true/false или false/true для Connected
/// </summary>
public DateTime? ConnectedChangedAt { get; set; }
/// <summary>
/// Последняя дата обновления Connected (не обязательно именно переключения true/false или false/true)
/// </summary>
public DateTime? ConnectedUpdatedAt { get; set; }
public int WorkerId { get; set; }
public int? RdpPort { get; set; }
/// <summary>
/// Переподключить сессию принудительно, даже если она подключена.
/// Только для Windows RDP.
/// </summary>
public bool? ForceKeepRdpSession { get; set; }
}При необходимости включить или отключить сессию RDP, служба WebApi отправляет в шину сообщение RdpSessionDataMessage с одной сессией в теле.
Служба RDP2 получает из шины сообщения RdpSessionDataMessage и сохраняет во внутреннем кэше “причитающиеся” ей сессии RDP. На регулярной основе служба RDP2 проверяет состояние сессий из внутреннего кэша и, при необходимости, останавливает или запускает их. В конце каждого цикла проверки служба RDP2 отправляет в шину сообщение RdpSessionStatusesMessage со статусами каждой обслуживаемой сессии:
/// <summary>
/// Информация о состоянии сессии RDP.
/// </summary>
public sealed class RdpSessionStatus
{
/// <summary>
/// Id сессии.
/// </summary>
public int SessionId { get; set; }
/// <summary>
/// Подключена ли сессия.
/// </summary>
public bool Connected { get; set; }
/// <summary>
/// Время изменения подключения.
/// </summary>
public DateTime ConnectedChangedAt { get; set; }
/// <summary>
/// Время обновления подключения.
/// </summary>
public DateTime ConnectedUpdatedAt { get; set; }
}и сообщение RdpCheckPausePeriodsMessage со своим AddressFilter.
При необходимости завершить сессию RDP, служба RDP2 отправляет в шину сообщение RdpSetNeedForLogoffMessage с идентификатором сессии.
Для включения режима взаимодействия через шину необходимо настроить службы RabbitMQ, NGINX, WebApi и RDP2.
Настройка RabbitMQ
В консоли сервера, на котором работает RabbitMQ, необходимо выполнить следующие команды с правами пользователя-администратора (для Windows необходимо предварительно перейти в каталог C:\Program Files\RabbitMQ Server\rabbitmq_server-Версия\sbin):
rabbitmq-plugins enable rabbitmq_mqtt
rabbitmq-plugins enable rabbitmq_web_mqttПри использовании брандмауэра необходимо открыть порт tcp/15675, который используется для MQTT-over-WebSockets.
Настройка NGINX
Для проксирования запросов клиентов к службе MQTT сервера RabbitMQ необходимо добавить в конфигурацию NGINX (nginx.conf) следующее (выделено полужирным шрифтом):
http {
...
upstream mqtt {
server <IP или имя сервера RabbitMQ>:15675;
}
...
server {
...
location /mqtt/ {
proxy_pass http://mqtt;
rewrite ^/mqtt/(.*)$ /$1 break;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
...
}
После внесения изменений в файл nginx.conf необходимо проверить правильность файла:
nginx -tи, в случае отсутсвия ошибок, перезапустить службу NGINX.
Настройка службы WebApi
Служба WebApi может взаимодействовать со службами RDP2 одновременно двумя способами: REST-запросами и через шину сообщений, в зависимости от того, какой метод настроен для конкретной службы RDP2.
Для включения взаимодействия через шину, необходимо добавить в файл appsettings.XXX.json раздел Mqtt:
{
...
},
"Mqtt":
{
"Url": "wss://<IP или имя и порт сервера NGINX>/mqtt/ws",
"Username": "<пользователь RabbitMQ>",
"Password": "<(зашифрованный) пароль пользователя RabbitMQ>"
},
...
}
Настройка службы RDP2
Для включения режима взаимодействия через шину сообщений, необходимо добавить в файл appsettings.XXX.json раздел Mqtt:
{
...
},
"Mqtt":
{
"Url": "wss://<IP или имя и порт сервера NGINX>/mqtt/ws",
"Username": "<пользователь RabbitMQ>",
"Password": "<(зашифрованный) пароль пользователя RabbitMQ>"
},
...
}
В случае отсутствия раздела Mqtt или пустом значении параметра Url взаимодействие по шине сообщений будет отключено.