Files
ubicloud/model/kubernetes/kubernetes_cluster.rb
mohi-kalantari 95a458be13 Add new semaphore for full mesh connectivity between k8s worker nodes
A new semaphore is added to start the rekey process, which creates an SSH
key pair for each worker node and distributes all public keys to all worker
VMs so they can connect to each other.
2025-07-15 10:57:25 +02:00

149 lines
5.3 KiB
Ruby

# frozen_string_literal: true
require_relative "../../model"
class KubernetesCluster < Sequel::Model
one_to_one :strand, key: :id
many_to_one :api_server_lb, class: :LoadBalancer
many_to_one :services_lb, class: :LoadBalancer
many_to_one :private_subnet
many_to_one :project
many_to_many :cp_vms, join_table: :kubernetes_clusters_cp_vms, class: :Vm, order: :created_at
one_to_many :nodepools, class: :KubernetesNodepool
one_to_many :active_billing_records, class: :BillingRecord, key: :resource_id, &:active
many_to_one :location, key: :location_id
dataset_module Pagination
plugin ResourceMethods
plugin SemaphoreMethods, :destroy, :sync_kubernetes_services, :upgrade, :install_metrics_server, :sync_worker_mesh
include HealthMonitorMethods
def validate
super
errors.add(:cp_node_count, "must be a positive integer") unless cp_node_count.is_a?(Integer) && cp_node_count > 0
errors.add(:version, "must be a valid Kubernetes version") unless Option.kubernetes_versions.include?(version)
end
def display_state
label = strand.label
return "deleting" if destroy_set? || label == "destroy"
return "running" if label == "wait"
"creating"
end
def display_location
location.display_name
end
def path
"/location/#{display_location}/kubernetes-cluster/#{name}"
end
def endpoint
api_server_lb.hostname
end
def client(session: cp_vms.first.sshable.connect)
Kubernetes::Client.new(self, session)
end
def sshable
cp_vms.first.sshable
end
def services_load_balancer_name
"#{ubid}-services"
end
def apiserver_load_balancer_name
"#{ubid}-apiserver"
end
def self.kubeconfig(vm)
rbac_token = vm.sshable.cmd("kubectl --kubeconfig <(sudo cat /etc/kubernetes/admin.conf) -n kube-system get secret k8s-access -o jsonpath='{.data.token}' | base64 -d", log: false)
admin_kubeconfig = vm.sshable.cmd("sudo cat /etc/kubernetes/admin.conf", log: false)
kubeconfig = YAML.safe_load(admin_kubeconfig)
kubeconfig["users"].each do |user|
user["user"].delete("client-certificate-data")
user["user"].delete("client-key-data")
user["user"]["token"] = rbac_token
end
kubeconfig.to_yaml
end
def kubeconfig
self.class.kubeconfig(cp_vms.first)
end
def vm_diff_for_lb(load_balancer)
worker_vms = nodepools.flat_map(&:vms)
worker_vm_ids = worker_vms.map(&:id).to_set
lb_vms = load_balancer.load_balancers_vms.map(&:vm)
lb_vm_ids = lb_vms.map(&:id).to_set
extra_vms = lb_vms.reject { |vm| worker_vm_ids.include?(vm.id) }
missing_vms = worker_vms.reject { |vm| lb_vm_ids.include?(vm.id) }
[extra_vms, missing_vms]
end
def port_diff_for_lb(load_balancer, desired_ports)
lb_ports_hash = load_balancer.ports.to_h { |p| [[p.src_port, p.dst_port], p.id] }
missing_ports = desired_ports - lb_ports_hash.keys
extra_ports = (lb_ports_hash.keys - desired_ports).map { |p| LoadBalancerPort[id: lb_ports_hash[p]] }
[extra_ports, missing_ports]
end
def init_health_monitor_session
{
ssh_session: sshable.start_fresh_session
}
end
def check_pulse(session:, previous_pulse:)
reading = begin
incr_sync_kubernetes_services if client(session: session[:ssh_session]).any_lb_services_modified?
"up"
rescue
"down"
end
aggregate_readings(previous_pulse: previous_pulse, reading: reading)
end
def all_vms
cp_vms + nodepools.flat_map(&:vms)
end
def worker_vms
nodepools.flat_map(&:vms)
end
end
# Table: kubernetes_cluster
# Columns:
# id | uuid | PRIMARY KEY
# name | text | NOT NULL
# cp_node_count | integer | NOT NULL
# version | text | NOT NULL
# created_at | timestamp with time zone | NOT NULL DEFAULT CURRENT_TIMESTAMP
# project_id | uuid | NOT NULL
# private_subnet_id | uuid | NOT NULL
# api_server_lb_id | uuid |
# target_node_size | text | NOT NULL
# target_node_storage_size_gib | bigint |
# location_id | uuid | NOT NULL
# services_lb_id | uuid |
# Indexes:
# kubernetes_cluster_pkey | PRIMARY KEY btree (id)
# kubernetes_cluster_project_id_location_id_name_uidx | UNIQUE btree (project_id, location_id, name)
# Foreign key constraints:
# kubernetes_cluster_api_server_lb_id_fkey | (api_server_lb_id) REFERENCES load_balancer(id)
# kubernetes_cluster_location_id_fkey | (location_id) REFERENCES location(id)
# kubernetes_cluster_private_subnet_id_fkey | (private_subnet_id) REFERENCES private_subnet(id)
# kubernetes_cluster_project_id_fkey | (project_id) REFERENCES project(id)
# kubernetes_cluster_services_lb_id_fkey | (services_lb_id) REFERENCES load_balancer(id)
# Referenced By:
# kubernetes_clusters_cp_vms | kubernetes_clusters_cp_vms_kubernetes_cluster_id_fkey | (kubernetes_cluster_id) REFERENCES kubernetes_cluster(id)
# kubernetes_nodepool | kubernetes_nodepool_kubernetes_cluster_id_fkey | (kubernetes_cluster_id) REFERENCES kubernetes_cluster(id)