awes_cli 0.0.0 → 0.0.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
- data/bin/ather +22 -2
- data/lib/build_app_image.rb +15 -5
- data/lib/deploy_app.rb +135 -0
- data/lib/deploy_config.rb +210 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: be520b19b3caa21d29f8208eab535c95e728180b7c74e77feb477263933587f4
|
4
|
+
data.tar.gz: 1233834f30464477ec72c618857d980bd68c2d750ce5c8cbd508a98db8876371
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 655d71c2e1f7563b8bd6f414f2e3ca73ee5a4c50713ab9009dc9a5709a30866682494cd1d2ddf6edd8bc8d8fa2e47d39cf2ae2c57c12bdf76ed45accd4671fa4
|
7
|
+
data.tar.gz: e4133b8c0233f5f89352e968daeaad5f31f837b1f0adeed939b83bd986e9d476dcf5e6f6ab8b52d6c56d4ad559754e44e656cad31dbdb21ae1203f15fc39d4b8
|
data/bin/ather
CHANGED
@@ -1,5 +1,25 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'build_app_image'
|
3
|
+
require 'deploy_app'
|
4
|
+
require 'deploy_config'
|
3
5
|
|
4
|
-
|
5
|
-
|
6
|
+
primary_cmd = ARGV[0]
|
7
|
+
secondary_cmd = ARGV[1]
|
8
|
+
|
9
|
+
if primary_cmd.nil?
|
10
|
+
puts 'Run `ather build|deploy`'
|
11
|
+
exit 1
|
12
|
+
end
|
13
|
+
|
14
|
+
if primary_cmd == 'deploy' && secondary_cmd.nil?
|
15
|
+
puts 'Run `ather deploy app|config`'
|
16
|
+
exit 1
|
17
|
+
end
|
18
|
+
|
19
|
+
if primary_cmd == 'build'
|
20
|
+
BuildAppImage.new.main
|
21
|
+
elsif primary_cmd == 'deploy' && secondary_cmd == 'app'
|
22
|
+
DeployApp.new.main
|
23
|
+
elsif primary_cmd == 'deploy' && secondary_cmd == 'config'
|
24
|
+
DeployConfig.new.main
|
25
|
+
end
|
data/lib/build_app_image.rb
CHANGED
@@ -17,7 +17,11 @@ class BuildAppImage
|
|
17
17
|
require_options_keys = [:project_id, :app_name]
|
18
18
|
|
19
19
|
opt_parser = OptionParser.new do |opts|
|
20
|
-
opts.banner = "Usage:
|
20
|
+
opts.banner = "Usage: ather build [options]"
|
21
|
+
|
22
|
+
opts.on("--image-tag IMAGE_TAG", "Image tag to deploy [optional]") do |val|
|
23
|
+
options[:image_tag] = val
|
24
|
+
end
|
21
25
|
|
22
26
|
opts.on("--project-id PROJECT_ID", "GCP project id [required or set env var PROJECT_ID]") do |val|
|
23
27
|
options[:project_id] = val
|
@@ -60,13 +64,19 @@ class BuildAppImage
|
|
60
64
|
def build_image(gcr_url, options)
|
61
65
|
commit_image_tag = ENV['CI_COMMIT_SHORT_SHA'] || `git rev-parse --short HEAD`
|
62
66
|
time_image_tag=`TZ=IST-5:30 date +'%Y.%m.%d.%HH.%MM.%SS'`
|
63
|
-
|
67
|
+
commit_image_url = "#{gcr_url}:#{commit_image_tag}".strip
|
68
|
+
time_image_url = "#{gcr_url}:#{time_image_tag}".strip
|
69
|
+
|
64
70
|
project_id = options[:project_id]
|
65
71
|
|
66
|
-
shell_cmd("gcloud builds submit --project #{project_id} --timeout=20m --tag #{
|
72
|
+
shell_cmd("gcloud builds submit --project #{project_id} --timeout=20m --tag #{time_image_url} || true")
|
73
|
+
|
74
|
+
shell_cmd("gcloud container images add-tag --quiet #{time_image_url} #{commit_image_url}")
|
75
|
+
|
76
|
+
opt_image_url = options[:image_tag] && "#{gcr_url}:#{options[:image_tag]}"
|
67
77
|
|
68
|
-
shell_cmd("gcloud container images add-tag --quiet #{
|
78
|
+
opt_image_url && shell_cmd("gcloud container images add-tag --quiet #{time_image_url} #{opt_image_url}")
|
69
79
|
|
70
|
-
|
80
|
+
opt_image_url
|
71
81
|
end
|
72
82
|
end
|
data/lib/deploy_app.rb
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
class DeployApp
|
5
|
+
def main
|
6
|
+
options = get_options
|
7
|
+
take_approval(options)
|
8
|
+
|
9
|
+
gcr_url = "gcr.io/#{options[:project_id]}/#{options[:app_name]}"
|
10
|
+
|
11
|
+
if(!options[:image_tag].nil?)
|
12
|
+
image_url = validate_image_tag_exists?(gcr_url, options[:image_tag])
|
13
|
+
else
|
14
|
+
image_url = build_image(gcr_url, options)
|
15
|
+
end
|
16
|
+
|
17
|
+
deploy_image(gcr_url, image_url, options)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def get_options
|
22
|
+
options = {}
|
23
|
+
|
24
|
+
require_options_keys = [:project_id, :app_name, :namespace, :cluster, :cluster_location]
|
25
|
+
|
26
|
+
opt_parser = OptionParser.new do |opts|
|
27
|
+
opts.banner = "Usage: ather deploy app [options]"
|
28
|
+
|
29
|
+
opts.on("-y", "Auto approve") do |flag|
|
30
|
+
options[:approve] = flag
|
31
|
+
end
|
32
|
+
|
33
|
+
opts.on("--image-tag IMAGE_TAG", "Image tag to deploy [optional]") do |val|
|
34
|
+
options[:image_tag] = val
|
35
|
+
end
|
36
|
+
|
37
|
+
opts.on("--project-id PROJECT_ID", "GCP project id [required or set env var PROJECT_ID]") do |val|
|
38
|
+
options[:project_id] = val
|
39
|
+
end
|
40
|
+
|
41
|
+
opts.on("--app-name APP_NAME", "K8s app name [required or set env var APP_NAME]") do |val|
|
42
|
+
options[:app_name] = val
|
43
|
+
end
|
44
|
+
|
45
|
+
opts.on("--namespace NAMESPACE", "K8s app namespace [required or set env var NAMESPACE]") do |val|
|
46
|
+
options[:namespace] = val
|
47
|
+
end
|
48
|
+
|
49
|
+
opts.on("--cluster CLUSTER", "App name [required or set env var CLUSTER]") do |val|
|
50
|
+
options[:cluster] = val
|
51
|
+
end
|
52
|
+
|
53
|
+
opts.on("--cluster-location CLUSTER_LOCATION", "App name [required or set env var CLUSTER_LOCATION]") do |val|
|
54
|
+
options[:cluster_location] = val
|
55
|
+
end
|
56
|
+
|
57
|
+
opts.on("-h", "--help", "Prints this help") do
|
58
|
+
puts opts
|
59
|
+
exit
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
opt_parser.parse!
|
64
|
+
|
65
|
+
require_options_keys.each do |key|
|
66
|
+
options[key] ||= ENV[key.to_s.upcase]
|
67
|
+
if options[key].nil?
|
68
|
+
puts "ERROR: Required option --#{key.to_s.gsub('_', '-')} or set env var #{key.to_s.upcase} \n"
|
69
|
+
opt_parser.parse! %w[--help]
|
70
|
+
exit 1
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
options
|
75
|
+
end
|
76
|
+
|
77
|
+
def shell_cmd(cmd)
|
78
|
+
puts "EXECUTING : \e[32m\e[1m#{cmd}\e[22m\e[0m"
|
79
|
+
op = system(cmd)
|
80
|
+
if !op
|
81
|
+
puts "FAILED : \e[31m\e[1m#{cmd}\e[22m\e[0m"
|
82
|
+
exit 1
|
83
|
+
end
|
84
|
+
puts "SUCCESS : \e[32m\e[1m#{cmd}\e[22m\e[0m"
|
85
|
+
end
|
86
|
+
|
87
|
+
def take_approval(options)
|
88
|
+
puts "\e[32m\e[1mDeployment parameter details \e[22m\e[0m"
|
89
|
+
options.each do |key, val|
|
90
|
+
puts "\e[1m#{key} = \e[31m#{val}\e[0m \e[22m"
|
91
|
+
end
|
92
|
+
|
93
|
+
return if(options[:approve])
|
94
|
+
puts 'Are you sure to want to deploy as per the above deployment parameters?'
|
95
|
+
confirmation = STDIN.gets.strip
|
96
|
+
return if(confirmation == 'y' || confirmation == 'Y')
|
97
|
+
exit
|
98
|
+
end
|
99
|
+
|
100
|
+
def validate_image_tag_exists?(gcr_url, image_tag)
|
101
|
+
image_url = "#{gcr_url}:#{image_tag}"
|
102
|
+
shell_cmd("gcloud container images describe #{image_url}")
|
103
|
+
image_url
|
104
|
+
end
|
105
|
+
|
106
|
+
def build_image(gcr_url, options)
|
107
|
+
commit_image_tag = ENV['CI_COMMIT_SHORT_SHA'] || `git rev-parse --short HEAD`
|
108
|
+
time_image_tag=`TZ=IST-5:30 date +'%Y.%m.%d.%HH.%MM.%SS'`
|
109
|
+
commit_image_url = "#{gcr_url}:#{commit_image_tag}".strip
|
110
|
+
time_image_url = "#{gcr_url}:#{time_image_tag}".strip
|
111
|
+
|
112
|
+
project_id = options[:project_id]
|
113
|
+
|
114
|
+
shell_cmd("gcloud builds submit --project #{project_id} --timeout=20m --tag #{time_image_url} || true")
|
115
|
+
|
116
|
+
shell_cmd("gcloud container images add-tag --quiet #{time_image_url} #{commit_image_url}")
|
117
|
+
|
118
|
+
commit_image_url
|
119
|
+
end
|
120
|
+
|
121
|
+
def deploy_image(gcr_url, image_url, options)
|
122
|
+
shell_cmd(
|
123
|
+
"gcloud container clusters get-credentials #{options[:cluster]} " \
|
124
|
+
"--region #{options[:cluster_location]} " \
|
125
|
+
"--project #{options[:project_id]} "
|
126
|
+
)
|
127
|
+
|
128
|
+
app_name = options[:app_name]
|
129
|
+
shell_cmd("kubectl set image deployment #{app_name} #{app_name}=#{image_url} -n #{options[:namespace]}")
|
130
|
+
|
131
|
+
shell_cmd("kubectl rollout status deployment/#{app_name} -n #{options[:namespace]}")
|
132
|
+
|
133
|
+
shell_cmd("gcloud container images add-tag --quiet #{image_url} #{gcr_url}:current")
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,210 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'json'
|
5
|
+
require 'yaml'
|
6
|
+
require 'fileutils'
|
7
|
+
|
8
|
+
class DeployConfig
|
9
|
+
def main
|
10
|
+
options = get_options
|
11
|
+
|
12
|
+
take_approval_deploy_params(options)
|
13
|
+
|
14
|
+
take_approval_app_env(options)
|
15
|
+
|
16
|
+
gcr_url = "gcr.io/#{options[:project_id]}/#{options[:app_name]}"
|
17
|
+
|
18
|
+
deploy_config(gcr_url, options)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def get_options
|
24
|
+
options = {}
|
25
|
+
|
26
|
+
require_options_keys = [:project_id, :app_name, :namespace, :cluster, :cluster_location, :kuztomize_env]
|
27
|
+
|
28
|
+
opt_parser = OptionParser.new do |opts|
|
29
|
+
opts.banner = "Usage: ather deploy config [options]"
|
30
|
+
|
31
|
+
opts.on("-y", "Auto approve") do |flag|
|
32
|
+
options[:approve] = flag
|
33
|
+
end
|
34
|
+
|
35
|
+
opts.on("--image-tag IMAGE_TAG", "Image tag to deploy [optional]") do |val|
|
36
|
+
options[:image_tag] = val
|
37
|
+
end
|
38
|
+
|
39
|
+
opts.on("--project-id PROJECT_ID", "GCP project id [required or set env var PROJECT_ID]") do |val|
|
40
|
+
options[:project_id] = val
|
41
|
+
end
|
42
|
+
|
43
|
+
opts.on("--app-name APP_NAME", "K8s app name [required or set env var APP_NAME]") do |val|
|
44
|
+
options[:app_name] = val
|
45
|
+
end
|
46
|
+
|
47
|
+
opts.on("--namespace NAMESPACE", "K8s app namespace [required or set env var NAMESPACE]") do |val|
|
48
|
+
options[:namespace] = val
|
49
|
+
end
|
50
|
+
|
51
|
+
opts.on("--cluster CLUSTER", "App name [required or set env var CLUSTER]") do |val|
|
52
|
+
options[:cluster] = val
|
53
|
+
end
|
54
|
+
|
55
|
+
opts.on("--cluster-location CLUSTER_LOCATION", "App name [required or set env var CLUSTER_LOCATION]") do |val|
|
56
|
+
options[:cluster_location] = val
|
57
|
+
end
|
58
|
+
|
59
|
+
opts.on("--kuztomize-env KUZTOMIZE_ENV", "App name [required or set env var KUZTOMIZE_ENV]") do |val|
|
60
|
+
options[:kuztomize_env] = val
|
61
|
+
end
|
62
|
+
|
63
|
+
opts.on("-h", "--help", "Prints this help") do
|
64
|
+
puts opts
|
65
|
+
exit
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
opt_parser.parse!
|
70
|
+
|
71
|
+
require_options_keys.each do |key|
|
72
|
+
options[key] ||= ENV[key.to_s.upcase]
|
73
|
+
if options[key].nil?
|
74
|
+
puts "ERROR: Required option --#{key.to_s.gsub('_', '-')} or set env var #{key.to_s.upcase} \n"
|
75
|
+
opt_parser.parse! %w[--help]
|
76
|
+
exit 1
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
options
|
81
|
+
end
|
82
|
+
|
83
|
+
def shell_cmd(cmd)
|
84
|
+
puts "EXECUTING : \e[32m\e[1m#{cmd}\e[22m\e[0m"
|
85
|
+
op = system(cmd)
|
86
|
+
if !op
|
87
|
+
puts "FAILED : \e[31m\e[1m#{cmd}\e[22m\e[0m"
|
88
|
+
exit 1
|
89
|
+
end
|
90
|
+
puts "SUCCESS : \e[32m\e[1m#{cmd}\e[22m\e[0m"
|
91
|
+
end
|
92
|
+
|
93
|
+
def take_approval_deploy_params(options)
|
94
|
+
puts "\e[32m\e[1mDeployment parameter details \e[22m\e[0m"
|
95
|
+
options.each do |key, val|
|
96
|
+
puts "\e[1m#{key} = \e[31m#{val}\e[0m \e[22m"
|
97
|
+
end
|
98
|
+
|
99
|
+
return if(options[:approve])
|
100
|
+
puts 'Are you sure to want to deploy as per the above deployment parameters? (y/N)'
|
101
|
+
confirmation = STDIN.gets.strip
|
102
|
+
return if(confirmation == 'y' || confirmation == 'Y')
|
103
|
+
exit
|
104
|
+
end
|
105
|
+
|
106
|
+
def take_approval_app_env(options)
|
107
|
+
override_env_filepath = "./deploy/env/#{options[:kuztomize_env]}.sh"
|
108
|
+
return if !File.file?(override_env_filepath)
|
109
|
+
puts "\e[32m\e[1mOverriding Application enviroment variables \e[22m\e[0m"
|
110
|
+
|
111
|
+
app_envs = `cat #{override_env_filepath}`.gsub('export ', "\n")
|
112
|
+
puts "\e[34m\e[1m#{app_envs}\e[22m\e[0m"
|
113
|
+
|
114
|
+
return if(options[:approve])
|
115
|
+
puts 'Are you sure to want to deploy the above application enviroment variables? (y/N)'
|
116
|
+
confirmation = STDIN.gets.strip
|
117
|
+
return if(confirmation == 'y' || confirmation == 'Y')
|
118
|
+
exit
|
119
|
+
end
|
120
|
+
|
121
|
+
def validate_image_tag_exists?(image_url)
|
122
|
+
shell_cmd("gcloud container images describe #{image_url}")
|
123
|
+
image_url
|
124
|
+
end
|
125
|
+
|
126
|
+
def deploy_config(gcr_url, options)
|
127
|
+
shell_cmd(
|
128
|
+
"gcloud container clusters get-credentials #{options[:cluster]} " \
|
129
|
+
"--region #{options[:cluster_location]} " \
|
130
|
+
"--project #{options[:project_id]} "
|
131
|
+
)
|
132
|
+
|
133
|
+
spec = app_container_spec(options[:app_name], options[:namespace]) || {}
|
134
|
+
|
135
|
+
override_envs = override_envs(options)
|
136
|
+
k8s_deployment_envs = k8s_deployment_envs(options)
|
137
|
+
|
138
|
+
yaml_file = `kustomize build deploy/overlays/#{options[:kuztomize_env]}`
|
139
|
+
|
140
|
+
yaml_file.scan(/\$[A-Z_]+/).each do |env_name|
|
141
|
+
env_key = env_name[1..-1]
|
142
|
+
env_val = override_envs[env_key] || ENV[env_key] || k8s_deployment_envs[env_key]
|
143
|
+
next if env_val.nil?
|
144
|
+
yaml_file[env_name] = env_val
|
145
|
+
end
|
146
|
+
|
147
|
+
gcr_url = "gcr.io/#{options[:project_id]}/#{options[:app_name]}"
|
148
|
+
|
149
|
+
opt_image_url = options[:image_tag] && "#{gcr_url}:#{options[:image_tag]}"
|
150
|
+
|
151
|
+
image_url = opt_image_url || spec[:image] || "#{gcr_url}:current"
|
152
|
+
validate_image_tag_exists?(image_url)
|
153
|
+
|
154
|
+
yaml_file['$IMAGE_URL'] = image_url
|
155
|
+
|
156
|
+
FileUtils.mkdir_p('./tmp')
|
157
|
+
|
158
|
+
File.write('./tmp/final.yaml', yaml_file)
|
159
|
+
|
160
|
+
puts "\e[36m\e[1m#{yaml_file}\e[22m\e[0m"
|
161
|
+
|
162
|
+
shell_cmd("kubectl apply -f ./tmp/final.yaml")
|
163
|
+
|
164
|
+
shell_cmd("kubectl rollout status deployment/#{options[:app_name]} -n #{options[:namespace]}")
|
165
|
+
end
|
166
|
+
|
167
|
+
def override_envs(options)
|
168
|
+
override_env_filepath = "./deploy/env/#{options[:kuztomize_env]}.yaml"
|
169
|
+
override_envs = {}
|
170
|
+
|
171
|
+
if File.file?(override_env_filepath)
|
172
|
+
env = YAML.load_file(override_env_filepath, symbolize_names: true)
|
173
|
+
env[:env].each do |env|
|
174
|
+
override_envs[env[:name]] = env[:value]
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
override_envs
|
179
|
+
end
|
180
|
+
|
181
|
+
def k8s_deployment_envs(options)
|
182
|
+
spec = app_container_spec(options[:app_name], options[:namespace])
|
183
|
+
|
184
|
+
return {} if spec.nil?
|
185
|
+
|
186
|
+
k8s_deployment_envs = {}
|
187
|
+
|
188
|
+
spec[:env].each do |env|
|
189
|
+
k8s_deployment_envs[env[:name]] = env[:value]
|
190
|
+
end
|
191
|
+
|
192
|
+
k8s_deployment_envs
|
193
|
+
end
|
194
|
+
|
195
|
+
def app_container_spec(app_name, namespace)
|
196
|
+
deploy_containers = `kubectl get deployment -n #{namespace} #{app_name} --output=jsonpath={.spec.template.spec.containers}`
|
197
|
+
return nil if deploy_containers == ''
|
198
|
+
JSON.parse(deploy_containers, symbolize_names: true).find { |container| container[:name] == app_name }
|
199
|
+
end
|
200
|
+
|
201
|
+
def app_container_env_vars_cmd(spec)
|
202
|
+
env_export_cmd = ''
|
203
|
+
spec[:env].each do |env|
|
204
|
+
env_var_val = ENV.fetch(env[:name]) { env[:value] }
|
205
|
+
env_export_cmd += "export #{env[:name]}=#{env_var_val} && "
|
206
|
+
end
|
207
|
+
|
208
|
+
env_export_cmd
|
209
|
+
end
|
210
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: awes_cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Umar Siddiqui
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-07-
|
11
|
+
date: 2021-07-22 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Ather cli tool
|
14
14
|
email: umar.siddiqui@atherenergy.com
|
@@ -20,6 +20,8 @@ files:
|
|
20
20
|
- bin/ather
|
21
21
|
- lib/awes_cli.rb
|
22
22
|
- lib/build_app_image.rb
|
23
|
+
- lib/deploy_app.rb
|
24
|
+
- lib/deploy_config.rb
|
23
25
|
homepage: https://rubygems.org/gems/awes_cli
|
24
26
|
licenses:
|
25
27
|
- MIT
|