mirror of
https://github.com/ubicloud/ubicloud.git
synced 2025-10-08 15:51:57 +08:00
All the logics related to k8s (provisioning, bootstrapping, upgrades) now all rely on the KuberneteNode object. The former methods for Vm are still kept in place until the code is deployed and in another commit those parts with their DB tables will be removed altogether. Code will no longer try to add vms to the join tables for the many_to_many tables of both KubernetesCluster and KubernetesNodepool Instead kubernetes_node object will be used to find the right Vms of nodepools and clusters.
193 lines
7 KiB
Ruby
193 lines
7 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require_relative "../spec_helper"
|
|
|
|
RSpec.describe KubernetesCluster do
|
|
subject(:kc) {
|
|
project = Project.create(name: "test")
|
|
private_subnet = PrivateSubnet.create(project_id: project.id, name: "test", location_id: Location::HETZNER_FSN1_ID, net6: "fe80::/64", net4: "192.168.0.0/24")
|
|
described_class.create(
|
|
name: "kc-name",
|
|
version: "v1.32",
|
|
location_id: Location::HETZNER_FSN1_ID,
|
|
cp_node_count: 3,
|
|
project_id: project.id,
|
|
private_subnet_id: private_subnet.id,
|
|
target_node_size: "standard-2"
|
|
)
|
|
}
|
|
|
|
it "displays location properly" do
|
|
expect(kc.display_location).to eq("eu-central-h1")
|
|
end
|
|
|
|
it "returns path" do
|
|
expect(kc.path).to eq("/location/eu-central-h1/kubernetes-cluster/kc-name")
|
|
end
|
|
|
|
it "initiates a new health monitor session" do
|
|
sshable = instance_double(Sshable)
|
|
expect(kc).to receive(:sshable).and_return(sshable)
|
|
expect(sshable).to receive(:start_fresh_session)
|
|
kc.init_health_monitor_session
|
|
end
|
|
|
|
it "checks pulse" do
|
|
session = {
|
|
ssh_session: instance_double(Net::SSH::Connection::Session)
|
|
}
|
|
pulse = {
|
|
reading: "down",
|
|
reading_rpt: 5,
|
|
reading_chg: Time.now - 30
|
|
}
|
|
|
|
expect(kc).to receive(:incr_sync_kubernetes_services)
|
|
client = instance_double(Kubernetes::Client)
|
|
expect(kc).to receive(:client).and_return(client)
|
|
expect(client).to receive(:any_lb_services_modified?).and_return(true)
|
|
|
|
expect(kc.check_pulse(session: session, previous_pulse: pulse)[:reading]).to eq("up")
|
|
end
|
|
|
|
it "checks pulse on with no changes to the internal services" do
|
|
session = {
|
|
ssh_session: instance_double(Net::SSH::Connection::Session)
|
|
}
|
|
pulse = {
|
|
reading: "up",
|
|
reading_rpt: 5,
|
|
reading_chg: Time.now - 30
|
|
}
|
|
|
|
client = instance_double(Kubernetes::Client)
|
|
expect(kc).to receive(:client).and_return(client)
|
|
expect(client).to receive(:any_lb_services_modified?).and_return(false)
|
|
|
|
expect(kc.check_pulse(session: session, previous_pulse: pulse)[:reading]).to eq("up")
|
|
end
|
|
|
|
it "checks pulse and fails" do
|
|
session = {
|
|
ssh_session: instance_double(Net::SSH::Connection::Session)
|
|
}
|
|
pulse = {
|
|
reading: "down",
|
|
reading_rpt: 5,
|
|
reading_chg: Time.now - 30
|
|
}
|
|
|
|
client = instance_double(Kubernetes::Client)
|
|
expect(kc).to receive(:client).and_return(client)
|
|
expect(client).to receive(:any_lb_services_modified?).and_raise Sshable::SshError
|
|
|
|
expect(kc.check_pulse(session: session, previous_pulse: pulse)[:reading]).to eq("down")
|
|
end
|
|
|
|
describe "#kubectl" do
|
|
it "create a new client" do
|
|
session = instance_double(Net::SSH::Connection::Session)
|
|
expect(kc.client(session: session)).to be_an_instance_of(Kubernetes::Client)
|
|
end
|
|
end
|
|
|
|
describe "#validate" do
|
|
it "validates cp_node_count" do
|
|
kc.cp_node_count = 0
|
|
expect(kc.valid?).to be false
|
|
expect(kc.errors[:cp_node_count]).to eq(["must be a positive integer"])
|
|
|
|
kc.cp_node_count = 2
|
|
expect(kc.valid?).to be true
|
|
end
|
|
|
|
it "validates version" do
|
|
kc.version = "v1.34"
|
|
expect(kc.valid?).to be false
|
|
expect(kc.errors[:version]).to eq(["must be a valid Kubernetes version"])
|
|
|
|
kc.version = "v1.32"
|
|
expect(kc.valid?).to be true
|
|
end
|
|
|
|
it "adds error if cp_node_count is nil" do
|
|
kc.cp_node_count = nil
|
|
expect(kc.valid?).to be false
|
|
expect(kc.errors[:cp_node_count]).to include("must be a positive integer")
|
|
end
|
|
|
|
it "adds error if cp_node_count is not an integer" do
|
|
kc.cp_node_count = "three"
|
|
expect(kc.valid?).to be false
|
|
expect(kc.errors[:cp_node_count]).to include("must be a positive integer")
|
|
end
|
|
end
|
|
|
|
describe "#kubeconfig" do
|
|
kubeconfig = <<~YAML
|
|
apiVersion: v1
|
|
kind: Config
|
|
users:
|
|
- name: admin
|
|
user:
|
|
client-certificate-data: "mocked_cert_data"
|
|
client-key-data: "mocked_key_data"
|
|
YAML
|
|
|
|
it "removes client certificate and key data from users and adds an RBAC token to users" do
|
|
sshable = instance_double(Sshable)
|
|
KubernetesNode.create(vm_id: create_vm.id, kubernetes_cluster_id: kc.id)
|
|
expect(kc.cp_vms_via_nodes.first).to receive(:sshable).and_return(sshable).twice
|
|
expect(sshable).to receive(:cmd).with("kubectl --kubeconfig <(sudo cat /etc/kubernetes/admin.conf) -n kube-system get secret k8s-access -o jsonpath='{.data.token}' | base64 -d", log: false).and_return("mocked_rbac_token")
|
|
expect(sshable).to receive(:cmd).with("sudo cat /etc/kubernetes/admin.conf", log: false).and_return(kubeconfig)
|
|
customer_config = kc.kubeconfig
|
|
YAML.safe_load(customer_config)["users"].each do |user|
|
|
expect(user["user"]).not_to have_key("client-certificate-data")
|
|
expect(user["user"]).not_to have_key("client-key-data")
|
|
expect(user["user"]["token"]).to eq("mocked_rbac_token")
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "vm_diff_for_lb" do
|
|
it "finds the extra and missing nodes" do
|
|
lb = Prog::Vnet::LoadBalancerNexus.assemble(kc.private_subnet.id, name: kc.services_load_balancer_name, src_port: 443, dst_port: 8443).subject
|
|
extra_vm = Prog::Vm::Nexus.assemble("k y", kc.project.id, name: "extra-vm", private_subnet_id: kc.private_subnet.id).subject
|
|
missing_vm = Prog::Vm::Nexus.assemble("k y", kc.project.id, name: "missing-vm", private_subnet_id: kc.private_subnet.id).subject
|
|
lb.add_vm(extra_vm)
|
|
kn = KubernetesNodepool.create(name: "np", node_count: 1, kubernetes_cluster_id: kc.id, target_node_size: "standard-2")
|
|
KubernetesNode.create(vm_id: missing_vm.id, kubernetes_cluster_id: kc.id, kubernetes_nodepool_id: kn.id)
|
|
extra_vms, missing_vms = kc.vm_diff_for_lb(lb)
|
|
expect(extra_vms.count).to eq(1)
|
|
expect(extra_vms[0].id).to eq(extra_vm.id)
|
|
expect(missing_vms.count).to eq(1)
|
|
expect(missing_vms[0].id).to eq(missing_vm.id)
|
|
end
|
|
end
|
|
|
|
describe "port_diff_for_lb" do
|
|
it "finds the extra and missing nodes" do
|
|
lb = Prog::Vnet::LoadBalancerNexus.assemble(kc.private_subnet.id, name: kc.services_load_balancer_name, src_port: 80, dst_port: 8000).subject
|
|
extra_ports, missing_ports = kc.port_diff_for_lb(lb, [[443, 8443]])
|
|
expect(extra_ports.count).to eq(1)
|
|
expect(extra_ports[0].src_port).to eq(80)
|
|
expect(missing_ports.count).to eq(1)
|
|
expect(missing_ports[0][0]).to eq(443)
|
|
end
|
|
end
|
|
|
|
describe "#all_nodes" do
|
|
it "returns all nodes in the cluster" do
|
|
expect(kc).to receive(:nodes).and_return([1, 2])
|
|
expect(kc).to receive(:nodepools).and_return([instance_double(KubernetesNodepool, nodes: [3, 4]), instance_double(KubernetesNodepool, nodes: [5, 6])])
|
|
expect(kc.all_nodes).to eq([1, 2, 3, 4, 5, 6])
|
|
end
|
|
end
|
|
|
|
describe "#worker_vms" do
|
|
it "returns all worker vms in the cluster" do
|
|
expect(kc).to receive(:nodepools).and_return([instance_double(KubernetesNodepool, vms_via_nodes: [3, 4]), instance_double(KubernetesNodepool, vms_via_nodes: [5, 6])])
|
|
expect(kc.worker_vms).to eq([3, 4, 5, 6])
|
|
end
|
|
end
|
|
end
|