uffizzi-cli 2.1.4 → 2.2.0

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: c57cec1f82e6f54de217f0d1e17b88a8ce5bb2dd58eb702df2a10930508f1203
4
+ data.tar.gz: b904d36aef21a479dac014429f09eebd80cb1715dfd71cf2457fea34cb5f5175
5
5
  SHA512:
6
- metadata.gz: 2d821267fb032b76f69cf03a2d0e08318e46b87fc8ac2084550a293dbd18591b16c10a48abf5efd82ffff9288edfda9105e00f6db979eb06424c7f68a80c5b56
7
- data.tar.gz: 3981689282eb4c43ce6bdd2281252cef925d609f879d73aeed3754cbf5b39c983d7927394ba81e1127db00ff372cbe6d8dec5ec2e092ccf28dfb9b4ec9e73bfd
6
+ metadata.gz: 9d5f9f27fab4efec5b44910d37e53ce60b65ba6995e89a5e65b1a7d60c0925899f7cce271c2670d728aeb66845da3c075cab9492baf1f2c45ac3d80504ae2b4f
7
+ data.tar.gz: c3b2a87f53468a55939cde535cf0389eaca7b2666b581312089ee0c51eed195a58366c7c763b16fad8da53ffe8ca9ba92b4cd4bfea88ccffc09397b4d6f39204
@@ -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,6 +61,16 @@ 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 = {})
@@ -81,6 +91,10 @@ module Uffizzi
81
91
  handle_update_kubeconfig_command(project_slug, command_args)
82
92
  when 'disconnect'
83
93
  ClusterDisconnectService.handle(options)
94
+ when 'sleep'
95
+ handle_sleep_command(project_slug, command_args)
96
+ when 'wake'
97
+ handle_wake_command(project_slug, command_args)
84
98
  end
85
99
  end
86
100
 
@@ -131,7 +145,7 @@ module Uffizzi
131
145
 
132
146
  if ClusterService.failed?(cluster_data[:state])
133
147
  spinner.error
134
- Uffizzi.ui.say_error_and_exit("Cluster with name: #{cluster_name} failed to be created.")
148
+ Uffizzi.ui.say_error_and_exit("Cluster #{cluster_name} failed to be created.")
135
149
  end
136
150
 
137
151
  spinner.success
@@ -196,7 +210,8 @@ module Uffizzi
196
210
 
197
211
  def handle_update_kubeconfig_command(project_slug, command_args)
198
212
  kubeconfig_path = options[:kubeconfig] || KubeconfigService.default_path
199
- cluster_data = fetch_cluster_data(project_slug, command_args[:cluster_name])
213
+ cluster_name = command_args[:cluster_name]
214
+ cluster_data = fetch_cluster_data(project_slug, cluster_name)
200
215
 
201
216
  unless cluster_data[:kubeconfig].present?
202
217
  say_error_update_kubeconfig(cluster_data)
@@ -218,13 +233,48 @@ module Uffizzi
218
233
  new_kubeconfig
219
234
  end
220
235
 
221
- update_clusters_config(cluster_data[:id], kubeconfig_path: kubeconfig_path)
236
+ update_clusters_config(cluster_data[:id], name: cluster_name, kubeconfig_path: kubeconfig_path)
222
237
 
223
238
  return if options[:quiet]
224
239
 
225
240
  Uffizzi.ui.say("Kubeconfig was updated by the path: #{kubeconfig_path}")
226
241
  end
227
242
 
