uffizzi-cli 2.2.0 → 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: c57cec1f82e6f54de217f0d1e17b88a8ce5bb2dd58eb702df2a10930508f1203
4
- data.tar.gz: b904d36aef21a479dac014429f09eebd80cb1715dfd71cf2457fea34cb5f5175
3
+ metadata.gz: d24e9582d66d329f45ab42194dfefbf1558843fbc94578dfc8b2127f0d7f3122
4
+ data.tar.gz: fa901b1e7257fc8c9384bcf11c4f41490f767dabbecbf039056aa8b0ed488f38
5
5
  SHA512:
6
- metadata.gz: 9d5f9f27fab4efec5b44910d37e53ce60b65ba6995e89a5e65b1a7d60c0925899f7cce271c2670d728aeb66845da3c075cab9492baf1f2c45ac3d80504ae2b4f
7
- data.tar.gz: c3b2a87f53468a55939cde535cf0389eaca7b2666b581312089ee0c51eed195a58366c7c763b16fad8da53ffe8ca9ba92b4cd4bfea88ccffc09397b4d6f39204
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
@@ -76,19 +76,18 @@ module Uffizzi
76
76
  def run(command, command_args = {})
77
77
  Uffizzi.ui.output_format = options[:output]
78
78
  Uffizzi::AuthHelper.check_login(options[:project])
79
- project_slug = options[:project].nil? ? ConfigFile.read_option(:project) : options[:project]
80
79
 
81
80
  case command
82
81
  when 'list'
83
- handle_list_command(project_slug)
82
+ handle_list_command
84
83
  when 'create'
85
- handle_create_command(project_slug, command_args)
84
+ handle_create_command(command_args)
86
85
  when 'describe'
87
- handle_describe_command(project_slug, command_args)
86
+ handle_describe_command(command_args)
88
87
  when 'delete'
89
- handle_delete_command(project_slug, command_args)
88
+ handle_delete_command(command_args)
90
89
  when 'update-kubeconfig'
91
- handle_update_kubeconfig_command(project_slug, command_args)
90
+ handle_update_kubeconfig_command(command_args)
92
91
  when 'disconnect'
93
92
  ClusterDisconnectService.handle(options)
94
93
  when 'sleep'
@@ -98,13 +97,12 @@ module Uffizzi
98
97
  end
99
98
  end
100
99
 
101
- def handle_list_command(project_slug)
100
+ def handle_list_command
102
101
  is_all = options[:all]
103
102
  response = if is_all
104
- get_account_clusters(ConfigFile.read_option(:server), ConfigFile.read_option(:account, :id))
103
+ get_account_clusters(server, ConfigFile.read_option(:account, :id))
105
104
  else
106
- oidc_token = ConfigFile.read_option(:oidc_token)
107
- get_project_clusters(ConfigFile.read_option(:server), project_slug, oidc_token: oidc_token)
105
+ get_project_clusters(server, project_slug, oidc_token: oidc_token)
108
106
  end
109
107
 
110
108
  if ResponseHelper.ok?(response)
@@ -115,7 +113,7 @@ module Uffizzi
115
113
  end
116
114
 
117
115
  # rubocop:disable Metrics/PerceivedComplexity
118
- def handle_create_command(project_slug, command_args)
116
+ def handle_create_command(command_args)
119
117
  Uffizzi.ui.disable_stdout if Uffizzi.ui.output_format
120
118
 
121
119
  if options[:name]
@@ -125,23 +123,20 @@ module Uffizzi
125
123
  end
126
124
 
127
125
  cluster_name = command_args[:name] || options[:name] || ClusterService.generate_name
128
- creation_source = options[:"creation-source"] || ClusterService::MANUAL_CREATION_SOURCE
129
- k8s_version = options[:"k8s-version"]
130
126
  Uffizzi.ui.say_error_and_exit("Cluster name: #{cluster_name} is not valid.") unless ClusterService.valid_name?(cluster_name)
131
127
 
132
- params = cluster_creation_params(
133
- name: cluster_name,
134
- creation_source: creation_source,
135
- manifest_file_path: options[:manifest],
136
- k8s_version: k8s_version,
137
- )
138
- 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)
139
134
 
140
135
  return ResponseHelper.handle_failed_response(response) unless ResponseHelper.created?(response)
141
136
 
142
137
  spinner = TTY::Spinner.new("[:spinner] Creating cluster #{cluster_name}...", format: :dots)
143
138
  spinner.auto_spin
144
- 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)
145
140
 
146
141
  if ClusterService.failed?(cluster_data[:state])
147
142
  spinner.error
@@ -151,26 +146,28 @@ module Uffizzi
151
146
  spinner.success
152
147
  handle_succeed_create_response(cluster_data)
153
148
  rescue SystemExit, Interrupt, SocketError
