uffizzi-cli 1.0.4 → 2.0.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. checksums.yaml +4 -4
  2. data/config/uffizzi.rb +1 -0
  3. data/lib/uffizzi/auth_helper.rb +13 -5
  4. data/lib/uffizzi/cli/account.rb +122 -0
  5. data/lib/uffizzi/cli/cluster.rb +363 -0
  6. data/lib/uffizzi/cli/common.rb +2 -4
  7. data/lib/uffizzi/cli/config.rb +5 -4
  8. data/lib/uffizzi/cli/connect.rb +14 -8
  9. data/lib/uffizzi/cli/disconnect.rb +1 -1
  10. data/lib/uffizzi/cli/login.rb +130 -66
  11. data/lib/uffizzi/cli/login_by_identity_token.rb +11 -7
  12. data/lib/uffizzi/cli/preview/service.rb +3 -4
  13. data/lib/uffizzi/cli/preview.rb +33 -32
  14. data/lib/uffizzi/cli/project.rb +17 -9
  15. data/lib/uffizzi/cli.rb +46 -7
  16. data/lib/uffizzi/clients/api/api_client.rb +92 -2
  17. data/lib/uffizzi/clients/api/api_routes.rb +44 -0
  18. data/lib/uffizzi/clients/api/http_client.rb +19 -7
  19. data/lib/uffizzi/config_file.rb +15 -40
  20. data/lib/uffizzi/error.rb +15 -0
  21. data/lib/uffizzi/helpers/config_helper.rb +49 -0
  22. data/lib/uffizzi/helpers/file_helper.rb +25 -0
  23. data/lib/uffizzi/helpers/login_helper.rb +33 -0
  24. data/lib/uffizzi/helpers/project_helper.rb +19 -0
  25. data/lib/uffizzi/promt.rb +4 -0
  26. data/lib/uffizzi/response_helper.rb +33 -14
  27. data/lib/uffizzi/services/cluster_service.rb +59 -0
  28. data/lib/uffizzi/services/compose_file_service.rb +5 -4
  29. data/lib/uffizzi/services/env_variables_service.rb +4 -2
  30. data/lib/uffizzi/services/github_service.rb +21 -0
  31. data/lib/uffizzi/services/kubeconfig_service.rb +132 -0
  32. data/lib/uffizzi/services/preview_service.rb +52 -18
  33. data/lib/uffizzi/shell.rb +19 -16
  34. data/lib/uffizzi/token.rb +37 -0
  35. data/lib/uffizzi/version.rb +1 -1
  36. data/lib/uffizzi.rb +10 -0
  37. data/man/uffizzi +7 -5
  38. data/man/uffizzi-account +29 -0
  39. data/man/uffizzi-account-list +26 -0
  40. data/man/uffizzi-account-list.html +103 -0
  41. data/man/uffizzi-account-list.ronn +19 -0
  42. data/man/uffizzi-account-set-default +29 -0
  43. data/man/uffizzi-account-set-default.html +105 -0
  44. data/man/uffizzi-account-set-default.ronn +22 -0
  45. data/man/uffizzi-account.html +106 -0
  46. data/man/uffizzi-account.ronn +23 -0
  47. data/man/uffizzi-cluster +37 -0
  48. data/man/uffizzi-cluster-create +49 -0
  49. data/man/uffizzi-cluster-create.ronn +41 -0
  50. data/man/uffizzi-cluster-delete +32 -0
  51. data/man/uffizzi-cluster-delete.ronn +24 -0
  52. data/man/uffizzi-cluster-describe +39 -0
  53. data/man/uffizzi-cluster-describe.ronn +30 -0
  54. data/man/uffizzi-cluster-list +34 -0
  55. data/man/uffizzi-cluster-list.ronn +26 -0
  56. data/man/uffizzi-cluster-update-kubeconfig +37 -0
  57. data/man/uffizzi-cluster-update-kubeconfig.ronn +29 -0
  58. data/man/uffizzi-cluster.ronn +32 -0
  59. data/man/uffizzi-compose +39 -0
  60. data/man/uffizzi-compose-create +67 -0
  61. data/man/uffizzi-compose-create.ronn +57 -0
  62. data/man/uffizzi-compose-delete +38 -0
  63. data/man/uffizzi-compose-delete.ronn +29 -0
  64. data/man/uffizzi-compose-describe +38 -0
  65. data/man/uffizzi-compose-describe.ronn +29 -0
  66. data/man/uffizzi-compose-events +38 -0
  67. data/man/uffizzi-compose-events.ronn +29 -0
  68. data/man/uffizzi-compose-list +58 -0
  69. data/man/uffizzi-compose-list.ronn +49 -0
  70. data/man/uffizzi-compose-service-list +42 -0
  71. data/man/uffizzi-compose-service-list.ronn +32 -0
  72. data/man/uffizzi-compose-service-logs +59 -0
  73. data/man/uffizzi-compose-service-logs.ronn +48 -0
  74. data/man/uffizzi-compose-update +61 -0
  75. data/man/uffizzi-compose-update.ronn +51 -0
  76. data/man/uffizzi-compose.ronn +33 -0
  77. data/man/uffizzi-compose_service_logs +59 -0
  78. data/man/uffizzi-compose_service_logs.ronn +50 -0
  79. data/man/uffizzi-config +2 -2
  80. data/man/uffizzi-config.ronn +1 -1
  81. data/man/uffizzi-connect +2 -4
  82. data/man/uffizzi-connect-acr +2 -2
  83. data/man/uffizzi-connect-acr.ronn +1 -1
  84. data/man/uffizzi-connect-docker-hub +2 -2
  85. data/man/uffizzi-connect-docker-hub.ronn +1 -1
  86. data/man/uffizzi-connect-docker-registry +2 -2
  87. data/man/uffizzi-connect-docker-registry.ronn +1 -1
  88. data/man/uffizzi-connect-ecr +2 -2
  89. data/man/uffizzi-connect-ecr.ronn +1 -1
  90. data/man/uffizzi-connect-gcr +2 -2
  91. data/man/uffizzi-connect-gcr.ronn +1 -1
  92. data/man/uffizzi-connect-ghcr +2 -2
  93. data/man/uffizzi-connect-ghcr.ronn +1 -1
  94. data/man/uffizzi-connect.ronn +2 -2
  95. data/man/uffizzi-disconnect +2 -2
  96. data/man/uffizzi-disconnect.ronn +1 -1
  97. data/man/uffizzi-login +7 -3
  98. data/man/uffizzi-login-by-identity-token +3 -3
  99. data/man/uffizzi-login-by-identity-token.ronn +2 -2
  100. data/man/uffizzi-login.html +113 -0
  101. data/man/uffizzi-login.ronn +6 -2
  102. data/man/uffizzi-logout +2 -2
  103. data/man/uffizzi-logout.ronn +1 -1
  104. data/man/uffizzi-preview +9 -9
  105. data/man/uffizzi-preview-create +22 -20
  106. data/man/uffizzi-preview-create.ronn +28 -26
  107. data/man/uffizzi-preview-delete +11 -10
  108. data/man/uffizzi-preview-delete.ronn +12 -11
  109. data/man/uffizzi-preview-describe +10 -10
  110. data/man/uffizzi-preview-describe.ronn +11 -11
  111. data/man/uffizzi-preview-events +12 -11
  112. data/man/uffizzi-preview-events.ronn +13 -12
  113. data/man/uffizzi-preview-list +19 -18
  114. data/man/uffizzi-preview-list.ronn +21 -20
  115. data/man/uffizzi-preview-service-list +16 -12
  116. data/man/uffizzi-preview-service-list.ronn +16 -13
  117. data/man/uffizzi-preview-service-logs +14 -12
  118. data/man/uffizzi-preview-service-logs.ronn +18 -17
  119. data/man/uffizzi-preview-update +19 -18
  120. data/man/uffizzi-preview-update.ronn +21 -20
  121. data/man/uffizzi-preview.ronn +10 -10
  122. data/man/uffizzi-preview_service_logs +14 -12
  123. data/man/uffizzi-preview_service_logs.ronn +18 -17
  124. data/man/uffizzi-project +3 -3
  125. data/man/uffizzi-project-compose +2 -2
  126. data/man/uffizzi-project-compose-describe +2 -2
  127. data/man/uffizzi-project-compose-describe.ronn +1 -1
  128. data/man/uffizzi-project-compose-set +2 -2
  129. data/man/uffizzi-project-compose-set.ronn +1 -1
  130. data/man/uffizzi-project-compose-unset +2 -2
  131. data/man/uffizzi-project-compose-unset.ronn +1 -1
  132. data/man/uffizzi-project-compose.ronn +1 -1
  133. data/man/uffizzi-project-create +2 -2
  134. data/man/uffizzi-project-create.ronn +1 -1
  135. data/man/uffizzi-project-delete +2 -2
  136. data/man/uffizzi-project-delete.ronn +1 -1
  137. data/man/uffizzi-project-describe +3 -3
  138. data/man/uffizzi-project-describe.ronn +1 -1
  139. data/man/uffizzi-project-preview-describe +37 -0
  140. data/man/uffizzi-project-preview-describe.ronn +29 -0
  141. data/man/uffizzi-project-preview-set +66 -0
  142. data/man/uffizzi-project-preview-set.ronn +57 -0
  143. data/man/uffizzi-project-secret +2 -2
  144. data/man/uffizzi-project-secret-create +2 -2
  145. data/man/uffizzi-project-secret-create.ronn +1 -1
  146. data/man/uffizzi-project-secret-delete +2 -2
  147. data/man/uffizzi-project-secret-delete.ronn +1 -1
  148. data/man/uffizzi-project-secret-list +2 -2
  149. data/man/uffizzi-project-secret-list.ronn +1 -1
  150. data/man/uffizzi-project-secret.ronn +1 -1
  151. data/man/uffizzi-project-set-default +2 -2
  152. data/man/uffizzi-project-set-default.ronn +1 -1
  153. data/man/uffizzi-project.html +124 -0
  154. data/man/uffizzi-project.ronn +2 -2
  155. data/man/uffizzi.ronn +12 -10
  156. metadata +131 -19
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5aa0242e35791e35a51a850316bb18a97f1651aa345c64ee05264cb6b7faa702
4
- data.tar.gz: bc9a8c8176c2969edf8728be715a0d45c38dab6a3d0e6da37c8022e04d9e8e24
3
+ metadata.gz: ff745e60f88baf8b836d5e230df85de2db8956879c1f3e241cf43196ffe499e3
4
+ data.tar.gz: 5ee75e82560d8a08442ae8d14fda0cb9dabf94d5e4f9c5771a6f238976b74939
5
5
  SHA512:
