feat: add HTTP Management API, migrate CLI from Akka ClusterClient to HTTP
Replace the CLI's Akka.NET ClusterClient transport with a simple HTTP client targeting a new POST /management endpoint on the Central Host. The endpoint handles Basic Auth, LDAP authentication, role resolution, and ManagementActor dispatch in a single round-trip — eliminating the CLI's Akka, LDAP, and Security dependencies. Also fixes DCL ReSubscribeAll losing subscriptions on repeated reconnect by deriving the tag list from _subscriptionsByInstance instead of _subscriptionIds.
This commit is contained in:
@@ -4,13 +4,7 @@ namespace ScadaLink.CLI;
|
||||
|
||||
public class CliConfig
|
||||
{
|
||||
public List<string> ContactPoints { get; set; } = new();
|
||||
public string? LdapServer { get; set; }
|
||||
public int LdapPort { get; set; } = 636;
|
||||
public bool LdapUseTls { get; set; } = true;
|
||||
public string LdapSearchBase { get; set; } = string.Empty;
|
||||
public string LdapServiceAccountDn { get; set; } = string.Empty;
|
||||
public string LdapServiceAccountPassword { get; set; } = string.Empty;
|
||||
public string? ManagementUrl { get; set; }
|
||||
public string DefaultFormat { get; set; } = "json";
|
||||
|
||||
public static CliConfig Load()
|
||||
@@ -28,51 +22,28 @@ public class CliConfig
|
||||
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
if (fileConfig != null)
|
||||
{
|
||||
if (fileConfig.ContactPoints?.Count > 0) config.ContactPoints = fileConfig.ContactPoints;
|
||||
if (fileConfig.Ldap != null)
|
||||
{
|
||||
config.LdapServer = fileConfig.Ldap.Server;
|
||||
config.LdapPort = fileConfig.Ldap.Port;
|
||||
config.LdapUseTls = fileConfig.Ldap.UseTls;
|
||||
if (!string.IsNullOrEmpty(fileConfig.Ldap.SearchBase))
|
||||
config.LdapSearchBase = fileConfig.Ldap.SearchBase;
|
||||
if (!string.IsNullOrEmpty(fileConfig.Ldap.ServiceAccountDn))
|
||||
config.LdapServiceAccountDn = fileConfig.Ldap.ServiceAccountDn;
|
||||
if (!string.IsNullOrEmpty(fileConfig.Ldap.ServiceAccountPassword))
|
||||
config.LdapServiceAccountPassword = fileConfig.Ldap.ServiceAccountPassword;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(fileConfig.DefaultFormat)) config.DefaultFormat = fileConfig.DefaultFormat;
|
||||
if (!string.IsNullOrEmpty(fileConfig.ManagementUrl))
|
||||
config.ManagementUrl = fileConfig.ManagementUrl;
|
||||
if (!string.IsNullOrEmpty(fileConfig.DefaultFormat))
|
||||
config.DefaultFormat = fileConfig.DefaultFormat;
|
||||
}
|
||||
}
|
||||
|
||||
// Override from environment variables
|
||||
var envContacts = Environment.GetEnvironmentVariable("SCADALINK_CONTACT_POINTS");
|
||||
if (!string.IsNullOrEmpty(envContacts))
|
||||
config.ContactPoints = envContacts.Split(',', StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
|
||||
var envLdap = Environment.GetEnvironmentVariable("SCADALINK_LDAP_SERVER");
|
||||
if (!string.IsNullOrEmpty(envLdap)) config.LdapServer = envLdap;
|
||||
var envUrl = Environment.GetEnvironmentVariable("SCADALINK_MANAGEMENT_URL");
|
||||
if (!string.IsNullOrEmpty(envUrl))
|
||||
config.ManagementUrl = envUrl;
|
||||
|
||||
var envFormat = Environment.GetEnvironmentVariable("SCADALINK_FORMAT");
|
||||
if (!string.IsNullOrEmpty(envFormat)) config.DefaultFormat = envFormat;
|
||||
if (!string.IsNullOrEmpty(envFormat))
|
||||
config.DefaultFormat = envFormat;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
private class CliConfigFile
|
||||
{
|
||||
public List<string>? ContactPoints { get; set; }
|
||||
public LdapConfig? Ldap { get; set; }
|
||||
public string? ManagementUrl { get; set; }
|
||||
public string? DefaultFormat { get; set; }
|
||||
}
|
||||
|
||||
private class LdapConfig
|
||||
{
|
||||
public string? Server { get; set; }
|
||||
public int Port { get; set; } = 636;
|
||||
public bool UseTls { get; set; } = true;
|
||||
public string? SearchBase { get; set; }
|
||||
public string? ServiceAccountDn { get; set; }
|
||||
public string? ServiceAccountPassword { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
using System.Collections.Immutable;
|
||||
using Akka.Actor;
|
||||
using Akka.Cluster.Tools.Client;
|
||||
using Akka.Configuration;
|
||||
using ScadaLink.Commons.Messages.Management;
|
||||
|
||||
namespace ScadaLink.CLI;
|
||||
|
||||
public class ClusterConnection : IAsyncDisposable
|
||||
{
|
||||
private ActorSystem? _system;
|
||||
private IActorRef? _clusterClient;
|
||||
|
||||
public async Task ConnectAsync(IReadOnlyList<string> contactPoints, TimeSpan timeout)
|
||||
{
|
||||
var seedNodes = string.Join(",", contactPoints.Select(cp => $"\"{cp}\""));
|
||||
var config = ConfigurationFactory.ParseString($@"
|
||||
akka {{
|
||||
actor.provider = remote
|
||||
remote.dot-netty.tcp {{
|
||||
hostname = ""127.0.0.1""
|
||||
port = 0
|
||||
}}
|
||||
}}
|
||||
");
|
||||
|
||||
_system = ActorSystem.Create("scadalink-cli", config);
|
||||
|
||||
var initialContacts = contactPoints
|
||||
.Select(cp => $"{cp}/system/receptionist")
|
||||
.Select(path => ActorPath.Parse(path))
|
||||
.ToImmutableHashSet();
|
||||
|
||||
var clientSettings = ClusterClientSettings.Create(_system)
|
||||
.WithInitialContacts(initialContacts);
|
||||
|
||||
_clusterClient = _system.ActorOf(ClusterClient.Props(clientSettings), "cluster-client");
|
||||
|
||||
// Wait for connection by sending a ping
|
||||
// ClusterClient doesn't have a direct "connected" signal, so we rely on the first Ask succeeding
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task<object> AskManagementAsync(ManagementEnvelope envelope, TimeSpan timeout)
|
||||
{
|
||||
if (_clusterClient == null) throw new InvalidOperationException("Not connected");
|
||||
|
||||
var response = await _clusterClient.Ask(
|
||||
new ClusterClient.Send("/user/management", envelope),
|
||||
timeout);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
if (_system != null)
|
||||
{
|
||||
await CoordinatedShutdown.Get(_system).Run(CoordinatedShutdown.ClrExitReason.Instance);
|
||||
_system = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,31 +6,31 @@ namespace ScadaLink.CLI.Commands;
|
||||
|
||||
public static class ApiMethodCommands
|
||||
{
|
||||
public static Command Build(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
public static Command Build(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var command = new Command("api-method") { Description = "Manage inbound API methods" };
|
||||
|
||||
command.Add(BuildList(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildGet(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildCreate(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildUpdate(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDelete(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildList(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildGet(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildCreate(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildUpdate(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDelete(urlOption, formatOption, usernameOption, passwordOption));
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
private static Command BuildList(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildList(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var cmd = new Command("list") { Description = "List all API methods" };
|
||||
cmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new ListApiMethodsCommand());
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new ListApiMethodsCommand());
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildGet(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildGet(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "API method ID", Required = true };
|
||||
var cmd = new Command("get") { Description = "Get an API method by ID" };
|
||||
@@ -39,12 +39,12 @@ public static class ApiMethodCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new GetApiMethodCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new GetApiMethodCommand(id));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildCreate(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildCreate(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var nameOption = new Option<string>("--name") { Description = "Method name", Required = true };
|
||||
var scriptOption = new Option<string>("--script") { Description = "Script code", Required = true };
|
||||
@@ -67,13 +67,13 @@ public static class ApiMethodCommands
|
||||
var parameters = result.GetValue(parametersOption);
|
||||
var returnDef = result.GetValue(returnDefOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new CreateApiMethodCommand(name, script, timeout, parameters, returnDef));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildUpdate(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildUpdate(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "API method ID", Required = true };
|
||||
var scriptOption = new Option<string>("--script") { Description = "Script code", Required = true };
|
||||
@@ -96,13 +96,13 @@ public static class ApiMethodCommands
|
||||
var parameters = result.GetValue(parametersOption);
|
||||
var returnDef = result.GetValue(returnDefOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new UpdateApiMethodCommand(id, script, timeout, parameters, returnDef));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildDelete(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildDelete(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "API method ID", Required = true };
|
||||
var cmd = new Command("delete") { Description = "Delete an API method" };
|
||||
@@ -111,7 +111,7 @@ public static class ApiMethodCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new DeleteApiMethodCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new DeleteApiMethodCommand(id));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
@@ -6,16 +6,16 @@ namespace ScadaLink.CLI.Commands;
|
||||
|
||||
public static class AuditLogCommands
|
||||
{
|
||||
public static Command Build(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
public static Command Build(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var command = new Command("audit-log") { Description = "Query audit logs" };
|
||||
|
||||
command.Add(BuildQuery(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildQuery(urlOption, formatOption, usernameOption, passwordOption));
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
private static Command BuildQuery(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildQuery(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var userOption = new Option<string?>("--user") { Description = "Filter by username" };
|
||||
var entityTypeOption = new Option<string?>("--entity-type") { Description = "Filter by entity type" };
|
||||
@@ -45,7 +45,7 @@ public static class AuditLogCommands
|
||||
var page = result.GetValue(pageOption);
|
||||
var pageSize = result.GetValue(pageSizeOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new QueryAuditLogCommand(user, entityType, action, from, to, page, pageSize));
|
||||
});
|
||||
return cmd;
|
||||
|
||||
@@ -1,46 +1,37 @@
|
||||
using System.CommandLine;
|
||||
using System.CommandLine.Parsing;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using ScadaLink.Commons.Messages.Management;
|
||||
using ScadaLink.Security;
|
||||
|
||||
namespace ScadaLink.CLI.Commands;
|
||||
|
||||
internal static class CommandHelpers
|
||||
{
|
||||
internal static string NewCorrelationId() => Guid.NewGuid().ToString("N");
|
||||
|
||||
internal static async Task<int> ExecuteCommandAsync(
|
||||
ParseResult result,
|
||||
Option<string> contactPointsOption,
|
||||
Option<string> urlOption,
|
||||
Option<string> formatOption,
|
||||
Option<string> usernameOption,
|
||||
Option<string> passwordOption,
|
||||
object command)
|
||||
{
|
||||
var contactPointsRaw = result.GetValue(contactPointsOption);
|
||||
var format = result.GetValue(formatOption) ?? "json";
|
||||
|
||||
var config = CliConfig.Load();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(contactPointsRaw))
|
||||
{
|
||||
if (config.ContactPoints.Count > 0)
|
||||
contactPointsRaw = string.Join(",", config.ContactPoints);
|
||||
}
|
||||
// Resolve management URL
|
||||
var url = result.GetValue(urlOption);
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
url = config.ManagementUrl;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(contactPointsRaw))
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
{
|
||||
OutputFormatter.WriteError("No contact points specified. Use --contact-points or set SCADALINK_CONTACT_POINTS.", "NO_CONTACT_POINTS");
|
||||
OutputFormatter.WriteError(
|
||||
"No management URL specified. Use --url, set SCADALINK_MANAGEMENT_URL, or add 'managementUrl' to ~/.scadalink/config.json.",
|
||||
"NO_URL");
|
||||
return 1;
|
||||
}
|
||||
|
||||
var contactPoints = contactPointsRaw.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
|
||||
// Authenticate via LDAP
|
||||
// Validate credentials
|
||||
var username = result.GetValue(usernameOption);
|
||||
var password = result.GetValue(passwordOption);
|
||||
|
||||
@@ -52,99 +43,36 @@ internal static class CommandHelpers
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Authenticate against LDAP
|
||||
var securityOptions = new SecurityOptions
|
||||
{
|
||||
LdapServer = config.LdapServer ?? string.Empty,
|
||||
LdapPort = config.LdapPort,
|
||||
LdapUseTls = config.LdapUseTls,
|
||||
AllowInsecureLdap = !config.LdapUseTls,
|
||||
LdapSearchBase = config.LdapSearchBase,
|
||||
LdapServiceAccountDn = config.LdapServiceAccountDn,
|
||||
LdapServiceAccountPassword = config.LdapServiceAccountPassword
|
||||
};
|
||||
// Derive command name from type
|
||||
var commandName = ManagementCommandRegistry.GetCommandName(command.GetType());
|
||||
|
||||
var ldapAuth = new LdapAuthService(
|
||||
Options.Create(securityOptions),
|
||||
NullLogger<LdapAuthService>.Instance);
|
||||
|
||||
var authResult = await ldapAuth.AuthenticateAsync(username, password);
|
||||
|
||||
if (!authResult.Success)
|
||||
{
|
||||
OutputFormatter.WriteError(
|
||||
authResult.ErrorMessage ?? "Authentication failed.",
|
||||
"AUTH_FAILED");
|
||||
return 1;
|
||||
}
|
||||
|
||||
await using var connection = new ClusterConnection();
|
||||
await connection.ConnectAsync(contactPoints, TimeSpan.FromSeconds(10));
|
||||
|
||||
// Resolve roles server-side
|
||||
var resolveEnvelope = new ManagementEnvelope(
|
||||
new AuthenticatedUser(authResult.Username!, authResult.DisplayName!, Array.Empty<string>(), Array.Empty<string>()),
|
||||
new ResolveRolesCommand(authResult.Groups ?? (IReadOnlyList<string>)Array.Empty<string>()),
|
||||
NewCorrelationId());
|
||||
var resolveResponse = await connection.AskManagementAsync(resolveEnvelope, TimeSpan.FromSeconds(30));
|
||||
|
||||
string[] roles;
|
||||
string[] permittedSiteIds;
|
||||
|
||||
if (resolveResponse is ManagementSuccess resolveSuccess)
|
||||
{
|
||||
var rolesDoc = JsonDocument.Parse(resolveSuccess.JsonData);
|
||||
roles = rolesDoc.RootElement.TryGetProperty("Roles", out var rolesEl)
|
||||
? rolesEl.EnumerateArray().Select(e => e.GetString()!).ToArray()
|
||||
: Array.Empty<string>();
|
||||
permittedSiteIds = rolesDoc.RootElement.TryGetProperty("PermittedSiteIds", out var sitesEl)
|
||||
? sitesEl.EnumerateArray().Select(e => e.GetString()!).ToArray()
|
||||
: Array.Empty<string>();
|
||||
}
|
||||
else
|
||||
{
|
||||
return HandleResponse(resolveResponse, format);
|
||||
}
|
||||
|
||||
var authenticatedUser = new AuthenticatedUser(
|
||||
authResult.Username!,
|
||||
authResult.DisplayName!,
|
||||
roles,
|
||||
permittedSiteIds);
|
||||
|
||||
var envelope = new ManagementEnvelope(authenticatedUser, command, NewCorrelationId());
|
||||
var response = await connection.AskManagementAsync(envelope, TimeSpan.FromSeconds(30));
|
||||
// Send via HTTP
|
||||
using var client = new ManagementHttpClient(url, username, password);
|
||||
var response = await client.SendCommandAsync(commandName, command, TimeSpan.FromSeconds(30));
|
||||
|
||||
return HandleResponse(response, format);
|
||||
}
|
||||
|
||||
internal static int HandleResponse(object response, string format)
|
||||
internal static int HandleResponse(ManagementResponse response, string format)
|
||||
{
|
||||
switch (response)
|
||||
if (response.JsonData != null)
|
||||
{
|
||||
case ManagementSuccess success:
|
||||
if (string.Equals(format, "table", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
WriteAsTable(success.JsonData);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine(success.JsonData);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case ManagementError error:
|
||||
OutputFormatter.WriteError(error.Error, error.ErrorCode);
|
||||
return 1;
|
||||
|
||||
case ManagementUnauthorized unauth:
|
||||
OutputFormatter.WriteError(unauth.Message, "UNAUTHORIZED");
|
||||
return 2;
|
||||
|
||||
default:
|
||||
OutputFormatter.WriteError($"Unexpected response type: {response.GetType().Name}", "UNEXPECTED_RESPONSE");
|
||||
return 1;
|
||||
if (string.Equals(format, "table", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
WriteAsTable(response.JsonData);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine(response.JsonData);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
var errorCode = response.ErrorCode ?? "ERROR";
|
||||
var error = response.Error ?? "Unknown error";
|
||||
|
||||
OutputFormatter.WriteError(error, errorCode);
|
||||
return response.StatusCode == 403 ? 2 : 1;
|
||||
}
|
||||
|
||||
private static void WriteAsTable(string json)
|
||||
@@ -161,7 +89,6 @@ internal static class CommandHelpers
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract headers from first object's property names
|
||||
var headers = items[0].ValueKind == JsonValueKind.Object
|
||||
? items[0].EnumerateObject().Select(p => p.Name).ToArray()
|
||||
: new[] { "Value" };
|
||||
@@ -182,7 +109,6 @@ internal static class CommandHelpers
|
||||
}
|
||||
else if (root.ValueKind == JsonValueKind.Object)
|
||||
{
|
||||
// Single object: render as key-value pairs
|
||||
var headers = new[] { "Property", "Value" };
|
||||
var rows = root.EnumerateObject().Select(p =>
|
||||
new[] { p.Name, p.Value.ValueKind == JsonValueKind.Null ? "" : p.Value.ToString() });
|
||||
|
||||
@@ -6,22 +6,22 @@ namespace ScadaLink.CLI.Commands;
|
||||
|
||||
public static class DataConnectionCommands
|
||||
{
|
||||
public static Command Build(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
public static Command Build(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var command = new Command("data-connection") { Description = "Manage data connections" };
|
||||
|
||||
command.Add(BuildList(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildGet(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildCreate(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildUpdate(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDelete(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildAssign(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildUnassign(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildList(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildGet(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildCreate(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildUpdate(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDelete(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildAssign(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildUnassign(urlOption, formatOption, usernameOption, passwordOption));
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
private static Command BuildGet(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildGet(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Data connection ID", Required = true };
|
||||
var cmd = new Command("get") { Description = "Get a data connection by ID" };
|
||||
@@ -30,12 +30,12 @@ public static class DataConnectionCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new GetDataConnectionCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new GetDataConnectionCommand(id));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildUpdate(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildUpdate(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Data connection ID", Required = true };
|
||||
var nameOption = new Option<string>("--name") { Description = "Connection name", Required = true };
|
||||
@@ -54,13 +54,13 @@ public static class DataConnectionCommands
|
||||
var protocol = result.GetValue(protocolOption)!;
|
||||
var config = result.GetValue(configOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new UpdateDataConnectionCommand(id, name, protocol, config));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildUnassign(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildUnassign(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--assignment-id") { Description = "Assignment ID", Required = true };
|
||||
var cmd = new Command("unassign") { Description = "Unassign a data connection from a site" };
|
||||
@@ -69,23 +69,23 @@ public static class DataConnectionCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new UnassignDataConnectionFromSiteCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new UnassignDataConnectionFromSiteCommand(id));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildList(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildList(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var cmd = new Command("list") { Description = "List all data connections" };
|
||||
cmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new ListDataConnectionsCommand());
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new ListDataConnectionsCommand());
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildCreate(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildCreate(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var nameOption = new Option<string>("--name") { Description = "Connection name", Required = true };
|
||||
var protocolOption = new Option<string>("--protocol") { Description = "Protocol (e.g. OpcUa)", Required = true };
|
||||
@@ -101,13 +101,13 @@ public static class DataConnectionCommands
|
||||
var protocol = result.GetValue(protocolOption)!;
|
||||
var config = result.GetValue(configOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new CreateDataConnectionCommand(name, protocol, config));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildDelete(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildDelete(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Data connection ID", Required = true };
|
||||
var cmd = new Command("delete") { Description = "Delete a data connection" };
|
||||
@@ -116,12 +116,12 @@ public static class DataConnectionCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new DeleteDataConnectionCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new DeleteDataConnectionCommand(id));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildAssign(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildAssign(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var connectionIdOption = new Option<int>("--connection-id") { Description = "Data connection ID", Required = true };
|
||||
var siteIdOption = new Option<int>("--site-id") { Description = "Site ID", Required = true };
|
||||
@@ -134,7 +134,7 @@ public static class DataConnectionCommands
|
||||
var connectionId = result.GetValue(connectionIdOption);
|
||||
var siteId = result.GetValue(siteIdOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new AssignDataConnectionToSiteCommand(connectionId, siteId));
|
||||
});
|
||||
return cmd;
|
||||
|
||||
@@ -6,31 +6,31 @@ namespace ScadaLink.CLI.Commands;
|
||||
|
||||
public static class DbConnectionCommands
|
||||
{
|
||||
public static Command Build(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
public static Command Build(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var command = new Command("db-connection") { Description = "Manage database connections" };
|
||||
|
||||
command.Add(BuildList(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildGet(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildCreate(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildUpdate(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDelete(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildList(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildGet(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildCreate(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildUpdate(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDelete(urlOption, formatOption, usernameOption, passwordOption));
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
private static Command BuildList(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildList(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var cmd = new Command("list") { Description = "List all database connections" };
|
||||
cmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new ListDatabaseConnectionsCommand());
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new ListDatabaseConnectionsCommand());
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildGet(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildGet(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Database connection ID", Required = true };
|
||||
var cmd = new Command("get") { Description = "Get a database connection by ID" };
|
||||
@@ -39,12 +39,12 @@ public static class DbConnectionCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new GetDatabaseConnectionCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new GetDatabaseConnectionCommand(id));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildCreate(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildCreate(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var nameOption = new Option<string>("--name") { Description = "Connection name", Required = true };
|
||||
var connStrOption = new Option<string>("--connection-string") { Description = "Connection string", Required = true };
|
||||
@@ -57,13 +57,13 @@ public static class DbConnectionCommands
|
||||
var name = result.GetValue(nameOption)!;
|
||||
var connStr = result.GetValue(connStrOption)!;
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new CreateDatabaseConnectionDefCommand(name, connStr));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildUpdate(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildUpdate(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Database connection ID", Required = true };
|
||||
var nameOption = new Option<string>("--name") { Description = "Connection name", Required = true };
|
||||
@@ -79,13 +79,13 @@ public static class DbConnectionCommands
|
||||
var name = result.GetValue(nameOption)!;
|
||||
var connStr = result.GetValue(connStrOption)!;
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new UpdateDatabaseConnectionDefCommand(id, name, connStr));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildDelete(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildDelete(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Database connection ID", Required = true };
|
||||
var cmd = new Command("delete") { Description = "Delete a database connection" };
|
||||
@@ -94,7 +94,7 @@ public static class DbConnectionCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new DeleteDatabaseConnectionDefCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new DeleteDatabaseConnectionDefCommand(id));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
@@ -6,16 +6,16 @@ namespace ScadaLink.CLI.Commands;
|
||||
|
||||
public static class DebugCommands
|
||||
{
|
||||
public static Command Build(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
public static Command Build(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var command = new Command("debug") { Description = "Runtime debugging" };
|
||||
|
||||
command.Add(BuildSnapshot(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildSnapshot(urlOption, formatOption, usernameOption, passwordOption));
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
private static Command BuildSnapshot(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildSnapshot(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Instance ID", Required = true };
|
||||
var cmd = new Command("snapshot") { Description = "Get a point-in-time snapshot of instance attribute values and alarm states" };
|
||||
@@ -23,7 +23,7 @@ public static class DebugCommands
|
||||
cmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new DebugSnapshotCommand(result.GetValue(idOption)));
|
||||
});
|
||||
return cmd;
|
||||
|
||||
@@ -6,18 +6,18 @@ namespace ScadaLink.CLI.Commands;
|
||||
|
||||
public static class DeployCommands
|
||||
{
|
||||
public static Command Build(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
public static Command Build(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var command = new Command("deploy") { Description = "Deployment operations" };
|
||||
|
||||
command.Add(BuildInstance(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildArtifacts(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildStatus(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildInstance(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildArtifacts(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildStatus(urlOption, formatOption, usernameOption, passwordOption));
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
private static Command BuildInstance(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildInstance(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Instance ID", Required = true };
|
||||
var cmd = new Command("instance") { Description = "Deploy a single instance" };
|
||||
@@ -26,12 +26,12 @@ public static class DeployCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new MgmtDeployInstanceCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new MgmtDeployInstanceCommand(id));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildArtifacts(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildArtifacts(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var siteIdOption = new Option<int?>("--site-id") { Description = "Target site ID (all sites if omitted)" };
|
||||
var cmd = new Command("artifacts") { Description = "Deploy artifacts to site(s)" };
|
||||
@@ -40,12 +40,12 @@ public static class DeployCommands
|
||||
{
|
||||
var siteId = result.GetValue(siteIdOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new MgmtDeployArtifactsCommand(siteId));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new MgmtDeployArtifactsCommand(siteId));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildStatus(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildStatus(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var instanceIdOption = new Option<int?>("--instance-id") { Description = "Filter by instance ID" };
|
||||
var statusOption = new Option<string?>("--status") { Description = "Filter by status" };
|
||||
@@ -66,7 +66,7 @@ public static class DeployCommands
|
||||
var page = result.GetValue(pageOption);
|
||||
var pageSize = result.GetValue(pageSizeOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new QueryDeploymentsCommand(instanceId, status, page, pageSize));
|
||||
});
|
||||
return cmd;
|
||||
|
||||
@@ -6,21 +6,21 @@ namespace ScadaLink.CLI.Commands;
|
||||
|
||||
public static class ExternalSystemCommands
|
||||
{
|
||||
public static Command Build(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
public static Command Build(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var command = new Command("external-system") { Description = "Manage external systems" };
|
||||
|
||||
command.Add(BuildList(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildGet(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildCreate(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildUpdate(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDelete(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildMethodGroup(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildList(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildGet(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildCreate(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildUpdate(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDelete(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildMethodGroup(urlOption, formatOption, usernameOption, passwordOption));
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
private static Command BuildGet(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildGet(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "External system ID", Required = true };
|
||||
var cmd = new Command("get") { Description = "Get an external system by ID" };
|
||||
@@ -29,76 +29,76 @@ public static class ExternalSystemCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new GetExternalSystemCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new GetExternalSystemCommand(id));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildUpdate(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildUpdate(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "External system ID", Required = true };
|
||||
var nameOption = new Option<string>("--name") { Description = "System name", Required = true };
|
||||
var urlOption = new Option<string>("--endpoint-url") { Description = "Endpoint URL", Required = true };
|
||||
var endpointUrlOption = new Option<string>("--endpoint-url") { Description = "Endpoint URL", Required = true };
|
||||
var authTypeOption = new Option<string>("--auth-type") { Description = "Auth type", Required = true };
|
||||
var authConfigOption = new Option<string?>("--auth-config") { Description = "Auth configuration JSON" };
|
||||
|
||||
var cmd = new Command("update") { Description = "Update an external system" };
|
||||
cmd.Add(idOption);
|
||||
cmd.Add(nameOption);
|
||||
cmd.Add(urlOption);
|
||||
cmd.Add(endpointUrlOption);
|
||||
cmd.Add(authTypeOption);
|
||||
cmd.Add(authConfigOption);
|
||||
cmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
var name = result.GetValue(nameOption)!;
|
||||
var url = result.GetValue(urlOption)!;
|
||||
var endpointUrl = result.GetValue(endpointUrlOption)!;
|
||||
var authType = result.GetValue(authTypeOption)!;
|
||||
var authConfig = result.GetValue(authConfigOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
new UpdateExternalSystemCommand(id, name, url, authType, authConfig));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new UpdateExternalSystemCommand(id, name, endpointUrl, authType, authConfig));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildList(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildList(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var cmd = new Command("list") { Description = "List all external systems" };
|
||||
cmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new ListExternalSystemsCommand());
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new ListExternalSystemsCommand());
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildCreate(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildCreate(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var nameOption = new Option<string>("--name") { Description = "System name", Required = true };
|
||||
var urlOption = new Option<string>("--endpoint-url") { Description = "Endpoint URL", Required = true };
|
||||
var endpointUrlOption = new Option<string>("--endpoint-url") { Description = "Endpoint URL", Required = true };
|
||||
var authTypeOption = new Option<string>("--auth-type") { Description = "Auth type (ApiKey, BasicAuth)", Required = true };
|
||||
var authConfigOption = new Option<string?>("--auth-config") { Description = "Auth configuration JSON" };
|
||||
|
||||
var cmd = new Command("create") { Description = "Create an external system" };
|
||||
cmd.Add(nameOption);
|
||||
cmd.Add(urlOption);
|
||||
cmd.Add(endpointUrlOption);
|
||||
cmd.Add(authTypeOption);
|
||||
cmd.Add(authConfigOption);
|
||||
cmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
var name = result.GetValue(nameOption)!;
|
||||
var url = result.GetValue(urlOption)!;
|
||||
var endpointUrl = result.GetValue(endpointUrlOption)!;
|
||||
var authType = result.GetValue(authTypeOption)!;
|
||||
var authConfig = result.GetValue(authConfigOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
new CreateExternalSystemCommand(name, url, authType, authConfig));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new CreateExternalSystemCommand(name, endpointUrl, authType, authConfig));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildDelete(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildDelete(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "External system ID", Required = true };
|
||||
var cmd = new Command("delete") { Description = "Delete an external system" };
|
||||
@@ -107,25 +107,25 @@ public static class ExternalSystemCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new DeleteExternalSystemCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new DeleteExternalSystemCommand(id));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
// -- Method subcommands --
|
||||
|
||||
private static Command BuildMethodGroup(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildMethodGroup(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var group = new Command("method") { Description = "Manage external system methods" };
|
||||
group.Add(BuildMethodList(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
group.Add(BuildMethodGet(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
group.Add(BuildMethodCreate(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
group.Add(BuildMethodUpdate(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
group.Add(BuildMethodDelete(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
group.Add(BuildMethodList(urlOption, formatOption, usernameOption, passwordOption));
|
||||
group.Add(BuildMethodGet(urlOption, formatOption, usernameOption, passwordOption));
|
||||
group.Add(BuildMethodCreate(urlOption, formatOption, usernameOption, passwordOption));
|
||||
group.Add(BuildMethodUpdate(urlOption, formatOption, usernameOption, passwordOption));
|
||||
group.Add(BuildMethodDelete(urlOption, formatOption, usernameOption, passwordOption));
|
||||
return group;
|
||||
}
|
||||
|
||||
private static Command BuildMethodList(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildMethodList(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var sysIdOption = new Option<int>("--external-system-id") { Description = "External system ID", Required = true };
|
||||
var cmd = new Command("list") { Description = "List methods for an external system" };
|
||||
@@ -133,13 +133,13 @@ public static class ExternalSystemCommands
|
||||
cmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new ListExternalSystemMethodsCommand(result.GetValue(sysIdOption)));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildMethodGet(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildMethodGet(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Method ID", Required = true };
|
||||
var cmd = new Command("get") { Description = "Get an external system method by ID" };
|
||||
@@ -147,13 +147,13 @@ public static class ExternalSystemCommands
|
||||
cmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new GetExternalSystemMethodCommand(result.GetValue(idOption)));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildMethodCreate(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildMethodCreate(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var sysIdOption = new Option<int>("--external-system-id") { Description = "External system ID", Required = true };
|
||||
var nameOption = new Option<string>("--name") { Description = "Method name", Required = true };
|
||||
@@ -172,7 +172,7 @@ public static class ExternalSystemCommands
|
||||
cmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new CreateExternalSystemMethodCommand(
|
||||
result.GetValue(sysIdOption),
|
||||
result.GetValue(nameOption)!,
|
||||
@@ -184,7 +184,7 @@ public static class ExternalSystemCommands
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildMethodUpdate(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildMethodUpdate(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Method ID", Required = true };
|
||||
var nameOption = new Option<string?>("--name") { Description = "Method name" };
|
||||
@@ -203,7 +203,7 @@ public static class ExternalSystemCommands
|
||||
cmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new UpdateExternalSystemMethodCommand(
|
||||
result.GetValue(idOption),
|
||||
result.GetValue(nameOption),
|
||||
@@ -215,7 +215,7 @@ public static class ExternalSystemCommands
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildMethodDelete(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildMethodDelete(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Method ID", Required = true };
|
||||
var cmd = new Command("delete") { Description = "Delete an external system method" };
|
||||
@@ -223,7 +223,7 @@ public static class ExternalSystemCommands
|
||||
cmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new DeleteExternalSystemMethodCommand(result.GetValue(idOption)));
|
||||
});
|
||||
return cmd;
|
||||
|
||||
@@ -6,30 +6,30 @@ namespace ScadaLink.CLI.Commands;
|
||||
|
||||
public static class HealthCommands
|
||||
{
|
||||
public static Command Build(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
public static Command Build(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var command = new Command("health") { Description = "Health monitoring" };
|
||||
|
||||
command.Add(BuildSummary(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildSite(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildEventLog(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildParkedMessages(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildSummary(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildSite(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildEventLog(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildParkedMessages(urlOption, formatOption, usernameOption, passwordOption));
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
private static Command BuildSummary(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildSummary(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var cmd = new Command("summary") { Description = "Get system health summary" };
|
||||
cmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new GetHealthSummaryCommand());
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new GetHealthSummaryCommand());
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildSite(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildSite(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var identifierOption = new Option<string>("--identifier") { Description = "Site identifier", Required = true };
|
||||
var cmd = new Command("site") { Description = "Get health for a specific site" };
|
||||
@@ -38,12 +38,12 @@ public static class HealthCommands
|
||||
{
|
||||
var identifier = result.GetValue(identifierOption)!;
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new GetSiteHealthCommand(identifier));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new GetSiteHealthCommand(identifier));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildEventLog(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildEventLog(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var siteOption = new Option<string>("--site") { Description = "Site identifier", Required = true };
|
||||
var eventTypeOption = new Option<string?>("--event-type") { Description = "Filter by event type" };
|
||||
@@ -70,7 +70,7 @@ public static class HealthCommands
|
||||
cmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new QueryEventLogsCommand(
|
||||
result.GetValue(siteOption)!,
|
||||
result.GetValue(eventTypeOption),
|
||||
@@ -85,7 +85,7 @@ public static class HealthCommands
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildParkedMessages(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildParkedMessages(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var siteOption = new Option<string>("--site") { Description = "Site identifier", Required = true };
|
||||
var pageOption = new Option<int>("--page") { Description = "Page number" };
|
||||
@@ -100,7 +100,7 @@ public static class HealthCommands
|
||||
cmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new QueryParkedMessagesCommand(
|
||||
result.GetValue(siteOption)!,
|
||||
result.GetValue(pageOption),
|
||||
|
||||
@@ -6,26 +6,26 @@ namespace ScadaLink.CLI.Commands;
|
||||
|
||||
public static class InstanceCommands
|
||||
{
|
||||
public static Command Build(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
public static Command Build(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var command = new Command("instance") { Description = "Manage instances" };
|
||||
|
||||
command.Add(BuildList(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildGet(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildCreate(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildSetBindings(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildSetOverrides(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildSetArea(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDiff(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDeploy(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildEnable(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDisable(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDelete(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildList(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildGet(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildCreate(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildSetBindings(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildSetOverrides(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildSetArea(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDiff(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDeploy(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildEnable(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDisable(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDelete(urlOption, formatOption, usernameOption, passwordOption));
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
private static Command BuildGet(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildGet(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Instance ID", Required = true };
|
||||
var cmd = new Command("get") { Description = "Get an instance by ID" };
|
||||
@@ -34,12 +34,12 @@ public static class InstanceCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new GetInstanceCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new GetInstanceCommand(id));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildSetBindings(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildSetBindings(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Instance ID", Required = true };
|
||||
var bindingsOption = new Option<string>("--bindings") { Description = "JSON array of [attributeName, dataConnectionId] pairs", Required = true };
|
||||
@@ -56,13 +56,13 @@ public static class InstanceCommands
|
||||
var bindings = pairs.Select(p =>
|
||||
(p[0].ToString()!, int.Parse(p[1].ToString()!))).ToList();
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new SetConnectionBindingsCommand(id, bindings));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildList(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildList(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var siteIdOption = new Option<int?>("--site-id") { Description = "Filter by site ID" };
|
||||
var templateIdOption = new Option<int?>("--template-id") { Description = "Filter by template ID" };
|
||||
@@ -78,13 +78,13 @@ public static class InstanceCommands
|
||||
var templateId = result.GetValue(templateIdOption);
|
||||
var search = result.GetValue(searchOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new ListInstancesCommand(siteId, templateId, search));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildCreate(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildCreate(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var nameOption = new Option<string>("--name") { Description = "Unique instance name", Required = true };
|
||||
var templateIdOption = new Option<int>("--template-id") { Description = "Template ID", Required = true };
|
||||
@@ -103,13 +103,13 @@ public static class InstanceCommands
|
||||
var siteId = result.GetValue(siteIdOption);
|
||||
var areaId = result.GetValue(areaIdOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new CreateInstanceCommand(name, templateId, siteId, areaId));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildDeploy(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildDeploy(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Instance ID", Required = true };
|
||||
var cmd = new Command("deploy") { Description = "Deploy an instance" };
|
||||
@@ -118,12 +118,12 @@ public static class InstanceCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new MgmtDeployInstanceCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new MgmtDeployInstanceCommand(id));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildEnable(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildEnable(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Instance ID", Required = true };
|
||||
var cmd = new Command("enable") { Description = "Enable an instance" };
|
||||
@@ -132,12 +132,12 @@ public static class InstanceCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new MgmtEnableInstanceCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new MgmtEnableInstanceCommand(id));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildDisable(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildDisable(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Instance ID", Required = true };
|
||||
var cmd = new Command("disable") { Description = "Disable an instance" };
|
||||
@@ -146,12 +146,12 @@ public static class InstanceCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new MgmtDisableInstanceCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new MgmtDisableInstanceCommand(id));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildDelete(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildDelete(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Instance ID", Required = true };
|
||||
var cmd = new Command("delete") { Description = "Delete an instance" };
|
||||
@@ -160,12 +160,12 @@ public static class InstanceCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new MgmtDeleteInstanceCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new MgmtDeleteInstanceCommand(id));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildSetOverrides(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildSetOverrides(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Instance ID", Required = true };
|
||||
var overridesOption = new Option<string>("--overrides") { Description = "JSON object of attribute name -> value pairs, e.g. {\"Speed\": \"100\", \"Mode\": null}", Required = true };
|
||||
@@ -180,13 +180,13 @@ public static class InstanceCommands
|
||||
var overrides = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, string?>>(overridesJson)
|
||||
?? throw new InvalidOperationException("Invalid overrides JSON");
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new SetInstanceOverridesCommand(id, overrides));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildSetArea(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildSetArea(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Instance ID", Required = true };
|
||||
var areaIdOption = new Option<int?>("--area-id") { Description = "Area ID (omit to clear area assignment)" };
|
||||
@@ -199,13 +199,13 @@ public static class InstanceCommands
|
||||
var id = result.GetValue(idOption);
|
||||
var areaId = result.GetValue(areaIdOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new SetInstanceAreaCommand(id, areaId));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildDiff(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildDiff(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Instance ID", Required = true };
|
||||
|
||||
@@ -215,7 +215,7 @@ public static class InstanceCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new GetDeploymentDiffCommand(id));
|
||||
});
|
||||
return cmd;
|
||||
|
||||
@@ -6,21 +6,21 @@ namespace ScadaLink.CLI.Commands;
|
||||
|
||||
public static class NotificationCommands
|
||||
{
|
||||
public static Command Build(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
public static Command Build(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var command = new Command("notification") { Description = "Manage notification lists" };
|
||||
|
||||
command.Add(BuildList(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildGet(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildCreate(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildUpdate(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDelete(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildSmtp(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildList(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildGet(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildCreate(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildUpdate(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDelete(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildSmtp(urlOption, formatOption, usernameOption, passwordOption));
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
private static Command BuildGet(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildGet(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Notification list ID", Required = true };
|
||||
var cmd = new Command("get") { Description = "Get a notification list by ID" };
|
||||
@@ -29,12 +29,12 @@ public static class NotificationCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new GetNotificationListCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new GetNotificationListCommand(id));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildUpdate(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildUpdate(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Notification list ID", Required = true };
|
||||
var nameOption = new Option<string>("--name") { Description = "List name", Required = true };
|
||||
@@ -51,13 +51,13 @@ public static class NotificationCommands
|
||||
var emailsRaw = result.GetValue(emailsOption)!;
|
||||
var emails = emailsRaw.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).ToList();
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new UpdateNotificationListCommand(id, name, emails));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildSmtp(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildSmtp(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var group = new Command("smtp") { Description = "Manage SMTP configuration" };
|
||||
|
||||
@@ -65,7 +65,7 @@ public static class NotificationCommands
|
||||
listCmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new ListSmtpConfigsCommand());
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new ListSmtpConfigsCommand());
|
||||
});
|
||||
group.Add(listCmd);
|
||||
|
||||
@@ -88,7 +88,7 @@ public static class NotificationCommands
|
||||
var authMode = result.GetValue(authModeOption)!;
|
||||
var from = result.GetValue(fromOption)!;
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new UpdateSmtpConfigCommand(id, server, port, authMode, from));
|
||||
});
|
||||
group.Add(updateCmd);
|
||||
@@ -96,18 +96,18 @@ public static class NotificationCommands
|
||||
return group;
|
||||
}
|
||||
|
||||
private static Command BuildList(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildList(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var cmd = new Command("list") { Description = "List all notification lists" };
|
||||
cmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new ListNotificationListsCommand());
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new ListNotificationListsCommand());
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildCreate(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildCreate(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var nameOption = new Option<string>("--name") { Description = "Notification list name", Required = true };
|
||||
var emailsOption = new Option<string>("--emails") { Description = "Comma-separated recipient emails", Required = true };
|
||||
@@ -121,13 +121,13 @@ public static class NotificationCommands
|
||||
var emailsRaw = result.GetValue(emailsOption)!;
|
||||
var emails = emailsRaw.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).ToList();
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new CreateNotificationListCommand(name, emails));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildDelete(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildDelete(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Notification list ID", Required = true };
|
||||
var cmd = new Command("delete") { Description = "Delete a notification list" };
|
||||
@@ -136,7 +136,7 @@ public static class NotificationCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new DeleteNotificationListCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new DeleteNotificationListCommand(id));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
@@ -6,18 +6,18 @@ namespace ScadaLink.CLI.Commands;
|
||||
|
||||
public static class SecurityCommands
|
||||
{
|
||||
public static Command Build(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
public static Command Build(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var command = new Command("security") { Description = "Manage security settings" };
|
||||
|
||||
command.Add(BuildApiKey(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildRoleMapping(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildScopeRule(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildApiKey(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildRoleMapping(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildScopeRule(urlOption, formatOption, usernameOption, passwordOption));
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
private static Command BuildApiKey(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildApiKey(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var group = new Command("api-key") { Description = "Manage API keys" };
|
||||
|
||||
@@ -25,7 +25,7 @@ public static class SecurityCommands
|
||||
listCmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new ListApiKeysCommand());
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new ListApiKeysCommand());
|
||||
});
|
||||
group.Add(listCmd);
|
||||
|
||||
@@ -36,7 +36,7 @@ public static class SecurityCommands
|
||||
{
|
||||
var name = result.GetValue(nameOption)!;
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new CreateApiKeyCommand(name));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new CreateApiKeyCommand(name));
|
||||
});
|
||||
group.Add(createCmd);
|
||||
|
||||
@@ -47,7 +47,7 @@ public static class SecurityCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new DeleteApiKeyCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new DeleteApiKeyCommand(id));
|
||||
});
|
||||
group.Add(deleteCmd);
|
||||
|
||||
@@ -61,14 +61,14 @@ public static class SecurityCommands
|
||||
var id = result.GetValue(updateIdOption);
|
||||
var enabled = result.GetValue(enabledOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new UpdateApiKeyCommand(id, enabled));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new UpdateApiKeyCommand(id, enabled));
|
||||
});
|
||||
group.Add(updateCmd);
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
private static Command BuildRoleMapping(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildRoleMapping(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var group = new Command("role-mapping") { Description = "Manage LDAP role mappings" };
|
||||
|
||||
@@ -76,7 +76,7 @@ public static class SecurityCommands
|
||||
listCmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new ListRoleMappingsCommand());
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new ListRoleMappingsCommand());
|
||||
});
|
||||
group.Add(listCmd);
|
||||
|
||||
@@ -90,7 +90,7 @@ public static class SecurityCommands
|
||||
var ldapGroup = result.GetValue(ldapGroupOption)!;
|
||||
var role = result.GetValue(roleOption)!;
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new CreateRoleMappingCommand(ldapGroup, role));
|
||||
});
|
||||
group.Add(createCmd);
|
||||
@@ -102,7 +102,7 @@ public static class SecurityCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new DeleteRoleMappingCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new DeleteRoleMappingCommand(id));
|
||||
});
|
||||
group.Add(deleteCmd);
|
||||
|
||||
@@ -119,7 +119,7 @@ public static class SecurityCommands
|
||||
var ldapGroup = result.GetValue(updateLdapGroupOption)!;
|
||||
var role = result.GetValue(updateRoleOption)!;
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new UpdateRoleMappingCommand(id, ldapGroup, role));
|
||||
});
|
||||
group.Add(updateCmd);
|
||||
@@ -127,7 +127,7 @@ public static class SecurityCommands
|
||||
return group;
|
||||
}
|
||||
|
||||
private static Command BuildScopeRule(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildScopeRule(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var group = new Command("scope-rule") { Description = "Manage LDAP scope rules" };
|
||||
|
||||
@@ -138,7 +138,7 @@ public static class SecurityCommands
|
||||
{
|
||||
var mappingId = result.GetValue(mappingIdOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new ListScopeRulesCommand(mappingId));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new ListScopeRulesCommand(mappingId));
|
||||
});
|
||||
group.Add(listCmd);
|
||||
|
||||
@@ -152,7 +152,7 @@ public static class SecurityCommands
|
||||
var mappingId = result.GetValue(addMappingIdOption);
|
||||
var siteId = result.GetValue(siteIdOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new AddScopeRuleCommand(mappingId, siteId));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new AddScopeRuleCommand(mappingId, siteId));
|
||||
});
|
||||
group.Add(addCmd);
|
||||
|
||||
@@ -163,7 +163,7 @@ public static class SecurityCommands
|
||||
{
|
||||
var id = result.GetValue(deleteIdOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new DeleteScopeRuleCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new DeleteScopeRuleCommand(id));
|
||||
});
|
||||
group.Add(deleteCmd);
|
||||
|
||||
|
||||
@@ -6,31 +6,31 @@ namespace ScadaLink.CLI.Commands;
|
||||
|
||||
public static class SharedScriptCommands
|
||||
{
|
||||
public static Command Build(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
public static Command Build(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var command = new Command("shared-script") { Description = "Manage shared scripts" };
|
||||
|
||||
command.Add(BuildList(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildGet(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildCreate(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildUpdate(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDelete(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildList(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildGet(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildCreate(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildUpdate(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDelete(urlOption, formatOption, usernameOption, passwordOption));
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
private static Command BuildList(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildList(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var cmd = new Command("list") { Description = "List all shared scripts" };
|
||||
cmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new ListSharedScriptsCommand());
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new ListSharedScriptsCommand());
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildGet(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildGet(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Shared script ID", Required = true };
|
||||
var cmd = new Command("get") { Description = "Get a shared script by ID" };
|
||||
@@ -39,12 +39,12 @@ public static class SharedScriptCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new GetSharedScriptCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new GetSharedScriptCommand(id));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildCreate(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildCreate(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var nameOption = new Option<string>("--name") { Description = "Script name", Required = true };
|
||||
var codeOption = new Option<string>("--code") { Description = "Script code", Required = true };
|
||||
@@ -63,13 +63,13 @@ public static class SharedScriptCommands
|
||||
var parameters = result.GetValue(parametersOption);
|
||||
var returnDef = result.GetValue(returnDefOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new CreateSharedScriptCommand(name, code, parameters, returnDef));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildUpdate(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildUpdate(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Shared script ID", Required = true };
|
||||
var nameOption = new Option<string>("--name") { Description = "Script name", Required = true };
|
||||
@@ -91,13 +91,13 @@ public static class SharedScriptCommands
|
||||
var parameters = result.GetValue(parametersOption);
|
||||
var returnDef = result.GetValue(returnDefOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new UpdateSharedScriptCommand(id, name, code, parameters, returnDef));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildDelete(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildDelete(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Shared script ID", Required = true };
|
||||
var cmd = new Command("delete") { Description = "Delete a shared script" };
|
||||
@@ -106,7 +106,7 @@ public static class SharedScriptCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new DeleteSharedScriptCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new DeleteSharedScriptCommand(id));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
@@ -6,22 +6,22 @@ namespace ScadaLink.CLI.Commands;
|
||||
|
||||
public static class SiteCommands
|
||||
{
|
||||
public static Command Build(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
public static Command Build(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var command = new Command("site") { Description = "Manage sites" };
|
||||
|
||||
command.Add(BuildList(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildGet(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildCreate(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildUpdate(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDelete(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDeployArtifacts(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildArea(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildList(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildGet(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildCreate(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildUpdate(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDelete(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDeployArtifacts(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildArea(urlOption, formatOption, usernameOption, passwordOption));
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
private static Command BuildGet(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildGet(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Site ID", Required = true };
|
||||
var cmd = new Command("get") { Description = "Get a site by ID" };
|
||||
@@ -30,23 +30,23 @@ public static class SiteCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new GetSiteCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new GetSiteCommand(id));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildList(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildList(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var cmd = new Command("list") { Description = "List all sites" };
|
||||
cmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new ListSitesCommand());
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new ListSitesCommand());
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildCreate(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildCreate(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var nameOption = new Option<string>("--name") { Description = "Site name", Required = true };
|
||||
var identifierOption = new Option<string>("--identifier") { Description = "Site identifier", Required = true };
|
||||
@@ -68,13 +68,13 @@ public static class SiteCommands
|
||||
var nodeA = result.GetValue(nodeAOption);
|
||||
var nodeB = result.GetValue(nodeBOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new CreateSiteCommand(name, identifier, desc, nodeA, nodeB));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildUpdate(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildUpdate(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Site ID", Required = true };
|
||||
var nameOption = new Option<string>("--name") { Description = "Site name", Required = true };
|
||||
@@ -96,13 +96,13 @@ public static class SiteCommands
|
||||
var nodeA = result.GetValue(nodeAOption);
|
||||
var nodeB = result.GetValue(nodeBOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new UpdateSiteCommand(id, name, desc, nodeA, nodeB));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildDelete(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildDelete(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Site ID", Required = true };
|
||||
var cmd = new Command("delete") { Description = "Delete a site" };
|
||||
@@ -111,12 +111,12 @@ public static class SiteCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new DeleteSiteCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new DeleteSiteCommand(id));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildArea(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildArea(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var group = new Command("area") { Description = "Manage areas" };
|
||||
|
||||
@@ -127,7 +127,7 @@ public static class SiteCommands
|
||||
{
|
||||
var siteId = result.GetValue(siteIdOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new ListAreasCommand(siteId));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new ListAreasCommand(siteId));
|
||||
});
|
||||
group.Add(listCmd);
|
||||
|
||||
@@ -144,7 +144,7 @@ public static class SiteCommands
|
||||
var name = result.GetValue(nameOption)!;
|
||||
var parentId = result.GetValue(parentOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new CreateAreaCommand(siteId, name, parentId));
|
||||
});
|
||||
group.Add(createCmd);
|
||||
@@ -159,7 +159,7 @@ public static class SiteCommands
|
||||
var id = result.GetValue(updateIdOption);
|
||||
var name = result.GetValue(updateNameOption)!;
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new UpdateAreaCommand(id, name));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new UpdateAreaCommand(id, name));
|
||||
});
|
||||
group.Add(updateCmd);
|
||||
|
||||
@@ -170,14 +170,14 @@ public static class SiteCommands
|
||||
{
|
||||
var id = result.GetValue(deleteIdOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new DeleteAreaCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new DeleteAreaCommand(id));
|
||||
});
|
||||
group.Add(deleteCmd);
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
private static Command BuildDeployArtifacts(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildDeployArtifacts(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var siteIdOption = new Option<int?>("--site-id") { Description = "Target site ID (all sites if omitted)" };
|
||||
var cmd = new Command("deploy-artifacts") { Description = "Deploy artifacts to site(s)" };
|
||||
@@ -186,7 +186,7 @@ public static class SiteCommands
|
||||
{
|
||||
var siteId = result.GetValue(siteIdOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new MgmtDeployArtifactsCommand(siteId));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new MgmtDeployArtifactsCommand(siteId));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
@@ -6,36 +6,36 @@ namespace ScadaLink.CLI.Commands;
|
||||
|
||||
public static class TemplateCommands
|
||||
{
|
||||
public static Command Build(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
public static Command Build(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var command = new Command("template") { Description = "Manage templates" };
|
||||
|
||||
command.Add(BuildList(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildGet(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildCreate(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildUpdate(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildValidate(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDelete(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildAttribute(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildAlarm(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildScript(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildComposition(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildList(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildGet(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildCreate(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildUpdate(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildValidate(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildDelete(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildAttribute(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildAlarm(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildScript(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildComposition(urlOption, formatOption, usernameOption, passwordOption));
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
private static Command BuildList(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildList(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var cmd = new Command("list") { Description = "List all templates" };
|
||||
cmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new ListTemplatesCommand());
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new ListTemplatesCommand());
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildGet(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildGet(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Template ID", Required = true };
|
||||
var cmd = new Command("get") { Description = "Get a template by ID" };
|
||||
@@ -44,12 +44,12 @@ public static class TemplateCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new GetTemplateCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new GetTemplateCommand(id));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildCreate(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildCreate(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var nameOption = new Option<string>("--name") { Description = "Template name", Required = true };
|
||||
var descOption = new Option<string?>("--description") { Description = "Template description" };
|
||||
@@ -65,13 +65,13 @@ public static class TemplateCommands
|
||||
var desc = result.GetValue(descOption);
|
||||
var parentId = result.GetValue(parentOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new CreateTemplateCommand(name, desc, parentId));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildUpdate(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildUpdate(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Template ID", Required = true };
|
||||
var nameOption = new Option<string>("--name") { Description = "Template name", Required = true };
|
||||
@@ -90,13 +90,13 @@ public static class TemplateCommands
|
||||
var desc = result.GetValue(descOption);
|
||||
var parentId = result.GetValue(parentOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new UpdateTemplateCommand(id, name, desc, parentId));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildValidate(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildValidate(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Template ID", Required = true };
|
||||
var cmd = new Command("validate") { Description = "Validate a template" };
|
||||
@@ -105,12 +105,12 @@ public static class TemplateCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new ValidateTemplateCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new ValidateTemplateCommand(id));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildDelete(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildDelete(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var idOption = new Option<int>("--id") { Description = "Template ID", Required = true };
|
||||
var cmd = new Command("delete") { Description = "Delete a template" };
|
||||
@@ -119,12 +119,12 @@ public static class TemplateCommands
|
||||
{
|
||||
var id = result.GetValue(idOption);
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption, new DeleteTemplateCommand(id));
|
||||
result, urlOption, formatOption, usernameOption, passwordOption, new DeleteTemplateCommand(id));
|
||||
});
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildAttribute(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildAttribute(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var group = new Command("attribute") { Description = "Manage template attributes" };
|
||||
|
||||
@@ -148,7 +148,7 @@ public static class TemplateCommands
|
||||
addCmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new AddTemplateAttributeCommand(
|
||||
result.GetValue(templateIdOption),
|
||||
result.GetValue(nameOption)!,
|
||||
@@ -180,7 +180,7 @@ public static class TemplateCommands
|
||||
updateCmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new UpdateTemplateAttributeCommand(
|
||||
result.GetValue(updateIdOption),
|
||||
result.GetValue(updateNameOption)!,
|
||||
@@ -198,7 +198,7 @@ public static class TemplateCommands
|
||||
deleteCmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new DeleteTemplateAttributeCommand(result.GetValue(deleteIdOption)));
|
||||
});
|
||||
group.Add(deleteCmd);
|
||||
@@ -206,7 +206,7 @@ public static class TemplateCommands
|
||||
return group;
|
||||
}
|
||||
|
||||
private static Command BuildAlarm(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildAlarm(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var group = new Command("alarm") { Description = "Manage template alarms" };
|
||||
|
||||
@@ -230,7 +230,7 @@ public static class TemplateCommands
|
||||
addCmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new AddTemplateAlarmCommand(
|
||||
result.GetValue(templateIdOption),
|
||||
result.GetValue(nameOption)!,
|
||||
@@ -262,7 +262,7 @@ public static class TemplateCommands
|
||||
updateCmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new UpdateTemplateAlarmCommand(
|
||||
result.GetValue(updateIdOption),
|
||||
result.GetValue(updateNameOption)!,
|
||||
@@ -280,7 +280,7 @@ public static class TemplateCommands
|
||||
deleteCmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new DeleteTemplateAlarmCommand(result.GetValue(deleteIdOption)));
|
||||
});
|
||||
group.Add(deleteCmd);
|
||||
@@ -288,7 +288,7 @@ public static class TemplateCommands
|
||||
return group;
|
||||
}
|
||||
|
||||
private static Command BuildScript(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildScript(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var group = new Command("script") { Description = "Manage template scripts" };
|
||||
|
||||
@@ -315,7 +315,7 @@ public static class TemplateCommands
|
||||
addCmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new AddTemplateScriptCommand(
|
||||
result.GetValue(templateIdOption),
|
||||
result.GetValue(nameOption)!,
|
||||
@@ -351,7 +351,7 @@ public static class TemplateCommands
|
||||
updateCmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new UpdateTemplateScriptCommand(
|
||||
result.GetValue(updateIdOption),
|
||||
result.GetValue(updateNameOption)!,
|
||||
@@ -370,7 +370,7 @@ public static class TemplateCommands
|
||||
deleteCmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new DeleteTemplateScriptCommand(result.GetValue(deleteIdOption)));
|
||||
});
|
||||
group.Add(deleteCmd);
|
||||
@@ -378,7 +378,7 @@ public static class TemplateCommands
|
||||
return group;
|
||||
}
|
||||
|
||||
private static Command BuildComposition(Option<string> contactPointsOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
private static Command BuildComposition(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var group = new Command("composition") { Description = "Manage template compositions" };
|
||||
|
||||
@@ -393,7 +393,7 @@ public static class TemplateCommands
|
||||
addCmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new AddTemplateCompositionCommand(
|
||||
result.GetValue(templateIdOption),
|
||||
result.GetValue(instanceNameOption)!,
|
||||
@@ -407,7 +407,7 @@ public static class TemplateCommands
|
||||
deleteCmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, contactPointsOption, formatOption, usernameOption, passwordOption,
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new DeleteTemplateCompositionCommand(result.GetValue(deleteIdOption)));
|
||||
});
|
||||
group.Add(deleteCmd);
|
||||
|
||||
69
src/ScadaLink.CLI/ManagementHttpClient.cs
Normal file
69
src/ScadaLink.CLI/ManagementHttpClient.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace ScadaLink.CLI;
|
||||
|
||||
public class ManagementHttpClient : IDisposable
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
|
||||
public ManagementHttpClient(string baseUrl, string username, string password)
|
||||
{
|
||||
_httpClient = new HttpClient { BaseAddress = new Uri(baseUrl.TrimEnd('/') + "/") };
|
||||
var credentials = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{username}:{password}"));
|
||||
_httpClient.DefaultRequestHeaders.Authorization =
|
||||
new AuthenticationHeaderValue("Basic", credentials);
|
||||
}
|
||||
|
||||
public async Task<ManagementResponse> SendCommandAsync(string commandName, object payload, TimeSpan timeout)
|
||||
{
|
||||
using var cts = new CancellationTokenSource(timeout);
|
||||
|
||||
var body = JsonSerializer.Serialize(new { command = commandName, payload },
|
||||
new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
|
||||
|
||||
var content = new StringContent(body, Encoding.UTF8, "application/json");
|
||||
|
||||
HttpResponseMessage httpResponse;
|
||||
try
|
||||
{
|
||||
httpResponse = await _httpClient.PostAsync("management", content, cts.Token);
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
return new ManagementResponse(504, null, "Request timed out.", "TIMEOUT");
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
return new ManagementResponse(0, null, $"Connection failed: {ex.Message}", "CONNECTION_FAILED");
|
||||
}
|
||||
|
||||
var responseBody = await httpResponse.Content.ReadAsStringAsync(cts.Token);
|
||||
|
||||
if (httpResponse.IsSuccessStatusCode)
|
||||
{
|
||||
return new ManagementResponse((int)httpResponse.StatusCode, responseBody, null, null);
|
||||
}
|
||||
|
||||
// Parse error response
|
||||
string? error = null;
|
||||
string? code = null;
|
||||
try
|
||||
{
|
||||
using var doc = JsonDocument.Parse(responseBody);
|
||||
error = doc.RootElement.TryGetProperty("error", out var e) ? e.GetString() : responseBody;
|
||||
code = doc.RootElement.TryGetProperty("code", out var c) ? c.GetString() : null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
error = responseBody;
|
||||
}
|
||||
|
||||
return new ManagementResponse((int)httpResponse.StatusCode, null, error, code);
|
||||
}
|
||||
|
||||
public void Dispose() => _httpClient.Dispose();
|
||||
}
|
||||
|
||||
public record ManagementResponse(int StatusCode, string? JsonData, string? Error, string? ErrorCode);
|
||||
@@ -4,32 +4,32 @@ using ScadaLink.CLI.Commands;
|
||||
|
||||
var rootCommand = new RootCommand("ScadaLink CLI — manage the ScadaLink SCADA system");
|
||||
|
||||
var contactPointsOption = new Option<string>("--contact-points") { Description = "Comma-separated cluster contact points", Recursive = true };
|
||||
var urlOption = new Option<string>("--url") { Description = "Management API URL", Recursive = true };
|
||||
var usernameOption = new Option<string>("--username") { Description = "LDAP username", Recursive = true };
|
||||
var passwordOption = new Option<string>("--password") { Description = "LDAP password", Recursive = true };
|
||||
var formatOption = new Option<string>("--format") { Description = "Output format (json or table)", Recursive = true };
|
||||
formatOption.DefaultValueFactory = _ => "json";
|
||||
|
||||
rootCommand.Add(contactPointsOption);
|
||||
rootCommand.Add(urlOption);
|
||||
rootCommand.Add(usernameOption);
|
||||
rootCommand.Add(passwordOption);
|
||||
rootCommand.Add(formatOption);
|
||||
|
||||
// Register command groups
|
||||
rootCommand.Add(TemplateCommands.Build(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(InstanceCommands.Build(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(SiteCommands.Build(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(DeployCommands.Build(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(DataConnectionCommands.Build(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(ExternalSystemCommands.Build(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(NotificationCommands.Build(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(SecurityCommands.Build(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(AuditLogCommands.Build(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(HealthCommands.Build(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(DebugCommands.Build(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(SharedScriptCommands.Build(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(DbConnectionCommands.Build(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(ApiMethodCommands.Build(contactPointsOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(TemplateCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(InstanceCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(SiteCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(DeployCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(DataConnectionCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(ExternalSystemCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(NotificationCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(SecurityCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(AuditLogCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(HealthCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(DebugCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(SharedScriptCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(DbConnectionCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
|
||||
rootCommand.Add(ApiMethodCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
|
||||
|
||||
rootCommand.SetAction(_ =>
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# ScadaLink CLI
|
||||
|
||||
Command-line tool for managing the ScadaLink SCADA system. Connects to a Central node via Akka.NET ClusterClient and routes commands through the ManagementActor.
|
||||
Command-line tool for managing the ScadaLink SCADA system. Connects to a Central node via HTTP and routes commands through the Management API endpoint (`POST /management`), which dispatches to the ManagementActor. Authentication is handled server-side via LDAP.
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -12,27 +12,23 @@ The output binary is `scadalink` (or `scadalink.exe` on Windows).
|
||||
|
||||
## Connection
|
||||
|
||||
Every command requires a connection to a running Central node. Contact points can be supplied three ways, evaluated in this priority order:
|
||||
Every command requires a connection to a running Central node. The management URL can be supplied three ways, evaluated in this priority order:
|
||||
|
||||
1. `--contact-points` flag on the command line
|
||||
2. `SCADALINK_CONTACT_POINTS` environment variable
|
||||
3. `contactPoints` array in `~/.scadalink/config.json`
|
||||
1. `--url` flag on the command line
|
||||
2. `SCADALINK_MANAGEMENT_URL` environment variable
|
||||
3. `managementUrl` field in `~/.scadalink/config.json`
|
||||
|
||||
```sh
|
||||
scadalink --contact-points akka.tcp://scadalink@central-host:8081 <command>
|
||||
scadalink --url http://central-host:5000 <command>
|
||||
```
|
||||
|
||||
For a two-node HA cluster, supply both nodes comma-separated:
|
||||
**Docker:** With the Docker setup, the Central UI (and management API) is available at `http://localhost:9001`:
|
||||
|
||||
```sh
|
||||
scadalink --contact-points akka.tcp://scadalink@node1:8081,akka.tcp://scadalink@node2:8082 <command>
|
||||
scadalink --url http://localhost:9001 <command>
|
||||
```
|
||||
|
||||
**Docker (OrbStack):** When running against Docker containers, the contact point hostname must match the central container's Akka `NodeHostname` config. With OrbStack, add `/etc/hosts` entries mapping the container names to their IPs (see `docker/README.md`). Example:
|
||||
|
||||
```sh
|
||||
scadalink --contact-points akka.tcp://scadalink@scadalink-central-a:8081 <command>
|
||||
```
|
||||
For HA failover, use a load balancer URL. The management API is stateless (Basic Auth per request), so any central node can handle any request without sticky sessions.
|
||||
|
||||
## Global Options
|
||||
|
||||
@@ -40,7 +36,7 @@ These options are accepted by the root command and inherited by all subcommands.
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--contact-points <value>` | Comma-separated Akka cluster contact point URIs |
|
||||
| `--url <value>` | Management API URL (e.g., `http://localhost:9001`) |
|
||||
| `--username <value>` | LDAP username for authentication |
|
||||
| `--password <value>` | LDAP password for authentication |
|
||||
| `--format <json\|table>` | Output format (default: `json`) |
|
||||
@@ -51,29 +47,17 @@ These options are accepted by the root command and inherited by all subcommands.
|
||||
|
||||
```json
|
||||
{
|
||||
"contactPoints": ["akka.tcp://scadalink@central-host:8081"],
|
||||
"ldap": {
|
||||
"server": "ldap.company.com",
|
||||
"port": 636,
|
||||
"useTls": true,
|
||||
"searchBase": "dc=example,dc=com",
|
||||
"serviceAccountDn": "cn=admin,dc=example,dc=com",
|
||||
"serviceAccountPassword": "secret"
|
||||
},
|
||||
"defaultFormat": "json"
|
||||
"managementUrl": "http://localhost:9001"
|
||||
}
|
||||
```
|
||||
|
||||
The `searchBase` and `serviceAccountDn`/`serviceAccountPassword` fields are required for LDAP servers that need search-then-bind authentication (including the test GLAuth server). Without them, direct bind with `cn={username},{searchBase}` is attempted, which may fail if the user's DN doesn't follow that pattern.
|
||||
|
||||
For the Docker test environment, see `docker/README.md` for a ready-to-use config.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `SCADALINK_CONTACT_POINTS` | Comma-separated contact point URIs (overrides config file) |
|
||||
| `SCADALINK_LDAP_SERVER` | LDAP server hostname (overrides config file) |
|
||||
| `SCADALINK_MANAGEMENT_URL` | Management API URL (overrides config file) |
|
||||
| `SCADALINK_FORMAT` | Default output format (overrides config file) |
|
||||
|
||||
## Output
|
||||
@@ -103,7 +87,7 @@ Exit codes:
|
||||
List all templates with their full attribute, alarm, script, and composition definitions.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> template list
|
||||
scadalink --url <url> template list
|
||||
```
|
||||
|
||||
#### `template get`
|
||||
@@ -111,7 +95,7 @@ scadalink --contact-points <uri> template list
|
||||
Get a single template by ID.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> template get --id <int>
|
||||
scadalink --url <url> template get --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -123,7 +107,7 @@ scadalink --contact-points <uri> template get --id <int>
|
||||
Create a new template, optionally inheriting from a parent.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> template create --name <string> [--description <string>] [--parent-id <int>]
|
||||
scadalink --url <url> template create --name <string> [--description <string>] [--parent-id <int>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -137,7 +121,7 @@ scadalink --contact-points <uri> template create --name <string> [--description
|
||||
Update an existing template's name, description, or parent.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> template update --id <int> [--name <string>] [--description <string>] [--parent-id <int>]
|
||||
scadalink --url <url> template update --id <int> [--name <string>] [--description <string>] [--parent-id <int>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -152,7 +136,7 @@ scadalink --contact-points <uri> template update --id <int> [--name <string>] [-
|
||||
Delete a template by ID.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> template delete --id <int>
|
||||
scadalink --url <url> template delete --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -164,7 +148,7 @@ scadalink --contact-points <uri> template delete --id <int>
|
||||
Run pre-deployment validation on a template (flattening, naming collisions, script compilation).
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> template validate --id <int>
|
||||
scadalink --url <url> template validate --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -176,7 +160,7 @@ scadalink --contact-points <uri> template validate --id <int>
|
||||
Add an attribute to a template.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> template attribute add --template-id <int> --name <string> --data-type <string> [--default-value <string>] [--tag-path <string>]
|
||||
scadalink --url <url> template attribute add --template-id <int> --name <string> --data-type <string> [--default-value <string>] [--tag-path <string>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -192,7 +176,7 @@ scadalink --contact-points <uri> template attribute add --template-id <int> --na
|
||||
Update an attribute on a template.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> template attribute update --template-id <int> --name <string> [--data-type <string>] [--default-value <string>] [--tag-path <string>]
|
||||
scadalink --url <url> template attribute update --template-id <int> --name <string> [--data-type <string>] [--default-value <string>] [--tag-path <string>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -208,7 +192,7 @@ scadalink --contact-points <uri> template attribute update --template-id <int> -
|
||||
Remove an attribute from a template.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> template attribute delete --template-id <int> --name <string>
|
||||
scadalink --url <url> template attribute delete --template-id <int> --name <string>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -221,7 +205,7 @@ scadalink --contact-points <uri> template attribute delete --template-id <int> -
|
||||
Add an alarm definition to a template.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> template alarm add --template-id <int> --name <string> --trigger-attribute <string> --condition <string> --setpoint <string> [--severity <string>] [--notification-list <string>]
|
||||
scadalink --url <url> template alarm add --template-id <int> --name <string> --trigger-attribute <string> --condition <string> --setpoint <string> [--severity <string>] [--notification-list <string>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -239,7 +223,7 @@ scadalink --contact-points <uri> template alarm add --template-id <int> --name <
|
||||
Update an alarm definition on a template.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> template alarm update --template-id <int> --name <string> [--condition <string>] [--setpoint <string>] [--severity <string>] [--notification-list <string>]
|
||||
scadalink --url <url> template alarm update --template-id <int> --name <string> [--condition <string>] [--setpoint <string>] [--severity <string>] [--notification-list <string>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -256,7 +240,7 @@ scadalink --contact-points <uri> template alarm update --template-id <int> --nam
|
||||
Remove an alarm definition from a template.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> template alarm delete --template-id <int> --name <string>
|
||||
scadalink --url <url> template alarm delete --template-id <int> --name <string>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -269,7 +253,7 @@ scadalink --contact-points <uri> template alarm delete --template-id <int> --nam
|
||||
Add a script to a template.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> template script add --template-id <int> --name <string> --trigger-type <string> [--trigger-attribute <string>] [--interval <int>] --code <string>
|
||||
scadalink --url <url> template script add --template-id <int> --name <string> --trigger-type <string> [--trigger-attribute <string>] [--interval <int>] --code <string>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -286,7 +270,7 @@ scadalink --contact-points <uri> template script add --template-id <int> --name
|
||||
Update a script on a template.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> template script update --template-id <int> --name <string> [--trigger-type <string>] [--trigger-attribute <string>] [--interval <int>] [--code <string>]
|
||||
scadalink --url <url> template script update --template-id <int> --name <string> [--trigger-type <string>] [--trigger-attribute <string>] [--interval <int>] [--code <string>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -303,7 +287,7 @@ scadalink --contact-points <uri> template script update --template-id <int> --na
|
||||
Remove a script from a template.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> template script delete --template-id <int> --name <string>
|
||||
scadalink --url <url> template script delete --template-id <int> --name <string>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -316,7 +300,7 @@ scadalink --contact-points <uri> template script delete --template-id <int> --na
|
||||
Add a feature module composition to a template.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> template composition add --template-id <int> --module-template-id <int> --instance-name <string>
|
||||
scadalink --url <url> template composition add --template-id <int> --module-template-id <int> --instance-name <string>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -330,7 +314,7 @@ scadalink --contact-points <uri> template composition add --template-id <int> --
|
||||
Remove a feature module composition from a template.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> template composition delete --template-id <int> --instance-name <string>
|
||||
scadalink --url <url> template composition delete --template-id <int> --instance-name <string>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -347,7 +331,7 @@ scadalink --contact-points <uri> template composition delete --template-id <int>
|
||||
Get a single instance by ID.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> instance get --id <int>
|
||||
scadalink --url <url> instance get --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -359,7 +343,7 @@ scadalink --contact-points <uri> instance get --id <int>
|
||||
List instances, with optional filters.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> instance list [--site-id <int>] [--template-id <int>] [--search <string>]
|
||||
scadalink --url <url> instance list [--site-id <int>] [--template-id <int>] [--search <string>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -373,7 +357,7 @@ scadalink --contact-points <uri> instance list [--site-id <int>] [--template-id
|
||||
Create a new instance of a template at a site.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> instance create --name <string> --template-id <int> --site-id <int> [--area-id <int>]
|
||||
scadalink --url <url> instance create --name <string> --template-id <int> --site-id <int> [--area-id <int>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -388,7 +372,7 @@ scadalink --contact-points <uri> instance create --name <string> --template-id <
|
||||
Deploy an instance to its site. Acquires the per-instance operation lock.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> instance deploy --id <int>
|
||||
scadalink --url <url> instance deploy --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -400,7 +384,7 @@ scadalink --contact-points <uri> instance deploy --id <int>
|
||||
Enable a previously disabled instance.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> instance enable --id <int>
|
||||
scadalink --url <url> instance enable --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -412,7 +396,7 @@ scadalink --contact-points <uri> instance enable --id <int>
|
||||
Disable a running instance without deleting it.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> instance disable --id <int>
|
||||
scadalink --url <url> instance disable --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -424,7 +408,7 @@ scadalink --contact-points <uri> instance disable --id <int>
|
||||
Delete an instance. The instance must be disabled first.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> instance delete --id <int>
|
||||
scadalink --url <url> instance delete --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -436,7 +420,7 @@ scadalink --contact-points <uri> instance delete --id <int>
|
||||
Set data connection bindings for an instance's attributes.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> instance set-bindings --id <int> --bindings <json>
|
||||
scadalink --url <url> instance set-bindings --id <int> --bindings <json>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -453,7 +437,7 @@ scadalink --contact-points <uri> instance set-bindings --id <int> --bindings <js
|
||||
Get a single site by ID.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> site get --id <int>
|
||||
scadalink --url <url> site get --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -465,7 +449,7 @@ scadalink --contact-points <uri> site get --id <int>
|
||||
List all registered sites.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> site list
|
||||
scadalink --url <url> site list
|
||||
```
|
||||
|
||||
#### `site create`
|
||||
@@ -473,7 +457,7 @@ scadalink --contact-points <uri> site list
|
||||
Register a new site.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> site create --name <string> --identifier <string> [--description <string>]
|
||||
scadalink --url <url> site create --name <string> --identifier <string> [--description <string>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -487,7 +471,7 @@ scadalink --contact-points <uri> site create --name <string> --identifier <strin
|
||||
Delete a site. Fails if any instances are assigned to it.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> site delete --id <int>
|
||||
scadalink --url <url> site delete --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -499,7 +483,7 @@ scadalink --contact-points <uri> site delete --id <int>
|
||||
Push compiled artifacts to one or all sites.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> site deploy-artifacts [--site-id <int>]
|
||||
scadalink --url <url> site deploy-artifacts [--site-id <int>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -511,7 +495,7 @@ scadalink --contact-points <uri> site deploy-artifacts [--site-id <int>]
|
||||
List all areas for a site.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> site area list --site-id <int>
|
||||
scadalink --url <url> site area list --site-id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -523,7 +507,7 @@ scadalink --contact-points <uri> site area list --site-id <int>
|
||||
Create an area within a site.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> site area create --site-id <int> --name <string> [--parent-area-id <int>]
|
||||
scadalink --url <url> site area create --site-id <int> --name <string> [--parent-area-id <int>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -537,7 +521,7 @@ scadalink --contact-points <uri> site area create --site-id <int> --name <string
|
||||
Update an area's name or parent.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> site area update --id <int> [--name <string>] [--parent-area-id <int>]
|
||||
scadalink --url <url> site area update --id <int> [--name <string>] [--parent-area-id <int>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -551,7 +535,7 @@ scadalink --contact-points <uri> site area update --id <int> [--name <string>] [
|
||||
Delete an area. Fails if any instances are assigned to it.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> site area delete --id <int>
|
||||
scadalink --url <url> site area delete --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -567,7 +551,7 @@ scadalink --contact-points <uri> site area delete --id <int>
|
||||
Deploy a single instance (same as `instance deploy`).
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> deploy instance --id <int>
|
||||
scadalink --url <url> deploy instance --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -579,7 +563,7 @@ scadalink --contact-points <uri> deploy instance --id <int>
|
||||
Deploy compiled artifacts to one or all sites (same as `site deploy-artifacts`).
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> deploy artifacts [--site-id <int>]
|
||||
scadalink --url <url> deploy artifacts [--site-id <int>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -591,7 +575,7 @@ scadalink --contact-points <uri> deploy artifacts [--site-id <int>]
|
||||
Query deployment records, with optional filters and pagination.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> deploy status [--instance-id <int>] [--status <string>] [--page <int>] [--page-size <int>]
|
||||
scadalink --url <url> deploy status [--instance-id <int>] [--status <string>] [--page <int>] [--page-size <int>]
|
||||
```
|
||||
|
||||
| Option | Required | Default | Description |
|
||||
@@ -610,7 +594,7 @@ scadalink --contact-points <uri> deploy status [--instance-id <int>] [--status <
|
||||
Get a single data connection by ID.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> data-connection get --id <int>
|
||||
scadalink --url <url> data-connection get --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -622,7 +606,7 @@ scadalink --contact-points <uri> data-connection get --id <int>
|
||||
List all configured data connections.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> data-connection list
|
||||
scadalink --url <url> data-connection list
|
||||
```
|
||||
|
||||
#### `data-connection create`
|
||||
@@ -630,7 +614,7 @@ scadalink --contact-points <uri> data-connection list
|
||||
Create a new data connection definition.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> data-connection create --name <string> --protocol <string> [--configuration <json>]
|
||||
scadalink --url <url> data-connection create --name <string> --protocol <string> [--configuration <json>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -644,7 +628,7 @@ scadalink --contact-points <uri> data-connection create --name <string> --protoc
|
||||
Update a data connection definition.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> data-connection update --id <int> [--name <string>] [--protocol <string>] [--configuration <json>]
|
||||
scadalink --url <url> data-connection update --id <int> [--name <string>] [--protocol <string>] [--configuration <json>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -659,7 +643,7 @@ scadalink --contact-points <uri> data-connection update --id <int> [--name <stri
|
||||
Delete a data connection.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> data-connection delete --id <int>
|
||||
scadalink --url <url> data-connection delete --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -671,7 +655,7 @@ scadalink --contact-points <uri> data-connection delete --id <int>
|
||||
Assign a data connection to a site.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> data-connection assign --connection-id <int> --site-id <int>
|
||||
scadalink --url <url> data-connection assign --connection-id <int> --site-id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -684,7 +668,7 @@ scadalink --contact-points <uri> data-connection assign --connection-id <int> --
|
||||
Remove a data connection assignment from a site.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> data-connection unassign --connection-id <int> --site-id <int>
|
||||
scadalink --url <url> data-connection unassign --connection-id <int> --site-id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -701,7 +685,7 @@ scadalink --contact-points <uri> data-connection unassign --connection-id <int>
|
||||
Get a single external system definition by ID.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> external-system get --id <int>
|
||||
scadalink --url <url> external-system get --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -713,7 +697,7 @@ scadalink --contact-points <uri> external-system get --id <int>
|
||||
List all external system definitions.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> external-system list
|
||||
scadalink --url <url> external-system list
|
||||
```
|
||||
|
||||
#### `external-system create`
|
||||
@@ -721,7 +705,7 @@ scadalink --contact-points <uri> external-system list
|
||||
Register an external HTTP system that scripts can call.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> external-system create --name <string> --endpoint-url <url> --auth-type <string> [--auth-config <json>]
|
||||
scadalink --url <url> external-system create --name <string> --endpoint-url <url> --auth-type <string> [--auth-config <json>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -736,7 +720,7 @@ scadalink --contact-points <uri> external-system create --name <string> --endpoi
|
||||
Update an external system definition.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> external-system update --id <int> [--name <string>] [--endpoint-url <url>] [--auth-type <string>] [--auth-config <json>]
|
||||
scadalink --url <url> external-system update --id <int> [--name <string>] [--endpoint-url <url>] [--auth-type <string>] [--auth-config <json>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -752,7 +736,7 @@ scadalink --contact-points <uri> external-system update --id <int> [--name <stri
|
||||
Delete an external system definition.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> external-system delete --id <int>
|
||||
scadalink --url <url> external-system delete --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -768,7 +752,7 @@ scadalink --contact-points <uri> external-system delete --id <int>
|
||||
Get a single notification list by ID.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> notification get --id <int>
|
||||
scadalink --url <url> notification get --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -780,7 +764,7 @@ scadalink --contact-points <uri> notification get --id <int>
|
||||
List all notification lists.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> notification list
|
||||
scadalink --url <url> notification list
|
||||
```
|
||||
|
||||
#### `notification create`
|
||||
@@ -788,7 +772,7 @@ scadalink --contact-points <uri> notification list
|
||||
Create a notification list with one or more recipients.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> notification create --name <string> --emails <email1,email2,...>
|
||||
scadalink --url <url> notification create --name <string> --emails <email1,email2,...>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -801,7 +785,7 @@ scadalink --contact-points <uri> notification create --name <string> --emails <e
|
||||
Update a notification list's name or recipients.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> notification update --id <int> [--name <string>] [--emails <email1,email2,...>]
|
||||
scadalink --url <url> notification update --id <int> [--name <string>] [--emails <email1,email2,...>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -815,7 +799,7 @@ scadalink --contact-points <uri> notification update --id <int> [--name <string>
|
||||
Delete a notification list.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> notification delete --id <int>
|
||||
scadalink --url <url> notification delete --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -827,7 +811,7 @@ scadalink --contact-points <uri> notification delete --id <int>
|
||||
Show the current SMTP configuration.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> notification smtp list
|
||||
scadalink --url <url> notification smtp list
|
||||
```
|
||||
|
||||
#### `notification smtp update`
|
||||
@@ -835,7 +819,7 @@ scadalink --contact-points <uri> notification smtp list
|
||||
Update the SMTP configuration.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> notification smtp update --host <string> --port <int> --auth-type <string> [--username <string>] [--password <string>] [--from-address <string>]
|
||||
scadalink --url <url> notification smtp update --host <string> --port <int> --auth-type <string> [--username <string>] [--password <string>] [--from-address <string>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -856,7 +840,7 @@ scadalink --contact-points <uri> notification smtp update --host <string> --port
|
||||
List all inbound API keys.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> security api-key list
|
||||
scadalink --url <url> security api-key list
|
||||
```
|
||||
|
||||
#### `security api-key create`
|
||||
@@ -864,7 +848,7 @@ scadalink --contact-points <uri> security api-key list
|
||||
Create a new inbound API key. The generated key value is returned in the response and not stored in plaintext — save it immediately.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> security api-key create --name <string>
|
||||
scadalink --url <url> security api-key create --name <string>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -876,7 +860,7 @@ scadalink --contact-points <uri> security api-key create --name <string>
|
||||
Update an API key's name or enabled status.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> security api-key update --id <int> [--name <string>] [--enabled <bool>]
|
||||
scadalink --url <url> security api-key update --id <int> [--name <string>] [--enabled <bool>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -890,7 +874,7 @@ scadalink --contact-points <uri> security api-key update --id <int> [--name <str
|
||||
Revoke and delete an API key.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> security api-key delete --id <int>
|
||||
scadalink --url <url> security api-key delete --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -902,7 +886,7 @@ scadalink --contact-points <uri> security api-key delete --id <int>
|
||||
List all LDAP group → role mappings.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> security role-mapping list
|
||||
scadalink --url <url> security role-mapping list
|
||||
```
|
||||
|
||||
#### `security role-mapping create`
|
||||
@@ -910,7 +894,7 @@ scadalink --contact-points <uri> security role-mapping list
|
||||
Map an LDAP group to a ScadaLink role.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> security role-mapping create --ldap-group <string> --role <string>
|
||||
scadalink --url <url> security role-mapping create --ldap-group <string> --role <string>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -923,7 +907,7 @@ scadalink --contact-points <uri> security role-mapping create --ldap-group <stri
|
||||
Update an LDAP role mapping.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> security role-mapping update --id <int> [--ldap-group <string>] [--role <string>]
|
||||
scadalink --url <url> security role-mapping update --id <int> [--ldap-group <string>] [--role <string>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -937,7 +921,7 @@ scadalink --contact-points <uri> security role-mapping update --id <int> [--ldap
|
||||
Remove an LDAP role mapping.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> security role-mapping delete --id <int>
|
||||
scadalink --url <url> security role-mapping delete --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -949,7 +933,7 @@ scadalink --contact-points <uri> security role-mapping delete --id <int>
|
||||
List all site scope rules for role mappings.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> security scope-rule list [--role-mapping-id <int>]
|
||||
scadalink --url <url> security scope-rule list [--role-mapping-id <int>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -961,7 +945,7 @@ scadalink --contact-points <uri> security scope-rule list [--role-mapping-id <in
|
||||
Add a site scope rule to a role mapping, restricting it to a specific site.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> security scope-rule add --role-mapping-id <int> --site-id <int>
|
||||
scadalink --url <url> security scope-rule add --role-mapping-id <int> --site-id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -974,7 +958,7 @@ scadalink --contact-points <uri> security scope-rule add --role-mapping-id <int>
|
||||
Remove a site scope rule from a role mapping.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> security scope-rule delete --id <int>
|
||||
scadalink --url <url> security scope-rule delete --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -990,7 +974,7 @@ scadalink --contact-points <uri> security scope-rule delete --id <int>
|
||||
Return the current health state for all known sites as a JSON object keyed by site identifier.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> health summary
|
||||
scadalink --url <url> health summary
|
||||
```
|
||||
|
||||
#### `health site`
|
||||
@@ -998,7 +982,7 @@ scadalink --contact-points <uri> health summary
|
||||
Return the health state for a single site.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> health site --identifier <string>
|
||||
scadalink --url <url> health site --identifier <string>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -1010,7 +994,7 @@ scadalink --contact-points <uri> health site --identifier <string>
|
||||
Query the site event log for a specific site. Events are fetched remotely from the site's local SQLite store.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> health event-log --site-identifier <string> [--from <datetime>] [--to <datetime>] [--search <string>] [--page <int>] [--page-size <int>]
|
||||
scadalink --url <url> health event-log --site-identifier <string> [--from <datetime>] [--to <datetime>] [--search <string>] [--page <int>] [--page-size <int>]
|
||||
```
|
||||
|
||||
| Option | Required | Default | Description |
|
||||
@@ -1027,7 +1011,7 @@ scadalink --contact-points <uri> health event-log --site-identifier <string> [--
|
||||
Query parked (dead-letter) messages at a specific site.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> health parked-messages --site-identifier <string> [--page <int>] [--page-size <int>]
|
||||
scadalink --url <url> health parked-messages --site-identifier <string> [--page <int>] [--page-size <int>]
|
||||
```
|
||||
|
||||
| Option | Required | Default | Description |
|
||||
@@ -1045,7 +1029,7 @@ scadalink --contact-points <uri> health parked-messages --site-identifier <strin
|
||||
Request a point-in-time snapshot of a running instance's current attribute values and alarm states from the site. The instance must be deployed and enabled.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> debug snapshot --id <int>
|
||||
scadalink --url <url> debug snapshot --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -1063,7 +1047,7 @@ The command resolves the instance's site internally and routes the request to th
|
||||
Query the central audit log with optional filters and pagination.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> audit-log query [options]
|
||||
scadalink --url <url> audit-log query [options]
|
||||
```
|
||||
|
||||
| Option | Required | Default | Description |
|
||||
@@ -1085,7 +1069,7 @@ scadalink --contact-points <uri> audit-log query [options]
|
||||
List all shared script definitions.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> shared-script list
|
||||
scadalink --url <url> shared-script list
|
||||
```
|
||||
|
||||
#### `shared-script get`
|
||||
@@ -1093,7 +1077,7 @@ scadalink --contact-points <uri> shared-script list
|
||||
Get a single shared script by ID.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> shared-script get --id <int>
|
||||
scadalink --url <url> shared-script get --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -1105,7 +1089,7 @@ scadalink --contact-points <uri> shared-script get --id <int>
|
||||
Create a new shared script.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> shared-script create --name <string> --code <string>
|
||||
scadalink --url <url> shared-script create --name <string> --code <string>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -1118,7 +1102,7 @@ scadalink --contact-points <uri> shared-script create --name <string> --code <st
|
||||
Update a shared script's name or code.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> shared-script update --id <int> [--name <string>] [--code <string>]
|
||||
scadalink --url <url> shared-script update --id <int> [--name <string>] [--code <string>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -1132,7 +1116,7 @@ scadalink --contact-points <uri> shared-script update --id <int> [--name <string
|
||||
Delete a shared script.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> shared-script delete --id <int>
|
||||
scadalink --url <url> shared-script delete --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -1148,7 +1132,7 @@ scadalink --contact-points <uri> shared-script delete --id <int>
|
||||
List all database connection definitions.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> db-connection list
|
||||
scadalink --url <url> db-connection list
|
||||
```
|
||||
|
||||
#### `db-connection get`
|
||||
@@ -1156,7 +1140,7 @@ scadalink --contact-points <uri> db-connection list
|
||||
Get a single database connection by ID.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> db-connection get --id <int>
|
||||
scadalink --url <url> db-connection get --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -1168,7 +1152,7 @@ scadalink --contact-points <uri> db-connection get --id <int>
|
||||
Create a new database connection definition.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> db-connection create --name <string> --connection-string <string> [--provider <string>]
|
||||
scadalink --url <url> db-connection create --name <string> --connection-string <string> [--provider <string>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -1182,7 +1166,7 @@ scadalink --contact-points <uri> db-connection create --name <string> --connecti
|
||||
Update a database connection definition.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> db-connection update --id <int> [--name <string>] [--connection-string <string>] [--provider <string>]
|
||||
scadalink --url <url> db-connection update --id <int> [--name <string>] [--connection-string <string>] [--provider <string>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -1197,7 +1181,7 @@ scadalink --contact-points <uri> db-connection update --id <int> [--name <string
|
||||
Delete a database connection definition.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> db-connection delete --id <int>
|
||||
scadalink --url <url> db-connection delete --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -1213,7 +1197,7 @@ scadalink --contact-points <uri> db-connection delete --id <int>
|
||||
List all inbound API method definitions.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> api-method list
|
||||
scadalink --url <url> api-method list
|
||||
```
|
||||
|
||||
#### `api-method get`
|
||||
@@ -1221,7 +1205,7 @@ scadalink --contact-points <uri> api-method list
|
||||
Get a single inbound API method by ID.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> api-method get --id <int>
|
||||
scadalink --url <url> api-method get --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -1233,7 +1217,7 @@ scadalink --contact-points <uri> api-method get --id <int>
|
||||
Create a new inbound API method.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> api-method create --name <string> --code <string> [--description <string>]
|
||||
scadalink --url <url> api-method create --name <string> --code <string> [--description <string>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -1247,7 +1231,7 @@ scadalink --contact-points <uri> api-method create --name <string> --code <strin
|
||||
Update an inbound API method.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> api-method update --id <int> [--name <string>] [--code <string>] [--description <string>]
|
||||
scadalink --url <url> api-method update --id <int> [--name <string>] [--code <string>] [--description <string>]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
@@ -1262,7 +1246,7 @@ scadalink --contact-points <uri> api-method update --id <int> [--name <string>]
|
||||
Delete an inbound API method.
|
||||
|
||||
```sh
|
||||
scadalink --contact-points <uri> api-method delete --id <int>
|
||||
scadalink --url <url> api-method delete --id <int>
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
|
||||
@@ -11,16 +11,9 @@
|
||||
<InternalsVisibleTo Include="ScadaLink.CLI.Tests" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Akka" Version="1.5.62" />
|
||||
<PackageReference Include="Akka.Remote" Version="1.5.62" />
|
||||
<PackageReference Include="Akka.Cluster.Tools" Version="1.5.62" />
|
||||
<PackageReference Include="System.CommandLine" Version="2.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="10.0.5" />
|
||||
<PackageReference Include="Novell.Directory.Ldap.NETStandard" Version="3.6.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../ScadaLink.Commons/ScadaLink.Commons.csproj" />
|
||||
<ProjectReference Include="../ScadaLink.Security/ScadaLink.Security.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.Collections.Frozen;
|
||||
|
||||
namespace ScadaLink.Commons.Messages.Management;
|
||||
|
||||
public static class ManagementCommandRegistry
|
||||
{
|
||||
private static readonly FrozenDictionary<string, Type> Commands = BuildRegistry();
|
||||
|
||||
public static Type? Resolve(string commandName)
|
||||
{
|
||||
return Commands.GetValueOrDefault(commandName);
|
||||
}
|
||||
|
||||
public static string GetCommandName(Type commandType)
|
||||
{
|
||||
var name = commandType.Name;
|
||||
return name.EndsWith("Command", StringComparison.Ordinal)
|
||||
? name[..^"Command".Length]
|
||||
: name;
|
||||
}
|
||||
|
||||
private static FrozenDictionary<string, Type> BuildRegistry()
|
||||
{
|
||||
var ns = typeof(ManagementEnvelope).Namespace!;
|
||||
var assembly = typeof(ManagementEnvelope).Assembly;
|
||||
|
||||
return assembly.GetTypes()
|
||||
.Where(t => t.Namespace == ns
|
||||
&& t.Name.EndsWith("Command", StringComparison.Ordinal)
|
||||
&& !t.IsAbstract)
|
||||
.ToFrozenDictionary(
|
||||
t => t.Name[..^"Command".Length],
|
||||
t => t,
|
||||
StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
@@ -483,11 +483,18 @@ public class DataConnectionActor : UntypedActor, IWithStash, IWithTimers
|
||||
|
||||
private void ReSubscribeAll()
|
||||
{
|
||||
_log.Info("[{0}] Re-subscribing {1} tags after reconnect", _connectionName, _subscriptionIds.Count);
|
||||
// Derive tag list from _subscriptionsByInstance (durable source of truth),
|
||||
// not _subscriptionIds which gets cleared and is only repopulated on success.
|
||||
var allTags = _subscriptionsByInstance.Values
|
||||
.SelectMany(tags => tags)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
_log.Info("[{0}] Re-subscribing {1} tags after reconnect", _connectionName, allTags.Count);
|
||||
|
||||
var self = Self;
|
||||
var allTags = _subscriptionIds.Keys.ToList();
|
||||
_subscriptionIds.Clear();
|
||||
_unresolvedTags.Clear();
|
||||
_resolvedTags = 0;
|
||||
|
||||
foreach (var tagPath in allTags)
|
||||
@@ -535,6 +542,16 @@ public class DataConnectionActor : UntypedActor, IWithStash, IWithTimers
|
||||
{
|
||||
_log.Debug("[{0}] Tag resolution still failing for {1}: {2}",
|
||||
_connectionName, msg.TagPath, msg.Error);
|
||||
|
||||
// Track as unresolved so periodic retry picks it up
|
||||
if (_unresolvedTags.Add(msg.TagPath))
|
||||
{
|
||||
Timers.StartPeriodicTimer(
|
||||
"tag-resolution-retry",
|
||||
new RetryTagResolution(),
|
||||
_options.TagResolutionRetryInterval,
|
||||
_options.TagResolutionRetryInterval);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleTagValueReceived(TagValueReceived msg)
|
||||
|
||||
@@ -192,6 +192,8 @@ akka {{
|
||||
Props.Create(() => new ScadaLink.ManagementService.ManagementActor(_serviceProvider, mgmtLogger)),
|
||||
"management");
|
||||
ClusterClientReceptionist.Get(_actorSystem).RegisterService(mgmtActor);
|
||||
var mgmtHolder = _serviceProvider.GetRequiredService<ScadaLink.ManagementService.ManagementActorHolder>();
|
||||
mgmtHolder.ActorRef = mgmtActor;
|
||||
_logger.LogInformation("ManagementActor registered with ClusterClientReceptionist");
|
||||
|
||||
_logger.LogInformation("Central actors registered. CentralCommunicationActor created.");
|
||||
|
||||
@@ -129,6 +129,7 @@ try
|
||||
app.MapStaticAssets();
|
||||
app.MapCentralUI<ScadaLink.Host.Components.App>();
|
||||
app.MapInboundAPI();
|
||||
app.MapManagementAPI();
|
||||
|
||||
// Compile and register all Inbound API method scripts at startup
|
||||
using (var scope = app.Services.CreateScope())
|
||||
|
||||
8
src/ScadaLink.ManagementService/ManagementActorHolder.cs
Normal file
8
src/ScadaLink.ManagementService/ManagementActorHolder.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using Akka.Actor;
|
||||
|
||||
namespace ScadaLink.ManagementService;
|
||||
|
||||
public class ManagementActorHolder
|
||||
{
|
||||
public IActorRef? ActorRef { get; set; }
|
||||
}
|
||||
151
src/ScadaLink.ManagementService/ManagementEndpoints.cs
Normal file
151
src/ScadaLink.ManagementService/ManagementEndpoints.cs
Normal file
@@ -0,0 +1,151 @@
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Akka.Actor;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ScadaLink.Commons.Messages.Management;
|
||||
using ScadaLink.Security;
|
||||
|
||||
namespace ScadaLink.ManagementService;
|
||||
|
||||
public static class ManagementEndpoints
|
||||
{
|
||||
private static readonly TimeSpan AskTimeout = TimeSpan.FromSeconds(30);
|
||||
|
||||
public static IEndpointRouteBuilder MapManagementAPI(this IEndpointRouteBuilder endpoints)
|
||||
{
|
||||
endpoints.MapPost("/management", (Delegate)HandleRequest);
|
||||
return endpoints;
|
||||
}
|
||||
|
||||
private static async Task<IResult> HandleRequest(HttpContext context)
|
||||
{
|
||||
var logger = context.RequestServices.GetRequiredService<ILogger<ManagementActorHolder>>();
|
||||
|
||||
// 1. Decode Basic Auth
|
||||
var authHeader = context.Request.Headers.Authorization.ToString();
|
||||
if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Basic ", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return Results.Json(new { error = "Authorization header required (Basic scheme).", code = "AUTH_FAILED" }, statusCode: 401);
|
||||
}
|
||||
|
||||
string username, password;
|
||||
try
|
||||
{
|
||||
var decoded = Encoding.UTF8.GetString(Convert.FromBase64String(authHeader["Basic ".Length..]));
|
||||
var colon = decoded.IndexOf(':');
|
||||
if (colon < 0) throw new FormatException();
|
||||
username = decoded[..colon];
|
||||
password = decoded[(colon + 1)..];
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Results.Json(new { error = "Malformed Basic Auth header.", code = "AUTH_FAILED" }, statusCode: 401);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
|
||||
{
|
||||
return Results.Json(new { error = "Username and password are required.", code = "AUTH_FAILED" }, statusCode: 401);
|
||||
}
|
||||
|
||||
// 2. LDAP authentication
|
||||
var ldapAuth = context.RequestServices.GetRequiredService<LdapAuthService>();
|
||||
var authResult = await ldapAuth.AuthenticateAsync(username, password);
|
||||
if (!authResult.Success)
|
||||
{
|
||||
return Results.Json(
|
||||
new { error = authResult.ErrorMessage ?? "Authentication failed.", code = "AUTH_FAILED" },
|
||||
statusCode: 401);
|
||||
}
|
||||
|
||||
// 3. Role resolution
|
||||
var roleMapper = context.RequestServices.GetRequiredService<RoleMapper>();
|
||||
var mappingResult = await roleMapper.MapGroupsToRolesAsync(
|
||||
authResult.Groups ?? (IReadOnlyList<string>)Array.Empty<string>());
|
||||
|
||||
var permittedSiteIds = mappingResult.IsSystemWideDeployment
|
||||
? Array.Empty<string>()
|
||||
: mappingResult.PermittedSiteIds.ToArray();
|
||||
|
||||
var authenticatedUser = new AuthenticatedUser(
|
||||
authResult.Username!,
|
||||
authResult.DisplayName!,
|
||||
mappingResult.Roles.ToArray(),
|
||||
permittedSiteIds);
|
||||
|
||||
// 4. Parse command from request body
|
||||
JsonDocument doc;
|
||||
try
|
||||
{
|
||||
doc = await JsonDocument.ParseAsync(context.Request.Body);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Results.Json(new { error = "Invalid JSON body.", code = "BAD_REQUEST" }, statusCode: 400);
|
||||
}
|
||||
|
||||
if (!doc.RootElement.TryGetProperty("command", out var commandNameElement))
|
||||
{
|
||||
return Results.Json(new { error = "Missing 'command' field.", code = "BAD_REQUEST" }, statusCode: 400);
|
||||
}
|
||||
|
||||
var commandName = commandNameElement.GetString();
|
||||
if (string.IsNullOrWhiteSpace(commandName))
|
||||
{
|
||||
return Results.Json(new { error = "Empty 'command' field.", code = "BAD_REQUEST" }, statusCode: 400);
|
||||
}
|
||||
|
||||
var commandType = ManagementCommandRegistry.Resolve(commandName);
|
||||
if (commandType == null)
|
||||
{
|
||||
return Results.Json(new { error = $"Unknown command: '{commandName}'.", code = "BAD_REQUEST" }, statusCode: 400);
|
||||
}
|
||||
|
||||
object command;
|
||||
try
|
||||
{
|
||||
var payloadElement = doc.RootElement.TryGetProperty("payload", out var p)
|
||||
? p
|
||||
: JsonDocument.Parse("{}").RootElement;
|
||||
command = JsonSerializer.Deserialize(payloadElement.GetRawText(), commandType,
|
||||
new JsonSerializerOptions { PropertyNameCaseInsensitive = true })!;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Results.Json(new { error = $"Failed to deserialize payload: {ex.Message}", code = "BAD_REQUEST" }, statusCode: 400);
|
||||
}
|
||||
|
||||
// 5. Dispatch to ManagementActor
|
||||
var holder = context.RequestServices.GetRequiredService<ManagementActorHolder>();
|
||||
if (holder.ActorRef == null)
|
||||
{
|
||||
return Results.Json(new { error = "Management service not ready.", code = "SERVICE_UNAVAILABLE" }, statusCode: 503);
|
||||
}
|
||||
|
||||
var correlationId = Guid.NewGuid().ToString("N");
|
||||
var envelope = new ManagementEnvelope(authenticatedUser, command, correlationId);
|
||||
|
||||
object response;
|
||||
try
|
||||
{
|
||||
response = await holder.ActorRef.Ask(envelope, AskTimeout);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "ManagementActor Ask timed out or failed (CorrelationId={CorrelationId})", correlationId);
|
||||
return Results.Json(new { error = "Request timed out.", code = "TIMEOUT" }, statusCode: 504);
|
||||
}
|
||||
|
||||
// 6. Map response
|
||||
return response switch
|
||||
{
|
||||
ManagementSuccess success => Results.Text(success.JsonData, "application/json", statusCode: 200),
|
||||
ManagementError error => Results.Json(new { error = error.Error, code = error.ErrorCode }, statusCode: 400),
|
||||
ManagementUnauthorized unauth => Results.Json(new { error = unauth.Message, code = "UNAUTHORIZED" }, statusCode: 403),
|
||||
_ => Results.Json(new { error = "Unexpected response.", code = "INTERNAL_ERROR" }, statusCode: 500)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -5,12 +5,12 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Akka" Version="1.5.62" />
|
||||
<PackageReference Include="Akka.Cluster.Tools" Version="1.5.62" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="10.0.5" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../ScadaLink.Commons/ScadaLink.Commons.csproj" />
|
||||
|
||||
@@ -6,6 +6,7 @@ public static class ServiceCollectionExtensions
|
||||
{
|
||||
public static IServiceCollection AddManagementService(this IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<ManagementActorHolder>();
|
||||
services.AddOptions<ManagementServiceOptions>()
|
||||
.BindConfiguration("ScadaLink:ManagementService");
|
||||
return services;
|
||||
|
||||
Reference in New Issue
Block a user