fix(striker-ui-api): add prepare subnode network, hoist utils from config striker

main
Tsu-ba-me 1 year ago
parent d90d2bc7c5
commit c35bc358b9
  1. 14
      striker-ui-api/src/lib/buildJobData.ts
  2. 42
      striker-ui-api/src/lib/fconfig/buildNetworkConfig.ts
  3. 19
      striker-ui-api/src/lib/fconfig/buildNetworkLinkConfig.ts
  4. 2
      striker-ui-api/src/lib/fconfig/index.ts
  5. 82
      striker-ui-api/src/lib/request_handlers/host/configStriker.ts
  6. 125
      striker-ui-api/src/lib/request_handlers/host/prepareNetwork.ts
  7. 2
      striker-ui-api/src/lib/request_handlers/host/updateHost.ts
  8. 2
      striker-ui-api/src/lib/varn.ts
  9. 14
      striker-ui-api/src/types/ApiHost.d.ts

@ -0,0 +1,14 @@
export const buildJobData = <T extends [string, unknown][]>({
entries,
getValue = (v) => String(v),
}: {
entries: T;
getValue?: (value: T[number][1]) => string;
}) =>
entries
.reduce<string>((previous, [key, value]) => {
previous += `${key}=${getValue(value)}\\n`;
return previous;
}, '')
.trim();

@ -0,0 +1,42 @@
import { buildNetworkLinkConfig } from './buildNetworkLinkConfig';
import { cvar } from '../varn';
export const buildNetworkConfig = (
networks: InitializeStrikerNetworkForm[],
configStep = 2,
): FormConfigData => {
const { counters: ncounts, data: cdata } = networks.reduce<{
counters: Record<InitializeStrikerNetworkForm['type'], number>;
data: FormConfigData;
}>(
(previous, { interfaces, ipAddress, subnetMask, type }) => {
const { counters } = previous;
counters[type] = counters[type] ? counters[type] + 1 : 1;
const networkShortName = `${type}${counters[type]}`;
previous.data = {
...previous.data,
[cvar(configStep, `${networkShortName}_ip`)]: {
step: configStep,
value: ipAddress,
},
[cvar(configStep, `${networkShortName}_subnet_mask`)]: {
step: configStep,
value: subnetMask,
},
...buildNetworkLinkConfig(networkShortName, interfaces),
};
return previous;
},
{ counters: {}, data: {} },
);
Object.entries(ncounts).forEach(([ntype, ncount]) => {
cdata[cvar(1, `${ntype}_count`)] = { value: ncount };
});
return cdata;
};

@ -0,0 +1,19 @@
import { cvar } from '../varn';
export const buildNetworkLinkConfig = (
networkShortName: string,
interfaces: InitializeStrikerNetworkForm['interfaces'],
configStep = 2,
) =>
interfaces.reduce<FormConfigData>((previous, iface, index) => {
if (iface) {
const { networkInterfaceMACAddress } = iface;
const linkNumber = index + 1;
previous[
cvar(configStep, `${networkShortName}_link${linkNumber}_mac_to_set`)
] = { step: configStep, value: networkInterfaceMACAddress };
}
return previous;
}, {});

@ -0,0 +1,2 @@
export * from './buildNetworkConfig';
export * from './buildNetworkLinkConfig';

