Skip to content

Commit e17cd8c

Browse files
committed
refactor: Transpilation and conversion of objects (#614)
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.
1 parent 9e3d802 commit e17cd8c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+2138
-843
lines changed

KubeOps.sln

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,14 @@ Microsoft Visual Studio Solution File, Format Version 12.00
44
VisualStudioVersion = 17.0.31903.59
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C587731F-8191-4A19-8662-B89A60FE79A1}"
7+
ProjectSection(SolutionItems) = preProject
8+
test\Directory.Build.props = test\Directory.Build.props
9+
EndProjectSection
710
EndProject
811
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4DB01062-6DC5-4028-BB72-C0619C2F5F2E}"
12+
ProjectSection(SolutionItems) = preProject
13+
src\Directory.Build.props = src\Directory.Build.props
14+
EndProjectSection
915
EndProject
1016
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{DC760E69-D0EA-417F-AE38-B12D0B04DE39}"
1117
EndProject
@@ -16,7 +22,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "config", "config", "{DCC363
1622
.editorconfig = .editorconfig
1723
.gitignore = .gitignore
1824
.releaserc.json = .releaserc.json
19-
Directory.Build.props = Directory.Build.props
2025
renovate.json = renovate.json
2126
EndProjectSection
2227
EndProject
@@ -38,7 +43,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KubeOps.Operator.Web", "src
3843
EndProject
3944
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}"
4045
EndProject
41-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KubeOps.Transpiler", "src\KubeOps.Transpiler\KubeOps.Transpiler.csproj", "{9C155732-5CE8-4F1D-8D5F-AB60DB1A1B5C}"
46+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KubeOps.Transpiler.Test", "test\KubeOps.Transpiler.Test\KubeOps.Transpiler.Test.csproj", "{47914451-147D-427E-B150-9C47DBF28F2C}"
47+
EndProject
48+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KubeOps.Transpiler", "src\KubeOps.Transpiler\KubeOps.Transpiler.csproj", "{A793FC08-E76C-448B-BE93-88C137D2C7AB}"
4249
EndProject
4350
Global
4451
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -59,7 +66,8 @@ Global
5966
{162EE2A9-F8BA-4D52-9D65-67CCDB76EAC9} = {C587731F-8191-4A19-8662-B89A60FE79A1}
6067
{E5012C55-B34E-4672-AF4C-C233B45E8EA2} = {4DB01062-6DC5-4028-BB72-C0619C2F5F2E}
6168
{BC6E6D3C-6404-4B01-9D72-AA16FEEBFF5C} = {C587731F-8191-4A19-8662-B89A60FE79A1}
62-
{9C155732-5CE8-4F1D-8D5F-AB60DB1A1B5C} = {4DB01062-6DC5-4028-BB72-C0619C2F5F2E}
69+
{47914451-147D-427E-B150-9C47DBF28F2C} = {C587731F-8191-4A19-8662-B89A60FE79A1}
70+
{A793FC08-E76C-448B-BE93-88C137D2C7AB} = {4DB01062-6DC5-4028-BB72-C0619C2F5F2E}
6371
EndGlobalSection
6472
GlobalSection(ProjectConfigurationPlatforms) = postSolution
6573
{E9A0B04E-D90E-4B94-90E0-DD3666B098FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
@@ -102,9 +110,13 @@ Global
102110
{BC6E6D3C-6404-4B01-9D72-AA16FEEBFF5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
103111
{BC6E6D3C-6404-4B01-9D72-AA16FEEBFF5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
104112
{BC6E6D3C-6404-4B01-9D72-AA16FEEBFF5C}.Release|Any CPU.Build.0 = Release|Any CPU
105-
{9C155732-5CE8-4F1D-8D5F-AB60DB1A1B5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
106-
{9C155732-5CE8-4F1D-8D5F-AB60DB1A1B5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
107-
{9C155732-5CE8-4F1D-8D5F-AB60DB1A1B5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
108-
{9C155732-5CE8-4F1D-8D5F-AB60DB1A1B5C}.Release|Any CPU.Build.0 = Release|Any CPU
113+
{47914451-147D-427E-B150-9C47DBF28F2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
114+
{47914451-147D-427E-B150-9C47DBF28F2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
115+
{47914451-147D-427E-B150-9C47DBF28F2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
116+
{47914451-147D-427E-B150-9C47DBF28F2C}.Release|Any CPU.Build.0 = Release|Any CPU
117+
{A793FC08-E76C-448B-BE93-88C137D2C7AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
118+
{A793FC08-E76C-448B-BE93-88C137D2C7AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
119+
{A793FC08-E76C-448B-BE93-88C137D2C7AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
120+
{A793FC08-E76C-448B-BE93-88C137D2C7AB}.Release|Any CPU.Build.0 = Release|Any CPU
109121
EndGlobalSection
110122
EndGlobal
Lines changed: 121 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -1,141 +1,121 @@
1-
using System.Reflection;
2-
3-
using FluentAssertions;
4-
5-
using k8s;
6-
using k8s.Models;
7-
8-
using KubeOps.Operator.Builder;
9-
using KubeOps.Operator.Entities;
10-
using KubeOps.Test.TestEntities;
11-
12-
using Xunit;
13-
14-
namespace KubeOps.Test.Operator.Generators;
15-
16-
public class CrdGeneratorTest
17-
{
18-
private readonly IEnumerable<V1CustomResourceDefinition> _crds;
19-
private readonly ComponentRegistrar _componentRegistrar = new();
20-
21-
public CrdGeneratorTest()
22-
{
23-
_componentRegistrar.RegisterEntity<TestIgnoredEntity>();
24-
_componentRegistrar.RegisterEntity<TestInvalidEntity>();
25-
_componentRegistrar.RegisterEntity<TestSpecEntity>();
26-
_componentRegistrar.RegisterEntity<TestClusterSpecEntity>();
27-
_componentRegistrar.RegisterEntity<TestStatusEntity>();
28-
_componentRegistrar.RegisterEntity<V1Alpha1VersionedEntity>();
29-
_componentRegistrar.RegisterEntity<V1AttributeVersionedEntity>();
30-
_componentRegistrar.RegisterEntity<V1Beta1VersionedEntity>();
31-
_componentRegistrar.RegisterEntity<V1VersionedEntity>();
32-
_componentRegistrar.RegisterEntity<V2AttributeVersionedEntity>();
33-
_componentRegistrar.RegisterEntity<V2Beta2VersionedEntity>();
34-
_componentRegistrar.RegisterEntity<V2VersionedEntity>();
35-
_componentRegistrar.RegisterEntity<TestCustomCrdTypeOverrides>();
36-
37-
// Should be ignored since V1Pod is from the k8s assembly.
38-
_componentRegistrar.RegisterEntity<V1Pod>();
39-
40-
_crds = new CrdBuilder(_componentRegistrar).BuildCrds();
41-
}
42-
43-
[Fact]
44-
public void Should_Generate_Correct_Number_Of_Crds()
45-
{
46-
_crds.Count().Should().Be(6);
47-
}
48-
49-
[Fact]
50-
public void Should_Not_Contain_Ignored_Entities()
51-
{
52-
_crds.Should()
53-
.NotContain(crd => crd.Name().Contains("ignored", StringComparison.InvariantCultureIgnoreCase));
54-
}
55-
56-
[Fact]
57-
public void Should_Not_Contain_K8s_Entities()
58-
{
59-
_crds.Should()
60-
.NotContain(crd => crd.Spec.Names.Kind == "Pod");
61-
}
62-
63-
[Fact]
64-
public void Should_Set_Highest_Version_As_Storage()
65-
{
66-
var crd = _crds.First(c => c.Spec.Names.Kind == "VersionedEntity");
67-
crd.Spec.Versions.Count(v => v.Storage).Should().Be(1);
68-
crd.Spec.Versions.First(v => v.Storage).Name.Should().Be("v2");
69-
}
70-
71-
[Fact]
72-
public void Should_Set_Storage_When_Attribute_Is_Set()
73-
{
74-
var crd = _crds.First(c => c.Spec.Names.Kind == "AttributeVersionedEntity");
75-
crd.Spec.Versions.Count(v => v.Storage).Should().Be(1);
76-
crd.Spec.Versions.First(v => v.Storage).Name.Should().Be("v1");
77-
}
78-
79-
[Fact]
80-
public void Should_Add_Multiple_Versions_To_Crd()
81-
{
82-
_crds
83-
.First(c => c.Spec.Names.Kind.Contains("testspecentity", StringComparison.InvariantCultureIgnoreCase))
84-
.Spec.Versions.Should()
85-
.HaveCount(1);
86-
_crds
87-
.First(c => c.Spec.Names.Kind.Contains("teststatusentity", StringComparison.InvariantCultureIgnoreCase))
88-
.Spec.Versions.Should()
89-
.HaveCount(1);
90-
_crds
91-
.First(c => c.Spec.Names.Kind == "VersionedEntity")
92-
.Spec.Versions.Should()
93-
.HaveCount(5);
94-
_crds
95-
.First(c => c.Spec.Names.Kind == "AttributeVersionedEntity")
96-
.Spec.Versions.Should()
97-
.HaveCount(2);
98-
}
99-
100-
[Fact]
101-
public void Should_Add_ShortNames_To_Crd()
102-
{
103-
_crds
104-
.First(c => c.Spec.Names.Kind.Contains("teststatusentity", StringComparison.InvariantCultureIgnoreCase))
105-
.Spec.Names.ShortNames.Should()
106-
.NotBeNull()
107-
.And
108-
.Contain(new[] { "foo", "bar", "baz" });
109-
}
110-
111-
[Fact]
112-
public void Should_Create_Crd_As_Default_Without_Crd_Type_Overrides()
113-
{
114-
var crdWithoutOverrides = new CrdBuilder(_componentRegistrar)
115-
.BuildCrds()
116-
.First(
117-
118-
c => c.Spec.Names.Kind.Contains("testcustomtypeoverrides", StringComparison.InvariantCultureIgnoreCase));
119-
120-
121-
var serializedWithoutOverrides = TestTypeOverridesValues.SerializeWithoutDescriptions(crdWithoutOverrides);
122-
123-
serializedWithoutOverrides.Should().Contain(TestTypeOverridesValues.ExpectedDefaultYamlResources);
124-
serializedWithoutOverrides.Should().NotContain(TestTypeOverridesValues.ExpectedOverriddenResourcesYaml);
125-
}
126-
127-
[Fact]
128-
public void Should_Convert_Desired_Crd_Type_Everywhere_To_Desired_Crd_Format()
129-
{
130-
var customOverrides = new List<ICrdBuilderTypeOverride> { new CrdBuilderResourceQuantityOverride() };
131-
var crdWithTypeOverrides = new CrdBuilder(_componentRegistrar, customOverrides)
132-
.BuildCrds()
133-
.First(
134-
c => c.Spec.Names.Kind.Contains("testcustomtypeoverrides", StringComparison.InvariantCultureIgnoreCase));
135-
var serializedWithOverrides = TestTypeOverridesValues.SerializeWithoutDescriptions(crdWithTypeOverrides);
136-
137-
serializedWithOverrides.Should().Contain(TestTypeOverridesValues.ExpectedOverriddenResourcesYaml);
138-
serializedWithOverrides.Should().NotContain(TestTypeOverridesValues.ExpectedDefaultYamlResources);
139-
140-
}
141-
}
1+
using System.Reflection;
2+
3+
using FluentAssertions;
4+
5+
using k8s;
6+
using k8s.Models;
7+
8+
using KubeOps.Operator.Builder;
9+
using KubeOps.Operator.Entities;
10+
using KubeOps.Test.TestEntities;
11+
12+
using Xunit;
13+
14+
namespace KubeOps.Test.Operator.Generators;
15+
16+
public class CrdGeneratorTest
17+
{
18+
private readonly IEnumerable<V1CustomResourceDefinition> _crds;
19+
private readonly ComponentRegistrar _componentRegistrar = new();
20+
21+
public CrdGeneratorTest()
22+
{
23+
_componentRegistrar.RegisterEntity<TestIgnoredEntity>();
24+
_componentRegistrar.RegisterEntity<TestInvalidEntity>();
25+
_componentRegistrar.RegisterEntity<TestSpecEntity>();
26+
_componentRegistrar.RegisterEntity<TestClusterSpecEntity>();
27+
_componentRegistrar.RegisterEntity<TestStatusEntity>();
28+
_componentRegistrar.RegisterEntity<V1Alpha1VersionedEntity>();
29+
_componentRegistrar.RegisterEntity<V1AttributeVersionedEntity>();
30+
_componentRegistrar.RegisterEntity<V1Beta1VersionedEntity>();
31+
_componentRegistrar.RegisterEntity<V1VersionedEntity>();
32+
_componentRegistrar.RegisterEntity<V2AttributeVersionedEntity>();
33+
_componentRegistrar.RegisterEntity<V2Beta2VersionedEntity>();
34+
_componentRegistrar.RegisterEntity<V2VersionedEntity>();
35+
_componentRegistrar.RegisterEntity<TestCustomCrdTypeOverrides>();
36+
37+
// Should be ignored since V1Pod is from the k8s assembly.
38+
_componentRegistrar.RegisterEntity<V1Pod>();
39+
40+
_crds = new CrdBuilder(_componentRegistrar).BuildCrds();
41+
}
42+
43+
[Fact]
44+
public void Should_Set_Highest_Version_As_Storage()
45+
{
46+
var crd = _crds.First(c => c.Spec.Names.Kind == "VersionedEntity");
47+
crd.Spec.Versions.Count(v => v.Storage).Should().Be(1);
48+
crd.Spec.Versions.First(v => v.Storage).Name.Should().Be("v2");
49+
}
50+
51+
[Fact]
52+
public void Should_Set_Storage_When_Attribute_Is_Set()
53+
{
54+
var crd = _crds.First(c => c.Spec.Names.Kind == "AttributeVersionedEntity");
55+
crd.Spec.Versions.Count(v => v.Storage).Should().Be(1);
56+
crd.Spec.Versions.First(v => v.Storage).Name.Should().Be("v1");
57+
}
58+
59+
[Fact]
60+
public void Should_Add_Multiple_Versions_To_Crd()
61+
{
62+
_crds
63+
.First(c => c.Spec.Names.Kind.Contains("testspecentity", StringComparison.InvariantCultureIgnoreCase))
64+
.Spec.Versions.Should()
65+
.HaveCount(1);
66+
_crds
67+
.First(c => c.Spec.Names.Kind.Contains("teststatusentity", StringComparison.InvariantCultureIgnoreCase))
68+
.Spec.Versions.Should()
69+
.HaveCount(1);
70+
_crds
71+
.First(c => c.Spec.Names.Kind == "VersionedEntity")
72+
.Spec.Versions.Should()
73+
.HaveCount(5);
74+
_crds
75+
.First(c => c.Spec.Names.Kind == "AttributeVersionedEntity")
76+
.Spec.Versions.Should()
77+
.HaveCount(2);
78+
}
79+
80+
[Fact]
81+
public void Should_Add_ShortNames_To_Crd()
82+
{
83+
_crds
84+
.First(c => c.Spec.Names.Kind.Contains("teststatusentity", StringComparison.InvariantCultureIgnoreCase))
85+
.Spec.Names.ShortNames.Should()
86+
.NotBeNull()
87+
.And
88+
.Contain(new[] { "foo", "bar", "baz" });
89+
}
90+
91+
[Fact]
92+
public void Should_Create_Crd_As_Default_Without_Crd_Type_Overrides()
93+
{
94+
var crdWithoutOverrides = new CrdBuilder(_componentRegistrar)
95+
.BuildCrds()
96+
.First(
97+
98+
c => c.Spec.Names.Kind.Contains("testcustomtypeoverrides", StringComparison.InvariantCultureIgnoreCase));
99+
100+
101+
var serializedWithoutOverrides = TestTypeOverridesValues.SerializeWithoutDescriptions(crdWithoutOverrides);
102+
103+
serializedWithoutOverrides.Should().Contain(TestTypeOverridesValues.ExpectedDefaultYamlResources);
104+
serializedWithoutOverrides.Should().NotContain(TestTypeOverridesValues.ExpectedOverriddenResourcesYaml);
105+
}
106+
107+
[Fact]
108+
public void Should_Convert_Desired_Crd_Type_Everywhere_To_Desired_Crd_Format()
109+
{
110+
var customOverrides = new List<ICrdBuilderTypeOverride> { new CrdBuilderResourceQuantityOverride() };
111+
var crdWithTypeOverrides = new CrdBuilder(_componentRegistrar, customOverrides)
112+
.BuildCrds()
113+
.First(
114+
c => c.Spec.Names.Kind.Contains("testcustomtypeoverrides", StringComparison.InvariantCultureIgnoreCase));
115+
var serializedWithOverrides = TestTypeOverridesValues.SerializeWithoutDescriptions(crdWithTypeOverrides);
116+
117+
serializedWithOverrides.Should().Contain(TestTypeOverridesValues.ExpectedOverriddenResourcesYaml);
118+
serializedWithOverrides.Should().NotContain(TestTypeOverridesValues.ExpectedDefaultYamlResources);
119+
120+
}
121+
}

docfx.json

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,24 @@
22
"build": {
33
"content": [
44
{
5-
"files": [
6-
"docs/api/**.yml"
7-
]
5+
"files": ["docs/api/**.yml"]
86
},
97
{
10-
"files": [
11-
"docs/**.md",
12-
"docs/**/toc.yml",
13-
"toc.yml",
14-
"*.md"
15-
]
8+
"files": ["docs/**.md", "docs/**/toc.yml", "toc.yml", "*.md"]
169
},
1710
{
18-
"files": [
19-
"src/**/*.md"
20-
]
11+
"files": ["src/**/*.md"]
2112
}
2213
],
2314
"resource": [
2415
{
25-
"files": [
26-
"res/**"
27-
]
16+
"files": ["res/**"]
2817
}
2918
],
3019
"output": "_site",
3120
"globalMetadataFiles": [],
3221
"fileMetadataFiles": [],
33-
"template": [
34-
"default",
35-
"modern"
36-
],
22+
"template": ["default", "modern"],
3723
"postProcessors": [],
3824
"keepFileLink": false,
3925
"disableGitFeatures": false
@@ -42,9 +28,7 @@
4228
{
4329
"src": [
4430
{
45-
"files": [
46-
"src/**/*.csproj"
47-
]
31+
"files": ["src/**/*.csproj"]
4832
}
4933
],
5034
"dest": "docs/api",

examples/Operator/Controller/V1TestEntityController.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
using KubeOps.Abstractions.Controller;
2+
using KubeOps.Abstractions.Rbac;
23

34
using Microsoft.Extensions.Logging;
45

56
using Operator.Entities;
67

78
namespace Operator.Controller;
89

10+
[EntityRbac(typeof(V1TestEntity), Verbs = RbacVerb.All)]
911
public class V1TestEntityController : IEntityController<V1TestEntity>
1012
{
1113
private readonly ILogger<V1TestEntityController> _logger;

0 commit comments

Comments
 (0)