mirror of
https://github.com/czhu12/canine.git
synced 2026-02-04 10:49:07 -06:00
Merge pull request #501 from CanineHQ/chriszhu__update_clusters_verify
update cluster verify
This commit is contained in:
@@ -208,6 +208,6 @@ class ClustersController < ApplicationController
|
||||
params[:cluster][:kubeconfig] = YAML.safe_load(yaml_content)
|
||||
end
|
||||
|
||||
params.require(:cluster).permit(:name, :cluster_type, kubeconfig: {})
|
||||
params.require(:cluster).permit(:name, :cluster_type, :skip_tls_verify, kubeconfig: {})
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,16 +2,17 @@
|
||||
#
|
||||
# Table name: clusters
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# cluster_type :integer default("k8s")
|
||||
# kubeconfig :jsonb
|
||||
# name :string not null
|
||||
# options :jsonb not null
|
||||
# status :integer default("initializing"), not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# account_id :bigint not null
|
||||
# external_id :string
|
||||
# id :bigint not null, primary key
|
||||
# cluster_type :integer default("k8s")
|
||||
# kubeconfig :jsonb
|
||||
# name :string not null
|
||||
# options :jsonb not null
|
||||
# skip_tls_verify :boolean default(FALSE), not null
|
||||
# status :integer default("initializing"), not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# account_id :bigint not null
|
||||
# external_id :string
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
|
||||
@@ -5,7 +5,6 @@ require 'ostruct'
|
||||
|
||||
module Builders
|
||||
class BuildCloud < Builders::Base
|
||||
include K8::Kubeconfig
|
||||
attr_reader :build_cloud_manager
|
||||
|
||||
def initialize(build, build_cloud_manager)
|
||||
@@ -26,15 +25,12 @@ module Builders
|
||||
|
||||
command = construct_buildx_command(project, repository_path)
|
||||
runner = Cli::RunAndLog.new(build, killable: build)
|
||||
with_kube_config do |kubeconfig_file|
|
||||
connection = build_cloud_manager.connection
|
||||
K8::Kubeconfig.with_kube_config(connection.kubeconfig, skip_tls_verify: connection.cluster.skip_tls_verify) do |kubeconfig_file|
|
||||
runner.call(command.join(" "), envs: { "KUBECONFIG" => kubeconfig_file.path })
|
||||
end
|
||||
end
|
||||
|
||||
def kubeconfig
|
||||
build_cloud_manager.connection.kubeconfig
|
||||
end
|
||||
|
||||
def construct_buildx_command(project, repository_path)
|
||||
command = [ "docker", "buildx", "build" ]
|
||||
command += [ "--builder", build_cloud_manager.build_cloud.name ]
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
class K8::BuildCloudManager
|
||||
include K8::Kubeconfig
|
||||
include StorageHelper
|
||||
# Only referenced in the migration for now.
|
||||
BUILDKIT_BUILDER_DEFAULT_NAMESPACE = 'canine-k8s-builder'
|
||||
@@ -159,7 +158,7 @@ class K8::BuildCloudManager
|
||||
|
||||
# Create the buildx builder with kubernetes driver
|
||||
# The --bootstrap flag will start the builder immediately
|
||||
with_kube_config do |kubeconfig_file|
|
||||
K8::Kubeconfig.with_kube_config(connection.kubeconfig, skip_tls_verify: connection.cluster.skip_tls_verify) do |kubeconfig_file|
|
||||
command = "docker buildx create "
|
||||
command += "--bootstrap "
|
||||
command += "--name #{build_cloud.name} "
|
||||
@@ -205,7 +204,7 @@ class K8::BuildCloudManager
|
||||
|
||||
def ensure_namespace!
|
||||
# Create namespace if it doesn't exist
|
||||
with_kube_config do |kubeconfig_file|
|
||||
K8::Kubeconfig.with_kube_config(connection.kubeconfig, skip_tls_verify: connection.cluster.skip_tls_verify) do |kubeconfig_file|
|
||||
command = "kubectl create namespace #{namespace}"
|
||||
runner.call(command, envs: { "KUBECONFIG" => kubeconfig_file.path })
|
||||
end
|
||||
@@ -227,11 +226,6 @@ class K8::BuildCloudManager
|
||||
@runner ||= Cli::RunAndLog.new(build_cloud)
|
||||
end
|
||||
|
||||
def kubeconfig
|
||||
# This is necessary for the include K8::Kubeconfig module
|
||||
connection.kubeconfig
|
||||
end
|
||||
|
||||
def parse_inspect_output(text)
|
||||
version = nil
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
class K8::Helm::Client
|
||||
DEFAULT_TIMEOUT = "1000s"
|
||||
CHARTS = YAML.load_file(Rails.root.join('resources', 'helm', 'charts.yml'))
|
||||
include K8::Kubeconfig
|
||||
attr_reader :kubeconfig, :runner
|
||||
attr_reader :connection, :runner
|
||||
|
||||
def initialize(runner)
|
||||
@runner = runner
|
||||
@@ -16,17 +15,16 @@ class K8::Helm::Client
|
||||
|
||||
def connect(connection)
|
||||
@connection = connection
|
||||
@kubeconfig = connection.kubeconfig.is_a?(String) ? JSON.parse(connection.kubeconfig) : connection.kubeconfig
|
||||
self
|
||||
end
|
||||
|
||||
def connected?
|
||||
@kubeconfig.present?
|
||||
@connection&.kubeconfig.present?
|
||||
end
|
||||
|
||||
def get_values_yaml(name, namespace: 'default')
|
||||
return StandardError.new("Can't get current values yaml if not connected") unless connected?
|
||||
with_kube_config do |kubeconfig_file|
|
||||
K8::Kubeconfig.with_kube_config(connection.kubeconfig, skip_tls_verify: connection.cluster.skip_tls_verify) do |kubeconfig_file|
|
||||
command = "helm get values #{name} --namespace #{namespace} --kubeconfig=#{kubeconfig_file.path}"
|
||||
output = runner.(command, envs: { "KUBECONFIG" => kubeconfig_file.path })
|
||||
# Remove the key USER-SUPPLIED VALUES
|
||||
@@ -38,7 +36,7 @@ class K8::Helm::Client
|
||||
|
||||
def get_all_values_yaml(name, namespace: 'default')
|
||||
return StandardError.new("Can't get all values yaml if not connected") unless connected?
|
||||
with_kube_config do |kubeconfig_file|
|
||||
K8::Kubeconfig.with_kube_config(connection.kubeconfig, skip_tls_verify: connection.cluster.skip_tls_verify) do |kubeconfig_file|
|
||||
command = "helm get values #{name} --all --namespace #{namespace} --kubeconfig=#{kubeconfig_file.path}"
|
||||
output = runner.(command, envs: { "KUBECONFIG" => kubeconfig_file.path })
|
||||
output
|
||||
@@ -47,7 +45,7 @@ class K8::Helm::Client
|
||||
|
||||
def ls
|
||||
return StandardError.new("Can't list helm charts if not connected") unless connected?
|
||||
with_kube_config do |kubeconfig_file|
|
||||
K8::Kubeconfig.with_kube_config(connection.kubeconfig, skip_tls_verify: connection.cluster.skip_tls_verify) do |kubeconfig_file|
|
||||
command_output = `helm ls --all-namespaces --kubeconfig=#{kubeconfig_file.path} -o yaml`
|
||||
output = YAML.safe_load(command_output)
|
||||
end
|
||||
@@ -107,12 +105,14 @@ class K8::Helm::Client
|
||||
wait: false,
|
||||
history_max: nil,
|
||||
create_namespace: false,
|
||||
skip_tls_verify: K8::Kubeconfig.skip_tls_verify?,
|
||||
skip_tls_verify: nil,
|
||||
timeout: DEFAULT_TIMEOUT
|
||||
)
|
||||
return StandardError.new("Can't install helm chart if not connected") unless connected?
|
||||
|
||||
with_kube_config do |kubeconfig_file|
|
||||
skip_tls = skip_tls_verify.nil? ? connection.cluster.skip_tls_verify : skip_tls_verify
|
||||
|
||||
K8::Kubeconfig.with_kube_config(connection.kubeconfig, skip_tls_verify: skip_tls) do |kubeconfig_file|
|
||||
Tempfile.create([ 'values', '.yaml' ]) do |values_file|
|
||||
values_file.write(values.to_yaml)
|
||||
values_file.flush
|
||||
@@ -129,7 +129,7 @@ class K8::Helm::Client
|
||||
wait: wait,
|
||||
history_max: history_max,
|
||||
create_namespace: create_namespace,
|
||||
skip_tls_verify: skip_tls_verify
|
||||
skip_tls_verify: skip_tls
|
||||
)
|
||||
exit_status = runner.(command, envs: { "KUBECONFIG" => kubeconfig_file.path })
|
||||
raise "`#{command}` failed with exit status #{exit_status}" unless exit_status.success?
|
||||
@@ -141,7 +141,7 @@ class K8::Helm::Client
|
||||
def uninstall(name, namespace: 'default')
|
||||
return StandardError.new("Can't uninstall helm chart if not connected") unless connected?
|
||||
|
||||
with_kube_config do |kubeconfig_file|
|
||||
K8::Kubeconfig.with_kube_config(connection.kubeconfig, skip_tls_verify: connection.cluster.skip_tls_verify) do |kubeconfig_file|
|
||||
command = "helm uninstall #{name} --namespace #{namespace}"
|
||||
exit_status = runner.(command, envs: { "KUBECONFIG" => kubeconfig_file.path })
|
||||
raise "Helm uninstall failed with exit status #{exit_status}" unless exit_status.success?
|
||||
|
||||
@@ -1,27 +1,17 @@
|
||||
module K8
|
||||
module Kubeconfig
|
||||
def self.skip_tls_verify?
|
||||
!ENV['VERIFY_CLUSTER_TLS'].present?
|
||||
end
|
||||
|
||||
def self.skip_tls_env
|
||||
skip_tls_verify? ? { "SKIP_TLS_VERIFY" => "true" } : {}
|
||||
end
|
||||
|
||||
def with_kube_config
|
||||
def self.with_kube_config(kubeconfig, skip_tls_verify: false)
|
||||
Tempfile.open([ 'kubeconfig', '.yaml' ]) do |kubeconfig_file|
|
||||
kubeconfig_hash = kubeconfig.is_a?(String) ? JSON.parse(kubeconfig) : kubeconfig
|
||||
kubeconfig_hash = apply_tls_settings(kubeconfig_hash)
|
||||
kubeconfig_hash = apply_tls_settings(kubeconfig_hash, skip_tls_verify)
|
||||
kubeconfig_file.write(kubeconfig_hash.to_yaml)
|
||||
kubeconfig_file.flush
|
||||
yield kubeconfig_file
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def apply_tls_settings(kubeconfig_hash)
|
||||
return kubeconfig_hash if ENV['VERIFY_CLUSTER_TLS'].present?
|
||||
def self.apply_tls_settings(kubeconfig_hash, skip_tls_verify)
|
||||
return kubeconfig_hash unless skip_tls_verify
|
||||
|
||||
kubeconfig_hash = kubeconfig_hash.deep_dup
|
||||
kubeconfig_hash['clusters']&.each do |cluster|
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class K8::Kubectl
|
||||
include K8::Kubeconfig
|
||||
attr_reader :kubeconfig, :runner
|
||||
attr_reader :connection, :runner
|
||||
|
||||
def initialize(connection, runner = Cli::RunAndReturnOutput.new)
|
||||
@_kubeconfig = connection.kubeconfig
|
||||
@kubeconfig = @_kubeconfig.is_a?(String) ? JSON.parse(@_kubeconfig) : @_kubeconfig
|
||||
if @kubeconfig.nil?
|
||||
@connection = connection
|
||||
if connection.kubeconfig.nil?
|
||||
raise "Kubeconfig is required"
|
||||
end
|
||||
@runner = runner
|
||||
@@ -28,7 +26,7 @@ class K8::Kubectl
|
||||
block.call(yaml_content)
|
||||
end
|
||||
|
||||
with_kube_config do |kubeconfig_file|
|
||||
K8::Kubeconfig.with_kube_config(connection.kubeconfig, skip_tls_verify: connection.cluster.skip_tls_verify) do |kubeconfig_file|
|
||||
# Create a temporary file for the YAML content
|
||||
Tempfile.open([ "k8s", ".yaml" ]) do |yaml_file|
|
||||
yaml_file.write(yaml_content)
|
||||
@@ -46,7 +44,7 @@ class K8::Kubectl
|
||||
end
|
||||
|
||||
def call(command)
|
||||
with_kube_config do |kubeconfig_file|
|
||||
K8::Kubeconfig.with_kube_config(connection.kubeconfig, skip_tls_verify: connection.cluster.skip_tls_verify) do |kubeconfig_file|
|
||||
full_command = "kubectl #{command}"
|
||||
runner.call(full_command, envs: { "KUBECONFIG" => kubeconfig_file.path })
|
||||
end
|
||||
|
||||
@@ -7,6 +7,13 @@
|
||||
</label>
|
||||
<% end %>
|
||||
|
||||
<%= render(FormFieldComponent.new(
|
||||
label: "Skip TLS Verification",
|
||||
description: "Enable this if your cluster uses self-signed certificates."
|
||||
)) do %>
|
||||
<%= form.check_box :skip_tls_verify, class: "checkbox checkbox-error" %>
|
||||
<% end %>
|
||||
|
||||
<div class="form-footer">
|
||||
<%= form.submit "Save", class: "btn btn-primary", data: { turbo_submits_with: "Saving..." } %>
|
||||
</div>
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
<%= render "clusters/cluster_types/instructions/local_k3s", form: form %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<% end %>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddSkipTlsVerifyToClusters < ActiveRecord::Migration[7.2]
|
||||
def change
|
||||
add_column :clusters, :skip_tls_verify, :boolean, default: false, null: false
|
||||
end
|
||||
end
|
||||
3
db/schema.rb
generated
3
db/schema.rb
generated
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[7.2].define(version: 2026_01_08_142856) do
|
||||
ActiveRecord::Schema[7.2].define(version: 2026_01_16_173824) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
||||
@@ -175,6 +175,7 @@ ActiveRecord::Schema[7.2].define(version: 2026_01_08_142856) do
|
||||
t.integer "cluster_type", default: 0
|
||||
t.string "external_id"
|
||||
t.jsonb "options", default: {}, null: false
|
||||
t.boolean "skip_tls_verify", default: false, null: false
|
||||
t.index ["account_id", "name"], name: "index_clusters_on_account_id_and_name", unique: true
|
||||
end
|
||||
|
||||
|
||||
@@ -2,16 +2,17 @@
|
||||
#
|
||||
# Table name: clusters
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# cluster_type :integer default("k8s")
|
||||
# kubeconfig :jsonb
|
||||
# name :string not null
|
||||
# options :jsonb not null
|
||||
# status :integer default("initializing"), not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# account_id :bigint not null
|
||||
# external_id :string
|
||||
# id :bigint not null, primary key
|
||||
# cluster_type :integer default("k8s")
|
||||
# kubeconfig :jsonb
|
||||
# name :string not null
|
||||
# options :jsonb not null
|
||||
# skip_tls_verify :boolean default(FALSE), not null
|
||||
# status :integer default("initializing"), not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# account_id :bigint not null
|
||||
# external_id :string
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
|
||||
@@ -2,16 +2,17 @@
|
||||
#
|
||||
# Table name: clusters
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# cluster_type :integer default("k8s")
|
||||
# kubeconfig :jsonb
|
||||
# name :string not null
|
||||
# options :jsonb not null
|
||||
# status :integer default("initializing"), not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# account_id :bigint not null
|
||||
# external_id :string
|
||||
# id :bigint not null, primary key
|
||||
# cluster_type :integer default("k8s")
|
||||
# kubeconfig :jsonb
|
||||
# name :string not null
|
||||
# options :jsonb not null
|
||||
# skip_tls_verify :boolean default(FALSE), not null
|
||||
# status :integer default("initializing"), not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# account_id :bigint not null
|
||||
# external_id :string
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
|
||||
@@ -3,19 +3,16 @@ require 'rails_helper'
|
||||
RSpec.describe K8::Helm::Client do
|
||||
let(:runner) { instance_double(Cli::RunAndReturnOutput) }
|
||||
let(:client) { described_class.new(runner) }
|
||||
let(:cluster) { create(:cluster) }
|
||||
let(:connection) { K8::Connection.new(cluster, nil) }
|
||||
|
||||
describe '#connected?' do
|
||||
it 'returns false when not connected' do
|
||||
expect(client).not_to be_connected
|
||||
end
|
||||
|
||||
it 'returns false when @kubeconfig is nil' do
|
||||
client.instance_variable_set(:@kubeconfig, nil)
|
||||
expect(client).not_to be_connected
|
||||
end
|
||||
|
||||
it 'returns true when @kubeconfig is present' do
|
||||
client.instance_variable_set(:@kubeconfig, { "apiVersion" => "v1" })
|
||||
it 'returns true when connection kubeconfig is present' do
|
||||
client.connect(connection)
|
||||
expect(client).to be_connected
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user