ky 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rspec +2 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +186 -0
- data/bin/ky +5 -0
- data/ky.gemspec +31 -0
- data/lib/ky.rb +36 -0
- data/lib/ky/cli.rb +55 -0
- data/lib/ky/env_generation.rb +52 -0
- data/lib/ky/manipulation.rb +46 -0
- data/lib/ky/version.rb +3 -0
- data/spec/ky_bin_spec.rb +72 -0
- data/spec/spec_helper.rb +104 -0
- data/spec/support/config.yml +8 -0
- data/spec/support/decoded.yml +9 -0
- data/spec/support/encoded.yml +9 -0
- data/spec/support/web-base.yml +19 -0
- data/spec/support/web-env.yml +31 -0
- data/spec/support/web-merged-original.yml +37 -0
- data/spec/support/web-merged.yml +49 -0
- metadata +143 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 80b326de6d0dd57558007807fe7441ea72f75c2e
|
4
|
+
data.tar.gz: 7788d551ece1c5bdafd05c99ea05a4a16a5d4b88
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3ff01e43e12fa0db1a2649c5f9b410572012f512c59a41445cb106be7b0902c406a3e3a26146fdc2b539ff465f6e2104576ab96ccf27a04d73a1efb2c4ed4384
|
7
|
+
data.tar.gz: 8614bfdae5d0aab41b98c4eedfb3668f54106dde827429f0397fc894042616e3ea3bb81305d317612aa8a09464b911b55aa34b551c6403ea97c95b4f1ab71ef5
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 bglusman
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
# KY - Kubernetes Yaml Workflow Lubricant
|
2
|
+
|
3
|
+
## This gem contains helper methods and workflows for working with kubernetes yml files
|
4
|
+
|
5
|
+
The primary purpose is to automate/DRY up duplication and agreement between multiple deployment YAML files and config/secret yaml files that we saw emerging as we built our kubernetes configuration.
|
6
|
+
|
7
|
+
|
8
|
+
The typical workflow for the tool might start with generating a yaml file of env mappings from a secrets.yml file and a config.yml file, like so:
|
9
|
+
###Example usage
|
10
|
+
Assuming config.yml such as:
|
11
|
+
```
|
12
|
+
apiVersion: v1
|
13
|
+
kind: ConfigMap
|
14
|
+
metadata:
|
15
|
+
name: test
|
16
|
+
data:
|
17
|
+
tz: EST
|
18
|
+
rest-api-id: 1234abcd
|
19
|
+
use-ssl: true
|
20
|
+
```
|
21
|
+
|
22
|
+
and secrets.yml such as:
|
23
|
+
```
|
24
|
+
apiVersion: v1
|
25
|
+
kind: Secret
|
26
|
+
metadata:
|
27
|
+
name: test
|
28
|
+
type: Opaque
|
29
|
+
data:
|
30
|
+
database-url: cG9zdGdyZXM6Ly91c2VyOnBhc3NAZGIuZXhhbXBsZS5jb20vZGI=
|
31
|
+
pii-encryption-key: ZmFrZWtleQ==
|
32
|
+
```
|
33
|
+
Then the command
|
34
|
+
|
35
|
+
```
|
36
|
+
$ ky env config.yml secrets.yml
|
37
|
+
```
|
38
|
+
|
39
|
+
Would yield
|
40
|
+
```
|
41
|
+
---
|
42
|
+
spec:
|
43
|
+
template:
|
44
|
+
spec:
|
45
|
+
containers:
|
46
|
+
- env:
|
47
|
+
- name: TZ
|
48
|
+
valueFrom:
|
49
|
+
configMapKeyRef:
|
50
|
+
name: test
|
51
|
+
key: tz
|
52
|
+
- name: REST_API_ID
|
53
|
+
valueFrom:
|
54
|
+
configMapKeyRef:
|
55
|
+
name: test
|
56
|
+
key: rest-api-id
|
57
|
+
- name: USE_SSL
|
58
|
+
valueFrom:
|
59
|
+
configMapKeyRef:
|
60
|
+
name: test
|
61
|
+
key: use-ssl
|
62
|
+
- name: DATABASE_URL
|
63
|
+
valueFrom:
|
64
|
+
secretKeyRef:
|
65
|
+
name: test
|
66
|
+
key: database-url
|
67
|
+
- name: PII_ENCRYPTION_KEY
|
68
|
+
valueFrom:
|
69
|
+
secretKeyRef:
|
70
|
+
name: test
|
71
|
+
key: pii-encryption-key
|
72
|
+
```
|
73
|
+
|
74
|
+
You can also pass in a non-base64 encoded secrets.yml above, and use KY as documented below to generate the encoded version you use on demand as needed (just don't check in either one to your repo!)
|
75
|
+
|
76
|
+
Then you can merge the generated file, we'll call `env.yml` below, with one or more base deployment YAML files, to help prevent duplication, and regenerating and applying to kubernetes hosts via kubectl as needed when env variable values or keys change. So with the `env.yml` above and a `base.yml` like so:
|
77
|
+
```
|
78
|
+
apiVersion: extensions/v1beta1
|
79
|
+
kind: Deployment
|
80
|
+
metadata:
|
81
|
+
name: test
|
82
|
+
spec:
|
83
|
+
replicas: 1
|
84
|
+
template:
|
85
|
+
metadata:
|
86
|
+
labels:
|
87
|
+
app: web
|
88
|
+
spec:
|
89
|
+
containers:
|
90
|
+
- name: web
|
91
|
+
image: docker/image
|
92
|
+
imagePullPolicy: Always
|
93
|
+
ports:
|
94
|
+
- containerPort: 3000
|
95
|
+
command: [ "/bin/bash","-c","bundle exec rake assets:precompile && bundle exec puma -C ./config/puma.rb" ]
|
96
|
+
```
|
97
|
+
then running this command:
|
98
|
+
|
99
|
+
```
|
100
|
+
$ ky merge base.yml env.yml # outputs combined yaml to stdout
|
101
|
+
```
|
102
|
+
|
103
|
+
Would yield:
|
104
|
+
```
|
105
|
+
---
|
106
|
+
apiVersion: extensions/v1beta1
|
107
|
+
kind: Deployment
|
108
|
+
metadata:
|
109
|
+
name: test
|
110
|
+
spec:
|
111
|
+
replicas: 1
|
112
|
+
template:
|
113
|
+
metadata:
|
114
|
+
labels:
|
115
|
+
app: web
|
116
|
+
spec:
|
117
|
+
containers:
|
118
|
+
- name: web
|
119
|
+
image: docker/image
|
120
|
+
imagePullPolicy: Always
|
121
|
+
ports:
|
122
|
+
- containerPort: 3000
|
123
|
+
command:
|
124
|
+
- "/bin/bash"
|
125
|
+
- "-c"
|
126
|
+
- bundle exec rake assets:precompile && bundle exec puma -C ./config/puma.rb
|
127
|
+
env:
|
128
|
+
- name: TZ
|
129
|
+
valueFrom:
|
130
|
+
configMapKeyRef:
|
131
|
+
name: test
|
132
|
+
key: tz
|
133
|
+
- name: REST_API_ID
|
134
|
+
valueFrom:
|
135
|
+
configMapKeyRef:
|
136
|
+
name: test
|
137
|
+
key: rest-api-id
|
138
|
+
- name: USE_SSL
|
139
|
+
valueFrom:
|
140
|
+
configMapKeyRef:
|
141
|
+
name: test
|
142
|
+
key: use-ssl
|
143
|
+
- name: DATABASE_URL
|
144
|
+
valueFrom:
|
145
|
+
secretKeyRef:
|
146
|
+
name: test
|
147
|
+
key: database-url
|
148
|
+
- name: PII_ENCRYPTION_KEY
|
149
|
+
valueFrom:
|
150
|
+
secretKeyRef:
|
151
|
+
name: test
|
152
|
+
key: pii-encryption-key
|
153
|
+
|
154
|
+
```
|
155
|
+
(Note the formatting of some yaml syntax may be affected, such as command array using multiline list form instead of single line square bracket notation)
|
156
|
+
|
157
|
+
Kubernetes requires its secrets.yml files to have their data values base64 encoded. KY will either read the value from a specified fle or use yaml value directly, and write the resulting data all to a single yaml file with base64 encoded values under a specfied key ('data' by default) for consistency. Decoding always results in a single file, with escaped values as necessary, but encoding can come from multiple files which all must be accessible to the process, either as local file references or as URL's it can read the file from at the moment it is run (S3 buckets can generate short lived unguessable URLs to help to this securely).
|
158
|
+
|
159
|
+
Those long/unescaped values can be loaded from files referenced in the source yaml by wrapping in "magic" file/url delimiters, ('@' by default), e.g:
|
160
|
+
```yaml
|
161
|
+
apiVersion: v1
|
162
|
+
kind: Secret
|
163
|
+
type: Opaque
|
164
|
+
data:
|
165
|
+
long_crazy_indirect_value: '@local_unescaped_file.txt@'
|
166
|
+
binary_indirect_url_value: '@https://example.com/secret_image.png@'
|
167
|
+
regular_direct_value_domain: example.com
|
168
|
+
```
|
169
|
+
|
170
|
+
The delimiter can be changed with the env var `MAGIC_FILE` from default value of '@', and the data key can be changed from it's default value of 'data' with env var `DATA_KEY`.
|
171
|
+
|
172
|
+
Gem install as usual in bundler or directly as `ky`, though only CLI usage is intended at present.
|
173
|
+
|
174
|
+
###Example usage
|
175
|
+
```
|
176
|
+
$ ky encode connect.configmap.yml # outputs encoded yaml to stdout
|
177
|
+
$ ky decode connect.secrets.yml # outputs decode yaml to stdout
|
178
|
+
$ ky encode connect.configmap.yml tmp.out # writes encoded yaml to tmp.out file
|
179
|
+
$ ky encode https://example.com/secret.unencoded.yaml secret.yml # downloads yml file from URL and encodes, writes to local yaml file
|
180
|
+
$ ky decode connect.secrets.yml tmp2.out # writes encoded yaml to tmp2.out file
|
181
|
+
$ ky decode https://example.com/secret.yaml # downloads yml file from URL and decodes, prints to standard out
|
182
|
+
$ cat file.yml | obscure decode # reads non-base64 input yaml from stdin, writes decoded yamlto stdout
|
183
|
+
$ cat file.yml | obscure encode # reads base64 encoded input yaml from stdin, write encoded to stdout
|
184
|
+
```
|
185
|
+
|
186
|
+
A valid url may also be used in place of a file path for input.
|
data/bin/ky
ADDED
data/ky.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib/', __FILE__)
|
3
|
+
$LOAD_PATH.unshift lib unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'ky/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = 'ky'
|
8
|
+
s.version = KY::VERSION
|
9
|
+
s.platform = Gem::Platform::RUBY
|
10
|
+
s.authors = ['Brian Glusman']
|
11
|
+
s.email = ['brian@stellaservice.com']
|
12
|
+
s.homepage = 'https://github.com/stellaservice/ky'
|
13
|
+
s.license = 'MIT'
|
14
|
+
s.summary = 'Kubernetes Yaml utilities and lubricant'
|
15
|
+
s.rubyforge_project = 'ky'
|
16
|
+
s.require_paths = ['lib']
|
17
|
+
s.add_development_dependency 'rspec', '~> 3.5'
|
18
|
+
s.add_development_dependency 'pry', '~> 0.10'
|
19
|
+
s.add_runtime_dependency 'deep_merge', '~> 1.1'
|
20
|
+
s.add_runtime_dependency 'thor', '~> 0.19'
|
21
|
+
s.add_runtime_dependency 'activesupport', ">= 3.0", "< 6"
|
22
|
+
|
23
|
+
s.description = <<-DESC
|
24
|
+
Utility belt for managing, manipulating and lubricating kubernetes deployment, config and secrets yml files
|
25
|
+
DESC
|
26
|
+
|
27
|
+
s.files = `git ls-files`.split("\n")
|
28
|
+
s.test_files = `git ls-files -- {test}/*`.split("\n")
|
29
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
30
|
+
s.require_paths = ['lib']
|
31
|
+
end
|
data/lib/ky.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'base64'
|
3
|
+
require 'open-uri'
|
4
|
+
require_relative 'ky/manipulation'
|
5
|
+
require_relative 'ky/env_generation'
|
6
|
+
require_relative 'ky/deploy_generation'
|
7
|
+
|
8
|
+
|
9
|
+
module KY
|
10
|
+
module_function
|
11
|
+
|
12
|
+
def decode(output, input)
|
13
|
+
output << Manipulation.code_yaml(input, :decode)
|
14
|
+
end
|
15
|
+
|
16
|
+
def encode(output, input)
|
17
|
+
output << Manipulation.code_yaml(input, :encode)
|
18
|
+
end
|
19
|
+
|
20
|
+
def merge(output, input1, input2)
|
21
|
+
output << Manipulation.merge_yaml(input1, input2)
|
22
|
+
end
|
23
|
+
|
24
|
+
def env(output, input1, input2)
|
25
|
+
output << EnvGeneration.generate_env(input1, input2)
|
26
|
+
rescue KY::EnvGeneration::ConflictingProjectError => e
|
27
|
+
$stderr << "Error processing yml files, please provide a config and a secrets file from the same kubernetes project/name"
|
28
|
+
exit(1)
|
29
|
+
end
|
30
|
+
|
31
|
+
def from_proc(proc_path, output_dir)
|
32
|
+
DeployGeneration.new(proc_path, output_dir).call
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
end
|
data/lib/ky/cli.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require_relative '../ky'
|
2
|
+
require 'thor'
|
3
|
+
module KY
|
4
|
+
class Cli < Thor
|
5
|
+
desc "encode secrets.yml", "base64 encoded yaml version of data attributes in secrets.yml"
|
6
|
+
def encode(input_source=$stdin, output_source=$stdout)
|
7
|
+
input_output(input_source, output_source) do |input_object, output_object|
|
8
|
+
KY.encode(output_object, input_object)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "decode secrets.yml", "decoded yaml version of secrets.yml with base64 encoded data attributes"
|
13
|
+
def decode(input_source=$stdin, output_source=$stdout)
|
14
|
+
input_output(input_source, output_source) do |input_object, output_object|
|
15
|
+
KY.decode(output_object, input_object)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "merge base.yml env.yml", "deep merged/combined yaml of two seperate files"
|
20
|
+
def merge(input_source1, input_source2=$stdin, output_source=$stdout)
|
21
|
+
input_output(input_source1, output_source) do |input_object1, output_object|
|
22
|
+
with(input_source2, 'r') {|input_object2| KY.merge(output_object, input_object1, input_object2) }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
desc "env config.yml secrets.yml", "generate env variables section of a deployment from a config and a secrets file"
|
27
|
+
def env(input_source1, input_source2=$stdin, output_source=$stdout)
|
28
|
+
input_output(input_source1, output_source) do |input_object1, output_object|
|
29
|
+
with(input_source2, 'r') {|input_object2| KY.env(output_object, input_object1, input_object2) }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "from_proc path/to/Procfile output_dir", "generate kubernetes deployment base configs from Procfile"
|
34
|
+
def from_proc(procfile_path, output_dir)
|
35
|
+
KY.from_proc(procfile_path, output_dir)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def input_output(input1, output1)
|
41
|
+
with(input1, 'r') {|input_object| with(output1, 'w+') { |output_object| yield(input_object, output_object) } }
|
42
|
+
end
|
43
|
+
|
44
|
+
def with(output, mode)
|
45
|
+
if output.kind_of?(IO)
|
46
|
+
yield output
|
47
|
+
else
|
48
|
+
open(output, mode) do |f|
|
49
|
+
yield f
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'active_support/core_ext'
|
3
|
+
module KY
|
4
|
+
class EnvGeneration
|
5
|
+
ConflictingProjectError = Class.new(StandardError)
|
6
|
+
|
7
|
+
#string array meta-trick to avoid naked strings everywhere below, yaml doesn't to_s symbols as desired
|
8
|
+
%w(ConfigMap configMapKeyRef Secret secretKeyRef kind data metadata name key valueFrom spec template containers env).each do |raw_string|
|
9
|
+
define_method(raw_string.underscore) { raw_string }
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.generate_env(input1, input2)
|
13
|
+
new(input1, input2).to_yaml
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :config_hsh, :secret_hsh
|
17
|
+
def initialize(input1, input2)
|
18
|
+
input_hashes = YAML.load(input1.read), YAML.load(input2.read)
|
19
|
+
@config_hsh = input_hashes.find {|h| h[kind] == config_map }
|
20
|
+
@secret_hsh = input_hashes.find {|h| h[kind] == secret }
|
21
|
+
raise ConflictingProjectError.new("Config and Secret metadata names do not agree") unless secret_hsh[metadata][name] == project
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_yaml
|
25
|
+
output_hash(config_hsh[data].map {|key, _| config_env(project, key) } + secret_hsh[data].map {|key, _| secret_env(project, key) }).to_yaml
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def project
|
31
|
+
config_hsh[metadata][name]
|
32
|
+
end
|
33
|
+
|
34
|
+
def config_env(project, kebab_version)
|
35
|
+
env_map(config_map_key_ref, project, kebab_version)
|
36
|
+
end
|
37
|
+
|
38
|
+
def secret_env(project, kebab_version)
|
39
|
+
env_map(secret_key_ref, project, kebab_version)
|
40
|
+
end
|
41
|
+
|
42
|
+
def env_map(type, project, kebab_version)
|
43
|
+
puts "WARNING: #{kebab_version} format appears incorrect, format as #{kebab_version.dasherize.downcase}" unless kebab_version == kebab_version.dasherize.downcase
|
44
|
+
{name => kebab_version.underscore.upcase, value_from => { type => {name => project, key => kebab_version }}}
|
45
|
+
end
|
46
|
+
|
47
|
+
def output_hash(env_array)
|
48
|
+
{spec => {template => {spec => { containers => [{env => env_array }]}}}}
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'deep_merge/rails_compat'
|
2
|
+
module KY
|
3
|
+
module Manipulation
|
4
|
+
DEFAULT_DATA_KEY = 'data'
|
5
|
+
MAGIC_DELIMITER = '@'
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def merge_yaml(input1, input2)
|
9
|
+
combined = {}
|
10
|
+
YAML.load(input1.read).tap { |hsh|
|
11
|
+
hsh.deeper_merge!(YAML.load(input2.read), merge_hash_arrays: true, extend_existing_arrays: true)
|
12
|
+
}.to_yaml
|
13
|
+
end
|
14
|
+
|
15
|
+
def code_yaml(yaml_source, direction)
|
16
|
+
YAML.load(yaml_source.read).tap { |hsh|
|
17
|
+
data = hsh[obscured_data_key]
|
18
|
+
hsh[obscured_data_key] = data.map { |key, value|
|
19
|
+
[key, handle_coding(direction, value)]
|
20
|
+
}.to_h
|
21
|
+
}.to_yaml
|
22
|
+
end
|
23
|
+
|
24
|
+
def handle_coding(direction, value)
|
25
|
+
direction == :decode ? Base64.decode64(value) : Base64.strict_encode64(value_or_file_contents(value))
|
26
|
+
end
|
27
|
+
|
28
|
+
def value_or_file_contents(value)
|
29
|
+
return value unless detect_file(value)
|
30
|
+
value_contents = open(value.gsub(magic_delimiter, '')) { |f| f.read }
|
31
|
+
end
|
32
|
+
|
33
|
+
def detect_file(value)
|
34
|
+
value.match /\A#{magic_delimiter}(.+)#{magic_delimiter}\z/
|
35
|
+
end
|
36
|
+
|
37
|
+
def magic_delimiter
|
38
|
+
ENV['MAGIC_FILE'] || MAGIC_DELIMITER
|
39
|
+
end
|
40
|
+
|
41
|
+
def obscured_data_key
|
42
|
+
ENV['DATA_KEY'] || DEFAULT_DATA_KEY
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/ky/version.rb
ADDED
data/spec/ky_bin_spec.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'ky/cli'
|
2
|
+
describe "cli commands" do
|
3
|
+
let(:tmpfile_path) { "spec/support/tmpfile.yml" }
|
4
|
+
after { `rm #{tmpfile_path}` if File.exists?(tmpfile_path) }
|
5
|
+
describe "works with stdout" do
|
6
|
+
it "decodes" do
|
7
|
+
output = File.read('spec/support/decoded.yml')
|
8
|
+
expect($stdout).to receive(:<<).with(output)
|
9
|
+
KY::Cli.new.decode("spec/support/encoded.yml")
|
10
|
+
end
|
11
|
+
|
12
|
+
it "encodes" do
|
13
|
+
output = File.read('spec/support/encoded.yml')
|
14
|
+
expect($stdout).to receive(:<<).with(output)
|
15
|
+
KY::Cli.new.encode("spec/support/decoded.yml")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "works with files" do
|
20
|
+
it "decodes" do
|
21
|
+
output = File.read('spec/support/decoded.yml')
|
22
|
+
KY::Cli.new.decode("spec/support/encoded.yml", tmpfile_path)
|
23
|
+
expect(File.read(tmpfile_path)).to eq(output)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "encodes" do
|
27
|
+
output = File.read('spec/support/encoded.yml')
|
28
|
+
KY::Cli.new.encode("spec/support/decoded.yml", tmpfile_path)
|
29
|
+
expect(File.read(tmpfile_path)).to eq(output)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "merges yml files" do
|
34
|
+
it "to stdout" do
|
35
|
+
output = File.read('spec/support/web-merged.yml')
|
36
|
+
expect($stdout).to receive(:<<).with(output)
|
37
|
+
KY::Cli.new.merge('spec/support/web-base.yml', 'spec/support/web-env.yml')
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "generates env section" do
|
42
|
+
it "to stdout" do
|
43
|
+
output = File.read('spec/support/web-env.yml')
|
44
|
+
expect($stdout).to receive(:<<).with(output)
|
45
|
+
KY::Cli.new.env('spec/support/decoded.yml', 'spec/support/config.yml')
|
46
|
+
end
|
47
|
+
|
48
|
+
it "config and secret are order independent" do
|
49
|
+
output = File.read('spec/support/web-env.yml')
|
50
|
+
expect($stdout).to receive(:<<).with(output)
|
51
|
+
KY::Cli.new.env('spec/support/config.yml', 'spec/support/decoded.yml')
|
52
|
+
end
|
53
|
+
|
54
|
+
it "to file" do
|
55
|
+
output = File.read('spec/support/web-env.yml')
|
56
|
+
KY::Cli.new.env('spec/support/config.yml', 'spec/support/decoded.yml', tmpfile_path)
|
57
|
+
expect(File.read(tmpfile_path)).to eq(output)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "parses Procfile into multiple deployment files" do
|
62
|
+
let(:tmpdir) { 'spec/support/tmpdir' }
|
63
|
+
it "to directory" do
|
64
|
+
KY::Cli.new.from_proc('spec/support/Procfile', tmpdir)
|
65
|
+
expect(File.exists?("#{tmpdir}/web.yml")).to be true
|
66
|
+
expect(File.exists?("#{tmpdir}/worker.yml")).to be true
|
67
|
+
expect(File.exists?("#{tmpdir}/jobs.yml")).to be true
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'pry'
|
2
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
3
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
4
|
+
# The generated `.rspec` file contains `--require spec_helper` which will cause
|
5
|
+
# this file to always be loaded, without a need to explicitly require it in any
|
6
|
+
# files.
|
7
|
+
#
|
8
|
+
# Given that it is always loaded, you are encouraged to keep this file as
|
9
|
+
# light-weight as possible. Requiring heavyweight dependencies from this file
|
10
|
+
# will add to the boot time of your test suite on EVERY test run, even for an
|
11
|
+
# individual file that may not need all of that loaded. Instead, consider making
|
12
|
+
# a separate helper file that requires the additional dependencies and performs
|
13
|
+
# the additional setup, and require it from the spec files that actually need
|
14
|
+
# it.
|
15
|
+
#
|
16
|
+
# The `.rspec` file also contains a few flags that are not defaults but that
|
17
|
+
# users commonly want.
|
18
|
+
#
|
19
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
20
|
+
RSpec.configure do |config|
|
21
|
+
# rspec-expectations config goes here. You can use an alternate
|
22
|
+
# assertion/expectation library such as wrong or the stdlib/minitest
|
23
|
+
# assertions if you prefer.
|
24
|
+
config.expect_with :rspec do |expectations|
|
25
|
+
# This option will default to `true` in RSpec 4. It makes the `description`
|
26
|
+
# and `failure_message` of custom matchers include text for helper methods
|
27
|
+
# defined using `chain`, e.g.:
|
28
|
+
# be_bigger_than(2).and_smaller_than(4).description
|
29
|
+
# # => "be bigger than 2 and smaller than 4"
|
30
|
+
# ...rather than:
|
31
|
+
# # => "be bigger than 2"
|
32
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
33
|
+
end
|
34
|
+
|
35
|
+
# rspec-mocks config goes here. You can use an alternate test double
|
36
|
+
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
37
|
+
config.mock_with :rspec do |mocks|
|
38
|
+
# Prevents you from mocking or stubbing a method that does not exist on
|
39
|
+
# a real object. This is generally recommended, and will default to
|
40
|
+
# `true` in RSpec 4.
|
41
|
+
mocks.verify_partial_doubles = true
|
42
|
+
end
|
43
|
+
|
44
|
+
# This option will default to `:apply_to_host_groups` in RSpec 4 (and will
|
45
|
+
# have no way to turn it off -- the option exists only for backwards
|
46
|
+
# compatibility in RSpec 3). It causes shared context metadata to be
|
47
|
+
# inherited by the metadata hash of host groups and examples, rather than
|
48
|
+
# triggering implicit auto-inclusion in groups with matching metadata.
|
49
|
+
config.shared_context_metadata_behavior = :apply_to_host_groups
|
50
|
+
|
51
|
+
# The settings below are suggested to provide a good initial experience
|
52
|
+
# with RSpec, but feel free to customize to your heart's content.
|
53
|
+
=begin
|
54
|
+
# This allows you to limit a spec run to individual examples or groups
|
55
|
+
# you care about by tagging them with `:focus` metadata. When nothing
|
56
|
+
# is tagged with `:focus`, all examples get run. RSpec also provides
|
57
|
+
# aliases for `it`, `describe`, and `context` that include `:focus`
|
58
|
+
# metadata: `fit`, `fdescribe` and `fcontext`, respectively.
|
59
|
+
config.filter_run_when_matching :focus
|
60
|
+
|
61
|
+
# Allows RSpec to persist some state between runs in order to support
|
62
|
+
# the `--only-failures` and `--next-failure` CLI options. We recommend
|
63
|
+
# you configure your source control system to ignore this file.
|
64
|
+
config.example_status_persistence_file_path = "spec/examples.txt"
|
65
|
+
|
66
|
+
# Limits the available syntax to the non-monkey patched syntax that is
|
67
|
+
# recommended. For more details, see:
|
68
|
+
# - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
|
69
|
+
# - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
70
|
+
# - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
|
71
|
+
config.disable_monkey_patching!
|
72
|
+
|
73
|
+
# This setting enables warnings. It's recommended, but in some cases may
|
74
|
+
# be too noisy due to issues in dependencies.
|
75
|
+
config.warnings = true
|
76
|
+
|
77
|
+
# Many RSpec users commonly either run the entire suite or an individual
|
78
|
+
# file, and it's useful to allow more verbose output when running an
|
79
|
+
# individual spec file.
|
80
|
+
if config.files_to_run.one?
|
81
|
+
# Use the documentation formatter for detailed output,
|
82
|
+
# unless a formatter has already been configured
|
83
|
+
# (e.g. via a command-line flag).
|
84
|
+
config.default_formatter = 'doc'
|
85
|
+
end
|
86
|
+
|
87
|
+
# Print the 10 slowest examples and example groups at the
|
88
|
+
# end of the spec run, to help surface which specs are running
|
89
|
+
# particularly slow.
|
90
|
+
config.profile_examples = 10
|
91
|
+
|
92
|
+
# Run specs in random order to surface order dependencies. If you find an
|
93
|
+
# order dependency and want to debug it, you can fix the order by providing
|
94
|
+
# the seed, which is printed after each run.
|
95
|
+
# --seed 1234
|
96
|
+
config.order = :random
|
97
|
+
|
98
|
+
# Seed global randomization in this process using the `--seed` CLI option.
|
99
|
+
# Setting this allows you to use `--seed` to deterministically reproduce
|
100
|
+
# test failures related to randomization by passing the same `--seed` value
|
101
|
+
# as the one that triggered the failure.
|
102
|
+
Kernel.srand config.seed
|
103
|
+
=end
|
104
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
apiVersion: extensions/v1beta1
|
2
|
+
kind: Deployment
|
3
|
+
metadata:
|
4
|
+
name: web
|
5
|
+
namespace: stg
|
6
|
+
spec:
|
7
|
+
replicas: 1
|
8
|
+
template:
|
9
|
+
metadata:
|
10
|
+
labels:
|
11
|
+
app: connect-web
|
12
|
+
spec:
|
13
|
+
containers:
|
14
|
+
- name: web
|
15
|
+
image: docker/image
|
16
|
+
imagePullPolicy: Always
|
17
|
+
ports:
|
18
|
+
- containerPort: 3000
|
19
|
+
command: [ "/bin/bash","-c","bundle exec rake assets:precompile && bundle exec puma -C ./config/puma.rb" ]
|
@@ -0,0 +1,31 @@
|
|
1
|
+
---
|
2
|
+
spec:
|
3
|
+
template:
|
4
|
+
spec:
|
5
|
+
containers:
|
6
|
+
- env:
|
7
|
+
- name: TZ
|
8
|
+
valueFrom:
|
9
|
+
configMapKeyRef:
|
10
|
+
name: test
|
11
|
+
key: tz
|
12
|
+
- name: REST_API_ID
|
13
|
+
valueFrom:
|
14
|
+
configMapKeyRef:
|
15
|
+
name: test
|
16
|
+
key: rest-api-id
|
17
|
+
- name: USE_SSL
|
18
|
+
valueFrom:
|
19
|
+
configMapKeyRef:
|
20
|
+
name: test
|
21
|
+
key: use-ssl
|
22
|
+
- name: DATABASE_URL
|
23
|
+
valueFrom:
|
24
|
+
secretKeyRef:
|
25
|
+
name: test
|
26
|
+
key: database-url
|
27
|
+
- name: PII_ENCRYPTION_KEY
|
28
|
+
valueFrom:
|
29
|
+
secretKeyRef:
|
30
|
+
name: test
|
31
|
+
key: pii-encryption-key
|
@@ -0,0 +1,37 @@
|
|
1
|
+
apiVersion: extensions/v1beta1
|
2
|
+
kind: Deployment
|
3
|
+
metadata:
|
4
|
+
name: web
|
5
|
+
namespace: stg
|
6
|
+
spec:
|
7
|
+
replicas: 1
|
8
|
+
template:
|
9
|
+
metadata:
|
10
|
+
labels:
|
11
|
+
app: connect-web
|
12
|
+
spec:
|
13
|
+
imagePullSecrets:
|
14
|
+
- name: stellaservice-dockerhub-key
|
15
|
+
containers:
|
16
|
+
- name: web
|
17
|
+
image: stellanetops/connect:staging
|
18
|
+
imagePullPolicy: Always
|
19
|
+
ports:
|
20
|
+
- containerPort: 3000
|
21
|
+
command: [ "/bin/bash","-c","bundle exec rake assets:precompile && bundle exec puma -C ./config/puma.rb" ]
|
22
|
+
env:
|
23
|
+
- name: TZ
|
24
|
+
valueFrom:
|
25
|
+
configMapKeyRef:
|
26
|
+
name: connect
|
27
|
+
key: tz
|
28
|
+
- name: USE_SSL
|
29
|
+
valueFrom:
|
30
|
+
configMapKeyRef:
|
31
|
+
name: connect
|
32
|
+
key: use-ssl
|
33
|
+
- name: REST_API_ID
|
34
|
+
valueFrom:
|
35
|
+
secretKeyRef:
|
36
|
+
name: connect
|
37
|
+
key: rest-api-id
|
@@ -0,0 +1,49 @@
|
|
1
|
+
---
|
2
|
+
apiVersion: extensions/v1beta1
|
3
|
+
kind: Deployment
|
4
|
+
metadata:
|
5
|
+
name: web
|
6
|
+
namespace: stg
|
7
|
+
spec:
|
8
|
+
replicas: 1
|
9
|
+
template:
|
10
|
+
metadata:
|
11
|
+
labels:
|
12
|
+
app: connect-web
|
13
|
+
spec:
|
14
|
+
containers:
|
15
|
+
- name: web
|
16
|
+
image: docker/image
|
17
|
+
imagePullPolicy: Always
|
18
|
+
ports:
|
19
|
+
- containerPort: 3000
|
20
|
+
command:
|
21
|
+
- "/bin/bash"
|
22
|
+
- "-c"
|
23
|
+
- bundle exec rake assets:precompile && bundle exec puma -C ./config/puma.rb
|
24
|
+
env:
|
25
|
+
- name: TZ
|
26
|
+
valueFrom:
|
27
|
+
configMapKeyRef:
|
28
|
+
name: test
|
29
|
+
key: tz
|
30
|
+
- name: REST_API_ID
|
31
|
+
valueFrom:
|
32
|
+
configMapKeyRef:
|
33
|
+
name: test
|
34
|
+
key: rest-api-id
|
35
|
+
- name: USE_SSL
|
36
|
+
valueFrom:
|
37
|
+
configMapKeyRef:
|
38
|
+
name: test
|
39
|
+
key: use-ssl
|
40
|
+
- name: DATABASE_URL
|
41
|
+
valueFrom:
|
42
|
+
secretKeyRef:
|
43
|
+
name: test
|
44
|
+
key: database-url
|
45
|
+
- name: PII_ENCRYPTION_KEY
|
46
|
+
valueFrom:
|
47
|
+
secretKeyRef:
|
48
|
+
name: test
|
49
|
+
key: pii-encryption-key
|
metadata
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ky
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brian Glusman
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-10-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pry
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.10'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.10'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: deep_merge
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.1'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: thor
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.19'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.19'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: activesupport
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.0'
|
76
|
+
- - "<"
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '6'
|
79
|
+
type: :runtime
|
80
|
+
prerelease: false
|
81
|
+
version_requirements: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '3.0'
|
86
|
+
- - "<"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '6'
|
89
|
+
description: " Utility belt for managing, manipulating and lubricating kubernetes
|
90
|
+
deployment, config and secrets yml files\n"
|
91
|
+
email:
|
92
|
+
- brian@stellaservice.com
|
93
|
+
executables:
|
94
|
+
- ky
|
95
|
+
extensions: []
|
96
|
+
extra_rdoc_files: []
|
97
|
+
files:
|
98
|
+
- ".gitignore"
|
99
|
+
- ".rspec"
|
100
|
+
- Gemfile
|
101
|
+
- LICENSE.txt
|
102
|
+
- README.md
|
103
|
+
- bin/ky
|
104
|
+
- ky.gemspec
|
105
|
+
- lib/ky.rb
|
106
|
+
- lib/ky/cli.rb
|
107
|
+
- lib/ky/env_generation.rb
|
108
|
+
- lib/ky/manipulation.rb
|
109
|
+
- lib/ky/version.rb
|
110
|
+
- spec/ky_bin_spec.rb
|
111
|
+
- spec/spec_helper.rb
|
112
|
+
- spec/support/config.yml
|
113
|
+
- spec/support/decoded.yml
|
114
|
+
- spec/support/encoded.yml
|
115
|
+
- spec/support/web-base.yml
|
116
|
+
- spec/support/web-env.yml
|
117
|
+
- spec/support/web-merged-original.yml
|
118
|
+
- spec/support/web-merged.yml
|
119
|
+
homepage: https://github.com/stellaservice/ky
|
120
|
+
licenses:
|
121
|
+
- MIT
|
122
|
+
metadata: {}
|
123
|
+
post_install_message:
|
124
|
+
rdoc_options: []
|
125
|
+
require_paths:
|
126
|
+
- lib
|
127
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
133
|
+
requirements:
|
134
|
+
- - ">="
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '0'
|
137
|
+
requirements: []
|
138
|
+
rubyforge_project: ky
|
139
|
+
rubygems_version: 2.5.1
|
140
|
+
signing_key:
|
141
|
+
specification_version: 4
|
142
|
+
summary: Kubernetes Yaml utilities and lubricant
|
143
|
+
test_files: []
|