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 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
@@ -0,0 +1,3 @@
1
+ p3�<x�H񏦀y�::��Ej�>��*@�x '=�����WeW�n~�T�<�t�s�� 䯔�c��[����S�^|�7�~s@��X���`���,D��W��>�n�
2
+ 4m�-S�nFr��F�]<���u��`R���y�$�� �D�q�K��}�aY��%D��3k�|�3}�~���*���ѐC%�K<��<cq��d��j� RFB�T�J
3
+ %|�2�ɰ�� E��E�-g,ں ��B4���s��
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
@@ -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
@@ -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