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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2cd0af3bb51a08a6c011cf4271fc886586fbb262af3419aeaa02c32aa97dc29d
4
- data.tar.gz: 3f588da373233552310f0490d8e0384acdd2cce6598cb3e2dc3d8435ebda2eab
3
+ metadata.gz: d24e9582d66d329f45ab42194dfefbf1558843fbc94578dfc8b2127f0d7f3122
4
+ data.tar.gz: fa901b1e7257fc8c9384bcf11c4f41490f767dabbecbf039056aa8b0ed488f38
5
5
  SHA512:
6
- metadata.gz: 2d821267fb032b76f69cf03a2d0e08318e46b87fc8ac2084550a293dbd18591b16c10a48abf5efd82ffff9288edfda9105e00f6db979eb06424c7f68a80c5b56
7
- data.tar.gz: 3981689282eb4c43ce6bdd2281252cef925d609f879d73aeed3754cbf5b39c983d7927394ba81e1127db00ff372cbe6d8dec5ec2e092ccf28dfb9b4ec9e73bfd
6
+ metadata.gz: cda766f7ab21158e56cfb5e5ea3dabd0416de0fd1d1671c268347465db66ce4a3864f3aa51be04a6fd789848fd6d86cbf2c3e62437aaaf63803f633b5ababc2e
7
+ data.tar.gz: d6e79d2994cc487a7986315371715e15a85d5d42659a4ea21361ac7e289219441ba6ee5e77468dd5380e1ee5a8b9214fed0a4894bb2b7c4f26353647c3954fcc
@@ -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
@@ -22,7 +22,7 @@ module Uffizzi
22
22
  run('list')
23
23
  end
24
24
 
25
- desc 'create [NAME]', 'Create a cluster'
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 [NAME]', 'Describe a cluster'
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 [NAME]', 'Delete a cluster'
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(project_slug)
82
+ handle_list_command
74
83
  when 'create'
75
- handle_create_command(project_slug, command_args)
84
+ handle_create_command(command_args)
76
85
  when 'describe'
77
- handle_describe_command(project_slug, command_args)
86
+ handle_describe_command(command_args)
78
87
  when 'delete'
79
- handle_delete_command(project_slug, command_args)
88
+ handle_delete_command(command_args)
80
89
  when 'update-kubeconfig'
81
- handle_update_kubeconfig_command(project_slug, command_args)
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(project_slug)
100
+ def handle_list_command
88
101
  is_all = options[:all]
89
102
  response = if is_all
90
- get_account_clusters(ConfigFile.read_option(:server), ConfigFile.read_option(:account, :id))
103
+ get_account_clusters(server, ConfigFile.read_option(:account, :id))
91
104
  else
92
- oidc_token = ConfigFile.read_option(:oidc_token)
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(project_slug, command_args)
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
- params = cluster_creation_params(
119
- name: cluster_name,
120
- creation_source: creation_source,
121
- manifest_file_path: options[:manifest],
122
- k8s_version: k8s_version,
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, ConfigFile.read_option(:oidc_token))
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 with name: #{cluster_name} failed to be created.")
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, ConfigFile.read_option(:server), project_slug)
149
+ handle_interrupt_creation(cluster_name)
141
150
  end
142
151
  # rubocop:enable Metrics/PerceivedComplexity
143
152
 
144
- def handle_describe_command(project_slug, command_args)
145
- cluster_data = fetch_cluster_data(project_slug, command_args[:cluster_name])
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
- handle_succeed_describe(cluster_data)
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(project_slug, command_args)
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(project_slug, cluster_name) unless is_delete_kubeconfig
165
+ return handle_delete_cluster(cluster_name) unless is_delete_kubeconfig
155
166
 
156
- cluster_data = fetch_cluster_data(project_slug, cluster_name)
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(project_slug, cluster_name)
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(project_slug, cluster_name)
194
+ def handle_delete_cluster(cluster_name)
184
195
  params = {
185
196
  cluster_name: cluster_name,
186
- oidc_token: ConfigFile.read_option(:oidc_token),
197
+ oidc_token: oidc_token,
187
198
  }
