Skip to content

Commit

Permalink
Add remotely managed, ephemeral and api options to Windows install sc…
Browse files Browse the repository at this point in the history
…ript/installer (#1437)

**feat: add new options to windows install script and installer**

* remotely managed
* ephemeral
* api
* add changelog entry
  • Loading branch information
fguimond committed Feb 8, 2024
1 parent f697d5b commit def2edd
Show file tree
Hide file tree
Showing 11 changed files with 465 additions and 27 deletions.
1 change: 1 addition & 0 deletions .changelog/1437.added.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
+ feat(install): add support for remote management, ephemeral and api url in Windows installer
4 changes: 4 additions & 0 deletions packaging/msi/SumoLogic.wixext/SumoLogic.wixext/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ public class Config
{
public string InstallationToken { get; set; }
public Dictionary<string, string> CollectorFields { get; set; }
public bool RemotelyManaged { get; set; }
public bool Ephemeral { get; set; }
public string OpAmpFolder { get; set; }
public string Api { get; set; }

public Config() {
this.CollectorFields = new Dictionary<string, string>();
Expand Down
64 changes: 64 additions & 0 deletions packaging/msi/SumoLogic.wixext/SumoLogic.wixext/ConfigUpdater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ public ConfigUpdater(StreamReader streamReader) {

public void Update(Config config)
{
if (config.RemotelyManaged && string.IsNullOrEmpty(config.OpAmpFolder))
{
throw new MissingConfigurationException("OpAmpFolder");
}

YamlMappingNode root = (YamlMappingNode)this.Document.RootNode;

EnsureMapKey(root, "extensions");
Expand All @@ -53,6 +58,48 @@ public void Update(Config config)
collectorFields.Children[field.Key] = field.Value;
}
}

if (config.RemotelyManaged)
{
EnsureMapKey(extensions, "opamp");
YamlMappingNode opamp = (YamlMappingNode)extensions.Children["opamp"];
EnsureScalarKey(opamp, "remote_configuration_directory");
opamp.Children["remote_configuration_directory"] = config.OpAmpFolder;

// Add OpAmp extension to service section
EnsureMapKey(root, "service");
YamlMappingNode service = (YamlMappingNode)root.Children["service"];
EnsureSequenceKey(service, "extensions");
YamlSequenceNode serviceExtensions = (YamlSequenceNode)service.Children["extensions"];
if (!serviceExtensions.Children.Contains("opamp"))
{
serviceExtensions.Children.Add("opamp");
}
}

if (config.Ephemeral)
{
EnsureScalarKey(sumologic, "ephemeral");
sumologic.Children["ephemeral"] = "true";
}

if (!string.IsNullOrEmpty(config.Api))
{
EnsureScalarKey(sumologic, "api_base_url");
sumologic.Children["api_base_url"] = config.Api;
}

// Make sure the sumologic processor node is a map node, otherwise an empty string
// is generated as the value instead of an empty node.
if (root.Children.ContainsKey("processors"))
{
EnsureMapKey(root, "processors");
YamlMappingNode processors = (YamlMappingNode)root.Children["processors"];
if (processors.Children.ContainsKey("sumologic"))
{
EnsureMapKey(processors, "sumologic");
}
}
}

public void Save(StreamWriter streamWriter)
Expand Down Expand Up @@ -100,5 +147,22 @@ private void EnsureScalarKey(YamlMappingNode node, string key)
// Add empty YamlScalarNode to key
node.Children.Add(key, new YamlScalarNode());
}

private void EnsureSequenceKey(YamlMappingNode node, string key)
{
if (node.Children.ContainsKey(key))
{
if (node.Children[key].NodeType == YamlNodeType.Sequence)
{
return;
}

// TODO: is this how we want to handle incorrect node types?
// YamlNode is wrong type, remove it
node.Children.Remove(key);
}
// Add empty YamlScalarNode to key
node.Children.Add(key, new YamlSequenceNode());
}
}
}
76 changes: 65 additions & 11 deletions packaging/msi/SumoLogic.wixext/SumoLogic.wixext/CustomAction.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using WixToolset.Dtf.WindowsInstaller;

namespace SumoLogic.wixext
Expand All @@ -13,9 +14,19 @@ public class CustomActions

// WiX property names
private const string pCommonConfigPath = "CommonConfigPath";
private const string pSumoLogicConfigPath = "SumoLogicConfigPath";
private const string pInstallationToken = "InstallationToken";
private const string pInstallToken = "InstallToken";
private const string pTags = "Tags";
private const string pApi = "Api";
private const string pRemotelyManaged = "RemotelyManaged";
private const string pEphemeral = "Ephemeral";
private const string pConfigFolder = "ConfigFolder";
private const string pOpAmpFolder = "OpAmpFolder";
private const string pConfigFragmentsFolder = "ConfigFragmentsFolder";

// WiX features
private const string fRemotelyManaged = "REMOTELYMANAGED";

