Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,36 @@ public void GivenInvalidManifest_ShouldNotPostServiceMessage(string enabledFeatu
mr.ReportManifestFileApplied(filePath);

memoryLog.ServiceMessages.Should().BeEmpty();

memoryLog.MessagesWarnFormatted.Should().ContainSingle(x => x.Contains("Invalid YAML syntax found, resources will not be added to live object status"));
}
}

[TestCase(nameof(FeatureToggle.KubernetesLiveObjectStatusFeatureToggle))]
[TestCase(OctopusFeatureToggles.KnownSlugs.KubernetesObjectManifestInspection)]
public void GivenInvalidManifestAndVerboseVariableSet_ShouldLogErrorAndManifest(string enabledFeatureToggle)
{
var memoryLog = new InMemoryLog();
var variables = new CalamariVariables();
variables.Set(KnownVariables.EnabledFeatureToggles, enabledFeatureToggle);
variables.Set(SpecialVariables.PrintVerboseManifestOnParsingError, bool.TrueString);

var namespaceResolver = Substitute.For<IKubernetesManifestNamespaceResolver>();

var yaml = "text: \"Bar";
using (CreateFile(yaml, out var filePath))
{
var mr = new ManifestReporter(variables, CalamariPhysicalFileSystem.GetPhysicalFileSystem(), memoryLog, namespaceResolver);

mr.ReportManifestFileApplied(filePath);

memoryLog.ServiceMessages.Should().BeEmpty();

memoryLog.MessagesWarnFormatted.Should().ContainSingle(x => x.Contains("Invalid YAML syntax found, resources will not be added to live object status") &&
x.Contains("The error and manifest are verbose logged below"));

memoryLog.MessagesVerboseFormatted.Should().Contain(x => x.Contains("While scanning a quoted scalar"));
memoryLog.MessagesVerboseFormatted.Should().Contain(x => x.Contains(yaml));
}
}

Expand Down Expand Up @@ -117,7 +147,6 @@ public void NamespacedResolved_ShouldReportResolvedNamespace(string enabledFeatu
}
}


[TestCase(nameof(FeatureToggle.KubernetesLiveObjectStatusFeatureToggle))]
[TestCase(OctopusFeatureToggles.KnownSlugs.KubernetesObjectManifestInspection)]
public void GivenValidYamlString_ShouldPostSingleServiceMessage(string enabledFeatureToggle)
Expand Down
47 changes: 32 additions & 15 deletions source/Calamari/Kubernetes/ManifestReporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using YamlDotNet.Core;
using YamlDotNet.RepresentationModel;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;

namespace Calamari.Kubernetes
{
Expand Down Expand Up @@ -43,25 +42,26 @@ public void ReportManifestFileApplied(string filePath)
&& !OctopusFeatureToggles.KubernetesObjectManifestInspectionFeatureToggle.IsEnabled(variables))
return;

using (var yamlFile = fileSystem.OpenFile(filePath, FileAccess.Read, FileShare.Read))
try
{
try
{
var yamlStream = new YamlStream();
yamlStream.Load(new StreamReader(yamlFile));
ReportManifestStreamApplied(yamlStream);
}
catch (SemanticErrorException)
using (var yamlFile = fileSystem.OpenFile(filePath, FileAccess.Read, FileShare.Read))
using (var reader = new StreamReader(yamlFile))
{
log.Warn("Invalid YAML syntax found, resources will not be added to live object status");
//read the manifest
var manifest = reader.ReadToEnd();
ReportManifestApplied(manifest);
}
}
catch (Exception e)
{
log.Warn($"Failed to read yaml manifest at {filePath}, resources will not be added to live object status.");
log.Verbose($"Error: {e.Message}");
}
}

public void ReportManifestApplied(string yamlManifest)
{
if (!FeatureToggle.KubernetesLiveObjectStatusFeatureToggle.IsEnabled(variables)
&& !OctopusFeatureToggles.KubernetesObjectManifestInspectionFeatureToggle.IsEnabled(variables))
if (!FeatureToggle.KubernetesLiveObjectStatusFeatureToggle.IsEnabled(variables) && !OctopusFeatureToggles.KubernetesObjectManifestInspectionFeatureToggle.IsEnabled(variables))
return;

try
Expand All @@ -70,9 +70,9 @@ public void ReportManifestApplied(string yamlManifest)
yamlStream.Load(new StringReader(yamlManifest));
ReportManifestStreamApplied(yamlStream);
}
catch (SemanticErrorException)
catch (YamlException e)
{
log.Warn("Invalid YAML syntax found, resources will not be added to live object status");
LogYamlException(e, yamlManifest);
}
}

Expand All @@ -82,7 +82,7 @@ void ReportManifestStreamApplied(YamlStream yamlStream)
{
if (!(document.RootNode is YamlMappingNode rootNode))
{
log.Warn("Could not parse manifest, resources will not be added to live object status");
log.Warn("Could not parse manifest, resources will not be added to live object status.");
continue;
}

Expand All @@ -102,6 +102,23 @@ void ReportManifestStreamApplied(YamlStream yamlStream)
}
}

void LogYamlException(YamlException e, string manifest)
{
if (variables.GetFlag(SpecialVariables.PrintVerboseManifestOnParsingError))
{
log.Warn("Invalid YAML syntax found, resources will not be added to live object status. The error and manifest are verbose logged below.");
log.Verbose("---------------------------");
log.Verbose($"Error: {e.Message}");
log.Verbose("---------------------------");
log.Verbose(manifest);
log.Verbose("---------------------------");
}
else
{
log.Warn($"Invalid YAML syntax found, resources will not be added to live object status. To view the error and manifest, set Octopus Variable '{SpecialVariables.PrintVerboseManifestOnParsingError}' to 'true'");
}
}

static string SerializeManifest(YamlMappingNode node)
{
return YamlSerializer.Serialize(node);
Expand Down
1 change: 1 addition & 0 deletions source/Calamari/Kubernetes/SpecialVariables.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public static class SpecialVariables
public const string Timeout = "Octopus.Action.Kubernetes.DeploymentTimeout";
public const string WaitForJobs = "Octopus.Action.Kubernetes.WaitForJobs";
public const string PrintVerboseKubectlOutputOnError = "Octopus.Action.Kubernetes.PrintVerboseKubectlOutputOnError";
public const string PrintVerboseManifestOnParsingError = "Octopus.Action.Kubernetes.PrintVerboseManifestOnParsingError";
public const string ClientCertificate = "Octopus.Action.Kubernetes.ClientCertificate";
public const string CertificateAuthorityPath = "Octopus.Action.Kubernetes.CertificateAuthorityPath";
public const string PodServiceAccountTokenPath = "Octopus.Action.Kubernetes.PodServiceAccountTokenPath";
Expand Down