-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement image metadata check for Kubernetes Agent tools to use the …
…latest image tag revision for pull policy workaround (#1010)
- Loading branch information
Showing
11 changed files
with
477 additions
and
121 deletions.
There are no files selected for viewing
87 changes: 87 additions & 0 deletions
87
source/Octopus.Tentacle.Tests/Kubernetes/ClusterVersionTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using FluentAssertions; | ||
using k8s.Models; | ||
using NUnit.Framework; | ||
using Octopus.Tentacle.Kubernetes; | ||
|
||
namespace Octopus.Tentacle.Tests.Kubernetes | ||
{ | ||
[TestFixture] | ||
public class ClusterVersionTests | ||
{ | ||
[TestCase("0", "1", 0, 1, false)] | ||
[TestCase("1abc", "1", 1, 1, false)] | ||
[TestCase("0", "1abc", 0, 1, false)] | ||
[TestCase("1+", "0", 1, 0, false)] | ||
[TestCase("0", "1+", 0, 1, false)] | ||
[TestCase("abc", "1", 999, 999, true)] | ||
public void FromVersionInfo_SanitizesAndReturnsNewClusterVersion(string major, string minor, int expectedMajor, int expectedMinor, bool shouldFail) | ||
{ | ||
try | ||
{ | ||
var versionInfo = new VersionInfo | ||
{ | ||
Major = major, | ||
Minor = minor | ||
}; | ||
var result = ClusterVersion.FromVersionInfo(versionInfo); | ||
result.Should().BeEquivalentTo(new ClusterVersion(expectedMajor, expectedMinor)); | ||
} | ||
catch (Exception e) | ||
{ | ||
if (shouldFail) | ||
e.Should().BeOfType<FormatException>(); | ||
else | ||
throw; | ||
} | ||
} | ||
|
||
static IEnumerable<TestCaseData> FromVersionTestData() | ||
{ | ||
yield return new TestCaseData(new Version("0.0.1"), 0, 0); | ||
yield return new TestCaseData(new Version("1.31"), 1, 31); | ||
yield return new TestCaseData(new Version("2.24.4"), 2, 24); | ||
} | ||
|
||
[TestCaseSource(nameof(FromVersionTestData))] | ||
public void FromVersion_ReturnsNewClusterVersion(Version version, int expectedMajor, int expectedMinor) | ||
{ | ||
var result = ClusterVersion.FromVersion(version); | ||
result.Should().BeEquivalentTo(new ClusterVersion(expectedMajor, expectedMinor)); | ||
} | ||
|
||
static IEnumerable<TestCaseData> CompareClusterVersionsTestData() | ||
{ | ||
yield return new TestCaseData(new ClusterVersion(0, 0), null, 1); | ||
yield return new TestCaseData(new ClusterVersion(0, 0), new ClusterVersion(0, 0), 0); | ||
yield return new TestCaseData(new ClusterVersion(0, 5), new ClusterVersion(0, 6), -1); | ||
yield return new TestCaseData(new ClusterVersion(1, 1), new ClusterVersion(2, 0), -1); | ||
yield return new TestCaseData(new ClusterVersion(1, 30), new ClusterVersion(1, 29), 1); | ||
yield return new TestCaseData(new ClusterVersion(3, 0), new ClusterVersion(2, 11), 1); | ||
yield return new TestCaseData(new ClusterVersion(3, 14), new ClusterVersion(3, 14), 0); | ||
} | ||
|
||
[TestCaseSource(nameof(CompareClusterVersionsTestData))] | ||
public void CompareClusterVersions(ClusterVersion thisClusterVersion, ClusterVersion otherClusterVersion, int expected) | ||
{ | ||
var result = thisClusterVersion.CompareTo(otherClusterVersion); | ||
result.Should().Be(expected); | ||
} | ||
|
||
static IEnumerable<TestCaseData> CheckEqualityClusterVersionsTestData() | ||
{ | ||
yield return new TestCaseData(new ClusterVersion(0, 0), null, false); | ||
yield return new TestCaseData(new ClusterVersion(0, 5), new ClusterVersion(0, 6), false); | ||
yield return new TestCaseData(new ClusterVersion(1, 0), new ClusterVersion(2, 0), false); | ||
yield return new TestCaseData(new ClusterVersion(3, 14), new ClusterVersion(3, 14), true); | ||
} | ||
|
||
[TestCaseSource(nameof(CheckEqualityClusterVersionsTestData))] | ||
public void CheckEqualityClusterVersions(ClusterVersion thisClusterVersion, ClusterVersion otherClusterVersion, bool expected) | ||
{ | ||
var result = thisClusterVersion.Equals(otherClusterVersion); | ||
result.Should().Be(expected); | ||
} | ||
} | ||
} |
126 changes: 126 additions & 0 deletions
126
source/Octopus.Tentacle.Tests/Kubernetes/KubernetesPodContainerResolverTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Threading.Tasks; | ||
using FluentAssertions; | ||
using NSubstitute; | ||
using NSubstitute.ReturnsExtensions; | ||
using NUnit.Framework; | ||
using Octopus.Tentacle.Kubernetes; | ||
|
||
namespace Octopus.Tentacle.Tests.Kubernetes | ||
{ | ||
[TestFixture] | ||
public class KubernetesPodContainerResolverTests | ||
{ | ||
readonly KubernetesAgentToolsImageVersionMetadata testVersionMetadata = new(new KubernetesAgentToolVersions(new List<Version> | ||
{ | ||
new("1.31.1"), | ||
new("1.30.5"), | ||
new("1.29.9"), | ||
new("1.28.14") | ||
}, new List<Version> { new("3.16.1") }, | ||
new List<Version> { new("7.4.5") }), new Version("1.30"), "Juaa5J", new Dictionary<Version, KubernetesAgentToolDeprecation> | ||
{ | ||
{ new Version("1.26"), new KubernetesAgentToolDeprecation("1.26@sha256:a0892db") }, | ||
{ new Version("1.27"), new KubernetesAgentToolDeprecation("1.27@sha256:9d1ce87") } | ||
}); | ||
|
||
readonly IToolsImageVersionMetadataProvider mockToolsImageVersionMetadataProvider = Substitute.For<IToolsImageVersionMetadataProvider>(); | ||
|
||
[SetUp] | ||
public void Init() | ||
{ | ||
mockToolsImageVersionMetadataProvider.TryGetVersionMetadata().Returns(testVersionMetadata); | ||
} | ||
|
||
[TestCase(30)] | ||
[TestCase(29)] | ||
[TestCase(28)] | ||
public async Task GetContainerImageForCluster_VersionMetadataExists_ClusterVersionSupported_GetsImageWithRevision(int clusterMinorVersion) | ||
{ | ||
// Arrange | ||
var clusterService = Substitute.For<IKubernetesClusterService>(); | ||
clusterService.GetClusterVersion().Returns(new ClusterVersion(1, clusterMinorVersion)); | ||
|
||
var podContainerResolver = new KubernetesPodContainerResolver(clusterService, mockToolsImageVersionMetadataProvider); | ||
|
||
// Act | ||
var result = await podContainerResolver.GetContainerImageForCluster(); | ||
|
||
// Assert | ||
result.Should().Be($"octopusdeploy/kubernetes-agent-tools-base:1.{clusterMinorVersion}-Juaa5J"); | ||
} | ||
|
||
[TestCase(27, "1.27@sha256:9d1ce87")] | ||
[TestCase(26, "1.26@sha256:a0892db")] | ||
public async Task GetContainerImageForCluster_VersionMetadataExists_ClusterVersionDeprecated_GetsLatestDeprecatedTag(int clusterMinorVersion, string expectedImageTag) | ||
{ | ||
// Arrange | ||
var clusterService = Substitute.For<IKubernetesClusterService>(); | ||
clusterService.GetClusterVersion().Returns(new ClusterVersion(1, clusterMinorVersion)); | ||
|
||
var podContainerResolver = new KubernetesPodContainerResolver(clusterService, mockToolsImageVersionMetadataProvider); | ||
|
||
// Act | ||
var result = await podContainerResolver.GetContainerImageForCluster(); | ||
|
||
// Assert | ||
result.Should().Be($"octopusdeploy/kubernetes-agent-tools-base:{expectedImageTag}"); | ||
} | ||
|
||
[Test] | ||
public async Task GetContainerImageForCluster_VersionMetadataExists_ClusterVersionGreaterThanLatest_FallbackToLatest() | ||
{ | ||
// Arrange | ||
var clusterService = Substitute.For<IKubernetesClusterService>(); | ||
clusterService.GetClusterVersion().Returns(new ClusterVersion(1, 31)); | ||
|
||
var podContainerResolver = new KubernetesPodContainerResolver(clusterService, mockToolsImageVersionMetadataProvider); | ||
|
||
// Act | ||
var result = await podContainerResolver.GetContainerImageForCluster(); | ||
|
||
// Assert | ||
result.Should().Be("octopusdeploy/kubernetes-agent-tools-base:latest"); | ||
} | ||
|
||
[Test] | ||
public async Task GetContainerImageForCluster_VersionMetadataExists_ClusterVersionNotFound_FallbackToLatest() | ||
{ | ||
// Arrange | ||
var clusterService = Substitute.For<IKubernetesClusterService>(); | ||
clusterService.GetClusterVersion().Returns(new ClusterVersion(1, 40)); | ||
|
||
var podContainerResolver = new KubernetesPodContainerResolver(clusterService, mockToolsImageVersionMetadataProvider); | ||
|
||
// Act | ||
var result = await podContainerResolver.GetContainerImageForCluster(); | ||
|
||
// Assert | ||
result.Should().Be("octopusdeploy/kubernetes-agent-tools-base:latest"); | ||
} | ||
|
||
[TestCase(31, "latest")] | ||
[TestCase(30, "1.30")] | ||
[TestCase(29, "1.29")] | ||
[TestCase(28, "1.28")] | ||
[TestCase(27, "1.27")] | ||
[TestCase(26, "1.26")] | ||
[TestCase(25, "latest")] | ||
public async Task GetContainerImageForCluster_VersionMetadataNotFound_FallBackToKnownTags(int clusterMinorVersion, string expectedImageTag) | ||
{ | ||
// Arrange | ||
var clusterService = Substitute.For<IKubernetesClusterService>(); | ||
clusterService.GetClusterVersion().Returns(new ClusterVersion(1, clusterMinorVersion)); | ||
mockToolsImageVersionMetadataProvider.TryGetVersionMetadata().ReturnsNull(); | ||
|
||
var podContainerResolver = new KubernetesPodContainerResolver(clusterService, mockToolsImageVersionMetadataProvider); | ||
|
||
// Act | ||
var result = await podContainerResolver.GetContainerImageForCluster(); | ||
|
||
// Assert | ||
result.Should().Be($"octopusdeploy/kubernetes-agent-tools-base:{expectedImageTag}"); | ||
} | ||
} | ||
} |
43 changes: 0 additions & 43 deletions
43
source/Octopus.Tentacle.Tests/Kubernetes/KubernetesVersionParserTests.cs
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
using System; | ||
using System.Text.RegularExpressions; | ||
using k8s.Models; | ||
|
||
namespace Octopus.Tentacle.Kubernetes | ||
{ | ||
public class ClusterVersion : IComparable<ClusterVersion> | ||
{ | ||
public ClusterVersion(int major, int minor) | ||
{ | ||
Major = major; | ||
Minor = minor; | ||
} | ||
|
||
public int Major { get; } | ||
public int Minor { get; } | ||
|
||
public static ClusterVersion FromVersion(Version version) | ||
{ | ||
return new ClusterVersion(version.Major, version.Minor); | ||
} | ||
|
||
public static ClusterVersion FromVersionInfo(VersionInfo versionInfo) | ||
{ | ||
return new ClusterVersion(SanitizeAndParseVersionNumber(versionInfo.Major), SanitizeAndParseVersionNumber(versionInfo.Minor)); | ||
} | ||
|
||
static int SanitizeAndParseVersionNumber(string version) | ||
{ | ||
return int.Parse(Regex.Replace(version, "[^0-9]", "")); | ||
} | ||
|
||
public int CompareTo(ClusterVersion? other) | ||
{ | ||
if (other == null) return 1; | ||
if (Major > other.Major || (Major == other.Major && Minor > other.Minor)) return 1; | ||
if (Major == other.Major && Minor == other.Minor) return 0; | ||
return -1; | ||
} | ||
|
||
public override bool Equals(object? obj) | ||
{ | ||
if (obj is not ClusterVersion clusterVersion) | ||
return false; | ||
|
||
return clusterVersion.Major == Major && clusterVersion.Minor == Minor; | ||
} | ||
|
||
public override int GetHashCode() | ||
{ | ||
#if NET8_0_OR_GREATER | ||
return HashCode.Combine(Major, Minor); | ||
#else | ||
unchecked // Overflow is fine in hash code calculations | ||
{ | ||
int hash = 17; | ||
hash = hash * 23 + Major.GetHashCode(); | ||
hash = hash * 23 + Minor.GetHashCode(); | ||
return hash; | ||
} | ||
#endif | ||
} | ||
|
||
public override string ToString() | ||
{ | ||
return $"{Major}.{Minor}"; | ||
} | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
source/Octopus.Tentacle/Kubernetes/KubernetesAgentToolsImageVersionMetadata.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using Newtonsoft.Json; | ||
|
||
namespace Octopus.Tentacle.Kubernetes | ||
{ | ||
public record KubernetesAgentToolsImageVersionMetadata( | ||
[JsonProperty("tools")] KubernetesAgentToolVersions ToolVersions, | ||
[JsonProperty("latest")] Version Latest, | ||
[JsonProperty("revisionHash")] string RevisionHash, | ||
[JsonProperty("deprecations")] Dictionary<Version, KubernetesAgentToolDeprecation> Deprecations); | ||
|
||
public record KubernetesAgentToolVersions( | ||
[JsonProperty("kubectl")] List<Version> Kubectl, | ||
[JsonProperty("helm")] List<Version> Helm, | ||
[JsonProperty("powershell")] List<Version> Powershell | ||
); | ||
|
||
public record KubernetesAgentToolDeprecation( | ||
[JsonProperty("latestTag")] string LatestTag); | ||
} |
Oops, something went wrong.