Skip to main content
Glama
ooples

MCP Console Automation Server

PuppetProtocol.ts34.1 kB
import { spawn, ChildProcess } from 'child_process'; import { BaseProtocol } from '../core/BaseProtocol.js'; import { ConsoleSession, SessionOptions, ConsoleType, ConsoleOutput, } from '../types/index.js'; import { ProtocolCapabilities, SessionState, ErrorContext, ProtocolHealthStatus, ErrorRecoveryResult, ResourceUsage, } from '../core/IProtocol.js'; // Puppet Protocol connection options interface PuppetConnectionOptions { operation?: | 'apply' | 'agent' | 'master' | 'cert' | 'module' | 'node' | 'resource' | 'config' | 'device' | 'lookup' | 'facts' | 'filebucket' | 'help' | 'describe' | 'doc' | 'epp' | 'parser'; manifestFile?: string; manifestContent?: string; modulePath?: string[]; configFile?: string; environment?: string; server?: string; port?: number; certname?: string; ca_server?: string; ca_port?: number; masterport?: number; ssldir?: string; certdir?: string; keydir?: string; privatekeydir?: string; publickeydir?: string; requestdir?: string; certdnsnames?: string[]; certipaddresses?: string[]; vardir?: string; rundir?: string; logdir?: string; codedir?: string; confdir?: string; hiera_config?: string; user?: string; group?: string; logLevel?: | 'debug' | 'info' | 'notice' | 'warning' | 'err' | 'alert' | 'emerg' | 'crit'; verbose?: boolean; debug?: boolean; noop?: boolean; dryRun?: boolean; test?: boolean; onetime?: boolean; detailed_exitcodes?: boolean; disable_warnings?: string[]; strict?: 'off' | 'warning' | 'error'; strict_variables?: boolean; disable_warnings_list?: string[]; compile?: boolean; catalog?: string; facts?: string; fact_format?: 'yaml' | 'json' | 'pson'; execute?: string; tags?: string[]; skip_tags?: string[]; ignorecache?: boolean; ignoreschedules?: boolean; usecacheonfailure?: boolean; no_use_srv_records?: boolean; use_srv_records?: boolean; srv_domain?: string; preferred_serialization_format?: 'pson' | 'json' | 'yaml' | 'b64_zlib_yaml'; report?: boolean; reports?: string[]; report_server?: string; report_port?: number; report_handler?: string[]; graph?: boolean; graphdir?: string; digest?: string; node_name?: string; node_name_fact?: string; node_name_value?: string; external_nodes?: string; enc_api?: string; storeconfigs?: boolean; storeconfigs_backend?: string; dbadapter?: string; dbname?: string; dbserver?: string; dbport?: number; dbuser?: string; dbpassword?: string; dbconnections?: number; railslog?: boolean; rails_loglevel?: | 'debug' | 'info' | 'notice' | 'warning' | 'err' | 'alert' | 'emerg' | 'crit'; autosign?: boolean | string; autosign_whitelist?: string; csr_attributes?: string; trusted_oid_mapping_file?: string; dns_alt_names?: string[]; ca?: boolean; ca_name?: string; cadir?: string; cacert?: string; cakey?: string; caprivatedir?: string; capublicdir?: string; csrdir?: string; signeddir?: string; ca_ttl?: string; ca_days?: number; req_bits?: number; keylength?: number; digest_algorithm?: string; ca_md?: string; bucketdir?: string; archive_files?: boolean; archive_file_server?: string; show_diff?: boolean; diff?: boolean; daemonize?: boolean; pid_file?: string; waitforcert?: number; maxwaitforcert?: number; http_proxy_host?: string; http_proxy_port?: number; http_proxy_user?: string; http_proxy_password?: string; http_keepalive_timeout?: number; http_debug?: boolean; filetimeout?: number; http_user_agent?: string; autoflush?: boolean; syslogfacility?: string; statedir?: string; clientyamldir?: string; client_datadir?: string; classfile?: string; resourcefile?: string; puppetdlockfile?: string; statefile?: string; clientbucketdir?: string; inventory_server?: string; inventory_port?: number; inventory_terminus?: string; facts_terminus?: string; catalog_terminus?: string; node_terminus?: string; report_terminus?: string; file_bucket_terminus?: string; yaml_facts?: boolean; plugindest?: string; pluginsource?: string; pluginsync?: boolean; pluginsignore?: string[]; ignoremissingtypes?: boolean; priority?: number; trace?: boolean; profile?: boolean; evaltrace?: boolean; summarize?: boolean; prerun_command?: string; postrun_command?: string; freeze_main?: boolean; preview_outputdir?: string; rich_data?: boolean; basemodulepath?: string; disable_per_environment_manifest?: boolean; parser?: 'current' | 'future'; binder?: boolean; environmentpath?: string; default_manifest?: string; disable_warnings_puppet?: string[]; always_retry_plugins?: boolean; module_working_dir?: string; module_skeleton_dir?: string; forge_authorization?: string; forge_cache_dir?: string; module_repository?: string; module_tool_pre_install_check?: boolean; module_tool_post_install_check?: boolean; resolve_options?: Record<string, any>; customPuppetPath?: string; customFlags?: string[]; environmentVars?: Record<string, string>; } /** * Puppet Protocol Implementation * * Provides Puppet configuration management capabilities for infrastructure automation * Supports comprehensive Puppet functionality including manifests, modules, agents, masters, * certificate management, facts, resources, environments, Hiera, PuppetDB integration, * and enterprise Puppet Enterprise features */ export class PuppetProtocol extends BaseProtocol { public readonly type: ConsoleType = 'puppet'; public readonly capabilities: ProtocolCapabilities; private puppetProcesses = new Map<string, ChildProcess>(); // Compatibility property for old ProtocolFactory interface public get healthStatus(): ProtocolHealthStatus { return { isHealthy: this.isInitialized, lastChecked: new Date(), errors: [], warnings: [], metrics: { activeSessions: this.sessions.size, totalSessions: this.sessions.size, averageLatency: 0, successRate: 100, uptime: 0, }, dependencies: {}, }; } constructor() { super('puppet'); this.capabilities = { supportsStreaming: true, supportsFileTransfer: true, supportsX11Forwarding: false, supportsPortForwarding: false, supportsAuthentication: true, supportsEncryption: true, supportsCompression: true, supportsMultiplexing: true, supportsKeepAlive: true, supportsReconnection: true, supportsBinaryData: true, supportsCustomEnvironment: true, supportsWorkingDirectory: true, supportsSignals: true, supportsResizing: false, supportsPTY: false, maxConcurrentSessions: 50, // Puppet can handle many concurrent operations defaultTimeout: 600000, // Puppet operations can take a very long time supportedEncodings: ['utf-8', 'ascii'], supportedAuthMethods: ['cert', 'psk'], platformSupport: { windows: true, // Puppet supports Windows linux: true, // Primary Puppet platform macos: true, // Puppet supports macOS freebsd: true, }, }; } async initialize(): Promise<void> { if (this.isInitialized) return; try { // Check if Puppet is available await this.checkPuppetAvailability(); this.isInitialized = true; this.logger.info('Puppet protocol initialized with enterprise features'); } catch (error: any) { this.logger.error('Failed to initialize Puppet protocol', error); throw error; } } async createSession(options: SessionOptions): Promise<ConsoleSession> { const sessionId = `puppet-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`; return await this.createSessionWithTypeDetection(sessionId, options); } async dispose(): Promise<void> { await this.cleanup(); } async executeCommand( sessionId: string, command: string, args?: string[] ): Promise<void> { const fullCommand = args && args.length > 0 ? `${command} ${args.join(' ')}` : command; await this.sendInput(sessionId, fullCommand + '\n'); } async sendInput(sessionId: string, input: string): Promise<void> { const puppetProcess = this.puppetProcesses.get(sessionId); const session = this.sessions.get(sessionId); if (!puppetProcess || !puppetProcess.stdin || !session) { throw new Error(`No active Puppet session: ${sessionId}`); } puppetProcess.stdin.write(input); session.lastActivity = new Date(); this.emit('input-sent', { sessionId, input, timestamp: new Date(), }); this.logger.debug( `Sent input to Puppet session ${sessionId}: ${input.substring(0, 100)}` ); } async closeSession(sessionId: string): Promise<void> { try { const puppetProcess = this.puppetProcesses.get(sessionId); if (puppetProcess) { // Try graceful shutdown first puppetProcess.kill('SIGTERM'); // Force kill after timeout setTimeout(() => { if (puppetProcess && !puppetProcess.killed) { puppetProcess.kill('SIGKILL'); } }, 30000); // Puppet operations can take a long time this.puppetProcesses.delete(sessionId); } // Clean up base protocol session this.sessions.delete(sessionId); this.logger.info(`Puppet session ${sessionId} closed`); this.emit('session-closed', sessionId); } catch (error) { this.logger.error(`Error closing Puppet session ${sessionId}:`, error); throw error; } } async doCreateSession( sessionId: string, options: SessionOptions, sessionState: SessionState ): Promise<ConsoleSession> { if (!this.isInitialized) { await this.initialize(); } const puppetOptions = options.puppetOptions || ({} as PuppetConnectionOptions); // Build Puppet command const puppetCommand = this.buildPuppetCommand(puppetOptions); // Spawn Puppet process const puppetProcess = spawn(puppetCommand[0], puppetCommand.slice(1), { stdio: ['pipe', 'pipe', 'pipe'], cwd: options.cwd || process.cwd(), env: { ...process.env, ...this.buildEnvironment(puppetOptions), ...options.env, }, }); // Set up output handling puppetProcess.stdout?.on('data', (data) => { const output: ConsoleOutput = { sessionId, type: 'stdout', data: data.toString(), timestamp: new Date(), }; this.addToOutputBuffer(sessionId, output); }); puppetProcess.stderr?.on('data', (data) => { const output: ConsoleOutput = { sessionId, type: 'stderr', data: data.toString(), timestamp: new Date(), }; this.addToOutputBuffer(sessionId, output); }); puppetProcess.on('error', (error) => { this.logger.error( `Puppet process error for session ${sessionId}:`, error ); this.emit('session-error', { sessionId, error }); }); puppetProcess.on('close', (code) => { this.logger.info( `Puppet process closed for session ${sessionId} with code ${code}` ); this.markSessionComplete(sessionId, code || 0); }); // Store the process this.puppetProcesses.set(sessionId, puppetProcess); // Create session object const session: ConsoleSession = { id: sessionId, command: puppetCommand[0], args: puppetCommand.slice(1), cwd: options.cwd || process.cwd(), env: { ...process.env, ...this.buildEnvironment(puppetOptions), ...options.env, }, createdAt: new Date(), lastActivity: new Date(), status: 'running', type: this.type, streaming: options.streaming, executionState: 'idle', activeCommands: new Map(), pid: puppetProcess.pid, }; this.sessions.set(sessionId, session); this.logger.info( `Puppet session ${sessionId} created for operation ${puppetOptions.operation || 'apply'}` ); this.emit('session-created', { sessionId, type: 'puppet', session }); return session; } // Override getOutput to satisfy old ProtocolFactory interface (returns string) async getOutput(sessionId: string, since?: Date): Promise<any> { const outputs = await super.getOutput(sessionId, since); return outputs.map((output) => output.data).join(''); } // Missing IProtocol methods for compatibility getAllSessions(): ConsoleSession[] { return Array.from(this.sessions.values()); } getActiveSessions(): ConsoleSession[] { return Array.from(this.sessions.values()).filter( (session) => session.status === 'running' ); } getSessionCount(): number { return this.sessions.size; } async getSessionState(sessionId: string): Promise<SessionState> { const session = this.sessions.get(sessionId); if (!session) { throw new Error(`Session ${sessionId} not found`); } return { sessionId, status: session.status, isOneShot: true, // Most Puppet operations are one-shot isPersistent: false, createdAt: session.createdAt, lastActivity: session.lastActivity, pid: session.pid, metadata: {}, }; } async handleError( error: Error, context: ErrorContext ): Promise<ErrorRecoveryResult> { this.logger.error( `Error in Puppet session ${context.sessionId}: ${error.message}` ); return { recovered: false, strategy: 'none', attempts: 0, duration: 0, error: error.message, }; } async recoverSession(sessionId: string): Promise<boolean> { const puppetProcess = this.puppetProcesses.get(sessionId); return (puppetProcess && !puppetProcess.killed) || false; } getResourceUsage(): ResourceUsage { const memUsage = process.memoryUsage(); const cpuUsage = process.cpuUsage(); return { memory: { used: memUsage.heapUsed, available: memUsage.heapTotal, peak: memUsage.heapTotal, }, cpu: { usage: cpuUsage.user + cpuUsage.system, load: [0, 0, 0], }, network: { bytesIn: 0, bytesOut: 0, connectionsActive: this.puppetProcesses.size, }, storage: { bytesRead: 0, bytesWritten: 0, }, sessions: { active: this.sessions.size, total: this.sessions.size, peak: this.sessions.size, }, }; } async getHealthStatus(): Promise<ProtocolHealthStatus> { const baseStatus = await super.getHealthStatus(); try { await this.checkPuppetAvailability(); return { ...baseStatus, dependencies: { puppet: { available: true }, }, }; } catch (error) { return { ...baseStatus, isHealthy: false, errors: [...baseStatus.errors, `Puppet not available: ${error}`], dependencies: { puppet: { available: false }, }, }; } } private async checkPuppetAvailability(): Promise<void> { return new Promise((resolve, reject) => { const testProcess = spawn('puppet', ['--version'], { stdio: 'pipe' }); testProcess.on('close', (code) => { if (code === 0) { resolve(); } else { reject( new Error( 'Puppet not found. Please install Puppet or Puppet Agent.' ) ); } }); testProcess.on('error', () => { reject( new Error('Puppet not found. Please install Puppet or Puppet Agent.') ); }); }); } private buildPuppetCommand(options: PuppetConnectionOptions): string[] { const command = []; // Puppet executable if (options.customPuppetPath) { command.push(options.customPuppetPath); } else { command.push('puppet'); } // Puppet operation if (options.operation) { command.push(options.operation); } else { command.push('apply'); } // Build operation-specific arguments switch (options.operation) { case 'apply': this.buildApplyArguments(command, options); break; case 'agent': this.buildAgentArguments(command, options); break; case 'master': this.buildMasterArguments(command, options); break; case 'cert': this.buildCertArguments(command, options); break; case 'module': this.buildModuleArguments(command, options); break; case 'node': this.buildNodeArguments(command, options); break; case 'resource': this.buildResourceArguments(command, options); break; case 'config': this.buildConfigArguments(command, options); break; case 'device': this.buildDeviceArguments(command, options); break; case 'lookup': this.buildLookupArguments(command, options); break; case 'facts': this.buildFactsArguments(command, options); break; case 'filebucket': this.buildFilebucketArguments(command, options); break; case 'describe': this.buildDescribeArguments(command, options); break; case 'doc': this.buildDocArguments(command, options); break; case 'epp': this.buildEppArguments(command, options); break; case 'parser': this.buildParserArguments(command, options); break; default: this.buildApplyArguments(command, options); break; } // Common arguments for all operations this.buildCommonArguments(command, options); // Custom flags if (options.customFlags && options.customFlags.length > 0) { command.push(...options.customFlags); } return command; } private buildApplyArguments( command: string[], options: PuppetConnectionOptions ): void { // Manifest file or content if (options.manifestFile) { command.push(options.manifestFile); } else if (options.manifestContent) { command.push('-e', options.manifestContent); } // Apply-specific options if (options.noop) { command.push('--noop'); } if (options.test) { command.push('--test'); } if (options.detailed_exitcodes) { command.push('--detailed-exitcodes'); } if (options.catalog) { command.push('--catalog', options.catalog); } if (options.facts) { command.push('--facts', options.facts); } if (options.compile) { command.push('--compile'); } if (options.execute) { command.push('--execute', options.execute); } if (options.tags && options.tags.length > 0) { command.push('--tags', options.tags.join(',')); } if (options.skip_tags && options.skip_tags.length > 0) { command.push('--skip-tags', options.skip_tags.join(',')); } } private buildAgentArguments( command: string[], options: PuppetConnectionOptions ): void { // Agent-specific options if (options.onetime) { command.push('--onetime'); } if (options.test) { command.push('--test'); } if (options.detailed_exitcodes) { command.push('--detailed-exitcodes'); } if (options.noop) { command.push('--noop'); } if (options.ignorecache) { command.push('--ignorecache'); } if (options.ignoreschedules) { command.push('--ignoreschedules'); } if (options.usecacheonfailure) { command.push('--usecacheonfailure'); } if (options.tags && options.tags.length > 0) { command.push('--tags', options.tags.join(',')); } if (options.skip_tags && options.skip_tags.length > 0) { command.push('--skip-tags', options.skip_tags.join(',')); } if (options.waitforcert !== undefined) { command.push('--waitforcert', options.waitforcert.toString()); } if (options.maxwaitforcert !== undefined) { command.push('--maxwaitforcert', options.maxwaitforcert.toString()); } if (options.daemonize) { command.push('--daemonize'); } if (options.no_use_srv_records) { command.push('--no-use_srv_records'); } if (options.use_srv_records) { command.push('--use_srv_records'); } if (options.srv_domain) { command.push('--srv_domain', options.srv_domain); } } private buildMasterArguments( command: string[], options: PuppetConnectionOptions ): void { // Master-specific options if (options.compile) { command.push('--compile'); } if (options.node_name) { command.push('--node-name', options.node_name); } if (options.daemonize) { command.push('--daemonize'); } if (options.ca) { command.push('--ca'); } if (options.no_use_srv_records) { command.push('--no-use_srv_records'); } if (options.use_srv_records) { command.push('--use_srv_records'); } if (options.srv_domain) { command.push('--srv_domain', options.srv_domain); } if (options.autosign !== undefined) { if (typeof options.autosign === 'boolean') { command.push('--autosign', options.autosign.toString()); } else { command.push('--autosign', options.autosign); } } } private buildCertArguments( command: string[], options: PuppetConnectionOptions ): void { // Certificate management arguments if (options.certname) { command.push('--certname', options.certname); } if (options.ca_server) { command.push('--ca_server', options.ca_server); } if (options.ca_port) { command.push('--ca_port', options.ca_port.toString()); } if (options.certdnsnames && options.certdnsnames.length > 0) { command.push('--certdnsnames', options.certdnsnames.join(',')); } if (options.certipaddresses && options.certipaddresses.length > 0) { command.push('--certipaddresses', options.certipaddresses.join(',')); } if (options.digest) { command.push('--digest', options.digest); } if (options.ca_name) { command.push('--ca-name', options.ca_name); } if (options.ca_ttl) { command.push('--ca-ttl', options.ca_ttl); } if (options.req_bits) { command.push('--req-bits', options.req_bits.toString()); } if (options.keylength) { command.push('--keylength', options.keylength.toString()); } } private buildModuleArguments( command: string[], options: PuppetConnectionOptions ): void { // Module management arguments if (options.module_working_dir) { command.push('--module_working_dir', options.module_working_dir); } if (options.module_skeleton_dir) { command.push('--module_skeleton_dir', options.module_skeleton_dir); } if (options.forge_authorization) { command.push('--forge_authorization', options.forge_authorization); } if (options.forge_cache_dir) { command.push('--forge_cache_dir', options.forge_cache_dir); } if (options.module_repository) { command.push('--module_repository', options.module_repository); } if (options.module_tool_pre_install_check !== undefined) { command.push( '--module_tool_pre_install_check', options.module_tool_pre_install_check.toString() ); } if (options.module_tool_post_install_check !== undefined) { command.push( '--module_tool_post_install_check', options.module_tool_post_install_check.toString() ); } } private buildNodeArguments( command: string[], options: PuppetConnectionOptions ): void { // Node management arguments if (options.node_name) { command.push('--node-name', options.node_name); } if (options.node_name_fact) { command.push('--node-name-fact', options.node_name_fact); } if (options.node_name_value) { command.push('--node-name-value', options.node_name_value); } if (options.external_nodes) { command.push('--external_nodes', options.external_nodes); } if (options.enc_api) { command.push('--enc_api', options.enc_api); } } private buildResourceArguments( command: string[], options: PuppetConnectionOptions ): void { // Resource management arguments if (options.tags && options.tags.length > 0) { command.push('--tags', options.tags.join(',')); } if (options.facts) { command.push('--facts', options.facts); } if (options.fact_format) { command.push('--fact-format', options.fact_format); } } private buildConfigArguments( command: string[], options: PuppetConnectionOptions ): void { // Config management arguments - most handled in common arguments } private buildDeviceArguments( command: string[], options: PuppetConnectionOptions ): void { // Device management arguments if (options.detailed_exitcodes) { command.push('--detailed-exitcodes'); } if (options.test) { command.push('--test'); } if (options.waitforcert !== undefined) { command.push('--waitforcert', options.waitforcert.toString()); } } private buildLookupArguments( command: string[], options: PuppetConnectionOptions ): void { // Hiera lookup arguments if (options.facts) { command.push('--facts', options.facts); } if (options.fact_format) { command.push('--fact-format', options.fact_format); } if (options.node_name) { command.push('--node', options.node_name); } } private buildFactsArguments( command: string[], options: PuppetConnectionOptions ): void { // Facts management arguments if (options.fact_format) { command.push('--format', options.fact_format); } } private buildFilebucketArguments( command: string[], options: PuppetConnectionOptions ): void { // Filebucket arguments if (options.bucketdir) { command.push('--bucketdir', options.bucketdir); } } private buildDescribeArguments( command: string[], options: PuppetConnectionOptions ): void { // Describe arguments - typically just the resource type } private buildDocArguments( command: string[], options: PuppetConnectionOptions ): void { // Documentation arguments if (options.modulePath && options.modulePath.length > 0) { command.push('--modulepath', options.modulePath.join(':')); } } private buildEppArguments( command: string[], options: PuppetConnectionOptions ): void { // EPP template arguments if (options.facts) { command.push('--facts', options.facts); } } private buildParserArguments( command: string[], options: PuppetConnectionOptions ): void { // Parser arguments if (options.parser) { command.push('--parser', options.parser); } } private buildCommonArguments( command: string[], options: PuppetConnectionOptions ): void { // Configuration and directories if (options.configFile) { command.push('--config', options.configFile); } if (options.confdir) { command.push('--confdir', options.confdir); } if (options.vardir) { command.push('--vardir', options.vardir); } if (options.rundir) { command.push('--rundir', options.rundir); } if (options.logdir) { command.push('--logdir', options.logdir); } if (options.codedir) { command.push('--codedir', options.codedir); } if (options.ssldir) { command.push('--ssldir', options.ssldir); } // Environment and paths if (options.environment) { command.push('--environment', options.environment); } if (options.modulePath && options.modulePath.length > 0) { command.push('--modulepath', options.modulePath.join(':')); } if (options.basemodulepath) { command.push('--basemodulepath', options.basemodulepath); } if (options.environmentpath) { command.push('--environmentpath', options.environmentpath); } if (options.hiera_config) { command.push('--hiera_config', options.hiera_config); } // Server connection if (options.server) { command.push('--server', options.server); } if (options.port) { command.push('--serverport', options.port.toString()); } if (options.masterport) { command.push('--masterport', options.masterport.toString()); } // Certificate settings if (options.certname) { command.push('--certname', options.certname); } // User and group if (options.user) { command.push('--user', options.user); } if (options.group) { command.push('--group', options.group); } // Logging and verbosity if (options.logLevel) { command.push('--log_level', options.logLevel); } if (options.verbose) { command.push('--verbose'); } if (options.debug) { command.push('--debug'); } if (options.trace) { command.push('--trace'); } if (options.profile) { command.push('--profile'); } if (options.evaltrace) { command.push('--evaltrace'); } if (options.summarize) { command.push('--summarize'); } // Behavior options if (options.strict) { command.push('--strict', options.strict); } if (options.strict_variables) { command.push('--strict_variables'); } if (options.disable_warnings && options.disable_warnings.length > 0) { command.push('--disable_warnings', options.disable_warnings.join(',')); } if (options.graph) { command.push('--graph'); } if (options.graphdir) { command.push('--graphdir', options.graphdir); } if (options.show_diff) { command.push('--show_diff'); } if (options.diff) { command.push('--diff'); } // HTTP settings if (options.http_proxy_host) { command.push('--http_proxy_host', options.http_proxy_host); } if (options.http_proxy_port) { command.push('--http_proxy_port', options.http_proxy_port.toString()); } if (options.http_debug) { command.push('--http_debug'); } // Report settings if (options.report) { command.push('--report'); } if (options.reports && options.reports.length > 0) { command.push('--reports', options.reports.join(',')); } // Plugin settings if (options.pluginsync) { command.push('--pluginsync'); } if (options.pluginsource) { command.push('--pluginsource', options.pluginsource); } if (options.plugindest) { command.push('--plugindest', options.plugindest); } // PID file if (options.pid_file) { command.push('--pidfile', options.pid_file); } } private buildEnvironment( options: PuppetConnectionOptions ): Record<string, string> { const env: Record<string, string> = {}; // Puppet environment variables if (options.environment) { env.PUPPET_ENVIRONMENT = options.environment; } if (options.confdir) { env.PUPPET_CONFDIR = options.confdir; } if (options.vardir) { env.PUPPET_VARDIR = options.vardir; } if (options.codedir) { env.PUPPET_CODEDIR = options.codedir; } if (options.logdir) { env.PUPPET_LOGDIR = options.logdir; } if (options.rundir) { env.PUPPET_RUNDIR = options.rundir; } if (options.ssldir) { env.PUPPET_SSLDIR = options.ssldir; } // Module path if (options.modulePath && options.modulePath.length > 0) { env.PUPPET_MODULEPATH = options.modulePath.join(':'); } // Server settings if (options.server) { env.PUPPET_SERVER = options.server; } if (options.port) { env.PUPPET_SERVERPORT = options.port.toString(); } if (options.certname) { env.PUPPET_CERTNAME = options.certname; } // Hiera settings if (options.hiera_config) { env.PUPPET_HIERA_CONFIG = options.hiera_config; } // Logging if (options.logLevel) { env.PUPPET_LOG_LEVEL = options.logLevel; } // Database settings for PuppetDB if (options.storeconfigs) { env.PUPPET_STORECONFIGS = 'true'; if (options.storeconfigs_backend) { env.PUPPET_STORECONFIGS_BACKEND = options.storeconfigs_backend; } } if (options.dbadapter) { env.PUPPET_DBADAPTER = options.dbadapter; } if (options.dbname) { env.PUPPET_DBNAME = options.dbname; } if (options.dbserver) { env.PUPPET_DBSERVER = options.dbserver; } if (options.dbport) { env.PUPPET_DBPORT = options.dbport.toString(); } if (options.dbuser) { env.PUPPET_DBUSER = options.dbuser; } // HTTP proxy settings if (options.http_proxy_host) { env.http_proxy = `http://${options.http_proxy_host}:${options.http_proxy_port || 8080}`; env.https_proxy = env.http_proxy; } // Custom environment variables if (options.environmentVars) { Object.assign(env, options.environmentVars); } return env; } async cleanup(): Promise<void> { this.logger.info('Cleaning up Puppet protocol'); // Close all Puppet processes for (const [sessionId, process] of Array.from(this.puppetProcesses)) { try { process.kill(); } catch (error) { this.logger.error( `Error killing Puppet process for session ${sessionId}:`, error ); } } // Clear all data this.puppetProcesses.clear(); // Call parent cleanup await super.cleanup(); } } export default PuppetProtocol;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ooples/mcp-console-automation'

If you have feedback or need assistance with the MCP directory API, please join our Discord server