Skip to content

Commit

Permalink
[343] Add dev describe
Browse files Browse the repository at this point in the history
  • Loading branch information
zipofar committed Oct 10, 2023
1 parent c5a708d commit 06a2197
Show file tree
Hide file tree
Showing 11 changed files with 326 additions and 69 deletions.
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,10 @@ gem_build_install:
gem_uninstall:
gem uninstall uffizzi-cli

brew_add_tap:
brew tap UffizziCloud/tap

brew_tap_install:
brew install uffizzicloud/tap/uffizzi

.PHONY: test
111 changes: 50 additions & 61 deletions lib/uffizzi/cli/cluster.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,31 +68,28 @@ def run(command, command_args = {})
raise Uffizzi::Error.new('You are not logged in.') unless Uffizzi::AuthHelper.signed_in?
raise Uffizzi::Error.new('This command needs project to be set in config file') unless CommandService.project_set?(options)

project_slug = options[:project].nil? ? ConfigFile.read_option(:project) : options[:project]

case command
when 'list'
handle_list_command(project_slug)
handle_list_command
when 'create'
handle_create_command(project_slug, command_args)
handle_create_command(command_args)
when 'describe'
handle_describe_command(project_slug, command_args)
handle_describe_command(command_args)
when 'delete'
handle_delete_command(project_slug, command_args)
handle_delete_command(command_args)
when 'update-kubeconfig'
handle_update_kubeconfig_command(project_slug, command_args)
handle_update_kubeconfig_command(command_args)
when 'disconnect'
ClusterDisconnectService.handle(options)
end
end

def handle_list_command(project_slug)
def handle_list_command
is_all = options[:all]
response = if is_all
get_account_clusters(ConfigFile.read_option(:server), ConfigFile.read_option(:account, :id))
get_account_clusters(server, ConfigFile.read_option(:account, :id))
else
oidc_token = ConfigFile.read_option(:oidc_token)
get_project_clusters(ConfigFile.read_option(:server), project_slug, oidc_token: oidc_token)
get_project_clusters(server, project_slug, oidc_token: oidc_token)
end

if ResponseHelper.ok?(response)
Expand All @@ -103,7 +100,7 @@ def handle_list_command(project_slug)
end

# rubocop:disable Metrics/PerceivedComplexity
def handle_create_command(project_slug, command_args)
def handle_create_command(command_args)
Uffizzi.ui.disable_stdout if Uffizzi.ui.output_format

if options[:name]
Expand All @@ -121,13 +118,13 @@ def handle_create_command(project_slug, command_args)

manifest_file_path = options[:manifest]
params = cluster_creation_params(cluster_name, creation_source, manifest_file_path)
response = create_cluster(ConfigFile.read_option(:server), project_slug, params)
response = create_cluster(server, project_slug, params)

return ResponseHelper.handle_failed_response(response) unless ResponseHelper.created?(response)

spinner = TTY::Spinner.new("[:spinner] Creating cluster #{cluster_name}...", format: :dots)
spinner.auto_spin
cluster_data = ClusterService.wait_cluster_deploy(project_slug, cluster_name, ConfigFile.read_option(:oidc_token))
cluster_data = ClusterService.wait_cluster_deploy(project_slug, cluster_name, oidc_token)

if ClusterService.failed?(cluster_data[:state])
spinner.error
Expand All @@ -137,26 +134,31 @@ def handle_create_command(project_slug, command_args)
spinner.success
handle_succeed_create_response(cluster_data)
rescue SystemExit, Interrupt, SocketError
handle_interrupt_creation(cluster_name, ConfigFile.read_option(:server), project_slug)
handle_interrupt_creation(cluster_name)
end
# rubocop:enable Metrics/PerceivedComplexity

def handle_describe_command(project_slug, command_args)
cluster_data = fetch_cluster_data(project_slug, command_args[:cluster_name])
def handle_describe_command(command_args)
cluster_data = ClusterService.fetch_cluster_data(command_args[:cluster_name], **cluster_api_connection_params)
render_data = ClusterService.build_render_data(cluster_data)

handle_succeed_describe(cluster_data)
if Uffizzi.ui.output_format.nil?
Uffizzi.ui.say(ClusterService.stringify_render_data(render_data))
else
Uffizzi.ui.say(render_data)
end
end

def handle_delete_command(project_slug, command_args)
def handle_delete_command(command_args)
cluster_name = command_args[:cluster_name]
is_delete_kubeconfig = options[:'delete-config']

return handle_delete_cluster(project_slug, cluster_name) unless is_delete_kubeconfig
return handle_delete_cluster(cluster_name) unless is_delete_kubeconfig

cluster_data = fetch_cluster_data(project_slug, cluster_name)
cluster_data = ClusterService.fetch_cluster_data(cluster_name, **cluster_api_connection_params)
kubeconfig = parse_kubeconfig(cluster_data[:kubeconfig])

handle_delete_cluster(project_slug, cluster_name)
handle_delete_cluster(cluster_name)
exclude_kubeconfig(cluster_data[:id], kubeconfig) if kubeconfig.present?
end

