hippo-cli 1.0.0
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 +7 -0
- checksums.yaml.gz.sig +3 -0
- data/bin/hippo +36 -0
- data/cli/apply_config.rb +17 -0
- data/cli/apply_services.rb +15 -0
- data/cli/build.rb +16 -0
- data/cli/console.rb +31 -0
- data/cli/deploy.rb +45 -0
- data/cli/edit-secret.rb +45 -0
- data/cli/help.rb +21 -0
- data/cli/init.rb +25 -0
- data/cli/install.rb +44 -0
- data/cli/kubectl.rb +16 -0
- data/cli/objects.rb +34 -0
- data/cli/publish.rb +17 -0
- data/cli/secrets.rb +23 -0
- data/cli/status.rb +15 -0
- data/lib/hippo/build_spec.rb +32 -0
- data/lib/hippo/cli_steps.rb +274 -0
- data/lib/hippo/error.rb +18 -0
- data/lib/hippo/kubernetes.rb +200 -0
- data/lib/hippo/recipe.rb +126 -0
- data/lib/hippo/repository.rb +122 -0
- data/lib/hippo/secret.rb +165 -0
- data/lib/hippo/secret_manager.rb +99 -0
- data/lib/hippo/stage.rb +34 -0
- data/lib/hippo/util.rb +50 -0
- data/lib/hippo/version.rb +3 -0
- data/lib/hippo/yaml_part.rb +47 -0
- data/lib/hippo.rb +7 -0
- data/template/Hippofile +19 -0
- data/template/config/production/env-vars.yaml +7 -0
- data/template/deployments/web.yaml +29 -0
- data/template/deployments/worker.yaml +26 -0
- data/template/jobs/install/load-schema.yaml +22 -0
- data/template/jobs/upgrade/db-migration.yaml +22 -0
- data/template/services/main.ingress.yaml +13 -0
- data/template/services/web.svc.yaml +11 -0
- data/template/stages/production.yaml +6 -0
- data.tar.gz.sig +0 -0
- metadata +163 -0
- metadata.gz.sig +1 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 432cb14031538080436b685d9bffb44890296eb4ee2e001f47112d0a60cf10ae
|
4
|
+
data.tar.gz: 155f1cfd1ef594b9ad3e863bb40c3ca89df2bbbb77a5b3657ea6abd4dd324d39
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dbf149c3462eaf4b7b2fcba7afe450d3a60c472a671ba117a991db9db2ae7b94d3f72c2e2f708cc2d316f1dcadb00e5a60e637bdf3d9dc27af724e5f7595da33
|
7
|
+
data.tar.gz: ce1c8ab412478c7d4dc13a3d975d2734c2ad60a75dfd43e60b95fec1c9493a232036056977e395ee6da021a871fef51c7827419eb11395e6c296475a537601ce
|
checksums.yaml.gz.sig
ADDED
data/bin/hippo
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
|
5
|
+
|
6
|
+
require 'hippo'
|
7
|
+
require 'hippo/error'
|
8
|
+
require 'hippo/version'
|
9
|
+
require 'swamp/cli'
|
10
|
+
|
11
|
+
COMMANDS_WITHOUT_STAGE = %w[help init].freeze
|
12
|
+
|
13
|
+
begin
|
14
|
+
cli = Swamp::CLI.new(:hippo, version: Hippo::VERSION)
|
15
|
+
cli.load_from_directory(File.expand_path('../cli', __dir__))
|
16
|
+
|
17
|
+
args = ARGV.dup
|
18
|
+
stage = args.shift
|
19
|
+
command = args.shift
|
20
|
+
|
21
|
+
if COMMANDS_WITHOUT_STAGE.include?(stage) || (command.nil? && stage.nil?)
|
22
|
+
cli.dispatch([stage || 'help'])
|
23
|
+
elsif command.nil?
|
24
|
+
puts 'usage: hippo [STAGE] [COMMAND] {options}'
|
25
|
+
puts '(Be sure to specify the stage name before the command)'
|
26
|
+
exit 2
|
27
|
+
else
|
28
|
+
CURRENT_STAGE = stage
|
29
|
+
cli.dispatch([command] + args)
|
30
|
+
end
|
31
|
+
rescue Swamp::Error, Hippo::Error => e
|
32
|
+
warn "\e[31mError: #{e.message}\e[0m"
|
33
|
+
exit 2
|
34
|
+
rescue Interrupt
|
35
|
+
exit 3
|
36
|
+
end
|
data/cli/apply_config.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :'apply-config' do
|
4
|
+
desc 'Apply configuration'
|
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_steps'
|
12
|
+
steps = Hippo::CLISteps.setup(context)
|
13
|
+
steps.apply_namespace
|
14
|
+
steps.apply_config
|
15
|
+
steps.apply_secrets
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :'apply-services' do
|
4
|
+
desc 'Apply service configuration'
|
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_steps'
|
12
|
+
steps = Hippo::CLISteps.setup(context)
|
13
|
+
steps.apply_services
|
14
|
+
end
|
15
|
+
end
|
data/cli/build.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :build do
|
4
|
+
desc 'Build an image for the given 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_steps'
|
12
|
+
steps = Hippo::CLISteps.setup(context)
|
13
|
+
steps.prepare_repository
|
14
|
+
steps.build
|
15
|
+
end
|
16
|
+
end
|
data/cli/console.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :console do
|
4
|
+
desc 'Open a console based on the configuration'
|
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 '-d', '--deployment [NAME]', 'The name of the deployment to use' do |value, options|
|
11
|
+
options[:deployment] = value.to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
option '-c', '--command [NAME]', 'The command to run' do |value, options|
|
15
|
+
options[:command] = value.to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
action do |context|
|
19
|
+
require 'hippo/cli_steps'
|
20
|
+
cli = Hippo::CLISteps.setup(context)
|
21
|
+
|
22
|
+
if cli.recipe.console.nil?
|
23
|
+
raise Error, 'No console configuration has been provided in Hippofile'
|
24
|
+
end
|
25
|
+
|
26
|
+
time = Time.now.to_i
|
27
|
+
deployment_name = context.options[:deployment] || cli.recipe.console['deployment']
|
28
|
+
command = context.options[:command] || cli.recipe.console['command'] || 'bash'
|
29
|
+
exec cli.stage.kubectl("exec -it deployment/#{deployment_name} -- #{command}")
|
30
|
+
end
|
31
|
+
end
|
data/cli/deploy.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :deploy do
|
4
|
+
desc 'Deploy the application to Kubernetes (including image build/push)'
|
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 '--no-jobs', 'Do not run the deploy jobs' do |_value, options|
|
11
|
+
options[:jobs] = false
|
12
|
+
end
|
13
|
+
|
14
|
+
option '--no-build', 'Do not build the images' do |_value, options|
|
15
|
+
options[:build] = false
|
16
|
+
end
|
17
|
+
|
18
|
+
action do |context|
|
19
|
+
require 'hippo/cli_steps'
|
20
|
+
steps = Hippo::CLISteps.setup(context)
|
21
|
+
if context.options[:build] == false
|
22
|
+
commit = steps.recipe.repository.commit_for_branch(steps.stage.branch)
|
23
|
+
puts 'Not building an image and just hoping one exists for current commit.'
|
24
|
+
puts "Using #{commit.objectish} from #{steps.stage.branch}"
|
25
|
+
steps.prepare_repository(fetch: false)
|
26
|
+
else
|
27
|
+
steps.prepare_repository
|
28
|
+
steps.build
|
29
|
+
steps.publish
|
30
|
+
end
|
31
|
+
|
32
|
+
steps.apply_namespace
|
33
|
+
steps.apply_config
|
34
|
+
steps.apply_secrets
|
35
|
+
|
36
|
+
unless context.options[:jobs] == false
|
37
|
+
if steps.run_deploy_jobs == false
|
38
|
+
raise Hippo::Error, 'Not all jobs completed successfully. Cannot continue with deployment.'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
steps.apply_services
|
43
|
+
steps.deploy
|
44
|
+
end
|
45
|
+
end
|
data/cli/edit-secret.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :'edit-secret' do
|
4
|
+
desc 'Create/edit an encrypted secrets file'
|
5
|
+
|
6
|
+
option '--create-key', 'Create a new encryption key if missing' do |_value, options|
|
7
|
+
options[:create_key] = true
|
8
|
+
end
|
9
|
+
|
10
|
+
action do |context|
|
11
|
+
require 'hippo/cli_steps'
|
12
|
+
steps = Hippo::CLISteps.setup(context)
|
13
|
+
|
14
|
+
secret_name = context.args[0]
|
15
|
+
raise Hippo::Error, 'You must provide a secret name' if secret_name.nil?
|
16
|
+
|
17
|
+
require 'hippo/secret_manager'
|
18
|
+
manager = Hippo::SecretManager.new(steps.recipe, steps.stage)
|
19
|
+
if !manager.key_available? && context.options[:create_key]
|
20
|
+
manager.create_key
|
21
|
+
elsif !manager.key_available?
|
22
|
+
puts "\e[31mNo key has been published for this stage yet. You can create"
|
23
|
+
puts "a key automatically by adding --create-key to this command.\e[0m"
|
24
|
+
exit 2
|
25
|
+
elsif context.options[:create_key]
|
26
|
+
puts "\e[31mThe --create-key option can only be provided when a key has not already"
|
27
|
+
puts "been generated. Remove the key from the Kubernetes API to regenerate.\e[0m"
|
28
|
+
exit 2
|
29
|
+
end
|
30
|
+
|
31
|
+
secret = manager.secret(secret_name)
|
32
|
+
if secret.exists?
|
33
|
+
secret.edit
|
34
|
+
else
|
35
|
+
puts "No secret exists at #{secret.path}. Would you like to create one?"
|
36
|
+
response = STDIN.gets.strip.downcase.strip
|
37
|
+
if %w[y yes please].include?(response)
|
38
|
+
secret.create
|
39
|
+
secret.edit
|
40
|
+
else
|
41
|
+
puts 'Not a problem. You can make it later.'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/cli/help.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :help do
|
4
|
+
desc 'Display this help text'
|
5
|
+
action do |context|
|
6
|
+
puts "\e[35mWelcome to Hippo v#{Hippo::VERSION}\e[0m"
|
7
|
+
puts 'For documentation see https://adam.ac/hippo.'
|
8
|
+
puts
|
9
|
+
|
10
|
+
puts 'The following commands are supported:'
|
11
|
+
puts
|
12
|
+
context.cli.commands.sort_by { |k, _v| k.to_s }.each do |_, command|
|
13
|
+
if command.description
|
14
|
+
puts " \e[36m#{command.name.to_s.ljust(18, ' ')}\e[0m #{command.description}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
puts
|
18
|
+
puts 'For details for the options available for each command, use the --help option.'
|
19
|
+
puts "For example 'hippo build --help'."
|
20
|
+
end
|
21
|
+
end
|
data/cli/init.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :init do
|
4
|
+
desc 'Initialize a new application to use Hippo'
|
5
|
+
|
6
|
+
action do |context|
|
7
|
+
require 'fileutils'
|
8
|
+
|
9
|
+
path = context.args[0]
|
10
|
+
|
11
|
+
if path.nil?
|
12
|
+
raise Error, 'You must pass the name of the directory you wish to create your Hippo manifest'
|
13
|
+
end
|
14
|
+
|
15
|
+
root = File.expand_path(path)
|
16
|
+
template_root = File.join(File.expand_path('../', __dir__), 'template')
|
17
|
+
|
18
|
+
raise Hippo::Error, "File already exists at #{root}" if File.exist?(root)
|
19
|
+
|
20
|
+
FileUtils.mkdir_p(path)
|
21
|
+
FileUtils.cp_r(File.join(template_root, '.'), root)
|
22
|
+
|
23
|
+
puts "Initialized Hippo manifest in #{root}"
|
24
|
+
end
|
25
|
+
end
|
data/cli/install.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :install do
|
4
|
+
desc 'Run installation jobs for the application'
|
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 '--no-build', 'Do not build the images' do |_value, options|
|
11
|
+
options[:build] = false
|
12
|
+
end
|
13
|
+
|
14
|
+
option '--no-deploy', 'Do not deploy after install' do |_value, options|
|
15
|
+
options[:deploy] = false
|
16
|
+
end
|
17
|
+
|
18
|
+
action do |context|
|
19
|
+
require 'hippo/cli_steps'
|
20
|
+
steps = Hippo::CLISteps.setup(context)
|
21
|
+
if context.options[:build] == false
|
22
|
+
commit = steps.recipe.repository.commit_for_branch(steps.stage.branch)
|
23
|
+
puts 'Not building an image and just hoping one exists for current commit.'
|
24
|
+
steps.prepare_repository(fetch: false)
|
25
|
+
else
|
26
|
+
steps.prepare_repository
|
27
|
+
steps.build
|
28
|
+
steps.publish
|
29
|
+
end
|
30
|
+
|
31
|
+
steps.apply_namespace
|
32
|
+
steps.apply_config
|
33
|
+
steps.apply_secrets
|
34
|
+
|
35
|
+
if steps.run_install_jobs == false
|
36
|
+
raise Hippo::Error, 'Not all installation jobs completed successfully. Cannot continue to deploy.'
|
37
|
+
end
|
38
|
+
|
39
|
+
unless context.options[:deploy] == false
|
40
|
+
steps.apply_services
|
41
|
+
steps.deploy
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/cli/kubectl.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :kubectl do
|
4
|
+
desc 'Execute kubectl commands with the correct namespace for the 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_steps'
|
12
|
+
cli = Hippo::CLISteps.setup(context)
|
13
|
+
ARGV.shift
|
14
|
+
exec cli.stage.kubectl(*ARGV)
|
15
|
+
end
|
16
|
+
end
|
data/cli/objects.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :objects do
|
4
|
+
desc 'Build and publish an image for the given 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
|
+
option '--types [TYPES]', 'The types of objects you wish to see' do |value, options|
|
11
|
+
options[:types] = value.split(/,/)
|
12
|
+
end
|
13
|
+
|
14
|
+
action do |context|
|
15
|
+
require 'hippo/cli_steps'
|
16
|
+
steps = Hippo::CLISteps.setup(context)
|
17
|
+
commit = steps.prepare_repository(fetch: false)
|
18
|
+
|
19
|
+
if context.options[:types].nil? || context.options[:types].include?('all')
|
20
|
+
types = Hippo::Kubernetes::OBJECT_DIRECTORY_NAMES
|
21
|
+
else
|
22
|
+
types = context.options[:types]
|
23
|
+
end
|
24
|
+
|
25
|
+
objects = []
|
26
|
+
types.each do |type|
|
27
|
+
next unless Hippo::Kubernetes::OBJECT_DIRECTORY_NAMES.include?(type)
|
28
|
+
|
29
|
+
objects |= steps.recipe.kubernetes.objects(type, steps.stage, commit)
|
30
|
+
end
|
31
|
+
|
32
|
+
puts objects.map { |o| o.hash.to_yaml }
|
33
|
+
end
|
34
|
+
end
|
data/cli/publish.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :publish do
|
4
|
+
desc 'Build and publish an image for the given 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_steps'
|
12
|
+
steps = Hippo::CLISteps.setup(context)
|
13
|
+
steps.prepare_repository
|
14
|
+
steps.build
|
15
|
+
steps.publish
|
16
|
+
end
|
17
|
+
end
|
data/cli/secrets.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :secrets do
|
4
|
+
desc 'View all secrets'
|
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_steps'
|
12
|
+
cli = Hippo::CLISteps.setup(context)
|
13
|
+
|
14
|
+
require 'hippo/secret_manager'
|
15
|
+
manager = Hippo::SecretManager.new(cli.recipe, cli.stage)
|
16
|
+
unless manager.key_available?
|
17
|
+
puts "\e[31mNo key has been published for this stage yet.\e[0m"
|
18
|
+
exit 2
|
19
|
+
end
|
20
|
+
|
21
|
+
puts manager.secrets.map(&:to_editable_yaml)
|
22
|
+
end
|
23
|
+
end
|
data/cli/status.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :status do
|
4
|
+
desc 'Print status information from Kubernetes'
|
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_steps'
|
12
|
+
cli = Hippo::CLISteps.setup(context)
|
13
|
+
exec cli.stage.kubectl('get pods,deployments,job,statefulset,pvc,svc,ingress')
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hippo
|
4
|
+
class BuildSpec
|
5
|
+
attr_reader :name
|
6
|
+
|
7
|
+
def initialize(recipe, name, options)
|
8
|
+
@recipe = recipe
|
9
|
+
@name = name
|
10
|
+
@options = options
|
11
|
+
end
|
12
|
+
|
13
|
+
def dockerfile
|
14
|
+
@options['dockerfile'] || 'Dockerfile'
|
15
|
+
end
|
16
|
+
|
17
|
+
def image_name
|
18
|
+
@options['image-name']
|
19
|
+
end
|
20
|
+
|
21
|
+
def image_name_for_commit(commit_ref)
|
22
|
+
"#{image_name}:#{commit_ref}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def template_vars
|
26
|
+
{
|
27
|
+
'dockerfile' => dockerfile,
|
28
|
+
'image-name' => image_name
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|