kubes 0.4.0 → 0.4.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/docs/_docs/config/hooks/docker.md +1 -1
- data/docs/_docs/config/hooks/kubectl.md +1 -1
- data/docs/_docs/config/hooks/ruby.md +5 -3
- data/docs/_docs/helpers.md +11 -3
- data/docs/_docs/helpers/aws.md +14 -0
- data/docs/_docs/helpers/aws/iam-role.md +91 -0
- data/docs/_docs/helpers/aws/secrets.md +129 -0
- data/docs/_docs/helpers/aws/ssm.md +76 -0
- data/docs/_docs/helpers/google.md +17 -0
- data/docs/_docs/helpers/google/secrets.md +76 -0
- data/docs/_docs/helpers/google/service-account.md +52 -0
- data/docs/_docs/learn/dsl/review-project.md +4 -2
- data/docs/_docs/learn/yaml/review-project.md +4 -2
- data/docs/_docs/patterns.md +4 -1
- data/docs/_docs/patterns/clock-web-worker.md +2 -0
- data/docs/_docs/patterns/migrations.md +2 -0
- data/docs/_docs/patterns/secrets.md +82 -0
- data/docs/_includes/config/hooks/options.md +1 -1
- data/docs/_includes/helpers/base64.md +1 -0
- data/docs/_includes/layering/layers.md +1 -1
- data/docs/_includes/sidebar.html +24 -3
- data/kubes.gemspec +4 -0
- data/lib/kubes.rb +5 -1
- data/lib/kubes/cli/compile.rb +8 -0
- data/lib/kubes/cli/init.rb +7 -2
- data/lib/kubes/compiler.rb +0 -7
- data/lib/kubes/compiler/shared/helpers.rb +7 -2
- data/lib/kubes/compiler/strategy/base.rb +2 -3
- data/lib/kubes/compiler/strategy/dsl.rb +2 -2
- data/lib/kubes/compiler/strategy/erb.rb +8 -1
- data/lib/kubes/compiler/strategy/erb/yaml_error.rb +60 -0
- data/lib/kubes/compiler/util/normalize.rb +1 -1
- data/lib/kubes/compiler/util/save_file.rb +8 -0
- data/lib/kubes/hooks/builder.rb +1 -1
- data/lib/kubes/version.rb +1 -1
- data/spec/fixtures/decorators/deployment/both/valueFrom.yaml +33 -0
- data/spec/fixtures/decorators/deployment/both/volumes.yaml +40 -0
- data/spec/kubes/compiler/decorator/post/deployment_spec.rb +27 -0
- metadata +45 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bbdaabc58ed6ae8e1c2941431c61a3e7edf7708b7782f1d456b4bcf2b01ef777
|
4
|
+
data.tar.gz: '04290becf20d593ba00d214dd2e790eac5501e3e8f5e3b62d636b3e882b7a5e1'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 302a4a216bc5007de836e335cc38e4fcd8d4c4db8d873f4333d862f84dbcfd32c302ba72c8123392f2a1679ca419be15ef660818f2b75a06b05cb0250a469198
|
7
|
+
data.tar.gz: dbbf8a825b893490963db61c6b08d2adf45ef62be0bad19d44235b1b822077ebb4e8728d45d119dddfb6f33e39ecb3d69ccb89ceda938275b8371306ca72efaa
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,24 @@
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
This project *loosely tries* to adhere to [Semantic Versioning](http://semver.org/), even before v1.0.
|
5
5
|
|
6
|
+
## [0.4.5]
|
7
|
+
- #31 kubes AWS helpers
|
8
|
+
|
9
|
+
## [0.4.4]
|
10
|
+
- #30 friendly message for rendered erb yaml and dsl errors
|
11
|
+
- fix backtrace_reject pattern
|
12
|
+
|
13
|
+
## [0.4.3]
|
14
|
+
- #29 fix edge case when user provides hook on option for non-kubectl hooks
|
15
|
+
|
16
|
+
## [0.4.2]
|
17
|
+
- #28 base64 helper
|
18
|
+
|
19
|
+
## [0.4.1]
|
20
|
+
- kubes init: default namespace now includes Kubes.env
|
21
|
+
- fix kubes deploy: compile it gets called once and output folder kept
|
22
|
+
- include kubes_google dependency helpers
|
23
|
+
|
6
24
|
## [0.4.0]
|
7
25
|
- #26 features: kubes vs kubectl hooks, prune, etc
|
8
26
|
- hooks: kubes, kubectl, docker breaking changes.
|
@@ -58,7 +58,7 @@ Results in:
|
|
58
58
|
|
59
59
|
## exit_on_fail option
|
60
60
|
|
61
|
-
By default, if the hook commands fail, then
|
61
|
+
By default, if the hook commands fail, then kubes will exit with the original hook error code. You can change this behavior with the `exit_on_fail` option.
|
62
62
|
|
63
63
|
```ruby
|
64
64
|
before("build"
|
@@ -70,7 +70,7 @@ The `on` option is used to match the path the gets applied: .kubes/resources/**w
|
|
70
70
|
|
71
71
|
## exit on fail
|
72
72
|
|
73
|
-
By default, if the hook commands fail, then
|
73
|
+
By default, if the hook commands fail, then kubes will exit with the original hook error code. You can change this behavior with the `exit_on_fail` option.
|
74
74
|
|
75
75
|
```ruby
|
76
76
|
before("apply"
|
@@ -18,7 +18,7 @@ When the Ruby object is a class with an instance method `call`, Kubes creates a
|
|
18
18
|
```ruby
|
19
19
|
class EnvExporter
|
20
20
|
def call
|
21
|
-
ENV['SECRET_FOO'] = Base64.
|
21
|
+
ENV['SECRET_FOO'] = Base64.strict_encode64("hi").strip
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -46,9 +46,11 @@ metadata:
|
|
46
46
|
apiVersion: v1
|
47
47
|
kind: Secret
|
48
48
|
data:
|
49
|
-
foo: <%= ENV['SECRET_FOO']
|
49
|
+
foo: <%= ENV['SECRET_FOO'] %>
|
50
50
|
```
|
51
51
|
|
52
|
+
Note, the example above is used to explain how Ruby can be used as the execute option. For secrets, kubes supports secrets with some helpers. See: [Secrets Pattern Docs]({% link _docs/patterns/secrets.md %})
|
53
|
+
|
52
54
|
## Ruby Object
|
53
55
|
|
54
56
|
When the Ruby object, Kubes expects it to have a `call` method and will run it. Example:
|
@@ -57,7 +59,7 @@ When the Ruby object, Kubes expects it to have a `call` method and will run it.
|
|
57
59
|
|
58
60
|
```ruby
|
59
61
|
before("compile",
|
60
|
-
execute: lambda { ENV['SECRET_FOO'] = Base64.
|
62
|
+
execute: lambda { ENV['SECRET_FOO'] = Base64.strict_encode64("hi2").strip }
|
61
63
|
)
|
62
64
|
```
|
63
65
|
|
data/docs/_docs/helpers.md
CHANGED
@@ -7,13 +7,21 @@ Kubes provides some helper methods to help write Kubernetes YAML files. Here's
|
|
7
7
|
Helper | Description
|
8
8
|
--- | ---
|
9
9
|
built_image | Method refers to the latest Docker image built by Kubes. This spares you from having to update the image manually in the deployment resource.
|
10
|
+
decode64 | Basey64d decode a string.
|
10
11
|
dockerfile_port | Exposed port extracted from the Dockerfile of the project.
|
12
|
+
encode64 | Basey64 encode a string. Also available as `base64` method.
|
11
13
|
extra | The `KUBES_EXTRA` value.
|
12
14
|
with_extra | Appends the `KUBES_EXTRA` value to a string if it's set. It's covered in the [Extra Env Docs]({% link _docs/extra-env.md %}).
|
13
15
|
|
14
|
-
Here's also the source code with the helpers: [helpers.rb](https://github.com/boltops-tools/kubes/blob/master/lib/kubes/compiler/shared/helpers.rb).
|
15
|
-
|
16
|
+
Here's also the source code with most of the helpers: [helpers.rb](https://github.com/boltops-tools/kubes/blob/master/lib/kubes/compiler/shared/helpers.rb).
|
16
17
|
|
17
18
|
## DSL Specific Methods
|
18
19
|
|
19
|
-
Each DSL resource has it's own specific methods. Refer to the [DSL Docs]({% link _docs/dsl.md %}) for their methods.
|
20
|
+
Each DSL resource has it's own specific methods. Refer to the [DSL Docs]({% link _docs/dsl.md %}) for their methods.
|
21
|
+
|
22
|
+
## Provider Helpers
|
23
|
+
|
24
|
+
There are also provider-specific helpers:
|
25
|
+
|
26
|
+
* [AWS Helpers]({% link _docs/helpers/aws.md %})
|
27
|
+
* [Google Helpers]({% link _docs/helpers/google.md %})
|
@@ -0,0 +1,14 @@
|
|
1
|
+
---
|
2
|
+
title: AWS Helpers
|
3
|
+
---
|
4
|
+
|
5
|
+
List of AWS helpers:
|
6
|
+
|
7
|
+
{% assign docs = site.docs | where: "categories","helpers-aws" %}
|
8
|
+
{% for doc in docs -%}
|
9
|
+
* [{{ doc.nav_text }}]({{ doc.url }})
|
10
|
+
{% endfor %}
|
11
|
+
|
12
|
+
## Notes
|
13
|
+
|
14
|
+
* By default, `KubeGoogle.logger = Kubes.logger`. This means, you can set `logger.level = "debug"` in `.kubes/config.rb` to see more details.
|
@@ -0,0 +1,91 @@
|
|
1
|
+
---
|
2
|
+
title: AWS IAM Role
|
3
|
+
nav_text: IAM Role
|
4
|
+
categories: helpers-aws
|
5
|
+
---
|
6
|
+
|
7
|
+
You can automatically create the IAM Role associated with the Kubernetes Service Account, covered in [Introducing fine-grained IAM roles for service accounts](https://aws.amazon.com/blogs/opensource/introducing-fine-grained-iam-roles-service-accounts/).
|
8
|
+
|
9
|
+
Here's a Kubes hook that creates an IAM Role:
|
10
|
+
|
11
|
+
.kubes/config/hooks/kubes.rb
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
iam_role = KubesAws::IamRole.new(
|
15
|
+
app: "demo",
|
16
|
+
namespace: "demo-#{Kubes.env}", # defaults to APP-ENV when not set. IE: demo-dev
|
17
|
+
managed_policies: ["AmazonS3ReadOnlyAccess", "AmazonSSMReadOnlyAccess"], # defaults to empty when not set
|
18
|
+
inline_policies: [:secrets_read_only], # See Secrets Read Only Inline Policy at the bottom
|
19
|
+
)
|
20
|
+
before("apply",
|
21
|
+
label: "create iam role",
|
22
|
+
execute: iam_role,
|
23
|
+
)
|
24
|
+
KubesAws::IamRole.role_arn = iam_role.arn # used in .kubes/resources/shared/service_account.yaml
|
25
|
+
```
|
26
|
+
|
27
|
+
The corresponding Kubernetes Service account looks like this:
|
28
|
+
|
29
|
+
.kubes/resources/shared/service_account.yaml
|
30
|
+
|
31
|
+
```yaml
|
32
|
+
apiVersion: v1
|
33
|
+
kind: ServiceAccount
|
34
|
+
metadata:
|
35
|
+
annotations:
|
36
|
+
eks.amazonaws.com/role-arn: <%= KubesAws::IamRole.role_arn %>
|
37
|
+
name: demo
|
38
|
+
labels:
|
39
|
+
app: demo
|
40
|
+
```
|
41
|
+
|
42
|
+
The role policy permissions are currently always added to the existing permissions. So removing roles that were previously added does not remove them.
|
43
|
+
|
44
|
+
IamRole#initialize options:
|
45
|
+
|
46
|
+
Variable | Description | Default
|
47
|
+
---|---|---
|
48
|
+
app | The app name. It's used to set other variables conventionally. This is required. | nil
|
49
|
+
ksa | The Kubernetes Service Account name. The conventional name is APP. IE: demo | APP
|
50
|
+
namespace | The Kubernetes namespace. Defaults to the APP-ENV. IE: demo-dev. | APP-ENV
|
51
|
+
policies | IAM policies to add. This adds permissions to the IAM Role. | []
|
52
|
+
role_name | The IAM Role name. The conventional name is APP-ENV. IE: demo-dev. | APP-ENV
|
53
|
+
|
54
|
+
## OpenID Connect Provider
|
55
|
+
|
56
|
+
The `KubesAws::IamRole` class also automatically creates the OpenID Connect Provider if it doesn't already exist.
|
57
|
+
|
58
|
+
## Secrets Read-Only Inline Policy
|
59
|
+
|
60
|
+
Note the the `:secrets_read_only` is a way to generate an Inline Policy that represents read-only access for Secrets. Kubes does this since there's no managed policy for this yet. For example:
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
inline_policies: [:secrets_read_only]
|
64
|
+
```
|
65
|
+
|
66
|
+
Is the same as:
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
inline_secrets_read_only = {
|
70
|
+
policy_document: {
|
71
|
+
Version: "2012-10-17",
|
72
|
+
Statement: {
|
73
|
+
Effect: "Allow",
|
74
|
+
Action: [
|
75
|
+
"secretsmanager:Describe*",
|
76
|
+
"secretsmanager:Get*",
|
77
|
+
"secretsmanager:List*"
|
78
|
+
],
|
79
|
+
Resource: "*"
|
80
|
+
}
|
81
|
+
},
|
82
|
+
policy_name: "SecretsReadOnly",
|
83
|
+
}
|
84
|
+
iam_role = KubesAws::IamRole.new(
|
85
|
+
app: "rails",
|
86
|
+
cluster: "dev-cluster",
|
87
|
+
namespace: "rails-#{Kubes.env}", # defaults to APP-ENV when not set. IE: rails-dev
|
88
|
+
managed_policies: ["AmazonS3ReadOnlyAccess", "AmazonSSMReadOnlyAccess"], # defaults to empty when not set
|
89
|
+
inline_policies: [inline_secrets_read_only],
|
90
|
+
)
|
91
|
+
```
|
@@ -0,0 +1,129 @@
|
|
1
|
+
---
|
2
|
+
title: AWS Secrets
|
3
|
+
nav_text: Secrets
|
4
|
+
categories: helpers-aws
|
5
|
+
---
|
6
|
+
|
7
|
+
## Simple Values
|
8
|
+
|
9
|
+
For example if you have these secret values:
|
10
|
+
|
11
|
+
$ aws secretsmanager get-secret-value --secret-id demo/dev/db_user | jq '.SecretString'
|
12
|
+
user
|
13
|
+
$ aws secretsmanager get-secret-value --secret-id demo/dev/db_pass | jq '.SecretString'
|
14
|
+
pass
|
15
|
+
|
16
|
+
Set up a [Kubes hook](https://kubes.guru/docs/config/hooks/kubes/).
|
17
|
+
|
18
|
+
.kubes/config/hooks/kubes.rb
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
secrets = KubesAws::Secrets.new(upcase: true, prefix: "demo/dev/")
|
22
|
+
before("compile",
|
23
|
+
label: "Get secrets from AWS Secrets Manager",
|
24
|
+
execute: secrets,
|
25
|
+
)
|
26
|
+
```
|
27
|
+
|
28
|
+
Then set the secrets in the YAML:
|
29
|
+
|
30
|
+
.kubes/resources/shared/secret.yaml
|
31
|
+
|
32
|
+
```yaml
|
33
|
+
apiVersion: v1
|
34
|
+
kind: Secret
|
35
|
+
metadata:
|
36
|
+
name: demo
|
37
|
+
labels:
|
38
|
+
app: demo
|
39
|
+
data:
|
40
|
+
<% KubesAws::Secrets.data.each do |k,v| -%>
|
41
|
+
<%= k %>: <%= base64(v) %>
|
42
|
+
<% end -%>
|
43
|
+
```
|
44
|
+
|
45
|
+
This results in AWS secrets with the prefix the `demo/dev/` being added to the Kubernetes secret data. The values are automatically base64 encoded. Produces:
|
46
|
+
|
47
|
+
.kubes/output/shared/secret.yaml
|
48
|
+
|
49
|
+
```yaml
|
50
|
+
metadata:
|
51
|
+
namespace: demo
|
52
|
+
name: demo-2a78a13682
|
53
|
+
labels:
|
54
|
+
app: demo
|
55
|
+
apiVersion: v1
|
56
|
+
kind: Secret
|
57
|
+
data:
|
58
|
+
db_pass: dGVzdDEK
|
59
|
+
db_user: dGVzdDIK
|
60
|
+
```
|
61
|
+
|
62
|
+
## JSON Values
|
63
|
+
|
64
|
+
For example if you have these secret values:
|
65
|
+
|
66
|
+
$ aws secretsmanager get-secret-value --secret-id demo/dev/k2 | jq '.SecretString'
|
67
|
+
{\"a\":1,\"b\":2}"
|
68
|
+
|
69
|
+
Set up a [Kubes hook](https://kubes.guru/docs/config/hooks/kubes/).
|
70
|
+
|
71
|
+
.kubes/config/hooks/kubes.rb
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
secrets = KubesAws::Secrets.new(prefix: "rails/dev/")
|
75
|
+
before("compile",
|
76
|
+
label: "Get secrets from AWS Secrets Manager",
|
77
|
+
execute: secrets,
|
78
|
+
)
|
79
|
+
```
|
80
|
+
|
81
|
+
Then set the secrets in the YAML:
|
82
|
+
|
83
|
+
.kubes/resources/shared/secret.yaml
|
84
|
+
|
85
|
+
```yaml
|
86
|
+
apiVersion: v1
|
87
|
+
kind: Secret
|
88
|
+
metadata:
|
89
|
+
name: demo
|
90
|
+
labels:
|
91
|
+
app: demo
|
92
|
+
data:
|
93
|
+
<% k2 = JSON.load(KubesAws::Secrets.data["k2"]) %>
|
94
|
+
a: <%= base64(k2["a"]) %>
|
95
|
+
b: <%= base64(k2["b"]) %>
|
96
|
+
```
|
97
|
+
|
98
|
+
Produces:
|
99
|
+
|
100
|
+
```yaml
|
101
|
+
metadata:
|
102
|
+
namespace: demo-dev
|
103
|
+
name: demo-a4cd604a95
|
104
|
+
labels:
|
105
|
+
app: demo
|
106
|
+
apiVersion: v1
|
107
|
+
kind: Secret
|
108
|
+
data:
|
109
|
+
a: MQ==
|
110
|
+
b: Mg==
|
111
|
+
```
|
112
|
+
|
113
|
+
## Variables
|
114
|
+
|
115
|
+
These environment variables can be set:
|
116
|
+
|
117
|
+
Name | Description
|
118
|
+
---|---
|
119
|
+
AWS_SECRET_PREFIX | Prefixed used to list and filter AWS secrets. IE: `demo/dev/`.
|
120
|
+
|
121
|
+
Secrets#initialize options:
|
122
|
+
|
123
|
+
Variable | Description | Default
|
124
|
+
---|---|---
|
125
|
+
base64 | Automatically base64 encode the values. | false
|
126
|
+
upcase | Automatically upcase the Kubernetes secret data keys. | false
|
127
|
+
prefix | Prefixed used to list and filter AWS secrets. IE: `demo/dev/`. Can also be set with the `AWS_SECRET_PREFIX` env variable. The env variable takes the highest precedence. | nil
|
128
|
+
|
129
|
+
{% include helpers/base64.md %}
|
@@ -0,0 +1,76 @@
|
|
1
|
+
---
|
2
|
+
title: AWS SSM Parameters
|
3
|
+
nav_text: SSM
|
4
|
+
categories: helpers-aws
|
5
|
+
---
|
6
|
+
|
7
|
+
For example if you have these secret values:
|
8
|
+
|
9
|
+
$ aws ssm get-parameter --name /demo/development/db_user --with-decryption | jq '.Parameter.Value'
|
10
|
+
user
|
11
|
+
$ aws ssm get-parameter --name /demo/development/db_pass --with-decryption | jq '.Parameter.Value'
|
12
|
+
pass
|
13
|
+
|
14
|
+
Set up a [Kubes hook](https://kubes.guru/docs/config/hooks/kubes/).
|
15
|
+
|
16
|
+
.kubes/config/hooks/kubes.rb
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
ssm = KubesAws::SSM.new(upcase: true, prefix: "/demo/development/")
|
20
|
+
before("compile",
|
21
|
+
label: "Get secrets from AWS SSM Manager",
|
22
|
+
execute: ssm,
|
23
|
+
)
|
24
|
+
```
|
25
|
+
|
26
|
+
Then set the secrets in the YAML:
|
27
|
+
|
28
|
+
.kubes/resources/shared/secret.yaml
|
29
|
+
|
30
|
+
```yaml
|
31
|
+
apiVersion: v1
|
32
|
+
kind: Secret
|
33
|
+
metadata:
|
34
|
+
name: demo
|
35
|
+
labels:
|
36
|
+
app: demo
|
37
|
+
data:
|
38
|
+
<% KubesAws::SSM.data.each do |k,v| -%>
|
39
|
+
<%= k %>: <%= base64(v) %>
|
40
|
+
<% end -%>
|
41
|
+
```
|
42
|
+
|
43
|
+
This results in AWS secrets with the prefix the `demo/dev/` being added to the Kubernetes secret data. The values are automatically base64 encoded. Produces:
|
44
|
+
|
45
|
+
.kubes/output/shared/secret.yaml
|
46
|
+
|
47
|
+
```yaml
|
48
|
+
metadata:
|
49
|
+
namespace: demo
|
50
|
+
name: demo-2a78a13682
|
51
|
+
labels:
|
52
|
+
app: demo
|
53
|
+
apiVersion: v1
|
54
|
+
kind: Secret
|
55
|
+
data:
|
56
|
+
db_pass: dGVzdDEK
|
57
|
+
db_user: dGVzdDIK
|
58
|
+
```
|
59
|
+
|
60
|
+
## Variables
|
61
|
+
|
62
|
+
These environment variables can be set:
|
63
|
+
|
64
|
+
Name | Description
|
65
|
+
---|---
|
66
|
+
AWS_SSM_PREFIX | Prefixed used to list and filter AWS SSM Parameters. IE: `demo/dev/`.
|
67
|
+
|
68
|
+
Secrets#initialize options:
|
69
|
+
|
70
|
+
Variable | Description | Default
|
71
|
+
---|---|---
|
72
|
+
base64 | Automatically base64 encode the values. | false
|
73
|
+
upcase | Automatically upcase the Kubernetes secret data keys. | false
|
74
|
+
prefix | Prefixed used to list and filter AWS secrets. IE: `demo/dev/`. Can also be set with the `AWS_SECRET_PREFIX` env variable. The env variable takes the highest precedence. | nil
|
75
|
+
|
76
|
+
{% include helpers/base64.md %}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
---
|
2
|
+
title: Google Helpers
|
3
|
+
---
|
4
|
+
|
5
|
+
List of Google helpers:
|
6
|
+
|
7
|
+
{% assign docs = site.docs | where: "categories","helpers-aws" %}
|
8
|
+
{% for doc in docs -%}
|
9
|
+
* [{{ doc.nav_text }}]({{ doc.url }})
|
10
|
+
{% endfor %}
|
11
|
+
|
12
|
+
## Notes
|
13
|
+
|
14
|
+
* By default, `KubeGoogle.logger = Kubes.logger`. This means, you can set `logger.level = "debug"` in `.kubes/config.rb` to see more details.
|
15
|
+
* The `gcloud` cli is used to create IAM roles. So `gcloud` is required.
|
16
|
+
* Note: Would like to use the google sdk, but it wasn't obvious how to do so. PRs are welcomed.
|
17
|
+
|
@@ -0,0 +1,76 @@
|
|
1
|
+
---
|
2
|
+
title: Google Secrets
|
3
|
+
nav_text: Secrets
|
4
|
+
categories: helpers-google
|
5
|
+
---
|
6
|
+
|
7
|
+
Set up a [Kubes hook](https://kubes.guru/docs/config/hooks/kubes/).
|
8
|
+
|
9
|
+
.kubes/config/hooks/kubes.rb
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
before("compile",
|
13
|
+
execute: KubesGoogle::Secrets.new(upcase: true, prefix: 'projects/686010496118/secrets/demo-dev-')
|
14
|
+
)
|
15
|
+
```
|
16
|
+
|
17
|
+
Then set the secrets in the YAML:
|
18
|
+
|
19
|
+
.kubes/resources/shared/secret.yaml
|
20
|
+
|
21
|
+
```yaml
|
22
|
+
apiVersion: v1
|
23
|
+
kind: Secret
|
24
|
+
metadata:
|
25
|
+
name: demo
|
26
|
+
labels:
|
27
|
+
app: demo
|
28
|
+
data:
|
29
|
+
<% KubesGoogle::Secrets.data.each do |k,v| -%>
|
30
|
+
<%= k %>: <%= base64(v) %>
|
31
|
+
<% end -%>
|
32
|
+
```
|
33
|
+
|
34
|
+
This results in Google secrets with the prefix the `demo-dev-` being added to the Kubernetes secret data. The values are automatically base64 encoded.
|
35
|
+
|
36
|
+
For example if you have these secret values:
|
37
|
+
|
38
|
+
$ gcloud secrets versions access latest --secret demo-dev-db_user
|
39
|
+
test1
|
40
|
+
$ gcloud secrets versions access latest --secret demo-dev-db_pass
|
41
|
+
test2
|
42
|
+
$
|
43
|
+
|
44
|
+
.kubes/output/shared/secret.yaml
|
45
|
+
|
46
|
+
```yaml
|
47
|
+
metadata:
|
48
|
+
namespace: demo
|
49
|
+
name: demo-2a78a13682
|
50
|
+
labels:
|
51
|
+
app: demo
|
52
|
+
apiVersion: v1
|
53
|
+
kind: Secret
|
54
|
+
data:
|
55
|
+
db_pass: dGVzdDEK
|
56
|
+
db_user: dGVzdDIK
|
57
|
+
```
|
58
|
+
|
59
|
+
## Variables
|
60
|
+
|
61
|
+
These environment variables can be set:
|
62
|
+
|
63
|
+
Name | Description
|
64
|
+
---|---
|
65
|
+
GCP_SECRET_PREFIX | Prefixed used to list and filter Google secrets. IE: `projects/686010496118/secrets/demo-dev-`.
|
66
|
+
GOOGLE_PROJECT | Google project id.
|
67
|
+
|
68
|
+
Secrets#initialize options:
|
69
|
+
|
70
|
+
Variable | Description | Default
|
71
|
+
---|---|---
|
72
|
+
base64 | Automatically base64 encode the values. | false
|
73
|
+
upcase | Automatically upcase the Kubernetes secret data keys. | false
|
74
|
+
prefix | Prefixed used to list and filter Google secrets. IE: `projects/686010496118/secrets/demo-dev-`. Can also be set with the `GCP_SECRET_PREFIX` env variable. The env variable takes the highest precedence. | nil
|
75
|
+
|
76
|
+
{% include helpers/base64.md %}
|
@@ -0,0 +1,52 @@
|
|
1
|
+
---
|
2
|
+
title: Google Service Account
|
3
|
+
nav_text: Service Account
|
4
|
+
categories: helpers-google
|
5
|
+
---
|
6
|
+
|
7
|
+
## Service Accounts
|
8
|
+
|
9
|
+
You can automatically create the Google Service Account associated with the [GKE Workload Identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity).
|
10
|
+
|
11
|
+
Here's a Kubes hook that creates a service account:
|
12
|
+
|
13
|
+
.kubes/config/hooks/kubes.rb
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
service_account = KubesGoogle::ServiceAccount.new(
|
17
|
+
app: "demo",
|
18
|
+
namespace: "demo-#{Kubes.env}", # defaults to APP-ENV when not set. IE: demo-dev
|
19
|
+
roles: ["cloudsql.client", "secretmanager.viewer"], # defaults to empty when not set
|
20
|
+
)
|
21
|
+
before("apply",
|
22
|
+
label: "create service account",
|
23
|
+
execute: service_account,
|
24
|
+
)
|
25
|
+
```
|
26
|
+
|
27
|
+
The corresponding Kubernetes Service account looks like this:
|
28
|
+
|
29
|
+
.kubes/resources/shared/service_account.yaml
|
30
|
+
|
31
|
+
```yaml
|
32
|
+
apiVersion: v1
|
33
|
+
kind: ServiceAccount
|
34
|
+
metadata:
|
35
|
+
annotations:
|
36
|
+
iam.gke.io/gcp-service-account: demo-<%= Kubes.env %>@<%= ENV['GOOGLE_PROJECT'] %>.iam.gserviceaccount.com
|
37
|
+
name: demo
|
38
|
+
labels:
|
39
|
+
app: demo
|
40
|
+
```
|
41
|
+
|
42
|
+
The role permissions are currently always added to the existing permissions. So removing roles that were previously added does not remove them.
|
43
|
+
|
44
|
+
ServiceAccount#initialize options:
|
45
|
+
|
46
|
+
Variable | Description | Default
|
47
|
+
---|---|---
|
48
|
+
app | The app name. It's used to set other variables conventionally. This is required. | nil
|
49
|
+
gsa | The Google Service Account name. The conventional name is APP-ENV. IE: demo-dev. | APP-ENV
|
50
|
+
ksa | The Kubernetes Service Account name. The conventional name is APP. IE: demo | APP
|
51
|
+
namespace | The Kubernetes namespace. Defaults to the APP-ENV. IE: demo-dev. | APP-ENV
|
52
|
+
roles | Google IAM roles to add. This adds permissions to the Google service account. | []
|
@@ -11,10 +11,12 @@ We'll create a namespace for the app resources:
|
|
11
11
|
.kubes/resources/shared/namespace.rb
|
12
12
|
|
13
13
|
```ruby
|
14
|
-
name "demo"
|
14
|
+
name "demo-#{Kubes.env}"
|
15
15
|
labels(app: "demo")
|
16
16
|
```
|
17
17
|
|
18
|
+
Notice, the `#{Kubes.env}`. Kubes adds the env to the namespace by default. You can change this with the `init --namespace` option.
|
19
|
+
|
18
20
|
## Deployment
|
19
21
|
|
20
22
|
The `web/deployment.rb` file is a little more interesting:
|
@@ -39,7 +41,7 @@ Also let's check the files in the base folder.
|
|
39
41
|
.kubes/resources/base/all.rb
|
40
42
|
|
41
43
|
```ruby
|
42
|
-
namespace "
|
44
|
+
namespace "demo-#{Kubes.env}"
|
43
45
|
labels(app: "demo")
|
44
46
|
```
|
45
47
|
|
@@ -14,11 +14,13 @@ We'll create a namespace for the app resources:
|
|
14
14
|
apiVersion: v1
|
15
15
|
kind: Namespace
|
16
16
|
metadata:
|
17
|
-
name: demo
|
17
|
+
name: demo-<%= Kubes.env %>
|
18
18
|
labels:
|
19
19
|
app: demo
|
20
20
|
```
|
21
21
|
|
22
|
+
Notice, the `<%= Kubes.env %>`. Kubes adds the env to the namespace by default. You can change this with the `init --namespace` option.
|
23
|
+
|
22
24
|
## Deployment
|
23
25
|
|
24
26
|
The `web/deployment.yaml` file is a little more interesting:
|
@@ -57,7 +59,7 @@ Also let's check the files in the base folder.
|
|
57
59
|
|
58
60
|
```yaml
|
59
61
|
metadata:
|
60
|
-
namespace: demo
|
62
|
+
namespace: demo-<%= Kubes.env %>
|
61
63
|
```
|
62
64
|
|
63
65
|
.kubes/resources/base/deployment.yaml
|
data/docs/_docs/patterns.md
CHANGED
@@ -4,4 +4,7 @@ title: Patterns
|
|
4
4
|
|
5
5
|
We'll cover some common deployment patterns here:
|
6
6
|
|
7
|
-
|
7
|
+
{% assign docs = site.docs | where: "categories","patterns" %}
|
8
|
+
{% for doc in docs -%}
|
9
|
+
* [{{ doc.title }}]({{ doc.url }})
|
10
|
+
{% endfor %}
|
@@ -0,0 +1,82 @@
|
|
1
|
+
---
|
2
|
+
title: Secrets
|
3
|
+
nav_text: Secrets
|
4
|
+
categories: patterns
|
5
|
+
---
|
6
|
+
|
7
|
+
A Google Secrets helper is currently supported.
|
8
|
+
|
9
|
+
## Set Up Kubes Hook
|
10
|
+
|
11
|
+
Set up a [Kubes hook]({% link _docs/config/hooks/kubes.md %}).
|
12
|
+
|
13
|
+
.kubes/config/hooks/kubes.rb
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
before("compile",
|
17
|
+
execute: KubesGoogle::Secrets.new(upcase: true, prefix: 'projects/686010496118/secrets/demo-dev-')
|
18
|
+
)
|
19
|
+
```
|
20
|
+
|
21
|
+
Then set the secrets in the YAML:
|
22
|
+
|
23
|
+
.kubes/resources/shared/secret.yaml
|
24
|
+
|
25
|
+
```yaml
|
26
|
+
apiVersion: v1
|
27
|
+
kind: Secret
|
28
|
+
metadata:
|
29
|
+
name: demo
|
30
|
+
labels:
|
31
|
+
app: demo
|
32
|
+
data:
|
33
|
+
<% KubesGoogle::Secrets.data.each do |k,v| -%>
|
34
|
+
<%= k %>: <%= base64(v) %>
|
35
|
+
<% end -%>
|
36
|
+
```
|
37
|
+
|
38
|
+
This results in Google secrets with the prefix the `demo-dev-` being added to the Kubernetes secret data. The values are base64 encoded.
|
39
|
+
|
40
|
+
For example if you have these secret values:
|
41
|
+
|
42
|
+
$ gcloud secrets versions access latest --secret demo-dev-db_user
|
43
|
+
test1
|
44
|
+
$ gcloud secrets versions access latest --secret demo-dev-db_pass
|
45
|
+
test2
|
46
|
+
$
|
47
|
+
|
48
|
+
The compiled secrets.yaml looks like this:
|
49
|
+
|
50
|
+
.kubes/output/shared/secret.yaml
|
51
|
+
|
52
|
+
```yaml
|
53
|
+
metadata:
|
54
|
+
namespace: demo
|
55
|
+
name: demo-2a78a13682
|
56
|
+
labels:
|
57
|
+
app: demo
|
58
|
+
apiVersion: v1
|
59
|
+
kind: Secret
|
60
|
+
data:
|
61
|
+
db_pass: dGVzdDEK
|
62
|
+
db_user: dGVzdDIK
|
63
|
+
```
|
64
|
+
|
65
|
+
These environment variables can be set:
|
66
|
+
|
67
|
+
Name | Description
|
68
|
+
---|---
|
69
|
+
GCP_SECRET_PREFIX | Prefixed used to list and filter Google secrets. IE: `projects/686010496118/secrets/demo-dev-`.
|
70
|
+
GOOGLE_PROJECT | Google project id.
|
71
|
+
|
72
|
+
Secrets#initialize options:
|
73
|
+
|
74
|
+
Variable | Description | Default
|
75
|
+
---|---|---
|
76
|
+
base64 | Automatically base64 encode the values. | false
|
77
|
+
upcase | Automatically upcase the Kubernetes secret data keys. | false
|
78
|
+
prefix | Prefixed used to list and filter Google secrets. IE: `projects/686010496118/secrets/demo-dev-`. Can also be set with the `GCP_SECRET_PREFIX` env variable. The env variable takes the highest precedence. | nil
|
79
|
+
|
80
|
+
Note, Kubernetes secrets are only base64 encoded. So users who have access to read Kubernetes secrets will be able to decode and get the value trivially. Depending on your security posture requirements, this may or may not suffice.
|
81
|
+
|
82
|
+
The Google helpers are provided by the [boltops-tools/kubes_google](https://github.com/boltops-tools/kubes_google) library. For more details, check out its README.
|
@@ -10,7 +10,7 @@ The command name corresponds to the `{{ include.command }}` commands: apply, del
|
|
10
10
|
|
11
11
|
Name | Description
|
12
12
|
---|---
|
13
|
-
label | A human-friendly label so you can see what hooks is being run
|
13
|
+
label | A human-friendly label so you can see what hooks is being run.
|
14
14
|
execute | The script or command to run. IE: path/to/some/script.sh
|
15
15
|
exit_on_fail | Whether or not to continue process if the script returns an failed exit code.
|
16
16
|
{% if include.command == "kubectl" %}on | What resource to run the hook on. IE: shared/namespace, web/deployment, web/service. Note: This option is only used by kubectl hooks.{% endif %}
|
@@ -0,0 +1 @@
|
|
1
|
+
Note, Kubernetes secrets are only base64 encoded. So users who have access to read Kubernetes secrets will be able to decode and get the value trivially. Depending on your security posture requirements, this may or may not suffice.
|
@@ -27,7 +27,7 @@ To explain the layering, here's the general processing order that Kubes takes.
|
|
27
27
|
|
28
28
|
Note, both YAML and DSL forms support layering.
|
29
29
|
|
30
|
-
Layering only combines resources definitions with the same form. For example, `base/all.rb` will not be combined with `web/deployment.yaml`.
|
30
|
+
Layering only combines resources definitions with the same form. For example, the DSL form `base/all.rb` will not be combined with YAML form `web/deployment.yaml`.
|
31
31
|
|
32
32
|
## Full Layering
|
33
33
|
|
data/docs/_includes/sidebar.html
CHANGED
@@ -97,11 +97,32 @@
|
|
97
97
|
<li><a href="{% link _docs/dsl/multiple-resources.md %}">Multiple Resources</a>
|
98
98
|
</ul>
|
99
99
|
</li>
|
100
|
-
<li><a href="{% link _docs/helpers.md %}">Helpers</a
|
100
|
+
<li><a href="{% link _docs/helpers.md %}">Helpers</a>
|
101
|
+
<ul>
|
102
|
+
<li><a href="{% link _docs/helpers/aws.md %}">AWS</a>
|
103
|
+
<ul>
|
104
|
+
{% assign docs = site.docs | where: "categories","helpers-aws" %}
|
105
|
+
{% for doc in docs -%}
|
106
|
+
<li><a href="{{ doc.url }}">{{ doc.nav_text }}</a></li>
|
107
|
+
{% endfor %}
|
108
|
+
</ul>
|
109
|
+
</li>
|
110
|
+
<li><a href="{% link _docs/helpers/google.md %}">Google</a>
|
111
|
+
<ul>
|
112
|
+
{% assign docs = site.docs | where: "categories","helpers-google" %}
|
113
|
+
{% for doc in docs -%}
|
114
|
+
<li><a href="{{ doc.url }}">{{ doc.nav_text }}</a></li>
|
115
|
+
{% endfor %}
|
116
|
+
</ul>
|
117
|
+
</li>
|
118
|
+
</ul>
|
119
|
+
</li>
|
101
120
|
<li><a href="{% link _docs/patterns.md %}">Patterns</a>
|
102
121
|
<ul>
|
103
|
-
|
104
|
-
|
122
|
+
{% assign docs = site.docs | where: "categories","patterns" %}
|
123
|
+
{% for doc in docs -%}
|
124
|
+
<li><a href="{{ doc.url }}">{{ doc.nav_text }}</a></li>
|
125
|
+
{% endfor %}
|
105
126
|
</ul>
|
106
127
|
</li>
|
107
128
|
<li><a href="{% link _docs/extra-env.md %}">Extra Env</a>
|
data/kubes.gemspec
CHANGED
@@ -28,6 +28,10 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.add_dependency "thor"
|
29
29
|
spec.add_dependency "zeitwerk"
|
30
30
|
|
31
|
+
# core helper libs
|
32
|
+
spec.add_dependency "kubes_aws"
|
33
|
+
spec.add_dependency "kubes_google"
|
34
|
+
|
31
35
|
spec.add_development_dependency "bundler"
|
32
36
|
spec.add_development_dependency "byebug"
|
33
37
|
spec.add_development_dependency "cli_markdown"
|
data/lib/kubes.rb
CHANGED
@@ -14,7 +14,11 @@ require "memoist"
|
|
14
14
|
require "rainbow/ext/string"
|
15
15
|
require "yaml"
|
16
16
|
|
17
|
-
|
17
|
+
# core helper libraries
|
18
|
+
require "kubes_aws"
|
19
|
+
require "kubes_google"
|
20
|
+
|
21
|
+
DslEvaluator.backtrace_reject = "lib/kubes"
|
18
22
|
|
19
23
|
require "kubes/autoloader"
|
20
24
|
Kubes::Autoloader.setup
|
data/lib/kubes/cli/compile.rb
CHANGED
@@ -1,8 +1,16 @@
|
|
1
1
|
class Kubes::CLI
|
2
2
|
class Compile < Base
|
3
|
+
# Separate command like prune can call compile. Apply also calls Prune.
|
4
|
+
# Instead of moving Compile out of Prune, will use this class variable.
|
5
|
+
# In case we have other cases where compile is called in another area.
|
6
|
+
# We only want compiled to be called once so hooks only fire once.
|
7
|
+
# Done here so we don't clean and remove the .kubes/output folder.
|
8
|
+
@@compiled = false
|
3
9
|
def run
|
10
|
+
return if @@compiled
|
4
11
|
Clean.new(@options.merge(mute: true)).run
|
5
12
|
Kubes::Compiler.new(@options).run
|
13
|
+
@@compiled = true
|
6
14
|
end
|
7
15
|
end
|
8
16
|
end
|
data/lib/kubes/cli/init.rb
CHANGED
@@ -6,7 +6,7 @@ class Kubes::CLI
|
|
6
6
|
[:force, type: :boolean, desc: "Bypass overwrite are you sure prompt for existing files"],
|
7
7
|
[:type, aliases: ["t"], default: "yaml", desc: "Type: dsl or yaml"],
|
8
8
|
[:repo, required: true, desc: "Docker repo name. Example: user/repo. Configures .kubes/config.rb"],
|
9
|
-
[:namespace, aliases: ["n"], desc: "Namespace to use, defaults to
|
9
|
+
[:namespace, aliases: ["n"], desc: "Namespace to use, defaults to APP-ENV. IE: demo-dev"],
|
10
10
|
]
|
11
11
|
end
|
12
12
|
|
@@ -19,7 +19,12 @@ class Kubes::CLI
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def namespace
|
22
|
-
@options[:namespace] ||
|
22
|
+
@options[:namespace] || default_namespace
|
23
|
+
end
|
24
|
+
|
25
|
+
def default_namespace
|
26
|
+
env = @options[:type] == "yaml" ? '<%= Kubes.env %>' : '#{Kubes.env}'
|
27
|
+
"#{app}-#{env}"
|
23
28
|
end
|
24
29
|
|
25
30
|
def excludes
|
data/lib/kubes/compiler.rb
CHANGED
@@ -8,13 +8,7 @@ module Kubes
|
|
8
8
|
@options = options
|
9
9
|
end
|
10
10
|
|
11
|
-
# Separate command like prune can call compile. Apply also calls Prune.
|
12
|
-
# Instead of moving Compile out of Prune, will use this class variable.
|
13
|
-
# In case we have other cases where compile is called in another area.
|
14
|
-
# We only want compiled to be called once so hooks only fire once.
|
15
|
-
@@compiled = false
|
16
11
|
def run
|
17
|
-
return if @@compiled
|
18
12
|
Kubes.config # trigger config load. So can set ENV['VAR'] in config/envs/dev.rb etc
|
19
13
|
run_hooks("kubes.rb", name: "compile") do
|
20
14
|
results = resources.map do |path|
|
@@ -28,7 +22,6 @@ module Kubes
|
|
28
22
|
end
|
29
23
|
|
30
24
|
puts "Compiled .kubes/resources files to .kubes/output" if show_compiled_message?
|
31
|
-
@@compiled = true
|
32
25
|
end
|
33
26
|
|
34
27
|
def resources
|
@@ -24,8 +24,13 @@ module Kubes::Compiler::Shared
|
|
24
24
|
extra&.strip&.empty? ? nil : extra # if blank string then also return nil
|
25
25
|
end
|
26
26
|
|
27
|
-
def
|
28
|
-
Base64.
|
27
|
+
def encode64(v)
|
28
|
+
Base64.strict_encode64(v.to_s).strip
|
29
|
+
end
|
30
|
+
alias_method :base64, :encode64
|
31
|
+
|
32
|
+
def decode64(v)
|
33
|
+
Base64.strict_decode64(v)
|
29
34
|
end
|
30
35
|
end
|
31
36
|
end
|
@@ -1,13 +1,12 @@
|
|
1
1
|
class Kubes::Compiler::Strategy
|
2
2
|
class Base
|
3
3
|
include Kubes::Logging
|
4
|
+
include Kubes::Compiler::Util::SaveFile
|
4
5
|
|
5
6
|
def initialize(options={})
|
6
7
|
@options = options
|
7
8
|
@path = options[:path]
|
8
|
-
|
9
|
-
@filename = @path.sub(%r{.*\.kubes/resources/},'') # IE: web/deployment.rb or web/deployment.yaml
|
10
|
-
@save_file = @filename.sub('.yml','.yaml').sub('.rb','.yaml')
|
9
|
+
@save_file = save_file(@path)
|
11
10
|
end
|
12
11
|
end
|
13
12
|
end
|
@@ -17,7 +17,7 @@ class Kubes::Compiler::Strategy
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def syntax_class
|
20
|
-
klass_name = normalize_kind(@
|
20
|
+
klass_name = normalize_kind(@save_file)
|
21
21
|
"Kubes::Compiler::Dsl::Syntax::#{klass_name}".constantize
|
22
22
|
rescue NameError
|
23
23
|
logger.debug "Using default resource for: #{klass_name}"
|
@@ -25,7 +25,7 @@ class Kubes::Compiler::Strategy
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def block_form?
|
28
|
-
type = extract_type(@
|
28
|
+
type = extract_type(@save_file)
|
29
29
|
type.pluralize == type
|
30
30
|
end
|
31
31
|
end
|
@@ -32,11 +32,18 @@ class Kubes::Compiler::Strategy
|
|
32
32
|
def render_result(path)
|
33
33
|
if File.exist?(path)
|
34
34
|
yaml = RenderMePretty.result(path, context: self)
|
35
|
-
result =
|
35
|
+
result = yaml_load(path, yaml)
|
36
36
|
result.is_a?(Hash) ? result : {} # in case of blank yaml doc a Boolean false is returned
|
37
37
|
else
|
38
38
|
{}
|
39
39
|
end
|
40
40
|
end
|
41
|
+
|
42
|
+
def yaml_load(path, yaml)
|
43
|
+
YAML.load(yaml)
|
44
|
+
rescue Psych::SyntaxError
|
45
|
+
YamlError.new(path, yaml).show
|
46
|
+
exit 1
|
47
|
+
end
|
41
48
|
end
|
42
49
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
class Kubes::Compiler::Strategy::Erb
|
2
|
+
class YamlError
|
3
|
+
include Kubes::Compiler::Util::SaveFile
|
4
|
+
|
5
|
+
def initialize(path, rendered_yaml)
|
6
|
+
@path, @rendered_yaml = path, rendered_yaml
|
7
|
+
end
|
8
|
+
|
9
|
+
def show
|
10
|
+
FileUtils.mkdir_p(File.dirname(dest))
|
11
|
+
IO.write(dest, @rendered_yaml)
|
12
|
+
show_error(dest)
|
13
|
+
end
|
14
|
+
|
15
|
+
def dest
|
16
|
+
save_file = save_file(@path)
|
17
|
+
"#{Kubes.root}/.kubes/output/#{save_file}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def show_error(path)
|
21
|
+
text = IO.read(path)
|
22
|
+
begin
|
23
|
+
YAML.load(text)
|
24
|
+
rescue Psych::SyntaxError => e
|
25
|
+
handle_yaml_syntax_error(e, path)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def handle_yaml_syntax_error(e, path)
|
30
|
+
io = StringIO.new
|
31
|
+
io.puts "Invalid yaml. Output written for debugging: #{path}".color(:red)
|
32
|
+
io.puts "ERROR: #{e.message}".color(:red)
|
33
|
+
|
34
|
+
# Grab line info. Example error:
|
35
|
+
# ERROR: (<unknown>): could not find expected ':' while scanning a simple key at line 2 column 1
|
36
|
+
md = e.message.match(/at line (\d+) column (\d+)/)
|
37
|
+
line = md[1].to_i
|
38
|
+
|
39
|
+
lines = IO.read(path).split("\n")
|
40
|
+
context = 5 # lines of context
|
41
|
+
top, bottom = [line-context-1, 0].max, line+context-1
|
42
|
+
spacing = lines.size.to_s.size
|
43
|
+
lines[top..bottom].each_with_index do |line_content, index|
|
44
|
+
line_number = top+index+1
|
45
|
+
if line_number == line
|
46
|
+
io.printf("%#{spacing}d %s\n".color(:red), line_number, line_content)
|
47
|
+
else
|
48
|
+
io.printf("%#{spacing}d %s\n", line_number, line_content)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
if ENV['KUBES_TEST']
|
53
|
+
io.string
|
54
|
+
else
|
55
|
+
puts io.string
|
56
|
+
exit 1
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/kubes/hooks/builder.rb
CHANGED
data/lib/kubes/version.rb
CHANGED
@@ -0,0 +1,33 @@
|
|
1
|
+
---
|
2
|
+
metadata:
|
3
|
+
namespace: default
|
4
|
+
labels:
|
5
|
+
app: demo
|
6
|
+
role: web
|
7
|
+
name: demo-web
|
8
|
+
spec:
|
9
|
+
selector:
|
10
|
+
matchLabels:
|
11
|
+
app: demo
|
12
|
+
role: web
|
13
|
+
template:
|
14
|
+
metadata:
|
15
|
+
labels:
|
16
|
+
app: demo
|
17
|
+
role: web
|
18
|
+
spec:
|
19
|
+
containers:
|
20
|
+
- name: demo-web
|
21
|
+
image: gcr.io/project/demo-web:kubes-2020-06-23T00-07-54
|
22
|
+
env:
|
23
|
+
- name: MYSQL_ROOT_PASSWORD
|
24
|
+
valueFrom:
|
25
|
+
configMapKeyRef:
|
26
|
+
name: demo-config-map
|
27
|
+
key: password
|
28
|
+
secretKeyRef:
|
29
|
+
name: demo-secret
|
30
|
+
key: password
|
31
|
+
replicas: 1
|
32
|
+
apiVersion: apps/v1
|
33
|
+
kind: Deployment
|
@@ -0,0 +1,40 @@
|
|
1
|
+
---
|
2
|
+
metadata:
|
3
|
+
namespace: default
|
4
|
+
labels:
|
5
|
+
app: demo
|
6
|
+
role: web
|
7
|
+
name: demo-web
|
8
|
+
spec:
|
9
|
+
selector:
|
10
|
+
matchLabels:
|
11
|
+
app: demo
|
12
|
+
role: web
|
13
|
+
template:
|
14
|
+
metadata:
|
15
|
+
labels:
|
16
|
+
app: demo
|
17
|
+
role: web
|
18
|
+
spec:
|
19
|
+
containers:
|
20
|
+
- name: demo-web
|
21
|
+
image: gcr.io/project/demo-web:kubes-2020-06-23T00-07-54
|
22
|
+
volumeMounts:
|
23
|
+
- mountPath: /config-map
|
24
|
+
name: config-map-volume
|
25
|
+
volumes:
|
26
|
+
- configMap:
|
27
|
+
name: demo-config-map
|
28
|
+
items:
|
29
|
+
- key: k1
|
30
|
+
path: config-map.conf
|
31
|
+
name: config-map-volume
|
32
|
+
- secret:
|
33
|
+
secretName: demo-secret
|
34
|
+
items:
|
35
|
+
- key: k1
|
36
|
+
path: secrets.conf
|
37
|
+
name: secrets-volume
|
38
|
+
replicas: 1
|
39
|
+
apiVersion: apps/v1
|
40
|
+
kind: Pod
|
@@ -5,6 +5,7 @@ describe Kubes::Compiler::Decorator::Post do
|
|
5
5
|
YAML.load_file("spec/fixtures/decorators/deployment/#{name}.yaml")
|
6
6
|
end
|
7
7
|
before(:each) do
|
8
|
+
allow(Kubes::Compiler::Decorator::Hashable::Storage).to receive(:fetch).and_return("fakehash")
|
8
9
|
allow(Kubes::Compiler::Decorator::Hashable::Storage).to receive(:fetch).with("Secret", "demo-secret").and_return("fakehash")
|
9
10
|
allow(Kubes::Compiler::Decorator::Hashable::Storage).to receive(:fetch).with("ConfigMap", "demo-config-map").and_return("fakehash-config")
|
10
11
|
allow(Kubes::Compiler::Decorator::Hashable::Storage).to receive(:fetch).with("ConfigMap", "demo-config-map-2").and_return("fakehash-config2")
|
@@ -107,5 +108,31 @@ describe Kubes::Compiler::Decorator::Post do
|
|
107
108
|
expect(name).to eq("demo-config-map-2-fakehash-config2")
|
108
109
|
end
|
109
110
|
end
|
111
|
+
|
112
|
+
describe "valueFrom" do
|
113
|
+
let(:data) { fixture("both/valueFrom") }
|
114
|
+
it "run" do
|
115
|
+
decorator.run
|
116
|
+
data = decorator.data
|
117
|
+
valueFrom = data['spec']['template']['spec']['containers'][0]['env'][0]['valueFrom']
|
118
|
+
name = valueFrom['configMapKeyRef']['name']
|
119
|
+
expect(name).to eq("demo-config-map-fakehash-config")
|
120
|
+
name = valueFrom['secretKeyRef']['name']
|
121
|
+
expect(name).to eq("demo-secret-fakehash")
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe "volumes" do
|
126
|
+
let(:data) { fixture("both/volumes") }
|
127
|
+
it "run" do
|
128
|
+
decorator.run
|
129
|
+
data = decorator.data
|
130
|
+
volumes = data['spec']['template']['spec']['volumes']
|
131
|
+
name = volumes[0]['configMap']['name']
|
132
|
+
expect(name).to eq("demo-config-map-fakehash-config")
|
133
|
+
name = volumes[1]['secret']['secretName']
|
134
|
+
expect(name).to eq("demo-secret-fakehash")
|
135
|
+
end
|
136
|
+
end
|
110
137
|
end
|
111
138
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kubes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tung Nguyen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-10-
|
11
|
+
date: 2020-10-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -136,6 +136,34 @@ dependencies:
|
|
136
136
|
- - ">="
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: kubes_aws
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :runtime
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: kubes_google
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :runtime
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
139
167
|
- !ruby/object:Gem::Dependency
|
140
168
|
name: bundler
|
141
169
|
requirement: !ruby/object:Gem::Requirement
|
@@ -271,6 +299,13 @@ files:
|
|
271
299
|
- docs/_docs/extra-env/dsl.md
|
272
300
|
- docs/_docs/extra-env/yaml.md
|
273
301
|
- docs/_docs/helpers.md
|
302
|
+
- docs/_docs/helpers/aws.md
|
303
|
+
- docs/_docs/helpers/aws/iam-role.md
|
304
|
+
- docs/_docs/helpers/aws/secrets.md
|
305
|
+
- docs/_docs/helpers/aws/ssm.md
|
306
|
+
- docs/_docs/helpers/google.md
|
307
|
+
- docs/_docs/helpers/google/secrets.md
|
308
|
+
- docs/_docs/helpers/google/service-account.md
|
274
309
|
- docs/_docs/intro.md
|
275
310
|
- docs/_docs/intro/concepts.md
|
276
311
|
- docs/_docs/intro/how-kubes-works.md
|
@@ -309,6 +344,7 @@ files:
|
|
309
344
|
- docs/_docs/patterns.md
|
310
345
|
- docs/_docs/patterns/clock-web-worker.md
|
311
346
|
- docs/_docs/patterns/migrations.md
|
347
|
+
- docs/_docs/patterns/secrets.md
|
312
348
|
- docs/_docs/resources.md
|
313
349
|
- docs/_docs/resources/base.md
|
314
350
|
- docs/_docs/resources/role.md
|
@@ -324,6 +360,7 @@ files:
|
|
324
360
|
- docs/_includes/footer.html
|
325
361
|
- docs/_includes/google_analytics.html
|
326
362
|
- docs/_includes/header.html
|
363
|
+
- docs/_includes/helpers/base64.md
|
327
364
|
- docs/_includes/intro/install.md
|
328
365
|
- docs/_includes/js.html
|
329
366
|
- docs/_includes/kubes-steps.md
|
@@ -525,9 +562,11 @@ files:
|
|
525
562
|
- lib/kubes/compiler/strategy/base.rb
|
526
563
|
- lib/kubes/compiler/strategy/dsl.rb
|
527
564
|
- lib/kubes/compiler/strategy/erb.rb
|
565
|
+
- lib/kubes/compiler/strategy/erb/yaml_error.rb
|
528
566
|
- lib/kubes/compiler/strategy/pass.rb
|
529
567
|
- lib/kubes/compiler/strategy/result.rb
|
530
568
|
- lib/kubes/compiler/util/normalize.rb
|
569
|
+
- lib/kubes/compiler/util/save_file.rb
|
531
570
|
- lib/kubes/compiler/util/yaml_dump.rb
|
532
571
|
- lib/kubes/completer.rb
|
533
572
|
- lib/kubes/completer/script.rb
|
@@ -588,6 +627,8 @@ files:
|
|
588
627
|
- spec/fixtures/artifacts/demo-web/service.yaml
|
589
628
|
- spec/fixtures/blocks/deployments.rb
|
590
629
|
- spec/fixtures/decorators/deployment/both/envFrom.yaml
|
630
|
+
- spec/fixtures/decorators/deployment/both/valueFrom.yaml
|
631
|
+
- spec/fixtures/decorators/deployment/both/volumes.yaml
|
591
632
|
- spec/fixtures/decorators/deployment/configMap/envFrom.yaml
|
592
633
|
- spec/fixtures/decorators/deployment/configMap/valueFrom.yaml
|
593
634
|
- spec/fixtures/decorators/deployment/configMap/volumes.yaml
|
@@ -661,6 +702,8 @@ test_files:
|
|
661
702
|
- spec/fixtures/artifacts/demo-web/service.yaml
|
662
703
|
- spec/fixtures/blocks/deployments.rb
|
663
704
|
- spec/fixtures/decorators/deployment/both/envFrom.yaml
|
705
|
+
- spec/fixtures/decorators/deployment/both/valueFrom.yaml
|
706
|
+
- spec/fixtures/decorators/deployment/both/volumes.yaml
|
664
707
|
- spec/fixtures/decorators/deployment/configMap/envFrom.yaml
|
665
708
|
- spec/fixtures/decorators/deployment/configMap/valueFrom.yaml
|
666
709
|
- spec/fixtures/decorators/deployment/configMap/volumes.yaml
|