6
- metadata.gz: 993d29e07d6fe739cd3ab82383a948ed2d251f7b00662b02b87cd3a9b1b556ee2e1ed16f224f857ce0689ac64b84d02b74aa711f24f477d546d1f13c378938a1
7
- data.tar.gz: d91befdb081561d8395800f672918518397a70734abc3ff1ec2b57faa0180063f808722afc14de85e056507972d97eb4ef774614d1dd72a54311f5f34629abf0
6
+ metadata.gz: 3a4b98fe851951079f4a106c4a34371ede1c9bc823375615edde4922f6e7a3712402c395f8f7e00fea588f51a1143c4c2b2058199475dac35808c1bcb2bc81cb
7
+ data.tar.gz: 9942d4da8f4e47060dd3e5f1c65810dfe972cbd05ccaca7750612f61e304aea1de8b587405e60f1210487a45a531fcfd52065b5d677089eea01a207dd4ba76a5
data/config/uffizzi.rb CHANGED
@@ -22,5 +22,6 @@ module Uffizzi
22
22
  docker_registry: 'UffizziCore::Credential::DockerRegistry',
23
23
  }
24
24
  config.default_server = 'app.uffizzi.com'
25
+ config.default_kubeconfig_path = ENV['CLI_DEFAULT_KUBECONFIG_PATH'] || '~/.kube/config'
25
26
  end
