feat(striker-ui-api): add POST, DELETE /host/connection

main
Tsu-ba-me 2 years ago
parent e20a3a4af1
commit 099b2c9470
  1. 2
      striker-ui-api/src/lib/consts/SERVER_PATHS.ts
  2. 190
      striker-ui-api/src/lib/request_handlers/host/createHostConnection.ts
  3. 42
      striker-ui-api/src/lib/request_handlers/host/deleteHostConnection.ts
  4. 11
      striker-ui-api/src/lib/request_handlers/host/getHostConnection.ts
  5. 2
      striker-ui-api/src/lib/request_handlers/host/index.ts
  6. 2
      striker-ui-api/src/lib/request_handlers/host/prepareHost.ts
  7. 6
      striker-ui-api/src/lib/request_handlers/ssh-key/deleteSSHKeyConflict.ts
  8. 10
      striker-ui-api/src/routes/host.ts
  9. 11
      striker-ui-api/src/types/CreateHostConnectionRequestBody.d.ts
  10. 3
      striker-ui-api/src/types/DeleteHostConnectionRequestBody.d.ts

@ -11,6 +11,7 @@ const EMPTY_SERVER_PATHS: ServerPath = {
bin: { bin: {
date: {}, date: {},
mkfifo: {}, mkfifo: {},
psql: {},
rm: {}, rm: {},
sed: {}, sed: {},
}, },
@ -25,6 +26,7 @@ const EMPTY_SERVER_PATHS: ServerPath = {
'anvil-update-system': {}, 'anvil-update-system': {},
'striker-initialize-host': {}, 'striker-initialize-host': {},
'striker-manage-install-target': {}, 'striker-manage-install-target': {},
'striker-manage-peers': {},
'striker-parse-os-list': {}, 'striker-parse-os-list': {},
}, },
}, },

