ky 0.3.3 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/ky.rb +33 -22
- data/lib/ky/cli.rb +2 -4
- data/lib/ky/deploy_generation.rb +2 -2
- data/lib/ky/env_generation.rb +6 -1
- data/lib/ky/hash.rb +17 -0
- data/lib/ky/manipulation.rb +6 -6
- data/lib/ky/version.rb +1 -1
- data/spec/ky_bin_spec.rb +48 -3
- data/spec/support/Lubefile +23 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b1de2efb87f781886061141962646b113a33da52
|
4
|
+
data.tar.gz: c51ee92b728200441a515f09953a2a25ac71d494
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 435791205d319456386a1b81774768ef80618225a15a55edca06839cdd1905bf4ad91cc0ee8e654ef5ed6d8a4bd032d95b4c878b103e4213aa96280325479064
|
7
|
+
data.tar.gz: 5b41cec9ba39bbf3b67cc5e7bfd102d5dfebc45992550031032500d164270fd8bf8053dbf7ee18576e1affab37c07c590f55dd4748a1bb4069714ed6f708af7b
|
data/README.md
CHANGED
@@ -9,7 +9,7 @@ The full/hopeful use of the tool may be enabled with the new `compile` command w
|
|
9
9
|
The command is invoked as:
|
10
10
|
`ky compile Procfile.file config.yml secrets.yml output_dir` and the output directory will be created if necessary. You may pass a namespace to compile which will be reflected in the deployments (and should agree with the config and secrets, though it's not checking they agree at present). The arguments are all configurable via the configuration file as well, so it can in practice be invoked as `ky compile` or `ky compile --envioronment stg` if you have a configuration file correctly present as described below.
|
11
11
|
|
12
|
-
Configuration begins with a config file in the project working directory, or in your home directory if you wish to share across several projects. Unfortunately there are several competing conventions for configuration files, the traditional dot-file configuration convention and newer, more visible Capitalfile configuration. KY is a lubricant, and has no opinion, and therefore currently supports naming your configuration file `.ky.yml`, `.ky.yaml`, or `Lubefile
|
12
|
+
Configuration begins with a config file in the project working directory, or in your home directory if you wish to share across several projects. Unfortunately there are several competing conventions for configuration files, the traditional dot-file configuration convention and newer, more visible Capitalfile configuration. KY is a lubricant, and has no opinion, and therefore currently supports naming your configuration file `.ky.yml`, `.ky.yaml`, or `Lubefile`. The default configuration, if this file is not found, is as follows:
|
13
13
|
```
|
14
14
|
environments: []
|
15
15
|
replica_count: 1
|
data/lib/ky.rb
CHANGED
@@ -7,10 +7,11 @@ require_relative 'ky/manipulation'
|
|
7
7
|
require_relative 'ky/env_generation'
|
8
8
|
require_relative 'ky/template'
|
9
9
|
require_relative 'ky/deploy_generation'
|
10
|
+
require_relative 'ky/hash'
|
10
11
|
|
11
12
|
|
12
13
|
class KY
|
13
|
-
CONFIG_FILE_NAMES = [".ky.yml", ".ky.yaml", "Lubefile"
|
14
|
+
CONFIG_FILE_NAMES = [".ky.yml", ".ky.yaml", "Lubefile"]
|
14
15
|
CONFIG_LOCATIONS = ["#{Dir.pwd}/", "#{Dir.home}/"]
|
15
16
|
DEFAULT_CONFIG = {
|
16
17
|
environments: [],
|
@@ -22,10 +23,17 @@ class KY
|
|
22
23
|
api_version: "extensions/v1beta1",
|
23
24
|
inline_config: true,
|
24
25
|
inline_secret: false,
|
25
|
-
project_name: "global"
|
26
|
+
project_name: "global",
|
27
|
+
force_configmap_apply: false
|
26
28
|
}.with_indifferent_access
|
27
29
|
|
28
|
-
|
30
|
+
attr_reader :opts, :configuration
|
31
|
+
|
32
|
+
def initialize(opts={})
|
33
|
+
@opts=opts
|
34
|
+
@configuration = build_configuration
|
35
|
+
define_methods_from_config(configuration)
|
36
|
+
end
|
29
37
|
|
30
38
|
def decode(output, input)
|
31
39
|
output << Manipulation.code_yaml(input, :decode)
|
@@ -40,44 +48,47 @@ class KY
|
|
40
48
|
end
|
41
49
|
|
42
50
|
def env(output, input1, input2)
|
43
|
-
output << EnvGeneration.generate_env(self, input1, input2).
|
51
|
+
output << EnvGeneration.generate_env(self, input1, input2).to_plain_yaml
|
44
52
|
rescue KY::EnvGeneration::ConflictingProjectError => e
|
45
53
|
$stderr << "Error processing yml files, please provide a config and a secrets file from the same kubernetes project/name"
|
46
54
|
exit(1)
|
47
55
|
end
|
48
56
|
|
49
|
-
def compile(proc_path, env1path, env2path, base_output_dir
|
50
|
-
full_output_dir = Pathname.new(base_output_dir).join(environment.to_s).to_s
|
57
|
+
def compile(proc_path, env1path, env2path, base_output_dir)
|
58
|
+
full_output_dir = Pathname.new(base_output_dir).join(configuration[:environment].to_s).to_s
|
51
59
|
FileUtils.mkdir_p(full_output_dir)
|
52
60
|
env_obj = EnvGeneration.new(self, env1path, env2path)
|
53
|
-
deploys_hash = DeployGeneration.new(self, proc_path, full_output_dir, env_obj.project, namespace).to_h
|
61
|
+
deploys_hash = DeployGeneration.new(self, proc_path, full_output_dir, env_obj.project, configuration[:namespace]).to_h
|
54
62
|
deploys_hash.each do |file_path, deploy_hash|
|
55
|
-
File.write(file_path, Manipulation.merge_hash(deploy_hash, env_obj.to_h).
|
63
|
+
File.write(file_path, Manipulation.merge_hash(deploy_hash, env_obj.to_h).to_plain_yaml)
|
56
64
|
end
|
57
65
|
Manipulation.write_configs_encode_if_needed(env_obj.config_hsh, env_obj.secret_hsh, full_output_dir, configuration[:project_name])
|
58
66
|
end
|
59
67
|
|
60
|
-
def
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
68
|
+
def build_configuration
|
69
|
+
config = if config_file_location
|
70
|
+
YAML.load(File.read(config_file_location))
|
71
|
+
else
|
72
|
+
DEFAULT_CONFIG
|
73
|
+
end.with_indifferent_access
|
74
|
+
config.merge!(current_environment_hash(config))
|
75
|
+
config
|
67
76
|
end
|
68
77
|
|
69
78
|
def deploy_merge(id)
|
70
|
-
return {} unless configuration[
|
71
|
-
configuration[
|
79
|
+
return {} unless configuration[:merge]
|
80
|
+
configuration[:merge][id].to_h
|
72
81
|
end
|
73
82
|
|
74
|
-
def current_environment_hash(partial_config
|
75
|
-
|
76
|
-
|
83
|
+
def current_environment_hash(partial_config)
|
84
|
+
current_config = partial_config || configuration
|
85
|
+
env_file_path = environment_files(current_config).find {|file| file.match(opts[:environment] || current_config[:environment]) } if opts[:environment] || current_config[:environment] # ugh, this find is accident waiting to happen, REFACTOR/RETHINK!
|
86
|
+
hsh = env_file_path ? YAML.load(File.read(env_file_path)).with_indifferent_access : {}
|
87
|
+
(hsh[:configuration] ? hsh[:configuration].merge(opts) : hsh.merge(opts)).with_indifferent_access
|
77
88
|
end
|
78
89
|
|
79
|
-
def environment_files(partial_config
|
80
|
-
environments = (partial_config || configuration)[
|
90
|
+
def environment_files(partial_config)
|
91
|
+
environments = (partial_config || configuration)[:environments].flat_map {|env| ["#{env}.yml", "#{env}.yaml"]}
|
81
92
|
(CONFIG_LOCATIONS * environments.count).zip(environments).map(&:join).select {|path| File.exist?(path) && !File.directory?(path) }
|
82
93
|
end
|
83
94
|
|
data/lib/ky/cli.rb
CHANGED
@@ -43,16 +43,14 @@ class KY
|
|
43
43
|
method_option :environment, type: :string, aliases: "-e"
|
44
44
|
method_option :image_tag, type: :string, aliases: "-t"
|
45
45
|
def compile(procfile_path=nil, config_or_secrets_path=nil, secrets_or_config_path=nil, output_dir=nil)
|
46
|
-
instance = KY.new
|
47
|
-
instance.environment = options[:environment]
|
48
|
-
instance.image_tag = options[:image_tag]
|
46
|
+
instance = KY.new(options.with_indifferent_access)
|
49
47
|
procfile_path ||= instance.configuration['procfile_path']
|
50
48
|
config_or_secrets_path ||= instance.configuration['config_path'] || instance.configuration['secret_path']
|
51
49
|
secrets_or_config_path ||= instance.configuration['secret_path'] || instance.configuration['config_path']
|
52
50
|
output_dir ||= instance.configuration['output_dir']
|
53
51
|
raise MissingParametersError unless procfile_path && config_or_secrets_path && secrets_or_config_path && output_dir
|
54
52
|
input_input(config_or_secrets_path, secrets_or_config_path) do |input1, input2|
|
55
|
-
instance.compile(procfile_path, input1, input2, output_dir
|
53
|
+
instance.compile(procfile_path, input1, input2, output_dir)
|
56
54
|
end
|
57
55
|
end
|
58
56
|
|
data/lib/ky/deploy_generation.rb
CHANGED
@@ -14,7 +14,7 @@ class KY
|
|
14
14
|
|
15
15
|
def call
|
16
16
|
to_h.each do |file_path, deploy_hash|
|
17
|
-
File.write(file_path, deploy_hash.
|
17
|
+
File.write(file_path, deploy_hash.to_plain_yaml)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
@@ -42,7 +42,7 @@ class KY
|
|
42
42
|
def template_hash(id, command_array)
|
43
43
|
app_name = instance.configuration['app_name'] || "#{project_name}-#{id}"
|
44
44
|
template_context = Template.context(app_name: app_name, id: id, command_array: command_array)
|
45
|
-
Manipulation.merge_hash(
|
45
|
+
tmp = Manipulation.merge_hash(
|
46
46
|
YAML.load(
|
47
47
|
ERB.new(deployment_yaml).result(template_context)
|
48
48
|
),
|
data/lib/ky/env_generation.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'active_support'
|
2
2
|
require 'active_support/core_ext'
|
3
|
+
require 'securerandom'
|
3
4
|
class KY
|
4
5
|
class EnvGeneration
|
5
6
|
ConflictingProjectError = Class.new(StandardError)
|
@@ -23,7 +24,7 @@ class KY
|
|
23
24
|
end
|
24
25
|
|
25
26
|
def to_h
|
26
|
-
output_hash(config_hsh[data].map {|key, value| config_env(key, value) } + secret_hsh[data].map {|key, value| secret_env(key, value) })
|
27
|
+
output_hash(config_hsh[data].map {|key, value| config_env(key, value) } + secret_hsh[data].map {|key, value| secret_env(key, value) } + force_config)
|
27
28
|
end
|
28
29
|
|
29
30
|
def project
|
@@ -32,6 +33,10 @@ class KY
|
|
32
33
|
|
33
34
|
private
|
34
35
|
|
36
|
+
def force_config
|
37
|
+
return [] unless instance.configuration[:force_configmap_apply]
|
38
|
+
[inline_env_map(config_map_key_ref, "force-configmap-apply", SecureRandom.hex)]
|
39
|
+
end
|
35
40
|
|
36
41
|
def config_env(kebab_version, value)
|
37
42
|
inline_config? ? inline_env_map(config_map_key_ref, kebab_version, value) : env_map(config_map_key_ref, kebab_version)
|
data/lib/ky/hash.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
class Hash # specifically for HashWithIndifferentAccess < Hash, instead of plain to_yaml
|
2
|
+
def to_plain_yaml(opts = {}) # which yields ugly !map:ActiveSupport::HashWithIndifferentAccess
|
3
|
+
self.to_hash_recursive.to_yaml(opts)
|
4
|
+
end
|
5
|
+
|
6
|
+
def to_hash_recursive
|
7
|
+
result = self.to_h
|
8
|
+
result.each do |key, value|
|
9
|
+
if(value.kind_of? Hash)
|
10
|
+
result[key] = value.to_hash_recursive.to_h
|
11
|
+
elsif (value.kind_of? Array)
|
12
|
+
result[key] = value.map { |item| item.kind_of?(Hash) ? item.to_hash_recursive : item }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
result
|
16
|
+
end
|
17
|
+
end
|
data/lib/ky/manipulation.rb
CHANGED
@@ -9,7 +9,7 @@ class KY
|
|
9
9
|
combined = {}
|
10
10
|
YAML.load(input1.read).tap { |hsh|
|
11
11
|
merge_hash(hsh, YAML.load(input2.read))
|
12
|
-
}.
|
12
|
+
}.to_plain_yaml
|
13
13
|
end
|
14
14
|
|
15
15
|
def merge_hash(hsh1, hsh2)
|
@@ -22,7 +22,7 @@ class KY
|
|
22
22
|
hsh[obscured_data_key] = data.map { |key, value|
|
23
23
|
[key, handle_coding(direction, value)]
|
24
24
|
}.to_h
|
25
|
-
}.
|
25
|
+
}.to_plain_yaml
|
26
26
|
end
|
27
27
|
|
28
28
|
def handle_coding(direction, value)
|
@@ -47,12 +47,12 @@ class KY
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def write_configs_encode_if_needed(config_hsh, secret_hsh, output_path, project_name)
|
50
|
-
if secret_hsh[obscured_data_key].values.
|
51
|
-
File.write("#{output_path}/#{project_name}.secret.yml", secret_hsh.
|
50
|
+
if secret_hsh[obscured_data_key].values.all? {|value| BASE_64_DETECTION_REGEX =~ value }
|
51
|
+
File.write("#{output_path}/#{project_name}.secret.yml", secret_hsh.to_plain_yaml)
|
52
52
|
else
|
53
|
-
File.write("#{output_path}/#{project_name}.secret.yml", code_yaml(StringIO.new(secret_hsh.
|
53
|
+
File.write("#{output_path}/#{project_name}.secret.yml", code_yaml(StringIO.new(secret_hsh.to_plain_yaml), :encode))
|
54
54
|
end
|
55
|
-
File.write("#{output_path}/#{project_name}.configmap.yml", config_hsh.
|
55
|
+
File.write("#{output_path}/#{project_name}.configmap.yml", config_hsh.to_plain_yaml)
|
56
56
|
end
|
57
57
|
|
58
58
|
end
|
data/lib/ky/version.rb
CHANGED
data/spec/ky_bin_spec.rb
CHANGED
@@ -61,11 +61,11 @@ describe "ky cli" do
|
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
64
|
-
describe "primary cli command" do
|
64
|
+
describe "primary cli command generates and" do
|
65
65
|
let(:instance) { KY.new }
|
66
66
|
let(:fake_tag) { 'fake_tag' }
|
67
67
|
let(:tmpdir) { 'spec/support/tmpdir' }
|
68
|
-
after { `rm -r #{tmpdir}`
|
68
|
+
after { `rm -r #{tmpdir}` }
|
69
69
|
describe "compiles Procfile and env secrets/configs into entire deployments" do
|
70
70
|
it "to directory" do
|
71
71
|
KY::Cli.new.compile('spec/support/Procfile', 'spec/support/config.yml', 'spec/support/decoded.yml', tmpdir)
|
@@ -99,7 +99,6 @@ describe "ky cli" do
|
|
99
99
|
end
|
100
100
|
|
101
101
|
describe "uses image_tag when passed in as option" do
|
102
|
-
let(:tmpdir) { 'spec/support/tmp2dir' }
|
103
102
|
it "to directory" do
|
104
103
|
instance = KY::Cli.new
|
105
104
|
instance.options = {image_tag: fake_tag}
|
@@ -109,6 +108,52 @@ describe "ky cli" do
|
|
109
108
|
end
|
110
109
|
end
|
111
110
|
|
111
|
+
describe "uses namespace when passed in as option" do
|
112
|
+
it "to directory" do
|
113
|
+
instance = KY::Cli.new
|
114
|
+
instance.options = {namespace: fake_tag}
|
115
|
+
instance.compile('spec/support/Procfile', 'spec/support/config.yml', 'spec/support/decoded.yml', tmpdir)
|
116
|
+
expect(File.exists?("#{tmpdir}/web.deployment.yml")).to be true
|
117
|
+
expect(File.read("#{tmpdir}/web.deployment.yml")).to match(fake_tag)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe "merges yaml to named ids templates when compiling" do
|
122
|
+
before { `cp spec/support/Lubefile .`}
|
123
|
+
after { `rm Lubefile` }
|
124
|
+
it "to directory" do
|
125
|
+
instance = KY::Cli.new
|
126
|
+
instance.compile('spec/support/Procfile', 'spec/support/config.yml', 'spec/support/decoded.yml', tmpdir)
|
127
|
+
expect(File.exists?("#{tmpdir}/web.deployment.yml")).to be true
|
128
|
+
expect(File.exists?("#{tmpdir}/jobs.deployment.yml")).to be true
|
129
|
+
expect(File.read("#{tmpdir}/web.deployment.yml")).to match('port')
|
130
|
+
expect(File.read("#{tmpdir}/jobs.deployment.yml")).not_to match('port')
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe "serializes yaml without reference to HashWithIndifferentAccess" do
|
135
|
+
before { `cp spec/support/Lubefile .`}
|
136
|
+
after { `rm Lubefile` }
|
137
|
+
it "to directory" do
|
138
|
+
instance = KY::Cli.new
|
139
|
+
instance.compile('spec/support/Procfile', 'spec/support/config.yml', 'spec/support/decoded.yml', tmpdir)
|
140
|
+
expect(File.exists?("#{tmpdir}/web.deployment.yml")).to be true
|
141
|
+
expect(File.read("#{tmpdir}/web.deployment.yml")).not_to match('HashWithIndifferentAccess')
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
describe "adds random inline value if force_configmap_apply is true" do
|
146
|
+
before { `cp spec/support/Lubefile .`}
|
147
|
+
after { `rm Lubefile` }
|
148
|
+
it "to directory" do
|
149
|
+
instance = KY::Cli.new
|
150
|
+
instance.options = {force_configmap_apply: true}
|
151
|
+
instance.compile('spec/support/Procfile', 'spec/support/config.yml', 'spec/support/decoded.yml', tmpdir)
|
152
|
+
expect(File.exists?("#{tmpdir}/web.deployment.yml")).to be true
|
153
|
+
expect(File.read("#{tmpdir}/web.deployment.yml")).to match('FORCE_CONFIGMAP_APPLY')
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
112
157
|
end
|
113
158
|
end
|
114
159
|
|
@@ -0,0 +1,23 @@
|
|
1
|
+
environments: [dev, stg, prd]
|
2
|
+
deployment: examples/deployment_base.yml
|
3
|
+
replica_count: 2
|
4
|
+
image_pull_policy: "IfNotPresent"
|
5
|
+
namespace: "default"
|
6
|
+
image: "organization/project"
|
7
|
+
image_tag: "latest"
|
8
|
+
api_version: "extensions/v1beta1"
|
9
|
+
inline_config: true
|
10
|
+
inline_secret: false
|
11
|
+
project_name: "connect"
|
12
|
+
config_path: "spec/support/config.yml"
|
13
|
+
secret_path: "spec/support/decoded.yml"
|
14
|
+
output_dir: "namespaces"
|
15
|
+
procfile_path: "spec/support/Procfile"
|
16
|
+
merge:
|
17
|
+
web:
|
18
|
+
spec:
|
19
|
+
template:
|
20
|
+
spec:
|
21
|
+
containers:
|
22
|
+
- ports:
|
23
|
+
- containerPort: 3000
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ky
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Glusman
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-10-
|
11
|
+
date: 2016-10-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -90,11 +90,13 @@ files:
|
|
90
90
|
- lib/ky/cli.rb
|
91
91
|
- lib/ky/deploy_generation.rb
|
92
92
|
- lib/ky/env_generation.rb
|
93
|
+
- lib/ky/hash.rb
|
93
94
|
- lib/ky/manipulation.rb
|
94
95
|
- lib/ky/template.rb
|
95
96
|
- lib/ky/version.rb
|
96
97
|
- spec/ky_bin_spec.rb
|
97
98
|
- spec/spec_helper.rb
|
99
|
+
- spec/support/Lubefile
|
98
100
|
- spec/support/Procfile
|
99
101
|
- spec/support/config.yml
|
100
102
|
- spec/support/decoded.yml
|