26
27
  end
@@ -4,15 +4,23 @@ module Uffizzi
4
4
  module AuthHelper
5
5
  class << self
6
6
  def signed_in?
7
- ConfigFile.exists? &&
8
- ConfigFile.option_has_value?(:account_id) &&
9
- ConfigFile.option_has_value?(:cookie) &&
10
- ConfigFile.option_has_value?(:server)
7
+ config_data_exists? || Uffizzi::Token.exists?
11
8
  end
12
9
 
13
10
  def sign_out
14
11
  Uffizzi::ConfigFile.unset_option(:cookie)
15
- Uffizzi::ConfigFile.unset_option(:account_id)
12
+ Uffizzi::ConfigFile.unset_option(:account)
13
+ Uffizzi::ConfigFile.unset_option(:project)
14
+ Uffizzi::Token.delete if Uffizzi::Token.exists?
15
+ end
16
+
17
+ private
18
+
19
+ def config_data_exists?
20
+ ConfigFile.exists? &&
21
+ ConfigFile.option_has_value?(:account) &&
22
+ ConfigFile.option_has_value?(:cookie) &&
23
+ ConfigFile.option_has_value?(:server)
16
24
  end
17
25
  end
18
26
  end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uffizzi'
4
+ require 'uffizzi/auth_helper'
5
+ require 'uffizzi/response_helper'
6
+ require 'uffizzi/helpers/config_helper'
7
+
8
+ module Uffizzi
9
+ class Cli::Account < Thor
10
+ include ApiClient
11
+
12
+ desc 'list', "List all user's accounts"
13
+ def list
14
+ run('list')
15
+ end
16
+
17
+ desc 'set-default ACCOUNT_NAME', 'set-default'
18
+ def set_default(account_name)
19
+ run('set-default', account_name)
20
+ end
21
+
22
+ map('set-default' => :set_default)
23
+ map('set' => :set_default)
24
+
25
+ private
26
+
27
+ def run(command, account_name = nil)
28
+ return Uffizzi.ui.say('You are not logged in.') unless Uffizzi::AuthHelper.signed_in?
29
+
30
+ case command
31
+ when 'list'
32
+ handle_list_command
33
+ when 'set-default'
34
+ handle_set_default_command(account_name)
35
+ end
36
+ end
37
+
38
+ def handle_list_command
39
+ server = ConfigFile.read_option(:server)
40
+ response = fetch_accounts(server)
41
+
42
+ if ResponseHelper.ok?(response)
43
+ handle_list_success_response(response)
44
+ else
45
+ ResponseHelper.handle_failed_response(response)
46
+ end
47
+ end
48
+
49
+ def handle_set_default_command(account_name)
50
+ response = fetch_account(ConfigFile.read_option(:server), account_name)
51
+
52
+ if ResponseHelper.ok?(response)
53
+ handle_succeed_set_default_response(response)
54
+ elsif ResponseHelper.not_found?(response)
55
+ Uffizzi.ui.say("Account with name #{account_name} does not exist")
56
+ else
57
+ ResponseHelper.handle_failed_response(response)
58
+ end
59
+ end
60
+
61
+ def handle_list_success_response(response)
62
+ accounts = response[:body][:accounts]
63
+ return Uffizzi.ui.say('No accounts found') if accounts.empty?
64
+
65
+ print_accounts(accounts)
66
+ end
67
+
68
+ def print_accounts(accounts)
69
+ accounts_list = accounts.reduce('') do |acc, account|
70
+ "#{acc}#{account[:name]}\n"
71
+ end
72
+ Uffizzi.ui.say(accounts_list)
73
+ end
74
+
75
+ def handle_succeed_set_default_response(response)
76
+ account = response[:body][:account]
77
+ account_id = account[:id]
78
+ account_name = account[:name]
79
+ ConfigFile.write_option(:account, Uffizzi::ConfigHelper.account_config(account_id, account_name))
80
+ Uffizzi.ui.say("The account with name '#{account_name}' was set as default.")
81
+
82
+ projects = account[:projects]
83
+
84
+ project = default_project(projects, account_id)
85
+ if project.nil?
86
+ ConfigFile.unset_option(:project)
87
+ message = "There is no project set. Run the 'uffizzi project set-default' command to set a project"
88
+ return Uffizzi.ui.say(message)
89
+ end
90
+
91
+ slug = project[:slug]
92
+ ConfigFile.write_option(:project, slug)
93
+ Uffizzi.ui.say("The project with slug '#{slug}' was set as default.")
94
+ end
95
+
96
+ def default_project(projects, account_id)
97
+ return projects.first if projects.count == 1
98
+ return create_default_project(account_id) if projects.count.zero?
99
+
100
+ nil
101
+ end
102
+
103
+ def create_default_project(account_id)
104
+ params = Uffizzi::ProjectHelper.generate_default_params
105
+ response = create_project(ConfigFile.read_option(:server), account_id, params)
106
+
107
+ if ResponseHelper.created?(response)
108
+ handle_project_create_success_response(response)
109
+ else
110
+ ResponseHelper.handle_failed_response(response)
111
+ end
112
+ end
113
+
114
+ def handle_project_create_success_response(response)
115
+ project = response[:body][:project]
116
+ ConfigFile.write_option(:project, project[:slug])
117
+ Uffizzi.ui.say("A default project '#{project[:name]}' was successfully created")
118
+
119
+ project
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,363 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'psych'
4
+ require 'faker'
5
+ require 'uffizzi'
6
+ require 'uffizzi/auth_helper'
7
+ require 'uffizzi/helpers/config_helper'
8
+ require 'uffizzi/services/preview_service'
9
+ require 'uffizzi/services/command_service'
10
+ require 'uffizzi/services/cluster_service'
11
+ require 'uffizzi/services/kubeconfig_service'
12
+
13
+ MANUAL = 'manual'
14
+
15
+ module Uffizzi
16
+ class Cli::Cluster < Thor
17
+ class Error < StandardError; end
18
+ include ApiClient
19
+
20
+ desc 'list', 'List all clusters'
21
+ method_option :all, required: false, type: :boolean, aliases: '-a'
22
+ method_option :output, required: false, type: :string, aliases: '-o', enum: ['json', 'pretty-json']
23
+ def list
24
+ run('list')
25
+ end
26
+
27
+ desc 'create', 'Create a cluster'
28
+ method_option :name, type: :string, required: false, aliases: '-n'
29
+ method_option :kubeconfig, type: :string, required: false, aliases: '-k'
30
+ method_option :manifest, type: :string, required: false, aliases: '-m'
31
+ method_option :'update-current-context', type: :boolean, required: false
32
+ method_option :output, required: false, type: :string, aliases: '-o', enum: ['json', 'pretty-json']
33
+ method_option :'creation-source', required: false, type: :string
34
+ def create
35
+ run('create')
36
+ end
37
+
38
+ desc 'describe [NAME]', 'Describe a cluster'
39
+ method_option :output, required: false, type: :string, aliases: '-o', enum: ['json', 'pretty-json']
40
+ def describe(name)
41
+ run('describe', cluster_name: name)
42
+ end
43
+
44
+ desc 'delete [NAME]', 'Delete a cluster'
45
+ method_option :'delete-config', required: false, type: :boolean, aliases: '-dc'
46
+ def delete(name)
47
+ run('delete', cluster_name: name)
48
+ end
49
+
50
+ method_option :kubeconfig, type: :string, required: false, aliases: '-k'
51
+ method_option :print, type: :boolean, required: false, aliases: '-p'
52
+ method_option :quiet, type: :boolean, required: false, aliases: '-q'
53
+ desc 'update-kubeconfig', 'Udpate your kubeconfig'
54
+ def update_kubeconfig(name)
55
+ run('update-kubeconfig', cluster_name: name)
56
+ end
57
+
58
+ private
59
+
60
+ def run(command, command_args = {})
61
+ Uffizzi.ui.output_format = options[:output]
62
+ raise Uffizzi::Error.new('You are not logged in.') unless Uffizzi::AuthHelper.signed_in?
63
+ raise Uffizzi::Error.new('This command needs project to be set in config file') unless CommandService.project_set?(options)
64
+
65
+ project_slug = options[:project].nil? ? ConfigFile.read_option(:project) : options[:project]
66
+
67
+ case command
68
+ when 'list'
69
+ handle_list_command(project_slug)
70
+ when 'create'
71
+ handle_create_command(project_slug)
72
+ when 'describe'
73
+ handle_describe_command(project_slug, command_args)
74
+ when 'delete'
75
+ handle_delete_command(project_slug, command_args)
76
+ when 'update-kubeconfig'
77
+ handle_update_kubeconfig_command(project_slug, command_args)
78
+ end
79
+ end
80
+
81
+ def handle_list_command(project_slug)
82
+ is_all = options[:all]
83
+ response = if is_all
84
+ get_account_clusters(ConfigFile.read_option(:server), ConfigFile.read_option(:account, :id))
85
+ else
86
+ oidc_token = ConfigFile.read_option(:oidc_token)
87
+ get_project_clusters(ConfigFile.read_option(:server), project_slug, oidc_token: oidc_token)
88
+ end
89
+
90
+ if ResponseHelper.ok?(response)
91
+ handle_succeed_list_response(response)
92
+ else
93
+ ResponseHelper.handle_failed_response(response)
94
+ end
95
+ end
96
+
97
+ def handle_create_command(project_slug)
98
+ Uffizzi.ui.disable_stdout if Uffizzi.ui.output_format
99
+ cluster_name = options[:name] || ClusterService.generate_name
100
+ creation_source = options[:"creation-source"] || MANUAL
101
+
102
+ unless ClusterService.valid_name?(cluster_name)
103
+ Uffizzi.ui.say_error_and_exit("Cluster name: #{cluster_name} is not valid.")
104
+ end
105
+
106
+ manifest_file_path = options[:manifest]
107
+ params = cluster_creation_params(cluster_name, creation_source, manifest_file_path)
108
+ response = create_cluster(ConfigFile.read_option(:server), project_slug, params)
109
+
110
+ return ResponseHelper.handle_failed_response(response) unless ResponseHelper.created?(response)
111
+
112
+ spinner = TTY::Spinner.new("[:spinner] Creating cluster #{cluster_name}...", format: :dots)
113
+ spinner.auto_spin
114
+ cluster_data = ClusterService.wait_cluster_deploy(project_slug, cluster_name, ConfigFile.read_option(:oidc_token))
115
+
116
+ if ClusterService.failed?(cluster_data[:state])
117
+ spinner.error
118
+ Uffizzi.ui.say_error_and_exit("Cluster with name: #{cluster_name} failed to be created.")
119
+ end
120
+
121
+ spinner.success
122
+ handle_succeed_create_response(cluster_data)
123
+ rescue SystemExit, Interrupt, SocketError
124
+ handle_interrupt_creation(cluster_name, ConfigFile.read_option(:server), project_slug)
125
+ end
126
+
127
+ def handle_describe_command(project_slug, command_args)
128
+ cluster_data = fetch_cluster_data(project_slug, command_args[:cluster_name])
129
+
130
+ handle_succeed_describe(cluster_data)
131
+ end
132
+
133
+ def handle_delete_command(project_slug, command_args)
134
+ cluster_name = command_args[:cluster_name]
135
+ is_delete_kubeconfig = options[:'delete-config']
136
+
137
+ return handle_delete_cluster(project_slug, cluster_name) unless is_delete_kubeconfig
138
+
139
+ cluster_data = fetch_cluster_data(project_slug, cluster_name)
140
+ kubeconfig = parse_kubeconfig(cluster_data[:kubeconfig])
141
+
142
+ handle_delete_cluster(project_slug, cluster_name)
143
+ exclude_kubeconfig(cluster_data[:id], kubeconfig)
144
+ end
145
+
146
+ def exclude_kubeconfig(cluster_id, kubeconfig)
147
+ cluster_config = Uffizzi::ConfigHelper.cluster_config_by_id(cluster_id)
148
+ return if cluster_config.nil?
149
+
150
+ kubeconfig_path = cluster_config[:kubeconfig_path]
151
+ ConfigFile.write_option(:clusters, Uffizzi::ConfigHelper.clusters_config_without(cluster_id))
152
+
153
+ KubeconfigService.save_to_filepath(kubeconfig_path, kubeconfig) do |kubeconfig_by_path|
154
+ if kubeconfig_by_path.nil?
155
+ msg = "Warning: kubeconfig at path #{kubeconfig_path} does not exist"
156
+ return Uffizzi.ui.say(msg)
157
+ end
158
+
159
+ new_kubeconfig = KubeconfigService.exclude(kubeconfig_by_path, kubeconfig)
160
+ first_context = KubeconfigService.get_first_context(new_kubeconfig)
161
+ new_current_context = first_context.present? ? first_context['name'] : nil
162
+ KubeconfigService.update_current_context(new_kubeconfig, new_current_context)
163
+ end
164
+ end
165
+
166
+ def handle_delete_cluster(project_slug, cluster_name)
167
+ params = {
168
+ cluster_name: cluster_name,
169
+ oidc_token: ConfigFile.read_option(:oidc_token),
170
+ }
171
+ response = delete_cluster(ConfigFile.read_option(:server), project_slug, params)
172
+
173
+ if ResponseHelper.no_content?(response)
174
+ Uffizzi.ui.say("Cluster #{cluster_name} deleted")
175
+ else
176
+ ResponseHelper.handle_failed_response(response)
177
+ end
178
+ end
179
+
180
+ def handle_update_kubeconfig_command(project_slug, command_args)
181
+ kubeconfig_path = options[:kubeconfig] || KubeconfigService.default_path
182
+ cluster_data = fetch_cluster_data(project_slug, command_args[:cluster_name])
183
+
184
+ unless cluster_data[:kubeconfig].present?
185
+ say_error_update_kubeconfig(cluster_data)
186
+ end
187
+
188
+ parsed_kubeconfig = parse_kubeconfig(cluster_data[:kubeconfig])
189
+
190
+ return Uffizzi.ui.say(parsed_kubeconfig.to_yaml) if options[:print]
191
+
192
+ KubeconfigService.save_to_filepath(kubeconfig_path, parsed_kubeconfig) do |kubeconfig_by_path|
193
+ merged_kubeconfig = KubeconfigService.merge(kubeconfig_by_path, parsed_kubeconfig)
194
+ current_context = KubeconfigService.get_current_context(parsed_kubeconfig)
195
+ KubeconfigService.update_current_context(merged_kubeconfig, current_context)
196
+ end
197
+
198
+ update_clusters_config(cluster_data[:id], kubeconfig_path: kubeconfig_path)
199
+
200
+ return if options[:quiet]
201
+
202
+ Uffizzi.ui.say("Kubeconfig was updated by the path: #{kubeconfig_path}")
203
+ end
204
+
205
+ def say_error_update_kubeconfig(cluster_data)
206
+ if ClusterService.failed?(cluster_data[:state])
207
+ Uffizzi.ui.say_error_and_exit('Kubeconfig is empty because cluster failed to be created.')
208
+ end
209
+
210
+ if ClusterService.deploying?(cluster_data[:state])
211
+ Uffizzi.ui.say_error_and_exit('Kubeconfig is empty because cluster is deploying.')
212
+ end
213
+
214
+ if ClusterService.deployed?(cluster_data[:state])
215
+ raise Error.new("Cluster with data: #{cluster_data.to_json} is deployed but kubeconfig does not exist.")
216
+ end
217
+ end
218
+
219
+ def cluster_creation_params(name, creation_source, manifest_file_path)
220
+ manifest_content = load_manifest_file(manifest_file_path)
221
+ oidc_token = Uffizzi::ConfigFile.read_option(:oidc_token)
222
+
223
+ {
224
+ cluster: {
225
+ name: name,
226
+ manifest: manifest_content,
227
+ creation_source: creation_source,
228
+ },
229
+ token: oidc_token,
230
+ }
231
+ end
232
+
233
+ def load_manifest_file(file_path)
234
+ return nil if file_path.nil?
235
+
236
+ File.read(file_path)
237
+ rescue Errno::ENOENT => e
238
+ raise Uffizzi::Error.new(e.message)
239
+ end
240
+
241
+ def handle_interrupt_creation(cluster_name, server, project_slug)
242
+ deletion_response = delete_cluster(server, project_slug, cluster_name: cluster_name)
243
+ deletion_message = if ResponseHelper.no_content?(deletion_response)
244
+ "The cluster #{cluster_name} has been disabled."
245
+ else
246
+ "Couldn't disable the cluster #{cluster_name} - please disable manually."
247
+ end
248
+
249
+ raise Uffizzi::Error.new("The cluster creation was interrupted. #{deletion_message}")
250
+ end
251
+
252
+ def handle_succeed_list_response(response)
253
+ clusters = response[:body][:clusters] || []
254
+ raise Uffizzi::Error.new('The project has no active clusters') if clusters.empty?
255
+
256
+ clusters_data = if Uffizzi.ui.output_format.nil?
257
+ render_plain_cluster_list(clusters)
258
+ else
259
+ clusters.map { |c| c.slice(:name, :project) }
260
+ end
261
+
262
+ Uffizzi.ui.say(clusters_data)
263
+ end
264
+
265
+ def render_plain_cluster_list(clusters)
266
+ clusters.map do |cluster|
267
+ project_name = cluster.dig(:project, :name)
268
+
269
+ if project_name.present?
270
+ "- Cluster name: #{cluster[:name].strip} Project name: #{project_name.strip}"
271
+ else
272
+ "- #{cluster[:name]}"
273
+ end
274
+ end.join("\n")
275
+ end
276
+
277
+ def handle_succeed_describe(cluster_data)
278
+ prepared_cluster_data = {
279
+ name: cluster_data[:name],
280
+ status: cluster_data[:state],
281
+ created: Time.strptime(cluster_data[:created_at], '%Y-%m-%dT%H:%M:%S.%N').strftime('%a %b %d %H:%M:%S %Y'),
282
+ url: cluster_data[:host],
283
+ }
284
+
285
+ rendered_cluster_data = if Uffizzi.ui.output_format.nil?
286
+ prepared_cluster_data.map { |k, v| "- #{k.to_s.upcase}: #{v}" }.join("\n").strip
287
+ else
288
+ prepared_cluster_data
289
+ end
290
+
291
+ Uffizzi.ui.say(rendered_cluster_data)
292
+ end
293
+
294
+ def handle_succeed_create_response(cluster_data)
295
+ kubeconfig_path = options[:kubeconfig]
296
+ is_update_current_context = options[:'update-current-context']
297
+ parsed_kubeconfig = parse_kubeconfig(cluster_data[:kubeconfig])
298
+ rendered_cluster_data = render_cluster_data(cluster_data)
299
+
300
+ Uffizzi.ui.enable_stdout
301
+ Uffizzi.ui.say("Cluster with name: #{rendered_cluster_data[:name]} was created.")
302
+
303
+ unless is_update_current_context
304
+ Uffizzi.ui.say("To update the current context, run:\nuffizzi cluster update-kubeconfig #{cluster_data[:name]}")
305
+ end
306
+
307
+ Uffizzi.ui.say(rendered_cluster_data) if Uffizzi.ui.output_format
308
+
309
+ save_kubeconfig(parsed_kubeconfig, kubeconfig_path)
310
+ update_clusters_config(cluster_data[:id], kubeconfig_path: kubeconfig_path)
311
+ GithubService.write_to_github_env(rendered_cluster_data) if GithubService.github_actions_exists?
312
+ end
313
+
314
+ def save_kubeconfig(kubeconfig, kubeconfig_path)
315
+ kubeconfig_path = kubeconfig_path.nil? ? KubeconfigService.default_path : kubeconfig_path
316
+ is_update_current_context = options[:'update-current-context']
317
+
318
+ KubeconfigService.save_to_filepath(kubeconfig_path, kubeconfig) do |kubeconfig_by_path|
319
+ merged_kubeconfig = KubeconfigService.merge(kubeconfig_by_path, kubeconfig)
320
+
321
+ if is_update_current_context
322
+ current_context = KubeconfigService.get_current_context(kubeconfig)
323
+ KubeconfigService.update_current_context(merged_kubeconfig, current_context)
324
+ else
325
+ merged_kubeconfig
326
+ end
327
+ end
328
+ end
329
+
330
+ def update_clusters_config(id, params)
331
+ clusters_config = Uffizzi::ConfigHelper.update_clusters_config_by_id(id, params)
332
+ ConfigFile.write_option(:clusters, clusters_config)
333
+ end
334
+
335
+ def render_cluster_data(cluster_data)
336
+ kubeconfig = parse_kubeconfig(cluster_data[:kubeconfig])
337
+ raise Uffizzi::Error.new('The kubeconfig data is empty') unless kubeconfig
338
+
339
+ new_cluster_data = cluster_data.slice(:name)
340
+ new_cluster_data[:context_name] = kubeconfig['current-context']
341
+
342
+ new_cluster_data
343
+ end
344
+
345
+ def parse_kubeconfig(kubeconfig)
346
+ Psych.safe_load(Base64.decode64(kubeconfig))
347
+ end
348
+
349
+ def fetch_cluster_data(project_slug, cluster_name)
350
+ params = {
351
+ cluster_name: cluster_name,
352
+ oidc_token: ConfigFile.read_option(:oidc_token),
353
+ }
354
+ response = get_cluster(ConfigFile.read_option(:server), project_slug, params)
355
+
356
+ if ResponseHelper.ok?(response)
357
+ response.dig(:body, :cluster)
358
+ else
359
+ ResponseHelper.handle_failed_response(response)
360
+ end
361
+ end
362
+ end
363
+ end
@@ -1,14 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'open3'
4
-
5
3
  module Uffizzi