243
+ def handle_sleep_command(project_slug, command_args)
244
+ cluster_name = command_args[:cluster_name] || ConfigFile.read_option(:current_cluster)&.fetch(:name)
245
+ return handle_missing_cluster_name_error if cluster_name.nil?
246
+
247
+ response = scale_down_cluster(ConfigFile.read_option(:server), project_slug, cluster_name)
248
+ return ResponseHelper.handle_failed_response(response) unless ResponseHelper.ok?(response)
249
+
250
+ spinner = TTY::Spinner.new("[:spinner] Scaling down cluster #{cluster_name}...", format: :dots)
251
+ spinner.auto_spin
252
+ ClusterService.wait_cluster_scale_down(project_slug, cluster_name)
253
+
254
+ spinner.success
255
+ Uffizzi.ui.say("Cluster #{cluster_name} was successfully scaled down")
256
+ end
257
+
258
+ def handle_wake_command(project_slug, command_args)
259
+ cluster_name = command_args[:cluster_name] || ConfigFile.read_option(:current_cluster)&.fetch(:name)
260
+ return handle_missing_cluster_name_error if cluster_name.nil?
261
+
262
+ response = scale_up_cluster(ConfigFile.read_option(:server), project_slug, cluster_name)
263
+ return ResponseHelper.handle_failed_response(response) unless ResponseHelper.ok?(response)
264
+
265
+ spinner = TTY::Spinner.new("[:spinner] Waking up cluster #{cluster_name}...", format: :dots)
266
+ spinner.auto_spin
267
+ cluster_data = ClusterService.wait_cluster_scale_up(project_slug, cluster_name)
268
+
269
+ if ClusterService.failed_scaling_up?(cluster_data[:state])
270
+ spinner.error
271
+ Uffizzi.ui.say_error_and_exit("Failed to wake up cluster #{cluster_name}.")
272
+ end
273
+
274
+ spinner.success
275
+ Uffizzi.ui.say("Cluster #{cluster_name} was successfully scaled up")
276
+ end
277
+
228
278
  def say_error_update_kubeconfig(cluster_data)
229
279
  if ClusterService.failed?(cluster_data[:state])
230
280
  Uffizzi.ui.say_error_and_exit('Kubeconfig is empty because cluster failed to be created.')
@@ -321,6 +371,7 @@ module Uffizzi
321
371
  is_update_current_context = options[:'update-current-context']
322
372
  parsed_kubeconfig = parse_kubeconfig(cluster_data[:kubeconfig])
323
373
  rendered_cluster_data = render_cluster_data(cluster_data)
374
+ cluster_name = cluster_data[:name]
324
375
 
325
376
  Uffizzi.ui.enable_stdout
326
377
  Uffizzi.ui.say("Cluster with name: #{rendered_cluster_data[:name]} was created.")
@@ -332,7 +383,7 @@ module Uffizzi
332
383
  Uffizzi.ui.say(rendered_cluster_data) if Uffizzi.ui.output_format
333
384
 
334
385
  save_kubeconfig(parsed_kubeconfig, kubeconfig_path)
335
- update_clusters_config(cluster_data[:id], kubeconfig_path: kubeconfig_path)
386
+ update_clusters_config(cluster_data[:id], name: cluster_name, kubeconfig_path: kubeconfig_path)
336
387
  GithubService.write_to_github_env(rendered_cluster_data) if GithubService.github_actions_exists?
337
388
  end
338
389
 
@@ -362,6 +413,7 @@ module Uffizzi
362
413
  def update_clusters_config(id, params)
363
414
  clusters_config = Uffizzi::ConfigHelper.update_clusters_config_by_id(id, params)
364
415
  ConfigFile.write_option(:clusters, clusters_config)
416
+ ConfigFile.write_option(:current_cluster, ConfigHelper.cluster_config_by_id(id))
365
417
  end
366
418
 
367
419
  def render_cluster_data(cluster_data)
@@ -400,5 +452,11 @@ module Uffizzi
400
452
  previous_current_contexts = Uffizzi::ConfigHelper.set_previous_current_context_by_path(kubeconfig_path, current_context)
401
453
  ConfigFile.write_option(:previous_current_contexts, previous_current_contexts)
402
454
  end
455
+
456
+ def handle_missing_cluster_name_error
457
+ Uffizzi.ui.say("No kubeconfig found at #{KubeconfigService.default_path}")
458
+ Uffizzi.ui.say('Please update the current context or provide a cluster name.')
459
+ Uffizzi.ui.say('$uffizzi cluster sleep my-cluster')
460
+ end
403
461
  end
404
462
  end
@@ -81,11 +81,12 @@ module Uffizzi
81
81
  def handle_succeed_cluster_creation(cluster_data)
82
82
  kubeconfig_path = options[:kubeconfig] || KubeconfigService.default_path
83
83
  parsed_kubeconfig = parse_kubeconfig(cluster_data[:kubeconfig])
84
+ cluster_name = cluster_data[:name]
84
85
 
85
- Uffizzi.ui.say("Cluster with name: #{cluster_data[:name]} was created.")
86
+ Uffizzi.ui.say("Cluster with name: #{cluster_name} was created.")
86
87
 
