uffizzi-cli 2.1.4 → 2.2.0

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