uffizzi-cli 2.1.4 → 2.2.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/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
|