[CustomAction]
public static ActionResult UpdateConfig(Session session)
Expand All @@ -26,44 +37,60 @@ public static ActionResult UpdateConfig(Session session)
// Validate presence of required WiX properties
if (!session.CustomActionData.ContainsKey(pCommonConfigPath))
{
showErrorMessage(session, ecMissingCustomActionData, pCommonConfigPath);
ShowErrorMessage(session, ecMissingCustomActionData, pCommonConfigPath);
return ActionResult.Failure;
}
if (!session.CustomActionData.ContainsKey(pInstallToken) && !session.CustomActionData.ContainsKey(pInstallationToken))
{
showErrorMessage(session, ecMissingCustomActionData, pInstallationToken);
ShowErrorMessage(session, ecMissingCustomActionData, pInstallationToken);
return ActionResult.Failure;
}
if (!session.CustomActionData.ContainsKey(pTags))
{
showErrorMessage(session, ecMissingCustomActionData, pTags);
ShowErrorMessage(session, ecMissingCustomActionData, pTags);
return ActionResult.Failure;
}

var commonConfigPath = session.CustomActionData[pCommonConfigPath];
var sumoLogicConfigPath = session.CustomActionData[pSumoLogicConfigPath];
var tags = session.CustomActionData[pTags];

var installationToken = "";
if (session.CustomActionData.ContainsKey(pInstallationToken) && session.CustomActionData[pInstallationToken] != "") {
if (session.CustomActionData.ContainsKey(pInstallationToken) && session.CustomActionData[pInstallationToken] != "")
{
installationToken = session.CustomActionData[pInstallationToken];
} else if (session.CustomActionData.ContainsKey(pInstallToken)){
}
else if (session.CustomActionData.ContainsKey(pInstallToken))
{
installationToken = session.CustomActionData[pInstallToken];
}

var remotelyManaged = (session.CustomActionData.ContainsKey(pRemotelyManaged) && session.CustomActionData[pRemotelyManaged] == "true");
var ephemeral = (session.CustomActionData.ContainsKey(pEphemeral) && session.CustomActionData[pEphemeral] == "true");
var opAmpFolder = session.CustomActionData[pOpAmpFolder];
var api = session.CustomActionData[pApi];

if (remotelyManaged && string.IsNullOrEmpty(opAmpFolder))
{
ShowErrorMessage(session, ecMissingCustomActionData, pOpAmpFolder);
return ActionResult.Failure;
}

// Load config from disk and replace values
Config config = new Config();
config.InstallationToken = installationToken;
Config config = new Config { InstallationToken = installationToken, RemotelyManaged = remotelyManaged, Ephemeral = ephemeral,
OpAmpFolder = opAmpFolder, Api = api };
config.SetCollectorFieldsFromTags(tags);

var configFile = remotelyManaged ? sumoLogicConfigPath : commonConfigPath;
try
{
ConfigUpdater configUpdater = new ConfigUpdater(new StreamReader(commonConfigPath));
ConfigUpdater configUpdater = new ConfigUpdater(new StreamReader(configFile));
configUpdater.Update(config);
configUpdater.Save(new StreamWriter(commonConfigPath));
configUpdater.Save(new StreamWriter(configFile));
}
catch (Exception e)
{
showErrorMessage(session, ecConfigError, e.Message);
ShowErrorMessage(session, ecConfigError, e.Message);
return ActionResult.Failure;
}

Expand All @@ -72,7 +99,34 @@ public static ActionResult UpdateConfig(Session session)
return ActionResult.Success;
}

private static void showErrorMessage(Session session, short errCode, string key)
[CustomAction]
public static ActionResult PopulateServiceArguments(Session session)
{
try
{
var configFolder = session.GetTargetPath(pConfigFolder);
var configFragmentsFolder = session.GetTargetPath(pConfigFragmentsFolder);
var remotelyManaged = session.Features.Contains(fRemotelyManaged) && session.Features[fRemotelyManaged].RequestState == InstallState.Local;

if (remotelyManaged)
{
session["SERVICEARGUMENTS"] = " --remote-config \"opamp:" + configFolder + "sumologic.yaml\"";
}
else
{
session["SERVICEARGUMENTS"] = " --config \"" + configFolder + "sumologic.yaml\" --config \"glob:" + configFragmentsFolder + "*.yaml\"";
}
}
catch (Exception e)
{
ShowErrorMessage(session, ecConfigError, e.Message + e.StackTrace);
return ActionResult.Failure;
}

return ActionResult.Success;
}

private static void ShowErrorMessage(Session session, short errCode, string key)
{
Record record = new Record(3);
record.SetInteger(1, errCode);
Expand Down
5 changes: 5 additions & 0 deletions packaging/msi/SumoLogic.wixext/SumoLogic.wixext/Exceptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,9 @@ public class TagValueLengthExceededException : Exception
{
public TagValueLengthExceededException(string message) { }
}

public class MissingConfigurationException : Exception
{
public MissingConfigurationException(string message) { }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace SumoLogicTests
[TestClass]
public class ConfigTests
{
private static Random random = new Random();
private static readonly Random random = new Random();

public static string RandomString(int length)
{
Expand Down
Loading

0 comments on commit def2edd

Please sign in to comment.