parent
d90d2bc7c5
commit
c35bc358b9
9 changed files with 225 additions and 77 deletions
@ -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'; |
@ -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(); |
||||||
|
}; |
@ -0,0 +1,2 @@ |
|||||||
|
export const cvar = (step: number, name: string) => |
||||||
|
['form', `config_step${step}`, name, 'value'].join('::'); |
Loading…
Reference in new issue