This makes test and production more similar. By piggybacking on the
existing rspec metadata used to add other common headers, it's
possible to likewise set the Host header by default.
Most of the bulk of this patch is from running `sed`, but the
interesting hunks are in:
* clover.rb: eliminate a branch to add `/api/` mangling
* routes/api/spec_helper.rb: add the Host header by default
* routes/api/project_spec.rb: remove a special test for the host
calling convention, as it's now used in every test.
The motivation for this was to make the program easier to validate
with OpenAPI and `committee`, where having two calling conventions
(even for the one test that set `Host`) would need more workarounds.
Of a minor note, the efforts to remove helsinki e.g.
e114669438
, generated quite a few
conflicts as norms in what to use in test as an example region change.
I used `sed` through the code base to rewrite identifiers, so I picked
up some extra ones that are not strictly necessary for this patch, but
I left them in.
311 lines
18 KiB
Ruby
311 lines
18 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require_relative "../../model/spec_helper"
|
|
require "netaddr"
|
|
|
|
RSpec.describe Prog::Test::ConnectedSubnets do
|
|
subject(:connected_subnets_test) {
|
|
described_class.new(Strand.new(prog: "Test::ConnectedSubnets"))
|
|
}
|
|
|
|
let(:ps_multiple) {
|
|
Prog::Vnet::SubnetNexus.assemble(project.id, name: "ps-multiple", location: "hetzner-fsn1").subject
|
|
}
|
|
|
|
let(:ps_single) {
|
|
Prog::Vnet::SubnetNexus.assemble(project.id, name: "ps-single", location: "hetzner-fsn1").subject
|
|
}
|
|
|
|
let(:project) {
|
|
prj = Project.create_with_id(name: "project1")
|
|
prj.associate_with_project(prj)
|
|
prj
|
|
}
|
|
|
|
let(:sshable) {
|
|
instance_double(Sshable)
|
|
}
|
|
|
|
before do
|
|
ps_multiple
|
|
ps_single
|
|
allow(connected_subnets_test).to receive(:frame).and_return({"subnet_id_multiple" => ps_multiple.id, "subnet_id_single" => ps_single.id}).at_least(:once)
|
|
end
|
|
|
|
describe "#start" do
|
|
it "updates firewall rules for both subnets, connects them, updates the stack, and naps" do
|
|
expect(connected_subnets_test).to receive(:update_firewall_rules).with(ps_single, ps_multiple, config: :perform_tests_public_blocked)
|
|
expect(connected_subnets_test).to receive(:update_firewall_rules).with(ps_multiple, ps_single, config: :perform_tests_public_blocked)
|
|
expect(connected_subnets_test).to receive(:ps_multiple).and_return(ps_multiple).at_least(:once)
|
|
vm1 = instance_double(Vm, sshable: sshable, ephemeral_net4: NetAddr::IPv4Net.parse("0.0.0.0"), boot_image: "debian-12")
|
|
vm2 = instance_double(Vm, sshable: sshable, boot_image: "almalinux-9")
|
|
expect(ps_multiple).to receive(:vms).and_return([vm1, vm2]).at_least(:once)
|
|
expect(sshable).to receive(:cmd).with("sudo yum install -y nc")
|
|
expect(sshable).to receive(:cmd).with("sudo apt-get update && sudo apt-get install -y netcat-openbsd")
|
|
expect(sshable).to receive(:cmd).with("echo '[Unit]
|
|
Description=A lightweight port 8080 listener
|
|
After=network.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
ExecStart=/usr/bin/nc -l 8080
|
|
' | sudo tee /etc/systemd/system/listening_ipv4.service > /dev/null")
|
|
expect(sshable).to receive(:cmd).with("echo '[Unit]
|
|
Description=A lightweight port 8080 listener
|
|
After=network.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
ExecStart=nc -l 8080 -6
|
|
' | sudo tee /etc/systemd/system/listening_ipv6.service > /dev/null")
|
|
expect(sshable).to receive(:cmd).with("sudo systemctl daemon-reload")
|
|
expect(sshable).to receive(:cmd).with("sudo systemctl enable listening_ipv4.service")
|
|
expect(sshable).to receive(:cmd).with("sudo systemctl enable listening_ipv6.service")
|
|
expect(connected_subnets_test).to receive(:update_stack).with({"connected" => true})
|
|
expect { connected_subnets_test.start }.to nap(5)
|
|
end
|
|
|
|
it "hops to perform_tests_public_blocked" do
|
|
expect(connected_subnets_test).to receive(:frame).and_return({"connected" => true})
|
|
ps_multiple.strand.update(label: "wait")
|
|
ps_single.strand.update(label: "wait")
|
|
Semaphore.all.map(&:destroy)
|
|
|
|
expect { connected_subnets_test.start }.to hop("perform_tests_public_blocked")
|
|
end
|
|
end
|
|
|
|
describe "#perform_tests_public_blocked" do
|
|
it "tests connection between the two subnets and fails" do
|
|
expect(connected_subnets_test).to receive(:ps_multiple).and_return(ps_multiple).at_least(:once)
|
|
expect(connected_subnets_test).to receive(:ps_single).and_return(ps_single).at_least(:once)
|
|
vm1 = instance_double(Vm, sshable: sshable, ephemeral_net4: NetAddr::IPv4Net.parse("0.0.0.0"))
|
|
vm2 = instance_double(Vm, sshable: sshable)
|
|
expect(ps_multiple).to receive(:vms).and_return([vm1, vm2]).at_least(:once)
|
|
expect(ps_single).to receive(:vms).and_return([vm2]).at_least(:once)
|
|
expect(sshable).to receive(:cmd).with("ping -c 2 google.com").at_least(:once)
|
|
expect(sshable).to receive(:cmd).with("sudo systemctl start listening_ipv4.service")
|
|
expect(sshable).to receive(:cmd).with("sudo systemctl stop listening_ipv6.service")
|
|
expect(connected_subnets_test).to receive(:test_connection).with(vm1.ephemeral_net4, vm2, should_fail: true, ipv4: true)
|
|
|
|
expect { connected_subnets_test.perform_tests_public_blocked }.to hop("perform_tests_private_ipv4")
|
|
end
|
|
end
|
|
|
|
describe "#perform_tests_private_ipv4" do
|
|
it "updates firewall rules, updates the stack, and naps" do
|
|
expect(connected_subnets_test).to receive(:ps_multiple).and_return(ps_multiple).at_least(:once)
|
|
expect(connected_subnets_test).to receive(:update_firewall_rules).with(ps_multiple, ps_single, config: :perform_connected_private_ipv4)
|
|
expect(connected_subnets_test).to receive(:update_stack).with({"firewalls" => "connected_private_ipv4"})
|
|
expect(ps_multiple).to receive(:update_firewall_rules_set?).and_return(true)
|
|
expect { connected_subnets_test.perform_tests_private_ipv4 }.to nap(5)
|
|
end
|
|
|
|
it "tests connection between the two subnets and hops to perform_tests_private_ipv6" do
|
|
expect(connected_subnets_test).to receive(:frame).and_return({"firewalls" => "connected_private_ipv4"})
|
|
expect(connected_subnets_test).to receive(:ps_multiple).and_return(ps_multiple).at_least(:once)
|
|
|
|
vm1 = instance_double(Vm, sshable: sshable, nics: [instance_double(Nic, private_ipv4: NetAddr::IPv4Net.parse("10.0.0.0/26"))])
|
|
vm2 = instance_double(Vm)
|
|
expect(connected_subnets_test).to receive(:vm_to_be_connected).and_return(vm1).at_least(:once)
|
|
expect(connected_subnets_test).to receive(:vm_to_connect).and_return(vm2).at_least(:once)
|
|
expect(connected_subnets_test).to receive(:vm_to_connect_outside).and_return(vm2).at_least(:once)
|
|
|
|
expect(sshable).to receive(:cmd).with("sudo systemctl start listening_ipv4.service")
|
|
expect(sshable).to receive(:cmd).with("sudo systemctl stop listening_ipv6.service")
|
|
expect(connected_subnets_test).to receive(:test_connection).with(vm1.nics.first.private_ipv4.nth(0).to_s, vm2, should_fail: false, ipv4: true)
|
|
expect(connected_subnets_test).to receive(:test_connection).with(vm1.nics.first.private_ipv4.nth(0).to_s, vm2, should_fail: true, ipv4: true)
|
|
|
|
expect { connected_subnets_test.perform_tests_private_ipv4 }.to hop("perform_tests_private_ipv6")
|
|
end
|
|
end
|
|
|
|
describe "#perform_tests_private_ipv6" do
|
|
it "updates firewall rules, updates the stack, and naps" do
|
|
expect(connected_subnets_test).to receive(:ps_multiple).and_return(ps_multiple).at_least(:once)
|
|
expect(connected_subnets_test).to receive(:update_firewall_rules).with(ps_multiple, ps_single, config: :perform_connected_private_ipv6)
|
|
expect(connected_subnets_test).to receive(:update_stack).with({"firewalls" => "connected_private_ipv6"})
|
|
expect(ps_multiple).to receive(:update_firewall_rules_set?).and_return(true)
|
|
expect { connected_subnets_test.perform_tests_private_ipv6 }.to nap(5)
|
|
end
|
|
|
|
it "tests connection between the two subnets and hops to perform_blocked_private_ipv4" do
|
|
expect(connected_subnets_test).to receive(:frame).and_return({"firewalls" => "connected_private_ipv6"})
|
|
vm1 = instance_double(Vm, sshable: sshable, nics: [instance_double(Nic, private_ipv6: NetAddr::IPv6Net.parse("2001:db8::/64"))])
|
|
vm2 = instance_double(Vm)
|
|
expect(connected_subnets_test).to receive(:vm_to_be_connected).and_return(vm1).at_least(:once)
|
|
expect(connected_subnets_test).to receive(:vm_to_connect).and_return(vm2).at_least(:once)
|
|
expect(connected_subnets_test).to receive(:vm_to_connect_outside).and_return(vm2).at_least(:once)
|
|
|
|
expect(sshable).to receive(:cmd).with("sudo systemctl start listening_ipv6.service")
|
|
expect(sshable).to receive(:cmd).with("sudo systemctl stop listening_ipv4.service")
|
|
expect(connected_subnets_test).to receive(:test_connection).with(vm1.nics.first.private_ipv6.nth(2).to_s, vm2, should_fail: false, ipv4: false)
|
|
expect(connected_subnets_test).to receive(:test_connection).with(vm1.nics.first.private_ipv6.nth(2).to_s, vm2, should_fail: true, ipv4: false)
|
|
|
|
expect { connected_subnets_test.perform_tests_private_ipv6 }.to hop("perform_blocked_private_ipv4")
|
|
end
|
|
end
|
|
|
|
describe "#perform_blocked_private_ipv4" do
|
|
it "updates firewall rules, updates the stack, and naps" do
|
|
expect(connected_subnets_test).to receive(:ps_multiple).and_return(ps_multiple).at_least(:once)
|
|
expect(connected_subnets_test).to receive(:update_firewall_rules).with(ps_multiple, ps_multiple, config: :perform_blocked_private_ipv4)
|
|
expect(connected_subnets_test).to receive(:update_stack).with({"firewalls" => "blocked_private_ipv4"})
|
|
expect(ps_multiple).to receive(:update_firewall_rules_set?).and_return(true)
|
|
expect { connected_subnets_test.perform_blocked_private_ipv4 }.to nap(5)
|
|
end
|
|
|
|
it "tests connection between the two subnets and hops to perform_blocked_private_ipv6" do
|
|
expect(connected_subnets_test).to receive(:frame).and_return({"firewalls" => "blocked_private_ipv4"})
|
|
vm1 = instance_double(Vm, sshable: sshable, nics: [instance_double(Nic, private_ipv4: NetAddr::IPv4Net.parse("10.0.0.0/26"))])
|
|
vm2 = instance_double(Vm)
|
|
expect(connected_subnets_test).to receive(:vm_to_be_connected).and_return(vm1).at_least(:once)
|
|
expect(connected_subnets_test).to receive(:vm_to_connect).and_return(vm2).at_least(:once)
|
|
expect(connected_subnets_test).to receive(:vm_to_connect_outside).and_return(vm2).at_least(:once)
|
|
|
|
expect(sshable).to receive(:cmd).with("sudo systemctl start listening_ipv4.service")
|
|
expect(sshable).to receive(:cmd).with("sudo systemctl stop listening_ipv6.service")
|
|
expect(connected_subnets_test).to receive(:test_connection).with(vm1.nics.first.private_ipv4.nth(0).to_s, vm2, should_fail: false, ipv4: true)
|
|
expect(connected_subnets_test).to receive(:test_connection).with(vm1.nics.first.private_ipv4.nth(0).to_s, vm2, should_fail: true, ipv4: true)
|
|
|
|
expect { connected_subnets_test.perform_blocked_private_ipv4 }.to hop("perform_blocked_private_ipv6")
|
|
end
|
|
end
|
|
|
|
describe "#perform_blocked_private_ipv6" do
|
|
it "updates firewall rules, updates the stack, and naps" do
|
|
expect(connected_subnets_test).to receive(:ps_multiple).and_return(ps_multiple).at_least(:once)
|
|
expect(connected_subnets_test).to receive(:update_firewall_rules).with(ps_multiple, ps_multiple, config: :perform_blocked_private_ipv6)
|
|
expect(connected_subnets_test).to receive(:update_stack).with({"firewalls" => "blocked_private_ipv6"})
|
|
expect(ps_multiple).to receive(:update_firewall_rules_set?).and_return(true)
|
|
expect { connected_subnets_test.perform_blocked_private_ipv6 }.to nap(5)
|
|
end
|
|
|
|
it "tests connection between the two subnets and hops to perform_tests_public_blocked" do
|
|
expect(connected_subnets_test).to receive(:frame).and_return({"firewalls" => "blocked_private_ipv6"})
|
|
vm1 = instance_double(Vm, sshable: sshable, nics: [instance_double(Nic, private_ipv6: NetAddr::IPv6Net.parse("2001:db8::/64"))])
|
|
vm2 = instance_double(Vm)
|
|
expect(connected_subnets_test).to receive(:vm_to_be_connected).and_return(vm1).at_least(:once)
|
|
expect(connected_subnets_test).to receive(:vm_to_connect).and_return(vm2).at_least(:once)
|
|
expect(connected_subnets_test).to receive(:vm_to_connect_outside).and_return(vm2).at_least(:once)
|
|
|
|
expect(sshable).to receive(:cmd).with("sudo systemctl start listening_ipv6.service")
|
|
expect(sshable).to receive(:cmd).with("sudo systemctl stop listening_ipv4.service")
|
|
expect(connected_subnets_test).to receive(:test_connection).with(vm1.nics.first.private_ipv6.nth(2).to_s, vm2, should_fail: false, ipv4: false)
|
|
expect(connected_subnets_test).to receive(:test_connection).with(vm1.nics.first.private_ipv6.nth(2).to_s, vm2, should_fail: true, ipv4: false)
|
|
|
|
expect { connected_subnets_test.perform_blocked_private_ipv6 }.to hop("finish")
|
|
end
|
|
end
|
|
|
|
describe "#finish" do
|
|
it "pops a message" do
|
|
expect(connected_subnets_test).to receive(:ps_multiple).and_return(ps_multiple).at_least(:once)
|
|
expect(connected_subnets_test).to receive(:ps_single).and_return(ps_single).at_least(:once)
|
|
expect(connected_subnets_test).to receive(:update_firewall_rules).with(ps_multiple, nil, config: :allow_all_traffic)
|
|
expect(connected_subnets_test).to receive(:update_firewall_rules).with(ps_single, nil, config: :allow_all_traffic)
|
|
expect(ps_multiple).to receive(:disconnect_subnet).with(ps_single)
|
|
expect(connected_subnets_test).to receive(:pop).with("Verified Connected Subnets!")
|
|
connected_subnets_test.finish
|
|
end
|
|
end
|
|
|
|
describe "#failed" do
|
|
it "naps" do
|
|
expect(connected_subnets_test).to receive(:nap).with(15)
|
|
connected_subnets_test.failed
|
|
end
|
|
end
|
|
|
|
describe ".update_firewall_rules" do
|
|
it "updates the firewall rules for different configurations" do
|
|
expect(Sequel).to receive(:pg_range).with(22..22).and_return("22..22").at_least(:once)
|
|
expect(Sequel).to receive(:pg_range).with(8080..8080).and_return("8080..8080").at_least(:once)
|
|
expect(Sequel).to receive(:pg_range).with(0..65535).and_return("0..65535").at_least(:once)
|
|
expect(Net::HTTP).to receive(:get).with(URI("https://api.ipify.org")).and_return("100.100.100.100").at_least(:once)
|
|
expect(ps_multiple.firewalls.first).to receive(:replace_firewall_rules).with([{cidr: "100.100.100.100/32", port_range: "22..22"}])
|
|
connected_subnets_test.update_firewall_rules(ps_multiple, ps_multiple, config: :perform_tests_public_blocked)
|
|
|
|
expect(ps_multiple.firewalls.first).to receive(:replace_firewall_rules).with([{cidr: "100.100.100.100/32", port_range: "22..22"}, {cidr: ps_single.net4.to_s, port_range: "8080..8080"}])
|
|
connected_subnets_test.update_firewall_rules(ps_multiple, ps_single, config: :perform_connected_private_ipv4)
|
|
|
|
expect(ps_multiple.firewalls.first).to receive(:replace_firewall_rules).with([{cidr: "100.100.100.100/32", port_range: "22..22"}, {cidr: ps_single.net6.to_s, port_range: "8080..8080"}])
|
|
connected_subnets_test.update_firewall_rules(ps_multiple, ps_single, config: :perform_connected_private_ipv6)
|
|
|
|
expect(ps_multiple.firewalls.first).to receive(:replace_firewall_rules).with([{cidr: "100.100.100.100/32", port_range: "22..22"}, {cidr: ps_multiple.net4.to_s, port_range: "8080..8080"}])
|
|
connected_subnets_test.update_firewall_rules(ps_multiple, ps_multiple, config: :perform_blocked_private_ipv4)
|
|
|
|
expect(ps_multiple.firewalls.first).to receive(:replace_firewall_rules).with([{cidr: "100.100.100.100/32", port_range: "22..22"}, {cidr: ps_multiple.net6.to_s, port_range: "8080..8080"}])
|
|
connected_subnets_test.update_firewall_rules(ps_multiple, ps_multiple, config: :perform_blocked_private_ipv6)
|
|
|
|
expect(ps_multiple.firewalls.first).to receive(:replace_firewall_rules).with([{cidr: "100.100.100.100/32", port_range: "22..22"}, {cidr: "0.0.0.0/0", port_range: "0..65535"}, {cidr: "::/0", port_range: "0..65535"}])
|
|
connected_subnets_test.update_firewall_rules(ps_multiple, nil, config: :allow_all_traffic)
|
|
|
|
expect { connected_subnets_test.update_firewall_rules(ps_multiple, ps_multiple, config: :unknown) }.to raise_error("Unknown config: unknown")
|
|
end
|
|
end
|
|
|
|
describe ".vm_to_be_connected" do
|
|
it "returns the vm to be connected" do
|
|
expect(connected_subnets_test).to receive(:ps_multiple).and_return(ps_multiple).at_least(:once)
|
|
vm1 = instance_double(Vm)
|
|
vm2 = instance_double(Vm)
|
|
expect(ps_multiple).to receive(:vms).and_return([vm1, vm2]).at_least(:once)
|
|
expect(connected_subnets_test.vm_to_be_connected).to eq(vm1)
|
|
end
|
|
end
|
|
|
|
describe ".vm_to_connect" do
|
|
it "returns the vm to connect" do
|
|
expect(connected_subnets_test).to receive(:ps_multiple).and_return(ps_multiple).at_least(:once)
|
|
vm1 = instance_double(Vm, id: "vm1")
|
|
vm2 = instance_double(Vm, id: "vm2")
|
|
expect(ps_multiple).to receive(:vms).and_return([vm1, vm2]).at_least(:once)
|
|
expect(connected_subnets_test.vm_to_connect).to eq(vm2)
|
|
end
|
|
end
|
|
|
|
describe ".vm_to_connect_outside" do
|
|
it "returns the vm to connect outside" do
|
|
expect(connected_subnets_test).to receive(:ps_single).and_return(ps_single).at_least(:once)
|
|
vm = instance_double(Vm)
|
|
expect(ps_single).to receive(:vms).and_return([vm]).at_least(:once)
|
|
expect(connected_subnets_test.vm_to_connect_outside).to eq(vm)
|
|
end
|
|
end
|
|
|
|
describe ".test_connection" do
|
|
it "tests the connection" do
|
|
to_connect_ip = "1.1.1.1"
|
|
connecting = instance_double(Vm, sshable: sshable, inhost_name: "connecting")
|
|
expect(sshable).to receive(:cmd).with("nc -zvw 1 1.1.1.1 8080 ").and_return("success!")
|
|
expect { connected_subnets_test.test_connection(to_connect_ip, connecting, should_fail: false, ipv4: true) }.not_to raise_error
|
|
|
|
expect(sshable).to receive(:cmd).with("nc -zvw 1 1.1.1.1 8080 ").and_raise("error")
|
|
expect(connected_subnets_test).to receive(:fail_test).with("connecting should be able to connect to 1.1.1.1 on port 8080")
|
|
connected_subnets_test.test_connection(to_connect_ip, connecting, should_fail: false, ipv4: true)
|
|
|
|
expect(sshable).to receive(:cmd).with("nc -zvw 1 1.1.1.1 8080 -6").and_return("success!")
|
|
expect { connected_subnets_test.test_connection(to_connect_ip, connecting, should_fail: false, ipv4: false) }.not_to raise_error
|
|
|
|
expect(sshable).to receive(:cmd).with("nc -zvw 1 1.1.1.1 8080 -6").and_raise("error")
|
|
expect(connected_subnets_test).to receive(:fail_test).with("connecting should be able to connect to 1.1.1.1 on port 8080")
|
|
connected_subnets_test.test_connection(to_connect_ip, connecting, should_fail: false, ipv4: false)
|
|
|
|
expect(sshable).to receive(:cmd).with("nc -zvw 1 1.1.1.1 8080 ").and_return("success!")
|
|
expect(connected_subnets_test).to receive(:fail_test).with("connecting should not be able to connect to 1.1.1.1 on port 8080")
|
|
connected_subnets_test.test_connection(to_connect_ip, connecting, should_fail: true, ipv4: true)
|
|
|
|
expect(sshable).to receive(:cmd).with("nc -zvw 1 1.1.1.1 8080 -6").and_return("success!")
|
|
expect(connected_subnets_test).to receive(:fail_test).with("connecting should not be able to connect to 1.1.1.1 on port 8080")
|
|
connected_subnets_test.test_connection(to_connect_ip, connecting, should_fail: true, ipv4: false)
|
|
|
|
expect(sshable).to receive(:cmd).with("nc -zvw 1 1.1.1.1 8080 ").and_raise("error")
|
|
expect(connected_subnets_test.test_connection(to_connect_ip, connecting, should_fail: true, ipv4: true)).to eq(0)
|
|
|
|
expect(sshable).to receive(:cmd).with("nc -zvw 1 1.1.1.1 8080 -6").and_raise("error")
|
|
expect(connected_subnets_test.test_connection(to_connect_ip, connecting, should_fail: true, ipv4: false)).to eq(0)
|
|
end
|
|
end
|
|
end
|