1
1
using System ;
2
2
using System . Collections . Generic ;
3
- using System . ComponentModel . DataAnnotations ;
4
3
using System . IO ;
5
4
using System . Linq ;
6
5
using System . Reflection ;
7
6
using System . Text ;
8
7
using System . Threading . Tasks ;
9
8
using k8s . Models ;
10
- using KubeOps . Operator . Entities ;
11
9
using KubeOps . Operator . Entities . Extensions ;
12
10
using KubeOps . Operator . Entities . Kustomize ;
13
11
using KubeOps . Operator . Serialization ;
@@ -18,18 +16,6 @@ namespace KubeOps.Operator.Commands.Generators
18
16
[ Command ( "crd" , "crds" , Description = "Generates the needed CRD for kubernetes." ) ]
19
17
internal class CrdGenerator : GeneratorBase
20
18
{
21
- private const string Integer = "integer" ;
22
- private const string Number = "number" ;
23
- private const string String = "string" ;
24
- private const string Boolean = "boolean" ;
25
- private const string Object = "object" ;
26
-
27
- private const string Int32 = "int32" ;
28
- private const string Int64 = "int64" ;
29
- private const string Float = "float" ;
30
- private const string Double = "double" ;
31
- private const string DateTime = "date-time" ;
32
-
33
19
private readonly EntitySerializer _serializer ;
34
20
35
21
public CrdGenerator ( EntitySerializer serializer )
@@ -47,15 +33,19 @@ public async Task<int> OnExecuteAsync(CommandLineApplication app)
47
33
{
48
34
Directory . CreateDirectory ( OutputPath ) ;
49
35
50
- var kustomizeOutput = Encoding . UTF8 . GetBytes ( _serializer . Serialize ( new KustomizationConfig
51
- {
52
- Resources = crds
53
- . Select ( crd => $ "{ crd . Metadata . Name . Replace ( '.' , '_' ) } .{ Format . ToString ( ) . ToLower ( ) } ") . ToList ( ) ,
54
- CommonLabels = new Dictionary < string , string >
55
- {
56
- { "operator-element" , "crd" } ,
57
- } ,
58
- } , Format ) ) ;
36
+ var kustomizeOutput = Encoding . UTF8 . GetBytes (
37
+ _serializer . Serialize (
38
+ new KustomizationConfig
39
+ {
40
+ Resources = crds
41
+ . Select ( crd => $ "{ crd . Metadata . Name . Replace ( '.' , '_' ) } .{ Format . ToString ( ) . ToLower ( ) } ")
42
+ . ToList ( ) ,
43
+ CommonLabels = new Dictionary < string , string >
44
+ {
45
+ { "operator-element" , "crd" } ,
46
+ } ,
47
+ } ,
48
+ Format ) ) ;
59
49
await using var kustomizationFile =
60
50
File . Open ( Path . Join ( OutputPath , $ "kustomization.{ Format . ToString ( ) . ToLower ( ) } ") , FileMode . Create ) ;
61
51
await kustomizationFile . WriteAsync ( kustomizeOutput ) ;
@@ -69,8 +59,11 @@ public async Task<int> OnExecuteAsync(CommandLineApplication app)
69
59
70
60
if ( ! string . IsNullOrWhiteSpace ( OutputPath ) )
71
61
{
72
- await using var file = File . Open ( Path . Join ( OutputPath ,
73
- $ "{ crd . Metadata . Name . Replace ( '.' , '_' ) } .{ Format . ToString ( ) . ToLower ( ) } ") , FileMode . Create ) ;
62
+ await using var file = File . Open (
63
+ Path . Join (
64
+ OutputPath ,
65
+ $ "{ crd . Metadata . Name . Replace ( '.' , '_' ) } .{ Format . ToString ( ) . ToLower ( ) } ") ,
66
+ FileMode . Create ) ;
74
67
await file . WriteAsync ( Encoding . UTF8 . GetBytes ( output ) ) ;
75
68
}
76
69
else
@@ -90,151 +83,12 @@ public static IEnumerable<V1CustomResourceDefinition> GenerateCrds()
90
83
throw new Exception ( "No Entry Assembly found." ) ;
91
84
}
92
85
93
- var result = new List < V1CustomResourceDefinition > ( ) ;
94
- foreach ( var entityType in GetTypesWithAttribute < KubernetesEntityAttribute > ( assembly ) )
95
- {
96
- var entityDefinition = CustomEntityDefinitionExtensions . CreateResourceDefinition ( entityType ) ;
97
-
98
- var crd = new V1CustomResourceDefinition (
99
- new V1CustomResourceDefinitionSpec ( ) ,
100
- $ "{ V1CustomResourceDefinition . KubeGroup } /{ V1CustomResourceDefinition . KubeApiVersion } ",
101
- V1CustomResourceDefinition . KubeKind ,
102
- new V1ObjectMeta { Name = $ "{ entityDefinition . Plural } .{ entityDefinition . Group } "} ) ;
103
-
104
- var spec = crd . Spec ;
105
- spec . Group = entityDefinition . Group ;
106
- spec . Names = new V1CustomResourceDefinitionNames
107
- {
108
- Kind = entityDefinition . Kind ,
109
- ListKind = entityDefinition . ListKind ,
110
- Singular = entityDefinition . Singular ,
111
- Plural = entityDefinition . Plural ,
112
- } ;
113
- spec . Scope = entityDefinition . Scope . ToString ( ) ;
114
-
115
- var version = new V1CustomResourceDefinitionVersion ( ) ;
116
- spec . Versions = new [ ] { version } ;
117
-
118
- // TODO: versions?
119
- version . Name = entityDefinition . Version ;
120
- version . Served = true ;
121
- version . Storage = true ;
122
-
123
- if ( entityType . GetProperty ( "Status" ) != null )
124
- {
125
- version . Subresources = new V1CustomResourceSubresources ( null , new { } ) ;
126
- }
127
-
128
- version . Schema = new V1CustomResourceValidation ( MapType ( entityType ) ) ;
129
-
130
- result . Add ( crd ) ;
131
- }
132
-
133
- return result ;
134
- }
135
-
136
- private static V1JSONSchemaProps MapProperty ( PropertyInfo info )
137
- {
138
- // TODO: get description somehow.
139
- // TODO: support description via XML fields -> but describe how (generate xml file stuff)
140
-
141
- var props = MapType ( info . PropertyType ) ;
142
- props . Description ??= info . GetCustomAttribute < DisplayAttribute > ( ) ? . Description ;
143
- return props ;
144
- }
145
-
146
- private static V1JSONSchemaProps MapType ( Type type )
147
- {
148
- var props = new V1JSONSchemaProps ( ) ;
149
-
150
- // this description is on the class
151
- props . Description = type . GetCustomAttributes < DisplayAttribute > ( true ) . FirstOrDefault ( ) ? . Description ;
152
-
153
- if ( type == typeof ( V1ObjectMeta ) )
154
- {
155
- // TODO(check): is this correct? should metadata be filtered?
156
- props . Type = Object ;
157
- }
158
- else if ( ! IsSimpleType ( type ) )
159
- {
160
- props . Type = Object ;
161
- props . Properties = new Dictionary < string , V1JSONSchemaProps > (
162
- type . GetProperties ( )
163
- . Select (
164
- prop => KeyValuePair . Create (
165
- CamelCase ( prop . Name ) ,
166
- MapProperty ( prop ) ) ) ) ;
167
- }
168
- else if ( type == typeof ( int ) || Nullable . GetUnderlyingType ( type ) == typeof ( int ) )
169
- {
170
- props . Type = Integer ;
171
- props . Format = Int32 ;
172
- }
173
- else if ( type == typeof ( long ) || Nullable . GetUnderlyingType ( type ) == typeof ( long ) )
174
- {
175
- props . Type = Integer ;
176
- props . Format = Int64 ;
177
- }
178
- else if ( type == typeof ( float ) || Nullable . GetUnderlyingType ( type ) == typeof ( float ) )
179
- {
180
- props . Type = Number ;
181
- props . Format = Float ;
182
- }
183
- else if ( type == typeof ( double ) || Nullable . GetUnderlyingType ( type ) == typeof ( double ) )
184
- {
185
- props . Type = Number ;
186
- props . Format = Double ;
187
- }
188
- else if ( type == typeof ( string ) || Nullable . GetUnderlyingType ( type ) == typeof ( string ) )
189
- {
190
- props . Type = String ;
191
- }
192
- else if ( type == typeof ( bool ) || Nullable . GetUnderlyingType ( type ) == typeof ( bool ) )
193
- {
194
- props . Type = Boolean ;
195
- }
196
- else if ( type == typeof ( DateTime ) || Nullable . GetUnderlyingType ( type ) == typeof ( DateTime ) )
197
- {
198
- props . Type = String ;
199
- props . Format = DateTime ;
200
- }
201
- else if ( type . IsEnum )
202
- {
203
- props . Type = String ;
204
- props . EnumProperty = new List < object > ( Enum . GetNames ( type ) ) ;
205
- }
206
-
207
- if ( Nullable . GetUnderlyingType ( type ) != null )
208
- {
209
- props . Nullable = true ;
210
- }
211
-
212
- // TODO: validator attributes
213
-
214
- return props ;
86
+ return GetTypesWithAttribute < KubernetesEntityAttribute > ( assembly )
87
+ . Select ( EntityToCrdExtensions . CreateCrd ) ;
215
88
}
216
89
217
90
private static IEnumerable < Type > GetTypesWithAttribute < TAttribute > ( Assembly assembly )
218
91
where TAttribute : Attribute =>
219
92
assembly . GetTypes ( ) . Where ( type => type . GetCustomAttributes < TAttribute > ( ) . Any ( ) ) ;
220
-
221
- private static bool IsSimpleType ( Type type ) =>
222
- type . IsPrimitive ||
223
- new [ ]
224
- {
225
- typeof ( string ) ,
226
- typeof ( decimal ) ,
227
- typeof ( DateTime ) ,
228
- typeof ( DateTimeOffset ) ,
229
- typeof ( TimeSpan ) ,
230
- typeof ( Guid )
231
- } . Contains ( type ) ||
232
- type . IsEnum ||
233
- Convert . GetTypeCode ( type ) != TypeCode . Object ||
234
- ( type . IsGenericType &&
235
- type . GetGenericTypeDefinition ( ) == typeof ( Nullable < > ) &&
236
- IsSimpleType ( type . GetGenericArguments ( ) [ 0 ] ) ) ;
237
-
238
- private static string CamelCase ( string str ) => $ "{ str . Substring ( 0 , 1 ) . ToLower ( ) } { str . Substring ( 1 ) } ";
239
93
}
240
94
}
0 commit comments