87
88
  save_kubeconfig(parsed_kubeconfig, kubeconfig_path)
88
- update_clusters_config(cluster_data[:id], kubeconfig_path: kubeconfig_path)
89
+ update_clusters_config(cluster_data[:id], name: cluster_name, kubeconfig_path: kubeconfig_path)
89
90
  end
90
91
 
91
92
  def save_kubeconfig(kubeconfig, kubeconfig_path)
@@ -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)
@@ -6,6 +6,9 @@ class ClusterService
6
6
  CLUSTER_STATE_DEPLOYING_NAMESPACE = 'deploying_namespace'
7
7
  CLUSTER_STATE_DEPLOYING = 'deploying'
8
8
  CLUSTER_STATE_DEPLOYED = 'deployed'
9
+ CLUSTER_STATE_SCALING_DOWN = 'scaling_down'
10
+ CLUSTER_STATE_SCALING_UP = 'scaling_up'
11
+ CLUSTER_FAILED_SCALING_UP = 'failed_scaling_up'
9
12
  CLUSTER_STATE_FAILED_DEPLOY_NAMESPACE = 'failed_deploy_namespace'
10
13
  CLUSTER_STATE_FAILED = 'failed'
11
14
  CLUSTER_NAME_MAX_LENGTH = 15
@@ -26,6 +29,18 @@ class ClusterService
26
29
  [CLUSTER_STATE_FAILED_DEPLOY_NAMESPACE, CLUSTER_STATE_FAILED].include?(cluster_state)
27
30
  end
28
31
 
32
+ def scaling_up?(cluster_state)
33
+ cluster_state === CLUSTER_STATE_SCALING_UP
34
+ end
35
+
36
+ def scaling_down?(cluster_state)
37
+ cluster_state === CLUSTER_STATE_SCALING_DOWN
38
+ end
39
+
40
+ def failed_scaling_up?(cluster_state)
41
+ cluster_state === CLUSTER_FAILED_SCALING_UP
42
+ end
43
+
29
44
  def wait_cluster_deploy(project_slug, cluster_name, oidc_token)
30
45
  loop do
31
46
  params = {
@@ -43,6 +58,38 @@ class ClusterService
43
58
  end
44
59
  end
45
60
 
61
+ def wait_cluster_scale_up(project_slug, cluster_name)
62
+ loop do
63
+ params = {
64
+ cluster_name: cluster_name,
65
+ }
66
+ response = get_cluster(Uffizzi::ConfigFile.read_option(:server), project_slug, params)
67
+ return Uffizzi::ResponseHelper.handle_failed_response(response) unless Uffizzi::ResponseHelper.ok?(response)
68
+
69
+ cluster_data = response.dig(:body, :cluster)
70
+
71
+ return cluster_data unless scaling_up?(cluster_data[:state])
72
+
73
+ sleep(5)
74
+ end
75
+ end
76
+
77
+ def wait_cluster_scale_down(project_slug, cluster_name)
78
+ loop do
79
+ params = {
80
+ cluster_name: cluster_name,
81
+ }
82
+ response = get_cluster(Uffizzi::ConfigFile.read_option(:server), project_slug, params)
83
+ return Uffizzi::ResponseHelper.handle_failed_response(response) unless Uffizzi::ResponseHelper.ok?(response)
84
+
85
+ cluster_data = response.dig(:body, :cluster)
86
+
87
+ return unless scaling_down?(cluster_data[:state])
88
+
89
+ sleep(3)
90
+ end
91
+ end
92
+
46
93
  def generate_name
47
94
  name = Faker::Internet.domain_word[0..CLUSTER_NAME_MAX_LENGTH]
48
95
 
@@ -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.0'
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"
@@ -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,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.
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.0
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-19 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,12 @@ files:
519
521
  - man/uffizzi-connect-ghcr
520
522
  - man/uffizzi-connect-ghcr.ronn
521
523
  - man/uffizzi-connect.ronn
524
+ - man/uffizzi-dev
522
525
  - man/uffizzi-dev-start
523
526
  - man/uffizzi-dev-start.ronn
524
527
  - man/uffizzi-dev-stop
525
528
  - man/uffizzi-dev-stop.ronn
529
+ - man/uffizzi-dev.ronn
526
530
  - man/uffizzi-disconnect
527
531
  - man/uffizzi-disconnect.ronn
528
532
  - man/uffizzi-login