Files
2020-09-12 16:11:43 +02:00

441 lines
18 KiB
C#

using Step.CmsConnectManager.Events;
using Step.CmsConnectManager.Exceptions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using static Step.CmsConnectManager.CMSConnectConstants;
namespace Step.CmsConnectManager
{
public class GatewayController
{
private SSHAdapter SSHAdapter;
//---------------------------------------------------------------------------------------------------
#region Public_methods
/// <summary>
/// Simple constructor.
/// Create an instance with this configuration: hostname: localhost, username: root, password: root.
/// </summary>
public GatewayController()
{
SSHAdapter = new SSHAdapter("localhost", "root", "root");
}
/// <summary>
/// Advanced constructor.
/// Create an instance with the configuration passed by arguments
/// </summary>
/// <param name="hostname">Name (or IP-Address) of the gateway</param>
/// <param name="username">Username for Gateway Login</param>
/// <param name="password">Password for Gateway Login</param>
/// <exception cref="System.NullReferenceException">Thrown when one parameter is null</exception>
public GatewayController(string hostname, string username, string password)
{
SSHAdapter = new SSHAdapter(hostname, username, password);
}
/// <summary>
/// Write Proxy-Configuration on Gateway.
/// <para />See <see cref="GatewayProxyConfigurationBuilder"/> for generate the configuration.
/// </summary>
/// <param name="proxyConfiguration">Configuration of the proxy.</param>
/// <exception cref="GatewayException"></exception>
public void WriteGatewayProxyConfiguration(GatewayProxyConfiguration proxyConfiguration)
{
string Command = SSHAdapter.GenerateSshProxyCommand(proxyConfiguration);
SSHAdapter.SendSSHCommand(Command);
}
/// <summary>
/// Write Newtork-Configuration on Gateway.
/// <para />See <see cref="GatewayNetworkConfigurationBuilder"/> for generate the configuration.
/// </summary>
/// <param name="networkConfiguration">Configuration of the network.</param>
/// <exception cref="GatewayException"></exception>
public void WriteGatewayNetworkConfiguration(GatewayNetworkConfiguration networkConfiguration)
{
string NetworkCommand = SSHAdapter.GenerateSshNetworkCommand(networkConfiguration);
string DnsIpCommand = SSHAdapter.GenerateSshDnsCommand(networkConfiguration);
string DnsSuffixCommand = SSHAdapter.GenerateSshDnsSuffxCommand(networkConfiguration);
SSHAdapter.SendSSHCommand(new List<string>() { NetworkCommand, DnsIpCommand, DnsSuffixCommand });
}
/// <summary>
/// Read Newtork-Configuration saved on Gateway.
/// </summary>
/// <returns>See <see cref="GatewayNetworkConfiguration"/>
/// </returns>
/// <exception cref="GatewayException"></exception>
public GatewayNetworkConfiguration ReadGatewayNetworkConfiguration()
{
return ElaborateConfigFromSshNetworkCommand( SSHAdapter.SendSSHCommand(SSH_GET_NETWORK_COMMAND) );
}
/// <summary>
/// Read Proxy-Configuration saved on Gateway.
/// </summary>
/// <returns>See <see cref="GatewayProxyConfiguration"/>
/// </returns>
/// <exception cref="GatewayException"></exception>
public GatewayProxyConfiguration ReadGatewayProxyConfiguration()
{
return ElaborateConfigFromSshProxyCommand( SSHAdapter.SendSSHCommand(SSH_GET_PROXY_COMMAND));
}
/// <summary>
/// Test connection to SCM/CMS Server, on Gateway.
/// </summary>
/// <param name="timeout">Seconds timeout for the request</param>
/// <exception cref="GatewayException"></exception>
public GatewayConnectionStatus TestGatewayConnection(int timeout)
{
if (timeout < 0)
throw new ArgumentOutOfRangeException("Timeout must be > 0");
return ElaborateTestConnectionCommand(SSHAdapter.SendSSHCommand(SSH_TEST_CONNECTION_COMMAND + timeout));
}
/// <summary>
/// Reboot asynchronously the Gateway.
/// </summary>
/// <param name="delay">Serconds to delay before reboot</param>
/// <param name="handler">Handler Callback when the operation is finished or an error occours.
/// See <see cref="GatewayRebootEventHandlerArgs"/>
/// </param>
public void RebootGatewayAsync(int delay, EventHandler<GatewayRebootEventHandlerArgs> handler)
{
if (delay < 0)
throw new ArgumentOutOfRangeException("Delay must be > 0");
//Create the Action
Action<int, EventHandler<GatewayRebootEventHandlerArgs>> action = (int del, EventHandler<GatewayRebootEventHandlerArgs> hand) =>
{
GatewayRebootEventHandlerArgs ev = new GatewayRebootEventHandlerArgs();
try
{
SSHAdapter.SendSSHReboot(del);
}
catch (Exception e)
{
ev.ErrorStatus = true;
ev.ErrorMessage = e.Message;
}
hand(this, ev);
};
// Create a task and not start it.
Task t = new Task (() => action(delay, handler));
t.Start();
}
/// <summary>
/// Reboot and wait a new session of the Gateway.
/// </summary>
/// <param name="delay">Seconds to delay before reboot</param>
/// <exception cref="GatewayException"></exception>
public void RebootGateway(int delay)
{
if (delay < 0)
throw new ArgumentOutOfRangeException("Delay must be > 0");
// Send Command
SSHAdapter.SendSSHReboot(delay);
}
#endregion
//---------------------------------------------------------------------------------------------------
#region SSH_commands_preparations_sub_methods
#endregion
//---------------------------------------------------------------------------------------------------
#region elaborate_SSH_values_sub_methods
private GatewayNetworkConfiguration ElaborateConfigFromSshNetworkCommand(List<string> lines)
{
GatewayNetworkConfiguration configuration = new GatewayNetworkConfiguration();
foreach (string line in lines)
{
if (line.StartsWith(IP_ADDR_LABEL))
DecodeNetworkIPAddress(line.Remove(0, IP_ADDR_LABEL.Length).Trim(), ref configuration);
else if (line.StartsWith(GATEWAY_LABEL))
DecodeNetworkDefGateway(line.Remove(0, GATEWAY_LABEL.Length).Trim(), ref configuration);
else if (line.StartsWith(DNSIP_LABEL))
DecodeNetworkDnsIp(line.Remove(0, DNSIP_LABEL.Length).Trim(), ref configuration);
else if (line.StartsWith(DNSPREFIX_LABEL))
DecodeNetworkDnsPrefix(line.Remove(0, DNSPREFIX_LABEL.Length).Trim(), ref configuration);
}
return configuration;
}
private GatewayProxyConfiguration ElaborateConfigFromSshProxyCommand(List<string> lines)
{
GatewayProxyConfiguration configuration = new GatewayProxyConfiguration();
foreach (string line in lines)
{
if (line.StartsWith(PROXY_ADDR_LABEL))
DecodeProxyAddress(line.Remove(0, PROXY_ADDR_LABEL.Length).Trim(), ref configuration);
else if (line.StartsWith(NO_PROXY_LABEL))
DecodeNoProxyUrls(line.Remove(0, NO_PROXY_LABEL.Length).Trim(), ref configuration);
}
return configuration;
}
private GatewayConnectionStatus ElaborateTestConnectionCommand(List<string> lines)
{
GatewayConnectionStatus status = new GatewayConnectionStatus();
foreach (string line in lines)
{
if (!string.IsNullOrWhiteSpace(line))
DecodeConnectionStatus(line.Trim(), ref status);
}
return status;
}
#endregion
//---------------------------------------------------------------------------------------------------
#region decode_SSH_values_sub_methods
private void DecodeNetworkIPAddress(string stringValue, ref GatewayNetworkConfiguration configuration)
{
//Check if has DHCP
if (stringValue == "DHCP")
configuration.hasDhcp = true;
else
{
configuration.hasDhcp = false;
//Check if has / for netmask
if (!stringValue.Contains('/'))
throw new GatewayException("Internal Gateway Error during read (bad format): " + IP_ADDR_LABEL + stringValue);
string [] tempAddr = stringValue.Split('/');
//Check if has lenght == 2
if (tempAddr.Length != 2)
throw new GatewayException("Internal Gateway Error during read (bad format): " + IP_ADDR_LABEL + stringValue);
//Set the IPAddress / Netmask
IPAddress tempIp;
if (!EvaluateIPV4(tempAddr[0], out tempIp))
throw new GatewayException("Internal Gateway Error during read (bad format): " + IP_ADDR_LABEL + stringValue);
IPNetwork tempIpNetw;
if (!IPNetwork.TryParse(stringValue, out tempIpNetw))
throw new GatewayException("Internal Gateway Error during read (bad format): " + IP_ADDR_LABEL + stringValue);
configuration.ipAddress = tempIp;
configuration.netMaskAddress = tempIpNetw.Netmask;
}
}
private void DecodeNetworkDefGateway(string stringValue, ref GatewayNetworkConfiguration configuration)
{
//check if is defined
if (stringValue == UNDEF_VALUE)
configuration.defaultGatewayAddress = null;
else
{
if (!EvaluateIPV4(stringValue, out IPAddress tempIp))
throw new GatewayException("Internal Gateway Error during read (bad format): " + GATEWAY_LABEL + stringValue);
configuration.defaultGatewayAddress = tempIp;
}
}
private void DecodeNetworkDnsIp(string stringValue, ref GatewayNetworkConfiguration configuration)
{
//check if is defined
if (stringValue == UNDEF_VALUE)
configuration.dnsAddresses = null;
else
{
string[] tempStr = stringValue.Split(' ');
if (tempStr.Length == 0)
configuration.dnsAddresses = null;
else
{
IPAddress tempIp;
List<IPAddress> tempDns = new List<IPAddress>();
foreach (string str in tempStr)
{
if (string.IsNullOrEmpty(str))
continue;
if (!EvaluateIPV4(str, out tempIp))
throw new GatewayException("Internal Gateway Error during read (bad format): " + DNSIP_LABEL + stringValue);
tempDns.Add(tempIp);
}
configuration.dnsAddresses = tempDns;
}
}
}
private void DecodeNetworkDnsPrefix(string stringValue, ref GatewayNetworkConfiguration configuration)
{
// Check if is defined
if (stringValue == UNDEF_VALUE)
configuration.dnsPrefixes = null;
else
{
string[] tempStr = stringValue.Split(' ');
if (tempStr.Length == 0)
configuration.dnsPrefixes = null;
else
configuration.dnsPrefixes = tempStr.Where(X=> !string.IsNullOrEmpty(X)).ToList();
}
}
private void DecodeProxyAddress(string stringValue, ref GatewayProxyConfiguration configuration)
{
// Check if is defined
if (stringValue == UNDEF_VALUE)
configuration.hasProxy = false;
else
{
configuration.hasProxy = true;
/* Must be one of these:
* - Address:Port
* - User:Password@Address:Port
*/
if (!stringValue.Contains("@"))
{
// Set username & password
configuration.username = null;
configuration.password = null;
// Check if has :
if (!stringValue.Contains(':'))
throw new GatewayException("Internal Gateway Error during read (bad format): " + PROXY_ADDR_LABEL + stringValue);
string[] tempAddr = stringValue.Split(':');
// Check if has lenght == 2
if (tempAddr.Length != 2)
throw new GatewayException("Internal Gateway Error during read (bad format): " + PROXY_ADDR_LABEL + stringValue);
// Set the address
configuration.address = tempAddr[0];
// Set the port
if (!uint.TryParse(tempAddr[1], out uint tempPort))
throw new GatewayException("Internal Gateway Error during read (bad format): " + PROXY_ADDR_LABEL + stringValue);
configuration.port = tempPort;
}
else
{
string[] splitted = stringValue.Split('@');
//Check if has lenght == 2
if (splitted.Length != 2)
throw new GatewayException("Internal Gateway Error during read (bad format): " + PROXY_ADDR_LABEL + stringValue);
//Check if has :
if (!splitted[0].Contains(':'))
throw new GatewayException("Internal Gateway Error during read (bad format): " + PROXY_ADDR_LABEL + stringValue);
if (!splitted[1].Contains(':'))
throw new GatewayException("Internal Gateway Error during read (bad format): " + PROXY_ADDR_LABEL + stringValue);
string[] tempLogin = splitted[0].Split(':');
string[] tempAddr = splitted[1].Split(':');
//Check if has lenght == 2
if (tempLogin.Length != 2)
throw new GatewayException("Internal Gateway Error during read (bad format): " + PROXY_ADDR_LABEL + stringValue);
if (tempAddr.Length != 2)
throw new GatewayException("Internal Gateway Error during read (bad format): " + PROXY_ADDR_LABEL + stringValue);
// Set the username
configuration.username = tempLogin[0];
// Set the password
configuration.password = tempLogin[1];
// Set the address
configuration.address = tempAddr[0];
// Set the port
if (!uint.TryParse(tempAddr[1], out uint tempPort))
throw new GatewayException("Internal Gateway Error during read (bad format): " + PROXY_ADDR_LABEL + stringValue);
configuration.port = tempPort;
}
}
}
private void DecodeNoProxyUrls(string stringValue, ref GatewayProxyConfiguration configuration)
{
// Check if is defined
if (stringValue == UNDEF_VALUE)
configuration.noproxyAddresses = null;
else
{
string[] tempStr = stringValue.Trim('"').Split(',');
for (int i=0;i<tempStr.Length;i++)
tempStr[i] = tempStr[i].Trim();
if (tempStr.Length == 0)
configuration.noproxyAddresses = null;
else
configuration.noproxyAddresses = tempStr.ToList();
}
}
private void DecodeConnectionStatus(string stringValue, ref GatewayConnectionStatus status)
{
if (stringValue == CONNECTION_OK_VALUE)
status = GatewayConnectionStatus.OK;
else if (stringValue == CONNECTION_NOWEB_VALUE)
status = GatewayConnectionStatus.WEB_ERROR;
else if (stringValue == CONNECTION_NOPORT_VALUE)
status = GatewayConnectionStatus.PORT_ERROR;
else
throw new GatewayException("Internal Gateway Error during Connection-Test (bad format): " + stringValue);
}
private bool EvaluateIPV4(string stringValue,out IPAddress address)
{
Regex rgx = new Regex(@"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");
if (rgx.IsMatch(stringValue))
{
IPAddress.TryParse(stringValue, out address);
return true;
}
address = new IPAddress(0);
return false;
}
#endregion
}
}