6
4
  class Cli::Common
7
5
  class << self
8
6
  def show_manual(command_name)
9
- manual_doc_path = File.join(Uffizzi.root, "man/#{command_name}")
7
+ manual_doc_path = File.join(Uffizzi.root, "man/#{command_name}.ronn")
10
8
 
11
- Open3.pipeline("man #{manual_doc_path}")
9
+ Uffizzi.ui.say(File.read(manual_doc_path))
12
10
  end
13
11
  end
14
12
  end
@@ -5,6 +5,7 @@ require 'uffizzi/clients/api/api_client'
5
5
 
6
6
  module Uffizzi
7
7
  class Cli::Config < Thor
8
+ ACCOUNT_PROPERTY = 'account'
8
9
  include ApiClient
9
10
 
10
11
  desc 'list', 'Lists all options and their values from the config file'
@@ -57,12 +58,10 @@ module Uffizzi
57
58
  Uffizzi.ui.say("Configure the default properties that will be used to authenticate with your \
58
59
  \nUffizzi API service and manage previews.\n")
59
60
  server = Uffizzi.ui.ask('Server: ', default: Uffizzi.configuration.default_server.to_s)
60
- username = Uffizzi.ui.ask('Username: ')
61
- project = Uffizzi.ui.ask('Project: ', default: 'default')
61
+
62
62
  ConfigFile.delete
63
63
  ConfigFile.write_option(:server, server)
64
- ConfigFile.write_option(:username, username)
65
- ConfigFile.write_option(:project, project)
64
+
66
65
  Uffizzi.ui.say('To login, run: uffizzi login')
67
66
  end
68
67
 
@@ -78,6 +77,8 @@ module Uffizzi
78
77
  end
79
78
 
80
79
  def handle_set_command(property, value)
80
+ return handle_set_account(value) if property == ACCOUNT_PROPERTY
81
+
81
82
  ConfigFile.write_option(property.to_sym, value)
82
83
  Uffizzi.ui.say("Updated property [#{property}]")
83
84
  end
@@ -10,7 +10,7 @@ module Uffizzi
10
10
  desc 'list-credentials', 'List existing credentials for an account'
11
11
  def list_credentials
12
12
  server = ConfigFile.read_option(:server)
13
- account_id = ConfigFile.read_option(:account_id)
13
+ account_id = ConfigFile.read_option(:account, :id)
14
14
  response = fetch_credentials(server, account_id)
15
15
  if ResponseHelper.ok?(response)
16
16
  handle_list_credentials_success(response)
@@ -36,9 +36,10 @@ module Uffizzi
36
36
  username: username,
37
37
  password: password,
38
38
  type: type,
39
+ token: ConfigFile.read_option(:oidc_token),
39
40
  }
