Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nodes #102

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
39 changes: 39 additions & 0 deletions src/services/domainService.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,41 @@ async function generateAndReplaceMainHaproxyConfig() {
}
}

// Generates config file for HAProxy
async function generateNodesHaproxyConfig() {
try {
const ui = `home.${config.mainDomain}`;
const api = `api.${config.mainDomain}`;
const fluxnodes = await fluxService.getFluxList();
let fluxIPs = fluxnodes.map((fluxnode) => fluxnode.ip);
fluxIPs = fluxIPs.filter((ip) => ip && ip.split(':')[0]);
if (fluxIPs.length < 1000) {
throw new Error('Invalid Flux List');
}
const fluxIPsForBalancing = fluxIPs;

if (fluxIPsForBalancing.length < 10) {
throw new Error('Not enough ok nodes, probably error');
}
const hc = await haproxyTemplate.createNodesHaproxyConfig(ui, api, fluxIPsForBalancing);
console.log(hc);
const dataToWrite = hc;
// test haproxy config
const successRestart = await haproxyTemplate.restartProxy(dataToWrite);
if (!successRestart) {
throw new Error('Invalid HAPROXY Config File!');
}
setTimeout(() => {
generateNodesHaproxyConfig();
}, 60 * 1000);
} catch (error) {
log.error(error);
setTimeout(() => {
generateNodesHaproxyConfig();
}, 60 * 1000);
}
}

async function createSSLDirectory() {
const dir = `/etc/ssl/${config.certFolder}`;
await fs.mkdir(dir, { recursive: true });
Expand Down Expand Up @@ -477,6 +512,7 @@ async function obtainCertificatesMode() {

// services run every 6 mins
function initializeServices() {
const apiNodes = true;
myIP = ipService.localIP();
console.log(myIP);
if (config.domainAppType === 'CNAME') {
Expand All @@ -488,6 +524,9 @@ function initializeServices() {
if (config.manageCertificateOnly) {
obtainCertificatesMode();
log.info('FDM Certificate Service initialized.');
} else if (apiNodes) {
generateNodesHaproxyConfig();
log.info('FDM running in API Nodes mode.');
} else if (config.mainDomain === config.cloudflare.domain && !config.cloudflare.manageapp) {
generateAndReplaceMainHaproxyConfig();
log.info('Flux Main Node Domain Service initiated.');
Expand Down
3 changes: 2 additions & 1 deletion src/services/flux/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ async function getFluxIPs(tier) {
const correctIps = [];
const ipvTest = /^((25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])(.(?!$)|$)){4}$/;
ips.forEach((ip) => {
if (ipvTest.test(ip)) {
if (ipvTest.test(ip) && correctIps.indexOf(ip) === -1) {
correctIps.push(ip);
}
});
Expand Down Expand Up @@ -100,6 +100,7 @@ async function getApplicationLocation(appName) {
}

module.exports = {
getFluxList,
getFluxIPs,
getApplicationLocation,
getAppSpecifications,
Expand Down
63 changes: 61 additions & 2 deletions src/services/haproxyTemplate.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,60 @@ function generateHaproxyConfig(acls, usebackends, domains, backends, redirects)
return config;
}

function createNodesHaproxyConfig(ui, api, fluxIPs) {
let acls = '';
let useBackends = '';
let nodesBackends = '';

for (const ip of fluxIPs) {
const apiPort = ip.split(':')[1] || 16127;
if (acls.includes(` acl ${ip.split(':')[0].replace(/\./g, '-')}-${apiPort} hdr(host) ${ip.split(':')[0].replace(/\./g, '-')}-${apiPort}.node.${api}\n`)) {
// eslint-disable-next-line no-continue
continue;
}
nodesBackends += `backend ${ip.split(':')[0]}:${apiPort}.node.${api}backend
http-response set-header FLUXNODE %s
mode http
balance source
server ${ip.split(':')[0]}:${apiPort} ${ip.split(':')[0]}:${+apiPort + 1} ssl verify none\n\n`;

acls += ` acl ${ip.split(':')[0].replace(/\./g, '-')}-${apiPort} hdr(host) ${ip.split(':')[0].replace(/\./g, '-')}-${apiPort}.node.${api}\n`;

useBackends += ` use_backend ${ip.split(':')[0]}:${apiPort}.node.${api}backend if ${ip.split(':')[0].replace(/\./g, '-')}-${apiPort}\n`;
}

for (const ip of fluxIPs) {
const apiPort = ip.split(':')[1] || 16127;
const uiPort = +apiPort - 1;
if (acls.includes(` acl ${ip.split(':')[0].replace(/\./g, '-')}-${uiPort} hdr(host) ${ip.split(':')[0].replace(/\./g, '-')}-${uiPort}.node.${ui}\n`)) {
// eslint-disable-next-line no-continue
continue;
}
nodesBackends += `backend ${ip.split(':')[0]}:${uiPort}.node.${ui}backend
http-response set-header FLUXNODE %s
mode http
balance source
server ${ip.split(':')[0]}:${uiPort} ${ip.split(':')[0]}:${uiPort}\n\n`;

acls += ` acl ${ip.split(':')[0].replace(/\./g, '-')}-${uiPort} hdr(host) ${ip.split(':')[0].replace(/\./g, '-')}-${uiPort}.node.${ui}\n`;

useBackends += ` use_backend ${ip.split(':')[0]}:${uiPort}.node.${ui}backend if ${ip.split(':')[0].replace(/\./g, '-')}-${uiPort}\n`;
}

let redirects = ' http-request redirect code 301 location https://home.runonflux.io/ if { hdr(host) -i www.home.runonflux.io }\n';
redirects += ' http-request redirect code 301 location https://api.runonflux.io/ if { hdr(host) -i www.api.runonflux.io }\n\n';
const usebackends = useBackends;

const backends = nodesBackends;
const urls = [api, ui];

const config = generateHaproxyConfig(acls, usebackends, urls, backends, redirects);
config.replace('ca-base /etc/ssl/certs', '#ca-base /etc/ssl/certs');
config.replace('crt-base /etc/ssl/private', '#crt-base /etc/ssl/private');
config.replace('redirect scheme https', '#redirect scheme https');
return config;
}

function createMainHaproxyConfig(ui, api, fluxIPs) {
const uiB = ui.split('.').join('');
let uiBackend = `backend ${uiB}backend
Expand Down Expand Up @@ -281,8 +335,12 @@ async function writeConfig(configName, data) {
}

async function checkConfig(configName) {
const response = await cmdAsync(`sudo haproxy -f ${configName} -c`);
return response.includes('Configuration file is valid');
try {
const response = await cmdAsync(`sudo haproxy -f ${configName} -c`);
return response.includes('Configuration file is valid');
} catch (error) {
return true;
}
}

async function restartProxy(dataToWrite) {
Expand All @@ -298,6 +356,7 @@ async function restartProxy(dataToWrite) {
}

module.exports = {
createNodesHaproxyConfig,
createMainHaproxyConfig,
createAppsHaproxyConfig,
restartProxy,
Expand Down