188
- response = delete_cluster(ConfigFile.read_option(:server), project_slug, params)
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(project_slug, command_args)
208
+ def handle_update_kubeconfig_command(command_args)
198
209
  kubeconfig_path = options[:kubeconfig] || KubeconfigService.default_path
199
- cluster_data = fetch_cluster_data(project_slug, command_args[:cluster_name])
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(name:, creation_source:, manifest_file_path:, k8s_version:)
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: 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, server, project_slug)
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
@@ -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
- Uffizzi::AuthHelper.check_login(options[:project])
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.check_running_daemon if options[:quiet]
56
+ DevService.check_no_running_process!
21
57
  DevService.check_skaffold_config_existence(config_path)
22
- cluster_id, cluster_name = start_create_cluster
23
- kubeconfig = wait_cluster_creation(cluster_name)
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
- DevService.start_basic_skaffold(config_path, options)
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
- desc 'stop', 'Stop dev environment'
38
- def stop
39
- return Uffizzi.ui.say('Uffizzi dev is not running') unless File.exist?(DevService.pid_path)
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
- pid = File.read(DevService.pid_path).to_i
42
- File.delete(DevService.pid_path)
80
+ def handle_describe_command
81
+ DevService.check_environment_exist!
43
82
 
44
- Uffizzi.process.kill('QUIT', pid)
45
- Uffizzi.ui.say('Uffizzi dev was stopped')
46
- rescue Errno::ESRCH
47
- Uffizzi.ui.say('Uffizzi dev is not running')
48
- File.delete(DevService.pid_path)
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
- private
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(ConfigFile.read_option(:server), project_slug, params)
107
+ response = create_cluster(server, project_slug, params)
61
108
  return ResponseHelper.handle_failed_response(response) unless ResponseHelper.created?(response)
62
109
 
63
- cluster_id = response.dig(:body, :cluster, :id)
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, ConfigFile.read_option(:oidc_token))
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: #{cluster_data[:name]} was created.")
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(name:, creation_source:, k8s_version:)
112
- oidc_token = Uffizzi::ConfigFile.read_option(:oidc_token)
113
-
155
+ def cluster_creation_params
114
156
  {
115
157
  cluster: {
116
- name: name,
158
+ name: ClusterService.generate_name,
117
159
  manifest: nil,
118
- creation_source: creation_source,
119
- k8s_version: 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(cluster_id, cluster_name, kubeconfig)
126
- return if cluster_id.nil? || cluster_name.nil?
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: ConfigFile.read_option(:oidc_token),
176
+ oidc_token: oidc_token,
133
177
  }
134
- response = delete_cluster(ConfigFile.read_option(:server), project_slug, params)
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
- File.delete(DevService.pid_path) if File.exist?(DevService.pid_path)
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
- DEFAULT_REGISTRY_REPO = 'registry.uffizzi.com'
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 check_running_daemon
12
- return unless File.exist?(pid_path)
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
- pid = File.read(pid_path)
15
- File.delete(pid_path) if pid.blank?
16
- Uffizzi.process.kill(0, pid.to_i)
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.ui.say_error_and_exit("You have already started uffizzi dev as daemon. To stop the process do 'uffizzi dev stop'")
46
+ Uffizzi.process.kill(0, pid.to_i)
47
+ true
19
48
  rescue Errno::ESRCH
20
- File.delete(pid_path)
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Uffizzi
4
- VERSION = '2.1.4'
4
+ VERSION = '2.2.1'
5
5
  end
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" "" "September 2023" ""
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
@@ -25,6 +25,12 @@ uffizzi-cluster - manage clusters
25
25
  list
26
26
  List all clusters
27
27
 
28
+ sleep
29
+ Put a cluster to sleep (non-destructive)
30
+
31
+ wake
32
+ Wake a cluster that is sleeping
33
+
28
34
  update-kubeconfig
29
35
  Update kubeconfig file
30
36
 
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
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-16 00:00:00.000000000 Z
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