hippo-cli 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/bin/hippo +4 -4
- data/cli/apply_config.rb +1 -0
- data/cli/apply_services.rb +1 -0
- data/cli/console.rb +2 -0
- data/cli/create.rb +83 -0
- data/cli/deploy.rb +2 -0
- data/cli/init.rb +1 -1
- data/cli/install.rb +3 -1
- data/cli/key.rb +34 -0
- data/cli/kubectl.rb +2 -0
- data/cli/logs.rb +56 -0
- data/cli/objects.rb +50 -0
- data/cli/package_install.rb +30 -0
- data/cli/package_list.rb +40 -0
- data/cli/package_notes.rb +23 -0
- data/cli/package_test.rb +21 -0
- data/cli/package_uninstall.rb +27 -0
- data/cli/package_upgrade.rb +30 -0
- data/cli/package_values.rb +22 -0
- data/cli/prepare.rb +18 -0
- data/cli/run.rb +37 -0
- data/cli/secrets.rb +24 -0
- data/cli/stages.rb +26 -0
- data/cli/status.rb +25 -0
- data/cli/vars.rb +20 -0
- data/cli/version.rb +8 -0
- data/lib/hippo.rb +12 -0
- data/lib/hippo/bootstrap_parser.rb +64 -0
- data/lib/hippo/cli.rb +47 -14
- data/lib/hippo/extensions.rb +9 -0
- data/lib/hippo/image.rb +35 -31
- data/lib/hippo/manifest.rb +17 -7
- data/lib/hippo/object_definition.rb +18 -5
- data/lib/hippo/package.rb +124 -0
- data/lib/hippo/repository_tag.rb +38 -0
- data/lib/hippo/secret_manager.rb +61 -14
- data/lib/hippo/stage.rb +60 -26
- data/lib/hippo/util.rb +34 -0
- data/lib/hippo/version.rb +1 -1
- data/template/Hippofile +10 -2
- metadata +44 -13
- metadata.gz.sig +0 -0
- data/cli/secrets_edit.rb +0 -34
- data/cli/secrets_key.rb +0 -20
- data/lib/hippo/secret.rb +0 -112
- data/template/config/env-vars.yaml +0 -7
- data/template/deployments/web.yaml +0 -29
- data/template/deployments/worker.yaml +0 -26
- data/template/jobs/deploy/db-migration.yaml +0 -22
- data/template/jobs/install/load-schema.yaml +0 -22
- data/template/services/main.ingress.yaml +0 -13
- data/template/services/web.svc.yaml +0 -11
- data/template/stages/production.yaml +0 -7
data/cli/package_test.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :'package:test' do
|
4
|
+
desc 'Test a package installation'
|
5
|
+
|
6
|
+
option '-h', '--hippofile [RECIPE]', 'The path to the Hippofile (defaults: ./Hippofile)' do |value, options|
|
7
|
+
options[:hippofile] = value.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
option '-p', '--package [NAME]', 'The name of the package' do |value, options|
|
11
|
+
options[:package] = value
|
12
|
+
end
|
13
|
+
|
14
|
+
action do |context|
|
15
|
+
require 'hippo/package'
|
16
|
+
package, cli = Hippo::Package.setup_from_cli_context(context)
|
17
|
+
cli.preflight
|
18
|
+
|
19
|
+
exec(*package.helm('test', package.name, '--logs'))
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :'package:uninstall' do
|
4
|
+
desc 'Uninstall a package'
|
5
|
+
|
6
|
+
option '-h', '--hippofile [RECIPE]', 'The path to the Hippofile (defaults: ./Hippofile)' do |value, options|
|
7
|
+
options[:hippofile] = value.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
option '-p', '--package [NAME]', 'The name of the package' do |value, options|
|
11
|
+
options[:package] = value
|
12
|
+
end
|
13
|
+
|
14
|
+
action do |context|
|
15
|
+
require 'hippo/package'
|
16
|
+
package, cli = Hippo::Package.setup_from_cli_context(context)
|
17
|
+
cli.preflight
|
18
|
+
|
19
|
+
if package.installed?
|
20
|
+
puts "Uninstalling #{package.name} with Helm..."
|
21
|
+
package.uninstall
|
22
|
+
puts "#{package.name} uninstalled successfully"
|
23
|
+
else
|
24
|
+
puts "#{package.name} is not installed."
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :'package:upgrade' do
|
4
|
+
desc 'Upgrade a package'
|
5
|
+
|
6
|
+
option '-h', '--hippofile [RECIPE]', 'The path to the Hippofile (defaults: ./Hippofile)' do |value, options|
|
7
|
+
options[:hippofile] = value.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
option '-p', '--package [NAME]', 'The name of the package' do |value, options|
|
11
|
+
options[:package] = value
|
12
|
+
end
|
13
|
+
|
14
|
+
action do |context|
|
15
|
+
require 'hippo/package'
|
16
|
+
package, cli = Hippo::Package.setup_from_cli_context(context)
|
17
|
+
cli.preflight
|
18
|
+
|
19
|
+
if package.installed?
|
20
|
+
cli.apply_namespace
|
21
|
+
cli.apply_config
|
22
|
+
|
23
|
+
puts "Upgrading #{package.name} with Helm..."
|
24
|
+
package.upgrade
|
25
|
+
puts "#{package.name} upgraded successfully"
|
26
|
+
else
|
27
|
+
puts "#{package.name} is not installed. You probably want to use package:install first."
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :'package:values' do
|
4
|
+
desc 'Display the values file that will be used for all packages'
|
5
|
+
|
6
|
+
option '-h', '--hippofile [RECIPE]', 'The path to the Hippofile (defaults: ./Hippofile)' do |value, options|
|
7
|
+
options[:hippofile] = value.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
action do |context|
|
11
|
+
require 'hippo/cli'
|
12
|
+
cli = Hippo::CLI.setup(context)
|
13
|
+
cli.preflight
|
14
|
+
|
15
|
+
cli.stage.packages.values.each do |package|
|
16
|
+
puts "\e[33m#{'=' * 80}"
|
17
|
+
puts package.name
|
18
|
+
puts "#{'=' * 80}\e[0m"
|
19
|
+
puts package.final_values.to_yaml.sub(/\A---\n/, '')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/cli/prepare.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :prepare do
|
4
|
+
desc 'Prepare Kubernetes namespace (including installing all packages)'
|
5
|
+
|
6
|
+
option '-h', '--hippofile [RECIPE]', 'The path to the Hippofile (defaults: ./Hippofile)' do |value, options|
|
7
|
+
options[:hippofile] = value.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
action do |context|
|
11
|
+
require 'hippo/cli'
|
12
|
+
cli = Hippo::CLI.setup(context)
|
13
|
+
cli.preflight
|
14
|
+
cli.apply_namespace
|
15
|
+
cli.apply_config
|
16
|
+
cli.install_all_packages
|
17
|
+
end
|
18
|
+
end
|
data/cli/run.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :run do
|
4
|
+
desc 'Create and run a pod using the given image'
|
5
|
+
|
6
|
+
option '-h', '--hippofile [RECIPE]', 'The path to the Hippofile (defaults: ./Hippofile)' do |value, options|
|
7
|
+
options[:hippofile] = value.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
option '--command [COMMAND]', 'The command to run (defaults to /bin/bash)' do |value, options|
|
11
|
+
options[:command] = value.to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
action do |context|
|
15
|
+
require 'hippo/cli'
|
16
|
+
cli = Hippo::CLI.setup(context)
|
17
|
+
cli.preflight
|
18
|
+
|
19
|
+
image = cli.stage.images.values.first
|
20
|
+
raise Error, "No image exists at #{image.image_url}" unless image.exists?
|
21
|
+
|
22
|
+
command = context.options[:command] || '/bin/bash'
|
23
|
+
|
24
|
+
pod_name = 'hp-run-' + SecureRandom.hex(4)
|
25
|
+
kubectl_command = cli.stage.kubectl(
|
26
|
+
'run', pod_name,
|
27
|
+
'--restart', 'Never',
|
28
|
+
'--rm',
|
29
|
+
'--attach',
|
30
|
+
'-it',
|
31
|
+
'--image', image.image_url,
|
32
|
+
'--command', '--', command
|
33
|
+
)
|
34
|
+
puts "Starting pod #{pod_name} with #{image.image_url}"
|
35
|
+
exec *kubectl_command
|
36
|
+
end
|
37
|
+
end
|
data/cli/secrets.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :secrets do
|
4
|
+
desc 'Create/edit an encrypted secrets file'
|
5
|
+
|
6
|
+
option '-h', '--hippofile [RECIPE]', 'The path to the Hippofile (defaults: ./Hippofile)' do |value, options|
|
7
|
+
options[:hippofile] = value.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
action do |context|
|
11
|
+
require 'hippo/cli'
|
12
|
+
cli = Hippo::CLI.setup(context)
|
13
|
+
cli.preflight
|
14
|
+
|
15
|
+
manager = cli.stage.secret_manager
|
16
|
+
unless manager.key_available?
|
17
|
+
puts "\e[31mNo key has been published for this stage yet.\e[0m"
|
18
|
+
puts "Use `hippo #{cli.stage.name} key --generate` to generate one."
|
19
|
+
exit 2
|
20
|
+
end
|
21
|
+
|
22
|
+
manager.edit
|
23
|
+
end
|
24
|
+
end
|
data/cli/stages.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :stages do
|
4
|
+
desc 'List all stages that are available'
|
5
|
+
option '-h', '--hippofile [RECIPE]', 'The path to the Hippofile (defaults: ./Hippofile)' do |value, options|
|
6
|
+
options[:hippofile] = value.to_s
|
7
|
+
end
|
8
|
+
|
9
|
+
action do |context|
|
10
|
+
require 'hippo/manifest'
|
11
|
+
manifest = Hippo::Manifest.load_from_file(context.options[:hippofile] || './Hippofile')
|
12
|
+
|
13
|
+
if manifest.stages.empty?
|
14
|
+
puts 'There are no stages configured yet.'
|
15
|
+
puts 'Use the following command to create one:'
|
16
|
+
puts
|
17
|
+
puts ' hippo [name] create'
|
18
|
+
puts
|
19
|
+
exit 0
|
20
|
+
end
|
21
|
+
|
22
|
+
manifest.stages.each do |_, stage|
|
23
|
+
puts "- #{stage.name}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/cli/status.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :status do
|
4
|
+
desc 'Show current status of the namespace'
|
5
|
+
|
6
|
+
option '-h', '--hippofile [RECIPE]', 'The path to the Hippofile (defaults: ./Hippofile)' do |value, options|
|
7
|
+
options[:hippofile] = value.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
option '--full', 'Include all relevant objects in namespace' do |_value, options|
|
11
|
+
options[:full] = true
|
12
|
+
end
|
13
|
+
|
14
|
+
action do |context|
|
15
|
+
require 'hippo/cli'
|
16
|
+
cli = Hippo::CLI.setup(context)
|
17
|
+
cli.preflight
|
18
|
+
|
19
|
+
objects = %w[pods svc ingress deployments jobs statefulset]
|
20
|
+
objects += %w[secret cm pvc networkpolicy] if context.options[:full]
|
21
|
+
|
22
|
+
command = cli.stage.kubectl('get', objects.join(','))
|
23
|
+
exec *command
|
24
|
+
end
|
25
|
+
end
|
data/cli/vars.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :vars do
|
4
|
+
desc 'Show all variables available for use in this stage'
|
5
|
+
|
6
|
+
option '-h', '--hippofile [RECIPE]', 'The path to the Hippofile (defaults: ./Hippofile)' do |value, options|
|
7
|
+
options[:hippofile] = value.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
action do |context|
|
11
|
+
require 'hippo/cli'
|
12
|
+
cli = Hippo::CLI.setup(context)
|
13
|
+
cli.preflight
|
14
|
+
|
15
|
+
hash = cli.stage.template_vars.to_yaml.gsub(/^(\s*[\w\-]+)\:(.*)/) do
|
16
|
+
"\e[32m#{Regexp.last_match(1)}:\e[0m" + Regexp.last_match(2)
|
17
|
+
end
|
18
|
+
puts hash
|
19
|
+
end
|
20
|
+
end
|
data/cli/version.rb
ADDED
data/lib/hippo.rb
CHANGED
@@ -23,4 +23,16 @@ module Hippo
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
end
|
26
|
+
|
27
|
+
# Return the current kubectl context
|
28
|
+
#
|
29
|
+
# @return [String]
|
30
|
+
def self.current_kubectl_context
|
31
|
+
stdout, stderr, status = Open3.capture3('kubectl config current-context')
|
32
|
+
unless status.success?
|
33
|
+
raise Error, 'Could not determine current kubectl context'
|
34
|
+
end
|
35
|
+
|
36
|
+
stdout.strip
|
37
|
+
end
|
26
38
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'securerandom'
|
4
|
+
require 'secure_random_string'
|
5
|
+
|
6
|
+
module Hippo
|
7
|
+
class BootstrapParser
|
8
|
+
def self.parse(source)
|
9
|
+
new(source).parse
|
10
|
+
end
|
11
|
+
|
12
|
+
TYPES = %w[placeholder password].freeze
|
13
|
+
|
14
|
+
def initialize(source)
|
15
|
+
@source = source || {}
|
16
|
+
end
|
17
|
+
|
18
|
+
def parse
|
19
|
+
parse_hash(@source)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def parse_hash(hash)
|
25
|
+
hash.each_with_object({}) do |(key, value), hash|
|
26
|
+
new_key = key.sub(/\A_/, '')
|
27
|
+
hash[new_key] = if value.is_a?(Hash) && key[0] == '_'
|
28
|
+
parse_generator(value)
|
29
|
+
elsif value.is_a?(Hash)
|
30
|
+
parse_hash(value)
|
31
|
+
else
|
32
|
+
value.to_s
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def parse_generator(value)
|
38
|
+
case value['type']
|
39
|
+
when 'password'
|
40
|
+
password = SecureRandomString.new(value['length'] || 24).to_s
|
41
|
+
if value['addHashes']
|
42
|
+
{
|
43
|
+
'plain' => password,
|
44
|
+
'sha1' => Digest::SHA1.hexdigest(password),
|
45
|
+
'sha2' => Digest::SHA2.hexdigest(password),
|
46
|
+
'sha256' => Digest::SHA256.hexdigest(password)
|
47
|
+
}
|
48
|
+
else
|
49
|
+
password
|
50
|
+
end
|
51
|
+
when 'placeholder'
|
52
|
+
value['prefix'].to_s + 'xxx' + value['suffix'].to_s
|
53
|
+
when 'hex'
|
54
|
+
SecureRandom.hex(value['size'] ? value['size'].to_i : 16)
|
55
|
+
when 'random'
|
56
|
+
Base64.encode64(SecureRandom.random_bytes(value['size'] ? value['size'].to_i : 16)).strip
|
57
|
+
when nil
|
58
|
+
raise Error, "A 'type' must be provided for each generated item"
|
59
|
+
else
|
60
|
+
raise Error, "Invalid generator type #{value['type']}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/hippo/cli.rb
CHANGED
@@ -24,13 +24,12 @@ module Hippo
|
|
24
24
|
# @return [void]
|
25
25
|
def verify_image_existence
|
26
26
|
missing = 0
|
27
|
-
@
|
28
|
-
|
29
|
-
|
30
|
-
puts "Image for #{image.name} exists for #{image.url} (with tag #{commit})"
|
27
|
+
@stage.images.each do |_, image|
|
28
|
+
if image.exists?
|
29
|
+
puts "Image for #{image.name} exists at #{image.image_url}"
|
31
30
|
else
|
32
31
|
missing += 1
|
33
|
-
puts "No #{image.name} image at #{image.
|
32
|
+
puts "No #{image.name} image at #{image.image_url}"
|
34
33
|
end
|
35
34
|
end
|
36
35
|
|
@@ -39,6 +38,21 @@ module Hippo
|
|
39
38
|
end
|
40
39
|
end
|
41
40
|
|
41
|
+
# Run any checks that should be performed before running
|
42
|
+
# any optionation which might influence the environment
|
43
|
+
#
|
44
|
+
# @return [void]
|
45
|
+
def preflight
|
46
|
+
if @stage.context.nil?
|
47
|
+
puts "\e[33mStage does not specify a context. The current context specified"
|
48
|
+
puts "by the kubectl config will be used (#{Hippo.current_kubectl_context}).\e[0m"
|
49
|
+
puts
|
50
|
+
puts 'This is not recommended. Add a context name to your stage configuration.'
|
51
|
+
puts
|
52
|
+
exit 0 unless Util.confirm('Do you wish to continue?')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
42
56
|
# Apply the namespace configuration
|
43
57
|
#
|
44
58
|
# @return [void]
|
@@ -59,13 +73,28 @@ module Hippo
|
|
59
73
|
# @return [void]
|
60
74
|
def apply_config
|
61
75
|
apply(@stage.configs, 'configuration')
|
76
|
+
end
|
62
77
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
78
|
+
# Install all packages
|
79
|
+
#
|
80
|
+
# @return [void]
|
81
|
+
def install_all_packages
|
82
|
+
if @stage.packages.empty?
|
83
|
+
puts 'There are no packages to install'
|
84
|
+
return
|
68
85
|
end
|
86
|
+
|
87
|
+
@stage.packages.values.each do |package|
|
88
|
+
if package.installed?
|
89
|
+
puts "#{package.name} is already installed. Upgrading..."
|
90
|
+
package.upgrade
|
91
|
+
else
|
92
|
+
puts "Installing #{package.name} using Helm..."
|
93
|
+
package.install
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
puts "Finished with #{@stage.packages.size} #{@stage.packages.size == 1 ? 'package' : 'packages'}"
|
69
98
|
end
|
70
99
|
|
71
100
|
# Apply all services, ingresses and policies
|
@@ -96,7 +125,7 @@ module Hippo
|
|
96
125
|
deployment_id = SecureRandom.hex(6)
|
97
126
|
deployments = @stage.deployments
|
98
127
|
if deployments.empty?
|
99
|
-
puts 'There are no deployment objects defined
|
128
|
+
puts 'There are no deployment objects defined'
|
100
129
|
return true
|
101
130
|
end
|
102
131
|
|
@@ -141,8 +170,12 @@ module Hippo
|
|
141
170
|
private
|
142
171
|
|
143
172
|
def apply(objects, type)
|
144
|
-
|
145
|
-
|
173
|
+
if objects.empty?
|
174
|
+
puts "No #{type} objects found to apply"
|
175
|
+
else
|
176
|
+
puts "Applying #{objects.size} #{type} #{objects.size == 1 ? 'object' : 'objects'}"
|
177
|
+
@stage.apply(objects)
|
178
|
+
end
|
146
179
|
end
|
147
180
|
|
148
181
|
def run_jobs(type)
|
@@ -188,7 +221,7 @@ module Hippo
|
|
188
221
|
else
|
189
222
|
'❌'
|
190
223
|
end
|
191
|
-
puts " #{icon}
|
224
|
+
puts " #{icon} hippo #{@stage.name} kubectl -- logs job/#{job.name}"
|
192
225
|
end
|
193
226
|
puts
|
194
227
|
result
|