Move noProxy handling to separate module

Signed-off-by: Christina Ying Wang <christina@balena.io>
This commit is contained in:
Christina Ying Wang 2024-04-30 21:40:38 -07:00
parent 0cf5a4bf18
commit 725d7790fb
4 changed files with 86 additions and 16 deletions

View File

@ -3,7 +3,12 @@ import _ from 'lodash';
import path from 'path';
import * as applicationManager from './compose/application-manager';
import { readHostname, setHostname } from './host-config/index';
import {
readHostname,
setHostname,
readNoProxy,
setNoProxy,
} from './host-config/index';
import * as dbus from './lib/dbus';
import { isENOENT } from './lib/errors';
import { mkdirp, unlinkAll } from './lib/fs-utils';
@ -30,7 +35,6 @@ const proxyFields = ['type', 'ip', 'port', 'login', 'password'];
const proxyBasePath = pathOnBoot('system-proxy');
const redsocksConfPath = path.join(proxyBasePath, 'redsocks.conf');
const noProxyPath = path.join(proxyBasePath, 'no_proxy');
interface ProxyConfig {
[key: string]: string | string[] | number;
@ -83,18 +87,9 @@ async function readProxy(): Promise<ProxyConfig | undefined> {
}
}
try {
const noProxy = await readFromBoot(noProxyPath, 'utf-8')
// Prevent empty newline from being reported as a noProxy address
.then((addrs) => addrs.split('\n').filter((addr) => addr !== ''));
if (noProxy.length) {
conf.noProxy = noProxy;
}
} catch (e: unknown) {
if (!isENOENT(e)) {
throw e;
}
const noProxy = await readNoProxy();
if (noProxy.length) {
conf.noProxy = noProxy;
}
// Convert port to number per API doc spec
@ -121,14 +116,15 @@ function generateRedsocksConfEntries(conf: ProxyConfig): string {
async function setProxy(maybeConf: ProxyConfig | null): Promise<void> {
if (_.isEmpty(maybeConf)) {
await unlinkAll(redsocksConfPath, noProxyPath);
await unlinkAll(redsocksConfPath);
await setNoProxy([]);
} else {
// We know that maybeConf is not null due to the _.isEmpty check above,
// but the compiler doesn't
const conf = maybeConf as ProxyConfig;
await mkdirp(proxyBasePath);
if (Array.isArray(conf.noProxy)) {
await writeToBoot(noProxyPath, conf.noProxy.join('\n'));
await setNoProxy(conf.noProxy);
}
let currentConf: ProxyConfig | undefined;

View File

@ -3,6 +3,8 @@ import { promises as fs } from 'fs';
import * as config from '../config';
import { pathOnRoot } from '../lib/host-utils';
export * from './proxy';
const hostnamePath = pathOnRoot('/etc/hostname');
export async function readHostname() {

36
src/host-config/proxy.ts Normal file
View File

@ -0,0 +1,36 @@
import { promises as fs } from 'fs';
import path from 'path';
import { pathOnBoot, readFromBoot } from '../lib/host-utils';
import { unlinkAll } from '../lib/fs-utils';
import { isENOENT } from '../lib/errors';
const proxyBasePath = pathOnBoot('system-proxy');
const noProxyPath = path.join(proxyBasePath, 'no_proxy');
export async function readNoProxy(): Promise<string[]> {
try {
const noProxy = await readFromBoot(noProxyPath, 'utf-8')
// Prevent empty newline from being reported as a noProxy address
.then((addrs) => addrs.split('\n').filter((addr) => addr !== ''));
if (noProxy.length) {
return noProxy;
} else {
return [];
}
} catch (e: unknown) {
if (!isENOENT(e)) {
throw e;
}
return [];
}
}
export async function setNoProxy(list: string[]) {
if (!list || !Array.isArray(list) || !list.length) {
await unlinkAll(noProxyPath);
} else {
await fs.writeFile(noProxyPath, list.join('\n'));
}
}

View File

@ -98,6 +98,42 @@ describe('host-config', () => {
});
});
describe('noProxy', () => {
it('reads IPs to exclude from proxy', async () => {
expect(await hostConfig.readNoProxy()).to.deep.equal([
'152.10.30.4',
'253.1.1.0/16',
]);
});
it('sets IPs to exclude from proxy', async () => {
await hostConfig.setNoProxy(['balena.io', '1.1.1.1']);
expect(await fs.readFile(noProxy, 'utf-8')).to.equal(
'balena.io\n1.1.1.1',
);
});
it('removes no_proxy file if empty or invalid', async () => {
// Set initial no_proxy
await hostConfig.setNoProxy(['2.2.2.2']);
expect(await hostConfig.readNoProxy()).to.deep.equal(['2.2.2.2']);
// Set to empty array
await hostConfig.setNoProxy([]);
expect(await hostConfig.readNoProxy()).to.deep.equal([]);
expect(await fs.readdir(proxyBase)).to.not.have.members(['no_proxy']);
// Reset initial no_proxy
await hostConfig.setNoProxy(['2.2.2.2']);
expect(await hostConfig.readNoProxy()).to.deep.equal(['2.2.2.2']);
// Set to invalid value
await hostConfig.setNoProxy(null as any);
expect(await hostConfig.readNoProxy()).to.deep.equal([]);
expect(await fs.readdir(proxyBase)).to.not.have.members(['no_proxy']);
});
});
it('reads proxy configs and hostname', async () => {
const { network } = await get();
expect(network).to.have.property('hostname', 'deadbeef');