hippo-cli 1.1.2 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/bin/hippo +1 -1
- data/cli/apply_config.rb +0 -4
- data/cli/apply_services.rb +0 -4
- data/cli/console.rb +0 -4
- data/cli/create.rb +9 -13
- data/cli/deploy.rb +0 -4
- data/cli/install.rb +0 -4
- data/cli/key.rb +1 -4
- data/cli/kubectl.rb +0 -4
- data/cli/logs.rb +0 -4
- data/cli/objects.rb +0 -4
- data/cli/package_install.rb +0 -4
- data/cli/package_list.rb +0 -4
- data/cli/package_notes.rb +0 -4
- data/cli/package_test.rb +0 -4
- data/cli/package_uninstall.rb +0 -4
- data/cli/package_upgrade.rb +0 -4
- data/cli/package_values.rb +0 -4
- data/cli/prepare.rb +0 -4
- data/cli/readme.rb +18 -0
- data/cli/run.rb +0 -4
- data/cli/secrets.rb +0 -4
- data/cli/setup.rb +71 -0
- data/cli/stages.rb +4 -7
- data/cli/status.rb +0 -4
- data/cli/tidy.rb +33 -0
- data/cli/update.rb +22 -0
- data/cli/vars.rb +0 -4
- data/lib/hippo/cli.rb +31 -27
- data/lib/hippo/image.rb +1 -0
- data/lib/hippo/manifest.rb +13 -17
- data/lib/hippo/repository_tag.rb +3 -2
- data/lib/hippo/secret_manager.rb +20 -19
- data/lib/hippo/stage.rb +75 -39
- data/lib/hippo/util.rb +61 -1
- data/lib/hippo/version.rb +1 -1
- data/lib/hippo/working_directory.rb +180 -0
- data/lib/hippo.rb +7 -0
- data/template/Hippofile +1 -2
- data.tar.gz.sig +0 -0
- metadata +7 -2
- metadata.gz.sig +0 -0
data/lib/hippo/cli.rb
CHANGED
@@ -3,28 +3,32 @@
|
|
3
3
|
require 'securerandom'
|
4
4
|
require 'hippo/manifest'
|
5
5
|
require 'hippo/deployment_monitor'
|
6
|
+
require 'hippo/working_directory'
|
6
7
|
|
7
8
|
module Hippo
|
8
9
|
class CLI
|
9
|
-
attr_reader :
|
10
|
+
attr_reader :wd
|
10
11
|
attr_reader :stage
|
11
12
|
|
12
13
|
# Initialize a new CLI instance
|
13
14
|
#
|
14
|
-
# @param
|
15
|
-
# @param stage [Hippo::Stage]
|
15
|
+
# @param wd [Hippo::WorkingDirectory]
|
16
16
|
# @return [Hippo::CLI]
|
17
|
-
def initialize(
|
18
|
-
@
|
17
|
+
def initialize(wd, stage)
|
18
|
+
@wd = wd
|
19
19
|
@stage = stage
|
20
20
|
end
|
21
21
|
|
22
|
+
def manifest
|
23
|
+
wd.manifest
|
24
|
+
end
|
25
|
+
|
22
26
|
# Verify image existence
|
23
27
|
#
|
24
28
|
# @return [void]
|
25
29
|
def verify_image_existence
|
26
30
|
missing = 0
|
27
|
-
|
31
|
+
stage.images.each do |_, image|
|
28
32
|
if image.exists?
|
29
33
|
puts "Image for #{image.name} exists at #{image.image_url}"
|
30
34
|
else
|
@@ -43,7 +47,7 @@ module Hippo
|
|
43
47
|
#
|
44
48
|
# @return [void]
|
45
49
|
def preflight
|
46
|
-
if
|
50
|
+
if stage.context.nil?
|
47
51
|
puts "\e[33mStage does not specify a context. The current context specified"
|
48
52
|
puts "by the kubectl config will be used (#{Hippo.current_kubectl_context}).\e[0m"
|
49
53
|
puts
|
@@ -61,9 +65,9 @@ module Hippo
|
|
61
65
|
{
|
62
66
|
'kind' => 'Namespace',
|
63
67
|
'apiVersion' => 'v1',
|
64
|
-
'metadata' => { 'name' =>
|
68
|
+
'metadata' => { 'name' => stage.namespace, 'labels' => { 'name' => stage.namespace } }
|
65
69
|
},
|
66
|
-
|
70
|
+
stage
|
67
71
|
)
|
68
72
|
apply([od], 'namespace')
|
69
73
|
end
|
@@ -72,19 +76,19 @@ module Hippo
|
|
72
76
|
#
|
73
77
|
# @return [void]
|
74
78
|
def apply_config
|
75
|
-
apply(
|
79
|
+
apply(stage.configs, 'configuration')
|
76
80
|
end
|
77
81
|
|
78
82
|
# Install all packages
|
79
83
|
#
|
80
84
|
# @return [void]
|
81
85
|
def install_all_packages
|
82
|
-
if
|
86
|
+
if stage.packages.empty?
|
83
87
|
puts 'There are no packages to install'
|
84
88
|
return
|
85
89
|
end
|
86
90
|
|
87
|
-
|
91
|
+
stage.packages.values.each do |package|
|
88
92
|
if package.installed?
|
89
93
|
puts "#{package.name} is already installed. Upgrading..."
|
90
94
|
package.upgrade
|
@@ -94,14 +98,14 @@ module Hippo
|
|
94
98
|
end
|
95
99
|
end
|
96
100
|
|
97
|
-
puts "Finished with #{
|
101
|
+
puts "Finished with #{stage.packages.size} #{stage.packages.size == 1 ? 'package' : 'packages'}"
|
98
102
|
end
|
99
103
|
|
100
104
|
# Apply all services, ingresses and policies
|
101
105
|
#
|
102
106
|
# @return [void]
|
103
107
|
def apply_services
|
104
|
-
apply(
|
108
|
+
apply(stage.services, 'service')
|
105
109
|
end
|
106
110
|
|
107
111
|
# Run all deploy jobs
|
@@ -123,7 +127,7 @@ module Hippo
|
|
123
127
|
# @return [void]
|
124
128
|
def deploy
|
125
129
|
deployment_id = SecureRandom.hex(6)
|
126
|
-
deployments =
|
130
|
+
deployments = stage.deployments
|
127
131
|
if deployments.empty?
|
128
132
|
puts 'There are no deployment objects defined'
|
129
133
|
return true
|
@@ -138,7 +142,7 @@ module Hippo
|
|
138
142
|
apply(deployments, 'deployment')
|
139
143
|
puts 'Waiting for all deployments to roll out...'
|
140
144
|
|
141
|
-
monitor = DeploymentMonitor.new(
|
145
|
+
monitor = DeploymentMonitor.new(stage, deployment_id)
|
142
146
|
monitor.on_success do |poll|
|
143
147
|
if poll.replica_sets.size == 1
|
144
148
|
puts "\e[32mDeployment rolled out successfully\e[0m"
|
@@ -158,8 +162,8 @@ module Hippo
|
|
158
162
|
poll.pending.each do |rs|
|
159
163
|
puts
|
160
164
|
name = rs.name.split('-').first
|
161
|
-
puts " hippo #{
|
162
|
-
puts " hippo #{
|
165
|
+
puts " hippo #{stage.name} kubectl -- describe deployment \e[35m#{name}\e[0m"
|
166
|
+
puts " hippo #{stage.name} kubectl -- logs deployment/\e[35m#{name}\e[0m --all-containers"
|
163
167
|
end
|
164
168
|
puts
|
165
169
|
end
|
@@ -174,25 +178,25 @@ module Hippo
|
|
174
178
|
puts "No #{type} objects found to apply"
|
175
179
|
else
|
176
180
|
puts "Applying #{objects.size} #{type} #{objects.size == 1 ? 'object' : 'objects'}"
|
177
|
-
|
181
|
+
stage.apply(objects)
|
178
182
|
end
|
179
183
|
end
|
180
184
|
|
181
185
|
def run_jobs(type)
|
182
186
|
puts "Running #{type} jobs"
|
183
|
-
jobs =
|
187
|
+
jobs = stage.jobs(type)
|
184
188
|
if jobs.empty?
|
185
189
|
puts "There are no #{type} jobs to run"
|
186
190
|
return true
|
187
191
|
end
|
188
192
|
|
189
193
|
jobs.each do |job|
|
190
|
-
|
194
|
+
stage.delete('job', job.name)
|
191
195
|
end
|
192
196
|
|
193
197
|
applied_jobs = apply(jobs, 'deploy job')
|
194
198
|
|
195
|
-
timeout, jobs =
|
199
|
+
timeout, jobs = stage.wait_for_jobs(applied_jobs.keys)
|
196
200
|
success_jobs = []
|
197
201
|
failed_jobs = []
|
198
202
|
jobs.each do |job|
|
@@ -221,22 +225,22 @@ module Hippo
|
|
221
225
|
else
|
222
226
|
'❌'
|
223
227
|
end
|
224
|
-
puts " #{icon} hippo #{
|
228
|
+
puts " #{icon} hippo #{stage.name} kubectl -- logs job/#{job.name}"
|
225
229
|
end
|
226
230
|
puts
|
227
231
|
result
|
228
232
|
end
|
229
233
|
|
230
234
|
class << self
|
231
|
-
def setup(
|
232
|
-
|
235
|
+
def setup(_context)
|
236
|
+
wd = Hippo::WorkingDirectory.new
|
233
237
|
|
234
|
-
stage =
|
238
|
+
stage = wd.stages[CURRENT_STAGE]
|
235
239
|
if stage.nil?
|
236
240
|
raise Error, "Invalid stage name `#{CURRENT_STAGE}`. Check this has been defined in in your stages directory with a matching name?"
|
237
241
|
end
|
238
242
|
|
239
|
-
new(
|
243
|
+
new(wd, stage)
|
240
244
|
end
|
241
245
|
end
|
242
246
|
end
|
data/lib/hippo/image.rb
CHANGED
data/lib/hippo/manifest.rb
CHANGED
@@ -51,6 +51,18 @@ module Hippo
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
+
def readme
|
55
|
+
return @readme if instance_variable_defined?('@readme')
|
56
|
+
|
57
|
+
path = File.join(@root, 'readme.txt')
|
58
|
+
unless File.file?(path)
|
59
|
+
@readme = nil
|
60
|
+
return
|
61
|
+
end
|
62
|
+
|
63
|
+
@readme = File.read(path)
|
64
|
+
end
|
65
|
+
|
54
66
|
def template_vars
|
55
67
|
{
|
56
68
|
'name' => name
|
@@ -63,29 +75,13 @@ module Hippo
|
|
63
75
|
@options['images']
|
64
76
|
end
|
65
77
|
|
66
|
-
# Load all stages that are available in the manifest
|
67
|
-
#
|
68
|
-
# @return [Hash<Symbol, Hippo::Stage>]
|
69
|
-
def stages
|
70
|
-
objects('stages').each_with_object({}) do |(_, objects), hash|
|
71
|
-
objects.each do |obj|
|
72
|
-
stage = Stage.new(self, obj)
|
73
|
-
hash[stage.name] = stage
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
78
|
# Load all YAML objects at a given path and return them.
|
79
79
|
#
|
80
80
|
# @param path [String]
|
81
81
|
# @param decorator [Proc] an optional parser to run across the raw YAML file
|
82
82
|
# @return [Array<Hash>]
|
83
83
|
def objects(path, decorator: nil)
|
84
|
-
|
85
|
-
files.each_with_object({}) do |path, objects|
|
86
|
-
file = Util.load_yaml_from_file(path, decorator: decorator)
|
87
|
-
objects[path.sub(%r{\A#{@root}/}, '')] = file
|
88
|
-
end
|
84
|
+
Util.load_objects_from_path(File.join(@root, path, '*.{yaml,yml}'), decorator: decorator)
|
89
85
|
end
|
90
86
|
end
|
91
87
|
end
|
data/lib/hippo/repository_tag.rb
CHANGED
@@ -30,8 +30,9 @@ module Hippo
|
|
30
30
|
return nil if @options['url'].nil?
|
31
31
|
|
32
32
|
@remote_refs ||= begin
|
33
|
-
|
34
|
-
|
33
|
+
Util.action "Getting remote refs from #{@options['url']}..." do
|
34
|
+
Git.ls_remote(@options['url'])
|
35
|
+
end
|
35
36
|
end
|
36
37
|
end
|
37
38
|
end
|
data/lib/hippo/secret_manager.rb
CHANGED
@@ -15,17 +15,7 @@ module Hippo
|
|
15
15
|
CIPHER = OpenSSL::Cipher.new('aes-256-gcm')
|
16
16
|
|
17
17
|
def path
|
18
|
-
File.join(@stage.
|
19
|
-
end
|
20
|
-
|
21
|
-
def secret(name)
|
22
|
-
Secret.new(self, name)
|
23
|
-
end
|
24
|
-
|
25
|
-
def secrets
|
26
|
-
Dir[File.join(root, '*.{yml,yaml}')].map do |path|
|
27
|
-
secret(path.split('/').last.sub(/\.ya?ml\z/, ''))
|
28
|
-
end
|
18
|
+
File.join(@stage.config_root, 'secrets.yaml')
|
29
19
|
end
|
30
20
|
|
31
21
|
# Download the current key from the Kubernetes API and set it as the
|
@@ -35,13 +25,24 @@ module Hippo
|
|
35
25
|
def download_key
|
36
26
|
return if @key
|
37
27
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
28
|
+
Util.action 'Downloading secret encryiption key...' do |state|
|
29
|
+
begin
|
30
|
+
value = @stage.get('secret', 'hippo-secret-key').first
|
31
|
+
|
32
|
+
if value.nil? || value.dig('data', 'key').nil?
|
33
|
+
state.call('not found')
|
34
|
+
return
|
35
|
+
end
|
36
|
+
|
37
|
+
@key = Base64.decode64(Base64.decode64(value['data']['key']))
|
38
|
+
rescue Hippo::Error => e
|
39
|
+
if e.message =~ /not found/
|
40
|
+
state.call('not found')
|
41
|
+
else
|
42
|
+
raise
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
45
46
|
end
|
46
47
|
|
47
48
|
# Is there a key availale in this manager?
|
@@ -118,7 +119,7 @@ module Hippo
|
|
118
119
|
|
119
120
|
return if exists?
|
120
121
|
|
121
|
-
yaml = { 'example' => 'This is an example
|
122
|
+
yaml = { 'example' => 'This is an example secret2!' }.to_yaml
|
122
123
|
FileUtils.mkdir_p(File.dirname(path))
|
123
124
|
File.open(path, 'w') { |f| f.write(encrypt(yaml)) }
|
124
125
|
end
|
data/lib/hippo/stage.rb
CHANGED
@@ -8,13 +8,19 @@ require 'hippo/liquid_filters'
|
|
8
8
|
|
9
9
|
module Hippo
|
10
10
|
class Stage
|
11
|
-
attr_reader :
|
11
|
+
attr_reader :wd
|
12
|
+
attr_reader :config_root
|
12
13
|
|
13
|
-
def initialize(
|
14
|
-
@
|
14
|
+
def initialize(wd, config_root, options)
|
15
|
+
@wd = wd
|
16
|
+
@config_root = config_root
|
15
17
|
@options = options
|
16
18
|
end
|
17
19
|
|
20
|
+
def manifest
|
21
|
+
wd.manifest
|
22
|
+
end
|
23
|
+
|
18
24
|
def name
|
19
25
|
@options['name']
|
20
26
|
end
|
@@ -40,7 +46,7 @@ module Hippo
|
|
40
46
|
end
|
41
47
|
|
42
48
|
def images
|
43
|
-
@images ||=
|
49
|
+
@images ||= manifest.images.deep_merge(@options['images'] || {}).each_with_object({}) do |(key, image), hash|
|
44
50
|
hash[key] = Image.new(key, image)
|
45
51
|
end
|
46
52
|
end
|
@@ -49,14 +55,14 @@ module Hippo
|
|
49
55
|
def template_vars
|
50
56
|
@template_vars ||= begin
|
51
57
|
{
|
52
|
-
'manifest' =>
|
58
|
+
'manifest' => manifest.template_vars,
|
53
59
|
'stage-name' => name,
|
54
60
|
'branch' => branch,
|
55
61
|
'image-tag' => image_tag,
|
56
62
|
'namespace' => namespace,
|
57
63
|
'context' => context,
|
58
64
|
'images' => images.values.each_with_object({}) { |image, hash| hash[image.name] = image.template_vars },
|
59
|
-
'config' =>
|
65
|
+
'config' => manifest.config.deep_merge(config),
|
60
66
|
'secrets' => secret_manager.all
|
61
67
|
}
|
62
68
|
end
|
@@ -75,8 +81,44 @@ module Hippo
|
|
75
81
|
end
|
76
82
|
end
|
77
83
|
|
84
|
+
def readme
|
85
|
+
return unless manifest.readme
|
86
|
+
|
87
|
+
decorator.call(manifest.readme)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Return an array of objects that currently exist on the kubernetesa
|
91
|
+
# API.
|
92
|
+
#
|
93
|
+
# @return [Array<Hash>]
|
94
|
+
def live_objects(pruneable_only: false)
|
95
|
+
los = get(all_objects.keys.join(','), '--selector', 'app.kubernetes.io/managed-by=hippo')
|
96
|
+
los.each_with_object([]) do |live_obj, array|
|
97
|
+
local = all_objects.dig(live_obj.kind, live_obj.name)
|
98
|
+
pruneable = local.nil? && (live_obj.kind != 'Secret' && live_obj.name != 'hippo-secret-key')
|
99
|
+
|
100
|
+
next if pruneable_only && !pruneable
|
101
|
+
|
102
|
+
array << {
|
103
|
+
live: live_obj,
|
104
|
+
local: local,
|
105
|
+
pruneable: pruneable
|
106
|
+
}
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Remove any objects which are prunable
|
111
|
+
#
|
112
|
+
# @return [void]
|
113
|
+
def delete_pruneable_objects
|
114
|
+
live_objects(pruneable_only: true).each do |object|
|
115
|
+
object = object[:live]
|
116
|
+
delete(object.kind, object.name)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
78
120
|
def objects(path)
|
79
|
-
|
121
|
+
manifest.objects(path, decorator: decorator)
|
80
122
|
end
|
81
123
|
|
82
124
|
def secret_manager
|
@@ -112,6 +154,19 @@ module Hippo
|
|
112
154
|
@jobs[type] ||= Util.create_object_definitions(objects("jobs/#{type}"), self)
|
113
155
|
end
|
114
156
|
|
157
|
+
# Return an array of all objects that should be managed by Hippo
|
158
|
+
#
|
159
|
+
# @return [Hash]
|
160
|
+
def all_objects
|
161
|
+
@all_objects ||= begin
|
162
|
+
all = (deployments | services | configs | jobs('install') | jobs('deploy'))
|
163
|
+
all.each_with_object({}) do |object, hash|
|
164
|
+
hash[object.kind] ||= {}
|
165
|
+
hash[object.kind][object.name] = object
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
115
170
|
# Return a hash of all packages available in the stage
|
116
171
|
#
|
117
172
|
# @return [Hash<String, Hippo::Package>]
|
@@ -145,33 +200,17 @@ module Hippo
|
|
145
200
|
# @param objects [Array<Hippo::ObjectDefinition>]
|
146
201
|
# @return [Hash]
|
147
202
|
def apply(objects)
|
148
|
-
yaml_to_apply = objects.map(&:yaml_to_apply).join("\n")
|
149
|
-
|
150
203
|
command = ['kubectl']
|
151
204
|
command += ['--context', context] if context
|
152
205
|
command += ['apply', '-f', '-']
|
153
|
-
Open3.popen3(command.join(' ')) do |stdin, stdout, stderr, wt|
|
154
|
-
stdin.puts yaml_to_apply
|
155
|
-
stdin.close
|
156
206
|
|
157
|
-
|
158
|
-
stderr = stderr.read.strip
|
207
|
+
yaml_to_apply = objects.map(&:yaml_to_apply).join("\n")
|
159
208
|
|
160
|
-
|
161
|
-
stdout.split("\n").each_with_object({}) do |line, hash|
|
162
|
-
next unless line =~ %r{\A([\w\/\-\.]+) (\w+)\z}
|
209
|
+
stdout, stderr, status = Open3.capture3(command.join(' '), stdin_data: yaml_to_apply + "\n")
|
163
210
|
|
164
|
-
|
165
|
-
status = Regexp.last_match(2)
|
166
|
-
hash[object] = status
|
211
|
+
raise Error, "[kubectl] #{stderr}" unless status.success?
|
167
212
|
|
168
|
-
|
169
|
-
puts "\e[37m====> #{object} #{status}\e[0m"
|
170
|
-
end
|
171
|
-
else
|
172
|
-
raise Error, "[kubectl] #{stderr}"
|
173
|
-
end
|
174
|
-
end
|
213
|
+
Util.parse_kubectl_apply_lines(stdout)
|
175
214
|
end
|
176
215
|
|
177
216
|
# Get some data from the kubernetes API
|
@@ -194,19 +233,16 @@ module Hippo
|
|
194
233
|
# @return [Boolean]
|
195
234
|
def delete(*names)
|
196
235
|
command = kubectl('delete', *names)
|
197
|
-
Open3.
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
236
|
+
stdout, stderr, status = Open3.capture3(*command)
|
237
|
+
if status.success?
|
238
|
+
Util.parse_kubectl_apply_lines(stdout)
|
239
|
+
true
|
240
|
+
else
|
241
|
+
stderr = stderr.read
|
242
|
+
if stderr =~ /\" not found$/
|
243
|
+
false
|
203
244
|
else
|
204
|
-
|
205
|
-
if stderr =~ /\" not found$/
|
206
|
-
false
|
207
|
-
else
|
208
|
-
raise Error, "[kutectl] #{stderr}"
|
209
|
-
end
|
245
|
+
raise Error, "[kutectl] #{stderr}"
|
210
246
|
end
|
211
247
|
end
|
212
248
|
end
|
data/lib/hippo/util.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'yaml'
|
4
|
+
require 'open3'
|
4
5
|
require 'hippo/error'
|
5
6
|
require 'hippo/object_definition'
|
6
7
|
|
@@ -30,6 +31,14 @@ module Hippo
|
|
30
31
|
end
|
31
32
|
end
|
32
33
|
|
34
|
+
def load_objects_from_path(path, decorator: nil)
|
35
|
+
files = Dir[path]
|
36
|
+
files.each_with_object({}) do |path, objects|
|
37
|
+
file = load_yaml_from_file(path, decorator: decorator)
|
38
|
+
objects[path] = file
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
33
42
|
def create_object_definitions(hash, stage, required_kinds: nil, clean: false)
|
34
43
|
index = 0
|
35
44
|
hash.each_with_object([]) do |(path, objects), array|
|
@@ -55,13 +64,17 @@ module Hippo
|
|
55
64
|
end
|
56
65
|
|
57
66
|
def open_in_editor(name, contents)
|
67
|
+
if ENV['EDITOR'].nil?
|
68
|
+
raise Error, 'No EDITOR environment variable has been defined'
|
69
|
+
end
|
70
|
+
|
58
71
|
tmp_root = File.join(ENV['HOME'], '.hippo')
|
59
72
|
FileUtils.mkdir_p(tmp_root)
|
60
73
|
begin
|
61
74
|
tmpfile = Tempfile.new([name, '.yaml'], tmp_root)
|
62
75
|
tmpfile.write(contents)
|
63
76
|
tmpfile.close
|
64
|
-
system("#{ENV['EDITOR']} #{tmpfile.path}")
|
77
|
+
Kernel.system("#{ENV['EDITOR']} #{tmpfile.path}")
|
65
78
|
tmpfile.open
|
66
79
|
tmpfile.read
|
67
80
|
ensure
|
@@ -102,6 +115,53 @@ module Hippo
|
|
102
115
|
response = response.to_s.strip
|
103
116
|
response.empty? ? default : response
|
104
117
|
end
|
118
|
+
|
119
|
+
def system(command, stdin_data: nil)
|
120
|
+
stdout, stderr, status = Open3.capture3(command, stdin_data: stdin_data)
|
121
|
+
unless status.success?
|
122
|
+
raise Error, "Command failed to execute: #{stderr}"
|
123
|
+
end
|
124
|
+
|
125
|
+
stdout
|
126
|
+
end
|
127
|
+
|
128
|
+
def action(message)
|
129
|
+
$stdout.print message
|
130
|
+
complete_state = 'done'
|
131
|
+
color = '32'
|
132
|
+
passed_proc = proc do |value|
|
133
|
+
complete_state = value
|
134
|
+
color = '33'
|
135
|
+
end
|
136
|
+
return_value = yield(passed_proc)
|
137
|
+
puts " \e[#{color}m#{complete_state}\e[0m"
|
138
|
+
return_value
|
139
|
+
rescue StandardError => e
|
140
|
+
puts " \e[31merror\e[0m"
|
141
|
+
raise
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def self.parse_kubectl_apply_lines(stdout)
|
146
|
+
stdout.split("\n").each_with_object({}) do |line, hash|
|
147
|
+
if line =~ %r{\A([\w\/\-\.]+) (\w+)\z}
|
148
|
+
object = Regexp.last_match(1)
|
149
|
+
status = Regexp.last_match(2)
|
150
|
+
elsif line =~ %r{\A[\w\.\/\-]+ \"([\w\-]+)\" (\w+)\z}
|
151
|
+
object = Regexp.last_match(1)
|
152
|
+
status = Regexp.last_match(2)
|
153
|
+
else
|
154
|
+
next
|
155
|
+
end
|
156
|
+
hash[object] = status
|
157
|
+
|
158
|
+
color = '32'
|
159
|
+
color = '31' if status == 'deleted'
|
160
|
+
color = '33' if status == 'configured'
|
161
|
+
|
162
|
+
status = "\e[#{color}m#{status}\e[0m" unless status == 'unchanged'
|
163
|
+
puts "\e[37m====> #{object} #{status}\e[0m"
|
164
|
+
end
|
105
165
|
end
|
106
166
|
end
|
107
167
|
end
|
data/lib/hippo/version.rb
CHANGED