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 +4 -4
- data/lib/uffizzi/auth_helper.rb +1 -1
- data/lib/uffizzi/cli/cluster.rb +57 -70
- data/lib/uffizzi/cli/dev.rb +127 -45
- data/lib/uffizzi/helpers/config_helper.rb +8 -0
- data/lib/uffizzi/services/cluster_service.rb +24 -0
- data/lib/uffizzi/services/dev_service.rb +110 -8
- data/lib/uffizzi/shell.rb +18 -0
- data/lib/uffizzi/version.rb +1 -1
- data/man/uffizzi +3 -0
- data/man/uffizzi-dev-describe +36 -0
- data/man/uffizzi-dev-describe.ronn +27 -0
- data/man/uffizzi.ronn +3 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d24e9582d66d329f45ab42194dfefbf1558843fbc94578dfc8b2127f0d7f3122
|
4
|
+
data.tar.gz: fa901b1e7257fc8c9384bcf11c4f41490f767dabbecbf039056aa8b0ed488f38
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cda766f7ab21158e56cfb5e5ea3dabd0416de0fd1d1671c268347465db66ce4a3864f3aa51be04a6fd789848fd6d86cbf2c3e62437aaaf63803f633b5ababc2e
|
7
|
+
data.tar.gz: d6e79d2994cc487a7986315371715e15a85d5d42659a4ea21361ac7e289219441ba6ee5e77468dd5380e1ee5a8b9214fed0a4894bb2b7c4f26353647c3954fcc
|
data/lib/uffizzi/auth_helper.rb
CHANGED
@@ -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
|
data/lib/uffizzi/cli/cluster.rb
CHANGED
@@ -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
|
82
|
+
handle_list_command
|
84
83
|
when 'create'
|
85
|
-
handle_create_command(
|
84
|
+
handle_create_command(command_args)
|
86
85
|
when 'describe'
|
87
|
-
handle_describe_command(
|
86
|
+
handle_describe_command(command_args)
|
88
87
|
when 'delete'
|
89
|
-
handle_delete_command(
|
88
|
+
handle_delete_command(command_args)
|
90
89
|
when 'update-kubeconfig'
|
91
|
-
handle_update_kubeconfig_command(
|
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
|
100
|
+
def handle_list_command
|
102
101
|
is_all = options[:all]
|
103
102
|
response = if is_all
|
104
|
-
get_account_clusters(
|
103
|
+
get_account_clusters(server, ConfigFile.read_option(:account, :id))
|
105
104
|
else
|
106
|
-
|
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(
|
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
|
-
|
133
|
-
name: cluster_name
|
134
|
-
|
135
|
-
|
136
|
-
|
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,
|
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
|
149
|
+
handle_interrupt_creation(cluster_name)
|
155
150
|
end
|
156
151
|
# rubocop:enable Metrics/PerceivedComplexity
|
157
152
|
|
158
|
-
def handle_describe_command(
|
159
|
-
cluster_data = fetch_cluster_data(
|
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
|
-
|
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(
|
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(
|
165
|
+
return handle_delete_cluster(cluster_name) unless is_delete_kubeconfig
|
169
166
|
|
170
|
-
cluster_data = fetch_cluster_data(
|
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(
|
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(
|
194
|
+
def handle_delete_cluster(cluster_name)
|
198
195
|
params = {
|
199
196
|
cluster_name: cluster_name,
|
200
|
-
oidc_token:
|
197
|
+
oidc_token: oidc_token,
|
201
198
|
}
|
202
|
-
response = delete_cluster(
|
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(
|
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(
|
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(
|
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:
|
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
|
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
|
data/lib/uffizzi/cli/dev.rb
CHANGED
@@ -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
|
-
|
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.
|
56
|
+
DevService.check_no_running_process!
|
21
57
|
DevService.check_skaffold_config_existence(config_path)
|
22
|
-
|
23
|
-
|
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
|
-
|
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
|
-
|
38
|
-
|
39
|
-
|
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
|
-
|
42
|
-
|
80
|
+
def handle_describe_command
|
81
|
+
DevService.check_environment_exist!
|
43
82
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
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
|
-
|
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(
|
107
|
+
response = create_cluster(server, project_slug, params)
|
61
108
|
return ResponseHelper.handle_failed_response(response) unless ResponseHelper.created?(response)
|
62
109
|
|
63
|
-
|
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,
|
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
|
113
|
-
oidc_token = Uffizzi::ConfigFile.read_option(:oidc_token)
|
114
|
-
|
155
|
+
def cluster_creation_params
|
115
156
|
{
|
116
157
|
cluster: {
|
117
|
-
name:
|
158
|
+
name: ClusterService.generate_name,
|
118
159
|
manifest: nil,
|
119
|
-
creation_source:
|
120
|
-
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(
|
127
|
-
|
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:
|
176
|
+
oidc_token: oidc_token,
|
134
177
|
}
|
135
|
-
response = delete_cluster(
|
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
|
-
|
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
|
-
|
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
|
12
|
-
|
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
|
-
|
15
|
-
|
16
|
-
|
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.
|
46
|
+
Uffizzi.process.kill(0, pid.to_i)
|
47
|
+
true
|
19
48
|
rescue Errno::ESRCH
|
20
|
-
|
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
|
data/lib/uffizzi/version.rb
CHANGED
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.
|
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-
|
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
|