This implements a fairly loose validation of the public key format. It does not check specific key types, nor try to decode the base64 key and check it for validity. It does check that the format in general is valid, and that at least one valid key is present. It will reject public keys, because those don't have a space. This requires changes to many specs to have them use a valid public key format. In many cases, that is done by changing a single dash to a space.
168 lines
5.8 KiB
Ruby
168 lines
5.8 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 greater than 0"])
|
|
|
|
kc.cp_node_count = 2
|
|
expect(kc.valid?).to be true
|
|
end
|
|
|
|
it "validates version" do
|
|
kc.version = "v1.33"
|
|
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
|
|
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
|
|
let(:sshable) { instance_double(Sshable) }
|
|
let(:vm) { instance_double(Vm, sshable: sshable) }
|
|
let(:cp_vms) { [vm] }
|
|
|
|
it "removes client certificate and key data from users and adds an RBAC token to users" do
|
|
expect(kc).to receive(:cp_vms).and_return(cp_vms)
|
|
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 vms" 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)
|
|
np = instance_double(KubernetesNodepool, vms: [missing_vm])
|
|
expect(kc).to receive(:nodepools).and_return([np])
|
|
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 vms" 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
|
|
end
|