fix: 🐛 Fix client daemon usage on windows (#2115)
* fix: 🐛 Fix client daemon usage on windows ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12365 * refactor: 💡 Fix error handling ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12365 --------- Co-authored-by: Cameron Perera <cameron.perera@hashicorp.com>
This commit is contained in:
1 parent
8f34d83c15
commit
3721f63edf
4 files changed
+102
-16
No files matched your search
@@ -106,10 +106,12 @@ export default class ClientDaemonHandler {
|
||||
}
|
||||
const sessionData = this.session.data?.authenticated;
|
||||
const auth_token_id = sessionData?.id;
|
||||
const token = sessionData?.token;
|
||||
remainingQuery = {
|
||||
...remainingQuery,
|
||||
query: searchQuery,
|
||||
auth_token_id,
|
||||
token,
|
||||
resource: pluralize(type),
|
||||
};
|
||||
|
||||
@@ -125,7 +127,7 @@ export default class ClientDaemonHandler {
|
||||
if (e.statusCode === 403 || e.statusCode === 401) {
|
||||
await this.ipc.invoke('addTokenToClientDaemon', {
|
||||
tokenId: auth_token_id,
|
||||
token: sessionData?.token,
|
||||
token,
|
||||
});
|
||||
try {
|
||||
clientDaemonResults = await this.ipc.invoke(
|
||||
|
||||
@@ -13,9 +13,9 @@ module.exports = {
|
||||
// Returns JSON-formatted version information from the CLI
|
||||
version: () => {
|
||||
const command = ['-v'];
|
||||
const rawOutput = spawnSync(command);
|
||||
let gitRevision = /Git Revision:\s*(?<rev>.*)\n/.exec(rawOutput);
|
||||
let versionNumber = /Version Number:\s*(?<ver>.*)\n/.exec(rawOutput);
|
||||
const { stdout } = spawnSync(command);
|
||||
let gitRevision = /Git Revision:\s*(?<rev>.*)\n/.exec(stdout);
|
||||
let versionNumber = /Version Number:\s*(?<ver>.*)\n/.exec(stdout);
|
||||
if (gitRevision) gitRevision = gitRevision.groups.rev;
|
||||
if (versionNumber) versionNumber = versionNumber.groups.ver;
|
||||
const formatted = versionNumber
|
||||
|
||||
@@ -74,12 +74,19 @@ module.exports = {
|
||||
* Spawn child process and return output immediately.
|
||||
* This function is intended for non-connection related tasks.
|
||||
* @param {string} command
|
||||
* @return {string}
|
||||
*/
|
||||
spawnSync(command) {
|
||||
const childProcess = spawnSync(path(), command);
|
||||
const rawOutput = childProcess.stdout.toString();
|
||||
return rawOutput;
|
||||
* @param {object} envVars
|
||||
* @returns {{stdout: string | undefined, stderr: string | undefined}} */
|
||||
spawnSync(command, envVars = {}) {
|
||||
const childProcess = spawnSync(path(), command, {
|
||||
env: {
|
||||
...process.env,
|
||||
...envVars,
|
||||
},
|
||||
});
|
||||
|
||||
const { stdout, stderr } = childProcess;
|
||||
|
||||
return { stdout: stdout?.toString(), stderr: stderr?.toString() };
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,10 +3,16 @@
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*/
|
||||
|
||||
const { spawnSync, spawn } = require('../helpers/spawn-promise');
|
||||
const {
|
||||
spawnSync,
|
||||
spawn,
|
||||
spawnAsyncJSONPromise,
|
||||
} = require('../helpers/spawn-promise');
|
||||
const jsonify = require('../utils/jsonify.js');
|
||||
const { unixSocketRequest } = require('../helpers/request-promise');
|
||||
const runtimeSettings = require('./runtime-settings');
|
||||
const sanitizer = require('../utils/sanitizer.js');
|
||||
const { isWindows } = require('../helpers/platform.js');
|
||||
|
||||
class ClientDaemonManager {
|
||||
#socketPath;
|
||||
@@ -22,9 +28,9 @@ class ClientDaemonManager {
|
||||
*/
|
||||
status() {
|
||||
const daemonStatusCommand = ['daemon', 'status', '-format=json'];
|
||||
const data = spawnSync(daemonStatusCommand);
|
||||
const { stdout } = spawnSync(daemonStatusCommand);
|
||||
|
||||
const status = jsonify(data);
|
||||
const status = jsonify(stdout);
|
||||
this.#socketPath = status?.item?.socket_address;
|
||||
return status;
|
||||
}
|
||||
@@ -35,6 +41,7 @@ class ClientDaemonManager {
|
||||
*/
|
||||
async start() {
|
||||
const startDaemonCommand = ['daemon', 'start'];
|
||||
// We use spawn here because we want to check the stderr for specific logs
|
||||
const { stderr } = await spawn(startDaemonCommand);
|
||||
|
||||
// If we get a null/undefined, err on safe side and don't stop daemon when
|
||||
@@ -65,11 +72,16 @@ class ClientDaemonManager {
|
||||
* @param tokenId
|
||||
* @returns {Promise}
|
||||
*/
|
||||
addToken({ token, tokenId }) {
|
||||
async addToken({ token, tokenId }) {
|
||||
// TODO: Should this and search just always call CLI even for non-Windows?
|
||||
if (isWindows()) {
|
||||
return addTokenCliCommand(token);
|
||||
}
|
||||
|
||||
const postBody = {
|
||||
auth_token_id: tokenId,
|
||||
auth_token_id: sanitizer.base62EscapeAndValidate(tokenId),
|
||||
boundary_addr: runtimeSettings.clusterUrl,
|
||||
auth_token: token,
|
||||
auth_token: sanitizer.base62EscapeAndValidate(token),
|
||||
};
|
||||
const request = {
|
||||
method: 'POST',
|
||||
@@ -80,6 +92,11 @@ class ClientDaemonManager {
|
||||
}
|
||||
|
||||
search(requestData) {
|
||||
if (isWindows()) {
|
||||
return searchCliCommand(requestData);
|
||||
}
|
||||
|
||||
delete requestData.token;
|
||||
const queryString = new URLSearchParams(requestData);
|
||||
|
||||
const request = {
|
||||
@@ -91,5 +108,65 @@ class ClientDaemonManager {
|
||||
}
|
||||
}
|
||||
|
||||
const addTokenCliCommand = (token) => {
|
||||
const addTokenCommand = [
|
||||
'daemon',
|
||||
'add-token',
|
||||
'-format=json',
|
||||
'-token=env://BOUNDARY_TOKEN',
|
||||
'-keyring-type=none',
|
||||
];
|
||||
const sanitizedToken = sanitizer.base62EscapeAndValidate(token);
|
||||
|
||||
// TODO: Is setting an env var for the address the only way? I'm surprised to not see an -addr flag
|
||||
const { stdout, stderr } = spawnSync(addTokenCommand, {
|
||||
BOUNDARY_TOKEN: sanitizedToken,
|
||||
BOUNDARY_ADDR: runtimeSettings.clusterUrl,
|
||||
});
|
||||
let parsedResponse = jsonify(stdout);
|
||||
|
||||
if (parsedResponse?.status_code === 204) {
|
||||
// 204 has no response body
|
||||
return;
|
||||
}
|
||||
|
||||
parsedResponse = jsonify(stderr);
|
||||
return Promise.reject({
|
||||
statusCode: parsedResponse?.status_code,
|
||||
...parsedResponse?.api_error,
|
||||
});
|
||||
};
|
||||
|
||||
const searchCliCommand = (requestData) => {
|
||||
const searchCommand = [
|
||||
'search',
|
||||
'-format=json',
|
||||
'-token=env://BOUNDARY_TOKEN',
|
||||
`-resource=${requestData.resource}`,
|
||||
];
|
||||
if (requestData.query) {
|
||||
searchCommand.push(`-query=${requestData.query}`);
|
||||
}
|
||||
if (requestData.filter) {
|
||||
searchCommand.push(`-filter=${requestData.filter}`);
|
||||
}
|
||||
const sanitizedToken = sanitizer.base62EscapeAndValidate(requestData.token);
|
||||
|
||||
const { stdout, stderr } = spawnSync(searchCommand, {
|
||||
BOUNDARY_TOKEN: sanitizedToken,
|
||||
});
|
||||
let parsedResponse = jsonify(stdout);
|
||||
|
||||
if (parsedResponse?.status_code === 200) {
|
||||
return parsedResponse?.item;
|
||||
}
|
||||
|
||||
parsedResponse = jsonify(stderr);
|
||||
return Promise.reject({
|
||||
statusCode: parsedResponse?.status_code,
|
||||
...parsedResponse?.api_error,
|
||||
});
|
||||
};
|
||||
|
||||
// Export an instance so we get a singleton
|
||||
module.exports = new ClientDaemonManager();
|
||||
Reference in new issue
Block a user