Skip to content

Commit

Permalink
refactor: Transpilation and conversion of objects (#614)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: This removes the entity and rbac conversion
from the operator package and extracts them into their own
`KubeOps.Transpiler` package. All static methods there
are used for transpilation of the entities and rbac attributes.
Additional logic for Lease, events and such will reside
in the CLI.
  • Loading branch information
buehler committed Sep 26, 2023
1 parent 89356f2 commit ca59816
Show file tree
Hide file tree
Showing 50 changed files with 2,138 additions and 843 deletions.
26 changes: 19 additions & 7 deletions KubeOps.sln
Expand Up @@ -4,8 +4,14 @@ Microsoft Visual Studio Solution File, Format Version 12.00
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C587731F-8191-4A19-8662-B89A60FE79A1}"
ProjectSection(SolutionItems) = preProject
test\Directory.Build.props = test\Directory.Build.props
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4DB01062-6DC5-4028-BB72-C0619C2F5F2E}"
ProjectSection(SolutionItems) = preProject
src\Directory.Build.props = src\Directory.Build.props
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{DC760E69-D0EA-417F-AE38-B12D0B04DE39}"
EndProject
Expand All @@ -16,7 +22,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "config", "config", "{DCC363
.editorconfig = .editorconfig
.gitignore = .gitignore
.releaserc.json = .releaserc.json
Directory.Build.props = Directory.Build.props
renovate.json = renovate.json
EndProjectSection
EndProject
Expand All @@ -38,7 +43,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KubeOps.Operator.Web", "src
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KubeOps.Operator.Web.Test", "test\KubeOps.Operator.Web.Test\KubeOps.Operator.Web.Test.csproj", "{BC6E6D3C-6404-4B01-9D72-AA16FEEBFF5C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KubeOps.Transpiler", "src\KubeOps.Transpiler\KubeOps.Transpiler.csproj", "{9C155732-5CE8-4F1D-8D5F-AB60DB1A1B5C}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KubeOps.Transpiler.Test", "test\KubeOps.Transpiler.Test\KubeOps.Transpiler.Test.csproj", "{47914451-147D-427E-B150-9C47DBF28F2C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KubeOps.Transpiler", "src\KubeOps.Transpiler\KubeOps.Transpiler.csproj", "{A793FC08-E76C-448B-BE93-88C137D2C7AB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -59,7 +66,8 @@ Global
{162EE2A9-F8BA-4D52-9D65-67CCDB76EAC9} = {C587731F-8191-4A19-8662-B89A60FE79A1}
{E5012C55-B34E-4672-AF4C-C233B45E8EA2} = {4DB01062-6DC5-4028-BB72-C0619C2F5F2E}
{BC6E6D3C-6404-4B01-9D72-AA16FEEBFF5C} = {C587731F-8191-4A19-8662-B89A60FE79A1}
{9C155732-5CE8-4F1D-8D5F-AB60DB1A1B5C} = {4DB01062-6DC5-4028-BB72-C0619C2F5F2E}
{47914451-147D-427E-B150-9C47DBF28F2C} = {C587731F-8191-4A19-8662-B89A60FE79A1}
{A793FC08-E76C-448B-BE93-88C137D2C7AB} = {4DB01062-6DC5-4028-BB72-C0619C2F5F2E}
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E9A0B04E-D90E-4B94-90E0-DD3666B098FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
Expand Down Expand Up @@ -102,9 +110,13 @@ Global
{BC6E6D3C-6404-4B01-9D72-AA16FEEBFF5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BC6E6D3C-6404-4B01-9D72-AA16FEEBFF5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BC6E6D3C-6404-4B01-9D72-AA16FEEBFF5C}.Release|Any CPU.Build.0 = Release|Any CPU
{9C155732-5CE8-4F1D-8D5F-AB60DB1A1B5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9C155732-5CE8-4F1D-8D5F-AB60DB1A1B5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9C155732-5CE8-4F1D-8D5F-AB60DB1A1B5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9C155732-5CE8-4F1D-8D5F-AB60DB1A1B5C}.Release|Any CPU.Build.0 = Release|Any CPU
{47914451-147D-427E-B150-9C47DBF28F2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{47914451-147D-427E-B150-9C47DBF28F2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{47914451-147D-427E-B150-9C47DBF28F2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{47914451-147D-427E-B150-9C47DBF28F2C}.Release|Any CPU.Build.0 = Release|Any CPU
{A793FC08-E76C-448B-BE93-88C137D2C7AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A793FC08-E76C-448B-BE93-88C137D2C7AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A793FC08-E76C-448B-BE93-88C137D2C7AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A793FC08-E76C-448B-BE93-88C137D2C7AB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
262 changes: 121 additions & 141 deletions _old/tests/KubeOps.Test/Operator/Generators/CrdGenerator.Test.cs
@@ -1,141 +1,121 @@
using System.Reflection;

using FluentAssertions;

using k8s;
using k8s.Models;

using KubeOps.Operator.Builder;
using KubeOps.Operator.Entities;
using KubeOps.Test.TestEntities;

using Xunit;

namespace KubeOps.Test.Operator.Generators;

public class CrdGeneratorTest
{
private readonly IEnumerable<V1CustomResourceDefinition> _crds;
private readonly ComponentRegistrar _componentRegistrar = new();

public CrdGeneratorTest()
{
_componentRegistrar.RegisterEntity<TestIgnoredEntity>();
_componentRegistrar.RegisterEntity<TestInvalidEntity>();
_componentRegistrar.RegisterEntity<TestSpecEntity>();
_componentRegistrar.RegisterEntity<TestClusterSpecEntity>();
_componentRegistrar.RegisterEntity<TestStatusEntity>();
_componentRegistrar.RegisterEntity<V1Alpha1VersionedEntity>();
_componentRegistrar.RegisterEntity<V1AttributeVersionedEntity>();
_componentRegistrar.RegisterEntity<V1Beta1VersionedEntity>();
_componentRegistrar.RegisterEntity<V1VersionedEntity>();
_componentRegistrar.RegisterEntity<V2AttributeVersionedEntity>();
_componentRegistrar.RegisterEntity<V2Beta2VersionedEntity>();
_componentRegistrar.RegisterEntity<V2VersionedEntity>();
_componentRegistrar.RegisterEntity<TestCustomCrdTypeOverrides>();

// Should be ignored since V1Pod is from the k8s assembly.
_componentRegistrar.RegisterEntity<V1Pod>();

_crds = new CrdBuilder(_componentRegistrar).BuildCrds();
}

[Fact]
public void Should_Generate_Correct_Number_Of_Crds()
{
_crds.Count().Should().Be(6);
}

[Fact]
public void Should_Not_Contain_Ignored_Entities()
{
_crds.Should()
.NotContain(crd => crd.Name().Contains("ignored", StringComparison.InvariantCultureIgnoreCase));
}

[Fact]
public void Should_Not_Contain_K8s_Entities()
{
_crds.Should()
.NotContain(crd => crd.Spec.Names.Kind == "Pod");
}

[Fact]
public void Should_Set_Highest_Version_As_Storage()
{
var crd = _crds.First(c => c.Spec.Names.Kind == "VersionedEntity");
crd.Spec.Versions.Count(v => v.Storage).Should().Be(1);
crd.Spec.Versions.First(v => v.Storage).Name.Should().Be("v2");
}

[Fact]
public void Should_Set_Storage_When_Attribute_Is_Set()
{
var crd = _crds.First(c => c.Spec.Names.Kind == "AttributeVersionedEntity");
crd.Spec.Versions.Count(v => v.Storage).Should().Be(1);
crd.Spec.Versions.First(v => v.Storage).Name.Should().Be("v1");
}

[Fact]
public void Should_Add_Multiple_Versions_To_Crd()
{
_crds
.First(c => c.Spec.Names.Kind.Contains("testspecentity", StringComparison.InvariantCultureIgnoreCase))
.Spec.Versions.Should()
.HaveCount(1);
_crds
.First(c => c.Spec.Names.Kind.Contains("teststatusentity", StringComparison.InvariantCultureIgnoreCase))
.Spec.Versions.Should()
.HaveCount(1);
_crds
.First(c => c.Spec.Names.Kind == "VersionedEntity")
.Spec.Versions.Should()
.HaveCount(5);
_crds
.First(c => c.Spec.Names.Kind == "AttributeVersionedEntity")
.Spec.Versions.Should()
.HaveCount(2);
}

[Fact]
public void Should_Add_ShortNames_To_Crd()
{
_crds
.First(c => c.Spec.Names.Kind.Contains("teststatusentity", StringComparison.InvariantCultureIgnoreCase))
.Spec.Names.ShortNames.Should()
.NotBeNull()
.And
.Contain(new[] { "foo", "bar", "baz" });
}

[Fact]
public void Should_Create_Crd_As_Default_Without_Crd_Type_Overrides()
{
var crdWithoutOverrides = new CrdBuilder(_componentRegistrar)
.BuildCrds()
.First(

c => c.Spec.Names.Kind.Contains("testcustomtypeoverrides", StringComparison.InvariantCultureIgnoreCase));


var serializedWithoutOverrides = TestTypeOverridesValues.SerializeWithoutDescriptions(crdWithoutOverrides);

serializedWithoutOverrides.Should().Contain(TestTypeOverridesValues.ExpectedDefaultYamlResources);
serializedWithoutOverrides.Should().NotContain(TestTypeOverridesValues.ExpectedOverriddenResourcesYaml);
}

[Fact]
public void Should_Convert_Desired_Crd_Type_Everywhere_To_Desired_Crd_Format()
{
var customOverrides = new List<ICrdBuilderTypeOverride> { new CrdBuilderResourceQuantityOverride() };
var crdWithTypeOverrides = new CrdBuilder(_componentRegistrar, customOverrides)
.BuildCrds()
.First(
c => c.Spec.Names.Kind.Contains("testcustomtypeoverrides", StringComparison.InvariantCultureIgnoreCase));
var serializedWithOverrides = TestTypeOverridesValues.SerializeWithoutDescriptions(crdWithTypeOverrides);

serializedWithOverrides.Should().Contain(TestTypeOverridesValues.ExpectedOverriddenResourcesYaml);
serializedWithOverrides.Should().NotContain(TestTypeOverridesValues.ExpectedDefaultYamlResources);

}
}
using System.Reflection;

using FluentAssertions;

using k8s;
using k8s.Models;

using KubeOps.Operator.Builder;
using KubeOps.Operator.Entities;
using KubeOps.Test.TestEntities;

using Xunit;

namespace KubeOps.Test.Operator.Generators;

public class CrdGeneratorTest
{
private readonly IEnumerable<V1CustomResourceDefinition> _crds;
private readonly ComponentRegistrar _componentRegistrar = new();

public CrdGeneratorTest()
{
_componentRegistrar.RegisterEntity<TestIgnoredEntity>();
_componentRegistrar.RegisterEntity<TestInvalidEntity>();
_componentRegistrar.RegisterEntity<TestSpecEntity>();
_componentRegistrar.RegisterEntity<TestClusterSpecEntity>();
_componentRegistrar.RegisterEntity<TestStatusEntity>();
_componentRegistrar.RegisterEntity<V1Alpha1VersionedEntity>();
_componentRegistrar.RegisterEntity<V1AttributeVersionedEntity>();
_componentRegistrar.RegisterEntity<V1Beta1VersionedEntity>();
_componentRegistrar.RegisterEntity<V1VersionedEntity>();
_componentRegistrar.RegisterEntity<V2AttributeVersionedEntity>();
_componentRegistrar.RegisterEntity<V2Beta2VersionedEntity>();
_componentRegistrar.RegisterEntity<V2VersionedEntity>();
_componentRegistrar.RegisterEntity<TestCustomCrdTypeOverrides>();

// Should be ignored since V1Pod is from the k8s assembly.
_componentRegistrar.RegisterEntity<V1Pod>();

_crds = new CrdBuilder(_componentRegistrar).BuildCrds();
}

[Fact]
public void Should_Set_Highest_Version_As_Storage()
{
var crd = _crds.First(c => c.Spec.Names.Kind == "VersionedEntity");
crd.Spec.Versions.Count(v => v.Storage).Should().Be(1);
crd.Spec.Versions.First(v => v.Storage).Name.Should().Be("v2");
}

[Fact]
public void Should_Set_Storage_When_Attribute_Is_Set()
{
var crd = _crds.First(c => c.Spec.Names.Kind == "AttributeVersionedEntity");
crd.Spec.Versions.Count(v => v.Storage).Should().Be(1);
crd.Spec.Versions.First(v => v.Storage).Name.Should().Be("v1");
}

[Fact]
public void Should_Add_Multiple_Versions_To_Crd()
{
_crds
.First(c => c.Spec.Names.Kind.Contains("testspecentity", StringComparison.InvariantCultureIgnoreCase))
.Spec.Versions.Should()
.HaveCount(1);
_crds
.First(c => c.Spec.Names.Kind.Contains("teststatusentity", StringComparison.InvariantCultureIgnoreCase))
.Spec.Versions.Should()
.HaveCount(1);
_crds
.First(c => c.Spec.Names.Kind == "VersionedEntity")
.Spec.Versions.Should()
.HaveCount(5);
_crds
.First(c => c.Spec.Names.Kind == "AttributeVersionedEntity")
.Spec.Versions.Should()
.HaveCount(2);
}

[Fact]
public void Should_Add_ShortNames_To_Crd()
{
_crds
.First(c => c.Spec.Names.Kind.Contains("teststatusentity", StringComparison.InvariantCultureIgnoreCase))
.Spec.Names.ShortNames.Should()
.NotBeNull()
.And
.Contain(new[] { "foo", "bar", "baz" });
}

[Fact]
public void Should_Create_Crd_As_Default_Without_Crd_Type_Overrides()
{
var crdWithoutOverrides = new CrdBuilder(_componentRegistrar)
.BuildCrds()
.First(

c => c.Spec.Names.Kind.Contains("testcustomtypeoverrides", StringComparison.InvariantCultureIgnoreCase));


var serializedWithoutOverrides = TestTypeOverridesValues.SerializeWithoutDescriptions(crdWithoutOverrides);

serializedWithoutOverrides.Should().Contain(TestTypeOverridesValues.ExpectedDefaultYamlResources);
serializedWithoutOverrides.Should().NotContain(TestTypeOverridesValues.ExpectedOverriddenResourcesYaml);
}

[Fact]
public void Should_Convert_Desired_Crd_Type_Everywhere_To_Desired_Crd_Format()
{
var customOverrides = new List<ICrdBuilderTypeOverride> { new CrdBuilderResourceQuantityOverride() };
var crdWithTypeOverrides = new CrdBuilder(_componentRegistrar, customOverrides)
.BuildCrds()
.First(
c => c.Spec.Names.Kind.Contains("testcustomtypeoverrides", StringComparison.InvariantCultureIgnoreCase));
var serializedWithOverrides = TestTypeOverridesValues.SerializeWithoutDescriptions(crdWithTypeOverrides);

serializedWithOverrides.Should().Contain(TestTypeOverridesValues.ExpectedOverriddenResourcesYaml);
serializedWithOverrides.Should().NotContain(TestTypeOverridesValues.ExpectedDefaultYamlResources);

}
}
28 changes: 6 additions & 22 deletions docfx.json
Expand Up @@ -2,38 +2,24 @@
"build": {
"content": [
{
"files": [
"docs/api/**.yml"
]
"files": ["docs/api/**.yml"]
},
{
"files": [
"docs/**.md",
"docs/**/toc.yml",
"toc.yml",
"*.md"
]
"files": ["docs/**.md", "docs/**/toc.yml", "toc.yml", "*.md"]
},
{
"files": [
"src/**/*.md"
]
"files": ["src/**/*.md"]
}
],
"resource": [
{
"files": [
"res/**"
]
"files": ["res/**"]
}
],
"output": "_site",
"globalMetadataFiles": [],
"fileMetadataFiles": [],
"template": [
"default",
"modern"
],
"template": ["default", "modern"],
"postProcessors": [],
"keepFileLink": false,
"disableGitFeatures": false
Expand All @@ -42,9 +28,7 @@
{
"src": [
{
"files": [
"src/**/*.csproj"
]
"files": ["src/**/*.csproj"]
}
],
"dest": "docs/api",
Expand Down
2 changes: 2 additions & 0 deletions examples/Operator/Controller/V1TestEntityController.cs
@@ -1,11 +1,13 @@
using KubeOps.Abstractions.Controller;
using KubeOps.Abstractions.Rbac;

using Microsoft.Extensions.Logging;

using Operator.Entities;

namespace Operator.Controller;

[EntityRbac(typeof(V1TestEntity), Verbs = RbacVerb.All)]
public class V1TestEntityController : IEntityController<V1TestEntity>
{
private readonly ILogger<V1TestEntityController> _logger;
Expand Down

0 comments on commit ca59816

Please sign in to comment.