40
41
  server = ConfigFile.read_option(:server)
41
- account_id = ConfigFile.read_option(:account_id)
42
+ account_id = ConfigFile.read_option(:account, :id)
42
43
 
43
44
  response = if credential_exists
44
45
  update_credential(server, account_id, params, type)
@@ -68,9 +69,10 @@ module Uffizzi
68
69
  username: username,
69
70
  password: password,
70
71
  type: type,
72
+ token: ConfigFile.read_option(:oidc_token),
71
73
  }
72
74
  server = ConfigFile.read_option(:server)
73
- account_id = ConfigFile.read_option(:account_id)
75
+ account_id = ConfigFile.read_option(:account, :id)
74
76
 
75
77
  response = if credential_exists
76
78
  update_credential(server, account_id, params, type)
@@ -100,9 +102,10 @@ module Uffizzi
100
102
  password: password,
101
103
  registry_url: prepare_registry_url(registry_url),
102
104
  type: type,
105
+ token: ConfigFile.read_option(:oidc_token),
103
106
  }
104
107
  server = ConfigFile.read_option(:server)
105
- account_id = ConfigFile.read_option(:account_id)
108
+ account_id = ConfigFile.read_option(:account, :id)
106
109
 
107
110
  response = if credential_exists
108
111
  update_credential(server, account_id, params, type)
