uffizzi-cli 2.1.4 → 2.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/uffizzi/auth_helper.rb +1 -1
- data/lib/uffizzi/cli/cluster.rb +121 -76
- data/lib/uffizzi/cli/dev.rb +130 -47
- data/lib/uffizzi/clients/api/api_client.rb +14 -0
- data/lib/uffizzi/clients/api/api_routes.rb +8 -0
- data/lib/uffizzi/helpers/config_helper.rb +9 -1
- data/lib/uffizzi/services/cluster_service.rb +71 -0
- data/lib/uffizzi/services/dev_service.rb +110 -8
- data/lib/uffizzi/shell.rb +18 -0
- data/lib/uffizzi/version.rb +1 -1
- data/man/uffizzi +4 -1
- data/man/uffizzi-cluster-sleep.ronn +30 -0
- data/man/uffizzi-cluster-wake.ronn +28 -0
- data/man/uffizzi-cluster.ronn +6 -0
- data/man/uffizzi-dev +51 -0
- data/man/uffizzi-dev-describe +36 -0
- data/man/uffizzi-dev-describe.ronn +27 -0
- data/man/uffizzi-dev.ronn +43 -0
- data/man/uffizzi.ronn +3 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d24e9582d66d329f45ab42194dfefbf1558843fbc94578dfc8b2127f0d7f3122
|
4
|
+
data.tar.gz: fa901b1e7257fc8c9384bcf11c4f41490f767dabbecbf039056aa8b0ed488f38
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cda766f7ab21158e56cfb5e5ea3dabd0416de0fd1d1671c268347465db66ce4a3864f3aa51be04a6fd789848fd6d86cbf2c3e62437aaaf63803f633b5ababc2e
|
7
|
+
data.tar.gz: d6e79d2994cc487a7986315371715e15a85d5d42659a4ea21361ac7e289219441ba6ee5e77468dd5380e1ee5a8b9214fed0a4894bb2b7c4f26353647c3954fcc
|
data/lib/uffizzi/auth_helper.rb
CHANGED
@@ -16,7 +16,7 @@ module Uffizzi
|
|
16
16
|
Uffizzi::Token.delete if Uffizzi::Token.exists?
|
17
17
|
end
|
18
18
|
|
19
|
-
def check_login(project_option)
|
19
|
+
def check_login(project_option = nil)
|
20
20
|
raise Uffizzi::Error.new('You are not logged in. Run `uffizzi login`.') unless signed_in?
|
21
21
|
raise Uffizzi::Error.new('This command needs project to be set in config file') unless project_set?(project_option)
|
22
22
|
end
|
data/lib/uffizzi/cli/cluster.rb
CHANGED
@@ -22,7 +22,7 @@ module Uffizzi
|
|
22
22
|
run('list')
|
23
23
|
end
|
24
24
|
|
25
|
-
desc 'create [
|
25
|
+
desc 'create [CLUSTER_NAME]', 'Create a cluster'
|
26
26
|
method_option :name, type: :string, required: false, aliases: '-n'
|
27
27
|
method_option :kubeconfig, type: :string, required: false, aliases: '-k'
|
28
28
|
method_option :manifest, type: :string, required: false, aliases: '-m'
|
@@ -34,13 +34,13 @@ module Uffizzi
|
|
34
34
|
run('create', { name: name })
|
35
35
|
end
|
36
36
|
|
37
|
-
desc 'describe [
|
37
|
+
desc 'describe [CLUSTER_NAME]', 'Describe a cluster'
|
38
38
|
method_option :output, required: false, type: :string, aliases: '-o', enum: ['json', 'pretty-json']
|
39
39
|
def describe(name)
|
40
40
|
run('describe', cluster_name: name)
|
41
41
|
end
|
42
42
|
|
43
|
-
desc 'delete [
|
43
|
+
desc 'delete [CLUSTER_NAME]', 'Delete a cluster'
|
44
44
|
method_option :'delete-config', required: false, type: :boolean, default: true
|
45
45
|
def delete(name)
|
46
46
|
run('delete', cluster_name: name)
|
@@ -61,36 +61,48 @@ module Uffizzi
|
|
61
61
|
run('disconnect')
|
62
62
|
end
|
63
63
|
|
64
|
+
desc 'sleep [CLUSTER_NAME]', 'Scales a Uffizzi cluster down to zero resource utilization'
|
65
|
+
def sleep(name = nil)
|
66
|
+
run('sleep', cluster_name: name)
|
67
|
+
end
|
68
|
+
|
69
|
+
desc 'wake [CLUSTER_NAME]', 'Scales up a Uffizzi cluster to its original resource'
|
70
|
+
def wake(name = nil)
|
71
|
+
run('wake', cluster_name: name)
|
72
|
+
end
|
73
|
+
|
64
74
|
private
|
65
75
|
|
66
76
|
def run(command, command_args = {})
|
67
77
|
Uffizzi.ui.output_format = options[:output]
|
68
78
|
Uffizzi::AuthHelper.check_login(options[:project])
|
69
|
-
project_slug = options[:project].nil? ? ConfigFile.read_option(:project) : options[:project]
|
70
79
|
|
71
80
|
case command
|
72
81
|
when 'list'
|
73
|
-
handle_list_command
|
82
|
+
handle_list_command
|
74
83
|
when 'create'
|
75
|
-
handle_create_command(
|
84
|
+
handle_create_command(command_args)
|
76
85
|
when 'describe'
|
77
|
-
handle_describe_command(
|
86
|
+
handle_describe_command(command_args)
|
78
87
|
when 'delete'
|
79
|
-
handle_delete_command(
|
88
|
+
handle_delete_command(command_args)
|
80
89
|
when 'update-kubeconfig'
|
81
|
-
handle_update_kubeconfig_command(
|
90
|
+
handle_update_kubeconfig_command(command_args)
|
82
91
|
when 'disconnect'
|
83
92
|
ClusterDisconnectService.handle(options)
|
93
|
+
when 'sleep'
|
94
|
+
handle_sleep_command(project_slug, command_args)
|
95
|
+
when 'wake'
|
96
|
+
handle_wake_command(project_slug, command_args)
|
84
97
|
end
|
85
98
|
end
|
86
99
|
|
87
|
-
def handle_list_command
|
100
|
+
def handle_list_command
|
88
101
|
is_all = options[:all]
|
89
102
|
response = if is_all
|
90
|
-
get_account_clusters(
|
103
|
+
get_account_clusters(server, ConfigFile.read_option(:account, :id))
|
91
104
|
else
|
92
|
-
|
93
|
-
get_project_clusters(ConfigFile.read_option(:server), project_slug, oidc_token: oidc_token)
|
105
|
+
get_project_clusters(server, project_slug, oidc_token: oidc_token)
|
94
106
|
end
|
95
107
|
|
96
108
|
if ResponseHelper.ok?(response)
|
@@ -101,7 +113,7 @@ module Uffizzi
|
|
101
113
|
end
|
102
114
|
|
103
115
|
# rubocop:disable Metrics/PerceivedComplexity
|
104
|
-
def handle_create_command(
|
116
|
+
def handle_create_command(command_args)
|
105
117
|
Uffizzi.ui.disable_stdout if Uffizzi.ui.output_format
|
106
118
|
|
107
119
|
if options[:name]
|
@@ -111,52 +123,51 @@ module Uffizzi
|
|
111
123
|
end
|
112
124
|
|
113
125
|
cluster_name = command_args[:name] || options[:name] || ClusterService.generate_name
|
114
|
-
creation_source = options[:"creation-source"] || ClusterService::MANUAL_CREATION_SOURCE
|
115
|
-
k8s_version = options[:"k8s-version"]
|
116
126
|
Uffizzi.ui.say_error_and_exit("Cluster name: #{cluster_name} is not valid.") unless ClusterService.valid_name?(cluster_name)
|
117
127
|
|
118
|
-
|
119
|
-
name: cluster_name
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
)
|
124
|
-
response = create_cluster(ConfigFile.read_option(:server), project_slug, params)
|
128
|
+
unless ClusterService.valid_name?(cluster_name)
|
129
|
+
Uffizzi.ui.say_error_and_exit("Cluster name: #{cluster_name} is not valid.")
|
130
|
+
end
|
131
|
+
|
132
|
+
params = cluster_creation_params(cluster_name)
|
133
|
+
response = create_cluster(server, project_slug, params)
|
125
134
|
|
126
135
|
return ResponseHelper.handle_failed_response(response) unless ResponseHelper.created?(response)
|
127
136
|
|
128
137
|
spinner = TTY::Spinner.new("[:spinner] Creating cluster #{cluster_name}...", format: :dots)
|
129
138
|
spinner.auto_spin
|
130
|
-
cluster_data = ClusterService.wait_cluster_deploy(project_slug, cluster_name,
|
139
|
+
cluster_data = ClusterService.wait_cluster_deploy(project_slug, cluster_name, oidc_token)
|
131
140
|
|
132
141
|
if ClusterService.failed?(cluster_data[:state])
|
133
142
|
spinner.error
|
134
|
-
Uffizzi.ui.say_error_and_exit("Cluster
|
143
|
+
Uffizzi.ui.say_error_and_exit("Cluster #{cluster_name} failed to be created.")
|
135
144
|
end
|
136
145
|
|
137
146
|
spinner.success
|
138
147
|
handle_succeed_create_response(cluster_data)
|
139
148
|
rescue SystemExit, Interrupt, SocketError
|
140
|
-
handle_interrupt_creation(cluster_name
|
149
|
+
handle_interrupt_creation(cluster_name)
|
141
150
|
end
|
142
151
|
# rubocop:enable Metrics/PerceivedComplexity
|
143
152
|
|
144
|
-
def handle_describe_command(
|
145
|
-
cluster_data = fetch_cluster_data(
|
153
|
+
def handle_describe_command(command_args)
|
154
|
+
cluster_data = ClusterService.fetch_cluster_data(command_args[:cluster_name], **cluster_api_connection_params)
|
155
|
+
render_data = ClusterService.build_render_data(cluster_data)
|
146
156
|
|
147
|
-
|
157
|
+
Uffizzi.ui.output_format = Uffizzi::UI::Shell::PRETTY_LIST
|
158
|
+
Uffizzi.ui.say(render_data)
|
148
159
|
end
|
149
160
|
|
150
|
-
def handle_delete_command(
|
161
|
+
def handle_delete_command(command_args)
|
151
162
|
cluster_name = command_args[:cluster_name]
|
152
163
|
is_delete_kubeconfig = options[:'delete-config']
|
153
164
|
|
154
|
-
return handle_delete_cluster(
|
165
|
+
return handle_delete_cluster(cluster_name) unless is_delete_kubeconfig
|
155
166
|
|
156
|
-
cluster_data = fetch_cluster_data(
|
167
|
+
cluster_data = ClusterService.fetch_cluster_data(cluster_name, **cluster_api_connection_params)
|
157
168
|
kubeconfig = parse_kubeconfig(cluster_data[:kubeconfig])
|
158
169
|
|
159
|
-
handle_delete_cluster(
|
170
|
+
handle_delete_cluster(cluster_name)
|
160
171
|
exclude_kubeconfig(cluster_data[:id], kubeconfig) if kubeconfig.present?
|
161
172
|
end
|
162
173
|
|
@@ -180,12 +191,12 @@ module Uffizzi
|
|
180
191
|
end
|
181
192
|
end
|
182
193
|
|
183
|
-
def handle_delete_cluster(
|
194
|
+
def handle_delete_cluster(cluster_name)
|
184
195
|
params = {
|
185
196
|
cluster_name: cluster_name,
|
186
|
-
oidc_token:
|
197
|
+
oidc_token: oidc_token,
|
187
198
|
}
|
188
|
-
response = delete_cluster(
|
199
|
+
response = delete_cluster(server, project_slug, params)
|
189
200
|
|
190
201
|
if ResponseHelper.no_content?(response)
|
191
202
|
Uffizzi.ui.say("Cluster #{cluster_name} deleted")
|
@@ -194,9 +205,10 @@ module Uffizzi
|
|
194
205
|
end
|
195
206
|
end
|
196
207
|
|
197
|
-
def handle_update_kubeconfig_command(
|
208
|
+
def handle_update_kubeconfig_command(command_args)
|
198
209
|
kubeconfig_path = options[:kubeconfig] || KubeconfigService.default_path
|
199
|
-
|
210
|
+
cluster_name = command_args[:cluster_name]
|
211
|
+
cluster_data = ClusterService.fetch_cluster_data(cluster_name, **cluster_api_connection_params)
|
200
212
|
|
201
213
|
unless cluster_data[:kubeconfig].present?
|
202
214
|
say_error_update_kubeconfig(cluster_data)
|
@@ -218,13 +230,48 @@ module Uffizzi
|
|
218
230
|
new_kubeconfig
|
219
231
|
end
|
220
232
|
|
221
|
-
update_clusters_config(cluster_data[:id], kubeconfig_path: kubeconfig_path)
|
233
|
+
update_clusters_config(cluster_data[:id], name: cluster_name, kubeconfig_path: kubeconfig_path)
|
222
234
|
|
223
235
|
return if options[:quiet]
|
224
236
|
|
225
237
|
Uffizzi.ui.say("Kubeconfig was updated by the path: #{kubeconfig_path}")
|
226
238
|
end
|
227
239
|
|
240
|
+
def handle_sleep_command(project_slug, command_args)
|
241
|
+
cluster_name = command_args[:cluster_name] || ConfigFile.read_option(:current_cluster)&.fetch(:name)
|
242
|
+
return handle_missing_cluster_name_error if cluster_name.nil?
|
243
|
+
|
244
|
+
response = scale_down_cluster(ConfigFile.read_option(:server), project_slug, cluster_name)
|
245
|
+
return ResponseHelper.handle_failed_response(response) unless ResponseHelper.ok?(response)
|
246
|
+
|
247
|
+
spinner = TTY::Spinner.new("[:spinner] Scaling down cluster #{cluster_name}...", format: :dots)
|
248
|
+
spinner.auto_spin
|
249
|
+
ClusterService.wait_cluster_scale_down(project_slug, cluster_name)
|
250
|
+
|
251
|
+
spinner.success
|
252
|
+
Uffizzi.ui.say("Cluster #{cluster_name} was successfully scaled down")
|
253
|
+
end
|
254
|
+
|
255
|
+
def handle_wake_command(project_slug, command_args)
|
256
|
+
cluster_name = command_args[:cluster_name] || ConfigFile.read_option(:current_cluster)&.fetch(:name)
|
257
|
+
return handle_missing_cluster_name_error if cluster_name.nil?
|
258
|
+
|
259
|
+
response = scale_up_cluster(ConfigFile.read_option(:server), project_slug, cluster_name)
|
260
|
+
return ResponseHelper.handle_failed_response(response) unless ResponseHelper.ok?(response)
|
261
|
+
|
262
|
+
spinner = TTY::Spinner.new("[:spinner] Waking up cluster #{cluster_name}...", format: :dots)
|
263
|
+
spinner.auto_spin
|
264
|
+
cluster_data = ClusterService.wait_cluster_scale_up(project_slug, cluster_name)
|
265
|
+
|
266
|
+
if ClusterService.failed_scaling_up?(cluster_data[:state])
|
267
|
+
spinner.error
|
268
|
+
Uffizzi.ui.say_error_and_exit("Failed to wake up cluster #{cluster_name}.")
|
269
|
+
end
|
270
|
+
|
271
|
+
spinner.success
|
272
|
+
Uffizzi.ui.say("Cluster #{cluster_name} was successfully scaled up")
|
273
|
+
end
|
274
|
+
|
228
275
|
def say_error_update_kubeconfig(cluster_data)
|
229
276
|
if ClusterService.failed?(cluster_data[:state])
|
230
277
|
Uffizzi.ui.say_error_and_exit('Kubeconfig is empty because cluster failed to be created.')
|
@@ -239,13 +286,15 @@ module Uffizzi
|
|
239
286
|
end
|
240
287
|
end
|
241
288
|
|
242
|
-
def cluster_creation_params(
|
289
|
+
def cluster_creation_params(cluster_name)
|
290
|
+
creation_source = options[:"creation-source"] || ClusterService::MANUAL_CREATION_SOURCE
|
291
|
+
manifest_file_path = options[:manifest]
|
292
|
+
k8s_version = options[:"k8s-version"]
|
243
293
|
manifest_content = load_manifest_file(manifest_file_path)
|
244
|
-
oidc_token = Uffizzi::ConfigFile.read_option(:oidc_token)
|
245
294
|
|
246
295
|
{
|
247
296
|
cluster: {
|
248
|
-
name:
|
297
|
+
name: cluster_name,
|
249
298
|
manifest: manifest_content,
|
250
299
|
creation_source: creation_source,
|
251
300
|
k8s_version: k8s_version,
|
@@ -262,7 +311,7 @@ module Uffizzi
|
|
262
311
|
raise Uffizzi::Error.new(e.message)
|
263
312
|
end
|
264
313
|
|
265
|
-
def handle_interrupt_creation(cluster_name
|
314
|
+
def handle_interrupt_creation(cluster_name)
|
266
315
|
deletion_response = delete_cluster(server, project_slug, cluster_name: cluster_name)
|
267
316
|
deletion_message = if ResponseHelper.no_content?(deletion_response)
|
268
317
|
"The cluster #{cluster_name} has been disabled."
|
@@ -298,29 +347,12 @@ module Uffizzi
|
|
298
347
|
end.join("\n")
|
299
348
|
end
|
300
349
|
|
301
|
-
def handle_succeed_describe(cluster_data)
|
302
|
-
prepared_cluster_data = {
|
303
|
-
name: cluster_data[:name],
|
304
|
-
status: cluster_data[:state],
|
305
|
-
created: Time.strptime(cluster_data[:created_at], '%Y-%m-%dT%H:%M:%S.%N').strftime('%a %b %d %H:%M:%S %Y'),
|
306
|
-
url: cluster_data[:host],
|
307
|
-
k8s_version: cluster_data[:k8s_version],
|
308
|
-
}
|
309
|
-
|
310
|
-
rendered_cluster_data = if Uffizzi.ui.output_format.nil?
|
311
|
-
prepared_cluster_data.map { |k, v| "- #{k.to_s.upcase}: #{v}" }.join("\n").strip
|
312
|
-
else
|
313
|
-
prepared_cluster_data
|
314
|
-
end
|
315
|
-
|
316
|
-
Uffizzi.ui.say(rendered_cluster_data)
|
317
|
-
end
|
318
|
-
|
319
350
|
def handle_succeed_create_response(cluster_data)
|
320
351
|
kubeconfig_path = options[:kubeconfig] || KubeconfigService.default_path
|
321
352
|
is_update_current_context = options[:'update-current-context']
|
322
353
|
parsed_kubeconfig = parse_kubeconfig(cluster_data[:kubeconfig])
|
323
354
|
rendered_cluster_data = render_cluster_data(cluster_data)
|
355
|
+
cluster_name = cluster_data[:name]
|
324
356
|
|
325
357
|
Uffizzi.ui.enable_stdout
|
326
358
|
Uffizzi.ui.say("Cluster with name: #{rendered_cluster_data[:name]} was created.")
|
@@ -332,7 +364,7 @@ module Uffizzi
|
|
332
364
|
Uffizzi.ui.say(rendered_cluster_data) if Uffizzi.ui.output_format
|
333
365
|
|
334
366
|
save_kubeconfig(parsed_kubeconfig, kubeconfig_path)
|
335
|
-
update_clusters_config(cluster_data[:id], kubeconfig_path: kubeconfig_path)
|
367
|
+
update_clusters_config(cluster_data[:id], name: cluster_name, kubeconfig_path: kubeconfig_path)
|
336
368
|
GithubService.write_to_github_env(rendered_cluster_data) if GithubService.github_actions_exists?
|
337
369
|
end
|
338
370
|
|
@@ -362,6 +394,7 @@ module Uffizzi
|
|
362
394
|
def update_clusters_config(id, params)
|
363
395
|
clusters_config = Uffizzi::ConfigHelper.update_clusters_config_by_id(id, params)
|
364
396
|
ConfigFile.write_option(:clusters, clusters_config)
|
397
|
+
ConfigFile.write_option(:current_cluster, ConfigHelper.cluster_config_by_id(id))
|
365
398
|
end
|
366
399
|
|
367
400
|
def render_cluster_data(cluster_data)
|
@@ -380,25 +413,37 @@ module Uffizzi
|
|
380
413
|
Psych.safe_load(Base64.decode64(kubeconfig))
|
381
414
|
end
|
382
415
|
|
383
|
-
def fetch_cluster_data(project_slug, cluster_name)
|
384
|
-
params = {
|
385
|
-
cluster_name: cluster_name,
|
386
|
-
oidc_token: ConfigFile.read_option(:oidc_token),
|
387
|
-
}
|
388
|
-
response = get_cluster(ConfigFile.read_option(:server), project_slug, params)
|
389
|
-
|
390
|
-
if ResponseHelper.ok?(response)
|
391
|
-
response.dig(:body, :cluster)
|
392
|
-
else
|
393
|
-
ResponseHelper.handle_failed_response(response)
|
394
|
-
end
|
395
|
-
end
|
396
|
-
|
397
416
|
def save_previous_current_context(kubeconfig_path, current_context)
|
398
417
|
return if kubeconfig_path.nil? || ConfigHelper.previous_current_context_by_path(kubeconfig_path).present?
|
399
418
|
|
400
419
|
previous_current_contexts = Uffizzi::ConfigHelper.set_previous_current_context_by_path(kubeconfig_path, current_context)
|
401
420
|
ConfigFile.write_option(:previous_current_contexts, previous_current_contexts)
|
402
421
|
end
|
422
|
+
|
423
|
+
def handle_missing_cluster_name_error
|
424
|
+
Uffizzi.ui.say("No kubeconfig found at #{KubeconfigService.default_path}")
|
425
|
+
Uffizzi.ui.say('Please update the current context or provide a cluster name.')
|
426
|
+
Uffizzi.ui.say('$uffizzi cluster sleep my-cluster')
|
427
|
+
end
|
428
|
+
|
429
|
+
def cluster_api_connection_params
|
430
|
+
{
|
431
|
+
server: server,
|
432
|
+
project_slug: project_slug,
|
433
|
+
oidc_token: oidc_token,
|
434
|
+
}
|
435
|
+
end
|
436
|
+
|
437
|
+
def oidc_token
|
438
|
+
@oidc_token ||= ConfigFile.read_option(:oidc_token)
|
439
|
+
end
|
440
|
+
|
441
|
+
def project_slug
|
442
|
+
@project_slug ||= options[:project].nil? ? ConfigFile.read_option(:project) : options[:project]
|
443
|
+
end
|
444
|
+
|
445
|
+
def server
|
446
|
+
@server ||= ConfigFile.read_option(:server)
|
447
|
+
end
|
403
448
|
end
|
404
449
|
end
|
data/lib/uffizzi/cli/dev.rb
CHANGED
@@ -15,77 +15,121 @@ module Uffizzi
|
|
15
15
|
method_option :kubeconfig, type: :string
|
16
16
|
method_option :'k8s-version', required: false, type: :string
|
17
17
|
def start(config_path = 'skaffold.yaml')
|
18
|
-
|
18
|
+
run('start', config_path: config_path)
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'stop', 'Stop dev environment'
|
22
|
+
def stop
|
23
|
+
run('stop')
|
24
|
+
end
|
25
|
+
|
26
|
+
desc 'describe', 'Describe dev environment'
|
27
|
+
def describe
|
28
|
+
run('describe')
|
29
|
+
end
|
30
|
+
|
31
|
+
desc 'delete', 'Delete dev environment'
|
32
|
+
def delete
|
33
|
+
run('delete')
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def run(command, command_args = {})
|
39
|
+
Uffizzi::AuthHelper.check_login
|
40
|
+
|
41
|
+
case command
|
42
|
+
when 'start'
|
43
|
+
handle_start_command(command_args)
|
44
|
+
when 'stop'
|
45
|
+
handle_stop_command
|
46
|
+
when 'describe'
|
47
|
+
handle_describe_command
|
48
|
+
when 'delete'
|
49
|
+
handle_delete_command
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def handle_start_command(command_args)
|
54
|
+
config_path = command_args[:config_path]
|
19
55
|
DevService.check_skaffold_existence
|
20
|
-
DevService.
|
56
|
+
DevService.check_no_running_process!
|
21
57
|
DevService.check_skaffold_config_existence(config_path)
|
22
|
-
|
23
|
-
|
58
|
+
|
59
|
+
if dev_environment.empty?
|
60
|
+
DevService.set_startup_state
|
61
|
+
cluster_name = start_create_cluster
|
62
|
+
wait_cluster_creation(cluster_name)
|
63
|
+
DevService.set_dev_environment_config(cluster_name, config_path, options)
|
64
|
+
DevService.set_cluster_deployed_state
|
65
|
+
end
|
24
66
|
|
25
67
|
if options[:quiet]
|
26
68
|
launch_demonise_skaffold(config_path)
|
27
69
|
else
|
28
|
-
|
29
|
-
end
|
30
|
-
ensure
|
31
|
-
if defined?(cluster_name).present? && defined?(cluster_id).present?
|
32
|
-
kubeconfig = defined?(kubeconfig).present? ? kubeconfig : nil
|
33
|
-
handle_delete_cluster(cluster_id, cluster_name, kubeconfig)
|
70
|
+
launch_basic_skaffold(config_path)
|
34
71
|
end
|
35
72
|
end
|
36
73
|
|
37
|
-
|
38
|
-
|
39
|
-
|
74
|
+
def handle_stop_command
|
75
|
+
DevService.check_running_process!
|
76
|
+
DevService.stop_process
|
77
|
+
Uffizzi.ui.say('Uffizzi dev was stopped')
|
78
|
+
end
|
40
79
|
|
41
|
-
|
42
|
-
|
80
|
+
def handle_describe_command
|
81
|
+
DevService.check_environment_exist!
|
43
82
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
83
|
+
cluster_data = fetch_dev_env_cluster!
|
84
|
+
cluster_render_data = ClusterService.build_render_data(cluster_data)
|
85
|
+
dev_environment_render_data = cluster_render_data.merge(config_path: dev_environment[:config_path])
|
86
|
+
|
87
|
+
Uffizzi.ui.output_format = Uffizzi::UI::Shell::PRETTY_LIST
|
88
|
+
Uffizzi.ui.say(dev_environment_render_data)
|
49
89
|
end
|
50
90
|
|
51
|
-
|
91
|
+
def handle_delete_command
|
92
|
+
DevService.check_environment_exist!
|
93
|
+
|
94
|
+
if DevService.process_running?
|
95
|
+
DevService.stop_process
|
96
|
+
Uffizzi.ui.say('Uffizzi dev was stopped')
|
97
|
+
end
|
98
|
+
|
99
|
+
cluster_data = fetch_dev_env_cluster!
|
100
|
+
handle_delete_cluster(cluster_data)
|
101
|
+
DevService.clear_dev_environment_config
|
102
|
+
end
|
52
103
|
|
53
104
|
def start_create_cluster
|
54
|
-
params = cluster_creation_params
|
55
|
-
name: ClusterService.generate_name,
|
56
|
-
creation_source: ClusterService::MANUAL_CREATION_SOURCE,
|
57
|
-
k8s_version: options[:"k8s-version"],
|
58
|
-
)
|
105
|
+
params = cluster_creation_params
|
59
106
|
Uffizzi.ui.say('Start creating a cluster')
|
60
|
-
response = create_cluster(
|
107
|
+
response = create_cluster(server, project_slug, params)
|
61
108
|
return ResponseHelper.handle_failed_response(response) unless ResponseHelper.created?(response)
|
62
109
|
|
63
|
-
|
64
|
-
cluster_name = response.dig(:body, :cluster, :name)
|
65
|
-
|
66
|
-
[cluster_id, cluster_name]
|
110
|
+
response.dig(:body, :cluster, :name)
|
67
111
|
end
|
68
112
|
|
69
113
|
def wait_cluster_creation(cluster_name)
|
70
114
|
Uffizzi.ui.say('Checking the cluster status...')
|
71
|
-
cluster_data = ClusterService.wait_cluster_deploy(project_slug, cluster_name,
|
115
|
+
cluster_data = ClusterService.wait_cluster_deploy(project_slug, cluster_name, oidc_token)
|
72
116
|
|
73
117
|
if ClusterService.failed?(cluster_data[:state])
|
74
118
|
Uffizzi.ui.say_error_and_exit("Cluster with name: #{cluster_name} failed to be created.")
|
75
119
|
end
|
76
120
|
|
77
121
|
handle_succeed_cluster_creation(cluster_data)
|
78
|
-
parse_kubeconfig(cluster_data[:kubeconfig])
|
79
122
|
end
|
80
123
|
|
81
124
|
def handle_succeed_cluster_creation(cluster_data)
|
82
125
|
kubeconfig_path = options[:kubeconfig] || KubeconfigService.default_path
|
83
126
|
parsed_kubeconfig = parse_kubeconfig(cluster_data[:kubeconfig])
|
127
|
+
cluster_name = cluster_data[:name]
|
84
128
|
|
85
|
-
Uffizzi.ui.say("Cluster with name: #{
|
129
|
+
Uffizzi.ui.say("Cluster with name: #{cluster_name} was created.")
|
86
130
|
|
87
131
|
save_kubeconfig(parsed_kubeconfig, kubeconfig_path)
|
88
|
-
update_clusters_config(cluster_data[:id], kubeconfig_path: kubeconfig_path)
|
132
|
+
update_clusters_config(cluster_data[:id], name: cluster_name, kubeconfig_path: kubeconfig_path)
|
89
133
|
end
|
90
134
|
|
91
135
|
def save_kubeconfig(kubeconfig, kubeconfig_path)
|
@@ -108,30 +152,30 @@ module Uffizzi
|
|
108
152
|
ConfigFile.write_option(:clusters, clusters_config)
|
109
153
|
end
|
110
154
|
|
111
|
-
def cluster_creation_params
|
112
|
-
oidc_token = Uffizzi::ConfigFile.read_option(:oidc_token)
|
113
|
-
|
155
|
+
def cluster_creation_params
|
114
156
|
{
|
115
157
|
cluster: {
|
116
|
-
name:
|
158
|
+
name: ClusterService.generate_name,
|
117
159
|
manifest: nil,
|
118
|
-
creation_source:
|
119
|
-
k8s_version:
|
160
|
+
creation_source: ClusterService::MANUAL_CREATION_SOURCE,
|
161
|
+
k8s_version: options[:"k8s-version"],
|
120
162
|
},
|
121
163
|
token: oidc_token,
|
122
164
|
}
|
123
165
|
end
|
124
166
|
|
125
|
-
def handle_delete_cluster(
|
126
|
-
|
167
|
+
def handle_delete_cluster(cluster_data)
|
168
|
+
cluster_id = cluster_data[:id]
|
169
|
+
cluster_name = cluster_data[:name]
|
170
|
+
kubeconfig = parse_kubeconfig(cluster_data[:kubeconfig])
|
127
171
|
|
128
172
|
exclude_kubeconfig(cluster_id, kubeconfig) if kubeconfig.present?
|
129
173
|
|
130
174
|
params = {
|
131
175
|
cluster_name: cluster_name,
|
132
|
-
oidc_token:
|
176
|
+
oidc_token: oidc_token,
|
133
177
|
}
|
134
|
-
response = delete_cluster(
|
178
|
+
response = delete_cluster(server, project_slug, params)
|
135
179
|
|
136
180
|
if ResponseHelper.no_content?(response)
|
137
181
|
Uffizzi.ui.say("Cluster #{cluster_name} deleted")
|
@@ -179,19 +223,58 @@ module Uffizzi
|
|
179
223
|
Uffizzi.process.daemon(true)
|
180
224
|
|
181
225
|
at_exit do
|
182
|
-
|
226
|
+
DevService.delete_pid
|
183
227
|
end
|
184
228
|
|
229
|
+
DevService.save_pid
|
185
230
|
File.delete(DevService.logs_path) if File.exist?(DevService.logs_path)
|
186
|
-
File.write(DevService.pid_path, Uffizzi.process.pid)
|
187
231
|
DevService.start_check_pid_file_existence
|
188
232
|
DevService.start_demonised_skaffold(config_path, options)
|
189
233
|
rescue StandardError => e
|
190
234
|
File.open(DevService.logs_path, 'a') { |f| f.puts(e.message) }
|
191
235
|
end
|
192
236
|
|
237
|
+
def launch_basic_skaffold(config_path)
|
238
|
+
at_exit do
|
239
|
+
DevService.delete_pid
|
240
|
+
end
|
241
|
+
|
242
|
+
DevService.save_pid
|
243
|
+
DevService.start_check_pid_file_existence
|
244
|
+
DevService.start_basic_skaffold(config_path, options)
|
245
|
+
end
|
246
|
+
|
247
|
+
def fetch_dev_env_cluster!
|
248
|
+
if DevService.startup?
|
249
|
+
Uffizzi.ui.say_error_and_exit('Dev environment not started yet')
|
250
|
+
end
|
251
|
+
|
252
|
+
cluster_name = dev_environment[:cluster_name]
|
253
|
+
ClusterService.fetch_cluster_data(cluster_name, **cluster_api_connection_params)
|
254
|
+
end
|
255
|
+
|
256
|
+
def dev_environment
|
257
|
+
@dev_environment ||= DevService.dev_environment
|
258
|
+
end
|
259
|
+
|
260
|
+
def cluster_api_connection_params
|
261
|
+
{
|
262
|
+
server: server,
|
263
|
+
project_slug: project_slug,
|
264
|
+
oidc_token: oidc_token,
|
265
|
+
}
|
266
|
+
end
|
267
|
+
|
193
268
|
def project_slug
|
194
269
|
@project_slug ||= ConfigFile.read_option(:project)
|
195
270
|
end
|
271
|
+
|
272
|
+
def oidc_token
|
273
|
+
@oidc_token ||= ConfigFile.read_option(:oidc_token)
|
274
|
+
end
|
275
|
+
|
276
|
+
def server
|
277
|
+
@server ||= ConfigFile.read_option(:server)
|
278
|
+
end
|
196
279
|
end
|
197
280
|
end
|
@@ -262,6 +262,20 @@ module ApiClient
|
|
262
262
|
build_response(response)
|
263
263
|
end
|
264
264
|
|
265
|
+
def scale_down_cluster(server, project_slug, cluster_name)
|
266
|
+
uri = scale_down_cluster_uri(server, project_slug, cluster_name)
|
267
|
+
response = http_client.make_put_request(uri)
|
268
|
+
|
269
|
+
build_response(response)
|
270
|
+
end
|
271
|
+
|
272
|
+
def scale_up_cluster(server, project_slug, cluster_name)
|
273
|
+
uri = scale_up_cluster_uri(server, project_slug, cluster_name)
|
274
|
+
response = http_client.make_put_request(uri)
|
275
|
+
|
276
|
+
build_response(response)
|
277
|
+
end
|
278
|
+
|
265
279
|
def create_access_token(server, session_id)
|
266
280
|
uri = access_tokens_url(server)
|
267
281
|
|
@@ -110,6 +110,14 @@ module ApiRoutes
|
|
110
110
|
"#{server}/api/cli/v1/projects/#{project_slug}/clusters/#{cluster_name}?token=#{oidc_token}"
|
111
111
|
end
|
112
112
|
|
113
|
+
def scale_up_cluster_uri(server, project_slug, cluster_name)
|
114
|
+
"#{server}/api/cli/v1/projects/#{project_slug}/clusters/#{cluster_name}/scale_up"
|
115
|
+
end
|
116
|
+
|
117
|
+
def scale_down_cluster_uri(server, project_slug, cluster_name)
|
118
|
+
"#{server}/api/cli/v1/projects/#{project_slug}/clusters/#{cluster_name}/scale_down"
|
119
|
+
end
|
120
|
+
|
113
121
|
def access_token_url(server, code)
|
114
122
|
"#{server}/api/cli/v1/access_tokens/#{code}"
|
115
123
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Uffizzi
|
4
4
|
module ConfigHelper
|
5
|
-
CLUSTER_PARAMS = [:kubeconfig_path].freeze
|
5
|
+
CLUSTER_PARAMS = [:kubeconfig_path, :name].freeze
|
6
6
|
|
7
7
|
class ConfigParamsError < StandardError
|
8
8
|
def initialize(unavailable_params, key)
|
@@ -52,6 +52,14 @@ module Uffizzi
|
|
52
52
|
cluster_previous_current_contexts.detect { |c| c[:kubeconfig_path] == path }
|
53
53
|
end
|
54
54
|
|
55
|
+
def set_dev_environment(cluster_name, params = {})
|
56
|
+
{ cluster_name: cluster_name }.merge(params)
|
57
|
+
end
|
58
|
+
|
59
|
+
def dev_environment
|
60
|
+
read_option_from_config(:dev_environment) || {}
|
61
|
+
end
|
62
|
+
|
55
63
|
private
|
56
64
|
|
57
65
|
def clusters
|
@@ -1,11 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'uffizzi/response_helper'
|
3
4
|
require 'uffizzi/clients/api/api_client'
|
4
5
|
|
5
6
|
class ClusterService
|
6
7
|
CLUSTER_STATE_DEPLOYING_NAMESPACE = 'deploying_namespace'
|
7
8
|
CLUSTER_STATE_DEPLOYING = 'deploying'
|
8
9
|
CLUSTER_STATE_DEPLOYED = 'deployed'
|
10
|
+
CLUSTER_STATE_SCALING_DOWN = 'scaling_down'
|
11
|
+
CLUSTER_STATE_SCALING_UP = 'scaling_up'
|
12
|
+
CLUSTER_FAILED_SCALING_UP = 'failed_scaling_up'
|
9
13
|
CLUSTER_STATE_FAILED_DEPLOY_NAMESPACE = 'failed_deploy_namespace'
|
10
14
|
CLUSTER_STATE_FAILED = 'failed'
|
11
15
|
CLUSTER_NAME_MAX_LENGTH = 15
|
@@ -26,6 +30,18 @@ class ClusterService
|
|
26
30
|
[CLUSTER_STATE_FAILED_DEPLOY_NAMESPACE, CLUSTER_STATE_FAILED].include?(cluster_state)
|
27
31
|
end
|
28
32
|
|
33
|
+
def scaling_up?(cluster_state)
|
34
|
+
cluster_state === CLUSTER_STATE_SCALING_UP
|
35
|
+
end
|
36
|
+
|
37
|
+
def scaling_down?(cluster_state)
|
38
|
+
cluster_state === CLUSTER_STATE_SCALING_DOWN
|
39
|
+
end
|
40
|
+
|
41
|
+
def failed_scaling_up?(cluster_state)
|
42
|
+
cluster_state === CLUSTER_FAILED_SCALING_UP
|
43
|
+
end
|
44
|
+
|
29
45
|
def wait_cluster_deploy(project_slug, cluster_name, oidc_token)
|
30
46
|
loop do
|
31
47
|
params = {
|
@@ -43,6 +59,38 @@ class ClusterService
|
|
43
59
|
end
|
44
60
|
end
|
45
61
|
|
62
|
+
def wait_cluster_scale_up(project_slug, cluster_name)
|
63
|
+
loop do
|
64
|
+
params = {
|
65
|
+
cluster_name: cluster_name,
|
66
|
+
}
|
67
|
+
response = get_cluster(Uffizzi::ConfigFile.read_option(:server), project_slug, params)
|
68
|
+
return Uffizzi::ResponseHelper.handle_failed_response(response) unless Uffizzi::ResponseHelper.ok?(response)
|
69
|
+
|
70
|
+
cluster_data = response.dig(:body, :cluster)
|
71
|
+
|
72
|
+
return cluster_data unless scaling_up?(cluster_data[:state])
|
73
|
+
|
74
|
+
sleep(5)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def wait_cluster_scale_down(project_slug, cluster_name)
|
79
|
+
loop do
|
80
|
+
params = {
|
81
|
+
cluster_name: cluster_name,
|
82
|
+
}
|
83
|
+
response = get_cluster(Uffizzi::ConfigFile.read_option(:server), project_slug, params)
|
84
|
+
return Uffizzi::ResponseHelper.handle_failed_response(response) unless Uffizzi::ResponseHelper.ok?(response)
|
85
|
+
|
86
|
+
cluster_data = response.dig(:body, :cluster)
|
87
|
+
|
88
|
+
return unless scaling_down?(cluster_data[:state])
|
89
|
+
|
90
|
+
sleep(3)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
46
94
|
def generate_name
|
47
95
|
name = Faker::Internet.domain_word[0..CLUSTER_NAME_MAX_LENGTH]
|
48
96
|
|
@@ -57,5 +105,28 @@ class ClusterService
|
|
57
105
|
regex = /\A[a-zA-Z0-9-]*\z/
|
58
106
|
regex.match?(name)
|
59
107
|
end
|
108
|
+
|
109
|
+
def fetch_cluster_data(cluster_name, server:, project_slug:, oidc_token:)
|
110
|
+
params = {
|
111
|
+
cluster_name: cluster_name,
|
112
|
+
oidc_token: oidc_token,
|
113
|
+
}
|
114
|
+
response = get_cluster(server, project_slug, params)
|
115
|
+
|
116
|
+
if Uffizzi::ResponseHelper.ok?(response)
|
117
|
+
response.dig(:body, :cluster)
|
118
|
+
else
|
119
|
+
Uffizzi::ResponseHelper.handle_failed_response(response)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def build_render_data(cluster_data)
|
124
|
+
{
|
125
|
+
name: cluster_data[:name],
|
126
|
+
status: cluster_data[:state],
|
127
|
+
created: Time.strptime(cluster_data[:created_at], '%Y-%m-%dT%H:%M:%S.%N').strftime('%a %b %d %H:%M:%S %Y'),
|
128
|
+
url: cluster_data[:host],
|
129
|
+
}
|
130
|
+
end
|
60
131
|
end
|
61
132
|
end
|
@@ -3,21 +3,50 @@
|
|
3
3
|
require 'uffizzi/clients/api/api_client'
|
4
4
|
|
5
5
|
class DevService
|
6
|
+
DEFAULT_REGISTRY_REPO = 'registry.uffizzi.com'
|
7
|
+
STARTUP_STATE = 'startup'
|
8
|
+
CLUSTER_DEPLOYED_STATE = 'cluster_deployed'
|
9
|
+
|
6
10
|
class << self
|
7
11
|
include ApiClient
|
8
12
|
|
9
|
-
|
13
|
+
def check_no_running_process!
|
14
|
+
if process_running?
|
15
|
+
Uffizzi.ui.say_error_and_exit("You have already started uffizzi dev. To stop the process do 'uffizzi dev stop'")
|
16
|
+
end
|
17
|
+
end
|
10
18
|
|
11
|
-
def
|
12
|
-
|
19
|
+
def check_running_process!
|
20
|
+
unless process_running?
|
21
|
+
Uffizzi.ui.say_error_and_exit('Uffizzi dev is not running')
|
22
|
+
end
|
23
|
+
end
|
13
24
|
|
14
|
-
|
15
|
-
|
16
|
-
|
25
|
+
def check_environment_exist!
|
26
|
+
if dev_environment.empty?
|
27
|
+
Uffizzi.ui.say_error_and_exit('Uffizzi dev does not exist')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def stop_process
|
32
|
+
dev_pid = running_pid
|
33
|
+
skaffold_pid = running_skaffold_pid
|
34
|
+
|
35
|
+
Uffizzi.process.kill('INT', skaffold_pid)
|
36
|
+
Uffizzi.process.kill('INT', dev_pid)
|
37
|
+
delete_pid
|
38
|
+
rescue Errno::ESRCH
|
39
|
+
delete_pid
|
40
|
+
end
|
41
|
+
|
42
|
+
def process_running?
|
43
|
+
pid = running_pid
|
44
|
+
return false unless pid.positive?
|
17
45
|
|
18
|
-
Uffizzi.
|
46
|
+
Uffizzi.process.kill(0, pid.to_i)
|
47
|
+
true
|
19
48
|
rescue Errno::ESRCH
|
20
|
-
|
49
|
+
false
|
21
50
|
end
|
22
51
|
|
23
52
|
def start_check_pid_file_existence
|
@@ -34,6 +63,9 @@ class DevService
|
|
34
63
|
cmd = build_skaffold_dev_command(config_path, options)
|
35
64
|
|
36
65
|
Uffizzi.ui.popen2e(cmd) do |_stdin, stdout_and_stderr, wait_thr|
|
66
|
+
pid = wait_thr.pid
|
67
|
+
skaffold_pid = find_skaffold_pid(pid)
|
68
|
+
save_skaffold_pid(skaffold_pid)
|
37
69
|
stdout_and_stderr.each { |l| Uffizzi.ui.say(l) }
|
38
70
|
wait_thr.value
|
39
71
|
end
|
@@ -44,6 +76,10 @@ class DevService
|
|
44
76
|
cmd = build_skaffold_dev_command(config_path, options)
|
45
77
|
|
46
78
|
Uffizzi.ui.popen2e(cmd) do |_stdin, stdout_and_stderr, wait_thr|
|
79
|
+
pid = wait_thr.pid
|
80
|
+
skaffold_pid = find_skaffold_pid(pid)
|
81
|
+
save_skaffold_pid(skaffold_pid)
|
82
|
+
|
47
83
|
File.open(logs_path, 'a') do |f|
|
48
84
|
stdout_and_stderr.each do |line|
|
49
85
|
f.puts(line)
|
@@ -80,6 +116,10 @@ class DevService
|
|
80
116
|
File.join(Uffizzi::ConfigFile::CONFIG_DIR, 'uffizzi_dev.pid')
|
81
117
|
end
|
82
118
|
|
119
|
+
def skaffold_pid_path
|
120
|
+
File.join(Uffizzi::ConfigFile::CONFIG_DIR, 'skaffold_dev.pid')
|
121
|
+
end
|
122
|
+
|
83
123
|
def logs_path
|
84
124
|
File.join(Uffizzi::ConfigFile::CONFIG_DIR, 'uffizzi_dev.log')
|
85
125
|
end
|
@@ -104,5 +144,67 @@ class DevService
|
|
104
144
|
|
105
145
|
File.expand_path(path)
|
106
146
|
end
|
147
|
+
|
148
|
+
def running_pid
|
149
|
+
return nil.to_i unless File.exist?(pid_path)
|
150
|
+
|
151
|
+
File.read(pid_path).to_i
|
152
|
+
end
|
153
|
+
|
154
|
+
def save_pid
|
155
|
+
File.write(pid_path, Uffizzi.process.pid)
|
156
|
+
end
|
157
|
+
|
158
|
+
def delete_pid
|
159
|
+
File.delete(pid_path) if File.exist?(pid_path)
|
160
|
+
File.delete(skaffold_pid_path) if File.exist?(skaffold_pid_path)
|
161
|
+
end
|
162
|
+
|
163
|
+
def running_skaffold_pid
|
164
|
+
return nil.to_i unless File.exist?(skaffold_pid_path)
|
165
|
+
|
166
|
+
File.read(skaffold_pid_path).to_i
|
167
|
+
end
|
168
|
+
|
169
|
+
def save_skaffold_pid(pid)
|
170
|
+
File.write(skaffold_pid_path, pid)
|
171
|
+
end
|
172
|
+
|
173
|
+
def set_dev_environment_config(cluster_name, config_path, options)
|
174
|
+
params = options.merge(config_path: File.expand_path(config_path))
|
175
|
+
new_dev_environment = Uffizzi::ConfigHelper.set_dev_environment(cluster_name, params)
|
176
|
+
Uffizzi::ConfigFile.write_option(:dev_environment, new_dev_environment)
|
177
|
+
end
|
178
|
+
|
179
|
+
def set_startup_state
|
180
|
+
new_dev_environment = dev_environment.merge(state: STARTUP_STATE)
|
181
|
+
Uffizzi::ConfigFile.write_option(:dev_environment, new_dev_environment)
|
182
|
+
end
|
183
|
+
|
184
|
+
def set_cluster_deployed_state
|
185
|
+
new_dev_environment = dev_environment.merge(state: CLUSTER_DEPLOYED_STATE)
|
186
|
+
Uffizzi::ConfigFile.write_option(:dev_environment, new_dev_environment)
|
187
|
+
end
|
188
|
+
|
189
|
+
def startup?
|
190
|
+
dev_environment[:state] == STARTUP_STATE
|
191
|
+
end
|
192
|
+
|
193
|
+
def clear_dev_environment_config
|
194
|
+
Uffizzi::ConfigFile.write_option(:dev_environment, {})
|
195
|
+
end
|
196
|
+
|
197
|
+
def dev_environment
|
198
|
+
Uffizzi::ConfigHelper.dev_environment
|
199
|
+
end
|
200
|
+
|
201
|
+
def find_skaffold_pid(ppid)
|
202
|
+
ppid_regex = /\w*\s+\d+\s+#{ppid}.*\sskaffold dev/
|
203
|
+
pid_regex = /\w*\s+(\d+)\s+#{ppid}.*\sskaffold dev/
|
204
|
+
|
205
|
+
io = Uffizzi.ui.popen('ps -ef')
|
206
|
+
ps = io.readlines.detect { |l| l.match?(ppid_regex) }
|
207
|
+
ps.match(pid_regex)[1]
|
208
|
+
end
|
107
209
|
end
|
108
210
|
end
|
data/lib/uffizzi/shell.rb
CHANGED
@@ -11,6 +11,7 @@ module Uffizzi
|
|
11
11
|
|
12
12
|
PRETTY_JSON = 'pretty-json'
|
13
13
|
REGULAR_JSON = 'json'
|
14
|
+
PRETTY_LIST = 'pretty-list'
|
14
15
|
|
15
16
|
def initialize
|
16
17
|
@shell = Thor::Shell::Basic.new
|
@@ -55,6 +56,10 @@ module Uffizzi
|
|
55
56
|
$stdout.stat.pipe?
|
56
57
|
end
|
57
58
|
|
59
|
+
def popen(command)
|
60
|
+
IO.popen(command)
|
61
|
+
end
|
62
|
+
|
58
63
|
def popen2e(command, &block)
|
59
64
|
Open3.popen2e(command, &block)
|
60
65
|
end
|
@@ -73,12 +78,25 @@ module Uffizzi
|
|
73
78
|
JSON.pretty_generate(data)
|
74
79
|
end
|
75
80
|
|
81
|
+
def format_to_pretty_list(data)
|
82
|
+
case data
|
83
|
+
when Array
|
84
|
+
data.map { |v| format_to_pretty_list(v) }.join("\n\n")
|
85
|
+
when Hash
|
86
|
+
data.map { |k, v| "- #{k.to_s.upcase}: #{v}" }.join("\n").strip
|
87
|
+
else
|
88
|
+
data
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
76
92
|
def format_message(message)
|
77
93
|
case output_format
|
78
94
|
when PRETTY_JSON
|
79
95
|
format_to_pretty_json(message)
|
80
96
|
when REGULAR_JSON
|
81
97
|
format_to_json(message)
|
98
|
+
when PRETTY_LIST
|
99
|
+
format_to_pretty_list(message)
|
82
100
|
else
|
83
101
|
message
|
84
102
|
end
|
data/lib/uffizzi/version.rb
CHANGED
data/man/uffizzi
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
.\" generated with Ronn-NG/v0.9.1
|
2
2
|
.\" http://github.com/apjanke/ronn-ng/tree/0.9.1
|
3
|
-
.TH "UFFIZZI" "" "
|
3
|
+
.TH "UFFIZZI" "" "October 2023" ""
|
4
4
|
.SH "NAME"
|
5
5
|
\fBuffizzi\fR \- manage Uffizzi resources
|
6
6
|
.SH "SYNOPSIS"
|
@@ -33,6 +33,9 @@ GROUP is one of the following:
|
|
33
33
|
project
|
34
34
|
Manage Uffizzi project resources including compose files for
|
35
35
|
specifying compose environment (preview) configurations and secrets
|
36
|
+
|
37
|
+
dev
|
38
|
+
Creates a Uffizzi cluster preconfigured for development workflows
|
36
39
|
.fi
|
37
40
|
.SH "COMMAND"
|
38
41
|
.nf
|
@@ -0,0 +1,30 @@
|
|
1
|
+
$ uffizzi cluster sleep -h
|
2
|
+
uffizzi-cluster-sleep - put a cluster to sleep (non-destructive)
|
3
|
+
================================================================
|
4
|
+
|
5
|
+
## SYNOPSIS
|
6
|
+
uffizzi cluster sleep [CLUSTER_NAME]
|
7
|
+
|
8
|
+
## DESCRIPTION
|
9
|
+
Scales a Uffizzi cluster down to zero resource utilization
|
10
|
+
while keeping the namespace and any stateful resources,
|
11
|
+
like persistent volume claims. If no CLUSTER_NAME is
|
12
|
+
specified, the kubeconfig current context is used.
|
13
|
+
|
14
|
+
For more information on Uffizzi clusters, see:
|
15
|
+
https://docs.uffizzi.com/references/cli/
|
16
|
+
|
17
|
+
## OPTIONS
|
18
|
+
CLUSTER_NAME
|
19
|
+
The name of the target Uffizzi cluster
|
20
|
+
|
21
|
+
## EXAMPLES
|
22
|
+
To put the Uffizzi cluster in the current context to
|
23
|
+
sleep, run:
|
24
|
+
|
25
|
+
$ uffizzi cluster sleep
|
26
|
+
|
27
|
+
To put a Uffizzi cluster outside the current context to
|
28
|
+
sleep, run:
|
29
|
+
|
30
|
+
$ uffizzi cluster sleep my-cluster
|
@@ -0,0 +1,28 @@
|
|
1
|
+
$ uffizzi cluster wake -h
|
2
|
+
uffizzi-cluster-wake - wake a cluster that is sleeping
|
3
|
+
================================================================
|
4
|
+
|
5
|
+
## SYNOPSIS
|
6
|
+
uffizzi cluster wake [CLUSTER_NAME]
|
7
|
+
|
8
|
+
## DESCRIPTION
|
9
|
+
Scales up a Uffizzi cluster to its original resource
|
10
|
+
utilization from zero (see 'uffizzi cluster sleep -h').
|
11
|
+
If no CLUSTER_NAME is specified, the kubeconfig current
|
12
|
+
context is used.
|
13
|
+
|
14
|
+
For more information on Uffizzi clusters, see:
|
15
|
+
https://docs.uffizzi.com/references/cli/
|
16
|
+
|
17
|
+
## OPTIONS
|
18
|
+
CLUSTER_NAME
|
19
|
+
The name of the target Uffizzi cluster
|
20
|
+
|
21
|
+
## EXAMPLES
|
22
|
+
To wake the Uffizzi cluster in the current context, run:
|
23
|
+
|
24
|
+
$ uffizzi cluster wake
|
25
|
+
|
26
|
+
To wake a Uffizzi cluster outside the current context, run:
|
27
|
+
|
28
|
+
$ uffizzi cluster wake my-cluster
|
data/man/uffizzi-cluster.ronn
CHANGED
data/man/uffizzi-dev
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
.\" generated with Ronn-NG/v0.9.1
|
2
|
+
.\" http://github.com/apjanke/ronn-ng/tree/0.9.1
|
3
|
+
.TH "UFFIZZI\-DEV" "" "October 2023" ""
|
4
|
+
.SH "NAME"
|
5
|
+
\fBuffizzi\-dev\fR \- manage dev environments
|
6
|
+
.SH "SYNOPSIS"
|
7
|
+
.nf
|
8
|
+
uffizzi dev COMMAND
|
9
|
+
.fi
|
10
|
+
.SH "DESCRIPTION"
|
11
|
+
.nf
|
12
|
+
Manage Uffizzi development environments\.
|
13
|
+
|
14
|
+
Use these commands for building, pushing, and deploying your
|
15
|
+
project changes to a remote development cluster\. Cloud\-based
|
16
|
+
dev environments offer many benefits compared to traditional
|
17
|
+
local development, including:
|
18
|
+
\- More similar to production deployments
|
19
|
+
\- Access to more memory and CPU for resource\-intensive
|
20
|
+
apps
|
21
|
+
\- Scalability and flexibility for microservices apps
|
22
|
+
\- Faster build times
|
23
|
+
\- Avoid accumulation of build artifacts on local machine
|
24
|
+
\- App components available at public URLs or IP addresses
|
25
|
+
\- TLS certificates for HTTPS
|
26
|
+
\- Better team collaboration via shareable links
|
27
|
+
|
28
|
+
For more information on Uffizzi clusters, see:
|
29
|
+
https://docs\.uffizzi\.com/references/cli/
|
30
|
+
.fi
|
31
|
+
.SH "COMMANDS"
|
32
|
+
.nf
|
33
|
+
COMMAND is one of the following:
|
34
|
+
|
35
|
+
start
|
36
|
+
Start a dev environment
|
37
|
+
|
38
|
+
stop
|
39
|
+
Stop a dev environment
|
40
|
+
|
41
|
+
describe
|
42
|
+
Display details of a dev environment
|
43
|
+
|
44
|
+
ingress
|
45
|
+
Display ingress hosts
|
46
|
+
.fi
|
47
|
+
.SH "HELP"
|
48
|
+
.nf
|
49
|
+
Run \'uffizzi dev COMMAND \-\-help\' for more information on a command\.
|
50
|
+
.fi
|
51
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
.\" generated with Ronn-NG/v0.9.1
|
2
|
+
.\" http://github.com/apjanke/ronn-ng/tree/0.9.1
|
3
|
+
.TH "UFFIZZI\-DEV\-DESCRIBE" "" "October 2023" ""
|
4
|
+
.SH "NAME"
|
5
|
+
\fBuffizzi\-dev\-describe\fR
|
6
|
+
.P
|
7
|
+
$ uffizzi dev describe \-h uffizzi\-dev\-describe \- show metadata for a dev environment ================================================================
|
8
|
+
.SH "SYNOPSIS"
|
9
|
+
.nf
|
10
|
+
uffizzi dev describe <NAME>
|
11
|
+
.fi
|
12
|
+
.SH "DESCRIPTION"
|
13
|
+
.nf
|
14
|
+
Shows metadata for a dev environment
|
15
|
+
|
16
|
+
This command can fail for the following reasons:
|
17
|
+
\- The dev environment specified does not exist\.
|
18
|
+
\- The dev environment specified belongs to a different project\.
|
19
|
+
|
20
|
+
For more information on Uffizzi clusters, see:
|
21
|
+
https://docs\.uffizzi\.com/references/cli/
|
22
|
+
.fi
|
23
|
+
.SH "POSITIONAL ARGUMENTS"
|
24
|
+
.nf
|
25
|
+
[NAME]
|
26
|
+
NAME for the dev environment you want to describe\.
|
27
|
+
This is an optional argument\.
|
28
|
+
.fi
|
29
|
+
.SH "EXAMPLES"
|
30
|
+
.nf
|
31
|
+
The following command prints metadata for the dev
|
32
|
+
environment:
|
33
|
+
|
34
|
+
$ uffizzi dev describe
|
35
|
+
.fi
|
36
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
$ uffizzi dev describe -h
|
2
|
+
uffizzi-dev-describe - show metadata for a dev environment
|
3
|
+
================================================================
|
4
|
+
|
5
|
+
## SYNOPSIS
|
6
|
+
uffizzi dev describe <NAME>
|
7
|
+
|
8
|
+
## DESCRIPTION
|
9
|
+
Shows metadata for a dev environment
|
10
|
+
|
11
|
+
This command can fail for the following reasons:
|
12
|
+
- The dev environment specified does not exist.
|
13
|
+
- The dev environment specified belongs to a different project.
|
14
|
+
|
15
|
+
For more information on Uffizzi clusters, see:
|
16
|
+
https://docs.uffizzi.com/references/cli/
|
17
|
+
|
18
|
+
## POSITIONAL ARGUMENTS
|
19
|
+
[NAME]
|
20
|
+
NAME for the dev environment you want to describe.
|
21
|
+
This is an optional argument.
|
22
|
+
|
23
|
+
## EXAMPLES
|
24
|
+
The following command prints metadata for the dev
|
25
|
+
environment:
|
26
|
+
|
27
|
+
$ uffizzi dev describe
|
@@ -0,0 +1,43 @@
|
|
1
|
+
uffizzi-dev - manage dev environments
|
2
|
+
================================================================
|
3
|
+
|
4
|
+
## SYNOPSIS
|
5
|
+
uffizzi dev COMMAND
|
6
|
+
|
7
|
+
## DESCRIPTION
|
8
|
+
Manage Uffizzi development environments.
|
9
|
+
|
10
|
+
Use these commands for building, pushing, and deploying your
|
11
|
+
project changes to a remote development cluster. Cloud-based
|
12
|
+
dev environments offer many benefits compared to traditional
|
13
|
+
local development, including:
|
14
|
+
- More similar to production deployments
|
15
|
+
- Access to more memory and CPU for resource-intensive
|
16
|
+
apps
|
17
|
+
- Scalability and flexibility for microservices apps
|
18
|
+
- Faster build times
|
19
|
+
- Avoid accumulation of build artifacts on local machine
|
20
|
+
- App components available at public URLs or IP addresses
|
21
|
+
- TLS certificates for HTTPS
|
22
|
+
- Better team collaboration via shareable links
|
23
|
+
|
24
|
+
For more information on Uffizzi clusters, see:
|
25
|
+
https://docs.uffizzi.com/references/cli/
|
26
|
+
|
27
|
+
## COMMANDS
|
28
|
+
COMMAND is one of the following:
|
29
|
+
|
30
|
+
start
|
31
|
+
Start a dev environment
|
32
|
+
|
33
|
+
stop
|
34
|
+
Stop a dev environment
|
35
|
+
|
36
|
+
describe
|
37
|
+
Display details of a dev environment
|
38
|
+
|
39
|
+
ingress
|
40
|
+
Display ingress hosts
|
41
|
+
|
42
|
+
## HELP
|
43
|
+
Run 'uffizzi dev COMMAND --help' for more information on a command.
|
data/man/uffizzi.ronn
CHANGED
@@ -29,6 +29,9 @@ uffizzi - manage Uffizzi resources
|
|
29
29
|
Manage Uffizzi project resources including compose files for
|
30
30
|
specifying compose environment (preview) configurations and secrets
|
31
31
|
|
32
|
+
dev
|
33
|
+
Creates a Uffizzi cluster preconfigured for development workflows
|
34
|
+
|
32
35
|
## COMMAND
|
33
36
|
COMMAND is one of the following:
|
34
37
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: uffizzi-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1
|
4
|
+
version: 2.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josh Thurman
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2023-10-
|
12
|
+
date: 2023-10-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -480,8 +480,10 @@ files:
|
|
480
480
|
- man/uffizzi-cluster-disconnect.ronn
|
481
481
|
- man/uffizzi-cluster-list
|
482
482
|
- man/uffizzi-cluster-list.ronn
|
483
|
+
- man/uffizzi-cluster-sleep.ronn
|
483
484
|
- man/uffizzi-cluster-update-kubeconfig
|
484
485
|
- man/uffizzi-cluster-update-kubeconfig.ronn
|
486
|
+
- man/uffizzi-cluster-wake.ronn
|
485
487
|
- man/uffizzi-cluster.ronn
|
486
488
|
- man/uffizzi-compose
|
487
489
|
- man/uffizzi-compose-create
|
@@ -519,10 +521,14 @@ files:
|
|
519
521
|
- man/uffizzi-connect-ghcr
|
520
522
|
- man/uffizzi-connect-ghcr.ronn
|
521
523
|
- man/uffizzi-connect.ronn
|
524
|
+
- man/uffizzi-dev
|
525
|
+
- man/uffizzi-dev-describe
|
526
|
+
- man/uffizzi-dev-describe.ronn
|
522
527
|
- man/uffizzi-dev-start
|
523
528
|
- man/uffizzi-dev-start.ronn
|
524
529
|
- man/uffizzi-dev-stop
|
525
530
|
- man/uffizzi-dev-stop.ronn
|
531
|
+
- man/uffizzi-dev.ronn
|
526
532
|
- man/uffizzi-disconnect
|
527
533
|
- man/uffizzi-disconnect.ronn
|
528
534
|
- man/uffizzi-login
|