@badc0d3/piece-bash-runner
Version:
Run bash commands with NFS/SMB mounting support in Activepieces
191 lines (189 loc) • 7.47 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.runBashCommand = void 0;
const pieces_framework_1 = require("@activepieces/pieces-framework");
const child_process_1 = require("child_process");
const util_1 = require("util");
const fs_1 = require("fs");
const execAsync = (0, util_1.promisify)(child_process_1.exec);
exports.runBashCommand = (0, pieces_framework_1.createAction)({
name: 'run-bash-command',
displayName: 'Run Bash Command',
description: 'Execute bash commands with optional NFS/SMB mounting',
props: {
command: pieces_framework_1.Property.LongText({
displayName: 'Bash Command',
description: 'The bash command or script to execute',
required: true,
defaultValue: `#!/bin/bash
# Example: List files and show system info
echo "Current directory: $(pwd)"
echo "Files:"
ls -la
echo ""
echo "System info:"
uname -a`,
}),
mountConfig: pieces_framework_1.Property.Object({
displayName: 'Mount Configuration (Optional)',
description: 'Configure NFS or SMB mount before running command',
required: false,
}),
mountType: pieces_framework_1.Property.StaticDropdown({
displayName: 'Mount Type',
description: 'Type of network mount (leave empty for no mount)',
required: false,
options: {
options: [
{ label: 'None', value: '' },
{ label: 'NFS', value: 'nfs' },
{ label: 'SMB/CIFS', value: 'smb' },
],
},
defaultValue: '',
}),
mountSource: pieces_framework_1.Property.ShortText({
displayName: 'Mount Source',
description: 'Network path (e.g., server:/path or //server/share)',
required: false,
}),
mountPoint: pieces_framework_1.Property.ShortText({
displayName: 'Mount Point',
description: 'Local mount point (e.g., /mnt/network)',
required: false,
defaultValue: '/mnt/network',
}),
mountOptions: pieces_framework_1.Property.ShortText({
displayName: 'Mount Options',
description: 'Additional mount options',
required: false,
defaultValue: '',
}),
mountUsername: pieces_framework_1.Property.ShortText({
displayName: 'Username (SMB only)',
description: 'Username for SMB authentication',
required: false,
}),
mountPassword: pieces_framework_1.Property.ShortText({
displayName: 'Password (SMB only)',
description: 'Password for SMB authentication (use secure storage in production)',
required: false,
}),
workingDirectory: pieces_framework_1.Property.ShortText({
displayName: 'Working Directory',
description: 'Directory to execute the command in',
required: false,
defaultValue: '/tmp',
}),
timeout: pieces_framework_1.Property.Number({
displayName: 'Timeout (seconds)',
description: 'Maximum execution time in seconds',
required: false,
defaultValue: 30,
}),
captureOutput: pieces_framework_1.Property.Checkbox({
displayName: 'Capture Output',
description: 'Capture stdout and stderr separately',
required: false,
defaultValue: true,
}),
},
async run(context) {
const { command, mountType, mountSource, mountPoint, mountOptions, mountUsername, mountPassword, workingDirectory, timeout, captureOutput } = context.propsValue;
let mountCleanup = '';
let fullCommand = '';
try {
// Create working directory if it doesn't exist
if (!(0, fs_1.existsSync)(workingDirectory)) {
(0, fs_1.mkdirSync)(workingDirectory, { recursive: true });
}
// Handle mount configuration if provided
if (mountType && mountType !== '' && mountSource) {
// Create mount point if it doesn't exist
if (!(0, fs_1.existsSync)(mountPoint)) {
(0, fs_1.mkdirSync)(mountPoint, { recursive: true });
}
// Build mount command based on type
let mountCommand = '';
if (mountType === 'nfs') {
const nfsOptions = mountOptions || 'rw,sync';
mountCommand = `mount -t nfs -o ${nfsOptions} ${mountSource} ${mountPoint}`;
}
else if (mountType === 'smb') {
let smbOptions = mountOptions || 'rw';
if (mountUsername) {
smbOptions += `,username=${mountUsername}`;
if (mountPassword) {
smbOptions += `,password=${mountPassword}`;
}
}
mountCommand = `mount -t cifs -o ${smbOptions} ${mountSource} ${mountPoint}`;
}
// Set up cleanup command
mountCleanup = `umount ${mountPoint} 2>/dev/null || true`;
// Combine mount, command, and cleanup
fullCommand = `
# Mount network drive
${mountCommand}
# Execute user command
cd ${workingDirectory}
${command}
# Cleanup will happen in finally block
`;
}
else {
// No mount needed, just run the command
fullCommand = `cd ${workingDirectory} && ${command}`;
}
// Execute the command
const { stdout, stderr } = await execAsync(fullCommand, {
timeout: (timeout || 30) * 1000,
maxBuffer: 10 * 1024 * 1024, // 10MB buffer
shell: '/bin/bash',
});
// Clean up mount if needed
if (mountCleanup) {
try {
await execAsync(mountCleanup);
}
catch (e) {
// Ignore unmount errors
}
}
if (captureOutput) {
return {
success: true,
output: stdout || '',
stdout: stdout || '',
stderr: stderr || '',
executionTime: new Date().toISOString(),
};
}
return {
success: true,
output: stdout || '',
executionTime: new Date().toISOString(),
};
}
catch (error) {
// Try to clean up mount on error
if (mountCleanup) {
try {
await execAsync(mountCleanup);
}
catch (e) {
// Ignore unmount errors
}
}
return {
success: false,
error: error.message,
stdout: error.stdout || '',
stderr: error.stderr || '',
code: error.code || 1,
executionTime: new Date().toISOString(),
};
}
},
});
//# sourceMappingURL=run-bash-command.js.map