@@ -132,9 +135,10 @@ module Uffizzi
132
135
  password: secret_access_key,
133
136
  registry_url: prepare_registry_url(registry_url),
134
137
  type: type,
138
+ token: ConfigFile.read_option(:oidc_token),
135
139
  }
136
140
  server = ConfigFile.read_option(:server)
137
- account_id = ConfigFile.read_option(:account_id)
141
+ account_id = ConfigFile.read_option(:account, :id)
138
142
 
139
143
  response = if credential_exists
140
144
  update_credential(server, account_id, params, type)
@@ -159,9 +163,10 @@ module Uffizzi
159
163
  params = {
160
164
  password: credential_content,
161
165
  type: type,
166
+ token: ConfigFile.read_option(:oidc_token),
162
167
  }
163
168
  server = ConfigFile.read_option(:server)
164
- account_id = ConfigFile.read_option(:account_id)
169
+ account_id = ConfigFile.read_option(:account, :id)
165
170
 
166
171
  response = if credential_exists
167
172
  update_credential(server, account_id, params, type)
@@ -189,9 +194,10 @@ module Uffizzi
189
194
  username: username,
190
195
  password: password,
191
196
  type: type,
197
+ token: ConfigFile.read_option(:oidc_token),
192
198
  }
193
199
  server = ConfigFile.read_option(:server)