@ -0,0 +1,190 @@
import { RequestHandler } from 'express';
import SERVER_PATHS from '../../consts/SERVER_PATHS';
import {
getAnvilData,
getLocalHostUUID,
getPeerData,
job,
sub,
} from '../../accessModule';
import { sanitize } from '../../sanitize';
import { rm, stderr, stdoutVar } from '../../shell';
export const createHostConnection: RequestHandler<
unknown,
undefined,
CreateHostConnectionRequestBody
> = (request, response) => {
const {
body: {
dbName = 'anvil',
ipAddress,
isPing = false,
password,
port = 5432,
sshPort = 22,
user = 'admin',
},
} = request;
const commonDBName = sanitize(dbName, 'string');
const commonIsPing = sanitize(isPing, 'boolean');
const commonPassword = sanitize(password, 'string');
const commonDBPort = sanitize(port, 'number');
const commonDBUser = sanitize(user, 'string');
const peerIPAddress = sanitize(ipAddress, 'string');
const peerSSHPort = sanitize(sshPort, 'number');
const commonPing = commonIsPing ? 1 : 0;
let localDBPort: number;
let localIPAddress: string;
let isPeerReachable = false;
let isPeerDBReachable = false;
let peerHostUUID: string;
try {
({ hostUUID: peerHostUUID, isConnected: isPeerReachable } = getPeerData(
peerIPAddress,
{ password: commonPassword, port: peerSSHPort },
));
} catch (subError) {
stderr(`Failed to get peer data; CAUSE: ${subError}`);
response.status(500).send();
return;
}
stdoutVar({ peerHostUUID, isPeerReachable });
if (!isPeerReachable) {
stderr(
`Cannot connect to peer; please verify credentials and SSH keys validity.`,
);
response.status(400).send();
return;
}
try {
localIPAddress = sub('find_matching_ip', {
subModuleName: 'System',
subParams: { host: peerIPAddress },
}).stdout;
} catch (subError) {
stderr(`Failed to get matching IP address; CAUSE: ${subError}`);
response.status(500).send();
return;
}
stdoutVar({ localIPAddress });
const pgpassFilePath = '/tmp/.pgpass';
const pgpassFileBody = `${peerIPAddress}:${commonDBPort}:${commonDBName}:${commonDBUser}:${commonPassword.replace(
/:/g,
'\\:',
)}`;
stdoutVar({ pgpassFilePath, pgpassFileBody });
try {
sub('write_file', {
subModuleName: 'Storage',
subParams: {
body: pgpassFileBody,
file: pgpassFilePath,
mode: '0600',
overwrite: 1,
secure: 1,
},
});
} catch (subError) {
stderr(`Failed to write ${pgpassFilePath}; CAUSE: ${subError}`);
response.status(500).send();
return;
}
try {
const [rawIsPeerDBReachable] = sub('call', {
subModuleName: 'System',
subParams: {
shell_call: `PGPASSFILE="${pgpassFilePath}" ${SERVER_PATHS.usr.bin.psql.self} --host ${peerIPAddress} --port ${commonDBPort} --dbname ${commonDBName} --username ${commonDBUser} --no-password --tuples-only --no-align --command "SELECT 1"`,
},
}).stdout as [output: string, returnCode: number];
isPeerDBReachable = rawIsPeerDBReachable === '1';
} catch (subError) {
stderr(`Failed to test connection to peer database; CAUSE: ${subError}`);
}
try {
rm(pgpassFilePath);
} catch (fsError) {
stderr(`Failed to remove ${pgpassFilePath}; CAUSE: ${fsError}`);
response.status(500).send();
return;
}
stdoutVar({ isPeerDBReachable });
if (!isPeerDBReachable) {
stderr(
`Cannot connect to peer database; please verify database credentials.`,
);
response.status(400).send();
return;
}
const localHostUUID = getLocalHostUUID();
try {
const {
database: {
[localHostUUID]: { port: rawLocalDBPort },
},
} = getAnvilData({ database: true }) as { database: DatabaseHash };
localDBPort = sanitize(rawLocalDBPort, 'number');
} catch (subError) {
stderr(`Failed to get local database data from hash; CAUSE: ${subError}`);
response.status(500).send();
return;
}
const jobCommand = `${SERVER_PATHS.usr.sbin['striker-manage-peers'].self} --add --host-uuid ${peerHostUUID} --host ${peerIPAddress} --port ${commonDBPort} --ping ${commonPing}`;
const peerJobCommand = `${SERVER_PATHS.usr.sbin['striker-manage-peers'].self} --add --host-uuid ${localHostUUID} --host ${localIPAddress} --port ${localDBPort} --ping ${commonPing}`;
try {
job({
file: __filename,
job_command: jobCommand,
job_data: `password=${commonPassword}
peer_job_command=${peerJobCommand}`,
job_description: 'job_0012',
job_name: 'striker-peer::add',
job_title: 'job_0011',
});
} catch (subError) {
stderr(`Failed to add peer ${peerHostUUID}; CAUSE: ${subError}`);
response.status(500).send();
return;
}
response.status(201).send();
};

@ -0,0 +1,42 @@
import { RequestHandler } from 'express';
import SERVER_PATHS from '../../consts/SERVER_PATHS';
import { job } from '../../accessModule';
import { toHostUUID } from '../../convertHostUUID';
import { stderr } from '../../shell';
export const deleteHostConnection: RequestHandler<
unknown,
undefined,
DeleteHostConnectionRequestBody
> = (request, response) => {
const { body } = request;
const hostUUIDs = Object.keys(body);
hostUUIDs.forEach((key) => {
const hostUUID = toHostUUID(key);
const peerHostUUIDs = body[key];
peerHostUUIDs.forEach((peerHostUUID) => {
try {
job({
file: __filename,
job_command: `${SERVER_PATHS.usr.sbin['striker-manage-peers'].self} --remove --host-uuid ${peerHostUUID}`,
job_description: 'job_0014',
job_host_uuid: hostUUID,
job_name: 'striker-peer::delete',
job_title: 'job_0013',
});
} catch (subError) {
stderr(`Failed to delete peer ${peerHostUUID}; CAUSE: ${subError}`);
response.status(500).send();
return;
}
});
});
response.status(204).send();
};

