diff --git a/appliances/VRouter/HAProxy/execute.rb b/appliances/VRouter/HAProxy/execute.rb index 6d954763..51532981 100644 --- a/appliances/VRouter/HAProxy/execute.rb +++ b/appliances/VRouter/HAProxy/execute.rb @@ -17,7 +17,7 @@ def extract_backends(objects = {}) static = backends.from_env(prefix: 'ONEAPP_VNF_HAPROXY_LB') - dynamic = VROUTER_ID.nil? ? backends.from_vms(objects, prefix: 'ONEGATE_HAPROXY_LB', id: SERVICE_ID) + dynamic = oneflow_api? ? backends.from_vms(objects, prefix: 'ONEGATE_HAPROXY_LB', id: SERVICE_ID) : backends.from_vnets(objects, prefix: 'ONEGATE_HAPROXY_LB', id: VROUTER_ID) # Replace all "", "" and "" placeholders where possible. diff --git a/appliances/VRouter/HAProxy/main.rb b/appliances/VRouter/HAProxy/main.rb index 93339f16..5561699a 100644 --- a/appliances/VRouter/HAProxy/main.rb +++ b/appliances/VRouter/HAProxy/main.rb @@ -16,6 +16,8 @@ module HAProxy ONEAPP_VNF_HAPROXY_INTERFACES = env :ONEAPP_VNF_HAPROXY_INTERFACES, '' # nil -> none, empty -> all + ONEAPP_VNF_LB_ONEGATE_API = env :ONEAPP_VNF_LB_ONEGATE_API, 'auto' + def install(initdir: '/etc/init.d') msg :info, 'HAProxy::install' diff --git a/appliances/VRouter/HAProxy/tests.rb b/appliances/VRouter/HAProxy/tests.rb index e476c968..d20a7da9 100644 --- a/appliances/VRouter/HAProxy/tests.rb +++ b/appliances/VRouter/HAProxy/tests.rb @@ -38,10 +38,13 @@ def clear_vars(object) ENV['ONEAPP_VNF_HAPROXY_LB1_SERVER1_HOST'] = '10.2.200.20' ENV['ONEAPP_VNF_HAPROXY_LB1_SERVER1_PORT'] = '54321' + ENV['ONEAPP_VNF_LB_ONEGATE_API'] = '' + load './main.rb'; include Service::HAProxy expect(Service::HAProxy::ONEAPP_VNF_HAPROXY_ENABLED).to be true expect(Service::HAProxy::ONEAPP_VNF_HAPROXY_REFRESH_RATE).to eq '30' + expect(Service::HAProxy::ONEAPP_VNF_LB_ONEGATE_API).to eq 'auto' Service::HAProxy.const_set :VROUTER_ID, '86' @@ -153,6 +156,9 @@ def clear_vars(object) ENV['ONEAPP_VNF_HAPROXY_LB1_IP'] = '10.2.11.86' ENV['ONEAPP_VNF_HAPROXY_LB1_PORT'] = '8686' + # Internally forced to 'VROUTER' since not in OneFlow + ENV['ONEAPP_VNF_LB_ONEGATE_API'] = 'service' + (vnets ||= []) << JSON.parse(<<~'VNET0') { "VNET": { @@ -284,6 +290,9 @@ def clear_vars(object) ENV['ONEAPP_VNF_HAPROXY_LB1_IP'] = '10.2.11.86' ENV['ONEAPP_VNF_HAPROXY_LB1_PORT'] = '4321' + ENV['ONEAPP_VNF_LB_ONEGATE_API'] = 'auto' + ENV['SERVICE_ID'] = '123' + (vms ||= []) << JSON.parse(<<~'VM0') { "VM": { @@ -429,4 +438,100 @@ def clear_vars(object) expect(result.strip).to eq output.strip end end + + it 'should render servers.cfg using VR API (dynamic/OneFlow)' do + clear_env + + ENV['ONEAPP_VNF_HAPROXY_ENABLED'] = 'YES' + ENV['ONEAPP_VNF_HAPROXY_ONEGATE_ENABLED'] = 'YES' + + ENV['ONEAPP_VNF_HAPROXY_REFRESH_RATE'] = '' + + ENV['ONEAPP_VNF_HAPROXY_LB0_IP'] = '10.2.11.86' + ENV['ONEAPP_VNF_HAPROXY_LB0_PORT'] = '6969' + + ENV['ONEAPP_VNF_HAPROXY_LB0_SERVER0_HOST'] = '10.2.11.200' + ENV['ONEAPP_VNF_HAPROXY_LB0_SERVER0_PORT'] = '1234' + + ENV['ONEAPP_VNF_LB_ONEGATE_API'] = 'vrouter' + + (vnets ||= []) << JSON.parse(<<~'VNET0') + { + "VNET": { + "ID": "0", + "AR_POOL": { + "AR": [ + { + "AR_ID": "0", + "LEASES": { + "LEASE": [ + { + "IP": "10.2.11.201", + "MAC": "02:00:0a:02:0b:ca", + "VM": "167", + "NIC_NAME": "NIC0", + "BACKEND": "YES", + + "ONEGATE_HAPROXY_LB0_IP": "10.2.11.86", + "ONEGATE_HAPROXY_LB0_PORT": "6969", + "ONEGATE_HAPROXY_LB0_SERVER_HOST": "10.2.11.201", + "ONEGATE_HAPROXY_LB0_SERVER_PORT": "1234", + "ONEGATE_HAPROXY_LB0_SERVER_WEIGHT": "1" + }, + { + "IP": "10.2.11.200", + "MAC": "02:00:0a:02:0b:c8", + "VM": "167", + "NIC_NAME": "NIC0", + "BACKEND": "YES", + + "ONEGATE_HAPROXY_LB0_IP": "10.2.11.86", + "ONEGATE_HAPROXY_LB0_PORT": "6969", + "ONEGATE_HAPROXY_LB0_SERVER_HOST": "10.2.11.200", + "ONEGATE_HAPROXY_LB0_SERVER_PORT": "1234", + "ONEGATE_HAPROXY_LB0_SERVER_WEIGHT": "1" + } + ] + } + } + ] + } + } + } + VNET0 + + load './main.rb'; include Service::HAProxy + + Service::HAProxy.const_set :VROUTER_ID, '87' + Service::HAProxy.const_set :SERVICE_ID, '124' + + allow(Service::HAProxy).to receive(:detect_nics).and_return(%w[eth0 eth1 eth2 eth3]) + allow(Service::HAProxy).to receive(:addrs_to_nics).and_return({ + '10.2.11.86' => ['eth0'] + }) + + clear_vars Service::HAProxy + + output = <<~'DYNAMIC' + frontend lb0_6969 + mode tcp + bind 10.2.11.86:6969 + default_backend lb0_6969 + + backend lb0_6969 + mode tcp + balance roundrobin + option tcp-check + server lb0_10.2.11.200_1234 10.2.11.200:1234 check observe layer4 error-limit 50 on-error mark-down + server lb0_10.2.11.201_1234 10.2.11.201:1234 check observe layer4 error-limit 50 on-error mark-down + DYNAMIC + + Dir.mktmpdir do |dir| + haproxy_vars = Service::HAProxy.extract_backends vnets + Service::HAProxy.render_servers_cfg haproxy_vars, basedir: dir + result = File.read "#{dir}/servers.cfg" + puts "#{output.strip}" + expect(result.strip).to eq output.strip + end + end end diff --git a/appliances/VRouter/LVS/execute.rb b/appliances/VRouter/LVS/execute.rb index 999a1d0c..f2b1afd2 100644 --- a/appliances/VRouter/LVS/execute.rb +++ b/appliances/VRouter/LVS/execute.rb @@ -17,7 +17,7 @@ def extract_backends(objects = {}) static = backends.from_env(prefix: 'ONEAPP_VNF_LB', allow_nil_ports: true) - dynamic = VROUTER_ID.nil? ? backends.from_vms(objects, prefix: 'ONEGATE_LB', id: SERVICE_ID) + dynamic = oneflow_api? ? backends.from_vms(objects, prefix: 'ONEGATE_LB', id: SERVICE_ID) : backends.from_vnets(objects, prefix: 'ONEGATE_LB', id: VROUTER_ID) # Replace all "", "" and "" placeholders where possible. diff --git a/appliances/VRouter/LVS/main.rb b/appliances/VRouter/LVS/main.rb index b8304e24..e032d60f 100644 --- a/appliances/VRouter/LVS/main.rb +++ b/appliances/VRouter/LVS/main.rb @@ -17,6 +17,8 @@ module LVS ONEAPP_VNF_LB_INTERFACES = env :ONEAPP_VNF_LB_INTERFACES, '' # nil -> none, empty -> all + ONEAPP_VNF_LB_ONEGATE_API = env :ONEAPP_VNF_LB_ONEGATE_API, 'auto' + def install(initdir: '/etc/init.d') msg :info, 'LVS::install' diff --git a/appliances/VRouter/LVS/tests.rb b/appliances/VRouter/LVS/tests.rb index aa5fa653..4456637e 100644 --- a/appliances/VRouter/LVS/tests.rb +++ b/appliances/VRouter/LVS/tests.rb @@ -39,11 +39,14 @@ def clear_vars(object) ENV['ONEAPP_VNF_LB1_SERVER1_HOST'] = '10.2.200.20' ENV['ONEAPP_VNF_LB1_SERVER1_PORT'] = '54321' + ENV['ONEAPP_VNF_LB_ONEGATE_API'] = '' + load './main.rb'; include Service::LVS expect(Service::LVS::ONEAPP_VNF_LB_ENABLED).to be true expect(Service::LVS::ONEAPP_VNF_LB_REFRESH_RATE).to eq '30' expect(Service::LVS::ONEAPP_VNF_LB_FWMARK_OFFSET).to eq '10000' + expect(Service::LVS::ONEAPP_VNF_LB_ONEGATE_API).to eq 'auto' Service::LVS.const_set :VROUTER_ID, '86' @@ -108,11 +111,14 @@ def clear_vars(object) ENV['ONEAPP_VNF_LB1_SERVER1_ULIMIT'] = '100' ENV['ONEAPP_VNF_LB1_SERVER1_LLIMIT'] = '0' + ENV['ONEAPP_VNF_LB_ONEGATE_API'] = 'vrouter' + load './main.rb'; include Service::LVS expect(Service::LVS::ONEAPP_VNF_LB_ENABLED).to be true expect(Service::LVS::ONEAPP_VNF_LB_REFRESH_RATE).to eq '45' expect(Service::LVS::ONEAPP_VNF_LB_FWMARK_OFFSET).to eq '12345' + expect(Service::LVS::ONEAPP_VNF_LB_ONEGATE_API).to eq 'vrouter' Service::LVS.const_set :VROUTER_ID, '86' @@ -313,6 +319,9 @@ def clear_vars(object) ENV['ONEAPP_VNF_LB1_TIMEOUT'] = '5' ENV['ONEAPP_VNF_LB1_SCHEDULER'] = 'rr' + # Internally forced to 'VROUTER' since not in OneFlow + ENV['ONEAPP_VNF_LB_ONEGATE_API'] = 'service' + (vnets ||= []) << JSON.parse(<<~'VNET0') { "VNET": { @@ -478,6 +487,9 @@ def clear_vars(object) ENV['ONEAPP_VNF_LB1_TIMEOUT'] = '5' ENV['ONEAPP_VNF_LB1_SCHEDULER'] = 'rr' + ENV['ONEAPP_VNF_LB_ONEGATE_API'] = 'auto' + ENV['SERVICE_ID'] = '123' + (vms ||= []) << JSON.parse(<<~'VM0') { "VM": { @@ -585,7 +597,7 @@ def clear_vars(object) load './main.rb'; include Service::LVS - Service::LVS.const_set :VROUTER_ID, nil + Service::LVS.const_set :VROUTER_ID, '86' Service::LVS.const_set :SERVICE_ID, '123' allow(Service::LVS).to receive(:detect_nics).and_return(%w[eth0 eth1 eth2 eth3]) @@ -640,4 +652,94 @@ def clear_vars(object) expect(result.strip).to eq output.strip end end + + it 'should render lvs.cfg using VR API (dynamic/OneFlow)' do + clear_env + + ENV['ONEAPP_VNF_LB_ENABLED'] = 'YES' + ENV['ONEAPP_VNF_LB_ONEGATE_ENABLED'] = 'YES' + + ENV['ONEAPP_VNF_LB_FWMARK_OFFSET'] = '' + + ENV['ONEAPP_VNF_LB3_IP'] = '10.2.11.86' + ENV['ONEAPP_VNF_LB3_PORT'] = '7969' + ENV['ONEAPP_VNF_LB3_PROTOCOL'] = 'TCP' + ENV['ONEAPP_VNF_LB3_METHOD'] = 'DR' + ENV['ONEAPP_VNF_LB3_TIMEOUT'] = '5' + ENV['ONEAPP_VNF_LB3_SCHEDULER'] = 'rr' + + ENV['ONEAPP_VNF_LB3_SERVER0_HOST'] = '10.2.11.300' + ENV['ONEAPP_VNF_LB3_SERVER0_PORT'] = '7969' + + ENV['ONEAPP_VNF_LB_ONEGATE_API'] = 'vrouter' + + (vnets ||= []) << JSON.parse(<<~'VNET0') + { + "VNET": { + "ID": "0", + "AR_POOL": { + "AR": [ + { + "AR_ID": "0", + "LEASES": { + "LEASE": [ + { + "IP": "10.2.11.300", + "MAC": "02:00:0a:02:0b:c8", + "VM": "167", + "NIC_NAME": "NIC0", + "BACKEND": "YES", + + "ONEGATE_LB3_IP": "10.2.11.86", + "ONEGATE_LB3_PORT": "7969", + + "ONEGATE_LB3_SERVER_HOST": "10.2.11.300", + "ONEGATE_LB3_SERVER_PORT": "7969", + "ONEGATE_LB3_SERVER_WEIGHT": "1" + } + ] + } + } + ] + } + } + } + VNET0 + + load './main.rb'; include Service::LVS + + Service::LVS.const_set :VROUTER_ID, '87' + Service::LVS.const_set :SERVICE_ID, '124' + + allow(Service::LVS).to receive(:detect_nics).and_return(%w[eth0 eth1 eth2 eth3]) + allow(Service::LVS).to receive(:addrs_to_nics).and_return({ + '10.2.11.86' => ['eth0'] + }) + + clear_vars Service::LVS + + output = <<~'DYNAMIC' + virtual_server 10.2.11.86 7969 { + delay_loop 6 + lb_algo rr + lb_kind DR + protocol TCP + + real_server 10.2.11.300 7969 { + weight 1 + TCP_CHECK { + connect_timeout 3 + connect_port 7969 + } + } + } + DYNAMIC + + Dir.mktmpdir do |dir| + lvs_vars = Service::LVS.extract_backends vnets + Service::LVS.render_lvs_conf lvs_vars, basedir: dir + result = File.read "#{dir}/conf.d/lvs.conf" + expect(result.strip).to eq output.strip + end + end end diff --git a/appliances/VRouter/vrouter.rb b/appliances/VRouter/vrouter.rb index c9b0a9e1..5de0a72c 100644 --- a/appliances/VRouter/vrouter.rb +++ b/appliances/VRouter/vrouter.rb @@ -407,6 +407,11 @@ def get_service_vms # OneFlow end end +def oneflow_api? + return false if env(:SERVICE_ID, nil).nil? + return env(:ONEAPP_VNF_LB_ONEGATE_API, nil)&.downcase != 'vrouter' +end + def backends def parse_static(names, prefix, allow_nil_ports: false) names.each_with_object({}) do |name, acc|