kube-dsl 0.4.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/README.md +293 -0
- data/Rakefile +28 -24
- data/lib/kube-dsl/builder.rb +35 -33
- data/lib/kube-dsl/field_res.rb +0 -2
- data/lib/kube-dsl/generator.rb +6 -6
- data/lib/kube-dsl/ref.rb +8 -5
- data/lib/kube-dsl/string_helpers.rb +5 -5
- data/lib/kube-dsl/validations.rb +23 -17
- data/lib/kube-dsl/value_fields.rb +1 -1
- data/lib/kube-dsl/version.rb +1 -1
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ee0373d4a49b731e08d691b25c84ba5c71f8e9a4018f411ba5bb8da87448096a
|
4
|
+
data.tar.gz: 7ffcad491b24630b21ae7a8799f75089816b066f4a9671db5774999d0fbac434
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3d584e068dffddfea89b6aaca1baa27633fe8681d161a53cc274daa20426496a1358c71223866dfde883ba80d2119a021110196fac087d20fd5d1d82380e57fd
|
7
|
+
data.tar.gz: ef1c9a440f42c5d8777ff0dc08377e264456344754f09f146e848ae2964811d67c23ddb6cbbf4fa18fc1755161bddb6fc73d7646e1041a30c1bf178534076d75
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
## 0.6.1
|
2
|
+
* Fix additional naming discrepancy in autoload manifests causing "API" to become "Api."
|
3
|
+
|
4
|
+
## 0.6.0
|
5
|
+
* Improve path and namespace handling in generator.
|
6
|
+
|
7
|
+
## 0.5.1
|
8
|
+
* Support Ruby 2.7
|
9
|
+
- Stop using the `RubyToken` class from irb, which doesn't exist anymore.
|
10
|
+
* Fix bug causing `NoMethodError`s if the type field contains a single string and not an array.
|
11
|
+
|
12
|
+
## 0.5.0
|
13
|
+
* Recursively validate.
|
14
|
+
* Add README.
|
15
|
+
|
1
16
|
## 0.4.0
|
2
17
|
* Add validations.
|
3
18
|
- You can now call `#valid?` and `#validate` methods on DSL objects.
|
data/README.md
ADDED
@@ -0,0 +1,293 @@
|
|
1
|
+
## kube-dsl
|
2
|
+
A Ruby DSL for defining Kubernetes resources.
|
3
|
+
|
4
|
+
## What is this thing?
|
5
|
+
|
6
|
+
KubeDSL provides a [domain-specific language](https://en.wikipedia.org/wiki/Domain-specific_language) for defining Kubernetes resource objects in Ruby. Why would you want to do this? Well,
|
7
|
+
|
8
|
+
1. I think Ruby code is easier to read than YAML.
|
9
|
+
1. every property is a Ruby method, meaning Ruby will blow up if you try to configure the object the wrong way.
|
10
|
+
1. doing so follows the principle of [infrastructure as code](https://en.wikipedia.org/wiki/Infrastructure_as_code).
|
11
|
+
1. validations are built-in.
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
Either run `gem install kube-dsl` or add it to your Gemfile:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
gem 'kube-dsl', '< 1'
|
19
|
+
```
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
KubeDSL directly mirrors the fields and nesting structure of each Kubernetes YAML (or JSON) object. Ruby fields are snake_cased while Kubernetes fields are camelCased. Let's take a look at a short example where we define a Namespace:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
ns = KubeDSL.namespace do
|
27
|
+
metadata do
|
28
|
+
name 'my-namespace'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
In the example above, we've defined a `KubeDSL::DSL::V1::Namespace` object and assigned it to a local variable called `ns`. Now let's convert it into a YAML string and print it out:
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
# ---
|
37
|
+
# apiVersion: v1
|
38
|
+
# kind: Namespace
|
39
|
+
# metadata:
|
40
|
+
# name: foo
|
41
|
+
puts ns.to_resource.to_yaml
|
42
|
+
```
|
43
|
+
|
44
|
+
The `#to_resource` method returns an instance of the `KubeDSL::Resource` class while `#to_yaml` converts the resource into a YAML string. Pretty cool, eh? See the next few sections for examples creating other types of common Kubernetes objects.
|
45
|
+
|
46
|
+
### ServiceAccount Example
|
47
|
+
|
48
|
+
Note how key/value pairs are added to the `labels` field.
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
KubeDSL.service_account do
|
52
|
+
metadata do
|
53
|
+
name 'my-service-account'
|
54
|
+
namespace 'my-namespace'
|
55
|
+
|
56
|
+
labels do
|
57
|
+
add :app, 'my-app'
|
58
|
+
add :role, 'web'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
```
|
63
|
+
|
64
|
+
### Service Example
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
KubeDSL.service do
|
68
|
+
metadata do
|
69
|
+
name 'my-service'
|
70
|
+
namespace 'my-namespace'
|
71
|
+
|
72
|
+
labels do
|
73
|
+
add :app, 'my-app'
|
74
|
+
add :role, 'web'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
spec do
|
79
|
+
type 'NodePort'
|
80
|
+
|
81
|
+
selector do
|
82
|
+
add :app, 'my-app'
|
83
|
+
add :role, 'web'
|
84
|
+
end
|
85
|
+
|
86
|
+
port do
|
87
|
+
name 'http'
|
88
|
+
port 3000
|
89
|
+
protocol 'TCP'
|
90
|
+
target_port 'http'
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
```
|
95
|
+
|
96
|
+
### Deployment Example
|
97
|
+
|
98
|
+
Note:
|
99
|
+
|
100
|
+
1. Elements of arrays can be given names (see the use of the `#container` method below) so they can be easily retrieved and/or modified later.
|
101
|
+
1. The example below shows how to add config maps and secrets to a deployment via references.
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
KubeDSL.deployment do
|
105
|
+
metadata do
|
106
|
+
name 'my-deployment'
|
107
|
+
namespace 'my-namespace'
|
108
|
+
|
109
|
+
labels do
|
110
|
+
add :app, 'my-app'
|
111
|
+
add :role, 'web'
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
spec do
|
116
|
+
replicas 2
|
117
|
+
|
118
|
+
selector do
|
119
|
+
match_labels do
|
120
|
+
add :app, 'my-app'
|
121
|
+
add :role, 'web'
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
strategy do
|
126
|
+
type 'RollingUpdate'
|
127
|
+
|
128
|
+
rolling_update do
|
129
|
+
max_surge '25%'
|
130
|
+
max_unavailable 1
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
template do
|
135
|
+
metadata do
|
136
|
+
labels do
|
137
|
+
add :app, 'my-app'
|
138
|
+
add :role, 'web'
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
spec do
|
143
|
+
# elements of arrays can be given names (:web in this case) so they can be
|
144
|
+
# easily retrieved and/or modified later
|
145
|
+
container(:web) do
|
146
|
+
name 'my-web-container'
|
147
|
+
image_pull_policy 'IfNotPresent'
|
148
|
+
|
149
|
+
port do
|
150
|
+
container_port 3000
|
151
|
+
name 'http'
|
152
|
+
protocol 'TCP'
|
153
|
+
end
|
154
|
+
|
155
|
+
env_from do
|
156
|
+
config_map_ref do
|
157
|
+
name 'my-config-map'
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
env_from do
|
162
|
+
secret_ref do
|
163
|
+
name 'my-secrets'
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
readiness_probe do
|
168
|
+
success_threshold 1
|
169
|
+
failure_threshold 2
|
170
|
+
initial_delay_seconds 15
|
171
|
+
period_seconds 3
|
172
|
+
timeout_seconds 1
|
173
|
+
|
174
|
+
http_get do
|
175
|
+
path '/healthz'
|
176
|
+
port 3000
|
177
|
+
scheme 'HTTP'
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
image_pull_secret do
|
183
|
+
name 'my-registry-secret'
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
restart_policy 'Always'
|
188
|
+
service_account_name 'my-service-account'
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
```
|
193
|
+
|
194
|
+
### Ingress Example
|
195
|
+
|
196
|
+
NOTE: the example below includes an annotation that is specific to the Nginx ingress controller.
|
197
|
+
|
198
|
+
```ruby
|
199
|
+
KubeDSL::DSL::Extensions::V1beta1::Ingress.new do
|
200
|
+
metadata do
|
201
|
+
name 'my-ingress'
|
202
|
+
namespace 'my-namespace'
|
203
|
+
|
204
|
+
annotations do
|
205
|
+
add :'kubernetes.io/ingress.class', 'nginx'
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
spec do
|
210
|
+
rule do
|
211
|
+
host 'my-website.com'
|
212
|
+
|
213
|
+
http do
|
214
|
+
path do
|
215
|
+
path '/'
|
216
|
+
|
217
|
+
backend do
|
218
|
+
service_name 'my-service'
|
219
|
+
service_port 80
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
```
|
227
|
+
|
228
|
+
### ConfigMap Example
|
229
|
+
|
230
|
+
```ruby
|
231
|
+
KubeDSL.config_map do
|
232
|
+
metadata do
|
233
|
+
name 'my-config-map'
|
234
|
+
namespace 'my-namespace'
|
235
|
+
end
|
236
|
+
|
237
|
+
data do
|
238
|
+
add :MY_VAR, 'value'
|
239
|
+
add :MY_OTHER_VAR, 'value'
|
240
|
+
end
|
241
|
+
end
|
242
|
+
```
|
243
|
+
|
244
|
+
### Secret Example
|
245
|
+
|
246
|
+
```ruby
|
247
|
+
KubeDSL.secret do
|
248
|
+
metadata do
|
249
|
+
name 'my-secrets'
|
250
|
+
namespace 'my-namespace'
|
251
|
+
end
|
252
|
+
|
253
|
+
type 'Opaque'
|
254
|
+
|
255
|
+
data do
|
256
|
+
add :MY_SECRET, 'value'
|
257
|
+
end
|
258
|
+
end
|
259
|
+
```
|
260
|
+
|
261
|
+
## Validations
|
262
|
+
|
263
|
+
All `KubeDSL::DSLObject`s respond to `#valid?` and `#validate` methods. Use `#valid?` to determine whether or not an object is valid. Use `#validate` to retrieve a list of validation errors:
|
264
|
+
|
265
|
+
```ruby
|
266
|
+
ns = KubeDSL.namespace do
|
267
|
+
metadata do
|
268
|
+
name 123
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
ns.valid? # => false
|
273
|
+
ns.validate # => #<KubeDSL::Validations::ValidationErrors:0x00007fc8ce276e80 ... >
|
274
|
+
ns.validate.messages # => {"metadata.name"=>["is not a String"]}
|
275
|
+
```
|
276
|
+
|
277
|
+
The handy `#validate!` method will raise a `KubeDSL::ValidationError` if the object is invalid.
|
278
|
+
|
279
|
+
## Code Generation
|
280
|
+
|
281
|
+
All the Ruby code present in KubeDSL is generated from the Kubernetes JSON schema available [here](https://github.com/instrumenta/kubernetes-json-schema). Run the following rake task to regenerate:
|
282
|
+
|
283
|
+
```bash
|
284
|
+
bundle exec rake generate
|
285
|
+
```
|
286
|
+
|
287
|
+
## Authors
|
288
|
+
|
289
|
+
* Cameron C. Dutro: http://github.com/camertron
|
290
|
+
|
291
|
+
## License
|
292
|
+
|
293
|
+
Licensed under the MIT license.
|
data/Rakefile
CHANGED
@@ -16,6 +16,7 @@ end
|
|
16
16
|
|
17
17
|
task :generate do
|
18
18
|
require 'dry/inflector'
|
19
|
+
require 'fileutils'
|
19
20
|
|
20
21
|
FileUtils.rm_rf('./lib/kube-dsl/entrypoint.rb')
|
21
22
|
FileUtils.rm_rf('./lib/kube-dsl/dsl.rb')
|
@@ -24,33 +25,36 @@ task :generate do
|
|
24
25
|
FileUtils.mkdir_p('./vendor')
|
25
26
|
|
26
27
|
export_url = "https://github.com/instrumenta/kubernetes-json-schema/trunk/v#{KubeDSL::KUBERNETES_VERSION}-local"
|
27
|
-
|
28
|
+
local_schema_path = "vendor/kubernetes-json-schema/v#{KubeDSL::KUBERNETES_VERSION}-local"
|
28
29
|
|
29
|
-
unless File.exist?(
|
30
|
-
system("svn export #{export_url} #{
|
30
|
+
unless File.exist?(local_schema_path)
|
31
|
+
system("svn export #{export_url} #{local_schema_path}")
|
31
32
|
end
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
generator.generate_autoload_files
|
51
|
-
generator.generate_entrypoint_file do |resource, ns|
|
52
|
-
version = resource.ref.version || ''
|
53
|
-
!version.include?('beta') && !version.include?('alpha')
|
34
|
+
generator = KubeDSL::Generator.new(
|
35
|
+
schema_dir: local_schema_path,
|
36
|
+
output_dir: File.join('lib'),
|
37
|
+
autoload_prefix: File.join('kube-dsl', 'dsl'),
|
38
|
+
dsl_namespace: ['KubeDSL', 'DSL'],
|
39
|
+
entrypoint_namespace: ['KubeDSL'],
|
40
|
+
inflector: Dry::Inflector.new do |inflections|
|
41
|
+
inflections.acronym('DSL')
|
42
|
+
|
43
|
+
inflections.singular('tls', 'tls')
|
44
|
+
inflections.singular('causes', 'cause')
|
45
|
+
|
46
|
+
inflections.plural('tls', 'tlses')
|
47
|
+
inflections.plural('enum', 'enums')
|
48
|
+
inflections.plural('one_of', 'one_ofs')
|
49
|
+
inflections.plural('any_of', 'any_ofs')
|
50
|
+
inflections.plural('all_of', 'all_ofs')
|
54
51
|
end
|
52
|
+
)
|
53
|
+
|
54
|
+
generator.generate_resource_files
|
55
|
+
generator.generate_autoload_files
|
56
|
+
generator.generate_entrypoint_file do |resource, ns|
|
57
|
+
version = resource.ref.version || ''
|
58
|
+
!version.include?('beta') && !version.include?('alpha')
|
55
59
|
end
|
56
60
|
end
|
data/lib/kube-dsl/builder.rb
CHANGED
@@ -4,12 +4,17 @@ module KubeDSL
|
|
4
4
|
class Builder
|
5
5
|
include StringHelpers
|
6
6
|
|
7
|
-
attr_reader :schema_dir, :output_dir, :
|
7
|
+
attr_reader :schema_dir, :output_dir, :autoload_prefix
|
8
|
+
attr_reader :dsl_namespace, :entrypoint_namespace
|
9
|
+
attr_reader :inflector, :resolvers
|
8
10
|
|
9
|
-
def initialize(schema_dir:, output_dir:, inflector:)
|
11
|
+
def initialize(schema_dir:, output_dir:, autoload_prefix:, inflector:, dsl_namespace:, entrypoint_namespace:)
|
10
12
|
@schema_dir = schema_dir
|
11
13
|
@output_dir = output_dir
|
14
|
+
@autoload_prefix = autoload_prefix
|
12
15
|
@inflector = inflector
|
16
|
+
@dsl_namespace = dsl_namespace
|
17
|
+
@entrypoint_namespace = entrypoint_namespace
|
13
18
|
@resolvers ||= {}
|
14
19
|
end
|
15
20
|
|
@@ -19,25 +24,17 @@ module KubeDSL
|
|
19
24
|
end
|
20
25
|
end
|
21
26
|
|
22
|
-
def
|
27
|
+
def each_resource_file
|
23
28
|
return to_enum(__method__) unless block_given?
|
24
29
|
|
25
|
-
|
26
|
-
|
27
|
-
# schema, i.e. k8s resources like ObjectMeta that other
|
28
|
-
# k8s-compatible schemas depend on.
|
29
|
-
#
|
30
|
-
# Resources can be "empty" if they contain no properties. This
|
31
|
-
# usually happens for resources that are really just aliases
|
32
|
-
# for basic types like integer and string. The k8s' Duration
|
33
|
-
# object is a good example. It's just an alias for string.
|
34
|
-
yield res if !res.external? && !res.empty?
|
30
|
+
each_resource do |res|
|
31
|
+
yield File.join(output_dir, res.ref.ruby_autoload_path), res
|
35
32
|
end
|
36
33
|
end
|
37
34
|
|
38
35
|
def entrypoint(&block)
|
39
36
|
''.tap do |ruby_code|
|
40
|
-
ruby_code << "module #{
|
37
|
+
ruby_code << "module #{entrypoint_namespace.join('::')}::Entrypoint\n"
|
41
38
|
|
42
39
|
each_resource do |resource|
|
43
40
|
ns = resource.ref.ruby_namespace.join('::')
|
@@ -53,26 +50,15 @@ module KubeDSL
|
|
53
50
|
end
|
54
51
|
end
|
55
52
|
|
56
|
-
def namespace
|
57
|
-
@namespace ||= inflector.classify(
|
58
|
-
File
|
59
|
-
.split(output_dir)
|
60
|
-
.map { |seg| inflector.camelize(underscore(seg)) }
|
61
|
-
.join('/')
|
62
|
-
).split('::')
|
63
|
-
end
|
64
|
-
|
65
53
|
def entrypoint_path
|
66
|
-
File.join(File.dirname(
|
54
|
+
File.join(output_dir, File.dirname(autoload_prefix), 'entrypoint.rb')
|
67
55
|
end
|
68
56
|
|
69
57
|
def each_autoload_file(&block)
|
70
58
|
return to_enum(__method__) unless block
|
71
59
|
|
72
|
-
start = output_dir.split(File::SEPARATOR).first
|
73
|
-
|
74
60
|
each_autoload_file_helper(
|
75
|
-
autoload_map[
|
61
|
+
autoload_map[:root], [], &block
|
76
62
|
)
|
77
63
|
end
|
78
64
|
|
@@ -88,11 +74,27 @@ module KubeDSL
|
|
88
74
|
end
|
89
75
|
|
90
76
|
def parse_ref(ref_str)
|
91
|
-
Ref.new(ref_str,
|
77
|
+
Ref.new(ref_str, dsl_namespace, inflector, schema_dir, autoload_prefix)
|
92
78
|
end
|
93
79
|
|
94
80
|
private
|
95
81
|
|
82
|
+
def each_resource
|
83
|
+
return to_enum(__method__) unless block_given?
|
84
|
+
|
85
|
+
resources.each do |res|
|
86
|
+
# "External" resources are ones that live outside the current
|
87
|
+
# schema, i.e. k8s resources like ObjectMeta that other
|
88
|
+
# k8s-compatible schemas depend on.
|
89
|
+
#
|
90
|
+
# Resources can be "empty" if they contain no properties. This
|
91
|
+
# usually happens for resources that are really just aliases
|
92
|
+
# for basic types like integer and string. The k8s' Duration
|
93
|
+
# object is a good example. It's just an alias for string.
|
94
|
+
yield res if !res.external? && !res.empty?
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
96
98
|
def resources
|
97
99
|
JSON.parse(File.read(start_path))['oneOf'].map do |entry|
|
98
100
|
resource_from_ref(resolve_ref(entry['$ref']))
|
@@ -105,7 +107,7 @@ module KubeDSL
|
|
105
107
|
parts = res.ref.ruby_autoload_path.split(File::SEPARATOR)
|
106
108
|
parts.reject!(&:empty?)
|
107
109
|
|
108
|
-
parts.inject(amap) do |ret, seg|
|
110
|
+
[:root, *parts].inject(amap) do |ret, seg|
|
109
111
|
if seg.end_with?('.rb')
|
110
112
|
ret[seg] = res
|
111
113
|
else
|
@@ -130,14 +132,14 @@ module KubeDSL
|
|
130
132
|
autoload_path = File.join(*path, ns, child_ns).chomp('.rb')
|
131
133
|
|
132
134
|
if res.is_a?(Hash)
|
133
|
-
ruby_code << " autoload :#{
|
135
|
+
ruby_code << " autoload :#{inflector.camelize(child_ns)}, '#{autoload_path}'\n"
|
134
136
|
else
|
135
137
|
ruby_code << " autoload :#{res.ref.kind}, '#{autoload_path}'\n"
|
136
138
|
end
|
137
139
|
end
|
138
140
|
|
139
141
|
ruby_code << "end\n"
|
140
|
-
yield File.join(*path, "#{ns}.rb"), ruby_code
|
142
|
+
yield File.join(output_dir, *path, "#{ns}.rb"), ruby_code
|
141
143
|
each_autoload_file_helper(children, path + [ns], &block)
|
142
144
|
end
|
143
145
|
end
|
@@ -194,7 +196,7 @@ module KubeDSL
|
|
194
196
|
res.fields[name] = DefaultFieldRes.new(name, res, enum)
|
195
197
|
else
|
196
198
|
res.fields[name] = FieldRes.new(
|
197
|
-
name, prop['type'].first, required
|
199
|
+
name, Array(prop['type']).first, required
|
198
200
|
)
|
199
201
|
end
|
200
202
|
|
@@ -216,7 +218,7 @@ module KubeDSL
|
|
216
218
|
end
|
217
219
|
|
218
220
|
def start_path
|
219
|
-
@
|
221
|
+
@start_path ||= File.join(schema_dir, 'all.json')
|
220
222
|
end
|
221
223
|
|
222
224
|
def resource_cache
|
data/lib/kube-dsl/field_res.rb
CHANGED
data/lib/kube-dsl/generator.rb
CHANGED
@@ -13,14 +13,14 @@ module KubeDSL
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def generate_resource_files
|
16
|
-
builder.
|
17
|
-
FileUtils.mkdir_p(File.dirname(
|
16
|
+
builder.each_resource_file do |path, res|
|
17
|
+
FileUtils.mkdir_p(File.dirname(path))
|
18
18
|
|
19
|
-
if File.exist?(
|
20
|
-
puts "Skipping #{
|
19
|
+
if File.exist?(path)
|
20
|
+
puts "Skipping #{path} because it already exists"
|
21
21
|
else
|
22
|
-
puts "Writing #{
|
23
|
-
File.write(
|
22
|
+
puts "Writing #{path}"
|
23
|
+
File.write(path, res.to_ruby)
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
data/lib/kube-dsl/ref.rb
CHANGED
@@ -5,12 +5,12 @@ module KubeDSL
|
|
5
5
|
attr_reader :str, :kind, :namespace, :version, :inflector, :schema_dir
|
6
6
|
attr_reader :ruby_namespace_prefix, :autoload_prefix
|
7
7
|
|
8
|
-
def initialize(str, ruby_namespace_prefix,
|
8
|
+
def initialize(str, ruby_namespace_prefix, inflector, schema_dir, autoload_prefix)
|
9
9
|
@str = str
|
10
10
|
@ruby_namespace_prefix = ruby_namespace_prefix
|
11
|
-
@autoload_prefix = autoload_prefix
|
12
11
|
@inflector = inflector
|
13
12
|
@schema_dir = schema_dir
|
13
|
+
@autoload_prefix = autoload_prefix
|
14
14
|
|
15
15
|
ns, v, k = str.split('.').last(3)
|
16
16
|
|
@@ -41,15 +41,18 @@ module KubeDSL
|
|
41
41
|
def ruby_namespace
|
42
42
|
@ruby_namespace ||= begin
|
43
43
|
[*ruby_namespace_prefix].tap do |mods|
|
44
|
-
mods <<
|
45
|
-
mods <<
|
44
|
+
mods << namespace if namespace
|
45
|
+
mods << version if version
|
46
|
+
mods.map! do |m|
|
47
|
+
inflector.camelize(underscore(m))
|
48
|
+
end
|
46
49
|
end
|
47
50
|
end
|
48
51
|
end
|
49
52
|
|
50
53
|
def ruby_autoload_path
|
51
54
|
@ruby_autoload_path ||= File.join(
|
52
|
-
[
|
55
|
+
[autoload_prefix].tap do |path|
|
53
56
|
path << underscore(namespace) if namespace
|
54
57
|
path << underscore(version) if version
|
55
58
|
path << "#{underscore(kind)}.rb"
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module KubeDSL
|
2
2
|
module StringHelpers
|
3
|
-
RUBY_KEYWORDS =
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
RUBY_KEYWORDS = %w(
|
4
|
+
BEGIN END alias and begin break case class def defined? do else elsif
|
5
|
+
end ensure false for if in module next nil not or redo rescue retry
|
6
|
+
return self super then true undef unless until when while yield
|
7
|
+
)
|
8
8
|
|
9
9
|
def capitalize(str)
|
10
10
|
str.sub(/\A(.)/) { $1.upcase }
|
data/lib/kube-dsl/validations.rb
CHANGED
@@ -27,9 +27,9 @@ module KubeDSL
|
|
27
27
|
@presence = presence
|
28
28
|
end
|
29
29
|
|
30
|
-
def validate(obj, errors)
|
30
|
+
def validate(obj, errors, nesting)
|
31
31
|
if presence && obj_empty?(obj)
|
32
|
-
errors.add(field_name, 'is required')
|
32
|
+
errors.add([*nesting, field_name].join('.'), 'is required')
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
@@ -52,17 +52,17 @@ module KubeDSL
|
|
52
52
|
@kind_of = opts.fetch(:kind_of)
|
53
53
|
end
|
54
54
|
|
55
|
-
def validate(obj, errors)
|
55
|
+
def validate(obj, errors, nesting)
|
56
56
|
unless obj.is_a?(Array)
|
57
|
-
errors.add(field_name, 'is not an array')
|
57
|
+
errors.add([*nesting, field_name].join('.'), 'is not an array')
|
58
58
|
return
|
59
59
|
end
|
60
60
|
|
61
61
|
obj.each_with_index do |elem, idx|
|
62
62
|
unless elem.nil? || elem.is_a?(kind_of)
|
63
63
|
errors.add(
|
64
|
-
field_name, "contains an object at index #{idx}
|
65
|
-
"expected '#{kind_of.name}'"
|
64
|
+
[*nesting, field_name].join('.'), "contains an object at index #{idx} "\
|
65
|
+
"of type '#{elem.class.name}', expected '#{kind_of.name}'"
|
66
66
|
)
|
67
67
|
end
|
68
68
|
end
|
@@ -102,9 +102,9 @@ module KubeDSL
|
|
102
102
|
@format_validator ||= FormatValidator.new(options[:format])
|
103
103
|
end
|
104
104
|
|
105
|
-
def validate(obj, errors)
|
105
|
+
def validate(obj, errors, nesting)
|
106
106
|
unless format_validator.valid?(obj)
|
107
|
-
errors.add(field_name, "is not a #{format_validator.klasses.map(&:to_s).join(', ')}")
|
107
|
+
errors.add([*nesting, field_name].join('.'), "is not a #{format_validator.klasses.map(&:to_s).join(', ')}")
|
108
108
|
end
|
109
109
|
end
|
110
110
|
end
|
@@ -117,9 +117,9 @@ module KubeDSL
|
|
117
117
|
@kind_of = opts.fetch(:kind_of)
|
118
118
|
end
|
119
119
|
|
120
|
-
def validate(obj, errors)
|
120
|
+
def validate(obj, errors, nesting)
|
121
121
|
unless obj.nil? || obj.is_a?(kind_of)
|
122
|
-
errors.add(field_name, "'#{obj.class.name}', expected '#{kind_of.name}'")
|
122
|
+
errors.add([*nesting, field_name].join('.'), "'#{obj.class.name}', expected '#{kind_of.name}'")
|
123
123
|
end
|
124
124
|
end
|
125
125
|
end
|
@@ -132,10 +132,12 @@ module KubeDSL
|
|
132
132
|
@format_validator ||= FormatValidator.new(options[:value_format])
|
133
133
|
end
|
134
134
|
|
135
|
-
def validate(obj, errors)
|
135
|
+
def validate(obj, errors, nesting)
|
136
136
|
obj.kv_pairs.each_pair do |k, v|
|
137
137
|
unless format_validator.valid?(v)
|
138
|
-
errors.add(
|
138
|
+
errors.add(
|
139
|
+
[*nesting, field_name].join('.'),
|
140
|
+
"expected element '#{k}' to be a #{format_validator.klasses.map(&:to_s).join(', ')}, got #{v.class.name}")
|
139
141
|
end
|
140
142
|
end
|
141
143
|
end
|
@@ -149,9 +151,9 @@ module KubeDSL
|
|
149
151
|
@list = opts[:in]
|
150
152
|
end
|
151
153
|
|
152
|
-
def validate(obj, errors)
|
154
|
+
def validate(obj, errors, nesting)
|
153
155
|
unless list.include?(obj)
|
154
|
-
errors.add(field_name, "is not in #{list.join(', ')}")
|
156
|
+
errors.add([*nesting, field_name].join('.'), "is not in #{list.join(', ')}")
|
155
157
|
end
|
156
158
|
end
|
157
159
|
end
|
@@ -186,12 +188,16 @@ module KubeDSL
|
|
186
188
|
end
|
187
189
|
|
188
190
|
module InstanceMethods
|
189
|
-
def validate
|
190
|
-
errors
|
191
|
+
def validate(errors = nil, nesting = [])
|
192
|
+
errors ||= ValidationErrors.new
|
191
193
|
|
192
194
|
self.class.validators.each do |field_name, validators|
|
193
195
|
field = send(field_name)
|
194
|
-
validators.each { |val| val.validate(field, errors) }
|
196
|
+
validators.each { |val| val.validate(field, errors, nesting) }
|
197
|
+
|
198
|
+
if field.respond_to?(:validate)
|
199
|
+
field.validate(errors, nesting + [field_name.to_s])
|
200
|
+
end
|
195
201
|
end
|
196
202
|
|
197
203
|
errors
|
@@ -15,7 +15,7 @@ module KubeDSL
|
|
15
15
|
define_method(field) do |*args|
|
16
16
|
if args.empty?
|
17
17
|
instance_variable_get(:"@#{field}") || (
|
18
|
-
default.respond_to?(:call) ? default.call : default
|
18
|
+
default.respond_to?(:call) ? default.call(self) : default
|
19
19
|
)
|
20
20
|
else
|
21
21
|
instance_variable_set(:"@#{field}", args.first)
|
data/lib/kube-dsl/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kube-dsl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cameron Dutro
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-08-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dry-inflector
|
@@ -34,6 +34,7 @@ files:
|
|
34
34
|
- CHANGELOG.md
|
35
35
|
- Gemfile
|
36
36
|
- LICENSE
|
37
|
+
- README.md
|
37
38
|
- Rakefile
|
38
39
|
- kube-dsl.gemspec
|
39
40
|
- lib/kube-dsl.rb
|
@@ -802,7 +803,7 @@ files:
|
|
802
803
|
homepage: http://github.com/getkuby/kube-dsl
|
803
804
|
licenses: []
|
804
805
|
metadata: {}
|
805
|
-
post_install_message:
|
806
|
+
post_install_message:
|
806
807
|
rdoc_options: []
|
807
808
|
require_paths:
|
808
809
|
- lib
|
@@ -817,8 +818,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
817
818
|
- !ruby/object:Gem::Version
|
818
819
|
version: '0'
|
819
820
|
requirements: []
|
820
|
-
rubygems_version: 3.1.
|
821
|
-
signing_key:
|
821
|
+
rubygems_version: 3.1.6
|
822
|
+
signing_key:
|
822
823
|
specification_version: 4
|
823
824
|
summary: A Ruby DSL for defining Kubernetes resources.
|
824
825
|
test_files: []
|