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 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