@ -42,16 +42,7 @@ export const getHostConnection = buildGetRequestHandler(
(request, buildQueryOptions) => { (request, buildQueryOptions) => {
const { hostUUIDs: rawHostUUIDs } = request.query; const { hostUUIDs: rawHostUUIDs } = request.query;
let rawDatabaseData: { let rawDatabaseData: DatabaseHash;
[hostUUID: string]: {
host: string;
name: string;
password: string;
ping: string;
port: string;
user: string;
};
};
const hostUUIDField = 'ip_add.ip_address_host_uuid'; const hostUUIDField = 'ip_add.ip_address_host_uuid';
const localHostUUID: string = getLocalHostUUID(); const localHostUUID: string = getLocalHostUUID();

@ -1,4 +1,6 @@
export * from './createHost'; export * from './createHost';
export * from './createHostConnection';
export * from './deleteHostConnection';
export * from './getHost'; export * from './getHost';
export * from './getHostConnection'; export * from './getHostConnection';
export * from './getHostDetail'; export * from './getHostDetail';

@ -11,7 +11,7 @@ import SERVER_PATHS from '../../consts/SERVER_PATHS';
import { job, variable } from '../../accessModule'; import { job, variable } from '../../accessModule';
import { sanitize } from '../../sanitize'; import { sanitize } from '../../sanitize';
import { stderr, stdout } from '../../shell'; import { stderr } from '../../shell';
export const prepareHost: RequestHandler< export const prepareHost: RequestHandler<
unknown, unknown,

@ -3,6 +3,7 @@ import { RequestHandler } from 'express';
import SERVER_PATHS from '../../consts/SERVER_PATHS'; import SERVER_PATHS from '../../consts/SERVER_PATHS';
import { job } from '../../accessModule'; import { job } from '../../accessModule';
import { toHostUUID } from '../../convertHostUUID';
import { stderr } from '../../shell'; import { stderr } from '../../shell';
export const deleteSSHKeyConflict: RequestHandler< export const deleteSSHKeyConflict: RequestHandler<
@ -13,8 +14,9 @@ export const deleteSSHKeyConflict: RequestHandler<
const { body } = request; const { body } = request;
const hostUUIDs = Object.keys(body); const hostUUIDs = Object.keys(body);
hostUUIDs.forEach((hostUUID) => { hostUUIDs.forEach((key) => {
const stateUUIDs = body[hostUUID]; const hostUUID = toHostUUID(key);
const stateUUIDs = body[key];
try { try {
job({ job({

@ -2,6 +2,8 @@ import express from 'express';
import { import {
createHost, createHost,
createHostConnection,
deleteHostConnection,
getHost, getHost,
getHostConnection, getHostConnection,
getHostDetail, getHostDetail,
@ -9,14 +11,18 @@ import {
updateHost, updateHost,
} from '../lib/request_handlers/host'; } from '../lib/request_handlers/host';
const CONNECTION_PATH = '/connection';
const router = express.Router(); const router = express.Router();
router router
.get('/', getHost) .get('/', getHost)
.get('/connection', getHostConnection) .get(CONNECTION_PATH, getHostConnection)
.get('/:hostUUID', getHostDetail) .get('/:hostUUID', getHostDetail)
.post('/', createHost) .post('/', createHost)
.post(CONNECTION_PATH, createHostConnection)
.put('/prepare', prepareHost) .put('/prepare', prepareHost)
.put('/:hostUUID', updateHost); .put('/:hostUUID', updateHost)
.delete(CONNECTION_PATH, deleteHostConnection);
export default router; export default router;

@ -0,0 +1,11 @@
type CreateHostConnectionRequestBody = {
dbName?: string;
ipAddress: string;
isPing?: boolean;
// Host password; same as database password.
password: string;
port?: number;
sshPort?: number;
// database user.
user?: string;
};

@ -0,0 +1,3 @@
type DeleteHostConnectionRequestBody = {
[hostUUID: string]: string[];
};
Loading…
Cancel
Save