uffizzi-cli 1.0.5 → 2.0.29
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/config/uffizzi.rb +1 -0
- data/lib/uffizzi/auth_helper.rb +13 -5
- data/lib/uffizzi/cli/account.rb +122 -0
- data/lib/uffizzi/cli/cluster.rb +363 -0
- data/lib/uffizzi/cli/common.rb +2 -4
- data/lib/uffizzi/cli/config.rb +5 -4
- data/lib/uffizzi/cli/connect.rb +14 -8
- data/lib/uffizzi/cli/disconnect.rb +1 -1
- data/lib/uffizzi/cli/login.rb +130 -66
- data/lib/uffizzi/cli/login_by_identity_token.rb +11 -7
- data/lib/uffizzi/cli/preview/service.rb +1 -1
- data/lib/uffizzi/cli/preview.rb +33 -32
- data/lib/uffizzi/cli/project.rb +17 -9
- data/lib/uffizzi/cli.rb +46 -7
- data/lib/uffizzi/clients/api/api_client.rb +92 -2
- data/lib/uffizzi/clients/api/api_routes.rb +44 -0
- data/lib/uffizzi/clients/api/http_client.rb +19 -7
- data/lib/uffizzi/config_file.rb +15 -40
- data/lib/uffizzi/error.rb +15 -0
- data/lib/uffizzi/helpers/config_helper.rb +49 -0
- data/lib/uffizzi/helpers/file_helper.rb +25 -0
- data/lib/uffizzi/helpers/login_helper.rb +33 -0
- data/lib/uffizzi/helpers/project_helper.rb +19 -0
- data/lib/uffizzi/promt.rb +4 -0
- data/lib/uffizzi/response_helper.rb +33 -14
- data/lib/uffizzi/services/cluster_service.rb +59 -0
- data/lib/uffizzi/services/compose_file_service.rb +5 -4
- data/lib/uffizzi/services/env_variables_service.rb +1 -1
- data/lib/uffizzi/services/github_service.rb +21 -0
- data/lib/uffizzi/services/kubeconfig_service.rb +132 -0
- data/lib/uffizzi/services/preview_service.rb +52 -18
- data/lib/uffizzi/shell.rb +19 -16
- data/lib/uffizzi/token.rb +37 -0
- data/lib/uffizzi/version.rb +1 -1
- data/lib/uffizzi.rb +10 -0
- data/man/uffizzi +7 -5
- data/man/uffizzi-account +29 -0
- data/man/uffizzi-account-list +26 -0
- data/man/uffizzi-account-list.html +103 -0
- data/man/uffizzi-account-list.ronn +19 -0
- data/man/uffizzi-account-set-default +29 -0
- data/man/uffizzi-account-set-default.html +105 -0
- data/man/uffizzi-account-set-default.ronn +22 -0
- data/man/uffizzi-account.html +106 -0
- data/man/uffizzi-account.ronn +23 -0
- data/man/uffizzi-cluster +37 -0
- data/man/uffizzi-cluster-create +49 -0
- data/man/uffizzi-cluster-create.ronn +41 -0
- data/man/uffizzi-cluster-delete +32 -0
- data/man/uffizzi-cluster-delete.ronn +24 -0
- data/man/uffizzi-cluster-describe +39 -0
- data/man/uffizzi-cluster-describe.ronn +30 -0
- data/man/uffizzi-cluster-list +34 -0
- data/man/uffizzi-cluster-list.ronn +26 -0
- data/man/uffizzi-cluster-update-kubeconfig +37 -0
- data/man/uffizzi-cluster-update-kubeconfig.ronn +29 -0
- data/man/uffizzi-cluster.ronn +32 -0
- data/man/uffizzi-compose +39 -0
- data/man/uffizzi-compose-create +67 -0
- data/man/uffizzi-compose-create.ronn +57 -0
- data/man/uffizzi-compose-delete +38 -0
- data/man/uffizzi-compose-delete.ronn +29 -0
- data/man/uffizzi-compose-describe +38 -0
- data/man/uffizzi-compose-describe.ronn +29 -0
- data/man/uffizzi-compose-events +38 -0
- data/man/uffizzi-compose-events.ronn +29 -0
- data/man/uffizzi-compose-list +58 -0
- data/man/uffizzi-compose-list.ronn +49 -0
- data/man/uffizzi-compose-service-list +42 -0
- data/man/uffizzi-compose-service-list.ronn +32 -0
- data/man/uffizzi-compose-service-logs +59 -0
- data/man/uffizzi-compose-service-logs.ronn +48 -0
- data/man/uffizzi-compose-update +61 -0
- data/man/uffizzi-compose-update.ronn +51 -0
- data/man/uffizzi-compose.ronn +33 -0
- data/man/uffizzi-compose_service_logs +59 -0
- data/man/uffizzi-compose_service_logs.ronn +50 -0
- data/man/uffizzi-config +2 -2
- data/man/uffizzi-config.ronn +1 -1
- data/man/uffizzi-connect +2 -4
- data/man/uffizzi-connect-acr +2 -2
- data/man/uffizzi-connect-acr.ronn +1 -1
- data/man/uffizzi-connect-docker-hub +2 -2
- data/man/uffizzi-connect-docker-hub.ronn +1 -1
- data/man/uffizzi-connect-docker-registry +2 -2
- data/man/uffizzi-connect-docker-registry.ronn +1 -1
- data/man/uffizzi-connect-ecr +2 -2
- data/man/uffizzi-connect-ecr.ronn +1 -1
- data/man/uffizzi-connect-gcr +2 -2
- data/man/uffizzi-connect-gcr.ronn +1 -1
- data/man/uffizzi-connect-ghcr +2 -2
- data/man/uffizzi-connect-ghcr.ronn +1 -1
- data/man/uffizzi-connect.ronn +2 -2
- data/man/uffizzi-disconnect +2 -2
- data/man/uffizzi-disconnect.ronn +1 -1
- data/man/uffizzi-login +7 -3
- data/man/uffizzi-login-by-identity-token +3 -3
- data/man/uffizzi-login-by-identity-token.ronn +2 -2
- data/man/uffizzi-login.html +113 -0
- data/man/uffizzi-login.ronn +6 -2
- data/man/uffizzi-logout +2 -2
- data/man/uffizzi-logout.ronn +1 -1
- data/man/uffizzi-preview +9 -9
- data/man/uffizzi-preview-create +22 -20
- data/man/uffizzi-preview-create.ronn +28 -26
- data/man/uffizzi-preview-delete +11 -10
- data/man/uffizzi-preview-delete.ronn +12 -11
- data/man/uffizzi-preview-describe +10 -10
- data/man/uffizzi-preview-describe.ronn +11 -11
- data/man/uffizzi-preview-events +12 -11
- data/man/uffizzi-preview-events.ronn +13 -12
- data/man/uffizzi-preview-list +19 -18
- data/man/uffizzi-preview-list.ronn +21 -20
- data/man/uffizzi-preview-service-list +16 -12
- data/man/uffizzi-preview-service-list.ronn +16 -13
- data/man/uffizzi-preview-service-logs +14 -12
- data/man/uffizzi-preview-service-logs.ronn +18 -17
- data/man/uffizzi-preview-update +19 -18
- data/man/uffizzi-preview-update.ronn +21 -20
- data/man/uffizzi-preview.ronn +10 -10
- data/man/uffizzi-preview_service_logs +14 -12
- data/man/uffizzi-preview_service_logs.ronn +18 -17
- data/man/uffizzi-project +3 -3
- data/man/uffizzi-project-compose +2 -2
- data/man/uffizzi-project-compose-describe +2 -2
- data/man/uffizzi-project-compose-describe.ronn +1 -1
- data/man/uffizzi-project-compose-set +2 -2
- data/man/uffizzi-project-compose-set.ronn +1 -1
- data/man/uffizzi-project-compose-unset +2 -2
- data/man/uffizzi-project-compose-unset.ronn +1 -1
- data/man/uffizzi-project-compose.ronn +1 -1
- data/man/uffizzi-project-create +2 -2
- data/man/uffizzi-project-create.ronn +1 -1
- data/man/uffizzi-project-delete +2 -2
- data/man/uffizzi-project-delete.ronn +1 -1
- data/man/uffizzi-project-describe +3 -3
- data/man/uffizzi-project-describe.ronn +1 -1
- data/man/uffizzi-project-preview-describe +37 -0
- data/man/uffizzi-project-preview-describe.ronn +29 -0
- data/man/uffizzi-project-preview-set +66 -0
- data/man/uffizzi-project-preview-set.ronn +57 -0
- data/man/uffizzi-project-secret +2 -2
- data/man/uffizzi-project-secret-create +2 -2
- data/man/uffizzi-project-secret-create.ronn +1 -1
- data/man/uffizzi-project-secret-delete +2 -2
- data/man/uffizzi-project-secret-delete.ronn +1 -1
- data/man/uffizzi-project-secret-list +2 -2
- data/man/uffizzi-project-secret-list.ronn +1 -1
- data/man/uffizzi-project-secret.ronn +1 -1
- data/man/uffizzi-project-set-default +2 -2
- data/man/uffizzi-project-set-default.ronn +1 -1
- data/man/uffizzi-project.html +124 -0
- data/man/uffizzi-project.ronn +2 -2
- data/man/uffizzi.ronn +12 -10
- metadata +134 -22
data/lib/uffizzi/cli.rb
CHANGED
@@ -19,6 +19,7 @@ module Uffizzi
|
|
19
19
|
desc 'login [OPTIONS]', 'Login to Uffizzi to view and manage your previews'
|
20
20
|
method_option :server, required: false, aliases: '-s'
|
21
21
|
method_option :username, required: false, aliases: '-u'
|
22
|
+
method_option :email, required: false, aliases: '-e'
|
22
23
|
def login
|
23
24
|
require_relative 'cli/login'
|
24
25
|
Login.new(options).run
|
@@ -26,7 +27,8 @@ module Uffizzi
|
|
26
27
|
|
27
28
|
desc 'login_by_identity_token [OPTIONS]', 'Login or register to Uffizzi to view and manage your previews'
|
28
29
|
method_option :server, required: true, aliases: '-s'
|
29
|
-
method_option :
|
30
|
+
method_option :oidc_token, required: true, aliases: '-t'
|
31
|
+
method_option :access_token, required: false
|
30
32
|
def login_by_identity_token
|
31
33
|
require_relative 'cli/login_by_identity_token'
|
32
34
|
LoginByIdentityToken.new(options).run
|
@@ -38,6 +40,10 @@ module Uffizzi
|
|
38
40
|
Logout.new(options).run
|
39
41
|
end
|
40
42
|
|
43
|
+
desc 'account', 'account'
|
44
|
+
require_relative 'cli/account'
|
45
|
+
subcommand 'account', Cli::Account
|
46
|
+
|
41
47
|
desc 'project', 'project'
|
42
48
|
require_relative 'cli/project'
|
43
49
|
subcommand 'project', Cli::Project
|
@@ -46,10 +52,14 @@ module Uffizzi
|
|
46
52
|
require_relative 'cli/config'
|
47
53
|
subcommand 'config', Cli::Config
|
48
54
|
|
49
|
-
desc '
|
55
|
+
desc 'compose', 'compose'
|
50
56
|
method_option :project, required: false
|
51
57
|
require_relative 'cli/preview'
|
52
|
-
subcommand '
|
58
|
+
subcommand 'compose', Cli::Preview
|
59
|
+
|
60
|
+
desc 'cluster', 'cluster'
|
61
|
+
require_relative 'cli/cluster'
|
62
|
+
subcommand 'cluster', Cli::Cluster
|
53
63
|
|
54
64
|
desc 'connect', 'connect'
|
55
65
|
require_relative 'cli/connect'
|
@@ -61,6 +71,8 @@ module Uffizzi
|
|
61
71
|
Disconnect.new.run(credential_type)
|
62
72
|
end
|
63
73
|
|
74
|
+
map preview: :compose
|
75
|
+
|
64
76
|
class << self
|
65
77
|
protected
|
66
78
|
|
@@ -70,10 +82,8 @@ module Uffizzi
|
|
70
82
|
return Common.show_manual(filename(args)) if show_help?(args, opts)
|
71
83
|
|
72
84
|
super
|
73
|
-
rescue Interrupt
|
74
|
-
|
75
|
-
rescue StandardError => e
|
76
|
-
raise Uffizzi::Error.new(e.message)
|
85
|
+
rescue Interrupt, StandardError => e
|
86
|
+
ci_workflow? ? handle_ci_exceptions(e) : handle_repl_exceptions(e)
|
77
87
|
end
|
78
88
|
|
79
89
|
private
|
@@ -89,6 +99,35 @@ module Uffizzi
|
|
89
99
|
help_options = ['--help', '-h', '--help=true']
|
90
100
|
args.empty? || args.include?('help') || opts.any? { |opt| help_options.include?(opt) }
|
91
101
|
end
|
102
|
+
|
103
|
+
def ci_workflow?
|
104
|
+
!['', 'false', 'f', '0'].include?(ENV['CI_WORKFLOW'].to_s.downcase)
|
105
|
+
end
|
106
|
+
|
107
|
+
def handle_ci_exceptions(exception)
|
108
|
+
case exception
|
109
|
+
when Thor::Error
|
110
|
+
raise exception
|
111
|
+
when Interrupt
|
112
|
+
raise Uffizzi::CliError.new('CI process was interrupted')
|
113
|
+
else
|
114
|
+
Sentry.capture_exception(exception)
|
115
|
+
raise Uffizzi::CliError.new('System Fault')
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def handle_repl_exceptions(exception)
|
120
|
+
case exception
|
121
|
+
when Thor::Error
|
122
|
+
raise exception
|
123
|
+
when Interrupt
|
124
|
+
raise Uffizzi::CliError.new('The command was interrupted')
|
125
|
+
when StandardError
|
126
|
+
raise Uffizzi::CliError.new(exception.message)
|
127
|
+
else
|
128
|
+
raise exception
|
129
|
+
end
|
130
|
+
end
|
92
131
|
end
|
93
132
|
end
|
94
133
|
end
|
@@ -4,6 +4,16 @@ require_relative 'api_routes'
|
|
4
4
|
require_relative 'http_client'
|
5
5
|
|
6
6
|
module ApiClient
|
7
|
+
class ResponseError < StandardError
|
8
|
+
attr_reader :response
|
9
|
+
|
10
|
+
def initialize(response)
|
11
|
+
@response = response
|
12
|
+
|
13
|
+
super(response.to_s)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
7
17
|
include ApiRoutes
|
8
18
|
|
9
19
|
def create_session(server, params = {})
|
@@ -27,6 +37,13 @@ module ApiClient
|
|
27
37
|
build_response(response)
|
28
38
|
end
|
29
39
|
|
40
|
+
def fetch_accounts(server)
|
41
|
+
uri = accounts_uri(server)
|
42
|
+
response = http_client.make_get_request(uri)
|
43
|
+
|
44
|
+
build_response(response)
|
45
|
+
end
|
46
|
+
|
30
47
|
def fetch_projects(server)
|
31
48
|
uri = projects_uri(server)
|
32
49
|
response = http_client.make_get_request(uri)
|
@@ -34,6 +51,13 @@ module ApiClient
|
|
34
51
|
build_response(response)
|
35
52
|
end
|
36
53
|
|
54
|
+
def fetch_account_projects(server, account_id)
|
55
|
+
uri = account_projects_uri(server, account_id)
|
56
|
+
response = http_client.make_get_request(uri)
|
57
|
+
|
58
|
+
build_response(response)
|
59
|
+
end
|
60
|
+
|
37
61
|
def fetch_credentials(server, account_id)
|
38
62
|
uri = credentials_uri(server, account_id)
|
39
63
|
|
@@ -49,13 +73,20 @@ module ApiClient
|
|
49
73
|
build_response(response)
|
50
74
|
end
|
51
75
|
|
52
|
-
def
|
76
|
+
def fetch_project(server, project_slug)
|
53
77
|
uri = project_uri(server, project_slug)
|
54
78
|
response = http_client.make_get_request(uri)
|
55
79
|
|
56
80
|
build_response(response)
|
57
81
|
end
|
58
82
|
|
83
|
+
def fetch_account(server, account_name)
|
84
|
+
uri = account_uri(server, account_name)
|
85
|
+
response = http_client.make_get_request(uri)
|
86
|
+
|
87
|
+
build_response(response)
|
88
|
+
end
|
89
|
+
|
59
90
|
def create_project(server, account_id, params)
|
60
91
|
uri = create_projects_uri(server, account_id)
|
61
92
|
response = http_client.make_post_request(uri, params)
|
@@ -210,6 +241,65 @@ module ApiClient
|
|
210
241
|
build_response(response)
|
211
242
|
end
|
212
243
|
|
244
|
+
def get_k8s_container_description(server, project_slug, deployment_id, container_name)
|
245
|
+
uri = k8s_container_description_uri(server, project_slug, deployment_id, container_name)
|
246
|
+
response = http_client.make_get_request(uri)
|
247
|
+
|
248
|
+
build_response(response)
|
249
|
+
end
|
250
|
+
|
251
|
+
def get_project_clusters(server, project_slug, params = nil)
|
252
|
+
uri = project_clusters_uri(server, project_slug, oidc_token: params[:oidc_token])
|
253
|
+
response = http_client.make_get_request(uri)
|
254
|
+
|
255
|
+
build_response(response)
|
256
|
+
end
|
257
|
+
|
258
|
+
def create_cluster(server, project_slug, params)
|
259
|
+
uri = project_clusters_uri(server, project_slug, oidc_token: nil)
|
260
|
+
response = http_client.make_post_request(uri, params)
|
261
|
+
|
262
|
+
build_response(response)
|
263
|
+
end
|
264
|
+
|
265
|
+
def create_access_token(server, session_id)
|
266
|
+
uri = access_tokens_url(server)
|
267
|
+
|
268
|
+
params = { session_id: session_id }
|
269
|
+
|
270
|
+
response = http_client.make_post_request(uri, params)
|
271
|
+
|
272
|
+
build_response(response)
|
273
|
+
end
|
274
|
+
|
275
|
+
def get_cluster(server, project_slug, params)
|
276
|
+
uri = cluster_uri(server, project_slug, cluster_name: params[:cluster_name], oidc_token: params[:oidc_token])
|
277
|
+
response = http_client.make_get_request(uri)
|
278
|
+
|
279
|
+
build_response(response)
|
280
|
+
end
|
281
|
+
|
282
|
+
def get_access_token(server, code)
|
283
|
+
uri = access_token_url(server, code)
|
284
|
+
response = http_client.make_get_request(uri)
|
285
|
+
|
286
|
+
build_response(response)
|
287
|
+
end
|
288
|
+
|
289
|
+
def delete_cluster(server, project_slug, params)
|
290
|
+
uri = cluster_uri(server, project_slug, cluster_name: params[:cluster_name], oidc_token: params[:oidc_token])
|
291
|
+
response = http_client.make_delete_request(uri)
|
292
|
+
|
293
|
+
build_response(response)
|
294
|
+
end
|
295
|
+
|
296
|
+
def get_account_clusters(server, account_id)
|
297
|
+
uri = account_clusters_uri(server, account_id)
|
298
|
+
response = http_client.make_get_request(uri)
|
299
|
+
|
300
|
+
build_response(response)
|
301
|
+
end
|
302
|
+
|
213
303
|
private
|
214
304
|
|
215
305
|
def http_client
|
@@ -221,7 +311,7 @@ module ApiClient
|
|
221
311
|
params[:basic_auth_password] = Uffizzi::ConfigFile.read_option(:basic_auth_password)
|
222
312
|
end
|
223
313
|
|
224
|
-
@http_client = Uffizzi::HttpClient.new(params
|
314
|
+
@http_client = Uffizzi::HttpClient.new(params)
|
225
315
|
end
|
226
316
|
|
227
317
|
@http_client
|
@@ -3,6 +3,14 @@
|
|
3
3
|
require 'cgi'
|
4
4
|
|
5
5
|
module ApiRoutes
|
6
|
+
def accounts_uri(server)
|
7
|
+
"#{server}/api/cli/v1/accounts"
|
8
|
+
end
|
9
|
+
|
10
|
+
def account_uri(server, account_name)
|
11
|
+
"#{server}/api/cli/v1/accounts/#{account_name}"
|
12
|
+
end
|
13
|
+
|
6
14
|
def compose_file_uri(server, project_slug)
|
7
15
|
"#{server}/api/cli/v1/projects/#{project_slug}/compose_file"
|
8
16
|
end
|
@@ -15,6 +23,10 @@ module ApiRoutes
|
|
15
23
|
"#{server}/api/cli/v1/projects"
|
16
24
|
end
|
17
25
|
|
26
|
+
def account_projects_uri(server, account_id)
|
27
|
+
"#{server}/api/cli/v1/accounts/#{account_id}/projects"
|
28
|
+
end
|
29
|
+
|
18
30
|
def create_projects_uri(server, account_id)
|
19
31
|
"#{server}/api/cli/v1/accounts/#{account_id}/projects"
|
20
32
|
end
|
@@ -81,4 +93,36 @@ module ApiRoutes
|
|
81
93
|
def preview_service_logs_uri(server, project_slug, deployment_id, container_name)
|
82
94
|
"#{server}/api/cli/v1/projects/#{project_slug}/deployments/#{deployment_id}/containers/#{container_name}/logs"
|
83
95
|
end
|
96
|
+
|
97
|
+
def k8s_container_description_uri(server, project_slug, deployment_id, container_name)
|
98
|
+
"#{server}/api/cli/v1/projects/#{project_slug}/deployments/#{deployment_id}/containers/#{container_name}/k8s_container_description"
|
99
|
+
end
|
100
|
+
|
101
|
+
def project_clusters_uri(server, project_slug, oidc_token:)
|
102
|
+
return "#{server}/api/cli/v1/projects/#{project_slug}/clusters" if oidc_token.nil?
|
103
|
+
|
104
|
+
"#{server}/api/cli/v1/projects/#{project_slug}/clusters?token=#{oidc_token}"
|
105
|
+
end
|
106
|
+
|
107
|
+
def cluster_uri(server, project_slug, cluster_name:, oidc_token:)
|
108
|
+
return "#{server}/api/cli/v1/projects/#{project_slug}/clusters/#{cluster_name}" if oidc_token.nil?
|
109
|
+
|
110
|
+
"#{server}/api/cli/v1/projects/#{project_slug}/clusters/#{cluster_name}?token=#{oidc_token}"
|
111
|
+
end
|
112
|
+
|
113
|
+
def access_token_url(server, code)
|
114
|
+
"#{server}/api/cli/v1/access_tokens/#{code}"
|
115
|
+
end
|
116
|
+
|
117
|
+
def access_tokens_url(server)
|
118
|
+
"#{server}/api/cli/v1/access_tokens"
|
119
|
+
end
|
120
|
+
|
121
|
+
def browser_sign_in_url(server, session_id)
|
122
|
+
"#{server}/sign_in?session_id=#{session_id}"
|
123
|
+
end
|
124
|
+
|
125
|
+
def account_clusters_uri(server, account_id)
|
126
|
+
"#{server}/api/cli/v1/accounts/#{account_id}/clusters"
|
127
|
+
end
|
84
128
|
end
|
@@ -7,10 +7,10 @@ module Uffizzi
|
|
7
7
|
class HttpClient
|
8
8
|
attr_accessor :auth_cookie, :basic_auth_user, :basic_auth_password
|
9
9
|
|
10
|
-
def initialize(
|
11
|
-
@auth_cookie =
|
12
|
-
@basic_auth_user = basic_auth_user
|
13
|
-
@basic_auth_password = basic_auth_password
|
10
|
+
def initialize(params)
|
11
|
+
@auth_cookie = params[:cookie]
|
12
|
+
@basic_auth_user = params[:basic_auth_user]
|
13
|
+
@basic_auth_password = params[:basic_auth_password]
|
14
14
|
end
|
15
15
|
|
16
16
|
def make_get_request(request_uri)
|
@@ -41,13 +41,17 @@ module Uffizzi
|
|
41
41
|
http.request(request)
|
42
42
|
end
|
43
43
|
|
44
|
-
|
44
|
+
if response.is_a?(Net::HTTPUnauthorized)
|
45
|
+
Uffizzi::Token.delete if Uffizzi::Token.exists?
|
46
|
+
raise Uffizzi::Error.new('Not authorized')
|
47
|
+
end
|
45
48
|
|
46
49
|
response
|
47
50
|
end
|
48
51
|
|
49
52
|
def build_request(uri, params, method)
|
50
|
-
|
53
|
+
access_token = Uffizzi::Token.read
|
54
|
+
headers = get_headers(access_token)
|
51
55
|
request = case method
|
52
56
|
when :get
|
53
57
|
Net::HTTP::Get.new(uri.request_uri, headers)
|
@@ -62,9 +66,17 @@ module Uffizzi
|
|
62
66
|
request.body = params.to_json
|
63
67
|
end
|
64
68
|
request['Cookie'] = @auth_cookie
|
65
|
-
request.basic_auth(@basic_auth_user, @basic_auth_password)
|
69
|
+
request.basic_auth(@basic_auth_user, @basic_auth_password) unless access_token
|
66
70
|
|
67
71
|
request
|
68
72
|
end
|
73
|
+
|
74
|
+
def get_headers(access_token)
|
75
|
+
content_type_headers = { 'Content-Type' => 'application/json' }
|
76
|
+
auth_headers = access_token ? { 'Authorization' => "Bearer #{access_token}" } : {}
|
77
|
+
cli_version = { 'x-uffizzi-cli-version' => Uffizzi::VERSION }
|
78
|
+
|
79
|
+
content_type_headers.merge(auth_headers).merge(cli_version)
|
80
|
+
end
|
69
81
|
end
|
70
82
|
end
|
data/lib/uffizzi/config_file.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'json'
|
4
|
-
require '
|
4
|
+
require 'uffizzi/helpers/file_helper'
|
5
5
|
|
6
6
|
module Uffizzi
|
7
7
|
class ConfigFile
|
8
|
-
CONFIG_PATH = "#{Dir.home}/.config/uffizzi/config_default"
|
8
|
+
CONFIG_PATH = "#{Dir.home}/.config/uffizzi/config_default.json"
|
9
9
|
|
10
10
|
class << self
|
11
11
|
def config_path
|
@@ -20,23 +20,25 @@ module Uffizzi
|
|
20
20
|
File.exist?(config_path)
|
21
21
|
end
|
22
22
|
|
23
|
-
def read_option(option)
|
23
|
+
def read_option(option, nested_option = nil)
|
24
24
|
data = read
|
25
|
-
return nil unless data.is_a?(Hash)
|
26
25
|
|
27
|
-
data[option]
|
26
|
+
value = data[option]
|
27
|
+
return value.presence if nested_option.nil?
|
28
|
+
return nil unless value.is_a?(Hash)
|
29
|
+
|
30
|
+
value[nested_option].presence
|
28
31
|
end
|
29
32
|
|
30
33
|
def option_has_value?(option)
|
31
34
|
data = read
|
32
|
-
return false
|
35
|
+
return false unless option_exists?(option)
|
33
36
|
|
34
|
-
|
37
|
+
data[option].present?
|
35
38
|
end
|
36
39
|
|
37
40
|
def write_option(key, value)
|
38
41
|
data = exists? ? read : {}
|
39
|
-
return nil unless data.is_a?(Hash)
|
40
42
|
|
41
43
|
data[key] = value
|
42
44
|
write(data)
|
@@ -44,7 +46,7 @@ module Uffizzi
|
|
44
46
|
|
45
47
|
def unset_option(key)
|
46
48
|
data = read
|
47
|
-
return
|
49
|
+
return unless option_exists?(key)
|
48
50
|
|
49
51
|
data[key] = ''
|
50
52
|
write(data)
|
@@ -56,7 +58,6 @@ module Uffizzi
|
|
56
58
|
|
57
59
|
def list
|
58
60
|
data = read
|
59
|
-
return nil unless data.is_a?(Hash)
|
60
61
|
|
61
62
|
content = data.reduce('') do |acc, pair|
|
62
63
|
property, value = pair
|
@@ -70,7 +71,6 @@ module Uffizzi
|
|
70
71
|
|
71
72
|
def option_exists?(option)
|
72
73
|
data = read
|
73
|
-
return false unless data.is_a?(Hash)
|
74
74
|
|
75
75
|
data.key?(option)
|
76
76
|
end
|
@@ -79,43 +79,18 @@ module Uffizzi
|
|
79
79
|
|
80
80
|
def read
|
81
81
|
data = File.read(config_path)
|
82
|
-
|
83
|
-
options.reduce({}) do |acc, option|
|
84
|
-
key, value = option.split('=', 2)
|
85
|
-
acc.merge({ key.strip.to_sym => value.strip })
|
86
|
-
end
|
82
|
+
JSON.parse(data).deep_symbolize_keys
|
87
83
|
rescue Errno::ENOENT => e
|
88
84
|
file_path = e.message.split(' ').last
|
89
85
|
message = "Configuration file not found: #{file_path}\n" \
|
90
86
|
'To configure the uffizzi CLI interactively, run $ uffizzi config'
|
91
87
|
raise Uffizzi::Error.new(message)
|
88
|
+
rescue JSON::ParserError
|
89
|
+
{}
|
92
90
|
end
|
93
91
|
|
94
92
|
def write(data)
|
95
|
-
|
96
|
-
|
97
|
-
lock(config_path) { atomic_write(config_path, "#{config_path}.tmp", prepared_data) }
|
98
|
-
end
|
99
|
-
|
100
|
-
def prepare_data(data)
|
101
|
-
data.reduce('') do |acc, option|
|
102
|
-
key, value = option
|
103
|
-
"#{acc}#{key} = #{value}\n"
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
def atomic_write(path, temp_path, content)
|
108
|
-
File.open(temp_path, 'w') { |f| f.write(content) }
|
109
|
-
FileUtils.mv(temp_path, path)
|
110
|
-
end
|
111
|
-
|
112
|
-
def lock(path)
|
113
|
-
dir = File.dirname(path)
|
114
|
-
FileUtils.mkdir_p(dir) unless File.directory?(dir)
|
115
|
-
|
116
|
-
File.open(path).flock(File::LOCK_EX) if File.exist?(path)
|
117
|
-
yield
|
118
|
-
File.open(path).flock(File::LOCK_UN)
|
93
|
+
Uffizzi::FileHelper.write_with_lock(config_path, data.to_json)
|
119
94
|
end
|
120
95
|
end
|
121
96
|
end
|
data/lib/uffizzi/error.rb
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Uffizzi
|
4
|
+
RESPONSE_SERVER_ERROR_HEADER = "Server Error:\n"
|
5
|
+
CLI_ERROR_HEADER = "CLI Error:\n"
|
6
|
+
|
4
7
|
class Error < Thor::Error; end
|
8
|
+
|
9
|
+
class ServerResponseError < Thor::Error
|
10
|
+
def initialize(message)
|
11
|
+
super("#{RESPONSE_SERVER_ERROR_HEADER}#{message}")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class CliError < Thor::Error
|
16
|
+
def initialize(message)
|
17
|
+
super("#{CLI_ERROR_HEADER}#{message}")
|
18
|
+
end
|
19
|
+
end
|
5
20
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Uffizzi
|
4
|
+
module ConfigHelper
|
5
|
+
CLUSTER_PARAMS = [:kubeconfig_path].freeze
|
6
|
+
|
7
|
+
class ConfigParamsError < StandardError
|
8
|
+
def initialize(unavailable_params, key)
|
9
|
+
msg = "These params #{unavailable_params.join(', ')} is not available for #{key}"
|
10
|
+
|
11
|
+
super(msg)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def read_option_from_config(option)
|
17
|
+
ConfigFile.option_has_value?(option) ? ConfigFile.read_option(option) : nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def account_config(id, name = nil)
|
21
|
+
{ id: id, name: name }
|
22
|
+
end
|
23
|
+
|
24
|
+
def update_clusters_config_by_id(id, params)
|
25
|
+
unavailable_params = params.keys - CLUSTER_PARAMS
|
26
|
+
raise ConfigParamsError.new(unavailable_params, :cluster) if unavailable_params.present?
|
27
|
+
|
28
|
+
current_cluster = cluster_config_by_id(id) || {}
|
29
|
+
new_current_cluster = current_cluster.merge({ id: id }).merge(params)
|
30
|
+
|
31
|
+
clusters_config_without(id) << new_current_cluster
|
32
|
+
end
|
33
|
+
|
34
|
+
def clusters_config_without(id)
|
35
|
+
clusters.reject { |c| c[:id] == id }
|
36
|
+
end
|
37
|
+
|
38
|
+
def cluster_config_by_id(id)
|
39
|
+
clusters.detect { |c| c[:id] == id }
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def clusters
|
45
|
+
read_option_from_config(:clusters) || []
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Uffizzi
|
4
|
+
module FileHelper
|
5
|
+
class << self
|
6
|
+
def write_with_lock(path, data)
|
7
|
+
lock(path) { atomic_write(path, "#{path}.tmp", data) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def atomic_write(path, temp_path, content)
|
11
|
+
File.open(temp_path, 'w') { |f| f.write(content) }
|
12
|
+
FileUtils.mv(temp_path, path)
|
13
|
+
end
|
14
|
+
|
15
|
+
def lock(path)
|
16
|
+
dir = File.dirname(path)
|
17
|
+
FileUtils.mkdir_p(dir) unless File.directory?(dir)
|
18
|
+
|
19
|
+
File.open(path).flock(File::LOCK_EX) if File.exist?(path)
|
20
|
+
yield
|
21
|
+
File.open(path).flock(File::LOCK_UN)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'uffizzi/helpers/config_helper'
|
4
|
+
|
5
|
+
module Uffizzi
|
6
|
+
module LoginHelper
|
7
|
+
class << self
|
8
|
+
def prepare_request_params(username, password)
|
9
|
+
{
|
10
|
+
user: {
|
11
|
+
email: username,
|
12
|
+
password: password,
|
13
|
+
},
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def set_server(options)
|
18
|
+
config_server = ConfigFile.exists? ? Uffizzi::ConfigHelper.read_option_from_config(:server) : nil
|
19
|
+
server_address = (options[:server] || config_server || Uffizzi.ui.ask('Server:')).sub(/\/+$/, '')
|
20
|
+
server_address.start_with?('http:', 'https:') ? server_address : "https://#{server_address}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def set_username(options)
|
24
|
+
config_username = ConfigFile.exists? ? Uffizzi::ConfigHelper.read_option_from_config(:username) : nil
|
25
|
+
options[:username] || config_username || Uffizzi.ui.ask('Username:')
|
26
|
+
end
|
27
|
+
|
28
|
+
def set_password
|
29
|
+
ENV['UFFIZZI_PASSWORD'] || Uffizzi.ui.ask('Password:', echo: false)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -1,9 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'faker'
|
4
|
+
|
3
5
|
module Uffizzi
|
4
6
|
module ProjectHelper
|
5
7
|
SLUG_ENDING_LENGTH = 6
|
6
8
|
class << self
|
9
|
+
def generate_default_params
|
10
|
+
name = generate_name
|
11
|
+
{
|
12
|
+
name: name,
|
13
|
+
description: default_description,
|
14
|
+
slug: generate_slug(name),
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
7
18
|
def generate_slug(name)
|
8
19
|
formatted_name = name.downcase.gsub(/ /, '-').gsub(/[^\w-]+/, '')
|
9
20
|
slug_ending = generate_random_string(SLUG_ENDING_LENGTH)
|
@@ -17,6 +28,14 @@ module Uffizzi
|
|
17
28
|
hexatridecimal_base = 36
|
18
29
|
rand(hexatridecimal_base**length).to_s(hexatridecimal_base)
|
19
30
|
end
|
31
|
+
|
32
|
+
def default_description
|
33
|
+
'Project generated by Uffizzi'
|
34
|
+
end
|
35
|
+
|
36
|
+
def generate_name
|
37
|
+
Faker::Lorem.word
|
38
|
+
end
|
20
39
|
end
|
21
40
|
end
|
22
41
|
end
|