hippo-cli 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|