@ -11,80 +11,11 @@ import {
} from '../../consts'; } from '../../consts';
import { getLocalHostUUID, job, variable } from '../../accessModule'; import { getLocalHostUUID, job, variable } from '../../accessModule';
import { buildJobData } from '../../buildJobData';
import { buildNetworkConfig } from '../../fconfig';
import { sanitize } from '../../sanitize'; import { sanitize } from '../../sanitize';
import { stderr, stdoutVar } from '../../shell'; import { stderr, stdoutVar } from '../../shell';
import { cvar } from '../../varn';
const cvar = (configStepCount: number, fieldName: string) =>
['form', `config_step${configStepCount}`, fieldName, 'value'].join('::');
const buildNetworkLinkConfigs = (
networkShortName: string,
interfaces: InitializeStrikerNetworkForm['interfaces'],
configStep = 2,
) =>
interfaces.reduce<FormConfigData>((previous, iface, index) => {
if (iface) {
const { networkInterfaceMACAddress } = iface;
const linkNumber = index + 1;
previous[
cvar(configStep, `${networkShortName}_link${linkNumber}_mac_to_set`)
] = { step: configStep, value: networkInterfaceMACAddress };
}
return previous;
}, {});
const buildNetworkConfigs = (
networks: InitializeStrikerNetworkForm[],
configStep = 2,
): FormConfigData => {
const { counters: ncounts, data: cdata } = networks.reduce<{
counters: Record<InitializeStrikerNetworkForm['type'], number>;
data: FormConfigData;
}>(
(previous, { interfaces, ipAddress, subnetMask, type }) => {
const { counters } = previous;
counters[type] = counters[type] ? counters[type] + 1 : 1;
const networkShortName = `${type}${counters[type]}`;
previous.data = {
...previous.data,
[cvar(configStep, `${networkShortName}_ip`)]: {
step: configStep,
value: ipAddress,
},
[cvar(configStep, `${networkShortName}_subnet_mask`)]: {
step: configStep,
value: subnetMask,
},
...buildNetworkLinkConfigs(networkShortName, interfaces),
};
return previous;
},
{ counters: {}, data: {} },
);
Object.entries(ncounts).forEach(([ntype, ncount]) => {
cdata[cvar(1, `${ntype}_count`)] = { value: ncount };
});
return cdata;
};
const configToJobData = (
entries: [keyof FormConfigData, FormConfigData[keyof FormConfigData]][],
) =>
entries
.reduce<string>((previous, [key, { value }]) => {
previous += `${key}=${value}\\n`;
return previous;
}, '')
.trim();
export const configStriker: RequestHandler< export const configStriker: RequestHandler<
unknown, unknown,
@ -182,7 +113,7 @@ export const configStriker: RequestHandler<
[cvar(2, 'host_name')]: { step: 2, value: hostName }, [cvar(2, 'host_name')]: { step: 2, value: hostName },
[cvar(2, 'striker_password')]: { step: 2, value: adminPassword }, [cvar(2, 'striker_password')]: { step: 2, value: adminPassword },
[cvar(2, 'striker_user')]: { step: 2, value: 'admin' }, [cvar(2, 'striker_user')]: { step: 2, value: 'admin' },
...buildNetworkConfigs(networks), ...buildNetworkConfig(networks),
}; };
stdoutVar(configData, `Config data before initiating striker config: `); stdoutVar(configData, `Config data before initiating striker config: `);
@ -215,7 +146,10 @@ export const configStriker: RequestHandler<
await job({ await job({
file: __filename, file: __filename,
job_command: SERVER_PATHS.usr.sbin['anvil-configure-host'].self, job_command: SERVER_PATHS.usr.sbin['anvil-configure-host'].self,
job_data: configToJobData(configEntries), job_data: buildJobData({
entries: configEntries,
getValue: ({ value }) => String(value),
}),
job_name: 'configure::network', job_name: 'configure::network',
job_title: 'job_0001', job_title: 'job_0001',
job_description: 'job_0071', job_description: 'job_0071',

@ -0,0 +1,125 @@
import assert from 'assert';
import { RequestHandler } from 'express';
import {
REP_IPV4,
REP_IPV4_CSV,
REP_PEACEFUL_STRING,
REP_UUID,
SERVER_PATHS,
} from '../../consts';
import { job, variable } from '../../accessModule';
import { buildJobData } from '../../buildJobData';
import { buildNetworkConfig } from '../../fconfig';
import { sanitize } from '../../sanitize';
import { stderr, stdoutVar } from '../../shell';
import { cvar } from '../../varn';
export const prepareNetwork: RequestHandler<
UpdateHostParams,
undefined,
PrepareNetworkRequestBody
> = async (request, response) => {
const {
body: {
dns: rDns,
gateway: rGateway,
hostName: rHostName,
gatewayInterface: rGatewayInterface,
networks = [],
} = {},
params: { hostUUID },
} = request;
const dns = sanitize(rDns, 'string');
const gateway = sanitize(rGateway, 'string');
const hostName = sanitize(rHostName, 'string');
const gatewayInterface = sanitize(rGatewayInterface, 'string');
try {
assert(
REP_UUID.test(hostUUID),
`Host UUID must be a valid UUIDv4; got [${hostUUID}]`,
);
assert(
REP_IPV4_CSV.test(dns),
`DNS must be a valid IPv4 CSV; got [${dns}]`,
);
assert(
REP_IPV4.test(gateway),
`Gateway must be a valid IPv4; got [${gateway}]`,
);
assert(
REP_PEACEFUL_STRING.test(hostName),
`Host name must be a peaceful string; got [${hostName}]`,
);
assert(
REP_PEACEFUL_STRING.test(gatewayInterface),
`Gateway interface must be a peaceful string; got [${gatewayInterface}]`,
);
} catch (error) {
stderr(`Failed to assert value when prepare network; CAUSE: ${error}`);
return response.status(400).send();
}
const configData: FormConfigData = {
[cvar(2, 'dns')]: { step: 2, value: dns },
[cvar(2, 'gateway')]: { step: 2, value: gateway },
[cvar(2, 'gateway_interface')]: { step: 2, value: gatewayInterface },
[cvar(2, 'host_name')]: { step: 2, value: hostName },
...buildNetworkConfig(networks),
};
stdoutVar(
configData,
`Config data before prepare network on host ${hostUUID}: `,
);
const configEntries = Object.entries(configData);
try {
for (const [ckey, cdetail] of configEntries) {
const { step = 1, value } = cdetail;
const vuuid = await variable({
file: __filename,
variable_default: '',
varaible_description: '',
variable_name: ckey,
variable_section: `config_step${step}`,
variable_source_uuid: hostUUID,
variable_source_table: 'hosts',
variable_value: value,
});
assert(
REP_UUID.test(vuuid),
`Not a UUIDv4 post insert or update of ${ckey} with [${cdetail}]`,
);
}
await job({
file: __filename,
job_command: SERVER_PATHS.usr.sbin['anvil-configure-host'].self,
job_data: buildJobData({
entries: configEntries,
getValue: ({ value }) => String(value),
}),
job_name: 'configure::network',
job_title: 'job_0001',
job_description: 'job_0071',
});
} catch (error) {
stderr(`Failed to queue prepare network; CAUSE: ${error}`);
return response.status(500).send();
}
return response.send();
};

@ -2,9 +2,11 @@ import { RequestHandler } from 'express';
import { buildBranchRequestHandler } from '../buildBranchRequestHandler'; import { buildBranchRequestHandler } from '../buildBranchRequestHandler';
import { configStriker } from './configStriker'; import { configStriker } from './configStriker';
import { prepareNetwork } from './prepareNetwork';
import { setHostInstallTarget } from './setHostInstallTarget'; import { setHostInstallTarget } from './setHostInstallTarget';
export const updateHost: RequestHandler = buildBranchRequestHandler({ export const updateHost: RequestHandler = buildBranchRequestHandler({
'install-target': setHostInstallTarget as RequestHandler, 'install-target': setHostInstallTarget as RequestHandler,
'subnode-network': prepareNetwork as RequestHandler,
striker: configStriker, striker: configStriker,
}); });

@ -0,0 +1,2 @@
export const cvar = (step: number, name: string) =>
['form', `config_step${step}`, name, 'value'].join('::');

@ -57,12 +57,12 @@ type InitializeStrikerNetworkForm = {
type InitializeStrikerForm = { type InitializeStrikerForm = {
adminPassword: string; adminPassword: string;
domainName: string;
hostName: string;
hostNumber: number;
dns: string; dns: string;
domainName: string;
gateway: string; gateway: string;
gatewayInterface: string; gatewayInterface: string;
hostName: string;
hostNumber: number;
networks: InitializeStrikerNetworkForm[]; networks: InitializeStrikerNetworkForm[];
organizationName: string; organizationName: string;
organizationPrefix: string; organizationPrefix: string;
@ -81,6 +81,14 @@ type PrepareHostRequestBody = {
redhatUser: string; redhatUser: string;
}; };
type PrepareNetworkRequestBody = {
dns: string;
gateway: string;
gatewayInterface: string;
hostName: string;
networks: InitializeStrikerNetworkForm[];
};
type SetHostInstallTargetRequestBody = { type SetHostInstallTargetRequestBody = {
isEnableInstallTarget: boolean; isEnableInstallTarget: boolean;
}; };

Loading…
Cancel
Save