Rabbitmq on top of VPN network, add users and passwords to rabbitmq

Created skript for automatic update of all the installations
This commit is contained in:
Noe 2023-11-29 21:28:11 +01:00
parent 30e4991032
commit 980089d7e0
5 changed files with 262 additions and 13 deletions

View File

@ -11,6 +11,7 @@ using Microsoft.OpenApi.Models;
using InnovEnergy.Lib.Utils; using InnovEnergy.Lib.Utils;
using RabbitMQ.Client; using RabbitMQ.Client;
namespace InnovEnergy.App.Backend; namespace InnovEnergy.App.Backend;
public static class Program public static class Program
@ -21,7 +22,7 @@ public static class Program
Watchdog.NotifyReady(); Watchdog.NotifyReady();
Db.Init(); Db.Init();
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
RabbitMqManager.InitializeEnvironment(); RabbitMqManager.InitializeEnvironment();
RabbitMqManager.StartRabbitMqConsumer(); RabbitMqManager.StartRabbitMqConsumer();
Console.WriteLine("Queue declared"); Console.WriteLine("Queue declared");

View File

@ -1,5 +1,9 @@
using System.Drawing.Printing;
using System.Net; using System.Net;
using System.Net.Security;
using System.Net.Sockets; using System.Net.Sockets;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
using InnovEnergy.App.Backend.Database; using InnovEnergy.App.Backend.Database;
@ -20,8 +24,130 @@ public static class RabbitMqManager
public static void InitializeEnvironment() public static void InitializeEnvironment()
{ {
string vpnServerIp = "194.182.190.208"; //string vpnServerIp = "194.182.190.208";
Factory = new ConnectionFactory { HostName = vpnServerIp}; string vpnServerIp = "10.2.0.11";
// ConnectionFactory factory = new ConnectionFactory();
// factory.HostName = vpnServerIp;
// factory.AutomaticRecoveryEnabled = true;
// //factory.UserName = "";
// //factory.Password = "";
// factory.VirtualHost = "/";
// factory.Port = 5672;
//
// //factory.AuthMechanisms = new IAuthMechanismFactory[] { new ExternalMechanismFactory() };
//
// System.Diagnostics.Debug.WriteLine("2 ");
//
// X509Certificate2Collection certCollection = new X509Certificate2Collection();
// X509Certificate2 certificate = new X509Certificate2("/etc/rabbitmq/testca/ca_certificate.pem");
// certCollection.Add(certificate);
//
// factory.Ssl.Certs = certCollection;
// factory.Ssl.Enabled = true;
// factory.Ssl.ServerName = "Webserver-FrontAndBack";
// factory.Ssl.Version = SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13;
// factory.Ssl.AcceptablePolicyErrors = SslPolicyErrors.RemoteCertificateChainErrors;
// factory.Ssl.CertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
// {
// if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors)
// {
// // Log or debug information about the chain
// foreach (var chainElement in chain.ChainElements)
// {
// Console.WriteLine($"Element Subject: {chainElement.Certificate.Subject}");
// Console.WriteLine($"Element Issuer: {chainElement.Certificate.Issuer}");
// // Add more details as needed
// }
// }
//
// // Your custom validation logic
// return sslPolicyErrors == SslPolicyErrors.None;
// };
Factory = new ConnectionFactory
{
HostName = vpnServerIp,
Port = 5672,
VirtualHost = "/",
UserName = "consumer",
Password = "faceaddb5005815199f8366d3d15ff8a",
//AuthMechanisms = new IAuthMechanismFactory[] { new ExternalMechanismFactory() },
// Ssl = new SslOption
// {
// Enabled = true,
// ServerName = "Webserver-FrontAndBack",
// //Roots = new X509Certificate2Collection { caCertificate },
// //CertPath = "/etc/rabbitmq/testca/ca_certificate.pem",
// CertPath = "/etc/rabbitmq/client/client_certificate.pem",
//
//
// // CertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
// // {
// // //X509Certificate2 clientCertificate = new X509Certificate2("/etc/rabbitmq/client/client_certificate.pem");
// //
// // //X509Certificate2 caCertificate = new X509Certificate2("/etc/openvpn/client/ca-certificate");
// // X509Certificate2 caCertificate = new X509Certificate2("/etc/rabbitmq/testca/ca_certificate.pem");
// //
// //
// //
// // Console.WriteLine(certificate.Subject);
// // Console.WriteLine("---------------------------------");
// // //Console.WriteLine(certificate.GetPublicKey());
// // // Your custom validation logic using the CA certificate
// // // Return true if the certificate is valid, false otherwise
// // return certificate.Issuer == caCertificate.Subject;
// // }
// CertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
// {
// X509Certificate2 caCertificate = new X509Certificate2("/etc/rabbitmq/testca/ca_certificate.pem");
//
// // Add the CA certificate to the chain policy's extra store
// chain.ChainPolicy.ExtraStore.Add(caCertificate);
//
// // Check if the chain builds successfully
// bool chainIsValid = chain.Build((X509Certificate2)certificate);
//
// if (!chainIsValid)
// {
// Console.WriteLine("Certificate chain validation failed:");
//
// // Print details of each chain status
// foreach (var chainStatus in chain.ChainStatus)
// {
// Console.WriteLine($"Chain Status: {chainStatus.Status}");
// Console.WriteLine($"Chain Status Information: {chainStatus.StatusInformation}");
// // Add more details as needed
// // Check if the failure is due to UntrustedRoot
// if (chainStatus.Status == X509ChainStatusFlags.UntrustedRoot)
// {
// // Manually check if the root certificate is the expected one
// if (certificate.Issuer == caCertificate.Subject)
// {
// Console.WriteLine("Manually trusting the root certificate.");
// chainIsValid = true;
// }
// }
// }
//
//
// }
//
// // Additional validation logic if needed
// Console.WriteLine($"Certificate Subject: {certificate.Subject}"+chainIsValid);
//
// // Return true if the certificate is valid
// return chainIsValid;
// }
//}
};
Connection = Factory.CreateConnection(); Connection = Factory.CreateConnection();
Channel = Connection.CreateModel(); Channel = Connection.CreateModel();
Console.WriteLine("Middleware subscribed to RabbitMQ queue, ready for receiving messages"); Console.WriteLine("Middleware subscribed to RabbitMQ queue, ready for receiving messages");
@ -36,9 +162,8 @@ public static class RabbitMqManager
var body = ea.Body.ToArray(); var body = ea.Body.ToArray();
var message = Encoding.UTF8.GetString(body); var message = Encoding.UTF8.GetString(body);
StatusMessage? receivedStatusMessage = JsonSerializer.Deserialize<StatusMessage>(message); StatusMessage? receivedStatusMessage = JsonSerializer.Deserialize<StatusMessage>(message);
var InstallationConnections = WebsocketManager.InstallationConnections;
lock (InstallationConnections) lock (WebsocketManager.InstallationConnections)
{ {
//Consumer received a message //Consumer received a message
if (receivedStatusMessage != null) if (receivedStatusMessage != null)
@ -78,6 +203,7 @@ public static class RabbitMqManager
//Traverse the Alarm list, and store each of them to the database //Traverse the Alarm list, and store each of them to the database
if (receivedStatusMessage.Alarms != null) if (receivedStatusMessage.Alarms != null)
{ {
Console.WriteLine("Add an alarm for installation "+receivedStatusMessage.InstallationId);
foreach (var alarm in receivedStatusMessage.Alarms) foreach (var alarm in receivedStatusMessage.Alarms)
{ {
Error newError = new Error Error newError = new Error
@ -95,11 +221,14 @@ public static class RabbitMqManager
} }
} }
var prevStatus = 0;
//This installation id does not exist in our data structure, add it. //This installation id does not exist in our data structure, add it.
if (!InstallationConnections.ContainsKey(installationId)) if (!WebsocketManager.InstallationConnections.ContainsKey(installationId))
{ {
prevStatus = -2;
Console.WriteLine("Create new empty list for installation: " + installationId); Console.WriteLine("Create new empty list for installation: " + installationId);
InstallationConnections[installationId] = new InstallationInfo WebsocketManager.InstallationConnections[installationId] = new InstallationInfo
{ {
Status = receivedStatusMessage.Status, Status = receivedStatusMessage.Status,
Timestamp = DateTime.Now Timestamp = DateTime.Now
@ -107,13 +236,14 @@ public static class RabbitMqManager
} }
else else
{ {
InstallationConnections[installationId].Status = receivedStatusMessage.Status; prevStatus = WebsocketManager.InstallationConnections[installationId].Status;
InstallationConnections[installationId].Timestamp = DateTime.Now; WebsocketManager.InstallationConnections[installationId].Status = receivedStatusMessage.Status;
WebsocketManager.InstallationConnections[installationId].Timestamp = DateTime.Now;
} }
//Console.WriteLine("----------------------------------------------"); //Console.WriteLine("----------------------------------------------");
//Update all the connected front-ends regarding this installation //Update all the connected front-ends regarding this installation
if(InstallationConnections[installationId].Connections.Count > 0) if(prevStatus != receivedStatusMessage.Status && WebsocketManager.InstallationConnections[installationId].Connections.Count > 0)
{ {
WebsocketManager.InformWebsocketsForInstallation(installationId); WebsocketManager.InformWebsocketsForInstallation(installationId);
} }

View File

@ -1,12 +1,65 @@
using System.Net;
using System.Net.Sockets;
using System.Net.WebSockets; using System.Net.WebSockets;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
using InnovEnergy.App.Backend.Database;
using InnovEnergy.App.Backend.DataTypes;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
namespace InnovEnergy.App.Backend.Websockets; namespace InnovEnergy.App.Backend.Websockets;
public static class WebsocketManager public static class WebsocketManager
{ {
public static Dictionary<int, InstallationInfo> InstallationConnections = new Dictionary<int, InstallationInfo>(); public static Dictionary<int, InstallationInfo> InstallationConnections = new Dictionary<int, InstallationInfo>();
public static void InformInstallationsToSubscribeToRabbitMq()
{
var installationIps = Db.Installations.Select(inst => inst.VpnIp).ToList();
Console.WriteLine("Count is "+installationIps.Count);
var maxRetransmissions = 2;
UdpClient udpClient = new UdpClient();
udpClient.Client.ReceiveTimeout = 2000;
int port = 9000;
//Send a message to each installation and tell it to subscribe to the queue
using (udpClient)
{
for (int i = 0; i < installationIps.Count; i++)
{
if(installationIps[i]==""){continue;}
Console.WriteLine("-----------------------------------------------------------");
Console.WriteLine("Trying to reach installation with IP: " + installationIps[i]);
//Try at most MAX_RETRANSMISSIONS times to reach an installation.
for (int j = 0; j < maxRetransmissions; j++)
{
string message = "This is a message from RabbitMQ server, you can subscribe to the RabbitMQ queue";
byte[] data = Encoding.UTF8.GetBytes(message);
udpClient.Send(data, data.Length, installationIps[i], port);
Console.WriteLine($"Sent UDP message to {installationIps[i]}:{port}: {message}");
IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Parse(installationIps[i]), port);
try
{
byte[] replyData = udpClient.Receive(ref remoteEndPoint);
string replyMessage = Encoding.UTF8.GetString(replyData);
Console.WriteLine("Received " + replyMessage + " from installation " + installationIps[i]);
break;
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.TimedOut){Console.WriteLine("Timed out waiting for a response. Retry...");}
else{Console.WriteLine("Error: " + ex.Message);}
}
}
}
}
Console.WriteLine("Start RabbitMQ Consumer");
}
//Every 1 minute, check the timestamp of the latest received message for every installation. //Every 1 minute, check the timestamp of the latest received message for every installation.
//If the difference between the two timestamps is more than one minute, we consider this installation unavailable. //If the difference between the two timestamps is more than one minute, we consider this installation unavailable.
@ -26,6 +79,8 @@ public static class WebsocketManager
} }
} }
//Inform all the connected websockets regarding installation "installationId" //Inform all the connected websockets regarding installation "installationId"
public static void InformWebsocketsForInstallation(int installationId) public static void InformWebsocketsForInstallation(int installationId)
{ {

View File

@ -0,0 +1,34 @@
#!/bin/bash
dotnet_version='net6.0'
salimax_ip="$1"
username='ie-entwicklung'
root_password='Salimax4x25'
set -e
echo -e "\n============================ Build ============================\n"
dotnet publish \
./SaliMax.csproj \
-p:PublishTrimmed=false \
-c Release \
-r linux-x64
echo -e "\n============================ Deploy ============================\n"
ip_addresses=("10.2.3.115" "10.2.3.104" "10.2.4.33" "10.2.4.32" "10.2.4.36" "10.2.4.35" "10.2.4.154" "10.2.4.113" "10.2.4.29")
for ip_address in "${ip_addresses[@]}"; do
rsync -v \
--exclude '*.pdb' \
./bin/Release/$dotnet_version/linux-x64/publish/* \
$username@"$ip_address":~/salimax
ssh "$username"@"$ip_address" "cd salimax && echo '$root_password' | sudo -S ./restart"
echo "Deployed and ran commands on $ip_address"
done

View File

@ -4,6 +4,7 @@ using System.Net.NetworkInformation;
using System.Net.Sockets; using System.Net.Sockets;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Reactive.Threading.Tasks; using System.Reactive.Threading.Tasks;
using System.Security.Cryptography.X509Certificates;
using System.Text; using System.Text;
using Flurl.Http; using Flurl.Http;
using InnovEnergy.App.SaliMax.Devices; using InnovEnergy.App.SaliMax.Devices;
@ -50,8 +51,9 @@ internal static class Program
private static readonly Channel RelaysChannel ; private static readonly Channel RelaysChannel ;
private static readonly Channel BatteriesChannel ; private static readonly Channel BatteriesChannel ;
private const String VpnServerIp = "194.182.190.208"; //private const String VpnServerIp = "194.182.190.208";
private const String VpnServerIp = "10.2.0.11";
private static IPAddress? _controllerIpAddress; private static IPAddress? _controllerIpAddress;
private static UdpClient _udpListener = null!; private static UdpClient _udpListener = null!;
private static ConnectionFactory? _factory ; private static ConnectionFactory? _factory ;
@ -314,7 +316,34 @@ internal static class Program
{ {
try try
{ {
_factory = new ConnectionFactory { HostName = VpnServerIp }; //_factory = new ConnectionFactory { HostName = VpnServerIp };
_factory = new ConnectionFactory
{
HostName = VpnServerIp,
Port = 5672,
VirtualHost = "/",
UserName = "producer",
Password = "b187ceaddb54d5485063ddc1d41af66f",
// Ssl = new SslOption
// {
// Enabled = true,
// ServerName = VpnServerIp, // Disable hostname validation
// CertPath = "/etc/openvpn/client/client-certificate",
//
// CertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
// {
// X509Certificate2 caCertificate = new X509Certificate2("/etc/openvpn/client/ca-certificate");
// //Console.WriteLine(caCertificate);
// //Console.WriteLine("---------------------------------");
// //Console.WriteLine(certificate.GetPublicKey());
// // Your custom validation logic using the CA certificate
// // Return true if the certificate is valid, false otherwise
// return certificate.Issuer == caCertificate.Subject;
// }
// }
};
_connection = _factory.CreateConnection(); _connection = _factory.CreateConnection();
_channel = _connection.CreateModel(); _channel = _connection.CreateModel();
_channel.QueueDeclare(queue: "statusQueue", durable: true, exclusive: false, autoDelete: false, arguments: null); _channel.QueueDeclare(queue: "statusQueue", durable: true, exclusive: false, autoDelete: false, arguments: null);