194
- account_id = ConfigFile.read_option(:account_id)
200
+ account_id = ConfigFile.read_option(:account, :id)
195
201
 
196
202
  response = if credential_exists
197
203
  update_credential(server, account_id, params, type)
@@ -228,7 +234,7 @@ module Uffizzi
228
234
 
229
235
  def credential_exists?(type)
230
236
  server = ConfigFile.read_option(:server)
231
- account_id = ConfigFile.read_option(:account_id)
237
+ account_id = ConfigFile.read_option(:account, :id)
232
238
  response = check_credential(server, account_id, type)
233
239
  return false if ResponseHelper.ok?(response)
234
240
  return true if ResponseHelper.unprocessable_entity?(response)
@@ -24,7 +24,7 @@ module Uffizzi
24
24
  raise Uffizzi::Error.new('Unsupported credential type.')
25
25
  end
26
26
 
27
- response = delete_credential(ConfigFile.read_option(:server), ConfigFile.read_option(:account_id), connection_type)
27
+ response = delete_credential(ConfigFile.read_option(:server), ConfigFile.read_option(:account, :id), connection_type)
28
28
 
29
29
  if ResponseHelper.no_content?(response)
30
30
  Uffizzi.ui.say("Successfully disconnected from #{connection_name(credential_type)}.")