154
- handle_interrupt_creation(cluster_name, ConfigFile.read_option(:server), project_slug)
149
+ handle_interrupt_creation(cluster_name)
155
150
  end
156
151
  # rubocop:enable Metrics/PerceivedComplexity
157
152
 
158
- def handle_describe_command(project_slug, command_args)
159
- 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)
160
156
 
161
- handle_succeed_describe(cluster_data)
157
+ Uffizzi.ui.output_format = Uffizzi::UI::Shell::PRETTY_LIST
158
+ Uffizzi.ui.say(render_data)
162
159
  end
163
160
 
164
- def handle_delete_command(project_slug, command_args)
161
+ def handle_delete_command(command_args)
165
162
  cluster_name = command_args[:cluster_name]
166
163
  is_delete_kubeconfig = options[:'delete-config']
167
164
 
168
- return handle_delete_cluster(project_slug, cluster_name) unless is_delete_kubeconfig
165
+ return handle_delete_cluster(cluster_name) unless is_delete_kubeconfig
169
166
 
170
- cluster_data = fetch_cluster_data(project_slug, cluster_name)
167
+ cluster_data = ClusterService.fetch_cluster_data(cluster_name, **cluster_api_connection_params)
171
168
  kubeconfig = parse_kubeconfig(cluster_data[:kubeconfig])
172
169
 
173
- handle_delete_cluster(project_slug, cluster_name)
170
+ handle_delete_cluster(cluster_name)
174
171
  exclude_kubeconfig(cluster_data[:id], kubeconfig) if kubeconfig.present?
175
172
  end
176
173
 
@@ -194,12 +191,12 @@ module Uffizzi
194
191
  end
195
192
  end
196
193
 
197
- def handle_delete_cluster(project_slug, cluster_name)
194
+ def handle_delete_cluster(cluster_name)
198
195
  params = {
199
196
  cluster_name: cluster_name,
200
- oidc_token: ConfigFile.read_option(:oidc_token),
197
+ oidc_token: oidc_token,
201
198
  }
202
- response = delete_cluster(ConfigFile.read_option(:server), project_slug, params)
199
+ response = delete_cluster(server, project_slug, params)
203
200
 
204
201
  if ResponseHelper.no_content?(response)
205
202
  Uffizzi.ui.say("Cluster #{cluster_name} deleted")
@@ -208,10 +205,10 @@ module Uffizzi
208
205
  end
209
206
  end
210
207
 
211
- def handle_update_kubeconfig_command(project_slug, command_args)
208
+ def handle_update_kubeconfig_command(command_args)
212
209
  kubeconfig_path = options[:kubeconfig] || KubeconfigService.default_path
213
210
  cluster_name = command_args[:cluster_name]
214
- cluster_data = fetch_cluster_data(project_slug, cluster_name)
211
+ cluster_data = ClusterService.fetch_cluster_data(cluster_name, **cluster_api_connection_params)
215
212
 
216
213
  unless cluster_data[:kubeconfig].present?
217
214
  say_error_update_kubeconfig(cluster_data)
@@ -289,13 +286,15 @@ module Uffizzi
289
286
  end
290
287
  end
291
288
 
292
- 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"]
293
293
  manifest_content = load_manifest_file(manifest_file_path)
294
- oidc_token = Uffizzi::ConfigFile.read_option(:oidc_token)
295
294
 