Expand All @@ -180,12 +182,12 @@ def exclude_kubeconfig(cluster_id, kubeconfig)
end
end

def handle_delete_cluster(project_slug, cluster_name)
def handle_delete_cluster(cluster_name)
params = {
cluster_name: cluster_name,
oidc_token: ConfigFile.read_option(:oidc_token),
oidc_token: oidc_token,
}
response = delete_cluster(ConfigFile.read_option(:server), project_slug, params)
response = delete_cluster(server, project_slug, params)

if ResponseHelper.no_content?(response)
Uffizzi.ui.say("Cluster #{cluster_name} deleted")
Expand All @@ -194,9 +196,9 @@ def handle_delete_cluster(project_slug, cluster_name)
end
end

def handle_update_kubeconfig_command(project_slug, command_args)
def handle_update_kubeconfig_command(command_args)
kubeconfig_path = options[:kubeconfig] || KubeconfigService.default_path
cluster_data = fetch_cluster_data(project_slug, command_args[:cluster_name])
cluster_data = ClusterService.fetch_cluster_data(command_args[:cluster_name], **cluster_api_connection_params)

unless cluster_data[:kubeconfig].present?
say_error_update_kubeconfig(cluster_data)
Expand Down Expand Up @@ -241,8 +243,6 @@ def say_error_update_kubeconfig(cluster_data)

def cluster_creation_params(name, creation_source, manifest_file_path)
manifest_content = load_manifest_file(manifest_file_path)
oidc_token = Uffizzi::ConfigFile.read_option(:oidc_token)

{
cluster: {
name: name,
Expand All @@ -261,7 +261,7 @@ def load_manifest_file(file_path)
raise Uffizzi::Error.new(e.message)
end

def handle_interrupt_creation(cluster_name, server, project_slug)
def handle_interrupt_creation(cluster_name)
deletion_response = delete_cluster(server, project_slug, cluster_name: cluster_name)
deletion_message = if ResponseHelper.no_content?(deletion_response)
"The cluster #{cluster_name} has been disabled."
Expand Down Expand Up @@ -297,23 +297,6 @@ def render_plain_cluster_list(clusters)
end.join("\n")
end

def handle_succeed_describe(cluster_data)
prepared_cluster_data = {
name: cluster_data[:name],
status: cluster_data[:state],
created: Time.strptime(cluster_data[:created_at], '%Y-%m-%dT%H:%M:%S.%N').strftime('%a %b %d %H:%M:%S %Y'),
url: cluster_data[:host],
}

rendered_cluster_data = if Uffizzi.ui.output_format.nil?
prepared_cluster_data.map { |k, v| "- #{k.to_s.upcase}: #{v}" }.join("\n").strip
else
prepared_cluster_data
end

Uffizzi.ui.say(rendered_cluster_data)
end

def handle_succeed_create_response(cluster_data)
kubeconfig_path = options[:kubeconfig] || KubeconfigService.default_path
is_update_current_context = options[:'update-current-context']
Expand Down Expand Up @@ -377,25 +360,31 @@ def parse_kubeconfig(kubeconfig)
Psych.safe_load(Base64.decode64(kubeconfig))
end

def fetch_cluster_data(project_slug, cluster_name)
params = {
cluster_name: cluster_name,
oidc_token: ConfigFile.read_option(:oidc_token),
}
response = get_cluster(ConfigFile.read_option(:server), project_slug, params)

if ResponseHelper.ok?(response)
response.dig(:body, :cluster)
else
ResponseHelper.handle_failed_response(response)
end
end

def save_previous_current_context(kubeconfig_path, current_context)
return if kubeconfig_path.nil? || ConfigHelper.previous_current_context_by_path(kubeconfig_path).present?

previous_current_contexts = Uffizzi::ConfigHelper.set_previous_current_context_by_path(kubeconfig_path, current_context)
ConfigFile.write_option(:previous_current_contexts, previous_current_contexts)
end

def cluster_api_connection_params
{
server: server,
project_slug: project_slug,
oidc_token: oidc_token,
}
end

def oidc_token
@oidc_token ||= ConfigFile.read_option(:oidc_token)
end

def project_slug
@project_slug ||= ConfigFile.read_option(:project)
end

def server
@server ||= ConfigFile.read_option(:server)
end
end
end
77 changes: 71 additions & 6 deletions lib/uffizzi/cli/dev.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ def start(config_path = 'skaffold.yaml')
check_login
cluster_id, cluster_name = start_create_cluster
kubeconfig = wait_cluster_creation(cluster_name)
save_config_dev_environment(cluster_name, config_path)

if options[:quiet]
launch_demonise_skaffold(config_path)
Expand All @@ -30,6 +31,7 @@ def start(config_path = 'skaffold.yaml')
if defined?(cluster_name).present? && defined?(cluster_id).present?
kubeconfig = defined?(kubeconfig).present? ? kubeconfig : nil
handle_delete_cluster(cluster_id, cluster_name, kubeconfig)
delete_config_dev_environment(cluster_name)
end
end

Expand All @@ -47,6 +49,26 @@ def stop
File.delete(DevService.pid_path)
end

desc 'describe [NAME]', 'Describe dev environment'
def describe(name = nil)
check_login
dev_environment = get_dev_environment(name)

if dev_environment.nil? && name.present?
return Uffizzi.ui.say("No running dev environment by name: #{name}")
elsif dev_environment.nil?
return Uffizzi.ui.say('No running dev environments')
end

cluster_name = dev_environment[:name]
cluster_data = ClusterService.fetch_cluster_data(cluster_name, **cluster_api_connection_params)
cluster_render_data = ClusterService.build_render_data(cluster_data)
dev_environment_render_data = cluster_render_data.merge(config_path: dev_environment[:config_path])
rendered_data = dev_environment_render_data.map { |k, v| "- #{k.to_s.upcase}: #{v}" }.join("\n").strip

Uffizzi.ui.say(rendered_data)
end

private

def check_login
Expand All @@ -59,7 +81,7 @@ def start_create_cluster
creation_source = ClusterService::MANUAL_CREATION_SOURCE
params = cluster_creation_params(cluster_name, creation_source)
Uffizzi.ui.say('Start creating a cluster')
response = create_cluster(ConfigFile.read_option(:server), project_slug, params)
response = create_cluster(server, project_slug, params)
return ResponseHelper.handle_failed_response(response) unless ResponseHelper.created?(response)

cluster_id = response.dig(:body, :cluster, :id)
Expand All @@ -70,7 +92,7 @@ def start_create_cluster

def wait_cluster_creation(cluster_name)
Uffizzi.ui.say('Checking the cluster status...')
cluster_data = ClusterService.wait_cluster_deploy(project_slug, cluster_name, ConfigFile.read_option(:oidc_token))
cluster_data = ClusterService.wait_cluster_deploy(project_slug, cluster_name, oidc_token)

if ClusterService.failed?(cluster_data[:state])
Uffizzi.ui.say_error_and_exit("Cluster with name: #{cluster_name} failed to be created.")
Expand Down Expand Up @@ -111,8 +133,6 @@ def update_clusters_config(id, params)
end

def cluster_creation_params(name, creation_source)
oidc_token = Uffizzi::ConfigFile.read_option(:oidc_token)

{
cluster: {
name: name,
Expand All @@ -130,9 +150,9 @@ def handle_delete_cluster(cluster_id, cluster_name, kubeconfig)

params = {
cluster_name: cluster_name,
oidc_token: ConfigFile.read_option(:oidc_token),
oidc_token: oidc_token,
}
response = delete_cluster(ConfigFile.read_option(:server), project_slug, params)
response = delete_cluster(server, project_slug, params)

if ResponseHelper.no_content?(response)
Uffizzi.ui.say("Cluster #{cluster_name} deleted")
Expand Down Expand Up @@ -191,8 +211,53 @@ def launch_demonise_skaffold(config_path)
File.open(DevService.logs_path, 'a') { |f| f.puts(e.message) }
end

def save_config_dev_environment(cluster_name, config_path)
params = options.merge(config_path: File.expand_path(config_path))
dev_environments = Uffizzi::ConfigHelper.set_dev_environment(cluster_name, params)
ConfigFile.write_option(:dev_environments, dev_environments)
end

def delete_config_dev_environment(cluster_name)
dev_environments = Uffizzi::ConfigHelper.dev_environments_without(cluster_name)
ConfigFile.write_option(:dev_environments, dev_environments)
end

def get_dev_environment(name)
dev_environments = ConfigHelper.dev_environments

if name.present?
ConfigHelper.dev_environments_by_name(name)
elsif dev_environments.count == 1
dev_environments.last
elsif dev_environments.count > 1
choices = dev_environments.map do |dev_env|
{ name: dev_env[:config_path], value: dev_env[:name] }
end

question = 'You have several dev environments, select one for describe:'
answer = Uffizzi.prompt.select(question, choices)
ConfigHelper.dev_environments_by_name(answer)
end
end

def cluster_api_connection_params
{
server: server,
project_slug: project_slug,
oidc_token: oidc_token,
}
end

def project_slug
@project_slug ||= ConfigFile.read_option(:project)
end

def oidc_token
@oidc_token ||= ConfigFile.read_option(:oidc_token)
end

def server
@server ||= ConfigFile.read_option(:server)
end
end
end
17 changes: 17 additions & 0 deletions lib/uffizzi/helpers/config_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,23 @@ def previous_current_context_by_path(path)
cluster_previous_current_contexts.detect { |c| c[:kubeconfig_path] == path }
end

def set_dev_environment(name, params = {})
current_dev_environments = dev_environments_without(name)
current_dev_environments << { name: name }.merge(params)
end

def dev_environments_without(name)
dev_environments.reject { |c| c[:name] == name }
end

def dev_environments_by_name(name)
dev_environments.detect { |c| c[:name] == name }
end

def dev_environments
read_option_from_config(:dev_environments) || []
end

private

def clusters
Expand Down
Loading

0 comments on commit 06a2197

Please sign in to comment.