296
295
  {
297
296
  cluster: {
298
- name: name,
297
+ name: cluster_name,
299
298
  manifest: manifest_content,
300
299
  creation_source: creation_source,
301
300
  k8s_version: k8s_version,
@@ -312,7 +311,7 @@ module Uffizzi
312
311
  raise Uffizzi::Error.new(e.message)
313
312
  end
314
313
 
315
- def handle_interrupt_creation(cluster_name, server, project_slug)
314
+ def handle_interrupt_creation(cluster_name)
316
315
  deletion_response = delete_cluster(server, project_slug, cluster_name: cluster_name)
317
316
  deletion_message = if ResponseHelper.no_content?(deletion_response)
318
317
  "The cluster #{cluster_name} has been disabled."
@@ -348,24 +347,6 @@ module Uffizzi
348
347
  end.join("\n")
349
348
  end
350
349
 
351
- def handle_succeed_describe(cluster_data)
352
- prepared_cluster_data = {
353
- name: cluster_data[:name],
354
- status: cluster_data[:state],
355
- created: Time.strptime(cluster_data[:created_at], '%Y-%m-%dT%H:%M:%S.%N').strftime('%a %b %d %H:%M:%S %Y'),
356
- url: cluster_data[:host],
357
- k8s_version: cluster_data[:k8s_version],
358
- }
359
-
360
- rendered_cluster_data = if Uffizzi.ui.output_format.nil?
361
- prepared_cluster_data.map { |k, v| "- #{k.to_s.upcase}: #{v}" }.join("\n").strip
362
- else
363
- prepared_cluster_data
364
- end
365
-
366
- Uffizzi.ui.say(rendered_cluster_data)
367
- end
368
-
369
350
  def handle_succeed_create_response(cluster_data)
370
351
  kubeconfig_path = options[:kubeconfig] || KubeconfigService.default_path
371
352
  is_update_current_context = options[:'update-current-context']
@@ -432,20 +413,6 @@ module Uffizzi
432
413
  Psych.safe_load(Base64.decode64(kubeconfig))
433
414
  end
434
415
 
435
- def fetch_cluster_data(project_slug, cluster_name)
436
- params = {
437
- cluster_name: cluster_name,
438
- oidc_token: ConfigFile.read_option(:oidc_token),
439
- }
440
- response = get_cluster(ConfigFile.read_option(:server), project_slug, params)
441
-
442
- if ResponseHelper.ok?(response)
443
- response.dig(:body, :cluster)
444
- else
445
- ResponseHelper.handle_failed_response(response)
446
- end
447
- end
448
-
449
416
  def save_previous_current_context(kubeconfig_path, current_context)
450
417
  return if kubeconfig_path.nil? || ConfigHelper.previous_current_context_by_path(kubeconfig_path).present?
451
418
 
@@ -458,5 +425,25 @@ module Uffizzi
458
425
  Uffizzi.ui.say('Please update the current context or provide a cluster name.')
459
426
  Uffizzi.ui.say('$uffizzi cluster sleep my-cluster')
460
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
461
448
  end
462
449
  end
@@ -15,67 +15,110 @@ 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)
@@ -109,30 +152,30 @@ module Uffizzi
109
152
  ConfigFile.write_option(:clusters, clusters_config)
110
153
  end
111
154
 
112
- def cluster_creation_params(name:, creation_source:, k8s_version:)
113
- oidc_token = Uffizzi::ConfigFile.read_option(:oidc_token)
114
-
155
+ def cluster_creation_params
115
156
  {
116
157
  cluster: {
117
- name: name,
158
+ name: ClusterService.generate_name,
118
159
  manifest: nil,
119
- creation_source: creation_source,
120
- k8s_version: k8s_version,
160
+ creation_source: ClusterService::MANUAL_CREATION_SOURCE,
161
+ k8s_version: options[:"k8s-version"],
121
162
  },
122
163
  token: oidc_token,
123
164
  }
124
165
  end
125
166
 
126
- def handle_delete_cluster(cluster_id, cluster_name, kubeconfig)
127
- 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])
128
171
 
129
172
  exclude_kubeconfig(cluster_id, kubeconfig) if kubeconfig.present?
130
173
 
131
174
  params = {
132
175
  cluster_name: cluster_name,
133
- oidc_token: ConfigFile.read_option(:oidc_token),
176
+ oidc_token: oidc_token,
134
177
  }
135
- response = delete_cluster(ConfigFile.read_option(:server), project_slug, params)
178
+ response = delete_cluster(server, project_slug, params)
136
179
 
137
180
  if ResponseHelper.no_content?(response)
138
181
  Uffizzi.ui.say("Cluster #{cluster_name} deleted")
@@ -180,19 +223,58 @@ module Uffizzi
180
223
  Uffizzi.process.daemon(true)
181
224
 
182
225
  at_exit do
183
- File.delete(DevService.pid_path) if File.exist?(DevService.pid_path)
226
+ DevService.delete_pid
184
227
  end
185
228
 
229
+ DevService.save_pid
186
230
  File.delete(DevService.logs_path) if File.exist?(DevService.logs_path)
187
- File.write(DevService.pid_path, Uffizzi.process.pid)
188
231
  DevService.start_check_pid_file_existence
189
232
  DevService.start_demonised_skaffold(config_path, options)
190
233
  rescue StandardError => e
191
234
  File.open(DevService.logs_path, 'a') { |f| f.puts(e.message) }
192
235
  end
193
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
+
194
268
  def project_slug
195
269
  @project_slug ||= ConfigFile.read_option(:project)
196
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
197
279
  end
198
280
  end
@@ -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,5 +1,6 @@
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
@@ -104,5 +105,28 @@ class ClusterService
104
105
  regex = /\A[a-zA-Z0-9-]*\z/
105
106
  regex.match?(name)
106
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
107
131
  end
108
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.2.0'
4
+ VERSION = '2.2.1'
5
5
  end
data/man/uffizzi CHANGED
@@ -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,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
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.2.0
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-19 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
@@ -522,6 +522,8 @@ files:
522
522
  - man/uffizzi-connect-ghcr.ronn
523
523
  - man/uffizzi-connect.ronn
524
524
  - man/uffizzi-dev
525
+ - man/uffizzi-dev-describe
526
+ - man/uffizzi-dev-describe.ronn
525
527
  - man/uffizzi-dev-start
526
528
  - man/uffizzi-dev-start.ronn
527
529
  - man/uffizzi-dev-stop